Keyboard shortcut to raise the dock
[wmaker-crm.git] / WPrefs.app / KeyboardShortcuts.c
1 /* KeyboardShortcuts.c- keyboard shortcut bindings
2  *
3  *  WPrefs - Window Maker Preferences Program
4  *
5  *  Copyright (c) 1998-2003 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.
11  *
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.
16  *
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.
21  */
22
23 #include "config.h"             /* for HAVE_XCONVERTCASE */
24
25 #include "WPrefs.h"
26 #include <ctype.h>
27
28 #include <X11/keysym.h>
29
30 typedef struct _Panel {
31         WMBox *box;
32
33         char *sectionName;
34
35         char *description;
36
37         CallbackRec callbacks;
38
39         WMWidget *parent;
40
41         WMLabel *actL;
42         WMList *actLs;
43
44         WMFrame *shoF;
45         WMTextField *shoT;
46         WMButton *cleB;
47         WMButton *defB;
48
49         WMLabel *instructionsL;
50
51         WMColor *white;
52         WMColor *black;
53         WMColor *gray;
54         WMFont *font;
55
56          /**/ char capturing;
57         char **shortcuts;
58         int actionCount;
59 } _Panel;
60
61 #define ICON_FILE       "keyshortcuts"
62
63 /* must be in the same order as the corresponding items in actions list */
64 static char *keyOptions[] = {
65         "RootMenuKey",
66         "WindowListKey",
67         "WindowMenuKey",
68         "HideKey",
69         "HideOthersKey",
70         "MiniaturizeKey",
71         "CloseKey",
72         "MaximizeKey",
73         "VMaximizeKey",
74         "HMaximizeKey",
75         "LHMaximizeKey",
76         "RHMaximizeKey",
77         "MaximusKey",
78         "RaiseKey",
79         "LowerKey",
80         "RaiseLowerKey",
81         "ShadeKey",
82         "MoveResizeKey",
83         "SelectKey",
84         "FocusNextKey",
85         "FocusPrevKey",
86         "GroupNextKey",
87         "GroupPrevKey",
88         "NextWorkspaceKey",
89         "PrevWorkspaceKey",
90         "NextWorkspaceLayerKey",
91         "PrevWorkspaceLayerKey",
92         "Workspace1Key",
93         "Workspace2Key",
94         "Workspace3Key",
95         "Workspace4Key",
96         "Workspace5Key",
97         "Workspace6Key",
98         "Workspace7Key",
99         "Workspace8Key",
100         "Workspace9Key",
101         "Workspace10Key",
102         "WindowShortcut1Key",
103         "WindowShortcut2Key",
104         "WindowShortcut3Key",
105         "WindowShortcut4Key",
106         "WindowShortcut5Key",
107         "WindowShortcut6Key",
108         "WindowShortcut7Key",
109         "WindowShortcut8Key",
110         "WindowShortcut9Key",
111         "WindowShortcut10Key",
112         "ScreenSwitchKey",
113 #ifdef VIRTUAL_DESKTOP
114         "VirtualEdgeLeftKey",
115         "VirtualEdgeRightKey",
116         "VirtualEdgeUpKey",
117         "VirtualEdgeDownKey",
118 #endif
119         "DockRaiseLowerKey",
120         "ClipRaiseKey",
121         "ClipLowerKey",
122 #ifndef XKB_MODELOCK
123         "ClipRaiseLowerKey"
124 #else
125         "ClipRaiseLowerKey",
126         "ToggleKbdModeKey"
127 #endif                          /* XKB_MODELOCK */
128 };
129
130 #ifndef HAVE_XCONVERTCASE
131 /* from Xlib */
132
133 static void XConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
134 {
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 && sym != XK_Greek_upsilonaccentdieresis)
222                         *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
223                 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
224                         *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
225                 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && sym != XK_Greek_finalsmallsigma)
226                         *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
227                 break;
228         case 0x14:              /* Armenian */
229                 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
230                         *lower = sym | 1;
231                         *upper = sym & ~1;
232                 }
233                 break;
234         }
235 }
236 #endif
237
238 static char *captureShortcut(Display * dpy, _Panel * panel)
239 {
240         XEvent ev;
241         KeySym ksym, lksym, uksym;
242         char buffer[64];
243         char *key = NULL;
244
245         while (panel->capturing) {
246                 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
247                 WMNextEvent(dpy, &ev);
248                 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
249                         ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
250                         if (!IsModifierKey(ksym)) {
251                                 XConvertCase(ksym, &lksym, &uksym);
252                                 key = XKeysymToString(uksym);
253
254                                 panel->capturing = 0;
255                                 break;
256                         }
257                 }
258                 WMHandleEvent(&ev);
259         }
260
261         if (!key)
262                 return NULL;
263
264         buffer[0] = 0;
265
266         if (ev.xkey.state & ControlMask) {
267                 strcat(buffer, "Control+");
268         }
269         if (ev.xkey.state & ShiftMask) {
270                 strcat(buffer, "Shift+");
271         }
272         if (ev.xkey.state & Mod1Mask) {
273                 strcat(buffer, "Mod1+");
274         }
275         if (ev.xkey.state & Mod2Mask) {
276                 strcat(buffer, "Mod2+");
277         }
278         if (ev.xkey.state & Mod3Mask) {
279                 strcat(buffer, "Mod3+");
280         }
281         if (ev.xkey.state & Mod4Mask) {
282                 strcat(buffer, "Mod4+");
283         }
284         if (ev.xkey.state & Mod5Mask) {
285                 strcat(buffer, "Mod5+");
286         }
287         strcat(buffer, key);
288
289         return wstrdup(buffer);
290 }
291
292 static void captureClick(WMWidget * w, void *data)
293 {
294         _Panel *panel = (_Panel *) data;
295         Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
296         char *shortcut;
297
298         if (!panel->capturing) {
299                 panel->capturing = 1;
300                 WMSetButtonText(w, _("Cancel"));
301                 WMSetLabelText(panel->instructionsL,
302                                _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
303                 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
304                 shortcut = captureShortcut(dpy, panel);
305                 if (shortcut) {
306                         int row = WMGetListSelectedItemRow(panel->actLs);
307
308                         WMSetTextFieldText(panel->shoT, shortcut);
309                         if (row >= 0) {
310                                 if (panel->shortcuts[row])
311                                         wfree(panel->shortcuts[row]);
312                                 panel->shortcuts[row] = shortcut;
313
314                                 WMRedisplayWidget(panel->actLs);
315                         } else {
316                                 wfree(shortcut);
317                         }
318                 }
319         }
320         panel->capturing = 0;
321         WMSetButtonText(w, _("Capture"));
322         WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
323         XUngrabKeyboard(dpy, CurrentTime);
324 }
325
326 static void clearShortcut(WMWidget * w, void *data)
327 {
328         _Panel *panel = (_Panel *) data;
329         int row = WMGetListSelectedItemRow(panel->actLs);
330
331         WMSetTextFieldText(panel->shoT, NULL);
332
333         if (row >= 0) {
334                 if (panel->shortcuts[row])
335                         wfree(panel->shortcuts[row]);
336                 panel->shortcuts[row] = NULL;
337                 WMRedisplayWidget(panel->actLs);
338         }
339 }
340
341 static void typedKeys(void *observerData, WMNotification * notification)
342 {
343         _Panel *panel = (_Panel *) observerData;
344         int row = WMGetListSelectedItemRow(panel->actLs);
345
346         if (row < 0)
347                 return;
348
349         if (panel->shortcuts[row])
350                 wfree(panel->shortcuts[row]);
351         panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
352         if (strlen(panel->shortcuts[row]) == 0) {
353                 wfree(panel->shortcuts[row]);
354                 panel->shortcuts[row] = NULL;
355         }
356         WMRedisplayWidget(panel->actLs);
357 }
358
359 static void listClick(WMWidget * w, void *data)
360 {
361         _Panel *panel = (_Panel *) data;
362         int row = WMGetListSelectedItemRow(w);
363
364         WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
365 }
366
367 static char *trimstr(char *str)
368 {
369         char *p = str;
370         int i;
371
372         while (isspace(*p))
373                 p++;
374         p = wstrdup(p);
375         i = strlen(p);
376         while (isspace(p[i]) && i > 0) {
377                 p[i] = 0;
378                 i--;
379         }
380
381         return p;
382 }
383
384 static void showData(_Panel * panel)
385 {
386         char *str;
387         int i;
388
389         for (i = 0; i < panel->actionCount; i++) {
390
391                 str = GetStringForKey(keyOptions[i]);
392                 if (panel->shortcuts[i])
393                         wfree(panel->shortcuts[i]);
394                 if (str)
395                         panel->shortcuts[i] = trimstr(str);
396                 else
397                         panel->shortcuts[i] = NULL;
398
399                 if (panel->shortcuts[i] &&
400                     (strcasecmp(panel->shortcuts[i], "none") == 0 || strlen(panel->shortcuts[i]) == 0)) {
401                         wfree(panel->shortcuts[i]);
402                         panel->shortcuts[i] = NULL;
403                 }
404         }
405         WMRedisplayWidget(panel->actLs);
406 }
407
408 static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
409 {
410         int width, height, x, y;
411         _Panel *panel = (_Panel *) WMGetHangedData(lPtr);
412         WMScreen *scr = WMWidgetScreen(lPtr);
413         Display *dpy = WMScreenDisplay(scr);
414         WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
415
416         width = rect->size.width;
417         height = rect->size.height;
418         x = rect->pos.x;
419         y = rect->pos.y;
420
421         XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
422
423         if (panel->shortcuts[index]) {
424                 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
425                 WMSize size = WMGetPixmapSize(pix);
426
427                 WMDrawPixmap(pix, d, x + (20 - size.width) / 2, (height - size.height) / 2 + y);
428                 WMReleasePixmap(pix);
429         }
430
431         WMDrawString(scr, d, panel->black, panel->font, x + 20, y, text, strlen(text));
432 }
433
434 static void createPanel(Panel * p)
435 {
436         _Panel *panel = (_Panel *) p;
437         WMScreen *scr = WMWidgetScreen(panel->parent);
438         WMColor *color;
439         WMFont *boldFont;
440
441         panel->capturing = 0;
442
443         panel->white = WMWhiteColor(scr);
444         panel->black = WMBlackColor(scr);
445         panel->gray = WMGrayColor(scr);
446         panel->font = WMSystemFontOfSize(scr, 12);
447
448         panel->box = WMCreateBox(panel->parent);
449         WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
450
451         boldFont = WMBoldSystemFontOfSize(scr, 12);
452
453         /* **************** Actions **************** */
454         panel->actL = WMCreateLabel(panel->box);
455         WMResizeWidget(panel->actL, 280, 20);
456         WMMoveWidget(panel->actL, 20, 10);
457         WMSetLabelFont(panel->actL, boldFont);
458         WMSetLabelText(panel->actL, _("Actions"));
459         WMSetLabelRelief(panel->actL, WRSunken);
460         WMSetLabelTextAlignment(panel->actL, WACenter);
461         color = WMDarkGrayColor(scr);
462         WMSetWidgetBackgroundColor(panel->actL, color);
463         WMReleaseColor(color);
464         WMSetLabelTextColor(panel->actL, panel->white);
465
466         panel->actLs = WMCreateList(panel->box);
467         WMResizeWidget(panel->actLs, 280, 190);
468         WMMoveWidget(panel->actLs, 20, 32);
469         WMSetListUserDrawProc(panel->actLs, paintItem);
470         WMHangData(panel->actLs, panel);
471
472         WMAddListItem(panel->actLs, _("Open applications menu"));
473         WMAddListItem(panel->actLs, _("Open window list menu"));
474         WMAddListItem(panel->actLs, _("Open window commands menu"));
475         WMAddListItem(panel->actLs, _("Hide active application"));
476         WMAddListItem(panel->actLs, _("Hide other applications"));
477         WMAddListItem(panel->actLs, _("Miniaturize active window"));
478         WMAddListItem(panel->actLs, _("Close active window"));
479         WMAddListItem(panel->actLs, _("Maximize active window"));
480         WMAddListItem(panel->actLs, _("Maximize active window vertically"));
481         WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
482         WMAddListItem(panel->actLs, _("Maximize active window left half"));
483         WMAddListItem(panel->actLs, _("Maximize active window right half"));
484         WMAddListItem(panel->actLs, _("Maximus: Tiled maximization "));
485         WMAddListItem(panel->actLs, _("Raise active window"));
486         WMAddListItem(panel->actLs, _("Lower active window"));
487         WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
488         WMAddListItem(panel->actLs, _("Shade active window"));
489         WMAddListItem(panel->actLs, _("Move/Resize active window"));
490         WMAddListItem(panel->actLs, _("Select active window"));
491         WMAddListItem(panel->actLs, _("Focus next window"));
492         WMAddListItem(panel->actLs, _("Focus previous window"));
493         WMAddListItem(panel->actLs, _("Focus next group window"));
494         WMAddListItem(panel->actLs, _("Focus previous group window"));
495         WMAddListItem(panel->actLs, _("Switch to next workspace"));
496         WMAddListItem(panel->actLs, _("Switch to previous workspace"));
497         WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
498         WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
499         WMAddListItem(panel->actLs, _("Switch to workspace 1"));
500         WMAddListItem(panel->actLs, _("Switch to workspace 2"));
501         WMAddListItem(panel->actLs, _("Switch to workspace 3"));
502         WMAddListItem(panel->actLs, _("Switch to workspace 4"));
503         WMAddListItem(panel->actLs, _("Switch to workspace 5"));
504         WMAddListItem(panel->actLs, _("Switch to workspace 6"));
505         WMAddListItem(panel->actLs, _("Switch to workspace 7"));
506         WMAddListItem(panel->actLs, _("Switch to workspace 8"));
507         WMAddListItem(panel->actLs, _("Switch to workspace 9"));
508         WMAddListItem(panel->actLs, _("Switch to workspace 10"));
509         WMAddListItem(panel->actLs, _("Shortcut for window 1"));
510         WMAddListItem(panel->actLs, _("Shortcut for window 2"));
511         WMAddListItem(panel->actLs, _("Shortcut for window 3"));
512         WMAddListItem(panel->actLs, _("Shortcut for window 4"));
513         WMAddListItem(panel->actLs, _("Shortcut for window 5"));
514         WMAddListItem(panel->actLs, _("Shortcut for window 6"));
515         WMAddListItem(panel->actLs, _("Shortcut for window 7"));
516         WMAddListItem(panel->actLs, _("Shortcut for window 8"));
517         WMAddListItem(panel->actLs, _("Shortcut for window 9"));
518         WMAddListItem(panel->actLs, _("Shortcut for window 10"));
519         WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
520 #ifdef VIRTUAL_DESKTOP
521         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next left edge"));
522         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next right edge"));
523         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next top edge"));
524         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next bottom edge"));
525 #endif
526         WMAddListItem(panel->actLs, _("Raise/Lower Dock"));
527         WMAddListItem(panel->actLs, _("Raise Clip"));
528         WMAddListItem(panel->actLs, _("Lower Clip"));
529         WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
530 #ifdef XKB_MODELOCK
531         WMAddListItem(panel->actLs, _("Toggle keyboard language"));
532 #endif                          /* XKB_MODELOCK */
533
534         WMSetListAction(panel->actLs, listClick, panel);
535
536         panel->actionCount = WMGetListNumberOfRows(panel->actLs);
537         panel->shortcuts = wmalloc(sizeof(char *) * panel->actionCount);
538         memset(panel->shortcuts, 0, sizeof(char *) * panel->actionCount);
539
540     /***************** Shortcut ****************/
541
542         panel->shoF = WMCreateFrame(panel->box);
543         WMResizeWidget(panel->shoF, 190, 210);
544         WMMoveWidget(panel->shoF, 315, 10);
545         WMSetFrameTitle(panel->shoF, _("Shortcut"));
546
547         panel->shoT = WMCreateTextField(panel->shoF);
548         WMResizeWidget(panel->shoT, 160, 20);
549         WMMoveWidget(panel->shoT, 15, 65);
550         WMAddNotificationObserver(typedKeys, panel, WMTextDidChangeNotification, panel->shoT);
551
552         panel->cleB = WMCreateCommandButton(panel->shoF);
553         WMResizeWidget(panel->cleB, 75, 24);
554         WMMoveWidget(panel->cleB, 15, 95);
555         WMSetButtonText(panel->cleB, _("Clear"));
556         WMSetButtonAction(panel->cleB, clearShortcut, panel);
557
558         panel->defB = WMCreateCommandButton(panel->shoF);
559         WMResizeWidget(panel->defB, 75, 24);
560         WMMoveWidget(panel->defB, 100, 95);
561         WMSetButtonText(panel->defB, _("Capture"));
562         WMSetButtonAction(panel->defB, captureClick, panel);
563
564         panel->instructionsL = WMCreateLabel(panel->shoF);
565         WMResizeWidget(panel->instructionsL, 160, 55);
566         WMMoveWidget(panel->instructionsL, 15, 140);
567         WMSetLabelTextAlignment(panel->instructionsL, WACenter);
568         WMSetLabelWraps(panel->instructionsL, True);
569         WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
570
571         WMMapSubwidgets(panel->shoF);
572
573         WMReleaseFont(boldFont);
574
575         WMRealizeWidget(panel->box);
576         WMMapSubwidgets(panel->box);
577
578         showData(panel);
579 }
580
581 static void storeData(_Panel * panel)
582 {
583         int i;
584         char *str;
585
586         for (i = 0; i < panel->actionCount; i++) {
587                 str = NULL;
588                 if (panel->shortcuts[i]) {
589                         str = trimstr(panel->shortcuts[i]);
590                         if (strlen(str) == 0) {
591                                 wfree(str);
592                                 str = NULL;
593                         }
594                 }
595                 if (str) {
596                         SetStringForKey(str, keyOptions[i]);
597                         wfree(str);
598                 } else {
599                         SetStringForKey("None", keyOptions[i]);
600                 }
601         }
602 }
603
604 Panel *InitKeyboardShortcuts(WMScreen * scr, WMWidget * parent)
605 {
606         _Panel *panel;
607
608         panel = wmalloc(sizeof(_Panel));
609         memset(panel, 0, sizeof(_Panel));
610
611         panel->sectionName = _("Keyboard Shortcut Preferences");
612
613         panel->description = _("Change the keyboard shortcuts for actions such\n"
614                                "as changing workspaces and opening menus.");
615
616         panel->parent = parent;
617
618         panel->callbacks.createWidgets = createPanel;
619         panel->callbacks.updateDomain = storeData;
620
621         AddSection(panel, ICON_FILE);
622
623         return panel;
624 }