Change to the linux kernel coding style
[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         "RaiseKey",
76         "LowerKey",
77         "RaiseLowerKey",
78         "ShadeKey",
79         "MoveResizeKey",
80         "SelectKey",
81         "FocusNextKey",
82         "FocusPrevKey",
83         "NextWorkspaceKey",
84         "PrevWorkspaceKey",
85         "NextWorkspaceLayerKey",
86         "PrevWorkspaceLayerKey",
87         "Workspace1Key",
88         "Workspace2Key",
89         "Workspace3Key",
90         "Workspace4Key",
91         "Workspace5Key",
92         "Workspace6Key",
93         "Workspace7Key",
94         "Workspace8Key",
95         "Workspace9Key",
96         "Workspace10Key",
97         "WindowShortcut1Key",
98         "WindowShortcut2Key",
99         "WindowShortcut3Key",
100         "WindowShortcut4Key",
101         "WindowShortcut5Key",
102         "WindowShortcut6Key",
103         "WindowShortcut7Key",
104         "WindowShortcut8Key",
105         "WindowShortcut9Key",
106         "WindowShortcut10Key",
107         "ScreenSwitchKey",
108 #ifdef VIRTUAL_DESKTOP
109         "VirtualEdgeLeftKey",
110         "VirtualEdgeRightKey",
111         "VirtualEdgeUpKey",
112         "VirtualEdgeDownKey",
113 #endif
114         "ClipRaiseKey",
115         "ClipLowerKey",
116 #ifndef XKB_MODELOCK
117         "ClipRaiseLowerKey"
118 #else
119         "ClipRaiseLowerKey",
120         "ToggleKbdModeKey"
121 #endif                          /* XKB_MODELOCK */
122 };
123
124 #ifndef HAVE_XCONVERTCASE
125 /* from Xlib */
126
127 static void XConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
128 {
129         *lower = sym;
130         *upper = sym;
131         switch (sym >> 8) {
132         case 0:         /* Latin 1 */
133                 if ((sym >= XK_A) && (sym <= XK_Z))
134                         *lower += (XK_a - XK_A);
135                 else if ((sym >= XK_a) && (sym <= XK_z))
136                         *upper -= (XK_a - XK_A);
137                 else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
138                         *lower += (XK_agrave - XK_Agrave);
139                 else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
140                         *upper -= (XK_agrave - XK_Agrave);
141                 else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
142                         *lower += (XK_oslash - XK_Ooblique);
143                 else if ((sym >= XK_oslash) && (sym <= XK_thorn))
144                         *upper -= (XK_oslash - XK_Ooblique);
145                 break;
146         case 1:         /* Latin 2 */
147                 /* Assume the KeySym is a legal value (ignore discontinuities) */
148                 if (sym == XK_Aogonek)
149                         *lower = XK_aogonek;
150                 else if (sym >= XK_Lstroke && sym <= XK_Sacute)
151                         *lower += (XK_lstroke - XK_Lstroke);
152                 else if (sym >= XK_Scaron && sym <= XK_Zacute)
153                         *lower += (XK_scaron - XK_Scaron);
154                 else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
155                         *lower += (XK_zcaron - XK_Zcaron);
156                 else if (sym == XK_aogonek)
157                         *upper = XK_Aogonek;
158                 else if (sym >= XK_lstroke && sym <= XK_sacute)
159                         *upper -= (XK_lstroke - XK_Lstroke);
160                 else if (sym >= XK_scaron && sym <= XK_zacute)
161                         *upper -= (XK_scaron - XK_Scaron);
162                 else if (sym >= XK_zcaron && sym <= XK_zabovedot)
163                         *upper -= (XK_zcaron - XK_Zcaron);
164                 else if (sym >= XK_Racute && sym <= XK_Tcedilla)
165                         *lower += (XK_racute - XK_Racute);
166                 else if (sym >= XK_racute && sym <= XK_tcedilla)
167                         *upper -= (XK_racute - XK_Racute);
168                 break;
169         case 2:         /* Latin 3 */
170                 /* Assume the KeySym is a legal value (ignore discontinuities) */
171                 if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
172                         *lower += (XK_hstroke - XK_Hstroke);
173                 else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
174                         *lower += (XK_gbreve - XK_Gbreve);
175                 else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
176                         *upper -= (XK_hstroke - XK_Hstroke);
177                 else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
178                         *upper -= (XK_gbreve - XK_Gbreve);
179                 else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
180                         *lower += (XK_cabovedot - XK_Cabovedot);
181                 else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
182                         *upper -= (XK_cabovedot - XK_Cabovedot);
183                 break;
184         case 3:         /* Latin 4 */
185                 /* Assume the KeySym is a legal value (ignore discontinuities) */
186                 if (sym >= XK_Rcedilla && sym <= XK_Tslash)
187                         *lower += (XK_rcedilla - XK_Rcedilla);
188                 else if (sym >= XK_rcedilla && sym <= XK_tslash)
189                         *upper -= (XK_rcedilla - XK_Rcedilla);
190                 else if (sym == XK_ENG)
191                         *lower = XK_eng;
192                 else if (sym == XK_eng)
193                         *upper = XK_ENG;
194                 else if (sym >= XK_Amacron && sym <= XK_Umacron)
195                         *lower += (XK_amacron - XK_Amacron);
196                 else if (sym >= XK_amacron && sym <= XK_umacron)
197                         *upper -= (XK_amacron - XK_Amacron);
198                 break;
199         case 6:         /* Cyrillic */
200                 /* Assume the KeySym is a legal value (ignore discontinuities) */
201                 if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
202                         *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
203                 else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
204                         *upper += (XK_Serbian_DJE - XK_Serbian_dje);
205                 else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
206                         *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
207                 else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
208                         *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
209                 break;
210         case 7:         /* Greek */
211                 /* Assume the KeySym is a legal value (ignore discontinuities) */
212                 if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
213                         *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
214                 else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
215                          sym != XK_Greek_iotaaccentdieresis && sym != XK_Greek_upsilonaccentdieresis)
216                         *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
217                 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
218                         *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
219                 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && sym != XK_Greek_finalsmallsigma)
220                         *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
221                 break;
222         case 0x14:              /* Armenian */
223                 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
224                         *lower = sym | 1;
225                         *upper = sym & ~1;
226                 }
227                 break;
228         }
229 }
230 #endif
231
232 static char *captureShortcut(Display * dpy, _Panel * panel)
233 {
234         XEvent ev;
235         KeySym ksym, lksym, uksym;
236         char buffer[64];
237         char *key = NULL;
238
239         while (panel->capturing) {
240                 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
241                 WMNextEvent(dpy, &ev);
242                 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
243                         ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
244                         if (!IsModifierKey(ksym)) {
245                                 XConvertCase(ksym, &lksym, &uksym);
246                                 key = XKeysymToString(uksym);
247
248                                 panel->capturing = 0;
249                                 break;
250                         }
251                 }
252                 WMHandleEvent(&ev);
253         }
254
255         if (!key)
256                 return NULL;
257
258         buffer[0] = 0;
259
260         if (ev.xkey.state & ControlMask) {
261                 strcat(buffer, "Control+");
262         }
263         if (ev.xkey.state & ShiftMask) {
264                 strcat(buffer, "Shift+");
265         }
266         if (ev.xkey.state & Mod1Mask) {
267                 strcat(buffer, "Mod1+");
268         }
269         if (ev.xkey.state & Mod2Mask) {
270                 strcat(buffer, "Mod2+");
271         }
272         if (ev.xkey.state & Mod3Mask) {
273                 strcat(buffer, "Mod3+");
274         }
275         if (ev.xkey.state & Mod4Mask) {
276                 strcat(buffer, "Mod4+");
277         }
278         if (ev.xkey.state & Mod5Mask) {
279                 strcat(buffer, "Mod5+");
280         }
281         strcat(buffer, key);
282
283         return wstrdup(buffer);
284 }
285
286 static void captureClick(WMWidget * w, void *data)
287 {
288         _Panel *panel = (_Panel *) data;
289         Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
290         char *shortcut;
291
292         if (!panel->capturing) {
293                 panel->capturing = 1;
294                 WMSetButtonText(w, _("Cancel"));
295                 WMSetLabelText(panel->instructionsL,
296                                _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
297                 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
298                 shortcut = captureShortcut(dpy, panel);
299                 if (shortcut) {
300                         int row = WMGetListSelectedItemRow(panel->actLs);
301
302                         WMSetTextFieldText(panel->shoT, shortcut);
303                         if (row >= 0) {
304                                 if (panel->shortcuts[row])
305                                         wfree(panel->shortcuts[row]);
306                                 panel->shortcuts[row] = shortcut;
307
308                                 WMRedisplayWidget(panel->actLs);
309                         } else {
310                                 wfree(shortcut);
311                         }
312                 }
313         }
314         panel->capturing = 0;
315         WMSetButtonText(w, _("Capture"));
316         WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
317         XUngrabKeyboard(dpy, CurrentTime);
318 }
319
320 static void clearShortcut(WMWidget * w, void *data)
321 {
322         _Panel *panel = (_Panel *) data;
323         int row = WMGetListSelectedItemRow(panel->actLs);
324
325         WMSetTextFieldText(panel->shoT, NULL);
326
327         if (row >= 0) {
328                 if (panel->shortcuts[row])
329                         wfree(panel->shortcuts[row]);
330                 panel->shortcuts[row] = NULL;
331                 WMRedisplayWidget(panel->actLs);
332         }
333 }
334
335 static void typedKeys(void *observerData, WMNotification * notification)
336 {
337         _Panel *panel = (_Panel *) observerData;
338         int row = WMGetListSelectedItemRow(panel->actLs);
339
340         if (row < 0)
341                 return;
342
343         if (panel->shortcuts[row])
344                 wfree(panel->shortcuts[row]);
345         panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
346         if (strlen(panel->shortcuts[row]) == 0) {
347                 wfree(panel->shortcuts[row]);
348                 panel->shortcuts[row] = NULL;
349         }
350         WMRedisplayWidget(panel->actLs);
351 }
352
353 static void listClick(WMWidget * w, void *data)
354 {
355         _Panel *panel = (_Panel *) data;
356         int row = WMGetListSelectedItemRow(w);
357
358         WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
359 }
360
361 static char *trimstr(char *str)
362 {
363         char *p = str;
364         int i;
365
366         while (isspace(*p))
367                 p++;
368         p = wstrdup(p);
369         i = strlen(p);
370         while (isspace(p[i]) && i > 0) {
371                 p[i] = 0;
372                 i--;
373         }
374
375         return p;
376 }
377
378 static void showData(_Panel * panel)
379 {
380         char *str;
381         int i;
382
383         for (i = 0; i < panel->actionCount; i++) {
384
385                 str = GetStringForKey(keyOptions[i]);
386                 if (panel->shortcuts[i])
387                         wfree(panel->shortcuts[i]);
388                 if (str)
389                         panel->shortcuts[i] = trimstr(str);
390                 else
391                         panel->shortcuts[i] = NULL;
392
393                 if (panel->shortcuts[i] &&
394                     (strcasecmp(panel->shortcuts[i], "none") == 0 || strlen(panel->shortcuts[i]) == 0)) {
395                         wfree(panel->shortcuts[i]);
396                         panel->shortcuts[i] = NULL;
397                 }
398         }
399         WMRedisplayWidget(panel->actLs);
400 }
401
402 static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
403 {
404         int width, height, x, y;
405         _Panel *panel = (_Panel *) WMGetHangedData(lPtr);
406         WMScreen *scr = WMWidgetScreen(lPtr);
407         Display *dpy = WMScreenDisplay(scr);
408         WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
409
410         width = rect->size.width;
411         height = rect->size.height;
412         x = rect->pos.x;
413         y = rect->pos.y;
414
415         XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
416
417         if (panel->shortcuts[index]) {
418                 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
419                 WMSize size = WMGetPixmapSize(pix);
420
421                 WMDrawPixmap(pix, d, x + (20 - size.width) / 2, (height - size.height) / 2 + y);
422                 WMReleasePixmap(pix);
423         }
424
425         WMDrawString(scr, d, panel->black, panel->font, x + 20, y, text, strlen(text));
426 }
427
428 static void createPanel(Panel * p)
429 {
430         _Panel *panel = (_Panel *) p;
431         WMScreen *scr = WMWidgetScreen(panel->parent);
432         WMColor *color;
433         WMFont *boldFont;
434
435         panel->capturing = 0;
436
437         panel->white = WMWhiteColor(scr);
438         panel->black = WMBlackColor(scr);
439         panel->gray = WMGrayColor(scr);
440         panel->font = WMSystemFontOfSize(scr, 12);
441
442         panel->box = WMCreateBox(panel->parent);
443         WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
444
445         boldFont = WMBoldSystemFontOfSize(scr, 12);
446
447         /* **************** Actions **************** */
448         panel->actL = WMCreateLabel(panel->box);
449         WMResizeWidget(panel->actL, 280, 20);
450         WMMoveWidget(panel->actL, 20, 10);
451         WMSetLabelFont(panel->actL, boldFont);
452         WMSetLabelText(panel->actL, _("Actions"));
453         WMSetLabelRelief(panel->actL, WRSunken);
454         WMSetLabelTextAlignment(panel->actL, WACenter);
455         color = WMDarkGrayColor(scr);
456         WMSetWidgetBackgroundColor(panel->actL, color);
457         WMReleaseColor(color);
458         WMSetLabelTextColor(panel->actL, panel->white);
459
460         panel->actLs = WMCreateList(panel->box);
461         WMResizeWidget(panel->actLs, 280, 190);
462         WMMoveWidget(panel->actLs, 20, 32);
463         WMSetListUserDrawProc(panel->actLs, paintItem);
464         WMHangData(panel->actLs, panel);
465
466         WMAddListItem(panel->actLs, _("Open applications menu"));
467         WMAddListItem(panel->actLs, _("Open window list menu"));
468         WMAddListItem(panel->actLs, _("Open window commands menu"));
469         WMAddListItem(panel->actLs, _("Hide active application"));
470         WMAddListItem(panel->actLs, _("Hide other applications"));
471         WMAddListItem(panel->actLs, _("Miniaturize active window"));
472         WMAddListItem(panel->actLs, _("Close active window"));
473         WMAddListItem(panel->actLs, _("Maximize active window"));
474         WMAddListItem(panel->actLs, _("Maximize active window vertically"));
475         WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
476         WMAddListItem(panel->actLs, _("Raise active window"));
477         WMAddListItem(panel->actLs, _("Lower active window"));
478         WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
479         WMAddListItem(panel->actLs, _("Shade active window"));
480         WMAddListItem(panel->actLs, _("Move/Resize active window"));
481         WMAddListItem(panel->actLs, _("Select active window"));
482         WMAddListItem(panel->actLs, _("Focus next window"));
483         WMAddListItem(panel->actLs, _("Focus previous window"));
484         WMAddListItem(panel->actLs, _("Switch to next workspace"));
485         WMAddListItem(panel->actLs, _("Switch to previous workspace"));
486         WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
487         WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
488         WMAddListItem(panel->actLs, _("Switch to workspace 1"));
489         WMAddListItem(panel->actLs, _("Switch to workspace 2"));
490         WMAddListItem(panel->actLs, _("Switch to workspace 3"));
491         WMAddListItem(panel->actLs, _("Switch to workspace 4"));
492         WMAddListItem(panel->actLs, _("Switch to workspace 5"));
493         WMAddListItem(panel->actLs, _("Switch to workspace 6"));
494         WMAddListItem(panel->actLs, _("Switch to workspace 7"));
495         WMAddListItem(panel->actLs, _("Switch to workspace 8"));
496         WMAddListItem(panel->actLs, _("Switch to workspace 9"));
497         WMAddListItem(panel->actLs, _("Switch to workspace 10"));
498         WMAddListItem(panel->actLs, _("Shortcut for window 1"));
499         WMAddListItem(panel->actLs, _("Shortcut for window 2"));
500         WMAddListItem(panel->actLs, _("Shortcut for window 3"));
501         WMAddListItem(panel->actLs, _("Shortcut for window 4"));
502         WMAddListItem(panel->actLs, _("Shortcut for window 5"));
503         WMAddListItem(panel->actLs, _("Shortcut for window 6"));
504         WMAddListItem(panel->actLs, _("Shortcut for window 7"));
505         WMAddListItem(panel->actLs, _("Shortcut for window 8"));
506         WMAddListItem(panel->actLs, _("Shortcut for window 9"));
507         WMAddListItem(panel->actLs, _("Shortcut for window 10"));
508         WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
509 #ifdef VIRTUAL_DESKTOP
510         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next left edge"));
511         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next right edge"));
512         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next top edge"));
513         WMAddListItem(panel->actLs, _("Move VirtualDesktop to next bottom edge"));
514 #endif
515         WMAddListItem(panel->actLs, _("Raise Clip"));
516         WMAddListItem(panel->actLs, _("Lower Clip"));
517         WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
518 #ifdef XKB_MODELOCK
519         WMAddListItem(panel->actLs, _("Toggle keyboard language"));
520 #endif                          /* XKB_MODELOCK */
521
522         WMSetListAction(panel->actLs, listClick, panel);
523
524         panel->actionCount = WMGetListNumberOfRows(panel->actLs);
525         panel->shortcuts = wmalloc(sizeof(char *) * panel->actionCount);
526         memset(panel->shortcuts, 0, sizeof(char *) * panel->actionCount);
527
528     /***************** Shortcut ****************/
529
530         panel->shoF = WMCreateFrame(panel->box);
531         WMResizeWidget(panel->shoF, 190, 210);
532         WMMoveWidget(panel->shoF, 315, 10);
533         WMSetFrameTitle(panel->shoF, _("Shortcut"));
534
535         panel->shoT = WMCreateTextField(panel->shoF);
536         WMResizeWidget(panel->shoT, 160, 20);
537         WMMoveWidget(panel->shoT, 15, 65);
538         WMAddNotificationObserver(typedKeys, panel, WMTextDidChangeNotification, panel->shoT);
539
540         panel->cleB = WMCreateCommandButton(panel->shoF);
541         WMResizeWidget(panel->cleB, 75, 24);
542         WMMoveWidget(panel->cleB, 15, 95);
543         WMSetButtonText(panel->cleB, _("Clear"));
544         WMSetButtonAction(panel->cleB, clearShortcut, panel);
545
546         panel->defB = WMCreateCommandButton(panel->shoF);
547         WMResizeWidget(panel->defB, 75, 24);
548         WMMoveWidget(panel->defB, 100, 95);
549         WMSetButtonText(panel->defB, _("Capture"));
550         WMSetButtonAction(panel->defB, captureClick, panel);
551
552         panel->instructionsL = WMCreateLabel(panel->shoF);
553         WMResizeWidget(panel->instructionsL, 160, 55);
554         WMMoveWidget(panel->instructionsL, 15, 140);
555         WMSetLabelTextAlignment(panel->instructionsL, WACenter);
556         WMSetLabelWraps(panel->instructionsL, True);
557         WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
558
559         WMMapSubwidgets(panel->shoF);
560
561         WMReleaseFont(boldFont);
562
563         WMRealizeWidget(panel->box);
564         WMMapSubwidgets(panel->box);
565
566         showData(panel);
567 }
568
569 static void storeData(_Panel * panel)
570 {
571         int i;
572         char *str;
573
574         for (i = 0; i < panel->actionCount; i++) {
575                 str = NULL;
576                 if (panel->shortcuts[i]) {
577                         str = trimstr(panel->shortcuts[i]);
578                         if (strlen(str) == 0) {
579                                 wfree(str);
580                                 str = NULL;
581                         }
582                 }
583                 if (str) {
584                         SetStringForKey(str, keyOptions[i]);
585                         wfree(str);
586                 } else {
587                         SetStringForKey("None", keyOptions[i]);
588                 }
589         }
590 }
591
592 Panel *InitKeyboardShortcuts(WMScreen * scr, WMWidget * parent)
593 {
594         _Panel *panel;
595
596         panel = wmalloc(sizeof(_Panel));
597         memset(panel, 0, sizeof(_Panel));
598
599         panel->sectionName = _("Keyboard Shortcut Preferences");
600
601         panel->description = _("Change the keyboard shortcuts for actions such\n"
602                                "as changing workspaces and opening menus.");
603
604         panel->parent = parent;
605
606         panel->callbacks.createWidgets = createPanel;
607         panel->callbacks.updateDomain = storeData;
608
609         AddSection(panel, ICON_FILE);
610
611         return panel;
612 }