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


Ignore:
File:
1 edited

Legend:

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

    r3d10a2f r983052c  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2023 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;
     
    252338        switch (event->type) {
    253339        case CEV_KEY:
     340                ui_lock(ui);
    254341                ui_window_send_kbd(awnd, &event->ev.key);
     342                ui_unlock(ui);
    255343                break;
    256344        case CEV_POS:
     
    262350                claim = ui_wdecor_pos_event(awnd->wdecor, &pos);
    263351                /* Note: If event is claimed, awnd might not be valid anymore */
    264                 if (claim == ui_unclaimed)
     352                if (claim == ui_unclaimed) {
     353                        ui_lock(ui);
    265354                        ui_window_send_pos(awnd, &pos);
     355                        ui_unlock(ui);
     356                }
    266357
    267358                break;
     
    355446}
    356447
     448/** Free up console for other users.
     449 *
     450 * Release console resources for another application (that the current
     451 * task is starting). After the other application finishes, resume
     452 * operation with ui_resume(). No calls to UI must happen inbetween
     453 * and no events must be processed (i.e. the calling function must not
     454 * return control to UI.
     455 *
     456 * @param ui UI
     457 * @return EOK on success or an error code
     458 */
     459errno_t ui_suspend(ui_t *ui)
     460{
     461        errno_t rc;
     462
     463        assert(!ui->suspended);
     464
     465        if (ui->cgc == NULL) {
     466                ui->suspended = true;
     467                return EOK;
     468        }
     469
     470        (void) console_set_caption(ui->console, "");
     471        rc = console_gc_suspend(ui->cgc);
     472        if (rc != EOK)
     473                return rc;
     474
     475        ui->suspended = true;
     476        return EOK;
     477}
     478
     479/** Resume suspended UI.
     480 *
     481 * Reclaim console resources (after child application has finished running)
     482 * and restore UI operation previously suspended by calling ui_suspend().
     483 *
     484 * @param ui UI
     485 * @return EOK on success or an error code
     486 */
     487errno_t ui_resume(ui_t *ui)
     488{
     489        errno_t rc;
     490        ui_window_t *awnd;
     491        sysarg_t col;
     492        sysarg_t row;
     493        cons_event_t ev;
     494
     495        assert(ui->suspended);
     496
     497        if (ui->cgc == NULL) {
     498                ui->suspended = false;
     499                return EOK;
     500        }
     501
     502        rc = console_get_pos(ui->console, &col, &row);
     503        if (rc != EOK)
     504                return rc;
     505
     506        /*
     507         * Here's a little heuristic to help determine if we need
     508         * to pause before returning to the UI. If we are in the
     509         * top-left corner, chances are the screen is empty and
     510         * there is no need to pause.
     511         */
     512        if (col != 0 || row != 0) {
     513                printf("Press any key or button to continue...\n");
     514
     515                while (true) {
     516                        rc = console_get_event(ui->console, &ev);
     517                        if (rc != EOK)
     518                                return EIO;
     519
     520                        if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS)
     521                                break;
     522
     523                        if (ev.type == CEV_POS && ev.ev.pos.type == POS_PRESS)
     524                                break;
     525                }
     526        }
     527
     528        rc = console_gc_resume(ui->cgc);
     529        if (rc != EOK)
     530                return rc;
     531
     532        ui->suspended = false;
     533
     534        awnd = ui_window_get_active(ui);
     535        if (awnd != NULL)
     536                (void) console_set_caption(ui->console, awnd->wdecor->caption);
     537
     538        rc = gfx_cursor_set_visible(console_gc_get_ctx(ui->cgc), false);
     539        if (rc != EOK)
     540                return rc;
     541
     542        return EOK;
     543}
     544
     545/** Determine if UI is suspended.
     546 *
     547 * @param ui UI
     548 * @return @c true iff UI is suspended
     549 */
     550bool ui_is_suspended(ui_t *ui)
     551{
     552        return ui->suspended;
     553}
     554
     555/** Lock UI.
     556 *
     557 * Block UI from calling window callbacks. @c ui_lock() and @c ui_unlock()
     558 * must be used when accessing UI resources from a fibril (as opposed to
     559 * from a window callback).
     560 *
     561 * @param ui UI
     562 */
     563void ui_lock(ui_t *ui)
     564{
     565        fibril_mutex_lock(&ui->lock);
     566}
     567
     568/** Unlock UI.
     569 *
     570 * Allow UI to call window callbacks. @c ui_lock() and @c ui_unlock()
     571 * must be used when accessing window resources from a fibril (as opposed to
     572 * from a window callback).
     573 *
     574 * @param ui UI
     575 */
     576void ui_unlock(ui_t *ui)
     577{
     578        fibril_mutex_unlock(&ui->lock);
     579}
     580
    357581/** Terminate user interface.
    358582 *
     
    392616}
    393617
     618/** Get UI screen rectangle.
     619 *
     620 * @param ui User interface
     621 * @param rect Place to store bounding rectangle
     622 */
     623errno_t ui_get_rect(ui_t *ui, gfx_rect_t *rect)
     624{
     625        display_info_t info;
     626        sysarg_t cols, rows;
     627        errno_t rc;
     628
     629        if (ui->display != NULL) {
     630                rc = display_get_info(ui->display, &info);
     631                if (rc != EOK)
     632                        return rc;
     633
     634                *rect = info.rect;
     635        } else if (ui->console != NULL) {
     636                rc = console_get_size(ui->console, &cols, &rows);
     637                if (rc != EOK)
     638                        return rc;
     639
     640                rect->p0.x = 0;
     641                rect->p0.y = 0;
     642                rect->p1.x = cols;
     643                rect->p1.y = rows;
     644        } else {
     645                return ENOTSUP;
     646        }
     647
     648        return EOK;
     649}
     650
     651/** Get clickmatic from UI.
     652 *
     653 * @pararm ui UI
     654 * @return Clickmatic
     655 */
     656ui_clickmatic_t *ui_get_clickmatic(ui_t *ui)
     657{
     658        return ui->clickmatic;
     659}
     660
    394661/** @}
    395662 */
Note: See TracChangeset for help on using the changeset viewer.