]> git.lizzy.rs Git - bspwm.git/blob - pointer.c
Add example bindings for history navigation
[bspwm.git] / pointer.c
1 #include "bspwm.h"
2 #include "query.h"
3 #include "settings.h"
4 #include "stack.h"
5 #include "tree.h"
6 #include "window.h"
7 #include "pointer.h"
8
9 void grab_pointer(pointer_action_t pac)
10 {
11     PRINTF("grab pointer %u\n", pac);
12
13     xcb_window_t win = XCB_NONE;
14     xcb_point_t pos;
15
16     query_pointer(&win, &pos);
17
18     coordinates_t loc;
19     if (locate_window(win, &loc)) {
20         client_t *c = NULL;
21         frozen_pointer->position = pos;
22         frozen_pointer->action = pac;
23         c = loc.node->client;
24         frozen_pointer->monitor = loc.monitor;
25         frozen_pointer->desktop = loc.desktop;
26         frozen_pointer->node = loc.node;
27         frozen_pointer->client = c;
28         frozen_pointer->window = c->window;
29         frozen_pointer->horizontal_fence = NULL;
30         frozen_pointer->vertical_fence = NULL;
31
32         switch (pac)  {
33             case ACTION_FOCUS:
34                 if (loc.node != mon->desk->focus) {
35                     bool backup = pointer_follows_monitor;
36                     pointer_follows_monitor = false;
37                     focus_node(loc.monitor, loc.desktop, loc.node);
38                     pointer_follows_monitor = backup;
39                 } else if (focus_follows_pointer) {
40                     stack(loc.node);
41                 }
42                 break;
43             case ACTION_MOVE:
44             case ACTION_RESIZE_SIDE:
45             case ACTION_RESIZE_CORNER:
46                 if (is_tiled(c)) {
47                     frozen_pointer->rectangle = c->tiled_rectangle;
48                     frozen_pointer->is_tiled = true;
49                 } else if (is_floating(c)) {
50                     frozen_pointer->rectangle = c->floating_rectangle;
51                     frozen_pointer->is_tiled = false;
52                 } else {
53                     frozen_pointer->action = ACTION_NONE;
54                     return;
55                 }
56                 if (pac == ACTION_RESIZE_SIDE) {
57                     float W = frozen_pointer->rectangle.width;
58                     float H = frozen_pointer->rectangle.height;
59                     float ratio = W / H;
60                     float x = pos.x - frozen_pointer->rectangle.x;
61                     float y = pos.y - frozen_pointer->rectangle.y;
62                     float diag_a = ratio * y;
63                     float diag_b = W - diag_a;
64                     if (x < diag_a) {
65                         if (x < diag_b)
66                             frozen_pointer->side = SIDE_LEFT;
67                         else
68                             frozen_pointer->side = SIDE_BOTTOM;
69                     } else {
70                         if (x < diag_b)
71                             frozen_pointer->side = SIDE_TOP;
72                         else
73                             frozen_pointer->side = SIDE_RIGHT;
74                     }
75                 } else if (pac == ACTION_RESIZE_CORNER) {
76                     int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2);
77                     int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2);
78                     if (pos.x > mid_x) {
79                         if (pos.y > mid_y)
80                             frozen_pointer->corner = CORNER_BOTTOM_RIGHT;
81                         else
82                             frozen_pointer->corner = CORNER_TOP_RIGHT;
83                     } else {
84                         if (pos.y > mid_y)
85                             frozen_pointer->corner = CORNER_BOTTOM_LEFT;
86                         else
87                             frozen_pointer->corner = CORNER_TOP_LEFT;
88                     }
89                 }
90                 if (frozen_pointer->is_tiled) {
91                     if (pac == ACTION_RESIZE_SIDE) {
92                         switch (frozen_pointer->side) {
93                             case SIDE_TOP:
94                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
95                                 break;
96                             case SIDE_RIGHT:
97                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
98                                 break;
99                             case SIDE_BOTTOM:
100                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
101                                 break;
102                             case SIDE_LEFT:
103                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
104                                 break;
105                         }
106                     } else if (pac == ACTION_RESIZE_CORNER) {
107                         switch (frozen_pointer->corner) {
108                             case CORNER_TOP_LEFT:
109                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
110                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
111                                 break;
112                             case CORNER_TOP_RIGHT:
113                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
114                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
115                                 break;
116                             case CORNER_BOTTOM_RIGHT:
117                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
118                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
119                                 break;
120                             case CORNER_BOTTOM_LEFT:
121                                 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
122                                 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
123                                 break;
124                         }
125                     }
126                     if (frozen_pointer->horizontal_fence != NULL)
127                         frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio;
128                     if (frozen_pointer->vertical_fence != NULL)
129                         frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio;
130                 }
131                 break;
132             case ACTION_NONE:
133                 break;
134         }
135     } else {
136         if (pac == ACTION_FOCUS) {
137             monitor_t *m = monitor_from_point(pos);
138             if (m != NULL && m != mon)
139                 focus_node(m, m->desk, m->desk->focus);
140         }
141         frozen_pointer->action = ACTION_NONE;
142     }
143 }
144
145 void track_pointer(int root_x, int root_y)
146 {
147     if (frozen_pointer->action == ACTION_NONE)
148         return;
149
150     int16_t delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
151     uint16_t width, height;
152
153     pointer_action_t pac = frozen_pointer->action;
154     monitor_t *m = frozen_pointer->monitor;
155     desktop_t *d = frozen_pointer->desktop;
156     node_t *n = frozen_pointer->node;
157     client_t *c = frozen_pointer->client;
158     xcb_window_t win = frozen_pointer->window;
159     xcb_rectangle_t rect = frozen_pointer->rectangle;
160     node_t *vertical_fence = frozen_pointer->vertical_fence;
161     node_t *horizontal_fence = frozen_pointer->horizontal_fence;
162
163     delta_x = root_x - frozen_pointer->position.x;
164     delta_y = root_y - frozen_pointer->position.y;
165
166     switch (pac) {
167         case ACTION_MOVE:
168             if (frozen_pointer->is_tiled) {
169                 xcb_window_t pwin = XCB_NONE;
170                 query_pointer(&pwin, NULL);
171                 if (pwin == win)
172                     return;
173                 coordinates_t loc;
174                 bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
175                 if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) {
176                     swap_nodes(m, d, n, m, d, loc.node);
177                     arrange(m, d);
178                 } else {
179                     if (is_managed && loc.monitor == m) {
180                         return;
181                     } else if (!is_managed) {
182                         xcb_point_t pt = (xcb_point_t) {root_x, root_y};
183                         monitor_t *pmon = monitor_from_point(pt);
184                         if (pmon == NULL || pmon == m) {
185                             return;
186                         } else {
187                             loc.monitor = pmon;
188                             loc.desktop = pmon->desk;
189                         }
190                     }
191                     bool focused = (n == mon->desk->focus);
192                     transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus);
193                     if (focused)
194                         focus_node(loc.monitor, loc.desktop, n);
195                     frozen_pointer->monitor = loc.monitor;
196                     frozen_pointer->desktop = loc.desktop;
197                 }
198             } else {
199                 x = rect.x + delta_x;
200                 y = rect.y + delta_y;
201                 window_move(win, x, y);
202                 c->floating_rectangle.x = x;
203                 c->floating_rectangle.y = y;
204                 xcb_point_t pt = (xcb_point_t) {root_x, root_y};
205                 monitor_t *pmon = monitor_from_point(pt);
206                 if (pmon == NULL || pmon == m)
207                     return;
208                 bool focused = (n == mon->desk->focus);
209                 transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus);
210                 if (focused)
211                     focus_node(pmon, pmon->desk, n);
212                 frozen_pointer->monitor = pmon;
213                 frozen_pointer->desktop = pmon->desk;
214             }
215             break;
216         case ACTION_RESIZE_SIDE:
217         case ACTION_RESIZE_CORNER:
218             if (frozen_pointer->is_tiled) {
219                 if (vertical_fence != NULL) {
220                     double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width;
221                     sr = MAX(0, sr);
222                     sr = MIN(1, sr);
223                     vertical_fence->split_ratio = sr;
224                 }
225                 if (horizontal_fence != NULL) {
226                     double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height;
227                     sr = MAX(0, sr);
228                     sr = MIN(1, sr);
229                     horizontal_fence->split_ratio = sr;
230                 }
231                 arrange(mon, mon->desk);
232             } else {
233                 if (pac == ACTION_RESIZE_SIDE) {
234                     switch (frozen_pointer->side) {
235                         case SIDE_TOP:
236                             x = rect.x;
237                             y = rect.y + delta_y;
238                             w = rect.width;
239                             h = rect.height - delta_y;
240                             break;
241                         case SIDE_RIGHT:
242                             x = rect.x;
243                             y = rect.y;
244                             w = rect.width + delta_x;
245                             h = rect.height;
246                             break;
247                         case SIDE_BOTTOM:
248                             x = rect.x;
249                             y = rect.y;
250                             w = rect.width;
251                             h = rect.height + delta_y;
252                             break;
253                         case SIDE_LEFT:
254                             x = rect.x + delta_x;
255                             y = rect.y;
256                             w = rect.width - delta_x;
257                             h = rect.height;
258                             break;
259                     }
260                     width = MAX(1, w);
261                     height = MAX(1, h);
262                     window_move_resize(win, x, y, width, height);
263                     c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
264                     window_draw_border(n, d->focus == n, mon == m);
265                 } else if (pac == ACTION_RESIZE_CORNER) {
266                     switch (frozen_pointer->corner) {
267                         case CORNER_TOP_LEFT:
268                             x = rect.x + delta_x;
269                             y = rect.y + delta_y;
270                             w = rect.width - delta_x;
271                             h = rect.height - delta_y;
272                             break;
273                         case CORNER_TOP_RIGHT:
274                             x = rect.x;
275                             y = rect.y + delta_y;
276                             w = rect.width + delta_x;
277                             h = rect.height - delta_y;
278                             break;
279                         case CORNER_BOTTOM_LEFT:
280                             x = rect.x + delta_x;
281                             y = rect.y;
282                             w = rect.width - delta_x;
283                             h = rect.height + delta_y;
284                             break;
285                         case CORNER_BOTTOM_RIGHT:
286                             x = rect.x;
287                             y = rect.y;
288                             w = rect.width + delta_x;
289                             h = rect.height + delta_y;
290                             break;
291                     }
292                     width = MAX(1, w);
293                     height = MAX(1, h);
294                     window_move_resize(win, x, y, width, height);
295                     c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
296                     window_draw_border(n, d->focus == n, mon == m);
297                 }
298             }
299             break;
300         case ACTION_FOCUS:
301         case ACTION_NONE:
302             break;
303     }
304 }