Changes in uspace/lib/ui/src/ui.c [bb14312:8279aab] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ui/src/ui.c

    rbb14312 r8279aab  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2025 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3939#include <errno.h>
    4040#include <fibril.h>
     41#include <fibril_synch.h>
     42#include <gfx/color.h>
     43#include <gfx/cursor.h>
     44#include <gfx/render.h>
    4145#include <io/console.h>
    4246#include <stdbool.h>
     
    4448#include <str.h>
    4549#include <task.h>
     50#include <types/common.h>
     51#include <ui/clickmatic.h>
    4652#include <ui/ui.h>
    4753#include <ui/wdecor.h>
    4854#include <ui/window.h>
     55#include "../private/wdecor.h"
    4956#include "../private/window.h"
    5057#include "../private/ui.h"
     
    5360 *
    5461 * Output specification has the form <proto>@<service> where proto is
    55  * eiher 'disp' for display service or 'cons' for console. Service
    56  * is a location ID service name (e.g. hid/display).
     62 * eiher 'disp' for display service, 'cons' for console, 'null'
     63 * for dummy output. Service is a location ID service name (e.g. hid/display).
    5764 *
    5865 * @param ospec Output specification
    5966 * @param ws Place to store window system type (protocol)
    6067 * @param osvc Place to store pointer to output service name
    61  */
    62 static void ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
    63     const char **osvc)
     68 * @param ridev_id Place to store input device ID
     69 * @return EOK on success, EINVAL if syntax is invalid, ENOMEM if out of
     70 *         memory
     71 */
     72static errno_t ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
     73    char **osvc, sysarg_t *ridev_id)
    6474{
    6575        const char *cp;
    66 
    67         if (ospec == UI_DISPLAY_DEFAULT) {
    68                 *ws = ui_ws_display;
    69                 *osvc = DISPLAY_DEFAULT;
    70                 return;
    71         }
     76        const char *qm;
     77        const char *endptr;
     78        uint64_t idev_id;
     79        errno_t rc;
     80
     81        *ridev_id = 0;
    7282
    7383        cp = ospec;
     
    7585                ++cp;
    7686
     87        /* Window system / protocol */
    7788        if (*cp == '@') {
    7889                if (str_lcmp(ospec, "disp@", str_length("disp@")) == 0) {
     
    8091                } else if (str_lcmp(ospec, "cons@", str_length("cons@")) == 0) {
    8192                        *ws = ui_ws_console;
     93                } else if (str_lcmp(ospec, "null@", str_length("null@")) == 0) {
     94                        *ws = ui_ws_null;
     95                } else if (str_lcmp(ospec, "@", str_length("@")) == 0) {
     96                        *ws = ui_ws_any;
    8297                } else {
    8398                        *ws = ui_ws_unknown;
    8499                }
    85100
    86                 if (cp[1] != '\0')
    87                         *osvc = cp + 1;
    88                 else
    89                         *osvc = NULL;
     101                ++cp;
    90102        } else {
    91103                *ws = ui_ws_display;
    92                 *osvc = ospec;
    93         }
     104        }
     105
     106        /* Output service is the part before question mark */
     107        qm = str_chr(cp, '?');
     108        if (qm != NULL) {
     109                *osvc = str_ndup(cp, qm - cp);
     110        } else {
     111                /* No question mark */
     112                *osvc = str_dup(cp);
     113        }
     114
     115        if (*osvc == NULL)
     116                return ENOMEM;
     117
     118        if (qm != NULL) {
     119                /* The part after the question mark */
     120                cp = qm + 1;
     121
     122                /* Input device ID parameter */
     123                if (str_lcmp(cp, "idev=", str_length("idev=")) == 0) {
     124                        cp += str_length("idev=");
     125
     126                        rc = str_uint64_t(cp, &endptr, 10, false, &idev_id);
     127                        if (rc != EOK)
     128                                goto error;
     129
     130                        *ridev_id = idev_id;
     131                        cp = endptr;
     132                }
     133        }
     134
     135        if (*cp != '\0') {
     136                rc = EINVAL;
     137                goto error;
     138        }
     139
     140        return EOK;
     141error:
     142        free(*osvc);
     143        *osvc = NULL;
     144        return rc;
    94145}
    95146
     
    97148 *
    98149 * @param ospec Output specification or @c UI_DISPLAY_DEFAULT to use
    99  *              the default output
     150 *              the default display service, UI_CONSOLE_DEFAULT to use
     151 *              the default console service, UI_DISPLAY_NULL to use
     152 *              dummy output.
    100153 * @param rui Place to store pointer to new UI
    101154 * @return EOK on success or an error code
     
    108161        console_gc_t *cgc;
    109162        ui_winsys_t ws;
    110         const char *osvc;
     163        char *osvc;
     164        sysarg_t cols;
     165        sysarg_t rows;
     166        sysarg_t idev_id;
    111167        ui_t *ui;
    112168
    113         ui_ospec_parse(ospec, &ws, &osvc);
    114 
    115         if (ws == ui_ws_display) {
    116                 rc = display_open(osvc, &display);
     169        rc = ui_ospec_parse(ospec, &ws, &osvc, &idev_id);
     170        if (rc != EOK)
     171                return rc;
     172
     173        if (ws == ui_ws_display || ws == ui_ws_any) {
     174                rc = display_open((str_cmp(osvc, "") != 0) ? osvc :
     175                    DISPLAY_DEFAULT, &display);
    117176                if (rc != EOK)
    118                         return rc;
     177                        goto disp_fail;
    119178
    120179                rc = ui_create_disp(display, &ui);
    121180                if (rc != EOK) {
    122181                        display_close(display);
    123                         return rc;
    124                 }
    125         } else if (ws == ui_ws_console) {
     182                        goto disp_fail;
     183                }
     184
     185                free(osvc);
     186                ui->myoutput = true;
     187                ui->idev_id = idev_id;
     188                *rui = ui;
     189                return EOK;
     190        }
     191
     192disp_fail:
     193        if (ws == ui_ws_console || ws == ui_ws_any) {
    126194                console = console_init(stdin, stdout);
    127195                if (console == NULL)
    128                         return EIO;
     196                        goto cons_fail;
     197
     198                rc = console_get_size(console, &cols, &rows);
     199                if (rc != EOK) {
     200                        console_done(console);
     201                        goto cons_fail;
     202                }
    129203
    130204                console_cursor_visibility(console, false);
     
    134208                if (rc != EOK) {
    135209                        console_done(console);
    136                         return rc;
     210                        goto cons_fail;
    137211                }
    138212
     
    141215                        ui_destroy(ui);
    142216                        console_done(console);
     217                        goto cons_fail;
     218                }
     219
     220                free(osvc);
     221
     222                ui->cgc = cgc;
     223                ui->rect.p0.x = 0;
     224                ui->rect.p0.y = 0;
     225                ui->rect.p1.x = cols;
     226                ui->rect.p1.y = rows;
     227
     228                (void) ui_paint(ui);
     229                ui->myoutput = true;
     230                *rui = ui;
     231                return EOK;
     232        }
     233
     234cons_fail:
     235        if (ws == ui_ws_null) {
     236                free(osvc);
     237                rc = ui_create_disp(NULL, &ui);
     238                if (rc != EOK)
    143239                        return rc;
    144                 }
    145 
    146                 ui->cgc = cgc;
    147         } else {
    148                 return EINVAL;
    149         }
    150 
    151         ui->myoutput = true;
    152         *rui = ui;
    153         return EOK;
     240
     241                ui->myoutput = true;
     242                *rui = ui;
     243                return EOK;
     244        }
     245
     246        free(osvc);
     247        return EINVAL;
    154248}
    155249
     
    162256{
    163257        ui_t *ui;
     258        errno_t rc;
    164259
    165260        ui = calloc(1, sizeof(ui_t));
     
    167262                return ENOMEM;
    168263
     264        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     265        if (rc != EOK) {
     266                free(ui);
     267                return rc;
     268        }
     269
    169270        ui->console = console;
    170271        list_initialize(&ui->windows);
     272        fibril_mutex_initialize(&ui->lock);
    171273        *rui = ui;
    172274        return EOK;
     
    182284{
    183285        ui_t *ui;
     286        errno_t rc;
    184287
    185288        ui = calloc(1, sizeof(ui_t));
     
    187290                return ENOMEM;
    188291
     292        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     293        if (rc != EOK) {
     294                free(ui);
     295                return rc;
     296        }
     297
    189298        ui->display = disp;
    190299        list_initialize(&ui->windows);
     300        fibril_mutex_initialize(&ui->lock);
    191301        *rui = ui;
    192302        return EOK;
     
    220330        ui_window_t *awnd;
    221331        ui_evclaim_t claim;
     332        pos_event_t pos;
    222333
    223334        awnd = ui_window_get_active(ui);
     
    227338        switch (event->type) {
    228339        case CEV_KEY:
     340                ui_lock(ui);
    229341                ui_window_send_kbd(awnd, &event->ev.key);
     342                ui_unlock(ui);
    230343                break;
    231344        case CEV_POS:
    232                 claim = ui_wdecor_pos_event(awnd->wdecor, &event->ev.pos);
     345                pos = event->ev.pos;
     346                /* Translate event to window-relative coordinates */
     347                pos.hpos -= awnd->dpos.x;
     348                pos.vpos -= awnd->dpos.y;
     349
     350                claim = ui_wdecor_pos_event(awnd->wdecor, &pos);
    233351                /* Note: If event is claimed, awnd might not be valid anymore */
    234                 if (claim == ui_unclaimed)
    235                         ui_window_send_pos(awnd, &event->ev.pos);
     352                if (claim == ui_unclaimed) {
     353                        ui_lock(ui);
     354                        ui_window_send_pos(awnd, &pos);
     355                        ui_unlock(ui);
     356                }
     357
     358                break;
     359        case CEV_RESIZE:
     360                ui_lock(ui);
     361                ui_window_send_resize(awnd);
     362                ui_unlock(ui);
    236363                break;
    237364        }
     
    284411{
    285412        errno_t rc;
     413        gfx_context_t *gc;
    286414        ui_window_t *awnd;
     415        gfx_color_t *color = NULL;
     416
     417        /* In case of null output */
     418        if (ui->cgc == NULL)
     419                return EOK;
     420
     421        gc = console_gc_get_ctx(ui->cgc);
     422
     423        rc = gfx_color_new_ega(0x11, &color);
     424        if (rc != EOK)
     425                return rc;
     426
     427        rc = gfx_set_color(gc, color);
     428        if (rc != EOK) {
     429                gfx_color_delete(color);
     430                return rc;
     431        }
     432
     433        rc = gfx_fill_rect(gc, &ui->rect);
     434        if (rc != EOK) {
     435                gfx_color_delete(color);
     436                return rc;
     437        }
     438
     439        gfx_color_delete(color);
    287440
    288441        /* XXX Should repaint all windows */
     
    296449
    297450        return ui_window_paint(awnd);
     451}
     452
     453/** Free up console for other users.
     454 *
     455 * Release console resources for another application (that the current
     456 * task is starting). After the other application finishes, resume
     457 * operation with ui_resume(). No calls to UI must happen inbetween
     458 * and no events must be processed (i.e. the calling function must not
     459 * return control to UI.
     460 *
     461 * @param ui UI
     462 * @return EOK on success or an error code
     463 */
     464errno_t ui_suspend(ui_t *ui)
     465{
     466        errno_t rc;
     467
     468        assert(!ui->suspended);
     469
     470        if (ui->cgc == NULL) {
     471                ui->suspended = true;
     472                return EOK;
     473        }
     474
     475        (void) console_set_caption(ui->console, "");
     476        rc = console_gc_suspend(ui->cgc);
     477        if (rc != EOK)
     478                return rc;
     479
     480        ui->suspended = true;
     481        return EOK;
     482}
     483
     484/** Resume suspended UI.
     485 *
     486 * Reclaim console resources (after child application has finished running)
     487 * and restore UI operation previously suspended by calling ui_suspend().
     488 *
     489 * @param ui UI
     490 * @return EOK on success or an error code
     491 */
     492errno_t ui_resume(ui_t *ui)
     493{
     494        errno_t rc;
     495        ui_window_t *awnd;
     496        sysarg_t col;
     497        sysarg_t row;
     498        cons_event_t ev;
     499
     500        assert(ui->suspended);
     501
     502        if (ui->cgc == NULL) {
     503                ui->suspended = false;
     504                return EOK;
     505        }
     506
     507        rc = console_get_pos(ui->console, &col, &row);
     508        if (rc != EOK)
     509                return rc;
     510
     511        /*
     512         * Here's a little heuristic to help determine if we need
     513         * to pause before returning to the UI. If we are in the
     514         * top-left corner, chances are the screen is empty and
     515         * there is no need to pause.
     516         */
     517        if (col != 0 || row != 0) {
     518                printf("Press any key or button to continue...\n");
     519
     520                while (true) {
     521                        rc = console_get_event(ui->console, &ev);
     522                        if (rc != EOK)
     523                                return EIO;
     524
     525                        if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS)
     526                                break;
     527
     528                        if (ev.type == CEV_POS && ev.ev.pos.type == POS_PRESS)
     529                                break;
     530                }
     531        }
     532
     533        rc = console_gc_resume(ui->cgc);
     534        if (rc != EOK)
     535                return rc;
     536
     537        ui->suspended = false;
     538
     539        awnd = ui_window_get_active(ui);
     540        if (awnd != NULL)
     541                (void) console_set_caption(ui->console, awnd->wdecor->caption);
     542
     543        rc = gfx_cursor_set_visible(console_gc_get_ctx(ui->cgc), false);
     544        if (rc != EOK)
     545                return rc;
     546
     547        return EOK;
     548}
     549
     550/** Determine if UI is suspended.
     551 *
     552 * @param ui UI
     553 * @return @c true iff UI is suspended
     554 */
     555bool ui_is_suspended(ui_t *ui)
     556{
     557        return ui->suspended;
     558}
     559
     560/** Lock UI.
     561 *
     562 * Block UI from calling window callbacks. @c ui_lock() and @c ui_unlock()
     563 * must be used when accessing UI resources from a fibril (as opposed to
     564 * from a window callback).
     565 *
     566 * @param ui UI
     567 */
     568void ui_lock(ui_t *ui)
     569{
     570        if (ui->display != NULL)
     571                display_lock(ui->display);
     572        fibril_mutex_lock(&ui->lock);
     573}
     574
     575/** Unlock UI.
     576 *
     577 * Allow UI to call window callbacks. @c ui_lock() and @c ui_unlock()
     578 * must be used when accessing window resources from a fibril (as opposed to
     579 * from a window callback).
     580 *
     581 * @param ui UI
     582 */
     583void ui_unlock(ui_t *ui)
     584{
     585        fibril_mutex_unlock(&ui->lock);
     586        if (ui->display != NULL)
     587                display_unlock(ui->display);
    298588}
    299589
     
    335625}
    336626
     627/** Get UI screen rectangle.
     628 *
     629 * @param ui User interface
     630 * @param rect Place to store bounding rectangle
     631 */
     632errno_t ui_get_rect(ui_t *ui, gfx_rect_t *rect)
     633{
     634        display_info_t info;
     635        sysarg_t cols, rows;
     636        errno_t rc;
     637
     638        if (ui->display != NULL) {
     639                rc = display_get_info(ui->display, &info);
     640                if (rc != EOK)
     641                        return rc;
     642
     643                *rect = info.rect;
     644        } else if (ui->console != NULL) {
     645                rc = console_get_size(ui->console, &cols, &rows);
     646                if (rc != EOK)
     647                        return rc;
     648
     649                rect->p0.x = 0;
     650                rect->p0.y = 0;
     651                rect->p1.x = cols;
     652                rect->p1.y = rows;
     653        } else {
     654                return ENOTSUP;
     655        }
     656
     657        return EOK;
     658}
     659
     660/** Get clickmatic from UI.
     661 *
     662 * @pararm ui UI
     663 * @return Clickmatic
     664 */
     665ui_clickmatic_t *ui_get_clickmatic(ui_t *ui)
     666{
     667        return ui->clickmatic;
     668}
     669
    337670/** @}
    338671 */
Note: See TracChangeset for help on using the changeset viewer.