/** * sn_xcb_display_process_event: * @display: a display * @xevent: X event * * libsn should be given a chance to see all X events by passing them * to this function. If the event was a property notify or client * message related to the launch feedback protocol, the * sn_display_process_event() returns true. Calling * sn_display_process_event() is not currently required for launchees, * only launchers and launch feedback displayers. The function returns * false for mapping, unmapping, window destruction, and selection * events even if they were involved in launch feedback. * * Return value: true if the event was a property notify or client message involved in launch feedback **/ sn_bool_t sn_xcb_display_process_event (SnDisplay *display, xcb_generic_event_t *xevent) { sn_bool_t retval; retval = FALSE; if (sn_internal_monitor_process_event (display)) retval = TRUE; switch(XCB_EVENT_RESPONSE_TYPE(xevent)) { case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t *ev = (xcb_client_message_event_t *) xevent; if (sn_internal_xmessage_process_client_message (display, ev->window, ev->type, (const char *) ev->data.data8)) retval = TRUE; } break; default: break; } return retval; }
static leaf_error_t leaf_run() { xcb_generic_event_t *event = NULL; int etype; leaf_error_t status = ERR_NONE; /* Start main loop */ gconf.running = true; do { event = xcb_poll_for_event(gconf.conn); if (!event) { if (xcb_connection_has_error(gconf.conn)) return ERR_CONN; continue; } etype = XCB_EVENT_RESPONSE_TYPE(event); /* Only for debug prupose */ print_event(etype); /* Execute specific event handler */ if (geventhandlers[etype]) if (geventhandlers[etype](event) != EVENT_ERR_NONE) status = ERR_EVENT; free(event); } while (gconf.running && status == ERR_NONE); return status; }
static void a_xcb_check_cb(EV_P_ ev_check *w, int revents) { xcb_generic_event_t *mouse = NULL, *event; while((event = xcb_poll_for_event(globalconf.connection))) { /* We will treat mouse events later. * We cannot afford to treat all mouse motion events, * because that would be too much CPU intensive, so we just * take the last we get after a bunch of events. */ if(XCB_EVENT_RESPONSE_TYPE(event) == XCB_MOTION_NOTIFY) { p_delete(&mouse); mouse = event; } else { event_handle(event); p_delete(&event); } } if(mouse) { event_handle(mouse); p_delete(&mouse); } }
static void kt_xcb_event_handler(xcb_connection_t *c) { xcb_generic_event_t *event = NULL; while((event = xcb_poll_for_event(c))) { guint8 response_type; response_type = XCB_EVENT_RESPONSE_TYPE(event); if (response_type != 0) { handle_x_event(response_type, event); } } xcb_flush(c); }
int main(void) { xcb_connection_t *dpy = xcb_connect(NULL, NULL); if (dpy == NULL) { fprintf(stderr, "Can't connect to X.\n"); return EXIT_FAILURE; } xcb_atom_t WM_PROTOCOLS, WM_DELETE_WINDOW; if (!get_atom(dpy, "WM_PROTOCOLS", &WM_PROTOCOLS) || !get_atom(dpy, "WM_DELETE_WINDOW", &WM_DELETE_WINDOW)) { fprintf(stderr, "Can't get required atoms.\n"); xcb_disconnect(dpy); return EXIT_FAILURE; } xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; if (screen == NULL) { fprintf(stderr, "Can't get current screen.\n"); xcb_disconnect(dpy); return EXIT_FAILURE; } xcb_window_t win = xcb_generate_id(dpy); uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; uint32_t values[] = {0xff111111, XCB_EVENT_MASK_EXPOSURE}; xcb_create_window(dpy, XCB_COPY_FROM_PARENT, win, screen->root, 0, 0, 320, 240, 2, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, mask, values); xcb_icccm_set_wm_class(dpy, win, sizeof(TEST_WINDOW_IC), TEST_WINDOW_IC); xcb_map_window(dpy, win); xcb_flush(dpy); xcb_generic_event_t *evt; bool running = true; while (running && (evt = xcb_wait_for_event(dpy)) != NULL) { uint8_t rt = XCB_EVENT_RESPONSE_TYPE(evt); if (rt == XCB_CLIENT_MESSAGE) { xcb_client_message_event_t *cme = (xcb_client_message_event_t *) evt; if (cme->type == WM_PROTOCOLS && cme->data.data32[0] == WM_DELETE_WINDOW) { running = false; } } else if (rt == XCB_EXPOSE) { render_text(dpy, win, 12, 24); } free(evt); } xcb_destroy_window(dpy, win); xcb_disconnect(dpy); return EXIT_SUCCESS; }
bool title_changed(xcb_generic_event_t *evt, xcb_window_t *win, xcb_window_t *last_win) { if (XCB_EVENT_RESPONSE_TYPE(evt) == XCB_PROPERTY_NOTIFY) { xcb_property_notify_event_t *pne = (xcb_property_notify_event_t *) evt; if (pne->atom == ewmh->_NET_ACTIVE_WINDOW) { watch(*last_win, false); if (get_active_window(win)) { watch(*win, true); *last_win = *win; } else { *win = *last_win = XCB_NONE; } return true; } else if (*win != XCB_NONE && pne->window == *win && (pne->atom == ewmh->_NET_WM_NAME || pne->atom == XCB_ATOM_WM_NAME)) { return true; } } return false; }
void handle_event(xcb_generic_event_t *evt) { uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt); switch (resp_type) { case XCB_MAP_REQUEST: map_request(evt); break; case XCB_DESTROY_NOTIFY: destroy_notify(evt); break; case XCB_UNMAP_NOTIFY: unmap_notify(evt); break; case XCB_CLIENT_MESSAGE: client_message(evt); break; case XCB_CONFIGURE_REQUEST: configure_request(evt); break; case XCB_PROPERTY_NOTIFY: property_notify(evt); break; case XCB_ENTER_NOTIFY: enter_notify(evt); break; case XCB_MOTION_NOTIFY: motion_notify(evt); break; case XCB_FOCUS_IN: focus_in(evt); break; case 0: process_error(evt); break; default: if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { update_monitors(); } break; } }
bool FdoSelectionManager::nativeEventFilter(const QByteArray& eventType, void* message, long int* result) { Q_UNUSED(result); if (eventType != "xcb_generic_event_t") { return false; } xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message); auto responseType = XCB_EVENT_RESPONSE_TYPE(ev); if (responseType == XCB_CLIENT_MESSAGE) { auto ce = reinterpret_cast<xcb_client_message_event_t *>(ev); if (ce->type == Xcb::atoms->opcodeAtom) { switch (ce->data.data32[1]) { case SYSTEM_TRAY_REQUEST_DOCK: dock(ce->data.data32[2]); return true; } } } else if (responseType == XCB_UNMAP_NOTIFY) { auto unmappedWId = reinterpret_cast<xcb_unmap_notify_event_t *>(ev)->window; if (m_proxies[unmappedWId]) { undock(unmappedWId); } } else if (responseType == m_damageEventBase + XCB_DAMAGE_NOTIFY) { auto damagedWId = reinterpret_cast<xcb_damage_notify_event_t *>(ev)->drawable; auto sniProx = m_proxies[damagedWId]; Q_ASSERT(sniProx); if(sniProx) { sniProx->update(); xcb_damage_subtract(QX11Info::connection(), m_damageWatches[damagedWId], XCB_NONE, XCB_NONE); } } return false; }
bool Compositor::nativeEventFilter(const QByteArray &eventType, void *message, long *) { Q_ASSERT(eventType == QByteArrayLiteral("xcb_generic_event_t")); auto responseType = XCB_EVENT_RESPONSE_TYPE(static_cast<xcb_generic_event_t *>(message)); if (responseType == damageExt_->first_event + XCB_DAMAGE_NOTIFY) { auto e = static_cast<xcb_damage_notify_event_t *>(message); auto i = pixmaps_.constFind(e->damage); if (i == pixmaps_.constEnd()) { return false; } (*i)->xcbEvent(e); return true; } switch (responseType) { case XCB_CREATE_NOTIFY: return xcbEvent(static_cast<xcb_create_notify_event_t *>(message)); case XCB_DESTROY_NOTIFY: return xcbEvent(static_cast<xcb_destroy_notify_event_t *>(message)); case XCB_REPARENT_NOTIFY: return xcbEvent(static_cast<xcb_reparent_notify_event_t *>(message)); case XCB_CONFIGURE_NOTIFY: return xcbEvent(static_cast<xcb_configure_notify_event_t *>(message)); case XCB_MAP_NOTIFY: return xcbEvent(static_cast<xcb_map_notify_event_t *>(message)); case XCB_UNMAP_NOTIFY: return xcbEvent(static_cast<xcb_unmap_notify_event_t *>(message)); case XCB_GRAVITY_NOTIFY: return xcbEvent(static_cast<xcb_gravity_notify_event_t *>(message)); case XCB_CIRCULATE_NOTIFY: return xcbEvent(static_cast<xcb_circulate_notify_event_t *>(message)); case XCB_PROPERTY_NOTIFY: return xcbEvent(static_cast<xcb_property_notify_event_t *>(message)); default: return false; } }
/* Handle a single event executing the handlers within its queue. * Prints an event dumb in case of empty queue. */ static void _handle(xcb_generic_event_t *e) { uint8_t sendEvent; uint16_t seq_num; fwm_eq_node_t *next_node; uint8_t response_type; fwm_eq_head_t *head; xcb_generic_error_t *er; /* Iterate queued handlers, if any. */ response_type = XCB_EVENT_RESPONSE_TYPE(e); if (response_type) { head = _this.evenths_queue[response_type - 2]; if (head != NULL) { next_node = head->first; while (next_node != NULL) { ((fwm_event_handler_t) (next_node->handler))(e); next_node = next_node->next; } } } else { /* Or format event if not to be handled. */ sendEvent = response_type ? 1 : 0; seq_num = *((uint16_t *) e + 1); switch (response_type) { case 0: er = (xcb_generic_error_t *) e; printf("Error (%s) on sequence number %d.\n", xcb_event_get_error_label(er->error_code), seq_num); break; default: printf("Unhandler event (%s) following seqnum %d.\n", xcb_event_get_label(response_type), seq_num); break; } fflush(stdout); } }
static void process_events(xcb_connection_t *c, xcb_gcontext_t g, xcb_window_t w, xcb_pixmap_t p, uint32_t width, uint32_t height) { xcb_generic_event_t *e; xcb_void_cookie_t cookie; while ((e = xcb_wait_for_event(c))) { uint32_t r = XCB_EVENT_RESPONSE_TYPE(e); xcb_generic_error_t *err; fprintf(stderr, "event %d\n", r); switch (r) { case XCB_EXPOSE: case XCB_MAP_NOTIFY: cookie = xcb_copy_area_checked(c, p, w, g, 0, 0, 0, 0, width, height); assert(!xcb_request_check(c, cookie)); break; case XCB_BUTTON_PRESS: exit(0); break; case 0: err = (xcb_generic_error_t *) e; printf("error: %d (sequence %d)\n", err->error_code, (unsigned int) err->full_sequence); exit(1); default: break; } free(e); } }
/** Emit a button signal. * The top of the lua stack has to be the object on which to emit the event. * \param L The Lua VM state. * \param ev The event to handle. */ static void event_emit_button(lua_State *L, xcb_button_press_event_t *ev) { const char *name; switch(XCB_EVENT_RESPONSE_TYPE(ev)) { case XCB_BUTTON_PRESS: name = "button::press"; break; case XCB_BUTTON_RELEASE: name = "button::release"; break; default: fatal("Invalid event type"); } /* Push the event's info */ lua_pushinteger(L, ev->event_x); lua_pushinteger(L, ev->event_y); lua_pushinteger(L, ev->detail); luaA_pushmodifiers(L, ev->state); /* And emit the signal */ luaA_object_emit_signal(L, -5, name, 4); }
void track_pointer(coordinates_t loc, pointer_action_t pac, xcb_point_t pos) { node_t *n = loc.node; resize_handle_t rh = get_handle(loc.node, pos, pac); uint16_t last_motion_x = pos.x, last_motion_y = pos.y; xcb_timestamp_t last_motion_time = 0; xcb_generic_event_t *evt = NULL; grabbing = true; grabbed_node = n; do { free(evt); while ((evt = xcb_wait_for_event(dpy)) == NULL) { xcb_flush(dpy); } uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt); if (resp_type == XCB_MOTION_NOTIFY) { xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t*) evt; uint32_t dtime = e->time - last_motion_time; if (dtime < pointer_motion_interval) { continue; } last_motion_time = e->time; int16_t dx = e->root_x - last_motion_x; int16_t dy = e->root_y - last_motion_y; if (pac == ACTION_MOVE) { move_client(&loc, dx, dy); } else { resize_client(&loc, rh, e->root_x, e->root_y, false); } last_motion_x = e->root_x; last_motion_y = e->root_y; xcb_flush(dpy); } else if (resp_type == XCB_BUTTON_RELEASE) { grabbing = false; } else { handle_event(evt); } } while (grabbing && grabbed_node != NULL); free(evt); xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME); if (grabbed_node == NULL) { grabbing = false; return; } if (pac == ACTION_MOVE) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X move end\n", loc.monitor->id, loc.desktop->id, n->id); } else if (pac == ACTION_RESIZE_CORNER) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_corner end\n", loc.monitor->id, loc.desktop->id, n->id); } else if (pac == ACTION_RESIZE_SIDE) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_side end\n", loc.monitor->id, loc.desktop->id, n->id); } xcb_rectangle_t r = get_rectangle(NULL, NULL, n); put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, loc.node->id, r.width, r.height, r.x, r.y); if ((pac == ACTION_MOVE && IS_TILED(n->client)) || ((pac == ACTION_RESIZE_CORNER || pac == ACTION_RESIZE_SIDE) && n->client->state == STATE_TILED)) { for (node_t *f = first_extrema(loc.desktop->root); f != NULL; f = next_leaf(f, loc.desktop->root)) { if (f == n || f->client == NULL || !IS_TILED(f->client)) { continue; } xcb_rectangle_t r = f->client->tiled_rectangle; put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, f->id, r.width, r.height, r.x, r.y); } } }
void xpost_view_main_loop(const Xpost_View_Window *win) { xcb_intern_atom_cookie_t cookie1; xcb_intern_atom_cookie_t cookie2; xcb_intern_atom_reply_t* reply1; xcb_intern_atom_reply_t* reply2; int finished; /* * Listen to X client messages in order to be able to pickup * the "delete window" message that is generated for example * when someone clicks the top-right X button within the window * manager decoration (or when user hits ALT-F4). */ cookie1 = xcb_intern_atom(win->c, 1, sizeof("WM_DELETE_WINDOW") - 1, "WM_DELETE_WINDOW"); cookie2 = xcb_intern_atom(win->c, 1, sizeof("WM_PROTOCOLS") - 1, "WM_PROTOCOLS"); reply1 = xcb_intern_atom_reply(win->c, cookie1, 0); reply2 = xcb_intern_atom_reply(win->c, cookie2, 0); xcb_change_property(win->c, XCB_PROP_MODE_REPLACE, win->window, reply2->atom, 4, 32, 1, &reply1->atom); finished = 0; while (!finished) { xcb_generic_event_t *e; if ((e = xcb_poll_for_event(win->c))) { switch (XCB_EVENT_RESPONSE_TYPE(e)) { case XCB_EXPOSE: xcb_image_put(win->c, win->window, win->gc, win->image, 0, 0, 0); xcb_flush(win->c); break; case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t *event; printf("client message\n"); event = (xcb_client_message_event_t *)e; if (event->data.data32[0] == reply1->atom) finished = 1; break; } case XCB_BUTTON_PRESS: printf("button pressed\n"); finished = 1; break; case XCB_KEY_RELEASE: { xcb_key_release_event_t *event; event = (xcb_key_release_event_t *)e; if (event->detail == 113) xpost_view_page_change(-1); if (event->detail == 114) xpost_view_page_change(1); break; } } free (e); } xcb_flush (win->c); } free(reply2); free(reply1); }
void print_x_event(xcb_generic_event_t *event) { uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event); const char *label = xcb_event_get_label(event_type); fprintf(stderr, "X event %d : %s\n", event_type, label); }
/** Hello, this is main. * \param argc Who knows. * \param argv Who knows. * \return EXIT_SUCCESS I hope. */ int main(int argc, char **argv) { char *confpath = NULL; int xfd, i, screen_nbr, opt, colors_nbr; xcolor_init_request_t colors_reqs[2]; ssize_t cmdlen = 1; xdgHandle xdg; xcb_generic_event_t *event; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "check", 0, NULL, 'k' }, { NULL, 0, NULL, 0 } }; /* event loop watchers */ ev_io xio = { .fd = -1 }; ev_check xcheck; ev_prepare a_refresh; ev_signal sigint; ev_signal sigterm; ev_signal sighup; /* clear the globalconf structure */ p_clear(&globalconf, 1); globalconf.keygrabber = LUA_REFNIL; globalconf.mousegrabber = LUA_REFNIL; buffer_init(&globalconf.startup_errors); /* save argv */ for(i = 0; i < argc; i++) cmdlen += a_strlen(argv[i]) + 1; globalconf.argv = p_new(char, cmdlen); a_strcpy(globalconf.argv, cmdlen, argv[0]); for(i = 1; i < argc; i++) { a_strcat(globalconf.argv, cmdlen, " "); a_strcat(globalconf.argv, cmdlen, argv[i]); } /* Text won't be printed correctly otherwise */ setlocale(LC_CTYPE, ""); /* Get XDG basedir data */ xdgInitHandle(&xdg); /* init lua */ luaA_init(&xdg); /* check args */ while((opt = getopt_long(argc, argv, "vhkc:", long_options, NULL)) != -1) switch(opt) { case 'v': eprint_version(); break; case 'h': exit_help(EXIT_SUCCESS); break; case 'k': if(!luaA_parserc(&xdg, confpath, false)) { fprintf(stderr, "✘ Configuration file syntax error.\n"); return EXIT_FAILURE; } else { fprintf(stderr, "✔ Configuration file syntax OK.\n"); return EXIT_SUCCESS; } case 'c': if(a_strlen(optarg)) confpath = a_strdup(optarg); else fatal("-c option requires a file name"); break; } globalconf.loop = ev_default_loop(0); ev_timer_init(&globalconf.timer, &luaA_on_timer, 0., 0.); /* register function for signals */ ev_signal_init(&sigint, exit_on_signal, SIGINT); ev_signal_init(&sigterm, exit_on_signal, SIGTERM); ev_signal_init(&sighup, restart_on_signal, SIGHUP); ev_signal_start(globalconf.loop, &sigint); ev_signal_start(globalconf.loop, &sigterm); ev_signal_start(globalconf.loop, &sighup); ev_unref(globalconf.loop); ev_unref(globalconf.loop); ev_unref(globalconf.loop); struct sigaction sa = { .sa_handler = signal_fatal, .sa_flags = 0 }; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, 0); /* XLib sucks */ XkbIgnoreExtension(True); /* X stuff */ globalconf.display = XOpenDisplay(NULL); if (globalconf.display == NULL) fatal("cannot open display"); globalconf.default_screen = XDefaultScreen(globalconf.display); globalconf.connection = XGetXCBConnection(globalconf.display); /* Double checking then everything is OK. */ if(xcb_connection_has_error(globalconf.connection)) fatal("cannot open display"); /* Prefetch all the extensions we might need */ xcb_prefetch_extension_data(globalconf.connection, &xcb_big_requests_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_test_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_shape_id); /* initialize dbus */ a_dbus_init(); /* Get the file descriptor corresponding to the X connection */ xfd = xcb_get_file_descriptor(globalconf.connection); ev_io_init(&xio, &a_xcb_io_cb, xfd, EV_READ); ev_io_start(globalconf.loop, &xio); ev_check_init(&xcheck, &a_xcb_check_cb); ev_check_start(globalconf.loop, &xcheck); ev_unref(globalconf.loop); ev_prepare_init(&a_refresh, &a_refresh_cb); ev_prepare_start(globalconf.loop, &a_refresh); ev_unref(globalconf.loop); /* Grab server */ xcb_grab_server(globalconf.connection); /* Make sure there are no pending events. Since we didn't really do anything * at all yet, we will just discard all events which we received so far. * The above GrabServer should make sure no new events are generated. */ xcb_aux_sync(globalconf.connection); while ((event = xcb_poll_for_event(globalconf.connection)) != NULL) { /* Make sure errors are printed */ uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event); if(response_type == 0) event_handle(event); p_delete(&event); } for(screen_nbr = 0; screen_nbr < xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); screen_nbr++) { const uint32_t select_input_val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; /* This causes an error if some other window manager is running */ xcb_change_window_attributes(globalconf.connection, xutil_screen_get(globalconf.connection, screen_nbr)->root, XCB_CW_EVENT_MASK, &select_input_val); } /* Need to xcb_flush to validate error handler */ xcb_aux_sync(globalconf.connection); /* Process all errors in the queue if any. There can be no events yet, so if * this function returns something, it must be an error. */ if (xcb_poll_for_event(globalconf.connection) != NULL) fatal("another window manager is already running"); /* Prefetch the maximum request length */ xcb_prefetch_maximum_request_length(globalconf.connection); /* check for xtest extension */ const xcb_query_extension_reply_t *xtest_query; xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id); globalconf.have_xtest = xtest_query->present; /* Allocate the key symbols */ globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection); xcb_get_modifier_mapping_cookie_t xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); /* init atom cache */ atoms_init(globalconf.connection); /* init screens information */ screen_scan(); /* init default font and colors */ colors_reqs[0] = xcolor_init_unchecked(&globalconf.colors.fg, "black", sizeof("black") - 1); colors_reqs[1] = xcolor_init_unchecked(&globalconf.colors.bg, "white", sizeof("white") - 1); globalconf.font = draw_font_new("sans 8"); for(colors_nbr = 0; colors_nbr < 2; colors_nbr++) xcolor_init_reply(colors_reqs[colors_nbr]); xutil_lock_mask_get(globalconf.connection, xmapping_cookie, globalconf.keysyms, &globalconf.numlockmask, &globalconf.shiftlockmask, &globalconf.capslockmask, &globalconf.modeswitchmask); /* Get the window tree associated to this screen */ const int screen_max = xcb_setup_roots_length(xcb_get_setup(globalconf.connection)); xcb_query_tree_cookie_t tree_c[screen_max]; /* do this only for real screen */ for(screen_nbr = 0; screen_nbr < screen_max; screen_nbr++) { /* select for events */ const uint32_t change_win_vals[] = { 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 }; tree_c[screen_nbr] = xcb_query_tree_unchecked(globalconf.connection, xutil_screen_get(globalconf.connection, screen_nbr)->root); xcb_change_window_attributes(globalconf.connection, xutil_screen_get(globalconf.connection, screen_nbr)->root, XCB_CW_EVENT_MASK, change_win_vals); ewmh_init(screen_nbr); systray_init(screen_nbr); } /* init spawn (sn) */ spawn_init(); /* we will receive events, stop grabbing server */ xcb_ungrab_server(globalconf.connection); /* Parse and run configuration file */ if (!luaA_parserc(&xdg, confpath, true)) fatal("couldn't find any rc file"); scan(tree_c); xcb_flush(globalconf.connection); /* main event loop */ ev_loop(globalconf.loop, 0); /* cleanup event loop */ ev_ref(globalconf.loop); ev_check_stop(globalconf.loop, &xcheck); ev_ref(globalconf.loop); ev_prepare_stop(globalconf.loop, &a_refresh); ev_ref(globalconf.loop); ev_io_stop(globalconf.loop, &xio); awesome_atexit(false); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { char opt; char *fifo_path = NULL; char *socket_path = NULL; status_fifo = NULL; config_path = NULL; mapping_count = 0; timeout = TIMEOUT; grabbed = false; sock_address.sun_family = AF_UNIX; sock_address.sun_path[0] = 0; snprintf(motion_msg_tpl, sizeof(motion_msg_tpl), "%s", MOTION_MSG_TPL); unsigned int max_freq = 0; motion_interval = 0; last_motion_time = 0; redir_fd = -1; while ((opt = getopt(argc, argv, "vhm:t:c:r:s:f:o:g:")) != (char)-1) { switch (opt) { case 'v': printf("%s\n", VERSION); exit(EXIT_SUCCESS); break; case 'h': printf("sxhkd [-h|-v|-m COUNT|-t TIMEOUT|-c CONFIG_FILE|-r REDIR_FILE|-s STATUS_FIFO|-o MOTION_SOCKET|-g MOTION_MSG_TPL] [EXTRA_CONFIG ...]\n"); exit(EXIT_SUCCESS); break; case 'm': if (sscanf(optarg, "%i", &mapping_count) != 1) warn("Can't parse mapping count.\n"); break; case 't': timeout = atoi(optarg); break; case 'c': config_path = optarg; break; case 'r': redir_fd = open(optarg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (redir_fd == -1) warn("Failed to open the command redirection file.\n"); break; case 's': fifo_path = optarg; break; case 'o': socket_path = optarg; break; case 'g': snprintf(motion_msg_tpl, sizeof(motion_msg_tpl), "%s", optarg); break; case 'f': if (sscanf(optarg, "%u", &max_freq) != 1) warn("Can't parse maximum pointer frequency.\n"); break; } } num_extra_confs = argc - optind; extra_confs = argv + optind; if (config_path == NULL) { char *config_home = getenv(CONFIG_HOME_ENV); if (config_home != NULL) snprintf(config_file, sizeof(config_file), "%s/%s", config_home, CONFIG_PATH); else snprintf(config_file, sizeof(config_file), "%s/%s/%s", getenv("HOME"), ".config", CONFIG_PATH); } else { snprintf(config_file, sizeof(config_file), "%s", config_path); } if (socket_path == NULL) { socket_path = getenv(SOCKET_ENV); } if (socket_path == NULL) { char *host = NULL; int dn = 0, sn = 0; if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) { snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn); } else { warn("Failed to set motion socket address."); } free(host); } else { snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path); } if (fifo_path != NULL) { int fifo_fd = open(fifo_path, O_RDWR | O_NONBLOCK); if (fifo_fd != -1) status_fifo = fdopen(fifo_fd, "w"); else warn("Couldn't open status fifo.\n"); } if (max_freq != 0) motion_interval = 1000.0 / max_freq; signal(SIGINT, hold); signal(SIGHUP, hold); signal(SIGTERM, hold); signal(SIGUSR1, hold); signal(SIGUSR2, hold); signal(SIGALRM, hold); setup(); get_standard_keysyms(); get_lock_fields(); escape_chord = make_chord(ESCAPE_KEYSYM, XCB_NONE, 0, XCB_KEY_PRESS, false, false); load_config(config_file); for (int i = 0; i < num_extra_confs; i++) load_config(extra_confs[i]); grab(); xcb_generic_event_t *evt; int fd = xcb_get_file_descriptor(dpy); fd_set descriptors; reload = toggle_grab = bell = chained = locked = false; running = true; xcb_flush(dpy); while (running) { FD_ZERO(&descriptors); FD_SET(fd, &descriptors); if (select(fd + 1, &descriptors, NULL, NULL, NULL) > 0) { while ((evt = xcb_poll_for_event(dpy)) != NULL) { uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(evt); switch (event_type) { case XCB_KEY_PRESS: case XCB_KEY_RELEASE: case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: key_button_event(evt, event_type); break; case XCB_MOTION_NOTIFY: motion_notify(evt); break; case XCB_MAPPING_NOTIFY: mapping_notify(evt); break; default: PRINTF("received event %u\n", event_type); break; } free(evt); } } if (reload) { signal(SIGUSR1, hold); reload_cmd(); reload = false; } if (toggle_grab) { signal(SIGUSR2, hold); toggle_grab_cmd(); toggle_grab = false; } if (bell) { signal(SIGALRM, hold); abort_chain(); if (status_fifo != NULL) put_status(TIMEOUT_PREFIX, "Timeout reached"); bell = false; } if (xcb_connection_has_error(dpy)) { warn("The server closed the connection.\n"); running = false; } } if (redir_fd != -1) close(redir_fd); if (status_fifo != NULL) fclose(status_fifo); ungrab(); cleanup(); destroy_chord(escape_chord); xcb_key_symbols_free(symbols); xcb_disconnect(dpy); return EXIT_SUCCESS; }
/** The button press event handler. * \param ev The event. */ static void event_handle_button(xcb_button_press_event_t *ev) { lua_State *L = globalconf_get_lua_State(); client_t *c; drawin_t *drawin; globalconf.timestamp = ev->time; { /* ev->state contains the state before the event. Compute the state * after the event for the mousegrabber. */ uint16_t state = ev->state, change = 1 << (ev->detail - 1 + 8); if (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_BUTTON_PRESS) state |= change; else state &= ~change; if(event_handle_mousegrabber(ev->root_x, ev->root_y, state)) return; } /* ev->state is * button status (8 bits) + modifiers status (8 bits) * we don't care for button status that we get, especially on release, so * drop them */ ev->state &= 0x00ff; if((drawin = drawin_getbywin(ev->event)) || (drawin = drawin_getbywin(ev->child))) { /* If the drawin is child, then x,y are * relative to root window */ if(drawin->window == ev->child) { ev->event_x -= drawin->geometry.x + drawin->border_width; ev->event_y -= drawin->geometry.y + drawin->border_width; } /* Push the drawable */ luaA_object_push(L, drawin); luaA_object_push_item(L, -1, drawin->drawable); /* and handle the button raw button event */ event_emit_button(L, ev); lua_pop(L, 1); /* check if any button object matches */ event_button_callback(ev, &drawin->buttons, L, -1, 1, NULL); /* Either we are receiving this due to ButtonPress/Release on the root * window or because we grabbed the button on the window. In the later * case we have to call AllowEvents. * Use AsyncPointer instead of ReplayPointer so that the event is * "eaten" instead of being handled again on the root window. */ if(ev->child == XCB_NONE) xcb_allow_events(globalconf.connection, XCB_ALLOW_ASYNC_POINTER, ev->time); } else if((c = client_getbyframewin(ev->event)) || (c = client_getbywin(ev->event))) { /* For clicks inside of c->window, we get two events. Once because of a * passive grab on c->window and then again for c->frame_window. * Ignore the second event (identifiable by ev->child != XCB_NONE). */ if (ev->event != c->frame_window || ev->child == XCB_NONE) { luaA_object_push(L, c); if (c->window == ev->event) { /* Button event into the client itself (not titlebar), translate * into the frame window. */ ev->event_x += c->titlebar[CLIENT_TITLEBAR_LEFT].size; ev->event_y += c->titlebar[CLIENT_TITLEBAR_TOP].size; } /* And handle the button raw button event */ event_emit_button(L, ev); /* then check if a titlebar was "hit" */ if (c->frame_window == ev->event) { int x = ev->event_x, y = ev->event_y; drawable_t *d = client_get_drawable_offset(c, &x, &y); if (d) { /* Copy the event so that we can fake x/y */ xcb_button_press_event_t event = *ev; event.event_x = x; event.event_y = y; luaA_object_push_item(L, -1, d); event_emit_button(L, &event); lua_pop(L, 1); } } /* then check if any button objects match */ event_button_callback(ev, &c->buttons, L, -1, 1, NULL); } xcb_allow_events(globalconf.connection, XCB_ALLOW_REPLAY_POINTER, ev->time); } else if(ev->child == XCB_NONE) if(globalconf.screen->root == ev->event) { event_button_callback(ev, &globalconf.buttons, L, 0, 0, NULL); return; } }
/** Hello, this is main. * \param argc Who knows. * \param argv Who knows. * \return EXIT_SUCCESS I hope. */ int main(int argc, char **argv) { char *confpath = NULL; int xfd, i, opt; ssize_t cmdlen = 1; xdgHandle xdg; bool no_argb = false; xcb_generic_event_t *event; xcb_query_tree_cookie_t tree_c; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "check", 0, NULL, 'k' }, { "no-argb", 0, NULL, 'a' }, { NULL, 0, NULL, 0 } }; /* event loop watchers */ ev_io xio = { .fd = -1 }; ev_check xcheck; ev_prepare a_refresh; ev_signal sigint; ev_signal sigterm; ev_signal sighup; /* clear the globalconf structure */ p_clear(&globalconf, 1); globalconf.keygrabber = LUA_REFNIL; globalconf.mousegrabber = LUA_REFNIL; buffer_init(&globalconf.startup_errors); /* save argv */ for(i = 0; i < argc; i++) cmdlen += a_strlen(argv[i]) + 1; awesome_argv = p_new(char, cmdlen); a_strcpy(awesome_argv, cmdlen, argv[0]); for(i = 1; i < argc; i++) { a_strcat(awesome_argv, cmdlen, " "); a_strcat(awesome_argv, cmdlen, argv[i]); } /* Text won't be printed correctly otherwise */ setlocale(LC_CTYPE, ""); /* Get XDG basedir data */ xdgInitHandle(&xdg); /* init lua */ luaA_init(&xdg); /* check args */ while((opt = getopt_long(argc, argv, "vhkc:a", long_options, NULL)) != -1) switch(opt) { case 'v': eprint_version(); break; case 'h': exit_help(EXIT_SUCCESS); break; case 'k': if(!luaA_parserc(&xdg, confpath, false)) { fprintf(stderr, "✘ Configuration file syntax error.\n"); return EXIT_FAILURE; } else { fprintf(stderr, "✔ Configuration file syntax OK.\n"); return EXIT_SUCCESS; } case 'c': if(a_strlen(optarg)) confpath = a_strdup(optarg); else fatal("-c option requires a file name"); break; case 'a': no_argb = true; break; } globalconf.loop = ev_default_loop(EVFLAG_NOSIGFD); /* register function for signals */ ev_signal_init(&sigint, exit_on_signal, SIGINT); ev_signal_init(&sigterm, exit_on_signal, SIGTERM); ev_signal_init(&sighup, restart_on_signal, SIGHUP); ev_signal_start(globalconf.loop, &sigint); ev_signal_start(globalconf.loop, &sigterm); ev_signal_start(globalconf.loop, &sighup); ev_unref(globalconf.loop); ev_unref(globalconf.loop); ev_unref(globalconf.loop); struct sigaction sa = { .sa_handler = signal_fatal, .sa_flags = 0 }; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, 0); /* X stuff */ globalconf.connection = xcb_connect(NULL, &globalconf.default_screen); if(xcb_connection_has_error(globalconf.connection)) fatal("cannot open display"); globalconf.screen = xcb_aux_get_screen(globalconf.connection, globalconf.default_screen); /* FIXME The following two assignments were swapped on purpose */ if(!no_argb) globalconf.visual = a_default_visual(globalconf.screen); if(!globalconf.visual) globalconf.visual = a_argb_visual(globalconf.screen); globalconf.default_depth = a_visual_depth(globalconf.screen, globalconf.visual->visual_id); globalconf.default_cmap = globalconf.screen->default_colormap; if(globalconf.default_depth != globalconf.screen->root_depth) { // We need our own color map if we aren't using the default depth globalconf.default_cmap = xcb_generate_id(globalconf.connection); xcb_create_colormap(globalconf.connection, XCB_COLORMAP_ALLOC_NONE, globalconf.default_cmap, globalconf.screen->root, globalconf.visual->visual_id); } /* Prefetch all the extensions we might need */ xcb_prefetch_extension_data(globalconf.connection, &xcb_big_requests_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_test_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id); xcb_prefetch_extension_data(globalconf.connection, &xcb_xinerama_id); /* initialize dbus */ a_dbus_init(); /* Get the file descriptor corresponding to the X connection */ xfd = xcb_get_file_descriptor(globalconf.connection); ev_io_init(&xio, &a_xcb_io_cb, xfd, EV_READ); ev_io_start(globalconf.loop, &xio); ev_check_init(&xcheck, &a_xcb_check_cb); ev_check_start(globalconf.loop, &xcheck); ev_unref(globalconf.loop); ev_prepare_init(&a_refresh, &a_refresh_cb); ev_prepare_start(globalconf.loop, &a_refresh); ev_unref(globalconf.loop); /* Grab server */ xcb_grab_server(globalconf.connection); /* Make sure there are no pending events. Since we didn't really do anything * at all yet, we will just discard all events which we received so far. * The above GrabServer should make sure no new events are generated. */ xcb_aux_sync(globalconf.connection); while ((event = xcb_poll_for_event(globalconf.connection)) != NULL) { /* Make sure errors are printed */ uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event); if(response_type == 0) event_handle(event); p_delete(&event); } { const uint32_t select_input_val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; /* This causes an error if some other window manager is running */ xcb_change_window_attributes(globalconf.connection, globalconf.screen->root, XCB_CW_EVENT_MASK, &select_input_val); } /* Need to xcb_flush to validate error handler */ xcb_aux_sync(globalconf.connection); /* Process all errors in the queue if any. There can be no events yet, so if * this function returns something, it must be an error. */ if (xcb_poll_for_event(globalconf.connection) != NULL) fatal("another window manager is already running"); /* Prefetch the maximum request length */ xcb_prefetch_maximum_request_length(globalconf.connection); /* check for xtest extension */ const xcb_query_extension_reply_t *xtest_query; xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id); globalconf.have_xtest = xtest_query->present; /* Allocate the key symbols */ globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection); xcb_get_modifier_mapping_cookie_t xmapping_cookie = xcb_get_modifier_mapping_unchecked(globalconf.connection); /* init atom cache */ atoms_init(globalconf.connection); /* init screens information */ screen_scan(); xutil_lock_mask_get(globalconf.connection, xmapping_cookie, globalconf.keysyms, &globalconf.numlockmask, &globalconf.shiftlockmask, &globalconf.capslockmask, &globalconf.modeswitchmask); /* do this only for real screen */ ewmh_init(); systray_init(); /* init spawn (sn) */ spawn_init(); /* The default GC is just a newly created associated with a window with * depth globalconf.default_depth */ xcb_window_t tmp_win = xcb_generate_id(globalconf.connection); globalconf.gc = xcb_generate_id(globalconf.connection); xcb_create_window(globalconf.connection, globalconf.default_depth, tmp_win, globalconf.screen->root, -1, -1, 1, 1, 0, XCB_COPY_FROM_PARENT, globalconf.visual->visual_id, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, (const uint32_t []) { globalconf.screen->black_pixel, globalconf.screen->black_pixel, globalconf.default_cmap }); xcb_create_gc(globalconf.connection, globalconf.gc, tmp_win, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, (const uint32_t[]) { globalconf.screen->black_pixel, globalconf.screen->white_pixel }); xcb_destroy_window(globalconf.connection, tmp_win); /* Get the window tree associated to this screen */ tree_c = xcb_query_tree_unchecked(globalconf.connection, globalconf.screen->root); xcb_change_window_attributes(globalconf.connection, globalconf.screen->root, XCB_CW_EVENT_MASK, ROOT_WINDOW_EVENT_MASK); /* we will receive events, stop grabbing server */ xcb_ungrab_server(globalconf.connection); /* Parse and run configuration file */ if (!luaA_parserc(&xdg, confpath, true)) fatal("couldn't find any rc file"); p_delete(&confpath); xdgWipeHandle(&xdg); /* scan existing windows */ scan(tree_c); xcb_flush(globalconf.connection); /* main event loop */ ev_loop(globalconf.loop, 0); /* cleanup event loop */ ev_ref(globalconf.loop); ev_check_stop(globalconf.loop, &xcheck); ev_ref(globalconf.loop); ev_prepare_stop(globalconf.loop, &a_refresh); ev_ref(globalconf.loop); ev_io_stop(globalconf.loop, &xio); awesome_atexit(false); return EXIT_SUCCESS; }
void event_handle(xcb_generic_event_t *event) { uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event); if(response_type == 0) { /* This is an error, not a event */ xerror((xcb_generic_error_t *) event); return; } switch(response_type) { #define EVENT(type, callback) case type: callback((void *) event); return EVENT(XCB_BUTTON_PRESS, event_handle_button); EVENT(XCB_BUTTON_RELEASE, event_handle_button); EVENT(XCB_CONFIGURE_REQUEST, event_handle_configurerequest); EVENT(XCB_CONFIGURE_NOTIFY, event_handle_configurenotify); EVENT(XCB_DESTROY_NOTIFY, event_handle_destroynotify); EVENT(XCB_ENTER_NOTIFY, event_handle_enternotify); EVENT(XCB_CLIENT_MESSAGE, event_handle_clientmessage); EVENT(XCB_EXPOSE, event_handle_expose); EVENT(XCB_FOCUS_IN, event_handle_focusin); EVENT(XCB_KEY_PRESS, event_handle_key); EVENT(XCB_KEY_RELEASE, event_handle_key); EVENT(XCB_LEAVE_NOTIFY, event_handle_leavenotify); EVENT(XCB_MAPPING_NOTIFY, event_handle_mappingnotify); EVENT(XCB_MAP_REQUEST, event_handle_maprequest); EVENT(XCB_MOTION_NOTIFY, event_handle_motionnotify); EVENT(XCB_PROPERTY_NOTIFY, property_handle_propertynotify); EVENT(XCB_REPARENT_NOTIFY, event_handle_reparentnotify); EVENT(XCB_UNMAP_NOTIFY, event_handle_unmapnotify); EVENT(XCB_SELECTION_CLEAR, event_handle_selectionclear); #undef EVENT } static uint8_t randr_screen_change_notify = 0; static uint8_t randr_output_change_notify = 0; static uint8_t shape_notify = 0; static uint8_t xkb_notify = 0; if(randr_screen_change_notify == 0 || randr_output_change_notify == 0) { /* check for randr extension */ const xcb_query_extension_reply_t *randr_query; randr_query = xcb_get_extension_data(globalconf.connection, &xcb_randr_id); if(randr_query->present) { xcb_randr_select_input(globalconf.connection, globalconf.screen->root, XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE); randr_screen_change_notify = randr_query->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY; randr_output_change_notify = randr_query->first_event + XCB_RANDR_NOTIFY; } } if(shape_notify == 0) { /* check for shape extension */ const xcb_query_extension_reply_t *shape_query; shape_query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id); if(shape_query->present) shape_notify = shape_query->first_event + XCB_SHAPE_NOTIFY; } if(xkb_notify == 0) { /* check for xkb extension */ const xcb_query_extension_reply_t *xkb_query; xkb_query = xcb_get_extension_data(globalconf.connection, &xcb_xkb_id); if(xkb_query->present) xkb_notify = xkb_query->first_event; } if (response_type == randr_screen_change_notify) event_handle_randr_screen_change_notify((void *) event); if (response_type == randr_output_change_notify) event_handle_randr_output_change_notify((void *) event); if (response_type == shape_notify) event_handle_shape_notify((void *) event); if (response_type == xkb_notify) event_handle_xkb_notify((void *) event); }
/** 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; }
void* widget_main (struct widget *widget) { unsigned short i; int xcb_fd; int screen_nbr = 0; xcb_connection_t *conn = xcb_connect(NULL, NULL); xcb_ewmh_connection_t *ewmh = malloc(sizeof(xcb_ewmh_connection_t)); struct epoll_event xcb_event; widget_epoll_init(widget); if (xcb_connection_has_error(conn)) { LOG_ERR("could not connect to display %s", getenv("DISPLAY")); goto cleanup; } xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(conn, ewmh); xcb_ewmh_init_atoms_replies(ewmh, ewmh_cookie, NULL); uint32_t values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE }; xcb_generic_event_t *evt; xcb_generic_error_t *err = xcb_request_check(ewmh->connection, xcb_change_window_attributes_checked(ewmh->connection, ewmh->screens[screen_nbr]->root, XCB_CW_EVENT_MASK, values)); if (err != NULL) { LOG_ERR("could not request EWMH property change notifications"); goto cleanup; } xcb_fd = xcb_get_file_descriptor(ewmh->connection); xcb_event.data.fd = xcb_fd; xcb_event.events = EPOLLIN | EPOLLET; if (epoll_ctl(efd, EPOLL_CTL_ADD, xcb_fd, &xcb_event) == -1) { LOG_ERR("failed to add fd to epoll instance: %s", strerror(errno)); return 0; } widget_update(widget, ewmh, screen_nbr); while (true) { while ((nfds = epoll_wait(efd, events, MAX_EVENTS, -1)) > 0) { for (i = 0; i < nfds; i++) { if (events[i].data.fd == widget->bar->efd) { goto cleanup; } } while ((evt = xcb_poll_for_event(ewmh->connection)) != NULL) { xcb_property_notify_event_t *pne; switch (XCB_EVENT_RESPONSE_TYPE(evt)) { case XCB_PROPERTY_NOTIFY: pne = (xcb_property_notify_event_t*)evt; if (pne->atom == ewmh->_NET_DESKTOP_NAMES) { widget_update(widget, ewmh, screen_nbr); } else if (pne->atom == ewmh->_NET_NUMBER_OF_DESKTOPS) { widget_update(widget, ewmh, screen_nbr); } else if (pne->atom == ewmh->_NET_CURRENT_DESKTOP) { widget_update(widget, ewmh, screen_nbr); } default: break; } free(evt); } } } cleanup: if (ewmh != NULL) { xcb_ewmh_connection_wipe(ewmh); } if (conn != NULL) { xcb_disconnect(conn); } widget_epoll_cleanup(widget); widget_clean_exit(widget); }