Hi

Hotkeys for dock applications is a really cool feature. After upgrading
to new windowmaker I was missing much for this feature.

Original patch did not applied successfully, so I updated patch to apply
to HEAD.

Please consider including it. Thanks!

PS. I want to thank the author of original patch for adding this
feature.

>From 56c8852a0f2ee753da79d4c04a785fa5d8e15953 Mon Sep 17 00:00:00 2001
From: Yuri Karaban <mli...@dev97.com>
Date: Thu, 29 Mar 2012 20:39:40 +0300
Subject: [PATCH] applied to HEAD WindowMaker-0.91.0-alt-dockhotkeys.patch

---
 src/appicon.c   |    2 +
 src/appicon.h   |    4 ++
 src/dock.c      |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/dockedapp.c |  137 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/event.c     |    2 +-
 src/screen.h    |    1 +
 src/window.c    |    1 +
 7 files changed, 289 insertions(+), 2 deletions(-)

diff --git a/src/appicon.c b/src/appicon.c
index d05413b..6a2e2e9 100644
--- a/src/appicon.c
+++ b/src/appicon.c
@@ -169,6 +169,8 @@ void wAppIconDestroy(WAppIcon * aicon)
 	if (aicon->dnd_command)
 		wfree(aicon->dnd_command);
 #endif
+	if (aicon->keyboard_shortcut)
+		wfree(aicon->keyboard_shortcut);
 	if (aicon->wm_instance)
 		wfree(aicon->wm_instance);
 
diff --git a/src/appicon.h b/src/appicon.h
index f10f847..4e6b5ef 100644
--- a/src/appicon.h
+++ b/src/appicon.h
@@ -50,6 +50,10 @@ typedef struct WAppIcon {
 
     char *paste_command;	       /* command to run when something is pasted */
 
+    char *keyboard_shortcut;           /* keyboard shortcut to launch app */
+    int modifier;
+    KeyCode keycode;
+
     char *wm_class;
     char *wm_instance;
     pid_t pid;			       /* for apps launched from the dock */
diff --git a/src/dock.c b/src/dock.c
index 71bef02..5cc8a5f 100644
--- a/src/dock.c
+++ b/src/dock.c
@@ -79,6 +79,7 @@ static WMPropList *dPasteCommand = NULL;
 #ifdef XDND			/* XXX was OFFIX */
 static WMPropList *dDropCommand = NULL;
 #endif
+static WMPropList *dKeyboardShortcut = NULL;
 static WMPropList *dAutoLaunch, *dLock;
 static WMPropList *dName, *dForced, *dBuggyApplication, *dYes, *dNo;
 static WMPropList *dHost, *dDock, *dClip;
@@ -131,6 +132,7 @@ static void make_keys(void)
 #ifdef XDND
 	dDropCommand = WMRetainPropList(WMCreatePLString("DropCommand"));
 #endif
+	dKeyboardShortcut = WMRetainPropList(WMCreatePLString("Shortcut"));
 	dLock = WMRetainPropList(WMCreatePLString("Lock"));
 	dAutoLaunch = WMRetainPropList(WMCreatePLString("AutoLaunch"));
 	dName = WMRetainPropList(WMCreatePLString("Name"));
@@ -1241,6 +1243,12 @@ static WMPropList *make_icon_state(WAppIcon *btn)
 			WMReleasePropList(command);
 		}
 
+		if (btn->keyboard_shortcut) {
+			command = WMCreatePLString(btn->keyboard_shortcut);
+			WMPutInPLDictionary(node, dKeyboardShortcut, command);
+			WMReleasePropList(command);
+		}
+
 		if (btn->client_machine && btn->remote_start) {
 			host = WMCreatePLString(btn->client_machine);
 			WMPutInPLDictionary(node, dHost, host);
@@ -1435,6 +1443,12 @@ static WAppIcon *restore_icon_state(WScreen *scr, WMPropList *info, int type, in
 		aicon->dnd_command = wstrdup(WMGetFromPLString(cmd));
 #endif
 
+	cmd = WMGetFromPLDictionary(info, dKeyboardShortcut);
+	if (cmd) {
+		if(addDockShortcut(WMGetFromPLString(cmd), aicon))
+			aicon->keyboard_shortcut = wstrdup(WMGetFromPLString(cmd));
+	}
+
 	cmd = WMGetFromPLDictionary(info, dPasteCommand);
 	if (cmd)
 		aicon->paste_command = wstrdup(WMGetFromPLString(cmd));
@@ -1704,6 +1718,8 @@ WDock *wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type)
 	if (type == WM_DOCK)
 		dock->icon_count = 0;
 
+	dock->screen_ptr->flags.dock_changed_shortcuts = 0;
+
 	for (i = 0; i < count; i++) {
 		if (dock->icon_count >= dock->max_icons) {
 			wwarning(_("there are too many icons stored in dock. Ignoring what doesn't fit"));
@@ -1736,6 +1752,12 @@ WDock *wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type)
 			dock->icon_count++;
 	}
 
+	if(dock->screen_ptr->flags.dock_changed_shortcuts)
+	{
+		rebind_key_grabs(dock->screen_ptr);
+		dock->screen_ptr->flags.dock_changed_shortcuts = 0;
+	}
+
 	/* if the first icon is not defined, use the default */
 	if (dock->icon_array[0] == NULL) {
 		/* update default icon */
@@ -4031,3 +4053,125 @@ int wClipMakeIconOmnipresent(WAppIcon *aicon, int omnipresent)
 
 	return status;
 }
+
+Bool
+addDockShortcut(char *shortcutDefinition, WAppIcon *icon)
+{
+	int modifier = 0;
+	KeyCode keycode;
+	KeySym ksym;
+	char *k;
+	char buf[128], *b;
+	
+	strcpy(buf, shortcutDefinition);
+	b = (char*)buf;
+
+	/* get modifiers */
+	while((k = strchr(b, '+'))!=NULL) {
+		int mod;
+
+		*k = 0;
+		mod = wXModifierFromKey(b);
+		if(mod < 0) {
+			wwarning(_("invalid key modifier \"%s\""), b);
+			return False;
+		}
+		modifier |= mod;
+
+		b = k+1;
+	}
+
+	/* get key */
+	ksym = XStringToKeysym(b);
+
+	if (ksym==NoSymbol) {
+		wwarning(_("invalid kbd shortcut specification \"%s\""), shortcutDefinition);
+		return False;
+	}
+
+	keycode = XKeysymToKeycode(dpy, ksym);
+	if (keycode==0) {
+		wwarning(_("invalid key in shortcut \"%s\""), shortcutDefinition);
+		return False;
+	}
+	icon->modifier = modifier;
+	icon->keycode = keycode;
+	if(icon->dock && icon->dock->screen_ptr)
+		icon->dock->screen_ptr->flags.dock_changed_shortcuts = 1;
+	return True;
+}
+
+static Bool
+wDockPerformShortcut(WDock *dock, XEvent *event)
+{
+	int i;
+	int modifiers;
+	int done = 0;
+
+	if(!dock) return done;
+	modifiers = event->xkey.state & ValidModMask;
+	for(i=(dock->type==WM_DOCK ? 0 : 1); i<dock->max_icons; i++) {
+		WAppIcon *btn = dock->icon_array[i];
+
+		if(!btn || btn->attracted)
+			continue;
+	
+		if(btn->keycode==event->xkey.keycode && (btn->modifier==modifiers)) {
+			launchDockedApplication(btn, False);
+			done = True;
+			break;
+		}
+
+	}
+	return done;
+}
+
+Bool
+wDockAndClipPerformShortcut(WScreen *scr, XEvent *event)
+{
+	int done = 0;
+	int i;
+	if(!(done = wDockPerformShortcut(scr->dock, event))) {
+		for(i=0; i < scr->workspace_count; i++)	{
+			if(done = wDockPerformShortcut(scr->workspaces[i]->clip, event)) break;
+		}
+	}
+	return done;
+}
+
+static void
+wDockBindShortcuts(Window window, WDock* dock)
+{
+	int i;
+	if(!dock) return;
+	for(i=(dock->type==WM_DOCK ? 0 : 1); i<dock->max_icons; i++) {
+		WAppIcon *btn = dock->icon_array[i];
+
+		if(!btn || btn->attracted)
+			continue;
+	
+		if(btn->keyboard_shortcut)
+		{
+			if(btn->keyboard_shortcut && btn->modifier!=AnyModifier) {
+				XGrabKey(dpy, btn->keycode, btn->modifier|LockMask,
+					window, True, GrabModeAsync, GrabModeAsync);
+#ifdef NUMLOCK_HACK
+				wHackedGrabKey(btn->keycode, btn->modifier,
+					window, True, GrabModeAsync, GrabModeAsync);	    
+#endif
+			}
+			XGrabKey(dpy, btn->keycode, btn->modifier, window, True, 
+				GrabModeAsync, GrabModeAsync);
+		}
+	}
+}
+
+void
+wDockAndClipBindShortcuts(Window window, WScreen *scr)
+{
+	int i;
+	wDockBindShortcuts(window, scr->dock);
+	for(i=0; i < scr->workspace_count; i++ ) {
+		wDockBindShortcuts(window, scr->workspaces[i]->clip);
+	}
+}
diff --git a/src/dockedapp.c b/src/dockedapp.c
index 944e025..b4a00c2 100644
--- a/src/dockedapp.c
+++ b/src/dockedapp.c
@@ -23,6 +23,7 @@
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/keysym.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -60,6 +61,10 @@ typedef struct _AppSettingsPanel {
 	WMTextField *pasteCommandField;
 	WMLabel *pasteCommandLabel;
 
+	WMFrame *keyboardShortcutFrame;
+	WMTextField *keyboardShortcutField;
+	WMButton *keyboardShortcutCaptureBtn;
+
 	WMFrame *iconFrame;
 	WMTextField *iconField;
 	WMButton *browseBtn;
@@ -75,6 +80,7 @@ typedef struct _AppSettingsPanel {
 	/* kluge */
 	unsigned int destroyed:1;
 	unsigned int choosingIcon:1;
+	unsigned int capturing:1;
 } AppSettingsPanel;
 
 void DestroyDockAppSettingsPanel(AppSettingsPanel * panel);
@@ -105,6 +111,43 @@ static void updatePasteCommand(WAppIcon * icon, char *command)
 	icon->paste_command = command;
 }
 
+static char*
+trimstr(char *str)
+{
+	char *p = str;
+	int i;
+
+	while (isspace(*p)) p++;
+	p = wstrdup(p);
+	i = strlen(p);
+	while (isspace(p[i]) && i>0) {
+		p[i]=0;
+		i--;
+	}
+
+	return p;
+}
+
+static void
+updateKeyboardShortcut(WAppIcon *icon, char *shortcut)
+{
+	char *str = NULL;
+	if(icon->keyboard_shortcut)
+		wfree(icon->keyboard_shortcut);
+	if(shortcut) {
+		str = trimstr(shortcut);
+		if(!strlen(str)) {
+			wfree(str);
+			str = NULL;
+		}
+	}
+	icon->keyboard_shortcut = str;
+	icon->modifier = 0;
+	icon->keycode = 0;
+	if(str) addDockShortcut(str, icon);
+	rebind_key_grabs(icon->dock->screen_ptr);
+}
+
 #ifdef XDND
 static void updateDNDCommand(WAppIcon * icon, char *command)
 {
@@ -242,6 +285,9 @@ static void panelBtnCallback(WMWidget * self, void *data)
 		text = WMGetTextFieldText(panel->pasteCommandField);
 		updatePasteCommand(panel->editedIcon, text);
 
+		text = WMGetTextFieldText(panel->keyboardShortcutField);
+		updateKeyboardShortcut(panel->editedIcon, text);
+
 		panel->editedIcon->auto_launch = WMGetButtonSelected(panel->autoLaunchBtn);
 
 		panel->editedIcon->lock = WMGetButtonSelected(panel->lockBtn);
@@ -251,8 +297,82 @@ static void panelBtnCallback(WMWidget * self, void *data)
 		DestroyDockAppSettingsPanel(panel);
 }
 
+static char*
+captureShortcut(Display *dpy, AppSettingsPanel *panel)
+{
+	XEvent ev;
+	KeySym ksym, lksym, uksym;
+	char buffer[64];
+	char *key = NULL;
+
+	while (panel->capturing) {
+		XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
+		WMNextEvent(dpy, &ev);
+		if (ev.type==KeyPress && ev.xkey.keycode!=0) {
+			ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
+			if (!IsModifierKey(ksym)) {
+				XConvertCase(ksym, &lksym, &uksym);
+				key=XKeysymToString(uksym);
+				panel->capturing = 0;
+				break;
+			}
+		}
+		WMHandleEvent(&ev);
+	}
+	if (!key)
+		return NULL;
+
+	buffer[0] = 0;
+	if (ev.xkey.state & ControlMask) {
+		strcat(buffer, "Control+");
+	}   
+        if (ev.xkey.state & ShiftMask) {
+		strcat(buffer, "Shift+");
+	}   
+	if (ev.xkey.state & Mod1Mask) {
+		strcat(buffer, "Mod1+");
+	}   
+	if (ev.xkey.state & Mod2Mask) {
+		strcat(buffer, "Mod2+");
+	}   
+	if (ev.xkey.state & Mod3Mask) {
+		strcat(buffer, "Mod3+");
+	}
+	if (ev.xkey.state & Mod4Mask) {
+		strcat(buffer, "Mod4+");
+	}
+	if (ev.xkey.state & Mod5Mask) {
+		strcat(buffer, "Mod5+");
+	}
+	strcat(buffer, key);
+
+	return wstrdup(buffer);
+}
+
+static void
+captureClick(WMWidget *w, void *data)
+{
+	AppSettingsPanel *panel = (AppSettingsPanel*)data;
+	char *shortcut;
+
+	if(!panel->capturing) {
+		panel->capturing = 1;
+		WMSetButtonText(w, _("Cancel"));
+	        XGrabKeyboard(dpy, WMWidgetXID(panel->win), True, GrabModeAsync,
+				GrabModeAsync, CurrentTime);
+		shortcut = captureShortcut(dpy, panel);
+		if (shortcut) {
+			WMSetTextFieldText(panel->keyboardShortcutField, shortcut);
+			wfree(shortcut);
+		}
+	}
+	panel->capturing = 0;
+	WMSetButtonText(w, _("Capture"));
+	XUngrabKeyboard(dpy, CurrentTime);
+}
+
 #define PWIDTH	295
-#define PHEIGHT	430
+#define PHEIGHT	490
 
 void ShowDockAppSettingsPanel(WAppIcon * aicon)
 {
@@ -352,6 +472,21 @@ void ShowDockAppSettingsPanel(WAppIcon * aicon)
 #endif
 	WMMapSubwidgets(panel->dndCommandFrame);
 
+	panel->keyboardShortcutFrame = WMCreateFrame(vbox);
+	WMSetFrameTitle(panel->keyboardShortcutFrame, _("Keyboard shortcut"));
+	WMAddBoxSubview(vbox, WMWidgetView(panel->keyboardShortcutFrame), False, True,
+		    50, 50, 10);
+	panel->keyboardShortcutField = WMCreateTextField(panel->keyboardShortcutFrame);
+	WMResizeWidget(panel->keyboardShortcutField, 176, 20);
+	WMMoveWidget(panel->keyboardShortcutField, 10, 20);
+	WMSetTextFieldText(panel->keyboardShortcutField, aicon->keyboard_shortcut);
+	panel->keyboardShortcutCaptureBtn = WMCreateCommandButton(panel->keyboardShortcutFrame);
+	WMSetButtonText(panel->keyboardShortcutCaptureBtn, _("Capture"));
+	WMResizeWidget(panel->keyboardShortcutCaptureBtn, 70, 24);
+	WMMoveWidget(panel->keyboardShortcutCaptureBtn, 195, 18);
+	WMSetButtonAction(panel->keyboardShortcutCaptureBtn, captureClick, panel);
+	WMMapSubwidgets(panel->keyboardShortcutFrame);
+
 	panel->iconFrame = WMCreateFrame(vbox);
 	WMSetFrameTitle(panel->iconFrame, _("Icon Image"));
 	WMAddBoxSubview(vbox, WMWidgetView(panel->iconFrame), False, True, 50, 50, 10);
diff --git a/src/event.c b/src/event.c
index 3bc3c40..98b2ff9 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1363,7 +1363,7 @@ static void handleKeyPress(XEvent * event)
 
 	if (command < 0) {
 
-		if (!wRootMenuPerformShortcut(event)) {
+		if (!wRootMenuPerformShortcut(event) && !wDockAndClipPerformShortcut(scr, event)) {
 			static int dontLoop = 0;
 
 			if (dontLoop > 10) {
diff --git a/src/screen.h b/src/screen.h
index af5a97b..a909bde 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -279,6 +279,7 @@ typedef struct _WScreen {
         unsigned int regenerate_icon_textures:1;
         unsigned int dnd_data_convertion_status:1;
         unsigned int root_menu_changed_shortcuts:1;
+	unsigned int dock_changed_shortcuts:1;
         unsigned int added_workspace_menu:1;
         unsigned int added_windows_menu:1;
         unsigned int startup2:1;       /* startup phase 2 */
diff --git a/src/window.c b/src/window.c
index d6a2a1b..e9f47a4 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2478,6 +2478,7 @@ void wWindowSetKeyGrabs(WWindow * wwin)
 	}
 
 	wRootMenuBindShortcuts(wwin->frame->core->window);
+	wDockAndClipBindShortcuts(wwin->frame->core->window, wwin->screen_ptr);
 }
 
 void wWindowResetMouseGrabs(WWindow * wwin)
-- 
1.7.8.5

-- 
Deo Vindice.

Reply via email to