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

Last change on this file was 3c54869, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Highlight active window in task bar

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