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


Ignore:
File:
1 edited

Legend:

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

    r983052c r252d03c  
    11/*
    2  * Copyright (c) 2023 Jiri Svoboda
     2 * Copyright (c) 2021 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>
    4541#include <io/console.h>
    4642#include <stdbool.h>
     
    4844#include <str.h>
    4945#include <task.h>
    50 #include <types/common.h>
    51 #include <ui/clickmatic.h>
    5246#include <ui/ui.h>
    5347#include <ui/wdecor.h>
    5448#include <ui/window.h>
    55 #include "../private/wdecor.h"
    5649#include "../private/window.h"
    5750#include "../private/ui.h"
     
    6053 *
    6154 * Output specification has the form <proto>@<service> where proto is
    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).
     55 * eiher 'disp' for display service or 'cons' for console. Service
     56 * is a location ID service name (e.g. hid/display).
    6457 *
    6558 * @param ospec Output specification
    6659 * @param ws Place to store window system type (protocol)
    6760 * @param osvc Place to store pointer to output service name
    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  */
    72 static errno_t ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
    73     char **osvc, sysarg_t *ridev_id)
     61 */
     62static void ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
     63    const char **osvc)
    7464{
    7565        const char *cp;
    76         const char *qm;
    77         const char *endptr;
    78         uint64_t idev_id;
    79         errno_t rc;
    80 
    81         *ridev_id = 0;
     66
     67        if (ospec == UI_DISPLAY_DEFAULT) {
     68                *ws = ui_ws_display;
     69                *osvc = DISPLAY_DEFAULT;
     70                return;
     71        }
    8272
    8373        cp = ospec;
     
    8575                ++cp;
    8676
    87         /* Window system / protocol */
    8877        if (*cp == '@') {
    8978                if (str_lcmp(ospec, "disp@", str_length("disp@")) == 0) {
     
    9180                } else if (str_lcmp(ospec, "cons@", str_length("cons@")) == 0) {
    9281                        *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;
    9782                } else {
    9883                        *ws = ui_ws_unknown;
    9984                }
    10085
    101                 ++cp;
     86                if (cp[1] != '\0')
     87                        *osvc = cp + 1;
     88                else
     89                        *osvc = NULL;
    10290        } else {
    10391                *ws = ui_ws_display;
    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;
    141 error:
    142         free(*osvc);
    143         *osvc = NULL;
    144         return rc;
     92                *osvc = ospec;
     93        }
    14594}
    14695
     
    14897 *
    14998 * @param ospec Output specification or @c UI_DISPLAY_DEFAULT to use
    150  *              the default display service, UI_CONSOLE_DEFAULT to use
    151  *              the default console service, UI_DISPLAY_NULL to use
    152  *              dummy output.
     99 *              the default output
    153100 * @param rui Place to store pointer to new UI
    154101 * @return EOK on success or an error code
     
    161108        console_gc_t *cgc;
    162109        ui_winsys_t ws;
    163         char *osvc;
    164         sysarg_t cols;
    165         sysarg_t rows;
    166         sysarg_t idev_id;
     110        const char *osvc;
    167111        ui_t *ui;
    168112
    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);
     113        ui_ospec_parse(ospec, &ws, &osvc);
     114
     115        if (ws == ui_ws_display) {
     116                rc = display_open(osvc, &display);
    176117                if (rc != EOK)
    177                         goto disp_fail;
     118                        return rc;
    178119
    179120                rc = ui_create_disp(display, &ui);
    180121                if (rc != EOK) {
    181122                        display_close(display);
    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 
    192 disp_fail:
    193         if (ws == ui_ws_console || ws == ui_ws_any) {
     123                        return rc;
     124                }
     125        } else if (ws == ui_ws_console) {
    194126                console = console_init(stdin, stdout);
    195127                if (console == NULL)
    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);
     128                        return EIO;
    205129
    206130                /* ws == ui_ws_console */
     
    208132                if (rc != EOK) {
    209133                        console_done(console);
    210                         goto cons_fail;
     134                        return rc;
    211135                }
    212136
     
    215139                        ui_destroy(ui);
    216140                        console_done(console);
    217                         goto cons_fail;
    218                 }
    219 
    220                 free(osvc);
     141                        return rc;
     142                }
    221143
    222144                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 
    234 cons_fail:
    235         if (ws == ui_ws_null) {
    236                 free(osvc);
    237                 rc = ui_create_disp(NULL, &ui);
    238                 if (rc != EOK)
    239                         return rc;
    240 
    241                 ui->myoutput = true;
    242                 *rui = ui;
    243                 return EOK;
    244         }
    245 
    246         free(osvc);
    247         return EINVAL;
     145        } else {
     146                return EINVAL;
     147        }
     148
     149        ui->myoutput = true;
     150        *rui = ui;
     151        return EOK;
    248152}
    249153
     
    256160{
    257161        ui_t *ui;
    258         errno_t rc;
    259162
    260163        ui = calloc(1, sizeof(ui_t));
     
    262165                return ENOMEM;
    263166
    264         rc = ui_clickmatic_create(ui, &ui->clickmatic);
    265         if (rc != EOK) {
    266                 free(ui);
    267                 return rc;
    268         }
    269 
    270167        ui->console = console;
    271168        list_initialize(&ui->windows);
    272         fibril_mutex_initialize(&ui->lock);
    273169        *rui = ui;
    274170        return EOK;
     
    284180{
    285181        ui_t *ui;
    286         errno_t rc;
    287182
    288183        ui = calloc(1, sizeof(ui_t));
     
    290185                return ENOMEM;
    291186
    292         rc = ui_clickmatic_create(ui, &ui->clickmatic);
    293         if (rc != EOK) {
    294                 free(ui);
    295                 return rc;
    296         }
    297 
    298187        ui->display = disp;
    299188        list_initialize(&ui->windows);
    300         fibril_mutex_initialize(&ui->lock);
    301189        *rui = ui;
    302190        return EOK;
     
    315203                if (ui->cgc != NULL)
    316204                        console_gc_delete(ui->cgc);
    317                 if (ui->console != NULL) {
    318                         console_cursor_visibility(ui->console, true);
     205                if (ui->console != NULL)
    319206                        console_done(ui->console);
    320                 }
    321207                if (ui->display != NULL)
    322208                        display_close(ui->display);
     
    330216        ui_window_t *awnd;
    331217        ui_evclaim_t claim;
    332         pos_event_t pos;
    333218
    334219        awnd = ui_window_get_active(ui);
     
    338223        switch (event->type) {
    339224        case CEV_KEY:
    340                 ui_lock(ui);
    341225                ui_window_send_kbd(awnd, &event->ev.key);
    342                 ui_unlock(ui);
    343226                break;
    344227        case CEV_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);
     228                claim = ui_wdecor_pos_event(awnd->wdecor, &event->ev.pos);
    351229                /* Note: If event is claimed, awnd might not be valid anymore */
    352                 if (claim == ui_unclaimed) {
    353                         ui_lock(ui);
    354                         ui_window_send_pos(awnd, &pos);
    355                         ui_unlock(ui);
    356                 }
    357 
     230                if (claim == ui_unclaimed)
     231                        ui_window_send_pos(awnd, &event->ev.pos);
    358232                break;
    359233        }
     
    406280{
    407281        errno_t rc;
    408         gfx_context_t *gc;
    409282        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);
    435283
    436284        /* XXX Should repaint all windows */
     
    444292
    445293        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  */
    459 errno_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  */
    487 errno_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  */
    550 bool 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  */
    563 void 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  */
    576 void ui_unlock(ui_t *ui)
    577 {
    578         fibril_mutex_unlock(&ui->lock);
    579294}
    580295
     
    616331}
    617332
    618 /** Get UI screen rectangle.
    619  *
    620  * @param ui User interface
    621  * @param rect Place to store bounding rectangle
    622  */
    623 errno_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  */
    656 ui_clickmatic_t *ui_get_clickmatic(ui_t *ui)
    657 {
    658         return ui->clickmatic;
    659 }
    660 
    661333/** @}
    662334 */
Note: See TracChangeset for help on using the changeset viewer.