void kde_update_icons() { gulong count = (unsigned) -1; /* grab as many as possible */ Window *ids; unsigned int i; GSList *it, *next; gboolean removed = FALSE; /* were any removed? */ if (! xprop_get32(root, kde_systray_prop, XA_WINDOW, sizeof(Window)*8, &count, &ids)) return; /* add new windows to our list */ for (i = 0; i < count; ++i) { for (it = icons; it != NULL; it = g_slist_next(it)) { TrayWindow *traywin = it->data; if (traywin->id == ids[i]) break; } if (!it) icon_add(ids[i], KDE); } /* remove windows from our list that no longer exist in the property */ for (it = icons; it != NULL;) { TrayWindow *traywin = it->data; gboolean exists; if (traywin->type != KDE) { /* don't go removing non-kde windows */ exists = TRUE; } else { exists = FALSE; for (i = 0; i < count; ++i) { if (traywin->id == ids[i]) { exists = TRUE; break; } } } next = g_slist_next(it); if (!exists) { icon_remove(it); removed =TRUE; } it = next; } if (removed) { /* at least one tray app was removed, so reorganize 'em all and resize*/ reposition_icons(); fix_geometry(); } XFree(ids); }
static void send_xembed_notify(Window w, Window parent){ XEvent ev; ev.xclient.type = ClientMessage; ev.xclient.window = w; ev.xclient.message_type = xembed; ev.xclient.format = 32; ev.xclient.data.l[0] = get_X_time(); ev.xclient.data.l[1] = 0; // XEMBED_EMBEDDED_NOTIFY ev.xclient.data.l[2] = 0; ev.xclient.data.l[3] = parent; ev.xclient.data.l[4] = 0; // version void *v=catch_BadWindow_errors(); XSendEvent(display, w, False, NoEventMask, &ev); if(uncatch_BadWindow_errors(v)){ warn(DEBUG_WARN, "Tray icon %lx is invalid", w); icon_remove(w); } }
static void event(XEvent *ev){ struct trayicon *icon; void *v; switch(ev->type){ case SelectionClear: if(ev->xselectionclear.selection == net_system_tray_s && XGetSelectionOwner(display, net_system_tray_s) != selwindow){ warn(DEBUG_ERROR, "fdtray: Another application (window %lx) has forcibly taken the system tray registration", ev->xselectionclear.window); exitapp = True; } break; case PropertyNotify: if(ev->xproperty.atom != xembed_info) break; icon = icon_find(ev->xproperty.window); if(!icon || icon->type!=my_id) break; v = catch_BadWindow_errors(); Bool map = get_map(icon->w); if(uncatch_BadWindow_errors(v)){ warn(DEBUG_WARN, "Tray icon %lx is invalid", icon->w); icon_remove(icon->w); } else { icon_set_mapping(icon, map); } break; case ConfigureNotify: icon = icon_find(ev->xconfigure.window); if(!icon || icon->type!=my_id) break; v = catch_BadWindow_errors(); { XWindowAttributes a; XGetWindowAttributes(display, icon->w, &a); if(a.width != iconsize || a.height != iconsize) XResizeWindow(display, icon->w, iconsize, iconsize); } if(uncatch_BadWindow_errors(v)){ warn(DEBUG_WARN, "Tray icon %lx is invalid", icon->w); icon_remove(icon->w); } break; case ReparentNotify: icon = icon_find(ev->xreparent.window); if(!icon || icon->type!=my_id) break; if(is_icon_parent(ev->xreparent.parent)){ send_xembed_notify(icon->w, ev->xreparent.parent); } else { warn(DEBUG_WARN, "Tray icon %lx was reparented, removing", icon->w); icon_remove(icon->w); } break; case DestroyNotify: icon = icon_find(ev->xdestroywindow.window); if(!icon || icon->type!=my_id) break; warn(DEBUG_WARN, "Tray icon %lx was destroyed, removing", icon->w); icon_remove(icon->w); break; case ClientMessage: if(ev->xclient.message_type == net_system_tray_opcode){ switch(ev->xclient.data.l[1]){ case 0: // SYSTEM_TRAY_REQUEST_DOCK add(ev->xclient.data.l[2]); break; case 1: // SYSTEM_TRAY_BEGIN_MESSAGE icon = icon_find(ev->xclient.window); if(!icon || icon->type!=my_id) break; *(int *)icon->data = ev->xclient.data.l[4]; icon_begin_message(icon->w, ev->xclient.data.l[4], ev->xclient.data.l[3], ev->xclient.data.l[2]); break; case 2: // SYSTEM_TRAY_CANCEL_MESSAGE icon = icon_find(ev->xclient.window); if(!icon || icon->type!=my_id) break; icon_cancel_message(icon->w, ev->xclient.data.l[2]); break; } } else if(ev->xclient.message_type == net_system_tray_message_data){ icon = icon_find(ev->xclient.window); if(!icon || icon->type!=my_id) break; icon_message_data(icon->w, *(int *)icon->data, ev->xclient.data.b, 20); } break; } }
/* Display functions */ static void update(){ int i, j, x, y, w; int icons_per_page=icons_per_row*icons_per_col*num_windows; char buf[42]; Window dummy; int pages; need_update = False; redo: pages = (num_mapped_icons-1)/icons_per_page+1; if(current_page >= pages){ warn(DEBUG_DEBUG, "Page %d is empty!", current_page+1); current_page=pages-1; } warn(DEBUG_DEBUG, "Updating display: page %d of %d", current_page+1, pages); for(i = 0; i<num_windows; i++){ warn(DEBUG_DEBUG, "Drawing window %d (%lx)", i, iconwin[i]); if(arrow_style==0 || (arrow_style==1 && i==0) || (arrow_style==2 && i==num_windows-1)){ y=(current_page==0)?0:(iconwin[i]==down_window && down_button==-1)?20:10; XCopyArea(display, pixmap, iconwin[i], gc5x8, 0,y, 15,10, 4,52); } if(arrow_style==0 || (arrow_style==1 && i==num_windows-1) || (arrow_style==2 && i==num_windows-1)){ sprintf(buf, "%d/%d", current_page+1, pages); x = strlen(buf); XClearArea(display, iconwin[i], 19,52, 25,8, False); XDrawString(display, iconwin[i], gc5x8, (current_page>8)?19:24,60, buf, x); y=(current_page+1>=pages)?0:(iconwin[i]==down_window && down_button==1)?20:10; XCopyArea(display, pixmap, iconwin[i], gc5x8, 15,y, 15,10, 45,52); } if(id_windows){ sprintf(buf, "%d", i); XDrawString(display, iconwin[i], gc10x20, 8,50, buf, strlen(buf)); } } struct trayicon *icon = icons; i=-current_page*icons_per_page; while(icon){ void *v=catch_BadWindow_errors(); if(!icon->mapped || i<0 || i>=icons_per_page){ warn(DEBUG_DEBUG, "Tray icon %lx is not visible", icon->w); icon->visible = False; if(icon->parent == None){ // Parent it somewhere warn(DEBUG_DEBUG, "Reparenting %lx to %lx", icon->w, iconwin[0]); XReparentWindow(display, icon->w, iconwin[0], 0, 0); icon->parent = iconwin[0]; } XUnmapWindow(display, icon->w); } else { icon->visible = True; j = i; switch(fill_style){ case 0: w = j / (icons_per_row * icons_per_col); j = j % (icons_per_row * icons_per_col); y = j / icons_per_row; x = j % icons_per_row; break; case 1: y = j / (icons_per_row * num_windows); j = j % (icons_per_row * num_windows); w = j / icons_per_row; x = j % icons_per_row; break; default: x=0; y=0; w=0; break; } x=8+x*iconsize; y=4+y*iconsize; warn(DEBUG_DEBUG, "[%d] Tray icon %lx at %d %d,%d", i, icon->w, w, x, y); if(icon->parent != iconwin[w]){ warn(DEBUG_DEBUG, "Reparenting %lx to %lx", icon->w, iconwin[w]); XReparentWindow(display, icon->w, iconwin[w], x, y); icon->parent = iconwin[w]; } XMoveResizeWindow(display, icon->w, x, y, iconsize, iconsize); XClearArea(display, icon->w, 0, 0, 0, 0, True); XMapRaised(display, icon->w); XTranslateCoordinates(display, icon->w, root, iconsize/2, iconsize/2, &icon->x, &icon->y, &dummy); } if(uncatch_BadWindow_errors(v)){ warn(DEBUG_INFO, "Tray icon %lx is invalid, removing and restarting layout", icon->w); icon_remove(icon->w); goto redo; } if(icon->mapped) i++; icon = icon->next; } // XXX: if point_messages is true, can we re-point any notifications? }