Changes in uspace/lib/ui/src/ui.c [252d03c:899bdfd] in mainline


Ignore:
File:
1 edited

Legend:

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

    r252d03c r899bdfd  
    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>
     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                }
     203
     204                console_cursor_visibility(console, false);
    129205
    130206                /* ws == ui_ws_console */
     
    132208                if (rc != EOK) {
    133209                        console_done(console);
    134                         return rc;
     210                        goto cons_fail;
    135211                }
    136212
     
    139215                        ui_destroy(ui);
    140216                        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)
    141239                        return rc;
    142                 }
    143 
    144                 ui->cgc = cgc;
    145         } else {
    146                 return EINVAL;
    147         }
    148 
    149         ui->myoutput = true;
    150         *rui = ui;
    151         return EOK;
     240
     241                ui->myoutput = true;
     242                *rui = ui;
     243                return EOK;
     244        }
     245
     246        free(osvc);
     247        return EINVAL;
    152248}
    153249
     
    160256{
    161257        ui_t *ui;
     258        errno_t rc;
    162259
    163260        ui = calloc(1, sizeof(ui_t));
     
    165262                return ENOMEM;
    166263
     264        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     265        if (rc != EOK) {
     266                free(ui);
     267                return rc;
     268        }
     269
    167270        ui->console = console;
    168271        list_initialize(&ui->windows);
     272        fibril_mutex_initialize(&ui->lock);
    169273        *rui = ui;
    170274        return EOK;
     
    180284{
    181285        ui_t *ui;
     286        errno_t rc;
    182287
    183288        ui = calloc(1, sizeof(ui_t));
     
    185290                return ENOMEM;
    186291
     292        rc = ui_clickmatic_create(ui, &ui->clickmatic);
     293        if (rc != EOK) {
     294                free(ui);
     295                return rc;
     296        }
     297
    187298        ui->display = disp;
    188299        list_initialize(&ui->windows);
     300        fibril_mutex_initialize(&ui->lock);
    189301        *rui = ui;
    190302        return EOK;
     
    203315                if (ui->cgc != NULL)
    204316                        console_gc_delete(ui->cgc);
    205                 if (ui->console != NULL)
     317                if (ui->console != NULL) {
     318                        console_cursor_visibility(ui->console, true);
    206319                        console_done(ui->console);
     320                }
    207321                if (ui->display != NULL)
    208322                        display_close(ui->display);
     
    216330        ui_window_t *awnd;
    217331        ui_evclaim_t claim;
     332        pos_event_t pos;
    218333
    219334        awnd = ui_window_get_active(ui);
     
    223338        switch (event->type) {
    224339        case CEV_KEY:
     340                ui_lock(ui);
    225341                ui_window_send_kbd(awnd, &event->ev.key);
     342                ui_unlock(ui);
    226343                break;
    227344        case CEV_POS:
    228                 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);
    229351                /* Note: If event is claimed, awnd might not be valid anymore */
    230                 if (claim == ui_unclaimed)
    231                         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);
    232363                break;
    233364        }
     
    280411{
    281412        errno_t rc;
     413        gfx_context_t *gc;
    282414        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);
    283440
    284441        /* XXX Should repaint all windows */
     
    292449
    293450        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        fibril_mutex_lock(&ui->lock);
     571}
     572
     573/** Unlock UI.
     574 *
     575 * Allow UI to call window callbacks. @c ui_lock() and @c ui_unlock()
     576 * must be used when accessing window resources from a fibril (as opposed to
     577 * from a window callback).
     578 *
     579 * @param ui UI
     580 */
     581void ui_unlock(ui_t *ui)
     582{
     583        fibril_mutex_unlock(&ui->lock);
    294584}
    295585
     
    331621}
    332622
     623/** Get UI screen rectangle.
     624 *
     625 * @param ui User interface
     626 * @param rect Place to store bounding rectangle
     627 */
     628errno_t ui_get_rect(ui_t *ui, gfx_rect_t *rect)
     629{
     630        display_info_t info;
     631        sysarg_t cols, rows;
     632        errno_t rc;
     633
     634        if (ui->display != NULL) {
     635                rc = display_get_info(ui->display, &info);
     636                if (rc != EOK)
     637                        return rc;
     638
     639                *rect = info.rect;
     640        } else if (ui->console != NULL) {
     641                rc = console_get_size(ui->console, &cols, &rows);
     642                if (rc != EOK)
     643                        return rc;
     644
     645                rect->p0.x = 0;
     646                rect->p0.y = 0;
     647                rect->p1.x = cols;
     648                rect->p1.y = rows;
     649        } else {
     650                return ENOTSUP;
     651        }
     652
     653        return EOK;
     654}
     655
     656/** Get clickmatic from UI.
     657 *
     658 * @pararm ui UI
     659 * @return Clickmatic
     660 */
     661ui_clickmatic_t *ui_get_clickmatic(ui_t *ui)
     662{
     663        return ui->clickmatic;
     664}
     665
    333666/** @}
    334667 */
Note: See TracChangeset for help on using the changeset viewer.