Add tools to the Workbench Tools menu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

toolrun.c 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. ToolsMenu - Add tools to the Workbench Tools menu
  3. Copyright (C) 2015, 2018 Kim Fastrup Larsen
  4. This program is free software: you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation, either ver-
  7. sion 3 of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be use-
  9. ful, but WITHOUT ANY WARRANTY; without even the implied war-
  10. ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public Li-
  13. cense along with this program. If not, see
  14. <http://www.gnu.org/licenses/>.
  15. The author can be contacted on <kimflarsen@hotmail.com>
  16. */
  17. #include <dos/dos.h>
  18. #include <dos/dostags.h>
  19. #include <exec/memory.h>
  20. #include <workbench/startup.h>
  21. #include <clib/dos_protos.h>
  22. #include <clib/exec_protos.h>
  23. #include <clib/icon_protos.h>
  24. #ifdef USE_PRAGMAS
  25. #include <proto/dos.h>
  26. #include <proto/exec.h>
  27. #include <proto/icon.h>
  28. #endif
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "common.h"
  32. #include "toolrun.h"
  33. #define MIN_STACK_SIZE 4000
  34. /* We send this extended WBStartup to any tool that we launch. It will
  35. contain the Workbench arguments passed to run_tool(). Once the tool quits,
  36. it will reply to this message, and at that point we call the clean_up
  37. function (also passed to run_tool()) to let it clean up the arguments. */
  38. typedef struct {
  39. struct WBStartup wb_startup;
  40. Tr_clean_up *clean_up;
  41. void *user_data;
  42. } Startmsg;
  43. /* The tools we run will be told to reply to this port when they quit. */
  44. static struct MsgPort *reply_port;
  45. /* The number of tools started that haven't quit yet. */
  46. static int running;
  47. static void free_startmsg(Startmsg *msg)
  48. {
  49. FreeVec(msg->wb_startup.sm_ToolWindow);
  50. FreeMem(msg, sizeof *msg);
  51. }
  52. /* Create the reply port and return its signal bit as a mask. */
  53. ULONG tr_set_up()
  54. {
  55. if ((reply_port = CreateMsgPort()) == NULL)
  56. exit(RETURN_FAIL);
  57. return 1UL << reply_port->mp_SigBit;
  58. }
  59. Bool tr_run_tool(struct WBArg *arg_list, LONG num_args,
  60. Tr_clean_up *clean_up, void *user_data)
  61. {
  62. BPTR old_dir;
  63. struct DiskObject *disk_obj;
  64. Startmsg *startmsg;
  65. LONG stack_size;
  66. BPTR home_dir;
  67. struct Process *process;
  68. /* Load the tool's icon and check that it really is a Workbench tool. */
  69. old_dir = CurrentDir(arg_list[0].wa_Lock);
  70. if ((disk_obj = GetDiskObject(arg_list[0].wa_Name)) == NULL)
  71. goto run_tool_failed1;
  72. if (disk_obj->do_Type != WBTOOL)
  73. goto run_tool_failed2;
  74. /* Use the stacksize specified in the icon unless it's too small. */
  75. if ((stack_size = disk_obj->do_StackSize) < MIN_STACK_SIZE)
  76. stack_size = MIN_STACK_SIZE;
  77. /* Set up startup message. */
  78. if ((startmsg=AllocMem(sizeof *startmsg,MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
  79. goto run_tool_failed2;
  80. startmsg->wb_startup.sm_ArgList = arg_list;
  81. startmsg->wb_startup.sm_NumArgs = num_args;
  82. startmsg->clean_up = clean_up;
  83. startmsg->user_data = user_data;
  84. /* We copy the icon's ToolWindow if it isn't NULL. */
  85. if (disk_obj->do_ToolWindow != NULL &&
  86. (startmsg->wb_startup.sm_ToolWindow = copy_of(disk_obj->do_ToolWindow))
  87. == NULL)
  88. goto run_tool_failed3;
  89. /* Load the tool. */
  90. if ((startmsg->wb_startup.sm_Segment = NewLoadSegTags(
  91. arg_list[0].wa_Name, TAG_DONE)) == NULL)
  92. goto run_tool_failed3;
  93. /* Get a lock for PROGDIR. */
  94. if ((home_dir = DupLock(arg_list[0].wa_Lock)) == 0)
  95. goto run_tool_failed4;
  96. /* Run the tool as a non-CLI process. */
  97. if ((process = CreateNewProcTags(
  98. NP_Seglist, startmsg->wb_startup.sm_Segment,
  99. NP_FreeSeglist, (LONG) TRUE,
  100. NP_Input, NULL,
  101. NP_CloseInput, (LONG) FALSE,
  102. NP_Output, NULL,
  103. NP_CloseOutput, (LONG) FALSE,
  104. NP_Error, NULL,
  105. NP_CloseError, (LONG) FALSE,
  106. NP_CurrentDir, NULL,
  107. NP_StackSize, stack_size,
  108. NP_Name, arg_list[0].wa_Name,
  109. NP_Priority, 0L,
  110. NP_ConsoleTask, NULL,
  111. NP_WindowPtr, NULL,
  112. NP_HomeDir, home_dir,
  113. TAG_DONE)) == NULL)
  114. goto run_tool_failed5;
  115. /* We have started the process, so we mustn't do anything after this point
  116. that might fail. Send the startup message to the tool. */
  117. startmsg->wb_startup.sm_Process = &process->pr_MsgPort;
  118. startmsg->wb_startup.sm_Message.mn_ReplyPort = reply_port;
  119. PutMsg(startmsg->wb_startup.sm_Process, (struct Message *) startmsg);
  120. ++running;
  121. FreeDiskObject(disk_obj);
  122. CurrentDir(old_dir);
  123. return YES;
  124. run_tool_failed5:
  125. UnLock(home_dir);
  126. run_tool_failed4:
  127. UnLoadSeg(startmsg->wb_startup.sm_Segment);
  128. run_tool_failed3:
  129. free_startmsg(startmsg);
  130. run_tool_failed2:
  131. FreeDiskObject(disk_obj);
  132. run_tool_failed1:
  133. CurrentDir(old_dir);
  134. return NO;
  135. }
  136. /* When a tool started by tr_run_tool() quits, we receive a reply to our
  137. startup message. At this point we call the clean up function provided,
  138. then clean up the message itself. */
  139. void tr_handle_signal()
  140. {
  141. Startmsg *msg;
  142. while ((msg = (Startmsg *) GetMsg(reply_port)) != NULL) {
  143. (*msg->clean_up)(msg->wb_startup.sm_ArgList,
  144. msg->wb_startup.sm_NumArgs, msg->user_data);
  145. free_startmsg(msg);
  146. --running;
  147. }
  148. }
  149. /* Wait for all currently running tools to quit before cleaning up the
  150. reply port and returning control to the caller. */
  151. void tr_clean_up()
  152. {
  153. while (running > 0 ) {
  154. WaitPort(reply_port);
  155. tr_handle_signal();
  156. }
  157. DeleteMsgPort(reply_port);
  158. }