From 8352c9ef606c5a89ae28715265748cf21b308b51 Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Fri, 30 Mar 2012 17:35:57 +0100 Subject: [PATCH] Allow relaunch with shortcut key. Use the WindowRelaunchKey shortcut to examine the WM_COMMAND property of the active application's main window and launch a new instance of the application using the retrieved command line. --- WPrefs.app/KeyboardShortcuts.c | 2 ++ src/defaults.c | 2 ++ src/event.c | 6 ++++ src/funcs.h | 2 ++ src/keybind.h | 3 ++ src/main.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+) diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index 4fd5305c..aad8f334 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -112,6 +112,7 @@ static char *keyOptions[] = { "WindowShortcut8Key", "WindowShortcut9Key", "WindowShortcut10Key", + "WindowRelaunchKey", "ScreenSwitchKey", "DockRaiseLowerKey", #ifndef XKB_MODELOCK @@ -499,6 +500,7 @@ static void createPanel(Panel * p) WMAddListItem(panel->actLs, _("Shortcut for window 8")); WMAddListItem(panel->actLs, _("Shortcut for window 9")); WMAddListItem(panel->actLs, _("Shortcut for window 10")); + WMAddListItem(panel->actLs, _("Launch new instance of application")); WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor")); WMAddListItem(panel->actLs, _("Raise/Lower Dock")); WMAddListItem(panel->actLs, _("Raise/Lower Clip")); diff --git a/src/defaults.c b/src/defaults.c index 5b5269bc..dba325aa 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -639,6 +639,8 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab, NULL, NULL}, {"WindowShortcut10Key", "None", (void *)WKBD_WINDOW10, NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, + NULL, getKeybind, setKeyGrab, NULL, NULL}, {"ScreenSwitchKey", "None", (void *)WKBD_SWITCH_SCREEN, NULL, getKeybind, setKeyGrab, NULL, NULL}, diff --git a/src/event.c b/src/event.c index 3bc3c406..50c5a564 100644 --- a/src/event.c +++ b/src/event.c @@ -1651,6 +1651,12 @@ static void handleKeyPress(XEvent * event) break; + case WKBD_RELAUNCH: + if (ISMAPPED(wwin) && ISFOCUSED(wwin)) + (void) RelaunchWindow(wwin); + + break; + case WKBD_SWITCH_SCREEN: if (wScreenCount > 1) { WScreen *scr2; diff --git a/src/funcs.h b/src/funcs.h index 6d2c5528..ce9a99dc 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -98,6 +98,8 @@ char *ExpandOptions(WScreen *scr, char *cmdline); void ExecuteShellCommand(WScreen *scr, char *command); +Bool RelaunchWindow(WWindow *wwin); + Bool IsDoubleClick(WScreen *scr, XEvent *event); WWindow *NextToFocusAfter(WWindow *wwin); diff --git a/src/keybind.h b/src/keybind.h index e8b503c4..99137d8b 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -86,6 +86,9 @@ enum { WKBD_WINDOW9, WKBD_WINDOW10, + /* launch a new instance of the active window */ + WKBD_RELAUNCH, + /* screen */ WKBD_SWITCH_SCREEN, diff --git a/src/main.c b/src/main.c index 9fc99766..7d44983a 100644 --- a/src/main.c +++ b/src/main.c @@ -400,6 +400,68 @@ void ExecuteShellCommand(WScreen * scr, char *command) /* *--------------------------------------------------------------------- + * RelaunchWindow-- + * Launch a new instance of the active window + * + *---------------------------------------------------------------------- + */ +Bool RelaunchWindow(WWindow *wwin) +{ + if (! wwin || ! wwin->client_win) { + werror("no window to relaunch"); + return False; + } + + char **argv; + int argc; + + if (! XGetCommand(dpy, wwin->client_win, &argv, &argc) || argc == 0 || argv == NULL) { + werror("cannot relaunch the application because no WM_COMMAND property is set"); + return False; + } + + pid_t pid = fork(); + + if (pid == 0) { + SetupEnvironment(wwin->screen_ptr); +#ifdef HAVE_SETSID + setsid(); +#endif + /* argv is not null-terminated */ + char **a = (char **) malloc(argc + 1); + if (! a) { + werror("out of memory trying to relaunch the application"); + Exit(-1); + } + + int i; + for (i = 0; i < argc; i++) a[i] = argv[i]; + a[i] = NULL; + + execvp(a[0], a); + Exit(-1); + } else if (pid < 0) { + werror("cannot fork a new process"); + + XFreeStringList(argv); + return False; + } else { + _tuple *data = wmalloc(sizeof(_tuple)); + + data->scr = wwin->screen_ptr; + data->command = wtokenjoin(argv, argc); + + /* not actually a shell command */ + wAddDeathHandler(pid, (WDeathHandler *) shellCommandHandler, data); + + XFreeStringList(argv); + return True; + } + +} + +/* + *--------------------------------------------------------------------- * wAbort-- * Do a major cleanup and exit the program * -- 2.11.4.GIT