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; }
/* Init the events handling queue setting default handler. */ void fwm_event_init() { int i; _this.evenths = &(gd.evenths); xcb_event_handlers_init(gd.conn, _this.evenths); for (i = 0; i < _QUEUE_SIZE; i++) { xcb_event_set_handler(_this.evenths, i + 2, _handle_until_empty_queue, NULL); _this.evenths_queue[i] = NULL; } FWM_MSG("event handling stuff initializated"); }
int main(int argc, char **argv) { xcb_connection_t *connection = xcb_connect(NULL, &wm_conf.default_screen_num); if (xcb_connection_has_error(connection)) { fprintf(stderr, "failed to open display\n"); exit(1); } init_wm_conf(); init_conf_dir(); wm_conf.connection = connection; const xcb_setup_t *setup = xcb_get_setup(connection); int num_screens = xcb_setup_roots_length(setup); fprintf(stderr, "init: num_screens = %d\n", num_screens); fprintf(stderr, "init: default_screen_num = %d\n", wm_conf.default_screen_num); xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; wm_conf.screen = screen; xcb_window_t root_window = screen->root; xcb_grab_server(connection); xcb_flush(connection); xcb_event_handlers_t *event_handlers = &wm_conf.event_handlers; xcb_event_handlers_init(connection, event_handlers); set_exclusive_error_handler(event_handlers, handle_startup_error); /* Try to get substructure redirect events from root window. * This will cause an error if a window manager is already running. */ const uint32_t sub_redirect = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; xcb_change_window_attributes(connection, root_window, XCB_CW_EVENT_MASK, &sub_redirect); /* Need to xcb_flush to validate error handler */ xcb_aux_sync(connection); /* Process all errors in the queue if any */ xcb_event_poll_for_event_loop(event_handlers); scan_windows(); xinerama_test(); set_exclusive_error_handler(event_handlers, handle_error); set_event_handlers(event_handlers); /* Allocate the key symbols */ wm_conf.key_syms = xcb_key_symbols_alloc(connection); fprintf(stderr, "selecting events from root window\n"); const uint32_t root_win_event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_FOCUS_CHANGE; xcb_change_window_attributes(connection, root_window, XCB_CW_EVENT_MASK, &root_win_event_mask); xcb_ungrab_server(connection); xcb_flush(connection); wm_conf.repl_server = repl_server_init(); load_init_scheme(); fprintf(stderr, "entering event loop\n"); event_loop(); xcb_disconnect(connection); 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; }