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

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

Closing windows

  • Property mode set to 100644
File size: 8.1 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 "display.h"
43#include "seat.h"
44#include "window.h"
45
46/** Create seat.
47 *
48 * @param display Parent display
49 * @param rseat Place to store pointer to new seat.
50 * @return EOK on success, ENOMEM if out of memory
51 */
52errno_t ds_seat_create(ds_display_t *display, ds_seat_t **rseat)
53{
54 ds_seat_t *seat;
55
56 seat = calloc(1, sizeof(ds_seat_t));
57 if (seat == NULL)
58 return ENOMEM;
59
60 ds_display_add_seat(display, seat);
61 seat->pntpos.x = 0;
62 seat->pntpos.y = 0;
63
64 *rseat = seat;
65 return EOK;
66}
67
68/** Destroy seat.
69 *
70 * @param seat Seat
71 */
72void ds_seat_destroy(ds_seat_t *seat)
73{
74 ds_display_remove_seat(seat);
75 free(seat);
76}
77
78/** Set seat focus to a window.
79 *
80 * @param seat Seat
81 * @param wnd Window to focus
82 */
83void ds_seat_set_focus(ds_seat_t *seat, ds_window_t *wnd)
84{
85 if (seat->focus != NULL)
86 ds_window_post_unfocus_event(seat->focus);
87
88 seat->focus = wnd;
89
90 if (wnd != NULL)
91 ds_window_post_focus_event(wnd);
92}
93
94/** Evacuate focus from window.
95 *
96 * If seat's focus is @a wnd, it will be set to a different window.
97 *
98 * @param seat Seat
99 * @param wnd Window to evacuate focus from
100 */
101void ds_seat_evac_focus(ds_seat_t *seat, ds_window_t *wnd)
102{
103 ds_window_t *nwnd;
104
105 if (seat->focus == wnd) {
106 nwnd = ds_display_next_window(wnd);
107 if (nwnd == NULL)
108 nwnd = ds_display_first_window(wnd->display);
109 if (nwnd == wnd)
110 nwnd = NULL;
111
112 ds_seat_set_focus(seat, nwnd);
113 }
114}
115
116/** Post keyboard event to the seat's focused window.
117 *
118 * @param seat Seat
119 * @param event Event
120 *
121 * @return EOK on success or an error code
122 */
123errno_t ds_seat_post_kbd_event(ds_seat_t *seat, kbd_event_t *event)
124{
125 ds_window_t *dwindow;
126 bool alt_or_shift;
127
128 alt_or_shift = event->mods & (KM_SHIFT | KM_ALT);
129 if (event->type == KEY_PRESS && alt_or_shift && event->key == KC_TAB) {
130 /* On Alt-Tab or Shift-Tab, switch focus to next window */
131 ds_seat_evac_focus(seat, seat->focus);
132 return EOK;
133 }
134
135 dwindow = seat->focus;
136 if (dwindow == NULL)
137 return EOK;
138
139 return ds_window_post_kbd_event(dwindow, event);
140}
141
142/** Draw cross at seat pointer position.
143 *
144 * @param seat Seat
145 * @param len Cross length
146 * @param w Cross extra width
147 * @param color Color
148 *
149 * @return EOK on success or an error code
150 */
151static errno_t ds_seat_draw_cross(ds_seat_t *seat, gfx_coord_t len,
152 gfx_coord_t w, gfx_color_t *color)
153{
154 gfx_context_t *gc;
155 gfx_rect_t rect, r0;
156 errno_t rc;
157
158 gc = ds_display_get_gc(seat->display);
159 if (gc == NULL)
160 return EOK;
161
162 rc = gfx_set_color(gc, color);
163 if (rc != EOK)
164 goto error;
165
166 r0.p0.x = -len;
167 r0.p0.y = -w;
168 r0.p1.x = +len + 1;
169 r0.p1.y = +w + 1;
170 gfx_rect_translate(&seat->pntpos, &r0, &rect);
171
172 rc = gfx_fill_rect(gc, &rect);
173 if (rc != EOK)
174 goto error;
175
176 r0.p0.x = -w;
177 r0.p0.y = -len;
178 r0.p1.x = +w + 1;
179 r0.p1.y = +len + 1;
180 gfx_rect_translate(&seat->pntpos, &r0, &rect);
181
182 rc = gfx_fill_rect(gc, &rect);
183 if (rc != EOK)
184 goto error;
185
186 return EOK;
187error:
188 return rc;
189}
190
191/** Draw seat pointer
192 *
193 * @param seat Seat
194 *
195 * @return EOK on success or an error code
196 */
197static errno_t ds_seat_draw_pointer(ds_seat_t *seat)
198{
199 errno_t rc;
200 gfx_color_t *black = NULL;
201 gfx_color_t *white;
202
203 rc = gfx_color_new_rgb_i16(0, 0, 0, &black);
204 if (rc != EOK)
205 goto error;
206
207 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &white);
208 if (rc != EOK)
209 goto error;
210
211 rc = ds_seat_draw_cross(seat, 8, 1, black);
212 if (rc != EOK)
213 goto error;
214
215 rc = ds_seat_draw_cross(seat, 8, 0, white);
216 if (rc != EOK)
217 goto error;
218
219 gfx_color_delete(black);
220 gfx_color_delete(white);
221
222 return EOK;
223error:
224 if (black != NULL)
225 gfx_color_delete(black);
226 if (white != NULL)
227 gfx_color_delete(white);
228 return rc;
229}
230
231/** Clear seat pointer
232 *
233 * @param seat Seat
234 *
235 * @return EOK on success or an error code
236 */
237static errno_t ds_seat_clear_pointer(ds_seat_t *seat)
238{
239 gfx_rect_t rect;
240
241 rect.p0.x = seat->pntpos.x - 8;
242 rect.p0.y = seat->pntpos.y - 8;
243 rect.p1.x = seat->pntpos.x + 8 + 1;
244 rect.p1.y = seat->pntpos.y + 8 + 1;
245
246 return ds_display_paint(seat->display, &rect);
247}
248
249/** Post pointing device event to the seat
250 *
251 * Update pointer position and generate position event.
252 *
253 * @param seat Seat
254 * @param event Event
255 *
256 * @return EOK on success or an error code
257 */
258#include <stdio.h>
259errno_t ds_seat_post_ptd_event(ds_seat_t *seat, ptd_event_t *event)
260{
261 ds_display_t *disp = seat->display;
262 gfx_coord2_t npos;
263 ds_window_t *wnd;
264 pos_event_t pevent;
265 errno_t rc;
266
267 wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
268
269 /* Focus window on button press */
270 if (event->type == PTD_PRESS && event->btn_num == 1) {
271 if (wnd != NULL) {
272 ds_seat_set_focus(seat, wnd);
273 }
274 }
275
276 if (event->type == PTD_PRESS || event->type == PTD_RELEASE) {
277 pevent.pos_id = 0;
278 pevent.type = (event->type == PTD_PRESS) ?
279 POS_PRESS : POS_RELEASE;
280 pevent.btn_num = event->btn_num;
281 pevent.hpos = seat->pntpos.x;
282 pevent.vpos = seat->pntpos.y;
283
284 rc = ds_seat_post_pos_event(seat, &pevent);
285 if (rc != EOK)
286 return rc;
287 }
288
289 if (event->type == PTD_MOVE) {
290 gfx_coord2_add(&seat->pntpos, &event->dmove, &npos);
291 gfx_coord2_clip(&npos, &disp->rect, &npos);
292
293 (void) ds_seat_clear_pointer(seat);
294 seat->pntpos = npos;
295
296 pevent.pos_id = 0;
297 pevent.type = POS_UPDATE;
298 pevent.btn_num = 0;
299 pevent.hpos = seat->pntpos.x;
300 pevent.vpos = seat->pntpos.y;
301
302 rc = ds_seat_post_pos_event(seat, &pevent);
303 if (rc != EOK)
304 return rc;
305
306 (void) ds_seat_draw_pointer(seat);
307 }
308
309 if (event->type == PTD_ABS_MOVE) {
310 /*
311 * Project input device area onto display area. Technically
312 * we probably want to project onto the area of a particular
313 * display device. The tricky part is figuring out which
314 * display device the input device is associated with.
315 */
316 gfx_coord2_project(&event->apos, &event->abounds,
317 &disp->rect, &npos);
318
319 gfx_coord2_clip(&npos, &disp->rect, &npos);
320
321 (void) ds_seat_clear_pointer(seat);
322 seat->pntpos = npos;
323
324 pevent.pos_id = 0;
325 pevent.type = POS_UPDATE;
326 pevent.btn_num = 0;
327 pevent.hpos = seat->pntpos.x;
328 pevent.vpos = seat->pntpos.y;
329
330 rc = ds_seat_post_pos_event(seat, &pevent);
331 if (rc != EOK)
332 return rc;
333
334 (void) ds_seat_draw_pointer(seat);
335 }
336
337 return EOK;
338}
339
340/** Post position event to seat.
341 *
342 * Deliver event to relevant windows.
343 *
344 * @param seat Seat
345 * @param event Position event
346 */
347errno_t ds_seat_post_pos_event(ds_seat_t *seat, pos_event_t *event)
348{
349 ds_window_t *wnd;
350 errno_t rc;
351
352 wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
353 if (wnd != NULL) {
354 rc = ds_window_post_pos_event(wnd, event);
355 if (rc != EOK)
356 return rc;
357 }
358
359 if (seat->focus != wnd) {
360 rc = ds_window_post_pos_event(seat->focus, event);
361 if (rc != EOK)
362 return rc;
363 }
364
365 return EOK;
366}
367
368/** @}
369 */
Note: See TracBrowser for help on using the repository browser.