source: mainline/uspace/srv/hid/display/display.c@ 978c9bc5

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

Pointer needs to be drawn as part of ds_display_paint

Everything needs to be painted from ds_display_paint. The pointers were
painted in an immediate fashion when they changed. Any window update
would wipe them.

  • Property mode set to 100644
File size: 12.7 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 display
34 */
35
36#include <errno.h>
37#include <gfx/context.h>
38#include <gfx/render.h>
39#include <io/log.h>
40#include <stdlib.h>
41#include "client.h"
42#include "cursimg.h"
43#include "cursor.h"
44#include "seat.h"
45#include "window.h"
46#include "display.h"
47
48/** Create display.
49 *
50 * @param gc Graphics context for displaying output
51 * @param rdisp Place to store pointer to new display.
52 * @return EOK on success, ENOMEM if out of memory
53 */
54errno_t ds_display_create(gfx_context_t *gc, ds_display_t **rdisp)
55{
56 ds_display_t *disp;
57 ds_cursor_t *cursor;
58 int i;
59 errno_t rc;
60
61 disp = calloc(1, sizeof(ds_display_t));
62 if (disp == NULL)
63 return ENOMEM;
64
65 rc = gfx_color_new_rgb_i16(0x8000, 0xc800, 0xffff, &disp->bg_color);
66 if (rc != EOK) {
67 free(disp);
68 return ENOMEM;
69 }
70
71 list_initialize(&disp->cursors);
72
73 for (i = 0; i < dcurs_limit; i++) {
74 rc = ds_cursor_create(disp, &ds_cursimg[i].rect,
75 ds_cursimg[i].image, &cursor);
76 if (rc != EOK)
77 goto error;
78
79 disp->cursor[i] = cursor;
80 }
81
82 fibril_mutex_initialize(&disp->lock);
83 list_initialize(&disp->clients);
84 disp->next_wnd_id = 1;
85 list_initialize(&disp->ddevs);
86 list_initialize(&disp->seats);
87 list_initialize(&disp->windows);
88 *rdisp = disp;
89 return EOK;
90error:
91 ds_display_destroy(disp);
92 return rc;
93}
94
95/** Destroy display.
96 *
97 * @param disp Display
98 */
99void ds_display_destroy(ds_display_t *disp)
100{
101 assert(list_empty(&disp->clients));
102 assert(list_empty(&disp->seats));
103 /* XXX destroy cursors */
104 gfx_color_delete(disp->bg_color);
105 free(disp);
106}
107
108/** Lock display.
109 *
110 * This should be called in any thread that wishes to access the display
111 * or its child objects (e.g. windows).
112 *
113 * @param disp Display
114 */
115void ds_display_lock(ds_display_t *disp)
116{
117 fibril_mutex_lock(&disp->lock);
118}
119
120/** Unlock display.
121 *
122 * @param disp Display
123 */
124void ds_display_unlock(ds_display_t *disp)
125{
126 fibril_mutex_unlock(&disp->lock);
127}
128
129/** Get display information.
130 *
131 * @param disp Display
132 */
133void ds_display_get_info(ds_display_t *disp, display_info_t *info)
134{
135 info->rect = disp->rect;
136}
137
138/** Add client to display.
139 *
140 * @param disp Display
141 * @param client Client
142 */
143void ds_display_add_client(ds_display_t *disp, ds_client_t *client)
144{
145 assert(client->display == NULL);
146 assert(!link_used(&client->lclients));
147
148 client->display = disp;
149 list_append(&client->lclients, &disp->clients);
150}
151
152/** Remove client from display.
153 *
154 * @param client Client
155 */
156void ds_display_remove_client(ds_client_t *client)
157{
158 list_remove(&client->lclients);
159 client->display = NULL;
160}
161
162/** Get first client in display.
163 *
164 * @param disp Display
165 * @return First client or @c NULL if there is none
166 */
167ds_client_t *ds_display_first_client(ds_display_t *disp)
168{
169 link_t *link = list_first(&disp->clients);
170
171 if (link == NULL)
172 return NULL;
173
174 return list_get_instance(link, ds_client_t, lclients);
175}
176
177/** Get next client in display.
178 *
179 * @param client Current client
180 * @return Next client or @c NULL if there is none
181 */
182ds_client_t *ds_display_next_client(ds_client_t *client)
183{
184 link_t *link = list_next(&client->lclients, &client->display->clients);
185
186 if (link == NULL)
187 return NULL;
188
189 return list_get_instance(link, ds_client_t, lclients);
190}
191
192/** Find window in all clients by ID.
193 *
194 * XXX This is just a hack needed to match GC connection to a window,
195 * as we don't have a good safe way to pass the GC endpoint to our client
196 * on demand.
197 *
198 * @param display Display
199 * @param id Window ID
200 */
201#include <stdio.h>
202ds_window_t *ds_display_find_window(ds_display_t *display, ds_wnd_id_t id)
203{
204 ds_client_t *client;
205 ds_window_t *wnd;
206
207 printf("ds_display_find_window: id=0x%x\n", (unsigned) id);
208
209 client = ds_display_first_client(display);
210 while (client != NULL) {
211 printf("ds_display_find_window: client=%p\n", client);
212 wnd = ds_client_find_window(client, id);
213 if (wnd != NULL) {
214 printf("ds_display_find_window: found wnd=%p id=0x%x\n",
215 wnd, (unsigned) wnd->id);
216 return wnd;
217 }
218 client = ds_display_next_client(client);
219 }
220
221 printf("ds_display_find_window: not found\n");
222 return NULL;
223}
224
225/** Find window by display position.
226 *
227 * @param display Display
228 * @param pos Display position
229 */
230ds_window_t *ds_display_window_by_pos(ds_display_t *display, gfx_coord2_t *pos)
231{
232 ds_window_t *wnd;
233 gfx_rect_t drect;
234
235 wnd = ds_display_first_window(display);
236 while (wnd != NULL) {
237 /* Window bounding rectangle on display */
238 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
239
240 if (gfx_pix_inside_rect(pos, &drect))
241 return wnd;
242
243 wnd = ds_display_next_window(wnd);
244 }
245
246 return NULL;
247}
248
249/** Add window to display.
250 *
251 * @param display Display
252 * @param wnd Window
253 */
254void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
255{
256 assert(wnd->display == NULL);
257 assert(!link_used(&wnd->ldwindows));
258
259 wnd->display = display;
260 list_prepend(&wnd->ldwindows, &display->windows);
261}
262
263/** Remove window from display.
264 *
265 * @param wnd Window
266 */
267void ds_display_remove_window(ds_window_t *wnd)
268{
269 list_remove(&wnd->ldwindows);
270 wnd->display = NULL;
271}
272
273/** Get first window in display.
274 *
275 * @param display Display
276 * @return First window or @c NULL if there is none
277 */
278ds_window_t *ds_display_first_window(ds_display_t *display)
279{
280 link_t *link = list_first(&display->windows);
281
282 if (link == NULL)
283 return NULL;
284
285 return list_get_instance(link, ds_window_t, ldwindows);
286}
287
288/** Get last window in display.
289 *
290 * @param display Display
291 * @return Last window or @c NULL if there is none
292 */
293ds_window_t *ds_display_last_window(ds_display_t *display)
294{
295 link_t *link = list_last(&display->windows);
296
297 if (link == NULL)
298 return NULL;
299
300 return list_get_instance(link, ds_window_t, ldwindows);
301}
302
303/** Get next window in client.
304 *
305 * @param wnd Current window
306 * @return Next window or @c NULL if there is none
307 */
308ds_window_t *ds_display_next_window(ds_window_t *wnd)
309{
310 link_t *link = list_next(&wnd->ldwindows, &wnd->display->windows);
311
312 if (link == NULL)
313 return NULL;
314
315 return list_get_instance(link, ds_window_t, ldwindows);
316}
317
318/** Get previous window in client.
319 *
320 * @param wnd Current window
321 * @return Previous window or @c NULL if there is none
322 */
323ds_window_t *ds_display_prev_window(ds_window_t *wnd)
324{
325 link_t *link = list_prev(&wnd->ldwindows, &wnd->display->windows);
326
327 if (link == NULL)
328 return NULL;
329
330 return list_get_instance(link, ds_window_t, ldwindows);
331}
332
333/** Post keyboard event to a display.
334 *
335 * The event is routed to the correct window by first determining the
336 * seat the keyboard device belongs to and then the event is sent to the
337 * window focused by that seat.
338 *
339 * @param display Display
340 * @param event Event
341 */
342errno_t ds_display_post_kbd_event(ds_display_t *display, kbd_event_t *event)
343{
344 ds_seat_t *seat;
345
346 // TODO Determine which seat the event belongs to
347 seat = ds_display_first_seat(display);
348 if (seat == NULL)
349 return EOK;
350
351 return ds_seat_post_kbd_event(seat, event);
352}
353
354/** Post position event to a display.
355 *
356 * @param display Display
357 * @param event Event
358 */
359errno_t ds_display_post_ptd_event(ds_display_t *display, ptd_event_t *event)
360{
361 ds_seat_t *seat;
362
363 // TODO Determine which seat the event belongs to
364 seat = ds_display_first_seat(display);
365 if (seat == NULL)
366 return EOK;
367
368 return ds_seat_post_ptd_event(seat, event);
369}
370
371/** Add seat to display.
372 *
373 * @param disp Display
374 * @param seat Seat
375 */
376void ds_display_add_seat(ds_display_t *disp, ds_seat_t *seat)
377{
378 assert(seat->display == NULL);
379 assert(!link_used(&seat->lseats));
380
381 seat->display = disp;
382 list_append(&seat->lseats, &disp->seats);
383}
384
385/** Remove seat from display.
386 *
387 * @param seat Seat
388 */
389void ds_display_remove_seat(ds_seat_t *seat)
390{
391 list_remove(&seat->lseats);
392 seat->display = NULL;
393}
394
395/** Get first seat in display.
396 *
397 * @param disp Display
398 * @return First seat or @c NULL if there is none
399 */
400ds_seat_t *ds_display_first_seat(ds_display_t *disp)
401{
402 link_t *link = list_first(&disp->seats);
403
404 if (link == NULL)
405 return NULL;
406
407 return list_get_instance(link, ds_seat_t, lseats);
408}
409
410/** Get next seat in display.
411 *
412 * @param seat Current seat
413 * @return Next seat or @c NULL if there is none
414 */
415ds_seat_t *ds_display_next_seat(ds_seat_t *seat)
416{
417 link_t *link = list_next(&seat->lseats, &seat->display->seats);
418
419 if (link == NULL)
420 return NULL;
421
422 return list_get_instance(link, ds_seat_t, lseats);
423}
424
425/** Add display device to display.
426 *
427 * @param disp Display
428 * @param ddev Display device
429 */
430void ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
431{
432 assert(ddev->display == NULL);
433 assert(!link_used(&ddev->lddevs));
434
435 /* Set display dimensions to dimensions of first display device */
436 if (gfx_rect_is_empty(&disp->rect))
437 disp->rect = ddev->info.rect;
438
439 ddev->display = disp;
440 list_append(&ddev->lddevs, &disp->ddevs);
441}
442
443/** Remove display device from display.
444 *
445 * @param ddev Display device
446 */
447void ds_display_remove_ddev(ds_ddev_t *ddev)
448{
449 list_remove(&ddev->lddevs);
450 ddev->display = NULL;
451}
452
453/** Get first display device in display.
454 *
455 * @param disp Display
456 * @return First display device or @c NULL if there is none
457 */
458ds_ddev_t *ds_display_first_ddev(ds_display_t *disp)
459{
460 link_t *link = list_first(&disp->ddevs);
461
462 if (link == NULL)
463 return NULL;
464
465 return list_get_instance(link, ds_ddev_t, lddevs);
466}
467
468/** Get next display device in display.
469 *
470 * @param ddev Current display device
471 * @return Next display device or @c NULL if there is none
472 */
473ds_ddev_t *ds_display_next_ddev(ds_ddev_t *ddev)
474{
475 link_t *link = list_next(&ddev->lddevs, &ddev->display->ddevs);
476
477 if (link == NULL)
478 return NULL;
479
480 return list_get_instance(link, ds_ddev_t, lddevs);
481}
482
483/** Add cursor to display.
484 *
485 * @param display Display
486 * @param cursor Cursor
487 */
488void ds_display_add_cursor(ds_display_t *display, ds_cursor_t *cursor)
489{
490 assert(cursor->display == NULL);
491 assert(!link_used(&cursor->ldisplay));
492
493 cursor->display = display;
494 list_prepend(&cursor->ldisplay, &display->cursors);
495}
496
497/** Remove cursor from display.
498 *
499 * @param cursor Cursor
500 */
501void ds_display_remove_cursor(ds_cursor_t *cursor)
502{
503 list_remove(&cursor->ldisplay);
504 cursor->display = NULL;
505}
506
507// XXX
508gfx_context_t *ds_display_get_gc(ds_display_t *display)
509{
510 ds_ddev_t *ddev;
511
512 ddev = ds_display_first_ddev(display);
513 if (ddev == NULL)
514 return NULL;
515
516 return ddev->gc;
517}
518
519/** Paint display background.
520 *
521 * @param display Display
522 * @param rect Bounding rectangle or @c NULL to repaint entire display
523 */
524errno_t ds_display_paint_bg(ds_display_t *disp, gfx_rect_t *rect)
525{
526 gfx_rect_t crect;
527 gfx_context_t *gc;
528 errno_t rc;
529
530 if (rect != NULL)
531 gfx_rect_clip(&disp->rect, rect, &crect);
532 else
533 crect = disp->rect;
534
535 gc = ds_display_get_gc(disp); // XXX
536 if (gc == NULL)
537 return EOK;
538
539 rc = gfx_set_color(gc, disp->bg_color);
540 if (rc != EOK)
541 return rc;
542
543 return gfx_fill_rect(gc, &crect);
544}
545
546/** Paint display.
547 *
548 * @param display Display
549 * @param rect Bounding rectangle or @c NULL to repaint entire display
550 */
551errno_t ds_display_paint(ds_display_t *disp, gfx_rect_t *rect)
552{
553 errno_t rc;
554 ds_window_t *wnd;
555 ds_seat_t *seat;
556
557 /* Paint background */
558 rc = ds_display_paint_bg(disp, rect);
559 if (rc != EOK)
560 return rc;
561
562 /* Paint windows bottom to top */
563 wnd = ds_display_last_window(disp);
564 while (wnd != NULL) {
565 rc = ds_window_paint(wnd, rect);
566 if (rc != EOK)
567 return rc;
568
569 wnd = ds_display_prev_window(wnd);
570 }
571
572 seat = ds_display_first_seat(disp);
573 while (seat != NULL) {
574 rc = ds_seat_paint_pointer(seat, rect);
575 if (rc != EOK)
576 return rc;
577
578 seat = ds_display_next_seat(seat);
579 }
580
581 return EOK;
582}
583
584/** @}
585 */
Note: See TracBrowser for help on using the repository browser.