X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fsystray%2Fsystraybar.c;h=0c515e9d726fcf0b3b50e70f1c1d2a56cf84b7bd;hb=bf2fd3cf8c96d2a747ba4ea3bd8bd9b0a0d7e0e7;hp=a6b3767ca90e2fed3f4b90754e6f871bb63911fd;hpb=26ddd8e4cc409b705ac7679851e603ff8b31d719;p=chaz%2Ftint2 diff --git a/src/systray/systraybar.c b/src/systray/systraybar.c index a6b3767..0c515e9 100644 --- a/src/systray/systraybar.c +++ b/src/systray/systraybar.c @@ -27,9 +27,43 @@ #include "systraybar.h" #include "server.h" -#include "window.h" +#include "panel.h" +GSList *icons; +/* defined in the systray spec */ +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +Window net_sel_win; + + +void init_systray(Systraybar *sysbar, Area *parent) +{ + Panel *panel = (Panel *)parent; + + sysbar->area.parent = parent; + sysbar->area.panel = panel; + + sysbar->area.posy = parent->pix.border.width + parent->paddingy; + sysbar->area.height = parent->height - (2 * sysbar->area.posy); + sysbar->area.width = 100; + + sysbar->area.posx = panel->area.width - panel->clock.area.width - panel->area.paddingxlr - panel->area.pix.border.width - panel->area.paddingx - sysbar->area.width; + + sysbar->area.redraw = 1; + +printf("init_systray"); + + net_init(); +} + + +// net_sel_atom == server.atom._NET_SYSTEM_TRAY +// net_opcode_atom == server.atom._NET_SYSTEM_TRAY_OPCODE +// net_manager_atom == server.atom.MANAGER +// net_message_data_atom == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA int resize_systray (Systraybar *sysbar) { @@ -38,3 +72,254 @@ int resize_systray (Systraybar *sysbar) +Window win, root; +int width, height; +int border; +int icon_size; + + +void fix_geometry() +{ + GSList *it; + + //* find the proper width and height + width = 0; + height = icon_size; + for (it = icons; it != NULL; it = g_slist_next(it)) { + width += icon_size; + } + + XResizeWindow(server.dsp, win, width + border * 2, height + border * 2); +} + + +static void net_create_selection_window() +{ + net_sel_win = XCreateSimpleWindow(server.dsp, root, -1, -1, 1, 1, 0, 0, 0); +} + + +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; +} + + +gboolean icon_swallow(TrayWindow *traywin) +{ + 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; +} + + +// The traywin must have its id and type set. +gboolean icon_add(Window id) +{ + TrayWindow *traywin; + + traywin = g_new0(TrayWindow, 1); + traywin->id = id; + + if (!icon_swallow(traywin)) { + g_free(traywin); + 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; + + // add the new icon to the list + icons = g_slist_append(icons, traywin); + + // 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, win); + + // show the window + XMapRaised(server.dsp, traywin->id); + + return TRUE; +} + + +void net_init() +{ + // init systray protocol + net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0); + + XSetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY, net_sel_win, CurrentTime); + if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY) != net_sel_win) { + fprintf(stderr, "tint error : can't get trayer selection"); + return; + } + + 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; + 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); +} + + +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; + } +} + + +/* +void event_loop() +{ + 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); + } +} +*/ +