Ignore:
File:
1 edited

Legend:

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

    rd7f82635 r9546146  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#include <gfx/color.h>
    3939#include <gfx/render.h>
     40#include <sif.h>
     41#include <stdio.h>
    4042#include <stdlib.h>
     43#include <str.h>
    4144#include "client.h"
    4245#include "cursor.h"
    4346#include "display.h"
     47#include "idevcfg.h"
    4448#include "seat.h"
    4549#include "window.h"
     
    5155 *
    5256 * @param display Parent display
     57 * @param name Seat name
    5358 * @param rseat Place to store pointer to new seat.
    5459 * @return EOK on success, ENOMEM if out of memory
    5560 */
    56 errno_t ds_seat_create(ds_display_t *display, ds_seat_t **rseat)
     61errno_t ds_seat_create(ds_display_t *display, const char *name,
     62    ds_seat_t **rseat)
    5763{
    5864        ds_seat_t *seat;
     65        ds_seat_t *s0;
     66
     67        s0 = ds_display_first_seat(display);
     68        while (s0 != NULL) {
     69                if (str_cmp(s0->name, name) == 0)
     70                        return EEXIST;
     71                s0 = ds_display_next_seat(s0);
     72        }
    5973
    6074        seat = calloc(1, sizeof(ds_seat_t));
     
    6276                return ENOMEM;
    6377
     78        seat->name = str_dup(name);
     79        if (seat->name == NULL) {
     80                free(seat);
     81                return ENOMEM;
     82        }
     83
     84        list_initialize(&seat->idevcfgs);
     85
    6486        ds_display_add_seat(display, seat);
    6587        seat->pntpos.x = 0;
     
    6890        seat->client_cursor = display->cursor[dcurs_arrow];
    6991        seat->wm_cursor = NULL;
     92        seat->focus = ds_display_first_window(display);
    7093
    7194        *rseat = seat;
     
    79102void ds_seat_destroy(ds_seat_t *seat)
    80103{
     104        ds_idevcfg_t *idevcfg;
     105
     106        /* Remove all input device configuration entries pointing to this seat */
     107        idevcfg = ds_seat_first_idevcfg(seat);
     108        while (idevcfg != NULL) {
     109                ds_idevcfg_destroy(idevcfg);
     110                idevcfg = ds_seat_first_idevcfg(seat);
     111        }
     112
     113        /* Remove this seat's focus */
     114        if (seat->focus != NULL)
     115                ds_window_post_unfocus_event(seat->focus);
     116
    81117        ds_display_remove_seat(seat);
     118
     119        free(seat->name);
    82120        free(seat);
    83121}
    84122
     123/** Load seat from SIF node.
     124 *
     125 * @param display Display
     126 * @param snode Seat node from which to load the seat
     127 * @param rseat Place to store pointer to the newly loaded seat
     128 *
     129 * @return EOK on success or an error code
     130 */
     131errno_t ds_seat_load(ds_display_t *display, sif_node_t *snode,
     132    ds_seat_t **rseat)
     133{
     134        const char *sid;
     135        const char *name;
     136        char *endptr;
     137        unsigned long id;
     138        errno_t rc;
     139
     140        sid = sif_node_get_attr(snode, "id");
     141        if (sid == NULL)
     142                return EIO;
     143
     144        name = sif_node_get_attr(snode, "name");
     145        if (name == NULL)
     146                return EIO;
     147
     148        id = strtoul(sid, &endptr, 10);
     149        if (*endptr != '\0')
     150                return EIO;
     151
     152        rc = ds_seat_create(display, name, rseat);
     153        if (rc != EOK)
     154                return EIO;
     155
     156        (*rseat)->id = id;
     157        return EOK;
     158}
     159
     160/** Save seat to SIF node.
     161 *
     162 * @param seat Seat
     163 * @param snode Seat node into which the seat should be saved
     164 *
     165 * @return EOK on success or an error code
     166 */
     167errno_t ds_seat_save(ds_seat_t *seat, sif_node_t *snode)
     168{
     169        char *sid;
     170        errno_t rc;
     171        int rv;
     172
     173        rv = asprintf(&sid, "%lu", (unsigned long)seat->id);
     174        if (rv < 0) {
     175                rc = ENOMEM;
     176                return rc;
     177        }
     178
     179        rc = sif_node_set_attr(snode, "id", sid);
     180        if (rc != EOK) {
     181                free(sid);
     182                return rc;
     183        }
     184
     185        free(sid);
     186
     187        rc = sif_node_set_attr(snode, "name", seat->name);
     188        if (rc != EOK)
     189                return rc;
     190
     191        return EOK;
     192}
     193
    85194/** Set seat focus to a window.
    86195 *
     
    90199void ds_seat_set_focus(ds_seat_t *seat, ds_window_t *wnd)
    91200{
     201        errno_t rc;
     202
    92203        if (wnd == seat->focus) {
    93204                /* Focus is not changing */
    94205                return;
     206        }
     207
     208        if (wnd != NULL) {
     209                rc = ds_window_unminimize(wnd);
     210                if (rc != EOK)
     211                        return;
    95212        }
    96213
     
    130247/** Evacuate seat references to window.
    131248 *
    132  * If seat's focus is @a wnd, it will be set to a different window.
     249 * If seat's focus is @a wnd, it will be set to NULL.
    133250 * If seat's popup window is @a wnd, it will be set to NULL.
    134251 *
    135252 * @param seat Seat
    136  * @param wnd Window to evacuate focus from
     253 * @param wnd Window to evacuate references from
    137254 */
    138255void ds_seat_evac_wnd_refs(ds_seat_t *seat, ds_window_t *wnd)
    139256{
    140         ds_window_t *nwnd;
    141 
    142         if (seat->focus == wnd) {
    143                 nwnd = ds_display_prev_window(wnd);
    144                 if (nwnd == NULL)
    145                         nwnd = ds_display_last_window(wnd->display);
    146                 if (nwnd == wnd)
    147                         nwnd = NULL;
    148 
    149                 ds_seat_set_focus(seat, nwnd);
    150         }
     257        if (seat->focus == wnd)
     258                ds_seat_set_focus(seat, NULL);
    151259
    152260        if (seat->popup == wnd)
     
    154262}
    155263
     264/** Unfocus window.
     265 *
     266 * If seat's focus is @a wnd, it will be set to a different window
     267 * that is not minimized, preferably not a system window.
     268 *
     269 * @param seat Seat
     270 * @param wnd Window to remove focus from
     271 */
     272void ds_seat_unfocus_wnd(ds_seat_t *seat, ds_window_t *wnd)
     273{
     274        ds_window_t *nwnd;
     275
     276        if (seat->focus != wnd)
     277                return;
     278
     279        /* Find alternate window that is neither system nor minimized */
     280        nwnd = ds_window_find_prev(wnd, ~(wndf_minimized | wndf_system));
     281
     282        if (nwnd == NULL) {
     283                /* Find alternate window that is not minimized */
     284                nwnd = ds_window_find_prev(wnd, ~wndf_minimized);
     285        }
     286
     287        ds_seat_set_focus(seat, nwnd);
     288}
     289
    156290/** Switch focus to another window.
    157291 *
     
    163297        ds_window_t *nwnd;
    164298
    165         if (seat->focus != NULL)
    166                 nwnd = ds_display_prev_window(seat->focus);
    167         else
    168                 nwnd = NULL;
    169 
    170         if (nwnd == NULL)
    171                 nwnd = ds_display_last_window(seat->display);
    172 
     299        if (seat->focus != NULL) {
     300                /* Find alternate window that is not a system window */
     301                nwnd = ds_window_find_next(seat->focus, ~wndf_system);
     302        } else {
     303                /* Currently no focus. Focus topmost window. */
     304                nwnd = ds_display_first_window(seat->display);
     305        }
     306
     307        /* Only switch focus if there is another window */
    173308        if (nwnd != NULL)
    174309                ds_seat_set_focus(seat, nwnd);
     
    362497        }
    363498
    364         if (event->type == PTD_PRESS || event->type == PTD_RELEASE) {
    365                 pevent.pos_id = 0;
    366                 pevent.type = (event->type == PTD_PRESS) ?
    367                     POS_PRESS : POS_RELEASE;
     499        if (event->type == PTD_PRESS || event->type == PTD_RELEASE ||
     500            event->type == PTD_DCLICK) {
     501                pevent.pos_id = event->pos_id;
     502                switch (event->type) {
     503                case PTD_PRESS:
     504                        pevent.type = POS_PRESS;
     505                        break;
     506                case PTD_RELEASE:
     507                        pevent.type = POS_RELEASE;
     508                        break;
     509                case PTD_DCLICK:
     510                        pevent.type = POS_DCLICK;
     511                        break;
     512                default:
     513                        assert(false);
     514                }
     515
    368516                pevent.btn_num = event->btn_num;
    369517                pevent.hpos = seat->pntpos.x;
     
    382530                seat->pntpos = npos;
    383531
    384                 pevent.pos_id = 0;
     532                pevent.pos_id = event->pos_id;
    385533                pevent.type = POS_UPDATE;
    386534                pevent.btn_num = 0;
     
    410558                seat->pntpos = npos;
    411559
    412                 pevent.pos_id = 0;
     560                pevent.pos_id = event->pos_id;
    413561                pevent.type = POS_UPDATE;
    414562                pevent.btn_num = 0;
     
    435583errno_t ds_seat_post_pos_event(ds_seat_t *seat, pos_event_t *event)
    436584{
    437         ds_window_t *wnd;
     585        ds_window_t *pwindow;
     586        ds_window_t *cwindow;
    438587        errno_t rc;
    439588
    440         wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
     589        /* Window under pointer */
     590        pwindow = ds_display_window_by_pos(seat->display, &seat->pntpos);
     591
     592        /* Current window: popup or focused */
     593        cwindow = seat->popup;
     594        if (cwindow == NULL)
     595                cwindow = seat->focus;
     596
     597        /*
     598         * Deliver move and release event to current window if different
     599         * from pwindow
     600         */
     601        if (event->type != POS_PRESS && cwindow != NULL &&
     602            cwindow != pwindow) {
     603                rc = ds_window_post_pos_event(cwindow, event);
     604                if (rc != EOK)
     605                        return rc;
     606        }
     607
     608        if (pwindow != NULL) {
     609                /* Moving over a window */
     610                ds_seat_set_client_cursor(seat, pwindow->cursor);
     611
     612                rc = ds_window_post_pos_event(pwindow, event);
     613                if (rc != EOK)
     614                        return rc;
     615        } else {
     616                /* Not over a window */
     617                ds_seat_set_client_cursor(seat,
     618                    seat->display->cursor[dcurs_arrow]);
     619        }
    441620
    442621        /* Click outside popup window */
    443         if (event->type == POS_PRESS && wnd != seat->popup) {
     622        if (event->type == POS_PRESS && pwindow != seat->popup) {
    444623                /* Close popup window */
    445624                ds_seat_set_popup(seat, NULL);
    446625        }
    447626
    448         /* Deliver event to popup window. */
    449         if (seat->popup != NULL) {
    450                 rc = ds_window_post_pos_event(seat->popup, event);
    451                 if (rc != EOK)
    452                         return rc;
    453         }
    454 
    455         if (seat->focus != wnd && seat->focus != NULL) {
    456                 rc = ds_window_post_pos_event(seat->focus, event);
    457                 if (rc != EOK)
    458                         return rc;
    459 
    460                 /* Only deliver release events to the focused window */
    461                 if (event->type == POS_RELEASE)
    462                         return EOK;
    463         }
    464 
    465         if (wnd != NULL) {
    466                 /* Moving over a window */
    467                 ds_seat_set_client_cursor(seat, wnd->cursor);
    468 
    469                 /*
    470                  * Only deliver event if we didn't already deliver it
    471                  * to the same window above.
    472                  */
    473                 if (wnd != seat->popup) {
    474                         rc = ds_window_post_pos_event(wnd, event);
    475                         if (rc != EOK)
    476                                 return rc;
    477                 }
    478         } else {
    479                 /* Not over a window */
    480                 ds_seat_set_client_cursor(seat, seat->display->cursor[dcurs_arrow]);
    481         }
    482 
    483627        return EOK;
    484628}
     
    497641}
    498642
     643/** Add input device configuration entry to seat.
     644 *
     645 * @param seat Seat
     646 * @param idevcfg Input device configuration
     647 */
     648void ds_seat_add_idevcfg(ds_seat_t *seat, ds_idevcfg_t *idevcfg)
     649{
     650        assert(idevcfg->seat == NULL);
     651        assert(!link_used(&idevcfg->lseatidcfgs));
     652
     653        idevcfg->seat = seat;
     654        list_append(&idevcfg->lseatidcfgs, &seat->idevcfgs);
     655}
     656
     657/** Remove input device configuration entry from seat.
     658 *
     659 * @param idevcfg Input device configuration entry
     660 */
     661void ds_seat_remove_idevcfg(ds_idevcfg_t *idevcfg)
     662{
     663        list_remove(&idevcfg->lseatidcfgs);
     664        idevcfg->seat = NULL;
     665}
     666
     667/** Get first input device configuration entry in seat.
     668 *
     669 * @param disp Display
     670 * @return First input device configuration entry or @c NULL if there is none
     671 */
     672ds_idevcfg_t *ds_seat_first_idevcfg(ds_seat_t *seat)
     673{
     674        link_t *link = list_first(&seat->idevcfgs);
     675
     676        if (link == NULL)
     677                return NULL;
     678
     679        return list_get_instance(link, ds_idevcfg_t, lseatidcfgs);
     680}
     681
     682/** Get next input device configuration entry in seat.
     683 *
     684 * @param idevcfg Current input device configuration entry
     685 * @return Next input device configuration entry or @c NULL if there is none
     686 */
     687ds_idevcfg_t *ds_seat_next_idevcfg(ds_idevcfg_t *idevcfg)
     688{
     689        link_t *link = list_next(&idevcfg->lseatidcfgs, &idevcfg->seat->idevcfgs);
     690
     691        if (link == NULL)
     692                return NULL;
     693
     694        return list_get_instance(link, ds_idevcfg_t, lseatidcfgs);
     695}
     696
    499697/** @}
    500698 */
Note: See TracChangeset for help on using the changeset viewer.