X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fsystray%2Fsystraybar.c;h=273d9bb8e2d9879a05c7582ae48ad384d55f96e5;hb=21dcd195642692401f855ef07b239364b5ef0c1b;hp=18c1f22e97ed3e4523316d85f75e6274704812da;hpb=a1783c29169a83f9359106678c26fdc28815ccde;p=chaz%2Ftint2 diff --git a/src/systray/systraybar.c b/src/systray/systraybar.c index 18c1f22..273d9bb 100644 --- a/src/systray/systraybar.c +++ b/src/systray/systraybar.c @@ -2,6 +2,7 @@ * Tint2 : systraybar * * Copyright (C) 2009 thierry lorthiois (lorthiois@bbsoft.fr) +* based on 'docker-1.5' from Ben Jansens. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -37,101 +38,59 @@ GSList *icons; #define SYSTEM_TRAY_CANCEL_MESSAGE 2 // selection window -Window net_sel_win = None; +Window net_sel_win = None, hint_win = None; // freedesktop specification doesn't allow multi systray Systraybar systray; +int refresh_systray; +int systray_enabled; void init_systray() { - cleanup_systray(); + start_net(); - Panel *panel = &panel1[0]; - systray.area.parent = panel; - systray.area.panel = panel; - systray.area._draw_foreground = draw_systray; - systray.area._resize = resize_systray; - - if (systray.area.on_screen) { - if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != None) { - fprintf(stderr, "tint2 : another systray is running\n"); - systray.area.on_screen = 0; - } - } - - if (systray.area.on_screen) - systray.area.on_screen = net_init(); - - if (!systray.area.on_screen) + if (!systray_enabled) return; - // configure systray - // draw only one systray (even with multi panel) - systray.area.posy = panel->area.pix.border.width + panel->area.paddingy; - systray.area.height = panel->area.height - (2 * systray.area.posy); - systray.area.width = 0; - - systray.area.posx = panel->area.width - panel->area.paddingxlr - panel->area.pix.border.width - systray.area.width; - if (panel->clock.area.on_screen) - systray.area.posx -= (panel->clock.area.width + panel->area.paddingx); - + systray.area._draw_foreground = draw_systray; + systray.area._resize = resize_systray; + systray.area.resize = 1; systray.area.redraw = 1; + systray.area.on_screen = 1; + refresh_systray = 0; } -void cleanup_systray() +void init_systray_panel(void *p) { - if (systray.list_icons) { - GSList *it; + Panel *panel =(Panel*)p; - for (it = systray.list_icons; it; it = it->next) - remove_icon((TrayWindow*)it->data); + if (panel_horizontal) { + systray.area.posy = panel->area.pix.border.width + panel->area.paddingy; + systray.area.height = panel->area.height - (2 * systray.area.posy); + } + else { + systray.area.posx = panel->area.pix.border.width + panel->area.paddingy; + systray.area.width = panel->area.width - (2 * panel->area.pix.border.width) - (2 * panel->area.paddingy); + } + systray.area.parent = p; + systray.area.panel = p; +} - g_slist_free(systray.list_icons); - systray.list_icons = 0; - } +void cleanup_systray() +{ + systray_enabled = 0; + systray.area.on_screen = 0; free_area(&systray.area); - - if (net_sel_win != None) { - XDestroyWindow(server.dsp, net_sel_win); - net_sel_win = None; - } } void draw_systray(void *obj, cairo_t *c, int active) { - Systraybar *sysbar = obj; - Panel *panel = sysbar->area.panel; - TrayWindow *traywin; - GSList *l; - int icon_size; - - icon_size = sysbar->area.height - (2 * sysbar->area.pix.border.width) - (2 * sysbar->area.paddingy); - for (l = systray.list_icons; l ; l = l->next) { - traywin = (TrayWindow*)l->data; - - printf("draw_systray %d %d\n", systray.area.posx, systray.area.width); - // watch for the icon trying to resize itself! - XSelectInput(server.dsp, traywin->id, StructureNotifyMask); - - // position and size the icon window - XMoveResizeWindow(server.dsp, traywin->id, traywin->x, traywin->y, icon_size, icon_size); - - // resize our window so that the new window can fit in it - //fix_geometry(); - - // flush before clearing, otherwise the clear isn't effective. - XFlush(server.dsp); - // make sure the new child will get the right stuff in its background - // for ParentRelative. - XClearWindow(server.dsp, panel->main_win); - - // show the window - XMapRaised(server.dsp, traywin->id); - } + // tint2 don't draw systray icons. just the background. + refresh_systray = 1; } @@ -144,51 +103,131 @@ void resize_systray(void *obj) int count, posx, posy; int icon_size; - icon_size = sysbar->area.height - (2 * sysbar->area.pix.border.width) - (2 * sysbar->area.paddingy); - count = g_slist_length(systray.list_icons); - - if (!count) systray.area.width = 0; - else systray.area.width = (2 * systray.area.pix.border.width) + (2 * systray.area.paddingxlr) + (icon_size * count) + ((count-1) * systray.area.paddingx); - - systray.area.posx = panel->area.width - panel->area.pix.border.width - panel->area.paddingxlr - systray.area.width; - if (panel->clock.area.on_screen) - systray.area.posx -= (panel->clock.area.width + panel->area.paddingx); - - systray.area.redraw = 1; + if (panel_horizontal) + icon_size = sysbar->area.height; + else + icon_size = sysbar->area.width; + icon_size = icon_size - (2 * sysbar->area.pix.border.width) - (2 * sysbar->area.paddingy); + count = 0; + for (l = systray.list_icons; l ; l = l->next) { + if (!((TrayWindow*)l->data)->hide) + count++; + } + //printf("count %d\n", count); + + if (panel_horizontal) { + if (!count) systray.area.width = 0; + else systray.area.width = (2 * systray.area.pix.border.width) + (2 * systray.area.paddingxlr) + (icon_size * count) + ((count-1) * systray.area.paddingx); + + systray.area.posx = panel->area.width - panel->area.pix.border.width - panel->area.paddingxlr - systray.area.width; + if (panel->clock.area.on_screen) + systray.area.posx -= (panel->clock.area.width + panel->area.paddingx); +#ifdef ENABLE_BATTERY + if (panel->battery.area.on_screen) + systray.area.posx -= (panel->battery.area.width + panel->area.paddingx); +#endif + } + else { + if (!count) systray.area.height = 0; + else systray.area.height = (2 * systray.area.pix.border.width) + (2 * systray.area.paddingxlr) + (icon_size * count) + ((count-1) * systray.area.paddingx); + + systray.area.posy = panel->area.pix.border.width + panel->area.paddingxlr; + if (panel->clock.area.on_screen) + systray.area.posy += (panel->clock.area.height + panel->area.paddingx); +#ifdef ENABLE_BATTERY + if (panel->battery.area.on_screen) + systray.area.posy += (panel->battery.area.height + panel->area.paddingx); +#endif + } - posy = panel->area.pix.border.width + panel->area.paddingy + systray.area.pix.border.width + systray.area.paddingy; - posx = systray.area.posx + systray.area.pix.border.width + systray.area.paddingxlr; + if (panel_horizontal) { + posy = panel->area.pix.border.width + panel->area.paddingy + systray.area.pix.border.width + systray.area.paddingy; + posx = systray.area.posx + systray.area.pix.border.width + systray.area.paddingxlr; + } + else { + posx = panel->area.pix.border.width + panel->area.paddingy + systray.area.pix.border.width + systray.area.paddingy; + posy = systray.area.posy + systray.area.pix.border.width + systray.area.paddingxlr; + } for (l = systray.list_icons; l ; l = l->next) { traywin = (TrayWindow*)l->data; + if (traywin->hide) continue; traywin->y = posy; traywin->x = posx; - posx += (icon_size + systray.area.paddingx); - } + traywin->width = icon_size; + traywin->height = icon_size; + if (panel_horizontal) + posx += (icon_size + systray.area.paddingx); + else + posy += (icon_size + systray.area.paddingx); - // resize other objects on panel - printf("resize_systray %d %d\n", systray.area.posx, systray.area.width); + // position and size the icon window + XMoveResizeWindow(server.dsp, traywin->id, traywin->x, traywin->y, icon_size, icon_size); + } } -int net_init() +// *********************************************** +// systray protocol + +void start_net() { + if (net_sel_win) { + // protocol already started + if (!systray_enabled) + stop_net(); + return; + } + else + if (!systray_enabled) + return; + + Window win = XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN); + + // freedesktop systray specification + if (win != None) { + // search pid + Atom _NET_WM_PID, actual_type; + int actual_format; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop = 0; + int pid; + + _NET_WM_PID = XInternAtom(server.dsp, "_NET_WM_PID", True); + int ret = XGetWindowProperty(server.dsp, win, _NET_WM_PID, 0, 1024, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); + + fprintf(stderr, "tint2 : another systray is running"); + if (ret == Success && prop) { + pid = prop[1] * 256; + pid += prop[0]; + fprintf(stderr, " pid=%d", pid); + } + fprintf(stderr, "\n"); + return; + } + // init systray protocol - net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0); + net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0); - // v0.2 trayer specification. tint2 always orizontal. + // v0.2 trayer specification. tint2 always horizontal. + // Vertical panel will draw the systray horizontal. int orient = 0; XChangeProperty(server.dsp, net_sel_win, server.atom._NET_SYSTEM_TRAY_ORIENTATION, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &orient, 1); + VisualID vid = XVisualIDFromVisual(server.visual); + XChangeProperty(server.dsp, net_sel_win, XInternAtom(server.dsp, "_NET_SYSTEM_TRAY_VISUAL", False), XA_VISUALID, 32, PropModeReplace, (unsigned char*)&vid, 1); XSetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN, net_sel_win, CurrentTime); if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != net_sel_win) { + stop_net(); fprintf(stderr, "tint2 : can't get systray manager\n"); - return 0; - } + return; + } - XClientMessageEvent ev; + //fprintf(stderr, "tint2 : systray started\n"); + XClientMessageEvent ev; ev.type = ClientMessage; - ev.window = server.root_win; + ev.window = server.root_win; ev.message_type = server.atom.MANAGER; ev.format = 32; ev.data.l[0] = CurrentTime; @@ -197,95 +236,141 @@ int net_init() ev.data.l[3] = 0; ev.data.l[4] = 0; XSendEvent(server.dsp, server.root_win, False, StructureNotifyMask, (XEvent*)&ev); - - return 1; } -//int width, height; - -/* -void fix_geometry() +void stop_net() { - GSList *it; - Panel *panel = systray.area.panel; - - // find the proper width and height - width = 0; - height = icon_size; - for (it = icons; it != NULL; it = g_slist_next(it)) { - width += icon_size; - } + //fprintf(stderr, "tint2 : systray stopped\n"); + if (systray.list_icons) { + // remove_icon change systray.list_icons + while(systray.list_icons) + remove_icon((TrayWindow*)systray.list_icons->data); + + g_slist_free(systray.list_icons); + systray.list_icons = 0; + } - XResizeWindow(server.dsp, panel->main_win, width + border * 2, height + border * 2); + if (net_sel_win != None) { + XDestroyWindow(server.dsp, net_sel_win); + net_sel_win = None; + } } -*/ + gboolean error; int window_error_handler(Display *d, XErrorEvent *e) { - d=d;e=e; - if (e->error_code == BadWindow) { - error = TRUE; - } else { - //g_printerr("X ERROR NOT BAD WINDOW!\n"); - abort(); - } - return 0; + d=d;e=e; + error = TRUE; + if (e->error_code != BadWindow) { + printf("error_handler %d\n", e->error_code); + } + return 0; } -gboolean icon_swallow(Window id) +static gint compare_traywindows(gconstpointer a, gconstpointer b) { - XErrorHandler old; - Panel *panel = systray.area.panel; - - error = FALSE; - old = XSetErrorHandler(window_error_handler); - XReparentWindow(server.dsp, id, panel->main_win, 0, 0); - XSync(server.dsp, False); - XSetErrorHandler(old); + const TrayWindow * traywin_a = (TrayWindow*)a; + const TrayWindow * traywin_b = (TrayWindow*)b; + XTextProperty name_a, name_b; - return !error; + if(XGetWMName(server.dsp, traywin_a->id, &name_a) == 0) { + return -1; + } + else if(XGetWMName(server.dsp, traywin_b->id, &name_b) == 0) { + XFree(name_a.value); + return 1; + } + else { + gint retval = g_ascii_strncasecmp((char*)name_a.value, (char*)name_b.value, -1) * systray.sort; + XFree(name_a.value); + XFree(name_b.value); + return retval; + } } -// The traywin must have its id and type set. gboolean add_icon(Window id) { TrayWindow *traywin; + XErrorHandler old; + Panel *panel = systray.area.panel; + int hide = 0; - if (!icon_swallow(id)) { + error = FALSE; + old = XSetErrorHandler(window_error_handler); + XReparentWindow(server.dsp, id, panel->main_win, 0, 0); + XSync(server.dsp, False); + XSetErrorHandler(old); + if (error != FALSE) { fprintf(stderr, "tint2 : not icon_swallow\n"); return FALSE; } + { + Atom acttype; + int actfmt; + unsigned long nbitem, bytes; + unsigned char *data = 0; + int ret; + + ret = XGetWindowProperty(server.dsp, id, server.atom._XEMBED_INFO, 0, 2, False, server.atom._XEMBED_INFO, &acttype, &actfmt, &nbitem, &bytes, &data); + if (ret == Success) { + if (data) { + if (nbitem == 2) { + //hide = ((data[1] & XEMBED_MAPPED) == 0); + //printf("hide %d\n", hide); + } + XFree(data); + } + } + else { + fprintf(stderr, "tint2 : xembed error\n"); + return FALSE; + } + } + { + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.serial = 0; + e.xclient.send_event = True; + e.xclient.message_type = server.atom._XEMBED; + e.xclient.window = id; + e.xclient.format = 32; + e.xclient.data.l[0] = CurrentTime; + e.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY; + e.xclient.data.l[2] = 0; + e.xclient.data.l[3] = panel->main_win; + e.xclient.data.l[4] = 0; + XSendEvent(server.dsp, id, False, 0xFFFFFF, &e); + } + traywin = g_new0(TrayWindow, 1); traywin->id = id; + traywin->hide = hide; + + if (systray.sort == 3) + systray.list_icons = g_slist_prepend(systray.list_icons, traywin); + else if (systray.sort == 2) + systray.list_icons = g_slist_append(systray.list_icons, traywin); + else + systray.list_icons = g_slist_insert_sorted(systray.list_icons, traywin, compare_traywindows); + systray.area.resize = 1; + systray.area.redraw = 1; + //printf("add_icon id %lx, %d\n", id, g_slist_length(systray.list_icons)); + + // watch for the icon trying to resize itself! + XSelectInput(server.dsp, traywin->id, StructureNotifyMask); - systray.list_icons = g_slist_prepend(systray.list_icons, traywin); - printf("ajout d'un icone %d (%lx)\n", g_slist_length(systray.list_icons), id); - systray.area.resize = 1; - systray.area.redraw = 1; + // show the window + if (!traywin->hide) + XMapRaised(server.dsp, traywin->id); // changed in systray force resize on panel - Panel *panel = systray.area.panel; panel->area.resize = 1; panel_refresh = 1; - -// => calcul x, y, width, height dans resize -/* - // find the positon for the systray app window - int count = g_slist_length(icons); - traywin->x = border + ((width % icon_size) / 2) + - (count % (width / icon_size)) * icon_size; - traywin->y = border + ((height % icon_size) / 2) + - (count / (height / icon_size)) * icon_size; - - // add the new icon to the list - icons = g_slist_append(icons, traywin); -*/ - return TRUE; } @@ -294,26 +379,28 @@ void remove_icon(TrayWindow *traywin) { XErrorHandler old; + // remove from our list + systray.list_icons = g_slist_remove(systray.list_icons, traywin); + systray.area.resize = 1; + systray.area.redraw = 1; + //printf("remove_icon id %lx, %d\n", traywin->id); + XSelectInput(server.dsp, traywin->id, NoEventMask); // reparent to root error = FALSE; old = XSetErrorHandler(window_error_handler); + if (!traywin->hide) + XUnmapWindow(server.dsp, traywin->id); XReparentWindow(server.dsp, traywin->id, server.root_win, 0, 0); XSync(server.dsp, False); XSetErrorHandler(old); - - // remove from our list - systray.list_icons = g_slist_remove(systray.list_icons, traywin); g_free(traywin); - printf("suppression d'un icone %d\n", g_slist_length(systray.list_icons)); - systray.area.resize = 1; // changed in systray force resize on panel Panel *panel = systray.area.panel; panel->area.resize = 1; panel_refresh = 1; - } @@ -323,7 +410,6 @@ void net_message(XClientMessageEvent *e) Window id; opcode = e->data.l[1]; - switch (opcode) { case SYSTEM_TRAY_REQUEST_DOCK: id = e->data.l[2]; @@ -331,24 +417,29 @@ void net_message(XClientMessageEvent *e) break; case SYSTEM_TRAY_BEGIN_MESSAGE: - printf("message from dockapp\n"); - id = e->window; - break; - case SYSTEM_TRAY_CANCEL_MESSAGE: - printf("message cancelled\n"); - id = e->window; + // we don't show baloons messages. break; default: - if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) { - printf("message from dockapp:\n %s\n", e->data.b); - id = e->window; - } - // unknown message type. not in the spec + if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) + printf("message from dockapp: %s\n", e->data.b); + else + fprintf(stderr, "SYSTEM_TRAY : unknown message type\n"); break; } } +void refresh_systray_icon() +{ + TrayWindow *traywin; + GSList *l; + for (l = systray.list_icons; l ; l = l->next) { + traywin = (TrayWindow*)l->data; + if (traywin->hide) continue; + XClearArea(server.dsp, traywin->id, 0, 0, traywin->width, traywin->height, True); + } +} +