source: mainline/uspace/lib/ui/src/ui.c@ 241ab7e

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 241ab7e was bb14312, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Use hardware cursor in text mode

We extend GC with cursor control operations. This will also allow to
control the HW cursor when running display server in text mode in
the future (provided that we implement the missing bits in the rest
of the stack, i.e. in IPC GC and in the display server).

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libui
30 * @{
31 */
32/**
33 * @file User interface
34 */
35
36#include <adt/list.h>
37#include <ctype.h>
38#include <display.h>
39#include <errno.h>
40#include <fibril.h>
41#include <io/console.h>
42#include <stdbool.h>
43#include <stdlib.h>
44#include <str.h>
45#include <task.h>
46#include <ui/ui.h>
47#include <ui/wdecor.h>
48#include <ui/window.h>
49#include "../private/window.h"
50#include "../private/ui.h"
51
52/** Parse output specification.
53 *
54 * 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).
57 *
58 * @param ospec Output specification
59 * @param ws Place to store window system type (protocol)
60 * @param osvc Place to store pointer to output service name
61 */
62static void ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
63 const char **osvc)
64{
65 const char *cp;
66
67 if (ospec == UI_DISPLAY_DEFAULT) {
68 *ws = ui_ws_display;
69 *osvc = DISPLAY_DEFAULT;
70 return;
71 }
72
73 cp = ospec;
74 while (isalpha(*cp))
75 ++cp;
76
77 if (*cp == '@') {
78 if (str_lcmp(ospec, "disp@", str_length("disp@")) == 0) {
79 *ws = ui_ws_display;
80 } else if (str_lcmp(ospec, "cons@", str_length("cons@")) == 0) {
81 *ws = ui_ws_console;
82 } else {
83 *ws = ui_ws_unknown;
84 }
85
86 if (cp[1] != '\0')
87 *osvc = cp + 1;
88 else
89 *osvc = NULL;
90 } else {
91 *ws = ui_ws_display;
92 *osvc = ospec;
93 }
94}
95
96/** Create new user interface.
97 *
98 * @param ospec Output specification or @c UI_DISPLAY_DEFAULT to use
99 * the default output
100 * @param rui Place to store pointer to new UI
101 * @return EOK on success or an error code
102 */
103errno_t ui_create(const char *ospec, ui_t **rui)
104{
105 errno_t rc;
106 display_t *display;
107 console_ctrl_t *console;
108 console_gc_t *cgc;
109 ui_winsys_t ws;
110 const char *osvc;
111 ui_t *ui;
112
113 ui_ospec_parse(ospec, &ws, &osvc);
114
115 if (ws == ui_ws_display) {
116 rc = display_open(osvc, &display);
117 if (rc != EOK)
118 return rc;
119
120 rc = ui_create_disp(display, &ui);
121 if (rc != EOK) {
122 display_close(display);
123 return rc;
124 }
125 } else if (ws == ui_ws_console) {
126 console = console_init(stdin, stdout);
127 if (console == NULL)
128 return EIO;
129
130 console_cursor_visibility(console, false);
131
132 /* ws == ui_ws_console */
133 rc = ui_create_cons(console, &ui);
134 if (rc != EOK) {
135 console_done(console);
136 return rc;
137 }
138
139 rc = console_gc_create(console, NULL, &cgc);
140 if (rc != EOK) {
141 ui_destroy(ui);
142 console_done(console);
143 return rc;
144 }
145
146 ui->cgc = cgc;
147 } else {
148 return EINVAL;
149 }
150
151 ui->myoutput = true;
152 *rui = ui;
153 return EOK;
154}
155
156/** Create new user interface using console service.
157 *
158 * @param rui Place to store pointer to new UI
159 * @return EOK on success or an error code
160 */
161errno_t ui_create_cons(console_ctrl_t *console, ui_t **rui)
162{
163 ui_t *ui;
164
165 ui = calloc(1, sizeof(ui_t));
166 if (ui == NULL)
167 return ENOMEM;
168
169 ui->console = console;
170 list_initialize(&ui->windows);
171 *rui = ui;
172 return EOK;
173}
174
175/** Create new user interface using display service.
176 *
177 * @param disp Display
178 * @param rui Place to store pointer to new UI
179 * @return EOK on success or an error code
180 */
181errno_t ui_create_disp(display_t *disp, ui_t **rui)
182{
183 ui_t *ui;
184
185 ui = calloc(1, sizeof(ui_t));
186 if (ui == NULL)
187 return ENOMEM;
188
189 ui->display = disp;
190 list_initialize(&ui->windows);
191 *rui = ui;
192 return EOK;
193}
194
195/** Destroy user interface.
196 *
197 * @param ui User interface or @c NULL
198 */
199void ui_destroy(ui_t *ui)
200{
201 if (ui == NULL)
202 return;
203
204 if (ui->myoutput) {
205 if (ui->cgc != NULL)
206 console_gc_delete(ui->cgc);
207 if (ui->console != NULL) {
208 console_cursor_visibility(ui->console, true);
209 console_done(ui->console);
210 }
211 if (ui->display != NULL)
212 display_close(ui->display);
213 }
214
215 free(ui);
216}
217
218static void ui_cons_event_process(ui_t *ui, cons_event_t *event)
219{
220 ui_window_t *awnd;
221 ui_evclaim_t claim;
222
223 awnd = ui_window_get_active(ui);
224 if (awnd == NULL)
225 return;
226
227 switch (event->type) {
228 case CEV_KEY:
229 ui_window_send_kbd(awnd, &event->ev.key);
230 break;
231 case CEV_POS:
232 claim = ui_wdecor_pos_event(awnd->wdecor, &event->ev.pos);
233 /* Note: If event is claimed, awnd might not be valid anymore */
234 if (claim == ui_unclaimed)
235 ui_window_send_pos(awnd, &event->ev.pos);
236 break;
237 }
238}
239
240/** Execute user interface.
241 *
242 * Return task exit code of zero and block unitl the application starts
243 * the termination process by calling ui_quit(@a ui).
244 *
245 * @param ui User interface
246 */
247void ui_run(ui_t *ui)
248{
249 cons_event_t event;
250 usec_t timeout;
251 errno_t rc;
252
253 /* Only return command prompt if we are running in a separate window */
254 if (ui->display != NULL)
255 task_retval(0);
256
257 while (!ui->quit) {
258 if (ui->console != NULL) {
259 timeout = 100000;
260 rc = console_get_event_timeout(ui->console,
261 &event, &timeout);
262
263 /* Do we actually have an event? */
264 if (rc == EOK) {
265 ui_cons_event_process(ui, &event);
266 } else if (rc != ETIMEOUT) {
267 /* Error, quit */
268 break;
269 }
270 } else {
271 fibril_usleep(100000);
272 }
273 }
274}
275
276/** Repaint UI (only used in fullscreen mode).
277 *
278 * This is used when an area is exposed in fullscreen mode.
279 *
280 * @param ui UI
281 * @return @c EOK on success or an error code
282 */
283errno_t ui_paint(ui_t *ui)
284{
285 errno_t rc;
286 ui_window_t *awnd;
287
288 /* XXX Should repaint all windows */
289 awnd = ui_window_get_active(ui);
290 if (awnd == NULL)
291 return EOK;
292
293 rc = ui_wdecor_paint(awnd->wdecor);
294 if (rc != EOK)
295 return rc;
296
297 return ui_window_paint(awnd);
298}
299
300/** Terminate user interface.
301 *
302 * Calling this function causes the user interface to terminate
303 * (i.e. exit from ui_run()). This would be typically called from
304 * an event handler.
305 *
306 * @param ui User interface
307 */
308void ui_quit(ui_t *ui)
309{
310 ui->quit = true;
311}
312
313/** Determine if we are running in text mode.
314 *
315 * @param ui User interface
316 * @return @c true iff we are running in text mode
317 */
318bool ui_is_textmode(ui_t *ui)
319{
320 /*
321 * XXX Currently console is always text and display is always
322 * graphics, but this need not always be true.
323 */
324 return (ui->console != NULL);
325}
326
327/** Determine if we are emulating windows.
328 *
329 * @param ui User interface
330 * @return @c true iff we are running in text mode
331 */
332bool ui_is_fullscreen(ui_t *ui)
333{
334 return (ui->display == NULL);
335}
336
337/** @}
338 */
Note: See TracBrowser for help on using the repository browser.