]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1595 from Deiz/fix-1484
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Sun, 29 Mar 2015 21:14:37 +0000 (23:14 +0200)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Sun, 29 Mar 2015 21:14:37 +0000 (23:14 +0200)
Fix percents when attaching a window to a ws creates a new split con

34 files changed:
.travis.yml
RELEASE-NOTES-4.10.1 [new file with mode: 0644]
RELEASE-NOTES-4.9.1 [deleted file]
debian/changelog
docs/i3bar-protocol
docs/userguide
i3-config-wizard/main.c
i3-dump-log/main.c
i3-nagbar/i3-nagbar.mk
i3-nagbar/main.c
i3bar/src/child.c
i3bar/src/ipc.c
i3bar/src/xcb.c
include/commands.h
include/libi3.h
include/util.h
libi3/get_config_path.c [new file with mode: 0644]
libi3/ipc_send_message.c
libi3/resolve_tilde.c [new file with mode: 0644]
libi3/safewrappers.c
man/asciidoc.conf
parser-specs/commands.spec
release.sh
src/click.c
src/commands.c
src/con.c
src/config.c
src/config_parser.c
src/handlers.c
src/load_layout.c
src/sighandler.c
src/util.c
testcases/t/113-urgent.t
testcases/t/210-mark-unmark.t

index ebabbfafeb14da1aa6958d99f314be8fc9851b7d..733daeac39117ae0f04587d31ddf8f4e3522588b 100644 (file)
@@ -42,6 +42,6 @@ install:
   - sudo /bin/sh -c 'cpanm -n -v X11::XCB || true'
   - sudo /bin/sh -c 'cpanm -n -v AnyEvent::I3 || true'
 script:
-  - make -j
+  - CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" make -j
   - (cd testcases && xvfb-run ./complete-run.pl --parallel=1 || (cat latest/complete-run.log; false))
   - clang-format-3.5 -i $(find . -name "*.[ch]" | tr '\n' ' ') && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false)
diff --git a/RELEASE-NOTES-4.10.1 b/RELEASE-NOTES-4.10.1
new file mode 100644 (file)
index 0000000..61b4770
--- /dev/null
@@ -0,0 +1,68 @@
+
+ ┌──────────────────────────────┐
+ │ Release notes for i3 v4.10.1 │
+ └──────────────────────────────┘
+
+This is i3 v4.10.1. This version is considered stable. All users of i3 are
+strongly encouraged to upgrade.
+
+This release contains mostly bugfixes, but we felt it was necessary since there
+are two important changes in behavior: we have reverted the pango markup
+parsing by default (introduced with i3 v4.9) and the change in how the
+“workspace” command behaves (introduced with i3 v4.9). Both of them broke some
+user’s setups, which is not acceptable. In order to help us avoid such mistakes
+in the future, please consider using the i3 git version — it is typically
+stable.
+
+PS: The v4.10 release did not contain any of the commits we meant to release
+due to a human error in our release automation. Hence the v4.10.1 release.
+
+ ┌────────────────────────────┐
+ │ Changes in i3 v4.10.1      │
+ └────────────────────────────┘
+
+  • i3bar: cut long statuslines from the left
+  • i3bar: add support for the short_text property
+  • i3-sensible-terminal: launch i3-nagbar when no terminal is found
+  • i3-config-wizard: switch modifier on key up/down
+  • docs/layout-saving: added a troubleshooting section
+  • docs: degender all the terms
+  • Revert "Workspace command number selection"
+  • don’t parse blocks as markup by default
+  • Allow escaping backslashes in commands.
+  • switch default font from “DejaVu Sans Mono 8” to “monospace 8”, which is
+    typically a synonym, except for users who prefer a different font.
+  • When renaming a workspace, look for assignments and move the renamed
+    workspace to the appropriate output.
+  • i3-save-tree: make --workspace optional by defaulting to the focused
+    workspace
+  • Allow nop command without argument
+
+ ┌────────────────────────────┐
+ │ Bugfixes                   │
+ └────────────────────────────┘
+
+  • i3bar: buffer the statusline to avoid flickering
+  • i3bar: fix click events for workspace buttons with long statusline
+  • i3bar: set correct initial position when reconfiguring
+  • i3bar: reconfigure strut partial on reload
+  • i3-nagbar: fix sizes/positioning on hi-dpi displays
+  • i3-config-wizard: fix sizes/positioning on hi-dpi displays
+  • i3-input: fix sizes/positioning on hi-dpi displays
+  • Fix scrolling in window decoration with hidden cursor.
+  • workspace rename focus mismatch
+  • Don’t overwrite border width when already set (placeholders).
+  • fix a segfault during config file validation
+  • Restore placeholder windows after restarting.
+  • Don’t focus placeholder windows.
+
+ ┌────────────────────────────┐
+ │ Thanks!                    │
+ └────────────────────────────┘
+
+Thanks for testing, bugfixes, discussions and everything I forgot go out to:
+
+  Chih-Chyuan Hwang, Deiz, Diana Dinosaur, Ingo Bürk, Michael Hofmann,
+  Michael Tipton, Micha Rosenbaum, shdown, Tony Crisci
+
+-- Michael Stapelberg, 2015-03-29
diff --git a/RELEASE-NOTES-4.9.1 b/RELEASE-NOTES-4.9.1
deleted file mode 100644 (file)
index 5ff6d22..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-
- ┌──────────────────────────────┐
- │ Release notes for i3 v4.9.1  │
- └──────────────────────────────┘
-
-This is i3 v4.9.1. This version is considered stable. All users of i3 are
-strongly encouraged to upgrade.
-
-This is a bugfix release for i3 v4.9.
-
- ┌────────────────────────────┐
- │ Bugfixes                   │
- └────────────────────────────┘
-
-  • i3bar: fix incorrect y-offset for text
-  • fix key bindings on big-endian platforms
-  • fix key bindings using Mode_switch
-  • fix keyboard layout change detection
-  • revert "Handle WM_CHANGE_STATE requests for iconic state" (fixes problems
-    with application windows disappearing, like SDL-based games when switching
-    workspaces)
-  • insert id-based match at HEAD, not TAIL (fixes window swallowing not
-    working when the criteria match the placeholder window)
-  • improve error messages on failing commands
-  • replace ~ in filepath when calling append_layout
-  • properly error out when the layout file cannot be read
-
- ┌────────────────────────────┐
- │ Thanks!                    │
- └────────────────────────────┘
-
-Thanks for testing, bugfixes, discussions and everything I forgot go out to:
-
-  Steven McDonald, Ton van den Heuvel, Ingo Bürk
-
--- Michael Stapelberg, 2015-03-07
index 1dcfc9f9fc6b45a458ded6042da814f30149c967..183e59406b9d8d96a388158a725ef9ac956ef34e 100644 (file)
@@ -1,8 +1,20 @@
-i3-wm (4.9.2-1) experimental; urgency=medium
+i3-wm (4.10.2-1) experimental; urgency=medium
 
   * NOT YET RELEASED.
 
- -- Michael Stapelberg <stapelberg@debian.org>  Sat, 07 Mar 2015 20:31:31 +0100
+ -- Michael Stapelberg <stapelberg@debian.org>  Sun, 29 Mar 2015 19:10:38 +0200
+
+i3-wm (4.10.1-1) experimental; urgency=medium
+
+  * New upstream release.
+
+ -- Michael Stapelberg <stapelberg@debian.org>  Sun, 29 Mar 2015 18:54:07 +0200
+
+i3-wm (4.10-1) experimental; urgency=medium
+
+  * New upstream release.
+
+ -- Michael Stapelberg <stapelberg@debian.org>  Sun, 29 Mar 2015 17:46:09 +0200
 
 i3-wm (4.9.1-1) experimental; urgency=medium
 
index ccc763460ced1db2108fcbee593c3840b111c736..6cb04bf67bda4563917f05b504b7893f083318f8 100644 (file)
@@ -117,10 +117,8 @@ click_events::
 === Blocks in detail
 
 full_text::
-       The most simple block you can think of is one which just includes the
-       only required key, the +full_text+ key. i3bar will display the string
-       value parsed as
-       https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup].
+       The +full_text+ will be displayed by i3bar on the status line. This is the
+       only required key.
 short_text::
        Where appropriate, the +short_text+ (string) entry should also be
        provided. It will be used in case the status line needs to be shortened
@@ -174,8 +172,8 @@ separator_block_width::
        is 9 pixels), since the separator line is drawn in the middle.
 markup::
        A string that indicates how the text of the block should be parsed. Set to
-       +"pango"+ to use https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup]
-       (default). Set to +"none"+ to not use any markup.
+       +"pango"+ to use https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup].
+       Set to +"none"+ to not use any markup (default).
 
 If you want to put in your own entries into a block, prefix the key with an
 underscore (_). i3bar will ignore all keys it doesn’t understand, and prefixing
index 3d935e40aac7c2fbf8f5d5f6c2b45e47db4dec8b..d6dbde00fad36d36e4ba24442b5fd331f78f457f 100644 (file)
@@ -1857,9 +1857,13 @@ window, you cannot simply bind it to a key.  +i3-input+ is a tool created
 for this purpose: It lets you input a command and sends the command to i3. It
 can also prefix this command and display a custom prompt for the input dialog.
 
+The additional +--toggle+ option will remove the mark if the window already has
+this mark, add it if the window has none or replace the current mark if it has
+another mark.
+
 *Syntax*:
 ------------------------------
-mark identifier
+mark [--toggle] identifier
 [con_mark="identifier"] focus
 unmark identifier
 ------------------------------
index f052d6d570e69a601d31e449b1da29aa5591b348..673259b9e96b56ac49809320583b1674e58eb15e 100644 (file)
 #include "xcb.h"
 #include "libi3.h"
 
+#define row_y(row) \
+    (((row)-1) * font.height + logical_px(4))
+#define window_height() \
+    (row_y(15) + font.height)
+
 enum { STEP_WELCOME,
        STEP_GENERATE } current_step = STEP_WELCOME;
 enum { MOD_Mod1,
@@ -80,6 +85,7 @@ xcb_screen_t *root_screen;
 static xcb_get_modifier_mapping_reply_t *modmap_reply;
 static i3Font font;
 static i3Font bold_font;
+static int char_width;
 static char *socket_path;
 static xcb_window_t win;
 static xcb_pixmap_t pixmap;
@@ -455,45 +461,13 @@ void errorlog(char *fmt, ...) {
 void debuglog(char *fmt, ...) {
 }
 
-/*
- * This function resolves ~ in pathnames.
- * It may resolve wildcards in the first part of the path, but if no match
- * or multiple matches are found, it just returns a copy of path as given.
- *
- */
-static char *resolve_tilde(const char *path) {
-    static glob_t globbuf;
-    char *head, *tail, *result;
-
-    tail = strchr(path, '/');
-    head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
-
-    int res = glob(head, GLOB_TILDE, NULL, &globbuf);
-    free(head);
-    /* no match, or many wildcard matches are bad */
-    if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
-        result = strdup(path);
-    else if (res != 0) {
-        err(1, "glob() failed");
-    } else {
-        head = globbuf.gl_pathv[0];
-        result = calloc(1, strlen(head) + (tail ? strlen(tail) : 0) + 1);
-        strncpy(result, head, strlen(head));
-        if (tail)
-            strncat(result, tail, strlen(tail));
-    }
-    globfree(&globbuf);
-
-    return result;
-}
-
 /*
  * Handles expose events, that is, draws the window contents.
  *
  */
 static int handle_expose() {
     /* re-draw the background */
-    xcb_rectangle_t border = {0, 0, logical_px(300), (logical_px(15) * font.height) + logical_px(8)};
+    xcb_rectangle_t border = {0, 0, logical_px(300), window_height()};
     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,7 +475,7 @@ static int handle_expose() {
 
 #define txt(x, row, text)                    \
     draw_text_ascii(text, pixmap, pixmap_gc, \
-                    x, (row - 1) * font.height + logical_px(4), logical_px(500) - x * 2)
+                    x, row_y(row), logical_px(500) - x * 2)
 
     if (current_step == STEP_WELCOME) {
         /* restore font color */
@@ -592,6 +566,12 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
             finish();
     }
 
+    /* Swap between modifiers when up or down is pressed. */
+    if (sym == XK_Up || sym == XK_Down) {
+        modifier = (modifier == MOD_Mod1) ? MOD_Mod4 : MOD_Mod1;
+        handle_expose();
+    }
+
     /* cancel any time */
     if (sym == XK_Escape)
         exit(0);
@@ -637,14 +617,16 @@ static void handle_button_press(xcb_button_press_event_t *event) {
     if (current_step != STEP_GENERATE)
         return;
 
-    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)) {
+    if (event->event_x < logical_px(32) ||
+        event->event_x > (logical_px(32) + char_width * 5))
+        return;
+
+    if (event->event_y >= row_y(4) && event->event_y <= (row_y(4) + font.height)) {
         modifier = MOD_Mod4;
         handle_expose();
     }
 
-    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)) {
+    if (event->event_y >= row_y(5) && event->event_y <= (row_y(5) + font.height)) {
         modifier = MOD_Mod1;
         handle_expose();
     }
@@ -858,6 +840,10 @@ int main(int argc, char *argv[]) {
     font = load_font(pattern, true);
     bold_font = load_font(patternbold, true);
 
+    /* Determine character width in the default font. */
+    set_font(&font);
+    char_width = predict_text_width(i3string_from_utf8("a"));
+
     /* Open an input window */
     win = xcb_generate_id(conn);
     xcb_create_window(
@@ -865,7 +851,7 @@ int main(int argc, char *argv[]) {
         XCB_COPY_FROM_PARENT,
         win,                                                                /* the window id */
         root,                                                               /* parent == root */
-        logical_px(490), logical_px(297), logical_px(300), logical_px(205), /* dimensions */
+        logical_px(490), logical_px(297), logical_px(300), window_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 */
index 86b39338eae682f927bf93236658719bb03899cc..1b0d593c5e1c7322c11c210e739adfade5f50030 100644 (file)
@@ -43,8 +43,7 @@ static int check_for_wrap(void) {
      * of the log. */
     wrap_count = header->wrap_count;
     const int len = (logbuffer + header->offset_last_wrap) - walk;
-    if (write(STDOUT_FILENO, walk, len) != len)
-        err(EXIT_FAILURE, "write()");
+    swrite(STDOUT_FILENO, walk, len);
     walk = logbuffer + sizeof(i3_shmlog_header);
     return 1;
 }
@@ -52,12 +51,8 @@ static int check_for_wrap(void) {
 static void print_till_end(void) {
     check_for_wrap();
     const int len = (logbuffer + header->offset_next_write) - walk;
-    const int n = write(STDOUT_FILENO, walk, len);
-    if (len != n)
-        err(EXIT_FAILURE, "write()");
-    if (n > 0) {
-        walk += n;
-    }
+    swrite(STDOUT_FILENO, walk, len);
+    walk += len;
 }
 
 int main(int argc, char *argv[]) {
index e54aa6544876739b6289edec0dad9f12acb5c825..e98d65824c845ce3ddc3faf5d6e3617d6118fad3 100644 (file)
@@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-nagbar
 
 i3_nagbar_SOURCES := $(wildcard i3-nagbar/*.c)
 i3_nagbar_HEADERS := $(wildcard i3-nagbar/*.h)
-i3_nagbar_CFLAGS   = $(XCB_CFLAGS) $(PANGO_CFLAGS)
-i3_nagbar_LIBS     = $(XCB_LIBS) $(PANGO_LIBS)
+i3_nagbar_CFLAGS   = $(XCB_CFLAGS) $(XCB_WM_CFLAGS) $(PANGO_CFLAGS)
+i3_nagbar_LIBS     = $(XCB_LIBS) $(XCB_WM_LIBS) $(PANGO_LIBS)
 
 i3_nagbar_OBJECTS := $(i3_nagbar_SOURCES:.c=.o)
 
index 805066f82d56b5a9002a0a836383356602b231cc..83389b34b240ed7da3f8c62152f25842a30438c6 100644 (file)
@@ -27,6 +27,7 @@
 #include <xcb/xcb.h>
 #include <xcb/xcb_aux.h>
 #include <xcb/xcb_event.h>
+#include <xcb/randr.h>
 
 #include "libi3.h"
 #include "i3-nagbar.h"
@@ -164,7 +165,9 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve
     char *link_path;
     char *exe_path = get_exe_path(argv0);
     sasprintf(&link_path, "%s.nagbar_cmd", script_path);
-    symlink(exe_path, link_path);
+    if (symlink(exe_path, link_path) == -1) {
+        err(EXIT_FAILURE, "Failed to symlink %s to %s", link_path, exe_path);
+    }
 
     char *terminal_cmd;
     sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", link_path);
@@ -286,6 +289,60 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
     return 1;
 }
 
+/**
+ * Return the position and size the i3-nagbar window should use.
+ * This will be the primary output or a fallback if it cannot be determined.
+ */
+static xcb_rectangle_t get_window_position(void) {
+    /* Default values if we cannot determine the primary output or its CRTC info. */
+    xcb_rectangle_t result = (xcb_rectangle_t){50, 50, 500, font.height + logical_px(8) + logical_px(8)};
+
+    xcb_randr_get_screen_resources_current_cookie_t rcookie = xcb_randr_get_screen_resources_current(conn, root);
+    xcb_randr_get_output_primary_cookie_t pcookie = xcb_randr_get_output_primary(conn, root);
+
+    xcb_randr_get_output_primary_reply_t *primary = NULL;
+    xcb_randr_get_screen_resources_current_reply_t *res = NULL;
+
+    if ((primary = xcb_randr_get_output_primary_reply(conn, pcookie, NULL)) == NULL) {
+        DLOG("Could not determine the primary output.\n");
+        goto free_resources;
+    }
+
+    if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) {
+        goto free_resources;
+    }
+
+    xcb_randr_get_output_info_reply_t *output =
+        xcb_randr_get_output_info_reply(conn,
+                                        xcb_randr_get_output_info(conn, primary->output, res->config_timestamp),
+                                        NULL);
+    if (output == NULL || output->crtc == XCB_NONE)
+        goto free_resources;
+
+    xcb_randr_get_crtc_info_reply_t *crtc =
+        xcb_randr_get_crtc_info_reply(conn,
+                                      xcb_randr_get_crtc_info(conn, output->crtc, res->config_timestamp),
+                                      NULL);
+    if (crtc == NULL)
+        goto free_resources;
+
+    DLOG("Found primary output on position x = %i / y = %i / w = %i / h = %i",
+         crtc->x, crtc->y, crtc->width, crtc->height);
+    if (crtc->width == 0 || crtc->height == 0) {
+        DLOG("Primary output is not active, ignoring it.\n");
+        goto free_resources;
+    }
+
+    result.x = crtc->x;
+    result.y = crtc->y;
+    goto free_resources;
+
+free_resources:
+    FREE(res);
+    FREE(primary);
+    return result;
+}
+
 int main(int argc, char *argv[]) {
     /* The following lines are a terribly horrible kludge. Because terminal
      * emulators have different ways of interpreting the -e command line
@@ -408,16 +465,18 @@ int main(int argc, char *argv[]) {
     font = load_font(pattern, true);
     set_font(&font);
 
+    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 */
-        50, 50, 500, font.height + logical_px(8) + logical_px(8) /* 8 px padding */, /* dimensions */
-        0,                                                                           /* x11 border = 0, we draw our own */
+        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_EVENT_MASK,
index 20fbd9b07bfc5c325670e7ceb30617090e0b3e4f..9cc50f2a25f7b5e3a3d9bb0981ecc4ea93ee8be3 100644 (file)
@@ -103,7 +103,7 @@ __attribute__((format(printf, 1, 2))) static void set_statusline_error(const cha
     char *message;
     va_list args;
     va_start(args, format);
-    vasprintf(&message, format, args);
+    (void)vasprintf(&message, format, args);
 
     struct status_block *err_block = scalloc(sizeof(struct status_block));
     err_block->full_text = i3string_from_utf8("Error: ");
@@ -164,9 +164,6 @@ static int stdin_start_map(void *context) {
     /* Default width of the separator block. */
     ctx->block.sep_block_width = logical_px(9);
 
-    /* Use markup by default */
-    ctx->block.is_markup = true;
-
     return 1;
 }
 
@@ -473,11 +470,22 @@ void child_write_output(void) {
     if (child.click_events) {
         const unsigned char *output;
         size_t size;
+        ssize_t n;
 
         yajl_gen_get_buf(gen, &output, &size);
-        write(child_stdin, output, size);
-        write(child_stdin, "\n", 1);
+
+        n = writeall(child_stdin, output, size);
+        if (n != -1)
+            n = writeall(child_stdin, "\n", 1);
+
         yajl_gen_clear(gen);
+
+        if (n == -1) {
+            child.click_events = false;
+            kill_child();
+            set_statusline_error("child_write_output failed");
+            draw_bars(false);
+        }
     }
 }
 
index ff6f57795cea3aa7e0f722c345521ebf8a6b94e7..15a26d7b4eb42b502fa3ca1a45d01cee90bc42d3 100644 (file)
@@ -296,18 +296,7 @@ int i3_send_msg(uint32_t type, const char *payload) {
     if (payload != NULL)
         strncpy(walk, payload, len);
 
-    uint32_t written = 0;
-
-    while (to_write > 0) {
-        int n = write(i3_connection->fd, buffer + written, to_write);
-        if (n == -1) {
-            ELOG("write() failed: %s\n", strerror(errno));
-            exit(EXIT_FAILURE);
-        }
-
-        to_write -= n;
-        written += n;
-    }
+    swrite(i3_connection->fd, buffer, to_write);
 
     FREE(buffer);
 
index d0bc3d6ca09d79b74d473ffef86b290e6e5c6ffe..e53b92262df976bd99d3bdccdfded1e04915c98a 100644 (file)
@@ -110,23 +110,23 @@ struct xcb_colors_t {
 struct xcb_colors_t colors;
 
 /* Horizontal offset between a workspace label and button borders */
-const static int ws_hoff_px = 4;
+static const int ws_hoff_px = 4;
 
 /* Vertical offset between a workspace label and button borders */
-const static int ws_voff_px = 3;
+static const int ws_voff_px = 3;
 
 /* Offset between two workspace buttons */
-const static int ws_spacing_px = 1;
+static const int ws_spacing_px = 1;
 
 /* Offset between the statusline and 1) workspace buttons on the left
  *                                   2) the tray or screen edge on the right */
-const static int sb_hoff_px = 4;
+static const int sb_hoff_px = 4;
 
 /* Additional offset between the tray and the statusline, if the tray is not empty */
-const static int tray_loff_px = 2;
+static const int tray_loff_px = 2;
 
 /* Vertical offset between the bar and a separator */
-const static int sep_voff_px = 4;
+static const int sep_voff_px = 4;
 
 /* We define xcb_request_failed as a macro to include the relevant line number */
 #define xcb_request_failed(cookie, err_msg) _xcb_request_failed(cookie, err_msg, __LINE__)
@@ -1941,7 +1941,7 @@ void draw_bars(bool unhide) {
             DLOG("Printing statusline!\n");
 
             int tray_width = get_tray_width(outputs_walk->trayclients);
-            int max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px);
+            uint32_t max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px);
 
             /* If the statusline is too long, try to use short texts. */
             if (statusline_width > max_statusline_width)
index 780a9e8eb781893dd3fb69c8642783b98c73e676..0f7e3635c0964b997f7ea219b930c5359fd50124 100644 (file)
@@ -109,10 +109,10 @@ void cmd_workspace_back_and_forth(I3_CMD);
 void cmd_workspace_name(I3_CMD, char *name);
 
 /**
- * Implementation of 'mark <mark>'
+ * Implementation of 'mark [--toggle] <mark>'
  *
  */
-void cmd_mark(I3_CMD, char *mark);
+void cmd_mark(I3_CMD, char *mark, char *toggle);
 
 /**
  * Implementation of 'unmark [mark]'
index c8d2e9561ad7b334cf421e70eef5fc1ce9cd3203..82c46fcea645a59ac44cad99bdac70ffb62f0e48 100644 (file)
@@ -134,6 +134,20 @@ char *sstrdup(const char *str);
  */
 int sasprintf(char **strp, const char *fmt, ...);
 
+/**
+ * Wrapper around correct write which returns -1 (meaning that
+ * write failed) or count (meaning that all bytes were written)
+ *
+ */
+ssize_t writeall(int fd, const void *buf, size_t count);
+
+/**
+ * Safe-wrapper around writeall which exits if it returns -1 (meaning that
+ * write failed)
+ *
+ */
+ssize_t swrite(int fd, const void *buf, size_t count);
+
 /**
  * Build an i3String from an UTF-8 encoded string.
  * Returns the newly-allocated i3String.
@@ -420,3 +434,21 @@ char *get_exe_path(const char *argv0);
  *
  */
 int logical_px(const int logical);
+
+/**
+ * This function resolves ~ in pathnames.
+ * It may resolve wildcards in the first part of the path, but if no match
+ * or multiple matches are found, it just returns a copy of path as given.
+ *
+ */
+char *resolve_tilde(const char *path);
+
+/**
+ * Get the path of the first configuration file found. If override_configpath
+ * is specified, that path is returned and saved for further calls. Otherwise,
+ * checks the home directory first, then the system directory first, always
+ * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
+ * $XDG_CONFIG_DIRS)
+ *
+ */
+char *get_config_path(const char *override_configpath, bool use_system_paths);
index dec681168b49ee851995dd3d88444405d598e257..270b2f229dfef7185a02a686db162ddb72e57034 100644 (file)
@@ -106,14 +106,6 @@ void exec_i3_utility(char *name, char *argv[]);
 void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie,
                  char *err_message);
 
-/**
- * This function resolves ~ in pathnames.
- * It may resolve wildcards in the first part of the path, but if no match
- * or multiple matches are found, it just returns a copy of path as given.
- *
- */
-char *resolve_tilde(const char *path);
-
 /**
  * Checks if the given path exists by calling stat().
  *
diff --git a/libi3/get_config_path.c b/libi3/get_config_path.c
new file mode 100644 (file)
index 0000000..8b6eeb7
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ */
+#include "libi3.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/*
+ * Checks if the given path exists by calling stat().
+ *
+ */
+static bool path_exists(const char *path) {
+    struct stat buf;
+    return (stat(path, &buf) == 0);
+}
+
+/*
+ * Get the path of the first configuration file found. If override_configpath
+ * is specified, that path is returned and saved for further calls. Otherwise,
+ * checks the home directory first, then the system directory first, always
+ * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
+ * $XDG_CONFIG_DIRS)
+ *
+ */
+char *get_config_path(const char *override_configpath, bool use_system_paths) {
+    char *xdg_config_home, *xdg_config_dirs, *config_path;
+
+    static const char *saved_configpath = NULL;
+
+    if (override_configpath != NULL) {
+        saved_configpath = override_configpath;
+        return sstrdup(saved_configpath);
+    }
+
+    if (saved_configpath != NULL)
+        return sstrdup(saved_configpath);
+
+    /* 1: check the traditional path under the home directory */
+    config_path = resolve_tilde("~/.i3/config");
+    if (path_exists(config_path))
+        return config_path;
+    free(config_path);
+
+    /* 2: check for $XDG_CONFIG_HOME/i3/config */
+    if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
+        xdg_config_home = "~/.config";
+
+    xdg_config_home = resolve_tilde(xdg_config_home);
+    sasprintf(&config_path, "%s/i3/config", xdg_config_home);
+    free(xdg_config_home);
+
+    if (path_exists(config_path))
+        return config_path;
+    free(config_path);
+
+    /* The below paths are considered system-level, and can be skipped if the
+     * caller only wants user-level configs. */
+    if (!use_system_paths)
+        return NULL;
+
+    /* 3: check the traditional path under /etc */
+    config_path = SYSCONFDIR "/i3/config";
+    if (path_exists(config_path))
+        return sstrdup(config_path);
+
+    /* 4: check for $XDG_CONFIG_DIRS/i3/config */
+    if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
+        xdg_config_dirs = "/etc/xdg";
+
+    char *buf = sstrdup(xdg_config_dirs);
+    char *tok = strtok(buf, ":");
+    while (tok != NULL) {
+        tok = resolve_tilde(tok);
+        sasprintf(&config_path, "%s/i3/config", tok);
+        free(tok);
+        if (path_exists(config_path)) {
+            free(buf);
+            return config_path;
+        }
+        free(config_path);
+        tok = strtok(NULL, ":");
+    }
+    free(buf);
+
+    return NULL;
+}
index 28cb8359207e128b648a664824b6dcc59950e07e..80709ed3b255c638933e0644841accecc7eb4318 100644 (file)
@@ -32,33 +32,11 @@ int ipc_send_message(int sockfd, const uint32_t message_size,
         .size = message_size,
         .type = message_type};
 
-    size_t sent_bytes = 0;
-    int n = 0;
+    if (writeall(sockfd, ((void *)&header), sizeof(i3_ipc_header_t)) == -1)
+        return -1;
 
-    /* This first loop is basically unnecessary. No operating system has
-     * buffers which cannot fit 14 bytes into them, so the write() will only be
-     * called once. */
-    while (sent_bytes < sizeof(i3_ipc_header_t)) {
-        if ((n = write(sockfd, ((void *)&header) + sent_bytes, sizeof(i3_ipc_header_t) - sent_bytes)) == -1) {
-            if (errno == EAGAIN)
-                continue;
-            return -1;
-        }
-
-        sent_bytes += n;
-    }
-
-    sent_bytes = 0;
-
-    while (sent_bytes < message_size) {
-        if ((n = write(sockfd, payload + sent_bytes, message_size - sent_bytes)) == -1) {
-            if (errno == EAGAIN)
-                continue;
-            return -1;
-        }
-
-        sent_bytes += n;
-    }
+    if (writeall(sockfd, payload, message_size) == -1)
+        return -1;
 
     return 0;
 }
diff --git a/libi3/resolve_tilde.c b/libi3/resolve_tilde.c
new file mode 100644 (file)
index 0000000..a4e8287
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3 - an improved dynamic tiling window manager
+ * © 2009-2015 Michael Stapelberg and contributors (see also: LICENSE)
+ *
+ */
+
+#include "libi3.h"
+#include <err.h>
+#include <glob.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This function resolves ~ in pathnames.
+ * It may resolve wildcards in the first part of the path, but if no match
+ * or multiple matches are found, it just returns a copy of path as given.
+ *
+ */
+char *resolve_tilde(const char *path) {
+    static glob_t globbuf;
+    char *head, *tail, *result;
+
+    tail = strchr(path, '/');
+    head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
+
+    int res = glob(head, GLOB_TILDE, NULL, &globbuf);
+    free(head);
+    /* no match, or many wildcard matches are bad */
+    if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
+        result = sstrdup(path);
+    else if (res != 0) {
+        err(EXIT_FAILURE, "glob() failed");
+    } else {
+        head = globbuf.gl_pathv[0];
+        result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
+        strncpy(result, head, strlen(head));
+        if (tail)
+            strncat(result, tail, strlen(tail));
+    }
+    globfree(&globbuf);
+
+    return result;
+}
index cf634ad43b8d0f9248f60f351f506908b3507d59..db9b6b4a42efbf287e06466295ad0e2d2e30e2e5 100644 (file)
@@ -8,8 +8,10 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <err.h>
+#include <errno.h>
 
 #include "libi3.h"
 
@@ -56,3 +58,30 @@ int sasprintf(char **strp, const char *fmt, ...) {
     va_end(args);
     return result;
 }
+
+ssize_t writeall(int fd, const void *buf, size_t count) {
+    size_t written = 0;
+    ssize_t n = 0;
+
+    while (written < count) {
+        n = write(fd, buf + written, count - written);
+        if (n == -1) {
+            if (errno == EINTR || errno == EAGAIN)
+                continue;
+            return n;
+        }
+        written += (size_t)n;
+    }
+
+    return written;
+}
+
+ssize_t swrite(int fd, const void *buf, size_t count) {
+    ssize_t n;
+
+    n = writeall(fd, buf, count);
+    if (n == -1)
+        err(EXIT_FAILURE, "Failed to write %d", fd);
+    else
+        return n;
+}
index d441e78f8449be4a42379bdd713c5609c0a72f2e..9a04b75c92180b07ba3920b54f22ab47b86c0b5b 100644 (file)
@@ -7,7 +7,7 @@ template::[header-declarations]
 <refentrytitle>{mantitle}</refentrytitle>
 <manvolnum>{manvolnum}</manvolnum>
 <refmiscinfo class="source">i3</refmiscinfo>
-<refmiscinfo class="version">4.9.1</refmiscinfo>
+<refmiscinfo class="version">4.10.1</refmiscinfo>
 <refmiscinfo class="manual">i3 Manual</refmiscinfo>
 </refmeta>
 <refnamediv>
index 315a9218dd5930695e540506ce11e0cd30cabbf4..87db6cf082cebfeb04e430cc5a31ba1fe19370e4 100644 (file)
@@ -189,10 +189,12 @@ state FLOATING:
   floating = 'enable', 'disable', 'toggle'
       -> call cmd_floating($floating)
 
-# mark <mark>
+# mark [--toggle] <mark>
 state MARK:
+  toggle = '--toggle'
+      ->
   mark = string
-      -> call cmd_mark($mark)
+      -> call cmd_mark($mark, $toggle)
 
 # unmark [mark]
 state UNMARK:
index db5ca09b77cd3f23d27c159dc0938e87c5b8380c..631ff42561f7b527ee80ec659787263c9669ebc6 100755 (executable)
@@ -1,9 +1,9 @@
 #!/bin/zsh
 # This script is used to prepare a new release of i3.
 
-export RELEASE_VERSION="4.9.1"
-export PREVIOUS_VERSION="4.9"
-export RELEASE_BRANCH="master"
+export RELEASE_VERSION="4.10.1"
+export PREVIOUS_VERSION="4.10"
+export RELEASE_BRANCH="next"
 
 if [ ! -e "../i3.github.io" ]
 then
@@ -82,6 +82,12 @@ else
        git merge --no-ff next -m "Merge branch 'next' into master"
 fi
 
+git remote remove origin
+git remote add origin git@github.com:i3/i3.git
+git config --add remote.origin.push "+refs/tags/*:refs/tags/*"
+git config --add remote.origin.push "+refs/heads/next:refs/heads/next"
+git config --add remote.origin.push "+refs/heads/master:refs/heads/master"
+
 ################################################################################
 # Section 2: Debian packaging
 ################################################################################
@@ -164,8 +170,27 @@ done
 
 git commit -a -m "update docs for ${RELEASE_VERSION}"
 
+git remote remove origin
+git remote add origin git@github.com:i3/i3.github.io.git
+
 ################################################################################
-# Section 4: final push instructions
+# Section 4: prepare release announcement email
+################################################################################
+
+cd ${TMPDIR}
+cat >email.txt <<EOT
+From: Michael Stapelberg <michael@i3wm.org>
+To: i3-announce@i3.zekjur.net
+Subject: i3 v${RELEASE_VERSION} released
+
+Hi,
+
+I just released i3 v${RELEASE_VERSION}. Release notes follow:
+EOT
+cat ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION}.txt >>email.txt
+
+################################################################################
+# Section 5: final push instructions
 ################################################################################
 
 echo "As a final sanity check, install the debian package and see whether i3 works."
@@ -174,18 +199,17 @@ echo "When satisfied, run:"
 echo "  cd ${TMPDIR}/i3"
 echo "  git checkout next"
 echo "  vi debian/changelog"
-# TODO: can we just set up the remote spec properly?
-echo "  git push git@github.com:i3/i3 next"
-echo "  git push git@github.com:i3/i3 master"
-echo "  git push git@github.com:i3/i3 --tags"
+echo "  git push"
 echo ""
 echo "  cd ${TMPDIR}/i3.github.io"
-# TODO: can we just set up the remote spec properly?
-echo "  git push git@github.com:i3/i3.github.io master"
+echo "  git push"
 echo ""
 echo "  cd ${TMPDIR}/debian"
 echo "  dput *.changes"
 echo ""
+echo "  cd ${TMPDIR}"
+echo "  sendmail < email.txt"
+echo ""
 echo "Announce on:"
 echo "  twitter"
 echo "  google+"
index 55e7147c557237c6cef5d7a1ff10978c86bc154b..10abc0570c3140201a1d46cae53421f3f243d16d 100644 (file)
@@ -46,6 +46,9 @@ static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press
         case BORDER_BOTTOM:
             search_direction = D_DOWN;
             break;
+        default:
+            assert(false);
+            break;
     }
 
     bool res = resize_find_tiling_participants(&first, &second, search_direction);
index 9b51b3ecc7cba9d7561819d77a42519fd757d142..ea0b90328367c9ec2f935753c96711b0a290c181 100644 (file)
@@ -1037,28 +1037,43 @@ void cmd_workspace_name(I3_CMD, char *name) {
 }
 
 /*
- * Implementation of 'mark <mark>'
+ * Implementation of 'mark [--toggle] <mark>'
  *
  */
-void cmd_mark(I3_CMD, char *mark) {
-    DLOG("Clearing all windows which have that mark first\n");
+void cmd_mark(I3_CMD, char *mark, char *toggle) {
+    HANDLE_EMPTY_MATCH;
 
+    owindow *current;
+    TAILQ_FOREACH(current, &owindows, owindows) {
+        DLOG("matching: %p / %s\n", current->con, current->con->name);
+        if (toggle != NULL && current->con->mark && strcmp(current->con->mark, mark) == 0) {
+            DLOG("removing window mark %s\n", mark);
+            FREE(current->con->mark);
+        } else {
+            DLOG("marking window with str %s\n", mark);
+            FREE(current->con->mark);
+            current->con->mark = sstrdup(mark);
+        }
+    }
+
+    DLOG("Clearing all non-matched windows with this mark\n");
     Con *con;
     TAILQ_FOREACH(con, &all_cons, all_cons) {
+        /* Skip matched windows, we took care of them already. */
+        bool matched = false;
+        TAILQ_FOREACH(current, &owindows, owindows) {
+            if (current->con == con) {
+                matched = true;
+                break;
+            }
+        }
+        if (matched)
+            continue;
+
         if (con->mark && strcmp(con->mark, mark) == 0)
             FREE(con->mark);
     }
 
-    DLOG("marking window with str %s\n", mark);
-    owindow *current;
-
-    HANDLE_EMPTY_MATCH;
-
-    TAILQ_FOREACH(current, &owindows, owindows) {
-        DLOG("matching: %p / %s\n", current->con, current->con->name);
-        current->con->mark = sstrdup(mark);
-    }
-
     cmd_output->needs_tree_render = true;
     // XXX: default reply for now, make this a better reply
     ysuccess(true);
index b610b0c60c1c9cfb792d107a7ff6d05acdc27487..41dd0196ba8931e9793a7ba7c103e99a2ec0cbf8 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -736,6 +736,9 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
         }
     }
 
+    /* Save the urgency state so that we can restore it. */
+    bool urgent = con->urgent;
+
     /* Save the current workspace. So we can call workspace_show() by the end
      * of this function. */
     Con *current_ws = con_get_workspace(focused);
@@ -843,7 +846,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
     if (source_ws == current_ws)
         con_focus(con_descend_focused(focus_next));
 
-    /* If anything within the container is associated with a startup sequence,
+    /* 9. If anything within the container is associated with a startup sequence,
      * delete it so child windows won't be created on the old workspace. */
     struct Startup_Sequence *sequence;
     xcb_get_property_cookie_t cookie;
@@ -877,6 +880,12 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
 
     CALL(parent, on_remove_child);
 
+    /* 10. If the container was marked urgent, move the urgency hint. */
+    if (urgent) {
+        workspace_update_urgent_flag(source_ws);
+        con_set_urgency(con, true);
+    }
+
     ipc_send_window_event("move", con);
 }
 
index 6f906b8ce02e7218828ae2f449bf3223a82dd205..36b7a16331c234171c543e76c39e44d85e264e83 100644 (file)
@@ -39,73 +39,6 @@ void update_barconfig() {
     }
 }
 
-/*
- * Get the path of the first configuration file found. If override_configpath
- * is specified, that path is returned and saved for further calls. Otherwise,
- * checks the home directory first, then the system directory first, always
- * taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
- * $XDG_CONFIG_DIRS)
- *
- */
-static char *get_config_path(const char *override_configpath) {
-    char *xdg_config_home, *xdg_config_dirs, *config_path;
-
-    static const char *saved_configpath = NULL;
-
-    if (override_configpath != NULL) {
-        saved_configpath = override_configpath;
-        return sstrdup(saved_configpath);
-    }
-
-    if (saved_configpath != NULL)
-        return sstrdup(saved_configpath);
-
-    /* 1: check the traditional path under the home directory */
-    config_path = resolve_tilde("~/.i3/config");
-    if (path_exists(config_path))
-        return config_path;
-    free(config_path);
-
-    /* 2: check for $XDG_CONFIG_HOME/i3/config */
-    if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
-        xdg_config_home = "~/.config";
-
-    xdg_config_home = resolve_tilde(xdg_config_home);
-    sasprintf(&config_path, "%s/i3/config", xdg_config_home);
-    free(xdg_config_home);
-
-    if (path_exists(config_path))
-        return config_path;
-    free(config_path);
-
-    /* 3: check the traditional path under /etc */
-    config_path = SYSCONFDIR "/i3/config";
-    if (path_exists(config_path))
-        return sstrdup(config_path);
-
-    /* 4: check for $XDG_CONFIG_DIRS/i3/config */
-    if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
-        xdg_config_dirs = "/etc/xdg";
-
-    char *buf = sstrdup(xdg_config_dirs);
-    char *tok = strtok(buf, ":");
-    while (tok != NULL) {
-        tok = resolve_tilde(tok);
-        sasprintf(&config_path, "%s/i3/config", tok);
-        free(tok);
-        if (path_exists(config_path)) {
-            free(buf);
-            return config_path;
-        }
-        free(config_path);
-        tok = strtok(NULL, ":");
-    }
-    free(buf);
-
-    die("Unable to find the configuration file (looked at "
-        "~/.i3/config, $XDG_CONFIG_HOME/i3/config, " SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)");
-}
-
 /*
  * Finds the configuration file to use (either the one specified by
  * override_configpath), the user’s one or the system default) and calls
@@ -113,7 +46,12 @@ static char *get_config_path(const char *override_configpath) {
  *
  */
 bool parse_configuration(const char *override_configpath, bool use_nagbar) {
-    char *path = get_config_path(override_configpath);
+    char *path = get_config_path(override_configpath, true);
+    if (path == NULL) {
+        die("Unable to find the configuration file (looked at "
+            "~/.i3/config, $XDG_CONFIG_HOME/i3/config, " SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)");
+    }
+
     LOG("Parsing configfile %s\n", path);
     FREE(current_configpath);
     current_configpath = path;
index b229b445ba24ae71358cfcc891e4fafa06d40490..eef03cae238e0cf7455fd64ca1b18658e47d977f 100644 (file)
@@ -778,14 +778,9 @@ static char *migrate_config(char *input, off_t size) {
 
     /* write the whole config file to the pipe, the script will read everything
      * immediately */
-    int written = 0;
-    int ret;
-    while (written < size) {
-        if ((ret = write(writepipe[1], input + written, size - written)) < 0) {
-            warn("Could not write to pipe");
-            return NULL;
-        }
-        written += ret;
+    if (writeall(writepipe[1], input, size) == -1) {
+        warn("Could not write to pipe");
+        return NULL;
     }
     close(writepipe[1]);
 
@@ -795,7 +790,7 @@ static char *migrate_config(char *input, off_t size) {
     /* read the script’s output */
     int conv_size = 65535;
     char *converted = malloc(conv_size);
-    int read_bytes = 0;
+    int read_bytes = 0, ret;
     do {
         if (read_bytes == conv_size) {
             conv_size += 65535;
index 4b5c87d4fd0651db363b8bea27e1c9507cd1fb0c..041f7e366f76a96da1620c1ab950ffacc084edc5 100644 (file)
@@ -874,12 +874,16 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             .root_y = y_root,
             .event_x = x_root - (con->rect.x),
             .event_y = y_root - (con->rect.y)};
-        if (direction == _NET_WM_MOVERESIZE_MOVE) {
-            floating_drag_window(con->parent, &fake);
-        } else if (direction >= _NET_WM_MOVERESIZE_SIZE_TOPLEFT && direction <= _NET_WM_MOVERESIZE_SIZE_LEFT) {
-            floating_resize_window(con->parent, FALSE, &fake);
-        } else {
-            DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction);
+        switch (direction) {
+            case _NET_WM_MOVERESIZE_MOVE:
+                floating_drag_window(con->parent, &fake);
+                break;
+            case _NET_WM_MOVERESIZE_SIZE_TOPLEFT... _NET_WM_MOVERESIZE_SIZE_LEFT:
+                floating_resize_window(con->parent, FALSE, &fake);
+                break;
+            default:
+                DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction);
+                break;
         }
     } else {
         DLOG("unhandled clientmessage\n");
@@ -1214,7 +1218,7 @@ static bool handle_strut_partial_change(void *data, xcb_connection_t *conn, uint
         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)) {
+        if (con->geometry.y < (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;
index ccd71c3736db139623305628fdc40694847ba4b1..c4d39fcee57fa569be1ac07fced152b57b56b55f 100644 (file)
@@ -105,7 +105,7 @@ static int json_end_map(void *ctx) {
             int cnt = 1;
             while (workspace != NULL) {
                 FREE(json_node->name);
-                asprintf(&(json_node->name), "%s_%d", base, cnt++);
+                sasprintf(&(json_node->name), "%s_%d", base, cnt++);
                 workspace = NULL;
                 TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
                 GREP_FIRST(workspace, output_get_content(output), !strcasecmp(child->name, json_node->name));
index 546b73d91104d2e19941b0f1f370ecc616dd8054..e971f6bdd18c8f8f3b2e38b0aeb165d50a6bb574 100644 (file)
@@ -70,8 +70,14 @@ static int backtrace(void) {
         int stdin_pipe[2],
             stdout_pipe[2];
 
-        pipe(stdin_pipe);
-        pipe(stdout_pipe);
+        if (pipe(stdin_pipe) == -1) {
+            ELOG("Failed to init stdin_pipe\n");
+            return -1;
+        }
+        if (pipe(stdout_pipe) == -1) {
+            ELOG("Failed to init stdout_pipe\n");
+            return -1;
+        }
 
         /* close standard streams in case i3 is started from a terminal; gdb
          * needs to run without controlling terminal for it to work properly in
index c5c22ba8c8c1f68351350d39db1a543cab6cd3f9..c891a6bc5c9678c998c4cf2a7cca348d40b56cfa 100644 (file)
@@ -159,38 +159,6 @@ void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_mes
     }
 }
 
-/*
- * This function resolves ~ in pathnames.
- * It may resolve wildcards in the first part of the path, but if no match
- * or multiple matches are found, it just returns a copy of path as given.
- *
- */
-char *resolve_tilde(const char *path) {
-    static glob_t globbuf;
-    char *head, *tail, *result;
-
-    tail = strchr(path, '/');
-    head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
-
-    int res = glob(head, GLOB_TILDE, NULL, &globbuf);
-    free(head);
-    /* no match, or many wildcard matches are bad */
-    if (res == GLOB_NOMATCH || globbuf.gl_pathc != 1)
-        result = sstrdup(path);
-    else if (res != 0) {
-        die("glob() failed");
-    } else {
-        head = globbuf.gl_pathv[0];
-        result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1);
-        strncpy(result, head, strlen(head));
-        if (tail)
-            strncat(result, tail, strlen(tail));
-    }
-    globfree(&globbuf);
-
-    return result;
-}
-
 /*
  * Checks if the given path exists by calling stat().
  *
@@ -265,25 +233,13 @@ char *store_restart_layout(void) {
         return NULL;
     }
 
-    size_t written = 0;
-    while (written < length) {
-        int n = write(fd, payload + written, length - written);
-        /* TODO: correct error-handling */
-        if (n == -1) {
-            perror("write()");
-            free(filename);
-            close(fd);
-            return NULL;
-        }
-        if (n == 0) {
-            DLOG("write == 0?\n");
-            free(filename);
-            close(fd);
-            return NULL;
-        }
-        written += n;
-        DLOG("written: %zd of %zd\n", written, length);
+    if (writeall(fd, payload, length) == -1) {
+        ELOG("Could not write restart layout to \"%s\", layout will be lost: %s\n", filename, strerror(errno));
+        free(filename);
+        close(fd);
+        return NULL;
     }
+
     close(fd);
 
     if (length > 0) {
index bb913819b108526371dbc1430813197e8d7dd80a..3b82fe222cf1944811ea87536265d3b91b0cefb2 100644 (file)
@@ -307,6 +307,33 @@ for ($type = 1; $type <= 2; $type++) {
     my $ws = get_ws($tmp);
     ok(!$ws->{urgent}, 'urgent flag not set on workspace');
 
+##############################################################################
+# Regression test for #1187: Urgency hint moves to new workspace when moving
+# a container to another workspace.
+##############################################################################
+
+    my $tmp_source = fresh_workspace;
+    my $tmp_target = fresh_workspace;
+    cmd 'workspace ' . $tmp_source;
+    sync_with_i3;
+    my $w1 = open_window;
+    my $w2 = open_window;
+    sync_with_i3;
+    cmd '[id="' . $w1->id . '"] focus';
+    sync_with_i3;
+    cmd 'mark urgent_con';
+    cmd '[id="' . $w2->id . '"] focus';
+    set_urgency($w1, 1, $type);
+    sync_with_i3;
+    cmd '[con_mark="urgent_con"] move container to workspace ' . $tmp_target;
+    sync_with_i3;
+    my $source_ws = get_ws($tmp_source);
+    my $target_ws = get_ws($tmp_target);
+    ok(!$source_ws->{urgent}, 'Source workspace is no longer marked urgent');
+    is($target_ws->{urgent}, 1, 'Target workspace is now marked urgent');
+
+##############################################################################
+
     exit_gracefully($pid);
 }
 
index f285338b8208efc2b1e1985d86069405bd0e1b3f..0083547fa2fde727e09a5285bcafa705fa9d5fd5 100644 (file)
 #
 # checks if mark and unmark work correctly
 use i3test;
+use List::Util qw(first);
 
 sub get_marks {
     return i3(get_socket_path())->get_marks->recv;
 }
 
+sub get_mark_for_window_on_workspace {
+    my ($ws, $con) = @_;
+
+    my $current = first { $_->{window} == $con->{id} } @{get_ws_content($ws)};
+    return $current->{mark};
+}
+
 ##############################################################
 # 1: check that there are no marks set yet
 ##############################################################
@@ -76,4 +84,61 @@ cmd 'unmark';
 
 is_deeply(get_marks(), [], 'all marks removed');
 
+##############################################################
+# 4: mark a con, use same mark to mark another con,
+#    check that only the latter is marked
+##############################################################
+
+my $first = open_window;
+my $second = open_window;
+
+cmd 'mark important';
+cmd 'focus left';
+cmd 'mark important';
+
+is(get_mark_for_window_on_workspace($tmp, $first), 'important', 'first container now has the mark');
+ok(!get_mark_for_window_on_workspace($tmp, $second), 'second container lost the mark');
+
+##############################################################
+# 5: mark a con, toggle the mark, check that the mark is gone
+##############################################################
+
+my $con = open_window;
+cmd 'mark important';
+cmd 'mark --toggle important';
+ok(!get_mark_for_window_on_workspace($tmp, $con), 'container no longer has the mark');
+
+##############################################################
+# 6: toggle a mark on an unmarked con, check it is marked
+##############################################################
+
+my $con = open_window;
+cmd 'mark --toggle important';
+is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container now has the mark');
+
+##############################################################
+# 7: mark a con, toggle a different mark, check it is marked
+#    with the new mark
+##############################################################
+
+my $con = open_window;
+cmd 'mark boring';
+cmd 'mark --toggle important';
+is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container has the most recent mark');
+
+##############################################################
+# 8: mark a con, toggle the mark on another con,
+#    check only the latter has the mark
+##############################################################
+
+my $first = open_window;
+my $second = open_window;
+
+cmd 'mark important';
+cmd 'focus left';
+cmd 'mark --toggle important';
+
+is(get_mark_for_window_on_workspace($tmp, $first), 'important', 'left container has the mark now');
+ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer has the mark');
+
 done_testing;