#define die(...) errx(EXIT_FAILURE, __VA_ARGS__);
char *convert_ucs_to_utf8(char *input);
+char *convert_utf8_to_ucs2(char *input, int *real_strlen);
uint32_t get_colorpixel(xcb_connection_t *conn, char *hex);
uint32_t get_mode_switch_mask(xcb_connection_t *conn);
int connect_ipc(char *socket_path);
static int input_position;
static int font_height;
static char *command_prefix;
+static char *prompt;
+static int prompt_len;
+static int limit;
/*
* Concats the glyphs (either UCS-2 or UTF-8) to a single string, suitable for
/* restore font color */
xcb_change_gc_single(conn, pixmap_gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#FFFFFF"));
uint8_t *con = concat_strings(glyphs_ucs, input_position);
- xcb_image_text_16(conn, input_position, pixmap, pixmap_gc, 4 /* X */,
- font_height + 2 /* Y = baseline of font */, (xcb_char2b_t*)con);
+ char *full_text = (char*)con;
+ 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);
+ }
+ 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;
}
return 1;
}
+static void finish_input() {
+ uint8_t *command = concat_strings(glyphs_utf8, input_position);
+ char *full_command = (char*)command;
+ /* prefix the command if a prefix was specified on commandline */
+ if (command_prefix != NULL) {
+ if (asprintf(&full_command, "%s%s", command_prefix, command) == -1)
+ err(EXIT_FAILURE, "asprintf() failed\n");
+ }
+ printf("command = %s\n", full_command);
+
+ ipc_send_message(sockfd, strlen(full_command), 0, (uint8_t*)full_command);
+
+#if 0
+ free(command);
+ return 1;
+#endif
+ exit(0);
+}
+
/*
* Handles keypresses by converting the keycodes to keysymbols, then the
* keysymbols to UCS-2. If the conversion succeeded, the glyph is saved in the
return 1;
}
- if (sym == XK_Return) {
- uint8_t *command = concat_strings(glyphs_utf8, input_position);
- char *full_command = (char*)command;
- /* prefix the command if a prefix was specified on commandline */
- if (command_prefix != NULL) {
- if (asprintf(&full_command, "%s%s", command_prefix, command) == -1)
- err(EXIT_FAILURE, "asprintf() failed\n");
- }
- printf("command = %s\n", full_command);
-
- ipc_send_message(sockfd, strlen(full_command), 0, (uint8_t*)full_command);
-
-#if 0
- free(command);
- return 1;
-#endif
- exit(0);
- }
+ if (sym == XK_Return)
+ finish_input();
if (sym == XK_BackSpace) {
if (input_position == 0)
glyphs_utf8[input_position] = strdup(out);
input_position++;
+ if (input_position == limit)
+ finish_input();
+
handle_expose(NULL, conn, NULL);
return 1;
}
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'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
- char *options_string = "s:p:vh";
+ char *options_string = "s:p:P:l:vh";
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
- if (o == 's') {
- socket_path = strdup(optarg);
- } else if (o == 'v') {
- printf("i3-input " I3_VERSION);
- return 0;
- } else if (o == 'p') {
- command_prefix = strdup(optarg);
- } else if (o == 'h') {
- printf("i3-input " I3_VERSION);
- printf("i3-input [-s <socket>] [-p <prefix>]\n");
- return 0;
+ switch (o) {
+ case 's':
+ socket_path = strdup(optarg);
+ break;
+ case 'v':
+ printf("i3-input " I3_VERSION);
+ return 0;
+ case 'p':
+ command_prefix = strdup(optarg);
+ break;
+ case 'l':
+ limit = atoi(optarg);
+ break;
+ case 'P':
+ prompt = strdup(optarg);
+ break;
+ case 'h':
+ printf("i3-input " I3_VERSION);
+ printf("i3-input [-s <socket>] [-p <prefix>] [-l <limit>] [-P <prompt>] [-v]\n");
+ return 0;
}
}
sockfd = connect_ipc(socket_path);
+ prompt = convert_utf8_to_ucs2(prompt, &prompt_len);
+
int screens;
xcb_connection_t *conn = xcb_connect(NULL, &screens);
if (xcb_connection_has_error(conn))
*/
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <err.h>
#include <iconv.h>
static iconv_t conversion_descriptor = 0;
+static iconv_t conversion_descriptor2 = 0;
/*
* Returns the input string, but converted from UCS-2 to UTF-8. Memory will be
return buffer;
}
+
+/*
+ * Converts the given string to UCS-2 big endian for use with
+ * xcb_image_text_16(). The amount of real glyphs is stored in real_strlen,
+ * a buffer containing the UCS-2 encoded string (16 bit per glyph) is
+ * returned. It has to be freed when done.
+ *
+ */
+char *convert_utf8_to_ucs2(char *input, int *real_strlen) {
+ size_t input_size = strlen(input) + 1;
+ /* UCS-2 consumes exactly two bytes for each glyph */
+ int buffer_size = input_size * 2;
+
+ char *buffer = malloc(buffer_size);
+ if (buffer == NULL)
+ err(EXIT_FAILURE, "malloc() failed\n");
+ size_t output_size = buffer_size;
+ /* We need to use an additional pointer, because iconv() modifies it */
+ char *output = buffer;
+
+ /* We convert the input into UCS-2 big endian */
+ if (conversion_descriptor2 == 0) {
+ conversion_descriptor2 = iconv_open("UCS-2BE", "UTF-8");
+ if (conversion_descriptor2 == 0) {
+ fprintf(stderr, "error opening the conversion context\n");
+ exit(1);
+ }
+ }
+
+ /* Get the conversion descriptor back to original state */
+ iconv(conversion_descriptor2, NULL, NULL, NULL, NULL);
+
+ /* Convert our text */
+ int rc = iconv(conversion_descriptor2, (void*)&input, &input_size, &output, &output_size);
+ if (rc == (size_t)-1) {
+ perror("Converting to UCS-2 failed");
+ if (real_strlen != NULL)
+ *real_strlen = 0;
+ return NULL;
+ }
+
+ if (real_strlen != NULL)
+ *real_strlen = ((buffer_size - output_size) / 2) - 1;
+
+ return buffer;
+}
+
*/
void client_map(xcb_connection_t *conn, Client *client);
+/**
+ * Set the given mark for this client. Used for jumping to the client
+ * afterwards (like m<mark> and '<mark> in vim).
+ *
+ */
+void client_mark(xcb_connection_t *conn, Client *client, const char *mark);
+
/**
* Pretty-prints the client’s information into the logfile.
*
/** Holds the WM_CLASS, useful for matching the client in commands */
char *window_class;
+ /** Holds the client’s mark, for vim-like jumping */
+ char *mark;
+
/** Holds the xcb_window_t (just an ID) for the leader window (logical
* parent for toolwindows and similar floating windows) */
xcb_window_t leader;
#include "queue.h"
#include "layout.h"
#include "client.h"
+#include "table.h"
/*
* Removes the given client from the container, either because it will be inserted into another
xcb_map_window(conn, client->frame);
}
+
+/*
+ * Set the given mark for this client. Used for jumping to the client
+ * afterwards (like m<mark> and '<mark> in vim).
+ *
+ */
+void client_mark(xcb_connection_t *conn, Client *client, const char *mark) {
+ if (client->mark != NULL)
+ free(client->mark);
+ client->mark = sstrdup(mark);
+
+ /* Make sure no other client has this mark set */
+ Client *current;
+ for (int c = 0; c < 10; c++)
+ SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
+ if (current == client ||
+ current->mark == NULL ||
+ strcmp(current->mark, mark) != 0)
+ continue;
+
+ free(current->mark);
+ current->mark = NULL;
+ /* We can break here since there can only be one other
+ * client with this mark. */
+ break;
+ }
+}
typedef enum { THING_WINDOW, THING_CONTAINER, THING_SCREEN } thing_t;
+static void jump_to_mark(xcb_connection_t *conn, const char *mark) {
+ Client *current;
+ LOG("Jumping to \"%s\"\n", mark);
+
+ for (int c = 0; c < 10; c++)
+ SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
+ if (current->mark == NULL || strcmp(current->mark, mark) != 0)
+ continue;
+
+ set_focus(conn, current, true);
+ return;
+ }
+
+ LOG("No window with this mark found\n");
+}
+
static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t thing) {
LOG("focusing direction %d\n", direction);
return;
}
+ if (STARTS_WITH(command, "mark")) {
+ if (last_focused == NULL) {
+ LOG("There is no window to mark\n");
+ return;
+ }
+ const char *rest = command + strlen("mark");
+ while (*rest == ' ')
+ rest++;
+ if (*rest == '\0') {
+ LOG("interactive mark starting\n");
+ start_application("i3-input -p 'mark ' -l 1 -P 'Mark: '");
+ } else {
+ LOG("mark with \"%s\"\n", rest);
+ client_mark(conn, last_focused, rest);
+ }
+ return;
+ }
+
+ if (STARTS_WITH(command, "goto")) {
+ const char *rest = command + strlen("goto");
+ while (*rest == ' ')
+ rest++;
+ if (*rest == '\0') {
+ LOG("interactive go to mark starting\n");
+ start_application("i3-input -p 'goto ' -l 1 -P 'Goto: '");
+ } else {
+ LOG("go to \"%s\"\n", rest);
+ jump_to_mark(conn, rest);
+ }
+ return;
+ }
+
/* Is it an <exit>? */
if (STARTS_WITH(command, "exit")) {
LOG("User issued exit-command, exiting without error.\n");