This patch add ability to assing kyboard shortcut to docked
appicons.
Original-patch-by: Alexey Voinov <[email protected]>
Signed-off-by: Alexey I. Froloff <[email protected]>
---
src/appicon.c | 2 +
src/appicon.h | 4 ++
src/dock.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/dockedapp.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/event.c | 2 +-
src/rootmenu.c | 2 +-
src/screen.h | 1 +
src/window.c | 1 +
8 files changed, 289 insertions(+), 3 deletions(-)
diff --git a/src/appicon.c b/src/appicon.c
index 75fc044..ae72922 100644
--- a/src/appicon.c
+++ b/src/appicon.c
@@ -168,6 +168,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);
if (aicon->wm_class)
diff --git a/src/appicon.h b/src/appicon.h
index f3e9796..8611527 100644
--- a/src/appicon.h
+++ b/src/appicon.h
@@ -51,6 +51,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 7e6d926..1892043 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"));
@@ -1272,6 +1274,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);
@@ -1466,6 +1474,12 @@ static WAppIcon *restore_icon_state(WScreen * scr,
WMPropList * info, int type,
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));
@@ -1752,6 +1766,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"));
@@ -1783,6 +1799,11 @@ WDock *wDockRestoreState(WScreen * scr, WMPropList *
dock_state, int type)
} else if (dock->icon_count == 0 && type == WM_DOCK)
dock->icon_count++;
}
+ if(dock->screen_ptr->flags.dock_changed_shortcuts)
+ {
+ rebindKeygrabs(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) {
@@ -4139,3 +4160,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 9c90387..0741f48 100644
--- a/src/dockedapp.c
+++ b/src/dockedapp.c
@@ -24,6 +24,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include <X11/keysym.h>
#include <stdlib.h>
#include <string.h>
@@ -61,6 +62,10 @@ typedef struct _AppSettingsPanel {
WMTextField *pasteCommandField;
WMLabel *pasteCommandLabel;
+ WMFrame *keyboardShortcutFrame;
+ WMTextField *keyboardShortcutField;
+ WMButton *keyboardShortcutCaptureBtn;
+
WMFrame *iconFrame;
WMTextField *iconField;
WMButton *browseBtn;
@@ -76,6 +81,7 @@ typedef struct _AppSettingsPanel {
/* kluge */
unsigned int destroyed:1;
unsigned int choosingIcon:1;
+ unsigned int capturing:1;
} AppSettingsPanel;
void DestroyDockAppSettingsPanel(AppSettingsPanel * panel);
@@ -106,6 +112,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);
+ rebindKeygrabs(icon->dock->screen_ptr);
+}
+
#ifdef XDND
static void updateDNDCommand(WAppIcon * icon, char *command)
{
@@ -243,6 +286,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);
@@ -252,8 +298,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)
{
@@ -353,6 +473,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 5d80fbe..4bc5d4f 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1358,7 +1358,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/rootmenu.c b/src/rootmenu.c
index 51a5791..8d56a7d 100644
--- a/src/rootmenu.c
+++ b/src/rootmenu.c
@@ -378,7 +378,7 @@ void wRootMenuBindShortcuts(Window window)
}
}
-static void rebindKeygrabs(WScreen * scr)
+void rebindKeygrabs(WScreen * scr)
{
WWindow *wwin;
diff --git a/src/screen.h b/src/screen.h
index 51edd53..fc2c783 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -285,6 +285,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 a7ed37e..e1a3778 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2507,6 +2507,7 @@ void wWindowSetKeyGrabs(WWindow * wwin)
}
wRootMenuBindShortcuts(wwin->frame->core->window);
+ wDockAndClipBindShortcuts(wwin->frame->core->window, wwin->screen_ptr);
}
void wWindowResetMouseGrabs(WWindow * wwin)
--
1.7.2.3
--
To unsubscribe, send mail to [email protected].