Ignore:
File:
1 edited

Legend:

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

    r1215db9 re90019d  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4141#include <memgfx/memgc.h>
    4242#include <stdlib.h>
     43#include <str.h>
    4344#include "client.h"
    4445#include "clonegc.h"
    4546#include "cursimg.h"
    4647#include "cursor.h"
     48#include "display.h"
     49#include "idevcfg.h"
    4750#include "seat.h"
    4851#include "window.h"
    49 #include "display.h"
     52#include "wmclient.h"
    5053
    5154static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
     
    9699        fibril_mutex_initialize(&disp->lock);
    97100        list_initialize(&disp->clients);
     101        list_initialize(&disp->wmclients);
     102        list_initialize(&disp->cfgclients);
    98103        disp->next_wnd_id = 1;
     104        disp->next_seat_id = 1;
    99105        list_initialize(&disp->ddevs);
     106        list_initialize(&disp->idevcfgs);
    100107        list_initialize(&disp->seats);
    101108        list_initialize(&disp->windows);
     
    114121void ds_display_destroy(ds_display_t *disp)
    115122{
     123        int i;
     124
    116125        assert(list_empty(&disp->clients));
     126        assert(list_empty(&disp->wmclients));
     127        assert(list_empty(&disp->cfgclients));
    117128        assert(list_empty(&disp->seats));
    118         /* XXX destroy cursors */
     129        assert(list_empty(&disp->ddevs));
     130        assert(list_empty(&disp->idevcfgs));
     131        assert(list_empty(&disp->seats));
     132        assert(list_empty(&disp->windows));
     133
     134        /* Destroy cursors */
     135        for (i = 0; i < dcurs_limit; i++) {
     136                ds_cursor_destroy(disp->cursor[i]);
     137                disp->cursor[i] = NULL;
     138        }
     139
    119140        gfx_color_delete(disp->bg_color);
    120141        free(disp);
    121142}
    122143
     144/** Load display configuration from SIF file.
     145 *
     146 * @param display Display
     147 * @param cfgpath Configuration file path
     148 *
     149 * @return EOK on success or an error code
     150 */
     151errno_t ds_display_load_cfg(ds_display_t *display, const char *cfgpath)
     152{
     153        sif_doc_t *doc = NULL;
     154        sif_node_t *rnode;
     155        sif_node_t *ndisplay;
     156        sif_node_t *nseats;
     157        sif_node_t *nseat;
     158        ds_seat_t *seat;
     159        sif_node_t *nidevcfgs;
     160        sif_node_t *nidevcfg;
     161        const char *ntype;
     162        ds_idevcfg_t *idevcfg;
     163        errno_t rc;
     164
     165        rc = sif_load(cfgpath, &doc);
     166        if (rc != EOK)
     167                goto error;
     168
     169        rnode = sif_get_root(doc);
     170        ndisplay = sif_node_first_child(rnode);
     171        ntype = sif_node_get_type(ndisplay);
     172        if (str_cmp(ntype, "display") != 0) {
     173                rc = EIO;
     174                goto error;
     175        }
     176
     177        nseats = sif_node_first_child(ndisplay);
     178        ntype = sif_node_get_type(nseats);
     179        if (str_cmp(ntype, "seats") != 0) {
     180                rc = EIO;
     181                goto error;
     182        }
     183
     184        /* Load individual seats */
     185        nseat = sif_node_first_child(nseats);
     186        while (nseat != NULL) {
     187                ntype = sif_node_get_type(nseat);
     188                if (str_cmp(ntype, "seat") != 0) {
     189                        rc = EIO;
     190                        goto error;
     191                }
     192
     193                rc = ds_seat_load(display, nseat, &seat);
     194                if (rc != EOK)
     195                        goto error;
     196
     197                (void)seat;
     198                nseat = sif_node_next_child(nseat);
     199        }
     200
     201        nidevcfgs = sif_node_next_child(nseats);
     202        ntype = sif_node_get_type(nidevcfgs);
     203        if (str_cmp(ntype, "idevcfgs") != 0) {
     204                rc = EIO;
     205                goto error;
     206        }
     207
     208        /* Load individual input device configuration entries */
     209        nidevcfg = sif_node_first_child(nidevcfgs);
     210        while (nidevcfg != NULL) {
     211                ntype = sif_node_get_type(nidevcfg);
     212                if (str_cmp(ntype, "idevcfg") != 0) {
     213                        rc = EIO;
     214                        goto error;
     215                }
     216
     217                /*
     218                 * Load device configuration entry. If the device
     219                 * is not currently connected (ENOENT), skip it.
     220                 */
     221                rc = ds_idevcfg_load(display, nidevcfg, &idevcfg);
     222                if (rc != EOK && rc != ENOENT)
     223                        goto error;
     224
     225                (void)idevcfg;
     226                nidevcfg = sif_node_next_child(nidevcfg);
     227        }
     228
     229        sif_delete(doc);
     230        return EOK;
     231error:
     232        if (doc != NULL)
     233                sif_delete(doc);
     234
     235        seat = ds_display_first_seat(display);
     236        while (seat != NULL) {
     237                ds_seat_destroy(seat);
     238                seat = ds_display_first_seat(display);
     239        }
     240        return rc;
     241}
     242
     243/** Save display configuration to SIF file.
     244 *
     245 * @param display Display
     246 * @param cfgpath Configuration file path
     247 *
     248 * @return EOK on success or an error code
     249 */
     250errno_t ds_display_save_cfg(ds_display_t *display, const char *cfgpath)
     251{
     252        sif_doc_t *doc = NULL;
     253        sif_node_t *rnode;
     254        sif_node_t *ndisplay;
     255        sif_node_t *nseats;
     256        sif_node_t *nseat;
     257        ds_seat_t *seat;
     258        sif_node_t *nidevcfgs;
     259        sif_node_t *nidevcfg;
     260        ds_idevcfg_t *idevcfg;
     261        errno_t rc;
     262
     263        rc = sif_new(&doc);
     264        if (rc != EOK)
     265                goto error;
     266
     267        rnode = sif_get_root(doc);
     268        rc = sif_node_append_child(rnode, "display", &ndisplay);
     269        if (rc != EOK)
     270                goto error;
     271
     272        rc = sif_node_append_child(ndisplay, "seats", &nseats);
     273        if (rc != EOK)
     274                goto error;
     275
     276        /* Save individual seats */
     277        seat = ds_display_first_seat(display);
     278        while (seat != NULL) {
     279                rc = sif_node_append_child(nseats, "seat", &nseat);
     280                if (rc != EOK)
     281                        goto error;
     282
     283                rc = ds_seat_save(seat, nseat);
     284                if (rc != EOK)
     285                        goto error;
     286
     287                seat = ds_display_next_seat(seat);
     288        }
     289
     290        rc = sif_node_append_child(ndisplay, "idevcfgs", &nidevcfgs);
     291        if (rc != EOK)
     292                goto error;
     293
     294        /* Save individual input device configuration entries */
     295        idevcfg = ds_display_first_idevcfg(display);
     296        while (idevcfg != NULL) {
     297                rc = sif_node_append_child(nidevcfgs, "idevcfg", &nidevcfg);
     298                if (rc != EOK)
     299                        goto error;
     300
     301                rc = ds_idevcfg_save(idevcfg, nidevcfg);
     302                if (rc != EOK)
     303                        goto error;
     304
     305                idevcfg = ds_display_next_idevcfg(idevcfg);
     306        }
     307
     308        rc = sif_save(doc, cfgpath);
     309        if (rc != EOK)
     310                goto error;
     311
     312        sif_delete(doc);
     313        return EOK;
     314error:
     315        if (doc != NULL)
     316                sif_delete(doc);
     317        return rc;
     318}
     319
    123320/** Lock display.
    124321 *
     
    203400
    204401        return list_get_instance(link, ds_client_t, lclients);
     402}
     403
     404/** Add WM client to display.
     405 *
     406 * @param disp Display
     407 * @param wmclient WM client
     408 */
     409void ds_display_add_wmclient(ds_display_t *disp, ds_wmclient_t *wmclient)
     410{
     411        assert(wmclient->display == NULL);
     412        assert(!link_used(&wmclient->lwmclients));
     413
     414        wmclient->display = disp;
     415        list_append(&wmclient->lwmclients, &disp->wmclients);
     416}
     417
     418/** Remove WM client from display.
     419 *
     420 * @param wmclient WM client
     421 */
     422void ds_display_remove_wmclient(ds_wmclient_t *wmclient)
     423{
     424        list_remove(&wmclient->lwmclients);
     425        wmclient->display = NULL;
     426}
     427
     428/** Add CFG client to display.
     429 *
     430 * @param disp Display
     431 * @param cfgclient CFG client
     432 */
     433void ds_display_add_cfgclient(ds_display_t *disp, ds_cfgclient_t *cfgclient)
     434{
     435        assert(cfgclient->display == NULL);
     436        assert(!link_used(&cfgclient->lcfgclients));
     437
     438        cfgclient->display = disp;
     439        list_append(&cfgclient->lcfgclients, &disp->cfgclients);
     440}
     441
     442/** Remove CFG client from display.
     443 *
     444 * @param cfgclient CFG client
     445 */
     446void ds_display_remove_cfgclient(ds_cfgclient_t *cfgclient)
     447{
     448        list_remove(&cfgclient->lcfgclients);
     449        cfgclient->display = NULL;
     450}
     451
     452/** Get first WM client in display.
     453 *
     454 * @param disp Display
     455 * @return First WM client or @c NULL if there is none
     456 */
     457ds_wmclient_t *ds_display_first_wmclient(ds_display_t *disp)
     458{
     459        link_t *link = list_first(&disp->wmclients);
     460
     461        if (link == NULL)
     462                return NULL;
     463
     464        return list_get_instance(link, ds_wmclient_t, lwmclients);
     465}
     466
     467/** Get next WM client in display.
     468 *
     469 * @param wmclient Current WM client
     470 * @return Next WM client or @c NULL if there is none
     471 */
     472ds_wmclient_t *ds_display_next_wmclient(ds_wmclient_t *wmclient)
     473{
     474        link_t *link = list_next(&wmclient->lwmclients,
     475            &wmclient->display->wmclients);
     476
     477        if (link == NULL)
     478                return NULL;
     479
     480        return list_get_instance(link, ds_wmclient_t, lwmclients);
    205481}
    206482
     
    246522                gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
    247523
    248                 if (gfx_pix_inside_rect(pos, &drect))
     524                if (gfx_pix_inside_rect(pos, &drect) &&
     525                    ds_window_is_visible(wnd))
    249526                        return wnd;
    250527
     
    255532}
    256533
     534/** Add window to window list.
     535 *
     536 * Topmost windows are enlisted before any other window. Non-topmost
     537 * windows are enlisted before any other non-topmost window.
     538 *
     539 * @param display Display
     540 * @param wnd Window
     541 */
     542void ds_display_enlist_window(ds_display_t *display, ds_window_t *wnd)
     543{
     544        ds_window_t *w;
     545
     546        assert(wnd->display == display);
     547        assert(!link_used(&wnd->ldwindows));
     548
     549        if ((wnd->flags & wndf_topmost) == 0) {
     550                /* Find the first non-topmost window */
     551                w = ds_display_first_window(display);
     552                while (w != NULL && (w->flags & wndf_topmost) != 0)
     553                        w = ds_display_next_window(w);
     554
     555                if (w != NULL)
     556                        list_insert_before(&wnd->ldwindows, &w->ldwindows);
     557                else
     558                        list_append(&wnd->ldwindows, &display->windows);
     559        } else {
     560                /* Insert at the beginning */
     561                list_prepend(&wnd->ldwindows, &display->windows);
     562        }
     563
     564}
     565
    257566/** Add window to display.
    258567 *
     
    262571void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
    263572{
     573        ds_wmclient_t *wmclient;
     574
    264575        assert(wnd->display == NULL);
    265576        assert(!link_used(&wnd->ldwindows));
    266577
    267578        wnd->display = display;
    268         list_prepend(&wnd->ldwindows, &display->windows);
     579        ds_display_enlist_window(display, wnd);
     580
     581        /* Notify window managers about the new window */
     582        wmclient = ds_display_first_wmclient(display);
     583        while (wmclient != NULL) {
     584                ds_wmclient_post_wnd_added_event(wmclient, wnd->id);
     585                wmclient = ds_display_next_wmclient(wmclient);
     586        }
    269587}
    270588
     
    275593void ds_display_remove_window(ds_window_t *wnd)
    276594{
     595        ds_wmclient_t *wmclient;
     596        ds_display_t *display;
     597
     598        display = wnd->display;
     599
    277600        list_remove(&wnd->ldwindows);
    278601        wnd->display = NULL;
     602
     603        /* Notify window managers about the removed window */
     604        wmclient = ds_display_first_wmclient(display);
     605        while (wmclient != NULL) {
     606                ds_wmclient_post_wnd_removed_event(wmclient, wnd->id);
     607                wmclient = ds_display_next_wmclient(wmclient);
     608        }
     609}
     610
     611/** Move window to top.
     612 *
     613 * @param display Display
     614 * @param wnd Window
     615 */
     616void ds_display_window_to_top(ds_window_t *wnd)
     617{
     618        assert(wnd->display != NULL);
     619        assert(link_used(&wnd->ldwindows));
     620
     621        list_remove(&wnd->ldwindows);
     622        ds_display_enlist_window(wnd->display, wnd);
    279623}
    280624
     
    352696        ds_seat_t *seat;
    353697
    354         // TODO Determine which seat the event belongs to
    355         seat = ds_display_first_seat(display);
     698        /* Determine which seat the event belongs to */
     699        seat = ds_display_seat_by_idev(display, event->kbd_id);
    356700        if (seat == NULL)
    357701                return EOK;
     
    369713        ds_seat_t *seat;
    370714
    371         // TODO Determine which seat the event belongs to
    372         seat = ds_display_first_seat(display);
     715        /* Determine which seat the event belongs to */
     716        seat = ds_display_seat_by_idev(display, event->pos_id);
    373717        if (seat == NULL)
    374718                return EOK;
     
    388732
    389733        seat->display = disp;
     734        seat->id = disp->next_seat_id++;
    390735        list_append(&seat->lseats, &disp->seats);
    391736}
     
    429774
    430775        return list_get_instance(link, ds_seat_t, lseats);
     776}
     777
     778/** Get default seat in display.
     779 *
     780 * @param disp Display
     781 * @return First seat or @c NULL if there is none
     782 */
     783ds_seat_t *ds_display_default_seat(ds_display_t *disp)
     784{
     785        /* XXX Probably not the best solution */
     786        return ds_display_first_seat(disp);
     787}
     788
     789/** Find seat by ID.
     790 *
     791 * @param display Display
     792 * @param id Seat ID
     793 */
     794ds_seat_t *ds_display_find_seat(ds_display_t *display, ds_seat_id_t id)
     795{
     796        ds_seat_t *seat;
     797
     798        seat = ds_display_first_seat(display);
     799        while (seat != NULL) {
     800                if (seat->id == id)
     801                        return seat;
     802
     803                seat = ds_display_next_seat(seat);
     804        }
     805
     806        return NULL;
     807}
     808
     809/** Get seat which owns the specified input device.
     810 *
     811 * @param disp Display
     812 * @param idev_id Input device ID
     813 * @return Seat which owns device with ID @a idev_id or @c NULL if not found
     814 */
     815ds_seat_t *ds_display_seat_by_idev(ds_display_t *disp, ds_idev_id_t idev_id)
     816{
     817        ds_idevcfg_t *idevcfg;
     818
     819        /*
     820         * Find input device configuration entry that maps this input device
     821         * to a seat.
     822         */
     823        idevcfg = ds_display_first_idevcfg(disp);
     824        while (idevcfg != NULL) {
     825                if (idevcfg->svc_id == idev_id)
     826                        return idevcfg->seat;
     827
     828                idevcfg = ds_display_next_idevcfg(idevcfg);
     829        }
     830
     831        /* If none was found, return the default seat */
     832        return ds_display_default_seat(disp);
    431833}
    432834
     
    493895{
    494896        errno_t rc;
     897        gfx_rect_t old_disp_rect;
    495898
    496899        assert(ddev->display == NULL);
    497900        assert(!link_used(&ddev->lddevs));
     901
     902        old_disp_rect = disp->rect;
    498903
    499904        ddev->display = disp;
     
    507912                /* Create cloning GC */
    508913                rc = ds_clonegc_create(ddev->gc, &disp->fbgc);
    509                 if (rc != EOK) {
    510                         // XXX Remove output
    511                         return ENOMEM;
    512                 }
     914                if (rc != EOK)
     915                        goto error;
    513916
    514917                /* Allocate backbuffer */
    515918                rc = ds_display_alloc_backbuf(disp);
    516919                if (rc != EOK) {
    517                         // XXX Remove output
    518                         // XXX Delete clone GC
     920                        ds_clonegc_delete(disp->fbgc);
     921                        disp->fbgc = NULL;
    519922                        goto error;
    520923                }
     
    526929        }
    527930
     931        ds_display_update_max_rect(disp);
     932
    528933        return EOK;
    529934error:
    530         disp->rect.p0.x = 0;
    531         disp->rect.p0.y = 0;
    532         disp->rect.p1.x = 0;
    533         disp->rect.p1.y = 0;
     935        disp->rect = old_disp_rect;
    534936        list_remove(&ddev->lddevs);
    535937        return rc;
     
    576978}
    577979
     980/** Add input device configuration entry to display.
     981 *
     982 * @param disp Display
     983 * @param idevcfg Input device configuration
     984 */
     985void ds_display_add_idevcfg(ds_display_t *disp, ds_idevcfg_t *idevcfg)
     986{
     987        assert(idevcfg->display == NULL);
     988        assert(!link_used(&idevcfg->ldispidcfgs));
     989
     990        idevcfg->display = disp;
     991        list_append(&idevcfg->ldispidcfgs, &disp->idevcfgs);
     992}
     993
     994/** Remove input device configuration entry from display.
     995 *
     996 * @param idevcfg Input device configuration entry
     997 */
     998void ds_display_remove_idevcfg(ds_idevcfg_t *idevcfg)
     999{
     1000        list_remove(&idevcfg->ldispidcfgs);
     1001        idevcfg->display = NULL;
     1002}
     1003
     1004/** Get first input device configuration entry in display.
     1005 *
     1006 * @param disp Display
     1007 * @return First input device configuration entry or @c NULL if there is none
     1008 */
     1009ds_idevcfg_t *ds_display_first_idevcfg(ds_display_t *disp)
     1010{
     1011        link_t *link = list_first(&disp->idevcfgs);
     1012
     1013        if (link == NULL)
     1014                return NULL;
     1015
     1016        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     1017}
     1018
     1019/** Get next input device configuration entry in display.
     1020 *
     1021 * @param idevcfg Current input device configuration entry
     1022 * @return Next input device configuration entry or @c NULL if there is none
     1023 */
     1024ds_idevcfg_t *ds_display_next_idevcfg(ds_idevcfg_t *idevcfg)
     1025{
     1026        link_t *link = list_next(&idevcfg->ldispidcfgs, &idevcfg->display->idevcfgs);
     1027
     1028        if (link == NULL)
     1029                return NULL;
     1030
     1031        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     1032}
     1033
    5781034/** Add cursor to display.
    5791035 *
     
    5981054        list_remove(&cursor->ldisplay);
    5991055        cursor->display = NULL;
     1056}
     1057
     1058/** Update display maximize rectangle.
     1059 *
     1060 * Recalculate the maximize rectangle (the rectangle used for maximized
     1061 * windows).
     1062 *
     1063 * @param display Display
     1064 */
     1065void ds_display_update_max_rect(ds_display_t *display)
     1066{
     1067        ds_window_t *wnd;
     1068        gfx_rect_t max_rect;
     1069        gfx_rect_t drect;
     1070
     1071        /* Start with the entire display */
     1072        max_rect = display->rect;
     1073
     1074        wnd = ds_display_first_window(display);
     1075        while (wnd != NULL) {
     1076                /* Should maximized windows avoid this window? */
     1077                if ((wnd->flags & wndf_avoid) != 0) {
     1078                        /* Window bounding rectangle on display */
     1079                        gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
     1080
     1081                        /* Crop maximized rectangle */
     1082                        ds_display_crop_max_rect(&drect, &max_rect);
     1083                }
     1084
     1085                wnd = ds_display_next_window(wnd);
     1086        }
     1087
     1088        /* Update the maximize rectangle */
     1089        display->max_rect = max_rect;
     1090}
     1091
     1092/** Crop maximize rectangle.
     1093 *
     1094 * Use the avoid rectangle @a arect to crop off maximization rectangle
     1095 * @a mrect. If @a arect covers the top, bottom, left or right part
     1096 * of @a mrect, it will be cropped off. Otherwise there will be
     1097 * no effect.
     1098 *
     1099 * @param arect Avoid rectangle
     1100 * @param mrect Maximize rectangle to be modified
     1101 */
     1102void ds_display_crop_max_rect(gfx_rect_t *arect, gfx_rect_t *mrect)
     1103{
     1104        if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     1105            arect->p1.x == mrect->p1.x) {
     1106                /* Cropp off top part */
     1107                mrect->p0.y = arect->p1.y;
     1108        } else if (arect->p0.x == mrect->p0.x && arect->p1.x == mrect->p1.x &&
     1109            arect->p1.y == mrect->p1.y) {
     1110                /* Cropp off bottom part */
     1111                mrect->p1.y = arect->p0.y;
     1112        } else if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     1113            arect->p1.y == mrect->p1.y) {
     1114                /* Cropp off left part */
     1115                mrect->p0.x = arect->p1.x;
     1116        } else if (arect->p0.y == mrect->p0.y && arect->p1.x == mrect->p1.x &&
     1117            arect->p1.y == mrect->p1.y) {
     1118                /* Cropp off right part */
     1119                mrect->p1.x = arect->p0.x;
     1120        }
    6001121}
    6011122
Note: See TracChangeset for help on using the changeset viewer.