Changes in uspace/lib/ui/src/ui.c [3d10a2f:26edcd6] in mainline


Ignore:
File:
1 edited

Legend:

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

    r3d10a2f r26edcd6  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2026 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3939#include <errno.h>
    4040#include <fibril.h>
     41#include <fibril_synch.h>
    4142#include <gfx/color.h>
     43#include <gfx/cursor.h>
    4244#include <gfx/render.h>
    4345#include <io/console.h>
     
    4648#include <str.h>
    4749#include <task.h>
     50#include <types/common.h>
     51#include <ui/clickmatic.h>
    4852#include <ui/ui.h>
    4953#include <ui/wdecor.h>
    5054#include <ui/window.h>
     55#include "../private/wdecor.h"
    5156#include "../private/window.h"
    5257#include "../private/ui.h"
     
    6166 * @param ws Place to store window system type (protocol)
    6267 * @param osvc Place to store pointer to output service name
    63  */
    64 static void ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
    65     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)
    6674{
    6775        const char *cp;
    68 
    69         if (ospec == UI_DISPLAY_DEFAULT) {
    70                 *ws = ui_ws_display;
    71                 *osvc = DISPLAY_DEFAULT;
    72                 return;
    73         }
     76        const char *qm;
     77        const char *endptr;
     78        uint64_t idev_id;
     79        errno_t rc;
     80
     81        *ridev_id = 0;
    7482
    7583        cp = ospec;
     
    7785                ++cp;
    7886
     87        /* Window system / protocol */
    7988        if (*cp == '@') {
    8089                if (str_lcmp(ospec, "disp@", str_length("disp@")) == 0) {
     
    8493                } else if (str_lcmp(ospec, "null@", str_length("null@")) == 0) {
    8594                        *ws = ui_ws_null;
     95                } else if (str_lcmp(ospec, "@", str_length("@")) == 0) {
     96                        *ws = ui_ws_any;
    8697                } else {
    8798                        *ws = ui_ws_unknown;
    8899                }
    89100
    90                 if (cp[1] != '\0')
    91                         *osvc = cp + 1;
    92                 else
    93                         *osvc = NULL;
     101                ++cp;
    94102        } else {
    95103                *ws = ui_ws_display;
    96                 *osvc = ospec;
    97         }
     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;
    98145}
    99146
     
    114161        console_gc_t *cgc;
    115162        ui_winsys_t ws;
    116         const char *osvc;
     163        char *osvc;
    117164        sysarg_t cols;
    118165        sysarg_t rows;
     166        sysarg_t idev_id;
    119167        ui_t *ui;
    120168
    121         ui_ospec_parse(ospec, &ws, &osvc);
    122 
    123         if (ws == ui_ws_display) {
    124                 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);
    125176                if (rc != EOK)
    126                         return rc;
     177                        goto disp_fail;
    127178
    128179                rc = ui_create_disp(display, &ui);
    129180                if (rc != EOK) {
    130181                        display_close(display);
    131                         return rc;
    132                 }
    133         } 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) {
    134194                console = console_init(stdin, stdout);
    135195                if (console == NULL)
    136                         return EIO;
     196                        goto cons_fail;
    137197
    138198                rc = console_get_size(console, &cols, &rows);
    139199                if (rc != EOK) {
    140200                        console_done(console);
    141                         return rc;
     201                        goto cons_fail;
    142202                }
    143203
     
    148208                if (rc != EOK) {
    149209                        console_done(console);
    150                         return rc;
     210                        goto cons_fail;
    151211                }
    152212
     
    155215                        ui_destroy(ui);
    156216                        console_done(console);
    157                         return rc;
    158                 }
     217                        goto cons_fail;
     218                }
     219
     220                free(osvc);
    159221
    160222                ui->cgc = cgc;
     
    165227
    166228                (void) ui_paint(ui);
    167         } else if (ws == ui_ws_null) {
     229                ui->myoutput = true;
     230                *rui = ui;
     231                return EOK;
     232        }
     233
     234cons_fail:
     235        if (ws == ui_ws_null) {
     236                free(osvc);
    168237                rc = ui_create_disp(NULL, &ui);
    169238                if (rc != EOK)
    170239                        return rc;
    171         } else {
    172                 return EINVAL;
    173         }
    174 
    175         ui->myoutput = true;
    176         *rui = ui;
    177         return EOK;
     240
     241                ui->myoutput = true;
     242                *rui = ui;
     243                return EOK;
     244        }
     245
     246        free(osvc);
     247        return EINVAL;
    178248}
    179249
     
    186256{
    187257        ui_t *ui;
     258        errno_t rc;
    188259
    189260        ui = calloc(1, sizeof(ui_t));
     
    191262                return ENOMEM;
    192263
     264        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     265        if (rc != EOK) {
     266                free(ui);
     267                return rc;
     268        }
     269
    193270        ui->console = console;
    194271        list_initialize(&ui->windows);
     272        fibril_mutex_initialize(&ui->lock);
    195273        *rui = ui;
    196274        return EOK;
     
    206284{
    207285        ui_t *ui;
     286        errno_t rc;
    208287
    209288        ui = calloc(1, sizeof(ui_t));
     
    211290                return ENOMEM;
    212291
     292        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     293        if (rc != EOK) {
     294                free(ui);
     295                return rc;
     296        }
     297
    213298        ui->display = disp;
    214299        list_initialize(&ui->windows);
     300        fibril_mutex_initialize(&ui->lock);
    215301        *rui = ui;
    216302        return EOK;
     
    240326}
    241327
     328/** Resize UI after screen size change.
     329 *
     330 * @param ui UI
     331 * @param rect New screen rectangle.
     332 */
     333static void ui_resize(ui_t *ui, gfx_rect_t *rect)
     334{
     335        ui_window_t *wnd;
     336
     337        ui->rect = *rect;
     338
     339        /* Reposition/resize windows */
     340        wnd = ui_window_first(ui);
     341        while (wnd != NULL) {
     342                ui_window_update_placement(wnd);
     343                wnd = ui_window_next(wnd);
     344        }
     345
     346        /*
     347         * XXX Resizing cleared console GC so we need to repaint the
     348         * background.
     349         */
     350        (void)ui_paint(ui);
     351}
     352
    242353static void ui_cons_event_process(ui_t *ui, cons_event_t *event)
    243354{
     
    245356        ui_evclaim_t claim;
    246357        pos_event_t pos;
     358        sysarg_t cols, rows;
     359        gfx_rect_t rect;
     360        errno_t rc;
    247361
    248362        awnd = ui_window_get_active(ui);
     
    252366        switch (event->type) {
    253367        case CEV_KEY:
     368                ui_lock(ui);
    254369                ui_window_send_kbd(awnd, &event->ev.key);
     370                ui_unlock(ui);
    255371                break;
    256372        case CEV_POS:
     
    262378                claim = ui_wdecor_pos_event(awnd->wdecor, &pos);
    263379                /* Note: If event is claimed, awnd might not be valid anymore */
    264                 if (claim == ui_unclaimed)
     380                if (claim == ui_unclaimed) {
     381                        ui_lock(ui);
    265382                        ui_window_send_pos(awnd, &pos);
    266 
     383                        ui_unlock(ui);
     384                }
     385
     386                break;
     387        case CEV_RESIZE:
     388                rc = console_gc_resize(ui->cgc);
     389                if (rc != EOK) {
     390                        /* XXX No good way to recover. */
     391                        console_done(ui->console);
     392                        exit(1);
     393                }
     394
     395                rc = console_get_size(ui->console, &cols, &rows);
     396                if (rc != EOK) {
     397                        /* XXX No good way to recover. */
     398                        console_done(ui->console);
     399                        exit(1);
     400                }
     401
     402                ui_lock(ui);
     403
     404                rect.p0.x = 0;
     405                rect.p0.y = 0;
     406                rect.p1.x = cols;
     407                rect.p1.y = rows;
     408
     409                ui_resize(ui, &rect);
     410                ui_unlock(ui);
    267411                break;
    268412        }
     
    316460        errno_t rc;
    317461        gfx_context_t *gc;
    318         ui_window_t *awnd;
     462        ui_window_t *wnd;
    319463        gfx_color_t *color = NULL;
    320464
     
    343487        gfx_color_delete(color);
    344488
    345         /* XXX Should repaint all windows */
     489        /* Repaint all windows */
     490        wnd = ui_window_first(ui);
     491        while (wnd != NULL) {
     492                rc = ui_wdecor_paint(wnd->wdecor);
     493                if (rc != EOK)
     494                        return rc;
     495
     496                rc = ui_window_paint(wnd);
     497                if (rc != EOK)
     498                        return rc;
     499
     500                wnd = ui_window_next(wnd);
     501        }
     502
     503        return EOK;
     504}
     505
     506/** Free up console for other users.
     507 *
     508 * Release console resources for another application (that the current
     509 * task is starting). After the other application finishes, resume
     510 * operation with ui_resume(). No calls to UI must happen inbetween
     511 * and no events must be processed (i.e. the calling function must not
     512 * return control to UI.
     513 *
     514 * @param ui UI
     515 * @return EOK on success or an error code
     516 */
     517errno_t ui_suspend(ui_t *ui)
     518{
     519        errno_t rc;
     520
     521        assert(!ui->suspended);
     522
     523        if (ui->cgc == NULL) {
     524                ui->suspended = true;
     525                return EOK;
     526        }
     527
     528        (void) console_set_caption(ui->console, "");
     529        rc = console_gc_suspend(ui->cgc);
     530        if (rc != EOK)
     531                return rc;
     532
     533        ui->suspended = true;
     534        return EOK;
     535}
     536
     537/** Resume suspended UI.
     538 *
     539 * Reclaim console resources (after child application has finished running)
     540 * and restore UI operation previously suspended by calling ui_suspend().
     541 *
     542 * @param ui UI
     543 * @return EOK on success or an error code
     544 */
     545errno_t ui_resume(ui_t *ui)
     546{
     547        errno_t rc;
     548        ui_window_t *awnd;
     549        sysarg_t col;
     550        sysarg_t row;
     551        cons_event_t ev;
     552
     553        assert(ui->suspended);
     554
     555        if (ui->cgc == NULL) {
     556                ui->suspended = false;
     557                return EOK;
     558        }
     559
     560        rc = console_get_pos(ui->console, &col, &row);
     561        if (rc != EOK)
     562                return rc;
     563
     564        /*
     565         * Here's a little heuristic to help determine if we need
     566         * to pause before returning to the UI. If we are in the
     567         * top-left corner, chances are the screen is empty and
     568         * there is no need to pause.
     569         */
     570        if (col != 0 || row != 0) {
     571                printf("Press any key or button to continue...\n");
     572
     573                while (true) {
     574                        rc = console_get_event(ui->console, &ev);
     575                        if (rc != EOK)
     576                                return EIO;
     577
     578                        if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS)
     579                                break;
     580
     581                        if (ev.type == CEV_POS && ev.ev.pos.type == POS_PRESS)
     582                                break;
     583                }
     584        }
     585
     586        rc = console_gc_resume(ui->cgc);
     587        if (rc != EOK)
     588                return rc;
     589
     590        ui->suspended = false;
     591
    346592        awnd = ui_window_get_active(ui);
    347         if (awnd == NULL)
    348                 return EOK;
    349 
    350         rc = ui_wdecor_paint(awnd->wdecor);
     593        if (awnd != NULL)
     594                (void) console_set_caption(ui->console, awnd->wdecor->caption);
     595
     596        rc = gfx_cursor_set_visible(console_gc_get_ctx(ui->cgc), false);
    351597        if (rc != EOK)
    352598                return rc;
    353599
    354         return ui_window_paint(awnd);
     600        return EOK;
     601}
     602
     603/** Determine if UI is suspended.
     604 *
     605 * @param ui UI
     606 * @return @c true iff UI is suspended
     607 */
     608bool ui_is_suspended(ui_t *ui)
     609{
     610        return ui->suspended;
     611}
     612
     613/** Lock UI.
     614 *
     615 * Block UI from calling window callbacks. @c ui_lock() and @c ui_unlock()
     616 * must be used when accessing UI resources from a fibril (as opposed to
     617 * from a window callback).
     618 *
     619 * @param ui UI
     620 */
     621void ui_lock(ui_t *ui)
     622{
     623        if (ui->display != NULL)
     624                display_lock(ui->display);
     625        fibril_mutex_lock(&ui->lock);
     626}
     627
     628/** Unlock UI.
     629 *
     630 * Allow UI to call window callbacks. @c ui_lock() and @c ui_unlock()
     631 * must be used when accessing window resources from a fibril (as opposed to
     632 * from a window callback).
     633 *
     634 * @param ui UI
     635 */
     636void ui_unlock(ui_t *ui)
     637{
     638        fibril_mutex_unlock(&ui->lock);
     639        if (ui->display != NULL)
     640                display_unlock(ui->display);
    355641}
    356642
     
    392678}
    393679
     680/** Get UI screen rectangle.
     681 *
     682 * @param ui User interface
     683 * @param rect Place to store bounding rectangle
     684 */
     685errno_t ui_get_rect(ui_t *ui, gfx_rect_t *rect)
     686{
     687        display_info_t info;
     688        sysarg_t cols, rows;
     689        errno_t rc;
     690
     691        if (ui->display != NULL) {
     692                rc = display_get_info(ui->display, &info);
     693                if (rc != EOK)
     694                        return rc;
     695
     696                *rect = info.rect;
     697        } else if (ui->console != NULL) {
     698                rc = console_get_size(ui->console, &cols, &rows);
     699                if (rc != EOK)
     700                        return rc;
     701
     702                rect->p0.x = 0;
     703                rect->p0.y = 0;
     704                rect->p1.x = cols;
     705                rect->p1.y = rows;
     706        } else {
     707                return ENOTSUP;
     708        }
     709
     710        return EOK;
     711}
     712
     713/** Get clickmatic from UI.
     714 *
     715 * @pararm ui UI
     716 * @return Clickmatic
     717 */
     718ui_clickmatic_t *ui_get_clickmatic(ui_t *ui)
     719{
     720        return ui->clickmatic;
     721}
     722
    394723/** @}
    395724 */
Note: See TracChangeset for help on using the changeset viewer.