X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Ftint.c;h=192fa36d01f139a8c03db3441f3cc58852b91bbb;hb=76d87d447e391bb097fd2b7ae1fbcb4bd6655622;hp=ac6980bdedc045696a62b7cfd7571422da5252d5;hpb=c60c5246fa5d9ef98cb234416cdd318130a2d336;p=chaz%2Ftint2 diff --git a/src/tint.c b/src/tint.c index ac6980b..192fa36 100644 --- a/src/tint.c +++ b/src/tint.c @@ -37,6 +37,7 @@ #include "taskbar.h" #include "systraybar.h" #include "panel.h" +#include "tooltip.h" void signal_handler(int sig) @@ -48,15 +49,28 @@ void signal_handler(int sig) void init (int argc, char *argv[]) { - int c; + int i; // read options - c = getopt (argc, argv, "c:"); - if (c != -1) { - config_path = strdup (optarg); - c = getopt (argc, argv, "j:"); - if (c != -1) - thumbnail_path = strdup (optarg); + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + printf("Usage: tint2 [-c] \n"); + exit(0); + } + if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { + printf("tint2 version 0.7.svn\n"); + exit(0); + } + if (!strcmp(argv[i], "-c")) { + i++; + if (i < argc) + config_path = strdup(argv[i]); + } + if (!strcmp(argv[i], "-s")) { + i++; + if (i < argc) + snapshot_path = strdup(argv[i]); + } } // Set signal handler @@ -65,6 +79,7 @@ void init (int argc, char *argv[]) signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, SIG_IGN); // don't have to wait() after fork() + signal(SIGALRM, tooltip_sighandler); // set global data memset(&server, 0, sizeof(Server_global)); @@ -82,7 +97,7 @@ void init (int argc, char *argv[]) server.visual = DefaultVisual (server.dsp, server.screen); server.desktop = server_get_current_desktop (); XGCValues gcv; - server.gc = XCreateGC (server.dsp, server.root_win, (unsigned long)0, &gcv) ; + server.gc = XCreateGC (server.dsp, server.root_win, (unsigned long)0, &gcv); XSetErrorHandler ((XErrorHandler) server_catch_error); @@ -94,30 +109,41 @@ void init (int argc, char *argv[]) XSelectInput (server.dsp, server.root_win, PropertyChangeMask|StructureNotifyMask); setlocale (LC_ALL, ""); + + // load default icon + char *path; + const gchar * const *data_dirs; + data_dirs = g_get_system_data_dirs (); + for (i = 0; data_dirs[i] != NULL; i++) { + path = g_build_filename(data_dirs[i], "tint2", "default_icon.png", NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS)) + default_icon = imlib_load_image(path); + g_free(path); + } + + // get monitor and desktop config + get_monitors(); + get_desktops(); } void cleanup() { + cleanup_systray(); + stop_net(); cleanup_panel(); - - if (time1_font_desc) pango_font_description_free(time1_font_desc); - if (time2_font_desc) pango_font_description_free(time2_font_desc); - if (time1_format) g_free(time1_format); - if (time2_format) g_free(time2_format); + cleanup_tooltip(); + cleanup_clock(); #ifdef ENABLE_BATTERY - if (bat1_font_desc) pango_font_description_free(bat1_font_desc); - if (bat2_font_desc) pango_font_description_free(bat2_font_desc); - if (battery_low_cmd) g_free(battery_low_cmd); - if (path_energy_now) g_free(path_energy_now); - if (path_energy_full) g_free(path_energy_full); - if (path_current_now) g_free(path_current_now); - if (path_status) g_free(path_status); + cleanup_battery(); #endif - if (clock_lclick_command) g_free(clock_lclick_command); - if (clock_rclick_command) g_free(clock_rclick_command); + + if (default_icon) { + imlib_context_set_image(default_icon); + imlib_free_image(); + } if (config_path) g_free(config_path); - if (thumbnail_path) g_free(thumbnail_path); + if (snapshot_path) g_free(snapshot_path); if (server.monitor) free(server.monitor); XFreeGC(server.dsp, server.gc); @@ -125,54 +151,68 @@ void cleanup() } -Taskbar *click_taskbar (Panel *panel, XEvent *e) +void get_snapshot(const char *path) { - GSList *l0; - Taskbar *tskbar = NULL; + Panel *panel = &panel1[0]; + + if (panel->temp_pmap) XFreePixmap(server.dsp, panel->temp_pmap); + panel->temp_pmap = XCreatePixmap(server.dsp, server.root_win, panel->area.width, panel->area.height, server.depth); + + refresh(&panel->area); + + Imlib_Image img = NULL; + imlib_context_set_drawable(panel->temp_pmap); + img = imlib_create_image_from_drawable(0, 0, 0, panel->area.width, panel->area.height, 0); + + imlib_context_set_image(img); + imlib_save_image(path); + imlib_free_image(); +} + + +Taskbar *click_taskbar (Panel *panel, int x, int y) +{ + Taskbar *tskbar; + int i; + if (panel_horizontal) { - int x = e->xbutton.x; - for (l0 = panel->area.list; l0 ; l0 = l0->next) { - tskbar = l0->data; - if (!tskbar->area.on_screen) continue; - if (x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width)) - break; + for (i=0; i < panel->nb_desktop ; i++) { + tskbar = &panel->taskbar[i]; + if (tskbar->area.on_screen && x >= tskbar->area.posx && x <= (tskbar->area.posx + tskbar->area.width)) + return tskbar; } } else { - int y = e->xbutton.y; - for (l0 = panel->area.list; l0 ; l0 = l0->next) { - tskbar = l0->data; - if (!tskbar->area.on_screen) continue; - if (y >= tskbar->area.posy && y <= (tskbar->area.posy + tskbar->area.height)) - break; + for (i=0; i < panel->nb_desktop ; i++) { + tskbar = &panel->taskbar[i]; + if (tskbar->area.on_screen && y >= tskbar->area.posy && y <= (tskbar->area.posy + tskbar->area.height)) + return tskbar; } } - return tskbar; + return NULL; } -Task *click_task (Panel *panel, XEvent *e) +Task *click_task (Panel *panel, int x, int y) { GSList *l0; Taskbar *tskbar; - if ( (tskbar = click_taskbar(panel, e)) ) { + if ( (tskbar = click_taskbar(panel, x, y)) ) { if (panel_horizontal) { - int x = e->xbutton.x; Task *tsk; for (l0 = tskbar->area.list; l0 ; l0 = l0->next) { tsk = l0->data; - if (x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) { + if (tsk->area.on_screen && x >= tsk->area.posx && x <= (tsk->area.posx + tsk->area.width)) { return tsk; } } } else { - int y = e->xbutton.y; Task *tsk; for (l0 = tskbar->area.list; l0 ; l0 = l0->next) { tsk = l0->data; - if (y >= tsk->area.posy && y <= (tsk->area.posy + tsk->area.height)) { + if (tsk->area.on_screen && y >= tsk->area.posy && y <= (tsk->area.posy + tsk->area.height)) { return tsk; } } @@ -182,28 +222,28 @@ Task *click_task (Panel *panel, XEvent *e) } -int click_padding(Panel *panel, XEvent *e) +int click_padding(Panel *panel, int x, int y) { if (panel_horizontal) { - if (e->xbutton.x < panel->area.paddingxlr || e->xbutton.x > panel->area.width-panel->area.paddingxlr) + if (x < panel->area.paddingxlr || x > panel->area.width-panel->area.paddingxlr) return 1; } else { - if (e->xbutton.y < panel->area.paddingxlr || e->xbutton.y > panel->area.height-panel->area.paddingxlr) + if (y < panel->area.paddingxlr || y > panel->area.height-panel->area.paddingxlr) return 1; } return 0; } -int click_clock(Panel *panel, XEvent *e) +int click_clock(Panel *panel, int x, int y) { Clock clk = panel->clock; if (panel_horizontal) { - if (clk.area.on_screen && e->xbutton.x >= clk.area.posx && e->xbutton.x <= (clk.area.posx + clk.area.width)) + if (clk.area.on_screen && x >= clk.area.posx && x <= (clk.area.posx + clk.area.width)) return TRUE; } else { - if (clk.area.on_screen && e->xbutton.y >= clk.area.posy && e->xbutton.y <= (clk.area.posy + clk.area.height)) + if (clk.area.on_screen && y >= clk.area.posy && y <= (clk.area.posy + clk.area.height)) return TRUE; } return FALSE; @@ -225,8 +265,10 @@ void window_action (Task *tsk, int action) XIconifyWindow (server.dsp, tsk->win, server.screen); break; case TOGGLE_ICONIFY: - if (tsk == task_active) XIconifyWindow (server.dsp, tsk->win, server.screen); - else set_active (tsk->win); + if (task_active && tsk->win == task_active->win) + XIconifyWindow (server.dsp, tsk->win, server.screen); + else + set_active (tsk->win); break; case SHADE: window_toggle_shade (tsk->win); @@ -262,19 +304,18 @@ void event_button_press (XEvent *e) Panel *panel = get_panel(e->xany.window); if (!panel) return; - if (panel_mode == MULTI_DESKTOP) - task_drag = click_task(panel, e); + task_drag = click_task(panel, e->xbutton.x, e->xbutton.y); - if (wm_menu && !task_drag && !click_clock(panel, e) && (e->xbutton.button != 1) ) { + if (wm_menu && !task_drag && !click_clock(panel, e->xbutton.x, e->xbutton.y) && (e->xbutton.button != 1) ) { // forward the click to the desktop window (thanks conky) XUngrabPointer(server.dsp, e->xbutton.time); e->xbutton.window = server.root_win; // icewm doesn't open under the mouse. // and xfce doesn't open at all. - //e->xbutton.x = e->xbutton.x_root; - //e->xbutton.y = e->xbutton.y_root; + e->xbutton.x = e->xbutton.x_root; + e->xbutton.y = e->xbutton.y_root; //printf("**** %d, %d\n", e->xbutton.x, e->xbutton.y); - XSetInputFocus(server.dsp, e->xbutton.window, RevertToParent, e->xbutton.time); + //XSetInputFocus(server.dsp, e->xbutton.window, RevertToParent, e->xbutton.time); XSendEvent(server.dsp, e->xbutton.window, False, ButtonPressMask, e); return; } @@ -288,13 +329,6 @@ void event_button_release (XEvent *e) Panel *panel = get_panel(e->xany.window); if (!panel) return; - if (wm_menu && click_padding(panel, e)) { - // forward the click to the desktop window (thanks conky) - e->xbutton.window = server.root_win; - XSendEvent(server.dsp, e->xbutton.window, False, ButtonReleaseMask, e); - return; - } - int action = TOGGLE_ICONIFY; switch (e->xbutton.button) { case 2: @@ -317,7 +351,7 @@ void event_button_release (XEvent *e) break; } - if ( click_clock(panel, e)) { + if ( click_clock(panel, e->xbutton.x, e->xbutton.y)) { clock_action(e->xbutton.button); XLowerWindow (server.dsp, panel->main_win); task_drag = 0; @@ -325,7 +359,7 @@ void event_button_release (XEvent *e) } Taskbar *tskbar; - if ( !(tskbar = click_taskbar(panel, e)) ) { + if ( !(tskbar = click_taskbar(panel, e->xbutton.x, e->xbutton.y)) ) { // TODO: check better solution to keep window below XLowerWindow (server.dsp, panel->main_win); task_drag = 0; @@ -353,7 +387,7 @@ void event_button_release (XEvent *e) } // action on task - window_action( click_task(panel, e), action); + window_action( click_task(panel, e->xbutton.x, e->xbutton.y), action); // to keep window below XLowerWindow (server.dsp, panel->main_win); @@ -387,33 +421,37 @@ void event_property_notify (XEvent *e) } // Change desktop else if (at == server.atom._NET_CURRENT_DESKTOP) { + int old_desktop = server.desktop; server.desktop = server_get_current_desktop (); for (i=0 ; i < nb_panel ; i++) { Panel *panel = &panel1[i]; if (panel_mode == MULTI_DESKTOP && panel->g_taskbar.use_active) { - // redraw taskbar + // redraw both taskbar + panel->taskbar[old_desktop].area.is_active = 0; + panel->taskbar[old_desktop].area.resize = 1; + panel->taskbar[server.desktop].area.is_active = 1; + panel->taskbar[server.desktop].area.resize = 1; panel_refresh = 1; - Taskbar *tskbar; - Task *tsk; - GSList *l; - for (j=0 ; j < panel->nb_desktop ; j++) { - tskbar = &panel->taskbar[j]; - if (tskbar->area.is_active) { - tskbar->area.is_active = 0; - tskbar->area.redraw = 1; - for (l = tskbar->area.list; l ; l = l->next) { - tsk = l->data; - tsk->area.redraw = 1; - } - } - if (j == server.desktop) { - tskbar->area.is_active = 1; - tskbar->area.redraw = 1; - for (l = tskbar->area.list; l ; l = l->next) { - tsk = l->data; - tsk->area.redraw = 1; - } - } + } + // check ALLDESKTOP task => resize taskbar + Taskbar *tskbar; + Task *tsk; + GSList *l; + tskbar = &panel->taskbar[old_desktop]; + for (l = tskbar->area.list; l ; l = l->next) { + tsk = l->data; + if (tsk->desktop == ALLDESKTOP) { + tsk->area.on_screen = 0; + tskbar->area.resize = 1; + panel_refresh = 1; + } + } + tskbar = &panel->taskbar[server.desktop]; + for (l = tskbar->area.list; l ; l = l->next) { + tsk = l->data; + if (tsk->desktop == ALLDESKTOP) { + tsk->area.on_screen = 1; + tskbar->area.resize = 1; } } } @@ -428,44 +466,7 @@ void event_property_notify (XEvent *e) } // Change active else if (at == server.atom._NET_ACTIVE_WINDOW) { - GSList *l0; - if (task_active) { - for (i=0 ; i < nb_panel ; i++) { - for (j=0 ; j < panel1[i].nb_desktop ; j++) { - for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) { - tsk = l0->data; - tsk->area.is_active = 0; - } - } - } - task_active = 0; - } - Window w1 = window_get_active (); - Task *t = task_get_task(w1); - if (!t) { - Window w2; - if (XGetTransientForHint(server.dsp, w1, &w2) != 0) - if (w2) t = task_get_task(w2); - } - if (task_urgent == t) { - init_precision(); - task_urgent = 0; - } - // put active state on all task (multi_desktop) - if (t) { - for (i=0 ; i < nb_panel ; i++) { - for (j=0 ; j < panel1[i].nb_desktop ; j++) { - for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) { - tsk = l0->data; - if (tsk->win == t->win) { - tsk->area.is_active = 1; - //printf("active monitor %d, task %s\n", panel1[i].monitor, tsk->title); - } - } - } - } - task_active = t; - } + active_task(); panel_refresh = 1; } else if (at == server.atom._XROOTPMAP_ID) { @@ -479,10 +480,20 @@ void event_property_notify (XEvent *e) else { tsk = task_get_task (win); if (!tsk) { - if ( at != server.atom._NET_WM_STATE) - return; - else if ( !(tsk = add_task(win)) ) + if (at != server.atom._NET_WM_STATE) return; + else { + // xfce4 sends _NET_WM_STATE after minimized to tray, so we need to check if window is mapped + // if it is mapped and not set as skip_taskbar, we must add it to our task list + XWindowAttributes wa; + XGetWindowAttributes(server.dsp, win, &wa); + if (wa.map_state == IsViewable && !window_is_skip_taskbar(win)) { + if ( (tsk = add_task(win)) ) + panel_refresh = 1; + else + return; + } + } } //printf("atom root_win = %s, %s\n", XGetAtomName(server.dsp, at), tsk->title); @@ -508,36 +519,37 @@ void event_property_notify (XEvent *e) // Demand attention else if (at == server.atom._NET_WM_STATE) { if (window_is_urgent (win)) { - task_urgent = tsk; - tick_urgent = 0; - time_precision = 1; + add_urgent(tsk); } if (window_is_skip_taskbar(win)) { remove_task( tsk ); panel_refresh = 1; } } - else if (at == server.atom.WM_STATE) { - // Iconic state - // TODO : try to delete following code - if (window_is_iconified (win)) { - if (task_active) { - if (task_active->win == tsk->win) { - Task *tsk2; - GSList *l0; - for (i=0 ; i < nb_panel ; i++) { - for (j=0 ; j < panel1[i].nb_desktop ; j++) { - for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) { - tsk2 = l0->data; - tsk2->area.is_active = 0; - } - } - } - task_active = 0; - } - } - } - } +// We do not check for the iconified state, since it only unsets our active window +// but in openbox a shaded window is considered iconified. So we would loose the active window +// property on unshading it again (commented 01.10.2009) +// else if (at == server.atom.WM_STATE) { +// // Iconic state +// // TODO : try to delete following code +// if (window_is_iconified (win)) { +// if (task_active) { +// if (task_active->win == tsk->win) { +// Task *tsk2; +// GSList *l0; +// for (i=0 ; i < nb_panel ; i++) { +// for (j=0 ; j < panel1[i].nb_desktop ; j++) { +// for (l0 = panel1[i].taskbar[j].area.list; l0 ; l0 = l0->next) { +// tsk2 = l0->data; +// tsk2->area.is_active = 0; +// } +// } +// } +// task_active = 0; +// } +// } +// } +// } // Window icon changed else if (at == server.atom._NET_WM_ICON) { get_icon(tsk); @@ -550,8 +562,8 @@ void event_property_notify (XEvent *e) if (tsk->win == tsk2->win && tsk != tsk2) { tsk2->icon_width = tsk->icon_width; tsk2->icon_height = tsk->icon_height; - tsk2->icon_data = tsk->icon_data; - tsk2->icon_data_active = tsk->icon_data_active; + tsk2->icon = tsk->icon; + tsk2->icon_active = tsk->icon_active; tsk2->area.redraw = 1; } } @@ -575,6 +587,13 @@ void event_property_notify (XEvent *e) panel_refresh = 1; } } + else if (at == server.atom.WM_HINTS) { + XWMHints* wmhints = XGetWMHints(server.dsp, win); + if (wmhints && wmhints->flags & XUrgencyHint) { + add_urgent(tsk); + } + XFree(wmhints); + } if (!server.got_root_win) server.root_win = RootWindow (server.dsp, server.screen); } @@ -583,18 +602,31 @@ void event_property_notify (XEvent *e) void event_expose (XEvent *e) { - Panel *panel; - - panel = get_panel(e->xany.window); - if (!panel) return; - // TODO : one panel_refresh per panel ? - panel_refresh = 1; + if (e->xany.window == g_tooltip.window) + tooltip_update(); + else { + Panel *panel; + panel = get_panel(e->xany.window); + if (!panel) return; + // TODO : one panel_refresh per panel ? + panel_refresh = 1; + } } void event_configure_notify (Window win) { - // check 'win' move in systray + // change in root window (xrandr) + if (win == server.root_win) { + get_monitors(); + init_config(); + config_read_file (config_path); + init_panel(); + cleanup_config(); + return; + } + + // 'win' is a trayer icon TrayWindow *traywin; GSList *l; for (l = systray.list_icons; l ; l = l->next) { @@ -607,9 +639,8 @@ void event_configure_notify (Window win) } } - // check 'win' move in another monitor + // 'win' move in another monitor if (nb_panel == 1) return; - if (server.nb_monitor == 1) return; Task *tsk = task_get_task (win); if (!tsk) return; @@ -639,17 +670,20 @@ void event_timer() time_clock.tv_sec -= time_clock.tv_sec % time_precision; // urgent task - if (task_urgent) { - if (tick_urgent < max_tick_urgent) { - task_urgent->area.is_active = !task_urgent->area.is_active; - task_urgent->area.redraw = 1; - tick_urgent++; + GSList* urgent_task = urgent_list; + while (urgent_task) { + Task_urgent* t = urgent_task->data; + if ( t->tick < max_tick_urgent) { + t->tsk->area.is_active = !t->tsk->area.is_active; + t->tsk->area.redraw = 1; + t->tick++; } + urgent_task = urgent_task->next; } // update battery #ifdef ENABLE_BATTERY - if (panel1[0].battery.area.on_screen) { + if (battery_enabled) { update_battery(); for (i=0 ; i < nb_panel ; i++) panel1[i].battery.area.resize = 1; @@ -665,6 +699,36 @@ void event_timer() } +void dnd_message(XClientMessageEvent *e) +{ + Panel *panel = get_panel(e->window); + int x, y, mapX, mapY; + Window child; + x = (e->data.l[2] >> 16) & 0xFFFF; + y = e->data.l[2] & 0xFFFF; + XTranslateCoordinates(server.dsp, server.root_win, e->window, x, y, &mapX, &mapY, &child); + Task* task = click_task(panel, mapX, mapY); + if (task) { + if (task->desktop != server.desktop ) + set_desktop (task->desktop); + window_action(task, TOGGLE); + } + + // send XdndStatus event to get more XdndPosition events + XClientMessageEvent se; + se.type = ClientMessage; + se.window = e->data.l[0]; + se.message_type = server.atom.XdndStatus; + se.format = 32; + se.data.l[0] = e->window; // XID of the target window + se.data.l[1] = 0; // bit 0: accept drop bit 1: send XdndPosition events if inside rectangle + se.data.l[2] = 0; // Rectangle x,y for which no more XdndPosition events + se.data.l[3] = (1 << 16) | 1; // Rectangle w,h for which no more XdndPosition events + se.data.l[4] = None; // None = drop will not be accepted + XSendEvent(server.dsp, e->data.l[0], False, NoEventMask, (XEvent*)&se); +} + + int main (int argc, char *argv[]) { XEvent e; @@ -676,7 +740,6 @@ int main (int argc, char *argv[]) init (argc, argv); -load_config: i = 0; init_config(); if (config_path) @@ -688,10 +751,10 @@ load_config: cleanup(); exit(1); } - config_finish(); - if (thumbnail_path) { - // usage: tint2 -j for internal use - printf("file %s\n", thumbnail_path); + init_panel(); + cleanup_config(); + if (snapshot_path) { + get_snapshot(snapshot_path); cleanup(); exit(0); } @@ -715,6 +778,7 @@ load_config: switch (e.type) { case ButtonPress: + tooltip_hide(); event_button_press (&e); break; @@ -722,6 +786,21 @@ load_config: event_button_release(&e); break; + case MotionNotify: { + if (!g_tooltip.enabled) break; + Panel* panel = get_panel(e.xmotion.window); + Task* task = click_task(panel, e.xmotion.x, e.xmotion.y); + if (task) + tooltip_trigger_show(task, e.xmotion.x_root, e.xmotion.y_root); + else + tooltip_trigger_hide(); + break; + } + + case LeaveNotify: + tooltip_trigger_hide(); + break; + case Expose: event_expose(&e); break; @@ -731,14 +810,11 @@ load_config: break; case ConfigureNotify: - if (e.xconfigure.window == server.root_win) - goto load_config; - else - event_configure_notify (e.xconfigure.window); + event_configure_notify (e.xconfigure.window); break; case ReparentNotify: - if (!systray.area.on_screen) + if (!systray_enabled) break; panel = (Panel*)systray.area.panel; if (e.xany.window == panel->main_win) // reparented to us @@ -762,6 +838,9 @@ load_config: 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); } + else if (e.xclient.message_type == server.atom.XdndPosition) { + dnd_message(&e.xclient); + } break; } } @@ -769,9 +848,13 @@ load_config: event_timer(); switch (signal_pending) { - case SIGUSR1: + case SIGUSR1: // reload config file signal_pending = 0; - goto load_config; + init_config(); + config_read_file (config_path); + init_panel(); + cleanup_config(); + break; case SIGINT: case SIGTERM: case SIGHUP: