int run(config_t* config, key_handler_t key_handler) { int default_screen; xcb_connection_t* c = xcb_connect(NULL, &default_screen); if(xcb_connection_has_error(c)) { fprintf(stderr, "Cannot open display %s\n", getenv("DISPLAY") ? getenv("DISPLAY") : "<NULL>"); return -1; } xcb_screen_t* screen; if(!(screen = xcb_aux_get_screen(c, default_screen))) { fprintf(stderr, "Cannot obtain default screen.\n"); return -1; } context_t context = { config, key_handler }; xcb_event_handlers_t eh; memset(&eh, 0, sizeof(xcb_event_handlers_t)); xcb_event_handlers_init(c, &eh); xcb_event_set_key_press_handler(&eh, handle_keypress, &context); xcb_void_cookie_t* cookies = alloca(sizeof(xcb_void_cookie_t) * config->count); if(!cookies) return -1; int i; for(i = 0; i < config->count; ++i) cookies[i] = xcb_grab_key(c, true, screen->root, config->keys[i].is_alt ? XCB_MOD_MASK_1 : 0, config->keys[i].keysym, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); for(i = 0; i < config->count; ++i) { xcb_generic_error_t* e = xcb_request_check(c, cookies[i]); if(e) { fprintf(stderr, "WARNING: unable to grab key: %d\n", e->error_code); free(e); } } xcb_generic_event_t* e; while((e = xcb_wait_for_event(c))) { xcb_event_handle(&eh, e); free(e); } return 0; }
void xcb_event_poll_for_event_loop(xcb_event_handlers_t *evenths) { xcb_generic_event_t *event; while ((event = xcb_poll_for_event(evenths->c))) { xcb_event_handle(evenths, event); free(event); } }
static void event_task_x_events(void) { xcb_generic_event_t *event; /* Handle all pending events */ while ((event = xcb_poll_for_event(wm_conf.connection))) { if (wm_conf.trace_x_events) print_x_event(event); xcb_event_handle(&wm_conf.event_handlers, event); free(event); xcb_flush(wm_conf.connection); } }
/** Get the current X selection buffer. * \param L The Lua VM state. * \return The number of elements pushed on stack. * \luastack * \lreturn A string with the current X selection buffer. */ int luaA_selection_get(lua_State *L) { if(selection_window == XCB_NONE) { xcb_screen_t *screen = xutil_screen_get(globalconf.connection, globalconf.default_screen); uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; uint32_t values[] = { screen->black_pixel, 1, XCB_EVENT_MASK_PROPERTY_CHANGE }; selection_window = xcb_generate_id(globalconf.connection); xcb_create_window(globalconf.connection, screen->root_depth, selection_window, screen->root, 0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT, screen->root_visual, mask, values); } xcb_convert_selection(globalconf.connection, selection_window, PRIMARY, UTF8_STRING, XSEL_DATA, XCB_CURRENT_TIME); xcb_flush(globalconf.connection); xcb_generic_event_t *event; while(true) { event = xcb_wait_for_event(globalconf.connection); if(!event) return 0; if(XCB_EVENT_RESPONSE_TYPE(event) != XCB_SELECTION_NOTIFY) { /* \todo Eventually, this may be rewritten with adding a static * buffer, then a event handler for XCB_SELECTION_NOTIFY, then call * xcb_event_poll_for_event_loop() and awesome_refresh(), * then check if some static buffer has been filled with data. * If yes, that'd be the xsel data, otherwise, re-loop. * Anyway that's still brokes the socket or D-Bus, so maybe using * ev_loop() would be even better. */ xcb_event_handle(&globalconf.evenths, event); p_delete(&event); awesome_refresh(); continue; } xcb_selection_notify_event_t *event_notify = (xcb_selection_notify_event_t *) event; if(event_notify->selection == PRIMARY && event_notify->property != XCB_NONE) { xcb_get_text_property_reply_t prop; xcb_get_property_cookie_t cookie = xcb_get_text_property(globalconf.connection, event_notify->requestor, event_notify->property); if(xcb_get_text_property_reply(globalconf.connection, cookie, &prop, NULL)) { lua_pushlstring(L, prop.name, prop.name_len); xcb_get_text_property_reply_wipe(&prop); xcb_delete_property(globalconf.connection, event_notify->requestor, event_notify->property); p_delete(&event); return 1; } else break; } } p_delete(&event); return 0; }
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; }