- Added double buffering when drawing a WMFrame title with an AA font to avoid
[wmaker-crm.git] / WPrefs.app / KeyboardShortcuts.c
blob9aa54edd2ae7414590b34f4f15f67fb862581539
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, height);
444 else
445 //XClearArea(dpy, d, x, y, width, height, False);
446 XFillRectangle(dpy, d, WMColorGC(WMGrayColor(scr)), x, y, width, height);
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, panel->black, panel->font, x+20, y, text, strlen(text));
460 static void
461 createPanel(Panel *p)
463 _Panel *panel = (_Panel*)p;
464 WMScreen *scr = WMWidgetScreen(panel->parent);
465 WMColor *color;
466 WMFont *boldFont;
468 panel->capturing = 0;
472 panel->box = WMCreateBox(panel->parent);
473 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
475 boldFont = WMBoldSystemFontOfSize(scr, 12);
477 /* **************** Actions **************** */
478 panel->actL = WMCreateLabel(panel->box);
479 WMResizeWidget(panel->actL, 280, 20);
480 WMMoveWidget(panel->actL, 20, 10);
481 WMSetLabelFont(panel->actL, boldFont);
482 WMSetLabelText(panel->actL, _("Actions"));
483 WMSetLabelRelief(panel->actL, WRSunken);
484 WMSetLabelTextAlignment(panel->actL, WACenter);
485 color = WMDarkGrayColor(scr);
486 WMSetWidgetBackgroundColor(panel->actL, color);
487 WMReleaseColor(color);
488 color = WMWhiteColor(scr);
489 WMSetLabelTextColor(panel->actL, color);
490 WMReleaseColor(color);
492 panel->actLs = WMCreateList(panel->box);
493 WMResizeWidget(panel->actLs, 280, 190);
494 WMMoveWidget(panel->actLs, 20, 32);
495 WMSetListUserDrawProc(panel->actLs, paintItem);
496 WMHangData(panel->actLs, panel);
498 WMAddListItem(panel->actLs, _("Open applications menu"));
499 WMAddListItem(panel->actLs, _("Open window list menu"));
500 WMAddListItem(panel->actLs, _("Open window commands menu"));
501 WMAddListItem(panel->actLs, _("Hide active application"));
502 WMAddListItem(panel->actLs, _("Hide other applications"));
503 WMAddListItem(panel->actLs, _("Miniaturize active window"));
504 WMAddListItem(panel->actLs, _("Close active window"));
505 WMAddListItem(panel->actLs, _("Maximize active window"));
506 WMAddListItem(panel->actLs, _("Maximize active window vertically"));
507 WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
508 WMAddListItem(panel->actLs, _("Raise active window"));
509 WMAddListItem(panel->actLs, _("Lower active window"));
510 WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
511 WMAddListItem(panel->actLs, _("Shade active window"));
512 WMAddListItem(panel->actLs, _("Move/Resize active window"));
513 WMAddListItem(panel->actLs, _("Select active window"));
514 WMAddListItem(panel->actLs, _("Focus next window"));
515 WMAddListItem(panel->actLs, _("Focus previous window"));
516 WMAddListItem(panel->actLs, _("Switch to next workspace"));
517 WMAddListItem(panel->actLs, _("Switch to previous workspace"));
518 WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
519 WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
520 WMAddListItem(panel->actLs, _("Switch to workspace 1"));
521 WMAddListItem(panel->actLs, _("Switch to workspace 2"));
522 WMAddListItem(panel->actLs, _("Switch to workspace 3"));
523 WMAddListItem(panel->actLs, _("Switch to workspace 4"));
524 WMAddListItem(panel->actLs, _("Switch to workspace 5"));
525 WMAddListItem(panel->actLs, _("Switch to workspace 6"));
526 WMAddListItem(panel->actLs, _("Switch to workspace 7"));
527 WMAddListItem(panel->actLs, _("Switch to workspace 8"));
528 WMAddListItem(panel->actLs, _("Switch to workspace 9"));
529 WMAddListItem(panel->actLs, _("Switch to workspace 10"));
530 WMAddListItem(panel->actLs, _("Shortcut for window 1"));
531 WMAddListItem(panel->actLs, _("Shortcut for window 2"));
532 WMAddListItem(panel->actLs, _("Shortcut for window 3"));
533 WMAddListItem(panel->actLs, _("Shortcut for window 4"));
534 WMAddListItem(panel->actLs, _("Shortcut for window 5"));
535 WMAddListItem(panel->actLs, _("Shortcut for window 6"));
536 WMAddListItem(panel->actLs, _("Shortcut for window 7"));
537 WMAddListItem(panel->actLs, _("Shortcut for window 8"));
538 WMAddListItem(panel->actLs, _("Shortcut for window 9"));
539 WMAddListItem(panel->actLs, _("Shortcut for window 10"));
540 WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
541 WMAddListItem(panel->actLs, _("Raise Clip"));
542 WMAddListItem(panel->actLs, _("Lower Clip"));
543 WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
544 #ifdef XKB_MODELOCK
545 WMAddListItem(panel->actLs, _("Toggle keyboard language"));
546 #endif /* XKB_MODELOCK */
548 WMSetListAction(panel->actLs, listClick, panel);
550 panel->actionCount = WMGetListNumberOfRows(panel->actLs);
551 panel->shortcuts = wmalloc(sizeof(char*)*panel->actionCount);
552 memset(panel->shortcuts, 0, sizeof(char*)*panel->actionCount);
554 /***************** Shortcut ****************/
556 panel->shoF = WMCreateFrame(panel->box);
557 WMResizeWidget(panel->shoF, 190, 210);
558 WMMoveWidget(panel->shoF, 315, 10);
559 WMSetFrameTitle(panel->shoF, _("Shortcut"));
561 panel->shoT = WMCreateTextField(panel->shoF);
562 WMResizeWidget(panel->shoT, 160, 20);
563 WMMoveWidget(panel->shoT, 15, 65);
564 WMAddNotificationObserver(typedKeys, panel,
565 WMTextDidChangeNotification, panel->shoT);
567 panel->cleB = WMCreateCommandButton(panel->shoF);
568 WMResizeWidget(panel->cleB, 75, 24);
569 WMMoveWidget(panel->cleB, 15, 95);
570 WMSetButtonText(panel->cleB, _("Clear"));
571 WMSetButtonAction(panel->cleB, clearShortcut, panel);
573 panel->defB = WMCreateCommandButton(panel->shoF);
574 WMResizeWidget(panel->defB, 75, 24);
575 WMMoveWidget(panel->defB, 100, 95);
576 WMSetButtonText(panel->defB, _("Capture"));
577 WMSetButtonAction(panel->defB, captureClick, panel);
579 panel->instructionsL = WMCreateLabel(panel->shoF);
580 WMResizeWidget(panel->instructionsL, 160, 55);
581 WMMoveWidget(panel->instructionsL, 15, 140);
582 WMSetLabelTextAlignment(panel->instructionsL, WACenter);
583 WMSetLabelWraps(panel->instructionsL, True);
584 WMSetLabelText(panel->instructionsL, _("Click Capture to interactively define the shortcut key."));
586 WMMapSubwidgets(panel->shoF);
588 WMReleaseFont(boldFont);
590 WMRealizeWidget(panel->box);
591 WMMapSubwidgets(panel->box);
594 showData(panel);
598 static void
599 storeData(_Panel *panel)
601 int i;
602 char *str;
604 for (i=0; i<panel->actionCount; i++) {
605 str = NULL;
606 if (panel->shortcuts[i]) {
607 str = trimstr(panel->shortcuts[i]);
608 if (strlen(str)==0) {
609 wfree(str);
610 str = NULL;
613 if (str) {
614 SetStringForKey(str, keyOptions[i]);
615 wfree(str);
616 } else {
617 SetStringForKey("None", keyOptions[i]);
624 Panel*
625 InitKeyboardShortcuts(WMScreen *scr, WMWidget *parent)
627 _Panel *panel;
629 panel = wmalloc(sizeof(_Panel));
630 memset(panel, 0, sizeof(_Panel));
632 panel->sectionName = _("Keyboard Shortcut Preferences");
634 panel->description = _("Change the keyboard shortcuts for actions such\n"
635 "as changing workspaces and opening menus.");
637 panel->parent = parent;
639 panel->callbacks.createWidgets = createPanel;
640 panel->callbacks.updateDomain = storeData;
642 panel->white = WMWhiteColor(scr);
643 panel->black = WMBlackColor(scr);
644 panel->font = WMSystemFontOfSize(scr, 12);
646 AddSection(panel, ICON_FILE);
648 return panel;