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

Last change on this file was 5caad1d, checked in by Jiri Svoboda <jiri@…>, 9 days ago

tbarcfg_listener_destroy() should clean up properly.

  • Property mode set to 100644
File size: 16.9 KB
RevLine 
[7d78e466]1/*
[ca48672]2 * Copyright (c) 2025 Jiri Svoboda
[7d78e466]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
[b279899]29/** @addtogroup libtbarcfg
[7d78e466]30 * @{
31 */
32/**
[95fc538]33 * @file Taskbar configuration
[7d78e466]34 */
35
[ee3b28a9]36#include <async.h>
[7d78e466]37#include <errno.h>
38#include <sif.h>
[ee3b28a9]39#include <ipc/tbarcfg.h>
40#include <loc.h>
41#include <task.h>
[b279899]42#include <tbarcfg/tbarcfg.h>
[ee3b28a9]43#include <stdio.h>
[7d78e466]44#include <stdlib.h>
45#include <str.h>
[b279899]46#include "../private/tbarcfg.h"
[7d78e466]47
[ee3b28a9]48static void tbarcfg_notify_conn(ipc_call_t *, void *);
[bff8619]49static errno_t smenu_entry_save(smenu_entry_t *, sif_node_t *);
[ee3b28a9]50
[84d29a2]51/** Create taskbar configuration.
52 *
53 * @param repopath Pathname of the new menu repository
54 * @param rtbcfg Place to store pointer to taskbar configuration
55 * @return EOK on success or an error code
56 */
57errno_t tbarcfg_create(const char *repopath, tbarcfg_t **rtbcfg)
58{
59 tbarcfg_t *tbcfg;
[bff8619]60 sif_doc_t *doc = NULL;
[84d29a2]61 sif_node_t *rnode;
[bff8619]62 sif_node_t *nentries;
[84d29a2]63 errno_t rc;
64
65 tbcfg = calloc(1, sizeof(tbarcfg_t));
66 if (tbcfg == NULL) {
67 rc = ENOMEM;
68 goto error;
69 }
70
71 list_initialize(&tbcfg->entries);
[bff8619]72 tbcfg->cfgpath = str_dup(repopath);
73 if (tbcfg->cfgpath == NULL) {
74 rc = ENOMEM;
75 goto error;
76 }
[84d29a2]77
[bff8619]78 rc = sif_new(&doc);
[84d29a2]79 if (rc != EOK)
80 goto error;
81
[bff8619]82 rnode = sif_get_root(doc);
[84d29a2]83
[bff8619]84 rc = sif_node_append_child(rnode, "entries", &nentries);
[84d29a2]85 if (rc != EOK)
86 goto error;
87
[bff8619]88 (void)nentries;
[84d29a2]89
[bff8619]90 rc = sif_save(doc, repopath);
[84d29a2]91 if (rc != EOK)
92 goto error;
93
[bff8619]94 sif_delete(doc);
95
[84d29a2]96 *rtbcfg = tbcfg;
97 return EOK;
98error:
[bff8619]99 if (doc != NULL)
100 sif_delete(doc);
101 if (tbcfg != NULL && tbcfg->cfgpath != NULL)
102 free(tbcfg->cfgpath);
[84d29a2]103 if (tbcfg != NULL)
104 free(tbcfg);
105 return rc;
106}
107
[95fc538]108/** Open taskbar configuration.
[7d78e466]109 *
110 * @param repopath Pathname of the menu repository
[95fc538]111 * @param rtbcfg Place to store pointer to taskbar configuration
[7d78e466]112 * @return EOK on success or an error code
113 */
[b279899]114errno_t tbarcfg_open(const char *repopath, tbarcfg_t **rtbcfg)
[7d78e466]115{
[b279899]116 tbarcfg_t *tbcfg;
[bff8619]117 sif_doc_t *doc = NULL;
118 sif_node_t *nentries;
[7d78e466]119 sif_node_t *rnode;
120 sif_node_t *nentry;
121 const char *ntype;
[e63e74a]122 const char *separator;
[7d78e466]123 const char *caption;
124 const char *cmd;
[806d761]125 const char *terminal = NULL;
[7d78e466]126 errno_t rc;
127
[b279899]128 tbcfg = calloc(1, sizeof(tbarcfg_t));
129 if (tbcfg == NULL) {
[7d78e466]130 rc = ENOMEM;
131 goto error;
132 }
133
[b279899]134 list_initialize(&tbcfg->entries);
[bff8619]135 tbcfg->cfgpath = str_dup(repopath);
136 if (tbcfg->cfgpath == NULL) {
137 rc = ENOMEM;
138 goto error;
139 }
[7d78e466]140
[bff8619]141 rc = sif_load(repopath, &doc);
[7d78e466]142 if (rc != EOK)
143 goto error;
144
[bff8619]145 rnode = sif_get_root(doc);
146 nentries = sif_node_first_child(rnode);
147 ntype = sif_node_get_type(nentries);
[7d78e466]148 if (str_cmp(ntype, "entries") != 0) {
149 rc = EIO;
150 goto error;
151 }
152
[bff8619]153 nentry = sif_node_first_child(nentries);
[7d78e466]154 while (nentry != NULL) {
155 ntype = sif_node_get_type(nentry);
156 if (str_cmp(ntype, "entry") != 0) {
157 rc = EIO;
158 goto error;
159 }
160
[e63e74a]161 separator = sif_node_get_attr(nentry, "separator");
162 if (separator != NULL && str_cmp(separator, "y") != 0) {
[7d78e466]163 rc = EIO;
164 goto error;
165 }
166
[e63e74a]167 if (separator == NULL) {
168 caption = sif_node_get_attr(nentry, "caption");
169 if (caption == NULL) {
170 rc = EIO;
171 goto error;
172 }
173
174 cmd = sif_node_get_attr(nentry, "cmd");
175 if (cmd == NULL) {
176 rc = EIO;
177 goto error;
178 }
179
180 terminal = sif_node_get_attr(nentry, "terminal");
181 if (terminal == NULL)
182 terminal = "n";
183
[bff8619]184 rc = smenu_entry_create(tbcfg, caption, cmd,
[e63e74a]185 str_cmp(terminal, "y") == 0, NULL);
186 if (rc != EOK)
187 goto error;
188 } else {
[bff8619]189 rc = smenu_entry_sep_create(tbcfg, NULL);
[e63e74a]190 if (rc != EOK)
191 goto error;
[7d78e466]192 }
193
194 nentry = sif_node_next_child(nentry);
195 }
196
[bff8619]197 sif_delete(doc);
[b279899]198 *rtbcfg = tbcfg;
[7d78e466]199 return EOK;
200error:
[bff8619]201 if (doc != NULL)
202 sif_delete(doc);
203 if (tbcfg != NULL && tbcfg->cfgpath != NULL)
204 free(tbcfg->cfgpath);
[b279899]205 if (tbcfg != NULL)
206 free(tbcfg);
[7d78e466]207 return rc;
208}
209
[95fc538]210/** Close taskbar configuration.
[7d78e466]211 *
[b279899]212 * @param tbcfg Start menu
[7d78e466]213 */
[b279899]214void tbarcfg_close(tbarcfg_t *tbcfg)
[7d78e466]215{
[8a43f01]216 smenu_entry_t *entry;
217
218 entry = tbarcfg_smenu_first(tbcfg);
219 while (entry != NULL) {
[bff8619]220 smenu_entry_destroy(entry);
[8a43f01]221 entry = tbarcfg_smenu_first(tbcfg);
222 }
223
[bff8619]224 free(tbcfg->cfgpath);
[8a43f01]225 free(tbcfg);
[7d78e466]226}
227
[bff8619]228/** Synchronize taskbar configuration to config file.
229 *
230 * @param repopath Pathname of the menu repository
231 * @param rtbcfg Place to store pointer to taskbar configuration
232 * @return EOK on success or an error code
233 */
234errno_t tbarcfg_sync(tbarcfg_t *tbcfg)
235{
236 sif_doc_t *doc = NULL;
237 sif_node_t *nentries;
238 sif_node_t *rnode;
239 smenu_entry_t *entry;
240 errno_t rc;
241
242 rc = sif_new(&doc);
243 if (rc != EOK)
244 goto error;
245
246 rnode = sif_get_root(doc);
247
248 rc = sif_node_append_child(rnode, "entries", &nentries);
249 if (rc != EOK)
250 goto error;
251
252 entry = tbarcfg_smenu_first(tbcfg);
253 while (entry != NULL) {
254 rc = smenu_entry_save(entry, nentries);
255 if (rc != EOK)
256 goto error;
257
258 entry = tbarcfg_smenu_next(entry);
259 }
260
261 rc = sif_save(doc, tbcfg->cfgpath);
262 if (rc != EOK)
263 goto error;
264
265 sif_delete(doc);
266 return EOK;
267error:
268 if (doc != NULL)
269 sif_delete(doc);
270 if (tbcfg != NULL && tbcfg->cfgpath != NULL)
271 free(tbcfg->cfgpath);
272 if (tbcfg != NULL)
273 free(tbcfg);
274 return rc;
275}
276
[7d78e466]277/** Get first start menu entry.
278 *
[95fc538]279 * @param tbcfg Taskbar configuration
[7d78e466]280 * @return First entry or @c NULL if the menu is empty
281 */
[b279899]282smenu_entry_t *tbarcfg_smenu_first(tbarcfg_t *tbcfg)
[7d78e466]283{
284 link_t *link;
285
[b279899]286 link = list_first(&tbcfg->entries);
[7d78e466]287 if (link == NULL)
288 return NULL;
289
[b279899]290 return list_get_instance(link, smenu_entry_t, lentries);
[7d78e466]291}
292
293/** Get next start menu entry.
294 *
295 * @param cur Current entry
296 * @return Next entry or @c NULL if @a cur is the last entry
297 */
[b279899]298smenu_entry_t *tbarcfg_smenu_next(smenu_entry_t *cur)
[7d78e466]299{
300 link_t *link;
301
302 link = list_next(&cur->lentries, &cur->smenu->entries);
303 if (link == NULL)
304 return NULL;
305
[b279899]306 return list_get_instance(link, smenu_entry_t, lentries);
[7d78e466]307}
308
[28ca31ed]309/** Get last start menu entry.
310 *
311 * @param tbcfg Taskbar configuration
312 * @return Previous entry or @c NULL if the menu is empty
313 */
314smenu_entry_t *tbarcfg_smenu_last(tbarcfg_t *tbcfg)
315{
316 link_t *link;
317
318 link = list_last(&tbcfg->entries);
319 if (link == NULL)
320 return NULL;
321
322 return list_get_instance(link, smenu_entry_t, lentries);
323}
324
325/** Get previous start menu entry.
326 *
327 * @param cur Current entry
328 * @return Previous entry or @c NULL if @a cur is the last entry
329 */
330smenu_entry_t *tbarcfg_smenu_prev(smenu_entry_t *cur)
331{
332 link_t *link;
333
334 link = list_prev(&cur->lentries, &cur->smenu->entries);
335 if (link == NULL)
336 return NULL;
337
338 return list_get_instance(link, smenu_entry_t, lentries);
339}
340
[7d78e466]341/** Get start menu entry caption.
342 *
343 * @param entry Start menu entry
344 * @return Caption (with accelerator markup)
345 */
[b279899]346const char *smenu_entry_get_caption(smenu_entry_t *entry)
[7d78e466]347{
[e63e74a]348 assert(!entry->separator);
[7d78e466]349 return entry->caption;
350}
351
352/** Get start menu entry command.
353 *
[806d761]354 * @param entry Start menu entry
[7d78e466]355 * @return Command to run
356 */
[b279899]357const char *smenu_entry_get_cmd(smenu_entry_t *entry)
[7d78e466]358{
[e63e74a]359 assert(!entry->separator);
[7d78e466]360 return entry->cmd;
361}
362
[e63e74a]363/** Get start menu entry start in terminal flag.
[806d761]364 *
365 * @param entry Start menu entry
366 * @return Start in terminal flag
367 */
368bool smenu_entry_get_terminal(smenu_entry_t *entry)
369{
[e63e74a]370 assert(!entry->separator);
[806d761]371 return entry->terminal;
372}
373
[e63e74a]374/** Get start menu entry separator flag.
375 *
376 * @param entry Start menu entry
377 * @return Separator flag
378 */
379bool smenu_entry_get_separator(smenu_entry_t *entry)
380{
381 return entry->separator;
382}
383
[b1397ab]384/** Set start menu entry caption.
385 *
386 * Note: To make the change visible to others and persistent,
[bff8619]387 * you must call @c tbarcfg_sync()
[b1397ab]388 *
389 * @param entry Start menu entry
390 * @param caption New caption
391 * @return EOK on success, ENOMEM if out of memory
392 */
393errno_t smenu_entry_set_caption(smenu_entry_t *entry, const char *caption)
394{
395 char *dcap;
396
[e63e74a]397 assert(!entry->separator);
398
[b1397ab]399 dcap = str_dup(caption);
400 if (dcap == NULL)
401 return ENOMEM;
402
403 free(entry->caption);
404 entry->caption = dcap;
405 return EOK;
406}
407
408/** Set start menu entry command.
409 *
410 * Note: To make the change visible to others and persistent,
[bff8619]411 * you must call @c tbarcfg_sync()
[b1397ab]412 *
413 * @param entry Start menu entry
414 * @param cmd New command
415 * @return EOK on success, ENOMEM if out of memory
416 */
417errno_t smenu_entry_set_cmd(smenu_entry_t *entry, const char *cmd)
418{
419 char *dcmd;
420
[e63e74a]421 assert(!entry->separator);
422
[b1397ab]423 dcmd = str_dup(cmd);
424 if (dcmd == NULL)
425 return ENOMEM;
426
427 free(entry->cmd);
428 entry->cmd = dcmd;
429 return EOK;
430}
431
[806d761]432/** Set start menu entry start in terminal flag.
433 *
434 * Note: To make the change visible to others and persistent,
[bff8619]435 * you must call @c tbarcfg_sync()
[806d761]436 *
437 * @param entry Start menu entry
438 * @param terminal Start in terminal flag
439 */
440void smenu_entry_set_terminal(smenu_entry_t *entry, bool terminal)
441{
[e63e74a]442 assert(!entry->separator);
[806d761]443 entry->terminal = terminal;
444}
445
[28ca31ed]446/** Save start menu entry using transaction.
[b1397ab]447 *
448 * @param entry Start menu entry
[bff8619]449 * @param nentries Entries node
[b1397ab]450 */
[bff8619]451static errno_t smenu_entry_save(smenu_entry_t *entry, sif_node_t *nentries)
[b1397ab]452{
[bff8619]453 sif_node_t *nentry = NULL;
[b1397ab]454 errno_t rc;
455
[bff8619]456 rc = sif_node_append_child(nentries, "entry", &nentry);
457 if (rc != EOK)
458 goto error;
459
[e63e74a]460 if (entry->separator) {
[bff8619]461 rc = sif_node_set_attr(nentry, "separator", "y");
[e63e74a]462 if (rc != EOK)
463 goto error;
464 } else {
[bff8619]465 rc = sif_node_set_attr(nentry, "cmd", entry->cmd);
[e63e74a]466 if (rc != EOK)
467 goto error;
[b1397ab]468
[bff8619]469 rc = sif_node_set_attr(nentry, "caption",
[e63e74a]470 entry->caption);
471 if (rc != EOK)
472 goto error;
473
[bff8619]474 rc = sif_node_set_attr(nentry, "terminal",
[e63e74a]475 entry->terminal ? "y" : "n");
476 if (rc != EOK)
477 goto error;
478 }
[806d761]479
[28ca31ed]480 return EOK;
481error:
[bff8619]482 if (nentry != NULL)
483 sif_node_destroy(nentry);
[28ca31ed]484 return rc;
485}
486
[bff8619]487/** Create new start menu entry and append it to the start menu (internal).
[7d78e466]488 *
489 * This only creates the entry in memory, but does not update the repository.
490 *
491 * @param smenu Start menu
492 * @param caption Caption
493 * @param cmd Command to run
[806d761]494 * @param terminal Start in terminal
[550ed86]495 * @param rentry Place to store pointer to new entry or @c NULL
[7d78e466]496 */
[bff8619]497errno_t smenu_entry_create(tbarcfg_t *smenu, const char *caption,
498 const char *cmd, bool terminal, smenu_entry_t **rentry)
[7d78e466]499{
[b279899]500 smenu_entry_t *entry;
[7d78e466]501 errno_t rc;
502
[b279899]503 entry = calloc(1, sizeof(smenu_entry_t));
[7d78e466]504 if (entry == NULL) {
505 rc = ENOMEM;
506 goto error;
507 }
508
509 entry->caption = str_dup(caption);
510 if (entry->caption == NULL) {
511 rc = ENOMEM;
512 goto error;
513 }
514
515 entry->cmd = str_dup(cmd);
516 if (entry->cmd == NULL) {
517 rc = ENOMEM;
518 goto error;
519 }
520
[806d761]521 entry->terminal = terminal;
522
[7d78e466]523 entry->smenu = smenu;
524 list_append(&entry->lentries, &smenu->entries);
[550ed86]525 if (rentry != NULL)
526 *rentry = entry;
[7d78e466]527 return EOK;
528error:
529 if (entry != NULL) {
530 if (entry->caption != NULL)
531 free(entry->caption);
532 if (entry->cmd != NULL)
533 free(entry->cmd);
534 free(entry);
535 }
536
537 return rc;
538}
539
[bff8619]540/** Create new start menu separator entry and append it to the start menu
[e63e74a]541 * (internal).
542 *
543 * This only creates the entry in memory, but does not update the repository.
544 *
545 * @param smenu Start menu
546 * @param rentry Place to store pointer to new entry or @c NULL
547 */
[bff8619]548errno_t smenu_entry_sep_create(tbarcfg_t *smenu, smenu_entry_t **rentry)
[e63e74a]549{
550 smenu_entry_t *entry;
551 errno_t rc;
552
553 entry = calloc(1, sizeof(smenu_entry_t));
554 if (entry == NULL) {
555 rc = ENOMEM;
556 goto error;
557 }
558
559 entry->separator = true;
560
561 entry->smenu = smenu;
562 list_append(&entry->lentries, &smenu->entries);
563 if (rentry != NULL)
564 *rentry = entry;
565
566 return EOK;
567error:
568 return rc;
569}
570
[bff8619]571/** Destroy start menu entry.
[8a43f01]572 *
573 * This only deletes the entry from, but does not update the
574 * repository.
575 *
576 * @param entry Start menu entry
577 */
[bff8619]578void smenu_entry_destroy(smenu_entry_t *entry)
[8a43f01]579{
580 list_remove(&entry->lentries);
[e63e74a]581 if (entry->caption != NULL)
582 free(entry->caption);
583 if (entry->cmd != NULL)
584 free(entry->cmd);
[8a43f01]585 free(entry);
586}
587
[28ca31ed]588/** Move start menu entry up.
589 *
590 * @param entry Start menu entry
591 */
[bff8619]592void smenu_entry_move_up(smenu_entry_t *entry)
[28ca31ed]593{
594 smenu_entry_t *prev;
595
596 prev = tbarcfg_smenu_prev(entry);
597 if (prev == NULL) {
598 /* Entry is already at first position, nothing to do. */
[bff8619]599 return;
[28ca31ed]600 }
601
602 list_remove(&entry->lentries);
603 list_insert_before(&entry->lentries, &prev->lentries);
604}
605
606/** Move start menu entry down.
607 *
608 * @param entry Start menu entry
609 */
[bff8619]610void smenu_entry_move_down(smenu_entry_t *entry)
[28ca31ed]611{
612 smenu_entry_t *next;
613
614 next = tbarcfg_smenu_next(entry);
615 if (next == NULL) {
616 /* Entry is already at last position, nothing to do. */
[bff8619]617 return;
[28ca31ed]618 }
619
620 list_remove(&entry->lentries);
621 list_insert_after(&entry->lentries, &next->lentries);
622}
623
[ee3b28a9]624/** Create taskbar configuration listener.
625 *
626 * Listens for taskbar configuration change notifications.
627 *
628 * @param nchan Notification channel (TBARCFG_NOTIFY_DEFAULT)
629 * @param rlst Place to store pointer to new listener
630 * @return EOK on success or an error code
631 */
632errno_t tbarcfg_listener_create(const char *nchan, void (*cb)(void *),
633 void *arg, tbarcfg_listener_t **rlst)
634{
635 tbarcfg_listener_t *lst;
636 service_id_t svcid = 0;
637 loc_srv_t *srv = NULL;
638 task_id_t taskid;
639 char *svcname = NULL;
640 category_id_t catid;
[ca48672]641 port_id_t port = 0;
[ee3b28a9]642 int rv;
643 errno_t rc;
644
645 lst = calloc(1, sizeof(tbarcfg_listener_t));
646 if (lst == NULL)
647 return ENOMEM;
648
649 lst->cb = cb;
650 lst->arg = arg;
651
652 rc = async_create_port(INTERFACE_TBARCFG_NOTIFY,
653 tbarcfg_notify_conn, (void *)lst, &port);
654 if (rc != EOK)
655 goto error;
656
657 rc = loc_server_register("tbarcfg-listener", &srv);
658 if (rc != EOK)
659 goto error;
660
661 taskid = task_get_id();
662
663 rv = asprintf(&svcname, "tbarcfg/%u", (unsigned)taskid);
664 if (rv < 0) {
665 rc = ENOMEM;
666 goto error;
667 }
668
[ca48672]669 rc = loc_service_register(srv, svcname, port, &svcid);
[ee3b28a9]670 if (rc != EOK)
671 goto error;
672
[5caad1d]673 free(svcname);
674 svcname = NULL;
675
[ee3b28a9]676 rc = loc_category_get_id(nchan, &catid, 0);
677 if (rc != EOK)
678 goto error;
679
680 rc = loc_service_add_to_cat(srv, svcid, catid);
681 if (rc != EOK)
682 goto error;
683
[5caad1d]684 lst->portid = port;
685 lst->srv = srv;
686 lst->svcid = svcid;
[ee3b28a9]687 *rlst = lst;
688 return EOK;
689error:
690 if (svcid != 0)
691 loc_service_unregister(srv, svcid);
692 if (srv != NULL)
693 loc_server_unregister(srv);
694 if (svcname != NULL)
695 free(svcname);
[ca48672]696 if (port != 0)
697 async_port_destroy(port);
[ee3b28a9]698 return rc;
699}
700
701/** Destroy taskbar configuration listener.
702 *
703 * @param lst Listener
704 */
705void tbarcfg_listener_destroy(tbarcfg_listener_t *lst)
706{
[5caad1d]707 loc_service_unregister(lst->srv, lst->svcid);
708 loc_server_unregister(lst->srv);
709 async_port_destroy(lst->portid);
[ee3b28a9]710 free(lst);
711}
712
713/** Send taskbar configuration notification to a particular service ID.
714 *
715 * @param svcid Service ID
716 * @return EOK on success or an error code
717 */
718static errno_t tbarcfg_notify_svc(service_id_t svcid)
719{
720 async_sess_t *sess;
721 async_exch_t *exch;
722 errno_t rc;
723
724 sess = loc_service_connect(svcid, INTERFACE_TBARCFG_NOTIFY, 0);
725 if (sess == NULL)
726 return EIO;
727
728 exch = async_exchange_begin(sess);
729 rc = async_req_0_0(exch, TBARCFG_NOTIFY_NOTIFY);
730 if (rc != EOK) {
731 async_exchange_end(exch);
732 async_hangup(sess);
733 return rc;
734 }
735
736 async_exchange_end(exch);
737 async_hangup(sess);
738 return EOK;
739}
740
741/** Send taskbar configuration change notification.
742 *
743 * @param nchan Notification channel (TBARCFG_NOTIFY_DEFAULT)
744 */
745errno_t tbarcfg_notify(const char *nchan)
746{
747 errno_t rc;
748 category_id_t catid;
749 service_id_t *svcs = NULL;
750 size_t count, i;
751
752 rc = loc_category_get_id(nchan, &catid, 0);
753 if (rc != EOK)
754 return rc;
755
756 rc = loc_category_get_svcs(catid, &svcs, &count);
757 if (rc != EOK)
758 return rc;
759
760 for (i = 0; i < count; i++) {
761 rc = tbarcfg_notify_svc(svcs[i]);
762 if (rc != EOK)
763 goto error;
764 }
765
766 free(svcs);
767 return EOK;
768error:
769 free(svcs);
770 return rc;
771}
772
773/** Taskbar configuration connection handler.
774 *
775 * @param icall Initial call
776 * @param arg Argument (tbarcfg_listener_t *)
777 */
778static void tbarcfg_notify_conn(ipc_call_t *icall, void *arg)
779{
780 tbarcfg_listener_t *lst = (tbarcfg_listener_t *)arg;
781
782 /* Accept the connection */
783 async_accept_0(icall);
784
785 while (true) {
786 ipc_call_t call;
787 async_get_call(&call);
788 sysarg_t method = ipc_get_imethod(&call);
789
790 if (!method) {
791 /* The other side has hung up */
792 async_answer_0(&call, EOK);
793 return;
794 }
795
796 switch (method) {
797 case TBARCFG_NOTIFY_NOTIFY:
798 lst->cb(lst->arg);
799 async_answer_0(&call, EOK);
800 break;
801 default:
802 async_answer_0(&call, EINVAL);
803 }
804 }
805}
806
[7d78e466]807/** @}
808 */
Note: See TracBrowser for help on using the repository browser.