cleaning the house today
[wmaker-crm.git] / WPrefs.app / KeyboardShortcuts.c
blobf48a27fe13bbf3623dde30f158d6a66334331a63
1 /* KeyboardShortcuts.c- keyboard shortcut bindings
2 *
3 * WPrefs - Window Maker Preferences Program
4 *
5 * Copyright (c) 1998-2002 Alfredo K. Kojima
6 *
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
24 #include "config.h" /* for HAVE_XCONVERTCASE */
27 #include "WPrefs.h"
28 #include <ctype.h>
30 #include <X11/keysym.h>
33 typedef struct _Panel {
34 WMBox *box;
36 char *sectionName;
38 char *description;
40 CallbackRec callbacks;
42 WMWidget *parent;
44 WMLabel *actL;
45 WMList *actLs;
47 WMFrame *shoF;
48 WMTextField *shoT;
49 WMButton *cleB;
50 WMButton *defB;
52 WMLabel *instructionsL;
54 WMColor *white;
55 WMColor *black;
56 WMFont *font;
58 /**/
59 char capturing;
60 char **shortcuts;
61 int actionCount;
62 } _Panel;
66 #define ICON_FILE "keyshortcuts"
69 /* must be in the same order as the corresponding items in actions list */
70 static char *keyOptions[] = {
71 "RootMenuKey",
72 "WindowListKey",
73 "WindowMenuKey",
74 "HideKey",
75 "HideOthersKey",
76 "MiniaturizeKey",
77 "CloseKey",
78 "MaximizeKey",
79 "VMaximizeKey",
80 "HMaximizeKey",
81 "RaiseKey",
82 "LowerKey",
83 "RaiseLowerKey",
84 "ShadeKey",
85 "MoveResizeKey",
86 "SelectKey",
87 "FocusNextKey",
88 "FocusPrevKey",
89 "NextWorkspaceKey",
90 "PrevWorkspaceKey",
91 "NextWorkspaceLayerKey",
92 "PrevWorkspaceLayerKey",
93 "Workspace1Key",
94 "Workspace2Key",
95 "Workspace3Key",
96 "Workspace4Key",
97 "Workspace5Key",
98 "Workspace6Key",
99 "Workspace7Key",
100 "Workspace8Key",
101 "Workspace9Key",
102 "Workspace10Key",
103 "WindowShortcut1Key",
104 "WindowShortcut2Key",
105 "WindowShortcut3Key",
106 "WindowShortcut4Key",
107 "WindowShortcut5Key",
108 "WindowShortcut6Key",
109 "WindowShortcut7Key",
110 "WindowShortcut8Key",
111 "WindowShortcut9Key",
112 "WindowShortcut10Key",
113 "ScreenSwitchKey",
114 "ClipRaiseKey",
115 "ClipLowerKey",
116 #ifndef XKB_MODELOCK
117 "ClipRaiseLowerKey"
118 #else
119 "ClipRaiseLowerKey",
120 "ToggleKbdModeKey"
121 #endif /* XKB_MODELOCK */
126 #ifndef HAVE_XCONVERTCASE
127 /* from Xlib */
129 static void
130 XConvertCase(sym, lower, upper)
131 register KeySym sym;
132 KeySym *lower;
133 KeySym *upper;
135 *lower = sym;
136 *upper = sym;
137 switch(sym >> 8) {
138 case 0: /* Latin 1 */
139 if ((sym >= XK_A) && (sym <= XK_Z))
140 *lower += (XK_a - XK_A);
141 else if ((sym >= XK_a) && (sym <= XK_z))
142 *upper -= (XK_a - XK_A);
143 else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
144 *lower += (XK_agrave - XK_Agrave);
145 else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
146 *upper -= (XK_agrave - XK_Agrave);
147 else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
148 *lower += (XK_oslash - XK_Ooblique);
149 else if ((sym >= XK_oslash) && (sym <= XK_thorn))
150 *upper -= (XK_oslash - XK_Ooblique);
151 break;
152 case 1: /* Latin 2 */
153 /* Assume the KeySym is a legal value (ignore discontinuities) */
154 if (sym == XK_Aogonek)
155 *lower = XK_aogonek;
156 else if (sym >= XK_Lstroke && sym <= XK_Sacute)
157 *lower += (XK_lstroke - XK_Lstroke);
158 else if (sym >= XK_Scaron && sym <= XK_Zacute)
159 *lower += (XK_scaron - XK_Scaron);
160 else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
161 *lower += (XK_zcaron - XK_Zcaron);
162 else if (sym == XK_aogonek)
163 *upper = XK_Aogonek;
164 else if (sym >= XK_lstroke && sym <= XK_sacute)
165 *upper -= (XK_lstroke - XK_Lstroke);
166 else if (sym >= XK_scaron && sym <= XK_zacute)
167 *upper -= (XK_scaron - XK_Scaron);
168 else if (sym >= XK_zcaron && sym <= XK_zabovedot)
169 *upper -= (XK_zcaron - XK_Zcaron);
170 else if (sym >= XK_Racute && sym <= XK_Tcedilla)
171 *lower += (XK_racute - XK_Racute);
172 else if (sym >= XK_racute && sym <= XK_tcedilla)
173 *upper -= (XK_racute - XK_Racute);
174 break;
175 case 2: /* Latin 3 */
176 /* Assume the KeySym is a legal value (ignore discontinuities) */
177 if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
178 *lower += (XK_hstroke - XK_Hstroke);
179 else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
180 *lower += (XK_gbreve - XK_Gbreve);
181 else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
182 *upper -= (XK_hstroke - XK_Hstroke);
183 else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
184 *upper -= (XK_gbreve - XK_Gbreve);
185 else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
186 *lower += (XK_cabovedot - XK_Cabovedot);
187 else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
188 *upper -= (XK_cabovedot - XK_Cabovedot);
189 break;
190 case 3: /* Latin 4 */
191 /* Assume the KeySym is a legal value (ignore discontinuities) */
192 if (sym >= XK_Rcedilla && sym <= XK_Tslash)
193 *lower += (XK_rcedilla - XK_Rcedilla);
194 else if (sym >= XK_rcedilla && sym <= XK_tslash)
195 *upper -= (XK_rcedilla - XK_Rcedilla);
196 else if (sym == XK_ENG)
197 *lower = XK_eng;
198 else if (sym == XK_eng)
199 *upper = XK_ENG;
200 else if (sym >= XK_Amacron && sym <= XK_Umacron)
201 *lower += (XK_amacron - XK_Amacron);
202 else if (sym >= XK_amacron && sym <= XK_umacron)
203 *upper -= (XK_amacron - XK_Amacron);
204 break;
205 case 6: /* Cyrillic */
206 /* Assume the KeySym is a legal value (ignore discontinuities) */
207 if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
208 *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
209 else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
210 *upper += (XK_Serbian_DJE - XK_Serbian_dje);
211 else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
212 *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
213 else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
214 *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
215 break;
216 case 7: /* Greek */
217 /* Assume the KeySym is a legal value (ignore discontinuities) */
218 if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
219 *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
220 else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
221 sym != XK_Greek_iotaaccentdieresis &&
222 sym != XK_Greek_upsilonaccentdieresis)
223 *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
224 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
225 *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
226 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
227 sym != XK_Greek_finalsmallsigma)
228 *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
229 break;
230 case 0x14: /* Armenian */
231 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
232 *lower = sym | 1;
233 *upper = sym & ~1;
235 break;
238 #endif
241 static char*
242 captureShortcut(Display *dpy, _Panel *panel)
244 XEvent ev;
245 KeySym ksym, lksym, uksym;
246 char buffer[64];
247 char *key = NULL;
249 while (panel->capturing) {
250 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
251 WMNextEvent(dpy, &ev);
252 if (ev.type==KeyPress && ev.xkey.keycode!=0) {
253 ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
254 if (!IsModifierKey(ksym)) {
255 XConvertCase(ksym, &lksym, &uksym);
256 key=XKeysymToString(uksym);
258 panel->capturing = 0;
259 break;
262 WMHandleEvent(&ev);
265 if (!key)
266 return NULL;
268 buffer[0] = 0;
270 if (ev.xkey.state & ControlMask) {
271 strcat(buffer, "Control+");
273 if (ev.xkey.state & ShiftMask) {
274 strcat(buffer, "Shift+");
276 if (ev.xkey.state & Mod1Mask) {
277 strcat(buffer, "Mod1+");
279 if (ev.xkey.state & Mod2Mask) {
280 strcat(buffer, "Mod2+");
282 if (ev.xkey.state & Mod3Mask) {
283 strcat(buffer, "Mod3+");
285 if (ev.xkey.state & Mod4Mask) {
286 strcat(buffer, "Mod4+");
288 if (ev.xkey.state & Mod5Mask) {
289 strcat(buffer, "Mod5+");
291 strcat(buffer, key);
293 return wstrdup(buffer);
297 static void
298 captureClick(WMWidget *w, void *data)
300 _Panel *panel = (_Panel*)data;
301 Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
302 char *shortcut;
304 if (!panel->capturing) {
305 panel->capturing = 1;
306 WMSetButtonText(w, _("Cancel"));
307 WMSetLabelText(panel->instructionsL, _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
308 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync,
309 GrabModeAsync, CurrentTime);
310 shortcut = captureShortcut(dpy, panel);
311 if (shortcut) {
312 int row = WMGetListSelectedItemRow(panel->actLs);
314 WMSetTextFieldText(panel->shoT, shortcut);
315 if (row>=0) {
316 if (panel->shortcuts[row])
317 wfree(panel->shortcuts[row]);
318 panel->shortcuts[row] = shortcut;
320 WMRedisplayWidget(panel->actLs);
321 } else {
322 wfree(shortcut);
326 panel->capturing = 0;
327 WMSetButtonText(w, _("Capture"));
328 WMSetLabelText(panel->instructionsL, _("Click Capture to interactively define the shortcut key."));
329 XUngrabKeyboard(dpy, CurrentTime);
334 static void
335 clearShortcut(WMWidget *w, void *data)
337 _Panel *panel = (_Panel*)data;
338 int row = WMGetListSelectedItemRow(panel->actLs);
340 WMSetTextFieldText(panel->shoT, NULL);
342 if (row>=0) {
343 if (panel->shortcuts[row])
344 wfree(panel->shortcuts[row]);
345 panel->shortcuts[row]=NULL;
346 WMRedisplayWidget(panel->actLs);
352 static void
353 typedKeys(void *observerData, WMNotification *notification)
355 _Panel *panel = (_Panel*)observerData;
356 int row = WMGetListSelectedItemRow(panel->actLs);
358 if (row<0)
359 return;
361 if (panel->shortcuts[row])
362 wfree(panel->shortcuts[row]);
363 panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
364 if (strlen(panel->shortcuts[row])==0) {
365 wfree(panel->shortcuts[row]);
366 panel->shortcuts[row] = NULL;
368 WMRedisplayWidget(panel->actLs);
373 static void
374 listClick(WMWidget *w, void *data)
376 _Panel *panel = (_Panel*)data;
377 int row = WMGetListSelectedItemRow(w);
379 WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
383 static char*
384 trimstr(char *str)
386 char *p = str;
387 int i;
389 while (isspace(*p)) p++;
390 p = wstrdup(p);
391 i = strlen(p);
392 while (isspace(p[i]) && i>0) {
393 p[i]=0;
394 i--;
397 return p;
401 static void
402 showData(_Panel *panel)
404 char *str;
405 int i;
407 for (i=0; i<panel->actionCount; i++) {
409 str = GetStringForKey(keyOptions[i]);
410 if (panel->shortcuts[i])
411 wfree(panel->shortcuts[i]);
412 if (str)
413 panel->shortcuts[i] = trimstr(str);
414 else
415 panel->shortcuts[i] = NULL;
417 if (panel->shortcuts[i] &&
418 (strcasecmp(panel->shortcuts[i], "none")==0
419 || strlen(panel->shortcuts[i])==0)) {
420 wfree(panel->shortcuts[i]);
421 panel->shortcuts[i] = NULL;
424 WMRedisplayWidget(panel->actLs);
428 static void
429 paintItem(WMList *lPtr, int index, Drawable d, char *text, int state,
430 WMRect *rect)
432 int width, height, x, y;
433 _Panel *panel = (_Panel*)WMGetHangedData(lPtr);
434 WMScreen *scr = WMWidgetScreen(lPtr);
435 Display *dpy = WMScreenDisplay(scr);
437 width = rect->size.width;
438 height = rect->size.height;
439 x = rect->pos.x;
440 y = rect->pos.y;
442 if (state & WLDSSelected)
443 XFillRectangle(dpy, d, WMColorGC(panel->white), x, y, width,
444 height);
445 else
446 XClearArea(dpy, d, x, y, width, height, False);
448 if (panel->shortcuts[index]) {
449 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
450 WMSize size = WMGetPixmapSize(pix);
452 WMDrawPixmap(pix, d, x+(20-size.width)/2, (height-size.height)/2+y);
453 WMReleasePixmap(pix);
456 WMDrawString(scr, d, WMColorGC(panel->black), panel->font, x+20, y,
457 text, strlen(text));
461 static void
462 createPanel(Panel *p)
464 _Panel *panel = (_Panel*)p;
465 WMScreen *scr = WMWidgetScreen(panel->parent);
466 WMColor *color;
467 WMFont *boldFont;
469 panel->capturing = 0;
473 panel->box = WMCreateBox(panel->parent);
474 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
476 boldFont = WMBoldSystemFontOfSize(scr, 12);
478 /* **************** Actions **************** */
479 panel->actL = WMCreateLabel(panel->box);
480 WMResizeWidget(panel->actL, 280, 20);
481 WMMoveWidget(panel->actL, 20, 10);
482 WMSetLabelFont(panel->actL, boldFont);
483 WMSetLabelText(panel->actL, _("Actions"));
484 WMSetLabelRelief(panel->actL, WRSunken);
485 WMSetLabelTextAlignment(panel->actL, WACenter);
486 color = WMDarkGrayColor(scr);
487 WMSetWidgetBackgroundColor(panel->actL, color);
488 WMReleaseColor(color);
489 color = WMWhiteColor(scr);
490 WMSetLabelTextColor(panel->actL, color);
491 WMReleaseColor(color);
493 panel->actLs = WMCreateList(panel->box);
494 WMResizeWidget(panel->actLs, 280, 190);
495 WMMoveWidget(panel->actLs, 20, 32);
496 WMSetListUserDrawProc(panel->actLs, paintItem);
497 WMHangData(panel->actLs, panel);
499 WMAddListItem(panel->actLs, _("Open applications menu"));
500 WMAddListItem(panel->actLs, _("Open window list menu"));
501 WMAddListItem(panel->actLs, _("Open window commands menu"));
502 WMAddListItem(panel->actLs, _("Hide active application"));
503 WMAddListItem(panel->actLs, _("Hide other applications"));
504 WMAddListItem(panel->actLs, _("Miniaturize active window"));
505 WMAddListItem(panel->actLs, _("Close active window"));
506 WMAddListItem(panel->actLs, _("Maximize active window"));
507 WMAddListItem(panel->actLs, _("Maximize active window vertically"));
508 WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
509 WMAddListItem(panel->actLs, _("Raise active window"));
510 WMAddListItem(panel->actLs, _("Lower active window"));
511 WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
512 WMAddListItem(panel->actLs, _("Shade active window"));
513 WMAddListItem(panel->actLs, _("Move/Resize active window"));
514 WMAddListItem(panel->actLs, _("Select active window"));
515 WMAddListItem(panel->actLs, _("Focus next window"));
516 WMAddListItem(panel->actLs, _("Focus previous window"));
517 WMAddListItem(panel->actLs, _("Switch to next workspace"));
518 WMAddListItem(panel->actLs, _("Switch to previous workspace"));
519 WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
520 WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
521 WMAddListItem(panel->actLs, _("Switch to workspace 1"));
522 WMAddListItem(panel->actLs, _("Switch to workspace 2"));
523 WMAddListItem(panel->actLs, _("Switch to workspace 3"));
524 WMAddListItem(panel->actLs, _("Switch to workspace 4"));
525 WMAddListItem(panel->actLs, _("Switch to workspace 5"));
526 WMAddListItem(panel->actLs, _("Switch to workspace 6"));
527 WMAddListItem(panel->actLs, _("Switch to workspace 7"));
528 WMAddListItem(panel->actLs, _("Switch to workspace 8"));
529 WMAddListItem(panel->actLs, _("Switch to workspace 9"));
530 WMAddListItem(panel->actLs, _("Switch to workspace 10"));
531 WMAddListItem(panel->actLs, _("Shortcut for window 1"));
532 WMAddListItem(panel->actLs, _("Shortcut for window 2"));
533 WMAddListItem(panel->actLs, _("Shortcut for window 3"));
534 WMAddListItem(panel->actLs, _("Shortcut for window 4"));
535 WMAddListItem(panel->actLs, _("Shortcut for window 5"));
536 WMAddListItem(panel->actLs, _("Shortcut for window 6"));
537 WMAddListItem(panel->actLs, _("Shortcut for window 7"));
538 WMAddListItem(panel->actLs, _("Shortcut for window 8"));
539 WMAddListItem(panel->actLs, _("Shortcut for window 9"));
540 WMAddListItem(panel->actLs, _("Shortcut for window 10"));
541 WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
542 WMAddListItem(panel->actLs, _("Raise Clip"));
543 WMAddListItem(panel->actLs, _("Lower Clip"));
544 WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
545 #ifdef XKB_MODELOCK
546 WMAddListItem(panel->actLs, _("Toggle keyboard language"));
547 #endif /* XKB_MODELOCK */
549 WMSetListAction(panel->actLs, listClick, panel);
551 panel->actionCount = WMGetListNumberOfRows(panel->actLs);
552 panel->shortcuts = wmalloc(sizeof(char*)*panel->actionCount);
553 memset(panel->shortcuts, 0, sizeof(char*)*panel->actionCount);
555 /***************** Shortcut ****************/
557 panel->shoF = WMCreateFrame(panel->box);
558 WMResizeWidget(panel->shoF, 190, 210);
559 WMMoveWidget(panel->shoF, 315, 10);
560 WMSetFrameTitle(panel->shoF, _("Shortcut"));
562 panel->shoT = WMCreateTextField(panel->shoF);
563 WMResizeWidget(panel->shoT, 160, 20);
564 WMMoveWidget(panel->shoT, 15, 65);
565 WMAddNotificationObserver(typedKeys, panel,
566 WMTextDidChangeNotification, panel->shoT);
568 panel->cleB = WMCreateCommandButton(panel->shoF);
569 WMResizeWidget(panel->cleB, 75, 24);
570 WMMoveWidget(panel->cleB, 15, 95);
571 WMSetButtonText(panel->cleB, _("Clear"));
572 WMSetButtonAction(panel->cleB, clearShortcut, panel);
574 panel->defB = WMCreateCommandButton(panel->shoF);
575 WMResizeWidget(panel->defB, 75, 24);
576 WMMoveWidget(panel->defB, 100, 95);
577 WMSetButtonText(panel->defB, _("Capture"));
578 WMSetButtonAction(panel->defB, captureClick, panel);
580 panel->instructionsL = WMCreateLabel(panel->shoF);
581 WMResizeWidget(panel->instructionsL, 160, 55);
582 WMMoveWidget(panel->instructionsL, 15, 140);
583 WMSetLabelTextAlignment(panel->instructionsL, WACenter);
584 WMSetLabelWraps(panel->instructionsL, True);
585 WMSetLabelText(panel->instructionsL, _("Click Capture to interactively define the shortcut key."));
587 WMMapSubwidgets(panel->shoF);
589 WMReleaseFont(boldFont);
591 WMRealizeWidget(panel->box);
592 WMMapSubwidgets(panel->box);
595 showData(panel);
599 static void
600 storeData(_Panel *panel)
602 int i;
603 char *str;
605 for (i=0; i<panel->actionCount; i++) {
606 str = NULL;
607 if (panel->shortcuts[i]) {
608 str = trimstr(panel->shortcuts[i]);
609 if (strlen(str)==0) {
610 wfree(str);
611 str = NULL;
614 if (str) {
615 SetStringForKey(str, keyOptions[i]);
616 wfree(str);
617 } else {
618 SetStringForKey("None", keyOptions[i]);
625 Panel*
626 InitKeyboardShortcuts(WMScreen *scr, WMWidget *parent)
628 _Panel *panel;
630 panel = wmalloc(sizeof(_Panel));
631 memset(panel, 0, sizeof(_Panel));
633 panel->sectionName = _("Keyboard Shortcut Preferences");
635 panel->description = _("Change the keyboard shortcuts for actions such\n"
636 "as changing workspaces and opening menus.");
638 panel->parent = parent;
640 panel->callbacks.createWidgets = createPanel;
641 panel->callbacks.updateDomain = storeData;
643 panel->white = WMWhiteColor(scr);
644 panel->black = WMBlackColor(scr);
645 panel->font = WMSystemFontOfSize(scr, 12);
647 AddSection(panel, ICON_FILE);
649 return panel;