chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / buttons.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "aclass.h"
26 #include "buttons.h"
27 #include "cursors.h"
28 #include "desktops.h"
29 #include "e16-ecore_list.h"
30 #include "eimage.h"
31 #include "emodule.h"
32 #include "file.h"
33 #include "grabs.h"
34 #include "iclass.h"
35 #include "tclass.h"
36 #include "tooltips.h"
37 #include "xwin.h"
38
39 #define BUTTON_EVENT_MASK \
40   (KeyPressMask | KeyReleaseMask | \
41    ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | \
42    PointerMotionMask)
43
44 typedef struct {
45    int                 width_min, width_max;
46    int                 height_min, height_max;
47    int                 xorigin, yorigin;
48    int                 xabs, xrel;
49    int                 yabs, yrel;
50    int                 xsizerel, xsizeabs;
51    int                 ysizerel, ysizeabs;
52    char                size_from_image;
53 } BGeometry;
54
55 struct _button {
56    EObj                o;
57    BGeometry           geom;
58    ImageClass         *iclass;
59    ActionClass        *aclass;
60    TextClass          *tclass;
61    char               *label;
62    int                 id;
63    int                 flags;
64    char                internal;
65    char                default_show;
66    EObj               *owner;
67    ButtonCbFunc       *func;
68
69    int                 state;
70    Window              inside_win;
71    Window              event_win;
72    char                left;
73    unsigned int        ref_count;
74 };
75
76 static Ecore_List  *button_list = NULL;
77
78 static struct {
79    Button             *button;
80    char                loading_user;
81    char                move_pending;
82    char                action_inhibit;
83    int                 start_x, start_y;
84 } Mode_buttons;
85
86 static void         ButtonHandleEvents(Win win, XEvent * ev, void *btn);
87
88 #if 0                           /* Unused */
89 void
90 ButtonIncRefcount(Button * b)
91 {
92    b->ref_count++;
93 }
94
95 void
96 ButtonDecRefcount(Button * b)
97 {
98    b->ref_count--;
99 }
100 #endif
101
102 static int
103 ButtonIsFixed(const Button * b)
104 {
105    return b->flags & FLAG_FIXED;
106 }
107
108 static int
109 ButtonIsInternal(const Button * b)
110 {
111    return b->internal;
112 }
113
114 Button             *
115 ButtonCreate(const char *name, int id, const char *iclass,
116              const char *aclass, const char *tclass, const char *label,
117              int ontop, int flags, int minw, int maxw, int minh, int maxh,
118              int xo, int yo, int xa, int xr, int ya, int yr, int xsr, int xsa,
119              int ysr, int ysa, char simg, int desk, char sticky)
120 {
121    Button             *b;
122
123    if (desk < 0 || desk >= (int)DesksGetNumber())
124       return NULL;
125
126    if (sticky && ontop == 1)
127       desk = 0;
128
129    b = ECALLOC(Button, 1);
130
131    if (!button_list)
132       button_list = ecore_list_new();
133    ecore_list_append(button_list, b);
134
135    b->id = id;
136    b->label = Estrdup(label);
137
138    b->iclass = ImageclassAlloc(iclass, 1);
139    b->aclass = ActionclassAlloc(aclass);
140    if (b->label)
141       b->tclass = TextclassAlloc(tclass, 1);
142
143    b->flags = flags;
144    b->geom.width_min = minw;
145    b->geom.width_max = maxw;
146    b->geom.height_min = minh;
147    b->geom.height_max = maxh;
148    b->geom.xorigin = xo;
149    b->geom.yorigin = yo;
150    b->geom.xabs = xa;
151    b->geom.xrel = xr;
152    b->geom.yabs = ya;
153    b->geom.yrel = yr;
154    b->geom.xsizeabs = xsa;
155    b->geom.xsizerel = xsr;
156    b->geom.ysizeabs = ysa;
157    b->geom.ysizerel = ysr;
158    b->geom.size_from_image = simg;
159    b->default_show = 1;
160
161    EoSetSticky(b, sticky);
162    EoSetDesk(b, DeskGet(desk));
163    EoInit(b, EOBJ_TYPE_BUTTON, None, -100, -100, 50, 50, 0, name);
164    EoSetLayer(b, ontop);
165    EoSetFade(b, 1);
166
167    ESelectInput(EoGetWin(b), BUTTON_EVENT_MASK);
168    EventCallbackRegister(EoGetWin(b), 0, ButtonHandleEvents, b);
169
170    return b;
171 }
172
173 void
174 ButtonDestroy(Button * b)
175 {
176    if (!b)
177       return;
178
179    if (b->ref_count > 0)
180      {
181         DialogOK("Button Error!", _("%u references remain\n"), b->ref_count);
182         return;
183      }
184
185    ecore_list_node_remove(button_list, b);
186
187    EoFini(b);
188
189    ImageclassFree(b->iclass);
190    ActionclassFree(b->aclass);
191    TextclassFree(b->tclass);
192    Efree(b->label);
193
194    Efree(b);
195 }
196
197 static int
198 _ButtonMatchName(const void *data, const void *match)
199 {
200    return strcmp(EoGetName((const Button *)data), (const char *)match);
201 }
202
203 Button             *
204 ButtonFind(const char *name)
205 {
206    return (Button *) ecore_list_find(button_list, _ButtonMatchName, name);
207 }
208
209 static void
210 ButtonCalc(Button * b)
211 {
212    int                 w, h, x, y, xo, yo;
213    EImage             *im;
214
215    x = 0;
216    y = 0;
217    w = 32;
218    h = 32;
219    if (b->geom.size_from_image)
220      {
221         im = ImageclassGetImage(b->iclass, 0, 0, 0);
222         if (im)
223           {
224              EImageGetSize(im, &w, &h);
225              EImageFree(im);
226           }
227         else
228           {
229              if (!b->iclass)
230                 b->iclass = ImageclassAlloc(NULL, 1);
231              w = 32;
232              h = 32;
233           }
234      }
235    else
236      {
237         w = ((b->geom.xsizerel * WinGetW(VROOT)) >> 10) + b->geom.xsizeabs;
238         h = ((b->geom.ysizerel * WinGetH(VROOT)) >> 10) + b->geom.ysizeabs;
239      }
240    if (w > b->geom.width_max)
241       w = b->geom.width_max;
242    else if (w < b->geom.width_min)
243       w = b->geom.width_min;
244    if (h > b->geom.height_max)
245       h = b->geom.height_max;
246    else if (h < b->geom.height_min)
247       h = b->geom.height_min;
248    xo = (w * b->geom.xorigin) >> 10;
249    yo = (h * b->geom.yorigin) >> 10;
250    x = ((b->geom.xrel * WinGetW(VROOT)) >> 10) + b->geom.xabs - xo;
251    y = ((b->geom.yrel * WinGetH(VROOT)) >> 10) + b->geom.yabs - yo;
252
253    EoMoveResize(b, x, y, w, h);
254 }
255
256 static void
257 ButtonDraw(Button * b)
258 {
259    ITApply(EoGetWin(b), b->iclass, NULL,
260            b->state, 0, 0, ST_BUTTON, b->tclass, NULL, b->label, 0);
261    EoShapeUpdate(b, 0);
262 }
263
264 #if 0                           /* Unused */
265 void
266 ButtonDrawWithState(Button * b, int state)
267 {
268    b->state = state;
269    ButtonDraw(b);
270 }
271 #endif
272
273 void
274 ButtonShow(Button * b)
275 {
276    ButtonCalc(b);
277    ButtonDraw(b);
278    EoMap(b, 0);
279 }
280
281 void
282 ButtonSwallowInto(Button * b, EObj * eo)
283 {
284    b->internal = 1;
285    b->default_show = 0;
286    b->flags |= FLAG_FIXED;
287    b->owner = eo;
288    b->ref_count++;
289    EobjReparent(EoObj(b), eo, 0, 0);
290    ButtonCalc(b);
291    ButtonDraw(b);
292    EMapWindow(EoGetWin(b));
293 }
294
295 void
296 ButtonSetCallback(Button * b, ButtonCbFunc * func, EObj * eo)
297 {
298    b->owner = eo;
299    b->func = func;
300 }
301
302 static void
303 ButtonMoveToDesktop(Button * b, Desk * dsk)
304 {
305    if (EoIsSticky(b) && EoGetLayer(b) == 1)
306       dsk = DeskGet(0);
307
308    if (!dsk)
309       return;
310
311    if (EoGetDesk(b) != dsk)
312       EoReparent(b, EoObj(dsk), EoGetX(b), EoGetY(b));
313 }
314
315 void
316 ButtonHide(Button * b)
317 {
318    EoUnmap(b);
319 }
320
321 static void
322 ButtonToggle(Button * b)
323 {
324    if (b->internal)
325       return;
326
327    if (EoIsShown(b))
328       ButtonHide(b);
329    else
330       ButtonShow(b);
331 }
332
333 void
334 ButtonMoveToCoord(Button * b, int x, int y)
335 {
336    int                 rx, ry, relx, rely, absx, absy;
337
338    if (ButtonIsFixed(b))
339       return;
340
341    if ((x + (EoGetW(b) >> 1)) < (WinGetW(VROOT) / 3))
342       relx = 0;
343    else if ((x + (EoGetW(b) >> 1)) > ((WinGetW(VROOT) * 2) / 3))
344       relx = 1024;
345    else
346       relx = 512;
347    rx = (relx * WinGetW(VROOT)) >> 10;
348    absx = x - rx;
349    if ((y + (EoGetH(b) >> 1)) < (WinGetH(VROOT) / 3))
350       rely = 0;
351    else if ((y + (EoGetH(b) >> 1)) > ((WinGetH(VROOT) * 2) / 3))
352       rely = 1024;
353    else
354       rely = 512;
355    ry = (rely * WinGetH(VROOT)) >> 10;
356    absy = y - ry;
357    if (!(b->flags & FLAG_FIXED_HORIZ))
358      {
359         b->geom.xorigin = 0;
360         b->geom.xabs = absx;
361         b->geom.xrel = relx;
362      }
363    if (!(b->flags & FLAG_FIXED_VERT))
364      {
365         b->geom.yorigin = 0;
366         b->geom.yabs = absy;
367         b->geom.yrel = rely;
368      }
369
370    ButtonCalc(b);
371 }
372
373 void
374 ButtonMoveRelative(Button * b, int dx, int dy)
375 {
376    ButtonMoveToCoord(b, EoGetX(b) + dx, EoGetY(b) + dy);
377 }
378
379 int
380 ButtonDoShowDefault(const Button * b)
381 {
382    return !b->internal && b->default_show;
383 }
384
385 #if 0                           /* Unused */
386 int
387 ButtonEmbedWindow(Button * b, Window WindowToEmbed)
388 {
389
390    int                 w, h;
391
392    EReparentWindow(WindowToEmbed, EoGetWin(b), 0, 0);
393    b->inside_win = WindowToEmbed;
394    EGetGeometry(WindowToEmbed, NULL, NULL, NULL, &w, &h, NULL, NULL);
395    EMoveWindow(b->inside_win, (EoGetW(b) - w) >> 1, (EoGetH(b) - h) >> 1);
396    b->event_win = ECreateEventWindow(EoGetWin(b), 0, 0, w, h);
397    EventCallbackRegister(b->event_win, 0, ButtonHandleEvents, b);
398
399    ESelectInput(b->event_win,
400                 ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
401                 LeaveWindowMask | ButtonMotionMask);
402
403    EMoveWindow(b->event_win, (EoGetW(b) - w) >> 1, (EoGetH(b) - h) >> 1);
404    EMapRaised(b->event_win);
405
406    return 0;
407 }
408 #endif
409
410 static void
411 ButtonDragStart(Button * b)
412 {
413    if (ButtonIsFixed(b))
414       return;
415
416    GrabPointerSet(EoGetWin(b), ECSR_GRAB, 0);
417    Mode.mode = MODE_BUTTONDRAG;
418    Mode_buttons.move_pending = 1;
419    Mode_buttons.start_x = Mode.events.cx;
420    Mode_buttons.start_y = Mode.events.cy;
421 }
422
423 static void
424 ButtonDragEnd(Button * b)
425 {
426    Desk               *dsk;
427
428    Mode.mode = MODE_NONE;
429
430    if (!Mode_buttons.move_pending)
431      {
432         dsk = DesktopAt(Mode.events.mx, Mode.events.my);
433         ButtonMoveToDesktop(b, dsk);
434         dsk = EoGetDesk(b);
435         ButtonMoveRelative(b, -EoGetX(dsk), -EoGetY(dsk));
436      }
437    else
438       Mode_buttons.move_pending = 0;
439
440    autosave();
441 }
442
443 void
444 ButtonsForeach(int id, Desk * dsk, void (*func) (Button * b))
445 {
446    Button             *b;
447
448    ECORE_LIST_FOR_EACH(button_list, b)
449    {
450       if (id >= 0 && id != b->id)
451          continue;
452       if (dsk && dsk != EoGetDesk(b))
453          continue;
454       func(b);
455    }
456 }
457
458 void
459 ButtonsMoveStickyToDesk(Desk * dsk)
460 {
461    Button             *b;
462
463    ECORE_LIST_FOR_EACH(button_list, b)
464    {
465       if (!EoIsSticky(b) || ButtonIsInternal(b))
466          continue;
467
468       ButtonMoveToDesktop(b, dsk);
469    }
470 }
471
472 /*
473  * Button event handlers
474  */
475
476 static void
477 ButtonDoAction(Button * b, XEvent * ev)
478 {
479    if (b->owner && b->func)
480       b->func(b->owner, ev, b->aclass);
481    else
482       ActionclassEvent(b->aclass, ev, NULL);
483 }
484
485 static void
486 ButtonEventMouseDown(Button * b, XEvent * ev)
487 {
488    Mode_buttons.button = b;
489
490    GrabPointerSet(EoGetWin(b), ECSR_GRAB, 0);
491
492    if (b->inside_win)
493      {
494         Window              win = ev->xbutton.window;
495
496         ev->xbutton.window = b->inside_win;
497         EXSendEvent(b->inside_win, ButtonPressMask, ev);
498         ev->xbutton.window = win;
499      }
500
501    b->state = STATE_CLICKED;
502    ButtonDraw(b);
503
504    if (!ButtonIsInternal(b))
505      {
506         ActionClass        *ac;
507
508         ac = ActionclassFind("ACTION_BUTTON_DRAG");
509         if (ac && !Mode_buttons.action_inhibit)
510            ActionclassEvent(ac, ev, NULL);
511      }
512
513    if (b->aclass && !Mode_buttons.action_inhibit)
514       ButtonDoAction(b, ev);
515 }
516
517 static void
518 ButtonEventMouseUp(Button * b, XEvent * ev)
519 {
520    if (b->inside_win && !Mode_buttons.action_inhibit)
521      {
522         Window              win = ev->xbutton.window;
523
524         ev->xbutton.window = b->inside_win;
525         EXSendEvent(b->inside_win, ButtonReleaseMask, ev);
526         ev->xbutton.window = win;
527      }
528
529    if ((b->state == STATE_CLICKED) && (!b->left))
530       b->state = STATE_HILITED;
531    else
532       b->state = STATE_NORMAL;
533    ButtonDraw(b);
534
535    GrabPointerRelease();
536
537    b->left = 0;
538
539    if (Mode.mode == MODE_BUTTONDRAG)
540       ButtonDragEnd(Mode_buttons.button);
541    Mode_buttons.button = NULL;
542
543    if (b->aclass && !b->left && !Mode_buttons.action_inhibit)
544       ButtonDoAction(b, ev);
545    Mode_buttons.action_inhibit = 0;
546 }
547
548 static void
549 ButtonEventMotion(Button * b, XEvent * ev __UNUSED__)
550 {
551    int                 dx, dy;
552
553    if (Mode.mode != MODE_BUTTONDRAG)
554       return;
555
556    dx = Mode.events.mx - Mode.events.px;
557    dy = Mode.events.my - Mode.events.py;
558
559    if (Mode_buttons.move_pending)
560      {
561         int                 x, y;
562
563         x = Mode.events.mx - Mode_buttons.start_x;
564         y = Mode.events.my - Mode_buttons.start_y;
565         if (x < 0)
566            x = -x;
567         if (y < 0)
568            y = -y;
569         if ((x > Conf.buttons.move_resistance) ||
570             (y > Conf.buttons.move_resistance))
571            Mode_buttons.move_pending = 0;
572         Mode_buttons.action_inhibit = 1;
573      }
574    if (!Mode_buttons.move_pending)
575       ButtonMoveRelative(b, dx, dy);
576 }
577
578 static void
579 ButtonEventMouseIn(Button * b, XEvent * ev)
580 {
581    if (b->state == STATE_CLICKED)
582       b->left = 0;
583    else
584      {
585         b->state = STATE_HILITED;
586         ButtonDraw(b);
587         if (b->aclass && !Mode_buttons.action_inhibit)
588            ActionclassEvent(b->aclass, ev, NULL);
589      }
590 }
591
592 static void
593 ButtonEventMouseOut(Button * b, XEvent * ev)
594 {
595    if (b->state == STATE_CLICKED)
596       b->left = 1;
597    else
598      {
599         b->state = STATE_NORMAL;
600         ButtonDraw(b);
601         if (b->aclass && !Mode_buttons.action_inhibit)
602            ActionclassEvent(b->aclass, ev, NULL);
603      }
604 }
605
606 static ActionClass *
607 ButtonGetAclass(void *data)
608 {
609    Button             *b = (Button *) data;
610
611    /* Validate button */
612    if (!ecore_list_goto(button_list, b))
613       return NULL;
614
615    return b->aclass;
616 }
617
618 static void
619 ButtonHandleEvents(Win win __UNUSED__, XEvent * ev, void *prm)
620 {
621    Button             *b = (Button *) prm;
622
623    switch (ev->type)
624      {
625      case ButtonPress:
626         ButtonEventMouseDown(b, ev);
627         break;
628      case ButtonRelease:
629         ButtonEventMouseUp(b, ev);
630         break;
631      case MotionNotify:
632         ButtonEventMotion(b, ev);
633         if (b->aclass)
634            TooltipsSetPending(0, ButtonGetAclass, b);
635         break;
636      case EnterNotify:
637         ButtonEventMouseIn(b, ev);
638         break;
639      case LeaveNotify:
640         ButtonEventMouseOut(b, ev);
641         break;
642      }
643
644    if (b->func)
645       b->func(b->owner, ev, NULL);
646 }
647
648 /*
649  * Configuration load/save
650  */
651 #include "conf.h"
652
653 int
654 ButtonsConfigLoad(FILE * fs)
655 {
656    int                 err = 0;
657    char                s[FILEPATH_LEN_MAX];
658    char                s2[FILEPATH_LEN_MAX];
659    char               *p2;
660    int                 i1, i2;
661    char                name[64], label[64];
662    char                iclass[64], aclass[64], tclass[64];
663    Button             *bt = NULL;
664    Button             *pbt = NULL;
665    int                 ontop = 0;
666    int                 flags = 0, minw = 1, maxw = 99999, minh = 1;
667    int                 maxh = 99999, xo = 0, yo = 0, xa = 0;
668    int                 xr = 0, ya = 0, yr = 0;
669    int                 xsr = 0, xsa = 0, ysr = 0, ysa = 0;
670    char                simg = 0;
671    int                 desk = 0;
672    char                sticky = 0;
673    char                show = 1;
674    char                internal = 0;
675
676    name[0] = label[0] = '\0';
677    iclass[0] = aclass[0] = tclass[0] = '\0';
678
679    while (GetLine(s, sizeof(s), fs))
680      {
681         i1 = ConfigParseline1(s, s2, &p2, NULL);
682         i2 = atoi(s2);
683         switch (i1)
684           {
685           case CONFIG_CLOSE:
686              if (!pbt && !Mode_buttons.loading_user)
687                {
688                   bt = ButtonCreate(name, 0, iclass, aclass, tclass, label,
689                                     ontop, flags, minw, maxw, minh, maxh,
690                                     xo, yo, xa, xr, ya, yr, xsr, xsa, ysr, ysa,
691                                     simg, desk, sticky);
692                   bt->default_show = show;
693                   bt->internal = internal;
694                }
695              else if (pbt)
696                {
697                   _EFDUP(pbt->label, label);
698                   EoSetLayer(pbt, ontop);
699                   EoSetSticky(pbt, sticky);
700                   ButtonMoveToDesktop(pbt, DeskGet(desk));
701                   pbt->iclass = ImageclassFind(iclass, 1);
702                   pbt->aclass = ActionclassFind(aclass);
703                   pbt->tclass = TextclassFind(tclass, 1);
704                   pbt->flags = flags;
705                   pbt->internal = internal;
706                   pbt->default_show = show;
707                   pbt->geom.width_min = minw;
708                   pbt->geom.width_max = maxw;
709                   pbt->geom.height_min = minh;
710                   pbt->geom.height_max = maxh;
711                   pbt->geom.xorigin = xo;
712                   pbt->geom.yorigin = yo;
713                   pbt->geom.xabs = xa;
714                   pbt->geom.xrel = xr;
715                   pbt->geom.yabs = ya;
716                   pbt->geom.yrel = yr;
717                   pbt->geom.xsizerel = xsr;
718                   pbt->geom.xsizeabs = xsa;
719                   pbt->geom.ysizerel = ysr;
720                   pbt->geom.ysizeabs = ysa;
721                   pbt->geom.size_from_image = simg;
722                }
723              goto done;
724           case CONFIG_CLASSNAME:
725           case BUTTON_NAME:
726              STRCPY(name, s2);
727              pbt = ButtonFind(name);
728              break;
729           case BUTTON_LABEL:
730              STRCPY(label, s2);
731              break;
732           case CONFIG_IMAGECLASS:
733           case BUTTON_ICLASS:
734              STRCPY(iclass, s2);
735              break;
736           case CONFIG_ACTIONCLASS:
737           case BUTTON_ACLASS:
738              STRCPY(aclass, s2);
739              break;
740           case CONFIG_TEXT:
741              STRCPY(tclass, s2);
742              break;
743           case BORDERPART_ONTOP:
744              ontop = i2;
745              break;
746           case BORDERPART_WMIN:
747              minw = i2;
748              break;
749           case BORDERPART_WMAX:
750              maxw = i2;
751              break;
752           case BORDERPART_HMIN:
753              minh = i2;
754              break;
755           case BORDERPART_FLAGS:
756              flags = i2;
757              break;
758           case BORDERPART_HMAX:
759              maxh = i2;
760              break;
761           case BUTTON_XO:
762              xo = i2;
763              break;
764           case BUTTON_YO:
765              yo = i2;
766              break;
767           case BUTTON_XA:
768              xa = i2;
769              break;
770           case BUTTON_XR:
771              xr = i2;
772              break;
773           case BUTTON_YA:
774              ya = i2;
775              break;
776           case BUTTON_YR:
777              yr = i2;
778              break;
779           case BUTTON_XSR:
780              xsr = i2;
781              break;
782           case BUTTON_XSA:
783              xsa = i2;
784              break;
785           case BUTTON_YSR:
786              ysr = i2;
787              break;
788           case BUTTON_YSA:
789              ysa = i2;
790              break;
791           case BUTTON_SIMG:
792              simg = i2;
793              break;
794           case BUTTON_DESK:
795              desk = i2;
796              break;
797           case BUTTON_STICKY:
798              sticky = i2;
799              break;
800           case BUTTON_INTERNAL:
801              internal = i2;
802              break;
803           case BUTTON_SHOW:
804              show = i2;
805              break;
806           default:
807              break;
808           }
809      }
810    err = -1;
811
812  done:
813    return err;
814 }
815
816 static void
817 ButtonsConfigLoadUser(void)
818 {
819    char                s[4096];
820
821    Esnprintf(s, sizeof(s), "%s.buttons", EGetSavePrefix());
822
823    Mode_buttons.loading_user = 1;
824    ConfigFileLoad(s, NULL, ConfigFileRead, 0);
825    Mode_buttons.loading_user = 0;
826 }
827
828 static void
829 ButtonsConfigSave(void)
830 {
831    char                s[FILEPATH_LEN_MAX], st[FILEPATH_LEN_MAX];
832    FILE               *fs;
833    Button             *b;
834    int                 flags;
835
836    if (ecore_list_count(button_list) <= 0)
837       return;
838
839    Etmp(st);
840    fs = fopen(st, "w");
841    if (!fs)
842       return;
843
844    ECORE_LIST_FOR_EACH(button_list, b)
845    {
846       if (b->id != 0 || b->internal)
847          continue;
848
849       fprintf(fs, "4 999\n");
850       fprintf(fs, "100 %s\n", EoGetName(b));
851       if (b->iclass)
852          fprintf(fs, "12 %s\n", ImageclassGetName(b->iclass));
853       if (b->aclass)
854          fprintf(fs, "11 %s\n", ActionclassGetName(b->aclass));
855       if (EoGetLayer(b) >= 0)
856          fprintf(fs, "453 %i\n", EoGetLayer(b));
857       fprintf(fs, "456 %i\n", b->geom.width_min);
858       fprintf(fs, "457 %i\n", b->geom.width_max);
859       fprintf(fs, "468 %i\n", b->geom.height_min);
860       fprintf(fs, "469 %i\n", b->geom.height_max);
861       fprintf(fs, "528 %i\n", b->geom.xorigin);
862       fprintf(fs, "529 %i\n", b->geom.yorigin);
863       fprintf(fs, "530 %i\n", b->geom.xabs);
864       fprintf(fs, "531 %i\n", b->geom.xrel);
865       fprintf(fs, "532 %i\n", b->geom.yabs);
866       fprintf(fs, "533 %i\n", b->geom.yrel);
867       fprintf(fs, "534 %i\n", b->geom.xsizerel);
868       fprintf(fs, "535 %i\n", b->geom.xsizeabs);
869       fprintf(fs, "536 %i\n", b->geom.ysizerel);
870       fprintf(fs, "537 %i\n", b->geom.ysizeabs);
871       fprintf(fs, "538 %i\n", b->geom.size_from_image);
872       fprintf(fs, "539 %i\n", EoGetDeskNum(b));
873       fprintf(fs, "540 %i\n", EoIsSticky(b));
874       fprintf(fs, "542 %i\n", EoIsShown(b));
875
876       if (b->flags)
877         {
878            flags = 0;
879            if (((b->flags & FLAG_FIXED_HORIZ) &&
880                 (b->flags & FLAG_FIXED_VERT)) || (b->flags & FLAG_FIXED))
881               flags = 2;
882            else if (b->flags & FLAG_FIXED_HORIZ)
883               flags = 3;
884            else if (b->flags & FLAG_FIXED_VERT)
885               flags = 4;
886            else if (b->flags & FLAG_TITLE)
887               flags = 0;
888            else if (b->flags & FLAG_MINIICON)
889               flags = 1;
890            fprintf(fs, "454 %i\n", flags);
891         }
892       fprintf(fs, "1000\n");
893    }
894
895    fclose(fs);
896
897    Esnprintf(s, sizeof(s), "%s.buttons", EGetSavePrefix());
898    E_mv(st, s);
899 }
900
901 /*
902  * Buttons Module
903  */
904
905 static void
906 ButtonsSighan(int sig, void *prm __UNUSED__)
907 {
908    switch (sig)
909      {
910      case ESIGNAL_INIT:
911         memset(&Mode_buttons, 0, sizeof(Mode_buttons));
912         break;
913
914      case ESIGNAL_CONFIGURE:
915         ButtonsConfigLoadUser();
916         break;
917
918      case ESIGNAL_EXIT:
919         if (Mode.wm.save_ok)
920            ButtonsConfigSave();
921         break;
922      }
923 }
924
925 typedef struct {
926    int                 id;
927    int                 match;
928    const char         *regex;
929 } button_match_data;
930
931 static void
932 _ButtonHideShow(void *data, void *prm)
933 {
934    Button             *b = (Button *) data;
935    button_match_data  *bmd = (button_match_data *) prm;
936    int                 match;
937
938    if (bmd->id >= 0 && bmd->id != b->id)
939       return;
940
941    if (bmd->regex)
942      {
943         match = matchregexp(bmd->regex, EoGetName(b));
944         if ((match && !bmd->match) || (!match && bmd->match))
945            return;
946 #if ENABLE_DESKRAY
947         if (!strcmp(EoGetName(b), "_DESKTOP_DESKRAY_DRAG_CONTROL"))
948            return;
949 #endif
950      }
951
952    ButtonToggle(b);
953 }
954
955 static void
956 doHideShowButton(const char *params)
957 {
958    char                s[1024];
959    const char         *ss;
960    int                 len;
961    button_match_data   bmd = { -1, 1, NULL };
962    Button             *b;
963
964    if (!params)
965      {
966         bmd.id = 0;
967         ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
968         goto done;
969      }
970
971    s[0] = '\0';
972    len = 0;
973    sscanf(params, "%1000s %n", s, &len);
974    ss = (len > 0) ? params + len : NULL;
975
976    if (!strcmp(s, "button"))
977      {
978         sscanf(params, "%*s %1000s", s);
979         b = ButtonFind(s);
980         if (b)
981            ButtonToggle(b);
982      }
983    else if (!strcmp(s, "buttons"))
984      {
985         if (!ss)
986            return;
987
988         bmd.regex = ss;
989         ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
990      }
991    else if (!strcmp(s, "all_buttons_except"))
992      {
993         if (!ss)
994            return;
995
996         bmd.id = 0;
997         bmd.match = 0;
998         bmd.regex = ss;
999         ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
1000      }
1001    else if (!strcmp(s, "all"))
1002      {
1003         ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
1004      }
1005
1006  done:
1007    autosave();
1008 }
1009
1010 static void
1011 ButtonsIpc(const char *params)
1012 {
1013    const char         *p;
1014    char                cmd[128], prm[4096];
1015    int                 len;
1016    Button             *b;
1017
1018    cmd[0] = prm[0] = '\0';
1019    p = params;
1020    if (p)
1021      {
1022         len = 0;
1023         sscanf(p, "%100s %4000s %n", cmd, prm, &len);
1024         p += len;
1025      }
1026
1027    if (!p || cmd[0] == '?')
1028      {
1029      }
1030    else if (!strncmp(cmd, "list", 2))
1031      {
1032         IpcPrintf("Win       d  s  l     x     y     w     h name\n");
1033         ECORE_LIST_FOR_EACH(button_list, b)
1034            IpcPrintf("%#lx %2d %2d %2d %5d+%5d %5dx%5d %s\n",
1035                      EoGetXwin(b), EoGetDeskNum(b), EoIsSticky(b),
1036                      EoGetLayer(b), EoGetX(b), EoGetY(b), EoGetW(b), EoGetH(b),
1037                      EoGetName(b));
1038      }
1039    else if (!strncmp(cmd, "move", 2))
1040      {
1041         if (Mode_buttons.button)
1042            ButtonDragStart(Mode_buttons.button);
1043      }
1044 }
1045
1046 static void
1047 IPC_ButtonShow(const char *params)
1048 {
1049    doHideShowButton(params);
1050 }
1051
1052 static const IpcItem ButtonsIpcArray[] = {
1053    {
1054     ButtonsIpc,
1055     "button", "btn",
1056     "Button functions",
1057     "  button list               List buttons\n"},
1058    {
1059     IPC_ButtonShow,
1060     "button_show", NULL,
1061     "Show or Hide buttons on desktop",
1062     "use \"button_show <button/buttons/all_buttons_except/all> "
1063     "<BUTTON_STRING>\"\nexamples: \"button_show buttons all\" "
1064     "(removes all buttons and the dragbar)\n\"button_show\" "
1065     "(removes all buttons)\n \"button_show buttons CONFIG*\" "
1066     "(removes all buttons with CONFIG in the start)\n"},
1067 };
1068 #define N_IPC_FUNCS (sizeof(ButtonsIpcArray)/sizeof(IpcItem))
1069
1070 #if 0
1071 static const CfgItem ButtonsCfgItems[] = {
1072    CFG_ITEM_BOOL(Conf.buttons, enable, 1),
1073 };
1074 #define N_CFG_ITEMS (sizeof(ButtonsCfgItems)/sizeof(CfgItem))
1075 #endif
1076
1077 /*
1078  * Module descriptor
1079  */
1080 extern const EModule ModButtons;
1081 const EModule       ModButtons = {
1082    "buttons", "btn",
1083    ButtonsSighan,
1084    {N_IPC_FUNCS, ButtonsIpcArray},
1085    {0, NULL}
1086 };