int main(int argc, char *argv[]) { int fd; struct sockaddr_un sock_address; char msg[BUFSIZ], rsp[BUFSIZ]; if (argc < 2) { err("No arguments given.\n"); } sock_address.sun_family = AF_UNIX; char *sp; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { err("Failed to create the socket.\n"); } sp = getenv(SOCKET_ENV_VAR); if (sp != NULL) { snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", sp); } else { 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); } free(host); } if (connect(fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) { err("Failed to connect to the socket.\n"); } argc--, argv++; int msg_len = 0; for (int offset = 0, rem = sizeof(msg), n = 0; argc > 0 && rem > 0; offset += n, rem -= n, argc--, argv++) { n = snprintf(msg + offset, rem, "%s%c", *argv, 0); msg_len += n; } if (send(fd, msg, msg_len, 0) == -1) { err("Failed to send the data.\n"); } int ret = EXIT_SUCCESS, nb; while ((nb = recv(fd, rsp, sizeof(rsp)-1, 0)) > 0) { rsp[nb] = '\0'; if (rsp[0] == FAILURE_MESSAGE[0]) { ret = EXIT_FAILURE; printf("%s", rsp + 1); } else { printf("%s", rsp); } fflush(stdout); } close(fd); return ret; }
int main(int argc, char *argv[]) { int fd; struct sockaddr_un sock_address; char msg[BUFSIZ], rsp[BUFSIZ]; if (argc < 2) err("No arguments given.\n"); sock_address.sun_family = AF_UNIX; char *sp; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err("Failed to create the socket.\n"); sp = getenv(SOCKET_ENV_VAR); if (sp != NULL) { snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", sp); } else { 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); free(host); } if (connect(fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) err("Failed to connect to the socket.\n"); argc--, argv++; int msg_len = 0; for (int offset = 0, rem = sizeof(msg), n = 0; argc > 0 && rem > 0; offset += n, rem -= n, argc--, argv++) { n = snprintf(msg + offset, rem, "%s%c", *argv, 0); msg_len += n; } if (send(fd, msg, msg_len, 0) == -1) err("Failed to send the data.\n"); int ret = 0, nb; while ((nb = recv(fd, rsp, sizeof(rsp)-1, 0)) > 0) { if (nb == 1 && rsp[0] < MSG_LENGTH) { ret = rsp[0]; if (ret == MSG_UNKNOWN) { warn("Unknown command.\n"); } else if (ret == MSG_SYNTAX) { warn("Invalid syntax.\n"); } } else { rsp[nb] = '\0'; printf("%s", rsp); fflush(stdout); } } close(fd); return ret; }
// https://www.x.org/releases/current/doc/xproto/x11protocol.html#Encoding::Connection_Setup static void read_client_setup_request_cb(EV_P_ ev_io *w, int revents) { ev_io_stop(EV_A_ w); struct connstate *connstate = (struct connstate *)w->data; /* Read X11 setup request in its entirety. */ xcb_setup_request_t setup_request; must_read(readall_into(&setup_request, sizeof(setup_request), w->fd)); /* Establish a connection to X11. */ int fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (fd == -1) { err(EXIT_FAILURE, "socket()"); } char *host; int displayp; if (xcb_parse_display(getenv("DISPLAY"), &host, &displayp, NULL) == 0) { errx(EXIT_FAILURE, "Could not parse DISPLAY=%s", getenv("DISPLAY")); } free(host); struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/.X11-unix/X%d", displayp); if (connect(fd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { err(EXIT_FAILURE, "connect(%s)", addr.sun_path); } /* Relay setup request. */ must_write(writeall(fd, &setup_request, sizeof(setup_request))); if (setup_request.authorization_protocol_name_len > 0 || setup_request.authorization_protocol_data_len > 0) { const size_t authlen = setup_request.authorization_protocol_name_len + XCB_PAD(setup_request.authorization_protocol_name_len) + setup_request.authorization_protocol_data_len + XCB_PAD(setup_request.authorization_protocol_data_len); void *buf = smalloc(authlen); must_read(readall_into(buf, authlen, w->fd)); must_write(writeall(fd, buf, authlen)); free(buf); } /* Wait for a response from the X11 server. */ ev_io *serverw = scalloc(1, sizeof(ev_io)); connstate->serverw = serverw; serverw->data = connstate; ev_io_init(serverw, read_server_setup_reply_cb, fd, EV_READ); ev_io_start(EV_A_ serverw); }
// hostname, display, screen virtual std::tuple<std::string, int, int> parse_display(const std::string & name) const { int screen = 0; int display = 0; char * host = NULL; std::string hostname; xcb_parse_display(name.c_str(), &host, &display, &screen); if (host != NULL) { hostname = std::string(host); } return std::make_tuple(hostname, display, screen); }
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; }
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; }