X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;ds=inline;f=src%2Fsystray%2Fsystraybar.c;h=02ed1b4ed20440b212fe422550be4399a363b210;hb=b7aaf2ac709f85602ef6152980a639fd3a8577e7;hp=f0adce7258220d9687fb11afe9378eaea80b7fdf;hpb=101ed479957ad40d2579faddb858a62a554007a3;p=chaz%2Ftint2 diff --git a/src/systray/systraybar.c b/src/systray/systraybar.c index f0adce7..02ed1b4 100644 --- a/src/systray/systraybar.c +++ b/src/systray/systraybar.c @@ -43,56 +43,47 @@ 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() { - Panel *panel = &panel1[0]; + start_net(); - if (systray.area.on_screen) - systray.area.on_screen = init_net(); - - if (!systray.area.on_screen) + if (!systray_enabled) return; - systray.area.parent = panel; - systray.area.panel = panel; systray.area._draw_foreground = draw_systray; systray.area._resize = resize_systray; - refresh_systray = 0; - - // 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.resize = 1; systray.area.redraw = 1; - - 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); -#ifdef ENABLE_BATTERY - if (panel->battery.area.on_screen) - systray.area.posx -= (panel->battery.area.width + panel->area.paddingx); -#endif + 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); - - cleanup_net(); } @@ -112,86 +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 (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); - 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.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.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.posx -= (panel->battery.area.width + panel->area.paddingx); + 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; traywin->width = icon_size; traywin->height = icon_size; - posx += (icon_size + systray.area.paddingx); + if (panel_horizontal) + posx += (icon_size + systray.area.paddingx); + else + posy += (icon_size + systray.area.paddingx); // position and size the icon window XMoveResizeWindow(server.dsp, traywin->id, traywin->x, traywin->y, icon_size, icon_size); } - //printf("resize_systray %d %d\n", systray.area.posx, systray.area.width); } -/* -void create_hint_win() -{ - XWMHints hints; - XClassHint classhints; - Panel *panel = systray.area.panel; - - hint_win = XCreateSimpleWindow(server.dsp, server.root_win, 0, 0, 1, 1, 0, 0, 0); - - hints.flags = StateHint | WindowGroupHint | IconWindowHint; - hints.initial_state = WithdrawnState; - hints.window_group = hint_win; - hints.icon_window = panel->main_win; - - classhints.res_name = "docker"; - classhints.res_class = "Docker"; - XSetWMProperties(server.dsp, hint_win, NULL, NULL, NULL, 0, - NULL, &hints, &classhints); +// *********************************************** +// systray protocol - XMapWindow(server.dsp, hint_win); -} -*/ - -int init_net() +void start_net() { - if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != None) { - fprintf(stderr, "tint2 : another systray is running\n"); - return 0; + 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; } - - //create_hint_win(); // 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; @@ -200,15 +236,24 @@ int init_net() ev.data.l[3] = 0; ev.data.l[4] = 0; XSendEvent(server.dsp, server.root_win, False, StructureNotifyMask, (XEvent*)&ev); - return 1; } -void cleanup_net() +void stop_net() { + //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; + } + if (net_sel_win != None) { - XDestroyWindow(server.dsp, net_sel_win); - net_sel_win = None; + XDestroyWindow(server.dsp, net_sel_win); + net_sel_win = None; } } @@ -225,37 +270,112 @@ int window_error_handler(Display *d, XErrorEvent *e) } -// The traywin must have its id and type set. +static gint compare_traywindows(gconstpointer a, gconstpointer b) +{ + const TrayWindow * traywin_a = (TrayWindow*)a; + const TrayWindow * traywin_b = (TrayWindow*)b; + XTextProperty name_a, name_b; + + 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; + } +} + + gboolean add_icon(Window id) { TrayWindow *traywin; XErrorHandler old; Panel *panel = systray.area.panel; + int hide = 0; error = FALSE; old = XSetErrorHandler(window_error_handler); + XWindowAttributes attr; + XGetWindowAttributes(server.dsp, id, &attr); + if ( attr.depth != server.depth ) { + XSetWindowAttributes a; + a.background_pixmap = None; // set to none, otherwise XReparentWindow fails... + a.background_pixel = 0; // set background pixel to 0. Looks ugly, but at least the icon appears + // TODO: maybe the XShape extension can be used, to clip the icon + XChangeWindowAttributes(server.dsp, id, CWBackPixmap|CWBackPixel, &a); + } 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; - - 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; + 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); // show the window - XMapRaised(server.dsp, traywin->id); + if (!traywin->hide) + XMapRaised(server.dsp, traywin->id); // changed in systray force resize on panel panel->area.resize = 1; @@ -268,27 +388,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; - systray.area.redraw = 1; // changed in systray force resize on panel Panel *panel = systray.area.panel; panel->area.resize = 1; panel_refresh = 1; - } @@ -310,11 +431,10 @@ void net_message(XClientMessageEvent *e) break; default: - if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) { + if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) printf("message from dockapp: %s\n", e->data.b); - } else - printf("SYSTEM_TRAY : unknown message type\n"); + fprintf(stderr, "SYSTEM_TRAY : unknown message type\n"); break; } } @@ -326,6 +446,7 @@ void refresh_systray_icon() 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); } }