~jbicha/hud/build-depend-on-valac-not-gir

« back to all changes in this revision

Viewing changes to service/hud-dbus.c

Merging the HUD into indicator-appmenu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
DBus facing code for the HUD
 
3
 
 
4
Copyright 2011 Canonical Ltd.
 
5
 
 
6
Authors:
 
7
    Ted Gould <ted@canonical.com>
 
8
 
 
9
This program is free software: you can redistribute it and/or modify it 
 
10
under the terms of the GNU General Public License version 3, as published 
 
11
by the Free Software Foundation.
 
12
 
 
13
This program is distributed in the hope that it will be useful, but 
 
14
WITHOUT ANY WARRANTY; without even the implied warranties of 
 
15
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
 
16
PURPOSE.  See the GNU General Public License for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License along 
 
19
with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include "config.h"
 
24
#endif
 
25
 
 
26
#include <gio/gio.h>
 
27
#include <gio/gdesktopappinfo.h>
 
28
 
 
29
#include "shared-values.h"
 
30
#include "hud.interface.h"
 
31
#include "hud-dbus.h"
 
32
#include "hud-search.h"
 
33
 
 
34
struct _HudDbusPrivate {
 
35
        GDBusConnection * bus;
 
36
        GCancellable * bus_lookup;
 
37
        guint bus_registration;
 
38
        HudSearch * search;
 
39
};
 
40
 
 
41
#define HUD_DBUS_GET_PRIVATE(o) \
 
42
(G_TYPE_INSTANCE_GET_PRIVATE ((o), HUD_DBUS_TYPE, HudDbusPrivate))
 
43
 
 
44
static void hud_dbus_class_init (HudDbusClass *klass);
 
45
static void hud_dbus_init       (HudDbus *self);
 
46
static void hud_dbus_dispose    (GObject *object);
 
47
static void hud_dbus_finalize   (GObject *object);
 
48
 
 
49
static void bus_got_cb          (GObject *object, GAsyncResult * res, gpointer user_data);
 
50
static void bus_method          (GDBusConnection *connection,
 
51
                                 const gchar *sender,
 
52
                                 const gchar *object_path,
 
53
                                 const gchar *interface_name,
 
54
                                 const gchar *method_name,
 
55
                                 GVariant *parameters,
 
56
                                 GDBusMethodInvocation *invocation,
 
57
                                 gpointer user_data);
 
58
static GVariant * get_suggestions (HudDbus * self, const gchar * query);
 
59
static void execute_query (HudDbus * self, GVariant * key, guint timestamp);
 
60
 
 
61
 
 
62
G_DEFINE_TYPE (HudDbus, hud_dbus, G_TYPE_OBJECT);
 
63
static GDBusNodeInfo * node_info = NULL;
 
64
static GDBusInterfaceInfo * iface_info = NULL;
 
65
static GDBusInterfaceVTable bus_vtable = {
 
66
        method_call: bus_method,
 
67
        get_property: NULL,
 
68
        set_property: NULL,
 
69
};
 
70
 
 
71
static void
 
72
hud_dbus_class_init (HudDbusClass *klass)
 
73
{
 
74
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
75
 
 
76
        g_type_class_add_private (klass, sizeof (HudDbusPrivate));
 
77
 
 
78
        object_class->dispose = hud_dbus_dispose;
 
79
        object_class->finalize = hud_dbus_finalize;
 
80
 
 
81
        if (node_info == NULL) {
 
82
                GError * error = NULL;
 
83
 
 
84
                node_info = g_dbus_node_info_new_for_xml(hud_interface, &error);
 
85
                if (error != NULL) {
 
86
                        g_error("Unable to parse HUD interface: %s", error->message);
 
87
                        g_error_free(error);
 
88
                }
 
89
        }
 
90
 
 
91
        if (node_info != NULL && iface_info == NULL) {
 
92
                iface_info = g_dbus_node_info_lookup_interface(node_info, DBUS_IFACE);
 
93
                if (iface_info == NULL) {
 
94
                        g_error("Unable to find interface '" DBUS_IFACE "'");
 
95
                }
 
96
        }
 
97
 
 
98
        return;
 
99
}
 
100
 
 
101
static void
 
102
hud_dbus_init (HudDbus *self)
 
103
{
 
104
        self->priv = HUD_DBUS_GET_PRIVATE(self);
 
105
 
 
106
        self->priv->bus = NULL;
 
107
        self->priv->bus_lookup = NULL;
 
108
        self->priv->bus_registration = 0;
 
109
        self->priv->search = NULL;
 
110
 
 
111
        self->priv->bus_lookup = g_cancellable_new();
 
112
        g_bus_get(G_BUS_TYPE_SESSION, self->priv->bus_lookup, bus_got_cb, self);
 
113
 
 
114
        self->priv->search = hud_search_new();
 
115
 
 
116
        return;
 
117
}
 
118
 
 
119
static void
 
120
hud_dbus_dispose (GObject *object)
 
121
{
 
122
        HudDbus * self = HUD_DBUS(object);
 
123
        g_return_if_fail(self != NULL);
 
124
 
 
125
        if (self->priv->bus_lookup != NULL) {
 
126
                g_cancellable_cancel(self->priv->bus_lookup);
 
127
                g_object_unref(self->priv->bus_lookup);
 
128
                self->priv->bus_lookup = NULL;
 
129
        }
 
130
 
 
131
        if (self->priv->bus_registration != 0) {
 
132
                g_dbus_connection_unregister_object(self->priv->bus, self->priv->bus_registration);
 
133
                self->priv->bus_registration = 0;
 
134
        }
 
135
 
 
136
        if (self->priv->bus != NULL) {
 
137
                g_object_unref(self->priv->bus);
 
138
                self->priv->bus = NULL;
 
139
        }
 
140
 
 
141
        if (self->priv->search != NULL) {
 
142
                g_object_unref(self->priv->search);
 
143
                self->priv->search = NULL;
 
144
        }
 
145
 
 
146
        G_OBJECT_CLASS (hud_dbus_parent_class)->dispose (object);
 
147
        return;
 
148
}
 
149
 
 
150
static void
 
151
hud_dbus_finalize (GObject *object)
 
152
{
 
153
 
 
154
        G_OBJECT_CLASS (hud_dbus_parent_class)->finalize (object);
 
155
        return;
 
156
}
 
157
 
 
158
HudDbus *
 
159
hud_dbus_new (void)
 
160
{
 
161
        return g_object_new(HUD_DBUS_TYPE, NULL);
 
162
}
 
163
 
 
164
static void
 
165
bus_got_cb (GObject *object, GAsyncResult * res, gpointer user_data)
 
166
{
 
167
        GError * error = NULL;
 
168
        HudDbus * self = HUD_DBUS(user_data);
 
169
        GDBusConnection * bus;
 
170
 
 
171
        bus = g_bus_get_finish(res, &error);
 
172
        if (error != NULL) {
 
173
                g_critical("Unable to get bus: %s", error->message);
 
174
                g_error_free(error);
 
175
                return;
 
176
        }
 
177
 
 
178
        self->priv->bus = bus;
 
179
 
 
180
        /* Register object */
 
181
        self->priv->bus_registration = g_dbus_connection_register_object(bus,
 
182
                                                        /* path */       DBUS_PATH,
 
183
                                                        /* interface */  iface_info,
 
184
                                                        /* vtable */     &bus_vtable,
 
185
                                                        /* userdata */   self,
 
186
                                                        /* destroy */    NULL,
 
187
                                                        /* error */      &error);
 
188
 
 
189
        return;
 
190
}
 
191
 
 
192
static void
 
193
bus_method (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
 
194
{
 
195
        HudDbus * self = HUD_DBUS(user_data);
 
196
 
 
197
        if (g_strcmp0(method_name, "GetSuggestions") == 0) {
 
198
                GVariant * ret = NULL;
 
199
                gchar * query = NULL;
 
200
 
 
201
                g_variant_get(parameters, "(s)", &query);
 
202
 
 
203
                ret = get_suggestions(self, query);
 
204
 
 
205
                g_dbus_method_invocation_return_value(invocation, ret);
 
206
                g_free(query);
 
207
        } else if (g_strcmp0(method_name, "ExecuteQuery") == 0) {
 
208
                GVariant * key = NULL;
 
209
                guint timestamp = 0;
 
210
 
 
211
                key = g_variant_get_child_value(parameters, 0);
 
212
                g_variant_get_child(parameters, 1, "u", &timestamp);
 
213
 
 
214
                execute_query(self, key, timestamp);
 
215
                
 
216
                g_dbus_method_invocation_return_value(invocation, NULL);
 
217
                g_variant_unref(key);
 
218
        }
 
219
 
 
220
        return;
 
221
}
 
222
 
 
223
/* Take a path to a desktop file and find its icon */
 
224
static gchar *
 
225
desktop2icon (gchar * desktop)
 
226
{
 
227
        g_return_val_if_fail(desktop != NULL, g_strdup(""));
 
228
 
 
229
        if (!g_file_test(desktop, G_FILE_TEST_EXISTS)) {
 
230
                return g_strdup("");
 
231
        }
 
232
 
 
233
        /* Try to build an app info from the desktop file
 
234
           path */
 
235
        GDesktopAppInfo * appinfo = g_desktop_app_info_new_from_filename(desktop);
 
236
 
 
237
        if (!G_IS_DESKTOP_APP_INFO(appinfo)) {
 
238
                return g_strdup("");
 
239
        }
 
240
 
 
241
        /* Get the name out of the icon, note the icon is not
 
242
           ref'd so it doesn't need to be free'd */
 
243
        gchar * retval = NULL;
 
244
        GIcon * icon = g_app_info_get_icon(G_APP_INFO(appinfo));
 
245
        if (icon != NULL) {
 
246
                retval = g_icon_to_string(icon);
 
247
        } else {
 
248
                retval = g_strdup("");
 
249
        }
 
250
 
 
251
        /* Drop the app info */
 
252
        g_object_unref(appinfo);
 
253
        appinfo = NULL;
 
254
 
 
255
        return retval;
 
256
}
 
257
 
 
258
/* Respond to the GetSuggestions command from DBus by looking
 
259
   in our HUD search object for suggestions from that query */
 
260
static GVariant *
 
261
get_suggestions (HudDbus * self, const gchar * query)
 
262
{
 
263
        /* Do the search */
 
264
        gchar * desktop = NULL;
 
265
        gchar * target = NULL;
 
266
        GList * suggestions = hud_search_suggestions(self->priv->search, query, &desktop, &target);
 
267
 
 
268
        gchar * icon = NULL;
 
269
        icon = desktop2icon(desktop);
 
270
 
 
271
        /* Build into into a variant */
 
272
        GVariantBuilder ret;
 
273
        g_variant_builder_init(&ret, G_VARIANT_TYPE_TUPLE);
 
274
        g_variant_builder_add_value(&ret, g_variant_new_string(icon));
 
275
        g_variant_builder_add_value(&ret, g_variant_new_string(target));
 
276
 
 
277
        /* Free the strings */
 
278
        g_free(icon);
 
279
        g_free(target);
 
280
        g_free(desktop);
 
281
 
 
282
        if (suggestions != NULL) {
 
283
                GList * suggestion = suggestions;
 
284
                GVariantBuilder builder;
 
285
                g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
 
286
 
 
287
                while (suggestion != NULL) {
 
288
                        HudSearchSuggest * suggest = (HudSearchSuggest *)suggestion->data;
 
289
 
 
290
                        GVariantBuilder tuple;
 
291
                        g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
 
292
                        g_variant_builder_add_value(&tuple, g_variant_new_string(hud_search_suggest_get_display(suggest)));
 
293
                        g_variant_builder_add_value(&tuple, g_variant_new_string(hud_search_suggest_get_icon(suggest)));
 
294
                        g_variant_builder_add_value(&tuple, hud_search_suggest_get_key(suggest));
 
295
 
 
296
                        g_variant_builder_add_value(&builder, g_variant_builder_end(&tuple));
 
297
 
 
298
                        suggestion = g_list_next(suggestion);
 
299
                }
 
300
 
 
301
                g_variant_builder_add_value(&ret, g_variant_builder_end(&builder));
 
302
        } else {
 
303
                /* If we didn't get any suggestions we need to build
 
304
                   a null array to make the DBus interface happy */
 
305
                g_variant_builder_add_value(&ret, g_variant_new_array(G_VARIANT_TYPE("(ssv)"), NULL, 0));
 
306
        }
 
307
 
 
308
        /* Clean up the list */
 
309
        g_list_free_full(suggestions, (GDestroyNotify)hud_search_suggest_free);
 
310
 
 
311
        return g_variant_builder_end(&ret);
 
312
}
 
313
 
 
314
static void
 
315
execute_query (HudDbus * self, GVariant * key, guint timestamp)
 
316
{
 
317
        hud_search_execute(self->priv->search, key, timestamp);
 
318
        return;
 
319
}