Update Serbian translation from master branch
[wmaker-crm.git] / WPrefs.app / KeyboardShortcuts.c
blob8df69a9e6b9a83900803877ea3b333ee634acb9f
1 /* KeyboardShortcuts.c- keyboard shortcut bindings
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 1998-2003 Alfredo K. Kojima
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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "config.h" /* for HAVE_XCONVERTCASE */
24 #include "WPrefs.h"
25 #include <ctype.h>
27 #include <X11/keysym.h>
28 #include <X11/XKBlib.h>
30 typedef struct _Panel {
31 WMBox *box;
33 char *sectionName;
35 char *description;
37 CallbackRec callbacks;
39 WMWidget *parent;
41 WMLabel *actL;
42 WMList *actLs;
44 WMFrame *shoF;
45 WMTextField *shoT;
46 WMButton *cleB;
47 WMButton *defB;
49 WMLabel *instructionsL;
51 WMColor *white;
52 WMColor *black;
53 WMColor *gray;
54 WMFont *font;
56 Bool capturing;
57 char **shortcuts;
58 int actionCount;
59 } _Panel;
61 #define ICON_FILE "keyshortcuts"
64 * List of user definable shortcut keys
65 * First parameter is the internal keyword known by WMaker
66 * Second is the text displayed to the user
68 static struct keyOption {
69 const char *key;
70 const char *title;
71 } keyOptions[] = {
72 { "RootMenuKey", N_("Open applications menu") },
73 { "WindowListKey", N_("Open window list menu") },
74 { "WindowMenuKey", N_("Open window commands menu") },
75 { "HideKey", N_("Hide active application") },
76 { "HideOthersKey", N_("Hide other applications") },
77 { "MiniaturizeKey", N_("Miniaturize active window") },
78 { "MinimizeAllKey", N_("Miniaturize all windows") },
79 { "CloseKey", N_("Close active window") },
80 { "MaximizeKey", N_("Maximize active window") },
81 { "VMaximizeKey", N_("Maximize active window vertically") },
82 { "HMaximizeKey", N_("Maximize active window horizontally") },
83 { "LHMaximizeKey", N_("Maximize active window left half") },
84 { "RHMaximizeKey", N_("Maximize active window right half") },
85 { "THMaximizeKey", N_("Maximize active window top half") },
86 { "BHMaximizeKey", N_("Maximize active window bottom half") },
87 { "TLCMaximizeKey", N_("Maximize active window top left corner") },
88 { "TRCMaximizeKey", N_("Maximize active window top right corner") },
89 { "BLCMaximizeKey", N_("Maximize active window bottom left corner") },
90 { "BRCMaximizeKey", N_("Maximize active window bottom right corner") },
91 { "MaximusKey", N_("Tile active window") },
92 { "CenterKey", N_("Center active window") },
93 { "KeepOnTopKey", N_("Toggle window on top status") },
94 { "KeepAtBottomKey",N_("Toggle window at bottom status") },
95 { "OmnipresentKey", N_("Toggle window omnipresent status") },
96 { "RaiseKey", N_("Raise active window") },
97 { "LowerKey", N_("Lower active window") },
98 { "RaiseLowerKey", N_("Raise/Lower window under mouse pointer") },
99 { "ShadeKey", N_("Shade active window") },
100 { "MoveResizeKey", N_("Move/Resize active window") },
101 { "SelectKey", N_("Select active window") },
102 { "FocusNextKey", N_("Focus next window") },
103 { "FocusPrevKey", N_("Focus previous window") },
104 { "GroupNextKey", N_("Focus next group window") },
105 { "GroupPrevKey", N_("Focus previous group window") },
107 /* Workspace Related */
108 { "WorkspaceMapKey", N_("Open workspace pager") },
109 { "NextWorkspaceKey", N_("Switch to next workspace") },
110 { "PrevWorkspaceKey", N_("Switch to previous workspace") },
111 { "LastWorkspaceKey", N_("Switch to last used workspace") },
112 { "NextWorkspaceLayerKey", N_("Switch to next ten workspaces") },
113 { "PrevWorkspaceLayerKey", N_("Switch to previous ten workspaces") },
114 { "Workspace1Key", N_("Switch to workspace 1") },
115 { "Workspace2Key", N_("Switch to workspace 2") },
116 { "Workspace3Key", N_("Switch to workspace 3") },
117 { "Workspace4Key", N_("Switch to workspace 4") },
118 { "Workspace5Key", N_("Switch to workspace 5") },
119 { "Workspace6Key", N_("Switch to workspace 6") },
120 { "Workspace7Key", N_("Switch to workspace 7") },
121 { "Workspace8Key", N_("Switch to workspace 8") },
122 { "Workspace9Key", N_("Switch to workspace 9") },
123 { "Workspace10Key", N_("Switch to workspace 10") },
124 { "MoveToNextWorkspaceKey", N_("Move window to next workspace") },
125 { "MoveToPrevWorkspaceKey", N_("Move window to previous workspace") },
126 { "MoveToLastWorkspaceKey", N_("Move window to last used workspace") },
127 { "MoveToNextWorkspaceLayerKey", N_("Move window to next ten workspaces") },
128 { "MoveToPrevWorkspaceLayerKey", N_("Move window to previous ten workspaces") },
129 { "MoveToWorkspace1Key", N_("Move window to workspace 1") },
130 { "MoveToWorkspace2Key", N_("Move window to workspace 2") },
131 { "MoveToWorkspace3Key", N_("Move window to workspace 3") },
132 { "MoveToWorkspace4Key", N_("Move window to workspace 4") },
133 { "MoveToWorkspace5Key", N_("Move window to workspace 5") },
134 { "MoveToWorkspace6Key", N_("Move window to workspace 6") },
135 { "MoveToWorkspace7Key", N_("Move window to workspace 7") },
136 { "MoveToWorkspace8Key", N_("Move window to workspace 8") },
137 { "MoveToWorkspace9Key", N_("Move window to workspace 9") },
138 { "MoveToWorkspace10Key", N_("Move window to workspace 10") },
140 /* Window Selection */
141 { "WindowShortcut1Key", N_("Shortcut for window 1") },
142 { "WindowShortcut2Key", N_("Shortcut for window 2") },
143 { "WindowShortcut3Key", N_("Shortcut for window 3") },
144 { "WindowShortcut4Key", N_("Shortcut for window 4") },
145 { "WindowShortcut5Key", N_("Shortcut for window 5") },
146 { "WindowShortcut6Key", N_("Shortcut for window 6") },
147 { "WindowShortcut7Key", N_("Shortcut for window 7") },
148 { "WindowShortcut8Key", N_("Shortcut for window 8") },
149 { "WindowShortcut9Key", N_("Shortcut for window 9") },
150 { "WindowShortcut10Key", N_("Shortcut for window 10") },
152 /* Head Selection */
153 { "MoveTo12to6Head", N_("Move to right/bottom/left/top head") },
154 { "MoveTo6to12Head", N_("Move to left/top/right/bottom head") },
156 /* Misc. */
157 { "WindowRelaunchKey", N_("Launch new instance of application") },
158 { "ScreenSwitchKey", N_("Switch to next screen/monitor") },
159 { "RunKey", N_("Run application") },
160 { "ExitKey", N_("Exit Window Maker") },
161 { "DockRaiseLowerKey", N_("Raise/Lower Dock") },
162 { "ClipRaiseLowerKey", N_("Raise/Lower Clip") },
163 { "ScreenCaptureKey", N_("Capture the entire screen") },
164 { "WindowCaptureKey", N_("Capture a window") },
165 { "PartialCaptureKey", N_("Capture a portion of the screen") }
166 #ifdef XKB_MODELOCK
167 ,{ "ToggleKbdModeKey", N_("Toggle keyboard language") }
168 #endif /* XKB_MODELOCK */
171 #ifndef HAVE_XCONVERTCASE
172 /* from Xlib */
174 static void XConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
176 *lower = sym;
177 *upper = sym;
178 switch (sym >> 8) {
179 case 0: /* Latin 1 */
180 if ((sym >= XK_A) && (sym <= XK_Z))
181 *lower += (XK_a - XK_A);
182 else if ((sym >= XK_a) && (sym <= XK_z))
183 *upper -= (XK_a - XK_A);
184 else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
185 *lower += (XK_agrave - XK_Agrave);
186 else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
187 *upper -= (XK_agrave - XK_Agrave);
188 else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
189 *lower += (XK_oslash - XK_Ooblique);
190 else if ((sym >= XK_oslash) && (sym <= XK_thorn))
191 *upper -= (XK_oslash - XK_Ooblique);
192 break;
193 case 1: /* Latin 2 */
194 /* Assume the KeySym is a legal value (ignore discontinuities) */
195 if (sym == XK_Aogonek)
196 *lower = XK_aogonek;
197 else if (sym >= XK_Lstroke && sym <= XK_Sacute)
198 *lower += (XK_lstroke - XK_Lstroke);
199 else if (sym >= XK_Scaron && sym <= XK_Zacute)
200 *lower += (XK_scaron - XK_Scaron);
201 else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
202 *lower += (XK_zcaron - XK_Zcaron);
203 else if (sym == XK_aogonek)
204 *upper = XK_Aogonek;
205 else if (sym >= XK_lstroke && sym <= XK_sacute)
206 *upper -= (XK_lstroke - XK_Lstroke);
207 else if (sym >= XK_scaron && sym <= XK_zacute)
208 *upper -= (XK_scaron - XK_Scaron);
209 else if (sym >= XK_zcaron && sym <= XK_zabovedot)
210 *upper -= (XK_zcaron - XK_Zcaron);
211 else if (sym >= XK_Racute && sym <= XK_Tcedilla)
212 *lower += (XK_racute - XK_Racute);
213 else if (sym >= XK_racute && sym <= XK_tcedilla)
214 *upper -= (XK_racute - XK_Racute);
215 break;
216 case 2: /* Latin 3 */
217 /* Assume the KeySym is a legal value (ignore discontinuities) */
218 if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
219 *lower += (XK_hstroke - XK_Hstroke);
220 else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
221 *lower += (XK_gbreve - XK_Gbreve);
222 else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
223 *upper -= (XK_hstroke - XK_Hstroke);
224 else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
225 *upper -= (XK_gbreve - XK_Gbreve);
226 else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
227 *lower += (XK_cabovedot - XK_Cabovedot);
228 else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
229 *upper -= (XK_cabovedot - XK_Cabovedot);
230 break;
231 case 3: /* Latin 4 */
232 /* Assume the KeySym is a legal value (ignore discontinuities) */
233 if (sym >= XK_Rcedilla && sym <= XK_Tslash)
234 *lower += (XK_rcedilla - XK_Rcedilla);
235 else if (sym >= XK_rcedilla && sym <= XK_tslash)
236 *upper -= (XK_rcedilla - XK_Rcedilla);
237 else if (sym == XK_ENG)
238 *lower = XK_eng;
239 else if (sym == XK_eng)
240 *upper = XK_ENG;
241 else if (sym >= XK_Amacron && sym <= XK_Umacron)
242 *lower += (XK_amacron - XK_Amacron);
243 else if (sym >= XK_amacron && sym <= XK_umacron)
244 *upper -= (XK_amacron - XK_Amacron);
245 break;
246 case 6: /* Cyrillic */
247 /* Assume the KeySym is a legal value (ignore discontinuities) */
248 if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
249 *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
250 else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
251 *upper += (XK_Serbian_DJE - XK_Serbian_dje);
252 else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
253 *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
254 else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
255 *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
256 break;
257 case 7: /* Greek */
258 /* Assume the KeySym is a legal value (ignore discontinuities) */
259 if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
260 *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
261 else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
262 sym != XK_Greek_iotaaccentdieresis && sym != XK_Greek_upsilonaccentdieresis)
263 *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
264 else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
265 *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
266 else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && sym != XK_Greek_finalsmallsigma)
267 *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
268 break;
269 case 0x14: /* Armenian */
270 if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
271 *lower = sym | 1;
272 *upper = sym & ~1;
274 break;
277 #endif
279 static int NumLockMask(Display *dpy)
281 int i, mask;
282 XModifierKeymap *map;
283 static int mask_table[8] = {
284 ShiftMask, LockMask, ControlMask, Mod1Mask,
285 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
287 KeyCode numlock_keycode = XKeysymToKeycode(dpy, XK_Num_Lock);
289 if (numlock_keycode == NoSymbol)
290 return 0;
292 map = XGetModifierMapping(dpy);
293 if (!map)
294 return 0;
296 mask = 0;
297 for (i = 0; i < 8 * map->max_keypermod; i++) {
298 if (map->modifiermap[i] == numlock_keycode && mask == 0) {
299 mask = mask_table[i/map->max_keypermod];
300 break;
304 if (map)
305 XFreeModifiermap(map);
307 return mask;
310 char *capture_shortcut(Display *dpy, Bool *capturing, Bool convert_case)
312 XEvent ev;
313 KeySym ksym, lksym, uksym;
314 char buffer[64];
315 char *key = NULL;
316 unsigned int numlock_mask;
318 while (*capturing) {
319 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
320 WMNextEvent(dpy, &ev);
321 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
322 numlock_mask = NumLockMask(dpy);
324 /* conditional mask check to get numeric keypad keys */
325 ksym = W_KeycodeToKeysym(dpy, ev.xkey.keycode, ev.xkey.state & numlock_mask?1:0);
327 if (!IsModifierKey(ksym)) {
328 if (convert_case) {
329 XConvertCase(ksym, &lksym, &uksym);
330 key = XKeysymToString(uksym);
331 } else {
332 key = XKeysymToString(ksym);
335 *capturing = 0;
336 break;
339 WMHandleEvent(&ev);
342 if (!key)
343 return NULL;
345 buffer[0] = 0;
347 if (ev.xkey.state & ControlMask)
348 strcat(buffer, "Control+");
350 if (ev.xkey.state & ShiftMask)
351 strcat(buffer, "Shift+");
353 if ((numlock_mask != Mod1Mask) && (ev.xkey.state & Mod1Mask))
354 strcat(buffer, "Mod1+");
356 if ((numlock_mask != Mod2Mask) && (ev.xkey.state & Mod2Mask))
357 strcat(buffer, "Mod2+");
359 if ((numlock_mask != Mod3Mask) && (ev.xkey.state & Mod3Mask))
360 strcat(buffer, "Mod3+");
362 if ((numlock_mask != Mod4Mask) && (ev.xkey.state & Mod4Mask))
363 strcat(buffer, "Mod4+");
365 if ((numlock_mask != Mod5Mask) && (ev.xkey.state & Mod5Mask))
366 strcat(buffer, "Mod5+");
368 wstrlcat(buffer, key, sizeof(buffer));
370 return wstrdup(buffer);
374 * check if the keystr entered is already set to another action
375 * if found it returns the position in the keyOptions
377 static int isKeySet(_Panel *panel, char *keystr)
379 int i;
380 char *str;
382 for (i = 0; i < panel->actionCount; i++) {
383 str = NULL;
384 if (panel->shortcuts[i]) {
385 str = wtrimspace(panel->shortcuts[i]);
386 if (strlen(str) == 0) {
387 wfree(str);
388 str = NULL;
391 if (str) {
392 if (strcmp(keystr, str) == 0) {
393 wfree(str);
394 return i;
396 wfree(str);
400 return -1;
403 static void captureClick(WMWidget * w, void *data)
405 _Panel *panel = (_Panel *) data;
406 Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
407 char *shortcut;
409 if (!panel->capturing) {
410 panel->capturing = 1;
411 WMSetButtonText(w, _("Cancel"));
412 WMSetLabelText(panel->instructionsL,
413 _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
414 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
415 shortcut = capture_shortcut(dpy, &panel->capturing, 1);
416 if (shortcut) {
417 int key_idx = -1;
418 int row = WMGetListSelectedItemRow(panel->actLs);
420 key_idx = isKeySet(panel, shortcut);
421 if (key_idx >= 0 && (key_idx != row)) {
422 char *msg;
424 msg = wstrconcat(_("Key shortcut already in use by the "), _(keyOptions[key_idx].title));
425 WMRunAlertPanel(WMWidgetScreen(w), GetWindow(),
426 _("Error"),
427 msg,
428 _("OK"), NULL, NULL);
429 wfree(msg);
430 wfree(shortcut);
431 } else {
432 WMSetTextFieldText(panel->shoT, shortcut);
433 if (row >= 0) {
434 if (panel->shortcuts[row])
435 wfree(panel->shortcuts[row]);
436 panel->shortcuts[row] = shortcut;
438 WMRedisplayWidget(panel->actLs);
439 } else {
440 wfree(shortcut);
445 panel->capturing = 0;
446 WMSetButtonText(w, _("Capture"));
447 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
448 XUngrabKeyboard(dpy, CurrentTime);
451 static void clearShortcut(WMWidget * w, void *data)
453 _Panel *panel = (_Panel *) data;
454 int row = WMGetListSelectedItemRow(panel->actLs);
456 /* Parameter not used, but tell the compiler that it is ok */
457 (void) w;
459 WMSetTextFieldText(panel->shoT, NULL);
461 if (row >= 0) {
462 if (panel->shortcuts[row])
463 wfree(panel->shortcuts[row]);
464 panel->shortcuts[row] = NULL;
465 WMRedisplayWidget(panel->actLs);
469 static void typedKeys(void *observerData, WMNotification * notification)
471 _Panel *panel = (_Panel *) observerData;
472 int row = WMGetListSelectedItemRow(panel->actLs);
474 /* Parameter not used, but tell the compiler that it is ok */
475 (void) notification;
477 if (row < 0)
478 return;
480 if (panel->shortcuts[row])
481 wfree(panel->shortcuts[row]);
482 panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
483 if (strlen(panel->shortcuts[row]) == 0) {
484 wfree(panel->shortcuts[row]);
485 panel->shortcuts[row] = NULL;
487 WMRedisplayWidget(panel->actLs);
490 static void listClick(WMWidget * w, void *data)
492 _Panel *panel = (_Panel *) data;
493 int row = WMGetListSelectedItemRow(w);
495 WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
498 static void showData(_Panel * panel)
500 char *str;
501 int i;
503 for (i = 0; i < panel->actionCount; i++) {
505 str = GetStringForKey(keyOptions[i].key);
506 if (panel->shortcuts[i])
507 wfree(panel->shortcuts[i]);
508 if (str)
509 panel->shortcuts[i] = wtrimspace(str);
510 else
511 panel->shortcuts[i] = NULL;
513 if (panel->shortcuts[i] &&
514 (strcasecmp(panel->shortcuts[i], "none") == 0 || strlen(panel->shortcuts[i]) == 0)) {
515 wfree(panel->shortcuts[i]);
516 panel->shortcuts[i] = NULL;
519 WMRedisplayWidget(panel->actLs);
522 static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
524 int width, height, x, y;
525 _Panel *panel = (_Panel *) WMGetHangedData(lPtr);
526 WMScreen *scr = WMWidgetScreen(lPtr);
527 Display *dpy = WMScreenDisplay(scr);
528 WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
530 width = rect->size.width;
531 height = rect->size.height;
532 x = rect->pos.x;
533 y = rect->pos.y;
535 XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
537 if (panel->shortcuts[index]) {
538 WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
539 WMSize size = WMGetPixmapSize(pix);
541 WMDrawPixmap(pix, d, x + (20 - size.width) / 2, (height - size.height) / 2 + y);
542 WMReleasePixmap(pix);
545 WMDrawString(scr, d, panel->black, panel->font, x + 20, y, text, strlen(text));
548 static int cmpKeyOptions(const void *v1, const void *v2)
550 int rc;
551 const struct keyOption *opt1 = (struct keyOption *)v1;
552 const struct keyOption *opt2 = (struct keyOption *)v2;
554 if ((rc = strncmp(opt1->title, opt2->title, 20)) < 0)
555 return -1;
556 else if (rc > 0)
557 return 1;
558 return 0;
562 static void createPanel(Panel * p)
564 _Panel *panel = (_Panel *) p;
565 WMScreen *scr = WMWidgetScreen(panel->parent);
566 WMColor *color;
567 WMFont *boldFont;
568 int i;
570 panel->capturing = 0;
572 panel->white = WMWhiteColor(scr);
573 panel->black = WMBlackColor(scr);
574 panel->gray = WMGrayColor(scr);
575 panel->font = WMSystemFontOfSize(scr, 12);
577 panel->box = WMCreateBox(panel->parent);
578 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
580 boldFont = WMBoldSystemFontOfSize(scr, 12);
582 /* **************** Actions **************** */
583 panel->actL = WMCreateLabel(panel->box);
584 WMResizeWidget(panel->actL, 314, 20);
585 WMMoveWidget(panel->actL, 9, 9);
586 WMSetLabelFont(panel->actL, boldFont);
587 WMSetLabelText(panel->actL, _("Actions"));
588 WMSetLabelRelief(panel->actL, WRSunken);
589 WMSetLabelTextAlignment(panel->actL, WACenter);
590 color = WMDarkGrayColor(scr);
591 WMSetWidgetBackgroundColor(panel->actL, color);
592 WMReleaseColor(color);
593 WMSetLabelTextColor(panel->actL, panel->white);
595 panel->actLs = WMCreateList(panel->box);
596 WMResizeWidget(panel->actLs, 314, 191);
597 WMMoveWidget(panel->actLs, 9, 31);
598 WMSetListUserDrawProc(panel->actLs, paintItem);
599 WMHangData(panel->actLs, panel);
601 qsort(keyOptions, wlengthof(keyOptions), sizeof(keyOptions[0]), cmpKeyOptions);
602 for (i = 0; i < wlengthof(keyOptions); i++) {
603 WMAddListItem(panel->actLs, _(keyOptions[i].title));
605 WMSetListAction(panel->actLs, listClick, panel);
607 panel->actionCount = WMGetListNumberOfRows(panel->actLs);
608 panel->shortcuts = wmalloc(sizeof(char *) * panel->actionCount);
610 /***************** Shortcut ****************/
612 panel->shoF = WMCreateFrame(panel->box);
613 WMResizeWidget(panel->shoF, 178, 214);
614 WMMoveWidget(panel->shoF, 333, 8);
615 WMSetFrameTitle(panel->shoF, _("Shortcut"));
617 panel->shoT = WMCreateTextField(panel->shoF);
618 WMResizeWidget(panel->shoT, 160, 20);
619 WMMoveWidget(panel->shoT, 9, 65);
620 WMAddNotificationObserver(typedKeys, panel, WMTextDidChangeNotification, panel->shoT);
622 panel->cleB = WMCreateCommandButton(panel->shoF);
623 WMResizeWidget(panel->cleB, 75, 24);
624 WMMoveWidget(panel->cleB, 9, 95);
625 WMSetButtonText(panel->cleB, _("Clear"));
626 WMSetButtonAction(panel->cleB, clearShortcut, panel);
628 panel->defB = WMCreateCommandButton(panel->shoF);
629 WMResizeWidget(panel->defB, 75, 24);
630 WMMoveWidget(panel->defB, 94, 95);
631 WMSetButtonText(panel->defB, _("Capture"));
632 WMSetButtonAction(panel->defB, captureClick, panel);
634 panel->instructionsL = WMCreateLabel(panel->shoF);
635 WMResizeWidget(panel->instructionsL, 160, 55);
636 WMMoveWidget(panel->instructionsL, 9, 140);
637 WMSetLabelTextAlignment(panel->instructionsL, WACenter);
638 WMSetLabelWraps(panel->instructionsL, True);
639 WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
641 WMMapSubwidgets(panel->shoF);
643 WMReleaseFont(boldFont);
645 WMRealizeWidget(panel->box);
646 WMMapSubwidgets(panel->box);
648 showData(panel);
651 static void storeData(_Panel * panel)
653 int i;
654 char *str;
656 for (i = 0; i < panel->actionCount; i++) {
657 str = NULL;
658 if (panel->shortcuts[i]) {
659 str = wtrimspace(panel->shortcuts[i]);
660 if (strlen(str) == 0) {
661 wfree(str);
662 str = NULL;
665 if (str) {
666 SetStringForKey(str, keyOptions[i].key);
667 wfree(str);
668 } else {
669 SetStringForKey("None", keyOptions[i].key);
674 Panel *InitKeyboardShortcuts(WMWidget *parent)
676 _Panel *panel;
678 panel = wmalloc(sizeof(_Panel));
680 panel->sectionName = _("Keyboard Shortcut Preferences");
682 panel->description = _("Change the keyboard shortcuts for actions such\n"
683 "as changing workspaces and opening menus.");
685 panel->parent = parent;
687 panel->callbacks.createWidgets = createPanel;
688 panel->callbacks.updateDomain = storeData;
690 AddSection(panel, ICON_FILE);
692 return panel;