source: mainline/uspace/lib/display/src/display.c@ b169619

topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b169619 was 5d380b6, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Create menu windows in the correct seat

Add a mechanism to set the seat of a new display window, UI window,
UI popup - input device ID. This is set to the ID of the device which
activated the menu (mouse, keyboard). The display server determines
the correct seat from there.

This makes sure clicking outside closes the correct pop-up window.

  • Property mode set to 100644
File size: 19.7 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#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 <mem.h>
39#include <stdlib.h>
40#include <str.h>
41#include "../private/display.h"
42#include "../private/params.h"
43
44static errno_t display_callback_create(display_t *);
45static void display_cb_conn(ipc_call_t *, void *);
46static errno_t display_get_window(display_t *, sysarg_t, display_window_t **);
47
48/** Open display service.
49 *
50 * @param dsname Display service name or @c NULL to use default display
51 * @param rdisplay Place to store pointer to display session
52 * @return EOK on success or an error code
53 */
54errno_t display_open(const char *dsname, display_t **rdisplay)
55{
56 service_id_t display_svc;
57 display_t *display;
58 errno_t rc;
59
60 display = calloc(1, sizeof(display_t));
61 if (display == NULL)
62 return ENOMEM;
63
64 fibril_mutex_initialize(&display->lock);
65 fibril_condvar_initialize(&display->cv);
66 list_initialize(&display->windows);
67
68 if (dsname == NULL)
69 dsname = SERVICE_NAME_DISPLAY;
70
71 rc = loc_service_get_id(dsname, &display_svc, 0);
72 if (rc != EOK) {
73 free(display);
74 return ENOENT;
75 }
76
77 display->sess = loc_service_connect(display_svc, INTERFACE_DISPLAY,
78 0);
79 if (display->sess == NULL) {
80 free(display);
81 return ENOENT;
82 }
83
84 rc = display_callback_create(display);
85 if (rc != EOK) {
86 async_hangup(display->sess);
87 free(display);
88 return EIO;
89 }
90
91 *rdisplay = display;
92 return EOK;
93}
94
95/** Create callback connection from display service.
96 *
97 * @param display Display session
98 * @return EOK on success or an error code
99 */
100static errno_t display_callback_create(display_t *display)
101{
102 async_exch_t *exch = async_exchange_begin(display->sess);
103
104 aid_t req = async_send_0(exch, DISPLAY_CALLBACK_CREATE, NULL);
105
106 port_id_t port;
107 errno_t rc = async_create_callback_port(exch, INTERFACE_DISPLAY_CB, 0, 0,
108 display_cb_conn, display, &port);
109
110 async_exchange_end(exch);
111
112 if (rc != EOK)
113 return rc;
114
115 errno_t retval;
116 async_wait_for(req, &retval);
117
118 return retval;
119}
120
121/** Close display service.
122 *
123 * @param display Display session
124 */
125void display_close(display_t *display)
126{
127 fibril_mutex_lock(&display->lock);
128 async_hangup(display->sess);
129 display->sess = NULL;
130
131 /* Wait for callback handler to terminate */
132
133 while (!display->cb_done)
134 fibril_condvar_wait(&display->cv, &display->lock);
135 fibril_mutex_unlock(&display->lock);
136
137 free(display);
138}
139
140/** Initialize window parameters structure.
141 *
142 * Window parameters structure must always be initialized using this function
143 * first.
144 *
145 * @param params Window parameters structure
146 */
147void display_wnd_params_init(display_wnd_params_t *params)
148{
149 memset(params, 0, sizeof(*params));
150 params->caption = "";
151}
152
153/** Create a display window.
154 *
155 * @param display Display
156 * @param params Window parameters
157 * @param cb Callback functions
158 * @param cb_arg Argument to callback functions
159 * @param rwindow Place to store pointer to new window
160 * @return EOK on success or an error code
161 */
162errno_t display_window_create(display_t *display, display_wnd_params_t *params,
163 display_wnd_cb_t *cb, void *cb_arg, display_window_t **rwindow)
164{
165 display_window_t *window;
166 display_wnd_params_enc_t eparams;
167 async_exch_t *exch;
168 aid_t req;
169 ipc_call_t answer;
170 errno_t rc;
171
172 /* Encode the parameters for transport */
173 eparams.rect = params->rect;
174 eparams.caption_size = str_size(params->caption);
175 eparams.min_size = params->min_size;
176 eparams.pos = params->pos;
177 eparams.flags = params->flags;
178 eparams.idev_id = params->idev_id;
179
180 window = calloc(1, sizeof(display_window_t));
181 if (window == NULL)
182 return ENOMEM;
183
184 exch = async_exchange_begin(display->sess);
185 req = async_send_0(exch, DISPLAY_WINDOW_CREATE, &answer);
186
187 /* Write fixed fields */
188 rc = async_data_write_start(exch, &eparams,
189 sizeof (display_wnd_params_enc_t));
190 if (rc != EOK) {
191 async_exchange_end(exch);
192 async_forget(req);
193 free(window);
194 return rc;
195 }
196
197 /* Write caption */
198 rc = async_data_write_start(exch, params->caption,
199 eparams.caption_size);
200 async_exchange_end(exch);
201 if (rc != EOK) {
202 async_forget(req);
203 free(window);
204 return rc;
205 }
206
207 async_wait_for(req, &rc);
208 if (rc != EOK) {
209 free(window);
210 return rc;
211 }
212
213 window->display = display;
214 window->id = ipc_get_arg1(&answer);
215 window->cb = cb;
216 window->cb_arg = cb_arg;
217
218 list_append(&window->lwindows, &display->windows);
219 *rwindow = window;
220 return EOK;
221}
222
223/** Destroy display window.
224 *
225 * @param window Window or @c NULL
226 * @return EOK on success or an error code. In both cases @a window must
227 * not be accessed anymore
228 */
229errno_t display_window_destroy(display_window_t *window)
230{
231 async_exch_t *exch;
232 errno_t rc;
233
234 if (window == NULL)
235 return EOK;
236
237 exch = async_exchange_begin(window->display->sess);
238 rc = async_req_1_0(exch, DISPLAY_WINDOW_DESTROY, window->id);
239
240 async_exchange_end(exch);
241
242 list_remove(&window->lwindows);
243 free(window);
244 return rc;
245}
246
247/** Create graphics context for drawing into a window.
248 *
249 * @param window Window
250 * @param rgc Place to store pointer to new graphics context
251 * @return EOK on success or an error code
252 */
253errno_t display_window_get_gc(display_window_t *window, gfx_context_t **rgc)
254{
255 async_sess_t *sess;
256 async_exch_t *exch;
257 ipc_gc_t *gc;
258 errno_t rc;
259
260 exch = async_exchange_begin(window->display->sess);
261 sess = async_connect_me_to(exch, INTERFACE_GC, 0, window->id, &rc);
262 if (sess == NULL) {
263 async_exchange_end(exch);
264 return rc;
265 }
266
267 async_exchange_end(exch);
268
269 rc = ipc_gc_create(sess, &gc);
270 if (rc != EOK) {
271 async_hangup(sess);
272 return ENOMEM;
273 }
274
275 *rgc = ipc_gc_get_ctx(gc);
276 return EOK;
277}
278
279/** Request a window move.
280 *
281 * Request the display service to initiate a user window move operation
282 * (i.e. let the user move the window). Used when the client detects
283 * mouse press on the title bar or such.
284 *
285 * @param window Window
286 * @param pos Position in the window where the button was pressed
287 * @param pos_id Positioning device ID
288 * @return EOK on success or an error code
289 */
290errno_t display_window_move_req(display_window_t *window, gfx_coord2_t *pos,
291 sysarg_t pos_id)
292{
293 async_exch_t *exch;
294 aid_t req;
295 ipc_call_t answer;
296 errno_t rc;
297
298 exch = async_exchange_begin(window->display->sess);
299 req = async_send_2(exch, DISPLAY_WINDOW_MOVE_REQ, window->id,
300 pos_id, &answer);
301 rc = async_data_write_start(exch, (void *)pos, sizeof (gfx_coord2_t));
302 async_exchange_end(exch);
303 if (rc != EOK) {
304 async_forget(req);
305 return rc;
306 }
307
308 async_wait_for(req, &rc);
309 if (rc != EOK)
310 return rc;
311
312 return EOK;
313}
314
315/** Move display window.
316 *
317 * Set new display position of a window. Display position determines where
318 * the origin of the window coordinate system lies. Note that the top left
319 * corner of the window need not coincide with the window's 0,0 point.
320 *
321 * @param window Window
322 * @param dpos New display position
323 * @return EOK on success or an error code
324 */
325errno_t display_window_move(display_window_t *window, gfx_coord2_t *dpos)
326{
327 async_exch_t *exch;
328 aid_t req;
329 ipc_call_t answer;
330 errno_t rc;
331
332 exch = async_exchange_begin(window->display->sess);
333 req = async_send_1(exch, DISPLAY_WINDOW_MOVE, window->id, &answer);
334 rc = async_data_write_start(exch, dpos, sizeof (gfx_coord2_t));
335 async_exchange_end(exch);
336 if (rc != EOK) {
337 async_forget(req);
338 return rc;
339 }
340
341 async_wait_for(req, &rc);
342 if (rc != EOK)
343 return rc;
344
345 return EOK;
346}
347
348/** Get display window position.
349 *
350 * Get display window position on the display.
351 *
352 * @param window Window
353 * @param dpos Place to store position
354 * @return EOK on success or an error code
355 */
356errno_t display_window_get_pos(display_window_t *window, gfx_coord2_t *dpos)
357{
358 async_exch_t *exch;
359 aid_t req;
360 ipc_call_t answer;
361 errno_t rc;
362
363 exch = async_exchange_begin(window->display->sess);
364 req = async_send_1(exch, DISPLAY_WINDOW_GET_POS, window->id, &answer);
365 rc = async_data_read_start(exch, dpos, sizeof (gfx_coord2_t));
366 async_exchange_end(exch);
367 if (rc != EOK) {
368 async_forget(req);
369 return rc;
370 }
371
372 async_wait_for(req, &rc);
373 if (rc != EOK)
374 return rc;
375
376 return EOK;
377}
378
379/** Get display window maximized rectangle.
380 *
381 * Get the rectangle to which a window would be maximized.
382 *
383 * @param window Window
384 * @param rect Place to store maximized rectangle
385 * @return EOK on success or an error code
386 */
387errno_t display_window_get_max_rect(display_window_t *window, gfx_rect_t *rect)
388{
389 async_exch_t *exch;
390 aid_t req;
391 ipc_call_t answer;
392 errno_t rc;
393
394 exch = async_exchange_begin(window->display->sess);
395 req = async_send_1(exch, DISPLAY_WINDOW_GET_MAX_RECT, window->id,
396 &answer);
397 rc = async_data_read_start(exch, rect, sizeof (gfx_rect_t));
398 async_exchange_end(exch);
399 if (rc != EOK) {
400 async_forget(req);
401 return rc;
402 }
403
404 async_wait_for(req, &rc);
405 if (rc != EOK)
406 return rc;
407
408 return EOK;
409}
410
411/** Request a window resize.
412 *
413 * Request the display service to initiate a user window resize operation
414 * (i.e. let the user resize the window). Used when the client detects
415 * mouse press on the window frame or such.
416 *
417 * @param window Window
418 * @param rsztype Resize type (which part of window frame is being dragged)
419 * @param pos Position in the window where the button was pressed
420 * @param pos_id Positioning device ID
421 * @return EOK on success or an error code
422 */
423errno_t display_window_resize_req(display_window_t *window,
424 display_wnd_rsztype_t rsztype, gfx_coord2_t *pos, sysarg_t pos_id)
425{
426 async_exch_t *exch;
427 aid_t req;
428 ipc_call_t answer;
429 errno_t rc;
430
431 exch = async_exchange_begin(window->display->sess);
432 req = async_send_3(exch, DISPLAY_WINDOW_RESIZE_REQ, window->id,
433 (sysarg_t) rsztype, pos_id, &answer);
434 rc = async_data_write_start(exch, (void *)pos, sizeof (gfx_coord2_t));
435 async_exchange_end(exch);
436 if (rc != EOK) {
437 async_forget(req);
438 return rc;
439 }
440
441 async_wait_for(req, &rc);
442 if (rc != EOK)
443 return rc;
444
445 return EOK;
446}
447
448/** Resize display window.
449 *
450 * It seems resizing windows should be easy with bounding rectangles.
451 * You have an old bounding rectangle and a new bounding rectangle (@a nrect).
452 * Change .p0 and top-left corner moves. Change .p1 and bottom-right corner
453 * moves. Piece of cake!
454 *
455 * There's always a catch, though. By series of resizes and moves .p0 could
456 * drift outside of the range of @c gfx_coord_t. Now what? @a offs to the
457 * rescue! @a offs moves the @em boundaries of the window with respect
458 * to the display, while keeping the @em contents of the window in the
459 * same place (with respect to the display). In other words, @a offs shifts
460 * the window's internal coordinate system.
461 *
462 * A few examples follow:
463 *
464 * Enlarge window by moving bottom-right corner 1 right, 1 down:
465 *
466 * bound = (0, 0, 10, 10)
467 * offs = (0, 0)
468 * nrect = (0, 0, 11, 11)
469 *
470 * Enlarge window by moving top-left corner, 1 up, 1 left, allowing the
471 * window-relative coordinate of the top-left corner to drift (undesirable)
472 *
473 * bound = (0, 0, 10, 10)
474 * offs = (0, 0)
475 * nrect = (-1, -1, 10, 10) <- this is the new bounding rectangle
476 *
477 * Enlarge window by moving top-left corner 1 up, 1 left, keeping top-left
478 * corner locked to (0,0) window-relative coordinates (desirable):
479 *
480 * bound = (0, 0, 10, 10)
481 * off = (-1,-1) <- top-left corner goes 1 up, 1 left
482 * nrect = (0, 0, 11, 11) <- window still starts at 0,0 window-relative
483 *
484 * @param window Window
485 * @param nrect New bounding rectangle
486 * @param offs
487 * @return EOK on success or an error code
488 */
489errno_t display_window_resize(display_window_t *window, gfx_coord2_t *offs,
490 gfx_rect_t *nrect)
491{
492 async_exch_t *exch;
493 aid_t req;
494 ipc_call_t answer;
495 display_wnd_resize_t wresize;
496 errno_t rc;
497
498 wresize.offs = *offs;
499 wresize.nrect = *nrect;
500
501 exch = async_exchange_begin(window->display->sess);
502 req = async_send_1(exch, DISPLAY_WINDOW_RESIZE, window->id, &answer);
503 rc = async_data_write_start(exch, &wresize, sizeof (display_wnd_resize_t));
504 async_exchange_end(exch);
505 if (rc != EOK) {
506 async_forget(req);
507 return rc;
508 }
509
510 async_wait_for(req, &rc);
511 if (rc != EOK)
512 return rc;
513
514 return EOK;
515}
516
517/** Minimize window.
518 *
519 * @param window Window
520 * @return EOK on success or an error code
521 */
522errno_t display_window_minimize(display_window_t *window)
523{
524 async_exch_t *exch;
525 errno_t rc;
526
527 exch = async_exchange_begin(window->display->sess);
528 rc = async_req_1_0(exch, DISPLAY_WINDOW_MINIMIZE, window->id);
529 async_exchange_end(exch);
530
531 return rc;
532}
533
534/** Maximize window.
535 *
536 * @param window Window
537 * @return EOK on success or an error code
538 */
539errno_t display_window_maximize(display_window_t *window)
540{
541 async_exch_t *exch;
542 errno_t rc;
543
544 exch = async_exchange_begin(window->display->sess);
545 rc = async_req_1_0(exch, DISPLAY_WINDOW_MAXIMIZE, window->id);
546 async_exchange_end(exch);
547
548 return rc;
549}
550
551/** Unmaximize window.
552 *
553 * @param window Window
554 * @return EOK on success or an error code
555 */
556errno_t display_window_unmaximize(display_window_t *window)
557{
558 async_exch_t *exch;
559 errno_t rc;
560
561 exch = async_exchange_begin(window->display->sess);
562 rc = async_req_1_0(exch, DISPLAY_WINDOW_UNMAXIMIZE, window->id);
563 async_exchange_end(exch);
564
565 return rc;
566}
567
568/** Set window cursor.
569 *
570 * Set cursor that is displayed when pointer is over the window. The default
571 * is the arrow pointer.
572 *
573 * @param window Window
574 * @param cursor Cursor to display
575 * @return EOK on success or an error code
576 */
577errno_t display_window_set_cursor(display_window_t *window,
578 display_stock_cursor_t cursor)
579{
580 async_exch_t *exch;
581 errno_t rc;
582
583 exch = async_exchange_begin(window->display->sess);
584 rc = async_req_2_0(exch, DISPLAY_WINDOW_SET_CURSOR, window->id,
585 cursor);
586 async_exchange_end(exch);
587 return rc;
588}
589
590/** Set display window caption.
591 *
592 * @param window Window
593 * @param caption New caption
594 * @return EOK on success or an error code
595 */
596errno_t display_window_set_caption(display_window_t *window,
597 const char *caption)
598{
599 async_exch_t *exch;
600 aid_t req;
601 ipc_call_t answer;
602 size_t cap_size;
603 errno_t rc;
604
605 cap_size = str_size(caption);
606
607 exch = async_exchange_begin(window->display->sess);
608 req = async_send_1(exch, DISPLAY_WINDOW_SET_CAPTION, window->id,
609 &answer);
610
611 /* Write caption */
612 rc = async_data_write_start(exch, caption, cap_size);
613 async_exchange_end(exch);
614 if (rc != EOK) {
615 async_forget(req);
616 return rc;
617 }
618
619 async_wait_for(req, &rc);
620 return rc;
621}
622
623/** Get display event.
624 *
625 * @param display Display
626 * @param rwindow Place to store pointer to window that received event
627 * @param event Place to store event
628 * @return EOK on success or an error code
629 */
630static errno_t display_get_event(display_t *display, display_window_t **rwindow,
631 display_wnd_ev_t *event)
632{
633 async_exch_t *exch;
634 ipc_call_t answer;
635 aid_t req;
636 errno_t rc;
637 sysarg_t wnd_id;
638 display_window_t *window;
639
640 exch = async_exchange_begin(display->sess);
641 req = async_send_0(exch, DISPLAY_GET_EVENT, &answer);
642 rc = async_data_read_start(exch, event, sizeof(*event));
643 async_exchange_end(exch);
644 if (rc != EOK) {
645 async_forget(req);
646 return rc;
647 }
648
649 async_wait_for(req, &rc);
650 if (rc != EOK)
651 return rc;
652
653 wnd_id = ipc_get_arg1(&answer);
654 rc = display_get_window(display, wnd_id, &window);
655 if (rc != EOK)
656 return EIO;
657
658 *rwindow = window;
659 return EOK;
660}
661
662/** Get display information.
663 *
664 * @param display Display
665 * @param info Place to store display information
666 * @return EOK on success or an error code
667 */
668errno_t display_get_info(display_t *display, display_info_t *info)
669{
670 async_exch_t *exch;
671 ipc_call_t answer;
672 aid_t req;
673 errno_t rc;
674
675 exch = async_exchange_begin(display->sess);
676 req = async_send_0(exch, DISPLAY_GET_INFO, &answer);
677 rc = async_data_read_start(exch, info, sizeof(*info));
678 async_exchange_end(exch);
679 if (rc != EOK) {
680 async_forget(req);
681 return rc;
682 }
683
684 async_wait_for(req, &rc);
685 if (rc != EOK)
686 return rc;
687
688 return EOK;
689}
690
691/** Display events are pending.
692 *
693 * @param display Display
694 * @param icall Call data
695 */
696static void display_ev_pending(display_t *display, ipc_call_t *icall)
697{
698 errno_t rc;
699 display_window_t *window = NULL;
700 display_wnd_ev_t event;
701
702 while (true) {
703 fibril_mutex_lock(&display->lock);
704
705 if (display->sess != NULL)
706 rc = display_get_event(display, &window, &event);
707 else
708 rc = ENOENT;
709
710 fibril_mutex_unlock(&display->lock);
711
712 if (rc != EOK)
713 break;
714
715 switch (event.etype) {
716 case wev_close:
717 if (window->cb != NULL && window->cb->close_event != NULL) {
718 window->cb->close_event(window->cb_arg);
719 }
720 break;
721 case wev_focus:
722 if (window->cb != NULL && window->cb->focus_event != NULL) {
723 window->cb->focus_event(window->cb_arg,
724 event.ev.focus.nfocus);
725 }
726 break;
727 case wev_kbd:
728 if (window->cb != NULL && window->cb->kbd_event != NULL) {
729 window->cb->kbd_event(window->cb_arg,
730 &event.ev.kbd);
731 }
732 break;
733 case wev_pos:
734 if (window->cb != NULL && window->cb->pos_event != NULL) {
735 window->cb->pos_event(window->cb_arg,
736 &event.ev.pos);
737 }
738 break;
739 case wev_resize:
740 if (window->cb != NULL && window->cb->resize_event != NULL) {
741 window->cb->resize_event(window->cb_arg,
742 &event.ev.resize.rect);
743 }
744 break;
745 case wev_unfocus:
746 if (window->cb != NULL && window->cb->unfocus_event != NULL) {
747 window->cb->unfocus_event(window->cb_arg,
748 event.ev.unfocus.nfocus);
749 }
750 break;
751 }
752 }
753
754 async_answer_0(icall, EOK);
755}
756
757/** Callback connection handler.
758 *
759 * @param icall Connect call data
760 * @param arg Argument, display_t *
761 */
762static void display_cb_conn(ipc_call_t *icall, void *arg)
763{
764 display_t *display = (display_t *) arg;
765
766 while (true) {
767 ipc_call_t call;
768 async_get_call(&call);
769
770 if (!ipc_get_imethod(&call)) {
771 /* Hangup */
772 async_answer_0(&call, EOK);
773 goto out;
774 }
775
776 switch (ipc_get_imethod(&call)) {
777 case DISPLAY_EV_PENDING:
778 display_ev_pending(display, &call);
779 break;
780 default:
781 async_answer_0(&call, ENOTSUP);
782 break;
783 }
784 }
785
786out:
787 fibril_mutex_lock(&display->lock);
788 display->cb_done = true;
789 fibril_mutex_unlock(&display->lock);
790 fibril_condvar_broadcast(&display->cv);
791}
792
793/** Find window by ID.
794 *
795 * @param display Display
796 * @param wnd_id Window ID
797 * @param rwindow Place to store pointer to window
798 * @return EOK on success, ENOENT if not found
799 */
800static errno_t display_get_window(display_t *display, sysarg_t wnd_id,
801 display_window_t **rwindow)
802{
803 link_t *link;
804 display_window_t *window;
805
806 link = list_first(&display->windows);
807 while (link != NULL) {
808 window = list_get_instance(link, display_window_t, lwindows);
809 if (window->id == wnd_id) {
810 *rwindow = window;
811 return EOK;
812 }
813
814 link = list_next(link, &display->windows);
815 }
816
817 return ENOENT;
818}
819
820/** @}
821 */
Note: See TracBrowser for help on using the repository browser.