/* * Parse a string (change) * */ static int mode_string_cb(void *params_, const unsigned char *val, size_t len) { struct mode_json_params *params = (struct mode_json_params *)params_; if (!strcmp(params->cur_key, "change")) { /* Save the name */ params->mode->name = i3string_from_markup_with_length((const char *)val, len); /* Save its rendered width */ params->mode->width = predict_text_width(params->mode->name); DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name)); FREE(params->cur_key); return 1; } return 0; }
*/ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { /* re-draw the background */ xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_background}); xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &rect); /* restore font color */ set_font_colors(pixmap_gc, color_text, color_background); draw_text(prompt, pixmap, pixmap_gc, 4 + 4, 4 + 4, rect.width - 4 - 4); /* render close button */ const char *close_button_label = "X"; int line_width = 4; /* set width to the width of the label */ int w = predict_text_width(i3string_from_utf8(close_button_label)); /* account for left/right padding, which seems to be set to 8px (total) below */ w += 8; int y = rect.width; uint32_t values[3]; values[0] = color_button_background; values[1] = line_width; xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); xcb_rectangle_t close = {y - w - (2 * line_width), 0, w + (2 * line_width), rect.height}; xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close); xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_border}); xcb_point_t points[] = { {y - w - (2 * line_width), line_width / 2}, {y - (line_width / 2), line_width / 2},
int main(int argc, char *argv[]) { format = sstrdup("%s"); char *socket_path = NULL; char *pattern = sstrdup("pango:monospace 8"); int o, option_index = 0; static struct option long_options[] = { {"socket", required_argument, 0, 's'}, {"version", no_argument, 0, 'v'}, {"limit", required_argument, 0, 'l'}, {"prompt", required_argument, 0, 'P'}, {"prefix", required_argument, 0, 'p'}, {"format", required_argument, 0, 'F'}, {"font", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; char *options_string = "s:p:P:f:l:F:vh"; while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { switch (o) { case 's': FREE(socket_path); socket_path = sstrdup(optarg); break; case 'v': printf("i3-input " I3_VERSION); return 0; case 'p': /* This option is deprecated, but will still work in i3 v4.1, 4.2 and 4.3 */ fprintf(stderr, "i3-input: WARNING: the -p option is DEPRECATED in favor of the -F (format) option\n"); FREE(format); sasprintf(&format, "%s%%s", optarg); break; case 'l': limit = atoi(optarg); break; case 'P': i3string_free(prompt); prompt = i3string_from_utf8(optarg); break; case 'f': FREE(pattern); pattern = sstrdup(optarg); break; case 'F': FREE(format); format = sstrdup(optarg); break; case 'h': printf("i3-input " I3_VERSION "\n"); printf("i3-input [-s <socket>] [-F <format>] [-l <limit>] [-P <prompt>] [-f <font>] [-v]\n"); printf("\n"); printf("Example:\n"); printf(" i3-input -F 'workspace \"%%s\"' -P 'Switch to workspace: '\n"); return 0; } } printf("using format \"%s\"\n", format); int screen; conn = xcb_connect(NULL, &screen); if (!conn || xcb_connection_has_error(conn)) die("Cannot open display\n"); sockfd = ipc_connect(socket_path); root_screen = xcb_aux_get_screen(conn, screen); root = root_screen->root; symbols = xcb_key_symbols_alloc(conn); init_dpi(); font = load_font(pattern, true); set_font(&font); if (prompt != NULL) prompt_offset = predict_text_width(prompt); const xcb_rectangle_t win_pos = get_window_position(); /* Open an input window */ win = xcb_generate_id(conn); xcb_create_window( conn, XCB_COPY_FROM_PARENT, win, /* the window id */ root, /* parent == root */ win_pos.x, win_pos.y, win_pos.width, win_pos.height, /* dimensions */ 0, /* X11 border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, (uint32_t[]){ 0, /* back pixel: black */ 1, /* override redirect: don’t manage this window */ XCB_EVENT_MASK_EXPOSURE}); /* Map the window (make it visible) */ xcb_map_window(conn, win); /* Initialize the drawable surface */ draw_util_surface_init(conn, &surface, win, get_visualtype(root_screen), win_pos.width, win_pos.height); /* Grab the keyboard to get all input */ xcb_flush(conn); /* Try (repeatedly, if necessary) to grab the keyboard. We might not * get the keyboard at the first attempt because of the keybinding * still being active when started via a wm’s keybinding. */ xcb_grab_keyboard_cookie_t cookie; xcb_grab_keyboard_reply_t *reply = NULL; int count = 0; while ((reply == NULL || reply->status != XCB_GRAB_STATUS_SUCCESS) && (count++ < 500)) { cookie = xcb_grab_keyboard(conn, false, win, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); reply = xcb_grab_keyboard_reply(conn, cookie, NULL); usleep(1000); } if (reply->status != XCB_GRAB_STATUS_SUCCESS) { fprintf(stderr, "Could not grab keyboard, status = %d\n", reply->status); exit(-1); } xcb_flush(conn); xcb_generic_event_t *event; while ((event = xcb_wait_for_event(conn)) != NULL) { if (event->response_type == 0) { fprintf(stderr, "X11 Error received! sequence %x\n", event->sequence); continue; } /* Strip off the highest bit (set if the event is generated) */ int type = (event->response_type & 0x7F); switch (type) { case XCB_KEY_PRESS: handle_key_press(NULL, conn, (xcb_key_press_event_t *)event); break; case XCB_KEY_RELEASE: handle_key_release(NULL, conn, (xcb_key_release_event_t *)event); break; case XCB_EXPOSE: if (((xcb_expose_event_t *)event)->count == 0) { handle_expose(NULL, conn, (xcb_expose_event_t *)event); } break; } free(event); } draw_util_surface_free(conn, &surface); return 0; }