source: mainline/uspace/app/taskbar/tbsmenu.c@ d76862d0

topic/simplify-dev-export
Last change on this file since d76862d0 was 95fc538, checked in by Jiri Svoboda <jiri@…>, 22 months ago

It should be Taskbar not Task Bar

  • Property mode set to 100644
File size: 11.0 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/** @addtogroup taskbar
30 * @{
31 */
32/** @file Taskbar start menu
33 */
34
35#include <gfx/coord.h>
36#include <stdbool.h>
37#include <stddef.h>
38#include <stdlib.h>
39#include <str.h>
40#include <task.h>
41#include <tbarcfg/tbarcfg.h>
42#include <ui/fixed.h>
43#include <ui/menu.h>
44#include <ui/menuentry.h>
45#include <ui/resource.h>
46#include <ui/ui.h>
47#include <ui/window.h>
48#include "tbsmenu.h"
49
50static void tbsmenu_smenu_close_req(ui_menu_t *, void *);
51
52/** Start menu callbacks */
53static ui_menu_cb_t tbsmenu_smenu_cb = {
54 .close_req = tbsmenu_smenu_close_req,
55};
56
57static void tbsmenu_button_down(ui_pbutton_t *, void *);
58
59/** Start button callbacks */
60static ui_pbutton_cb_t tbsmenu_button_cb = {
61 .down = tbsmenu_button_down
62};
63
64static void tbsmenu_smenu_entry_cb(ui_menu_entry_t *, void *);
65static errno_t tbsmenu_entry_start(tbsmenu_entry_t *);
66
67/** Create taskbar start menu.
68 *
69 * @param window Containing window
70 * @param fixed Fixed layout to which start button will be added
71 * @param rtbsmenu Place to store pointer to new start menu
72 * @return @c EOK on success or an error code
73 */
74errno_t tbsmenu_create(ui_window_t *window, ui_fixed_t *fixed,
75 tbsmenu_t **rtbsmenu)
76{
77 ui_resource_t *res = ui_window_get_res(window);
78 tbsmenu_t *tbsmenu = NULL;
79 errno_t rc;
80
81 tbsmenu = calloc(1, sizeof(tbsmenu_t));
82 if (tbsmenu == NULL) {
83 rc = ENOMEM;
84 goto error;
85 }
86
87 rc = ui_pbutton_create(res, "Start", &tbsmenu->sbutton);
88 if (rc != EOK)
89 goto error;
90
91 ui_pbutton_set_cb(tbsmenu->sbutton, &tbsmenu_button_cb,
92 (void *)tbsmenu);
93
94 ui_pbutton_set_default(tbsmenu->sbutton, true);
95
96 rc = ui_fixed_add(fixed, ui_pbutton_ctl(tbsmenu->sbutton));
97 if (rc != EOK)
98 goto error;
99
100 rc = ui_menu_create(window, &tbsmenu->smenu);
101 if (rc != EOK)
102 goto error;
103
104 ui_menu_set_cb(tbsmenu->smenu, &tbsmenu_smenu_cb, (void *)tbsmenu);
105
106 tbsmenu->window = window;
107 tbsmenu->fixed = fixed;
108 list_initialize(&tbsmenu->entries);
109
110 *rtbsmenu = tbsmenu;
111 return EOK;
112error:
113 if (tbsmenu != NULL)
114 ui_pbutton_destroy(tbsmenu->sbutton);
115 if (tbsmenu != NULL)
116 free(tbsmenu);
117 return rc;
118}
119
120/** Load start menu from repository.
121 *
122 * @param tbsmenu Start menu
123 * @param Repository path
124 * @return EOK on success or an error code
125 */
126errno_t tbsmenu_load(tbsmenu_t *tbsmenu, const char *repopath)
127{
128 tbsmenu_entry_t *tentry;
129 tbarcfg_t *tbcfg = NULL;
130 smenu_entry_t *sme;
131 const char *caption;
132 const char *cmd;
133 errno_t rc;
134
135 rc = tbarcfg_open(repopath, &tbcfg);
136 if (rc != EOK)
137 goto error;
138
139 sme = tbarcfg_smenu_first(tbcfg);
140 while (sme != NULL) {
141 caption = smenu_entry_get_caption(sme);
142 cmd = smenu_entry_get_cmd(sme);
143
144 rc = tbsmenu_add(tbsmenu, caption, cmd, &tentry);
145 if (rc != EOK)
146 goto error;
147
148 (void)tentry;
149
150 sme = tbarcfg_smenu_next(sme);
151 }
152
153 tbarcfg_close(tbcfg);
154 return EOK;
155error:
156 if (tbcfg != NULL)
157 tbarcfg_close(tbcfg);
158 return rc;
159}
160
161/** Set start menu rectangle.
162 *
163 * @param tbsmenu Start menu
164 * @param rect Rectangle
165 */
166void tbsmenu_set_rect(tbsmenu_t *tbsmenu, gfx_rect_t *rect)
167{
168 tbsmenu->rect = *rect;
169 ui_pbutton_set_rect(tbsmenu->sbutton, rect);
170}
171
172/** Open taskbar start menu.
173 *
174 * @param tbsmenu Start menu
175 */
176void tbsmenu_open(tbsmenu_t *tbsmenu)
177{
178 (void) ui_menu_open(tbsmenu->smenu, &tbsmenu->rect,
179 tbsmenu->ev_idev_id);
180}
181
182/** Close taskbar start menu.
183 *
184 * @param tbsmenu Start menu
185 */
186void tbsmenu_close(tbsmenu_t *tbsmenu)
187{
188 ui_menu_close(tbsmenu->smenu);
189}
190
191/** Determine if taskbar start menu is open.
192 *
193 * @param tbsmenu Start menu
194 * @return @c true iff start menu is open
195 */
196bool tbsmenu_is_open(tbsmenu_t *tbsmenu)
197{
198 return ui_menu_is_open(tbsmenu->smenu);
199}
200
201/** Destroy taskbar start menu.
202 *
203 * @param tbsmenu Start menu
204 */
205void tbsmenu_destroy(tbsmenu_t *tbsmenu)
206{
207 tbsmenu_entry_t *entry;
208
209 /* Destroy entries */
210 entry = tbsmenu_first(tbsmenu);
211 while (entry != NULL) {
212 tbsmenu_remove(tbsmenu, entry, false);
213 entry = tbsmenu_first(tbsmenu);
214 }
215
216 ui_fixed_remove(tbsmenu->fixed, ui_pbutton_ctl(tbsmenu->sbutton));
217 ui_pbutton_destroy(tbsmenu->sbutton);
218 ui_menu_destroy(tbsmenu->smenu);
219
220 free(tbsmenu);
221}
222
223/** Add entry to start menu.
224 *
225 * @param tbsmenu Start menu
226 * @param caption Caption
227 * @param cmd Command to run
228 * @param entry Start menu entry
229 * @return @c EOK on success or an error code
230 */
231errno_t tbsmenu_add(tbsmenu_t *tbsmenu, const char *caption,
232 const char *cmd, tbsmenu_entry_t **rentry)
233{
234 errno_t rc;
235 tbsmenu_entry_t *entry;
236
237 entry = calloc(1, sizeof(tbsmenu_entry_t));
238 if (entry == NULL)
239 return ENOMEM;
240
241 entry->caption = str_dup(caption);
242 if (entry->caption == NULL) {
243 rc = ENOMEM;
244 goto error;
245 }
246
247 entry->cmd = str_dup(cmd);
248 if (entry->cmd == NULL) {
249 rc = ENOMEM;
250 goto error;
251 }
252
253 rc = ui_menu_entry_create(tbsmenu->smenu, caption, "", &entry->mentry);
254 if (rc != EOK)
255 goto error;
256
257 ui_menu_entry_set_cb(entry->mentry, tbsmenu_smenu_entry_cb,
258 (void *)entry);
259
260 entry->tbsmenu = tbsmenu;
261 list_append(&entry->lentries, &tbsmenu->entries);
262 *rentry = entry;
263 return EOK;
264error:
265 if (entry->caption != NULL)
266 free(entry->caption);
267 if (entry->cmd != NULL)
268 free(entry->cmd);
269 free(entry);
270 return rc;
271}
272
273/** Remove entry from start menu.
274 *
275 * @param tbsmenu Start menu
276 * @param entry Start menu entry
277 * @param paint @c true to repaint start menu
278 */
279void tbsmenu_remove(tbsmenu_t *tbsmenu, tbsmenu_entry_t *entry,
280 bool paint)
281{
282 assert(entry->tbsmenu == tbsmenu);
283
284 list_remove(&entry->lentries);
285
286 ui_menu_entry_destroy(entry->mentry);
287 free(entry->caption);
288 free(entry->cmd);
289 free(entry);
290}
291
292/** Handle start menu close request.
293 *
294 * @param menu Menu
295 * @param arg Argument (tbsmenu_t *)
296 * @param wnd_id Window ID
297 */
298static void tbsmenu_smenu_close_req(ui_menu_t *menu, void *arg)
299{
300 tbsmenu_t *tbsmenu = (tbsmenu_t *)arg;
301
302 (void)tbsmenu;
303 ui_menu_close(menu);
304}
305
306/** Start menu entry was activated.
307 *
308 * @param smentry Start menu entry
309 * @param arg Argument (tbsmenu_entry_t *)
310 */
311static void tbsmenu_smenu_entry_cb(ui_menu_entry_t *smentry, void *arg)
312{
313 tbsmenu_entry_t *entry = (tbsmenu_entry_t *)arg;
314
315 (void)tbsmenu_entry_start(entry);
316}
317
318/** Get first start menu entry.
319 *
320 * @param tbsmenu Start menu
321 * @return First entry or @c NULL if the menu is empty
322 */
323tbsmenu_entry_t *tbsmenu_first(tbsmenu_t *tbsmenu)
324{
325 link_t *link;
326
327 link = list_first(&tbsmenu->entries);
328 if (link == NULL)
329 return NULL;
330
331 return list_get_instance(link, tbsmenu_entry_t, lentries);
332}
333
334/** Get last start menu entry.
335 *
336 * @param tbsmenu Start menu
337 * @return Last entry or @c NULL if the menu is empty
338 */
339tbsmenu_entry_t *tbsmenu_last(tbsmenu_t *tbsmenu)
340{
341 link_t *link;
342
343 link = list_last(&tbsmenu->entries);
344 if (link == NULL)
345 return NULL;
346
347 return list_get_instance(link, tbsmenu_entry_t, lentries);
348}
349
350/** Get next start menu entry.
351 *
352 * @param cur Current entry
353 * @return Next entry or @c NULL if @a cur is the last entry
354 */
355tbsmenu_entry_t *tbsmenu_next(tbsmenu_entry_t *cur)
356{
357 link_t *link;
358
359 link = list_next(&cur->lentries, &cur->tbsmenu->entries);
360 if (link == NULL)
361 return NULL;
362
363 return list_get_instance(link, tbsmenu_entry_t, lentries);
364}
365
366/** Get number of start menu entries.
367 *
368 * @param tbsmenu Start menu
369 * @return Number of entries
370 */
371size_t tbsmenu_count(tbsmenu_t *tbsmenu)
372{
373 return list_count(&tbsmenu->entries);
374}
375
376/** Start button was depressed.
377 *
378 * @param pbutton Push button
379 * @param arg Argument (tbsmenu_entry_t *)
380 */
381static void tbsmenu_button_down(ui_pbutton_t *pbutton, void *arg)
382{
383 tbsmenu_t *tbsmenu = (tbsmenu_t *)arg;
384
385 if (!tbsmenu_is_open(tbsmenu)) {
386 tbsmenu_open(tbsmenu);
387 } else {
388 /* menu is open */
389 tbsmenu_close(tbsmenu);
390 }
391}
392
393/** Split command string into individual parts.
394 *
395 * Command arguments are separated by spaces. There is no way
396 * to provide an argument containing spaces.
397 *
398 * @param str Command with arguments separated by spaces
399 * @param cmd Command structure to fill in
400 * @return EOK on success or an error code
401 */
402static errno_t tbsmenu_cmd_split(const char *str, tbsmenu_cmd_t *cmd)
403{
404 char *arg;
405 char *next;
406 size_t cnt;
407
408 cmd->buf = str_dup(str);
409 if (cmd->buf == NULL)
410 return ENOMEM;
411
412 /* Count the entries */
413 cnt = 0;
414 arg = str_tok(cmd->buf, " ", &next);
415 while (arg != NULL) {
416 ++cnt;
417 arg = str_tok(next, " ", &next);
418 }
419
420 /* Need to copy again as buf was mangled */
421 free(cmd->buf);
422 cmd->buf = str_dup(str);
423 if (cmd->buf == NULL)
424 return ENOMEM;
425
426 cmd->argv = calloc(cnt + 1, sizeof(char *));
427 if (cmd->argv == NULL) {
428 free(cmd->buf);
429 return ENOMEM;
430 }
431
432 /* Fill in pointers */
433 cnt = 0;
434 arg = str_tok(cmd->buf, " ", &next);
435 while (arg != NULL) {
436 cmd->argv[cnt++] = arg;
437 arg = str_tok(next, " ", &next);
438 }
439
440 return EOK;
441}
442
443/** Free command structure.
444 *
445 * @param cmd Command
446 */
447static void tbsmenu_cmd_fini(tbsmenu_cmd_t *cmd)
448{
449 free(cmd->argv);
450 free(cmd->buf);
451}
452
453/** Execute start menu entry.
454 *
455 * @param entry Start menu entry
456 *
457 * @return EOK on success or an error code
458 */
459static errno_t tbsmenu_entry_start(tbsmenu_entry_t *entry)
460{
461 task_id_t id;
462 task_wait_t wait;
463 task_exit_t texit;
464 tbsmenu_cmd_t cmd;
465 int retval;
466 bool suspended;
467 errno_t rc;
468 ui_t *ui;
469
470 ui = ui_window_get_ui(entry->tbsmenu->window);
471 suspended = false;
472
473 rc = tbsmenu_cmd_split(entry->cmd, &cmd);
474 if (rc != EOK)
475 return rc;
476
477 /* Free up and clean console for the child task. */
478 rc = ui_suspend(ui);
479 if (rc != EOK)
480 goto error;
481
482 suspended = true;
483
484 rc = task_spawnv(&id, &wait, cmd.argv[0], (const char *const *)
485 cmd.argv);
486 if (rc != EOK)
487 goto error;
488
489 rc = task_wait(&wait, &texit, &retval);
490 if ((rc != EOK) || (texit != TASK_EXIT_NORMAL))
491 goto error;
492
493 /* Resume UI operation */
494 rc = ui_resume(ui);
495 if (rc != EOK)
496 goto error;
497
498 (void) ui_paint(ui);
499 return EOK;
500error:
501 tbsmenu_cmd_fini(&cmd);
502 if (suspended)
503 (void) ui_resume(ui);
504 (void) ui_paint(ui);
505 return rc;
506}
507
508/** @}
509 */
Note: See TracBrowser for help on using the repository browser.