From bf2fd3cf8c96d2a747ba4ea3bd8bd9b0a0d7e0e7 Mon Sep 17 00:00:00 2001 From: Thierry Lorthiois Date: Tue, 10 Feb 2009 23:16:10 +0000 Subject: [PATCH] fixed bug : clock resize when date changed, number of desktop changed --- ChangeLog | 4 + src/Makefile | 4 +- src/clock/clock.c | 92 ++++++++----- src/clock/clock.h | 1 + src/config.c | 27 ++-- src/panel.c | 15 +- src/panel.h | 7 +- src/server.c | 15 ++ src/server.h | 4 + src/systray/docker.c | 196 ++------------------------ src/systray/net.c | 83 +---------- src/systray/systraybar.c | 287 ++++++++++++++++++++++++++++++++++++++- src/systray/systraybar.h | 10 +- src/systray/tint_merge.h | 2 +- src/taskbar/task.c | 4 +- src/taskbar/taskbar.c | 22 +-- src/taskbar/taskbar.h | 2 +- src/tint.c | 53 +++++--- src/tint2 | Bin 59968 -> 55640 bytes src/util/area.c | 23 +++- src/util/area.h | 11 +- 21 files changed, 505 insertions(+), 357 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9cce93f..1a94a50 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-02-11 +- fixed bug with number of desktop changed +- fixed clock resize when date changed + 2009-02-08 - backward compatibility with tint-0.6 (convert config file) feature freeze until next release. need bug correction. diff --git a/src/Makefile b/src/Makefile index 63d4bd2..c31fc32 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,8 +1,8 @@ CFLAGS= -O2 CC = gcc -FLAGS=-W -Wall -g `pkg-config --cflags --libs cairo pangocairo x11 xinerama imlib2 glib-2.0` +FLAGS=-W -g `pkg-config --cflags --libs cairo pangocairo x11 xinerama imlib2 glib-2.0` PROGNAME=tint2 -FILES=tint.c server.c panel.c config.c taskbar/task.c taskbar/taskbar.c clock/clock.c systray/systraybar.c systray/docker.c systray/icons.c systray/kde.c systray/net.c systray/xproperty.c util/window.c util/area.c +FILES=tint.c server.c panel.c config.c taskbar/task.c taskbar/taskbar.c clock/clock.c systray/systraybar.c util/window.c util/area.c ifndef DESTDIR ifndef PREFIX diff --git a/src/clock/clock.c b/src/clock/clock.c index 64ac1ba..e7bb32f 100644 --- a/src/clock/clock.c +++ b/src/clock/clock.c @@ -37,18 +37,19 @@ struct timeval time_clock; int time_precision; PangoFontDescription *time1_font_desc; PangoFontDescription *time2_font_desc; +static char buf_time[40]; +static char buf_date[40]; void init_clock(Clock *clock, Area *parent) { Panel *panel = (Panel *)parent; - char buf_time[40]; - char buf_date[40]; int time_height, time_height_ink, date_height, date_height_ink; clock->area.parent = parent; clock->area.panel = panel; - clock->area.draw_foreground = draw_foreground_clock; + clock->area._draw_foreground = draw_foreground_clock; + clock->area._resize = resize_clock; if (!time1_format) return; if (strchr(time1_format, 'S') == NULL) time_precision = 60; @@ -62,7 +63,7 @@ void init_clock(Clock *clock, Area *parent) clock->area.posy = parent->pix.border.width + parent->paddingy; clock->area.height = parent->height - (2 * clock->area.posy); - clock->area.width = 0; // force posx and width detection + clock->area.resize = 1; clock->area.redraw = 1; strftime(buf_time, sizeof(buf_time), time1_format, localtime(&time_clock.tv_sec)); @@ -82,12 +83,45 @@ void init_clock(Clock *clock, Area *parent) void draw_foreground_clock (void *obj, cairo_t *c, int active) +{ + Clock *clock = obj; + PangoLayout *layout; + + //printf(" draw_foreground_clock : %s en (%d, %d)\n", buf_time, clock->area.posx, clock->area.width); + layout = pango_cairo_create_layout (c); + + // draw layout + pango_layout_set_font_description (layout, time1_font_desc); + pango_layout_set_width (layout, clock->area.width * PANGO_SCALE); + pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); + pango_layout_set_text (layout, buf_time, strlen(buf_time)); + + cairo_set_source_rgba (c, clock->font.color[0], clock->font.color[1], clock->font.color[2], clock->font.alpha); + + pango_cairo_update_layout (c, layout); + cairo_move_to (c, 0, clock->time1_posy); + pango_cairo_show_layout (c, layout); + + if (time2_format) { + pango_layout_set_font_description (layout, time2_font_desc); + pango_layout_set_indent(layout, 0); + pango_layout_set_text (layout, buf_date, strlen(buf_date)); + pango_layout_set_width (layout, clock->area.width * PANGO_SCALE); + + pango_cairo_update_layout (c, layout); + cairo_move_to (c, 0, clock->time2_posy); + pango_cairo_show_layout (c, layout); + } + + g_object_unref (layout); +} + + +void resize_clock (void *obj) { Area *parent = ((Area*)obj)->parent; Clock *clock = obj; PangoLayout *layout; - char buf_time[40]; - char buf_date[40]; int time_width, date_width, new_width; time_width = date_width = 0; @@ -95,8 +129,14 @@ void draw_foreground_clock (void *obj, cairo_t *c, int active) if (time2_format) strftime(buf_date, sizeof(buf_date), time2_format, localtime(&time_clock.tv_sec)); - //printf(" draw_foreground_clock : %s\n", buf_time); -redraw: + //printf(" resize_clock\n"); + cairo_surface_t *cs; + cairo_t *c; + Pixmap pmap; + pmap = XCreatePixmap (server.dsp, server.root_win, clock->area.width, clock->area.height, server.depth); + + cs = cairo_xlib_surface_create (server.dsp, pmap, server.visual, clock->area.width, clock->area.height); + c = cairo_create (cs); layout = pango_cairo_create_layout (c); // check width @@ -110,44 +150,22 @@ redraw: pango_layout_set_text (layout, buf_date, strlen(buf_date)); pango_layout_get_pixel_size (layout, &date_width, NULL); } + if (time_width > date_width) new_width = time_width; else new_width = date_width; new_width += (2*clock->area.paddingxlr) + (2*clock->area.pix.border.width); - if (new_width > clock->area.width || (new_width != clock->area.width && date_width > time_width)) { - //printf("clock_width %d, new_width %d\n", clock->area.width, new_width); + if (new_width > clock->area.width || new_width < (clock->area.width-3)) { // resize clock + //printf("clock_width %d, new_width %d\n", clock->area.width, new_width); clock->area.width = new_width; clock->area.posx = parent->width - clock->area.width - parent->paddingxlr - parent->pix.border.width; - - g_object_unref (layout); - resize_taskbar(parent); - goto redraw; - } - - // draw layout - pango_layout_set_font_description (layout, time1_font_desc); - pango_layout_set_width (layout, clock->area.width * PANGO_SCALE); - pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); - pango_layout_set_text (layout, buf_time, strlen(buf_time)); - - cairo_set_source_rgba (c, clock->font.color[0], clock->font.color[1], clock->font.color[2], clock->font.alpha); - - pango_cairo_update_layout (c, layout); - cairo_move_to (c, 0, clock->time1_posy); - pango_cairo_show_layout (c, layout); - - if (time2_format) { - pango_layout_set_font_description (layout, time2_font_desc); - pango_layout_set_indent(layout, 0); - pango_layout_set_text (layout, buf_date, strlen(buf_date)); - pango_layout_set_width (layout, clock->area.width * PANGO_SCALE); - - pango_cairo_update_layout (c, layout); - cairo_move_to (c, 0, clock->time2_posy); - pango_cairo_show_layout (c, layout); + set_resize(parent); } g_object_unref (layout); + cairo_destroy (c); + cairo_surface_destroy (cs); + XFreePixmap (server.dsp, pmap); } diff --git a/src/clock/clock.h b/src/clock/clock.h index a074797..613c40d 100644 --- a/src/clock/clock.h +++ b/src/clock/clock.h @@ -37,5 +37,6 @@ void init_clock(Clock *clock, Area *parent); void draw_foreground_clock (void *obj, cairo_t *c, int active); +void resize_clock (void *obj); #endif diff --git a/src/config.c b/src/config.c index 6f7d42a..f423654 100644 --- a/src/config.c +++ b/src/config.c @@ -38,6 +38,7 @@ #include "server.h" #include "task.h" #include "taskbar.h" +#include "systraybar.h" #include "clock.h" #include "panel.h" #include "config.h" @@ -409,6 +410,14 @@ void add_entry (char *key, char *value) memcpy(&panel_config->g_task.area.pix_active.border, &a->pix.border, sizeof(Border)); } + /* Trayer */ + else if (strcmp (key, "trayer_background_id") == 0) { + int id = atoi (value); + Area *a = g_slist_nth_data(list_back, id); + memcpy(&panel_config->trayer.area.pix.back, &a->pix.back, sizeof(Color)); + memcpy(&panel_config->trayer.area.pix.border, &a->pix.border, sizeof(Border)); + } + /* Mouse actions */ else if (strcmp (key, "mouse_middle") == 0) get_action (value, &mouse_middle); @@ -539,20 +548,18 @@ void config_finish () fprintf(stderr, "tint2 exit : monitor %d not found.\n", panel_config->monitor+1); exit(0); } - else { - if (!server.monitor[panel_config->monitor].width || !server.monitor[panel_config->monitor].height) - fprintf(stderr, "tint2 error : invalid monitor size.\n"); - } // alloc panels int i; if (panel_config->monitor >= 0) { + // just one monitor nb_panel = 1; panel1 = calloc(nb_panel, sizeof(Panel)); memcpy(panel1, panel_config, sizeof(Panel)); + panel1->monitor = panel_config->monitor; } else { - // multi monitor + // all monitors nb_panel = server.nb_monitor; panel1 = calloc(nb_panel, sizeof(Panel)); @@ -566,10 +573,14 @@ void config_finish () init_taskbar(); visible_object(); - task_refresh_tasklist(); - panel_refresh = 1; - cleanup_config(); + + // force the resize (using visible_object() order) + for (i=0 ; i < nb_panel ; i++) { + //init_systray(&panel1[i].trayer, &panel1[i].area); + set_resize(&panel1[i]); + } + task_refresh_tasklist(); } diff --git a/src/panel.c b/src/panel.c index 3e2d76e..881fdaf 100644 --- a/src/panel.c +++ b/src/panel.c @@ -115,6 +115,7 @@ void init_panel() init_clock(&p->clock, &p->area); } + panel_refresh = 1; } @@ -129,10 +130,17 @@ void cleanup_panel() for (i=0 ; i < nb_panel ; i++) { p = &panel1[i]; - free_area(&p->area); + // no free_area(&p->area) because it's the list of visible objects + if (p->area.list) { + g_slist_free(p->area.list); + p->area.list = 0; + } + free_area(&p->g_task.area); free_area(&p->g_taskbar); free_area(&p->clock.area); + if (p->area.pix.pmap) XFreePixmap(server.dsp, p->area.pix.pmap); + if (p->area.pix_active.pmap) XFreePixmap(server.dsp, p->area.pix_active.pmap); if (p->root_pmap) XFreePixmap(server.dsp, p->root_pmap); if (p->main_win) XDestroyWindow(server.dsp, p->main_win); } @@ -154,8 +162,9 @@ void visual_refresh (Panel *p) // draw child object GSList *l = p->area.list; - for (; l ; l = l->next) + for (; l ; l = l->next) { refresh (l->data); + } XCopyArea(server.dsp, p->root_pmap, p->main_win, server.gc, 0, 0, p->area.width, p->area.height, 0, 0); @@ -244,6 +253,8 @@ void visible_object() if (time1_format) panel->area.list = g_slist_append(panel->area.list, &panel->clock); + //panel->area.list = g_slist_append(panel->area.list, &panel->trayer); + Taskbar *taskbar; for (j=0 ; j < panel->nb_desktop ; j++) { taskbar = &panel->taskbar[j]; diff --git a/src/panel.h b/src/panel.h index 5992f7a..3a4b6dd 100644 --- a/src/panel.h +++ b/src/panel.h @@ -61,7 +61,7 @@ typedef struct { int monitor; // -------------------------------------------------- - // task annd taskbar parameter per panel + // task and taskbar parameter per panel Area g_taskbar; Global_task g_task; @@ -77,7 +77,10 @@ typedef struct { // -------------------------------------------------- // systray - Systraybar systraybar; + Systraybar trayer; + + // global taskbar parameter + //Area g_systraybar; } Panel; diff --git a/src/server.c b/src/server.c index 65d1099..1fccd6e 100644 --- a/src/server.c +++ b/src/server.c @@ -28,6 +28,8 @@ void server_catch_error (Display *d, XErrorEvent *ev){} +static char *name_trayer = 0; + void server_init_atoms () { @@ -68,6 +70,19 @@ void server_init_atoms () server.atom.WM_NAME = XInternAtom(server.dsp, "WM_NAME", False); server.atom.__SWM_VROOT = XInternAtom(server.dsp, "__SWM_VROOT", False); server.atom._MOTIF_WM_HINTS = XInternAtom(server.dsp, "_MOTIF_WM_HINTS", False); + + // systray protocol + name_trayer = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", DefaultScreen(server.dsp)); + server.atom._NET_SYSTEM_TRAY = XInternAtom(server.dsp, name_trayer, False); + server.atom._NET_SYSTEM_TRAY_OPCODE = XInternAtom(server.dsp, "_NET_SYSTEM_TRAY_OPCODE", False); + server.atom.MANAGER = XInternAtom(server.dsp, "MANAGER", False); + server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA = XInternAtom(server.dsp, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); +} + + +void cleanup_server() +{ + if (name_trayer) free(name_trayer); } diff --git a/src/server.h b/src/server.h index b8014e6..2d0aacb 100644 --- a/src/server.h +++ b/src/server.h @@ -53,6 +53,10 @@ typedef struct Global_atom Atom WM_NAME; Atom __SWM_VROOT; Atom _MOTIF_WM_HINTS; + Atom _NET_SYSTEM_TRAY; + Atom _NET_SYSTEM_TRAY_OPCODE; + Atom MANAGER; + Atom _NET_SYSTEM_TRAY_MESSAGE_DATA; } Global_atom; diff --git a/src/systray/docker.c b/src/systray/docker.c index 091c62e..a2e6152 100644 --- a/src/systray/docker.c +++ b/src/systray/docker.c @@ -28,85 +28,6 @@ int icon_size = 24; /* width and height of systray icons */ static gboolean exit_app = FALSE; /* -void parse_cmd_line() -{ - int i; - gboolean help = FALSE; - - for (i = 1; i < argc; i++) { - if (0 == strcasecmp(argv[i], "-display")) { - ++i; - if (i < argc) { - display_string = argv[i]; - } else { - g_printerr("-display requires a parameter\n"); - help = TRUE; - } - } else if (0 == strcasecmp(argv[i], "-wmaker")) { - wmaker = TRUE; - } else if (0 == strcasecmp(argv[i], "-vertical")) { - horizontal = FALSE; - } else if (0 == strcasecmp(argv[i], "-border")) { - ++i; - - if (i < argc) { - int b = atoi(argv[i]); - if (b > 0) { - border = b; - } else { - g_printerr("-border must be a value greater than 0\n"); - help = TRUE; - } - } else { - g_printerr("-border requires a parameter\n"); - help = TRUE; - } - } else if (0 == strcasecmp(argv[i], "-iconsize")) { - ++i; - if (i < argc) { - int s = atoi(argv[i]); - if (s > 0) { - icon_size = s; - } else { - g_printerr("-iconsize must be a value greater than 0\n"); - help = TRUE; - } - } else { - g_printerr("-iconsize requires a parameter\n"); - help = TRUE; - } - } else { - if (argv[i][0] == '-') - help = TRUE; - } - - - if (help) { - - g_print("%s - version %s\n", argv[0], VERSION); - g_print("Copyright 2003, Ben Jansens \n\n"); - g_print("Usage: %s [OPTIONS]\n\n", argv[0]); - g_print("Options:\n"); - g_print(" -help Show this help.\n"); - g_print(" -display DISLPAY The X display to connect to.\n"); - g_print(" -border The width of the border to put around the\n" - " system tray icons. Defaults to 1.\n"); - g_print(" -vertical Line up the icons vertically. Defaults to\n" - " horizontally.\n"); - g_print(" -wmaker WindowMaker mode. This makes docker a\n" - " fixed size (64x64) to appear nicely in\n" - " in WindowMaker.\n" - " Note: In this mode, you have a fixed\n" - " number of icons that docker can hold.\n"); - g_print(" -iconsize SIZE The size (width and height) to display\n" - " icons as in the system tray. Defaults to\n" - " 24.\n"); - exit(1); - } - } -} -*/ - void create_hint_win() { XWMHints hints; @@ -136,7 +57,7 @@ void create_main_window() XTextProperty text; char *name = "Docker"; - /* the border must be > 0 if not in wmaker mode */ + // the border must be > 0 if not in wmaker mode assert(wmaker || border > 0); if (!wmaker) @@ -145,7 +66,7 @@ void create_main_window() else win = XCreateSimpleWindow(display, root, 0, 0, 64, 64, 0, 0, 0); - + assert(win); XStringListToTextProperty(&name, 1, &text); @@ -154,21 +75,21 @@ void create_main_window() hints.flags = StateHint; hints.initial_state = WithdrawnState; XSetWMHints(display, win, &hints); - + create_hint_win(); - + XSync(display, False); XSetWindowBackgroundPixmap(display, win, ParentRelative); XClearWindow(display, win); } - +*/ void reposition_icons() { int x = border + ((width % icon_size) / 2), y = border + ((height % icon_size) / 2); GSList *it; - + for (it = icons; it != NULL; it = g_slist_next(it)) { TrayWindow *traywin = it->data; traywin->x = x; @@ -193,10 +114,10 @@ void fix_geometry() { GSList *it; - /* in wmaker mode we're a fixed size */ + // in wmaker mode we're a fixed size if (wmaker) return; - - /* find the proper width and height */ + + //* find the proper width and height width = horizontal ? 0 : icon_size; height = horizontal ? icon_size : 0; for (it = icons; it != NULL; it = g_slist_next(it)) { @@ -209,100 +130,13 @@ void fix_geometry() XResizeWindow(display, win, width + border * 2, height + border * 2); } - -void event_loop() -{ - XEvent e; - Window cover; - GSList *it; - - while (!exit_app) { - while (XPending(display)) { - 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); - } -} - /* int main(int c, char **v) { struct sigaction act; - + argc = c; argv = v; - + act.sa_handler = signal_handler; act.sa_flags = 0; sigaction(SIGSEGV, &act, NULL); @@ -325,18 +159,18 @@ int main(int c, char **v) if (wmaker) width = height = 64 - border * 2; - + create_main_window(); - // set up to find KDE systray icons, and get any that already exist + // set up to find KDE systray icons, and get any that already exist kde_init(); net_init(); // we want to get ConfigureNotify events, and assume our parent's background - // has changed when we do, so we need to refresh ourself to match + // has changed when we do, so we need to refresh ourself to match XSelectInput(display, win, StructureNotifyMask); - + event_loop(); XCloseDisplay(display); diff --git a/src/systray/net.c b/src/systray/net.c index 9f0c94a..8591834 100644 --- a/src/systray/net.c +++ b/src/systray/net.c @@ -14,7 +14,7 @@ static Atom net_message_data_atom; #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 - + static void net_create_selection_window() { net_sel_win = XCreateSimpleWindow(display, root, -1, -1, 1, 1, 0, 0, 0); @@ -28,38 +28,11 @@ static void net_destroy_selection_window() net_sel_win = None; } - -void net_init() +void net_icon_remove(TrayWindow *traywin) { - char *name; - XEvent m; - - name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", DefaultScreen(display)); - net_sel_atom = XInternAtom(display, name, False); - assert(net_sel_atom); - net_opcode_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False); - assert(net_opcode_atom); - net_manager_atom = XInternAtom(display, "MANAGER", False); - assert(net_manager_atom); - net_message_data_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_MESSAGE_DATA", - False); - assert(net_message_data_atom); - - net_create_selection_window(); - - XSetSelectionOwner(display, net_sel_atom, net_sel_win, CurrentTime); - if (XGetSelectionOwner(display, net_sel_atom) != net_sel_win) - return; /* we don't get the selection */ + assert(traywin); - m.type = ClientMessage; - m.xclient.message_type = net_manager_atom; - m.xclient.format = 32; - m.xclient.data.l[0] = CurrentTime; - m.xclient.data.l[1] = net_sel_atom; - m.xclient.data.l[2] = net_sel_win; - m.xclient.data.l[3] = 0; - m.xclient.data.l[4] = 0; - XSendEvent(display, root, False, StructureNotifyMask, &m); + XSelectInput(display, traywin->id, NoEventMask); } @@ -69,51 +42,3 @@ void net_destroy() } -void net_message(XClientMessageEvent *e) -{ - unsigned long opcode; - Window id; - - assert(e); - - 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, NET)) - XSelectInput(display, 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 == net_message_data_atom) { - 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 net_icon_remove(TrayWindow *traywin) -{ - assert(traywin); - - XSelectInput(display, traywin->id, NoEventMask); -} 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); + } +} +*/ + diff --git a/src/systray/systraybar.h b/src/systray/systraybar.h index 7fd8c9e..761bda6 100644 --- a/src/systray/systraybar.h +++ b/src/systray/systraybar.h @@ -18,11 +18,15 @@ typedef struct { } Systraybar; -// -------------------------------------------------- -// global taskbar parameter -Area g_systraybar; +typedef struct +{ + Window id; + int x, y; +} TrayWindow; +void init_systray(Systraybar *sysbar, Area *parent); + // return 1 if task_width changed int resize_systray (Systraybar *sysbar); diff --git a/src/systray/tint_merge.h b/src/systray/tint_merge.h index 475ebac..2cfbff5 100644 --- a/src/systray/tint_merge.h +++ b/src/systray/tint_merge.h @@ -8,7 +8,7 @@ #ifndef TINT_MERGE_H #define TINT_MERGE_H - +/* #define display server.dsp #define root server.root_win diff --git a/src/taskbar/task.c b/src/taskbar/task.c index 839f6f5..2ec873f 100644 --- a/src/taskbar/task.c +++ b/src/taskbar/task.c @@ -91,6 +91,7 @@ void remove_task (Task *tsk) if (!tsk) return; Window win = tsk->win; + int desktop = tsk->desktop; // free title and icon just for the first task // even with task_on_all_desktop and with task_on_all_panel @@ -106,8 +107,7 @@ void remove_task (Task *tsk) Taskbar *tskbar; for (i=0 ; i < nb_panel ; i++) { for (j=0 ; j < panel1[i].nb_desktop ; j++) { - if (tsk->desktop != ALLDESKTOP && tsk->desktop != j) continue; - //if (!panel1[i].taskbar) continue; + if (desktop != ALLDESKTOP && desktop != j) continue; GSList *l0; tskbar = &panel1[i].taskbar[j]; diff --git a/src/taskbar/taskbar.c b/src/taskbar/taskbar.c index 2044912..45d3b3d 100644 --- a/src/taskbar/taskbar.c +++ b/src/taskbar/taskbar.c @@ -43,12 +43,13 @@ void init_taskbar() panel = &panel1[i]; // taskbar + panel->g_taskbar._resize = resize_taskbar; panel->g_taskbar.posy = panel->area.pix.border.width + panel->area.paddingy; panel->g_taskbar.height = panel->area.height - (2 * panel->g_taskbar.posy); panel->g_taskbar.redraw = 1; // task - panel->g_task.area.draw_foreground = draw_foreground_task; + panel->g_task.area._draw_foreground = draw_foreground_task; panel->g_task.area.posy = panel->g_taskbar.posy + panel->g_taskbar.pix.border.width + panel->g_taskbar.paddingy; panel->g_task.area.height = panel->area.height - (2 * panel->g_task.area.posy); panel->g_task.area.use_active = 1; @@ -84,10 +85,7 @@ void init_taskbar() memcpy(&tskbar->area, &panel->g_taskbar, sizeof(Area)); tskbar->desktop = j; } - - resize_taskbar(panel); } - } @@ -115,8 +113,10 @@ void cleanup_taskbar() for (i=0 ; i < nb_panel ; i++) { panel = &panel1[i]; - free(panel->taskbar); - panel->taskbar = 0; + if (panel->taskbar) { + free(panel->taskbar); + panel->taskbar = 0; + } } } @@ -174,7 +174,7 @@ void task_refresh_tasklist () if (tsk->win == win[k]) break; } // careful : remove_task change l0->next - if (tsk->win != win[k]) remove_task (tsk); + if (k == num_results) remove_task (tsk); } } } @@ -198,6 +198,7 @@ int resize_tasks (Taskbar *taskbar) // new task width for 'desktop' task_count = g_slist_length(taskbar->area.list); + if (!task_count) pixel_width = panel->g_task.maximum_width; else { taskbar_width = taskbar->area.width - (2 * panel->g_taskbar.pix.border.width) - (2 * panel->g_taskbar.paddingxlr); @@ -239,9 +240,9 @@ int resize_tasks (Taskbar *taskbar) // initialise taskbar posx and width -void resize_taskbar(void *p) +void resize_taskbar(void *obj) { - Panel *panel = p; + Panel *panel = ((Area*)obj)->panel; int taskbar_width, modulo_width, taskbar_on_screen; if (panel_mode == MULTI_DESKTOP) taskbar_on_screen = panel->nb_desktop; @@ -250,6 +251,8 @@ void resize_taskbar(void *p) taskbar_width = panel->area.width - (2 * panel->area.paddingxlr) - (2 * panel->area.pix.border.width); if (time1_format) taskbar_width -= (panel->clock.area.width + panel->area.paddingx); + //taskbar_width -= (panel->trayer.area.width + panel->area.paddingx); + taskbar_width = (taskbar_width - ((taskbar_on_screen-1) * panel->area.paddingx)) / taskbar_on_screen; if (taskbar_on_screen > 1) @@ -272,6 +275,7 @@ void resize_taskbar(void *p) modulo--; } + set_redraw (&panel->taskbar[i].area); resize_tasks(&panel->taskbar[i]); } } diff --git a/src/taskbar/taskbar.h b/src/taskbar/taskbar.h index 881eab2..807e285 100644 --- a/src/taskbar/taskbar.h +++ b/src/taskbar/taskbar.h @@ -34,7 +34,7 @@ void task_refresh_tasklist (); // return 1 if task_width changed int resize_tasks (Taskbar *tskbar); -void resize_taskbar(void *panel); +void resize_taskbar(void *obj); #endif diff --git a/src/tint.c b/src/tint.c index 10ccb36..b84ee18 100644 --- a/src/tint.c +++ b/src/tint.c @@ -35,10 +35,8 @@ #include "config.h" #include "task.h" #include "taskbar.h" +#include "systraybar.h" #include "panel.h" -#include "docker.h" -#include "net.h" -#include "kde.h" void signal_handler(int sig) @@ -74,14 +72,6 @@ void init () XSetErrorHandler ((XErrorHandler) server_catch_error); - // init systray - //display = server.dsp; - //root = RootWindow(display, DefaultScreen(display)); - //create_main_window(); - //kde_init(); - //net_init(); - //printf("ici 4\n"); - imlib_context_set_display (server.dsp); imlib_context_set_visual (server.visual); imlib_context_set_colormap (DefaultColormap (server.dsp, server.screen)); @@ -138,7 +128,7 @@ void event_button_press (XEvent *e) if (panel_mode != MULTI_DESKTOP) { // drag and drop disabled - //XLowerWindow (server.dsp, panel.main_win); + XLowerWindow (server.dsp, panel->main_win); return; } @@ -163,7 +153,7 @@ void event_button_press (XEvent *e) } } - //XLowerWindow (server.dsp, panel.main_win); + XLowerWindow (server.dsp, panel->main_win); } @@ -202,7 +192,7 @@ void event_button_release (XEvent *e) } // TODO: check better solution to keep window below - //XLowerWindow (server.dsp, panel.main_win); + XLowerWindow (server.dsp, panel->main_win); task_drag = 0; return; @@ -238,7 +228,7 @@ suite: } // to keep window below - //XLowerWindow (server.dsp, panel.main_win); + XLowerWindow (server.dsp, panel->main_win); } @@ -259,6 +249,9 @@ void event_property_notify (Window win, Atom at) cleanup_taskbar(); init_taskbar(); visible_object(); + for (i=0 ; i < nb_panel ; i++) { + set_resize(&panel1[i]); + } task_refresh_tasklist(); panel_refresh = 1; } @@ -429,6 +422,7 @@ void event_timer() int i; for (i=0 ; i < nb_panel ; i++) { panel1[i].clock.area.redraw = 1; + panel1[i].clock.area.resize = 1; } panel_refresh = 1; } @@ -459,11 +453,6 @@ load_config: } config_finish(); - // BUG: refresh(clock) is needed here, but 'on the paper' it's not necessary. - for (i=0 ; i < nb_panel ; i++) { - refresh(&panel1[i].clock.area); - } - x11_fd = ConnectionNumber(server.dsp); XSync(server.dsp, False); @@ -500,7 +489,6 @@ load_config: break; case PropertyNotify: - //printf("PropertyNotify %lx\n", e.xproperty.window); event_property_notify (e.xproperty.window, e.xproperty.atom); break; @@ -509,6 +497,25 @@ load_config: goto load_config; else event_configure_notify (e.xconfigure.window); + break; + + case UnmapNotify: + case DestroyNotify: + /* + GSList *it; + for (it = icons; it; it = g_slist_next(it)) { + if (((TrayWindow*)it->data)->id == e.xany.window) { + icon_remove(it); + break; + } + }*/ + break; + + case ClientMessage: + break; + if (e.xclient.message_type == server.atom._NET_SYSTEM_TRAY_OPCODE && e.xclient.format == 32) + // && e.xclient.window == net_sel_win) + net_message(&e.xclient); break; } } @@ -525,8 +532,10 @@ load_config: } if (panel_refresh) { - for (i=0 ; i < nb_panel ; i++) + for (i=0 ; i < nb_panel ; i++) { visual_refresh(&panel1[i]); + } + XFlush (server.dsp); panel_refresh = 0; } diff --git a/src/tint2 b/src/tint2 index e7365a76026be2f733848278b37193f616a8181f..91ceff45118cd99719456736918be3151c88fa91 100755 GIT binary patch literal 55640 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 z
    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�#RL?$Y>bf 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 UDrugsQ`0ZJ&Dd{s23IZjAJU_+FaQ7m diff --git a/src/util/area.c b/src/util/area.c index bd6cf95..7606679 100644 --- a/src/util/area.c +++ b/src/util/area.c @@ -32,6 +32,13 @@ void refresh (Area *a) { + if (a->resize) { + // resize can generate a redraw + if (a->_resize) + a->_resize(a); + a->resize = 0; + } + if (a->redraw) { //printf("draw pix\n"); draw(a, 0); @@ -61,6 +68,16 @@ void set_redraw (Area *a) } +void set_resize (Area *a) +{ + a->resize = 1; + + GSList *l; + for (l = a->list ; l ; l = l->next) + set_resize(l->data); +} + + void draw (Area *a, int active) { Pixmap *pmap = (active == 0) ? (&a->pix.pmap) : (&a->pix_active.pmap); @@ -80,8 +97,8 @@ void draw (Area *a, int active) draw_background (a, c, active); - if (a->draw_foreground) - a->draw_foreground(a, c, active); + if (a->_draw_foreground) + a->_draw_foreground(a, c, active); cairo_destroy (c); cairo_surface_destroy (cs); @@ -180,6 +197,8 @@ void free_area (Area *a) g_slist_free(a->list); a->list = 0; } + if (a->pix.pmap) XFreePixmap (server.dsp, a->pix.pmap); + if (a->pix_active.pmap) XFreePixmap (server.dsp, a->pix_active.pmap); } diff --git a/src/util/area.h b/src/util/area.h index b03b2d1..708c033 100644 --- a/src/util/area.h +++ b/src/util/area.h @@ -60,8 +60,6 @@ typedef struct } Pmap; -// TODO: isoler 'draw' de 'refresh' -// TODO: isoler les données locales des données communes aux freres typedef struct { // absolute coordinate in panel int posx, posy; @@ -72,6 +70,8 @@ typedef struct { // list of child : Area object GSList *list; + // need compute position and width + int resize; // need redraw Pixmap int redraw; int use_active, is_active; @@ -84,9 +84,10 @@ typedef struct { void *panel; // each object can overwrite following function - void (*draw_foreground)(void *obj, cairo_t *c, int active); - void (*add_child)(void *obj); - int (*remove_child)(void *obj); + void (*_draw_foreground)(void *obj, cairo_t *c, int active); + void (*_resize)(void *obj); + void (*_add_child)(void *obj); + int (*_remove_child)(void *obj); } Area; -- 2.45.2