source: mainline/uspace/app/taskbar/wndlist.c@ 901b302

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

Do not show window buttons that do not fit

  • Property mode set to 100644
File size: 11.7 KB
Line 
1/*
2 * Copyright (c) 2022 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 taskbar
30 * @{
31 */
32/** @file Task bar window list
33 */
34
35#include <gfx/coord.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <str.h>
40#include <ui/fixed.h>
41#include <ui/label.h>
42#include <ui/resource.h>
43#include <ui/ui.h>
44#include <ui/window.h>
45#include "clock.h"
46#include "wndlist.h"
47
48static void wndlist_wm_window_added(void *, sysarg_t);
49static void wndlist_wm_window_removed(void *, sysarg_t);
50static void wndlist_wm_window_changed(void *, sysarg_t);
51
52/** Window list WM callbacks */
53static wndmgt_cb_t wndlist_wndmgt_cb = {
54 .window_added = wndlist_wm_window_added,
55 .window_removed = wndlist_wm_window_removed,
56 .window_changed = wndlist_wm_window_changed
57};
58
59static void wndlist_button_clicked(ui_pbutton_t *, void *);
60
61/** Window list button callbacks */
62static ui_pbutton_cb_t wndlist_button_cb = {
63 .clicked = wndlist_button_clicked
64};
65
66enum {
67 /** X distance between left edges of two consecutive buttons */
68 wndlist_button_pitch = 145,
69 /** X distance between left edges of two consecutive buttons (text) */
70 wndlist_button_pitch_text = 17,
71 /** Padding between buttons */
72 wndlist_button_pad = 5,
73 /** Padding between buttons (text) */
74 wndlist_button_pad_text = 1
75};
76
77/** Create task bar window list.
78 *
79 * @param window Containing window
80 * @param fixed Fixed layout to which buttons will be added
81 * @param wndmgt Window management service
82 * @param rwndlist Place to store pointer to new window list
83 * @return @c EOK on success or an error code
84 */
85errno_t wndlist_create(ui_window_t *window, ui_fixed_t *fixed,
86 wndlist_t **rwndlist)
87{
88 wndlist_t *wndlist = NULL;
89 errno_t rc;
90
91 wndlist = calloc(1, sizeof(wndlist_t));
92 if (wndlist == NULL) {
93 rc = ENOMEM;
94 goto error;
95 }
96
97 wndlist->window = window;
98 wndlist->fixed = fixed;
99 list_initialize(&wndlist->entries);
100 *rwndlist = wndlist;
101 return EOK;
102error:
103 return rc;
104}
105
106/** Set window list rectangle.
107 *
108 * @param wndlist Window list
109 * @param rect Rectangle
110 */
111void wndlist_set_rect(wndlist_t *wndlist, gfx_rect_t *rect)
112{
113 wndlist->rect = *rect;
114}
115
116/** Attach window management service to window list.
117 *
118 * @param wndlist Window list
119 * @param wndmgt_svc Window management service name
120 * @return @c EOK on success or an error code
121 */
122errno_t wndlist_open_wm(wndlist_t *wndlist, const char *wndmgt_svc)
123{
124 errno_t rc;
125 wndmgt_window_list_t *wlist = NULL;
126 wndmgt_window_info_t *winfo = NULL;
127 sysarg_t i;
128
129 rc = wndmgt_open(wndmgt_svc, &wndlist_wndmgt_cb, (void *)wndlist,
130 &wndlist->wndmgt);
131 if (rc != EOK)
132 goto error;
133
134 rc = wndmgt_get_window_list(wndlist->wndmgt, &wlist);
135 if (rc != EOK)
136 goto error;
137
138 for (i = 0; i < wlist->nwindows; i++) {
139 rc = wndmgt_get_window_info(wndlist->wndmgt, wlist->windows[i],
140 &winfo);
141 if (rc != EOK)
142 goto error;
143
144 if ((winfo->flags & (wndf_popup | wndf_system)) == 0) {
145 rc = wndlist_append(wndlist, wlist->windows[i],
146 winfo->caption, false);
147 if (rc != EOK) {
148 wndmgt_free_window_info(winfo);
149 goto error;
150 }
151 }
152
153 wndmgt_free_window_info(winfo);
154 }
155
156 return EOK;
157error:
158 if (wlist != NULL)
159 wndmgt_free_window_list(wlist);
160 if (wndlist->wndmgt != NULL) {
161 wndmgt_close(wndlist->wndmgt);
162 wndlist->wndmgt = NULL;
163 }
164 return rc;
165}
166
167/** Destroy task bar window list. */
168void wndlist_destroy(wndlist_t *wndlist)
169{
170 wndlist_entry_t *entry;
171
172 /* Close window management service */
173 if (wndlist->wndmgt)
174 wndmgt_close(wndlist->wndmgt);
175
176 /* Destroy entries */
177 entry = wndlist_first(wndlist);
178 while (entry != NULL) {
179 (void)wndlist_remove(wndlist, entry, false);
180 entry = wndlist_first(wndlist);
181 }
182
183 free(wndlist);
184}
185
186/** Append new entry to window list.
187 *
188 * @param wndlist Window list
189 * @param wnd_id Window ID
190 * @param caption Entry caption
191 * @param paint @c true to paint immediately
192 * @return @c EOK on success or an error code
193 */
194errno_t wndlist_append(wndlist_t *wndlist, sysarg_t wnd_id,
195 const char *caption, bool paint)
196{
197 wndlist_entry_t *entry = NULL;
198 ui_resource_t *res;
199 errno_t rc;
200
201 entry = calloc(1, sizeof(wndlist_entry_t));
202 if (entry == NULL) {
203 rc = ENOMEM;
204 goto error;
205 }
206
207 entry->wnd_id = wnd_id;
208 res = ui_window_get_res(wndlist->window);
209
210 rc = ui_pbutton_create(res, caption, &entry->button);
211 if (rc != EOK)
212 goto error;
213
214 entry->wndlist = wndlist;
215 list_append(&entry->lentries, &wndlist->entries);
216
217 /* Set the button rectangle */
218 wndlist_set_entry_rect(wndlist, entry);
219
220 /* Set button callbacks */
221 ui_pbutton_set_cb(entry->button, &wndlist_button_cb, (void *)entry);
222
223 rc = ui_fixed_add(wndlist->fixed, ui_pbutton_ctl(entry->button));
224 if (rc != EOK)
225 goto error;
226
227 if (paint) {
228 rc = ui_pbutton_paint(entry->button);
229 if (rc != EOK)
230 goto error;
231 }
232
233 return EOK;
234error:
235 if (entry != NULL && entry->button != NULL)
236 ui_pbutton_destroy(entry->button);
237 if (entry != NULL)
238 free(entry);
239 return rc;
240
241}
242
243/** Remove entry from window list.
244 *
245 * @param wndlist Window list
246 * @param entry Window list entry
247 * @param paint @c true to repaint window list
248 * @return @c EOK on success or an error code
249 */
250errno_t wndlist_remove(wndlist_t *wndlist, wndlist_entry_t *entry,
251 bool paint)
252{
253 wndlist_entry_t *next;
254 assert(entry->wndlist == wndlist);
255
256 next = wndlist_next(entry);
257
258 ui_fixed_remove(wndlist->fixed, ui_pbutton_ctl(entry->button));
259 ui_pbutton_destroy(entry->button);
260 list_remove(&entry->lentries);
261 free(entry);
262
263 /* Update positions of the remaining entries */
264 while (next != NULL) {
265 wndlist_set_entry_rect(wndlist, next);
266 next = wndlist_next(next);
267 }
268
269 if (!paint)
270 return EOK;
271
272 return wndlist_repaint(wndlist);
273}
274
275/** Update window list entry.
276 *
277 * @param wndlist Window list
278 * @param entry Window list entry
279 * @return @c EOK on success or an error code
280 */
281errno_t wndlist_update(wndlist_t *wndlist, wndlist_entry_t *entry,
282 const char *caption)
283{
284 errno_t rc;
285 assert(entry->wndlist == wndlist);
286
287 rc = ui_pbutton_set_caption(entry->button, caption);
288 if (rc != EOK)
289 return rc;
290
291 rc = ui_pbutton_paint(entry->button);
292 if (rc != EOK)
293 return rc;
294
295 return wndlist_repaint(wndlist);
296}
297
298/** Compute and set window list entry rectangle.
299 *
300 * Compute rectangle for window list entry and set it.
301 *
302 * @param wndlist Window list
303 * @param entry Window list entry
304 */
305void wndlist_set_entry_rect(wndlist_t *wndlist, wndlist_entry_t *entry)
306{
307 wndlist_entry_t *e;
308 gfx_rect_t rect;
309 ui_resource_t *res;
310 gfx_coord_t pitch;
311 gfx_coord_t pad;
312 size_t idx;
313
314 /* Determine entry index */
315 idx = 0;
316 e = wndlist_first(wndlist);
317 while (e != entry) {
318 assert(e != NULL);
319 e = wndlist_next(e);
320 ++idx;
321 }
322
323 res = ui_window_get_res(wndlist->window);
324
325 if (ui_resource_is_textmode(res)) {
326 pitch = wndlist_button_pitch_text;
327 pad = wndlist_button_pad_text;
328 } else {
329 pitch = wndlist_button_pitch;
330 pad = wndlist_button_pad;
331 }
332
333 rect.p0.x = wndlist->rect.p0.x + pitch * idx;
334 rect.p0.y = wndlist->rect.p0.y;
335 rect.p1.x = wndlist->rect.p0.x + pitch * (idx + 1) - pad;
336 rect.p1.y = wndlist->rect.p1.y;
337
338 /* Entry does not fit? */
339 if (rect.p1.x > wndlist->rect.p1.x) {
340 /* Make entry invisible */
341 rect.p0.x = 0;
342 rect.p0.y = 0;
343 rect.p1.x = 0;
344 rect.p1.y = 0;
345 }
346
347 ui_pbutton_set_rect(entry->button, &rect);
348}
349
350/** Handle WM window added event.
351 *
352 * @param arg Argument (wndlist_t *)
353 * @param wnd_id Window ID
354 */
355static void wndlist_wm_window_added(void *arg, sysarg_t wnd_id)
356{
357 wndlist_t *wndlist = (wndlist_t *)arg;
358 wndmgt_window_info_t *winfo = NULL;
359 errno_t rc;
360
361 rc = wndmgt_get_window_info(wndlist->wndmgt, wnd_id, &winfo);
362 if (rc != EOK)
363 goto error;
364
365 if ((winfo->flags & (wndf_popup | wndf_system)) == 0) {
366 rc = wndlist_append(wndlist, wnd_id, winfo->caption, true);
367 if (rc != EOK) {
368 wndmgt_free_window_info(winfo);
369 goto error;
370 }
371 }
372
373 wndmgt_free_window_info(winfo);
374 return;
375error:
376 if (winfo != NULL)
377 wndmgt_free_window_info(winfo);
378}
379
380/** Handle WM window removed event.
381 *
382 * @param arg Argument (wndlist_t *)
383 * @param wnd_id Window ID
384 */
385static void wndlist_wm_window_removed(void *arg, sysarg_t wnd_id)
386{
387 wndlist_t *wndlist = (wndlist_t *)arg;
388 wndlist_entry_t *entry;
389
390 entry = wndlist_entry_by_id(wndlist, wnd_id);
391 if (entry == NULL)
392 return;
393
394 (void) wndlist_remove(wndlist, entry, true);
395}
396
397/** Handle WM window changed event.
398 *
399 * @param arg Argument (wndlist_t *)
400 * @param wnd_id Window ID
401 */
402static void wndlist_wm_window_changed(void *arg, sysarg_t wnd_id)
403{
404 wndlist_t *wndlist = (wndlist_t *)arg;
405 wndmgt_window_info_t *winfo = NULL;
406 wndlist_entry_t *entry;
407 errno_t rc;
408
409 entry = wndlist_entry_by_id(wndlist, wnd_id);
410 if (entry == NULL)
411 return;
412
413 rc = wndmgt_get_window_info(wndlist->wndmgt, wnd_id, &winfo);
414 if (rc != EOK)
415 return;
416
417 (void) wndlist_update(wndlist, entry, winfo->caption);
418 wndmgt_free_window_info(winfo);
419}
420
421/** Find window list entry by ID.
422 *
423 * @param wndlist Window list
424 * @param wnd_id Window ID
425 * @return Window list entry on success or @c NULL if not found
426 */
427wndlist_entry_t *wndlist_entry_by_id(wndlist_t *wndlist, sysarg_t wnd_id)
428{
429 wndlist_entry_t *entry;
430
431 entry = wndlist_first(wndlist);
432 while (entry != NULL) {
433 if (entry->wnd_id == wnd_id)
434 return entry;
435
436 entry = wndlist_next(entry);
437 }
438
439 return NULL;
440}
441
442/** Get first window list entry.
443 *
444 * @param wndlist Window list
445 * @return First entry or @c NULL if the list is empty
446 */
447wndlist_entry_t *wndlist_first(wndlist_t *wndlist)
448{
449 link_t *link;
450
451 link = list_first(&wndlist->entries);
452 if (link == NULL)
453 return NULL;
454
455 return list_get_instance(link, wndlist_entry_t, lentries);
456}
457
458/** Get next window list entry.
459 *
460 * @param cur Current entry
461 * @return Next entry or @c NULL if @a cur is the last entry
462 */
463wndlist_entry_t *wndlist_next(wndlist_entry_t *cur)
464{
465 link_t *link;
466
467 link = list_next(&cur->lentries, &cur->wndlist->entries);
468 if (link == NULL)
469 return NULL;
470
471 return list_get_instance(link, wndlist_entry_t, lentries);
472}
473
474/** Repaint window list.
475 *
476 * @param wndlist Window list
477 * @return @c EOK on success or an error code
478 */
479errno_t wndlist_repaint(wndlist_t *wndlist)
480{
481 return ui_window_paint(wndlist->window);
482}
483
484/** Window button was clicked.
485 *
486 * @param pbutton Push button
487 * @param arg Argument (wndlist_entry_t *)
488 */
489static void wndlist_button_clicked(ui_pbutton_t *pbutton, void *arg)
490{
491 wndlist_entry_t *entry = (wndlist_entry_t *)arg;
492 sysarg_t dev_id;
493
494 /* ID of device that clicked the button */
495 dev_id = entry->wndlist->ev_pos_id;
496
497 (void) wndmgt_activate_window(entry->wndlist->wndmgt,
498 dev_id, entry->wnd_id);
499}
500
501/** @}
502 */
Note: See TracBrowser for help on using the repository browser.