|
- /*
- 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);
- }
|