source: mainline/uspace/srv/hid/display/display.c@ 0680854

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

Allow getting display dimensions

Can be used to position special windows such as panels, or to help
emulate libgui's window placement policy. To support multi-monitor
setups we would rather need to be able to query individual monitors.
But let's keep things simple for now.

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/*
2 * Copyright (c) 2019 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 display
30 * @{
31 */
32/**
33 * @file Display server display
34 */
35
36#include <errno.h>
37#include <gfx/context.h>
38#include <gfx/render.h>
39#include <io/log.h>
40#include <stdlib.h>
41#include "client.h"
42#include "seat.h"
43#include "window.h"
44#include "display.h"
45
46/** Create display.
47 *
48 * @param gc Graphics context for displaying output
49 * @param rdisp Place to store pointer to new display.
50 * @return EOK on success, ENOMEM if out of memory
51 */
52errno_t ds_display_create(gfx_context_t *gc, ds_display_t **rdisp)
53{
54 ds_display_t *disp;
55 errno_t rc;
56
57 disp = calloc(1, sizeof(ds_display_t));
58 if (disp == NULL)
59 return ENOMEM;
60
61 rc = gfx_color_new_rgb_i16(0x8000, 0xc800, 0xffff, &disp->bg_color);
62 if (rc != EOK) {
63 free(disp);
64 return ENOMEM;
65 }
66
67 list_initialize(&disp->clients);
68 disp->next_wnd_id = 1;
69 list_initialize(&disp->ddevs);
70 list_initialize(&disp->seats);
71 list_initialize(&disp->windows);
72 *rdisp = disp;
73 return EOK;
74}
75
76/** Destroy display.
77 *
78 * @param disp Display
79 */
80void ds_display_destroy(ds_display_t *disp)
81{
82 assert(list_empty(&disp->clients));
83 assert(list_empty(&disp->seats));
84 gfx_color_delete(disp->bg_color);
85 free(disp);
86}
87
88/** Get display information.
89 *
90 * @param disp Display
91 */
92void ds_display_get_info(ds_display_t *disp, display_info_t *info)
93{
94 info->rect = disp->rect;
95}
96
97/** Add client to display.
98 *
99 * @param disp Display
100 * @param client Client
101 */
102void ds_display_add_client(ds_display_t *disp, ds_client_t *client)
103{
104 assert(client->display == NULL);
105 assert(!link_used(&client->lclients));
106
107 client->display = disp;
108 list_append(&client->lclients, &disp->clients);
109}
110
111/** Remove client from display.
112 *
113 * @param client Client
114 */
115void ds_display_remove_client(ds_client_t *client)
116{
117 list_remove(&client->lclients);
118 client->display = NULL;
119}
120
121/** Get first client in display.
122 *
123 * @param disp Display
124 * @return First client or @c NULL if there is none
125 */
126ds_client_t *ds_display_first_client(ds_display_t *disp)
127{
128 link_t *link = list_first(&disp->clients);
129
130 if (link == NULL)
131 return NULL;
132
133 return list_get_instance(link, ds_client_t, lclients);
134}
135
136/** Get next client in display.
137 *
138 * @param client Current client
139 * @return Next client or @c NULL if there is none
140 */
141ds_client_t *ds_display_next_client(ds_client_t *client)
142{
143 link_t *link = list_next(&client->lclients, &client->display->clients);
144
145 if (link == NULL)
146 return NULL;
147
148 return list_get_instance(link, ds_client_t, lclients);
149}
150
151/** Find window in all clients by ID.
152 *
153 * XXX This is just a hack needed to match GC connection to a window,
154 * as we don't have a good safe way to pass the GC endpoint to our client
155 * on demand.
156 *
157 * @param display Display
158 * @param id Window ID
159 */
160#include <stdio.h>
161ds_window_t *ds_display_find_window(ds_display_t *display, ds_wnd_id_t id)
162{
163 ds_client_t *client;
164 ds_window_t *wnd;
165
166 printf("ds_display_find_window: id=0x%x\n", (unsigned) id);
167
168 client = ds_display_first_client(display);
169 while (client != NULL) {
170 printf("ds_display_find_window: client=%p\n", client);
171 wnd = ds_client_find_window(client, id);
172 if (wnd != NULL) {
173 printf("ds_display_find_window: found wnd=%p id=0x%x\n",
174 wnd, (unsigned) wnd->id);
175 return wnd;
176 }
177 client = ds_display_next_client(client);
178 }
179
180 printf("ds_display_find_window: not found\n");
181 return NULL;
182}
183
184/** Find window by display position.
185 *
186 * @param display Display
187 * @param pos Display position
188 */
189ds_window_t *ds_display_window_by_pos(ds_display_t *display, gfx_coord2_t *pos)
190{
191 ds_window_t *wnd;
192 gfx_rect_t drect;
193
194 wnd = ds_display_first_window(display);
195 while (wnd != NULL) {
196 /* Window bounding rectangle on display */
197 gfx_rect_translate(&wnd->dpos, &wnd->rect, &drect);
198
199 if (gfx_pix_inside_rect(pos, &drect))
200 return wnd;
201
202 wnd = ds_display_next_window(wnd);
203 }
204
205 return NULL;
206}
207
208/** Add window to display.
209 *
210 * @param display Display
211 * @param wnd Window
212 */
213void ds_display_add_window(ds_display_t *display, ds_window_t *wnd)
214{
215 assert(wnd->display == NULL);
216 assert(!link_used(&wnd->ldwindows));
217
218 wnd->display = display;
219 list_prepend(&wnd->ldwindows, &display->windows);
220}
221
222/** Remove window from display.
223 *
224 * @param wnd Window
225 */
226void ds_display_remove_window(ds_window_t *wnd)
227{
228 list_remove(&wnd->ldwindows);
229 wnd->display = NULL;
230}
231
232/** Get first window in display.
233 *
234 * @param display Display
235 * @return First window or @c NULL if there is none
236 */
237ds_window_t *ds_display_first_window(ds_display_t *display)
238{
239 link_t *link = list_first(&display->windows);
240
241 if (link == NULL)
242 return NULL;
243
244 return list_get_instance(link, ds_window_t, ldwindows);
245}
246
247/** Get last window in display.
248 *
249 * @param display Display
250 * @return Last window or @c NULL if there is none
251 */
252ds_window_t *ds_display_last_window(ds_display_t *display)
253{
254 link_t *link = list_last(&display->windows);
255
256 if (link == NULL)
257 return NULL;
258
259 return list_get_instance(link, ds_window_t, ldwindows);
260}
261
262/** Get next window in client.
263 *
264 * @param wnd Current window
265 * @return Next window or @c NULL if there is none
266 */
267ds_window_t *ds_display_next_window(ds_window_t *wnd)
268{
269 link_t *link = list_next(&wnd->ldwindows, &wnd->display->windows);
270
271 if (link == NULL)
272 return NULL;
273
274 return list_get_instance(link, ds_window_t, ldwindows);
275}
276
277/** Get previous window in client.
278 *
279 * @param wnd Current window
280 * @return Previous window or @c NULL if there is none
281 */
282ds_window_t *ds_display_prev_window(ds_window_t *wnd)
283{
284 link_t *link = list_prev(&wnd->ldwindows, &wnd->display->windows);
285
286 if (link == NULL)
287 return NULL;
288
289 return list_get_instance(link, ds_window_t, ldwindows);
290}
291
292/** Post keyboard event to a display.
293 *
294 * The event is routed to the correct window by first determining the
295 * seat the keyboard device belongs to and then the event is sent to the
296 * window focused by that seat.
297 *
298 * @param display Display
299 * @param event Event
300 */
301errno_t ds_display_post_kbd_event(ds_display_t *display, kbd_event_t *event)
302{
303 ds_seat_t *seat;
304
305 // TODO Determine which seat the event belongs to
306 seat = ds_display_first_seat(display);
307 if (seat == NULL)
308 return EOK;
309
310 return ds_seat_post_kbd_event(seat, event);
311}
312
313/** Post position event to a display.
314 *
315 * @param display Display
316 * @param event Event
317 */
318errno_t ds_display_post_ptd_event(ds_display_t *display, ptd_event_t *event)
319{
320 ds_seat_t *seat;
321
322 // TODO Determine which seat the event belongs to
323 seat = ds_display_first_seat(display);
324 if (seat == NULL)
325 return EOK;
326
327 return ds_seat_post_ptd_event(seat, event);
328}
329
330/** Add seat to display.
331 *
332 * @param disp Display
333 * @param seat Seat
334 */
335void ds_display_add_seat(ds_display_t *disp, ds_seat_t *seat)
336{
337 assert(seat->display == NULL);
338 assert(!link_used(&seat->lseats));
339
340 seat->display = disp;
341 list_append(&seat->lseats, &disp->seats);
342}
343
344/** Remove seat from display.
345 *
346 * @param seat Seat
347 */
348void ds_display_remove_seat(ds_seat_t *seat)
349{
350 list_remove(&seat->lseats);
351 seat->display = NULL;
352}
353
354/** Get first seat in display.
355 *
356 * @param disp Display
357 * @return First seat or @c NULL if there is none
358 */
359ds_seat_t *ds_display_first_seat(ds_display_t *disp)
360{
361 link_t *link = list_first(&disp->seats);
362
363 if (link == NULL)
364 return NULL;
365
366 return list_get_instance(link, ds_seat_t, lseats);
367}
368
369/** Get next seat in display.
370 *
371 * @param seat Current seat
372 * @return Next seat or @c NULL if there is none
373 */
374ds_seat_t *ds_display_next_seat(ds_seat_t *seat)
375{
376 link_t *link = list_next(&seat->lseats, &seat->display->seats);
377
378 if (link == NULL)
379 return NULL;
380
381 return list_get_instance(link, ds_seat_t, lseats);
382}
383
384/** Add display device to display.
385 *
386 * @param disp Display
387 * @param ddev Display device
388 */
389void ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
390{
391 assert(ddev->display == NULL);
392 assert(!link_used(&ddev->lddevs));
393
394 /* Set display dimensions to dimensions of first display device */
395 if (gfx_rect_is_empty(&disp->rect))
396 disp->rect = ddev->info.rect;
397
398 ddev->display = disp;
399 list_append(&ddev->lddevs, &disp->ddevs);
400}
401
402/** Remove display device from display.
403 *
404 * @param ddev Display device
405 */
406void ds_display_remove_ddev(ds_ddev_t *ddev)
407{
408 list_remove(&ddev->lddevs);
409 ddev->display = NULL;
410}
411
412/** Get first display device in display.
413 *
414 * @param disp Display
415 * @return First display device or @c NULL if there is none
416 */
417ds_ddev_t *ds_display_first_ddev(ds_display_t *disp)
418{
419 link_t *link = list_first(&disp->ddevs);
420
421 if (link == NULL)
422 return NULL;
423
424 return list_get_instance(link, ds_ddev_t, lddevs);
425}
426
427/** Get next display device in display.
428 *
429 * @param ddev Current display device
430 * @return Next display device or @c NULL if there is none
431 */
432ds_ddev_t *ds_display_next_ddev(ds_ddev_t *ddev)
433{
434 link_t *link = list_next(&ddev->lddevs, &ddev->display->ddevs);
435
436 if (link == NULL)
437 return NULL;
438
439 return list_get_instance(link, ds_ddev_t, lddevs);
440}
441
442// XXX
443gfx_context_t *ds_display_get_gc(ds_display_t *display)
444{
445 ds_ddev_t *ddev;
446
447 ddev = ds_display_first_ddev(display);
448 if (ddev == NULL)
449 return NULL;
450
451 return ddev->gc;
452}
453
454/** Paint display background.
455 *
456 * @param display Display
457 * @param rect Bounding rectangle or @c NULL to repaint entire display
458 */
459errno_t ds_display_paint_bg(ds_display_t *disp, gfx_rect_t *rect)
460{
461 gfx_rect_t crect;
462 gfx_context_t *gc;
463 errno_t rc;
464
465 if (rect != NULL)
466 gfx_rect_clip(&disp->rect, rect, &crect);
467 else
468 crect = disp->rect;
469
470 gc = ds_display_get_gc(disp); // XXX
471 if (gc == NULL)
472 return EOK;
473
474 rc = gfx_set_color(gc, disp->bg_color);
475 if (rc != EOK)
476 return rc;
477
478 return gfx_fill_rect(gc, &crect);
479}
480
481/** Paint display.
482 *
483 * @param display Display
484 * @param rect Bounding rectangle or @c NULL to repaint entire display
485 */
486errno_t ds_display_paint(ds_display_t *disp, gfx_rect_t *rect)
487{
488 errno_t rc;
489 ds_window_t *wnd;
490
491 /* Paint background */
492 rc = ds_display_paint_bg(disp, rect);
493 if (rc != EOK)
494 return rc;
495
496 /* Paint windows bottom to top */
497 wnd = ds_display_last_window(disp);
498 while (wnd != NULL) {
499 rc = ds_window_paint(wnd, rect);
500 if (rc != EOK)
501 return rc;
502
503 wnd = ds_display_prev_window(wnd);
504 }
505
506 return EOK;
507}
508
509/** @}
510 */
Note: See TracBrowser for help on using the repository browser.