2 * Copyright (C) 2004-2009 Kim Woelders
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include "container.h"
25 #include "e16-ecore_hints.h"
31 #define DEBUG_SYSTRAY 0
33 /* Systray object info */
39 #define StObjGetWin(o) (((SWin*)(o))->win)
40 #define StObjIsMapped(o) (((SWin*)(o))->mapped)
43 static Atom E_XA__XEMBED = 0;
44 static Atom E_XA__XEMBED_INFO = 0;
47 static Atom _NET_SYSTEM_TRAY_OPCODE = 0;
48 static Atom _NET_SYSTEM_TRAY_MESSAGE_DATA = 0;
50 /* Systray selection */
51 static ESelection *systray_sel = NULL;
53 static void SystrayItemEvent(Win win, XEvent * ev, void *prm);
55 #define SYSTEM_TRAY_REQUEST_DOCK 0
56 #define SYSTEM_TRAY_BEGIN_MESSAGE 1
57 #define SYSTEM_TRAY_CANCEL_MESSAGE 2
59 /* _XEMBED client message */
60 #define XEMBED_EMBEDDED_NOTIFY 0
62 /* _XEMBED_INFO property */
63 #define XEMBED_MAPPED (1 << 0)
66 SystrayGetXembedInfo(Window win, int *info)
68 unsigned char *prop_ret;
70 unsigned long bytes_after, num_ret;
74 if (XGetWindowProperty(disp, win, E_XA__XEMBED_INFO, 0, 0x7fffffff,
75 False, E_XA__XEMBED_INFO, &type_ret, &format_ret,
76 &num_ret, &bytes_after, &prop_ret) != Success)
79 if (prop_ret && type_ret == E_XA__XEMBED_INFO && format_ret == 32
82 info[0] = ((unsigned long *)prop_ret)[0];
83 info[1] = ((unsigned long *)prop_ret)[1];
87 /* Property invalid or not there. I doubt we ever get here */
88 info[0] = 0; /* Set protocol version 0 */
89 info[1] = 1; /* Set mapped */
99 * Return index, -1 if not found.
102 SystrayObjFind(Container * ct, Window win)
106 for (i = 0; i < ct->num_objs; i++)
107 if (win == WinGetXwin(StObjGetWin(ct->objs[i].obj)))
114 SystrayObjManage(Container * ct, Window xwin)
119 Eprintf("SystrayObjManage %#lx\n", xwin);
121 win = ERegisterWindow(xwin, NULL);
125 ESelectInput(win, StructureNotifyMask | PropertyChangeMask);
126 EventCallbackRegister(win, 0, SystrayItemEvent, ct);
127 EReparentWindow(win, ct->icon_win, 0, 0);
128 XAddToSaveSet(disp, xwin);
134 SystrayObjUnmanage(Container * ct __UNUSED__, Win win, int gone)
137 Eprintf("SystrayObjUnmanage %#lx gone=%d\n", WinGetXwin(win), gone);
142 ESelectInput(win, NoEventMask);
144 EReparentWindow(win, VROOT, 0, 0);
145 XRemoveFromSaveSet(disp, WinGetXwin(win));
147 EventCallbackUnregister(win, 0, SystrayItemEvent, ct);
148 EUnregisterWindow(win);
152 SystrayObjAdd(Container * ct, Window xwin)
158 /* Not if already there */
159 if (SystrayObjFind(ct, xwin) >= 0)
164 switch (SystrayGetXembedInfo(xwin, xembed_info))
166 case -1: /* Error - assume invalid window */
167 Eprintf("SystrayObjAdd: Hmm.. Invalid window? Ignoring %#lx\n", xwin);
169 case 0: /* Assume broken - proceed anyway */
170 Eprintf("SystrayObjAdd: Hmm.. No _XEMBED_INFO?\n");
173 if (EDebug(EDBUG_TYPE_ICONBOX))
174 Eprintf("SystrayObjAdd: _XEMBED_INFO: %#lx: %d %d\n", xwin,
175 xembed_info[0], xembed_info[1]);
179 swin = EMALLOC(SWin, 1);
183 if (ContainerObjectAdd(ct, swin) < 0)
186 win = SystrayObjManage(ct, xwin);
191 swin->mapped = (xembed_info[1] & XEMBED_MAPPED) != 0;
195 /* TBD - Always set protocol version as reported by client */
196 ecore_x_client_message32_send(xwin, E_XA__XEMBED, NoEventMask,
197 CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0,
198 xwin, xembed_info[0]);
202 return; /* Success */
208 ContainerObjectDel(ct, swin);
213 SystrayObjDel(Container * ct, Win win, int gone)
218 i = SystrayObjFind(ct, WinGetXwin(win));
222 if (EDebug(EDBUG_TYPE_ICONBOX))
223 Eprintf("SystrayObjDel %#lx\n", WinGetXwin(win));
225 swin = (SWin *) ct->objs[i].obj;
227 ContainerObjectDel(ct, swin);
230 SystrayObjUnmanage(ct, swin->win, gone);
236 SystrayObjMapUnmap(Container * ct, Window win)
242 i = SystrayObjFind(ct, win);
246 swin = (SWin *) ct->objs[i].obj;
248 if (SystrayGetXembedInfo(win, xembed_info) >= 0)
250 if (EDebug(EDBUG_TYPE_ICONBOX))
251 Eprintf("SystrayObjMapUnmap: _XEMBED_INFO: %#lx: %d %d\n", win,
252 xembed_info[0], xembed_info[1]);
254 map = (xembed_info[1] & XEMBED_MAPPED) != 0;
255 if (map == swin->mapped)
259 EMapWindow(swin->win);
261 EUnmapWindow(swin->win);
265 if (EDebug(EDBUG_TYPE_ICONBOX))
266 Eprintf("SystrayObjMapUnmap: _XEMBED_INFO: %#lx: gone?\n", win);
269 if (map == swin->mapped)
278 SystrayEventClientMessage(Container * ct, XClientMessageEvent * ev)
282 if (EDebug(EDBUG_TYPE_ICONBOX))
284 ("SystrayEventClientMessage: ev->type=%ld ev->data.l: %#lx %#lx %#lx %#lx\n",
285 ev->message_type, ev->data.l[0], ev->data.l[1], ev->data.l[2],
288 if (ev->message_type == _NET_SYSTEM_TRAY_OPCODE)
294 SystrayObjAdd(ct, win);
296 else if (ev->message_type == _NET_SYSTEM_TRAY_MESSAGE_DATA)
298 if (EDebug(EDBUG_TYPE_ICONBOX))
299 Eprintf("SystrayEventClientMessage: Got data message\n");
306 SystrayEventClientProperty(Container * ct, XPropertyEvent * ev)
308 if (EDebug(EDBUG_TYPE_ICONBOX))
309 Eprintf("SystrayEventClientProperty %#lx %ld\n", ev->window, ev->atom);
311 if (ev->atom == E_XA__XEMBED_INFO)
313 SystrayObjMapUnmap(ct, ev->window);
318 SystraySelectionEvent(Win win __UNUSED__, XEvent * ev, void *prm)
320 if (EDebug(EDBUG_TYPE_ICONBOX))
321 Eprintf("SystraySelectionEvent %2d %#lx\n", ev->type, ev->xany.window);
326 Eprintf(" ??? SystraySelectionEvent %2d %#lx\n", ev->type,
331 DialogOK(_("Systray Error!"), _("Systray went elsewhere?!?"));
332 SelectionRelease(systray_sel);
334 EwinHide(((Container *) prm)->ewin);
338 SystrayEventClientMessage((Container *) prm, &(ev->xclient));
344 SystrayEvent(Win _win __UNUSED__, XEvent * ev, void *prm __UNUSED__)
346 if (EDebug(EDBUG_TYPE_ICONBOX))
347 Eprintf("SystrayEvent %2d %#lx\n", ev->type, ev->xany.window);
349 #if 0 /* FIXME - Need this one at all? ConfigureRequest? */
355 EWindowSync(ELookupXwin(ev->xmap.window));
356 ContainerRedraw(prm);
360 win = ev->xdestroywindow.window;
364 case EX_EVENT_REPARENT_GONE:
365 /* Terminate if reparenting away from systray */
366 if (ev->xreparent.parent == ev->xreparent.event)
368 win = ev->xreparent.window;
372 SystrayObjDel(prm, win);
379 SystrayItemEvent(Win win, XEvent * ev, void *prm)
381 Container *ct = (Container *) prm;
383 if (EDebug(EDBUG_TYPE_ICONBOX))
384 Eprintf("SystrayItemEvent %2d %#lx\n", ev->type, ev->xany.window);
397 case EX_EVENT_REPARENT_GONE:
398 /* Terminate if reparenting away from systray */
399 if (ev->xreparent.parent == WinGetXwin(ct->icon_win))
404 SystrayEventClientMessage(ct, &(ev->xclient));
408 SystrayEventClientProperty(ct, &(ev->xproperty));
412 SystrayObjDel(ct, win, ev->type != ReparentNotify);
419 SystrayInit(Container * ct)
423 E_XA__XEMBED = EInternAtom("_XEMBED");
424 E_XA__XEMBED_INFO = EInternAtom("_XEMBED_INFO");
425 _NET_SYSTEM_TRAY_OPCODE = EInternAtom("_NET_SYSTEM_TRAY_OPCODE");
426 _NET_SYSTEM_TRAY_MESSAGE_DATA = EInternAtom("_NET_SYSTEM_TRAY_MESSAGE_DATA");
428 /* Acquire selection */
431 DialogOK(_("Systray Error!"), _("Only one systray is allowed"));
436 SelectionAcquire("_NET_SYSTEM_TRAY_S", SystraySelectionEvent, ct);
439 DialogOK(_("Systray Error!"), _("Could not activate systray"));
444 ESelectInputChange(win, SubstructureRedirectMask, 0);
445 EventCallbackRegister(win, 0, SystrayEvent, ct);
447 /* Container parameter setup */
448 ct->wm_name = "Systray";
449 ct->menu_title = _("Systray Options");
450 ct->dlg_title = _("Systray Settings");
455 SystrayExit(Container * ct, int wm_exit __UNUSED__)
457 SelectionRelease(systray_sel);
460 EventCallbackUnregister(ct->win, 0, SystrayEvent, ct);
464 SystrayObjDel(ct, StObjGetWin(ct->objs[0].obj), 0);
469 SystrayObjSizeCalc(Container * ct, ContainerObject * cto)
472 if (StObjIsMapped(cto->obj))
473 cto->wi = cto->hi = ct->iconsize;
475 cto->wi = cto->hi = 0;
479 SystrayObjPlace(Container * ct __UNUSED__, ContainerObject * cto,
480 EImage * im __UNUSED__)
482 if (StObjIsMapped(cto->obj))
484 EMoveResizeWindow(StObjGetWin(cto->obj), cto->xi, cto->yi, cto->wi,
486 /* This seems to fix rendering for ceratin apps which seem to expect
487 * expose events after resize (e.g. opera) */
489 XClearArea(disp, WinGetXwin(StObjGetWin(cto->obj)), 0, 0, 0, 0, True);
493 extern const ContainerOps SystrayOps;
494 const ContainerOps SystrayOps = {