Ignore:
File:
1 edited

Legend:

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

    r2ab8ab3 r6fbd1f9  
    11/*
    2  * Copyright (c) 2019 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 *);
    5255static void ds_display_invalidate_cb(void *, gfx_rect_t *);
    5356static void ds_display_update_cb(void *);
     57
     58static mem_gc_cb_t ds_display_mem_gc_cb = {
     59        .invalidate = ds_display_invalidate_cb,
     60        .update = ds_display_update_cb
     61};
    5462
    5563/** Create display.
     
    9199        fibril_mutex_initialize(&disp->lock);
    92100        list_initialize(&disp->clients);
     101        list_initialize(&disp->wmclients);
     102        list_initialize(&disp->cfgclients);
    93103        disp->next_wnd_id = 1;
     104        disp->next_seat_id = 1;
    94105        list_initialize(&disp->ddevs);
     106        list_initialize(&disp->idevcfgs);
     107        list_initialize(&disp->ievents);
     108        fibril_condvar_initialize(&disp->ievent_cv);
    95109        list_initialize(&disp->seats);
    96110        list_initialize(&disp->windows);
     
    109123void ds_display_destroy(ds_display_t *disp)
    110124{
     125        int i;
     126
    111127        assert(list_empty(&disp->clients));
     128        assert(list_empty(&disp->wmclients));
     129        assert(list_empty(&disp->cfgclients));
    112130        assert(list_empty(&disp->seats));
    113         /* XXX destroy cursors */
     131        assert(list_empty(&disp->ddevs));
     132        assert(list_empty(&disp->idevcfgs));
     133        assert(list_empty(&disp->ievents));
     134        assert(list_empty(&disp->seats));
     135        assert(list_empty(&disp->windows));
     136
     137        /* Destroy cursors */
     138        for (i = 0; i < dcurs_limit; i++) {
     139                ds_cursor_destroy(disp->cursor[i]);
     140                disp->cursor[i] = NULL;
     141        }
     142
    114143        gfx_color_delete(disp->bg_color);
    115144        free(disp);
    116145}
    117146
     147/** Load display configuration from SIF file.
     148 *
     149 * @param display Display
     150 * @param cfgpath Configuration file path
     151 *
     152 * @return EOK on success or an error code
     153 */
     154errno_t ds_display_load_cfg(ds_display_t *display, const char *cfgpath)
     155{
     156        sif_doc_t *doc = NULL;
     157        sif_node_t *rnode;
     158        sif_node_t *ndisplay;
     159        sif_node_t *nseats;
     160        sif_node_t *nseat;
     161        ds_seat_t *seat;
     162        sif_node_t *nidevcfgs;
     163        sif_node_t *nidevcfg;
     164        const char *ntype;
     165        ds_idevcfg_t *idevcfg;
     166        errno_t rc;
     167
     168        rc = sif_load(cfgpath, &doc);
     169        if (rc != EOK)
     170                goto error;
     171
     172        rnode = sif_get_root(doc);
     173        ndisplay = sif_node_first_child(rnode);
     174        ntype = sif_node_get_type(ndisplay);
     175        if (str_cmp(ntype, "display") != 0) {
     176                rc = EIO;
     177                goto error;
     178        }
     179
     180        nseats = sif_node_first_child(ndisplay);
     181        ntype = sif_node_get_type(nseats);
     182        if (str_cmp(ntype, "seats") != 0) {
     183                rc = EIO;
     184                goto error;
     185        }
     186
     187        /* Load individual seats */
     188        nseat = sif_node_first_child(nseats);
     189        while (nseat != NULL) {
     190                ntype = sif_node_get_type(nseat);
     191                if (str_cmp(ntype, "seat") != 0) {
     192                        rc = EIO;
     193                        goto error;
     194                }
     195
     196                rc = ds_seat_load(display, nseat, &seat);
     197                if (rc != EOK)
     198                        goto error;
     199
     200                (void)seat;
     201                nseat = sif_node_next_child(nseat);
     202        }
     203
     204        nidevcfgs = sif_node_next_child(nseats);
     205        ntype = sif_node_get_type(nidevcfgs);
     206        if (str_cmp(ntype, "idevcfgs") != 0) {
     207                rc = EIO;
     208                goto error;
     209        }
     210
     211        /* Load individual input device configuration entries */
     212        nidevcfg = sif_node_first_child(nidevcfgs);
     213        while (nidevcfg != NULL) {
     214                ntype = sif_node_get_type(nidevcfg);
     215                if (str_cmp(ntype, "idevcfg") != 0) {
     216                        rc = EIO;
     217                        goto error;
     218                }
     219
     220                /*
     221                 * Load device configuration entry. If the device
     222                 * is not currently connected (ENOENT), skip it.
     223                 */
     224                rc = ds_idevcfg_load(display, nidevcfg, &idevcfg);
     225                if (rc != EOK && rc != ENOENT)
     226                        goto error;
     227
     228                (void)idevcfg;
     229                nidevcfg = sif_node_next_child(nidevcfg);
     230        }
     231
     232        sif_delete(doc);
     233        return EOK;
     234error:
     235        if (doc != NULL)
     236                sif_delete(doc);
     237
     238        seat = ds_display_first_seat(display);
     239        while (seat != NULL) {
     240                ds_seat_destroy(seat);
     241                seat = ds_display_first_seat(display);
     242        }
     243        return rc;
     244}
     245
     246/** Save display configuration to SIF file.
     247 *
     248 * @param display Display
     249 * @param cfgpath Configuration file path
     250 *
     251 * @return EOK on success or an error code
     252 */
     253errno_t ds_display_save_cfg(ds_display_t *display, const char *cfgpath)
     254{
     255        sif_doc_t *doc = NULL;
     256        sif_node_t *rnode;
     257        sif_node_t *ndisplay;
     258        sif_node_t *nseats;
     259        sif_node_t *nseat;
     260        ds_seat_t *seat;
     261        sif_node_t *nidevcfgs;
     262        sif_node_t *nidevcfg;
     263        ds_idevcfg_t *idevcfg;
     264        errno_t rc;
     265
     266        rc = sif_new(&doc);
     267        if (rc != EOK)
     268                goto error;
     269
     270        rnode = sif_get_root(doc);
     271        rc = sif_node_append_child(rnode, "display", &ndisplay);
     272        if (rc != EOK)
     273                goto error;
     274
     275        rc = sif_node_append_child(ndisplay, "seats", &nseats);
     276        if (rc != EOK)
     277                goto error;
     278
     279        /* Save individual seats */
     280        seat = ds_display_first_seat(display);
     281        while (seat != NULL) {
     282                rc = sif_node_append_child(nseats, "seat", &nseat);
     283                if (rc != EOK)
     284                        goto error;
     285
     286                rc = ds_seat_save(seat, nseat);
     287                if (rc != EOK)
     288                        goto error;
     289
     290                seat = ds_display_next_seat(seat);
     291        }
     292
     293        rc = sif_node_append_child(ndisplay, "idevcfgs", &nidevcfgs);
     294        if (rc != EOK)
     295                goto error;
     296
     297        /* Save individual input device configuration entries */
     298        idevcfg = ds_display_first_idevcfg(display);
     299        while (idevcfg != NULL) {
     300                rc = sif_node_append_child(nidevcfgs, "idevcfg", &nidevcfg);
     301                if (rc != EOK)
     302                        goto error;
     303
     304                rc = ds_idevcfg_save(idevcfg, nidevcfg);
     305                if (rc != EOK)
     306                        goto error;
     307
     308                idevcfg = ds_display_next_idevcfg(idevcfg);
     309        }
     310
     311        rc = sif_save(doc, cfgpath);
     312        if (rc != EOK)
     313                goto error;
     314
     315        sif_delete(doc);
     316        return EOK;
     317error:
     318        if (doc != NULL)
     319                sif_delete(doc);
     320        return rc;
     321}
     322
    118323/** Lock display.
    119324 *
     
    198403
    199404        return list_get_instance(link, ds_client_t, lclients);
     405}
     406
     407/** Add WM client to display.
     408 *
     409 * @param disp Display
     410 * @param wmclient WM client
     411 */
     412void ds_display_add_wmclient(ds_display_t *disp, ds_wmclient_t *wmclient)
     413{
     414        assert(wmclient->display == NULL);
     415        assert(!link_used(&wmclient->lwmclients));
     416
     417        wmclient->display = disp;
     418        list_append(&wmclient->lwmclients, &disp->wmclients);
     419}
     420
     421/** Remove WM client from display.
     422 *
     423 * @param wmclient WM client
     424 */
     425void ds_display_remove_wmclient(ds_wmclient_t *wmclient)
     426{
     427        list_remove(&wmclient->lwmclients);
     428        wmclient->display = NULL;
     429}
     430
     431/** Add CFG client to display.
     432 *
     433 * @param disp Display
     434 * @param cfgclient CFG client
     435 */
     436void ds_display_add_cfgclient(ds_display_t *disp, ds_cfgclient_t *cfgclient)
     437{
     438        assert(cfgclient->display == NULL);
     439        assert(!link_used(&cfgclient->lcfgclients));
     440
     441        cfgclient->display = disp;
     442        list_append(&cfgclient->lcfgclients, &disp->cfgclients);
     443}
     444
     445/** Remove CFG client from display.
     446 *
     447 * @param cfgclient CFG client
     448 */
     449void ds_display_remove_cfgclient(ds_cfgclient_t *cfgclient)
     450{
     451        list_remove(&cfgclient->lcfgclients);
     452        cfgclient->display = NULL;
     453}
     454
     455/** Get first WM client in display.
     456 *
     457 * @param disp Display
     458 * @return First WM client or @c NULL if there is none
     459 */
     460ds_wmclient_t *ds_display_first_wmclient(ds_display_t *disp)
     461{
     462        link_t *link = list_first(&disp->wmclients);
     463
     464        if (link == NULL)
     465                return NULL;
     466
     467        return list_get_instance(link, ds_wmclient_t, lwmclients);
     468}
     469
     470/** Get next WM client in display.
     471 *
     472 * @param wmclient Current WM client
     473 * @return Next WM client or @c NULL if there is none
     474 */
     475ds_wmclient_t *ds_display_next_wmclient(ds_wmclient_t *wmclient)
     476{
     477        link_t *link = list_next(&wmclient->lwmclients,
     478            &wmclient->display->wmclients);
     479
     480        if (link == NULL)
     481                return NULL;
     482
     483        return list_get_instance(link, ds_wmclient_t, lwmclients);
    200484}
    201485
     
    241525                gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
    242526
    243                 if (gfx_pix_inside_rect(pos, &drect))
     527                if (gfx_pix_inside_rect(pos, &drect) &&
     528                    ds_window_is_visible(wnd))
    244529                        return wnd;
    245530
     
    250535}
    251536
     537/** Add window to window list.
     538 *
     539 * Topmost windows are enlisted before any other window. Non-topmost
     540 * windows are enlisted before any other non-topmost window.
     541 *
     542 * @param display Display
     543 * @param wnd Window
     544 */
     545void ds_display_enlist_window(ds_display_t *display, ds_window_t *wnd)
     546{
     547        ds_window_t *w;
     548
     549        assert(wnd->display == display);
     550        assert(!link_used(&wnd->ldwindows));
     551
     552        if ((wnd->flags & wndf_topmost) == 0) {
     553                /* Find the first non-topmost window */
     554                w = ds_display_first_window(display);
     555                while (w != NULL && (w->flags & wndf_topmost) != 0)
     556                        w = ds_display_next_window(w);
     557
     558                if (w != NULL)
     559                        list_insert_before(&wnd->ldwindows, &w->ldwindows);
     560                else
     561                        list_append(&wnd->ldwindows, &display->windows);
     562        } else {
     563                /* Insert at the beginning */
     564                list_prepend(&wnd->ldwindows, &display->windows);
     565        }
     566
     567}
     568
    252569/** Add window to display.
    253570 *
     
    257574void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
    258575{
     576        ds_wmclient_t *wmclient;
     577
    259578        assert(wnd->display == NULL);
    260579        assert(!link_used(&wnd->ldwindows));
    261580
    262581        wnd->display = display;
    263         list_prepend(&wnd->ldwindows, &display->windows);
     582        ds_display_enlist_window(display, wnd);
     583
     584        /* Notify window managers about the new window */
     585        wmclient = ds_display_first_wmclient(display);
     586        while (wmclient != NULL) {
     587                ds_wmclient_post_wnd_added_event(wmclient, wnd->id);
     588                wmclient = ds_display_next_wmclient(wmclient);
     589        }
    264590}
    265591
     
    270596void ds_display_remove_window(ds_window_t *wnd)
    271597{
     598        ds_wmclient_t *wmclient;
     599        ds_display_t *display;
     600
     601        display = wnd->display;
     602
    272603        list_remove(&wnd->ldwindows);
    273604        wnd->display = NULL;
     605
     606        /* Notify window managers about the removed window */
     607        wmclient = ds_display_first_wmclient(display);
     608        while (wmclient != NULL) {
     609                ds_wmclient_post_wnd_removed_event(wmclient, wnd->id);
     610                wmclient = ds_display_next_wmclient(wmclient);
     611        }
     612}
     613
     614/** Move window to top.
     615 *
     616 * @param display Display
     617 * @param wnd Window
     618 */
     619void ds_display_window_to_top(ds_window_t *wnd)
     620{
     621        assert(wnd->display != NULL);
     622        assert(link_used(&wnd->ldwindows));
     623
     624        list_remove(&wnd->ldwindows);
     625        ds_display_enlist_window(wnd->display, wnd);
    274626}
    275627
     
    347699        ds_seat_t *seat;
    348700
    349         // TODO Determine which seat the event belongs to
    350         seat = ds_display_first_seat(display);
     701        /* Determine which seat the event belongs to */
     702        seat = ds_display_seat_by_idev(display, event->kbd_id);
    351703        if (seat == NULL)
    352704                return EOK;
     
    364716        ds_seat_t *seat;
    365717
    366         // TODO Determine which seat the event belongs to
    367         seat = ds_display_first_seat(display);
     718        /* Determine which seat the event belongs to */
     719        seat = ds_display_seat_by_idev(display, event->pos_id);
    368720        if (seat == NULL)
    369721                return EOK;
     
    383735
    384736        seat->display = disp;
     737        seat->id = disp->next_seat_id++;
    385738        list_append(&seat->lseats, &disp->seats);
    386739}
     
    424777
    425778        return list_get_instance(link, ds_seat_t, lseats);
     779}
     780
     781/** Get default seat in display.
     782 *
     783 * @param disp Display
     784 * @return First seat or @c NULL if there is none
     785 */
     786ds_seat_t *ds_display_default_seat(ds_display_t *disp)
     787{
     788        /* XXX Probably not the best solution */
     789        return ds_display_first_seat(disp);
     790}
     791
     792/** Find seat by ID.
     793 *
     794 * @param display Display
     795 * @param id Seat ID
     796 */
     797ds_seat_t *ds_display_find_seat(ds_display_t *display, ds_seat_id_t id)
     798{
     799        ds_seat_t *seat;
     800
     801        seat = ds_display_first_seat(display);
     802        while (seat != NULL) {
     803                if (seat->id == id)
     804                        return seat;
     805
     806                seat = ds_display_next_seat(seat);
     807        }
     808
     809        return NULL;
     810}
     811
     812/** Get seat which owns the specified input device.
     813 *
     814 * @param disp Display
     815 * @param idev_id Input device ID
     816 * @return Seat which owns device with ID @a idev_id or @c NULL if not found
     817 */
     818ds_seat_t *ds_display_seat_by_idev(ds_display_t *disp, ds_idev_id_t idev_id)
     819{
     820        ds_idevcfg_t *idevcfg;
     821
     822        /*
     823         * Find input device configuration entry that maps this input device
     824         * to a seat.
     825         */
     826        idevcfg = ds_display_first_idevcfg(disp);
     827        while (idevcfg != NULL) {
     828                if (idevcfg->svc_id == idev_id)
     829                        return idevcfg->seat;
     830
     831                idevcfg = ds_display_next_idevcfg(idevcfg);
     832        }
     833
     834        /* If none was found, return the default seat */
     835        return ds_display_default_seat(disp);
    426836}
    427837
     
    459869                goto error;
    460870
    461         rc = mem_gc_create(&disp->rect, &alloc,
    462             ds_display_invalidate_cb, ds_display_update_cb, (void *) disp,
    463             &disp->bbgc);
     871        rc = mem_gc_create(&disp->rect, &alloc, &ds_display_mem_gc_cb,
     872            (void *) disp, &disp->bbgc);
    464873        if (rc != EOK)
    465874                goto error;
     
    489898{
    490899        errno_t rc;
     900        gfx_rect_t old_disp_rect;
    491901
    492902        assert(ddev->display == NULL);
    493903        assert(!link_used(&ddev->lddevs));
     904
     905        old_disp_rect = disp->rect;
    494906
    495907        ddev->display = disp;
     
    503915                /* Create cloning GC */
    504916                rc = ds_clonegc_create(ddev->gc, &disp->fbgc);
    505                 if (rc != EOK) {
    506                         // XXX Remove output
    507                         return ENOMEM;
    508                 }
     917                if (rc != EOK)
     918                        goto error;
    509919
    510920                /* Allocate backbuffer */
    511921                rc = ds_display_alloc_backbuf(disp);
    512922                if (rc != EOK) {
    513                         // XXX Remove output
    514                         // XXX Delete clone GC
     923                        ds_clonegc_delete(disp->fbgc);
     924                        disp->fbgc = NULL;
    515925                        goto error;
    516926                }
     
    522932        }
    523933
     934        ds_display_update_max_rect(disp);
     935
    524936        return EOK;
    525937error:
    526         disp->rect.p0.x = 0;
    527         disp->rect.p0.y = 0;
    528         disp->rect.p1.x = 0;
    529         disp->rect.p1.y = 0;
     938        disp->rect = old_disp_rect;
    530939        list_remove(&ddev->lddevs);
    531940        return rc;
     
    572981}
    573982
     983/** Add input device configuration entry to display.
     984 *
     985 * @param disp Display
     986 * @param idevcfg Input device configuration
     987 */
     988void ds_display_add_idevcfg(ds_display_t *disp, ds_idevcfg_t *idevcfg)
     989{
     990        assert(idevcfg->display == NULL);
     991        assert(!link_used(&idevcfg->ldispidcfgs));
     992
     993        idevcfg->display = disp;
     994        list_append(&idevcfg->ldispidcfgs, &disp->idevcfgs);
     995}
     996
     997/** Remove input device configuration entry from display.
     998 *
     999 * @param idevcfg Input device configuration entry
     1000 */
     1001void ds_display_remove_idevcfg(ds_idevcfg_t *idevcfg)
     1002{
     1003        list_remove(&idevcfg->ldispidcfgs);
     1004        idevcfg->display = NULL;
     1005}
     1006
     1007/** Get first input device configuration entry in display.
     1008 *
     1009 * @param disp Display
     1010 * @return First input device configuration entry or @c NULL if there is none
     1011 */
     1012ds_idevcfg_t *ds_display_first_idevcfg(ds_display_t *disp)
     1013{
     1014        link_t *link = list_first(&disp->idevcfgs);
     1015
     1016        if (link == NULL)
     1017                return NULL;
     1018
     1019        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     1020}
     1021
     1022/** Get next input device configuration entry in display.
     1023 *
     1024 * @param idevcfg Current input device configuration entry
     1025 * @return Next input device configuration entry or @c NULL if there is none
     1026 */
     1027ds_idevcfg_t *ds_display_next_idevcfg(ds_idevcfg_t *idevcfg)
     1028{
     1029        link_t *link = list_next(&idevcfg->ldispidcfgs, &idevcfg->display->idevcfgs);
     1030
     1031        if (link == NULL)
     1032                return NULL;
     1033
     1034        return list_get_instance(link, ds_idevcfg_t, ldispidcfgs);
     1035}
     1036
    5741037/** Add cursor to display.
    5751038 *
     
    5941057        list_remove(&cursor->ldisplay);
    5951058        cursor->display = NULL;
     1059}
     1060
     1061/** Update display maximize rectangle.
     1062 *
     1063 * Recalculate the maximize rectangle (the rectangle used for maximized
     1064 * windows).
     1065 *
     1066 * @param display Display
     1067 */
     1068void ds_display_update_max_rect(ds_display_t *display)
     1069{
     1070        ds_window_t *wnd;
     1071        gfx_rect_t max_rect;
     1072        gfx_rect_t drect;
     1073
     1074        /* Start with the entire display */
     1075        max_rect = display->rect;
     1076
     1077        wnd = ds_display_first_window(display);
     1078        while (wnd != NULL) {
     1079                /* Should maximized windows avoid this window? */
     1080                if ((wnd->flags & wndf_avoid) != 0) {
     1081                        /* Window bounding rectangle on display */
     1082                        gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
     1083
     1084                        /* Crop maximized rectangle */
     1085                        ds_display_crop_max_rect(&drect, &max_rect);
     1086                }
     1087
     1088                wnd = ds_display_next_window(wnd);
     1089        }
     1090
     1091        /* Update the maximize rectangle */
     1092        display->max_rect = max_rect;
     1093}
     1094
     1095/** Crop maximize rectangle.
     1096 *
     1097 * Use the avoid rectangle @a arect to crop off maximization rectangle
     1098 * @a mrect. If @a arect covers the top, bottom, left or right part
     1099 * of @a mrect, it will be cropped off. Otherwise there will be
     1100 * no effect.
     1101 *
     1102 * @param arect Avoid rectangle
     1103 * @param mrect Maximize rectangle to be modified
     1104 */
     1105void ds_display_crop_max_rect(gfx_rect_t *arect, gfx_rect_t *mrect)
     1106{
     1107        if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     1108            arect->p1.x == mrect->p1.x) {
     1109                /* Cropp off top part */
     1110                mrect->p0.y = arect->p1.y;
     1111        } else if (arect->p0.x == mrect->p0.x && arect->p1.x == mrect->p1.x &&
     1112            arect->p1.y == mrect->p1.y) {
     1113                /* Cropp off bottom part */
     1114                mrect->p1.y = arect->p0.y;
     1115        } else if (arect->p0.x == mrect->p0.x && arect->p0.y == mrect->p0.y &&
     1116            arect->p1.y == mrect->p1.y) {
     1117                /* Cropp off left part */
     1118                mrect->p0.x = arect->p1.x;
     1119        } else if (arect->p0.y == mrect->p0.y && arect->p1.x == mrect->p1.x &&
     1120            arect->p1.y == mrect->p1.y) {
     1121                /* Cropp off right part */
     1122                mrect->p1.x = arect->p0.x;
     1123        }
    5961124}
    5971125
Note: See TracChangeset for help on using the changeset viewer.