source: mainline/uspace/srv/hid/display/display.c@ 4e7b0ad

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

Add missing actions in display destructor

We might to actually destroy the other components rather than assert
they have been destroyed. But we shall see when we actually implement
graceful shutdown for this (and any other) server.

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