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

Last change on this file was 8279aab, checked in by Jiri Svoboda <jiri@…>, 6 months ago

ui_lock() needs to lock display

If ui_lock() is used to lock UI while destroying a window in a separate
fibril, we need to make sure we cannot get display events for
that destroyed window.

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