source: mainline/uspace/lib/ui/src/ui.c@ 7896f23

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

Correctly position windows in fullscreen mode (only works with CSR)

This involves translating the rendering operations as well as
hardware cursor operations and position events. This currently
only works with client-side rendering (using memory GC for translation),
but not with server-side rendering (need a new special GC to translate
the operations).

  • Property mode set to 100644
File size: 8.4 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#ifdef CONFIG_UI_CS_RENDER
251 /*
252 * TODO Enable translation for server-side rendering
253 * once we can translate rendering operations in this
254 * case.
255 */
256 pos.hpos -= awnd->dpos.x;
257 pos.vpos -= awnd->dpos.y;
258#endif
259
260 claim = ui_wdecor_pos_event(awnd->wdecor, &pos);
261 /* Note: If event is claimed, awnd might not be valid anymore */
262 if (claim == ui_unclaimed)
263 ui_window_send_pos(awnd, &pos);
264
265 break;
266 }
267}
268
269/** Execute user interface.
270 *
271 * Return task exit code of zero and block unitl the application starts
272 * the termination process by calling ui_quit(@a ui).
273 *
274 * @param ui User interface
275 */
276void ui_run(ui_t *ui)
277{
278 cons_event_t event;
279 usec_t timeout;
280 errno_t rc;
281
282 /* Only return command prompt if we are running in a separate window */
283 if (ui->display != NULL)
284 task_retval(0);
285
286 while (!ui->quit) {
287 if (ui->console != NULL) {
288 timeout = 100000;
289 rc = console_get_event_timeout(ui->console,
290 &event, &timeout);
291
292 /* Do we actually have an event? */
293 if (rc == EOK) {
294 ui_cons_event_process(ui, &event);
295 } else if (rc != ETIMEOUT) {
296 /* Error, quit */
297 break;
298 }
299 } else {
300 fibril_usleep(100000);
301 }
302 }
303}
304
305/** Repaint UI (only used in fullscreen mode).
306 *
307 * This is used when an area is exposed in fullscreen mode.
308 *
309 * @param ui UI
310 * @return @c EOK on success or an error code
311 */
312errno_t ui_paint(ui_t *ui)
313{
314 errno_t rc;
315 gfx_context_t *gc;
316 ui_window_t *awnd;
317 gfx_color_t *color = NULL;
318
319 gc = console_gc_get_ctx(ui->cgc);
320
321 rc = gfx_color_new_ega(0x11, &color);
322 if (rc != EOK)
323 return rc;
324
325 rc = gfx_set_color(gc, color);
326 if (rc != EOK) {
327 gfx_color_delete(color);
328 return rc;
329 }
330
331 rc = gfx_fill_rect(gc, &ui->rect);
332 if (rc != EOK) {
333 gfx_color_delete(color);
334 return rc;
335 }
336
337 gfx_color_delete(color);
338
339 /* XXX Should repaint all windows */
340 awnd = ui_window_get_active(ui);
341 if (awnd == NULL)
342 return EOK;
343
344 rc = ui_wdecor_paint(awnd->wdecor);
345 if (rc != EOK)
346 return rc;
347
348 return ui_window_paint(awnd);
349}
350
351/** Terminate user interface.
352 *
353 * Calling this function causes the user interface to terminate
354 * (i.e. exit from ui_run()). This would be typically called from
355 * an event handler.
356 *
357 * @param ui User interface
358 */
359void ui_quit(ui_t *ui)
360{
361 ui->quit = true;
362}
363
364/** Determine if we are running in text mode.
365 *
366 * @param ui User interface
367 * @return @c true iff we are running in text mode
368 */
369bool ui_is_textmode(ui_t *ui)
370{
371 /*
372 * XXX Currently console is always text and display is always
373 * graphics, but this need not always be true.
374 */
375 return (ui->console != NULL);
376}
377
378/** Determine if we are emulating windows.
379 *
380 * @param ui User interface
381 * @return @c true iff we are running in text mode
382 */
383bool ui_is_fullscreen(ui_t *ui)
384{
385 return (ui->display == NULL);
386}
387
388/** @}
389 */
Note: See TracBrowser for help on using the repository browser.