source: mainline/uspace/lib/display/src/display.c@ 6828a56

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

Add pos_id information to move request, too

This will become useful momentarily.

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