2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2008 Kim Woelders
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:
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.
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.
29 #include "e16-ecore_list.h"
39 #define BUTTON_EVENT_MASK \
40 (KeyPressMask | KeyReleaseMask | \
41 ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | \
45 int width_min, width_max;
46 int height_min, height_max;
50 int xsizerel, xsizeabs;
51 int ysizerel, ysizeabs;
73 unsigned int ref_count;
76 static Ecore_List *button_list = NULL;
86 static void ButtonHandleEvents(Win win, XEvent * ev, void *btn);
90 ButtonIncRefcount(Button * b)
96 ButtonDecRefcount(Button * b)
103 ButtonIsFixed(const Button * b)
105 return b->flags & FLAG_FIXED;
109 ButtonIsInternal(const Button * b)
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)
123 if (desk < 0 || desk >= (int)DesksGetNumber())
126 if (sticky && ontop == 1)
129 b = ECALLOC(Button, 1);
132 button_list = ecore_list_new();
133 ecore_list_append(button_list, b);
136 b->label = Estrdup(label);
138 b->iclass = ImageclassAlloc(iclass, 1);
139 b->aclass = ActionclassAlloc(aclass);
141 b->tclass = TextclassAlloc(tclass, 1);
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;
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;
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);
167 ESelectInput(EoGetWin(b), BUTTON_EVENT_MASK);
168 EventCallbackRegister(EoGetWin(b), 0, ButtonHandleEvents, b);
174 ButtonDestroy(Button * b)
179 if (b->ref_count > 0)
181 DialogOK("Button Error!", _("%u references remain\n"), b->ref_count);
185 ecore_list_node_remove(button_list, b);
189 ImageclassFree(b->iclass);
190 ActionclassFree(b->aclass);
191 TextclassFree(b->tclass);
198 _ButtonMatchName(const void *data, const void *match)
200 return strcmp(EoGetName((const Button *)data), (const char *)match);
204 ButtonFind(const char *name)
206 return (Button *) ecore_list_find(button_list, _ButtonMatchName, name);
210 ButtonCalc(Button * b)
212 int w, h, x, y, xo, yo;
219 if (b->geom.size_from_image)
221 im = ImageclassGetImage(b->iclass, 0, 0, 0);
224 EImageGetSize(im, &w, &h);
230 b->iclass = ImageclassAlloc(NULL, 1);
237 w = ((b->geom.xsizerel * WinGetW(VROOT)) >> 10) + b->geom.xsizeabs;
238 h = ((b->geom.ysizerel * WinGetH(VROOT)) >> 10) + b->geom.ysizeabs;
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;
253 EoMoveResize(b, x, y, w, h);
257 ButtonDraw(Button * b)
259 ITApply(EoGetWin(b), b->iclass, NULL,
260 b->state, 0, 0, ST_BUTTON, b->tclass, NULL, b->label, 0);
266 ButtonDrawWithState(Button * b, int state)
274 ButtonShow(Button * b)
282 ButtonSwallowInto(Button * b, EObj * eo)
286 b->flags |= FLAG_FIXED;
289 EobjReparent(EoObj(b), eo, 0, 0);
292 EMapWindow(EoGetWin(b));
296 ButtonSetCallback(Button * b, ButtonCbFunc * func, EObj * eo)
303 ButtonMoveToDesktop(Button * b, Desk * dsk)
305 if (EoIsSticky(b) && EoGetLayer(b) == 1)
311 if (EoGetDesk(b) != dsk)
312 EoReparent(b, EoObj(dsk), EoGetX(b), EoGetY(b));
316 ButtonHide(Button * b)
322 ButtonToggle(Button * b)
334 ButtonMoveToCoord(Button * b, int x, int y)
336 int rx, ry, relx, rely, absx, absy;
338 if (ButtonIsFixed(b))
341 if ((x + (EoGetW(b) >> 1)) < (WinGetW(VROOT) / 3))
343 else if ((x + (EoGetW(b) >> 1)) > ((WinGetW(VROOT) * 2) / 3))
347 rx = (relx * WinGetW(VROOT)) >> 10;
349 if ((y + (EoGetH(b) >> 1)) < (WinGetH(VROOT) / 3))
351 else if ((y + (EoGetH(b) >> 1)) > ((WinGetH(VROOT) * 2) / 3))
355 ry = (rely * WinGetH(VROOT)) >> 10;
357 if (!(b->flags & FLAG_FIXED_HORIZ))
363 if (!(b->flags & FLAG_FIXED_VERT))
374 ButtonMoveRelative(Button * b, int dx, int dy)
376 ButtonMoveToCoord(b, EoGetX(b) + dx, EoGetY(b) + dy);
380 ButtonDoShowDefault(const Button * b)
382 return !b->internal && b->default_show;
387 ButtonEmbedWindow(Button * b, Window WindowToEmbed)
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);
399 ESelectInput(b->event_win,
400 ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
401 LeaveWindowMask | ButtonMotionMask);
403 EMoveWindow(b->event_win, (EoGetW(b) - w) >> 1, (EoGetH(b) - h) >> 1);
404 EMapRaised(b->event_win);
411 ButtonDragStart(Button * b)
413 if (ButtonIsFixed(b))
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;
424 ButtonDragEnd(Button * b)
428 Mode.mode = MODE_NONE;
430 if (!Mode_buttons.move_pending)
432 dsk = DesktopAt(Mode.events.mx, Mode.events.my);
433 ButtonMoveToDesktop(b, dsk);
435 ButtonMoveRelative(b, -EoGetX(dsk), -EoGetY(dsk));
438 Mode_buttons.move_pending = 0;
444 ButtonsForeach(int id, Desk * dsk, void (*func) (Button * b))
448 ECORE_LIST_FOR_EACH(button_list, b)
450 if (id >= 0 && id != b->id)
452 if (dsk && dsk != EoGetDesk(b))
459 ButtonsMoveStickyToDesk(Desk * dsk)
463 ECORE_LIST_FOR_EACH(button_list, b)
465 if (!EoIsSticky(b) || ButtonIsInternal(b))
468 ButtonMoveToDesktop(b, dsk);
473 * Button event handlers
477 ButtonDoAction(Button * b, XEvent * ev)
479 if (b->owner && b->func)
480 b->func(b->owner, ev, b->aclass);
482 ActionclassEvent(b->aclass, ev, NULL);
486 ButtonEventMouseDown(Button * b, XEvent * ev)
488 Mode_buttons.button = b;
490 GrabPointerSet(EoGetWin(b), ECSR_GRAB, 0);
494 Window win = ev->xbutton.window;
496 ev->xbutton.window = b->inside_win;
497 EXSendEvent(b->inside_win, ButtonPressMask, ev);
498 ev->xbutton.window = win;
501 b->state = STATE_CLICKED;
504 if (!ButtonIsInternal(b))
508 ac = ActionclassFind("ACTION_BUTTON_DRAG");
509 if (ac && !Mode_buttons.action_inhibit)
510 ActionclassEvent(ac, ev, NULL);
513 if (b->aclass && !Mode_buttons.action_inhibit)
514 ButtonDoAction(b, ev);
518 ButtonEventMouseUp(Button * b, XEvent * ev)
520 if (b->inside_win && !Mode_buttons.action_inhibit)
522 Window win = ev->xbutton.window;
524 ev->xbutton.window = b->inside_win;
525 EXSendEvent(b->inside_win, ButtonReleaseMask, ev);
526 ev->xbutton.window = win;
529 if ((b->state == STATE_CLICKED) && (!b->left))
530 b->state = STATE_HILITED;
532 b->state = STATE_NORMAL;
535 GrabPointerRelease();
539 if (Mode.mode == MODE_BUTTONDRAG)
540 ButtonDragEnd(Mode_buttons.button);
541 Mode_buttons.button = NULL;
543 if (b->aclass && !b->left && !Mode_buttons.action_inhibit)
544 ButtonDoAction(b, ev);
545 Mode_buttons.action_inhibit = 0;
549 ButtonEventMotion(Button * b, XEvent * ev __UNUSED__)
553 if (Mode.mode != MODE_BUTTONDRAG)
556 dx = Mode.events.mx - Mode.events.px;
557 dy = Mode.events.my - Mode.events.py;
559 if (Mode_buttons.move_pending)
563 x = Mode.events.mx - Mode_buttons.start_x;
564 y = Mode.events.my - Mode_buttons.start_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;
574 if (!Mode_buttons.move_pending)
575 ButtonMoveRelative(b, dx, dy);
579 ButtonEventMouseIn(Button * b, XEvent * ev)
581 if (b->state == STATE_CLICKED)
585 b->state = STATE_HILITED;
587 if (b->aclass && !Mode_buttons.action_inhibit)
588 ActionclassEvent(b->aclass, ev, NULL);
593 ButtonEventMouseOut(Button * b, XEvent * ev)
595 if (b->state == STATE_CLICKED)
599 b->state = STATE_NORMAL;
601 if (b->aclass && !Mode_buttons.action_inhibit)
602 ActionclassEvent(b->aclass, ev, NULL);
607 ButtonGetAclass(void *data)
609 Button *b = (Button *) data;
611 /* Validate button */
612 if (!ecore_list_goto(button_list, b))
619 ButtonHandleEvents(Win win __UNUSED__, XEvent * ev, void *prm)
621 Button *b = (Button *) prm;
626 ButtonEventMouseDown(b, ev);
629 ButtonEventMouseUp(b, ev);
632 ButtonEventMotion(b, ev);
634 TooltipsSetPending(0, ButtonGetAclass, b);
637 ButtonEventMouseIn(b, ev);
640 ButtonEventMouseOut(b, ev);
645 b->func(b->owner, ev, NULL);
649 * Configuration load/save
654 ButtonsConfigLoad(FILE * fs)
657 char s[FILEPATH_LEN_MAX];
658 char s2[FILEPATH_LEN_MAX];
661 char name[64], label[64];
662 char iclass[64], aclass[64], tclass[64];
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;
676 name[0] = label[0] = '\0';
677 iclass[0] = aclass[0] = tclass[0] = '\0';
679 while (GetLine(s, sizeof(s), fs))
681 i1 = ConfigParseline1(s, s2, &p2, NULL);
686 if (!pbt && !Mode_buttons.loading_user)
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,
692 bt->default_show = show;
693 bt->internal = internal;
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);
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;
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;
724 case CONFIG_CLASSNAME:
727 pbt = ButtonFind(name);
732 case CONFIG_IMAGECLASS:
736 case CONFIG_ACTIONCLASS:
743 case BORDERPART_ONTOP:
746 case BORDERPART_WMIN:
749 case BORDERPART_WMAX:
752 case BORDERPART_HMIN:
755 case BORDERPART_FLAGS:
758 case BORDERPART_HMAX:
800 case BUTTON_INTERNAL:
817 ButtonsConfigLoadUser(void)
821 Esnprintf(s, sizeof(s), "%s.buttons", EGetSavePrefix());
823 Mode_buttons.loading_user = 1;
824 ConfigFileLoad(s, NULL, ConfigFileRead, 0);
825 Mode_buttons.loading_user = 0;
829 ButtonsConfigSave(void)
831 char s[FILEPATH_LEN_MAX], st[FILEPATH_LEN_MAX];
836 if (ecore_list_count(button_list) <= 0)
844 ECORE_LIST_FOR_EACH(button_list, b)
846 if (b->id != 0 || b->internal)
849 fprintf(fs, "4 999\n");
850 fprintf(fs, "100 %s\n", EoGetName(b));
852 fprintf(fs, "12 %s\n", ImageclassGetName(b->iclass));
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));
879 if (((b->flags & FLAG_FIXED_HORIZ) &&
880 (b->flags & FLAG_FIXED_VERT)) || (b->flags & FLAG_FIXED))
882 else if (b->flags & FLAG_FIXED_HORIZ)
884 else if (b->flags & FLAG_FIXED_VERT)
886 else if (b->flags & FLAG_TITLE)
888 else if (b->flags & FLAG_MINIICON)
890 fprintf(fs, "454 %i\n", flags);
892 fprintf(fs, "1000\n");
897 Esnprintf(s, sizeof(s), "%s.buttons", EGetSavePrefix());
906 ButtonsSighan(int sig, void *prm __UNUSED__)
911 memset(&Mode_buttons, 0, sizeof(Mode_buttons));
914 case ESIGNAL_CONFIGURE:
915 ButtonsConfigLoadUser();
932 _ButtonHideShow(void *data, void *prm)
934 Button *b = (Button *) data;
935 button_match_data *bmd = (button_match_data *) prm;
938 if (bmd->id >= 0 && bmd->id != b->id)
943 match = matchregexp(bmd->regex, EoGetName(b));
944 if ((match && !bmd->match) || (!match && bmd->match))
947 if (!strcmp(EoGetName(b), "_DESKTOP_DESKRAY_DRAG_CONTROL"))
956 doHideShowButton(const char *params)
961 button_match_data bmd = { -1, 1, NULL };
967 ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
973 sscanf(params, "%1000s %n", s, &len);
974 ss = (len > 0) ? params + len : NULL;
976 if (!strcmp(s, "button"))
978 sscanf(params, "%*s %1000s", s);
983 else if (!strcmp(s, "buttons"))
989 ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
991 else if (!strcmp(s, "all_buttons_except"))
999 ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
1001 else if (!strcmp(s, "all"))
1003 ecore_list_for_each(button_list, _ButtonHideShow, &bmd);
1011 ButtonsIpc(const char *params)
1014 char cmd[128], prm[4096];
1018 cmd[0] = prm[0] = '\0';
1023 sscanf(p, "%100s %4000s %n", cmd, prm, &len);
1027 if (!p || cmd[0] == '?')
1030 else if (!strncmp(cmd, "list", 2))
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),
1039 else if (!strncmp(cmd, "move", 2))
1041 if (Mode_buttons.button)
1042 ButtonDragStart(Mode_buttons.button);
1047 IPC_ButtonShow(const char *params)
1049 doHideShowButton(params);
1052 static const IpcItem ButtonsIpcArray[] = {
1057 " button list List buttons\n"},
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"},
1068 #define N_IPC_FUNCS (sizeof(ButtonsIpcArray)/sizeof(IpcItem))
1071 static const CfgItem ButtonsCfgItems[] = {
1072 CFG_ITEM_BOOL(Conf.buttons, enable, 1),
1074 #define N_CFG_ITEMS (sizeof(ButtonsCfgItems)/sizeof(CfgItem))
1080 extern const EModule ModButtons;
1081 const EModule ModButtons = {
1084 {N_IPC_FUNCS, ButtonsIpcArray},