X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=i3-input%2Fmain.c;h=da95c903fae825cf762d7633bcc7dd0bac2fa555;hb=d3beff23395356ec71fcc35a3b802163e12df73e;hp=2d4def7c59ccd9bc9ee3d7ab54f782c33c92728d;hpb=f4469eee0b0988c082a5df580c24c15b5eed2c2e;p=i3%2Fi3 diff --git a/i3-input/main.c b/i3-input/main.c index 2d4def7c..da95c903 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -2,16 +2,12 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * - * © 2009-2011 Michael Stapelberg and contributors - * - * See file LICENSE for license information. + * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE) * * i3-input/main.c: Utility which lets the user input commands and sends them - * to i3. + * to i3. * */ -#include #include #include #include @@ -48,15 +44,55 @@ static bool modeswitch_active = false; static xcb_window_t win; static xcb_pixmap_t pixmap; static xcb_gcontext_t pixmap_gc; -static char *glyphs_ucs[512]; +static xcb_char2b_t glyphs_ucs[512]; static char *glyphs_utf8[512]; static int input_position; static i3Font font; -static char *prompt; -static int prompt_len; +static i3String *prompt; +static int prompt_offset = 0; static int limit; xcb_window_t root; xcb_connection_t *conn; +xcb_screen_t *root_screen; +static xcb_get_input_focus_cookie_t focus_cookie; + +/* + * Having verboselog() and errorlog() is necessary when using libi3. + * + */ +void verboselog(char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); +} + +void errorlog(char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +/* + * Restores the X11 input focus to whereever it was before. + * This is necessary because i3-input’s window has override_redirect=1 + * (→ unmanaged by the window manager) and thus i3-input changes focus itself. + * This function is called on exit(). + * + */ +static void restore_input_focus(void) { + xcb_generic_error_t *error; + xcb_get_input_focus_reply_t *reply = xcb_get_input_focus_reply(conn, focus_cookie, &error); + if (error != NULL) { + fprintf(stderr, "[i3-input] ERROR: Could not restore input focus (X error %d)\n", error->error_code); + return; + } + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, reply->focus, XCB_CURRENT_TIME); + xcb_flush(conn); +} /* * Concats the glyphs (either UCS-2 or UTF-8) to a single string, suitable for @@ -97,25 +133,23 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &inner); /* restore font color */ - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#FFFFFF") }); - uint8_t *con = concat_strings(glyphs_ucs, input_position); - char *full_text = (char*)con; + set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000")); + + /* draw the prompt … */ if (prompt != NULL) { - full_text = malloc((prompt_len + input_position) * 2 + 1); - if (full_text == NULL) - err(EXIT_FAILURE, "malloc() failed\n"); - memcpy(full_text, prompt, prompt_len * 2); - memcpy(full_text + (prompt_len * 2), con, input_position * 2); + draw_text(prompt, pixmap, pixmap_gc, 4, 4, 492); + } + /* … and the text */ + if (input_position > 0) + { + i3String *input = i3string_from_ucs2(glyphs_ucs, input_position); + draw_text(input, pixmap, pixmap_gc, prompt_offset + 4, 4, 492); + i3string_free(input); } - xcb_image_text_16(conn, input_position + prompt_len, pixmap, pixmap_gc, 4 /* X */, - font.height + 2 /* Y = baseline of font */, (xcb_char2b_t*)full_text); /* Copy the contents of the pixmap to the real window */ xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, /* */ 500, font.height + 8); xcb_flush(conn); - free(con); - if (prompt != NULL) - free(full_text); return 1; } @@ -127,16 +161,6 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) { printf("releasing %d, state raw = %d\n", event->detail, event->state); - /* See the documentation of xcb_key_symbols_get_keysym for this one. - * Basically: We get either col 0 or col 1, depending on whether shift is - * pressed. */ - int col = (event->state & XCB_MOD_MASK_SHIFT); - - /* If modeswitch is currently active, we need to look in group 2 or 3, - * respectively. */ - if (modeswitch_active) - col += 2; - xcb_keysym_t sym = xcb_key_press_lookup_keysym(symbols, event, event->state); if (sym == XK_Mode_switch) { printf("Mode switch disabled\n"); @@ -181,6 +205,10 @@ static void finish_input() { /* prefix the command if a prefix was specified on commandline */ printf("command = %s\n", full); + restore_input_focus(); + + xcb_aux_sync(conn); + ipc_send_message(sockfd, strlen(full), 0, (uint8_t*)full); #if 0 @@ -227,13 +255,13 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press return 1; input_position--; - free(glyphs_ucs[input_position]); free(glyphs_utf8[input_position]); handle_expose(NULL, conn, NULL); return 1; } if (sym == XK_Escape) { + restore_input_focus(); exit(0); } @@ -258,19 +286,17 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press return 1; } - /* store the UCS into a string */ - uint8_t inp[3] = {(ucs & 0xFF00) >> 8, (ucs & 0xFF), 0}; + xcb_char2b_t inp; + inp.byte1 = ( ucs & 0xff00 ) >> 2; + inp.byte2 = ( ucs & 0x00ff ) >> 0; - printf("inp[0] = %02x, inp[1] = %02x, inp[2] = %02x\n", inp[0], inp[1], inp[2]); + printf("inp.byte1 = %02x, inp.byte2 = %02x\n", inp.byte1, inp.byte2); /* convert it to UTF-8 */ - char *out = convert_ucs_to_utf8((char*)inp); + char *out = convert_ucs2_to_utf8(&inp, 1); printf("converted to %s\n", out); - glyphs_ucs[input_position] = malloc(3 * sizeof(uint8_t)); - if (glyphs_ucs[input_position] == NULL) - err(EXIT_FAILURE, "malloc() failed\n"); - memcpy(glyphs_ucs[input_position], inp, 3); - glyphs_utf8[input_position] = strdup(out); + glyphs_ucs[input_position] = inp; + glyphs_utf8[input_position] = out; input_position++; if (input_position == limit) @@ -319,8 +345,8 @@ int main(int argc, char *argv[]) { limit = atoi(optarg); break; case 'P': - FREE(prompt); - prompt = strdup(optarg); + i3string_free(prompt); + prompt = i3string_from_utf8(optarg); break; case 'f': FREE(pattern); @@ -342,28 +368,32 @@ int main(int argc, char *argv[]) { 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"); + if (socket_path == NULL) - socket_path = socket_path_from_x11(); + socket_path = root_atom_contents("I3_SOCKET_PATH", conn, screen); if (socket_path == NULL) socket_path = "/tmp/i3-ipc.sock"; sockfd = ipc_connect(socket_path); - if (prompt != NULL) - prompt = convert_utf8_to_ucs2(prompt, &prompt_len); - - int screens; - conn = xcb_connect(NULL, &screens); - if (!conn || xcb_connection_has_error(conn)) - die("Cannot open display\n"); + /* Request the current InputFocus to restore when i3-input exits. */ + focus_cookie = xcb_get_input_focus(conn); - xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens); + root_screen = xcb_aux_get_screen(conn, screen); root = root_screen->root; symbols = xcb_key_symbols_alloc(conn); font = load_font(pattern, true); + set_font(&font); + + if (prompt != NULL) + prompt_offset = predict_text_width(prompt); /* Open an input window */ win = xcb_generate_id(conn); @@ -396,9 +426,6 @@ int main(int argc, char *argv[]) { * this for us) */ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME); - /* Create graphics context */ - xcb_change_gc(conn, pixmap_gc, XCB_GC_FONT, (uint32_t[]){ font.id }); - /* Grab the keyboard to get all input */ xcb_flush(conn); @@ -417,6 +444,7 @@ int main(int argc, char *argv[]) { if (reply->status != XCB_GRAB_STATUS_SUCCESS) { fprintf(stderr, "Could not grab keyboard, status = %d\n", reply->status); + restore_input_focus(); exit(-1); }