ToolsMenu/wb.c

210 lines
6.1 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 <exec/memory.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/icon_protos.h>
#include <clib/wb_protos.h>
#ifdef USE_PRAGMAS
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/icon.h>
#include <proto/wb.h>
#endif
#include <stdlib.h>
#include <strings.h>
#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);
}