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