X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Fsystray%2Fsystraybar.c;h=d382d8a72eaa5c5ce61e8b350f6ef8d8f0c63d67;hb=bd9ade337cc85297242a10d5eb258aad2e71d021;hp=26b9b8d1b99369ef1cf02db5b5f5bebab6d017be;hpb=ce50a6305fd40385929dd383655292fd475d2df0;p=chaz%2Ftint2 diff --git a/src/systray/systraybar.c b/src/systray/systraybar.c index 26b9b8d..d382d8a 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 @@ -36,330 +37,287 @@ GSList *icons; #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 -Window net_sel_win = None; +// selection window +Window net_sel_win = None, hint_win = None; + +// freedesktop specification doesn't allow multi systray +Systraybar systray; void init_systray() { - Panel *panel; - Systraybar *sysbar; - int i, run_systray; - - cleanup_systray(); - - run_systray = 0; - for (i=0 ; i < nb_panel ; i++) { - if (panel1[i].systray.area.visible) { - run_systray = 1; - break; - } - } - if (run_systray) { - if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != None) { - fprintf(stderr, "tint2 warning : another systray is running\n"); - run_systray = 0; - } - } + Panel *panel = &panel1[0]; + + if (systray.area.on_screen) + systray.area.on_screen = init_net(); + + if (!systray.area.on_screen) + return; + + systray.area.parent = panel; + systray.area.panel = panel; + systray.area._resize = resize_systray; + + // 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.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 +} - if (run_systray) - run_systray = net_init(); - for (i=0 ; i < nb_panel ; i++) { - panel = &panel1[i]; - sysbar = &panel->systray; +void cleanup_systray() +{ + if (systray.list_icons) { + GSList *it; - if (!run_systray) { - sysbar->area.visible = 0; - continue; - } - if (!sysbar->area.visible) - continue; + for (it = systray.list_icons; it; it = it->next) + remove_icon((TrayWindow*)it->data); - sysbar->area.parent = panel; - sysbar->area.panel = panel; + g_slist_free(systray.list_icons); + systray.list_icons = 0; + } - sysbar->area.posy = panel->area.pix.border.width + panel->area.paddingy; - sysbar->area.height = panel->area.height - (2 * sysbar->area.posy); - sysbar->area.width = 100; + free_area(&systray.area); + + cleanup_net(); +} - sysbar->area.posx = panel->area.width - panel->area.paddingxlr - panel->area.pix.border.width - sysbar->area.width; - if (panel->clock.area.visible) - sysbar->area.posx -= (panel->clock.area.width + panel->area.paddingx); - sysbar->area.redraw = 1; +void resize_systray(void *obj) +{ + Systraybar *sysbar = obj; + Panel *panel = sysbar->area.panel; + TrayWindow *traywin; + GSList *l; + 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); +#ifdef ENABLE_BATTERY + if (panel->battery.area.on_screen) + systray.area.posx -= (panel->battery.area.width + 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; + for (l = systray.list_icons; l ; l = l->next) { + traywin = (TrayWindow*)l->data; + + traywin->y = posy; + traywin->x = posx; + traywin->width = icon_size; + traywin->height = icon_size; + posx += (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 cleanup_systray() +/* +void create_hint_win() { - Panel *panel; - int i; + XWMHints hints; + XClassHint classhints; + Panel *panel = systray.area.panel; - for (i=0 ; i < nb_panel ; i++) { - panel = &panel1[i]; - if (!panel->systray.area.visible) continue; + hint_win = XCreateSimpleWindow(server.dsp, server.root_win, 0, 0, 1, 1, 0, 0, 0); - free_area(&panel->systray.area); - } + hints.flags = StateHint | WindowGroupHint | IconWindowHint; + hints.initial_state = WithdrawnState; + hints.window_group = hint_win; + hints.icon_window = panel->main_win; - if (net_sel_win != None) { - XDestroyWindow(server.dsp, net_sel_win); - net_sel_win = None; - } -} + classhints.res_name = "docker"; + classhints.res_class = "Docker"; + XSetWMProperties(server.dsp, hint_win, NULL, NULL, NULL, 0, + NULL, &hints, &classhints); -int resize_systray (Systraybar *sysbar) -{ - return 0; + XMapWindow(server.dsp, hint_win); } +*/ +int init_net() +{ + if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != None) { + fprintf(stderr, "tint2 : another systray is running\n"); + return 0; + } + //create_hint_win(); -Window win, root; -int width, height; -int border; -int icon_size; - + // init systray protocol + net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0); -void fix_geometry() -{ - GSList *it; + // v0.2 trayer specification. tint2 always orizontal. + int orient = 0; + XChangeProperty(server.dsp, net_sel_win, server.atom._NET_SYSTEM_TRAY_ORIENTATION, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &orient, 1); - //* find the proper width and height - width = 0; - height = icon_size; - for (it = icons; it != NULL; it = g_slist_next(it)) { - width += icon_size; - } + 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) { + fprintf(stderr, "tint2 : can't get systray manager\n"); + return 0; + } - XResizeWindow(server.dsp, win, width + border * 2, height + border * 2); + XClientMessageEvent ev; + ev.type = ClientMessage; + ev.window = server.root_win; + ev.message_type = server.atom.MANAGER; + ev.format = 32; + ev.data.l[0] = CurrentTime; + ev.data.l[1] = server.atom._NET_SYSTEM_TRAY_SCREEN; + ev.data.l[2] = net_sel_win; + ev.data.l[3] = 0; + ev.data.l[4] = 0; + XSendEvent(server.dsp, server.root_win, False, StructureNotifyMask, (XEvent*)&ev); + return 1; } -gboolean error; -int window_error_handler(Display *d, XErrorEvent *e) +void cleanup_net() { - d=d;e=e; - if (e->error_code == BadWindow) { - error = TRUE; - } else { - //g_printerr("X ERROR NOT BAD WINDOW!\n"); - abort(); - } - return 0; + if (net_sel_win != None) { + XDestroyWindow(server.dsp, net_sel_win); + net_sel_win = None; + } } -gboolean icon_swallow(TrayWindow *traywin) +gboolean error; +int window_error_handler(Display *d, XErrorEvent *e) { - XErrorHandler old; - - error = FALSE; - old = XSetErrorHandler(window_error_handler); - XReparentWindow(server.dsp, traywin->id, win, 0, 0); - XSync(server.dsp, False); - XSetErrorHandler(old); - - return !error; + d=d;e=e; + error = TRUE; + if (e->error_code != BadWindow) { + printf("error_handler %d\n", e->error_code); + } + return 0; } // The traywin must have its id and type set. -gboolean icon_add(Window id) +gboolean add_icon(Window id) { - TrayWindow *traywin; - - traywin = g_new0(TrayWindow, 1); - traywin->id = id; - - if (!icon_swallow(traywin)) { - g_free(traywin); - return FALSE; - } + TrayWindow *traywin; + 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); + + if (error != FALSE) { + fprintf(stderr, "tint2 : not icon_swallow\n"); + return FALSE; + } - // 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; + traywin = g_new0(TrayWindow, 1); + traywin->id = id; - // add the new icon to the list - icons = g_slist_append(icons, traywin); + 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; - // watch for the icon trying to resize itself! - XSelectInput(server.dsp, traywin->id, StructureNotifyMask); + // 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); + // show the window + XMapRaised(server.dsp, traywin->id); - // resize our window so that the new window can fit in it - fix_geometry(); + // changed in systray force resize on panel + panel->area.resize = 1; + panel_refresh = 1; + return TRUE; +} - // 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, win); - // show the window - XMapRaised(server.dsp, traywin->id); +void remove_icon(TrayWindow *traywin) +{ + XErrorHandler old; - return TRUE; -} + XSelectInput(server.dsp, traywin->id, NoEventMask); + // reparent to root + error = FALSE; + old = XSetErrorHandler(window_error_handler); + XReparentWindow(server.dsp, traywin->id, server.root_win, 0, 0); + XSync(server.dsp, False); + XSetErrorHandler(old); -int net_init() -{ - // init systray protocol - net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0); + // 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; - 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) { - fprintf(stderr, "tint2 warning : can't get systray manager\n"); - return 0; - } + // changed in systray force resize on panel + Panel *panel = systray.area.panel; + panel->area.resize = 1; + panel_refresh = 1; - XEvent m; - m.type = ClientMessage; - m.xclient.message_type = server.atom.MANAGER; - m.xclient.format = 32; - m.xclient.data.l[0] = CurrentTime; - m.xclient.data.l[1] = server.atom._NET_SYSTEM_TRAY_SCREEN; - m.xclient.data.l[2] = net_sel_win; - m.xclient.data.l[3] = 0; - m.xclient.data.l[4] = 0; - XSendEvent(server.dsp, server.root_win, False, StructureNotifyMask, &m); - return 1; } void net_message(XClientMessageEvent *e) { - unsigned long opcode; - Window id; - - opcode = e->data.l[1]; - - switch (opcode) - { - case SYSTEM_TRAY_REQUEST_DOCK: /* dock a new icon */ - id = e->data.l[2]; - if (id && icon_add(id)) - XSelectInput(server.dsp, id, StructureNotifyMask); - break; - - case SYSTEM_TRAY_BEGIN_MESSAGE: - //g_printerr("Message From Dockapp\n"); - id = e->window; - break; - - case SYSTEM_TRAY_CANCEL_MESSAGE: - //g_printerr("Message Cancelled\n"); - id = e->window; - break; - - default: - if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) { - //g_printerr("Text For Message From Dockapp:\n%s\n", e->data.b); - id = e->window; - break; - } - - /* unknown message type. not in the spec. */ - //g_printerr("Warning: Received unknown client message to System Tray selection window.\n"); - break; - } + unsigned long opcode; + Window id; + + opcode = e->data.l[1]; + switch (opcode) { + case SYSTEM_TRAY_REQUEST_DOCK: + id = e->data.l[2]; + if (id) add_icon(id); + break; + + case SYSTEM_TRAY_BEGIN_MESSAGE: + case SYSTEM_TRAY_CANCEL_MESSAGE: + // we don't show baloons messages. + break; + + default: + 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"); + break; + } } -/* -void event_loop() +void refresh_systray() { - XEvent e; - Window cover; - GSList *it; - - while (!exit_app) { - while (XPending(server.dsp)) { - XNextEvent(display, &e); - - switch (e.type) - { - case PropertyNotify: - // systray window list has changed? - if (e.xproperty.atom == kde_systray_prop) { - XSelectInput(display, win, NoEventMask); - kde_update_icons(); - XSelectInput(display, win, StructureNotifyMask); - - while (XCheckTypedEvent(display, PropertyNotify, &e)); - } - - break; - - case ConfigureNotify: - if (e.xany.window != win) { - // find the icon it pertains to and beat it into submission - GSList *it; - - for (it = icons; it != NULL; it = g_slist_next(it)) { - TrayWindow *traywin = it->data; - if (traywin->id == e.xany.window) { - XMoveResizeWindow(display, traywin->id, traywin->x, traywin->y, - icon_size, icon_size); - break; - } - } - break; - } - - // briefly cover the entire containing window, which causes it and - // all of the icons to refresh their windows. finally, they update - // themselves when the background of the main window's parent changes. - - cover = XCreateSimpleWindow(display, win, 0, 0, - border * 2 + width, border * 2 + height, - 0, 0, 0); - XMapWindow(display, cover); - XDestroyWindow(display, cover); - - break; - - case ReparentNotify: - if (e.xany.window == win) // reparented to us - break; - case UnmapNotify: - case DestroyNotify: - for (it = icons; it; it = g_slist_next(it)) { - if (((TrayWindow*)it->data)->id == e.xany.window) { - icon_remove(it); - break; - } - } - break; - - case ClientMessage: - if (e.xclient.message_type == net_opcode_atom && - e.xclient.format == 32 && - e.xclient.window == net_sel_win) - net_message(&e.xclient); - - default: - break; - } - } - usleep(500000); - } - - // remove/unparent all the icons - while (icons) { - // do the remove here explicitly, cuz the event handler isn't going to - // happen anymore. - icon_remove(icons); - } + TrayWindow *traywin; + GSList *l; + for (l = systray.list_icons; l ; l = l->next) { + traywin = (TrayWindow*)l->data; + XClearArea(server.dsp, traywin->id, 0, 0, traywin->width, traywin->height, True); + } } -*/ +