source: mainline/uspace/lib/ui/src/ui.c@ 6c0766b

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

Translate window rendering in console/SSR with translation GC

In full-screen mode (such as text/console) and server-side rendering
we need other mechanism than memory GC to translate the coordinates
while rendering. We use a translation GC (xlategc).

Note the extensively elaborate testing of this very simple GC seems
quite overboard. At least the very elaborate test_gc_t could be hoisted
into a library and used wherever a test GC is required.

  • Property mode set to 100644
File size: 8.3 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 <gfx/color.h>
42#include <gfx/render.h>
43#include <io/console.h>
44#include <stdbool.h>
45#include <stdlib.h>
46#include <str.h>
47#include <task.h>
48#include <ui/ui.h>
49#include <ui/wdecor.h>
50#include <ui/window.h>
51#include "../private/window.h"
52#include "../private/ui.h"
53
54/** Parse output specification.
55 *
56 * Output specification has the form <proto>@<service> where proto is
57 * eiher 'disp' for display service or 'cons' for console. Service
58 * is a location ID service name (e.g. hid/display).
59 *
60 * @param ospec Output specification
61 * @param ws Place to store window system type (protocol)
62 * @param osvc Place to store pointer to output service name
63 */
64static void ui_ospec_parse(const char *ospec, ui_winsys_t *ws,
65 const char **osvc)
66{
67 const char *cp;
68
69 if (ospec == UI_DISPLAY_DEFAULT) {
70 *ws = ui_ws_display;
71 *osvc = DISPLAY_DEFAULT;
72 return;
73 }
74
75 cp = ospec;
76 while (isalpha(*cp))
77 ++cp;
78
79 if (*cp == '@') {
80 if (str_lcmp(ospec, "disp@", str_length("disp@")) == 0) {
81 *ws = ui_ws_display;
82 } else if (str_lcmp(ospec, "cons@", str_length("cons@")) == 0) {
83 *ws = ui_ws_console;
84 } else {
85 *ws = ui_ws_unknown;
86 }
87
88 if (cp[1] != '\0')
89 *osvc = cp + 1;
90 else
91 *osvc = NULL;
92 } else {
93 *ws = ui_ws_display;
94 *osvc = ospec;
95 }
96}
97
98/** Create new user interface.
99 *
100 * @param ospec Output specification or @c UI_DISPLAY_DEFAULT to use
101 * the default output
102 * @param rui Place to store pointer to new UI
103 * @return EOK on success or an error code
104 */
105errno_t ui_create(const char *ospec, ui_t **rui)
106{
107 errno_t rc;
108 display_t *display;
109 console_ctrl_t *console;
110 console_gc_t *cgc;
111 ui_winsys_t ws;
112 const char *osvc;
113 sysarg_t cols;
114 sysarg_t rows;
115 ui_t *ui;
116
117 ui_ospec_parse(ospec, &ws, &osvc);
118
119 if (ws == ui_ws_display) {
120 rc = display_open(osvc, &display);
121 if (rc != EOK)
122 return rc;
123
124 rc = ui_create_disp(display, &ui);
125 if (rc != EOK) {
126 display_close(display);
127 return rc;
128 }
129 } else if (ws == ui_ws_console) {
130 console = console_init(stdin, stdout);
131 if (console == NULL)
132 return EIO;
133
134 rc = console_get_size(console, &cols, &rows);
135 if (rc != EOK) {
136 console_done(console);
137 return rc;
138 }
139
140 console_cursor_visibility(console, false);
141
142 /* ws == ui_ws_console */
143 rc = ui_create_cons(console, &ui);
144 if (rc != EOK) {
145 console_done(console);
146 return rc;
147 }
148
149 rc = console_gc_create(console, NULL, &cgc);
150 if (rc != EOK) {
151 ui_destroy(ui);
152 console_done(console);
153 return rc;
154 }
155
156 ui->cgc = cgc;
157 ui->rect.p0.x = 0;
158 ui->rect.p0.y = 0;
159 ui->rect.p1.x = cols;
160 ui->rect.p1.y = rows;
161
162 (void) ui_paint(ui);
163 } else {
164 return EINVAL;
165 }
166
167 ui->myoutput = true;
168 *rui = ui;
169 return EOK;
170}
171
172/** Create new user interface using console service.
173 *
174 * @param rui Place to store pointer to new UI
175 * @return EOK on success or an error code
176 */
177errno_t ui_create_cons(console_ctrl_t *console, ui_t **rui)
178{
179 ui_t *ui;
180
181 ui = calloc(1, sizeof(ui_t));
182 if (ui == NULL)
183 return ENOMEM;
184
185 ui->console = console;
186 list_initialize(&ui->windows);
187 *rui = ui;
188 return EOK;
189}
190
191/** Create new user interface using display service.
192 *
193 * @param disp Display
194 * @param rui Place to store pointer to new UI
195 * @return EOK on success or an error code
196 */
197errno_t ui_create_disp(display_t *disp, ui_t **rui)
198{
199 ui_t *ui;
200
201 ui = calloc(1, sizeof(ui_t));
202 if (ui == NULL)
203 return ENOMEM;
204
205 ui->display = disp;
206 list_initialize(&ui->windows);
207 *rui = ui;
208 return EOK;
209}
210
211/** Destroy user interface.
212 *
213 * @param ui User interface or @c NULL
214 */
215void ui_destroy(ui_t *ui)
216{
217 if (ui == NULL)
218 return;
219
220 if (ui->myoutput) {
221 if (ui->cgc != NULL)
222 console_gc_delete(ui->cgc);
223 if (ui->console != NULL) {
224 console_cursor_visibility(ui->console, true);
225 console_done(ui->console);
226 }
227 if (ui->display != NULL)
228 display_close(ui->display);
229 }
230
231 free(ui);
232}
233
234static void ui_cons_event_process(ui_t *ui, cons_event_t *event)
235{
236 ui_window_t *awnd;
237 ui_evclaim_t claim;
238 pos_event_t pos;
239
240 awnd = ui_window_get_active(ui);
241 if (awnd == NULL)
242 return;
243
244 switch (event->type) {
245 case CEV_KEY:
246 ui_window_send_kbd(awnd, &event->ev.key);
247 break;
248 case CEV_POS:
249 pos = event->ev.pos;
250 /* Translate event to window-relative coordinates */
251 pos.hpos -= awnd->dpos.x;
252 pos.vpos -= awnd->dpos.y;
253
254 claim = ui_wdecor_pos_event(awnd->wdecor, &pos);
255 /* Note: If event is claimed, awnd might not be valid anymore */
256 if (claim == ui_unclaimed)
257 ui_window_send_pos(awnd, &pos);
258
259 break;
260 }
261}
262
263/** Execute user interface.
264 *
265 * Return task exit code of zero and block unitl the application starts
266 * the termination process by calling ui_quit(@a ui).
267 *
268 * @param ui User interface
269 */
270void ui_run(ui_t *ui)
271{
272 cons_event_t event;
273 usec_t timeout;
274 errno_t rc;
275
276 /* Only return command prompt if we are running in a separate window */
277 if (ui->display != NULL)
278 task_retval(0);
279
280 while (!ui->quit) {
281 if (ui->console != NULL) {
282 timeout = 100000;
283 rc = console_get_event_timeout(ui->console,
284 &event, &timeout);
285
286 /* Do we actually have an event? */
287 if (rc == EOK) {
288 ui_cons_event_process(ui, &event);
289 } else if (rc != ETIMEOUT) {
290 /* Error, quit */
291 break;
292 }
293 } else {
294 fibril_usleep(100000);
295 }
296 }
297}
298
299/** Repaint UI (only used in fullscreen mode).
300 *
301 * This is used when an area is exposed in fullscreen mode.
302 *
303 * @param ui UI
304 * @return @c EOK on success or an error code
305 */
306errno_t ui_paint(ui_t *ui)
307{
308 errno_t rc;
309 gfx_context_t *gc;
310 ui_window_t *awnd;
311 gfx_color_t *color = NULL;
312
313 gc = console_gc_get_ctx(ui->cgc);
314
315 rc = gfx_color_new_ega(0x11, &color);
316 if (rc != EOK)
317 return rc;
318
319 rc = gfx_set_color(gc, color);
320 if (rc != EOK) {
321 gfx_color_delete(color);
322 return rc;
323 }
324
325 rc = gfx_fill_rect(gc, &ui->rect);
326 if (rc != EOK) {
327 gfx_color_delete(color);
328 return rc;
329 }
330
331 gfx_color_delete(color);
332
333 /* XXX Should repaint all windows */
334 awnd = ui_window_get_active(ui);
335 if (awnd == NULL)
336 return EOK;
337
338 rc = ui_wdecor_paint(awnd->wdecor);
339 if (rc != EOK)
340 return rc;
341
342 return ui_window_paint(awnd);
343}
344
345/** Terminate user interface.
346 *
347 * Calling this function causes the user interface to terminate
348 * (i.e. exit from ui_run()). This would be typically called from
349 * an event handler.
350 *
351 * @param ui User interface
352 */
353void ui_quit(ui_t *ui)
354{
355 ui->quit = true;
356}
357
358/** Determine if we are running in text mode.
359 *
360 * @param ui User interface
361 * @return @c true iff we are running in text mode
362 */
363bool ui_is_textmode(ui_t *ui)
364{
365 /*
366 * XXX Currently console is always text and display is always
367 * graphics, but this need not always be true.
368 */
369 return (ui->console != NULL);
370}
371
372/** Determine if we are emulating windows.
373 *
374 * @param ui User interface
375 * @return @c true iff we are running in text mode
376 */
377bool ui_is_fullscreen(ui_t *ui)
378{
379 return (ui->display == NULL);
380}
381
382/** @}
383 */
Note: See TracBrowser for help on using the repository browser.