]> git.lizzy.rs Git - bspwm.git/blob - pointer.c
New setting: merge_overlapping_monitors
[bspwm.git] / pointer.c
1 /* Copyright (c) 2012-2014, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those
25  * of the authors and should not be interpreted as representing official policies,
26  * either expressed or implied, of the FreeBSD Project.
27  */
28
29 #include "bspwm.h"
30 #include "query.h"
31 #include "settings.h"
32 #include "stack.h"
33 #include "tree.h"
34 #include "monitor.h"
35 #include "window.h"
36 #include "pointer.h"
37
38 void grab_pointer(pointer_action_t pac)
39 {
40         PRINTF("grab pointer %u\n", pac);
41
42         xcb_window_t win = XCB_NONE;
43         xcb_point_t pos;
44
45         query_pointer(&win, &pos);
46
47         coordinates_t loc;
48         if (locate_window(win, &loc)) {
49                 client_t *c = NULL;
50                 frozen_pointer->position = pos;
51                 frozen_pointer->action = pac;
52                 c = loc.node->client;
53                 frozen_pointer->monitor = loc.monitor;
54                 frozen_pointer->desktop = loc.desktop;
55                 frozen_pointer->node = loc.node;
56                 frozen_pointer->client = c;
57                 frozen_pointer->window = c->window;
58                 frozen_pointer->horizontal_fence = NULL;
59                 frozen_pointer->vertical_fence = NULL;
60
61                 switch (pac)  {
62                         case ACTION_FOCUS:
63                                 if (loc.node != mon->desk->focus) {
64                                         bool backup = pointer_follows_monitor;
65                                         pointer_follows_monitor = false;
66                                         focus_node(loc.monitor, loc.desktop, loc.node);
67                                         pointer_follows_monitor = backup;
68                                 } else if (focus_follows_pointer) {
69                                         stack(loc.node, STACK_ABOVE);
70                                 }
71                                 frozen_pointer->action = ACTION_NONE;
72                                 break;
73                         case ACTION_MOVE:
74                         case ACTION_RESIZE_SIDE:
75                         case ACTION_RESIZE_CORNER:
76                                 if (is_floating(c)) {
77                                         frozen_pointer->rectangle = c->floating_rectangle;
78                                         frozen_pointer->is_tiled = false;
79                                 } else if (is_tiled(c)) {
80                                         frozen_pointer->rectangle = c->tiled_rectangle;
81                                         frozen_pointer->is_tiled = (pac == ACTION_MOVE || !c->pseudo_tiled);
82                                 } else {
83                                         frozen_pointer->action = ACTION_NONE;
84                                         return;
85                                 }
86                                 if (pac == ACTION_RESIZE_SIDE) {
87                                         float W = frozen_pointer->rectangle.width;
88                                         float H = frozen_pointer->rectangle.height;
89                                         float ratio = W / H;
90                                         float x = pos.x - frozen_pointer->rectangle.x;
91                                         float y = pos.y - frozen_pointer->rectangle.y;
92                                         float diag_a = ratio * y;
93                                         float diag_b = W - diag_a;
94                                         if (x < diag_a) {
95                                                 if (x < diag_b)
96                                                         frozen_pointer->side = SIDE_LEFT;
97                                                 else
98                                                         frozen_pointer->side = SIDE_BOTTOM;
99                                         } else {
100                                                 if (x < diag_b)
101                                                         frozen_pointer->side = SIDE_TOP;
102                                                 else
103                                                         frozen_pointer->side = SIDE_RIGHT;
104                                         }
105                                 } else if (pac == ACTION_RESIZE_CORNER) {
106                                         int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2);
107                                         int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2);
108                                         if (pos.x > mid_x) {
109                                                 if (pos.y > mid_y)
110                                                         frozen_pointer->corner = CORNER_BOTTOM_RIGHT;
111                                                 else
112                                                         frozen_pointer->corner = CORNER_TOP_RIGHT;
113                                         } else {
114                                                 if (pos.y > mid_y)
115                                                         frozen_pointer->corner = CORNER_BOTTOM_LEFT;
116                                                 else
117                                                         frozen_pointer->corner = CORNER_TOP_LEFT;
118                                         }
119                                 }
120                                 if (frozen_pointer->is_tiled) {
121                                         if (pac == ACTION_RESIZE_SIDE) {
122                                                 switch (frozen_pointer->side) {
123                                                         case SIDE_TOP:
124                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
125                                                                 break;
126                                                         case SIDE_RIGHT:
127                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
128                                                                 break;
129                                                         case SIDE_BOTTOM:
130                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
131                                                                 break;
132                                                         case SIDE_LEFT:
133                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
134                                                                 break;
135                                                 }
136                                         } else if (pac == ACTION_RESIZE_CORNER) {
137                                                 switch (frozen_pointer->corner) {
138                                                         case CORNER_TOP_LEFT:
139                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
140                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
141                                                                 break;
142                                                         case CORNER_TOP_RIGHT:
143                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
144                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
145                                                                 break;
146                                                         case CORNER_BOTTOM_RIGHT:
147                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
148                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
149                                                                 break;
150                                                         case CORNER_BOTTOM_LEFT:
151                                                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
152                                                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
153                                                                 break;
154                                                 }
155                                         }
156                                         if (frozen_pointer->horizontal_fence != NULL)
157                                                 frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio;
158                                         if (frozen_pointer->vertical_fence != NULL)
159                                                 frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio;
160                                 }
161                                 break;
162                         case ACTION_NONE:
163                                 break;
164                 }
165         } else {
166                 if (pac == ACTION_FOCUS) {
167                         monitor_t *m = monitor_from_point(pos);
168                         if (m != NULL && m != mon)
169                                 focus_node(m, m->desk, m->desk->focus);
170                 }
171                 frozen_pointer->action = ACTION_NONE;
172         }
173 }
174
175 void track_pointer(int root_x, int root_y)
176 {
177         if (frozen_pointer->action == ACTION_NONE)
178                 return;
179
180         int delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
181
182         pointer_action_t pac = frozen_pointer->action;
183         monitor_t *m = frozen_pointer->monitor;
184         desktop_t *d = frozen_pointer->desktop;
185         node_t *n = frozen_pointer->node;
186         client_t *c = frozen_pointer->client;
187         xcb_window_t win = frozen_pointer->window;
188         xcb_rectangle_t rect = frozen_pointer->rectangle;
189         node_t *vertical_fence = frozen_pointer->vertical_fence;
190         node_t *horizontal_fence = frozen_pointer->horizontal_fence;
191
192         delta_x = root_x - frozen_pointer->position.x;
193         delta_y = root_y - frozen_pointer->position.y;
194
195         switch (pac) {
196                 case ACTION_MOVE:
197                         if (frozen_pointer->is_tiled) {
198                                 xcb_window_t pwin = XCB_NONE;
199                                 query_pointer(&pwin, NULL);
200                                 if (pwin == win)
201                                         return;
202                                 coordinates_t loc;
203                                 bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
204                                 if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) {
205                                         swap_nodes(m, d, n, m, d, loc.node);
206                                         arrange(m, d);
207                                 } else {
208                                         if (is_managed && loc.monitor == m) {
209                                                 return;
210                                         } else if (!is_managed) {
211                                                 xcb_point_t pt = (xcb_point_t) {root_x, root_y};
212                                                 monitor_t *pmon = monitor_from_point(pt);
213                                                 if (pmon == NULL || pmon == m) {
214                                                         return;
215                                                 } else {
216                                                         loc.monitor = pmon;
217                                                         loc.desktop = pmon->desk;
218                                                 }
219                                         }
220                                         bool focused = (n == mon->desk->focus);
221                                         transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus);
222                                         if (focused)
223                                                 focus_node(loc.monitor, loc.desktop, n);
224                                         frozen_pointer->monitor = loc.monitor;
225                                         frozen_pointer->desktop = loc.desktop;
226                                 }
227                         } else {
228                                 x = rect.x + delta_x;
229                                 y = rect.y + delta_y;
230                                 window_move(win, x, y);
231                                 c->floating_rectangle.x = x;
232                                 c->floating_rectangle.y = y;
233                                 xcb_point_t pt = (xcb_point_t) {root_x, root_y};
234                                 monitor_t *pmon = monitor_from_point(pt);
235                                 if (pmon == NULL || pmon == m)
236                                         return;
237                                 bool focused = (n == mon->desk->focus);
238                                 transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus);
239                                 if (focused)
240                                         focus_node(pmon, pmon->desk, n);
241                                 frozen_pointer->monitor = pmon;
242                                 frozen_pointer->desktop = pmon->desk;
243                         }
244                         break;
245                 case ACTION_RESIZE_SIDE:
246                 case ACTION_RESIZE_CORNER:
247                         if (frozen_pointer->is_tiled) {
248                                 if (vertical_fence != NULL) {
249                                         double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width;
250                                         sr = MAX(0, sr);
251                                         sr = MIN(1, sr);
252                                         vertical_fence->split_ratio = sr;
253                                 }
254                                 if (horizontal_fence != NULL) {
255                                         double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height;
256                                         sr = MAX(0, sr);
257                                         sr = MIN(1, sr);
258                                         horizontal_fence->split_ratio = sr;
259                                 }
260                                 arrange(m, d);
261                         } else {
262                                 if (pac == ACTION_RESIZE_SIDE) {
263                                         switch (frozen_pointer->side) {
264                                                 case SIDE_TOP:
265                                                         x = rect.x;
266                                                         y = rect.y + delta_y;
267                                                         w = rect.width;
268                                                         h = rect.height - delta_y;
269                                                         break;
270                                                 case SIDE_RIGHT:
271                                                         x = rect.x;
272                                                         y = rect.y;
273                                                         w = rect.width + delta_x;
274                                                         h = rect.height;
275                                                         break;
276                                                 case SIDE_BOTTOM:
277                                                         x = rect.x;
278                                                         y = rect.y;
279                                                         w = rect.width;
280                                                         h = rect.height + delta_y;
281                                                         break;
282                                                 case SIDE_LEFT:
283                                                         x = rect.x + delta_x;
284                                                         y = rect.y;
285                                                         w = rect.width - delta_x;
286                                                         h = rect.height;
287                                                         break;
288                                         }
289                                 } else if (pac == ACTION_RESIZE_CORNER) {
290                                         switch (frozen_pointer->corner) {
291                                                 case CORNER_TOP_LEFT:
292                                                         x = rect.x + delta_x;
293                                                         y = rect.y + delta_y;
294                                                         w = rect.width - delta_x;
295                                                         h = rect.height - delta_y;
296                                                         break;
297                                                 case CORNER_TOP_RIGHT:
298                                                         x = rect.x;
299                                                         y = rect.y + delta_y;
300                                                         w = rect.width + delta_x;
301                                                         h = rect.height - delta_y;
302                                                         break;
303                                                 case CORNER_BOTTOM_LEFT:
304                                                         x = rect.x + delta_x;
305                                                         y = rect.y;
306                                                         w = rect.width - delta_x;
307                                                         h = rect.height + delta_y;
308                                                         break;
309                                                 case CORNER_BOTTOM_RIGHT:
310                                                         x = rect.x;
311                                                         y = rect.y;
312                                                         w = rect.width + delta_x;
313                                                         h = rect.height + delta_y;
314                                                         break;
315                                         }
316                                 }
317
318                                 int oldw = w, oldh = h;
319                                 restrain_floating_size(c, &w, &h);
320
321                                 if (c->pseudo_tiled) {
322                                         c->floating_rectangle.width = w;
323                                         c->floating_rectangle.height = h;
324                                         arrange(m, d);
325                                 } else {
326                                         if (oldw == w) {
327                                                 c->floating_rectangle.x = x;
328                                                 c->floating_rectangle.width = w;
329                                         }
330                                         if (oldh == h) {
331                                                 c->floating_rectangle.y = y;
332                                                 c->floating_rectangle.height = h;
333                                         }
334                                         window_move_resize(win, c->floating_rectangle.x,
335                                                                 c->floating_rectangle.y,
336                                                                 c->floating_rectangle.width,
337                                                                 c->floating_rectangle.height);
338                                 }
339                         }
340                         break;
341                 case ACTION_FOCUS:
342                 case ACTION_NONE:
343                         break;
344         }
345 }
346
347 void ungrab_pointer(void)
348 {
349         frozen_pointer->action = ACTION_NONE;
350 }