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

Last change on this file since a3ba37d was ee3b28a9, checked in by Jiri Svoboda <jiri@…>, 18 months ago

Notify taskbar when start menu changes

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