/** Finish acquiring ownership by checking whether the SetOwner * request succeeded * * \see display_register_cm * \return bool true if it succeeded, false otherwise */ bool display_register_cm_finalise(void) { assert(_get_wm_cm_owner_cookie.sequence); xcb_window_t wm_cm_owner_win; /* Check whether the ownership of WM_CM_Sn succeeded */ return (xcb_ewmh_get_wm_cm_owner_reply(&globalconf.ewmh, _get_wm_cm_owner_cookie, &wm_cm_owner_win, NULL) && wm_cm_owner_win == globalconf.cm_window); }
void Compositor::registerCompositor(QWindow *w) { xcb_ewmh_set_wm_cm_owner(&ewmh_, QX11Info::appScreen(), w->winId(), QX11Info::getTimestamp(), 0, 0); auto wmCmCookie = xcb_ewmh_get_wm_cm_owner_unchecked(&ewmh_, QX11Info::appScreen()); xcb_window_t wmCmOwnerWin = XCB_NONE; if (!xcb_ewmh_get_wm_cm_owner_reply(&ewmh_, wmCmCookie, &wmCmOwnerWin, Q_NULLPTR)) { qFatal("Cannot check _NET_WM_CM_Sn"); } if (wmCmOwnerWin != w->winId()) { qFatal("Another compositing manager is already running"); } }
int check_wm_cm_owner(xcwm_context_t *context) { xcb_get_selection_owner_cookie_t cookie; xcb_window_t wm_owner; cookie = xcb_ewmh_get_wm_cm_owner(&context->atoms.ewmh_conn, context->conn_screen); xcb_ewmh_get_wm_cm_owner_reply(&context->atoms.ewmh_conn, cookie, &wm_owner, NULL); if (wm_owner != XCB_NONE) { return 0; } return 1; }
static gboolean _eventd_nd_xcb_start(EventdNdBackendContext *self, const gchar *target) { gint r; gchar *h; gint d; r = xcb_parse_display(target, &h, &d, NULL); if ( r == 0 ) return FALSE; free(h); const xcb_query_extension_reply_t *extension_query; gint screen; self->source = g_water_xcb_source_new(NULL, target, &screen, _eventd_nd_xcb_events_callback, self, NULL); if ( self->source == NULL ) { g_warning("Couldn't initialize X connection for '%s'", target); return FALSE; } self->xcb_connection = g_water_xcb_source_get_connection(self->source); self->screen_number = screen; self->screen = xcb_aux_get_screen(self->xcb_connection, screen); self->bubbles = g_hash_table_new(NULL, NULL); if ( self->follow_focus != EVENTD_ND_XCB_FOLLOW_FOCUS_NONE ) { guint32 mask[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; xcb_change_window_attributes(self->xcb_connection, self->screen->root, XCB_CW_EVENT_MASK, mask); } xcb_intern_atom_cookie_t *ac; ac = xcb_ewmh_init_atoms(self->xcb_connection, &self->ewmh); xcb_ewmh_init_atoms_replies(&self->ewmh, ac, NULL); extension_query = xcb_get_extension_data(self->xcb_connection, &xcb_randr_id); if ( ! extension_query->present ) g_warning("No RandR extension"); else { self->randr = TRUE; self->randr_event_base = extension_query->first_event; xcb_randr_select_input(self->xcb_connection, self->screen->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); } self->custom_map = _eventd_nd_xcb_get_colormap(self); if ( self->custom_map ) { /* We have a 32bit color map, try to support compositing */ xcb_get_selection_owner_cookie_t oc; xcb_window_t owner; oc = xcb_ewmh_get_wm_cm_owner(&self->ewmh, self->screen_number); self->compositing = xcb_ewmh_get_wm_cm_owner_reply(&self->ewmh, oc, &owner, NULL) && ( owner != XCB_WINDOW_NONE ); extension_query = xcb_get_extension_data(self->xcb_connection, &xcb_xfixes_id); if ( ! extension_query->present ) g_warning("No XFixes extension"); else { xcb_xfixes_query_version_cookie_t vc; xcb_xfixes_query_version_reply_t *r; vc = xcb_xfixes_query_version(self->xcb_connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); r = xcb_xfixes_query_version_reply(self->xcb_connection, vc, NULL); if ( r == NULL ) g_warning("Cannot get XFixes version"); else { self->xfixes = TRUE; self->xfixes_event_base = extension_query->first_event; xcb_xfixes_select_selection_input_checked(self->xcb_connection, self->screen->root, self->ewmh._NET_WM_CM_Sn[self->screen_number], XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE); } } } extension_query = xcb_get_extension_data(self->xcb_connection, &xcb_shape_id); if ( ! extension_query->present ) g_warning("No Shape extension"); else self->shape = TRUE; xcb_flush(self->xcb_connection); _eventd_nd_xcb_check_geometry(self); return TRUE; }
int main(int argc, char **argv) { memset(&globalconf, 0, sizeof(globalconf)); globalconf.connection = xcb_connect(NULL, &globalconf.screen_nbr); if(xcb_connection_has_error(globalconf.connection)) fatal("Cannot open display"); /* Get the root window */ globalconf.screen = xcb_aux_get_screen(globalconf.connection, globalconf.screen_nbr); /* Set up signal handlers and function called on normal exit */ struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_handler = exit_on_signal; sa.sa_flags = 0; sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); atexit(exit_cleanup); /** * First round-trip */ /* Send requests for EWMH atoms initialisation */ xcb_intern_atom_cookie_t *ewmh_cookies = atoms_init(); parse_command_line_parameters(argc, argv); /* Prefetch the extensions data */ xcb_prefetch_extension_data(globalconf.connection, &xcb_composite_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_damage_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_xfixes_id); /* Initialise errors handlers */ xcb_event_handlers_init(globalconf.connection, &globalconf.evenths); event_init_start_handlers(); /* Pre-initialisation of the rendering backend */ if(!rendering_load()) { free(ewmh_cookies); fatal("Can't initialise rendering backend"); } /* Get replies for EWMH atoms initialisation */ if(!atoms_init_finalise(ewmh_cookies)) /* No need to free ewmh_cookies in case of error as it's already handles by xcb-ewmh when getting the replies */ fatal("Cannot initialise atoms"); /* First check whether there is already a Compositing Manager (ICCCM) */ xcb_get_selection_owner_cookie_t wm_cm_owner_cookie = xcb_ewmh_get_wm_cm_owner(&globalconf.ewmh, globalconf.screen_nbr); /** * Second round-trip */ /* Initialise extensions based on the cache and perform initialisation of the rendering backend */ display_init_extensions(); if(!(*globalconf.rendering->init)()) return EXIT_FAILURE; /* Check ownership for WM_CM_Sn before actually claiming it (ICCCM) */ xcb_window_t wm_cm_owner_win; if(xcb_ewmh_get_wm_cm_owner_reply(&globalconf.ewmh, wm_cm_owner_cookie, &wm_cm_owner_win, NULL) && wm_cm_owner_win != XCB_NONE) fatal("A compositing manager is already active (window=%jx)", (uintmax_t) wm_cm_owner_win); /* Now send requests to register the CM */ display_register_cm(); /** * Third round-trip */ /* Check extensions version and finish initialisation of the rendering backend */ display_init_extensions_finalise(); if(!(*globalconf.rendering->init_finalise)()) return EXIT_FAILURE; /* All the plugins given in the configuration file */ plugin_load_all(); /* Validate errors and get PropertyNotify needed to acquire _NET_WM_CM_Sn ownership */ xcb_aux_sync(globalconf.connection); xcb_event_poll_for_event_loop(&globalconf.evenths); globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection); xcb_get_modifier_mapping_cookie_t key_mapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); /* Finish CM X registration */ if(!display_register_cm_finalise()) fatal("Could not acquire _NET_WM_CM_Sn ownership"); /** * Last initialisation round-trip */ /* Grab the server before performing redirection and get the tree of windows to ensure there won't be anything else at the same time */ xcb_grab_server(globalconf.connection); /* Now redirect windows and add existing windows */ display_init_redirect(); /* Validate errors handlers during redirect */ xcb_aux_sync(globalconf.connection); xcb_event_poll_for_event_loop(&globalconf.evenths); /* Manage existing windows */ display_init_redirect_finalise(); xcb_ungrab_server(globalconf.connection); /* Check the plugin requirements which will disable plugins which don't meet the requirements */ plugin_check_requirements(); /* Get the lock masks reply of the request previously sent */ key_lock_mask_get_reply(key_mapping_cookie); /* Initialise normal errors and events handlers */ event_init_handlers(); xcb_generic_event_t *event; /* Flush existing requests before the loop as DamageNotify events may have been received in the meantime */ xcb_flush(globalconf.connection); globalconf.do_repaint = true; /* Main event and error loop */ do { /* Block until an event is received */ event = xcb_wait_for_event(globalconf.connection); /* Check X connection to avoid SIGSEGV */ if(xcb_connection_has_error(globalconf.connection)) fatal("X connection invalid"); xcb_event_handle(&globalconf.evenths, event); free(event); /* Then process all remaining events in the queue because before painting, all the DamageNotify have to be received */ xcb_event_poll_for_event_loop(&globalconf.evenths); /* Now paint the windows */ if(globalconf.do_repaint) { window_t *windows = NULL; for(plugin_t *plugin = globalconf.plugins; plugin; plugin = plugin->next) if(plugin->enable && plugin->vtable->render_windows && (windows = (*plugin->vtable->render_windows)())) break; if(!windows) windows = globalconf.windows; window_paint_all(windows); xcb_aux_sync(globalconf.connection); } globalconf.do_repaint = false; } while(true); return EXIT_SUCCESS; }
Compositor::Compositor() : connection_(QX11Info::connection()), root_(QX11Info::appRootWindow()), damageExt_(xcb_get_extension_data(connection_, &xcb_damage_id)), initFinished_(false) { qRegisterMetaType<ClientWindow *>(); Q_ASSERT(QCoreApplication::instance()); QCoreApplication::instance()->installNativeEventFilter(this); auto ewmhCookie = xcb_ewmh_init_atoms(connection_, &ewmh_); if (!xcb_ewmh_init_atoms_replies(&ewmh_, ewmhCookie, Q_NULLPTR)) { qFatal("Cannot init EWMH"); } auto wmCmCookie = xcb_ewmh_get_wm_cm_owner_unchecked(&ewmh_, QX11Info::appScreen()); xcb_window_t wmCmOwnerWin = XCB_NONE; if (!xcb_ewmh_get_wm_cm_owner_reply(&ewmh_, wmCmCookie, &wmCmOwnerWin, Q_NULLPTR)) { qFatal("Cannot check _NET_WM_CM_Sn"); } if (wmCmOwnerWin) { qFatal("Another compositing manager is already running"); } auto attributesCookie = xcb_get_window_attributes_unchecked(connection_, root_); auto damageQueryVersionCookie = xcb_damage_query_version_unchecked(connection_, 1, 1); auto overlayWindowCookie = xcb_composite_get_overlay_window_unchecked(connection_, root_); auto attributes = xcbReply(xcb_get_window_attributes_reply(connection_, attributesCookie, Q_NULLPTR)); if (!attributes) { qFatal("Cannot get root window attributes"); } auto newEventMask = attributes->your_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_change_window_attributes(connection_, root_, XCB_CW_EVENT_MASK, &newEventMask); auto treeCookie = xcb_query_tree_unchecked(connection_, root_); auto rootGeometryCookie = xcb_get_geometry_unchecked(connection_, root_); auto damageVersion = xcbReply(xcb_damage_query_version_reply(connection_, damageQueryVersionCookie, Q_NULLPTR)); if (!damageVersion) { qFatal("Cannot query version of Damage extension"); } auto overlayWindow = xcbReply(xcb_composite_get_overlay_window_reply(connection_, overlayWindowCookie, Q_NULLPTR)); if (!overlayWindow) { qFatal("Cannot get overlay window"); } overlayWindow_.reset(QWindow::fromWinId(overlayWindow->overlay_win)); auto region = xcb_generate_id(connection_); xcb_xfixes_create_region(connection_, region, 0, Q_NULLPTR); xcb_xfixes_set_window_shape_region(connection_, overlayWindow->overlay_win, XCB_SHAPE_SK_INPUT, 0, 0, region); xcb_xfixes_destroy_region(connection_, region); xcb_composite_redirect_subwindows(connection_, root_, XCB_COMPOSITE_REDIRECT_MANUAL); auto rootGeometry = xcbReply(xcb_get_geometry_reply(connection_, rootGeometryCookie, Q_NULLPTR)); if (!rootGeometry) { qFatal("Cannot query root window geometry"); } rootGeometry_ = QRect(rootGeometry->x, rootGeometry->y, rootGeometry->width, rootGeometry->height); auto tree = xcbReply(xcb_query_tree_reply(connection_, treeCookie, Q_NULLPTR)); if (!tree) { qFatal("Cannot query window tree"); } auto children = xcb_query_tree_children(tree.get()); for (int i = 0; i < xcb_query_tree_children_length(tree.get()); i++) { addChildWindow(children[i]); } updateActiveWindow(); initFinished_ = true; }