]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1580 from Airblader/feature-nop
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 27 Mar 2015 08:39:28 +0000 (09:39 +0100)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 27 Mar 2015 08:39:28 +0000 (09:39 +0100)
Allow nop command without argument

28 files changed:
debian/control
docs/userguide
i3-config-wizard/main.c
i3-input/main.c
i3-nagbar/main.c
i3-sensible-terminal
i3bar/include/child.h
i3bar/include/config.h
i3bar/include/ipc.h
i3bar/include/util.h
i3bar/include/xcb.h
i3bar/src/child.c
i3bar/src/config.c
i3bar/src/ipc.c
i3bar/src/main.c
i3bar/src/mode.c
i3bar/src/workspaces.c
i3bar/src/xcb.c
include/config.h
include/config_directives.h
parser-specs/config.spec
src/config_directives.c
src/handlers.c
src/ipc.c
src/restore_layout.c
src/tree.c
testcases/t/102-dock.t
testcases/t/201-config-parser.t

index cc9660f7260bccd8472ef07b81310c13efbc37f0..52fb1538130dae9aa9bbc45868cf68001fb02fa7 100644 (file)
@@ -40,8 +40,7 @@ Package: i3-wm
 Architecture: any
 Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, x11-utils
 Provides: x-window-manager
-Suggests: rxvt-unicode | x-terminal-emulator
-Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl (>= 0.12), libjson-xs-perl
+Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl (>= 0.12), libjson-xs-perl, rxvt-unicode | x-terminal-emulator
 Description: improved dynamic tiling window manager
  Key features of i3 are good documentation, reasonable defaults (changeable in
  a simple configuration file) and good multi-monitor support. The user
index 8528d684a89bd2515dde9e5b9f1ce7af07a614a9..3d935e40aac7c2fbf8f5d5f6c2b45e47db4dec8b 100644 (file)
@@ -1249,6 +1249,24 @@ bar {
 }
 --------------------------------------------------------------
 
+=== Custom separator symbol
+
+Specifies a custom symbol to be used for the separator as opposed to the vertical,
+one pixel thick separator. Note that you may have to adjust the +sep_block_width+ 
+property.
+
+*Syntax*:
+-------------------------
+separator_symbol <symbol>
+-------------------------
+
+*Example*:
+------------------------
+bar {
+    separator_symbol ":|:"
+}
+------------------------
+
 === Workspace buttons
 
 Specifies whether workspace buttons should be shown or not. This is useful if
index 5a855c40cb76832978b794a4acbb3e2fe05af3f9..f052d6d570e69a601d31e449b1da29aa5591b348 100644 (file)
@@ -493,7 +493,7 @@ static char *resolve_tilde(const char *path) {
  */
 static int handle_expose() {
     /* re-draw the background */
-    xcb_rectangle_t border = {0, 0, 300, (15 * font.height) + 8};
+    xcb_rectangle_t border = {0, 0, logical_px(300), (logical_px(15) * font.height) + logical_px(8)};
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")});
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
 
@@ -501,62 +501,62 @@ static int handle_expose() {
 
 #define txt(x, row, text)                    \
     draw_text_ascii(text, pixmap, pixmap_gc, \
-                    x, (row - 1) * font.height + 4, 300 - x * 2)
+                    x, (row - 1) * font.height + logical_px(4), logical_px(500) - x * 2)
 
     if (current_step == STEP_WELCOME) {
         /* restore font color */
         set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
 
-        txt(10, 2, "You have not configured i3 yet.");
-        txt(10, 3, "Do you want me to generate ~/.i3/config?");
-        txt(85, 5, "Yes, generate ~/.i3/config");
-        txt(85, 7, "No, I will use the defaults");
+        txt(logical_px(10), 2, "You have not configured i3 yet.");
+        txt(logical_px(10), 3, "Do you want me to generate ~/.i3/config?");
+        txt(logical_px(85), 5, "Yes, generate ~/.i3/config");
+        txt(logical_px(85), 7, "No, I will use the defaults");
 
         /* green */
         set_font_colors(pixmap_gc, get_colorpixel("#00FF00"), get_colorpixel("#000000"));
-        txt(25, 5, "<Enter>");
+        txt(logical_px(25), 5, "<Enter>");
 
         /* red */
         set_font_colors(pixmap_gc, get_colorpixel("#FF0000"), get_colorpixel("#000000"));
-        txt(31, 7, "<ESC>");
+        txt(logical_px(31), 7, "<ESC>");
     }
 
     if (current_step == STEP_GENERATE) {
         set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
 
-        txt(10, 2, "Please choose either:");
-        txt(85, 4, "Win as default modifier");
-        txt(85, 5, "Alt as default modifier");
-        txt(10, 7, "Afterwards, press");
-        txt(85, 9, "to write ~/.i3/config");
-        txt(85, 10, "to abort");
+        txt(logical_px(10), 2, "Please choose either:");
+        txt(logical_px(85), 4, "Win as default modifier");
+        txt(logical_px(85), 5, "Alt as default modifier");
+        txt(logical_px(10), 7, "Afterwards, press");
+        txt(logical_px(85), 9, "to write ~/.i3/config");
+        txt(logical_px(85), 10, "to abort");
 
         /* the not-selected modifier */
         if (modifier == MOD_Mod4)
-            txt(31, 5, "<Alt>");
+            txt(logical_px(31), 5, "<Alt>");
         else
-            txt(31, 4, "<Win>");
+            txt(logical_px(31), 4, "<Win>");
 
         /* the selected modifier */
         set_font(&bold_font);
         set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
         if (modifier == MOD_Mod4)
-            txt(10, 4, "-> <Win>");
+            txt(logical_px(10), 4, "-> <Win>");
         else
-            txt(10, 5, "-> <Alt>");
+            txt(logical_px(10), 5, "-> <Alt>");
 
         /* green */
         set_font(&font);
         set_font_colors(pixmap_gc, get_colorpixel("#00FF00"), get_colorpixel("#000000"));
-        txt(25, 9, "<Enter>");
+        txt(logical_px(25), 9, "<Enter>");
 
         /* red */
         set_font_colors(pixmap_gc, get_colorpixel("#FF0000"), get_colorpixel("#000000"));
-        txt(31, 10, "<ESC>");
+        txt(logical_px(31), 10, "<ESC>");
     }
 
     /* Copy the contents of the pixmap to the real window */
-    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, /* */ 500, 500);
+    xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, logical_px(500), logical_px(500));
     xcb_flush(conn);
 
     return 1;
@@ -637,14 +637,14 @@ static void handle_button_press(xcb_button_press_event_t *event) {
     if (current_step != STEP_GENERATE)
         return;
 
-    if (event->event_x >= 32 && event->event_x <= 68 &&
-        event->event_y >= 45 && event->event_y <= 54) {
+    if (event->event_x >= logical_px(32) && event->event_x <= logical_px(68) &&
+        event->event_y >= logical_px(45) && event->event_y <= logical_px(54)) {
         modifier = MOD_Mod4;
         handle_expose();
     }
 
-    if (event->event_x >= 32 && event->event_x <= 68 &&
-        event->event_y >= 56 && event->event_y <= 70) {
+    if (event->event_x >= logical_px(32) && event->event_x <= logical_px(68) &&
+        event->event_y >= logical_px(56) && event->event_y <= logical_px(70)) {
         modifier = MOD_Mod1;
         handle_expose();
     }
@@ -760,8 +760,8 @@ static void finish() {
 int main(int argc, char *argv[]) {
     config_path = resolve_tilde("~/.i3/config");
     socket_path = getenv("I3SOCK");
-    char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1";
-    char *patternbold = "-misc-fixed-bold-r-normal--13-120-75-75-C-70-iso10646-1";
+    char *pattern = "pango:monospace 8";
+    char *patternbold = "pango:monospace bold 8";
     int o, option_index = 0;
 
     static struct option long_options[] = {
@@ -863,10 +863,10 @@ int main(int argc, char *argv[]) {
     xcb_create_window(
         conn,
         XCB_COPY_FROM_PARENT,
-        win,                /* the window id */
-        root,               /* parent == root */
-        490, 297, 300, 205, /* dimensions */
-        0,                  /* X11 border = 0, we draw our own */
+        win,                                                                /* the window id */
+        root,                                                               /* parent == root */
+        logical_px(490), logical_px(297), logical_px(300), logical_px(205), /* 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_EVENT_MASK,
@@ -914,7 +914,7 @@ int main(int argc, char *argv[]) {
     /* Create pixmap */
     pixmap = xcb_generate_id(conn);
     pixmap_gc = xcb_generate_id(conn);
-    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, 500);
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), logical_px(500));
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
 
     /* Grab the keyboard to get all input */
index 7d5231905ccd0cd408624f32d64ac90310967f48..996fc0ea9f08958a3b563a359e85ad6c7388b798 100644 (file)
@@ -129,7 +129,8 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
     printf("expose!\n");
 
     /* re-draw the background */
-    xcb_rectangle_t border = {0, 0, 500, font.height + 8}, inner = {2, 2, 496, font.height + 8 - 4};
+    xcb_rectangle_t border = {0, 0, logical_px(500), font.height + logical_px(8)},
+                    inner = {logical_px(2), logical_px(2), logical_px(496), font.height + logical_px(8) - logical_px(4)};
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#FF0000")});
     xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")});
@@ -140,17 +141,17 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
 
     /* draw the prompt … */
     if (prompt != NULL) {
-        draw_text(prompt, pixmap, pixmap_gc, 4, 4, 492);
+        draw_text(prompt, pixmap, pixmap_gc, logical_px(4), logical_px(4), logical_px(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);
+        draw_text(input, pixmap, pixmap_gc, prompt_offset + logical_px(4), logical_px(4), logical_px(492));
         i3string_free(input);
     }
 
     /* 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_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, logical_px(500), font.height + logical_px(8));
     xcb_flush(conn);
 
     return 1;
@@ -234,6 +235,9 @@ static void finish_input() {
 static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
     printf("Keypress %d, state raw = %d\n", event->detail, event->state);
 
+    // TODO: port the input handling code from i3lock once libxkbcommon ≥ 0.5.0
+    // is available in distros.
+
     /* 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. */
@@ -313,7 +317,7 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
 int main(int argc, char *argv[]) {
     format = strdup("%s");
     socket_path = getenv("I3SOCK");
-    char *pattern = sstrdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1");
+    char *pattern = sstrdup("pango:monospace 8");
     int o, option_index = 0;
 
     static struct option long_options[] = {
@@ -403,10 +407,10 @@ int main(int argc, char *argv[]) {
     xcb_create_window(
         conn,
         XCB_COPY_FROM_PARENT,
-        win,                          /* the window id */
-        root,                         /* parent == root */
-        50, 50, 500, font.height + 8, /* dimensions */
-        0,                            /* X11 border = 0, we draw our own */
+        win,                                                                          /* the window id */
+        root,                                                                         /* parent == root */
+        logical_px(50), logical_px(50), logical_px(500), font.height + logical_px(8), /* 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,
@@ -421,7 +425,7 @@ int main(int argc, char *argv[]) {
     /* Create pixmap */
     pixmap = xcb_generate_id(conn);
     pixmap_gc = xcb_generate_id(conn);
-    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + 8);
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), font.height + logical_px(8));
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
 
     /* Set input focus (we have override_redirect=1, so the wm will not do
index b501ff6a304536437e02525d9f4846bd860922a8..805066f82d56b5a9002a0a836383356602b231cc 100644 (file)
@@ -131,7 +131,7 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve
     printf("button released on x = %d, y = %d\n",
            event->event_x, event->event_y);
     /* If the user hits the close button, we exit(0) */
-    if (event->event_x >= (rect.width - 32))
+    if (event->event_x >= (rect.width - logical_px(32)))
         exit(0);
     button_t *button = get_button_at(event->event_x, event->event_y);
     if (!button)
@@ -194,15 +194,17 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
     /* 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);
+              logical_px(4) + logical_px(4),
+              logical_px(4) + logical_px(4),
+              rect.width - logical_px(4) - logical_px(4));
 
     /* render close button */
     const char *close_button_label = "X";
-    int line_width = 4;
+    int line_width = logical_px(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;
+    w += logical_px(8);
     int y = rect.width;
     uint32_t values[3];
     values[0] = color_button_background;
@@ -216,19 +218,21 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
     xcb_point_t points[] = {
         {y - w - (2 * line_width), line_width / 2},
         {y - (line_width / 2), line_width / 2},
-        {y - (line_width / 2), (rect.height - (line_width / 2)) - 2},
-        {y - w - (2 * line_width), (rect.height - (line_width / 2)) - 2},
+        {y - (line_width / 2), (rect.height - (line_width / 2)) - logical_px(2)},
+        {y - w - (2 * line_width), (rect.height - (line_width / 2)) - logical_px(2)},
         {y - w - (2 * line_width), line_width / 2}};
     xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points);
 
     values[0] = 1;
     set_font_colors(pixmap_gc, color_text, color_button_background);
     /* the x term here seems to set left/right padding */
-    draw_text_ascii(close_button_label, pixmap, pixmap_gc, y - w - line_width + w / 2 - 4,
-                    4 + 4 - 1, rect.width - y + w + line_width - w / 2 + 4);
+    draw_text_ascii(close_button_label, pixmap, pixmap_gc,
+                    y - w - line_width + w / 2 - logical_px(4),
+                    logical_px(4) + logical_px(3),
+                    rect.width - y + w + line_width - w / 2 + logical_px(4));
     y -= w;
 
-    y -= 20;
+    y -= logical_px(20);
 
     /* render custom buttons */
     line_width = 1;
@@ -236,21 +240,21 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
         /* set w to the width of the label */
         w = predict_text_width(buttons[c].label);
         /* account for left/right padding, which seems to be set to 12px (total) below */
-        w += 12;
-        y -= 30;
+        w += logical_px(12);
+        y -= logical_px(30);
         xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_button_background});
-        close = (xcb_rectangle_t){y - w - (2 * line_width), 2, w + (2 * line_width), rect.height - 6};
+        close = (xcb_rectangle_t){y - w - (2 * line_width), logical_px(2), w + (2 * line_width), rect.height - logical_px(6)};
         xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close);
 
         xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_border});
         buttons[c].x = y - w - (2 * line_width);
         buttons[c].width = w;
         xcb_point_t points2[] = {
-            {y - w - (2 * line_width), (line_width / 2) + 2},
-            {y - (line_width / 2), (line_width / 2) + 2},
-            {y - (line_width / 2), (rect.height - 4 - (line_width / 2))},
-            {y - w - (2 * line_width), (rect.height - 4 - (line_width / 2))},
-            {y - w - (2 * line_width), (line_width / 2) + 2}};
+            {y - w - (2 * line_width), (line_width / 2) + logical_px(2)},
+            {y - (line_width / 2), (line_width / 2) + logical_px(2)},
+            {y - (line_width / 2), (rect.height - logical_px(4) - (line_width / 2))},
+            {y - w - (2 * line_width), (rect.height - logical_px(4) - (line_width / 2))},
+            {y - w - (2 * line_width), (line_width / 2) + logical_px(2)}};
         xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points2);
 
         values[0] = color_text;
@@ -258,13 +262,15 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
         set_font_colors(pixmap_gc, color_text, color_button_background);
         /* the x term seems to set left/right padding */
         draw_text(buttons[c].label, pixmap, pixmap_gc,
-                  y - w - line_width + 6, 4 + 3, rect.width - y + w + line_width - 6);
+                  y - w - line_width + logical_px(6),
+                  logical_px(4) + logical_px(3),
+                  rect.width - y + w + line_width - logical_px(6));
 
         y -= w;
     }
 
     /* border line at the bottom */
-    line_width = 2;
+    line_width = logical_px(2);
     values[0] = color_border_bottom;
     values[1] = line_width;
     xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values);
@@ -316,7 +322,7 @@ int main(int argc, char *argv[]) {
 
     argv0 = argv[0];
 
-    char *pattern = sstrdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1");
+    char *pattern = sstrdup("pango:monospace 8");
     int o, option_index = 0;
     enum { TYPE_ERROR = 0,
            TYPE_WARNING = 1 } bar_type = TYPE_ERROR;
@@ -408,10 +414,10 @@ int main(int argc, char *argv[]) {
     xcb_create_window(
         conn,
         XCB_COPY_FROM_PARENT,
-        win,                                                 /* the window id */
-        root,                                                /* parent == root */
-        50, 50, 500, font.height + 8 + 8 /* 8 px padding */, /* dimensions */
-        0,                                                   /* x11 border = 0, we draw our own */
+        win,                                                                         /* the window id */
+        root,                                                                        /* parent == root */
+        50, 50, 500, font.height + logical_px(8) + logical_px(8) /* 8 px padding */, /* 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_EVENT_MASK,
@@ -465,7 +471,7 @@ int main(int argc, char *argv[]) {
     } __attribute__((__packed__)) strut_partial;
     memset(&strut_partial, 0, sizeof(strut_partial));
 
-    strut_partial.top = font.height + 6;
+    strut_partial.top = font.height + logical_px(6);
     strut_partial.top_start_x = 0;
     strut_partial.top_end_x = 800;
 
@@ -481,7 +487,7 @@ int main(int argc, char *argv[]) {
     /* Create pixmap */
     pixmap = xcb_generate_id(conn);
     pixmap_gc = xcb_generate_id(conn);
-    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + 8);
+    xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + logical_px(8));
     xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0);
 
     /* Grab the keyboard to get all input */
index 747a9280aa6e307f77d155aeaab74717e5f3f6a0..dd4b075ac981740144011de201ebcb5acba232c3 100755 (executable)
@@ -13,3 +13,5 @@ for terminal in $TERMINAL x-terminal-emulator urxvt rxvt terminator Eterm aterm
         exec $terminal "$@"
     fi
 done
+
+i3-nagbar -m 'i3-sensible-terminal could not find a terminal emulator. Please install one.'
index 091230622b9b8661a5849418d59685f9876adb63..b87cfaacacffd8d78ff8679cf71dd8fe7e32c998 100644 (file)
@@ -4,7 +4,7 @@
  * i3bar - an xcb-based status- and ws-bar for i3
  * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
  *
- * child.c: Getting Input for the statusline
+ * child.c: Getting input for the statusline
  *
  */
 #pragma once
index fe04bf31aa9e2dc48fa478c795279e0e93957da2..fdc37445ab4944549742ca7c580fa4f488e51de0 100644 (file)
@@ -35,6 +35,7 @@ typedef struct config_t {
     char *bar_id;
     char *command;
     char *fontname;
+    i3String *separator_symbol;
     char *tray_output;
     int num_outputs;
     char **outputs;
index d1fcb069592a2ea20b46b64f74f8e8203da57080..a60a1ebae1603e44ae0f93847e58ebc6d4fc9f00 100644 (file)
@@ -25,7 +25,7 @@ int init_connection(const char *socket_path);
 void destroy_connection(void);
 
 /*
- * Sends a Message to i3.
+ * Sends a message to i3.
  * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information)
  *
  */
index 52abc9b980cb204c837b9ae29ea86006d0b620bd..ac13799851c097d08a4c638cf53eb8dda8a44933 100644 (file)
@@ -26,7 +26,7 @@
         }                \
     } while (0)
 
-/* Securely fee single-linked list */
+/* Securely free single-linked list */
 #define FREE_SLIST(l, type)              \
     do {                                 \
         type *walk = SLIST_FIRST(l);     \
@@ -37,7 +37,7 @@
         }                                \
     } while (0)
 
-/* Securely fee tail-queues */
+/* Securely free tail queue */
 #define FREE_TAILQ(l, type)                         \
     do {                                            \
         type *walk = TAILQ_FIRST(l);                \
index d8411a0a76ddc0974c4c23efabe2fb5a19a965ba..8e48c0c138e0734ea34ea77eae1ceddd689107c8 100644 (file)
@@ -90,7 +90,7 @@ void kick_tray_clients(i3_output *output);
 
 /*
  * We need to set the _NET_SYSTEM_TRAY_COLORS atom on the tray selection window
- * to make GTK+ 3 applets with Symbolic Icons visible. If the colors are unset,
+ * to make GTK+ 3 applets with symbolic icons visible. If the colors are unset,
  * they assume a light background.
  * See also https://bugzilla.gnome.org/show_bug.cgi?id=679591
  *
index 5347632ad6490d92edcbdd7ebc8bb4d3dfef132a..3de754e7c34039d1260844e47eb1ce4c4648b253 100644 (file)
@@ -4,7 +4,7 @@
  * i3bar - an xcb-based status- and ws-bar for i3
  * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
  *
- * child.c: Getting Input for the statusline
+ * child.c: Getting input for the statusline
  *
  */
 #include <stdlib.h>
index c568ac5b9c5a6f28426daa22348104ba63186175..f7abaee7dff9f9aa65abab5af1fc36a3c4c65cfb 100644 (file)
@@ -144,6 +144,13 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
         return 1;
     }
 
+    if (!strcmp(cur_key, "separator_symbol")) {
+        DLOG("separator = %.*s\n", len, val);
+        I3STRING_FREE(config.separator_symbol);
+        config.separator_symbol = i3string_from_utf8_with_length((const char *)val, len);
+        return 1;
+    }
+
     if (!strcmp(cur_key, "outputs")) {
         DLOG("+output %.*s\n", len, val);
         int new_num_outputs = config.num_outputs + 1;
@@ -241,7 +248,7 @@ void parse_config_json(char *json) {
 
     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
 
-    /* FIXME: Proper errorhandling for JSON-parsing */
+    /* FIXME: Proper error handling for JSON parsing */
     switch (state) {
         case yajl_status_ok:
             break;
index c6e67eb600dedc8a8e710b7475b4b2a4400cc9e8..ff6f57795cea3aa7e0f722c345521ebf8a6b94e7 100644 (file)
@@ -40,7 +40,7 @@ void got_command_reply(char *reply) {
  *
  */
 void got_workspace_reply(char *reply) {
-    DLOG("Got Workspace-Data!\n");
+    DLOG("Got workspace data!\n");
     parse_workspaces_json(reply);
     draw_bars(false);
 }
@@ -51,7 +51,7 @@ void got_workspace_reply(char *reply) {
  *
  */
 void got_subscribe_reply(char *reply) {
-    DLOG("Got Subscribe Reply: %s\n", reply);
+    DLOG("Got subscribe reply: %s\n", reply);
     /* TODO: Error handling for subscribe commands */
 }
 
@@ -60,9 +60,9 @@ void got_subscribe_reply(char *reply) {
  *
  */
 void got_output_reply(char *reply) {
-    DLOG("Parsing Outputs-JSON...\n");
+    DLOG("Parsing outputs JSON...\n");
     parse_outputs_json(reply);
-    DLOG("Reconfiguring Windows...\n");
+    DLOG("Reconfiguring windows...\n");
     realloc_sl_buffer();
     reconfig_windows(false);
 
@@ -104,7 +104,7 @@ void got_bar_config(char *reply) {
     FREE(config.command);
 }
 
-/* Data-structure to easily call the reply handlers later */
+/* Data structure to easily call the reply handlers later */
 handler_t reply_handlers[] = {
     &got_command_reply,
     &got_workspace_reply,
@@ -120,16 +120,16 @@ handler_t reply_handlers[] = {
  *
  */
 void got_workspace_event(char *event) {
-    DLOG("Got Workspace Event!\n");
+    DLOG("Got workspace event!\n");
     i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
 }
 
 /*
- * Called, when an output event arrives (i.e. the screen-configuration changed)
+ * Called, when an output event arrives (i.e. the screen configuration changed)
  *
  */
 void got_output_event(char *event) {
-    DLOG("Got Output Event!\n");
+    DLOG("Got output event!\n");
     i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
     if (!config.disable_ws) {
         i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
@@ -141,7 +141,7 @@ void got_output_event(char *event) {
  *
  */
 void got_mode_event(char *event) {
-    DLOG("Got Mode Event!\n");
+    DLOG("Got mode event!\n");
     parse_mode_json(event);
     draw_bars(false);
 }
@@ -180,7 +180,7 @@ void got_bar_config_update(char *event) {
     draw_bars(false);
 }
 
-/* Data-structure to easily call the event handlers later */
+/* Data structure to easily call the event handlers later */
 handler_t event_handlers[] = {
     &got_workspace_event,
     &got_output_event,
@@ -201,7 +201,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
     uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) * 2;
     char *header = smalloc(header_len);
 
-    /* We first parse the fixed-length IPC-header, to know, how much data
+    /* We first parse the fixed-length IPC header, to know, how much data
      * we have to expect */
     uint32_t rec = 0;
     while (rec < header_len) {
@@ -268,7 +268,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
 }
 
 /*
- * Sends a Message to i3.
+ * Sends a message to i3.
  * type must be a valid I3_IPC_MESSAGE_TYPE (see i3/ipc.h for further information)
  *
  */
index 34fc807b0a4c1f68d72b084c980b1f331be97375..a9a972dbe6c12a37a5893b830bf7244b5ef34bca 100644 (file)
@@ -140,7 +140,7 @@ int main(int argc, char **argv) {
     }
 
     if (socket_path == NULL) {
-        ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path);
+        ELOG("No socket path specified, default to %s\n", i3_default_sock_path);
         socket_path = expand_path(i3_default_sock_path);
     }
 
index 05f6de1a6d830eb02696966a5985a27679ff0c48..0ff8ba4f0239fd3fa70d6706e108d40a8144349d 100644 (file)
@@ -90,7 +90,7 @@ void parse_mode_json(char *json) {
 
     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
 
-    /* FIXME: Propper errorhandling for JSON-parsing */
+    /* FIXME: Propper error handling for JSON parsing */
     switch (state) {
         case yajl_status_ok:
             break;
index fa981f4eeaf562b863f97a40744157d74b4f9811..e30325265bb36835b2b5bdac5f8a7a76b54d2386 100644 (file)
@@ -135,7 +135,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t
         params->workspaces_walk->name_width =
             predict_text_width(params->workspaces_walk->name);
 
-        DLOG("Got Workspace canonical: %s, name: '%s', name_width: %d, glyphs: %zu\n",
+        DLOG("Got workspace canonical: %s, name: '%s', name_width: %d, glyphs: %zu\n",
              params->workspaces_walk->canonical_name,
              i3string_as_utf8(params->workspaces_walk->name),
              params->workspaces_walk->name_width,
@@ -239,13 +239,13 @@ void parse_workspaces_json(char *json) {
 
     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
 
-    /* FIXME: Propper errorhandling for JSON-parsing */
+    /* FIXME: Propper error handling for JSON parsing */
     switch (state) {
         case yajl_status_ok:
             break;
         case yajl_status_client_canceled:
         case yajl_status_error:
-            ELOG("Could not parse workspaces-reply!\n");
+            ELOG("Could not parse workspaces reply!\n");
             exit(EXIT_FAILURE);
             break;
     }
index d87e56e49e7ce590b363937c5cfcc89c7679db10..81f0bb4ae3c796b85f7ee1b7ab6ffda424591c65 100644 (file)
@@ -34,7 +34,7 @@
 #include "common.h"
 #include "libi3.h"
 
-/* We save the Atoms in an easy to access array, indexed by an enum */
+/* We save the atoms in an easy to access array, indexed by an enum */
 enum {
 #define ATOM_DO(name) name,
 #include "xcb_atoms.def"
@@ -63,6 +63,9 @@ static i3Font font;
 /* Overall height of the bar (based on font size) */
 int bar_height;
 
+/* Cached width of the custom separator if one was set */
+int separator_symbol_width;
+
 /* These are only relevant for XKB, which we only need for grabbing modifiers */
 int xkb_base;
 int mod_pressed = 0;
@@ -74,7 +77,7 @@ xcb_gcontext_t statusline_clear;
 xcb_pixmap_t statusline_pm;
 uint32_t statusline_width;
 
-/* Event-Watchers, to interact with the user */
+/* Event watchers, to interact with the user */
 ev_prepare *xcb_prep;
 ev_check *xcb_chk;
 ev_io *xcb_io;
@@ -155,6 +158,33 @@ int get_tray_width(struct tc_head *trayclients) {
     return tray_width;
 }
 
+/*
+ * Draws a separator for the given block if necessary.
+ *
+ */
+static void draw_separator(uint32_t x, struct status_block *block) {
+    uint32_t sep_offset = get_sep_offset(block);
+    if (TAILQ_NEXT(block, blocks) == NULL || sep_offset == 0)
+        return;
+
+    uint32_t center_x = x - sep_offset;
+    if (config.separator_symbol == NULL) {
+        /* Draw a classic one pixel, vertical separator. */
+        uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH;
+        uint32_t values[] = {colors.sep_fg, colors.bar_bg, logical_px(1)};
+        xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
+        xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm, statusline_ctx, 2,
+                      (xcb_point_t[]){{center_x, logical_px(sep_voff_px)},
+                                      {center_x, bar_height - logical_px(sep_voff_px)}});
+    } else {
+        /* Draw a custom separator. */
+        uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2);
+        set_font_colors(statusline_ctx, colors.sep_fg, colors.bar_bg);
+        draw_text(config.separator_symbol, statusline_pm, statusline_ctx,
+                  separator_x, logical_px(ws_voff_px), x - separator_x);
+    }
+}
+
 /*
  * Redraws the statusline to the buffer
  *
@@ -245,17 +275,8 @@ void refresh_statusline(bool use_short_text) {
         draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, logical_px(ws_voff_px), block->width);
         x += block->width + block->sep_block_width + block->x_offset + block->x_append;
 
-        uint32_t sep_offset = get_sep_offset(block);
-        if (TAILQ_NEXT(block, blocks) != NULL && sep_offset > 0) {
-            /* This is not the last block, draw a separator. */
-            uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH;
-            uint32_t values[] = {colors.sep_fg, colors.bar_bg, logical_px(1)};
-            xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
-            xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm,
-                          statusline_ctx, 2,
-                          (xcb_point_t[]){{x - sep_offset, logical_px(sep_voff_px)},
-                                          {x - sep_offset, bar_height - logical_px(sep_voff_px)}});
-        }
+        /* If this is not the last block, draw a separator. */
+        draw_separator(x, block);
     }
 }
 
@@ -1026,7 +1047,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
                 redraw_bars();
                 break;
             case XCB_BUTTON_PRESS:
-                /* Button press events are mouse-buttons clicked on one of our bars */
+                /* Button press events are mouse buttons clicked on one of our bars */
                 handle_button((xcb_button_press_event_t *)event);
                 break;
             case XCB_CLIENT_MESSAGE:
@@ -1059,7 +1080,7 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
 }
 
 /*
- * Dummy Callback. We only need this, so that the Prepare- and Check-Watchers
+ * Dummy callback. We only need this, so that the prepare and check watchers
  * are triggered
  *
  */
@@ -1072,7 +1093,7 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
  *
  */
 char *init_xcb_early() {
-    /* FIXME: xcb_connect leaks Memory */
+    /* FIXME: xcb_connect leaks memory */
     xcb_connection = xcb_connect(NULL, &screen);
     if (xcb_connection_has_error(xcb_connection)) {
         ELOG("Cannot open display\n");
@@ -1115,7 +1136,7 @@ char *init_xcb_early() {
                                                                root_screen->width_in_pixels,
                                                                root_screen->height_in_pixels);
 
-    /* The various Watchers to communicate with xcb */
+    /* The various watchers to communicate with xcb */
     xcb_io = smalloc(sizeof(ev_io));
     xcb_prep = smalloc(sizeof(ev_prepare));
     xcb_chk = smalloc(sizeof(ev_check));
@@ -1198,6 +1219,9 @@ void init_xcb_late(char *fontname) {
     DLOG("Calculated font height: %d\n", font.height);
     bar_height = font.height + 2 * logical_px(ws_voff_px);
 
+    if (config.separator_symbol)
+        separator_symbol_width = predict_text_width(config.separator_symbol);
+
     xcb_flush(xcb_connection);
 
     if (config.hide_on_modifier == M_HIDE)
@@ -1309,7 +1333,7 @@ void init_tray(void) {
 
 /*
  * We need to set the _NET_SYSTEM_TRAY_COLORS atom on the tray selection window
- * to make GTK+ 3 applets with Symbolic Icons visible. If the colors are unset,
+ * to make GTK+ 3 applets with symbolic icons visible. If the colors are unset,
  * they assume a light background.
  * See also https://bugzilla.gnome.org/show_bug.cgi?id=679591
  *
@@ -1501,6 +1525,50 @@ void realloc_sl_buffer(void) {
     }
 }
 
+/* Strut partial tells i3 where to reserve space for i3bar. This is determined
+ * by the `position` bar config directive. */
+xcb_void_cookie_t config_strut_partial(i3_output *output) {
+    /* A local struct to save the strut_partial property */
+    struct {
+        uint32_t left;
+        uint32_t right;
+        uint32_t top;
+        uint32_t bottom;
+        uint32_t left_start_y;
+        uint32_t left_end_y;
+        uint32_t right_start_y;
+        uint32_t right_end_y;
+        uint32_t top_start_x;
+        uint32_t top_end_x;
+        uint32_t bottom_start_x;
+        uint32_t bottom_end_x;
+    } __attribute__((__packed__)) strut_partial;
+    memset(&strut_partial, 0, sizeof(strut_partial));
+
+    switch (config.position) {
+        case POS_NONE:
+            break;
+        case POS_TOP:
+            strut_partial.top = bar_height;
+            strut_partial.top_start_x = output->rect.x;
+            strut_partial.top_end_x = output->rect.x + output->rect.w;
+            break;
+        case POS_BOT:
+            strut_partial.bottom = bar_height;
+            strut_partial.bottom_start_x = output->rect.x;
+            strut_partial.bottom_end_x = output->rect.x + output->rect.w;
+            break;
+    }
+    return xcb_change_property(xcb_connection,
+                               XCB_PROP_MODE_REPLACE,
+                               output->bar,
+                               atoms[_NET_WM_STRUT_PARTIAL],
+                               XCB_ATOM_CARDINAL,
+                               32,
+                               12,
+                               &strut_partial);
+}
+
 /*
  * Reconfigure all bars and create new bars for recently activated outputs
  *
@@ -1600,49 +1668,7 @@ void reconfig_windows(bool redraw_bars) {
                                                                 1,
                                                                 (unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
 
-            /* We need to tell i3, where to reserve space for i3bar */
-            /* left, right, top, bottom, left_start_y, left_end_y,
-             * right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
-             * bottom_end_x */
-            /* A local struct to save the strut_partial property */
-            struct {
-                uint32_t left;
-                uint32_t right;
-                uint32_t top;
-                uint32_t bottom;
-                uint32_t left_start_y;
-                uint32_t left_end_y;
-                uint32_t right_start_y;
-                uint32_t right_end_y;
-                uint32_t top_start_x;
-                uint32_t top_end_x;
-                uint32_t bottom_start_x;
-                uint32_t bottom_end_x;
-            } __attribute__((__packed__)) strut_partial;
-            memset(&strut_partial, 0, sizeof(strut_partial));
-
-            switch (config.position) {
-                case POS_NONE:
-                    break;
-                case POS_TOP:
-                    strut_partial.top = bar_height;
-                    strut_partial.top_start_x = walk->rect.x;
-                    strut_partial.top_end_x = walk->rect.x + walk->rect.w;
-                    break;
-                case POS_BOT:
-                    strut_partial.bottom = bar_height;
-                    strut_partial.bottom_start_x = walk->rect.x;
-                    strut_partial.bottom_end_x = walk->rect.x + walk->rect.w;
-                    break;
-            }
-            xcb_void_cookie_t strut_cookie = xcb_change_property(xcb_connection,
-                                                                 XCB_PROP_MODE_REPLACE,
-                                                                 walk->bar,
-                                                                 atoms[_NET_WM_STRUT_PARTIAL],
-                                                                 XCB_ATOM_CARDINAL,
-                                                                 32,
-                                                                 12,
-                                                                 &strut_partial);
+            xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
 
             /* We also want a graphics context for the bars (it defines the properties
              * with which we draw to them) */
@@ -1702,6 +1728,9 @@ void reconfig_windows(bool redraw_bars) {
             values[3] = bar_height;
             values[4] = XCB_STACK_MODE_ABOVE;
 
+            DLOG("Reconfiguring strut partial property for output %s\n", walk->name);
+            xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
+
             DLOG("Destroying buffer for output %s\n", walk->name);
             xcb_free_pixmap(xcb_connection, walk->buffer);
 
@@ -1750,6 +1779,7 @@ void reconfig_windows(bool redraw_bars) {
             if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
                 xcb_request_failed(chg_cookie, "Could not change window") ||
                 xcb_request_failed(pm_cookie, "Could not create pixmap") ||
+                xcb_request_failed(strut_cookie, "Could not set strut") ||
                 (redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
                                  (config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
                 exit(EXIT_FAILURE);
index afafb64be0cb8da35017684d0ec354e7cd03f50c..9a0af0e6cd6b8119e1a5ae4a4bd5fcef915cb66e 100644 (file)
@@ -285,6 +285,9 @@ struct Barconfig {
     /** Font specification for all text rendered on the bar. */
     char *font;
 
+    /** A custom separator to use instead of a vertical line. */
+    char *separator_symbol;
+
     /** Hide workspace buttons? Configuration option is 'workspace_buttons no'
      * but we invert the bool to get the correct default when initializing with
      * zero. */
index 0f1a6620ef1200f47b2f8b0738a7ab4589a4b24e..6c960b1f8c765771c2fd6d340872a76d7ea4fae6 100644 (file)
@@ -67,6 +67,7 @@ CFGFUN(enter_mode, const char *mode);
 CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command);
 
 CFGFUN(bar_font, const char *font);
+CFGFUN(bar_separator_symbol, const char *separator);
 CFGFUN(bar_mode, const char *mode);
 CFGFUN(bar_hidden_state, const char *hidden_state);
 CFGFUN(bar_id, const char *bar_id);
index dbdf83c2808aa076fce039a0a27313c8cb7c6953..25be5cf107e2bef2eebdba243980ee04085c9efa 100644 (file)
@@ -370,6 +370,7 @@ state BAR:
   'output'                 -> BAR_OUTPUT
   'tray_output'            -> BAR_TRAY_OUTPUT
   'font'                   -> BAR_FONT
+  'separator_symbol'       -> BAR_SEPARATOR_SYMBOL
   'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
   'workspace_buttons'      -> BAR_WORKSPACE_BUTTONS
   'strip_workspace_numbers' -> BAR_STRIP_WORKSPACE_NUMBERS
@@ -435,6 +436,10 @@ state BAR_FONT:
   font = string
       -> call cfg_bar_font($font); BAR
 
+state BAR_SEPARATOR_SYMBOL:
+  separator = string
+      -> call cfg_bar_separator_symbol($separator); BAR
+
 state BAR_BINDING_MODE_INDICATOR:
   value = word
       -> call cfg_bar_binding_mode_indicator($value); BAR
index 80d7876b927f573d080a52a5b5c1aa259d593a1a..c8b25c7645f6cfc7e8c2d8ab210101138719957d 100644 (file)
@@ -421,6 +421,11 @@ CFGFUN(bar_font, const char *font) {
     current_bar.font = sstrdup(font);
 }
 
+CFGFUN(bar_separator_symbol, const char *separator) {
+    FREE(current_bar.separator_symbol);
+    current_bar.separator_symbol = sstrdup(separator);
+}
+
 CFGFUN(bar_mode, const char *mode) {
     current_bar.mode = (strcmp(mode, "dock") == 0 ? M_DOCK : (strcmp(mode, "hide") == 0 ? M_HIDE : M_INVISIBLE));
 }
index 0cd397fd0669e6f855dc80e6a4957498f3c8c1b6..4b5c87d4fd0651db363b8bea27e1c9507cd1fb0c 100644 (file)
@@ -1159,6 +1159,87 @@ static bool handle_class_change(void *data, xcb_connection_t *conn, uint8_t stat
     return true;
 }
 
+/*
+ * Handles the _NET_WM_STRUT_PARTIAL property for allocating space for dock clients.
+ *
+ */
+static bool handle_strut_partial_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
+                                        xcb_atom_t name, xcb_get_property_reply_t *prop) {
+    DLOG("strut partial change for window 0x%08x\n", window);
+
+    Con *con;
+    if ((con = con_by_window_id(window)) == NULL || con->window == NULL) {
+        return false;
+    }
+
+    if (prop == NULL) {
+        xcb_generic_error_t *err = NULL;
+        xcb_get_property_cookie_t strut_cookie = xcb_get_property(conn, false, window, A__NET_WM_STRUT_PARTIAL,
+                                                                  XCB_GET_PROPERTY_TYPE_ANY, 0, UINT32_MAX);
+        prop = xcb_get_property_reply(conn, strut_cookie, &err);
+
+        if (err != NULL) {
+            DLOG("got error when getting strut partial property: %d\n", err->error_code);
+            free(err);
+            return false;
+        }
+
+        if (prop == NULL) {
+            return false;
+        }
+    }
+
+    DLOG("That is con %p / %s\n", con, con->name);
+
+    window_update_strut_partial(con->window, prop);
+
+    /* we only handle this change for dock clients */
+    if (con->parent == NULL || con->parent->type != CT_DOCKAREA) {
+        return true;
+    }
+
+    Con *search_at = croot;
+    Con *output = con_get_output(con);
+    if (output != NULL) {
+        DLOG("Starting search at output %s\n", output->name);
+        search_at = output;
+    }
+
+    /* find out the desired position of this dock window */
+    if (con->window->reserved.top > 0 && con->window->reserved.bottom == 0) {
+        DLOG("Top dock client\n");
+        con->window->dock = W_DOCK_TOP;
+    } else if (con->window->reserved.top == 0 && con->window->reserved.bottom > 0) {
+        DLOG("Bottom dock client\n");
+        con->window->dock = W_DOCK_BOTTOM;
+    } else {
+        DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n");
+        if (con->geometry.y < (int16_t)(search_at->rect.height / 2)) {
+            DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n",
+                 con->geometry.y, (search_at->rect.height / 2));
+            con->window->dock = W_DOCK_TOP;
+        } else {
+            DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n",
+                 con->geometry.y, (search_at->rect.height / 2));
+            con->window->dock = W_DOCK_BOTTOM;
+        }
+    }
+
+    /* find the dockarea */
+    Con *dockarea = con_for_window(search_at, con->window, NULL);
+    assert(dockarea != NULL);
+
+    /* attach the dock to the dock area */
+    con_detach(con);
+    con->parent = dockarea;
+    TAILQ_INSERT_HEAD(&(dockarea->focus_head), con, focused);
+    TAILQ_INSERT_HEAD(&(dockarea->nodes_head), con, nodes);
+
+    tree_render();
+
+    return true;
+}
+
 /* Returns false if the event could not be processed (e.g. the window could not
  * be found), true otherwise */
 typedef bool (*cb_property_handler_t)(void *data, xcb_connection_t *c, uint8_t state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
@@ -1177,7 +1258,8 @@ static struct property_handler_t property_handlers[] = {
     {0, UINT_MAX, handle_clientleader_change},
     {0, UINT_MAX, handle_transient_for},
     {0, 128, handle_windowrole_change},
-    {0, 128, handle_class_change}};
+    {0, 128, handle_class_change},
+    {0, UINT_MAX, handle_strut_partial_change}};
 #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
 
 /*
@@ -1196,6 +1278,7 @@ void property_handlers_init(void) {
     property_handlers[5].atom = XCB_ATOM_WM_TRANSIENT_FOR;
     property_handlers[6].atom = A_WM_WINDOW_ROLE;
     property_handlers[7].atom = XCB_ATOM_WM_CLASS;
+    property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
 }
 
 static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
index acd2267bdb61f761f34511d3adaf3bec7afcff50..52f7db2efe432c50fedecefb0940b8404b8ef2b2 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -450,6 +450,10 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     y(array_open);
     Match *match;
     TAILQ_FOREACH(match, &(con->swallow_head), matches) {
+        /* We will generate a new restart_mode match specification after this
+         * loop, so skip this one. */
+        if (match->restart_mode)
+            continue;
         y(map_open);
         if (match->dock != -1) {
             ystr("dock");
@@ -594,6 +598,11 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
     YSTR_IF_SET(status_command);
     YSTR_IF_SET(font);
 
+    if (config->separator_symbol) {
+        ystr("separator_symbol");
+        ystr(config->separator_symbol);
+    }
+
     ystr("workspace_buttons");
     y(bool, !config->hide_workspace_buttons);
 
index 0f6e54f9cc18e68d01d832680ab201e4b503838d..53a70d69afe7345c8ed792951303e98aa7c4b18d 100644 (file)
@@ -180,7 +180,9 @@ static void update_placeholder_contents(placeholder_state *state) {
 
 static void open_placeholder_window(Con *con) {
     if (con_is_leaf(con) &&
-        (con->window == NULL || con->window->id == XCB_NONE)) {
+        (con->window == NULL || con->window->id == XCB_NONE) &&
+        !TAILQ_EMPTY(&(con->swallow_head)) &&
+        con->type == CT_CON) {
         xcb_window_t placeholder = create_window(
             restore_conn,
             con->rect,
@@ -194,6 +196,11 @@ static void open_placeholder_window(Con *con) {
                 config.client.placeholder.background,
                 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY,
             });
+        /* Make i3 not focus this window. */
+        xcb_icccm_wm_hints_t hints;
+        xcb_icccm_wm_hints_set_none(&hints);
+        xcb_icccm_wm_hints_set_input(&hints, 0);
+        xcb_icccm_set_wm_hints(restore_conn, placeholder, &hints);
         /* Set the same name as was stored in the layout file. While perhaps
          * slightly confusing in the first instant, this brings additional
          * clarity to which placeholder is waiting for which actual window. */
index 9b60fea6f9cc5031fc2663d1cd494986909c08ea..b40ba2a2879203b503d7640937184fae91f3ea13 100644 (file)
@@ -104,6 +104,8 @@ bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) {
         TAILQ_INSERT_HEAD(&(croot->nodes_head), __i3, nodes);
     }
 
+    restore_open_placeholder_windows(croot);
+
     return true;
 }
 
index 1bac40f053e43318b242c0b61b2d1b6175e83b4b..bb9c71c9283826b1b6e2cae025b109e8d7cddecd 100644 (file)
@@ -143,6 +143,22 @@ wait_for_map $window;
 @docked = get_dock_clients('top');
 is(@docked, 1, 'dock client on top');
 
+# now change strut_partial to reserve space on the bottom and the dock should
+# be moved to the bottom dock area
+$x->change_property(
+    PROP_MODE_REPLACE,
+    $window->id,
+    $atomname->id,
+    $atomtype->id,
+    32,         # 32 bit integer
+    12,
+    pack('L12', 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1280, 0)
+);
+
+sync_with_i3;
+@docked = get_dock_clients('bottom');
+is(@docked, 1, 'dock client on bottom');
+
 $window->destroy;
 
 wait_for_unmap $window;
index 9643aa42f5f5678536a181e481cc1a1da00f1fdf..1e91d47f9cf5cdcb71f9ccf350aefd1f61f2e364 100644 (file)
@@ -647,7 +647,7 @@ EOT
 
 $expected = <<'EOT';
 cfg_bar_output(LVDS-1)
-ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}'
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'separator_symbol', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}'
 ERROR: CONFIG: (in file <stdin>)
 ERROR: CONFIG: Line   1: bar {
 ERROR: CONFIG: Line   2:     output LVDS-1