]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1665 from Airblader/feature-1658
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Tue, 21 Apr 2015 06:42:16 +0000 (08:42 +0200)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Tue, 21 Apr 2015 06:42:16 +0000 (08:42 +0200)
Added criterion 'window_type'

15 files changed:
1  2 
docs/userguide
include/data.h
include/window.h
include/xcb.h
parser-specs/commands.spec
parser-specs/config.spec
src/commands.c
src/config_directives.c
src/ewmh.c
src/handlers.c
src/main.c
src/manage.c
src/match.c
src/window.c
src/xcb.c

diff --combined docs/userguide
index f7135c6a5ee915a171700a0b647527f5351d222f,965f839ea3e0ce94482a493d0b49560877c686d8..ad89fae8b522f558e134cce90bc7c8e63f88a841
@@@ -405,16 -405,13 +405,16 @@@ can configure mouse bindings in a simil
  
  *Syntax*:
  ----------------------------------
 -bindsym [--release] [--whole-window] [Modifiers+]button[n] command
 +bindsym [--release] [--border] [--whole-window] [Modifiers+]button[n] command
  ----------------------------------
  
  By default, the binding will only run when you click on the titlebar of the
 -window. If the +--whole-window+ flag is given, it will run when any part of the
 -window is clicked. If the +--release+ flag is given, it will run when the mouse
 -button is released.
 +window. If the +--release+ flag is given, it will run when the mouse button
 +is released.
 +
 +If the +--whole-window+ flag is given, the binding will also run when any part
 +of the window is clicked, with the exception of the border. To have a bind run
 +when the border is clicked, specify the +--border+ flag.
  
  *Examples*:
  --------------------------------
@@@ -1511,6 -1508,10 +1511,10 @@@ instance:
        Compares the window instance (the first part of WM_CLASS)
  window_role::
        Compares the window role (WM_WINDOW_ROLE).
+ window_type::
+         Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+         +normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+         +popup_menu+ and +toolti+.
  id::
        Compares the X11 window ID, which you can get via +xwininfo+ for example.
  title::
@@@ -1837,26 -1838,6 +1841,26 @@@ bindsym $mod+x move workspace to outpu
  bindsym $mod+x move container to output VGA1
  --------------------------------------------------------
  
 +=== Moving containers/workspaces to marks
 +
 +To move a container to another container with a specific mark (see <<vim_like_marks>>),
 +you can use the following command.
 +
 +The window will be moved right after the marked container in the tree, i.e., it ends up
 +in the same position as if you had opened a new window when the marked container was
 +focused. If the mark is on a split container, the window will appear as a new child
 +after the currently focused child within that container.
 +
 +*Syntax*:
 +------------------------------------
 +move window|container to mark <mark>
 +------------------------------------
 +
 +*Example*:
 +--------------------------------------------------------
 +for_window [instance="tabme"] move window to mark target
 +--------------------------------------------------------
 +
  [[resizingconfig]]
  
  === Resizing containers/windows
diff --combined include/data.h
index 75bff3a2d80b97946b7ac02e29a4020b98a2d5b5,5fb9a07458e28a60d1e6ee1974d9b31a510653cd..6cb6babc56d5ec0668a55799bde0a3885f2f98ea
@@@ -2,7 -2,7 +2,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * include/data.h: This file defines all data structures used by i3
   *
@@@ -255,10 -255,6 +255,10 @@@ struct Binding 
          B_UPON_KEYRELEASE_IGNORE_MODS = 2,
      } release;
  
 +    /** If this is true for a mouse binding, the binding should be executed
 +     * when the button is pressed over the window border. */
 +    bool border;
 +
      /** If this is true for a mouse binding, the binding should be executed
       * when the button is pressed over any part of the window, not just the
       * title bar (default). */
@@@ -382,6 -378,9 +382,9 @@@ struct Window 
       * default will be 'accepts focus'. */
      bool doesnt_accept_focus;
  
+     /** The _NET_WM_WINDOW_TYPE for this window. */
+     xcb_atom_t window_type;
      /** Whether the window says it is a dock window */
      enum { W_NODOCK = 0,
             W_DOCK_TOP = 1,
@@@ -412,6 -411,7 +415,7 @@@ struct Match 
      struct regex *instance;
      struct regex *mark;
      struct regex *window_role;
+     xcb_atom_t window_type;
      enum {
          U_DONTCHECK = -1,
          U_LATEST = 0,
diff --combined include/window.h
index 5f8b933bd86fe8e4f5b3a558738daea755fe28fd,d5b07cb1202ce7d20cc8767c12972e15c4372d67..7a248277abd09cf92fa564998f07602544d066f9
@@@ -2,7 -2,7 +2,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * window.c: Updates window attributes (X11 hints/properties).
   *
@@@ -56,6 -56,12 +56,12 @@@ void window_update_strut_partial(i3Wind
   */
  void window_update_role(i3Window *win, xcb_get_property_reply_t *prop, bool before_mgmt);
  
+ /**
+  * Updates the _NET_WM_WINDOW_TYPE property.
+  *
+  */
+ void window_update_type(i3Window *window, xcb_get_property_reply_t *reply);
  /**
   * Updates the WM_HINTS (we only care about the input focus handling part).
   *
diff --combined include/xcb.h
index 1928d76a159057365b2c600f592a795b9dd825bc,69d5af2ce5eef440d7d3ec72e4063820b6a7eacd..7dab5d100c8a39014dcc5d9f11db6588d853d3ab
@@@ -2,7 -2,7 +2,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * xcb.c: Helper functions for easier usage of XCB
   *
@@@ -108,6 -108,16 +108,16 @@@ void xcb_raise_window(xcb_connection_t 
   */
  void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r);
  
+ /**
+  * Returns the first supported _NET_WM_WINDOW_TYPE atom.
+  *
+  */
+ xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply);
+ /**
+  * Returns true if the given reply contains the given data.
+  *
+  */
  bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom);
  
  /**
index 297da145161a2d909153d39497e426f9623fbe60,d8f81d3e477db2589e166c5e438db8b9d0f006bd..1cd8d2f6789686dda558edb5f102e4ff3140bffd
@@@ -1,7 -1,7 +1,7 @@@
  # vim:ts=2:sw=2:expandtab
  #
  # i3 - an improved dynamic tiling window manager
 -# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 +# © 2009 Michael Stapelberg and contributors (see also: LICENSE)
  #
  # parser-specs/commands.spec: Specification file for generate-command-parser.pl
  # which will generate the appropriate header files for our C parser.
@@@ -41,14 -41,15 +41,15 @@@ state INITIAL
    'bar' -> BAR
  
  state CRITERIA:
-   ctype = 'class' -> CRITERION
-   ctype = 'instance' -> CRITERION
+   ctype = 'class'       -> CRITERION
+   ctype = 'instance'    -> CRITERION
    ctype = 'window_role' -> CRITERION
-   ctype = 'con_id' -> CRITERION
-   ctype = 'id' -> CRITERION
-   ctype = 'con_mark' -> CRITERION
-   ctype = 'title' -> CRITERION
-   ctype = 'urgent' -> CRITERION
+   ctype = 'con_id'      -> CRITERION
+   ctype = 'id'          -> CRITERION
+   ctype = 'window_type' -> CRITERION
+   ctype = 'con_mark'    -> CRITERION
+   ctype = 'title'       -> CRITERION
+   ctype = 'urgent'      -> CRITERION
    ']' -> call cmd_criteria_match_windows(); INITIAL
  
  state CRITERION:
@@@ -265,7 -266,6 +266,7 @@@ state RENAME_WORKSPACE_NEW_NAME
  # move <direction> [<pixels> [px]]
  # move [window|container] [to] workspace [<str>|next|prev|next_on_output|prev_on_output|current]
  # move [window|container] [to] output <str>
 +# move [window|container] [to] mark <str>
  # move [window|container] [to] scratchpad
  # move workspace to [output] <str>
  # move scratchpad
@@@ -281,8 -281,6 +282,8 @@@ state MOVE
        -> MOVE_WORKSPACE
    'output'
        -> MOVE_TO_OUTPUT
 +  'mark'
 +      -> MOVE_TO_MARK
    'scratchpad'
        -> call cmd_move_scratchpad()
    direction = 'left', 'right', 'up', 'down'
@@@ -324,10 -322,6 +325,10 @@@ state MOVE_TO_OUTPUT
    output = string
        -> call cmd_move_con_to_output($output)
  
 +state MOVE_TO_MARK:
 +  mark = string
 +      -> call cmd_move_con_to_mark($mark)
 +
  state MOVE_WORKSPACE_TO_OUTPUT:
    'output'
        ->
diff --combined parser-specs/config.spec
index 72bea3b8fd9501f948abbd64ef6c15287ea19f60,c5c8ad2535db5dfe8689162c3d6334f5185e9642..422efe485947c23fb30d20598fe8a1a53de80467
@@@ -1,7 -1,7 +1,7 @@@
  # vim:ts=2:sw=2:expandtab
  #
  # i3 - an improved dynamic tiling window manager
 -# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 +# © 2009 Michael Stapelberg and contributors (see also: LICENSE)
  #
  # parser-specs/config.spec: Specification file for generate-command-parser.pl
  # which will generate the appropriate header files for our C parser.
@@@ -167,6 -167,7 +167,7 @@@ state CRITERIA
    ctype = 'window_role' -> CRITERION
    ctype = 'con_id'      -> CRITERION
    ctype = 'id'          -> CRITERION
+   ctype = 'window_type' -> CRITERION
    ctype = 'con_mark'    -> CRITERION
    ctype = 'title'       -> CRITERION
    ctype = 'urgent'      -> CRITERION
@@@ -300,8 -301,6 +301,8 @@@ state FONT
  state BINDING:
    release = '--release'
        ->
 +  border = '--border'
 +      ->
    whole_window = '--whole-window'
        ->
    modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod'
  state BINDCOMMAND:
    release = '--release'
        ->
 +  border = '--border'
 +      ->
    whole_window = '--whole-window'
        ->
    command = string
 -      -> call cfg_binding($bindtype, $modifiers, $key, $release, $whole_window, $command)
 +      -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command)
  
  ################################################################################
  # Mode configuration
@@@ -353,8 -350,6 +354,8 @@@ state MODE_IGNORE_LINE
  state MODE_BINDING:
    release = '--release'
        ->
 +  border = '--border'
 +      ->
    whole_window = '--whole-window'
        ->
    modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', '$mod'
  state MODE_BINDCOMMAND:
    release = '--release'
        ->
 +  border = '--border'
 +      ->
    whole_window = '--whole-window'
        ->
    command = string
 -      -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $whole_window, $command); MODE
 +      -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command); MODE
  
  ################################################################################
  # Bar configuration (i3bar)
diff --combined src/commands.c
index 2a9e37650d3e39b8d3ab27470eeb86eb01eca657,6b72025139ad30d10dc3615028eed7bc61859b71..3263dd0394b0d73216151f454e31bbb214f6bb22
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * commands.c: all command functions (see commands_parser.c)
   *
@@@ -363,6 -363,31 +363,31 @@@ void cmd_criteria_add(I3_CMD, char *cty
          return;
      }
  
+     if (strcmp(ctype, "window_type") == 0) {
+         if (strcasecmp(cvalue, "normal") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
+         else if (strcasecmp(cvalue, "dialog") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
+         else if (strcasecmp(cvalue, "utility") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
+         else if (strcasecmp(cvalue, "toolbar") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
+         else if (strcasecmp(cvalue, "splash") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
+         else if (strcasecmp(cvalue, "menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
+         else if (strcasecmp(cvalue, "dropdown_menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+         else if (strcasecmp(cvalue, "popup_menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
+         else if (strcasecmp(cvalue, "tooltip") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
+         else
+             ELOG("unknown window_type value \"%s\"\n", cvalue);
+         return;
+     }
      if (strcmp(ctype, "con_mark") == 0) {
          current_match->mark = regex_new(cvalue);
          return;
@@@ -1100,10 -1125,12 +1125,10 @@@ void cmd_unmark(I3_CMD, char *mark) 
          }
          DLOG("removed all window marks");
      } else {
 -        Con *con;
 -        TAILQ_FOREACH(con, &all_cons, all_cons) {
 -            if (con->mark && strcmp(con->mark, mark) == 0) {
 -                FREE(con->mark);
 -                con->mark_changed = true;
 -            }
 +        Con *con = con_by_mark(mark);
 +        if (con != NULL) {
 +            FREE(con->mark);
 +            con->mark_changed = true;
          }
          DLOG("removed window mark %s\n", mark);
      }
@@@ -1167,26 -1194,6 +1192,26 @@@ void cmd_move_con_to_output(I3_CMD, cha
      ysuccess(true);
  }
  
 +/*
 + * Implementation of 'move [container|window] [to] mark <str>'.
 + *
 + */
 +void cmd_move_con_to_mark(I3_CMD, char *mark) {
 +    DLOG("moving window to mark \"%s\"\n", mark);
 +
 +    HANDLE_EMPTY_MATCH;
 +
 +    bool result = true;
 +    owindow *current;
 +    TAILQ_FOREACH(current, &owindows, owindows) {
 +        DLOG("moving matched window %p / %s to mark \"%s\"\n", current->con, current->con->name, mark);
 +        result &= con_move_to_mark(current->con, mark);
 +    }
 +
 +    cmd_output->needs_tree_render = true;
 +    ysuccess(result);
 +}
 +
  /*
   * Implementation of 'floating enable|disable|toggle'
   *
diff --combined src/config_directives.c
index eea3dba85fe2de2ee7bbc6177c56275d02d3b4ad,49e8d91d8faaeb98b8ae684b90f438ac39bed461..ff1c280e4f6d7fac4adb51c70510b6d5722694a8
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * config_directives.c: all config storing functions (see config_parser.c)
   *
@@@ -89,6 -89,31 +89,31 @@@ CFGFUN(criteria_add, const char *ctype
          return;
      }
  
+     if (strcmp(ctype, "window_type") == 0) {
+         if (strcasecmp(cvalue, "normal") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
+         else if (strcasecmp(cvalue, "dialog") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
+         else if (strcasecmp(cvalue, "utility") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
+         else if (strcasecmp(cvalue, "toolbar") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
+         else if (strcasecmp(cvalue, "splash") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
+         else if (strcasecmp(cvalue, "menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
+         else if (strcasecmp(cvalue, "dropdown_menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+         else if (strcasecmp(cvalue, "popup_menu") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
+         else if (strcasecmp(cvalue, "tooltip") == 0)
+             current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
+         else
+             ELOG("unknown window_type value \"%s\"\n", cvalue);
+         return;
+     }
      if (strcmp(ctype, "con_mark") == 0) {
          current_match->mark = regex_new(cvalue);
          return;
@@@ -171,8 -196,8 +196,8 @@@ CFGFUN(font, const char *font) 
      font_pattern = sstrdup(font);
  }
  
 -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) {
 -    configure_binding(bindtype, modifiers, key, release, whole_window, command, DEFAULT_BINDING_MODE);
 +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) {
 +    configure_binding(bindtype, modifiers, key, release, border, whole_window, command, DEFAULT_BINDING_MODE);
  }
  
  /*******************************************************************************
  
  static char *current_mode;
  
 -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command) {
 -    configure_binding(bindtype, modifiers, key, release, whole_window, command, current_mode);
 +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) {
 +    configure_binding(bindtype, modifiers, key, release, border, whole_window, command, current_mode);
  }
  
  CFGFUN(enter_mode, const char *modename) {
diff --combined src/ewmh.c
index 328bcab819f317cbcfb28aca9a601f316bca1500,883b929e8e31f2dea6de2291500658411f1b1371..1a357f23b742bbad9513ae9c6b489d2fcb5a70af
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * ewmh.c: Get/set certain EWMH properties easily.
   *
@@@ -234,6 -234,6 +234,6 @@@ void ewmh_setup_hints(void) 
      /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */
      xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
  
-     /* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
-     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms);
+     /* only send the first 29 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
+     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms);
  }
diff --combined src/handlers.c
index 532ab18966f3fc25b66a8ccc4a94b4e68fd069aa,0d536e44fda3d4ec48d733fb099c22736d192a14..e7dde581d08e2e73ae7338edee86ab39704dfd02
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * handlers.c: Small handlers for various events (keypresses, focus changes,
   *             …).
@@@ -880,7 -880,7 +880,7 @@@ static void handle_client_message(xcb_c
                  floating_drag_window(con->parent, &fake);
                  break;
              case _NET_WM_MOVERESIZE_SIZE_TOPLEFT... _NET_WM_MOVERESIZE_SIZE_LEFT:
 -                floating_resize_window(con->parent, FALSE, &fake);
 +                floating_resize_window(con->parent, false, &fake);
                  break;
              default:
                  DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction);
      }
  }
  
- #if 0
- int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
-                         xcb_atom_t atom, xcb_get_property_reply_t *property) {
-         /* TODO: Implement this one. To do this, implement a little test program which sleep(1)s
-          before changing this property. */
-         ELOG("_NET_WM_WINDOW_TYPE changed, this is not yet implemented.\n");
-         return 0;
+ bool handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
+                         xcb_atom_t atom, xcb_get_property_reply_t *reply) {
+     Con *con;
+     if ((con = con_by_window_id(window)) == NULL || con->window == NULL)
+         return false;
+     window_update_type(con->window, reply);
+     return true;
  }
- #endif
  
  /*
   * Handles the size hints set by a window, but currently only the part necessary for displaying
@@@ -1264,7 -1264,8 +1264,8 @@@ static struct property_handler_t proper
      {0, UINT_MAX, handle_transient_for},
      {0, 128, handle_windowrole_change},
      {0, 128, handle_class_change},
-     {0, UINT_MAX, handle_strut_partial_change}};
+     {0, UINT_MAX, handle_strut_partial_change},
+     {0, UINT_MAX, handle_window_type}};
  #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
  
  /*
@@@ -1284,6 -1285,7 +1285,7 @@@ void property_handlers_init(void) 
      property_handlers[6].atom = A_WM_WINDOW_ROLE;
      property_handlers[7].atom = XCB_ATOM_WM_CLASS;
      property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
+     property_handlers[9].atom = A__NET_WM_WINDOW_TYPE;
  }
  
  static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
diff --combined src/main.c
index 792736278e73f238365f2d49cbd2bf96b99acb6f,3c534431291cbc5e2b090ab332fe82aadbaaa9c0..86e40831902eef2051eb940d7fdd8b33cb91f01e
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * main.c: Initialization, main loop
   *
@@@ -261,11 -261,11 +261,11 @@@ int main(int argc, char *argv[]) 
                  only_check_config = true;
                  break;
              case 'v':
 -                printf("i3 version %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version);
 +                printf("i3 version %s © 2009 Michael Stapelberg and contributors\n", i3_version);
                  exit(EXIT_SUCCESS);
                  break;
              case 'm':
 -                printf("Binary i3 version:  %s © 2009-2014 Michael Stapelberg and contributors\n", i3_version);
 +                printf("Binary i3 version:  %s © 2009 Michael Stapelberg and contributors\n", i3_version);
                  display_running_version();
                  exit(EXIT_SUCCESS);
                  break;
      root_screen = xcb_aux_get_screen(conn, conn_screen);
      root = root_screen->root;
  
+ /* Place requests for the atoms we need as soon as possible */
+ #define xmacro(atom) \
+     xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
+ #include "atoms.xmacro"
+ #undef xmacro
      /* By default, we use the same depth and visual as the root window, which
       * usually is TrueColor (24 bit depth) and the corresponding visual.
       * However, we also check if a 32 bit depth and visual are available (for
      xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root);
      xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root);
  
+ /* Setup NetWM atoms */
+ #define xmacro(name)                                                                       \
+     do {                                                                                   \
+         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
+         if (!reply) {                                                                      \
+             ELOG("Could not get atom " #name "\n");                                        \
+             exit(-1);                                                                      \
+         }                                                                                  \
+         A_##name = reply->atom;                                                            \
+         free(reply);                                                                       \
+     } while (0);
+ #include "atoms.xmacro"
+ #undef xmacro
      load_configuration(conn, override_configpath, false);
  
      if (config.ipc_socket_path == NULL) {
      }
      DLOG("root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
  
- /* Place requests for the atoms we need as soon as possible */
- #define xmacro(atom) \
-     xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
- #include "atoms.xmacro"
- #undef xmacro
      xcursor_load_cursors();
  
      /* Set a cursor for the root window (otherwise the root window will show no
  
      restore_connect();
  
- /* Setup NetWM atoms */
- #define xmacro(name)                                                                       \
-     do {                                                                                   \
-         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
-         if (!reply) {                                                                      \
-             ELOG("Could not get atom " #name "\n");                                        \
-             exit(-1);                                                                      \
-         }                                                                                  \
-         A_##name = reply->atom;                                                            \
-         free(reply);                                                                       \
-     } while (0);
- #include "atoms.xmacro"
- #undef xmacro
      property_handlers_init();
  
      ewmh_setup_hints();
diff --combined src/manage.c
index ee56c0b39b28fa7ae78559a1d7409a204916cd32,bc9c9bff08043f60b2261eaf71458e3d2bf4b4f2..9d27ddea90149c22e32e77cd748aa01fa17bdfac
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * manage.c: Initially managing new windows (or existing ones on restart).
   *
@@@ -210,6 -210,9 +210,9 @@@ void manage_window(xcb_window_t window
      /* check if the window needs WM_TAKE_FOCUS */
      cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);
  
+     /* read the preferred _NET_WM_WINDOW_TYPE atom */
+     cwindow->window_type = xcb_get_preferred_window_type(type_reply);
      /* Where to start searching for a container that swallows the new one? */
      Con *search_at = croot;
  
diff --combined src/match.c
index d16ff0a00b4a50d91bdbf55c232e26dd0edc71d8,21778ed13dd541e1e56e1ac8e7070fe006b15859..f1bc8430d45fca43db596b293dd71bfed959304d
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * A "match" is a data structure which acts like a mask or expression to match
   * certain windows or not. For example, when using commands, you can specify a
   */
  void match_init(Match *match) {
      memset(match, 0, sizeof(Match));
-     match->dock = -1;
+     match->dock = M_DONTCHECK;
      match->urgent = U_DONTCHECK;
+     /* we use this as the placeholder value for "not set". */
+     match->window_type = UINT32_MAX;
  }
  
  /*
@@@ -48,6 -50,7 +50,7 @@@ bool match_is_empty(Match *match) 
              match->window_role == NULL &&
              match->urgent == U_DONTCHECK &&
              match->id == XCB_NONE &&
+             match->window_type == UINT32_MAX &&
              match->con_id == NULL &&
              match->dock == -1 &&
              match->floating == M_ANY);
@@@ -129,6 -132,14 +132,14 @@@ bool match_matches_window(Match *match
          }
      }
  
+     if (match->window_type != UINT32_MAX) {
+         if (window->window_type == match->window_type) {
+             LOG("window_type matches (%i)\n", match->window_type);
+         } else {
+             return false;
+         }
+     }
      Con *con = NULL;
      if (match->urgent == U_LATEST) {
          /* if the window isn't urgent, no sense in searching */
          LOG("urgent matches oldest\n");
      }
  
-     if (match->dock != -1) {
+     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) ||
              ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
diff --combined src/window.c
index 253f738da7653e17e830747e965b3bf7cd8bd31b,b87c1db53bf79b5cae5ac6736566d1fc94567280..3ffffa3bc3f1981a8851ca7ee224bd50734cb43c
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * window.c: Updates window attributes (X11 hints/properties).
   *
@@@ -232,6 -232,23 +232,23 @@@ void window_update_role(i3Window *win, 
      free(prop);
  }
  
+ /*
+  * Updates the _NET_WM_WINDOW_TYPE property.
+  *
+  */
+ void window_update_type(i3Window *window, xcb_get_property_reply_t *reply) {
+     xcb_atom_t new_type = xcb_get_preferred_window_type(reply);
+     if (new_type == XCB_NONE) {
+         DLOG("cannot read _NET_WM_WINDOW_TYPE from window.\n");
+         return;
+     }
+     window->window_type = new_type;
+     LOG("_NET_WM_WINDOW_TYPE changed to %i", window->window_type);
+     run_assignments(window);
+ }
  /*
   * Updates the WM_HINTS (we only care about the input focus handling part).
   *
diff --combined src/xcb.c
index d5684353bb2a46b21ef3f1c53a1883ec87516eba,d081d54d10a29a510dc69b1818cc2d540979cdf2..303d6af1cf2c9b583fff8653bd69fe230e00e457
+++ b/src/xcb.c
@@@ -4,7 -4,7 +4,7 @@@
   * vim:ts=4:sw=4:expandtab
   *
   * i3 - an improved dynamic tiling window manager
 - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
 + * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
   *
   * xcb.c: Helper functions for easier usage of XCB
   *
@@@ -154,6 -154,35 +154,35 @@@ void xcb_set_window_rect(xcb_connection
      add_ignore_event(cookie.sequence, -1);
  }
  
+ /*
+  * Returns the first supported _NET_WM_WINDOW_TYPE atom.
+  *
+  */
+ xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply) {
+     if (reply == NULL || xcb_get_property_value_length(reply) == 0)
+         return XCB_NONE;
+     xcb_atom_t *atoms;
+     if ((atoms = xcb_get_property_value(reply)) == NULL)
+         return XCB_NONE;
+     for (int i = 0; i < xcb_get_property_value_length(reply) / (reply->format / 8); i++) {
+         if (atoms[i] == A__NET_WM_WINDOW_TYPE_NORMAL ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_DIALOG ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_UTILITY ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_SPLASH ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_MENU ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_POPUP_MENU ||
+             atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLTIP) {
+             return atoms[i];
+         }
+     }
+     return XCB_NONE;
+ }
  /*
   * Returns true if the given reply contains the given atom.
   *