aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/appmenu/e_mod_dbus_registrar_server.c
blob: bc2b5b1a401d8a6eeca68c72787e8affecda3417 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "e_mod_appmenu_private.h"

#define REGISTRAR_BUS "com.canonical.AppMenu.Registrar"
#define REGISTRAR_PATH "/com/canonical/AppMenu/Registrar"
#define REGISTRAR_IFACE "com.canonical.AppMenu.Registrar"

#define ERROR_WINDOW_NOT_FOUND "com.canonical.AppMenu.Registrar.WindowNotFound"

void
appmenu_application_monitor(void *data, const char *bus EINA_UNUSED, const char *old __UNUSED__, const char *new __UNUSED__)
{
   E_AppMenu_Window *window = data;
   edbus_service_signal_emit(window->ctxt->iface, 1, window->window_id);
   appmenu_window_free(window);
}

static void
menu_update_cb(void *data, E_DBusMenu_Item *item)
{
   E_AppMenu_Window *window = data;
   window->root_item = item;
   if (!item)
     return;
   if (window->window_id == window->ctxt->window_with_focus)
     appmenu_menu_render(window->ctxt, window);
}

static void
menu_pop_cb(void *data EINA_UNUSED, const E_DBusMenu_Item *new_root_item EINA_UNUSED)
{
   //TODO
}

static EDBus_Message *
_on_register_window(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
{
   EDBus_Connection *conn = edbus_service_connection_get(iface);
   E_AppMenu_Context *ctxt = edbus_service_object_data_get(iface, "ctxt");
   unsigned window_id;
   const char *path, *bus_id;
   E_AppMenu_Window *window;

   if (!edbus_message_arguments_get(msg, "uo", &window_id, &path))
     {
        ERR("Error reading message");
        return NULL;
     }

   window = calloc(1, sizeof(E_AppMenu_Window));
   EINA_SAFETY_ON_NULL_RETURN_VAL(window, NULL);


   bus_id = edbus_message_sender_get(msg);

   window->window_id = window_id;
   window->dbus_menu = e_dbusmenu_load(conn, bus_id, path, window);
   e_dbusmenu_update_cb_set(window->dbus_menu, menu_update_cb);
   e_dbusmenu_pop_request_cb_set(window->dbus_menu, menu_pop_cb);
   window->bus_id = eina_stringshare_add(bus_id);
   window->path = eina_stringshare_add(path);

   edbus_name_owner_changed_callback_add(conn, bus_id, appmenu_application_monitor,
                                         window, EINA_FALSE);
   ctxt->windows = eina_list_append(ctxt->windows, window);
   window->ctxt = ctxt;

   edbus_service_signal_emit(iface, 0, window_id, bus_id, path);
   return edbus_message_method_return_new(msg);
}

static E_AppMenu_Window *
window_find(E_AppMenu_Context *ctxt, unsigned window_id)
{
   Eina_List *l;
   E_AppMenu_Window *w;
   EINA_LIST_FOREACH(ctxt->windows, l, w)
     {
        if (w->window_id == window_id)
          return w;
     }
   return NULL;
}

static EDBus_Message *
_on_unregister_window(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
{
   E_AppMenu_Context *ctxt = edbus_service_object_data_get(iface, "ctxt");
   E_AppMenu_Window *w;
   unsigned window_id;

   if (!edbus_message_arguments_get(msg, "u", &window_id))
     {
        ERR("Error reading message.");
        return NULL;
     }

   w = window_find(ctxt, window_id);
   if (w)
     appmenu_window_free(w);
   edbus_service_signal_emit(iface, 1, window_id);
   return edbus_message_method_return_new(msg);
}

static EDBus_Message *
_on_getmenu(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
{
   unsigned window_id;
   Eina_List *l;
   E_AppMenu_Window *w;
   E_AppMenu_Context *ctxt = edbus_service_object_data_get(iface, "ctxt");

   if (!edbus_message_arguments_get(msg, "u", &window_id))
     {
        ERR("Error reading message");
        return NULL;
     }
   EINA_LIST_FOREACH(ctxt->windows, l, w)
     {
        if (w->window_id == window_id)
          {
             EDBus_Message *reply;
             reply = edbus_message_method_return_new(msg);
             edbus_message_arguments_append(reply, "so", w->bus_id, w->path);
             return reply;
          }
     }
   return edbus_message_error_new(msg, ERROR_WINDOW_NOT_FOUND, "");
}

static EDBus_Message *
_on_getmenus(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
{
   Eina_List *l;
   E_AppMenu_Window *w;
   E_AppMenu_Context *ctxt = edbus_service_object_data_get(iface, "ctxt");
   EDBus_Message *reply;
   EDBus_Message_Iter *array, *main_iter;

   reply = edbus_message_method_return_new(msg);
   main_iter = edbus_message_iter_get(reply);
   edbus_message_iter_arguments_append(main_iter, "a(uso)", &array);

   EINA_LIST_FOREACH(ctxt->windows, l, w)
     {
        EDBus_Message_Iter *entry;
        edbus_message_iter_arguments_append(array, "(uso)", &entry);
        edbus_message_iter_arguments_append(entry, "uso", w->window_id,
                                            w->bus_id, w->path);
        edbus_message_iter_container_close(array, entry);
     }

   edbus_message_iter_container_close(main_iter, array);
   return reply;
}

static const EDBus_Method registrar_methods[] = {
   {
      "RegisterWindow", EDBUS_ARGS({"u", "windowId"},{"o", "menuObjectPath"}),
      NULL, _on_register_window, 0
   },
   {
      "UnregisterWindow", EDBUS_ARGS({"u", "windowId"}),
      NULL, _on_unregister_window, 0
   },
   {
     "GetMenuForWindow", EDBUS_ARGS({"u", "windowId"}),
     EDBUS_ARGS({"s", "bus_id"},{"o", "menu_path"}), _on_getmenu, 0
   },
   {
    "GetMenus", NULL, EDBUS_ARGS({"a(uso)", "array_of_menu"}), _on_getmenus, 0
   },
   { NULL, NULL, NULL, NULL, 0 }
};

static const EDBus_Signal registrar_signals[] = {
   { "WindowRegistered", EDBUS_ARGS({"u", "windowId"}, {"s", "bus_id"}, {"o", "menu_path"}), 0 },
   { "WindowUnregistered", EDBUS_ARGS({"u", "windowId"}), 0 },
   { NULL, NULL, 0 }
};

static const EDBus_Service_Interface_Desc registrar_iface = {
   REGISTRAR_IFACE, registrar_methods, registrar_signals, NULL, NULL, NULL
};

void
appmenu_dbus_registrar_server_init(E_AppMenu_Context *ctx)
{
   ctx->iface = edbus_service_interface_register(ctx->conn,
                                                 REGISTRAR_PATH,
                                                 &registrar_iface);
   edbus_service_object_data_set(ctx->iface, "ctxt", ctx);
   edbus_name_request(ctx->conn, REGISTRAR_BUS,
                      EDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING, NULL, NULL);
}