]> git.sur5r.net Git - i3/i3/commitdiff
Allow assign to output 2959/head
authorOrestis Floros <orestisf1993@gmail.com>
Sat, 16 Sep 2017 17:54:44 +0000 (20:54 +0300)
committerOrestis Floros <orestisf1993@gmail.com>
Sun, 17 Sep 2017 12:37:17 +0000 (15:37 +0300)
Implements the "assign" part of issue #2764.

docs/userguide
include/config_directives.h
include/data.h
parser-specs/config.spec
src/config_directives.c
src/manage.c
testcases/t/166-assign.t

index 38b16e5c9095c8cc28871bcf362dd12c1661d6a8..a911b08c2bda054ba252f4a084c4f3a16613a526 100644 (file)
@@ -760,6 +760,10 @@ title change. As i3 will get the title as soon as the application maps the
 window (mapping means actually displaying it on the screen), you’d need to have
 to match on 'Firefox' in this case.
 
+You can also assign a window to show up on a specific output. You can use RandR
+names such as +VGA1+ or names relative to the output with the currently focused
+workspace such as +left+ and +down+.
+
 Assignments are processed by i3 in the order in which they appear in the config
 file. The first one which matches the window wins and later assignments are not
 considered.
@@ -767,6 +771,7 @@ considered.
 *Syntax*:
 ------------------------------------------------------------
 assign <criteria> [→] [workspace] [number] <workspace>
+assign <criteria> [→] output left|right|up|down|primary|<output>
 ------------------------------------------------------------
 
 *Examples*:
@@ -791,9 +796,20 @@ assign [class="^URxvt$"] → number "2: work"
 
 # Start urxvt -name irssi
 assign [class="^URxvt$" instance="^irssi$"] → 3
+
+# Assign urxvt to the output right of the current one
+assign [class="^URxvt$"] → output right
+
+# Assign urxvt to the primary output
+assign [class="^URxvt$"] → output primary
 ----------------------
 
-Note that the arrow is not required, it just looks good :-). If you decide to
+Note that you might not have a primary output configured yet. To do so, run:
+-------------------------
+xrandr --output <output> --primary
+-------------------------
+
+Also, the arrow is not required, it just looks good :-). If you decide to
 use it, it has to be a UTF-8 encoded arrow, not `->` or something like that.
 
 To get the class and instance, you can use +xprop+. After clicking on the
index b729e72880d3fd5509f4992ec0d680730f650baf..5318bae809cbc45eba158f93b4902a4ae92b6ea9 100644 (file)
@@ -57,6 +57,7 @@ CFGFUN(force_display_urgency_hint, const long duration_ms);
 CFGFUN(focus_on_window_activation, const char *mode);
 CFGFUN(show_marks, const char *value);
 CFGFUN(hide_edge_borders, const char *borders);
+CFGFUN(assign_output, const char *output);
 CFGFUN(assign, const char *workspace, bool is_number);
 CFGFUN(no_focus);
 CFGFUN(ipc_socket, const char *path);
index 7411ac20cdb5780627068ace61fa95e54b43c9b4..632dfb4f04c98191a0b9c11405e7a0cff0c074a4 100644 (file)
@@ -557,7 +557,8 @@ struct Assignment {
         A_COMMAND = (1 << 0),
         A_TO_WORKSPACE = (1 << 1),
         A_NO_FOCUS = (1 << 2),
-        A_TO_WORKSPACE_NUMBER = (1 << 3)
+        A_TO_WORKSPACE_NUMBER = (1 << 3),
+        A_TO_OUTPUT = (1 << 4)
     } type;
 
     /** the criteria to check if a window matches */
@@ -567,6 +568,7 @@ struct Assignment {
     union {
         char *command;
         char *workspace;
+        char *output;
     } dest;
 
     TAILQ_ENTRY(Assignment)
index 665b046aeeed0701151bc2feccdd430ca26454fc..8c89b3f912024a6695d2a7f13687cf8bcbf1d6c3 100644 (file)
@@ -141,7 +141,7 @@ state FOR_WINDOW_COMMAND:
   command = string
       -> call cfg_for_window($command)
 
-# assign <criteria> [→] workspace
+# assign <criteria> [→] [workspace | output] <name>
 state ASSIGN:
   '['
       -> call cfg_criteria_init(ASSIGN_WORKSPACE); CRITERIA
@@ -149,6 +149,8 @@ state ASSIGN:
 state ASSIGN_WORKSPACE:
   '→'
       ->
+  'output'
+      -> ASSIGN_OUTPUT
   'workspace'
       ->
   'number'
@@ -156,6 +158,10 @@ state ASSIGN_WORKSPACE:
   workspace = string
       -> call cfg_assign($workspace, 0)
 
+state ASSIGN_OUTPUT:
+  output = string
+      -> call cfg_assign_output($output)
+
 state ASSIGN_WORKSPACE_NUMBER:
   number = string
       -> call cfg_assign($number, 1)
index 376397e8abe877146b9c7cb85fdd563ea832a3c0..c981ff60910729c57aec228d289e18e7ea37362c 100644 (file)
@@ -377,6 +377,20 @@ CFGFUN(color, const char *colorclass, const char *border, const char *background
 #undef APPLY_COLORS
 }
 
+CFGFUN(assign_output, const char *output) {
+    if (match_is_empty(current_match)) {
+        ELOG("Match is empty, ignoring this assignment\n");
+        return;
+    }
+
+    DLOG("New assignment, using above criteria, to output \"%s\".\n", output);
+    Assignment *assignment = scalloc(1, sizeof(Assignment));
+    match_copy(&(assignment->match), current_match);
+    assignment->type = A_TO_OUTPUT;
+    assignment->dest.output = sstrdup(output);
+    TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
+}
+
 CFGFUN(assign, const char *workspace, bool is_number) {
     if (match_is_empty(current_match)) {
         ELOG("Match is empty, ignoring this assignment\n");
index 8087d563faf264ce2f0d6b3722d31bbd84c21ec6..d12ce8d6e11c8b475bc0068738df87994f2b032b 100644 (file)
@@ -322,6 +322,10 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
             } else
                 nc = tree_open_con(NULL, cwindow);
         }
+
+        if ((assignment = assignment_for(cwindow, A_TO_OUTPUT))) {
+            con_move_to_output_name(nc, assignment->dest.output, true);
+        }
     } else {
         /* M_BELOW inserts the new window as a child of the one which was
          * matched (e.g. dock areas) */
index 07bddfff034c58ed7d1f53e42a336a0a312a127c..3c425467a62fab66e2ecac1e7a98c9f6d6be8af0 100644 (file)
@@ -203,8 +203,127 @@ my $content = get_ws($tmp);
 ok(@{$content->{nodes}} == 0, 'no tiling cons');
 ok(@{$content->{floating_nodes}} == 1, 'one floating con');
 
-$window->destroy;
+kill_all_windows;
+exit_gracefully($pid);
+
+#####################################################################
+# test assignments to named outputs
+#####################################################################
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+fake-outputs 1024x768+0+0,1024x768+1024+0,1024x768+1024+768,1024x768+0+768
+
+workspace ws-0 output fake-0
+workspace ws-1 output fake-1
+workspace ws-2 output fake-2
+workspace ws-3 output fake-3
+
+assign [class="special-0"] → output fake-0
+assign [class="special-1"] → output fake-1
+assign [class="special-2"] → output fake-2
+assign [class="special-3"] → output fake-3
+assign [class="special-4"] → output invalid
+
+EOT
+
+$pid = launch_with_config($config);
+
+sub open_in_output {
+    my ($num, $expected_count) = @_;
+    my $ws = "ws-$num";
+    my $class = "special-$num";
+    my $output = "fake-$num";
+
+    is_num_children($ws, $expected_count - 1,
+                    "before: " . ($expected_count - 1) . " containers on output $output");
+    $window = open_special(wm_class => $class);
+    sync_with_i3;
+    is_num_children($ws, $expected_count,
+                    "after: $expected_count containers on output $output");
+}
+
+cmd "workspace ws-0";
+open_in_output(0, 1);
+my $focused = $x->input_focus;
+
+open_in_output(1, 1);
+is($x->input_focus, $focused, 'focus remains on output fake-0');
+
+open_in_output(2, 1);
+is($x->input_focus, $focused, 'focus remains on output fake-0');
+
+for my $i (1 .. 5){
+    open_in_output(3, $i);
+    is($x->input_focus, $focused, 'focus remains on output fake-0');
+}
+
+# Check invalid output
+$tmp = fresh_workspace;
+open_special(wm_class => "special-4");
+sync_with_i3;
+is_num_children($tmp, 1, 'window assigned to invalid output opened in current workspace');
+open_special(wm_class => "special-3");
+sync_with_i3;
+is_num_children($tmp, 1, 'but window assigned to valid output did not');
+
+kill_all_windows;
+exit_gracefully($pid);
+
+#####################################################################
+# Test assignments to outputs with relative names
+#####################################################################
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+fake-outputs 1024x768+0+0,1024x768+1024+0,1024x768+1024+768,1024x768+0+768
+
+workspace left-top output fake-0
+workspace right-top output fake-1
+workspace right-bottom output fake-2
+workspace left-bottom output fake-3
+
+assign [class="current"] → output current
+assign [class="left"] → output left
+assign [class="right"] → output right
+assign [class="up"] → output up
+assign [class="down"] → output down
+EOT
+
+$pid = launch_with_config($config);
+
+cmd 'workspace left-top';
+
+is_num_children('left-top', 0, 'no childreon on left-top');
+for my $i (1 .. 5){
+    open_special(wm_class => 'current');
+}
+sync_with_i3;
+is_num_children('left-top', 5, 'windows opened in current workspace');
+
+is_num_children('right-top', 0, 'no children on right-top');
+open_special(wm_class => 'right');
+sync_with_i3;
+is_num_children('right-top', 1, 'one child on right-top');
+
+is_num_children('left-bottom', 0, 'no children on left-bottom');
+open_special(wm_class => 'down');
+sync_with_i3;
+is_num_children('left-bottom', 1, 'one child on left-bottom');
+
+cmd 'workspace right-bottom';
+
+open_special(wm_class => 'up');
+sync_with_i3;
+is_num_children('right-top', 2, 'two children on right-top');
+
+open_special(wm_class => 'left');
+sync_with_i3;
+is_num_children('left-bottom', 2, 'two children on left-bottom');
 
+kill_all_windows;
 exit_gracefully($pid);
 
 #####################################################################