/* 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 . The author can be contacted on */ #include #include #include #include #include #include #include #include #ifdef USE_PRAGMAS #include #include #include #include #endif #include #include #include "common.h" #include "cx.h" #include "toolrun.h" #include "wb.h" static struct MsgPort *wb_port; static void add_tool_from_icon(char *name) { char path[MAX_PATH_LENGTH + 1]; BPTR lock; if ((lock = Lock(name, ACCESS_READ)) == NULL) return; if (NameFromLock(lock, path, MAX_PATH_LENGTH + 1)) cx_add_tool(name, path); UnLock(lock); } static void handle_app_window_msg(struct AppMessage *msg) { struct WBArg *arg; struct WBArg *end = msg->am_ArgList + msg->am_NumArgs; BPTR old_dir; struct DiskObject *disk_obj; cx_show(); for (arg = msg->am_ArgList; arg != end; ++arg) { old_dir = CurrentDir(arg->wa_Lock); /* Check that name isn't NULL and isn't empty, and that the icon is a Workbench tool. */ if (arg->wa_Name != NULL && *arg->wa_Name != '\0') if ((disk_obj = GetDiskObject(arg->wa_Name)) != NULL) { if (disk_obj->do_Type == WBTOOL) add_tool_from_icon(arg->wa_Name); FreeDiskObject(disk_obj); } CurrentDir(old_dir); } ReplyMsg((struct Message *) msg); } static void free_args(struct WBArg *arg_list, LONG num_args) { FreeVec(arg_list[0].wa_Name); if (arg_list[0].wa_Lock != NULL) UnLock(arg_list[0].wa_Lock); FreeMem(arg_list, sizeof(struct WBArg) * num_args); } /* Creates the directory locks and tool names to pass to tr_run_tool(). It actually only creates the first element, ie. the home directory and name of the tool itself, the rest are copied from the AppMessage that workbench.library sent us. */ static struct WBArg *create_args(STRPTR path, struct WBArg *arg_list, LONG num_args) { struct WBArg *result; size_t args_size; UBYTE t; UBYTE *file_part; /* Create an array one element bigger than the one received from workbench.library, so we can put the tool itself at the front. */ args_size = sizeof(struct WBArg) * num_args; result = AllocMem(args_size+sizeof(struct WBArg),MEMF_PUBLIC|MEMF_CLEAR); if (result == NULL) return NULL; /* Temporarily separate the file part and directory part of the tool's path with a string terminator. */ t = *(file_part = FilePart(path)); *file_part = '\0'; /* Create the tool's directory lock. */ result[0].wa_Lock = Lock(path, ACCESS_READ); /* Restore original string. */ *file_part = t; if (result[0].wa_Lock == NULL) goto create_args_failed; /* Copy the tool's name. */ if ((result[0].wa_Name = copy_of(file_part)) == NULL) goto create_args_failed; /* The rest of the array is just a copy of the AppMessage array. */ if (args_size > 0) memcpy(result + 1, arg_list, args_size); return result; create_args_failed: free_args(result, num_args + 1); return NULL; } /* This function is called whenever a tool we started quits. At this point, we reply to the workbench.library so it can free the arguments that we borrowed. Called indirectly by tr_clean_up(), so we must not clean up anything needed by reply_app_msg() until after the call to tr_clean_up(). */ static void reply_app_msg(struct WBArg *arg_list, LONG num_args, struct AppMessage *app_message) { if (arg_list != NULL) free_args(arg_list, num_args); ReplyMsg((struct Message *) app_message); } static void handle_app_menu_item_msg(struct AppMessage *msg) { Tool *t = (Tool *) msg->am_UserData; struct WBArg *args = NULL; LONG num_args = msg->am_NumArgs + 1; /* Check that the path isn't empty and that the tool hasn't been removed prior to handling this event, then create the Workbench arguments and run the tool. */ if (*t->path == '\0' || !is_in_list(tools, &t->node) || (args = create_args(t->path,msg->am_ArgList,msg->am_NumArgs)) == NULL || !tr_run_tool(args, num_args, reply_app_msg, msg)) /* Failed to run, reply to the AppMessage right away. */ reply_app_msg(args, num_args, msg); } ULONG wb_set_up() { if ((wb_port = CreateMsgPort()) == NULL) exit(RETURN_FAIL); return 1UL << wb_port->mp_SigBit; } struct AppWindow *wb_add_window(struct Window *window) { return AddAppWindow(0, 0, window, wb_port, TAG_DONE); } void wb_remove_window(struct AppWindow *app_window) { RemoveAppWindow(app_window); } void wb_add_tool(Tool *tool) { tool->menu_item = AddAppMenuItemA(0, (ULONG) tool, tool->node.ln_Name, wb_port, TAG_DONE); } void wb_remove_tool(Tool *tool) { RemoveAppMenuItem(tool->menu_item); tool->menu_item = NULL; } void wb_handle_signal(void) { struct AppMessage *msg; while ((msg = (struct AppMessage *) GetMsg(wb_port)) != NULL) switch (msg->am_Type) { case AMTYPE_APPWINDOW: handle_app_window_msg(msg); break; case AMTYPE_APPMENUITEM: handle_app_menu_item_msg(msg); break; } } void wb_clean_up() { delete_port(wb_port); }