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