source: mainline/uspace/srv/hid/display/display.c@ b0ae23f

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

Assigning devices to seats

  • Property mode set to 100644
File size: 24.9 KB
Line 
1/*
2 * Copyright (c) 2023 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/bitmap.h>
38#include <gfx/context.h>
39#include <gfx/render.h>
40#include <io/log.h>
41#include <memgfx/memgc.h>
42#include <stdlib.h>
43#include "client.h"
44#include "clonegc.h"
45#include "cursimg.h"
46#include "cursor.h"
47#include "display.h"
48#include "seat.h"
49#include "window.h"
50#include "wmclient.h"
51
52static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
53static void ds_display_invalidate_cb(void *, gfx_rect_t *);
54static void ds_display_update_cb(void *);
55
56static mem_gc_cb_t ds_display_mem_gc_cb = {
57 .invalidate = ds_display_invalidate_cb,
58 .update = ds_display_update_cb
59};
60
61/** Create display.
62 *
63 * @param gc Graphics context for displaying output
64 * @param flags Display flags
65 * @param rdisp Place to store pointer to new display.
66 * @return EOK on success, ENOMEM if out of memory
67 */
68errno_t ds_display_create(gfx_context_t *gc, ds_display_flags_t flags,
69 ds_display_t **rdisp)
70{
71 ds_display_t *disp;
72 ds_cursor_t *cursor;
73 int i;
74 errno_t rc;
75
76 disp = calloc(1, sizeof(ds_display_t));
77 if (disp == NULL)
78 return ENOMEM;
79
80 rc = gfx_color_new_rgb_i16(0x8000, 0xc800, 0xffff, &disp->bg_color);
81 if (rc != EOK) {
82 free(disp);
83 return ENOMEM;
84 }
85
86 list_initialize(&disp->cursors);
87
88 for (i = 0; i < dcurs_limit; i++) {
89 rc = ds_cursor_create(disp, &ds_cursimg[i].rect,
90 ds_cursimg[i].image, &cursor);
91 if (rc != EOK)
92 goto error;
93
94 disp->cursor[i] = cursor;
95 }
96
97 fibril_mutex_initialize(&disp->lock);
98 list_initialize(&disp->clients);
99 list_initialize(&disp->wmclients);
100 list_initialize(&disp->cfgclients);
101 disp->next_wnd_id = 1;
102 list_initialize(&disp->ddevs);
103 list_initialize(&disp->idevcfgs);
104 list_initialize(&disp->seats);
105 list_initialize(&disp->windows);
106 disp->flags = flags;
107 *rdisp = disp;
108 return EOK;
109error:
110 ds_display_destroy(disp);
111 return rc;
112}
113
114/** Destroy display.
115 *
116 * @param disp Display
117 */
118void ds_display_destroy(ds_display_t *disp)
119{
120 int i;
121
122 assert(list_empty(&disp->clients));
123 assert(list_empty(&disp->wmclients));
124 assert(list_empty(&disp->cfgclients));
125 assert(list_empty(&disp->seats));
126 assert(list_empty(&disp->ddevs));
127 assert(list_empty(&disp->idevcfgs));
128 assert(list_empty(&disp->seats));
129 assert(list_empty(&disp->windows));
130
131 /* Destroy cursors */
132 for (i = 0; i < dcurs_limit; i++) {
133 ds_cursor_destroy(disp->cursor[i]);
134 disp->cursor[i] = NULL;
135 }
136
137 gfx_color_delete(disp->bg_color);
138 free(disp);
139}
140
141/** Lock display.
142 *
143 * This should be called in any thread that wishes to access the display
144 * or its child objects (e.g. windows).
145 *
146 * @param disp Display
147 */
148void ds_display_lock(ds_display_t *disp)
149{
150 fibril_mutex_lock(&disp->lock);
151}
152
153/** Unlock display.
154 *
155 * @param disp Display
156 */
157void ds_display_unlock(ds_display_t *disp)
158{
159 fibril_mutex_unlock(&disp->lock);
160}
161
162/** Get display information.
163 *
164 * @param disp Display
165 */
166void ds_display_get_info(ds_display_t *disp, display_info_t *info)
167{
168 info->rect = disp->rect;
169}
170
171/** Add client to display.
172 *
173 * @param disp Display
174 * @param client Client
175 */
176void ds_display_add_client(ds_display_t *disp, ds_client_t *client)
177{
178 assert(client->display == NULL);
179 assert(!link_used(&client->lclients));
180
181 client->display = disp;
182 list_append(&client->lclients, &disp->clients);
183}
184
185/** Remove client from display.
186 *
187 * @param client Client
188 */
189void ds_display_remove_client(ds_client_t *client)
190{
191 list_remove(&client->lclients);
192 client->display = NULL;
193}
194
195/** Get first client in display.
196 *
197 * @param disp Display
198 * @return First client or @c NULL if there is none
199 */
200ds_client_t *ds_display_first_client(ds_display_t *disp)
201{
202 link_t *link = list_first(&disp->clients);
203
204 if (link == NULL)
205 return NULL;
206
207 return list_get_instance(link, ds_client_t, lclients);
208}
209
210/** Get next client in display.
211 *
212 * @param client Current client
213 * @return Next client or @c NULL if there is none
214 */
215ds_client_t *ds_display_next_client(ds_client_t *client)
216{
217 link_t *link = list_next(&client->lclients, &client->display->clients);
218
219 if (link == NULL)
220 return NULL;
221
222 return list_get_instance(link, ds_client_t, lclients);
223}
224
225/** Add WM client to display.
226 *
227 * @param disp Display
228 * @param wmclient WM client
229 */
230void ds_display_add_wmclient(ds_display_t *disp, ds_wmclient_t *wmclient)
231{
232 assert(wmclient->display == NULL);
233 assert(!link_used(&wmclient->lwmclients));
234
235 wmclient->display = disp;
236 list_append(&wmclient->lwmclients, &disp->wmclients);
237}
238
239/** Remove WM client from display.
240 *
241 * @param wmclient WM client
242 */
243void ds_display_remove_wmclient(ds_wmclient_t *wmclient)
244{
245 list_remove(&wmclient->lwmclients);
246 wmclient->display = NULL;
247}
248
249/** Add CFG client to display.
250 *
251 * @param disp Display
252 * @param cfgclient CFG client
253 */
254void ds_display_add_cfgclient(ds_display_t *disp, ds_cfgclient_t *cfgclient)
255{
256 assert(cfgclient->display == NULL);
257 assert(!link_used(&cfgclient->lcfgclients));
258
259 cfgclient->display = disp;
260 list_append(&cfgclient->lcfgclients, &disp->cfgclients);
261}
262
263/** Remove CFG client from display.
264 *
265 * @param cfgclient CFG client
266 */
267void ds_display_remove_cfgclient(ds_cfgclient_t *cfgclient)
268{
269 list_remove(&cfgclient->lcfgclients);
270 cfgclient->display = NULL;
271}
272
273/** Get first WM client in display.
274 *
275 * @param disp Display
276 * @return First WM client or @c NULL if there is none
277 */
278ds_wmclient_t *ds_display_first_wmclient(ds_display_t *disp)
279{
280 link_t *link = list_first(&disp->wmclients);
281
282 if (link == NULL)
283 return NULL;
284
285 return list_get_instance(link, ds_wmclient_t, lwmclients);
286}
287
288/** Get next WM client in display.
289 *
290 * @param wmclient Current WM client
291 * @return Next WM client or @c NULL if there is none
292 */
293ds_wmclient_t *ds_display_next_wmclient(ds_wmclient_t *wmclient)
294{
295 link_t *link = list_next(&wmclient->lwmclients,
296 &wmclient->display->wmclients);
297
298 if (link == NULL)
299 return NULL;
300
301 return list_get_instance(link, ds_wmclient_t, lwmclients);
302}
303
304/** Find window in all clients by ID.
305 *
306 * XXX This is just a hack needed to match GC connection to a window,
307 * as we don't have a good safe way to pass the GC endpoint to our client
308 * on demand.
309 *
310 * @param display Display
311 * @param id Window ID
312 */
313ds_window_t *ds_display_find_window(ds_display_t *display, ds_wnd_id_t id)
314{
315 ds_client_t *client;
316 ds_window_t *wnd;
317
318 client = ds_display_first_client(display);
319 while (client != NULL) {
320 wnd = ds_client_find_window(client, id);
321 if (wnd != NULL)
322 return wnd;
323
324 client = ds_display_next_client(client);
325 }
326
327 return NULL;
328}
329
330/** Find window by display position.
331 *
332 * @param display Display
333 * @param pos Display position
334 */
335ds_window_t *ds_display_window_by_pos(ds_display_t *display, gfx_coord2_t *pos)
336{
337 ds_window_t *wnd;
338 gfx_rect_t drect;
339
340 wnd = ds_display_first_window(display);
341 while (wnd != NULL) {
342 /* Window bounding rectangle on display */
343 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
344
345 if (gfx_pix_inside_rect(pos, &drect) &&
346 ds_window_is_visible(wnd))
347 return wnd;
348
349 wnd = ds_display_next_window(wnd);
350 }
351
352 return NULL;
353}
354
355/** Add window to window list.
356 *
357 * Topmost windows are enlisted before any other window. Non-topmost
358 * windows are enlisted before any other non-topmost window.
359 *
360 * @param display Display
361 * @param wnd Window
362 */
363void ds_display_enlist_window(ds_display_t *display, ds_window_t *wnd)
364{
365 ds_window_t *w;
366
367 assert(wnd->display == display);
368 assert(!link_used(&wnd->ldwindows));
369
370 if ((wnd->flags & wndf_topmost) == 0) {
371 /* Find the first non-topmost window */
372 w = ds_display_first_window(display);
373 while (w != NULL && (w->flags & wndf_topmost) != 0)
374 w = ds_display_next_window(w);
375
376 if (w != NULL)
377 list_insert_before(&wnd->ldwindows, &w->ldwindows);
378 else
379 list_append(&wnd->ldwindows, &display->windows);
380 } else {
381 /* Insert at the beginning */
382 list_prepend(&wnd->ldwindows, &display->windows);
383 }
384
385}
386
387/** Add window to display.
388 *
389 * @param display Display
390 * @param wnd Window
391 */
392void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
393{
394 ds_wmclient_t *wmclient;
395
396 assert(wnd->display == NULL);
397 assert(!link_used(&wnd->ldwindows));
398
399 wnd->display = display;
400 ds_display_enlist_window(display, wnd);
401
402 /* Notify window managers about the new window */
403 wmclient = ds_display_first_wmclient(display);
404 while (wmclient != NULL) {
405 ds_wmclient_post_wnd_added_event(wmclient, wnd->id);
406 wmclient = ds_display_next_wmclient(wmclient);
407 }
408}
409
410/** Remove window from display.
411 *
412 * @param wnd Window
413 */
414void ds_display_remove_window(ds_window_t *wnd)
415{
416 ds_wmclient_t *wmclient;
417 ds_display_t *display;
418
419 display = wnd->display;
420
421 list_remove(&wnd->ldwindows);
422 wnd->display = NULL;
423
424 /* Notify window managers about the removed window */
425 wmclient = ds_display_first_wmclient(display);
426 while (wmclient != NULL) {
427 ds_wmclient_post_wnd_removed_event(wmclient, wnd->id);
428 wmclient = ds_display_next_wmclient(wmclient);
429 }
430}
431
432/** Move window to top.
433 *
434 * @param display Display
435 * @param wnd Window
436 */
437void ds_display_window_to_top(ds_window_t *wnd)
438{
439 assert(wnd->display != NULL);
440 assert(link_used(&wnd->ldwindows));
441
442 list_remove(&wnd->ldwindows);
443 ds_display_enlist_window(wnd->display, wnd);
444}
445
446/** Get first window in display.
447 *
448 * @param display Display
449 * @return First window or @c NULL if there is none
450 */
451ds_window_t *ds_display_first_window(ds_display_t *display)
452{
453 link_t *link = list_first(&display->windows);
454
455 if (link == NULL)
456 return NULL;
457
458 return list_get_instance(link, ds_window_t, ldwindows);
459}
460
461/** Get last window in display.
462 *
463 * @param display Display
464 * @return Last window or @c NULL if there is none
465 */
466ds_window_t *ds_display_last_window(ds_display_t *display)
467{
468 link_t *link = list_last(&display->windows);
469
470 if (link == NULL)
471 return NULL;
472
473 return list_get_instance(link, ds_window_t, ldwindows);
474}
475
476/** Get next window in client.
477 *
478 * @param wnd Current window
479 * @return Next window or @c NULL if there is none
480 */
481ds_window_t *ds_display_next_window(ds_window_t *wnd)
482{
483 link_t *link = list_next(&wnd->ldwindows, &wnd->display->windows);
484
485 if (link == NULL)
486 return NULL;
487
488 return list_get_instance(link, ds_window_t, ldwindows);
489}
490
491/** Get previous window in client.
492 *
493 * @param wnd Current window
494 * @return Previous window or @c NULL if there is none
495 */
496ds_window_t *ds_display_prev_window(ds_window_t *wnd)
497{
498 link_t *link = list_prev(&wnd->ldwindows, &wnd->display->windows);
499
500 if (link == NULL)
501 return NULL;
502
503 return list_get_instance(link, ds_window_t, ldwindows);
504}
505
506/** Post keyboard event to a display.
507 *
508 * The event is routed to the correct window by first determining the
509 * seat the keyboard device belongs to and then the event is sent to the
510 * window focused by that seat.
511 *
512 * @param display Display
513 * @param event Event
514 */
515errno_t ds_display_post_kbd_event(ds_display_t *display, kbd_event_t *event)
516{
517 ds_seat_t *seat;
518
519 /* Determine which seat the event belongs to */
520 seat = ds_display_seat_by_idev(display, event->kbd_id);
521 if (seat == NULL)
522 return EOK;
523
524 return ds_seat_post_kbd_event(seat, event);
525}
526
527/** Post position event to a display.
528 *
529 * @param display Display
530 * @param event Event
531 */
532errno_t ds_display_post_ptd_event(ds_display_t *display, ptd_event_t *event)
533{
534 ds_seat_t *seat;
535
536 /* Determine which seat the event belongs to */
537 seat = ds_display_seat_by_idev(display, event->pos_id);
538 if (seat == NULL)
539 return EOK;
540
541 return ds_seat_post_ptd_event(seat, event);
542}
543
544/** Add seat to display.
545 *
546 * @param disp Display
547 * @param seat Seat
548 */
549void ds_display_add_seat(ds_display_t *disp, ds_seat_t *seat)
550{
551 assert(seat->display == NULL);
552 assert(!link_used(&seat->lseats));
553
554 seat->display = disp;
555 seat->id = disp->next_seat_id++;
556 list_append(&seat->lseats, &disp->seats);
557}
558
559/** Remove seat from display.
560 *
561 * @param seat Seat
562 */
563void ds_display_remove_seat(ds_seat_t *seat)
564{
565 list_remove(&seat->lseats);
566 seat->display = NULL;
567}
568
569/** Get first seat in display.
570 *
571 * @param disp Display
572 * @return First seat or @c NULL if there is none
573 */
574ds_seat_t *ds_display_first_seat(ds_display_t *disp)
575{
576 link_t *link = list_first(&disp->seats);
577
578 if (link == NULL)
579 return NULL;
580
581 return list_get_instance(link, ds_seat_t, lseats);
582}
583
584/** Get next seat in display.
585 *
586 * @param seat Current seat
587 * @return Next seat or @c NULL if there is none
588 */
589ds_seat_t *ds_display_next_seat(ds_seat_t *seat)
590{
591 link_t *link = list_next(&seat->lseats, &seat->display->seats);
592
593 if (link == NULL)
594 return NULL;
595
596 return list_get_instance(link, ds_seat_t, lseats);
597}
598
599/** Find seat by ID.
600 *
601 * @param display Display
602 * @param id Seat ID
603 */
604ds_seat_t *ds_display_find_seat(ds_display_t *display, ds_seat_id_t id)
605{
606 ds_seat_t *seat;
607
608 seat = ds_display_first_seat(display);
609 while (seat != NULL) {
610 if (seat->id == id)
611 return seat;
612
613 seat = ds_display_next_seat(seat);
614 }
615
616 return NULL;
617}
618
619/** Get seat which owns the specified input device.
620 *
621 * @param disp Display
622 * @param idev_id Input device ID
623 * @return Seat which owns device with ID @a idev_id or @c NULL if not found
624 */
625ds_seat_t *ds_display_seat_by_idev(ds_display_t *disp, ds_idev_id_t idev_id)
626{
627 ds_idevcfg_t *idevcfg;
628
629 /*
630 * Find input device configuration entry that maps this input device
631 * to a seat.
632 */
633 idevcfg = ds_display_first_idevcfg(disp);
634 while (idevcfg != NULL) {
635 if (idevcfg->svc_id == idev_id)
636 return idevcfg->seat;
637
638 idevcfg = ds_display_next_idevcfg(idevcfg);
639 }
640
641 /* If none was found, return the default seat */
642 return ds_display_first_seat(disp);
643}
644
645/** Allocate back buffer for display.
646 *
647 * @param disp Display
648 * @return EOK on success or if no back buffer is required, otherwise
649 * an error code.
650 */
651static errno_t ds_display_alloc_backbuf(ds_display_t *disp)
652{
653 gfx_context_t *ugc;
654 gfx_bitmap_params_t params;
655 gfx_bitmap_alloc_t alloc;
656 errno_t rc;
657
658 /* Allocate backbuffer */
659 if ((disp->flags & df_disp_double_buf) == 0) {
660 /* Not double buffering. Nothing to do. */
661 return EOK;
662 }
663
664 ugc = ds_display_get_unbuf_gc(disp);
665
666 gfx_bitmap_params_init(&params);
667 params.rect = disp->rect;
668
669 rc = gfx_bitmap_create(ugc, &params, NULL,
670 &disp->backbuf);
671 if (rc != EOK)
672 goto error;
673
674 rc = gfx_bitmap_get_alloc(disp->backbuf, &alloc);
675 if (rc != EOK)
676 goto error;
677
678 rc = mem_gc_create(&disp->rect, &alloc, &ds_display_mem_gc_cb,
679 (void *) disp, &disp->bbgc);
680 if (rc != EOK)
681 goto error;
682
683 disp->dirty_rect.p0.x = 0;
684 disp->dirty_rect.p0.y = 0;
685 disp->dirty_rect.p1.x = 0;
686 disp->dirty_rect.p1.y = 0;
687
688 return EOK;
689error:
690 if (disp->backbuf != NULL) {
691 gfx_bitmap_destroy(disp->backbuf);
692 disp->backbuf = NULL;
693 }
694
695 return rc;
696}
697
698/** Add display device to display.
699 *
700 * @param disp Display
701 * @param ddev Display device
702 * @return EOK on success, or an error code
703 */
704errno_t ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
705{
706 errno_t rc;
707 gfx_rect_t old_disp_rect;
708
709 assert(ddev->display == NULL);
710 assert(!link_used(&ddev->lddevs));
711
712 old_disp_rect = disp->rect;
713
714 ddev->display = disp;
715 list_append(&ddev->lddevs, &disp->ddevs);
716
717 /* First display device */
718 if (gfx_rect_is_empty(&disp->rect)) {
719 /* Set screen dimensions */
720 disp->rect = ddev->info.rect;
721
722 /* Create cloning GC */
723 rc = ds_clonegc_create(ddev->gc, &disp->fbgc);
724 if (rc != EOK)
725 goto error;
726
727 /* Allocate backbuffer */
728 rc = ds_display_alloc_backbuf(disp);
729 if (rc != EOK) {
730 ds_clonegc_delete(disp->fbgc);
731 disp->fbgc = NULL;
732 goto error;
733 }
734 } else {
735 /* Add new output device to cloning GC */
736 rc = ds_clonegc_add_output(disp->fbgc, ddev->gc);
737 if (rc != EOK)
738 goto error;
739 }
740
741 ds_display_update_max_rect(disp);
742
743 return EOK;
744error:
745 disp->rect = old_disp_rect;
746 list_remove(&ddev->lddevs);
747 return rc;
748}
749
750/** Remove display device from display.
751 *
752 * @param ddev Display device
753 */
754void ds_display_remove_ddev(ds_ddev_t *ddev)
755{
756 list_remove(&ddev->lddevs);
757 ddev->display = NULL;
758}
759
760/** Get first display device in display.
761 *
762 * @param disp Display
763 * @return First display device or @c NULL if there is none
764 */
765ds_ddev_t *ds_display_first_ddev(ds_display_t *disp)
766{
767 link_t *link = list_first(&disp->ddevs);
768
769 if (link == NULL)
770 return NULL;
771
772 return list_get_instance(link, ds_ddev_t, lddevs);
773}
774
775/** Get next display device in display.
776 *
777 * @param ddev Current display device
778 * @return Next display device or @c NULL if there is none
779 */
780ds_ddev_t *ds_display_next_ddev(ds_ddev_t *ddev)
781{
782 link_t *link = list_next(&ddev->lddevs, &ddev->display->ddevs);
783
784 if (link == NULL)
785 return NULL;
786
787 return list_get_instance(link, ds_ddev_t, lddevs);
788}
789
790/** Add input device configuration entry to display.
791 *
792 * @param disp Display
793 * @param idevcfg Input device configuration
794 */
795void ds_display_add_idevcfg(ds_display_t *disp, ds_idevcfg_t *idevcfg)
796{
797 assert(idevcfg->display == NULL);
798 assert(!link_used(&idevcfg->lidevcfgs));
799
800 idevcfg->display = disp;
801 list_append(&idevcfg->lidevcfgs, &disp->idevcfgs);
802}
803
804/** Remove input device configuration entry from display.
805 *
806 * @param idevcfg Input device configuration entry
807 */
808void ds_display_remove_idevcfg(ds_idevcfg_t *idevcfg)
809{
810 list_remove(&idevcfg->lidevcfgs);
811 idevcfg->display = NULL;
812}
813
814/** Get first input device configuration entry in display.
815 *
816 * @param disp Display
817 * @return First input device configuration entry or @c NULL if there is none
818 */
819ds_idevcfg_t *ds_display_first_idevcfg(ds_display_t *disp)
820{
821 link_t *link = list_first(&disp->idevcfgs);
822
823 if (link == NULL)
824 return NULL;
825
826 return list_get_instance(link, ds_idevcfg_t, lidevcfgs);
827}
828
829/** Get next input device configuration entry in display.
830 *
831 * @param idevcfg Current input device configuration entry
832 * @return Next input device configuration entry or @c NULL if there is none
833 */
834ds_idevcfg_t *ds_display_next_idevcfg(ds_idevcfg_t *idevcfg)
835{
836 link_t *link = list_next(&idevcfg->lidevcfgs, &idevcfg->display->idevcfgs);
837
838 if (link == NULL)
839 return NULL;
840
841 return list_get_instance(link, ds_idevcfg_t, lidevcfgs);
842}
843
844/** Add cursor to display.
845 *
846 * @param display Display
847 * @param cursor Cursor
848 */
849void ds_display_add_cursor(ds_display_t *display, ds_cursor_t *cursor)
850{
851 assert(cursor->display == NULL);
852 assert(!link_used(&cursor->ldisplay));
853
854 cursor->display = display;
855 list_prepend(&cursor->ldisplay, &display->cursors);
856}
857
858/** Remove cursor from display.
859 *
860 * @param cursor Cursor
861 */
862void ds_display_remove_cursor(ds_cursor_t *cursor)
863{
864 list_remove(&cursor->ldisplay);
865 cursor->display = NULL;
866}
867
868/** Update display maximize rectangle.
869 *
870 * Recalculate the maximize rectangle (the rectangle used for maximized
871 * windows).
872 *
873 * @param display Display
874 */
875void ds_display_update_max_rect(ds_display_t *display)
876{
877 ds_window_t *wnd;
878 gfx_rect_t max_rect;
879 gfx_rect_t drect;
880
881 /* Start with the entire display */
882 max_rect = display->rect;
883
884 wnd = ds_display_first_window(display);
885 while (wnd != NULL) {
886 /* Should maximized windows avoid this window? */
887 if ((wnd->flags & wndf_avoid) != 0) {
888 /* Window bounding rectangle on display */
889 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
890
891 /* Crop maximized rectangle */
892 ds_display_crop_max_rect(&drect, &max_rect);
893 }
894
895 wnd = ds_display_next_window(wnd);
896 }
897
898 /* Update the maximize rectangle */
899 display->max_rect = max_rect;
900}
901
902/** Crop maximize rectangle.
903 *
904 * Use the avoid rectangle @a arect to crop off maximization rectangle
905 * @a mrect. If @a arect covers the top, bottom, left or right part
906 * of @a mrect, it will be cropped off. Otherwise there will be
907 * no effect.
908 *
909 * @param arect Avoid rectangle
910 * @param mrect Maximize rectangle to be modified
911 */
912void ds_display_crop_max_rect(gfx_rect_t *arect, gfx_rect_t *mrect)
913{
914 if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
915 arect->p1.x == mrect->p1.x) {
916 /* Cropp off top part */
917 mrect->p0.y = arect->p1.y;
918 } else if (arect->p0.x == mrect->p0.x && arect->p1.x == mrect->p1.x &&
919 arect->p1.y == mrect->p1.y) {
920 /* Cropp off bottom part */
921 mrect->p1.y = arect->p0.y;
922 } else if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
923 arect->p1.y == mrect->p1.y) {
924 /* Cropp off left part */
925 mrect->p0.x = arect->p1.x;
926 } else if (arect->p0.y == mrect->p0.y && arect->p1.x == mrect->p1.x &&
927 arect->p1.y == mrect->p1.y) {
928 /* Cropp off right part */
929 mrect->p1.x = arect->p0.x;
930 }
931}
932
933/** Get unbuffered GC.
934 *
935 * Get the display's (unbuffered) graphic context. If the display
936 * is double-buffered, this returns GC of the front buffer. If the display
937 * is unbuffered, this is the same as @c ds_display_get_gc().
938 *
939 * @param display Display
940 * @return Unbuffered GC
941 */
942static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *display)
943{
944 /* In case of unit tests */
945 if (display->fbgc == NULL)
946 return NULL;
947
948 return ds_clonegc_get_ctx(display->fbgc);
949}
950
951/** Get display GC.
952 *
953 * Get the graphic context used to paint the display. This is to be used
954 * for all display server paint operations.
955 *
956 * @param display Display
957 * @return Graphic context for painting to the display
958 */
959gfx_context_t *ds_display_get_gc(ds_display_t *display)
960{
961 if ((display->flags & df_disp_double_buf) != 0)
962 return mem_gc_get_ctx(display->bbgc);
963 else
964 return ds_display_get_unbuf_gc(display);
965}
966
967/** Paint display background.
968 *
969 * @param display Display
970 * @param rect Bounding rectangle or @c NULL to repaint entire display
971 */
972errno_t ds_display_paint_bg(ds_display_t *disp, gfx_rect_t *rect)
973{
974 gfx_rect_t crect;
975 gfx_context_t *gc;
976 errno_t rc;
977
978 if (rect != NULL)
979 gfx_rect_clip(&disp->rect, rect, &crect);
980 else
981 crect = disp->rect;
982
983 gc = ds_display_get_gc(disp);
984 if (gc == NULL)
985 return EOK;
986
987 rc = gfx_set_color(gc, disp->bg_color);
988 if (rc != EOK)
989 return rc;
990
991 return gfx_fill_rect(gc, &crect);
992}
993
994/** Update front buffer from back buffer.
995 *
996 * If the display is not double-buffered, no action is taken.
997 *
998 * @param disp Display
999 * @return EOK on success, or an error code
1000 */
1001static errno_t ds_display_update(ds_display_t *disp)
1002{
1003 errno_t rc;
1004
1005 if (disp->backbuf == NULL) {
1006 /* Not double-buffered, nothing to do. */
1007 return EOK;
1008 }
1009
1010 rc = gfx_bitmap_render(disp->backbuf, &disp->dirty_rect, NULL);
1011 if (rc != EOK)
1012 return rc;
1013
1014 disp->dirty_rect.p0.x = 0;
1015 disp->dirty_rect.p0.y = 0;
1016 disp->dirty_rect.p1.x = 0;
1017 disp->dirty_rect.p1.y = 0;
1018
1019 return EOK;
1020}
1021
1022/** Paint display.
1023 *
1024 * @param display Display
1025 * @param rect Bounding rectangle or @c NULL to repaint entire display
1026 */
1027errno_t ds_display_paint(ds_display_t *disp, gfx_rect_t *rect)
1028{
1029 errno_t rc;
1030 ds_window_t *wnd;
1031 ds_seat_t *seat;
1032
1033 /* Paint background */
1034 rc = ds_display_paint_bg(disp, rect);
1035 if (rc != EOK)
1036 return rc;
1037
1038 /* Paint windows bottom to top */
1039 wnd = ds_display_last_window(disp);
1040 while (wnd != NULL) {
1041 rc = ds_window_paint(wnd, rect);
1042 if (rc != EOK)
1043 return rc;
1044
1045 wnd = ds_display_prev_window(wnd);
1046 }
1047
1048 /* Paint window previews for windows being resized or moved */
1049 wnd = ds_display_last_window(disp);
1050 while (wnd != NULL) {
1051 rc = ds_window_paint_preview(wnd, rect);
1052 if (rc != EOK)
1053 return rc;
1054
1055 wnd = ds_display_prev_window(wnd);
1056 }
1057
1058 /* Paint pointers */
1059 seat = ds_display_first_seat(disp);
1060 while (seat != NULL) {
1061 rc = ds_seat_paint_pointer(seat, rect);
1062 if (rc != EOK)
1063 return rc;
1064
1065 seat = ds_display_next_seat(seat);
1066 }
1067
1068 return ds_display_update(disp);
1069}
1070
1071/** Display invalidate callback.
1072 *
1073 * Called by backbuffer memory GC when something is rendered into it.
1074 * Updates the display's dirty rectangle.
1075 *
1076 * @param arg Argument (display cast as void *)
1077 * @param rect Rectangle to update
1078 */
1079static void ds_display_invalidate_cb(void *arg, gfx_rect_t *rect)
1080{
1081 ds_display_t *disp = (ds_display_t *) arg;
1082 gfx_rect_t env;
1083
1084 gfx_rect_envelope(&disp->dirty_rect, rect, &env);
1085 disp->dirty_rect = env;
1086}
1087
1088/** Display update callback.
1089 *
1090 * @param arg Argument (display cast as void *)
1091 */
1092static void ds_display_update_cb(void *arg)
1093{
1094 ds_display_t *disp = (ds_display_t *) arg;
1095
1096 (void) disp;
1097}
1098
1099/** @}
1100 */
Note: See TracBrowser for help on using the repository browser.