i3 - improved tiling WM


new commandline argument for i3-input -c with options "default", "focused" or ${W}x${H}+${X}+${Y}

Patch status: superseded

Patch by Bastian

Long description:

"default": legacy method, place the input box at 500x(${fontheight} +8)+50+50
"focused": place the input box at the top of the window with input focuse
"${W}x${H}+${X}+${Y}" : specify fixed geometry, use h=0 to calculate height by
font width

To apply this patch, use:
curl http://cr.i3wm.org/patch/224/raw.patch | git am

b/i3-input/i3-input.h

19
@@ -12,6 +12,13 @@
20
 } \
21
 while (0)
22
 
23
+typedef struct coordinates {
24
+  int x;
25
+  int y;
26
+  int w;
27
+  int h;
28
+} coordinates_t;
29
+
30
 extern xcb_window_t root;
31
 
32
 #endif

b/i3-input/main.c

37
@@ -55,6 +55,7 @@ xcb_window_t root;
38
 xcb_connection_t *conn;
39
 xcb_screen_t *root_screen;
40
 static xcb_get_input_focus_cookie_t focus_cookie;
41
+static xcb_get_input_focus_reply_t* focus_reply;
42
 
43
 /*
44
  * Having verboselog() and errorlog() is necessary when using libi3.
45
@@ -84,13 +85,7 @@ void errorlog(char *fmt, ...) {
46
  *
47
  */
48
 static void restore_input_focus(void) {
49
-    xcb_generic_error_t *error;
50
-    xcb_get_input_focus_reply_t *reply = xcb_get_input_focus_reply(conn, focus_cookie, &error);
51
-    if (error != NULL) {
52
-        fprintf(stderr, "[i3-input] ERROR: Could not restore input focus (X error %d)\n", error->error_code);
53
-        return;
54
-    }
55
-    xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, reply->focus, XCB_CURRENT_TIME);
56
+    xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, focus_reply->focus, XCB_CURRENT_TIME);
57
     xcb_flush(conn);
58
 }
59
 
60
@@ -122,11 +117,11 @@ static uint8_t *concat_strings(char **glyphs, int max) {
61
  * be called from the code with event == NULL or from X with event != NULL.
62
  *
63
  */
64
-static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t *event) {
65
+static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t *event, coordinates_t* coord) {
66
     printf("expose!\n");
67
 
68
     /* re-draw the background */
69
-    xcb_rectangle_t border = {0, 0, 500, font.height + 8}, inner = {2, 2, 496, font.height + 8 - 4};
70
+    xcb_rectangle_t border = {0, 0, coord->w, coord->h}, inner = {2, 2, coord->w-4, coord->h - 4};
71
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#FF0000") });
72
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
73
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#000000") });
74
@@ -137,18 +132,18 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
75
 
76
     /* draw the prompt … */
77
     if (prompt != NULL) {
78
-        draw_text(prompt, pixmap, pixmap_gc, 4, 4, 492);
79
+        draw_text(prompt, pixmap, pixmap_gc, 4, 4, coord->w-8);
80
     }
81
     /* … and the text */
82
     if (input_position > 0)
83
     {
84
         i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
85
-        draw_text(input, pixmap, pixmap_gc, prompt_offset + 4, 4, 492);
86
+        draw_text(input, pixmap, pixmap_gc, prompt_offset + 4, 4, coord->w-8);
87
         i3string_free(input);
88
     }
89
 
90
     /* Copy the contents of the pixmap to the real window */
91
-    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, /* */ 500, font.height + 8);
92
+    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, /* */ coord->w, coord->h);
93
     xcb_flush(conn);
94
 
95
     return 1;
96
@@ -227,7 +222,7 @@ static void finish_input() {
97
  * command to i3).
98
  *
99
  */
100
-static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
101
+static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event, coordinates_t* coordinates) {
102
     printf("Keypress %d, state raw = %d\n", event->detail, event->state);
103
 
104
     /* See the documentation of xcb_key_symbols_get_keysym for this one.
105
@@ -257,7 +252,7 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
106
         input_position--;
107
         free(glyphs_utf8[input_position]);
108
 
109
-        handle_expose(NULL, conn, NULL);
110
+        handle_expose(NULL, conn, NULL, coordinates);
111
         return 1;
112
     }
113
     if (sym == XK_Escape) {
114
@@ -302,15 +297,76 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
115
     if (input_position == limit)
116
         finish_input();
117
 
118
-    handle_expose(NULL, conn, NULL);
119
+    handle_expose(NULL, conn, NULL, coordinates);
120
     return 1;
121
 }
122
 
123
+
124
+coordinates_t* compute_coordinates(char* coordinate_arg) {
125
+    xcb_get_geometry_reply_t* focused_geometry_reply;
126
+    xcb_translate_coordinates_reply_t *trans_reply;
127
+    xcb_generic_error_t *error;
128
+    coordinates_t* coordinates = malloc( sizeof (coordinates_t) );
129
+    int w, h, x, y;
130
+
131
+    /* set default coordinates */
132
+    x=50; y=50;
133
+    w=500; h=0; /* if h==0: h=font.size + 8 */
134
+    coordinates->x=x;
135
+    coordinates->y=y;
136
+    coordinates->w=w;
137
+    coordinates->h=h;
138
+
139
+
140
+    if( strcmp(coordinate_arg, "default") == 0 ) {
141
+        fprintf(stderr, "[i3-input] INFO: using default coordinates\n");
142
+    } else if( sscanf(coordinate_arg, "%dx%d+%d+%d", &w, &h, &x, &y) == 4 ) {
143
+        fprintf(stderr, "[i3-input] INFO: using coordinates from argument %dx%d+%d+%d\n", w, h, x, y);
144
+    } else if( strcmp(coordinate_arg, "focused") == 0 ) {
145
+        fprintf(stderr, "[i3-input] INFO: using coordinates from focused window, if any\n");
146
+        focused_geometry_reply  = xcb_get_geometry_reply (conn, xcb_get_geometry(conn, focus_reply->focus), &error);
147
+        if (error != NULL) {
148
+            fprintf(stderr, "[i3-input] ERROR: Could not get geometry of focused window (X error %d)\n", error->error_code);
149
+            return coordinates;
150
+        }
151
+        printf("Geometry of focused window is: %dx%d%+d%+d\n", 
152
+                focused_geometry_reply->width, focused_geometry_reply->height,
153
+                focused_geometry_reply->x, focused_geometry_reply->y);
154
+        trans_reply = xcb_translate_coordinates_reply(
155
+                conn, 
156
+                xcb_translate_coordinates(conn, focus_reply->focus, root, 
157
+                    focused_geometry_reply->x, focused_geometry_reply->y),
158
+                &error);
159
+        if (error != NULL) {
160
+            fprintf(stderr, "[i3-input] ERROR: Could not translate coordiantes for focused window (X error %d)\n", error->error_code);
161
+            return coordinates;
162
+        }
163
+        printf("Translated coordinates are: %+d%+d\n", trans_reply->dst_x, trans_reply->dst_y);
164
+        w=focused_geometry_reply->width - 10;
165
+        h=0;
166
+        x=trans_reply->dst_x + 5;
167
+        y=trans_reply->dst_y + 5;
168
+    } else { 
169
+        fprintf(stderr, "[i3-input] ERROR: could not understand coordinate argument %s.\n", coordinate_arg);
170
+        return coordinates;
171
+    }
172
+    if(w<0) w=500; /* somehow i get on firefox a dimension of -1 -1, workaround here: */
173
+    if(h<0) h=0;
174
+    coordinates->x=x;
175
+    coordinates->y=y;
176
+    coordinates->w=w;
177
+    coordinates->h=h;
178
+    return coordinates;
179
+}
180
+
181
 int main(int argc, char *argv[]) {
182
     format = strdup("%s");
183
     socket_path = getenv("I3SOCK");
184
     char *pattern = sstrdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1");
185
     int o, option_index = 0;
186
+    xcb_generic_error_t *error;
187
+    char* coordinate_arg = strdup("default");
188
+    coordinates_t* coordinates;
189
 
190
     static struct option long_options[] = {
191
         {"socket", required_argument, 0, 's'},
192
@@ -321,10 +377,11 @@ int main(int argc, char *argv[]) {
193
         {"format", required_argument, 0, 'F'},
194
         {"font", required_argument, 0, 'f'},
195
         {"help", no_argument, 0, 'h'},
196
+        {"coordinates", required_argument, 0, 'c'},
197
         {0, 0, 0, 0}
198
     };
199
 
200
-    char *options_string = "s:p:P:f:l:F:vh";
201
+    char *options_string = "s:p:P:f:l:F:vhc:";
202
 
203
     while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
204
         switch (o) {
205
@@ -356,9 +413,13 @@ int main(int argc, char *argv[]) {
206
                 FREE(format);
207
                 format = strdup(optarg);
208
                 break;
209
+            case 'c':
210
+                FREE(coordinate_arg);
211
+                coordinate_arg=strdup(optarg);
212
+                break;                                
213
             case 'h':
214
                 printf("i3-input " I3_VERSION "\n");
215
-                printf("i3-input [-s <socket>] [-F <format>] [-l <limit>] [-P <prompt>] [-f <font>] [-v]\n");
216
+                printf("i3-input [-s <socket>] [-F <format>] [-l <limit>] [-P <prompt>] [-f <font>] [-v] [-c <default|focused|WxH+X+Y>]\n");
217
                 printf("\n");
218
                 printf("Example:\n");
219
                 printf("    i3-input -F 'workspace \"%%s\"' -P 'Switch to workspace: '\n");
220
@@ -381,17 +442,30 @@ int main(int argc, char *argv[]) {
221
     if (!conn || xcb_connection_has_error(conn))
222
         die("Cannot open display\n");
223
 
224
-    /* Request the current InputFocus to restore when i3-input exits. */
225
-    focus_cookie = xcb_get_input_focus(conn);
226
-
227
     root_screen = xcb_aux_get_screen(conn, screens);
228
     root = root_screen->root;
229
 
230
+    /* Request the current InputFocus to restore when i3-input exits. */
231
+    focus_cookie = xcb_get_input_focus(conn);
232
+    focus_reply = xcb_get_input_focus_reply(conn, focus_cookie, &error);
233
+    if (error != NULL) {
234
+        fprintf(stderr, "[i3-input] ERROR: Could not restore input focus (X error %d)\n", error->error_code);
235
+    }
236
+
237
     symbols = xcb_key_symbols_alloc(conn);
238
 
239
     font = load_font(pattern, true);
240
     set_font(&font);
241
 
242
+    
243
+    coordinates =  compute_coordinates(coordinate_arg);
244
+    if ( coordinates->h == 0 ) {
245
+        coordinates->h = font.height + 8;
246
+    }
247
+    fprintf(stderr, "[i3-input] INFO: using coordinates %dx%d+%d+%d\n", 
248
+            coordinates->w, coordinates->h,
249
+            coordinates->x, coordinates->y);
250
+
251
     if (prompt != NULL)
252
         prompt_offset = predict_text_width(prompt);
253
 
254
@@ -402,7 +476,7 @@ int main(int argc, char *argv[]) {
255
         XCB_COPY_FROM_PARENT,
256
         win, /* the window id */
257
         root, /* parent == root */
258
-        50, 50, 500, font.height + 8, /* dimensions */
259
+        coordinates->x, coordinates->y, coordinates->w, coordinates->h, /* dimensions */
260
         0, /* X11 border = 0, we draw our own */
261
         XCB_WINDOW_CLASS_INPUT_OUTPUT,
262
         XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
263
@@ -419,7 +493,8 @@ int main(int argc, char *argv[]) {
264
     /* Create pixmap */
265
     pixmap = xcb_generate_id(conn);
266
     pixmap_gc = xcb_generate_id(conn);
267
-    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + 8);
268
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 
269
+            coordinates->w, coordinates->h);
270
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
271
 
272
     /* Set input focus (we have override_redirect=1, so the wm will not do
273
@@ -462,7 +537,7 @@ int main(int argc, char *argv[]) {
274
 
275
         switch (type) {
276
             case XCB_KEY_PRESS:
277
-                handle_key_press(NULL, conn, (xcb_key_press_event_t*)event);
278
+                handle_key_press(NULL, conn, (xcb_key_press_event_t*)event, coordinates);
279
                 break;
280
 
281
             case XCB_KEY_RELEASE:
282
@@ -470,7 +545,7 @@ int main(int argc, char *argv[]) {
283
                 break;
284
 
285
             case XCB_EXPOSE:
286
-                handle_expose(NULL, conn, (xcb_expose_event_t*)event);
287
+                handle_expose(NULL, conn, (xcb_expose_event_t*)event, coordinates);
288
                 break;
289
         }
290