i3 - improved tiling WM


wrap when moving things to outputs with direction

Patch status: merged

Patch by Francesco Mazzoli

To apply this patch, use:
curl http://cr.i3wm.org/patch/21/raw.patch | git am

b/include/randr.h

15
@@ -88,19 +88,28 @@ Output *get_output_by_name(const char *name);
16
 Output *get_output_containing(int x, int y);
17
 
18
 /**
19
- * Gets the output which is the last one in the given direction, for example
20
- * the output on the most bottom when direction == D_DOWN, the output most
21
- * right when direction == D_RIGHT and so on.
22
+ * Gets the output which is the next one in the given direction.
23
+ *
24
+ * If close_far == CLOSEST_OUTPUT, then the output next to the current one will
25
+ * selected.  If close_far == FARTHEST_OUTPUT, the output which is the last one
26
+ * in the given direction will be selected.
27
  *
28
- * This function always returns a output.
29
+ * NULL will be returned when no active outputs are present in the direction
30
+ * specified (note that ‘current’ counts as such an output).
31
  *
32
  */
33
-Output *get_output_most(direction_t direction, Output *current);
34
+Output *get_output_next(direction_t direction, Output *current, output_close_far_t close_far);
35
 
36
 /**
37
- * Gets the output which is the next one in the given direction.
38
+ * Like get_output_next with close_far == CLOSEST_OUTPUT, but wraps.
39
+ *
40
+ * For example if get_output_next(D_DOWN, x, FARTHEST_OUTPUT) = NULL, then
41
+ * get_output_next_wrap(D_DOWN, x) will return the topmost output.
42
+ *
43
+ * This function always returns a output: if no active outputs can be found,
44
+ * current itself is returned.
45
  *
46
  */
47
-Output *get_output_next(direction_t direction, Output *current, output_close_far_t close_far);
48
+Output *get_output_next_wrap(direction_t direction, Output *current);
49
 
50
 #endif

b/src/commands.c

55
@@ -55,23 +55,15 @@ static bool definitelyGreaterThan(float a, float b, float epsilon) {
56
 static Output *get_output_from_string(Output *current_output, const char *output_str) {
57
     Output *output;
58
 
59
-    if (strcasecmp(output_str, "left") == 0) {
60
-        output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
61
-        if (!output)
62
-            output = get_output_most(D_RIGHT, current_output);
63
-    } else if (strcasecmp(output_str, "right") == 0) {
64
-        output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
65
-        if (!output)
66
-            output = get_output_most(D_LEFT, current_output);
67
-    } else if (strcasecmp(output_str, "up") == 0) {
68
-        output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
69
-        if (!output)
70
-            output = get_output_most(D_DOWN, current_output);
71
-    } else if (strcasecmp(output_str, "down") == 0) {
72
-        output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
73
-        if (!output)
74
-            output = get_output_most(D_UP, current_output);
75
-    } else output = get_output_by_name(output_str);
76
+    if (strcasecmp(output_str, "left") == 0)
77
+        output = get_output_next_wrap(D_LEFT, current_output);
78
+    else if (strcasecmp(output_str, "right") == 0)
79
+        output = get_output_next_wrap(D_RIGHT, current_output);
80
+    else if (strcasecmp(output_str, "up") == 0)
81
+        output = get_output_next_wrap(D_UP, current_output);
82
+    else if (strcasecmp(output_str, "down") == 0)
83
+        output = get_output_next_wrap(D_DOWN, current_output);
84
+    else output = get_output_by_name(output_str);
85
 
86
     return output;
87
 }
88
@@ -1052,13 +1044,13 @@ void cmd_move_con_to_output(I3_CMD, char *name) {
89
 
90
     // TODO: clean this up with commands.spec as soon as we switched away from the lex/yacc command parser
91
     if (strcasecmp(name, "up") == 0)
92
-        output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
93
+        output = get_output_next_wrap(D_UP, current_output);
94
     else if (strcasecmp(name, "down") == 0)
95
-        output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
96
+        output = get_output_next_wrap(D_DOWN, current_output);
97
     else if (strcasecmp(name, "left") == 0)
98
-        output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
99
+        output = get_output_next_wrap(D_LEFT, current_output);
100
     else if (strcasecmp(name, "right") == 0)
101
-        output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
102
+        output = get_output_next_wrap(D_RIGHT, current_output);
103
     else
104
         output = get_output_by_name(name);
105
 

b/src/randr.c

110
@@ -93,15 +93,30 @@ Output *get_output_containing(int x, int y) {
111
 }
112
 
113
 /*
114
- * Gets the output which is the last one in the given direction, for example
115
- * the output on the most bottom when direction == D_DOWN, the output most
116
- * right when direction == D_RIGHT and so on.
117
+ * Like get_output_next with close_far == CLOSEST_OUTPUT, but wraps.
118
  *
119
- * This function always returns a output.
120
+ * For example if get_output_next(D_DOWN, x, FARTHEST_OUTPUT) = NULL, then
121
+ * get_output_next_wrap(D_DOWN, x) will return the topmost output.
122
+ *
123
+ * This function always returns a output: if no active outputs can be found,
124
+ * current itself is returned.
125
  *
126
  */
127
-Output *get_output_most(direction_t direction, Output *current) {
128
-    Output *best = get_output_next(direction, current, FARTHEST_OUTPUT);
129
+Output *get_output_next_wrap(direction_t direction, Output *current) {
130
+    Output *best = get_output_next(direction, current, CLOSEST_OUTPUT);
131
+    /* If no output can be found, wrap */
132
+    if (!best) {
133
+        direction_t opposite;
134
+        if (direction == D_RIGHT)
135
+            opposite = D_LEFT;
136
+        else if (direction == D_LEFT)
137
+            opposite = D_RIGHT;
138
+        else if (direction == D_DOWN)
139
+            opposite = D_UP;
140
+        else
141
+            opposite = D_DOWN;
142
+        best = get_output_next(opposite, current, FARTHEST_OUTPUT);
143
+    }
144
     if (!best)
145
         best = current;
146
     DLOG("current = %s, best = %s\n", current->name, best->name);
147
@@ -111,6 +126,13 @@ Output *get_output_most(direction_t direction, Output *current) {
148
 /*
149
  * Gets the output which is the next one in the given direction.
150
  *
151
+ * If close_far == CLOSEST_OUTPUT, then the output next to the current one will
152
+ * selected. If close_far == FARTHEST_OUTPUT, the output which is the last one
153
+ * in the given direction will be selected.
154
+ *
155
+ * NULL will be returned when no active outputs are present in the direction
156
+ * specified (note that “current” counts as such an output).
157
+ *
158
  */
159
 Output *get_output_next(direction_t direction, Output *current, output_close_far_t close_far) {
160
     Rect *cur = &(current->rect),