184 rindas
5.5 KiB
C
Executable File
184 rindas
5.5 KiB
C
Executable File
/*
|
|
ToolsMenu - Add tools to the Workbench Tools menu
|
|
|
|
Copyright (C) 2015, 2018 Kim Fastrup Larsen
|
|
|
|
This program is free software: you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation, either ver-
|
|
sion 3 of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be use-
|
|
ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
|
ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public Li-
|
|
cense along with this program. If not, see
|
|
<http://www.gnu.org/licenses/>.
|
|
|
|
The author can be contacted on <kimflarsen@hotmail.com>
|
|
*/
|
|
|
|
#include <dos/dos.h>
|
|
#include <dos/dostags.h>
|
|
#include <exec/memory.h>
|
|
#include <workbench/startup.h>
|
|
|
|
#include <clib/dos_protos.h>
|
|
#include <clib/exec_protos.h>
|
|
#include <clib/icon_protos.h>
|
|
|
|
#ifdef USE_PRAGMAS
|
|
#include <proto/dos.h>
|
|
#include <proto/exec.h>
|
|
#include <proto/icon.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
#include "toolrun.h"
|
|
|
|
#define MIN_STACK_SIZE 4000
|
|
|
|
/* We send this extended WBStartup to any tool that we launch. It will
|
|
contain the Workbench arguments passed to run_tool(). Once the tool quits,
|
|
it will reply to this message, and at that point we call the clean_up
|
|
function (also passed to run_tool()) to let it clean up the arguments. */
|
|
typedef struct {
|
|
struct WBStartup wb_startup;
|
|
Tr_clean_up *clean_up;
|
|
void *user_data;
|
|
} Startmsg;
|
|
|
|
/* The tools we run will be told to reply to this port when they quit. */
|
|
static struct MsgPort *reply_port;
|
|
/* The number of tools started that haven't quit yet. */
|
|
static int running;
|
|
|
|
static void free_startmsg(Startmsg *msg)
|
|
{
|
|
FreeVec(msg->wb_startup.sm_ToolWindow);
|
|
FreeMem(msg, sizeof *msg);
|
|
}
|
|
|
|
/* Create the reply port and return its signal bit as a mask. */
|
|
ULONG tr_set_up()
|
|
{
|
|
if ((reply_port = CreateMsgPort()) == NULL)
|
|
exit(RETURN_FAIL);
|
|
return 1UL << reply_port->mp_SigBit;
|
|
}
|
|
|
|
Bool tr_run_tool(struct WBArg *arg_list, LONG num_args,
|
|
Tr_clean_up *clean_up, void *user_data)
|
|
{
|
|
BPTR old_dir;
|
|
struct DiskObject *disk_obj;
|
|
Startmsg *startmsg;
|
|
LONG stack_size;
|
|
BPTR home_dir;
|
|
struct Process *process;
|
|
|
|
/* Load the tool's icon and check that it really is a Workbench tool. */
|
|
old_dir = CurrentDir(arg_list[0].wa_Lock);
|
|
if ((disk_obj = GetDiskObject(arg_list[0].wa_Name)) == NULL)
|
|
goto run_tool_failed1;
|
|
if (disk_obj->do_Type != WBTOOL)
|
|
goto run_tool_failed2;
|
|
/* Use the stacksize specified in the icon unless it's too small. */
|
|
if ((stack_size = disk_obj->do_StackSize) < MIN_STACK_SIZE)
|
|
stack_size = MIN_STACK_SIZE;
|
|
/* Set up startup message. */
|
|
if ((startmsg=AllocMem(sizeof *startmsg,MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
|
|
goto run_tool_failed2;
|
|
startmsg->wb_startup.sm_ArgList = arg_list;
|
|
startmsg->wb_startup.sm_NumArgs = num_args;
|
|
startmsg->clean_up = clean_up;
|
|
startmsg->user_data = user_data;
|
|
/* We copy the icon's ToolWindow if it isn't NULL. */
|
|
if (disk_obj->do_ToolWindow != NULL &&
|
|
(startmsg->wb_startup.sm_ToolWindow = copy_of(disk_obj->do_ToolWindow))
|
|
== NULL)
|
|
goto run_tool_failed3;
|
|
/* Load the tool. */
|
|
if ((startmsg->wb_startup.sm_Segment = NewLoadSegTags(
|
|
arg_list[0].wa_Name, TAG_DONE)) == NULL)
|
|
goto run_tool_failed3;
|
|
/* Get a lock for PROGDIR. */
|
|
if ((home_dir = DupLock(arg_list[0].wa_Lock)) == 0)
|
|
goto run_tool_failed4;
|
|
/* Run the tool as a non-CLI process. */
|
|
if ((process = CreateNewProcTags(
|
|
NP_Seglist, startmsg->wb_startup.sm_Segment,
|
|
NP_FreeSeglist, (LONG) TRUE,
|
|
NP_Input, NULL,
|
|
NP_CloseInput, (LONG) FALSE,
|
|
NP_Output, NULL,
|
|
NP_CloseOutput, (LONG) FALSE,
|
|
NP_Error, NULL,
|
|
NP_CloseError, (LONG) FALSE,
|
|
NP_CurrentDir, NULL,
|
|
NP_StackSize, stack_size,
|
|
NP_Name, arg_list[0].wa_Name,
|
|
NP_Priority, 0L,
|
|
NP_ConsoleTask, NULL,
|
|
NP_WindowPtr, NULL,
|
|
NP_HomeDir, home_dir,
|
|
TAG_DONE)) == NULL)
|
|
goto run_tool_failed5;
|
|
/* We have started the process, so we mustn't do anything after this point
|
|
that might fail. Send the startup message to the tool. */
|
|
startmsg->wb_startup.sm_Process = &process->pr_MsgPort;
|
|
startmsg->wb_startup.sm_Message.mn_ReplyPort = reply_port;
|
|
PutMsg(startmsg->wb_startup.sm_Process, (struct Message *) startmsg);
|
|
++running;
|
|
FreeDiskObject(disk_obj);
|
|
CurrentDir(old_dir);
|
|
return YES;
|
|
|
|
run_tool_failed5:
|
|
UnLock(home_dir);
|
|
|
|
run_tool_failed4:
|
|
UnLoadSeg(startmsg->wb_startup.sm_Segment);
|
|
|
|
run_tool_failed3:
|
|
free_startmsg(startmsg);
|
|
|
|
run_tool_failed2:
|
|
FreeDiskObject(disk_obj);
|
|
|
|
run_tool_failed1:
|
|
CurrentDir(old_dir);
|
|
return NO;
|
|
}
|
|
|
|
/* When a tool started by tr_run_tool() quits, we receive a reply to our
|
|
startup message. At this point we call the clean up function provided,
|
|
then clean up the message itself. */
|
|
void tr_handle_signal()
|
|
{
|
|
Startmsg *msg;
|
|
|
|
while ((msg = (Startmsg *) GetMsg(reply_port)) != NULL) {
|
|
(*msg->clean_up)(msg->wb_startup.sm_ArgList,
|
|
msg->wb_startup.sm_NumArgs, msg->user_data);
|
|
free_startmsg(msg);
|
|
--running;
|
|
}
|
|
}
|
|
|
|
/* Wait for all currently running tools to quit before cleaning up the
|
|
reply port and returning control to the caller. */
|
|
void tr_clean_up()
|
|
{
|
|
while (running > 0 ) {
|
|
WaitPort(reply_port);
|
|
tr_handle_signal();
|
|
}
|
|
DeleteMsgPort(reply_port);
|
|
}
|