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

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

Pass ID of device that clicked the window button to activate window

To ensure the correct seat's focus is switched.

  • Property mode set to 100644
File size: 9.9 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 dev_id ID of input device belonging to seat whose
290 * focus is to be switched
291 * @param wnd_id Window ID
292 * @return EOK on success or an error code
293 */
294errno_t wndmgt_activate_window(wndmgt_t *wndmgt, sysarg_t dev_id,
295 sysarg_t wnd_id)
296{
297 async_exch_t *exch;
298 errno_t rc;
299
300 exch = async_exchange_begin(wndmgt->sess);
301 rc = async_req_2_0(exch, WNDMGT_ACTIVATE_WINDOW, dev_id,
302 wnd_id);
303
304 async_exchange_end(exch);
305 return rc;
306}
307
308/** Close window.
309 *
310 * @param wndmgt Window management
311 * @param wnd_id Window ID
312 * @return EOK on success or an error code
313 */
314errno_t wndmgt_close_window(wndmgt_t *wndmgt, sysarg_t wnd_id)
315{
316 async_exch_t *exch;
317 errno_t rc;
318
319 exch = async_exchange_begin(wndmgt->sess);
320 rc = async_req_1_0(exch, WNDMGT_CLOSE_WINDOW, wnd_id);
321
322 async_exchange_end(exch);
323 return rc;
324}
325
326/** Get window management event.
327 *
328 * @param wndmgt Window management
329 * @param event Place to store event
330 * @return EOK on success or an error code
331 */
332static errno_t wndmgt_get_event(wndmgt_t *wndmgt, wndmgt_ev_t *event)
333{
334 async_exch_t *exch;
335 ipc_call_t answer;
336 aid_t req;
337 errno_t rc;
338
339 exch = async_exchange_begin(wndmgt->sess);
340 req = async_send_0(exch, WNDMGT_GET_EVENT, &answer);
341 rc = async_data_read_start(exch, event, sizeof(*event));
342 async_exchange_end(exch);
343 if (rc != EOK) {
344 async_forget(req);
345 return rc;
346 }
347
348 async_wait_for(req, &rc);
349 if (rc != EOK)
350 return rc;
351
352 return EOK;
353}
354
355/** Window management events are pending.
356 *
357 * @param wndmgt Window management
358 * @param icall Call data
359 */
360static void wndmgt_ev_pending(wndmgt_t *wndmgt, ipc_call_t *icall)
361{
362 errno_t rc;
363 wndmgt_ev_t event;
364
365 while (true) {
366 fibril_mutex_lock(&wndmgt->lock);
367
368 if (wndmgt->sess != NULL)
369 rc = wndmgt_get_event(wndmgt, &event);
370 else
371 rc = ENOENT;
372
373 fibril_mutex_unlock(&wndmgt->lock);
374
375 if (rc != EOK)
376 break;
377
378 switch (event.etype) {
379 case wmev_window_added:
380 if (wndmgt->cb != NULL &&
381 wndmgt->cb->window_added != NULL) {
382 wndmgt->cb->window_added(wndmgt->cb_arg,
383 event.wnd_id);
384 }
385 break;
386 case wmev_window_removed:
387 if (wndmgt->cb != NULL &&
388 wndmgt->cb->window_removed != NULL) {
389 wndmgt->cb->window_removed(wndmgt->cb_arg,
390 event.wnd_id);
391 }
392 break;
393 case wmev_window_changed:
394 if (wndmgt->cb != NULL &&
395 wndmgt->cb->window_changed != NULL) {
396 wndmgt->cb->window_changed(wndmgt->cb_arg,
397 event.wnd_id);
398 }
399 break;
400 }
401 }
402
403 async_answer_0(icall, EOK);
404}
405
406/** Callback connection handler.
407 *
408 * @param icall Connect call data
409 * @param arg Argument, wndmgt_t *
410 */
411static void wndmgt_cb_conn(ipc_call_t *icall, void *arg)
412{
413 wndmgt_t *wndmgt = (wndmgt_t *) arg;
414
415 while (true) {
416 ipc_call_t call;
417 async_get_call(&call);
418
419 if (!ipc_get_imethod(&call)) {
420 /* Hangup */
421 async_answer_0(&call, EOK);
422 goto out;
423 }
424
425 switch (ipc_get_imethod(&call)) {
426 case WNDMGT_EV_PENDING:
427 wndmgt_ev_pending(wndmgt, &call);
428 break;
429 default:
430 async_answer_0(&call, ENOTSUP);
431 break;
432 }
433 }
434
435out:
436 fibril_mutex_lock(&wndmgt->lock);
437 wndmgt->cb_done = true;
438 fibril_mutex_unlock(&wndmgt->lock);
439 fibril_condvar_broadcast(&wndmgt->cv);
440}
441
442/** @}
443 */
Note: See TracBrowser for help on using the repository browser.