Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/display/display.c

    r2ab8ab3 r5d380b6  
    11/*
    2  * Copyright (c) 2019 Jiri Svoboda
     2 * Copyright (c) 2023 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4545#include "cursimg.h"
    4646#include "cursor.h"
     47#include "display.h"
    4748#include "seat.h"
    4849#include "window.h"
    49 #include "display.h"
     50#include "wmclient.h"
    5051
    5152static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
    5253static void ds_display_invalidate_cb(void *, gfx_rect_t *);
    5354static 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};
    5460
    5561/** Create display.
     
    9197        fibril_mutex_initialize(&disp->lock);
    9298        list_initialize(&disp->clients);
     99        list_initialize(&disp->wmclients);
     100        list_initialize(&disp->cfgclients);
    93101        disp->next_wnd_id = 1;
    94102        list_initialize(&disp->ddevs);
     103        list_initialize(&disp->idevcfgs);
    95104        list_initialize(&disp->seats);
    96105        list_initialize(&disp->windows);
     
    109118void ds_display_destroy(ds_display_t *disp)
    110119{
     120        int i;
     121
    111122        assert(list_empty(&disp->clients));
     123        assert(list_empty(&disp->wmclients));
     124        assert(list_empty(&disp->cfgclients));
    112125        assert(list_empty(&disp->seats));
    113         /* XXX destroy cursors */
     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
    114137        gfx_color_delete(disp->bg_color);
    115138        free(disp);
     
    198221
    199222        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);
    200302}
    201303
     
    241343                gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
    242344
    243                 if (gfx_pix_inside_rect(pos, &drect))
     345                if (gfx_pix_inside_rect(pos, &drect) &&
     346                    ds_window_is_visible(wnd))
    244347                        return wnd;
    245348
     
    250353}
    251354
     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
    252387/** Add window to display.
    253388 *
     
    257392void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
    258393{
     394        ds_wmclient_t *wmclient;
     395
    259396        assert(wnd->display == NULL);
    260397        assert(!link_used(&wnd->ldwindows));
    261398
    262399        wnd->display = display;
    263         list_prepend(&wnd->ldwindows, &display->windows);
     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        }
    264408}
    265409
     
    270414void ds_display_remove_window(ds_window_t *wnd)
    271415{
     416        ds_wmclient_t *wmclient;
     417        ds_display_t *display;
     418
     419        display = wnd->display;
     420
    272421        list_remove(&wnd->ldwindows);
    273422        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);
    274444}
    275445
     
    347517        ds_seat_t *seat;
    348518
    349         // TODO Determine which seat the event belongs to
    350         seat = ds_display_first_seat(display);
     519        /* Determine which seat the event belongs to */
     520        seat = ds_display_seat_by_idev(display, event->kbd_id);
    351521        if (seat == NULL)
    352522                return EOK;
     
    364534        ds_seat_t *seat;
    365535
    366         // TODO Determine which seat the event belongs to
    367         seat = ds_display_first_seat(display);
     536        /* Determine which seat the event belongs to */
     537        seat = ds_display_seat_by_idev(display, event->pos_id);
    368538        if (seat == NULL)
    369539                return EOK;
     
    383553
    384554        seat->display = disp;
     555        seat->id = disp->next_seat_id++;
    385556        list_append(&seat->lseats, &disp->seats);
    386557}
     
    424595
    425596        return list_get_instance(link, ds_seat_t, lseats);
     597}
     598
     599/** Get default seat in display.
     600 *
     601 * @param disp Display
     602 * @return First seat or @c NULL if there is none
     603 */
     604ds_seat_t *ds_display_default_seat(ds_display_t *disp)
     605{
     606        /* XXX Probably not the best solution */
     607        return ds_display_first_seat(disp);
     608}
     609
     610/** Find seat by ID.
     611 *
     612 * @param display Display
     613 * @param id Seat ID
     614 */
     615ds_seat_t *ds_display_find_seat(ds_display_t *display, ds_seat_id_t id)
     616{
     617        ds_seat_t *seat;
     618
     619        seat = ds_display_first_seat(display);
     620        while (seat != NULL) {
     621                if (seat->id == id)
     622                        return seat;
     623
     624                seat = ds_display_next_seat(seat);
     625        }
     626
     627        return NULL;
     628}
     629
     630/** Get seat which owns the specified input device.
     631 *
     632 * @param disp Display
     633 * @param idev_id Input device ID
     634 * @return Seat which owns device with ID @a idev_id or @c NULL if not found
     635 */
     636ds_seat_t *ds_display_seat_by_idev(ds_display_t *disp, ds_idev_id_t idev_id)
     637{
     638        ds_idevcfg_t *idevcfg;
     639
     640        /*
     641         * Find input device configuration entry that maps this input device
     642         * to a seat.
     643         */
     644        idevcfg = ds_display_first_idevcfg(disp);
     645        while (idevcfg != NULL) {
     646                if (idevcfg->svc_id == idev_id)
     647                        return idevcfg->seat;
     648
     649                idevcfg = ds_display_next_idevcfg(idevcfg);
     650        }
     651
     652        /* If none was found, return the default seat */
     653        return ds_display_default_seat(disp);
    426654}
    427655
     
    459687                goto error;
    460688
    461         rc = mem_gc_create(&disp->rect, &alloc,
    462             ds_display_invalidate_cb, ds_display_update_cb, (void *) disp,
    463             &disp->bbgc);
     689        rc = mem_gc_create(&disp->rect, &alloc, &ds_display_mem_gc_cb,
     690            (void *) disp, &disp->bbgc);
    464691        if (rc != EOK)
    465692                goto error;
     
    489716{
    490717        errno_t rc;
     718        gfx_rect_t old_disp_rect;
    491719
    492720        assert(ddev->display == NULL);
    493721        assert(!link_used(&ddev->lddevs));
     722
     723        old_disp_rect = disp->rect;
    494724
    495725        ddev->display = disp;
     
    503733                /* Create cloning GC */
    504734                rc = ds_clonegc_create(ddev->gc, &disp->fbgc);
    505                 if (rc != EOK) {
    506                         // XXX Remove output
    507                         return ENOMEM;
    508                 }
     735                if (rc != EOK)
     736                        goto error;
    509737
    510738                /* Allocate backbuffer */
    511739                rc = ds_display_alloc_backbuf(disp);
    512740                if (rc != EOK) {
    513                         // XXX Remove output
    514                         // XXX Delete clone GC
     741                        ds_clonegc_delete(disp->fbgc);
     742                        disp->fbgc = NULL;
    515743                        goto error;
    516744                }
     
    522750        }
    523751
     752        ds_display_update_max_rect(disp);
     753
    524754        return EOK;
    525755error:
    526         disp->rect.p0.x = 0;
    527         disp->rect.p0.y = 0;
    528         disp->rect.p1.x = 0;
    529         disp->rect.p1.y = 0;
     756        disp->rect = old_disp_rect;
    530757        list_remove(&ddev->lddevs);
    531758        return rc;
     
    572799}
    573800
     801/** Add input device configuration entry to display.
     802 *
     803 * @param disp Display
     804 * @param idevcfg Input device configuration
     805 */
     806void ds_display_add_idevcfg(ds_display_t *disp, ds_idevcfg_t *idevcfg)
     807{
     808        assert(idevcfg->display == NULL);
     809        assert(!link_used(&idevcfg->ldispidcfgs));
     810
     811        idevcfg->display = disp;
     812        list_append(&idevcfg->ldispidcfgs, &disp->idevcfgs);
     813}
     814
     815/** Remove input device configuration entry from display.
     816 *
     817 * @param idevcfg Input device configuration entry
     818 */
     819void ds_display_remove_idevcfg(ds_idevcfg_t *idevcfg)
     820{
     821        list_remove(&idevcfg->ldispidcfgs);
     822        idevcfg->display = NULL;
     823}
     824
     825/** Get first input device configuration entry in display.
     826 *
     827 * @param disp Display
     828 * @return First input device configuration entry or @c NULL if there is none
     829 */
     830ds_idevcfg_t *ds_display_first_idevcfg(ds_display_t *disp)
     831{
     832        link_t *link = list_first(&disp->idevcfgs);
     833
     834        if (link == NULL)
     835                return NULL;
     836
     837        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     838}
     839
     840/** Get next input device configuration entry in display.
     841 *
     842 * @param idevcfg Current input device configuration entry
     843 * @return Next input device configuration entry or @c NULL if there is none
     844 */
     845ds_idevcfg_t *ds_display_next_idevcfg(ds_idevcfg_t *idevcfg)
     846{
     847        link_t *link = list_next(&idevcfg->ldispidcfgs, &idevcfg->display->idevcfgs);
     848
     849        if (link == NULL)
     850                return NULL;
     851
     852        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     853}
     854
    574855/** Add cursor to display.
    575856 *
     
    594875        list_remove(&cursor->ldisplay);
    595876        cursor->display = NULL;
     877}
     878
     879/** Update display maximize rectangle.
     880 *
     881 * Recalculate the maximize rectangle (the rectangle used for maximized
     882 * windows).
     883 *
     884 * @param display Display
     885 */
     886void ds_display_update_max_rect(ds_display_t *display)
     887{
     888        ds_window_t *wnd;
     889        gfx_rect_t max_rect;
     890        gfx_rect_t drect;
     891
     892        /* Start with the entire display */
     893        max_rect = display->rect;
     894
     895        wnd = ds_display_first_window(display);
     896        while (wnd != NULL) {
     897                /* Should maximized windows avoid this window? */
     898                if ((wnd->flags & wndf_avoid) != 0) {
     899                        /* Window bounding rectangle on display */
     900                        gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
     901
     902                        /* Crop maximized rectangle */
     903                        ds_display_crop_max_rect(&drect, &max_rect);
     904                }
     905
     906                wnd = ds_display_next_window(wnd);
     907        }
     908
     909        /* Update the maximize rectangle */
     910        display->max_rect = max_rect;
     911}
     912
     913/** Crop maximize rectangle.
     914 *
     915 * Use the avoid rectangle @a arect to crop off maximization rectangle
     916 * @a mrect. If @a arect covers the top, bottom, left or right part
     917 * of @a mrect, it will be cropped off. Otherwise there will be
     918 * no effect.
     919 *
     920 * @param arect Avoid rectangle
     921 * @param mrect Maximize rectangle to be modified
     922 */
     923void ds_display_crop_max_rect(gfx_rect_t *arect, gfx_rect_t *mrect)
     924{
     925        if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     926            arect->p1.x == mrect->p1.x) {
     927                /* Cropp off top part */
     928                mrect->p0.y = arect->p1.y;
     929        } else if (arect->p0.x == mrect->p0.x && arect->p1.x == mrect->p1.x &&
     930            arect->p1.y == mrect->p1.y) {
     931                /* Cropp off bottom part */
     932                mrect->p1.y = arect->p0.y;
     933        } else if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     934            arect->p1.y == mrect->p1.y) {
     935                /* Cropp off left part */
     936                mrect->p0.x = arect->p1.x;
     937        } else if (arect->p0.y == mrect->p0.y && arect->p1.x == mrect->p1.x &&
     938            arect->p1.y == mrect->p1.y) {
     939                /* Cropp off right part */
     940                mrect->p1.x = arect->p0.x;
     941        }
    596942}
    597943
Note: See TracChangeset for help on using the changeset viewer.