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


Ignore:
File:
1 edited

Legend:

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

    r252d03c 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>
     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
    232358                break;
    233359        }
     
    280406{
    281407        errno_t rc;
     408        gfx_context_t *gc;
    282409        ui_window_t *awnd;
     410        gfx_color_t *color = NULL;
     411
     412        /* In case of null output */
     413        if (ui->cgc == NULL)
     414                return EOK;
     415
     416        gc = console_gc_get_ctx(ui->cgc);
     417
     418        rc = gfx_color_new_ega(0x11, &color);
     419        if (rc != EOK)
     420                return rc;
     421
     422        rc = gfx_set_color(gc, color);
     423        if (rc != EOK) {
     424                gfx_color_delete(color);
     425                return rc;
     426        }
     427
     428        rc = gfx_fill_rect(gc, &ui->rect);
     429        if (rc != EOK) {
     430                gfx_color_delete(color);
     431                return rc;
     432        }
     433
     434        gfx_color_delete(color);
    283435
    284436        /* XXX Should repaint all windows */
     
    292444
    293445        return ui_window_paint(awnd);
     446}
     447
     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);
    294579}
    295580
     
    331616}
    332617
     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
    333661/** @}
    334662 */
Note: See TracChangeset for help on using the changeset viewer.