source: mainline/uspace/lib/wndmgt/src/wndmgt.c@ f1f433d

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

Update window button when window caption changes

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/*
2 * Copyright (c) 2022 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 libwndmgt
30 * @{
31 */
32/**
33 * @file
34 * @brief Window management protocol client
35 */
36
37#include <async.h>
38#include <wndmgt.h>
39#include <errno.h>
40#include <fibril_synch.h>
41#include <ipc/wndmgt.h>
42#include <ipc/services.h>
43#include <loc.h>
44#include <mem.h>
45#include <stdlib.h>
46#include "../private/wndmgt.h"
47
48static errno_t wndmgt_callback_create(wndmgt_t *);
49static void wndmgt_cb_conn(ipc_call_t *, void *);
50
51/** Open window management service.
52 *
53 * @param wmname Window management service name or @c NULL to use default
54 * @param cb Window management callbacks
55 * @param cb_arg Callback argument
56 * @param rwndmgt Place to store pointer to window management session
57 * @return EOK on success or an error code
58 */
59errno_t wndmgt_open(const char *wmname, wndmgt_cb_t *cb, void *cb_arg,
60 wndmgt_t **rwndmgt)
61{
62 service_id_t wndmgt_svc;
63 wndmgt_t *wndmgt;
64 errno_t rc;
65
66 wndmgt = calloc(1, sizeof(wndmgt_t));
67 if (wndmgt == NULL)
68 return ENOMEM;
69
70 wndmgt->cb = cb;
71 wndmgt->cb_arg = cb_arg;
72
73 fibril_mutex_initialize(&wndmgt->lock);
74 fibril_condvar_initialize(&wndmgt->cv);
75
76 if (wmname == NULL)
77 wmname = SERVICE_NAME_WNDMGT;
78
79 rc = loc_service_get_id(wmname, &wndmgt_svc, 0);
80 if (rc != EOK) {
81 free(wndmgt);
82 return ENOENT;
83 }
84
85 wndmgt->sess = loc_service_connect(wndmgt_svc, INTERFACE_WNDMGT,
86 0);
87 if (wndmgt->sess == NULL) {
88 free(wndmgt);
89 return ENOENT;
90 }
91
92 rc = wndmgt_callback_create(wndmgt);
93 if (rc != EOK) {
94 async_hangup(wndmgt->sess);
95 free(wndmgt);
96 return EIO;
97 }
98
99 *rwndmgt = wndmgt;
100 return EOK;
101}
102
103/** Create callback connection from window management service.
104 *
105 * @param wndmgt Window management
106 * @return EOK on success or an error code
107 */
108static errno_t wndmgt_callback_create(wndmgt_t *wndmgt)
109{
110 async_exch_t *exch = async_exchange_begin(wndmgt->sess);
111
112 aid_t req = async_send_0(exch, WNDMGT_CALLBACK_CREATE, NULL);
113
114 port_id_t port;
115 errno_t rc = async_create_callback_port(exch, INTERFACE_WNDMGT_CB, 0, 0,
116 wndmgt_cb_conn, wndmgt, &port);
117
118 async_exchange_end(exch);
119
120 if (rc != EOK)
121 return rc;
122
123 errno_t retval;
124 async_wait_for(req, &retval);
125
126 return retval;
127}
128
129/** Close window management service.
130 *
131 * @param wndmgt Window management
132 */
133void wndmgt_close(wndmgt_t *wndmgt)
134{
135 fibril_mutex_lock(&wndmgt->lock);
136 async_hangup(wndmgt->sess);
137 wndmgt->sess = NULL;
138
139 /* Wait for callback handler to terminate */
140
141 while (!wndmgt->cb_done)
142 fibril_condvar_wait(&wndmgt->cv, &wndmgt->lock);
143 fibril_mutex_unlock(&wndmgt->lock);
144
145 free(wndmgt);
146}
147
148/** Get window list.
149 *
150 * @param wndmgt Window management
151 * @param rlist Place to store pointer to new window list structure
152 * @return EOK on success or an error code
153 */
154errno_t wndmgt_get_window_list(wndmgt_t *wndmgt, wndmgt_window_list_t **rlist)
155{
156 async_exch_t *exch;
157 aid_t req;
158 ipc_call_t answer;
159 wndmgt_window_list_t *list;
160 sysarg_t nwindows;
161 sysarg_t *windows;
162 errno_t rc;
163
164 exch = async_exchange_begin(wndmgt->sess);
165 req = async_send_0(exch, WNDMGT_GET_WINDOW_LIST, &answer);
166
167 /* Receive window list length */
168 rc = async_data_read_start(exch, &nwindows, sizeof (nwindows));
169 if (rc != EOK) {
170 async_exchange_end(exch);
171 async_wait_for(req, &rc);
172 return rc;
173 }
174
175 windows = calloc(nwindows, sizeof(sysarg_t));
176 if (windows == NULL) {
177 async_exchange_end(exch);
178 async_forget(req);
179 return ENOMEM;
180 }
181
182 /* Receive window list */
183 rc = async_data_read_start(exch, windows, nwindows * sizeof (sysarg_t));
184 async_exchange_end(exch);
185
186 if (rc != EOK) {
187 async_forget(req);
188 return rc;
189 }
190
191 async_wait_for(req, &rc);
192 if (rc != EOK)
193 return rc;
194
195 list = calloc(1, sizeof(wndmgt_window_list_t));
196 if (list == NULL)
197 return ENOMEM;
198
199 list->nwindows = nwindows;
200 list->windows = windows;
201 *rlist = list;
202 return EOK;
203}
204
205/** Free window list.
206 *
207 * @param list Window management list
208 */
209void wndmgt_free_window_list(wndmgt_window_list_t *list)
210{
211 free(list->windows);
212 free(list);
213}
214
215/** Get window information.
216 *
217 * @param wndmgt Window management
218 * @param wnd_id Window ID
219 * @param rinfo Place to store pointer to new window information structure
220 * @return EOK on success or an error code
221 */
222errno_t wndmgt_get_window_info(wndmgt_t *wndmgt, sysarg_t wnd_id,
223 wndmgt_window_info_t **rinfo)
224{
225 async_exch_t *exch;
226 aid_t req;
227 ipc_call_t answer;
228 wndmgt_window_info_t *info;
229 sysarg_t capsize;
230 char *caption;
231 errno_t rc;
232
233 exch = async_exchange_begin(wndmgt->sess);
234 req = async_send_1(exch, WNDMGT_GET_WINDOW_INFO, wnd_id, &answer);
235
236 /* Receive caption size */
237 rc = async_data_read_start(exch, &capsize, sizeof (capsize));
238 if (rc != EOK) {
239 async_exchange_end(exch);
240 async_wait_for(req, &rc);
241 return rc;
242 }
243
244 caption = calloc(capsize + 1, sizeof(char));
245 if (caption == NULL) {
246 async_exchange_end(exch);
247 async_forget(req);
248 return ENOMEM;
249 }
250
251 /* Receive caption */
252 rc = async_data_read_start(exch, caption, capsize);
253 async_exchange_end(exch);
254
255 if (rc != EOK) {
256 async_forget(req);
257 return rc;
258 }
259
260 async_wait_for(req, &rc);
261 if (rc != EOK)
262 return rc;
263
264 /* Null-terminate the string */
265 caption[capsize] = '\0';
266
267 info = calloc(1, sizeof(wndmgt_window_info_t));
268 if (info == NULL)
269 return ENOMEM;
270
271 info->caption = caption;
272 *rinfo = info;
273 return EOK;
274}
275
276/** Free window information.
277 *
278 * @param info Window management information
279 */
280void wndmgt_free_window_info(wndmgt_window_info_t *info)
281{
282 free(info->caption);
283 free(info);
284}
285
286/** Activate window.
287 *
288 * @param wndmgt Window management session
289 * @param wnd_id Window ID
290 * @return EOK on success or an error code
291 */
292errno_t wndmgt_activate_window(wndmgt_t *wndmgt, sysarg_t wnd_id)
293{
294 async_exch_t *exch;
295 errno_t rc;
296
297 exch = async_exchange_begin(wndmgt->sess);
298 rc = async_req_1_0(exch, WNDMGT_ACTIVATE_WINDOW, wnd_id);
299
300 async_exchange_end(exch);
301 return rc;
302}
303
304/** Close window.
305 *
306 * @param wndmgt Window management
307 * @param wnd_id Window ID
308 * @return EOK on success or an error code
309 */
310errno_t wndmgt_close_window(wndmgt_t *wndmgt, sysarg_t wnd_id)
311{
312 async_exch_t *exch;
313 errno_t rc;
314
315 exch = async_exchange_begin(wndmgt->sess);
316 rc = async_req_1_0(exch, WNDMGT_CLOSE_WINDOW, wnd_id);
317
318 async_exchange_end(exch);
319 return rc;
320}
321
322/** Get window management event.
323 *
324 * @param wndmgt Window management
325 * @param event Place to store event
326 * @return EOK on success or an error code
327 */
328static errno_t wndmgt_get_event(wndmgt_t *wndmgt, wndmgt_ev_t *event)
329{
330 async_exch_t *exch;
331 ipc_call_t answer;
332 aid_t req;
333 errno_t rc;
334
335 exch = async_exchange_begin(wndmgt->sess);
336 req = async_send_0(exch, WNDMGT_GET_EVENT, &answer);
337 rc = async_data_read_start(exch, event, sizeof(*event));
338 async_exchange_end(exch);
339 if (rc != EOK) {
340 async_forget(req);
341 return rc;
342 }
343
344 async_wait_for(req, &rc);
345 if (rc != EOK)
346 return rc;
347
348 return EOK;
349}
350
351/** Window management events are pending.
352 *
353 * @param wndmgt Window management
354 * @param icall Call data
355 */
356static void wndmgt_ev_pending(wndmgt_t *wndmgt, ipc_call_t *icall)
357{
358 errno_t rc;
359 wndmgt_ev_t event;
360
361 while (true) {
362 fibril_mutex_lock(&wndmgt->lock);
363
364 if (wndmgt->sess != NULL)
365 rc = wndmgt_get_event(wndmgt, &event);
366 else
367 rc = ENOENT;
368
369 fibril_mutex_unlock(&wndmgt->lock);
370
371 if (rc != EOK)
372 break;
373
374 switch (event.etype) {
375 case wmev_window_added:
376 if (wndmgt->cb != NULL &&
377 wndmgt->cb->window_added != NULL) {
378 wndmgt->cb->window_added(wndmgt->cb_arg,
379 event.wnd_id);
380 }
381 break;
382 case wmev_window_removed:
383 if (wndmgt->cb != NULL &&
384 wndmgt->cb->window_removed != NULL) {
385 wndmgt->cb->window_removed(wndmgt->cb_arg,
386 event.wnd_id);
387 }
388 break;
389 case wmev_window_changed:
390 if (wndmgt->cb != NULL &&
391 wndmgt->cb->window_changed != NULL) {
392 wndmgt->cb->window_changed(wndmgt->cb_arg,
393 event.wnd_id);
394 }
395 break;
396 }
397 }
398
399 async_answer_0(icall, EOK);
400}
401
402/** Callback connection handler.
403 *
404 * @param icall Connect call data
405 * @param arg Argument, wndmgt_t *
406 */
407static void wndmgt_cb_conn(ipc_call_t *icall, void *arg)
408{
409 wndmgt_t *wndmgt = (wndmgt_t *) arg;
410
411 while (true) {
412 ipc_call_t call;
413 async_get_call(&call);
414
415 if (!ipc_get_imethod(&call)) {
416 /* Hangup */
417 async_answer_0(&call, EOK);
418 goto out;
419 }
420
421 switch (ipc_get_imethod(&call)) {
422 case WNDMGT_EV_PENDING:
423 wndmgt_ev_pending(wndmgt, &call);
424 break;
425 default:
426 async_answer_0(&call, ENOTSUP);
427 break;
428 }
429 }
430
431out:
432 fibril_mutex_lock(&wndmgt->lock);
433 wndmgt->cb_done = true;
434 fibril_mutex_unlock(&wndmgt->lock);
435 fibril_condvar_broadcast(&wndmgt->cv);
436}
437
438/** @}
439 */
Note: See TracBrowser for help on using the repository browser.