WPrefs: Remove trimstr() and use wtrimspace() from WINGs
[wmaker-crm.git] / WPrefs.app / KeyboardShortcuts.c
blob4ea7fa4c21c2677c6263a7f583c7a82562670343
1 /* KeyboardShortcuts.c- keyboard shortcut bindings
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 1998-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "config.h" /* for HAVE_XCONVERTCASE */
24 #include "WPrefs.h"
25 #include <ctype.h>
27 #include <X11/keysym.h>
29 typedef struct _Panel {
30 WMBox *box;
32 char *sectionName;
34 char *description;
36 CallbackRec callbacks;
38 WMWidget *parent;
40 WMLabel *actL;
41 WMList *actLs;
43 WMFrame *shoF;
44 WMTextField *shoT;
45 WMButton *cleB;
46 WMButton *defB;
48 WMLabel *instructionsL;
50 WMColor *white;
51 WMColor *black;
52 WMColor *gray;
53 WMFont *font;
55 /**/ char capturing;
56 char **shortcuts;
57 int actionCount;
58 } _Panel;
60 #define ICON_FILE "keyshortcuts"
63 * Must be in the same order as the corresponding items in
64 * "actions list" in createPanel()
66 static char *keyOptions[] = {
67 "RootMenuKey",
68 "WindowListKey",
69 "WindowMenuKey",
70 "HideKey",
71 "HideOthersKey",
72 "MiniaturizeKey",
73 "MinimizeAllKey",
74 "CloseKey",
75 "MaximizeKey",
76 "VMaximizeKey",
77 "HMaximizeKey",
78 "LHMaximizeKey",
79 "RHMaximizeKey",
80 "MaximusKey",
81 "RaiseKey",
82 "LowerKey",
83 "RaiseLowerKey",
84 "ShadeKey",
85 "MoveResizeKey",
86 "SelectKey",
87 "FocusNextKey",
88 "FocusPrevKey",
89 "GroupNextKey",
90 "GroupPrevKey",
91 "NextWorkspaceKey",
92 "PrevWorkspaceKey",
93 "NextWorkspaceLayerKey",
94 "PrevWorkspaceLayerKey",
95 "Workspace1Key",
96 "Workspace2Key",
97 "Workspace3Key",
98 "Workspace4Key",
99 "Workspace5Key",
100 "Workspace6Key",
101 "Workspace7Key",
102 "Workspace8Key",
103 "Workspace9Key",
104 "Workspace10Key",
105 "WindowShortcut1Key",
106 "WindowShortcut2Key",
107 "WindowShortcut3Key",
108 "WindowShortcut4Key",
109 "WindowShortcut5Key",
110 "WindowShortcut6Key",
111 "WindowShortcut7Key",
112 "WindowShortcut8Key",
113 "WindowShortcut9Key",
114 "WindowShortcut10Key",
115 "ScreenSwitchKey",
116 "DockRaiseLowerKey",
117 #ifndef XKB_MODELOCK
118 "ClipRaiseLowerKey"
119 #else
120 "ClipRaiseLowerKey",
121 "ToggleKbdModeKey"
122 #endif /* XKB_MODELOCK */
125 #ifndef HAVE_XCONVERTCASE
126 /* from Xlib */
128 static void XConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
130 *lower = sym;
131 *upper = sym;
132 switch (sym >> 8) {
133 case 0: /* Latin 1 */
134 if ((sym >= XK_A) && (sym <= XK_Z))
135 *lower += (XK_a - XK_A);
136 else if ((sym >= XK_a) && (sym <= XK_z))
137 *upper -= (XK_a - XK_A);
138 else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
139 *lower += (XK_agrave - XK_Agrave);
140 else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
141 *upper -= (XK_agrave - XK_Agrave);
142 else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
143 *lower += (XK_oslash - XK_Ooblique);
144 else if ((sym >= XK_oslash) && (sym <= XK_thorn))
145 *upper -= (XK_oslash - XK_Ooblique);
146 break;
147 case 1: /* Latin 2 */
148 /* Assume the KeySym is a legal value (ignore discontinuities) */
149 if (sym == XK_Aogonek)
150 *lower = XK_aogonek;
151 else if (sym >= XK_Lstroke && sym <= XK_Sacute)
152 *lower += (XK_lstroke - XK_Lstroke);
153 else if (sym >= XK_Scaron && sym <= XK_Zacute)
154 *lower += (XK_scaron - XK_Scaron);
155 else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
156 *lower += (XK_zcaron - XK_Zcaron);
157 else if (sym == XK_aogonek)
158 *upper = XK_Aogonek;
159 else if (sym >= XK_lstroke && sym <= XK_sacute)
160 *upper -= (XK_lstroke - XK_Lstroke);
161 else if (sym >= XK_scaron && sym <= XK_zacute)
162 *upper -= (XK_scaron - XK_Scaron);
163 else if (sym >= XK_zcaron && sym <= XK_zabovedot)
164 *upper -= (XK_zcaron - XK_Zcaron);
165 else if (sym >= XK_Racute && sym <= XK_Tcedilla)
166 *lower += (XK_racute - XK_Racute);
167 else if (sym >= XK_racute && sym <= XK_tcedilla)
168 *upper -= (XK_racute - XK_Racute);
169 break;
170 case 2: /* Latin 3 */
171 /* Assume the KeySym is a legal value (ignore discontinuities) */
172 if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
173 *lower += (XK_hstroke - XK_Hstroke);
174 else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
175 *lower += (XK_gbreve - XK_Gbreve);
176 else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
177 *upper -= (XK_hstroke - XK_Hstroke);
178 else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
179 *upper -= (XK_gbreve - XK_Gbreve);
180 else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
181 *lower += (XK_cabovedot - XK_Cabovedot);
182 else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
183 *upper -= (XK_cabovedot - XK_Cabovedot);
184 break;
185 case 3: /* Latin 4 */
186 /* Assume the KeySym is a legal value (ignore discontinuities) */
187 if (sym >= XK_Rcedilla && sym <= XK_Tslash)
188 *lower += (XK_rcedilla - XK_Rcedilla);
189 else if (sym >= XK_rcedilla && sym <= XK_tslash)
190 *upper -= (XK_rcedilla - XK_Rcedilla);
191 else if (sym == XK_ENG)
192 *lower = XK_eng;
193 else if (sym == XK_eng)
194 *upper = XK_ENG;
195 else if (sym >= XK_Amacron && sym <= XK_Umacron)
196 *lower += (XK_amacron - XK_Amacron);
197 else if (sym >= XK_amacron && sym <= XK_umacron)
198 *upper -= (XK_amacron - XK_Amacron);
199 break;
200 case 6: /* Cyrillic */
201 /* Assume the KeySym is a legal value (ignore discontinuities) */
202 if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
203 *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
204 else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
205 *upper += (XK_Serbian_DJE - XK_Serbian_dje);
206 else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
207 *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
208 else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
209 *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
210 break;
211 case 7: /* Greek */
212 /* Assume the KeySym is a legal value (ignore discontinuities) */
213 if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
214 *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
215 else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
216 sym != XK_Greek_iotaaccentdieresis && sym != XK_Greek_upsilonaccentdieresis)
217 *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
218 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
219 *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
220 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && sym != XK_Greek_finalsmallsigma)
221 *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
222 break;
223 case 0x14: /* Armenian */
224 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
225 *lower = sym | 1;
226 *upper = sym & ~1;
228 break;
231 #endif
233 static char *captureShortcut(Display * dpy, _Panel * panel)
235 XEvent ev;
236 KeySym ksym, lksym, uksym;
237 char buffer[64];
238 char *key = NULL;
240 while (panel->capturing) {
241 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
242 WMNextEvent(dpy, &ev);
243 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
244 ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
245 if (!IsModifierKey(ksym)) {
246 XConvertCase(ksym, &lksym, &uksym);
247 key = XKeysymToString(uksym);
249 panel->capturing = 0;
250 break;
253 WMHandleEvent(&ev);
256 if (!key)
257 return NULL;
259 buffer[0] = 0;
261 if (ev.xkey.state & ControlMask) {
262 strcat(buffer, "Control+");
264 if (ev.xkey.state & ShiftMask) {
265 strcat(buffer, "Shift+");
267 if (ev.xkey.state & Mod1Mask) {
268 strcat(buffer, "Mod1+");
270 if (ev.xkey.state & Mod2Mask) {
271 strcat(buffer, "Mod2+");
273 if (ev.xkey.state & Mod3Mask) {
274 strcat(buffer, "Mod3+");
276 if (ev.xkey.state & Mod4Mask) {
277 strcat(buffer, "Mod4+");
279 if (ev.xkey.state & Mod5Mask) {
280 strcat(buffer, "Mod5+");
282 strcat(buffer, key);
284 return wstrdup(buffer);
287 static void captureClick(WMWidget * w, void *data)
289 _Panel *panel = (_Panel *) data;
290 Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
291 char *shortcut;
293 if (!panel->capturing) {
294 panel->capturing = 1;
295 WMSetButtonText(w, _("Cancel"));
296 WMSetLabelText(panel->instructionsL,
297 _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
298 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
299 shortcut = captureShortcut(dpy, panel);
300 if (shortcut) {
301 int row = WMGetListSelectedItemRow(panel->actLs);
303 WMSetTextFieldText(panel->shoT, shortcut);
304 if (row >= 0) {
305 if (panel->shortcuts[row])
306 wfree(panel->shortcuts[row]);
307 panel->shortcuts[row] = shortcut;
309 WMRedisplayWidget(panel->actLs);
310 } else {
311 wfree(shortcut);
315 panel->capturing = 0;
316 WMSetButtonText(w, _("Capture"));
317 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
318 XUngrabKeyboard(dpy, CurrentTime);
321 static void clearShortcut(WMWidget * w, void *data)
323 _Panel *panel = (_Panel *) data;
324 int row = WMGetListSelectedItemRow(panel->actLs);
326 WMSetTextFieldText(panel->shoT, NULL);
328 if (row >= 0) {
329 if (panel->shortcuts[row])
330 wfree(panel->shortcuts[row]);
331 panel->shortcuts[row] = NULL;
332 WMRedisplayWidget(panel->actLs);
336 static void typedKeys(void *observerData, WMNotification * notification)
338 _Panel *panel = (_Panel *) observerData;
339 int row = WMGetListSelectedItemRow(panel->actLs);
341 if (row < 0)
342 return;
344 if (panel->shortcuts[row])
345 wfree(panel->shortcuts[row]);
346 panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
347 if (strlen(panel->shortcuts[row]) == 0) {
348 wfree(panel->shortcuts[row]);
349 panel->shortcuts[row] = NULL;
351 WMRedisplayWidget(panel->actLs);
354 static void listClick(WMWidget * w, void *data)
356 _Panel *panel = (_Panel *) data;
357 int row = WMGetListSelectedItemRow(w);
359 WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
362 static void showData(_Panel * panel)
364 char *str;
365 int i;
367 for (i = 0; i < panel->actionCount; i++) {
369 str = GetStringForKey(keyOptions[i]);
370 if (panel->shortcuts[i])
371 wfree(panel->shortcuts[i]);
372 if (str)
373 panel->shortcuts[i] = wtrimspace(str);
374 else
375 panel->shortcuts[i] = NULL;
377 if (panel->shortcuts[i] &&
378 (strcasecmp(panel->shortcuts[i], "none") == 0 || strlen(panel->shortcuts[i]) == 0)) {
379 wfree(panel->shortcuts[i]);
380 panel->shortcuts[i] = NULL;
383 WMRedisplayWidget(panel->actLs);
386 static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
388 int width, height, x, y;
389 _Panel *panel = (_Panel *) WMGetHangedData(lPtr);
390 WMScreen *scr = WMWidgetScreen(lPtr);
391 Display *dpy = WMScreenDisplay(scr);
392 WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
394 width = rect->size.width;
395 height = rect->size.height;
396 x = rect->pos.x;
397 y = rect->pos.y;
399 XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
401 if (panel->shortcuts[index]) {
402 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
403 WMSize size = WMGetPixmapSize(pix);
405 WMDrawPixmap(pix, d, x + (20 - size.width) / 2, (height - size.height) / 2 + y);
406 WMReleasePixmap(pix);
409 WMDrawString(scr, d, panel->black, panel->font, x + 20, y, text, strlen(text));
412 static void createPanel(Panel * p)
414 _Panel *panel = (_Panel *) p;
415 WMScreen *scr = WMWidgetScreen(panel->parent);
416 WMColor *color;
417 WMFont *boldFont;
419 panel->capturing = 0;
421 panel->white = WMWhiteColor(scr);
422 panel->black = WMBlackColor(scr);
423 panel->gray = WMGrayColor(scr);
424 panel->font = WMSystemFontOfSize(scr, 12);
426 panel->box = WMCreateBox(panel->parent);
427 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
429 boldFont = WMBoldSystemFontOfSize(scr, 12);
431 /* **************** Actions **************** */
432 panel->actL = WMCreateLabel(panel->box);
433 WMResizeWidget(panel->actL, 280, 20);
434 WMMoveWidget(panel->actL, 20, 10);
435 WMSetLabelFont(panel->actL, boldFont);
436 WMSetLabelText(panel->actL, _("Actions"));
437 WMSetLabelRelief(panel->actL, WRSunken);
438 WMSetLabelTextAlignment(panel->actL, WACenter);
439 color = WMDarkGrayColor(scr);
440 WMSetWidgetBackgroundColor(panel->actL, color);
441 WMReleaseColor(color);
442 WMSetLabelTextColor(panel->actL, panel->white);
444 panel->actLs = WMCreateList(panel->box);
445 WMResizeWidget(panel->actLs, 280, 190);
446 WMMoveWidget(panel->actLs, 20, 32);
447 WMSetListUserDrawProc(panel->actLs, paintItem);
448 WMHangData(panel->actLs, panel);
450 WMAddListItem(panel->actLs, _("Open applications menu"));
451 WMAddListItem(panel->actLs, _("Open window list menu"));
452 WMAddListItem(panel->actLs, _("Open window commands menu"));
453 WMAddListItem(panel->actLs, _("Hide active application"));
454 WMAddListItem(panel->actLs, _("Hide other applications"));
455 WMAddListItem(panel->actLs, _("Miniaturize active window"));
456 WMAddListItem(panel->actLs, _("Miniaturize all windows"));
457 WMAddListItem(panel->actLs, _("Close active window"));
458 WMAddListItem(panel->actLs, _("Maximize active window"));
459 WMAddListItem(panel->actLs, _("Maximize active window vertically"));
460 WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
461 WMAddListItem(panel->actLs, _("Maximize active window left half"));
462 WMAddListItem(panel->actLs, _("Maximize active window right half"));
463 WMAddListItem(panel->actLs, _("Maximus: Tiled maximization "));
464 WMAddListItem(panel->actLs, _("Raise active window"));
465 WMAddListItem(panel->actLs, _("Lower active window"));
466 WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
467 WMAddListItem(panel->actLs, _("Shade active window"));
468 WMAddListItem(panel->actLs, _("Move/Resize active window"));
469 WMAddListItem(panel->actLs, _("Select active window"));
470 WMAddListItem(panel->actLs, _("Focus next window"));
471 WMAddListItem(panel->actLs, _("Focus previous window"));
472 WMAddListItem(panel->actLs, _("Focus next group window"));
473 WMAddListItem(panel->actLs, _("Focus previous group window"));
474 WMAddListItem(panel->actLs, _("Switch to next workspace"));
475 WMAddListItem(panel->actLs, _("Switch to previous workspace"));
476 WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
477 WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
478 WMAddListItem(panel->actLs, _("Switch to workspace 1"));
479 WMAddListItem(panel->actLs, _("Switch to workspace 2"));
480 WMAddListItem(panel->actLs, _("Switch to workspace 3"));
481 WMAddListItem(panel->actLs, _("Switch to workspace 4"));
482 WMAddListItem(panel->actLs, _("Switch to workspace 5"));
483 WMAddListItem(panel->actLs, _("Switch to workspace 6"));
484 WMAddListItem(panel->actLs, _("Switch to workspace 7"));
485 WMAddListItem(panel->actLs, _("Switch to workspace 8"));
486 WMAddListItem(panel->actLs, _("Switch to workspace 9"));
487 WMAddListItem(panel->actLs, _("Switch to workspace 10"));
488 WMAddListItem(panel->actLs, _("Shortcut for window 1"));
489 WMAddListItem(panel->actLs, _("Shortcut for window 2"));
490 WMAddListItem(panel->actLs, _("Shortcut for window 3"));
491 WMAddListItem(panel->actLs, _("Shortcut for window 4"));
492 WMAddListItem(panel->actLs, _("Shortcut for window 5"));
493 WMAddListItem(panel->actLs, _("Shortcut for window 6"));
494 WMAddListItem(panel->actLs, _("Shortcut for window 7"));
495 WMAddListItem(panel->actLs, _("Shortcut for window 8"));
496 WMAddListItem(panel->actLs, _("Shortcut for window 9"));
497 WMAddListItem(panel->actLs, _("Shortcut for window 10"));
498 WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
499 WMAddListItem(panel->actLs, _("Raise/Lower Dock"));
500 WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
501 #ifdef XKB_MODELOCK
502 WMAddListItem(panel->actLs, _("Toggle keyboard language"));
503 #endif /* XKB_MODELOCK */
505 WMSetListAction(panel->actLs, listClick, panel);
507 panel->actionCount = WMGetListNumberOfRows(panel->actLs);
508 panel->shortcuts = wmalloc(sizeof(char *) * panel->actionCount);
509 memset(panel->shortcuts, 0, sizeof(char *) * panel->actionCount);
511 /***************** Shortcut ****************/
513 panel->shoF = WMCreateFrame(panel->box);
514 WMResizeWidget(panel->shoF, 190, 210);
515 WMMoveWidget(panel->shoF, 315, 10);
516 WMSetFrameTitle(panel->shoF, _("Shortcut"));
518 panel->shoT = WMCreateTextField(panel->shoF);
519 WMResizeWidget(panel->shoT, 160, 20);
520 WMMoveWidget(panel->shoT, 15, 65);
521 WMAddNotificationObserver(typedKeys, panel, WMTextDidChangeNotification, panel->shoT);
523 panel->cleB = WMCreateCommandButton(panel->shoF);
524 WMResizeWidget(panel->cleB, 75, 24);
525 WMMoveWidget(panel->cleB, 15, 95);
526 WMSetButtonText(panel->cleB, _("Clear"));
527 WMSetButtonAction(panel->cleB, clearShortcut, panel);
529 panel->defB = WMCreateCommandButton(panel->shoF);
530 WMResizeWidget(panel->defB, 75, 24);
531 WMMoveWidget(panel->defB, 100, 95);
532 WMSetButtonText(panel->defB, _("Capture"));
533 WMSetButtonAction(panel->defB, captureClick, panel);
535 panel->instructionsL = WMCreateLabel(panel->shoF);
536 WMResizeWidget(panel->instructionsL, 160, 55);
537 WMMoveWidget(panel->instructionsL, 15, 140);
538 WMSetLabelTextAlignment(panel->instructionsL, WACenter);
539 WMSetLabelWraps(panel->instructionsL, True);
540 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
542 WMMapSubwidgets(panel->shoF);
544 WMReleaseFont(boldFont);
546 WMRealizeWidget(panel->box);
547 WMMapSubwidgets(panel->box);
549 showData(panel);
552 static void storeData(_Panel * panel)
554 int i;
555 char *str;
557 for (i = 0; i < panel->actionCount; i++) {
558 str = NULL;
559 if (panel->shortcuts[i]) {
560 str = wtrimspace(panel->shortcuts[i]);
561 if (strlen(str) == 0) {
562 wfree(str);
563 str = NULL;
566 if (str) {
567 SetStringForKey(str, keyOptions[i]);
568 wfree(str);
569 } else {
570 SetStringForKey("None", keyOptions[i]);
575 Panel *InitKeyboardShortcuts(WMScreen * scr, WMWidget * parent)
577 _Panel *panel;
579 panel = wmalloc(sizeof(_Panel));
580 memset(panel, 0, sizeof(_Panel));
582 panel->sectionName = _("Keyboard Shortcut Preferences");
584 panel->description = _("Change the keyboard shortcuts for actions such\n"
585 "as changing workspaces and opening menus.");
587 panel->parent = parent;
589 panel->callbacks.createWidgets = createPanel;
590 panel->callbacks.updateDomain = storeData;
592 AddSection(panel, ICON_FILE);
594 return panel;