source: mainline/uspace/lib/wndmgt/src/wndmgt.c@ 3a6d44b7

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

Activate window by pushing window button on taskbar

Note that with multiple seats, one would need to know which seat pushed
the button and set the appropriate focus.

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