Change to the linux kernel coding style
[wmaker-crm.git] / src / switchpanel.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2004 Alfredo K. Kojima
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  *  USA.
20  */
21
22 #include "wconfig.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/time.h>
27
28 #include "WindowMaker.h"
29 #include "screen.h"
30 #include "wcore.h"
31 #include "framewin.h"
32 #include "window.h"
33 #include "defaults.h"
34 #include "switchpanel.h"
35 #include "funcs.h"
36 #include "xinerama.h"
37
38 #ifdef SHAPE
39 #include <X11/extensions/shape.h>
40
41 extern Bool wShapeSupported;
42 #endif
43
44 struct SwitchPanel {
45         WScreen *scr;
46         WMWindow *win;
47         WMFrame *iconBox;
48
49         WMArray *icons;
50         WMArray *images;
51         WMArray *windows;
52         RImage *bg;
53         int current;
54         int firstVisible;
55         int visibleCount;
56
57         WMLabel *label;
58
59         RImage *defIcon;
60
61         RImage *tileTmp;
62         RImage *tile;
63
64         WMFont *font;
65         WMColor *white;
66 };
67
68 extern WPreferences wPreferences;
69
70 #define BORDER_SPACE 10
71 #define ICON_SIZE 48
72 #define ICON_TILE_SIZE 64
73 #define LABEL_HEIGHT 25
74 #define SCREEN_BORDER_SPACING 2*20
75 #define SCROLL_STEPS (ICON_TILE_SIZE/2)
76
77 static int canReceiveFocus(WWindow * wwin)
78 {
79         if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
80                 return 0;
81         if (!wwin->flags.mapped) {
82                 if (!wwin->flags.shaded && !wwin->flags.miniaturized && !wwin->flags.hidden)
83                         return 0;
84                 else
85                         return -1;
86         }
87         if (WFLAGP(wwin, no_focusable))
88                 return 0;
89         return 1;
90 }
91
92 static void changeImage(WSwitchPanel * panel, int idecks, int selected)
93 {
94         WMFrame *icon = WMGetFromArray(panel->icons, idecks);
95         RImage *image = WMGetFromArray(panel->images, idecks);
96
97         if (!panel->bg && !panel->tile) {
98                 if (!selected)
99                         WMSetFrameRelief(icon, WRFlat);
100         }
101
102         if (image && icon) {
103                 RImage *back;
104                 int opaq = 255;
105                 RImage *tile;
106                 WMPoint pos;
107                 Pixmap p;
108
109                 if (canReceiveFocus(WMGetFromArray(panel->windows, idecks)) < 0)
110                         opaq = 50;
111
112                 pos = WMGetViewPosition(WMWidgetView(icon));
113                 back = panel->tileTmp;
114                 if (panel->bg)
115                         RCopyArea(back, panel->bg,
116                                   BORDER_SPACE + pos.x - panel->firstVisible * ICON_TILE_SIZE,
117                                   BORDER_SPACE + pos.y, back->width, back->height, 0, 0);
118                 else {
119                         RColor color;
120                         WMScreen *wscr = WMWidgetScreen(icon);
121                         color.red = 255;
122                         color.red = WMRedComponentOfColor(WMGrayColor(wscr)) >> 8;
123                         color.green = WMGreenComponentOfColor(WMGrayColor(wscr)) >> 8;
124                         color.blue = WMBlueComponentOfColor(WMGrayColor(wscr)) >> 8;
125                         RFillImage(back, &color);
126                 }
127                 if (selected) {
128                         tile = panel->tile;
129                         RCombineArea(back, tile, 0, 0, tile->width, tile->height,
130                                      (back->width - tile->width) / 2, (back->height - tile->height) / 2);
131                 }
132                 RCombineAreaWithOpaqueness(back, image, 0, 0, image->width, image->height,
133                                            (back->width - image->width) / 2, (back->height - image->height) / 2,
134                                            opaq);
135
136                 RConvertImage(panel->scr->rcontext, back, &p);
137                 XSetWindowBackgroundPixmap(dpy, WMWidgetXID(icon), p);
138                 XClearWindow(dpy, WMWidgetXID(icon));
139                 XFreePixmap(dpy, p);
140         }
141
142         if (!panel->bg && !panel->tile) {
143                 if (selected)
144                         WMSetFrameRelief(icon, WRSimple);
145         }
146 }
147
148 static RImage *scaleDownIfNeeded(RImage * image)
149 {
150         if (image && ((image->width - ICON_SIZE) > 2 || (image->height - ICON_SIZE) > 2)) {
151                 RImage *nimage;
152                 nimage = RScaleImage(image, ICON_SIZE, (image->height * ICON_SIZE / image->width));
153                 RReleaseImage(image);
154                 image = nimage;
155         }
156         return image;
157 }
158
159 static void addIconForWindow(WSwitchPanel * panel, WMWidget * parent, WWindow * wwin, int x, int y)
160 {
161         WMFrame *icon = WMCreateFrame(parent);
162         RImage *image = NULL;
163
164         WMSetFrameRelief(icon, WRFlat);
165         WMResizeWidget(icon, ICON_TILE_SIZE, ICON_TILE_SIZE);
166         WMMoveWidget(icon, x, y);
167
168         if (!WFLAGP(wwin, always_user_icon) && wwin->net_icon_image)
169                 image = RRetainImage(wwin->net_icon_image);
170
171         // Make this use a caching thing. When there are many windows,
172         // it's very likely that most of them are instances of the same thing,
173         // so caching them should get performance acceptable in these cases.
174         if (!image)
175                 image = wDefaultGetImage(panel->scr, wwin->wm_instance, wwin->wm_class);
176
177         if (!image && !panel->defIcon) {
178                 char *file = wDefaultGetIconFile(panel->scr, NULL, NULL, False);
179                 if (file) {
180                         char *path = FindImage(wPreferences.icon_path, file);
181                         if (path) {
182                                 image = RLoadImage(panel->scr->rcontext, path, 0);
183                                 wfree(path);
184                         }
185                 }
186                 if (image)
187                         panel->defIcon = scaleDownIfNeeded(image);
188                 image = NULL;
189         }
190         if (!image && panel->defIcon)
191                 image = RRetainImage(panel->defIcon);
192
193         image = scaleDownIfNeeded(image);
194
195         WMAddToArray(panel->images, image);
196         WMAddToArray(panel->icons, icon);
197 }
198
199 static void scrollIcons(WSwitchPanel * panel, int delta)
200 {
201         int nfirst = panel->firstVisible + delta;
202         int i;
203         int count = WMGetArrayItemCount(panel->windows);
204 //    int nx, ox;
205 //    struct timeval tv1, tv2;
206
207         if (count <= panel->visibleCount)
208                 return;
209
210         if (nfirst < 0)
211                 nfirst = 0;
212         else if (nfirst >= count - panel->visibleCount)
213                 nfirst = count - panel->visibleCount;
214
215         if (nfirst == panel->firstVisible)
216                 return;
217 /*
218     ox = -panel->firstVisible * ICON_TILE_SIZE;
219     nx = -nfirst * ICON_TILE_SIZE;
220     for (i= 0; i < SCROLL_STEPS; i++) {
221         unsigned int diff;
222         gettimeofday(&tv1, NULL);
223         WMMoveWidget(panel->iconBox, (nx*i + ox*(SCROLL_STEPS-i))/(SCROLL_STEPS-1), 0);
224         XSync(dpy, False);
225         gettimeofday(&tv2, NULL);
226         diff = (tv2.tv_sec-tv1.tv_sec)*10000+(tv2.tv_usec-tv1.tv_usec)/100;
227         if (diff < 200)
228           wusleep(300-diff);
229     }
230  */
231         WMMoveWidget(panel->iconBox, -nfirst * ICON_TILE_SIZE, 0);
232
233         panel->firstVisible = nfirst;
234
235         for (i = panel->firstVisible; i < panel->firstVisible + panel->visibleCount; i++) {
236                 changeImage(panel, i, i == panel->current);
237         }
238 }
239
240 /*
241  * 0 1 2
242  * 3 4 5
243  * 6 7 8
244  */
245 static RImage *assemblePuzzleImage(RImage ** images, int width, int height)
246 {
247         RImage *img = RCreateImage(width, height, 1);
248         RImage *tmp;
249         int tw, th;
250         RColor color;
251         if (!img)
252                 return NULL;
253
254         color.red = 0;
255         color.green = 0;
256         color.blue = 0;
257         color.alpha = 255;
258
259         RFillImage(img, &color);
260
261         tw = width - images[0]->width - images[2]->width;
262         th = height - images[0]->height - images[6]->height;
263
264         if (tw <= 0 || th <= 0) {
265                 //XXX
266                 return NULL;
267         }
268
269         /* top */
270         if (tw > 0) {
271                 tmp = RSmoothScaleImage(images[1], tw, images[1]->height);
272                 RCopyArea(img, tmp, 0, 0, tmp->width, tmp->height, images[0]->width, 0);
273                 RReleaseImage(tmp);
274         }
275         /* bottom */
276         if (tw > 0) {
277                 tmp = RSmoothScaleImage(images[7], tw, images[7]->height);
278                 RCopyArea(img, tmp, 0, 0, tmp->width, tmp->height, images[6]->width, height - images[6]->height);
279                 RReleaseImage(tmp);
280         }
281         /* left */
282         if (th > 0) {
283                 tmp = RSmoothScaleImage(images[3], images[3]->width, th);
284                 RCopyArea(img, tmp, 0, 0, tmp->width, tmp->height, 0, images[0]->height);
285                 RReleaseImage(tmp);
286         }
287         /* right */
288         if (th > 0) {
289                 tmp = RSmoothScaleImage(images[5], images[5]->width, th);
290                 RCopyArea(img, tmp, 0, 0, tmp->width, tmp->height, width - images[5]->width, images[2]->height);
291                 RReleaseImage(tmp);
292         }
293         /* center */
294         if (tw > 0 && th > 0) {
295                 tmp = RSmoothScaleImage(images[4], tw, th);
296                 RCopyArea(img, tmp, 0, 0, tmp->width, tmp->height, images[0]->width, images[0]->height);
297                 RReleaseImage(tmp);
298         }
299
300         /* corners */
301         RCopyArea(img, images[0], 0, 0, images[0]->width, images[0]->height, 0, 0);
302
303         RCopyArea(img, images[2], 0, 0, images[2]->width, images[2]->height, width - images[2]->width, 0);
304
305         RCopyArea(img, images[6], 0, 0, images[6]->width, images[6]->height, 0, height - images[6]->height);
306
307         RCopyArea(img, images[8], 0, 0, images[8]->width, images[8]->height,
308                   width - images[8]->width, height - images[8]->height);
309
310         return img;
311 }
312
313 static RImage *createBackImage(WScreen * scr, int width, int height)
314 {
315         return assemblePuzzleImage(wPreferences.swbackImage, width, height);
316 }
317
318 static RImage *getTile(WSwitchPanel * panel)
319 {
320         RImage *stile;
321
322         if (!wPreferences.swtileImage)
323                 return NULL;
324
325         stile = RScaleImage(wPreferences.swtileImage, ICON_TILE_SIZE, ICON_TILE_SIZE);
326         if (!stile)
327                 return wPreferences.swtileImage;
328
329         return stile;
330 }
331
332 static void drawTitle(WSwitchPanel * panel, int idecks, char *title)
333 {
334         char *ntitle;
335         int width = WMWidgetWidth(panel->win);
336         int x;
337
338         if (title)
339                 ntitle = ShrinkString(panel->font, title, width - 2 * BORDER_SPACE);
340         else
341                 ntitle = NULL;
342
343         if (panel->bg) {
344                 if (ntitle) {
345                         if (strcmp(ntitle, title) != 0)
346                                 x = BORDER_SPACE;
347                         else {
348                                 int w = WMWidthOfString(panel->font, ntitle, strlen(ntitle));
349
350                                 x = BORDER_SPACE + (idecks - panel->firstVisible) * ICON_TILE_SIZE +
351                                     ICON_TILE_SIZE / 2 - w / 2;
352                                 if (x < BORDER_SPACE)
353                                         x = BORDER_SPACE;
354                                 else if (x + w > width - BORDER_SPACE)
355                                         x = width - BORDER_SPACE - w;
356                         }
357                 }
358                 XClearWindow(dpy, WMWidgetXID(panel->win));
359                 if (ntitle)
360                         WMDrawString(panel->scr->wmscreen,
361                                      WMWidgetXID(panel->win),
362                                      panel->white, panel->font,
363                                      x,
364                                      WMWidgetHeight(panel->win) - BORDER_SPACE - LABEL_HEIGHT +
365                                      WMFontHeight(panel->font) / 2, ntitle, strlen(ntitle));
366         } else {
367                 if (ntitle)
368                         WMSetLabelText(panel->label, ntitle);
369         }
370         if (ntitle)
371                 free(ntitle);
372 }
373
374 static WMArray *makeWindowListArray(WScreen * scr, WWindow * curwin, int workspace, int include_unmapped)
375 {
376         WMArray *windows = WMCreateArray(10);
377         int fl;
378         WWindow *wwin;
379
380         for (fl = 0; fl < 2; fl++) {
381                 for (wwin = curwin; wwin; wwin = wwin->prev) {
382                         if (((!fl && canReceiveFocus(wwin) > 0) || (fl && canReceiveFocus(wwin) < 0)) &&
383                             (!WFLAGP(wwin, skip_window_list) || wwin->flags.internal_window) &&
384                             (wwin->flags.mapped || include_unmapped)) {
385                                 WMAddToArray(windows, wwin);
386                         }
387                 }
388                 wwin = curwin;
389                 /* start over from the beginning of the list */
390                 while (wwin->next)
391                         wwin = wwin->next;
392
393                 for (wwin = curwin; wwin && wwin != curwin; wwin = wwin->prev) {
394                         if (((!fl && canReceiveFocus(wwin) > 0) || (fl && canReceiveFocus(wwin) < 0)) &&
395                             (!WFLAGP(wwin, skip_window_list) || wwin->flags.internal_window) &&
396                             (wwin->flags.mapped || include_unmapped)) {
397                                 WMAddToArray(windows, wwin);
398                         }
399                 }
400         }
401
402         return windows;
403 }
404
405 WSwitchPanel *wInitSwitchPanel(WScreen * scr, WWindow * curwin, int workspace)
406 {
407         WWindow *wwin;
408         WSwitchPanel *panel = wmalloc(sizeof(WSwitchPanel));
409         WMFrame *viewport;
410         int i;
411         int width, height;
412         int iconsThatFitCount;
413         int count;
414         WMRect rect;
415         rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
416
417         memset(panel, 0, sizeof(WSwitchPanel));
418
419         panel->scr = scr;
420
421         panel->windows = makeWindowListArray(scr, curwin, workspace, wPreferences.swtileImage != 0);
422         count = WMGetArrayItemCount(panel->windows);
423
424         if (count == 0) {
425                 WMFreeArray(panel->windows);
426                 wfree(panel);
427                 return NULL;
428         }
429
430         width = ICON_TILE_SIZE * count;
431         iconsThatFitCount = count;
432
433         if (width > rect.size.width) {
434                 iconsThatFitCount = (rect.size.width - SCREEN_BORDER_SPACING) / ICON_TILE_SIZE;
435                 width = iconsThatFitCount * ICON_TILE_SIZE;
436         }
437
438         panel->visibleCount = iconsThatFitCount;
439
440         if (!wPreferences.swtileImage)
441                 return panel;
442
443         height = LABEL_HEIGHT + ICON_TILE_SIZE;
444
445         panel->tileTmp = RCreateImage(ICON_TILE_SIZE, ICON_TILE_SIZE, 1);
446         panel->tile = getTile(panel);
447         if (panel->tile && wPreferences.swbackImage[8]) {
448                 panel->bg = createBackImage(scr, width + 2 * BORDER_SPACE, height + 2 * BORDER_SPACE);
449         }
450         if (!panel->tileTmp || !panel->tile) {
451                 if (panel->bg)
452                         RReleaseImage(panel->bg);
453                 panel->bg = NULL;
454                 if (panel->tile)
455                         RReleaseImage(panel->tile);
456                 panel->tile = NULL;
457                 if (panel->tileTmp)
458                         RReleaseImage(panel->tileTmp);
459                 panel->tileTmp = NULL;
460         }
461
462         panel->white = WMWhiteColor(scr->wmscreen);
463         panel->font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
464         panel->icons = WMCreateArray(count);
465         panel->images = WMCreateArray(count);
466
467         panel->win = WMCreateWindow(scr->wmscreen, "");
468
469         if (!panel->bg) {
470                 WMFrame *frame = WMCreateFrame(panel->win);
471                 WMColor *darkGray = WMDarkGrayColor(scr->wmscreen);
472                 WMSetFrameRelief(frame, WRSimple);
473                 WMSetViewExpandsToParent(WMWidgetView(frame), 0, 0, 0, 0);
474
475                 panel->label = WMCreateLabel(panel->win);
476                 WMResizeWidget(panel->label, width, LABEL_HEIGHT);
477                 WMMoveWidget(panel->label, BORDER_SPACE, BORDER_SPACE + ICON_TILE_SIZE + 5);
478                 WMSetLabelRelief(panel->label, WRSimple);
479                 WMSetWidgetBackgroundColor(panel->label, darkGray);
480                 WMSetLabelFont(panel->label, panel->font);
481                 WMSetLabelTextColor(panel->label, panel->white);
482
483                 WMReleaseColor(darkGray);
484                 height += 5;
485         }
486
487         WMResizeWidget(panel->win, width + 2 * BORDER_SPACE, height + 2 * BORDER_SPACE);
488
489         viewport = WMCreateFrame(panel->win);
490         WMResizeWidget(viewport, width, ICON_TILE_SIZE);
491         WMMoveWidget(viewport, BORDER_SPACE, BORDER_SPACE);
492         WMSetFrameRelief(viewport, WRFlat);
493
494         panel->iconBox = WMCreateFrame(viewport);
495         WMMoveWidget(panel->iconBox, 0, 0);
496         WMResizeWidget(panel->iconBox, ICON_TILE_SIZE * count, ICON_TILE_SIZE);
497         WMSetFrameRelief(panel->iconBox, WRFlat);
498
499         WM_ITERATE_ARRAY(panel->windows, wwin, i) {
500                 addIconForWindow(panel, panel->iconBox, wwin, i * ICON_TILE_SIZE, 0);
501         }
502
503         WMMapSubwidgets(panel->win);
504         WMRealizeWidget(panel->win);
505
506         WM_ITERATE_ARRAY(panel->windows, wwin, i) {
507                 changeImage(panel, i, 0);
508         }
509
510         if (panel->bg) {
511                 Pixmap pixmap, mask;
512
513                 RConvertImageMask(scr->rcontext, panel->bg, &pixmap, &mask, 250);
514
515                 XSetWindowBackgroundPixmap(dpy, WMWidgetXID(panel->win), pixmap);
516
517 #ifdef SHAPE
518                 if (mask && wShapeSupported)
519                         XShapeCombineMask(dpy, WMWidgetXID(panel->win), ShapeBounding, 0, 0, mask, ShapeSet);
520 #endif
521
522                 if (pixmap)
523                         XFreePixmap(dpy, pixmap);
524                 if (mask)
525                         XFreePixmap(dpy, mask);
526         }
527
528         {
529                 WMPoint center;
530                 center = wGetPointToCenterRectInHead(scr, wGetHeadForPointerLocation(scr),
531                                                      width + 2 * BORDER_SPACE, height + 2 * BORDER_SPACE);
532                 WMMoveWidget(panel->win, center.x, center.y);
533         }
534
535         panel->current = WMGetFirstInArray(panel->windows, curwin);
536         if (panel->current >= 0)
537                 changeImage(panel, panel->current, 1);
538
539         WMMapWidget(panel->win);
540
541         return panel;
542 }
543
544 void wSwitchPanelDestroy(WSwitchPanel * panel)
545 {
546         int i;
547         RImage *image;
548
549         if (panel->win)
550                 WMUnmapWidget(panel->win);
551
552         if (panel->images) {
553                 WM_ITERATE_ARRAY(panel->images, image, i) {
554                         if (image)
555                                 RReleaseImage(image);
556                 }
557                 WMFreeArray(panel->images);
558         }
559         if (panel->win)
560                 WMDestroyWidget(panel->win);
561         if (panel->icons)
562                 WMFreeArray(panel->icons);
563         WMFreeArray(panel->windows);
564         if (panel->defIcon)
565                 RReleaseImage(panel->defIcon);
566         if (panel->tile)
567                 RReleaseImage(panel->tile);
568         if (panel->tileTmp)
569                 RReleaseImage(panel->tileTmp);
570         if (panel->bg)
571                 RReleaseImage(panel->bg);
572         if (panel->font)
573                 WMReleaseFont(panel->font);
574         if (panel->white)
575                 WMReleaseColor(panel->white);
576         wfree(panel);
577 }
578
579 WWindow *wSwitchPanelSelectNext(WSwitchPanel * panel, int back)
580 {
581         WWindow *wwin;
582         int count = WMGetArrayItemCount(panel->windows);
583
584         if (count == 0)
585                 return NULL;
586
587         if (panel->win)
588                 changeImage(panel, panel->current, 0);
589
590         if (back)
591                 panel->current--;
592         else
593                 panel->current++;
594
595         wwin = WMGetFromArray(panel->windows, (count + panel->current) % count);
596
597         if (back) {
598                 if (panel->current < 0)
599                         scrollIcons(panel, count);
600                 else if (panel->current < panel->firstVisible)
601                         scrollIcons(panel, -1);
602         } else {
603                 if (panel->current >= count)
604                         scrollIcons(panel, -count);
605                 else if (panel->current - panel->firstVisible >= panel->visibleCount)
606                         scrollIcons(panel, 1);
607         }
608
609         panel->current = (count + panel->current) % count;
610
611         if (panel->win) {
612                 drawTitle(panel, panel->current, wwin->frame->title);
613
614                 changeImage(panel, panel->current, 1);
615         }
616
617         return wwin;
618 }
619
620 WWindow *wSwitchPanelSelectFirst(WSwitchPanel * panel, int back)
621 {
622         WWindow *wwin;
623         int count = WMGetArrayItemCount(panel->windows);
624
625         if (count == 0)
626                 return NULL;
627
628         if (panel->win)
629                 changeImage(panel, panel->current, 0);
630
631         if (back) {
632                 panel->current = count - 1;
633                 scrollIcons(panel, count);
634         } else {
635                 panel->current = 0;
636                 scrollIcons(panel, -count);
637         }
638
639         wwin = WMGetFromArray(panel->windows, panel->current);
640
641         if (panel->win) {
642                 drawTitle(panel, panel->current, wwin->frame->title);
643
644                 changeImage(panel, panel->current, 1);
645         }
646         return wwin;
647 }
648
649 WWindow *wSwitchPanelHandleEvent(WSwitchPanel * panel, XEvent * event)
650 {
651         WMFrame *icon;
652         int i;
653         int focus = -1;
654
655         if (!panel->win)
656                 return NULL;
657
658         /*   if (event->type == LeaveNotify) {
659            if (event->xcrossing.window == WMWidgetXID(panel->win))
660            focus= 0;
661            } else */ if (event->type == MotionNotify) {
662
663                 WM_ITERATE_ARRAY(panel->icons, icon, i) {
664                         if (WMWidgetXID(icon) == event->xmotion.window) {
665                                 focus = i;
666                                 break;
667                         }
668                 }
669         }
670         if (focus >= 0 && panel->current != focus) {
671                 WWindow *wwin;
672
673                 changeImage(panel, panel->current, 0);
674                 changeImage(panel, focus, 1);
675                 panel->current = focus;
676
677                 wwin = WMGetFromArray(panel->windows, focus);
678
679                 drawTitle(panel, panel->current, wwin->frame->title);
680
681                 return wwin;
682         }
683
684         return NULL;
685 }
686
687 Window wSwitchPanelGetWindow(WSwitchPanel * swpanel)
688 {
689         if (!swpanel->win)
690                 return None;
691         return WMWidgetXID(swpanel->win);
692 }