void selection_clear(XSelectionClearEvent ev) { /* Is it _NET_SYSTEM_TRAY selection? */ if (ev.selection == tray_data.xa_tray_selection) { /* Is it us who has lost the selection */ if (ev.window == tray_data.tray) { LOG_INFO(("another tray detected; deactivating\n")); tray_data.is_active = False; tray_data.old_selection_owner = XGetSelectionOwner(tray_data.dpy, tray_data.xa_tray_selection); if (!x11_ok()) { LOG_INFO(("could not find proper new tray; reactivating\n")); tray_acquire_selection(); }; LOG_TRACE(("new selection owner is 0x%x\n", tray_data.old_selection_owner)); XSelectInput(tray_data.dpy, tray_data.old_selection_owner, StructureNotifyMask); return; } else if (!tray_data.is_active) { /* Someone else has lost selection and tray is not active --- take over the selection */ LOG_INFO(("another tray exited; reactivating\n")); tray_acquire_selection(); } else { /* Just in case */ LOG_TRACE(("WEIRD: tray is active and someone else has lost tray selection\n")); } } }
void destroy_notify(XDestroyWindowEvent ev) { if (!tray_data.is_active && ev.window == tray_data.old_selection_owner) { /* Old tray selection owner was destroyed. Take over selection ownership. */ tray_acquire_selection(); } else if (ev.window != tray_data.tray) { /* Try to remove icon from the tray */ remove_icon(ev.window); #ifndef NO_NATIVE_KDE } else if (kde_tray_is_old_icon(ev.window)) { /* Since X Server may reuse window ids, remove ev.window * from the list of old KDE icons */ kde_tray_old_icons_remove(ev.window); #endif } }
/* main() for usual operation */ static void tray_main(int argc, char **argv, Window window) { X11_enable_event_filter(TRUE); /* Interpret those settings that need an open display */ //interpret_settings(); #ifdef DEBUG ewmh_list_supported_atoms(tray_data.dpy); #endif /* Create and show tray window */ tray_create_window(argc, argv, window); tray_acquire_selection(); //tray_show_window(); #ifndef NO_NATIVE_KDE kde_tray_init(tray_data.dpy); #endif xembed_init(); #ifndef NO_NATIVE_KDE kde_icons_update(); #endif }
/* main() for usual operation */ int tray_main(int argc, char **argv) { XEvent ev; /* Interpret those settings that need an open display */ interpret_settings(); #ifdef DEBUG ewmh_list_supported_atoms(tray_data.dpy); #endif /* Create and show tray window */ tray_create_window(argc, argv); tray_acquire_selection(); tray_show_window(); #ifndef NO_NATIVE_KDE kde_tray_init(tray_data.dpy); #endif xembed_init(); #ifndef NO_NATIVE_KDE kde_icons_update(); #endif /* Main event loop */ while ("my guitar gently wheeps") { /* This is ugly and extra dependency. But who cares? * Rationale: we want to block unless absolutely needed. * This way we ensure that stalonetray does not show up * in powertop (i.e. does not eat unnecessary power and * CPU cycles) * Drawback: handling of signals is very limited. XNextEvent() * does not if signal occurs. This means that graceful * exit on e.g. Ctrl-C cannot be implemented without hacks. */ while (XPending(tray_data.dpy) || tray_data.scrollbars_data.scrollbar_down == -1) { XNextEvent(tray_data.dpy, &ev); xembed_handle_event(ev); scrollbars_handle_event(ev); switch (ev.type) { case VisibilityNotify: LOG_TRACE(("VisibilityNotify (0x%x, state=%d)\n", ev.xvisibility.window, ev.xvisibility.state)); visibility_notify(ev.xvisibility); break; case Expose: LOG_TRACE(("Expose (0x%x)\n", ev.xexpose.window)); expose(ev.xexpose); break; case PropertyNotify: LOG_TRACE(("PropertyNotify(0x%x)\n", ev.xproperty.window)); property_notify(ev.xproperty); break; case DestroyNotify: LOG_TRACE(("DestroyNotify(0x%x)\n", ev.xdestroywindow.window)); destroy_notify(ev.xdestroywindow); break; case ClientMessage: LOG_TRACE(("ClientMessage(from 0x%x?)\n", ev.xclient.window)); client_message(ev.xclient); break; case ConfigureNotify: LOG_TRACE(("ConfigureNotify(0x%x)\n", ev.xconfigure.window)); configure_notify(ev.xconfigure); break; case MapNotify: LOG_TRACE(("MapNotify(0x%x)\n", ev.xmap.window)); map_notify(ev.xmap); break; case ReparentNotify: LOG_TRACE(("ReparentNotify(0x%x to 0x%x)\n", ev.xreparent.window, ev.xreparent.parent)); reparent_notify(ev.xreparent); break; case SelectionClear: LOG_TRACE(("SelectionClear (0x%x has lost selection)\n", ev.xselectionclear.window)); selection_clear(ev.xselectionclear); break; case SelectionNotify: LOG_TRACE(("SelectionNotify\n")); break; case SelectionRequest: LOG_TRACE(("SelectionRequest (from 0x%x to 0x%x)\n", ev.xselectionrequest.requestor, ev.xselectionrequest.owner)); break; case UnmapNotify: LOG_TRACE(("UnmapNotify(0x%x)\n", ev.xunmap.window)); unmap_notify(ev.xunmap); break; default: #if defined(DEBUG) && defined(TRACE_EVENTS) LOG_TRACE(("Unhandled event: %s, serial: %d, window: 0x%x\n", x11_event_names[ev.type], ev.xany.serial, ev.xany.window)); #endif break; } if (tray_data.terminated) goto bailout; /* Perform all periodic tasks but for scrollbars */ perform_periodic_tasks(PT_MASK_ALL & (~PT_MASK_SB)); } perform_periodic_tasks(PT_MASK_ALL); my_usleep(500000L); } bailout: LOG_TRACE(("Clean exit\n")); return 0; }