source: mainline/uspace/srv/hid/display/seat.c@ dbef30f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dbef30f was 9901f267, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Display server needs to override cursor when resizing windows

Although the pointer moves, the window is not resized until button
is released. Therefore we need override the cursor from what it
would be just based on where the pointer is located.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup display
30 * @{
31 */
32/**
33 * @file Display server seat
34 */
35
36#include <adt/list.h>
37#include <errno.h>
38#include <gfx/color.h>
39#include <gfx/render.h>
40#include <stdlib.h>
41#include "client.h"
42#include "cursor.h"
43#include "display.h"
44#include "seat.h"
45#include "window.h"
46
47static errno_t ds_seat_clear_pointer(ds_seat_t *);
48static errno_t ds_seat_draw_pointer(ds_seat_t *);
49
50/** Create seat.
51 *
52 * @param display Parent display
53 * @param rseat Place to store pointer to new seat.
54 * @return EOK on success, ENOMEM if out of memory
55 */
56errno_t ds_seat_create(ds_display_t *display, ds_seat_t **rseat)
57{
58 ds_seat_t *seat;
59
60 seat = calloc(1, sizeof(ds_seat_t));
61 if (seat == NULL)
62 return ENOMEM;
63
64 ds_display_add_seat(display, seat);
65 seat->pntpos.x = 0;
66 seat->pntpos.y = 0;
67
68 seat->client_cursor = display->cursor[dcurs_arrow];
69 seat->wm_cursor = NULL;
70
71 *rseat = seat;
72 return EOK;
73}
74
75/** Destroy seat.
76 *
77 * @param seat Seat
78 */
79void ds_seat_destroy(ds_seat_t *seat)
80{
81 ds_display_remove_seat(seat);
82 free(seat);
83}
84
85/** Set seat focus to a window.
86 *
87 * @param seat Seat
88 * @param wnd Window to focus
89 */
90void ds_seat_set_focus(ds_seat_t *seat, ds_window_t *wnd)
91{
92 if (seat->focus != NULL)
93 ds_window_post_unfocus_event(seat->focus);
94
95 seat->focus = wnd;
96
97 if (wnd != NULL) {
98 ds_window_post_focus_event(wnd);
99 ds_window_bring_to_top(wnd);
100 }
101}
102
103/** Evacuate focus from window.
104 *
105 * If seat's focus is @a wnd, it will be set to a different window.
106 *
107 * @param seat Seat
108 * @param wnd Window to evacuate focus from
109 */
110void ds_seat_evac_focus(ds_seat_t *seat, ds_window_t *wnd)
111{
112 ds_window_t *nwnd;
113
114 if (seat->focus == wnd) {
115 nwnd = ds_display_next_window(wnd);
116 if (nwnd == NULL)
117 nwnd = ds_display_first_window(wnd->display);
118 if (nwnd == wnd)
119 nwnd = NULL;
120
121 ds_seat_set_focus(seat, nwnd);
122 }
123}
124
125/** Post keyboard event to the seat's focused window.
126 *
127 * @param seat Seat
128 * @param event Event
129 *
130 * @return EOK on success or an error code
131 */
132errno_t ds_seat_post_kbd_event(ds_seat_t *seat, kbd_event_t *event)
133{
134 ds_window_t *dwindow;
135 bool alt_or_shift;
136
137 alt_or_shift = event->mods & (KM_SHIFT | KM_ALT);
138 if (event->type == KEY_PRESS && alt_or_shift && event->key == KC_TAB) {
139 /* On Alt-Tab or Shift-Tab, switch focus to next window */
140 ds_seat_evac_focus(seat, seat->focus);
141 return EOK;
142 }
143
144 dwindow = seat->focus;
145 if (dwindow == NULL)
146 return EOK;
147
148 return ds_window_post_kbd_event(dwindow, event);
149}
150
151/** Get current cursor used by seat.
152 *
153 * @param wmcurs WM curor
154 * @param ccurs Client cursor
155 * @return
156 */
157static ds_cursor_t *ds_seat_compute_cursor(ds_cursor_t *wmcurs, ds_cursor_t *ccurs)
158{
159 if (wmcurs != NULL)
160 return wmcurs;
161
162 return ccurs;
163}
164
165/** Get current cursor used by seat.
166 *
167 * @param seat Seat
168 * @return Current cursor
169 */
170static ds_cursor_t *ds_seat_get_cursor(ds_seat_t *seat)
171{
172 return ds_seat_compute_cursor(seat->wm_cursor, seat->client_cursor);
173}
174
175/** Set client cursor.
176 *
177 * Set cursor selected by client. This may update the actual cursor
178 * if WM is not overriding the cursor.
179 *
180 * @param seat Seat
181 * @param cursor Client cursor
182 */
183static void ds_seat_set_client_cursor(ds_seat_t *seat, ds_cursor_t *cursor)
184{
185 ds_cursor_t *old_cursor;
186 ds_cursor_t *new_cursor;
187
188 old_cursor = ds_seat_get_cursor(seat);
189 new_cursor = ds_seat_compute_cursor(seat->wm_cursor, cursor);
190
191 if (new_cursor != old_cursor)
192 ds_seat_clear_pointer(seat);
193
194 seat->client_cursor = cursor;
195
196 if (new_cursor != old_cursor)
197 ds_seat_draw_pointer(seat);
198}
199
200/** Set WM cursor.
201 *
202 * Set cursor override for window management.
203 *
204 * @param seat Seat
205 * @param cursor WM cursor override or @c NULL not to override the cursor
206 */
207void ds_seat_set_wm_cursor(ds_seat_t *seat, ds_cursor_t *cursor)
208{
209 ds_cursor_t *old_cursor;
210 ds_cursor_t *new_cursor;
211
212 old_cursor = ds_seat_get_cursor(seat);
213 new_cursor = ds_seat_compute_cursor(cursor, seat->client_cursor);
214
215 if (new_cursor != old_cursor)
216 ds_seat_clear_pointer(seat);
217
218 seat->wm_cursor = cursor;
219
220 if (new_cursor != old_cursor)
221 ds_seat_draw_pointer(seat);
222}
223
224/** Draw seat pointer
225 *
226 * @param seat Seat
227 *
228 * @return EOK on success or an error code
229 */
230static errno_t ds_seat_draw_pointer(ds_seat_t *seat)
231{
232 ds_cursor_t *cursor;
233
234 cursor = ds_seat_get_cursor(seat);
235 return ds_cursor_paint(cursor, &seat->pntpos);
236}
237
238/** Clear seat pointer
239 *
240 * @param seat Seat
241 *
242 * @return EOK on success or an error code
243 */
244static errno_t ds_seat_clear_pointer(ds_seat_t *seat)
245{
246 gfx_rect_t rect;
247 ds_cursor_t *cursor;
248
249 cursor = ds_seat_get_cursor(seat);
250
251 /* Get rectangle covered by cursor */
252 ds_cursor_get_rect(cursor, &seat->pntpos, &rect);
253
254 /* Repaint it */
255 return ds_display_paint(seat->display, &rect);
256}
257
258/** Post pointing device event to the seat
259 *
260 * Update pointer position and generate position event.
261 *
262 * @param seat Seat
263 * @param event Event
264 *
265 * @return EOK on success or an error code
266 */
267errno_t ds_seat_post_ptd_event(ds_seat_t *seat, ptd_event_t *event)
268{
269 ds_display_t *disp = seat->display;
270 gfx_coord2_t npos;
271 ds_window_t *wnd;
272 pos_event_t pevent;
273 errno_t rc;
274
275 wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
276
277 /* Focus window on button press */
278 if (event->type == PTD_PRESS && event->btn_num == 1) {
279 if (wnd != NULL) {
280 ds_seat_set_focus(seat, wnd);
281 }
282 }
283
284 if (event->type == PTD_PRESS || event->type == PTD_RELEASE) {
285 pevent.pos_id = 0;
286 pevent.type = (event->type == PTD_PRESS) ?
287 POS_PRESS : POS_RELEASE;
288 pevent.btn_num = event->btn_num;
289 pevent.hpos = seat->pntpos.x;
290 pevent.vpos = seat->pntpos.y;
291
292 rc = ds_seat_post_pos_event(seat, &pevent);
293 if (rc != EOK)
294 return rc;
295 }
296
297 if (event->type == PTD_MOVE) {
298 gfx_coord2_add(&seat->pntpos, &event->dmove, &npos);
299 gfx_coord2_clip(&npos, &disp->rect, &npos);
300
301 (void) ds_seat_clear_pointer(seat);
302 seat->pntpos = npos;
303
304 pevent.pos_id = 0;
305 pevent.type = POS_UPDATE;
306 pevent.btn_num = 0;
307 pevent.hpos = seat->pntpos.x;
308 pevent.vpos = seat->pntpos.y;
309
310 rc = ds_seat_post_pos_event(seat, &pevent);
311 if (rc != EOK)
312 return rc;
313
314 (void) ds_seat_draw_pointer(seat);
315 }
316
317 if (event->type == PTD_ABS_MOVE) {
318 /*
319 * Project input device area onto display area. Technically
320 * we probably want to project onto the area of a particular
321 * display device. The tricky part is figuring out which
322 * display device the input device is associated with.
323 */
324 gfx_coord2_project(&event->apos, &event->abounds,
325 &disp->rect, &npos);
326
327 gfx_coord2_clip(&npos, &disp->rect, &npos);
328
329 (void) ds_seat_clear_pointer(seat);
330 seat->pntpos = npos;
331
332 pevent.pos_id = 0;
333 pevent.type = POS_UPDATE;
334 pevent.btn_num = 0;
335 pevent.hpos = seat->pntpos.x;
336 pevent.vpos = seat->pntpos.y;
337
338 rc = ds_seat_post_pos_event(seat, &pevent);
339 if (rc != EOK)
340 return rc;
341
342 (void) ds_seat_draw_pointer(seat);
343 }
344
345 return EOK;
346}
347
348/** Post position event to seat.
349 *
350 * Deliver event to relevant windows.
351 *
352 * @param seat Seat
353 * @param event Position event
354 */
355errno_t ds_seat_post_pos_event(ds_seat_t *seat, pos_event_t *event)
356{
357 ds_window_t *wnd;
358 errno_t rc;
359
360 wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
361 if (wnd != NULL) {
362 /* Moving over a window */
363 ds_seat_set_client_cursor(seat, wnd->cursor);
364
365 rc = ds_window_post_pos_event(wnd, event);
366 if (rc != EOK)
367 return rc;
368 } else {
369 /* Not over a window */
370 ds_seat_set_client_cursor(seat, seat->display->cursor[dcurs_arrow]);
371 }
372
373 if (seat->focus != wnd) {
374 rc = ds_window_post_pos_event(seat->focus, event);
375 if (rc != EOK)
376 return rc;
377 }
378
379 return EOK;
380}
381
382/** @}
383 */
Note: See TracBrowser for help on using the repository browser.