]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1712 from Airblader/feature-next-wm-size-hints-adopted
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 3 Aug 2015 06:52:10 +0000 (23:52 -0700)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 3 Aug 2015 06:52:10 +0000 (23:52 -0700)
[Adopted] Use WM_SIZE_HINTS when available to set the geometry of floating windows

72 files changed:
.travis.yml
CONTRIBUTING.md
DEPENDS
RELEASE-NOTES-4.10.2 [deleted file]
RELEASE-NOTES-4.10.3 [new file with mode: 0644]
debian/changelog
debian/i3-wm.docs
docs/ipc
docs/stacklimit.png [deleted file]
docs/userguide
i3-input/main.c
i3-migrate-config-to-v4
i3-nagbar/main.c
i3-sensible-pager
i3-sensible-terminal
i3bar/include/config.h
i3bar/include/xcb.h
i3bar/src/child.c
i3bar/src/config.c
i3bar/src/mode.c
i3bar/src/xcb.c
include/commands.h
include/config.h
include/config_directives.h
include/data.h
include/libi3.h
libi3/font.c
libi3/mkdirp.c
libi3/string.c
man/asciidoc.conf
parser-specs/commands.spec
parser-specs/config.spec
release.sh
src/bindings.c
src/click.c
src/commands.c
src/con.c
src/config.c
src/config_directives.c
src/config_parser.c
src/display_version.c
src/floating.c
src/handlers.c
src/ipc.c
src/main.c
src/manage.c
src/match.c
src/resize.c
src/sighandler.c
src/startup.c
src/tree.c
src/window.c
src/workspace.c
src/x.c
testcases/t/113-urgent.t
testcases/t/141-resize.t
testcases/t/165-for_window.t
testcases/t/171-config-migrate.t
testcases/t/177-bar-config.t
testcases/t/185-scratchpad.t
testcases/t/187-commands-parser.t
testcases/t/201-config-parser.t
testcases/t/210-mark-unmark.t
testcases/t/231-ipc-floating-event.t
testcases/t/232-ipc-window-urgent.t
testcases/t/235-check-config-no-x.t
testcases/t/240-focus-on-window-activation.t
testcases/t/242-no-focus.t
testcases/t/246-window-decoration-focus.t [new file with mode: 0644]
testcases/t/247-config-line-continuation.t [new file with mode: 0644]
testcases/t/248-regress-urgency-clear.t [new file with mode: 0644]
testcases/t/525-i3bar-mouse-bindings.t [new file with mode: 0644]

index 733daeac39117ae0f04587d31ddf8f4e3522588b..e3e45656b0509d618bad2228209ff8923745a76d 100644 (file)
@@ -32,7 +32,7 @@ before_install:
   - sudo cp /tmp/pin /etc/apt/preferences.d/trustypin
   - sudo apt-get update
   - sudo apt-get install -t trusty libc6 libc6-dev
-  - sudo apt-get install --no-install-recommends devscripts equivs
+  - sudo apt-get install --no-install-recommends devscripts equivs xdotool
   - sudo apt-get install -t utopic clang-format-3.5
   - clang-format-3.5 --version
 install:
index 1e1307614cc10e8f7ff14794ae6f44e9e4f9c3a2..474355ad90f7a98c5325ce584f0ce871bf4c719b 100644 (file)
@@ -1,12 +1,12 @@
-# i3status/i3lock bugreports/feature requests
+# Contributing
 
-Note that i3status and i3lock related bugreports and feature requests should be
-filed in the corresponding repositories, i.e. https://github.com/i3/i3status
-and https://github.com/i3/i3lock
+## i3status/i3lock bug reports and feature requests
 
-# i3 bugreports/feature requests
+Note that bug reports and feature requests for related projects should be filed in the corresponding repositories for [i3status](https://github.com/i3/i3status) and [i3lock](https://github.com/i3/i3lock).
 
-1. Read http://i3wm.org/docs/debugging.html
+## i3 bug reports and feature requests
+
+1. Read the [debugging instructions](http://i3wm.org/docs/debugging.html).
 2. Make sure you include a link to your logfile in your report (section 3).
 3. Make sure you include the i3 version number in your report (section 1).
 4. Please be aware that we cannot support compatibility issues with
@@ -15,11 +15,18 @@ and https://github.com/i3/i3lock
    experience has shown that often, the software in question is responsible for
    the issue. Please raise an issue with the software in question, not i3.
 
-# Pull requests
+## Pull requests
 
 * Before sending a pull request for new features, please check with us that the
   feature is something we want to see in i3 by opening an issue which has
-  â\80\9cfeature requestâ\80\9d or â\80\9cenhancement” in its title.
+  â\80\9dfeature requestâ\80\9d or â\80\9denhancement” in its title.
 * Use the `next` branch for developing and sending your pull request.
 * Use `clang-format` to format your code.
-* Run the testsuite, see http://i3wm.org/docs/testsuite.html
+* Run the [testsuite](http://i3wm.org/docs/testsuite.html)
+
+## Finding something to do
+
+* Find a [reproducible bug](https://github.com/i3/i3/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Areproducible+label%3Abug+) from the issue tracker. These issues have been reviewed and confirmed by a project contributor.
+* Find an [accepted enhancement](https://github.com/i3/i3/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Aaccepted+label%3Aenhancement) from the issue tracker. These have been approved and are ok to start working on.
+
+There's a very good [overview of the codebase](http://i3wm.org/docs/hacking-howto.html) available to get you started.
diff --git a/DEPENDS b/DEPENDS
index d5dae1429d05192a5d0bb56671354d34933b3cb4..0882f1475be4ac96afaefb1611f7b94b42086ddf 100644 (file)
--- a/DEPENDS
+++ b/DEPENDS
@@ -7,29 +7,30 @@
 ┌──────────────┬────────┬────────┬────────────────────────────────────────┐
 │ dependency   │ min.   │ lkgv   │ URL                                    │
 ├──────────────┼────────┼────────┼────────────────────────────────────────┤
-│ pkg-config   │ 0.25   │ 0.26   │ http://pkgconfig.freedesktop.org/      │
-│ libxcb       │ 1.1.93 │ 1.10   │ http://xcb.freedesktop.org/dist/       │
+│ pkg-config   │ 0.25   │ 0.28   │ http://pkgconfig.freedesktop.org/      │
+│ libxcb       │ 1.1.93 │ 1.11   │ http://xcb.freedesktop.org/dist/       │
 │ xcb-util     │ 0.3.3  │ 0.4.1  │ http://xcb.freedesktop.org/dist/       │
-│ xkbcommon    │ 0.4.0  │ 0.4.0  │ http://xkbcommon.org/                  │
-│ xkbcommon-x11│ 0.4.0  │ 0.4.0  │ http://xkbcommon.org/                  │
-│ util-cursor³ │ 0.0.99 │ 0.0.99 │ http://xcb.freedesktop.org/dist/       │
-│ libev        │ 4.0    │ 4.11   │ http://libev.schmorp.de/               │
-│ yajl         │ 2.0.1  │ 2.0.4  │ http://lloyd.github.com/yajl/          │
-│ asciidoc     │ 8.3.0  │ 8.6.4  │ http://www.methods.co.nz/asciidoc/     │
+│ xkbcommon    │ 0.4.0  │ 0.5.0  │ http://xkbcommon.org/                  │
+│ xkbcommon-x11│ 0.4.0  │ 0.5.0  │ http://xkbcommon.org/                  │
+│ util-cursor³⁴│ 0.0.99 │ 0.1.2  │ http://xcb.freedesktop.org/dist/       │
+│ util-wm⁴     │ 0.3.8  │ 0.3.8  │ http://xcb.freedesktop.org/dist/       │
+│ util-keysyms⁴│ 0.3.8  │ 0.4.0  │ http://xcb.freedesktop.org/dist/       │
+│ libev        │ 4.0    │ 4.19   │ http://libev.schmorp.de/               │
+│ yajl         │ 2.0.1  │ 2.1.0  │ http://lloyd.github.com/yajl/          │
+│ asciidoc     │ 8.3.0  │ 8.6.8  │ http://www.methods.co.nz/asciidoc/     │
 │ xmlto        │ 0.0.23 │ 0.0.23 │ http://www.methods.co.nz/asciidoc/     │
 │ Pod::Simple² │ 3.22   │ 3.22   │ http://search.cpan.org/~dwheeler/Pod-Simple-3.23/
 │ docbook-xml  │ 4.5    │ 4.5    │ http://www.methods.co.nz/asciidoc/     │
-│ Xlib         │ 1.3.3  │ 1.4.3  │ http://ftp.x.org/pub/current/src/lib/  │
-│ PCRE         │ 8.12   │ 8.12   │ http://www.pcre.org/                   │
+│ PCRE         │ 8.12   │ 8.35   │ http://www.pcre.org/                   │
 │ libsn¹       │ 0.10   │ 0.12   │ http://freedesktop.org/wiki/Software/startup-notification
-│ pango        │ 1.30.0 | 1.30.0 │ http://www.pango.org/                  │
-│ cairo        │ 1.12.2 │ 1.12.2 │ http://cairographics.org/              │
+│ pango        │ 1.30.0 | 1.36.8 │ http://www.pango.org/                  │
+│ cairo        │ 1.12.2 │ 1.14.0 │ http://cairographics.org/              │
 └──────────────┴────────┴────────┴────────────────────────────────────────┘
  ¹ libsn = libstartup-notification
  ² Pod::Simple is a Perl module required for converting the testsuite
    documentation to HTML. See http://michael.stapelberg.de/cpan/#Pod::Simple
- ³ xcb-util-cursor, to be precise. Might be considered part of xcb-util, or not
  :-).
+ ³ xcb-util-cursor, to be precise.
⁴ Depending on your distribution, this might be considered part of xcb-util.
 
  i3bar, i3-msg, i3-input, i3-nagbar and i3-config-wizard do not introduce any
  new dependencies.
diff --git a/RELEASE-NOTES-4.10.2 b/RELEASE-NOTES-4.10.2
deleted file mode 100644 (file)
index 49c06e5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
- ┌──────────────────────────────┐
- │ Release notes for i3 v4.10.2 │
- └──────────────────────────────┘
-
-This is i3 v4.10.2. This version is considered stable. All users of i3 are
-strongly encouraged to upgrade.
-
- ┌────────────────────────────┐
- │ Bugfixes                   │
- └────────────────────────────┘
-
-  • Cope with non-null-terminated x class properties.
-  • Get workspace name when renaming current workspace (fixes crash).
-  • Use a reasonable default sep_block_width if a separator_symbol is given.
-  • Remove windows from the save set when unmapping.
-
- ┌────────────────────────────┐
- │ Thanks!                    │
- └────────────────────────────┘
-
-Thanks for testing, bugfixes, discussions and everything I forgot go out to:
-
-  Ingo Bürk, Michael Hofmann,
-
--- Michael Stapelberg, 2015-04-16
diff --git a/RELEASE-NOTES-4.10.3 b/RELEASE-NOTES-4.10.3
new file mode 100644 (file)
index 0000000..524f552
--- /dev/null
@@ -0,0 +1,30 @@
+
+ ┌──────────────────────────────┐
+ │ Release notes for i3 v4.10.3 │
+ └──────────────────────────────┘
+
+This is i3 v4.10.3. This version is considered stable. All users of i3 are
+strongly encouraged to upgrade.
+
+ ┌────────────────────────────┐
+ │ Bugfixes                   │
+ └────────────────────────────┘
+
+  • serialize con_id with %p in run_binding() (For FreeBSD)
+  • ignore InputHint when not in WM_HINTS (fixes e.g. mupdf focus)
+  • disable physically disconnect RandR outputs
+  • initialize workspace rect to the output's upon creation
+  • userguide: quoted strings need to be used, escaping isn’t possible
+  • mkdirp: do not throw an error if directory exists (fixes layout loss for
+    in-place restarts)
+  • i3bar: fix freeing static strings
+
+ ┌────────────────────────────┐
+ │ Thanks!                    │
+ └────────────────────────────┘
+
+Thanks for testing, bugfixes, discussions and everything I forgot go out to:
+
+  Tony Crisci, Deiz, Theo Buehler, shdown
+
+-- Michael Stapelberg, 2015-07-30
index 023eeac10b6e000570cfc0c624f2ca04c1248cd9..96b7fd2379595a99934fb5210e934f59cb745a28 100644 (file)
@@ -1,8 +1,22 @@
-i3-wm (4.10.3-1) experimental; urgency=medium
+i3-wm (4.10.4-1) unstable; urgency=medium
 
   * NOT YET RELEASED.
 
- -- Michael Stapelberg <stapelberg@debian.org>  Thu, 16 Apr 2015 09:08:30 +0200
+ -- Michael Stapelberg <stapelberg@debian.org>  Thu, 30 Jul 2015 22:30:45 +0200
+
+i3-wm (4.10.3-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Michael Stapelberg <stapelberg@debian.org>  Thu, 30 Jul 2015 21:51:27 +0200
+
+i3-wm (4.10.2-2) unstable; urgency=medium
+
+  * New upstream release.
+  * experimental to unstable because i3-wm 4.10.2-1 was only in experimental
+    due to the freeze.
+
+ -- Michael Stapelberg <stapelberg@debian.org>  Fri, 01 May 2015 20:21:18 +0200
 
 i3-wm (4.10.2-1) experimental; urgency=medium
 
index 11a695ba7ea5093f58a54c3d87da812b326cd142..437175b310fef4fe748500dad6d538f367be92d2 100644 (file)
@@ -8,7 +8,6 @@ docs/snapping.png
 docs/two_columns.png
 docs/two_terminals.png
 docs/modes.png
-docs/stacklimit.png
 docs/ipc.html
 docs/multi-monitor.html
 docs/wsbar.html
index ff7c8aaeb0f185299520dc5f271460060a8d13be..4462e772ba405cfc5332bea42eed400922085076 100644 (file)
--- a/docs/ipc
+++ b/docs/ipc
@@ -520,21 +520,23 @@ statusline::
        Text color to be used for the statusline.
 separator::
        Text color to be used for the separator.
-focused_workspace_text/focused_workspace_bg::
-       Text color/background color for a workspace button when the workspace
+focused_workspace_text/focused_workspace_bg/focused_workspace_border::
+       Text/background/border color for a workspace button when the workspace
        has focus.
-active_workspace_text/active_workspace_bg::
-       Text color/background color for a workspace button when the workspace
+active_workspace_text/active_workspace_bg/active_workspace_border::
+       Text/background/border color for a workspace button when the workspace
        is active (visible) on some output, but the focus is on another one.
        You can only tell this apart from the focused workspace when you are
        using multiple monitors.
-inactive_workspace_text/inactive_workspace_bg::
-       Text color/background color for a workspace button when the workspace
+inactive_workspace_text/inactive_workspace_bg/inactive_workspace_border::
+       Text/background/border color for a workspace button when the workspace
        does not have focus and is not active (visible) on any output. This
        will be the case for most workspaces.
-urgent_workspace_text/urgent_workspace_bar::
-       Text color/background color for workspaces which contain at least one
+urgent_workspace_text/urgent_workspace_bg/urgent_workspace_border::
+       Text/background/border color for workspaces which contain at least one
        window with the urgency hint set.
+binding_mode_text/binding_mode_bg/binding_mode_border::
+        Text/background/border color for the binding mode indicator.
 
 
 *Example of configured bars:*
@@ -580,11 +582,14 @@ human_readable (string)::
        build date and branch name. When you need to display the i3 version to
        your users, use the human-readable version whenever possible (since
        this is what +i3 --version+ displays, too).
+loaded_config_file_name (string)::
+       The current config path.
 
 *Example:*
 -------------------
 {
    "human_readable" : "4.2-169-gf80b877 (2012-08-05, branch \"next\")",
+   "loaded_config_file_name" : "/home/hwangcc23/.i3/config",
    "minor" : 2,
    "patch" : 0,
    "major" : 4
@@ -822,4 +827,7 @@ Python::
        * https://github.com/whitelynx/i3ipc (not maintained)
        * https://github.com/ziberna/i3-py (not maintained)
 Ruby::
-       * http://github.com/badboy/i3-ipc
+       * https://github.com/veelenga/i3ipc-ruby
+       * https://github.com/badboy/i3-ipc (not maintained)
+Rust::
+       * https://github.com/tmerr/i3ipc-rs
diff --git a/docs/stacklimit.png b/docs/stacklimit.png
deleted file mode 100644 (file)
index ab5bed7..0000000
Binary files a/docs/stacklimit.png and /dev/null differ
index 977e1358c3632460d737ff36176bf04ab093a04b..e21553815601c5bebd60c5793c22595afd6863f5 100644 (file)
@@ -503,17 +503,11 @@ default_orientation vertical
 
 This option determines in which mode new containers on workspace level will
 start.
-///////////////////////////////
-See also <<stack-limit>>.
-//////////////////////////////
 
 *Syntax*:
 ---------------------------------------------
 workspace_layout default|stacking|tabbed
 ---------------------------------------------
-/////////////////////////////////////////////
-new_container stack-limit <cols|rows> <value>
-/////////////////////////////////////////////
 
 *Example*:
 ---------------------
@@ -523,20 +517,20 @@ workspace_layout tabbed
 === Border style for new windows
 
 This option determines which border style new windows will have. The default is
-"normal". Note that new_float applies only to windows which are starting out as
-floating windows, e.g. dialog windows.
++normal+. Note that new_float applies only to windows which are starting out as
+floating windows, e.g., dialog windows, but not windows that are floated later on.
 
 *Syntax*:
 ---------------------------------------------
-new_window normal|1pixel|none|pixel
+new_window normal|none|pixel
 new_window normal|pixel <px>
-new_float normal|1pixel|none|pixel
+new_float normal|none|pixel
 new_float normal|pixel <px>
 ---------------------------------------------
 
 *Example*:
 ---------------------
-new_window 1pixel
+new_window pixel
 ---------------------
 
 The "normal" and "pixel" border styles support an optional border width in
@@ -570,6 +564,8 @@ hide_edge_borders vertical
 
 === Arbitrary commands for specific windows (for_window)
 
+[[for_window]]
+
 With the +for_window+ command, you can let i3 execute any command when it
 encounters a specific window. This can be used to set windows to floating or to
 change their border style, for example.
@@ -585,7 +581,7 @@ for_window <criteria> <command>
 for_window [class="XTerm"] floating enable
 
 # Make all urxvts use a 1-pixel border:
-for_window [class="urxvt"] border 1pixel
+for_window [class="urxvt"] border pixel 1
 
 # A less useful, but rather funny example:
 # makes the window floating as soon as I change
@@ -1082,6 +1078,20 @@ show_marks yes|no
 show_marks yes
 --------------
 
+[[line_continuation]]
+
+=== Line continuation
+
+Config files support line continuation, meaning when you end a line in a
+backslash character (`\`), the line-break will be ignored by the parser. This
+feature can be used to create more readable configuration files.
+
+*Examples*:
+-------------------
+bindsym Mod1+f \
+fullscreen toggle
+-------------------
+
 == Configuring i3bar
 
 The bar at the bottom of your monitor is drawn by a separate process called
@@ -1143,7 +1153,10 @@ right hand side of the bar. This is useful to display system information like
 your current IP address, battery status or date/time.
 
 The specified command will be passed to +sh -c+, so you can use globbing and
-have to have correct quoting etc.
+have to have correct quoting etc. Note that for signal handling, depending on
+your shell (users of dash(1) are known to be affected), you have to use the
+shell’s exec command so that signals are passed to your program, not to the
+shell.
 
 *Syntax*:
 ------------------------
@@ -1154,6 +1167,9 @@ status_command <command>
 -------------------------------------------------
 bar {
     status_command i3status --config ~/.i3status.conf
+
+    # For dash(1) users who want signal handling to work:
+    status_command exec ~/.bin/my_status_command
 }
 -------------------------------------------------
 
@@ -1209,23 +1225,41 @@ Available modifiers are Mod1-Mod5, Shift, Control (see +xmodmap(1)+).
 === Mouse button commands
 
 Specifies a command to run when a button was pressed on i3bar to override the
-default behavior. Currently only the mouse wheel buttons are supported. This is
-useful for disabling the scroll wheel action or running scripts that implement
-custom behavior for these buttons.
+default behavior. This is useful, e.g., for disabling the scroll wheel action
+or running scripts that implement custom behavior for these buttons.
+
+A button is always named +button<n>+, where 1 to 5 are default buttons as follows and higher
+numbers can be special buttons on devices offering more buttons:
+
+button1::
+    Left mouse button.
+button2::
+    Middle mouse button.
+button3::
+    Right mouse button.
+button4::
+    Scroll wheel up.
+button5::
+    Scroll wheel down.
+
+Please note that the old +wheel_up_cmd+ and +wheel_down_cmd+ commands are deprecated
+and will be removed in a future release. We strongly recommend using the more general
++bindsym+ with +button4+ and +button5+ instead.
 
 *Syntax*:
----------------------
-wheel_up_cmd <command>
-wheel_down_cmd <command>
----------------------
+----------------------------
+bindsym button<n> <command>
+----------------------------
 
 *Example*:
----------------------
+---------------------------------------------------------
 bar {
-    wheel_up_cmd nop
-    wheel_down_cmd exec ~/.i3/scripts/custom_wheel_down
+    # disable clicking on workspace buttons
+    bindsym button1 nop
+    # execute custom script when scrolling downwards
+    bindsym button5 exec ~/.i3/scripts/custom_wheel_down
 }
----------------------
+---------------------------------------------------------
 
 === Bar ID
 
@@ -1308,9 +1342,9 @@ You can configure on which output (monitor) the icons should be displayed or
 you can turn off the functionality entirely.
 
 *Syntax*:
--------------------------------
-tray_output none|primary|output
--------------------------------
+---------------------------------
+tray_output none|primary|<output>
+---------------------------------
 
 *Example*:
 -------------------------
@@ -1320,7 +1354,9 @@ bar {
 }
 
 # show tray icons on the primary monitor
-tray_output primary
+bar {
+    tray_output primary
+}
 
 # show tray icons on the big monitor
 bar {
@@ -1333,6 +1369,23 @@ Note that you might not have a primary output configured yet. To do so, run:
 xrandr --output <output> --primary
 -------------------------
 
+=== Tray padding
+
+The tray is shown on the right-hand side of the bar. By default, a padding of 2
+pixels is used for the upper, lower and right-hand side of the tray area and
+between the individual icons.
+
+*Syntax*:
+-------------------------
+tray_padding <px> [px]
+-------------------------
+
+*Example*:
+-------------------------
+# Obey Fitts's law
+tray_padding 0
+-------------------------
+
 === Font
 
 Specifies the font to be used in the bar. See <<fonts>>.
@@ -1457,7 +1510,10 @@ inactive_workspace::
        will be the case for most workspaces.
 urgent_workspace::
        Border, background and text color for a workspace button when the workspace
-       contains a window with the urgency hint set. Also applies to +mode+ indicators.
+       contains a window with the urgency hint set.
+binding_mode::
+        Border, background and text color for the binding mode indicator. If not used,
+        the colors will be taken from +urgent_workspace+.
 
 *Syntax*:
 ----------------------------------------
@@ -1482,6 +1538,7 @@ bar {
         active_workspace   #333333 #5f676a #ffffff
         inactive_workspace #333333 #222222 #888888
         urgent_workspace   #2f343a #900000 #ffffff
+        binding_mode       #2f343a #900000 #ffffff
     }
 }
 --------------------------------------
@@ -1556,14 +1613,16 @@ urgent::
        Compares the urgent state of the window. Can be "latest" or "oldest".
        Matches the latest or oldest urgent window, respectively.
        (The following aliases are also available: newest, last, recent, first)
+workspace::
+       Compares the workspace name of the workspace the window belongs to.
 con_mark::
        Compares the mark set for this container, see <<vim_like_marks>>.
 con_id::
        Compares the i3-internal container ID, which you can get via the IPC
        interface. Handy for scripting.
 
-The criteria +class+, +instance+, +role+, +title+ and +mark+ are actually
-regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc perlre+ for
+The criteria +class+, +instance+, +role+, +title+, +workspace+ and +mark+ are
+actually regular expressions (PCRE). See +pcresyntax(3)+ or +perldoc perlre+ for
 information on how to use them.
 
 [[exec]]
@@ -2044,52 +2103,63 @@ Alternatively, if you do not want to mess with +i3-input+, you could create
 seperate bindings for a specific set of labels and then only use those labels.
 ///////////////////////////////////////////////////////////////////
 
-=== Changing border style
+=== Window title format
 
-To change the border of the current client, you can use +border normal+ to use the normal
-border (including window title), +border 1pixel+ to use a 1-pixel border (no window title)
-and +border none+ to make the client borderless.
+By default, i3 will simply print the X11 window title. Using +title_format+,
+this can be customized by setting the format to the desired output. This
+directive supports
+https://developer.gnome.org/pango/stable/PangoMarkupFormat.html[Pango markup]
+and the following placeholders which will be replaced:
 
-There is also +border toggle+ which will toggle the different border styles.
++%title+::
+    The X11 window title (_NET_WM_NAME or WM_NAME as fallback).
+
+Using the <<for_window>> directive, you can set the title format for any window
+based on <<command_criteria>>.
+
+*Syntax*:
+---------------------
+title_format <format>
+---------------------
 
 *Examples*:
-----------------------------
-bindsym $mod+t border normal
-bindsym $mod+y border 1pixel
-bindsym $mod+u border none
-----------------------------
+-------------------------------------------------------------------------------------
+# give the focused window a prefix
+bindsym $mod+p title_format "Important | %title"
+
+# print all window titles bold
+for_window [class=".*"] title_format "<b>%title</b>"
 
-[[stack-limit]]
+# print window titles of firefox windows red
+for_window [class="(?i)firefox"] title_format "<span foreground='red'>%title</span>"
+-------------------------------------------------------------------------------------
 
-///////////////////////////////////////////////////////////////////////////////
-TODO: not yet implemented
-=== Changing the stack-limit of a container
+=== Changing border style
 
-If you have a single container with a lot of windows inside it (say, more than
-10), the default layout of a stacking container can get a little unhandy.
-Depending on your screen’s size, you might end up with only half of the title
-lines being actually used, wasting a lot of screen space.
+To change the border of the current client, you can use +border normal+ to use the normal
+border (including window title), +border pixel 1+ to use a 1-pixel border (no window title)
+and +border none+ to make the client borderless.
 
-Using the +stack-limit+ command, you can limit the number of rows or columns
-in a stacking container. i3 will create columns or rows (depending on what
-you limited) automatically as needed.
+There is also +border toggle+ which will toggle the different border styles.
 
 *Syntax*:
------------------------------
-stack-limit cols|rows <value>
------------------------------
-
-*Examples*:
--------------------
-# I always want to have two window titles in one line
-stack-limit cols 2
+-----------------------------------------------
+border normal|pixel [<n>]
+border none|toggle
 
-# Not more than 5 rows in this stacking container
-stack-limit rows 5
--------------------
+# legacy syntax, equivalent to "border pixel 1"
+border 1pixel
+-----------------------------------------------
 
-image:stacklimit.png[Container limited to two columns]
-///////////////////////////////////////////////////////////////////////////////
+*Examples*:
+----------------------------------------------
+# use window title, but no border
+bindsym $mod+t border normal 0
+# use no window title and a thick border
+bindsym $mod+y border pixel 3
+# use neither window title nor border
+bindsym $mod+u border none
+----------------------------------------------
 
 [[shmlog]]
 
index 5a6a740e1e6b789cc22f6c21d3fa89f2be8a27db..6736aad3a97052e3d671029275b9510c28935860 100644 (file)
@@ -344,7 +344,7 @@ static xcb_rectangle_t get_window_position(void) {
         goto free_resources;
     }
 
-    DLOG("Determined coordinates of window with input focus at x = %i / y = %i", coordinates->dst_x, coordinates->dst_y);
+    DLOG("Determined coordinates of window with input focus at x = %i / y = %i.\n", coordinates->dst_x, coordinates->dst_y);
     result.x += coordinates->dst_x;
     result.y += coordinates->dst_y;
 
index b78378be1c65a68225a38d8ebace7b5be0845a3d..5da4e26ed447d7b30316adec7fd81af1bf6b9f22 100755 (executable)
@@ -117,7 +117,6 @@ for my $line (@lines) {
 
     # new_container changed only the statement name to workspace_layout
     if ($statement eq 'new_container') {
-        # TODO: new_container stack-limit
         print "workspace_layout$parameters\n";
         next;
     }
@@ -184,7 +183,6 @@ sub convert_command {
         restart
         reload
         exit
-        stack-limit
     );
 
     my ($statement, $key, $command) = ($line =~ /([a-zA-Z_-]+)\s+([^\s]+)\s+(.*)/);
index d93c6585e831b7a3b1222d0768f8ef4e29315f86..aca70ab115efd4c2021a81b37dff41068f3db26b 100644 (file)
@@ -326,7 +326,7 @@ static xcb_rectangle_t get_window_position(void) {
     if (crtc == NULL)
         goto free_resources;
 
-    DLOG("Found primary output on position x = %i / y = %i / w = %i / h = %i",
+    DLOG("Found primary output on position x = %i / y = %i / w = %i / h = %i.\n",
          crtc->x, crtc->y, crtc->width, crtc->height);
     if (crtc->width == 0 || crtc->height == 0) {
         DLOG("Primary output is not active, ignoring it.\n");
index 5ad786062405a9c4a571ca6a1f54cf60ee366ade..ce71686bd01182ec79651f2d46c078fe7ce36c11 100755 (executable)
@@ -11,7 +11,7 @@
 # Hopefully one of these is installed (no flamewars about preference please!):
 # We don't use 'more' because it will exit if the file is too short.
 # Worst case scenario we'll open the file in your editor.
-for pager in $PAGER less most w3m i3-sensible-editor; do
+for pager in $PAGER less most w3m pg i3-sensible-editor; do
     if command -v $pager > /dev/null 2>&1; then
         exec $pager "$@"
     fi
index dd4b075ac981740144011de201ebcb5acba232c3..c80e5ee211b785e1f4dc59efc4501c73d5b44bcb 100755 (executable)
@@ -8,7 +8,7 @@
 # We welcome patches that add distribution-specific mechanisms to find the
 # preferred terminal emulator. On Debian, there is the x-terminal-emulator
 # symlink for example.
-for terminal in $TERMINAL x-terminal-emulator urxvt rxvt terminator Eterm aterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal; do
+for terminal in $TERMINAL x-terminal-emulator urxvt rxvt terminator Eterm aterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology; do
     if command -v $terminal > /dev/null 2>&1; then
         exec $terminal "$@"
     fi
index aeb9f0fd1b523606b542f8f917198e6547d69c8e..1ce5dfa6e4bebaaf930114d61081498a1f77ce55 100644 (file)
@@ -22,10 +22,16 @@ typedef enum { M_DOCK = 0,
                M_HIDE = 1,
                M_INVISIBLE = 2 } bar_display_mode_t;
 
+typedef struct binding_t {
+    int input_code;
+    char *command;
+
+    TAILQ_ENTRY(binding_t) bindings;
+} binding_t;
+
 typedef struct config_t {
     int modifier;
-    char *wheel_up_cmd;
-    char *wheel_down_cmd;
+    TAILQ_HEAD(bindings_head, binding_t) bindings;
     position_t position;
     int verbose;
     struct xcb_color_strings_t colors;
@@ -37,6 +43,7 @@ typedef struct config_t {
     char *fontname;
     i3String *separator_symbol;
     char *tray_output;
+    int tray_padding;
     int num_outputs;
     char **outputs;
 
index 2e34c7760e299e2f36b74e1919cab6c67c547635..835105e7fe7bde2a7315c9bb659cbce66a854697 100644 (file)
@@ -40,6 +40,9 @@ struct xcb_color_strings_t {
     char *urgent_ws_bg;
     char *urgent_ws_fg;
     char *urgent_ws_border;
+    char *binding_mode_bg;
+    char *binding_mode_fg;
+    char *binding_mode_border;
 };
 
 typedef struct xcb_colors_t xcb_colors_t;
index e5ce209d1562959d47862db37a9d1025822afb96..e369c54deb190a0e3651c34e0fb3cab7e1d5525c 100644 (file)
@@ -107,14 +107,14 @@ __attribute__((format(printf, 1, 2))) static void set_statusline_error(const cha
 
     struct status_block *err_block = scalloc(sizeof(struct status_block));
     err_block->full_text = i3string_from_utf8("Error: ");
-    err_block->name = "error";
-    err_block->color = "red";
+    err_block->name = sstrdup("error");
+    err_block->color = sstrdup("red");
     err_block->no_separator = true;
 
     struct status_block *message_block = scalloc(sizeof(struct status_block));
     message_block->full_text = i3string_from_utf8(message);
-    message_block->name = "error_message";
-    message_block->color = "red";
+    message_block->name = sstrdup("error_message");
+    message_block->color = sstrdup("red");
     message_block->no_separator = true;
 
     TAILQ_INSERT_HEAD(&statusline_head, err_block, blocks);
index 86f66cbb07fd6758235636458ac15a50a70540bb..65447e7ecaa14bf0f11af8d634f262261c29c28f 100644 (file)
@@ -20,6 +20,7 @@
 #include "common.h"
 
 static char *cur_key;
+static bool parsing_bindings;
 
 /*
  * Parse a key.
@@ -34,6 +35,14 @@ static int config_map_key_cb(void *params_, const unsigned char *keyVal, size_t
     strncpy(cur_key, (const char *)keyVal, keyLen);
     cur_key[keyLen] = '\0';
 
+    if (strcmp(cur_key, "bindings") == 0)
+        parsing_bindings = true;
+
+    return 1;
+}
+
+static int config_end_array_cb(void *params_) {
+    parsing_bindings = false;
     return 1;
 }
 
@@ -63,6 +72,27 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
     if (!strcmp(cur_key, "id") || !strcmp(cur_key, "socket_path"))
         return 1;
 
+    if (parsing_bindings) {
+        if (strcmp(cur_key, "command") == 0) {
+            binding_t *binding = TAILQ_LAST(&(config.bindings), bindings_head);
+            if (binding == NULL) {
+                ELOG("There is no binding to put the current command onto. This is a bug in i3.\n");
+                return 0;
+            }
+
+            if (binding->command != NULL) {
+                ELOG("The binding for input_code = %d already has a command. This is a bug in i3.\n", binding->input_code);
+                return 0;
+            }
+
+            sasprintf(&(binding->command), "%.*s", len, val);
+            return 1;
+        }
+
+        ELOG("Unknown key \"%s\" while parsing bar bindings.\n", cur_key);
+        return 0;
+    }
+
     if (!strcmp(cur_key, "mode")) {
         DLOG("mode = %.*s, len = %d\n", len, val, len);
         config.hide_on_modifier = (len == 4 && !strncmp((const char *)val, "dock", strlen("dock")) ? M_DOCK
@@ -112,17 +142,25 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
         return 1;
     }
 
+    /* This key was sent in <= 4.10.2. We keep it around to avoid breakage for
+     * users updating from that version and restarting i3bar before i3. */
     if (!strcmp(cur_key, "wheel_up_cmd")) {
         DLOG("wheel_up_cmd = %.*s\n", len, val);
-        FREE(config.wheel_up_cmd);
-        sasprintf(&config.wheel_up_cmd, "%.*s", len, val);
+        binding_t *binding = scalloc(sizeof(binding_t));
+        binding->input_code = 4;
+        sasprintf(&(binding->command), "%.*s", len, val);
+        TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
         return 1;
     }
 
+    /* This key was sent in <= 4.10.2. We keep it around to avoid breakage for
+     * users updating from that version and restarting i3bar before i3. */
     if (!strcmp(cur_key, "wheel_down_cmd")) {
         DLOG("wheel_down_cmd = %.*s\n", len, val);
-        FREE(config.wheel_down_cmd);
-        sasprintf(&config.wheel_down_cmd, "%.*s", len, val);
+        binding_t *binding = scalloc(sizeof(binding_t));
+        binding->input_code = 5;
+        sasprintf(&(binding->command), "%.*s", len, val);
+        TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
         return 1;
     }
 
@@ -191,6 +229,9 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
     COLOR(urgent_workspace_border, urgent_ws_border);
     COLOR(urgent_workspace_bg, urgent_ws_bg);
     COLOR(urgent_workspace_text, urgent_ws_fg);
+    COLOR(binding_mode_border, binding_mode_border);
+    COLOR(binding_mode_bg, binding_mode_bg);
+    COLOR(binding_mode_text, binding_mode_fg);
 
     printf("got unexpected string %.*s for cur_key = %s\n", len, val, cur_key);
 
@@ -229,11 +270,40 @@ static int config_boolean_cb(void *params_, int val) {
     return 0;
 }
 
+/*
+ * Parse an integer value
+ *
+ */
+static int config_integer_cb(void *params_, long long val) {
+    if (parsing_bindings) {
+        if (strcmp(cur_key, "input_code") == 0) {
+            binding_t *binding = scalloc(sizeof(binding_t));
+            binding->input_code = val;
+            TAILQ_INSERT_TAIL(&(config.bindings), binding, bindings);
+
+            return 1;
+        }
+
+        ELOG("Unknown key \"%s\" while parsing bar bindings.\n", cur_key);
+        return 0;
+    }
+
+    if (!strcmp(cur_key, "tray_padding")) {
+        DLOG("tray_padding = %lld\n", val);
+        config.tray_padding = val;
+        return 1;
+    }
+
+    return 0;
+}
+
 /* A datastructure to pass all these callbacks to yajl */
 static yajl_callbacks outputs_callbacks = {
     .yajl_null = config_null_cb,
     .yajl_boolean = config_boolean_cb,
+    .yajl_integer = config_integer_cb,
     .yajl_string = config_string_cb,
+    .yajl_end_array = config_end_array_cb,
     .yajl_map_key = config_map_key_cb,
 };
 
@@ -246,6 +316,8 @@ void parse_config_json(char *json) {
     yajl_status state;
     handle = yajl_alloc(&outputs_callbacks, NULL, NULL);
 
+    TAILQ_INIT(&(config.bindings));
+
     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
 
     /* FIXME: Proper error handling for JSON parsing */
@@ -286,5 +358,8 @@ void free_colors(struct xcb_color_strings_t *colors) {
     FREE_COLOR(focus_ws_fg);
     FREE_COLOR(focus_ws_bg);
     FREE_COLOR(focus_ws_border);
+    FREE_COLOR(binding_mode_fg);
+    FREE_COLOR(binding_mode_bg);
+    FREE_COLOR(binding_mode_border);
 #undef FREE_COLOR
 }
index bae08913106ed9bc11409fba4c29878647a7eeaf..7f7537af7d086e6db8168df6943932fa6e5530f9 100644 (file)
@@ -32,7 +32,7 @@ static int mode_string_cb(void *params_, const unsigned char *val, size_t len) {
 
     if (!strcmp(params->cur_key, "change")) {
         /* Save the name */
-        params->mode->name = i3string_from_utf8_with_length((const char *)val, len);
+        params->mode->name = i3string_from_markup_with_length((const char *)val, len);
         /* Save its rendered width */
         params->mode->width = predict_text_width(params->mode->name);
 
index b9e5659f11a8b01264f5f82b2253e52f2ef52f03..f31d711a80a2b05a2d8d509cb0eb8ab308386395 100644 (file)
@@ -106,6 +106,9 @@ struct xcb_colors_t {
     uint32_t focus_ws_bg;
     uint32_t focus_ws_fg;
     uint32_t focus_ws_border;
+    uint32_t binding_mode_bg;
+    uint32_t binding_mode_fg;
+    uint32_t binding_mode_border;
 };
 struct xcb_colors_t colors;
 
@@ -125,9 +128,6 @@ static const int sb_hoff_px = 4;
 /* Additional offset between the tray and the statusline, if the tray is not empty */
 static const int tray_loff_px = 2;
 
-/* Padding around the tray icons */
-static const int tray_spacing_px = 2;
-
 /* Vertical offset between the bar and a separator */
 static const int sep_voff_px = 4;
 
@@ -154,7 +154,7 @@ int get_tray_width(struct tc_head *trayclients) {
     TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) {
         if (!trayclient->mapped)
             continue;
-        tray_width += icon_size + logical_px(tray_spacing_px);
+        tray_width += icon_size + logical_px(config.tray_padding);
     }
     if (tray_width > 0)
         tray_width += logical_px(tray_loff_px);
@@ -374,6 +374,18 @@ void init_colors(const struct xcb_color_strings_t *new_colors) {
     PARSE_COLOR(focus_ws_border, "#4c7899");
 #undef PARSE_COLOR
 
+#define PARSE_COLOR_FALLBACK(name, fallback)                                                 \
+    do {                                                                                     \
+        colors.name = new_colors->name ? get_colorpixel(new_colors->name) : colors.fallback; \
+    } while (0)
+
+    /* For the binding mode indicator colors, we don't hardcode a default.
+     * Instead, we fall back to urgent_ws_* colors. */
+    PARSE_COLOR_FALLBACK(binding_mode_fg, urgent_ws_fg);
+    PARSE_COLOR_FALLBACK(binding_mode_bg, urgent_ws_bg);
+    PARSE_COLOR_FALLBACK(binding_mode_border, urgent_ws_border);
+#undef PARSE_COLOR_FALLBACK
+
     init_tray_colors();
     xcb_flush(xcb_connection);
 }
@@ -448,25 +460,27 @@ void handle_button(xcb_button_press_event_t *event) {
         x = original_x;
     }
 
+    /* If a custom command was specified for this mouse button, it overrides
+     * the default behavior. */
+    binding_t *binding;
+    TAILQ_FOREACH(binding, &(config.bindings), bindings) {
+        if (binding->input_code != event->detail)
+            continue;
+
+        i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, binding->command);
+        return;
+    }
+
     if (cur_ws == NULL) {
         DLOG("No workspace active?\n");
         return;
     }
-
     switch (event->detail) {
         case 4:
             /* Mouse wheel up. We select the previous ws, if any.
              * If there is no more workspace, don’t even send the workspace
              * command, otherwise (with workspace auto_back_and_forth) we’d end
              * up on the wrong workspace. */
-
-            /* If `wheel_up_cmd [COMMAND]` was specified, it should override
-             * the default behavior */
-            if (config.wheel_up_cmd) {
-                i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_up_cmd);
-                return;
-            }
-
             if (cur_ws == TAILQ_FIRST(walk->workspaces))
                 return;
 
@@ -477,14 +491,6 @@ void handle_button(xcb_button_press_event_t *event) {
              * If there is no more workspace, don’t even send the workspace
              * command, otherwise (with workspace auto_back_and_forth) we’d end
              * up on the wrong workspace. */
-
-            /* if `wheel_down_cmd [COMMAND]` was specified, it should override
-             * the default behavior */
-            if (config.wheel_down_cmd) {
-                i3_send_msg(I3_IPC_MESSAGE_TYPE_COMMAND, config.wheel_down_cmd);
-                return;
-            }
-
             if (cur_ws == TAILQ_LAST(walk->workspaces, ws_head))
                 return;
 
@@ -597,8 +603,8 @@ static void configure_trayclients(void) {
             clients++;
 
             DLOG("Configuring tray window %08x to x=%d\n",
-                 trayclient->win, output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px))));
-            uint32_t x = output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px)));
+                 trayclient->win, output->rect.w - (clients * (icon_size + logical_px(config.tray_padding))));
+            uint32_t x = output->rect.w - (clients * (icon_size + logical_px(config.tray_padding)));
             xcb_configure_window(xcb_connection,
                                  trayclient->win,
                                  XCB_CONFIG_WINDOW_X,
@@ -708,8 +714,8 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             xcb_reparent_window(xcb_connection,
                                 client,
                                 output->bar,
-                                output->rect.w - icon_size - logical_px(tray_spacing_px),
-                                logical_px(tray_spacing_px));
+                                output->rect.w - icon_size - logical_px(config.tray_padding),
+                                logical_px(config.tray_padding));
             /* We reconfigure the window to use a reasonable size. The systray
              * specification explicitly says:
              *   Tray icons may be assigned any size by the system tray, and
@@ -947,8 +953,8 @@ static void handle_configure_request(xcb_configure_request_event_t *event) {
                 continue;
 
             xcb_rectangle_t rect;
-            rect.x = output->rect.w - (clients * (icon_size + logical_px(tray_spacing_px)));
-            rect.y = logical_px(tray_spacing_px);
+            rect.x = output->rect.w - (clients * (icon_size + logical_px(config.tray_padding)));
+            rect.y = logical_px(config.tray_padding);
             rect.width = icon_size;
             rect.height = icon_size;
 
@@ -1221,7 +1227,7 @@ void init_xcb_late(char *fontname) {
     set_font(&font);
     DLOG("Calculated font height: %d\n", font.height);
     bar_height = font.height + 2 * logical_px(ws_voff_px);
-    icon_size = bar_height - 2 * logical_px(tray_spacing_px);
+    icon_size = bar_height - 2 * logical_px(config.tray_padding);
 
     if (config.separator_symbol)
         separator_symbol_width = predict_text_width(config.separator_symbol);
@@ -1897,11 +1903,11 @@ void draw_bars(bool unhide) {
         if (binding.name && !config.disable_binding_mode_indicator) {
             workspace_width += logical_px(ws_spacing_px);
 
-            uint32_t fg_color = colors.urgent_ws_fg;
-            uint32_t bg_color = colors.urgent_ws_bg;
+            uint32_t fg_color = colors.binding_mode_fg;
+            uint32_t bg_color = colors.binding_mode_bg;
             uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
 
-            uint32_t vals_border[] = {colors.urgent_ws_border, colors.urgent_ws_border};
+            uint32_t vals_border[] = {colors.binding_mode_border, colors.binding_mode_border};
             xcb_change_gc(xcb_connection,
                           outputs_walk->bargc,
                           mask,
index afb3c32abb605fd04a4c95ece8f18def5f04f273..6d1046d4b74cece97c59ee2ee36e475dbb13eeda 100644 (file)
@@ -67,7 +67,7 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which);
 void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resize_ppt);
 
 /**
- * Implementation of 'border normal|none|1pixel|toggle'.
+ * Implementation of 'border normal|pixel [<n>]', 'border none|1pixel|toggle'.
  *
  */
 void cmd_border(I3_CMD, char *border_style_str, char *border_width);
@@ -276,6 +276,12 @@ void cmd_move_scratchpad(I3_CMD);
  */
 void cmd_scratchpad_show(I3_CMD);
 
+/**
+ * Implementation of 'title_format <format>'
+ *
+ */
+void cmd_title_format(I3_CMD, char *format);
+
 /**
  * Implementation of 'rename workspace <name> to <name>'
  *
index 75e0b127f96e084b9e566dad84b1db7e9ed0a3c7..ff360bb5d126e348fa393abf428d415d21a83b36 100644 (file)
@@ -255,6 +255,9 @@ struct Barconfig {
      * disables the tray (it’s enabled by default). */
     char *tray_output;
 
+    /* Padding around the tray icons. */
+    int tray_padding;
+
     /** Path to the i3 IPC socket. This option is discouraged since programs
      * can find out the path by looking for the I3_SOCKET_PATH property on the
      * root window! */
@@ -281,13 +284,7 @@ struct Barconfig {
         M_MOD5 = 7
     } modifier;
 
-    /** Command that should be run when mouse wheel up button is pressed over
-     * i3bar to override the default behavior. */
-    char *wheel_up_cmd;
-
-    /** Command that should be run when mouse wheel down button is pressed over
-     * i3bar to override the default behavior. */
-    char *wheel_down_cmd;
+    TAILQ_HEAD(bar_bindings_head, Barbinding) bar_bindings;
 
     /** Bar position (bottom by default). */
     enum { P_BOTTOM = 0,
@@ -344,11 +341,30 @@ struct Barconfig {
         char *urgent_workspace_border;
         char *urgent_workspace_bg;
         char *urgent_workspace_text;
+
+        char *binding_mode_border;
+        char *binding_mode_bg;
+        char *binding_mode_text;
     } colors;
 
     TAILQ_ENTRY(Barconfig) configs;
 };
 
+/**
+ * Defines a mouse command to be executed instead of the default behavior when
+ * clicking on the non-statusline part of i3bar.
+ *
+ */
+struct Barbinding {
+    /** The button to be used (e.g., 1 for "button1"). */
+    int input_code;
+
+    /** The command which is to be executed for this button. */
+    char *command;
+
+    TAILQ_ENTRY(Barbinding) bindings;
+};
+
 /**
  * Finds the configuration file to use (either the one specified by
  * override_configpath), the user’s one or the system default) and calls
index 1a7a39329e06c765e1de8ae3b637f36e94f64201..fc34a85f751e3862796915e9fc5462a7b5e12078 100644 (file)
@@ -80,14 +80,17 @@ CFGFUN(bar_verbose, const char *verbose);
 CFGFUN(bar_modifier, const char *modifier);
 CFGFUN(bar_wheel_up_cmd, const char *command);
 CFGFUN(bar_wheel_down_cmd, const char *command);
+CFGFUN(bar_bindsym, const char *button, const char *command);
 CFGFUN(bar_position, const char *position);
 CFGFUN(bar_i3bar_command, const char *i3bar_command);
 CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text);
 CFGFUN(bar_socket_path, const char *socket_path);
 CFGFUN(bar_tray_output, const char *output);
+CFGFUN(bar_tray_padding, const long spacing_px);
 CFGFUN(bar_color_single, const char *colorclass, const char *color);
 CFGFUN(bar_status_command, const char *command);
 CFGFUN(bar_binding_mode_indicator, const char *value);
 CFGFUN(bar_workspace_buttons, const char *value);
 CFGFUN(bar_strip_workspace_numbers, const char *value);
+CFGFUN(bar_start);
 CFGFUN(bar_finish);
index 6cb6babc56d5ec0668a55799bde0a3885f2f98ea..66000e45462fa03fda2b5f2b9548aa023b14272d 100644 (file)
@@ -363,6 +363,8 @@ struct Window {
 
     /** The name of the window. */
     i3String *name;
+    /** The format with which the window's name should be displayed. */
+    char *title_format;
 
     /** The WM_WINDOW_ROLE of this window (for example, the pidgin buddy window
      * sets "buddy list"). Useful to match specific windows in assignments or
@@ -415,6 +417,7 @@ struct Match {
     struct regex *instance;
     struct regex *mark;
     struct regex *window_role;
+    struct regex *workspace;
     xcb_atom_t window_type;
     enum {
         U_DONTCHECK = -1,
index 3e6f8427d4f8e0f984e5d6c2964cd6413b1ff086..69c4452862a026b979e04d0796cb1aa18a0fb295 100644 (file)
@@ -243,6 +243,11 @@ bool i3string_is_markup(i3String *str);
  */
 void i3string_set_markup(i3String *str, bool is_markup);
 
+/**
+ * Escape pango markup characters in the given string.
+ */
+i3String *i3string_escape_markup(i3String *str);
+
 /**
  * Returns the number of glyphs in an i3String.
  *
@@ -381,6 +386,12 @@ xcb_char2b_t *convert_utf8_to_ucs2(char *input, size_t *real_strlen);
  */
 void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background);
 
+/**
+ * Returns true if and only if the current font is a pango font.
+ *
+ */
+bool font_is_pango(void);
+
 /**
  * Draws text onto the specified X drawable (normally a pixmap) at the
  * specified coordinates (from the top left corner of the leftmost, uppermost
index 0f30e74eb517a4cf2d2253671984fa57d952d9e6..b502b52c6390c57dc5e9774ba269f33bce738716 100644 (file)
@@ -340,6 +340,18 @@ void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background
     }
 }
 
+/*
+ * Returns true if and only if the current font is a pango font.
+ *
+ */
+bool font_is_pango(void) {
+#if PANGO_SUPPORT
+    return savedFont->type == FONT_TYPE_PANGO;
+#else
+    return false;
+#endif
+}
+
 static int predict_text_width_xcb(const xcb_char2b_t *text, size_t text_len);
 
 static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawable_t drawable,
index a0d35f961dbfcbd35687f051bcdd010ffc812282..95c31b59d5634bc6a1026195aaabad7d1b68942d 100644 (file)
 bool mkdirp(const char *path) {
     if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
         return true;
-    if (errno != ENOENT) {
+    if (errno == EEXIST) {
+        struct stat st;
+        /* Check that the named file actually is a directory. */
+        if (stat(path, &st)) {
+            ELOG("stat(%s) failed: %s\n", path, strerror(errno));
+            return false;
+        }
+        if (!S_ISDIR(st.st_mode)) {
+            ELOG("mkdir(%s) failed: %s\n", path, strerror(ENOTDIR));
+            return false;
+        }
+        return true;
+    } else if (errno != ENOENT) {
         ELOG("mkdir(%s) failed: %s\n", path, strerror(errno));
         return false;
     }
index 28575e1fb6bcaa2b4eb1625e0dff2456be8cf269..70244743283f33e9f8034682e1f2a01b26ce42a8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#if PANGO_SUPPORT
+#include <glib.h>
+#endif
+
 #include "libi3.h"
 
 struct _i3String {
@@ -185,6 +189,18 @@ void i3string_set_markup(i3String *str, bool is_markup) {
     str->is_markup = is_markup;
 }
 
+/*
+ * Escape pango markup characters in the given string.
+ */
+i3String *i3string_escape_markup(i3String *str) {
+#if PANGO_SUPPORT
+    const char *text = i3string_as_utf8(str);
+    return i3string_from_utf8(g_markup_escape_text(text, -1));
+#else
+    return str;
+#endif
+}
+
 /*
  * Returns the number of glyphs in an i3String.
  *
index 9fbce99157e3087c7aa87b3e08c25959b27b1846..eda71d6e2c1e1041c9019dc1f3d5033529416efe 100644 (file)
@@ -7,7 +7,7 @@ template::[header-declarations]
 <refentrytitle>{mantitle}</refentrytitle>
 <manvolnum>{manvolnum}</manvolnum>
 <refmiscinfo class="source">i3</refmiscinfo>
-<refmiscinfo class="version">4.10.2</refmiscinfo>
+<refmiscinfo class="version">4.10.3</refmiscinfo>
 <refmiscinfo class="manual">i3 Manual</refmiscinfo>
 </refmeta>
 <refnamediv>
index 8d497cd140d4eeb3a335b66c36bb4c0e7208dcc4..94dc630a8c1e0ab6e7de6e54508dacfcdb4e1b2a 100644 (file)
@@ -37,6 +37,7 @@ state INITIAL:
   'rename' -> RENAME
   'nop' -> NOP
   'scratchpad' -> SCRATCHPAD
+  'title_format' -> TITLE_FORMAT
   'mode' -> MODE
   'bar' -> BAR
 
@@ -50,6 +51,7 @@ state CRITERIA:
   ctype = 'con_mark'    -> CRITERION
   ctype = 'title'       -> CRITERION
   ctype = 'urgent'      -> CRITERION
+  ctype = 'workspace'   -> CRITERION
   ']' -> call cmd_criteria_match_windows(); INITIAL
 
 state CRITERION:
@@ -77,7 +79,8 @@ state DEBUGLOG:
   argument = 'toggle', 'on', 'off'
     -> call cmd_debuglog($argument)
 
-# border normal|none|1pixel|toggle|1pixel
+# border normal|pixel [<n>]
+# border none|1pixel|toggle
 state BORDER:
   border_style = 'normal', 'pixel'
     -> BORDER_WIDTH
@@ -373,6 +376,10 @@ state SCRATCHPAD:
   'show'
       -> call cmd_scratchpad_show()
 
+state TITLE_FORMAT:
+  format = string
+      -> call cmd_title_format($format)
+
 # bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) [<bar_id>]
 state BAR:
   bar_type = 'hidden_state'
index a0218ba6e72ec38f549ac2f667812181b54e26fe..3767acf8a4847ce21ea074b079c0e04e6dbaaa89 100644 (file)
@@ -170,6 +170,7 @@ state CRITERIA:
   ctype = 'con_mark'    -> CRITERION
   ctype = 'title'       -> CRITERION
   ctype = 'urgent'      -> CRITERION
+  ctype = 'workspace'   -> CRITERION
   ']'
       -> call cfg_criteria_pop_state()
 
@@ -393,7 +394,7 @@ state BARBRACE:
   end
       ->
   '{'
-      -> BAR
+      -> call cfg_bar_start(); BAR
 
 state BAR:
   end ->
@@ -409,9 +410,11 @@ state BAR:
   'modifier'               -> BAR_MODIFIER
   'wheel_up_cmd'           -> BAR_WHEEL_UP_CMD
   'wheel_down_cmd'         -> BAR_WHEEL_DOWN_CMD
+  'bindsym'                -> BAR_BINDSYM
   'position'               -> BAR_POSITION
   'output'                 -> BAR_OUTPUT
   'tray_output'            -> BAR_TRAY_OUTPUT
+  'tray_padding'           -> BAR_TRAY_PADDING
   'font'                   -> BAR_FONT
   'separator_symbol'       -> BAR_SEPARATOR_SYMBOL
   'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
@@ -463,6 +466,14 @@ state BAR_WHEEL_DOWN_CMD:
   command = string
       -> call cfg_bar_wheel_down_cmd($command); BAR
 
+state BAR_BINDSYM:
+  button = word
+      -> BAR_BINDSYM_COMMAND
+
+state BAR_BINDSYM_COMMAND:
+  command = string
+      -> call cfg_bar_bindsym($button, $command); BAR
+
 state BAR_POSITION:
   position = 'top', 'bottom'
       -> call cfg_bar_position($position); BAR
@@ -475,6 +486,16 @@ state BAR_TRAY_OUTPUT:
   output = word
       -> call cfg_bar_tray_output($output); BAR
 
+state BAR_TRAY_PADDING:
+  padding_px = number
+      -> BAR_TRAY_PADDING_PX
+
+state BAR_TRAY_PADDING_PX:
+  'px'
+      ->
+  end
+      -> call cfg_bar_tray_padding(&padding_px); BAR
+
 state BAR_FONT:
   font = string
       -> call cfg_bar_font($font); BAR
@@ -511,7 +532,7 @@ state BAR_COLORS:
   'set' -> BAR_COLORS_IGNORE_LINE
   colorclass = 'background', 'statusline', 'separator'
       -> BAR_COLORS_SINGLE
-  colorclass = 'focused_workspace', 'active_workspace', 'inactive_workspace', 'urgent_workspace'
+  colorclass = 'focused_workspace', 'active_workspace', 'inactive_workspace', 'urgent_workspace', 'binding_mode'
       -> BAR_COLORS_BORDER
   '}'
       -> BAR
index 4dd027779ed03541710a0e3e055f929d23b7d827..1ca70754d25ec5eaa8118c0867063cad2360a660 100755 (executable)
@@ -1,8 +1,8 @@
 #!/bin/zsh
 # This script is used to prepare a new release of i3.
 
-export RELEASE_VERSION="4.10.2"
-export PREVIOUS_VERSION="4.10.1"
+export RELEASE_VERSION="4.10.3"
+export PREVIOUS_VERSION="4.10.2"
 export RELEASE_BRANCH="master"
 
 if [ ! -e "../i3.github.io" ]
@@ -12,6 +12,12 @@ then
        exit 1
 fi
 
+if ! (cd ../i3.github.io && git pull)
+then
+       echo "Could not update ../i3.github.io repository"
+       exit 1
+fi
+
 if [ ! -e "RELEASE-NOTES-${RELEASE_VERSION}" ]
 then
        echo "RELEASE-NOTES-${RELEASE_VERSION} not found."
@@ -74,12 +80,12 @@ if [ "${RELEASE_BRANCH}" = "master" ]; then
        git checkout master
        git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
        git checkout next
-       git merge --no-ff master -m "Merge branch 'master' into next"
+       git merge --no-ff -X ours master -m "Merge branch 'master' into next"
 else
        git checkout next
        git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
        git checkout master
-       git merge --no-ff next -m "Merge branch 'next' into master"
+       git merge --no-ff -X theirs next -m "Merge branch 'next' into master"
 fi
 
 git remote remove origin
@@ -98,6 +104,7 @@ mkdir debian
 # Copy over the changelog because we expect it to be locally modified in the
 # start directory.
 cp "${STARTDIR}/debian/changelog" i3/debian/changelog
+(cd i3 && git add debian/changelog && git commit -m 'Update debian/changelog')
 
 cat > ${TMPDIR}/Dockerfile <<EOT
 FROM debian:sid
@@ -147,7 +154,6 @@ git add downloads/i3-${RELEASE_VERSION}.tar.bz2*
 cp ${TMPDIR}/i3/RELEASE-NOTES-${RELEASE_VERSION} downloads/RELEASE-NOTES-${RELEASE_VERSION}.txt
 git add downloads/RELEASE-NOTES-${RELEASE_VERSION}.txt
 sed -i "s,<h2>Documentation for i3 v[^<]*</h2>,<h2>Documentation for i3 v${RELEASE_VERSION}</h2>,g" docs/index.html
-sed -i "s,Verify you are using i3 ≥ .*,Verify you are using i3 ≥ ${RELEASE_VERSION},g" docs/debugging.html
 sed -i "s,<span style=\"margin-left: 2em; color: #c0c0c0\">[^<]*</span>,<span style=\"margin-left: 2em; color: #c0c0c0\">${RELEASE_VERSION}</span>,g" index.html
 sed -i "s,The current stable version is .*$,The current stable version is ${RELEASE_VERSION}.,g" downloads/index.html
 sed -i "s,<tbody>,<tbody>\n  <tr>\n    <td>${RELEASE_VERSION}</td>\n    <td><a href=\"/downloads/i3-${RELEASE_VERSION}.tar.bz2\">i3-${RELEASE_VERSION}.tar.bz2</a></td>\n    <td>$(ls -lh ../i3/i3-${RELEASE_VERSION}.tar.bz2 | awk -F " " {'print $5'} | sed 's/K$/ KiB/g')</td>\n    <td><a href=\"/downloads/i3-${RELEASE_VERSION}.tar.bz2.asc\">signature</a></td>\n    <td>$(date +'%Y-%m-%d')</td>\n    <td><a href=\"/downloads/RELEASE-NOTES-${RELEASE_VERSION}.txt\">release notes</a></td>\n  </tr>\n,g" downloads/index.html
@@ -162,15 +168,17 @@ git commit -a -m "save docs for ${PREVIOUS_VERSION}"
 for i in $(find _docs -maxdepth 1 -and -type f -and \! -regex ".*\.\(html\|man\)$" -and \! -name "Makefile")
 do
        base="$(basename $i)"
-       [ -e "${STARTDIR}/docs/${base}" ] && cp "${STARTDIR}/docs/${base}" "_docs/${base}"
+       [ -e "${TMPDIR}/i3/docs/${base}" ] && cp "${TMPDIR}/i3/docs/${base}" "_docs/${base}"
 done
 
+sed -i "s,Verify you are using i3 ≥ .*,Verify you are using i3 ≥ ${RELEASE_VERSION},g" _docs/debugging
+
 (cd _docs && make)
 
 for i in $(find _docs -maxdepth 1 -and -type f -and \! -regex ".*\.\(html\|man\)$" -and \! -name "Makefile")
 do
        base="$(basename $i)"
-       [ -e "${STARTDIR}/docs/${base}" ] && cp "_docs/${base}.html" docs/
+       [ -e "${TMPDIR}/i3/docs/${base}" ] && cp "_docs/${base}.html" docs/
 done
 
 git commit -a -m "update docs for ${RELEASE_VERSION}"
@@ -222,5 +230,4 @@ echo ""
 echo "Announce on:"
 echo "  twitter"
 echo "  google+"
-echo "  mailing list"
 echo "  #i3 topic"
index 5815908c46ece42c3ba524d71e8210f274fc3ac4..63ca0836a352a784f1c3de7da12bb71d61a8a85d 100644 (file)
@@ -63,10 +63,11 @@ Binding *configure_binding(const char *bindtype, const char *modifiers, const ch
 
         new_binding->symbol = sstrdup(input_code);
     } else {
-        // TODO: strtol with proper error handling
-        new_binding->keycode = atoi(input_code);
+        char *endptr;
+        long keycode = strtol(input_code, &endptr, 10);
+        new_binding->keycode = keycode;
         new_binding->input_type = B_KEYBOARD;
-        if (new_binding->keycode == 0) {
+        if (keycode == LONG_MAX || keycode == LONG_MIN || keycode < 0 || *endptr != '\0' || endptr == input_code) {
             ELOG("Could not parse \"%s\" as an input code, ignoring this binding.\n", input_code);
             FREE(new_binding);
             return NULL;
@@ -256,10 +257,11 @@ void translate_keysyms(void) {
 
     TAILQ_FOREACH(bind, bindings, bindings) {
         if (bind->input_type == B_MOUSE) {
-            int button = atoi(bind->symbol + (sizeof("button") - 1));
+            char *endptr;
+            long button = strtol(bind->symbol + (sizeof("button") - 1), &endptr, 10);
             bind->keycode = button;
 
-            if (button < 1)
+            if (button == LONG_MAX || button == LONG_MIN || button < 0 || *endptr != '\0' || endptr == bind->symbol)
                 ELOG("Could not translate string to button: \"%s\"\n", bind->symbol);
 
             continue;
index 690bd1f8aca2525b383654cd5b40cee37e7f6be2..bd2dcb9fdac2bb5a93d8769e42b3749f93234fff 100644 (file)
@@ -349,8 +349,8 @@ done:
  */
 int handle_button_press(xcb_button_press_event_t *event) {
     Con *con;
-    DLOG("Button %d %s on window 0x%08x (child 0x%08x) at (%d, %d) (root %d, %d)\n",
-         event->state, (event->response_type == XCB_BUTTON_PRESS ? "press" : "release"),
+    DLOG("Button %d (state %d) %s on window 0x%08x (child 0x%08x) at (%d, %d) (root %d, %d)\n",
+         event->detail, event->state, (event->response_type == XCB_BUTTON_PRESS ? "press" : "release"),
          event->event, event->child, event->event_x, event->event_y, event->root_x,
          event->root_y);
 
index b5558182d567d6b549cc37126eb20076d22bfcfc..62adcc6536ab87b36dd02c45ce50d555e1292200 100644 (file)
@@ -411,6 +411,11 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
         return;
     }
 
+    if (strcmp(ctype, "workspace") == 0) {
+        current_match->workspace = regex_new(cvalue);
+        return;
+    }
+
     ELOG("Unknown criterion: %s\n", ctype);
 }
 
@@ -816,7 +821,7 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
 }
 
 /*
- * Implementation of 'border normal|none|1pixel|toggle|pixel'.
+ * Implementation of 'border normal|pixel [<n>]', 'border none|1pixel|toggle'.
  *
  */
 void cmd_border(I3_CMD, char *border_style_str, char *border_width) {
@@ -1123,14 +1128,14 @@ void cmd_unmark(I3_CMD, char *mark) {
             FREE(con->mark);
             con->mark_changed = true;
         }
-        DLOG("removed all window marks");
+        DLOG("Removed all window marks.\n");
     } else {
         Con *con = con_by_mark(mark);
         if (con != NULL) {
             FREE(con->mark);
             con->mark_changed = true;
         }
-        DLOG("removed window mark %s\n", mark);
+        DLOG("Removed window mark \"%s\".\n", mark);
     }
 
     cmd_output->needs_tree_render = true;
@@ -1899,13 +1904,42 @@ void cmd_scratchpad_show(I3_CMD) {
     ysuccess(true);
 }
 
+/*
+ * Implementation of 'title_format <format>'
+ *
+ */
+void cmd_title_format(I3_CMD, char *format) {
+    DLOG("setting title_format to \"%s\"\n", format);
+    HANDLE_EMPTY_MATCH;
+
+    owindow *current;
+    TAILQ_FOREACH(current, &owindows, owindows) {
+        if (current->con->window == NULL)
+            continue;
+
+        DLOG("setting title_format for %p / %s\n", current->con, current->con->name);
+        FREE(current->con->window->title_format);
+
+        /* If we only display the title without anything else, we can skip the parsing step,
+         * so we remove the title format altogether. */
+        if (strcasecmp(format, "%title") != 0)
+            current->con->window->title_format = sstrdup(format);
+
+        /* Make sure the window title is redrawn immediately. */
+        current->con->window->name_x_changed = true;
+    }
+
+    cmd_output->needs_tree_render = true;
+    ysuccess(true);
+}
+
 /*
  * Implementation of 'rename workspace [<name>] to <name>'
  *
  */
 void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
     if (strncasecmp(new_name, "__", strlen("__")) == 0) {
-        LOG("Cannot rename workspace to \"%s\": names starting with __ are i3-internal.", new_name);
+        LOG("Cannot rename workspace to \"%s\": names starting with __ are i3-internal.\n", new_name);
         ysuccess(false);
         return;
     }
index 05f608bd0e9299ce7e6e7adc7ae0af4581c1351f..b63d5578a3e7f713a08879c9717e8877ad6c5eaa 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -211,7 +211,7 @@ void con_focus(Con *con) {
      * checks before resetting the urgency.
      */
     if (con->urgent && con_is_leaf(con)) {
-        con->urgent = false;
+        con_set_urgency(con, false);
         con_update_parents_urgency(con);
         workspace_update_urgent_flag(con_get_workspace(con));
         ipc_send_window_event("urgent", con);
@@ -729,12 +729,12 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
     /* Prevent moving if this would violate the fullscreen focus restrictions. */
     Con *target_ws = con_get_workspace(target);
     if (!con_fullscreen_permits_focusing(target_ws)) {
-        LOG("Cannot move out of a fullscreen container");
+        LOG("Cannot move out of a fullscreen container.\n");
         return false;
     }
 
     if (con_is_floating(con)) {
-        DLOG("Using FLOATINGCON instead\n");
+        DLOG("Container is floating, using parent instead.\n");
         con = con->parent;
     }
 
@@ -1722,13 +1722,13 @@ void con_update_parents_urgency(Con *con) {
  *
  */
 void con_set_urgency(Con *con, bool urgent) {
-    if (focused == con) {
+    if (urgent && focused == con) {
         DLOG("Ignoring urgency flag for current client\n");
-        con->window->urgent.tv_sec = 0;
-        con->window->urgent.tv_usec = 0;
         return;
     }
 
+    const bool old_urgent = con->urgent;
+
     if (con->urgency_timer == NULL) {
         con->urgent = urgent;
     } else
@@ -1752,7 +1752,7 @@ void con_set_urgency(Con *con, bool urgent) {
     if ((ws = con_get_workspace(con)) != NULL)
         workspace_update_urgent_flag(ws);
 
-    if (con->urgent == urgent) {
+    if (con->urgent != old_urgent) {
         LOG("Urgency flag changed to %d\n", con->urgent);
         ipc_send_window_event("urgent", con);
     }
index bac9d7f369b168c6f9ed345d66c7c1281b606140..a931ba1f2de513d3e9d44a6e313e883a149cbd3f 100644 (file)
@@ -130,6 +130,9 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
             FREE(barconfig->colors.urgent_workspace_border);
             FREE(barconfig->colors.urgent_workspace_bg);
             FREE(barconfig->colors.urgent_workspace_text);
+            FREE(barconfig->colors.binding_mode_border);
+            FREE(barconfig->colors.binding_mode_bg);
+            FREE(barconfig->colors.binding_mode_text);
             TAILQ_REMOVE(&barconfigs, barconfig, configs);
             FREE(barconfig);
         }
index ae78e0c0e87b255ad7e3c3a1ac63c24f27dc43f4..5b85012cbe6b8e7f0f7cf2ee849162f5080b45f5 100644 (file)
@@ -137,6 +137,11 @@ CFGFUN(criteria_add, const char *ctype, const char *cvalue) {
         return;
     }
 
+    if (strcmp(ctype, "workspace") == 0) {
+        current_match->workspace = regex_new(cvalue);
+        return;
+    }
+
     ELOG("Unknown criterion: %s\n", ctype);
 }
 
@@ -372,7 +377,7 @@ CFGFUN(focus_on_window_activation, const char *mode) {
         return;
     }
 
-    DLOG("Set new focus_on_window_activation mode = %i", config.focus_on_window_activation);
+    DLOG("Set new focus_on_window_activation mode = %i.\n", config.focus_on_window_activation);
 }
 
 CFGFUN(show_marks, const char *value) {
@@ -452,7 +457,7 @@ CFGFUN(assign, const char *workspace) {
         ELOG("Match is empty, ignoring this assignment\n");
         return;
     }
-    DLOG("new assignment, using above criteria, to workspace %s\n", workspace);
+    DLOG("New assignment, using above criteria, to workspace \"%s\".\n", workspace);
     Assignment *assignment = scalloc(sizeof(Assignment));
     match_copy(&(assignment->match), current_match);
     assignment->type = A_TO_WORKSPACE;
@@ -466,7 +471,7 @@ CFGFUN(no_focus) {
         return;
     }
 
-    DLOG("new assignment, using above criteria, to ignore focus on manage");
+    DLOG("New assignment, using above criteria, to ignore focus on manage.\n");
     Assignment *assignment = scalloc(sizeof(Assignment));
     match_copy(&(assignment->match), current_match);
     assignment->type = A_NO_FOCUS;
@@ -530,14 +535,44 @@ CFGFUN(bar_modifier, const char *modifier) {
         current_bar.modifier = M_SHIFT;
 }
 
+static void bar_configure_binding(const char *button, const char *command) {
+    if (strncasecmp(button, "button", strlen("button")) != 0) {
+        ELOG("Bindings for a bar can only be mouse bindings, not \"%s\", ignoring.\n", button);
+        return;
+    }
+
+    int input_code = atoi(button + strlen("button"));
+    if (input_code < 1) {
+        ELOG("Button \"%s\" does not seem to be in format 'buttonX'.\n", button);
+        return;
+    }
+
+    struct Barbinding *current;
+    TAILQ_FOREACH(current, &(current_bar.bar_bindings), bindings) {
+        if (current->input_code == input_code) {
+            ELOG("command for button %s was already specified, ignoring.\n", button);
+            return;
+        }
+    }
+
+    struct Barbinding *new_binding = scalloc(sizeof(struct Barbinding));
+    new_binding->input_code = input_code;
+    new_binding->command = sstrdup(command);
+    TAILQ_INSERT_TAIL(&(current_bar.bar_bindings), new_binding, bindings);
+}
+
 CFGFUN(bar_wheel_up_cmd, const char *command) {
-    FREE(current_bar.wheel_up_cmd);
-    current_bar.wheel_up_cmd = sstrdup(command);
+    ELOG("'wheel_up_cmd' is deprecated. Please us 'bindsym button4 %s' instead.\n", command);
+    bar_configure_binding("button4", command);
 }
 
 CFGFUN(bar_wheel_down_cmd, const char *command) {
-    FREE(current_bar.wheel_down_cmd);
-    current_bar.wheel_down_cmd = sstrdup(command);
+    ELOG("'wheel_down_cmd' is deprecated. Please us 'bindsym button5 %s' instead.\n", command);
+    bar_configure_binding("button5", command);
+}
+
+CFGFUN(bar_bindsym, const char *button, const char *command) {
+    bar_configure_binding(button, command);
 }
 
 CFGFUN(bar_position, const char *position) {
@@ -570,6 +605,7 @@ CFGFUN(bar_color, const char *colorclass, const char *border, const char *backgr
     APPLY_COLORS(active_workspace);
     APPLY_COLORS(inactive_workspace);
     APPLY_COLORS(urgent_workspace);
+    APPLY_COLORS(binding_mode);
 
 #undef APPLY_COLORS
 }
@@ -584,6 +620,10 @@ CFGFUN(bar_tray_output, const char *output) {
     current_bar.tray_output = sstrdup(output);
 }
 
+CFGFUN(bar_tray_padding, const long padding_px) {
+    current_bar.tray_padding = padding_px;
+}
+
 CFGFUN(bar_color_single, const char *colorclass, const char *color) {
     if (strcmp(colorclass, "background") == 0)
         current_bar.colors.background = sstrdup(color);
@@ -610,6 +650,11 @@ CFGFUN(bar_strip_workspace_numbers, const char *value) {
     current_bar.strip_workspace_numbers = eval_boolstr(value);
 }
 
+CFGFUN(bar_start) {
+    TAILQ_INIT(&(current_bar.bar_bindings));
+    current_bar.tray_padding = 2;
+}
+
 CFGFUN(bar_finish) {
     DLOG("\t new bar configuration finished, saving.\n");
     /* Generate a unique ID for this bar if not already configured */
index a9baef2710bc386f98fe4c0004e4649ff82db16d..9a0d19254db4d2c7d349054bdf351c8a96d24b11 100644 (file)
@@ -837,11 +837,11 @@ static char *migrate_config(char *input, off_t size) {
  */
 bool parse_file(const char *f, bool use_nagbar) {
     SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
-    int fd, ret, read_bytes = 0;
+    int fd;
     struct stat stbuf;
     char *buf;
     FILE *fstr;
-    char buffer[1026], key[512], value[512];
+    char buffer[4096], key[512], value[512], *continuation = NULL;
 
     if ((fd = open(f, O_RDONLY)) == -1)
         die("Could not open configuration file: %s\n", strerror(errno));
@@ -850,27 +850,30 @@ bool parse_file(const char *f, bool use_nagbar) {
         die("Could not fstat file: %s\n", strerror(errno));
 
     buf = scalloc((stbuf.st_size + 1) * sizeof(char));
-    while (read_bytes < stbuf.st_size) {
-        if ((ret = read(fd, buf + read_bytes, (stbuf.st_size - read_bytes))) < 0)
-            die("Could not read(): %s\n", strerror(errno));
-        read_bytes += ret;
-    }
-
-    if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
-        die("Could not lseek: %s\n", strerror(errno));
 
     if ((fstr = fdopen(fd, "r")) == NULL)
         die("Could not fdopen: %s\n", strerror(errno));
 
     while (!feof(fstr)) {
-        if (fgets(buffer, 1024, fstr) == NULL) {
+        if (!continuation)
+            continuation = buffer;
+        if (fgets(continuation, sizeof(buffer) - (continuation - buffer), fstr) == NULL) {
             if (feof(fstr))
                 break;
             die("Could not read configuration file\n");
         }
+        if (buffer[strlen(buffer) - 1] != '\n') {
+            ELOG("Your line continuation is too long, it exceeds %zd bytes\n", sizeof(buffer));
+        }
+        continuation = strstr(buffer, "\\\n");
+        if (continuation) {
+            continue;
+        }
+
+        strncpy(buf + strlen(buf), buffer, strlen(buffer) + 1);
 
         /* sscanf implicitly strips whitespace. Also, we skip comments and empty lines. */
-        if (sscanf(buffer, "%s %[^\n]", key, value) < 1 ||
+        if (sscanf(buffer, "%511s %511[^\n]", key, value) < 1 ||
             key[0] == '#' || strlen(key) < 3)
             continue;
 
index 6ece3f742dde32f9916b66a061661fee0e86b6d5..c82610ed38ff2856975a8ae37838b947a4f23e1b 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <fcntl.h>
+#include <time.h>
 #include "all.h"
 
-static bool human_readable_key;
-static char *human_readable_version;
+static bool human_readable_key, loaded_config_file_name_key;
+static char *human_readable_version, *loaded_config_file_name;
 
 static int version_string(void *ctx, const unsigned char *val, size_t len) {
     if (human_readable_key)
         sasprintf(&human_readable_version, "%.*s", (int)len, val);
+    if (loaded_config_file_name_key)
+        sasprintf(&loaded_config_file_name, "%.*s", (int)len, val);
     return 1;
 }
 
 static int version_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
     human_readable_key = (stringlen == strlen("human_readable") &&
                           strncmp((const char *)stringval, "human_readable", strlen("human_readable")) == 0);
+    loaded_config_file_name_key = (stringlen == strlen("loaded_config_file_name") &&
+                                   strncmp((const char *)stringval, "loaded_config_file_name", strlen("loaded_config_file_name")) == 0);
     return 1;
 }
 
@@ -104,6 +109,21 @@ void display_running_version(void) {
 
     printf("\rRunning i3 version: %s (pid %s)\n", human_readable_version, pid_from_atom);
 
+    if (loaded_config_file_name) {
+        struct stat sb;
+        time_t now;
+        char mtime[64];
+        printf("Loaded i3 config: %s", loaded_config_file_name);
+        if (stat(loaded_config_file_name, &sb) == -1) {
+            printf("\n");
+            ELOG("Cannot stat config file \"%s\"\n", loaded_config_file_name);
+        } else {
+            strftime(mtime, sizeof(mtime), "%c", localtime(&(sb.st_mtime)));
+            time(&now);
+            printf(" (Last modified: %s, %.f seconds ago)\n", mtime, difftime(now, sb.st_mtime));
+        }
+    }
+
 #ifdef __linux__
     size_t destpath_size = 1024;
     ssize_t linksize;
index a2843535e3d5c2396231c13caf5f349db0bedbbf..a82e2525c2a1e31927f428b56a304838c1b7e6e8 100644 (file)
@@ -441,7 +441,7 @@ void floating_move_to_pointer(Con *con) {
 
     Output *output = get_output_containing(reply->root_x, reply->root_y);
     if (output == NULL) {
-        ELOG("The pointer is not on any output, cannot move the container here.");
+        ELOG("The pointer is not on any output, cannot move the container here.\n");
         return;
     }
 
@@ -663,7 +663,7 @@ static void xcb_drag_check_cb(EV_P_ ev_check *w, int revents) {
                 break;
 
             case XCB_KEY_PRESS:
-                DLOG("A key was pressed during drag, reverting changes.");
+                DLOG("A key was pressed during drag, reverting changes.\n");
                 dragloop->result = DRAG_REVERT;
                 handle_event(type, event);
                 break;
index e7dde581d08e2e73ae7338edee86ab39704dfd02..8e08d697c505641ed5ed46c0171fea6045862dcc 100644 (file)
@@ -215,7 +215,7 @@ static void handle_motion_notify(xcb_motion_notify_event_t *event) {
 
     /* Skip events where the pointer was over a child window, we are only
      * interested in events on the root window. */
-    if (event->child != 0)
+    if (event->child != XCB_NONE)
         return;
 
     Con *con;
@@ -228,7 +228,7 @@ static void handle_motion_notify(xcb_motion_notify_event_t *event) {
     if (config.disable_focus_follows_mouse)
         return;
 
-    if (con->layout != L_DEFAULT)
+    if (con->layout != L_DEFAULT && con->layout != L_SPLITV && con->layout != L_SPLITH)
         return;
 
     /* see over which rect the user is */
@@ -245,8 +245,6 @@ static void handle_motion_notify(xcb_motion_notify_event_t *event) {
         x_push_changes(croot);
         return;
     }
-
-    return;
 }
 
 /*
@@ -753,7 +751,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
                 DLOG("Marking con = %p urgent\n", con);
                 con_set_urgency(con, true);
             } else
-                DLOG("Ignoring request for con = %p", con);
+                DLOG("Ignoring request for con = %p.\n", con);
         }
 
         tree_render();
@@ -1321,7 +1319,9 @@ static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom)
  *
  */
 void handle_event(int type, xcb_generic_event_t *event) {
-    DLOG("event type %d, xkb_base %d\n", type, xkb_base);
+    if (type != XCB_MOTION_NOTIFY)
+        DLOG("event type %d, xkb_base %d\n", type, xkb_base);
+
     if (randr_base > -1 &&
         type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
         handle_screen_change(event);
index a60b19004780bb9d9c764608abc83d80e238dde0..51a3d22315e625945f0e2765a033cfb83ee6d20c 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -469,6 +469,28 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
     y(map_close);
 }
 
+static void dump_bar_bindings(yajl_gen gen, Barconfig *config) {
+    if (TAILQ_EMPTY(&(config->bar_bindings)))
+        return;
+
+    ystr("bindings");
+    y(array_open);
+
+    struct Barbinding *current;
+    TAILQ_FOREACH(current, &(config->bar_bindings), bindings) {
+        y(map_open);
+
+        ystr("input_code");
+        y(integer, current->input_code);
+        ystr("command");
+        ystr(current->command);
+
+        y(map_close);
+    }
+
+    y(array_close);
+}
+
 static void dump_bar_config(yajl_gen gen, Barconfig *config) {
     y(map_open);
 
@@ -492,6 +514,10 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
     } while (0)
 
     YSTR_IF_SET(tray_output);
+
+    ystr("tray_padding");
+    y(integer, config->tray_padding);
+
     YSTR_IF_SET(socket_path);
 
     ystr("mode");
@@ -549,15 +575,7 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
             break;
     }
 
-    if (config->wheel_up_cmd) {
-        ystr("wheel_up_cmd");
-        ystr(config->wheel_up_cmd);
-    }
-
-    if (config->wheel_down_cmd) {
-        ystr("wheel_down_cmd");
-        ystr(config->wheel_down_cmd);
-    }
+    dump_bar_bindings(gen, config);
 
     ystr("position");
     if (config->position == P_BOTTOM)
@@ -611,6 +629,9 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
     YSTR_IF_SET(urgent_workspace_border);
     YSTR_IF_SET(urgent_workspace_bg);
     YSTR_IF_SET(urgent_workspace_text);
+    YSTR_IF_SET(binding_mode_border);
+    YSTR_IF_SET(binding_mode_bg);
+    YSTR_IF_SET(binding_mode_text);
     y(map_close);
 
     y(map_close);
@@ -793,6 +814,9 @@ IPC_HANDLER(get_version) {
     ystr("human_readable");
     ystr(i3_version);
 
+    ystr("loaded_config_file_name");
+    ystr(current_configpath);
+
     y(map_close);
 
     const unsigned char *payload;
index e8e0daa8c84a4bbfa783ef5afb8f691cda19de5e..4c5b5f18ced0aff76ae7b2838c89039dfe49673d 100644 (file)
@@ -450,7 +450,7 @@ int main(int argc, char *argv[]) {
             memset(cwd, '\0', cwd_size);
             if (read(patternfd, cwd, cwd_size) > 0)
                 /* a trailing newline is included in cwd */
-                LOG("CORE DUMPS: Your core_pattern is: %s", cwd);
+                LOG("CORE DUMPS: Your core_pattern is: \"%s\".\n", cwd);
             close(patternfd);
         }
         free(cwd);
@@ -574,7 +574,7 @@ int main(int argc, char *argv[]) {
 
     bool needs_tree_init = true;
     if (layout_path) {
-        LOG("Trying to restore the layout from %s...", layout_path);
+        LOG("Trying to restore the layout from \"%s\".\n", layout_path);
         needs_tree_init = !tree_restore(layout_path, greply);
         if (delete_layout_path) {
             unlink(layout_path);
@@ -768,7 +768,7 @@ int main(int argc, char *argv[]) {
             sigaction(SIGABRT, &action, NULL) == -1 ||
             sigaction(SIGFPE, &action, NULL) == -1 ||
             sigaction(SIGSEGV, &action, NULL) == -1)
-            ELOG("Could not setup signal handler");
+            ELOG("Could not setup signal handler.\n");
     }
 
     /* Catch all signals with default action "Term", see signal(7) */
@@ -777,7 +777,7 @@ int main(int argc, char *argv[]) {
         sigaction(SIGALRM, &action, NULL) == -1 ||
         sigaction(SIGUSR1, &action, NULL) == -1 ||
         sigaction(SIGUSR2, &action, NULL) == -1)
-        ELOG("Could not setup signal handler");
+        ELOG("Could not setup signal handler.\n");
 
     /* Ignore SIGPIPE to survive errors when an IPC client disconnects
      * while we are sending them a message */
index 0bea0ba8f7fcb1206acdfa8712052e29834f077b..5512602edfd6e1724b7f95780f7bdba577a32f85 100644 (file)
@@ -168,20 +168,11 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     cwindow->id = window;
     cwindow->depth = get_visual_depth(attr->visual);
 
-    /* We need to grab the mouse buttons for click to focus */
+    /* We need to grab buttons 1-3 for click-to-focus and buttons 1-5
+     * to allow for mouse bindings using --whole-window to work correctly. */
     xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
                     XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
-                    1 /* left mouse button */,
-                    XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
-    xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
-                    XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
-                    2 /* middle mouse button */,
-                    XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
-    xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
-                    XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
-                    3 /* right mouse button */,
+                    XCB_BUTTON_INDEX_ANY,
                     XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
 
     /* update as much information as possible so far (some replies may be NULL) */
index f1bc8430d45fca43db596b293dd71bfed959304d..b95cf2342bf61bbebdd90c7aebb5c4e9de89e39d 100644 (file)
@@ -48,6 +48,7 @@ bool match_is_empty(Match *match) {
             match->class == NULL &&
             match->instance == NULL &&
             match->window_role == NULL &&
+            match->workspace == NULL &&
             match->urgent == U_DONTCHECK &&
             match->id == XCB_NONE &&
             match->window_type == UINT32_MAX &&
@@ -78,6 +79,7 @@ void match_copy(Match *dest, Match *src) {
     DUPLICATE_REGEX(class);
     DUPLICATE_REGEX(instance);
     DUPLICATE_REGEX(window_role);
+    DUPLICATE_REGEX(workspace);
 }
 
 /*
@@ -172,6 +174,21 @@ bool match_matches_window(Match *match, i3Window *window) {
         LOG("urgent matches oldest\n");
     }
 
+    if (match->workspace != NULL) {
+        if ((con = con_by_window_id(window->id)) == NULL)
+            return false;
+
+        Con *ws = con_get_workspace(con);
+        if (ws == NULL)
+            return false;
+
+        if (regex_matches(match->workspace, ws->name)) {
+            LOG("workspace matches (%s)\n", ws->name);
+        } else {
+            return false;
+        }
+    }
+
     if (match->dock != M_DONTCHECK) {
         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
             (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
index 994fd69262fc205ab6b081cfe7efd8b33b691e33..05fe50558dba737352efc15333b362cf4ce69e20 100644 (file)
@@ -88,7 +88,7 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t dir
         }
     }
 
-    DLOG("Found participants: first=%p and second=%p.", first, second);
+    DLOG("Found participants: first=%p and second=%p.\n", first, second);
     *current = first;
     *other = second;
     if (first == NULL || second == NULL) {
index 4b1307c9de145ce472f964e2760ae72222c3d190..ceaa4842286ec14f27567fdf56c29188853719f9 100644 (file)
@@ -327,5 +327,5 @@ void setup_signal_handler(void) {
         sigaction(SIGABRT, &action, NULL) == -1 ||
         sigaction(SIGFPE, &action, NULL) == -1 ||
         sigaction(SIGSEGV, &action, NULL) == -1)
-        ELOG("Could not setup signal handler");
+        ELOG("Could not setup signal handler.\n");
 }
index 41f18d006ee23fbd981ef9f0f20a07d2323264cd..b062ea8ba0cb3af34d32d5a047dc5d84cdfeeb8f 100644 (file)
@@ -131,7 +131,7 @@ void startup_sequence_delete(struct Startup_Sequence *sequence) {
  *
  */
 void start_application(const char *command, bool no_startup_id) {
-    SnLauncherContext *context;
+    SnLauncherContext *context = NULL;
 
     if (!no_startup_id) {
         /* Create a startup notification context to monitor the progress of this
index 92b56e6c310909afe95ea828a796f1b7d9e36259..1d06d87481bc42b53cecb9748db111d6f0348369 100644 (file)
@@ -202,7 +202,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool
 
     /* remove the urgency hint of the workspace (if set) */
     if (con->urgent) {
-        con->urgent = false;
+        con_set_urgency(con, false);
         con_update_parents_urgency(con);
         workspace_update_urgent_flag(con_get_workspace(con));
     }
index 7b0f397d5d05fee52efdd2f32ae60e23ed20825e..dd04b1b9e822c851e56948775ef6e45364773de9 100644 (file)
@@ -241,7 +241,7 @@ void window_update_type(i3Window *window, xcb_get_property_reply_t *reply) {
     }
 
     window->window_type = new_type;
-    LOG("_NET_WM_WINDOW_TYPE changed to %i", window->window_type);
+    LOG("_NET_WM_WINDOW_TYPE changed to %i.\n", window->window_type);
 
     run_assignments(window);
 }
index c7f1a1bbc0605a30257a72c4bf41511b737b6b46..45d031da2f873a65ea1a56179eb24f988e770a2a 100644 (file)
@@ -129,7 +129,7 @@ Con *create_workspace_on_output(Output *output, Con *content) {
             continue;
         DLOG("relevant command = %s\n", bind->command);
         const char *target = bind->command + strlen("workspace ");
-        while ((*target == ' ' || *target == '\t') && target != '\0')
+        while (*target == ' ' || *target == '\t')
             target++;
         /* We check if this is the workspace
          * next/prev/next_on_output/prev_on_output/back_and_forth/number command.
@@ -322,17 +322,17 @@ static void workspace_reassign_sticky(Con *con) {
 static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents) {
     Con *con = w->data;
 
+    ev_timer_stop(main_loop, con->urgency_timer);
+    FREE(con->urgency_timer);
+
     if (con->urgent) {
         DLOG("Resetting urgency flag of con %p by timer\n", con);
-        con->urgent = false;
+        con_set_urgency(con, false);
         con_update_parents_urgency(con);
         workspace_update_urgent_flag(con_get_workspace(con));
         ipc_send_window_event("urgent", con);
         tree_render();
     }
-
-    ev_timer_stop(main_loop, con->urgency_timer);
-    FREE(con->urgency_timer);
 }
 
 static void _workspace_show(Con *workspace) {
@@ -729,7 +729,7 @@ workspace_prev_on_output_end:
  */
 void workspace_back_and_forth(void) {
     if (!previous_workspace_name) {
-        DLOG("No previous workspace name set. Not switching.");
+        DLOG("No previous workspace name set. Not switching.\n");
         return;
     }
 
@@ -742,7 +742,7 @@ void workspace_back_and_forth(void) {
  */
 Con *workspace_back_and_forth_get(void) {
     if (!previous_workspace_name) {
-        DLOG("no previous workspace name set.");
+        DLOG("No previous workspace name set.\n");
         return NULL;
     }
 
diff --git a/src/x.c b/src/x.c
index 2dcffe6b15929ae8d25d6a656ae1017d8d122a20..ef6c734162c0431bc6dad0ee7bb56d17e9c78788 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -302,6 +302,45 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
     free(event);
 }
 
+static i3String *parse_title_format(char *format, i3String *_title) {
+    /* We need to ensure that we only escape the window title if pango
+     * is used by the current font. */
+    const bool is_markup = font_is_pango();
+
+    i3String *title = is_markup ? i3string_escape_markup(_title) : _title;
+    const char *escaped_title = i3string_as_utf8(title);
+
+    /* We have to first iterate over the string to see how much buffer space
+     * we need to allocate. */
+    int buffer_len = strlen(format) + 1;
+    for (char *walk = format; *walk != '\0'; walk++) {
+        if (STARTS_WITH(walk, "%title")) {
+            buffer_len = buffer_len - strlen("%title") + strlen(escaped_title);
+            walk += strlen("%title") - 1;
+        }
+    }
+
+    /* Now we can parse the format string. */
+    char buffer[buffer_len];
+    char *outwalk = buffer;
+    for (char *walk = format; *walk != '\0'; walk++) {
+        if (*walk != '%') {
+            *(outwalk++) = *walk;
+            continue;
+        }
+
+        if (STARTS_WITH(walk + 1, "title")) {
+            outwalk += sprintf(outwalk, "%s", escaped_title);
+            walk += strlen("title");
+        }
+    }
+    *outwalk = '\0';
+
+    i3String *formatted = i3string_from_utf8(buffer);
+    i3string_set_markup(formatted, is_markup);
+    return formatted;
+}
+
 /*
  * Draws the decoration of the given container onto its parent.
  *
@@ -549,10 +588,13 @@ void x_draw_decoration(Con *con) {
         I3STRING_FREE(mark);
     }
 
-    draw_text(win->name,
+    i3String *title = win->title_format == NULL ? win->name : parse_title_format(win->title_format, win->name);
+    draw_text(title,
               parent->pixmap, parent->pm_gc,
               con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
               con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
+    if (win->title_format != NULL)
+        I3STRING_FREE(title);
 
 after_title:
     /* Since we don’t clip the text at all, it might in some cases be painted
index 3b82fe222cf1944811ea87536265d3b91b0cefb2..e88c37a283e366ca03bf0e02aff4b257746edf26 100644 (file)
@@ -53,10 +53,10 @@ font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 force_display_urgency_hint 0ms
 EOT
 
-my $type;
+my ($type, $tmp, $w1, $w2);
 for ($type = 1; $type <= 2; $type++) {
     my $pid = launch_with_config($config);
-    my $tmp = fresh_workspace;
+    $tmp = fresh_workspace;
 
 #####################################################################
 # Create two windows and put them in stacking mode
@@ -269,8 +269,8 @@ for ($type = 1; $type <= 2; $type++) {
     my $ws1 = fresh_workspace;
     my $ws2 = fresh_workspace;
     cmd "workspace $ws1";
-    my $w1 = open_window;
-    my $w2 = open_window;
+    $w1 = open_window;
+    $w2 = open_window;
     cmd "workspace $ws2";
     sync_with_i3;
     set_urgency($w1, 1, $type);
@@ -284,10 +284,10 @@ for ($type = 1; $type <= 2; $type++) {
 ##############################################################################
 # Check if urgent flag can be unset if we move the window out of the container
 ##############################################################################
-    my $tmp = fresh_workspace;
+    $tmp = fresh_workspace;
     cmd 'layout tabbed';
-    my $w1 = open_window;
-    my $w2 = open_window;
+    $w1 = open_window;
+    $w2 = open_window;
     sync_with_i3;
     cmd '[id="' . $w2->id . '"] focus';
     sync_with_i3;
@@ -316,8 +316,8 @@ for ($type = 1; $type <= 2; $type++) {
     my $tmp_target = fresh_workspace;
     cmd 'workspace ' . $tmp_source;
     sync_with_i3;
-    my $w1 = open_window;
-    my $w2 = open_window;
+    $w1 = open_window;
+    $w2 = open_window;
     sync_with_i3;
     cmd '[id="' . $w1->id . '"] focus';
     sync_with_i3;
index 97315c3deb2f5876f404f41058bf42af54db9db9..c5e61a328935404d4a3438ec6e275dca3efebc77 100644 (file)
@@ -17,6 +17,7 @@
 # Tests resizing tiling containers
 use i3test;
 
+my ($left, $right);
 my $tmp = fresh_workspace;
 
 cmd 'split v';
@@ -84,8 +85,8 @@ cmp_float($nodes->[1]->{percent}, 0.75, 'bottom window got 75%');
 
 $tmp = fresh_workspace;
 
-my $left = open_window;
-my $right = open_window;
+$left = open_window;
+$right = open_window;
 
 cmd 'split v';
 
@@ -261,8 +262,8 @@ cmp_ok($content[0]->{rect}->{width}, '==', $oldrect->{width}, 'width the same as
 
 $tmp = fresh_workspace;
 
-my $left = open_floating_window;
-my $right = open_floating_window;
+$left = open_floating_window;
+$right = open_floating_window;
 
 sub get_floating_rect {
     my ($window_id) = @_;
index b684d41fca41f7e10c645a6400ad08ddcc4ad806..985a7bfd687ec5e8d44e99c81d6ef64a1bafaeca 100644 (file)
@@ -17,6 +17,8 @@
 use i3test i3_autostart => 0;
 use X11::XCB qw(PROP_MODE_REPLACE);
 
+my (@nodes);
+
 ##############################################################
 # 1: test the following directive:
 #    for_window [class="borderless"] border none
@@ -435,6 +437,27 @@ EOT
 
 }
 
+##############################################################
+# 12: check that the criterion 'workspace' works
+##############################################################
+
+$config = <<"EOT";
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+for_window [workspace="trigger"] floating enable, mark triggered
+EOT
+
+$pid = launch_with_config($config);
+
+cmd 'workspace trigger';
+$window = open_window;
+
+@nodes = @{get_ws('trigger')->{floating_nodes}};
+cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
+is($nodes[0]->{nodes}[0]->{mark}, 'triggered', "mark set for workspace criterion");
+
+exit_gracefully($pid);
+
 ##############################################################
 
 done_testing;
index a0363ef3df4017238a801433c5e67e7fb935ee69..d8f9d2890c4d542d9780935e77937cdb5eb2bc0d 100644 (file)
@@ -147,8 +147,6 @@ $input = <<EOT;
     bindsym Mod1+s restart
     bindsym Mod1+s reload
     bindsym Mod1+s exit
-    bindsym Mod1+s stack-limit cols 2
-    bindsym Mod1+s stack-limit rows 3
     bind Mod1+c exec /usr/bin/urxvt
     mode "asdf" {
         bind 36 mode default
@@ -161,8 +159,6 @@ ok(line_exists($output, qr|^bindsym Mod1\+s mark foo$|), 'mark unchanged');
 ok(line_exists($output, qr|^bindsym Mod1\+s restart$|), 'restart unchanged');
 ok(line_exists($output, qr|^bindsym Mod1\+s reload$|), 'reload unchanged');
 ok(line_exists($output, qr|^bindsym Mod1\+s exit$|), 'exit unchanged');
-ok(line_exists($output, qr|^bindsym Mod1\+s stack-limit cols 2$|), 'stack-limit unchanged');
-ok(line_exists($output, qr|^bindsym Mod1\+s stack-limit rows 3$|), 'stack-limit unchanged');
 ok(line_exists($output, qr|^bindcode Mod1\+c exec /usr/bin/urxvt$|), 'bind changed to bindcode');
 ok(line_exists($output, qr|^mode "asdf" {$|), 'mode asdf unchanged');
 ok(line_exists($output, qr|^bindcode 36 mode \"default\"$|), 'mode default unchanged');
index 8675dd7183c003c335753308d140eef89b050867..cc4826c15766be171d652b4a102e813001d52da6 100644 (file)
@@ -66,6 +66,7 @@ ok($bar_config->{workspace_buttons}, 'workspace buttons enabled per default');
 ok($bar_config->{binding_mode_indicator}, 'mode indicator enabled per default');
 is($bar_config->{mode}, 'dock', 'dock mode by default');
 is($bar_config->{position}, 'bottom', 'position bottom by default');
+is($bar_config->{tray_padding}, 2, 'tray_padding ok');
 
 #####################################################################
 # ensure that reloading cleans up the old bar configs
@@ -96,6 +97,7 @@ bar {
 
     tray_output LVDS1
     tray_output HDMI2
+    tray_padding 0
     position top
     mode dock
     font Terminus
@@ -112,6 +114,7 @@ bar {
         active_workspace    #333333 #222222 #888888
         inactive_workspace  #333333 #222222 #888888
         urgent_workspace    #2f343a #900000 #ffffff
+        binding_mode        #abc123 #123abc #ababab
     }
 }
 EOT
@@ -133,6 +136,7 @@ is($bar_config->{mode}, 'dock', 'dock mode');
 is($bar_config->{position}, 'top', 'position top');
 is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok');
 is($bar_config->{tray_output}, 'HDMI2', 'tray_output ok');
+is($bar_config->{tray_padding}, 0, 'tray_padding ok');
 is($bar_config->{font}, 'Terminus', 'font ok');
 is($bar_config->{socket_path}, '/tmp/foobar', 'socket_path ok');
 is_deeply($bar_config->{colors},
@@ -151,6 +155,9 @@ is_deeply($bar_config->{colors},
         urgent_workspace_border => '#2f343a',
         urgent_workspace_text => '#ffffff',
         urgent_workspace_bg => '#900000',
+        binding_mode_border => '#abc123',
+        binding_mode_text => '#ababab',
+        binding_mode_bg => '#123abc',
     }, 'colors ok');
 
 exit_gracefully($pid);
index edfc46e0374158eab1eba96380de55f2da92bc3f..eeaee449f96108420082087243d16d8a1a4b2fe2 100644 (file)
@@ -377,7 +377,7 @@ sub verify_scratchpad_move_with_visible_scratch_con {
     # this should bring up window 1
     cmd 'scratchpad show';
 
-    my $ws = get_ws($first);
+    $ws = get_ws($first);
     is(scalar @{$ws->{floating_nodes}}, 1, 'one floating node on ws1');
     is($x->input_focus, $window1->id, "showed the correct scratchpad window1");
 
index 094caeaa5f13437c9ee80813b07f93c1461dfb0c..fc7fa882797f861e2d4ddefd1f6ad133fb1ae5cc 100644 (file)
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
 ################################################################################
 
 is(parser_calls('unknown_literal'),
-   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
+   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'title_format', 'mode', 'bar'\n" .
    "ERROR: Your command: unknown_literal\n" .
    "ERROR:               ^^^^^^^^^^^^^^^",
    'error for unknown literal ok');
index de25e7ff70f52c3e6b02e763fba2e4fb71d58c86..fbcc586a5d0952cde9020d899b9c56d01e137909 100644 (file)
@@ -688,8 +688,9 @@ bar {
 EOT
 
 $expected = <<'EOT';
+cfg_bar_start()
 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', 'separator_symbol', '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', 'bindsym', 'position', 'output', 'tray_output', 'tray_padding', '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
index 99fc92c81a475543b362e7e891413cbb628509ab..93b26d94294d7eb3bb5f88685ee3460879bbd446 100644 (file)
@@ -18,6 +18,8 @@
 use i3test;
 use List::Util qw(first);
 
+my ($con, $first, $second);
+
 sub get_marks {
     return i3(get_socket_path())->get_marks->recv;
 }
@@ -89,8 +91,8 @@ is_deeply(get_marks(), [], 'all marks removed');
 #    check that only the latter is marked
 ##############################################################
 
-my $first = open_window;
-my $second = open_window;
+$first = open_window;
+$second = open_window;
 
 cmd 'mark important';
 cmd 'focus left';
@@ -103,7 +105,7 @@ ok(!get_mark_for_window_on_workspace($tmp, $second), 'second container lost the
 # 5: mark a con, toggle the mark, check that the mark is gone
 ##############################################################
 
-my $con = open_window;
+$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');
@@ -112,7 +114,7 @@ ok(!get_mark_for_window_on_workspace($tmp, $con), 'container no longer has the m
 # 6: toggle a mark on an unmarked con, check it is marked
 ##############################################################
 
-my $con = open_window;
+$con = open_window;
 cmd 'mark --toggle important';
 is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container now has the mark');
 
@@ -121,7 +123,7 @@ is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container now has
 #    with the new mark
 ##############################################################
 
-my $con = open_window;
+$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');
@@ -131,8 +133,8 @@ is(get_mark_for_window_on_workspace($tmp, $con), 'important', 'container has the
 #    check only the latter has the mark
 ##############################################################
 
-my $first = open_window;
-my $second = open_window;
+$first = open_window;
+$second = open_window;
 
 cmd 'mark important';
 cmd 'focus left';
@@ -146,8 +148,8 @@ ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer
 #    it fails
 ##############################################################
 
-my $first = open_window(wm_class => 'iamnotunique');
-my $second = open_window(wm_class => 'iamnotunique');
+$first = open_window(wm_class => 'iamnotunique');
+$second = open_window(wm_class => 'iamnotunique');
 
 my $result = cmd "[instance=iamnotunique] mark important";
 
index c2de64e4da9a53a0ef6b9c02ef71d7ed008c4942..4c172ff578a2de8014acb9b8802b2f585bcabd54 100644 (file)
@@ -50,7 +50,7 @@ is($e->{container}->{floating}, 'user_on', 'the container should be floating');
 
 $cv = AnyEvent->condvar;
 cmd '[id="' . $win->{id} . '"] floating disable';
-my $e = $cv->recv;
+$e = $cv->recv;
 
 isnt($e, 0, 'disabling floating on a container should send an ipc window event');
 is($e->{container}->{window}, $win->{id}, 'the event should contain information about the window');
index 2ac9ecbbcc92a82d08620cf03868b5d15ee2d5ad..09226ff1f1ebe650259a86a068f300dedd69ea79 100644 (file)
@@ -59,7 +59,7 @@ is($event->{container}->{urgent}, 1, 'the container should be urgent');
 
 $cv = AnyEvent->condvar;
 $win->delete_hint('urgency');
-my $event = $cv->recv;
+$event = $cv->recv;
 
 isnt($event, 0, 'an urgent con should emit the window::urgent event');
 is($event->{container}->{window}, $win->{id}, 'the event should contain information about the window');
index 614d6b3a8896a4a8b1bcc30101ccfa89ab4a19b3..ec17353e177c56e9d64043e2c82aea44a28908f1 100644 (file)
@@ -20,6 +20,8 @@
 use i3test i3_autostart => 0;
 use File::Temp qw(tempfile);
 
+my ($cfg, $ret, $out);
+
 sub check_config {
     my ($config) = @_;
     my ($fh, $tmpfile) = tempfile(UNLINK => 1);
@@ -35,12 +37,12 @@ sub check_config {
 # 1: test with a bogus configuration file
 ################################################################################
 
-my $cfg = <<EOT;
+$cfg = <<EOT;
 # i3 config file (v4)
 i_am_an_unknown_config option
 EOT
 
-my ($ret, $out) = check_config($cfg);
+($ret, $out) = check_config($cfg);
 is($ret, 1, "exit code == 1");
 like($out, qr/ERROR: *CONFIG: *[Ee]xpected.*tokens/, 'bogus config file');
 
@@ -48,12 +50,12 @@ like($out, qr/ERROR: *CONFIG: *[Ee]xpected.*tokens/, 'bogus config file');
 # 2: test with a valid configuration file
 ################################################################################
 
-my $cfg = <<EOT;
+$cfg = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 EOT
 
-my ($ret, $out) = check_config($cfg);
+($ret, $out) = check_config($cfg);
 is($ret, 0, "exit code == 0");
 is($out, "", 'valid config file');
 
index 5f0b6e1c2796a97000d44e40d4ab93063a5f69d1..b2f8cac8aa5a808fdea3456d322593c063e9487b 100644 (file)
@@ -19,6 +19,8 @@
 use i3test i3_autostart => 0;
 use List::Util qw(first);
 
+my ($config, $pid, $first, $second, $ws1, $ws2);
+
 sub send_net_active_window {
     my ($id) = @_; 
 
@@ -46,18 +48,18 @@ sub get_urgency_for_window_on_workspace {
 #    check that the urgent flag is set and focus is not lost.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation urgent
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
 my $ws = fresh_workspace;
-my $first = open_window;
-my $second = open_window;
+$first = open_window;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
@@ -72,19 +74,19 @@ exit_gracefully($pid);
 #    visible, check that the urgent flag is set and focus is not lost.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation urgent
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
-my $ws1 = fresh_workspace;
-my $first = open_window;
-my $ws2 = fresh_workspace;
-my $second = open_window;
+$ws1 = fresh_workspace;
+$first = open_window;
+$ws2 = fresh_workspace;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
@@ -100,18 +102,18 @@ exit_gracefully($pid);
 #    check that the focus is switched.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation focus
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
 my $ws = fresh_workspace;
-my $first = open_window;
-my $second = open_window;
+$first = open_window;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
@@ -126,19 +128,19 @@ exit_gracefully($pid);
 #    visible, check that the focus switched.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation focus
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
-my $ws1 = fresh_workspace;
-my $first = open_window;
-my $ws2 = fresh_workspace;
-my $second = open_window;
+$ws1 = fresh_workspace;
+$first = open_window;
+$ws2 = fresh_workspace;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
@@ -154,18 +156,18 @@ exit_gracefully($pid);
 #    check that nothing happens.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation none
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
 my $ws = fresh_workspace;
-my $first = open_window;
-my $second = open_window;
+$first = open_window;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
@@ -180,19 +182,19 @@ exit_gracefully($pid);
 #    visible, check that nothing happens.
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 focus_on_window_activation none
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
 
-my $ws1 = fresh_workspace;
-my $first = open_window;
-my $ws2 = fresh_workspace;
-my $second = open_window;
+$ws1 = fresh_workspace;
+$first = open_window;
+$ws2 = fresh_workspace;
+$second = open_window;
 
 send_net_active_window($first->id);
 sync_with_i3;
index b3983436a2d411124dfdb1a585a36c58d4aa1d57..143ae5cf0bac2819c7bdaeac9866c26e909f09bf 100644 (file)
 # Ticket: #1416
 use i3test i3_autostart => 0;
 
+my ($config, $pid, $ws, $first, $second, $focused);
+
 #####################################################################
 # 1: open a window and check that it takes focus
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
  
-my $ws = fresh_workspace;
-my $first = open_window;
-my $focused = get_focused($ws);
-my $second = open_window;
+$ws = fresh_workspace;
+$first = open_window;
+$focused = get_focused($ws);
+$second = open_window;
 
 isnt(get_focused($ws), $focused, 'focus has changed');
 
@@ -43,19 +45,19 @@ exit_gracefully($pid);
 #    it doesn't take focus
 #####################################################################
 
-my $config = <<EOT;
+$config = <<EOT;
 # i3 config file (v4)
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
 
 no_focus [instance=notme]
 EOT
 
-my $pid = launch_with_config($config);
+$pid = launch_with_config($config);
  
-my $ws = fresh_workspace;
-my $first = open_window;
-my $focused = get_focused($ws);
-my $second = open_window(wm_class => 'notme');
+$ws = fresh_workspace;
+$first = open_window;
+$focused = get_focused($ws);
+$second = open_window(wm_class => 'notme');
 
 is(get_focused($ws), $focused, 'focus has not changed');
 
diff --git a/testcases/t/246-window-decoration-focus.t b/testcases/t/246-window-decoration-focus.t
new file mode 100644 (file)
index 0000000..06dfad8
--- /dev/null
@@ -0,0 +1,148 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Ensure that hovering over the window decoration of a window causes it to focus
+# correctly.
+# Ticket: #1056
+# Bug still in: 4.10.2-174-g8029ff0
+use i3test;
+
+my ($ws, $A, $B, $C, $target, $y);
+my @cons;
+
+# ==================================================================================
+# Given the following layout (= denotes the window decoration),
+# when moving the mouse from 1 to 2,
+# then the C should be focused.
+#
+# This should especially be the case if B is the focus head of its vertically split parent container.
+#
+# +===A===+===B===+
+# |       |       |
+# |     1 +=2=C===+
+# |       |       |
+# +-------+-------+
+#
+# ==================================================================================
+
+$ws = fresh_workspace;
+
+open_window;
+$B = open_window;
+cmd 'split v';
+open_window;
+$target = get_focused($ws);
+
+@cons = @{get_ws($ws)->{nodes}};
+$A = $cons[0];
+$C = $cons[1]->{nodes}[1];
+
+$y = $C->{rect}->{y} - 0.5 * $C->{deco_rect}->{height};
+
+# make sure that B is the focus head of its parent
+cmd '[id="' . $B->{id} . '"] focus';
+
+# move pointer to position 1
+$x->root->warp_pointer($C->{rect}->{x} - 0.5 * $A->{rect}->{width}, $y);
+sync_with_i3;
+
+# move pointer to position 2
+$x->root->warp_pointer($C->{rect}->{x} + 0.5 * $C->{rect}->{width}, $y);
+sync_with_i3;
+
+is(get_focused($ws), $target, 'focus switched to container C');
+
+# ==================================================================================
+# Given a tabbed container when the mouse is moved onto the window decoration
+# then the focus head of the tabbed container is focused regardless of which particular
+# tab's decoration the mouse is on.
+#
+# +=========+=========+
+# |         |         |
+# |       1 +=2==|****| <- tab to the right is focus head of tabbed container
+# |         |         |
+# +---------+---------+
+#
+# ==================================================================================
+
+$ws = fresh_workspace;
+
+open_window;
+open_window;
+cmd 'split v';
+open_window;
+cmd 'split h';
+open_window;
+$target = get_focused($ws);
+cmd 'layout tabbed';
+
+@cons = @{get_ws($ws)->{nodes}};
+$A = $cons[0];
+$B = $cons[1]->{nodes}[1]->{nodes}[1];
+
+$y = $B->{rect}->{y} - 0.5 * $B->{deco_rect}->{height};
+
+$x->root->warp_pointer($B->{rect}->{x} - 0.5 * $A->{rect}->{width}, $y);
+sync_with_i3;
+
+$x->root->warp_pointer($B->{rect}->{x} + 0.2 * $B->{rect}->{width}, $y);
+sync_with_i3;
+
+is(get_focused($ws), $target, 'focus switched to the focus head of the tabbed container');
+
+# ==================================================================================
+# Given a stacked container when the mouse is moved onto the window decoration
+# then the focus head of the stacked container is focused regardless of which particular
+# tab's decoration the mouse is on.
+#
+# +=========+=========+
+# |         |         |
+# |       1 +=2=======+
+# |         +*********+ <- the lower tab is the focus head of the stacked container
+# |         |         |
+# +---------+---------+
+#
+# ==================================================================================
+
+$ws = fresh_workspace;
+
+open_window;
+open_window;
+cmd 'split v';
+open_window;
+cmd 'split h';
+open_window;
+$target = get_focused($ws);
+cmd 'layout stacked';
+
+@cons = @{get_ws($ws)->{nodes}};
+$A = $cons[0];
+$B = $cons[1]->{nodes}[1]->{nodes}[0];
+$C = $cons[1]->{nodes}[1]->{nodes}[1];
+
+$y = $B->{rect}->{y} - 1.5 * $B->{deco_rect}->{height};
+
+$x->root->warp_pointer($B->{rect}->{x} - 0.5 * $A->{rect}->{width}, $y);
+sync_with_i3;
+
+$x->root->warp_pointer($B->{rect}->{x} + 0.5 * $B->{rect}->{width}, $y);
+sync_with_i3;
+
+is(get_focused($ws), $target, 'focus switched to the focus head of the stacked container');
+
+# ==================================================================================
+
+done_testing;
diff --git a/testcases/t/247-config-line-continuation.t b/testcases/t/247-config-line-continuation.t
new file mode 100644 (file)
index 0000000..0396d87
--- /dev/null
@@ -0,0 +1,201 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Checks that the line continuation are parsed correctly
+#
+
+use i3test i3_autostart => 0;
+
+# starts i3 with the given config, opens a window, returns its border style
+sub launch_get_border {
+    my ($config) = @_;
+
+    my $pid = launch_with_config($config);
+
+    my $i3 = i3(get_socket_path(0));
+    my $tmp = fresh_workspace;
+
+    my $window = open_window(name => '"special title"');
+
+    my @content = @{get_ws_content($tmp)};
+    cmp_ok(@content, '==', 1, 'one node on this workspace now');
+    my $border = $content[0]->{border};
+
+    exit_gracefully($pid);
+
+    return $border;
+}
+
+#####################################################################
+# test string escaping
+#####################################################################
+
+my $config = <<'EOT';
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+set $vartest \"special title\"
+for_window [title="$vartest"] border none
+EOT
+
+is(launch_get_border($config), 'none', 'no border');
+
+#####################################################################
+# test the line continuation
+#####################################################################
+
+$config = <<'EOT';
+# i3 config file (v4)
+font \
+-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+# Use line contiuation with too many lines (>4096 characters).
+# This config is invalid. Use it to ensure no buffer overflow.
+bindsym Mod1+b \
+0001-This is a very very very very very very very very very very very very very very very very very long cmd \
+0002-This is a very very very very very very very very very very very very very very very very very long cmd \
+0003-This is a very very very very very very very very very very very very very very very very very long cmd \
+0004-This is a very very very very very very very very very very very very very very very very very long cmd \
+0005-This is a very very very very very very very very very very very very very very very very very long cmd \
+0006-This is a very very very very very very very very very very very very very very very very very long cmd \
+0007-This is a very very very very very very very very very very very very very very very very very long cmd \
+0008-This is a very very very very very very very very very very very very very very very very very long cmd \
+0009-This is a very very very very very very very very very very very very very very very very very long cmd \
+0010-This is a very very very very very very very very very very very very very very very very very long cmd \
+0011-This is a very very very very very very very very very very very very very very very very very long cmd \
+0012-This is a very very very very very very very very very very very very very very very very very long cmd \
+0013-This is a very very very very very very very very very very very very very very very very very long cmd \
+0014-This is a very very very very very very very very very very very very very very very very very long cmd \
+0015-This is a very very very very very very very very very very very very very very very very very long cmd \
+0016-This is a very very very very very very very very very very very very very very very very very long cmd \
+0017-This is a very very very very very very very very very very very very very very very very very long cmd \
+0018-This is a very very very very very very very very very very very very very very very very very long cmd \
+0019-This is a very very very very very very very very very very very very very very very very very long cmd \
+0020-This is a very very very very very very very very very very very very very very very very very long cmd \
+0021-This is a very very very very very very very very very very very very very very very very very long cmd \
+0022-This is a very very very very very very very very very very very very very very very very very long cmd \
+0023-This is a very very very very very very very very very very very very very very very very very long cmd \
+0024-This is a very very very very very very very very very very very very very very very very very long cmd \
+0025-This is a very very very very very very very very very very very very very very very very very long cmd \
+0026-This is a very very very very very very very very very very very very very very very very very long cmd \
+0027-This is a very very very very very very very very very very very very very very very very very long cmd \
+0028-This is a very very very very very very very very very very very very very very very very very long cmd \
+0029-This is a very very very very very very very very very very very very very very very very very long cmd \
+0030-This is a very very very very very very very very very very very very very very very very very long cmd \
+0031-This is a very very very very very very very very very very very very very very very very very long cmd \
+0032-This is a very very very very very very very very very very very very very very very very very long cmd \
+0033-This is a very very very very very very very very very very very very very very very very very long cmd \
+0034-This is a very very very very very very very very very very very very very very very very very long cmd \
+0035-This is a very very very very very very very very very very very very very very very very very long cmd \
+0036-This is a very very very very very very very very very very very very very very very very very long cmd \
+0037-This is a very very very very very very very very very very very very very very very very very long cmd \
+0038-This is a very very very very very very very very very very very very very very very very very long cmd \
+0039-This is a very very very very very very very very very very very very very very very very very long cmd \
+0040-This is a very very very very very very very very very very very very very very very very very long cmd \
+0041-This is a very very very very very very very very very very very very very very very very very long cmd \
+0042-This is a very very very very very very very very very very very very very very very very very long cmd \
+0043-This is a very very very very very very very very very very very very very very very very very long cmd \
+0044-This is a very very very very very very very very very very very very very very very very very long cmd \
+0045-This is a very very very very very very very very very very very very very very very very very long cmd \
+0046-This is a very very very very very very very very very very very very very very very very very long cmd \
+0047-This is a very very very very very very very very very very very very very very very very very long cmd \
+0048-This is a very very very very very very very very very very very very very very very very very long cmd \
+0049-This is a very very very very very very very very very very very very very very very very very long cmd \
+0050-This is a very very very very very very very very very very very very very very very very very long cmd \
+0051-This is a very very very very very very very very very very very very very very very very very long cmd \
+0052-This is a very very very very very very very very very very very very very very very very very long cmd \
+0053-This is a very very very very very very very very very very very very very very very very very long cmd \
+0054-This is a very very very very very very very very very very very very very very very very very long cmd \
+0055-This is a very very very very very very very very very very very very very very very very very long cmd \
+0056-This is a very very very very very very very very very very very very very very very very very long cmd \
+0057-This is a very very very very very very very very very very very very very very very very very long cmd \
+0058-This is a very very very very very very very very very very very very very very very very very long cmd \
+0059-This is a very very very very very very very very very very very very very very very very very long cmd \
+0060-This is a very very very very very very very very very very very very very very very very very long cmd \
+0061-This is a very very very very very very very very very very very very very very very very very long cmd \
+0062-This is a very very very very very very very very very very very very very very very very very long cmd \
+0063-This is a very very very very very very very very very very very very very very very very very long cmd \
+0064-This is a very very very very very very very very very very very very very very very very very long cmd \
+0065-This is a very very very very very very very very very very very very very very very very very long cmd \
+0066-This is a very very very very very very very very very very very very very very very very very long cmd \
+0067-This is a very very very very very very very very very very very very very very very very very long cmd \
+0068-This is a very very very very very very very very very very very very very very very very very long cmd \
+0069-This is a very very very very very very very very very very very very very very very very very long cmd \
+0070-This is a very very very very very very very very very very very very very very very very very long cmd \
+0071-This is a very very very very very very very very very very very very very very very very very long cmd \
+0072-This is a very very very very very very very very very very very very very very very very very long cmd \
+0073-This is a very very very very very very very very very very very very very very very very very long cmd \
+0074-This is a very very very very very very very very very very very very very very very very very long cmd \
+0075-This is a very very very very very very very very very very very very very very very very very long cmd \
+0076-This is a very very very very very very very very very very very very very very very very very long cmd \
+0077-This is a very very very very very very very very very very very very very very very very very long cmd \
+0078-This is a very very very very very very very very very very very very very very very very very long cmd \
+0079-This is a very very very very very very very very very very very very very very very very very long cmd \
+0080-This is a very very very very very very very very very very very very very very very very very long cmd \
+0081-This is a very very very very very very very very very very very very very very very very very long cmd \
+0082-This is a very very very very very very very very very very very very very very very very very long cmd \
+0083-This is a very very very very very very very very very very very very very very very very very long cmd \
+0084-This is a very very very very very very very very very very very very very very very very very long cmd \
+0085-This is a very very very very very very very very very very very very very very very very very long cmd \
+0086-This is a very very very very very very very very very very very very very very very very very long cmd \
+0087-This is a very very very very very very very very very very very very very very very very very long cmd \
+0088-This is a very very very very very very very very very very very very very very very very very long cmd \
+0089-This is a very very very very very very very very very very very very very very very very very long cmd \
+0090-This is a very very very very very very very very very very very very very very very very very long cmd \
+0091-This is a very very very very very very very very very very very very very very very very very long cmd \
+0092-This is a very very very very very very very very very very very very very very very very very long cmd \
+0093-This is a very very very very very very very very very very very very very very very very very long cmd \
+0094-This is a very very very very very very very very very very very very very very very very very long cmd \
+0095-This is a very very very very very very very very very very very very very very very very very long cmd \
+0096-This is a very very very very very very very very very very very very very very very very very long cmd \
+0097-This is a very very very very very very very very very very very very very very very very very long cmd \
+0098-This is a very very very very very very very very very very very very very very very very very long cmd \
+0099-This is a very very very very very very very very very very very very very very very very very long cmd
+
+# Use line continuation for variables
+set \
+$vartest \
+\"special title\"
+
+# Use line continuation for commands
+for_window \
+[title="$vartest"] \
+border \
+none
+
+EOT
+
+is(launch_get_border($config), 'none', 'no border');
+
+#####################################################################
+# test the line continuation within a string
+#####################################################################
+
+$config = <<'EOT';
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+set \
+$vartest \
+\"special \
+title\"
+for_window [title="$vartest"] border none
+EOT
+
+is(launch_get_border($config), 'none', 'no border');
+
+
+done_testing;
diff --git a/testcases/t/248-regress-urgency-clear.t b/testcases/t/248-regress-urgency-clear.t
new file mode 100644 (file)
index 0000000..10ef377
--- /dev/null
@@ -0,0 +1,69 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Ensures the urgency hint is cleared properly in the case where i3 set it (due
+# to focus_on_window_activation=urgent), hence the application not clearing it.
+# Ticket: #1825
+# Bug still in: 4.10.3-253-g03799dd
+use i3test i3_autostart => 0;
+
+sub send_net_active_window {
+    my ($id) = @_;
+
+    my $msg = pack "CCSLLLLLLL",
+        X11::XCB::CLIENT_MESSAGE, # response_type
+        32, # format
+        0, # sequence
+        $id, # destination window
+        $x->atom(name => '_NET_ACTIVE_WINDOW')->id,
+        0, # source
+        0, 0, 0, 0;
+
+    $x->send_event(0, $x->get_root_window(), X11::XCB::EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg);
+}
+
+my $config = <<'EOT';
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+focus_on_window_activation urgent
+EOT
+
+my $pid = launch_with_config($config);
+my $i3 = i3(get_socket_path(0));
+my $ws = fresh_workspace;
+my $first = open_window;
+my $second = open_window;
+
+send_net_active_window($first->id);
+sync_with_i3;
+is($x->input_focus, $second->id, 'second window still focused');
+
+cmd '[urgent=latest] focus';
+sync_with_i3;
+is($x->input_focus, $first->id, 'first window focused');
+
+cmd 'focus right';
+sync_with_i3;
+is($x->input_focus, $second->id, 'second window focused again');
+
+cmd '[urgent=latest] focus';
+sync_with_i3;
+is($x->input_focus, $second->id, 'second window still focused');
+
+exit_gracefully($pid);
+
+done_testing;
diff --git a/testcases/t/525-i3bar-mouse-bindings.t b/testcases/t/525-i3bar-mouse-bindings.t
new file mode 100644 (file)
index 0000000..eabcad7
--- /dev/null
@@ -0,0 +1,104 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Ensures that mouse bindings on the i3bar work correctly.
+# Ticket: #1695
+use i3test i3_autostart => 0;
+
+my ($cv, $timer);
+sub reset_test {
+    $cv = AE::cv;
+    $timer = AE::timer(1, 0, sub { $cv->send(0); });
+}
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+focus_follows_mouse no
+
+bar {
+    font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+    position top
+
+    bindsym button1 focus left
+    bindsym button2 focus right
+    bindsym button3 focus left
+    bindsym button4 focus right
+    bindsym button5 focus left
+}
+EOT
+
+SKIP: {
+    qx(command -v xdotool 2> /dev/null);
+    skip 'xdotool is required for this test', 1 if $?;
+
+    my $pid = launch_with_config($config);
+    my $i3 = i3(get_socket_path());
+    $i3->connect()->recv;
+    my $ws = fresh_workspace;
+
+    reset_test;
+    $i3->subscribe({
+        window => sub {
+            my ($event) = @_;
+            if ($event->{change} eq 'focus') {
+                $cv->send($event->{container});
+            }
+        },
+    })->recv;
+
+    my $left = open_window;
+    my $right = open_window;
+    sync_with_i3;
+    my $con = $cv->recv;
+    is($con->{window}, $right->{id}, 'focus is initially on the right container');
+    reset_test;
+
+    qx(xdotool mousemove 3 3 click 1);
+    sync_with_i3;
+    $con = $cv->recv;
+    is($con->{window}, $left->{id}, 'button 1 moves focus left');
+    reset_test;
+
+    qx(xdotool mousemove 3 3 click 2);
+    sync_with_i3;
+    $con = $cv->recv;
+    is($con->{window}, $right->{id}, 'button 2 moves focus right');
+    reset_test;
+
+    qx(xdotool mousemove 3 3 click 3);
+    sync_with_i3;
+    $con = $cv->recv;
+    is($con->{window}, $left->{id}, 'button 3 moves focus left');
+    reset_test;
+
+    qx(xdotool mousemove 3 3 click 4);
+    sync_with_i3;
+    $con = $cv->recv;
+    is($con->{window}, $right->{id}, 'button 4 moves focus right');
+    reset_test;
+
+    qx(xdotool mousemove 3 3 click 5);
+    sync_with_i3;
+    $con = $cv->recv;
+    is($con->{window}, $left->{id}, 'button 5 moves focus left');
+    reset_test;
+
+    exit_gracefully($pid);
+
+}
+
+done_testing;