source: mainline/uspace/lib/display/src/display.c@ 6427f083

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

Do not forget to end exchange in failure case of display_get_event()

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