/* Perform several periodic tasks */ void perform_periodic_tasks(int mask) { struct TrayIcon *ti; /* 1. Remove all invalid icons */ while ((ti = icon_list_forall(&find_invalid_icons)) != NULL) { LOG_TRACE(("icon 0x%x is invalid; removing\n", ti->wid)); remove_icon(ti->wid); } /* 2. Print tray status if asked to */ if (tray_status_requested) dump_tray_status(); /* 3. KLUDGE to fix window size on (buggy?) WMs */ if (settings.kludge_flags & KLUDGE_FIX_WND_SIZE) { /* KLUDGE TODO: resolve */ XWindowAttributes xwa; XGetWindowAttributes(tray_data.dpy, tray_data.tray, &xwa); if (!tray_data.is_reparented && (xwa.width != tray_data.xsh.width || xwa.height != tray_data.xsh.height)) { LOG_TRACE(("KLUDGE: fixing tray window size (current: %dx%d, required: %dx%d)\n", xwa.width, xwa.height, tray_data.xsh.width, tray_data.xsh.height)); tray_update_window_props(); } } /* 4. run scrollbars periodic tasks */ if (mask & PT_MASK_SB) scrollbars_periodic_tasks(); }
/* Track icon visibility state changes */ void icon_track_visibility_changes(Window w) { struct TrayIcon *ti; int mapped; /* Ignore false alarms */ if ((ti = icon_list_find(w)) == NULL || !ti->is_xembed_supported) return; mapped = xembed_get_mapped_state(ti); LOG_TRACE(("xembed_is_mapped(0x%x) = %u\n", w, mapped)); LOG_TRACE(("is_visible = %u\n", ti->is_visible)); #ifdef DEBUG x11_dump_win_info(tray_data.dpy, ti->wid); #endif /* Nothing has changed */ if (mapped == ti->is_visible) return; ti->is_visible = mapped; LOG_INFO(("%s icon 0x%x\n", mapped ? "showing" : "hiding", w)); if (mapped) { /* Icon has become mapped and is listed as hidden. Show this icon. */ embedder_reset_size(ti); if (!layout_add(ti)) { xembed_set_mapped_state(ti, False); return; } embedder_show(ti); } else { /* Icon has become unmapped and is listed as visible. Hide this icon. */ layout_remove(ti); embedder_hide(ti); } embedder_update_positions(False); tray_update_window_props(); }
static void refresh_icons() { embedder_update_positions(_refresh_forced); tray_update_window_props(); _refresh = FALSE; _refresh_forced = FALSE; }
void configure_notify(XConfigureEvent ev) { struct TrayIcon *ti; struct Point sz; XWindowAttributes xwa; if (ev.window == tray_data.tray) { /* Tray window was resized */ /* TODO: distinguish between synthetic and real configure notifies */ /* TODO: catch rejected configure requests */ /* XXX: Geometry stuff is a mess. Geometry * is specified in slots, but almost always is * stored in pixels... */ LOG_TRACE(("tray window geometry from event: %ux%u+%d+%d\n", ev.width, ev.height, ev.x, ev.y)); /* Sometimes, configure notifies come too late, so we fetch real geometry ourselves */ XGetWindowAttributes(tray_data.dpy, tray_data.tray, &xwa); x11_get_window_abs_coords(tray_data.dpy, tray_data.tray, &tray_data.xsh.x, &tray_data.xsh.y); LOG_TRACE(("tray window geometry from X11 calls: %dx%d+%d+%d\n", xwa.width, xwa.height, tray_data.xsh.x, tray_data.xsh.y)); tray_data.xsh.width = xwa.width; tray_data.xsh.height = xwa.height; /* Update icons positions */ /* XXX: internal API is bad. example below */ icon_list_forall(&layout_translate_to_window); embedder_update_positions(True); /* Adjust window background if necessary */ tray_update_bg(False); tray_refresh_window(True); tray_update_window_strut(); scrollbars_update(); } else if ((ti = icon_list_find(ev.window)) != NULL) { /* Some icon has resized its window */ /* KDE icons are not allowed to change their size. Reset icon size. */ if (ti->cmode == CM_KDE || settings.kludge_flags & KLUDGE_FORCE_ICONS_SIZE) { embedder_reset_size(ti); return; } if (settings.kludge_flags & KLUDGE_FORCE_ICONS_SIZE) return; /* Get new window size */ if (!x11_get_window_size(tray_data.dpy, ti->wid, &sz.x, &sz.y)) { embedder_unembed(ti); return; } LOG_TRACE(("icon 0x%x was resized, new size: %ux%u, old size: %ux%u\n", ev.window, sz.x, sz.y, ti->l.wnd_sz.x, ti->l.wnd_sz.y)); /* Check if the size has really changed */ if (sz.x == ti->l.wnd_sz.x && sz.y == ti->l.wnd_sz.y) return; ti->l.wnd_sz = sz; ti->is_resized = True; /* Do the job */ layout_handle_icon_resize(ti); embedder_refresh(ti); #ifdef DEBUG print_icon_data(ti); #endif embedder_update_positions(False); tray_update_window_props(); #ifdef DEBUG dump_tray_status(); #endif } }
/* Add icon to the tray */ void add_icon(Window w, int cmode) { struct TrayIcon *ti; /* Aviod adding duplicates */ if ((ti = icon_list_find(w)) != NULL) { LOG_TRACE(("ignoring second request to embed 0x%x" "(requested cmode=%d, current cmode=%d\n", w, cmode, ti->cmode)); return; } /* Dear Edsger W. Dijkstra, I see you behind my back =( */ if ((ti = icon_list_new(w, cmode)) == NULL) goto failed0; LOG_TRACE(("starting embedding for icon 0x%x, cmode=%d\n", w, cmode)); x11_dump_win_info(tray_data.dpy, w); /* Start embedding cycle */ if (!xembed_check_support(ti)) goto failed1; if (ti->is_xembed_supported) ti->is_visible = xembed_get_mapped_state(ti); else ti->is_visible = True; if (ti->is_visible) { if (!embedder_reset_size(ti)) goto failed1; if (!layout_add(ti)) goto failed1; } if (!xembed_embed(ti)) goto failed1; if (!embedder_embed(ti)) goto failed2; embedder_update_positions(False); tray_update_window_props(); /* Report success */ LOG_INFO(("added icon %s (wid 0x%x) as %s\n", x11_get_window_name(tray_data.dpy, ti->wid, "<unknown>"), ti->wid, ti->is_visible ? "visible" : "hidden")); goto ok; failed2: layout_remove(ti); failed1: icon_list_free(ti); failed0: LOG_INFO(("failed to add icon %s (wid 0x%x)\n", x11_get_window_name(tray_data.dpy, ti->wid, "<unknown>"), ti->wid)); ok: if (settings.log_level >= LOG_LEVEL_TRACE) dump_tray_status(); return; }
/* Remove icon from the tray */ void remove_icon(Window w) { struct TrayIcon *ti; char *name; /* Ignore false alarms */ if ((ti = icon_list_find(w)) == NULL) return; dump_tray_status(); embedder_unembed(ti); xembed_unembed(ti); layout_remove(ti); icon_list_free(ti); LOG_INFO(("removed icon %s (wid 0x%x)\n", x11_get_window_name(tray_data.dpy, ti->wid, "<unknown>"), w)); /* no need to call embedde_update_positions(), as * scrollbars_click(SB_WND_MAX) will call it */ /* XXX: maybe we need a different name for this * routine instad of passing cryptinc constant? */ scrollbars_click(SB_WND_MAX); tray_update_window_props(); dump_tray_status(); }
void client_message(XClientMessageEvent ev) { int cmode = CM_FDO; struct TrayIcon *ti; #ifdef DEBUG /* Print neat message(s) about this event to aid debugging */ char *msg_type_name; msg_type_name = XGetAtomName(tray_data.dpy, ev.message_type); if (msg_type_name != NULL) { LOG_TRACE(("message \"%s\"\n", msg_type_name)); XFree(msg_type_name); } if (ev.message_type == tray_data.xa_wm_protocols) { msg_type_name = XGetAtomName(tray_data.dpy, ev.data.l[0]); if (msg_type_name != NULL) { LOG_TRACE(("WM_PROTOCOLS message type: %s\n", msg_type_name)); XFree(msg_type_name); } } #endif /* Graceful exit */ if (ev.message_type == tray_data.xa_wm_protocols && ev.data.l[0] == tray_data.xa_wm_delete_window && ev.window == tray_data.tray) { LOG_TRACE(("got WM_DELETE message, will now exit\n")); exit(0); // atexit will call cleanup() } /* Handle _NET_SYSTEM_TRAY_* messages */ if (ev.message_type == tray_data.xa_tray_opcode && tray_data.is_active) { LOG_TRACE(("this is the _NET_SYSTEM_TRAY_OPCODE(%lu) message\n", ev.data.l[1])); switch (ev.data.l[1]) { /* This is the starting point of NET SYSTEM TRAY protocol */ case SYSTEM_TRAY_REQUEST_DOCK: LOG_TRACE(("dockin' requested by window 0x%x, serving in a moment\n", ev.data.l[2])); #ifndef NO_NATIVE_KDE if (kde_tray_check_for_icon(tray_data.dpy, ev.data.l[2])) cmode = CM_KDE; if (kde_tray_is_old_icon(ev.data.l[2])) kde_tray_old_icons_remove(ev.data.l[2]); #endif add_icon(ev.data.l[2], cmode); break; /* We ignore these messages, since we do not show * any baloons anyways */ case SYSTEM_TRAY_BEGIN_MESSAGE: case SYSTEM_TRAY_CANCEL_MESSAGE: break; /* Below are special cases added by this implementation */ /* STALONETRAY_TRAY_DOCK_CONFIRMED is sent by stalonetray * to itself. (see embed.c) */ case STALONE_TRAY_DOCK_CONFIRMED: ti = icon_list_find(ev.data.l[2]); if (ti != NULL && !ti->is_embedded) { ti->is_embedded = True; LOG_TRACE(("embedding confirmed for icon 0x%x\n", ti->wid)); #ifdef DEBUG dump_tray_status(); #endif } tray_update_window_props(); break; /* Dump tray status on request */ case STALONE_TRAY_STATUS_REQUESTED: dump_tray_status(); break; /* Find icon and scroll to it if necessary */ case STALONE_TRAY_REMOTE_CONTROL: ti = icon_list_find(ev.window); if (ti == NULL) break; scrollbars_scroll_to(ti); #if 0 /* Quick hack */ { Window icon = ev.window; int rc; int x = ev.data.l[3], y = ev.data.l[4], depth = 0, idummy, i; int btn = ev.data.l[2]; Window win, root; unsigned int udummy, w, h; XGetGeometry(tray_data.dpy, icon, &root, &idummy, &idummy, &w, &h, &udummy, &udummy); LOG_TRACE(("wid=0x%x w=%d h=%d\n", icon, w, h)); x = (x == REMOTE_CLICK_POS_DEFAULT) ? w / 2 : x; y = (y == REMOTE_CLICK_POS_DEFAULT) ? h / 2 : y; /* 3.2. Find subwindow to execute click on */ win = x11_find_subwindow_at(tray_data.dpy, icon, &x, &y, depth); /* 3.3. Send mouse click(s) to target */ LOG_TRACE(("wid=0x%x btn=%d x=%d y=%d\n", win, btn, x, y)); #define SEND_BTN_EVENT(press, time) do { \ x11_send_button(tray_data.dpy, /* dispslay */ \ press, /* event type */ \ win, /* target window */ \ root, /* root window */ \ time, /* time */ \ btn, /* button */ \ Button1Mask << (btn - 1), /* state mask */ \ x, /* x coord (relative) */ \ y); /* y coord (relative) */ \ } while (0) for (i = 0; i < ev.data.l[0]; i++) { SEND_BTN_EVENT(1, x11_get_server_timestamp(tray_data.dpy, tray_data.tray)); my_usleep(250); SEND_BTN_EVENT(0, x11_get_server_timestamp(tray_data.dpy, tray_data.tray)); } #undef SEND_BTN_EVENT } #endif break; default: break; } } #ifdef DEBUG if (ev.message_type == tray_data.xa_tray_opcode && !tray_data.is_active) LOG_TRACE(("ignoring _NET_SYSTEM_TRAY_OPCODE(%lu) message because tray is not active\n", tray_data.is_active)); #endif }