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

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b3eeae5 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
RevLine 
[c8cf261]1/*
[d8503fd]2 * Copyright (c) 2023 Jiri Svoboda
[c8cf261]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/**
[38e5f36c]33 * @file Display server display
[c8cf261]34 */
35
36#include <errno.h>
[8aef01c]37#include <gfx/bitmap.h>
[159776f]38#include <gfx/context.h>
[c79545e]39#include <gfx/render.h>
[c8cf261]40#include <io/log.h>
[8aef01c]41#include <memgfx/memgc.h>
[6af4b4f]42#include <stdlib.h>
[b3c185b6]43#include "client.h"
[5271e4c]44#include "clonegc.h"
[4d8002d]45#include "cursimg.h"
46#include "cursor.h"
[913add60]47#include "display.h"
[cf32dbd]48#include "seat.h"
[6af4b4f]49#include "window.h"
[913add60]50#include "wmclient.h"
[c8cf261]51
[8aef01c]52static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
[2ab8ab3]53static void ds_display_invalidate_cb(void *, gfx_rect_t *);
54static void ds_display_update_cb(void *);
[8aef01c]55
[1215db9]56static mem_gc_cb_t ds_display_mem_gc_cb = {
57 .invalidate = ds_display_invalidate_cb,
58 .update = ds_display_update_cb
59};
60
[6af4b4f]61/** Create display.
62 *
[159776f]63 * @param gc Graphics context for displaying output
[8aef01c]64 * @param flags Display flags
[6af4b4f]65 * @param rdisp Place to store pointer to new display.
66 * @return EOK on success, ENOMEM if out of memory
67 */
[8aef01c]68errno_t ds_display_create(gfx_context_t *gc, ds_display_flags_t flags,
69 ds_display_t **rdisp)
[6af4b4f]70{
71 ds_display_t *disp;
[4d8002d]72 ds_cursor_t *cursor;
73 int i;
[c79545e]74 errno_t rc;
[6af4b4f]75
76 disp = calloc(1, sizeof(ds_display_t));
77 if (disp == NULL)
78 return ENOMEM;
79
[c79545e]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
[4d8002d]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
[c11ee605]97 fibril_mutex_initialize(&disp->lock);
[b3c185b6]98 list_initialize(&disp->clients);
[913add60]99 list_initialize(&disp->wmclients);
[d8503fd]100 list_initialize(&disp->cfgclients);
[b3c185b6]101 disp->next_wnd_id = 1;
[87a7cdb]102 list_initialize(&disp->ddevs);
[b3eeae5]103 list_initialize(&disp->idevcfgs);
[cf32dbd]104 list_initialize(&disp->seats);
[fd777a2]105 list_initialize(&disp->windows);
[8aef01c]106 disp->flags = flags;
[6af4b4f]107 *rdisp = disp;
108 return EOK;
[4d8002d]109error:
110 ds_display_destroy(disp);
111 return rc;
[6af4b4f]112}
113
114/** Destroy display.
115 *
116 * @param disp Display
117 */
118void ds_display_destroy(ds_display_t *disp)
119{
[4e7b0ad]120 int i;
121
[b3c185b6]122 assert(list_empty(&disp->clients));
[913add60]123 assert(list_empty(&disp->wmclients));
[d8503fd]124 assert(list_empty(&disp->cfgclients));
[cf32dbd]125 assert(list_empty(&disp->seats));
[4e7b0ad]126 assert(list_empty(&disp->ddevs));
[b3eeae5]127 assert(list_empty(&disp->idevcfgs));
[4e7b0ad]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
[c79545e]137 gfx_color_delete(disp->bg_color);
[6af4b4f]138 free(disp);
139}
140
[c11ee605]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
[aeb3037]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
[b3c185b6]171/** Add client to display.
[6af4b4f]172 *
173 * @param disp Display
[cf32dbd]174 * @param client Client
[6af4b4f]175 */
[b3c185b6]176void ds_display_add_client(ds_display_t *disp, ds_client_t *client)
[6af4b4f]177{
[b3c185b6]178 assert(client->display == NULL);
179 assert(!link_used(&client->lclients));
[6af4b4f]180
[b3c185b6]181 client->display = disp;
182 list_append(&client->lclients, &disp->clients);
[c8cf261]183}
184
[b3c185b6]185/** Remove client from display.
[6af4b4f]186 *
[cf32dbd]187 * @param client Client
[6af4b4f]188 */
[b3c185b6]189void ds_display_remove_client(ds_client_t *client)
[6af4b4f]190{
[b3c185b6]191 list_remove(&client->lclients);
192 client->display = NULL;
[6af4b4f]193}
194
[b3c185b6]195/** Get first client in display.
[6af4b4f]196 *
197 * @param disp Display
[b3c185b6]198 * @return First client or @c NULL if there is none
[6af4b4f]199 */
[b3c185b6]200ds_client_t *ds_display_first_client(ds_display_t *disp)
[6af4b4f]201{
[b3c185b6]202 link_t *link = list_first(&disp->clients);
[6af4b4f]203
[b3c185b6]204 if (link == NULL)
205 return NULL;
[6af4b4f]206
[b3c185b6]207 return list_get_instance(link, ds_client_t, lclients);
[6af4b4f]208}
209
[b3c185b6]210/** Get next client in display.
[6af4b4f]211 *
[b3c185b6]212 * @param client Current client
213 * @return Next client or @c NULL if there is none
[6af4b4f]214 */
[b3c185b6]215ds_client_t *ds_display_next_client(ds_client_t *client)
[6af4b4f]216{
[b3c185b6]217 link_t *link = list_next(&client->lclients, &client->display->clients);
[6af4b4f]218
219 if (link == NULL)
220 return NULL;
221
[b3c185b6]222 return list_get_instance(link, ds_client_t, lclients);
[6af4b4f]223}
224
[913add60]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
[d8503fd]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
[913add60]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
[b3c185b6]304/** Find window in all clients by ID.
[6af4b4f]305 *
[b3c185b6]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
[6af4b4f]312 */
[b3c185b6]313ds_window_t *ds_display_find_window(ds_display_t *display, ds_wnd_id_t id)
[6af4b4f]314{
[b3c185b6]315 ds_client_t *client;
316 ds_window_t *wnd;
[6af4b4f]317
[b3c185b6]318 client = ds_display_first_client(display);
319 while (client != NULL) {
320 wnd = ds_client_find_window(client, id);
[195b7b3]321 if (wnd != NULL)
[b3c185b6]322 return wnd;
[195b7b3]323
[b3c185b6]324 client = ds_display_next_client(client);
325 }
326
327 return NULL;
328}
329
[24cf391a]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;
[fb420e48]338 gfx_rect_t drect;
[24cf391a]339
340 wnd = ds_display_first_window(display);
341 while (wnd != NULL) {
[fb420e48]342 /* Window bounding rectangle on display */
343 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
344
[06176e1]345 if (gfx_pix_inside_rect(pos, &drect) &&
346 ds_window_is_visible(wnd))
[24cf391a]347 return wnd;
348
349 wnd = ds_display_next_window(wnd);
350 }
351
352 return NULL;
353}
354
[5d62130]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
[fd777a2]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{
[913add60]394 ds_wmclient_t *wmclient;
395
[fd777a2]396 assert(wnd->display == NULL);
397 assert(!link_used(&wnd->ldwindows));
398
399 wnd->display = display;
[5d62130]400 ds_display_enlist_window(display, wnd);
[913add60]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 }
[fd777a2]408}
409
410/** Remove window from display.
411 *
412 * @param wnd Window
413 */
414void ds_display_remove_window(ds_window_t *wnd)
415{
[913add60]416 ds_wmclient_t *wmclient;
417 ds_display_t *display;
418
419 display = wnd->display;
420
[fd777a2]421 list_remove(&wnd->ldwindows);
422 wnd->display = NULL;
[913add60]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);
[5d62130]443 ds_display_enlist_window(wnd->display, wnd);
[fd777a2]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
[2012fe0]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
[fd777a2]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
[2012fe0]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
[cf32dbd]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 */
[b3c185b6]515errno_t ds_display_post_kbd_event(ds_display_t *display, kbd_event_t *event)
516{
[cf32dbd]517 ds_seat_t *seat;
[b3c185b6]518
[88d828e]519 /* Determine which seat the event belongs to */
520 seat = ds_display_seat_by_idev(display, event->kbd_id);
[cf32dbd]521 if (seat == NULL)
[b3c185b6]522 return EOK;
523
[cf32dbd]524 return ds_seat_post_kbd_event(seat, event);
525}
526
[24cf391a]527/** Post position event to a display.
528 *
529 * @param display Display
530 * @param event Event
531 */
[4fbdc3d]532errno_t ds_display_post_ptd_event(ds_display_t *display, ptd_event_t *event)
[24cf391a]533{
534 ds_seat_t *seat;
535
[88d828e]536 /* Determine which seat the event belongs to */
537 seat = ds_display_seat_by_idev(display, event->pos_id);
[4fbdc3d]538 if (seat == NULL)
539 return EOK;
[24cf391a]540
[4fbdc3d]541 return ds_seat_post_ptd_event(seat, event);
[24cf391a]542}
543
[cf32dbd]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;
[d8503fd]555 seat->id = disp->next_seat_id++;
[cf32dbd]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;
[6af4b4f]595
[cf32dbd]596 return list_get_instance(link, ds_seat_t, lseats);
[6af4b4f]597}
598
[d8503fd]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
[88d828e]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{
[b3eeae5]627 ds_idevcfg_t *idevcfg;
[88d828e]628
[b3eeae5]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 */
[88d828e]642 return ds_display_first_seat(disp);
643}
644
[8aef01c]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
[1215db9]678 rc = mem_gc_create(&disp->rect, &alloc, &ds_display_mem_gc_cb,
679 (void *) disp, &disp->bbgc);
[8aef01c]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
[87a7cdb]698/** Add display device to display.
699 *
700 * @param disp Display
701 * @param ddev Display device
[8aef01c]702 * @return EOK on success, or an error code
[87a7cdb]703 */
[8aef01c]704errno_t ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
[87a7cdb]705{
[8aef01c]706 errno_t rc;
[d9d6f29]707 gfx_rect_t old_disp_rect;
[8aef01c]708
[87a7cdb]709 assert(ddev->display == NULL);
710 assert(!link_used(&ddev->lddevs));
711
[d9d6f29]712 old_disp_rect = disp->rect;
713
[87a7cdb]714 ddev->display = disp;
715 list_append(&ddev->lddevs, &disp->ddevs);
[8aef01c]716
717 /* First display device */
718 if (gfx_rect_is_empty(&disp->rect)) {
719 /* Set screen dimensions */
720 disp->rect = ddev->info.rect;
721
[5271e4c]722 /* Create cloning GC */
723 rc = ds_clonegc_create(ddev->gc, &disp->fbgc);
[d9d6f29]724 if (rc != EOK)
725 goto error;
[5271e4c]726
[8aef01c]727 /* Allocate backbuffer */
728 rc = ds_display_alloc_backbuf(disp);
[5271e4c]729 if (rc != EOK) {
[d9d6f29]730 ds_clonegc_delete(disp->fbgc);
731 disp->fbgc = NULL;
[5271e4c]732 goto error;
733 }
734 } else {
735 /* Add new output device to cloning GC */
736 rc = ds_clonegc_add_output(disp->fbgc, ddev->gc);
[8aef01c]737 if (rc != EOK)
738 goto error;
739 }
740
[29a5a99]741 ds_display_update_max_rect(disp);
742
[8aef01c]743 return EOK;
744error:
[d9d6f29]745 disp->rect = old_disp_rect;
[8aef01c]746 list_remove(&ddev->lddevs);
747 return rc;
[87a7cdb]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
[b3eeae5]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
[4d8002d]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
[29a5a99]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
[84e74ea]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 */
[8aef01c]942static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *display)
[87a7cdb]943{
[5271e4c]944 /* In case of unit tests */
945 if (display->fbgc == NULL)
[4fbdc3d]946 return NULL;
[87a7cdb]947
[5271e4c]948 return ds_clonegc_get_ctx(display->fbgc);
[87a7cdb]949}
950
[84e74ea]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 */
[8aef01c]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
[c79545e]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)
[e1f2079]979 gfx_rect_clip(&disp->rect, rect, &crect);
[c79545e]980 else
[e1f2079]981 crect = disp->rect;
[c79545e]982
[84e74ea]983 gc = ds_display_get_gc(disp);
[f5191b4]984 if (gc == NULL)
985 return EOK;
[c79545e]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
[8aef01c]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
[2012fe0]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;
[978c9bc5]1031 ds_seat_t *seat;
[2012fe0]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
[6301a24f]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 */
[978c9bc5]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
[8aef01c]1068 return ds_display_update(disp);
1069}
1070
[2ab8ab3]1071/** Display invalidate callback.
[8aef01c]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 */
[2ab8ab3]1079static void ds_display_invalidate_cb(void *arg, gfx_rect_t *rect)
[8aef01c]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;
[2012fe0]1086}
1087
[2ab8ab3]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
[c8cf261]1099/** @}
1100 */
Note: See TracBrowser for help on using the repository browser.