source: mainline/uspace/lib/display/src/display.c@ b3c185b6

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

Window event delivery mechanism

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2019 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#include <async.h>
30#include <display.h>
31#include <errno.h>
32#include <fibril_synch.h>
33#include <ipc/display.h>
34#include <ipc/services.h>
35#include <ipcgfx/client.h>
36#include <loc.h>
37#include <stdlib.h>
38
39static errno_t display_callback_create(display_t *);
40static void display_cb_conn(ipc_call_t *, void *);
41static errno_t display_get_window(display_t *, sysarg_t, display_window_t **);
42
43/** Open display service.
44 *
45 * @param dsname Display service name or @c NULL to use default display
46 * @param rdisplay Place to store pointer to display session
47 * @return EOK on success or an error code
48 */
49errno_t display_open(const char *dsname, display_t **rdisplay)
50{
51 service_id_t display_svc;
52 display_t *display;
53 errno_t rc;
54
55 display = calloc(1, sizeof(display_t));
56 if (display == NULL)
57 return ENOMEM;
58
59 list_initialize(&display->windows);
60
61 if (dsname == NULL)
62 dsname = SERVICE_NAME_DISPLAY;
63
64 rc = loc_service_get_id(dsname, &display_svc, IPC_FLAG_BLOCKING);
65 if (rc != EOK) {
66 free(display);
67 return ENOENT;
68 }
69
70 display->sess = loc_service_connect(display_svc, INTERFACE_DISPLAY,
71 IPC_FLAG_BLOCKING);
72 if (display->sess == NULL) {
73 free(display);
74 return ENOENT;
75 }
76
77 rc = display_callback_create(display);
78 if (rc != EOK) {
79 async_hangup(display->sess);
80 free(display);
81 return EIO;
82 }
83
84 *rdisplay = display;
85 return EOK;
86}
87
88/** Create callback connection from display service.
89 *
90 * @param display Display session
91 * @return EOK on success or an error code
92 */
93static errno_t display_callback_create(display_t *display)
94{
95 async_exch_t *exch = async_exchange_begin(display->sess);
96
97 aid_t req = async_send_0(exch, DISPLAY_CALLBACK_CREATE, NULL);
98
99 port_id_t port;
100 errno_t rc = async_create_callback_port(exch, INTERFACE_DISPLAY_CB, 0, 0,
101 display_cb_conn, display, &port);
102
103 async_exchange_end(exch);
104
105 if (rc != EOK)
106 return rc;
107
108 errno_t retval;
109 async_wait_for(req, &retval);
110
111 return retval;
112}
113
114/** Close display service.
115 *
116 * @param display Display session
117 */
118void display_close(display_t *display)
119{
120 async_hangup(display->sess);
121
122 /* Wait for callback handler to terminate */
123
124 fibril_mutex_lock(&display->lock);
125 while (!display->cb_done)
126 fibril_condvar_wait(&display->cv, &display->lock);
127 fibril_mutex_unlock(&display->lock);
128
129 free(display);
130}
131
132/** Create a display window.
133 *
134 * @param display Display
135 * @param cb Callback functions
136 * @param cb_arg Argument to callback functions
137 * @param rwindow Place to store pointer to new window
138 * @return EOK on success or an error code
139 */
140errno_t display_window_create(display_t *display, display_wnd_cb_t *cb,
141 void *cb_arg, display_window_t **rwindow)
142{
143 display_window_t *window;
144 async_exch_t *exch;
145 sysarg_t wnd_id;
146 errno_t rc;
147
148 window = calloc(1, sizeof(display_window_t));
149 if (window == NULL)
150 return ENOMEM;
151
152 exch = async_exchange_begin(display->sess);
153 rc = async_req_0_1(exch, DISPLAY_WINDOW_CREATE, &wnd_id);
154
155 async_exchange_end(exch);
156
157 if (rc != EOK) {
158 free(window);
159 return rc;
160 }
161
162 window->display = display;
163 window->id = wnd_id;
164 window->cb = cb;
165 window->cb_arg = cb_arg;
166
167 list_append(&window->lwindows, &display->windows);
168 *rwindow = window;
169 return EOK;
170}
171
172/** Destroy display window.
173 *
174 * @param window Window
175 * @return EOK on success or an error code. In both cases @a window must
176 * not be accessed anymore
177 */
178errno_t display_window_destroy(display_window_t *window)
179{
180 async_exch_t *exch;
181 errno_t rc;
182
183 exch = async_exchange_begin(window->display->sess);
184 rc = async_req_1_0(exch, DISPLAY_WINDOW_DESTROY, window->id);
185
186 async_exchange_end(exch);
187
188 free(window);
189 return rc;
190}
191
192/** Create graphics context for drawing into a window.
193 *
194 * @param window Window
195 * @param rgc Place to store pointer to new graphics context
196 */
197errno_t display_window_get_gc(display_window_t *window, gfx_context_t **rgc)
198{
199 async_sess_t *sess;
200 async_exch_t *exch;
201 ipc_gc_t *gc;
202 errno_t rc;
203
204 exch = async_exchange_begin(window->display->sess);
205 sess = async_connect_me_to(exch, INTERFACE_GC, 0, window->id);
206 if (sess == NULL) {
207 async_exchange_end(exch);
208 return EIO;
209 }
210
211 async_exchange_end(exch);
212
213 rc = ipc_gc_create(sess, &gc);
214 if (rc != EOK) {
215 async_hangup(sess);
216 return ENOMEM;
217 }
218
219 *rgc = ipc_gc_get_ctx(gc);
220 return EOK;
221}
222
223/** Get display event.
224 *
225 * @param display Display
226 * @param rwindow Place to store pointe to window that received event
227 * @param event Place to store event
228 * @return EOK on success or an error code
229 */
230static errno_t display_get_event(display_t *display, display_window_t **rwindow,
231 display_wnd_ev_t *event)
232{
233 async_exch_t *exch;
234 ipc_call_t answer;
235 aid_t req;
236 errno_t rc;
237 sysarg_t wnd_id;
238 display_window_t *window;
239
240 exch = async_exchange_begin(display->sess);
241 req = async_send_0(exch, DISPLAY_GET_EVENT, &answer);
242 rc = async_data_read_start(exch, event, sizeof(*event));
243 if (rc != EOK) {
244 async_forget(req);
245 return rc;
246 }
247
248 async_exchange_end(exch);
249
250 async_wait_for(req, &rc);
251 if (rc != EOK)
252 return rc;
253
254 wnd_id = ipc_get_arg1(&answer);
255 rc = display_get_window(display, wnd_id, &window);
256 if (rc != EOK)
257 return EIO;
258
259 *rwindow = window;
260 return EOK;
261}
262
263/** Display events are pending.
264 *
265 * @param display Display
266 * @param icall Call data
267 */
268static void display_ev_pending(display_t *display, ipc_call_t *icall)
269{
270 errno_t rc;
271 display_window_t *window = NULL;
272 display_wnd_ev_t event;
273
274 while (true) {
275 rc = display_get_event(display, &window, &event);
276 if (rc != EOK)
277 break;
278
279 if (window->cb->kbd_event != NULL)
280 window->cb->kbd_event(window->cb_arg, &event.kbd_event);
281 }
282
283 async_answer_0(icall, EOK);
284}
285
286/** Callback connection handler.
287 *
288 * @param icall Connect call data
289 * @param arg Argument, display_t *
290 */
291static void display_cb_conn(ipc_call_t *icall, void *arg)
292{
293 display_t *display = (display_t *) arg;
294
295 while (true) {
296 ipc_call_t call;
297 async_get_call(&call);
298
299 if (!ipc_get_imethod(&call)) {
300 /* Hangup */
301 async_answer_0(&call, EOK);
302 goto out;
303 }
304
305 switch (ipc_get_imethod(&call)) {
306 case DISPLAY_EV_PENDING:
307 display_ev_pending(display, &call);
308 break;
309 default:
310 async_answer_0(&call, ENOTSUP);
311 break;
312 }
313 }
314
315out:
316 fibril_mutex_lock(&display->lock);
317 display->cb_done = true;
318 fibril_mutex_unlock(&display->lock);
319 fibril_condvar_broadcast(&display->cv);
320}
321
322/** Find window by ID.
323 *
324 * @param display Display
325 * @param wnd_id Window ID
326 * @param rwindow Place to store pointer to window
327 * @return EOK on success, ENOENT if not found
328 */
329static errno_t display_get_window(display_t *display, sysarg_t wnd_id,
330 display_window_t **rwindow)
331{
332 link_t *link;
333 display_window_t *window;
334
335 link = list_first(&display->windows);
336 while (link != NULL) {
337 window = list_get_instance(link, display_window_t, lwindows);
338 if (window->id == wnd_id) {
339 *rwindow = window;
340 return EOK;
341 }
342
343 link = list_next(link, &display->windows);
344 }
345
346 return ENOENT;
347}
348
349/** @}
350 */
Note: See TracBrowser for help on using the repository browser.