Ignore:
File:
1 edited

Legend:

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

    r554a5f1 r9546146  
    11/*
    2  * Copyright (c) 2019 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 */
     
    95206        }
    96207
     208        if (wnd != NULL) {
     209                rc = ds_window_unminimize(wnd);
     210                if (rc != EOK)
     211                        return;
     212        }
     213
    97214        if (seat->focus != NULL)
    98215                ds_window_post_unfocus_event(seat->focus);
     
    104221                ds_window_bring_to_top(wnd);
    105222        }
    106 }
    107 
    108 /** Evacuate focus from window.
    109  *
    110  * If seat's focus is @a wnd, it will be set to a different window.
     223
     224        /* When focus changes, popup window should be closed */
     225        ds_seat_set_popup(seat, NULL);
     226}
     227
     228/** Set seat popup window.
     229 *
     230 * @param seat Seat
     231 * @param wnd Popup window
     232 */
     233void ds_seat_set_popup(ds_seat_t *seat, ds_window_t *wnd)
     234{
     235        if (wnd == seat->popup)
     236                return;
     237
     238        if (seat->popup != NULL) {
     239                /* Window is no longer the popup window, send close request */
     240                ds_client_post_close_event(seat->popup->client,
     241                    seat->popup);
     242        }
     243
     244        seat->popup = wnd;
     245}
     246
     247/** Evacuate seat references to window.
     248 *
     249 * If seat's focus is @a wnd, it will be set to NULL.
     250 * If seat's popup window is @a wnd, it will be set to NULL.
     251 *
     252 * @param seat Seat
     253 * @param wnd Window to evacuate references from
     254 */
     255void ds_seat_evac_wnd_refs(ds_seat_t *seat, ds_window_t *wnd)
     256{
     257        if (seat->focus == wnd)
     258                ds_seat_set_focus(seat, NULL);
     259
     260        if (seat->popup == wnd)
     261                ds_seat_set_popup(seat, NULL);
     262}
     263
     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
     290/** Switch focus to another window.
    111291 *
    112292 * @param seat Seat
    113293 * @param wnd Window to evacuate focus from
    114294 */
    115 void ds_seat_evac_focus(ds_seat_t *seat, ds_window_t *wnd)
     295void ds_seat_switch_focus(ds_seat_t *seat)
    116296{
    117297        ds_window_t *nwnd;
    118298
    119         if (seat->focus == wnd) {
    120                 nwnd = ds_display_next_window(wnd);
    121                 if (nwnd == NULL)
    122                         nwnd = ds_display_first_window(wnd->display);
    123                 if (nwnd == wnd)
    124                         nwnd = NULL;
    125 
     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 */
     308        if (nwnd != NULL)
    126309                ds_seat_set_focus(seat, nwnd);
    127         }
    128310}
    129311
     
    143325        if (event->type == KEY_PRESS && alt_or_shift && event->key == KC_TAB) {
    144326                /* On Alt-Tab or Shift-Tab, switch focus to next window */
    145                 ds_seat_evac_focus(seat, seat->focus);
     327                ds_seat_switch_focus(seat);
    146328                return EOK;
    147329        }
    148330
    149         dwindow = seat->focus;
     331        dwindow = seat->popup;
     332        if (dwindow == NULL)
     333                dwindow = seat->focus;
     334
    150335        if (dwindow == NULL)
    151336                return EOK;
     
    307492        /* Focus window on button press */
    308493        if (event->type == PTD_PRESS && event->btn_num == 1) {
    309                 if (wnd != NULL) {
     494                if (wnd != NULL && (wnd->flags & wndf_popup) == 0) {
    310495                        ds_seat_set_focus(seat, wnd);
    311496                }
    312497        }
    313498
    314         if (event->type == PTD_PRESS || event->type == PTD_RELEASE) {
    315                 pevent.pos_id = 0;
    316                 pevent.type = (event->type == PTD_PRESS) ?
    317                     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
    318516                pevent.btn_num = event->btn_num;
    319517                pevent.hpos = seat->pntpos.x;
     
    332530                seat->pntpos = npos;
    333531
    334                 pevent.pos_id = 0;
     532                pevent.pos_id = event->pos_id;
    335533                pevent.type = POS_UPDATE;
    336534                pevent.btn_num = 0;
     
    360558                seat->pntpos = npos;
    361559
    362                 pevent.pos_id = 0;
     560                pevent.pos_id = event->pos_id;
    363561                pevent.type = POS_UPDATE;
    364562                pevent.btn_num = 0;
     
    385583errno_t ds_seat_post_pos_event(ds_seat_t *seat, pos_event_t *event)
    386584{
    387         ds_window_t *wnd;
     585        ds_window_t *pwindow;
     586        ds_window_t *cwindow;
    388587        errno_t rc;
    389588
    390         wnd = ds_display_window_by_pos(seat->display, &seat->pntpos);
    391 
    392         if (seat->focus != wnd) {
    393                 rc = ds_window_post_pos_event(seat->focus, event);
    394                 if (rc != EOK)
    395                         return rc;
    396 
    397                 /* Only deliver release events to the focused window */
    398                 if (event->type == POS_RELEASE)
    399                         return EOK;
    400         }
    401 
    402         if (wnd != NULL) {
     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) {
    403609                /* Moving over a window */
    404                 ds_seat_set_client_cursor(seat, wnd->cursor);
    405 
    406                 rc = ds_window_post_pos_event(wnd, event);
     610                ds_seat_set_client_cursor(seat, pwindow->cursor);
     611
     612                rc = ds_window_post_pos_event(pwindow, event);
    407613                if (rc != EOK)
    408614                        return rc;
    409615        } else {
    410616                /* Not over a window */
    411                 ds_seat_set_client_cursor(seat, seat->display->cursor[dcurs_arrow]);
     617                ds_seat_set_client_cursor(seat,
     618                    seat->display->cursor[dcurs_arrow]);
     619        }
     620
     621        /* Click outside popup window */
     622        if (event->type == POS_PRESS && pwindow != seat->popup) {
     623                /* Close popup window */
     624                ds_seat_set_popup(seat, NULL);
    412625        }
    413626
     
    428641}
    429642
     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
    430697/** @}
    431698 */
Note: See TracChangeset for help on using the changeset viewer.