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

« back to all changes in this revision

Viewing changes to src/hudquery.c

  • Committer: Tarmac
  • Author(s): Ted Gould, Pete Woods, Antti Kaijanmäki, Ted Gould, Albert Astals, Ryan Lortie, Łukasz 'sil2100' Zemczak, Albert Astals Cid, Mathieu Trudel-Lapierre, Kaleo, Tarmac, Ricardo Salveti de Araujo, Michael Terry, Automatic PS uploader
  • Date: 2013-04-10 16:04:51 UTC
  • mfrom: (227.3.148 phablet)
  • Revision ID: tarmac-20130410160451-o3owpv3zaxulm5of
HUD 2.0 Merge.

Approved by PS Jenkins bot, Mathieu Trudel-Lapierre.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#define G_LOG_DOMAIN "hudquery"
20
20
 
 
21
#include <dee.h>
 
22
 
21
23
#include "hudquery.h"
22
 
 
 
24
#include "hud-query-iface.h"
 
25
#include "hudsourcelist.h"
23
26
#include "hudresult.h"
 
27
#include "hudmenumodelcollector.h"
 
28
#include "huddbusmenucollector.h"
 
29
#include "hudvoice.h"
 
30
#include "application-source.h"
 
31
#include "application-list.h"
 
32
#include "query-columns.h"
 
33
#include "watchdog.h"
24
34
 
25
35
/**
26
36
 * SECTION:hudquery
49
59
{
50
60
  GObject parent_instance;
51
61
 
52
 
  HudSource *source;
 
62
  HudWatchdog * watchdog;
 
63
  HudSource *all_sources;
 
64
  HudApplicationList *app_list;
 
65
  HudSource *current_source;
 
66
  HudSource *last_used_source;
53
67
  gchar *search_string;
54
68
  HudTokenList *token_list;
55
69
  gint num_results;
56
70
  guint refresh_id;
57
71
 
58
 
  GPtrArray *results;
 
72
  guint querynumber; /* Incrementing count, which one were we? */
 
73
  HudQueryIfaceComCanonicalHudQuery * skel;
 
74
  gchar * object_path;
 
75
 
 
76
  DeeModel * results_model;
 
77
  gchar * results_name;
 
78
  DeeModelTag * results_tag;
 
79
 
 
80
  DeeModel * appstack_model;
 
81
  gchar * appstack_name;
 
82
 
 
83
  GSequence * results_list; /* Should almost always be NULL except when refreshing the query */
 
84
  guint max_usage; /* Used to make the GList search easier */
 
85
 
 
86
  HudVoice *voice;
59
87
};
60
88
 
61
89
typedef GObjectClass HudQueryClass;
62
90
 
63
91
G_DEFINE_TYPE (HudQuery, hud_query, G_TYPE_OBJECT)
 
92
 
64
93
static guint hud_query_changed_signal;
65
94
 
66
 
static HudQuery *last_created_query;
67
 
 
68
 
static void
69
 
hud_query_find_max_usage (gpointer data,
70
 
                          gpointer user_data)
71
 
{
72
 
  guint *max_usage = user_data;
73
 
  HudResult *result = data;
74
 
  HudItem *item;
75
 
  guint usage;
76
 
 
77
 
  item = hud_result_get_item (result);
78
 
  usage = hud_item_get_usage (item);
79
 
 
80
 
  *max_usage = MAX (*max_usage, usage);
81
 
}
82
 
 
83
 
static gint
84
 
hud_query_compare_results (gconstpointer a,
85
 
                           gconstpointer b,
86
 
                           gpointer      user_data)
87
 
{
88
 
  HudResult *result_a = *(HudResult * const *) a;
89
 
  HudResult *result_b = *(HudResult * const *) b;
90
 
  gint max_usage = GPOINTER_TO_INT (user_data);
91
 
  guint distance_a;
92
 
  guint distance_b;
93
 
 
94
 
  distance_a = hud_result_get_distance (result_a, max_usage);
95
 
  distance_b = hud_result_get_distance (result_b, max_usage);
96
 
 
97
 
  return distance_a - distance_b;
 
95
/* Schema that is used in the DeeModel representing
 
96
   the results */
 
97
static const gchar * results_model_schema[HUD_QUERY_RESULTS_COUNT] = {
 
98
        "v", /* Command ID */
 
99
        "s", /* Command Name */
 
100
        "a(ii)", /* Highlights in command name */
 
101
        "s", /* Description */
 
102
        "a(ii)", /* Highlights in description */
 
103
        "s", /* Shortcut */
 
104
        "u", /* Distance */
 
105
        "b", /* Parameterized */
 
106
};
 
107
 
 
108
/* Schema that is used in the DeeModel representing
 
109
   the appstack */
 
110
static const gchar * appstack_model_schema[HUD_QUERY_APPSTACK_COUNT] = {
 
111
        "s", /* Application ID */
 
112
        "s", /* Icon Name */
 
113
        "i", /* Item Type */
 
114
};
 
115
 
 
116
static gint
 
117
compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
 
118
{
 
119
  gint max_usage = ((HudQuery *) user_data)->max_usage;
 
120
  return hud_result_get_distance ((HudResult *) a, max_usage)
 
121
      - hud_result_get_distance ((HudResult *) b, max_usage);
 
122
}
 
123
 
 
124
/* Add a HudResult to the list of results. This is inserted at the
 
125
   end for the moment, until action sort priorities are implemented.
 
126
   We can't sort until we have the max usage, then we can sort
 
127
   everything depending on distance and usage.  */
 
128
static void
 
129
results_list_populate (HudResult * result, gpointer user_data)
 
130
{
 
131
        HudQuery * query = (HudQuery *)user_data;
 
132
        // TODO: Change back to prepend after we have action sort priorities
 
133
        // g_sequence_insert_before(g_sequence_get_begin_iter(query->results_list), result);
 
134
        g_sequence_append(query->results_list, result);
 
135
        return;
 
136
}
 
137
 
 
138
/* A structure to track the items in the appstack */
 
139
typedef struct _appstack_item_t appstack_item_t;
 
140
struct _appstack_item_t {
 
141
        gchar * app_id;
 
142
        gchar * app_icon;
 
143
        HudSourceItemType type;
 
144
};
 
145
 
 
146
/* Free all of them items */
 
147
static void
 
148
appstack_item_free (gpointer user_data)
 
149
{
 
150
        appstack_item_t * item = (appstack_item_t *)user_data;
 
151
 
 
152
        g_free(item->app_id);
 
153
        g_free(item->app_icon);
 
154
 
 
155
        g_free(item);
 
156
        return;
 
157
}
 
158
 
 
159
/* Sort function for the appstack */
 
160
static gint
 
161
appstack_sort (GVariant ** row1, GVariant ** row2, gpointer user_data)
 
162
{
 
163
        gint32 type1 = g_variant_get_int32(row1[HUD_QUERY_APPSTACK_ITEM_TYPE]);
 
164
        gint32 type2 = g_variant_get_int32(row2[HUD_QUERY_APPSTACK_ITEM_TYPE]);
 
165
 
 
166
        /* If the types are the same, we'll alphabetize by ID */
 
167
        if (type1 == type2) {
 
168
                const gchar * app_id1 = g_variant_get_string(row1[HUD_QUERY_APPSTACK_APPLICATION_ID], NULL);
 
169
                const gchar * app_id2 = g_variant_get_string(row2[HUD_QUERY_APPSTACK_APPLICATION_ID], NULL);
 
170
 
 
171
                return g_strcmp0(app_id1, app_id2);
 
172
        }
 
173
 
 
174
        return type1 - type2;
 
175
}
 
176
 
 
177
/* Takes the hash and puts it into the Dee Model */
 
178
static void
 
179
appstack_hash_to_model (GHashTable * hash, DeeModel * model)
 
180
{
 
181
        GList * values = g_hash_table_get_values(hash);
 
182
        GList * value;
 
183
 
 
184
        for (value = values; value != NULL; value = g_list_next(value)) {
 
185
                appstack_item_t * item = (appstack_item_t *)value->data;
 
186
 
 
187
                GVariant * columns[HUD_QUERY_APPSTACK_COUNT + 1];
 
188
                columns[HUD_QUERY_APPSTACK_APPLICATION_ID] = g_variant_new_string(item->app_id ? item->app_id : "");
 
189
                columns[HUD_QUERY_APPSTACK_ICON_NAME]      = g_variant_new_string(item->app_icon ? item->app_icon : "");
 
190
                columns[HUD_QUERY_APPSTACK_ITEM_TYPE]      = g_variant_new_int32(item->type);
 
191
                columns[HUD_QUERY_APPSTACK_COUNT]          = NULL;
 
192
 
 
193
                dee_model_insert_row_sorted(model, columns, appstack_sort, NULL);
 
194
        }
 
195
 
 
196
        return;
 
197
}
 
198
 
 
199
/* Add an item to the hash table */
 
200
static void
 
201
appstack_hash_add_source (GHashTable * table, HudSource * source, HudSourceItemType in_type)
 
202
{
 
203
        if (source == NULL) {
 
204
                return;
 
205
        }
 
206
 
 
207
        const gchar * id = hud_source_get_app_id(source);;
 
208
        g_return_if_fail(id != NULL);
 
209
 
 
210
        const gchar * icon = hud_source_get_app_icon(source);;
 
211
        HudSourceItemType type = in_type;
 
212
 
 
213
        if (HUD_IS_MENU_MODEL_COLLECTOR(source) || HUD_IS_DBUSMENU_COLLECTOR(source)) {
 
214
                type = HUD_SOURCE_ITEM_TYPE_INDICATOR;
 
215
        }
 
216
 
 
217
        appstack_item_t * item = g_new0(appstack_item_t, 1);
 
218
        item->app_id = g_strdup(id);
 
219
        item->app_icon = g_strdup(icon);
 
220
        item->type = type;
 
221
 
 
222
        g_hash_table_insert(table, g_strdup(id), item);
 
223
 
 
224
        return;
 
225
}
 
226
 
 
227
/* Add a HudItem to the list of app results */
 
228
static void
 
229
app_results_list_populate (const gchar *application_id, const gchar *application_icon, HudSourceItemType type, gpointer user_data)
 
230
{
 
231
        g_return_if_fail(application_id != NULL);
 
232
 
 
233
        GHashTable * table = (GHashTable *)user_data;
 
234
 
 
235
        appstack_item_t * item = g_new0(appstack_item_t, 1);
 
236
        item->app_id = g_strdup(application_id);
 
237
        item->app_icon = g_strdup(application_icon);
 
238
        item->type = type;
 
239
 
 
240
        g_hash_table_insert(table, g_strdup(application_id), item);
 
241
 
 
242
        return;
 
243
}
 
244
 
 
245
/* Go through the list and find the item with the highest usage
 
246
   that the others will be compared against */
 
247
static void
 
248
results_list_max_usage (gpointer data, gpointer user_data)
 
249
{
 
250
        HudResult * result = (HudResult *)data;
 
251
        HudItem * item = hud_result_get_item(result);
 
252
        guint * max_usage = (guint *)user_data;
 
253
 
 
254
        *max_usage = MAX(*max_usage, hud_item_get_usage(item));
 
255
        return;
 
256
}
 
257
 
 
258
/* Turn the results list into a DeeModel. It assumes the results are already sorted. */
 
259
static void
 
260
results_list_to_model (gpointer data, gpointer user_data)
 
261
{
 
262
        HudResult * result = (HudResult *)data;
 
263
        HudQuery * query = (HudQuery *)user_data;
 
264
        HudItem * item = hud_result_get_item(result);
 
265
 
 
266
        GVariant * columns[HUD_QUERY_RESULTS_COUNT + 1];
 
267
        columns[HUD_QUERY_RESULTS_COMMAND_ID]             = g_variant_new_variant(g_variant_new_uint64(hud_item_get_id(item)));
 
268
        columns[HUD_QUERY_RESULTS_COMMAND_NAME]           = g_variant_new_string(hud_item_get_command(item));
 
269
        columns[HUD_QUERY_RESULTS_COMMAND_HIGHLIGHTS]     = g_variant_new_array(G_VARIANT_TYPE("(ii)"), NULL, 0);
 
270
        columns[HUD_QUERY_RESULTS_DESCRIPTION]            = g_variant_new_string(hud_item_get_description(item));
 
271
        columns[HUD_QUERY_RESULTS_DESCRIPTION_HIGHLIGHTS] = g_variant_new_array(G_VARIANT_TYPE("(ii)"), NULL, 0);
 
272
        columns[HUD_QUERY_RESULTS_SHORTCUT]               = g_variant_new_string(hud_item_get_shortcut(item));
 
273
        columns[HUD_QUERY_RESULTS_DISTANCE]               = g_variant_new_uint32(hud_result_get_distance(result, query->max_usage));
 
274
        columns[HUD_QUERY_RESULTS_PARAMETERIZED]          = g_variant_new_boolean(HUD_IS_MODEL_ITEM(item) ? hud_model_item_is_parameterized(HUD_MODEL_ITEM(item)) : FALSE);
 
275
        columns[HUD_QUERY_RESULTS_COUNT] = NULL;
 
276
 
 
277
        DeeModelIter * iter = dee_model_append_row(query->results_model,
 
278
                                                          columns /* variants */);
 
279
 
 
280
        dee_model_set_tag(query->results_model, iter, query->results_tag, result);
 
281
 
 
282
        return;
98
283
}
99
284
 
100
285
static void
101
286
hud_query_refresh (HudQuery *query)
102
287
{
103
 
  guint max_usage = 0;
104
288
  guint64 start_time;
105
289
 
 
290
  hud_watchdog_ping(query->watchdog);
106
291
  start_time = g_get_monotonic_time ();
107
292
 
108
 
  g_ptr_array_set_size (query->results, 0);
109
 
 
110
 
  if (hud_token_list_get_length (query->token_list) != 0)
111
 
    hud_source_search (query->source, query->results, query->token_list);
112
 
 
113
 
  g_ptr_array_foreach (query->results, hud_query_find_max_usage, &max_usage);
114
 
  g_ptr_array_sort_with_data (query->results, hud_query_compare_results, GINT_TO_POINTER (max_usage));
115
 
  if (query->results->len > query->num_results)
116
 
    g_ptr_array_set_size (query->results, query->num_results);
 
293
  dee_model_clear(query->results_model);
 
294
  query->results_list = g_sequence_new(NULL);
 
295
  query->max_usage = 0;
 
296
 
 
297
  /* Note that the results are kept sorted as they are collected using a GSequence */
 
298
  HudSource * search_source = query->current_source;
 
299
  if (search_source == NULL) {
 
300
    search_source = hud_application_list_get_focused_app(query->app_list);
 
301
  }
 
302
 
 
303
  /* Make sure we've used it before searching it */
 
304
  if (search_source != NULL && search_source != query->last_used_source) {
 
305
    if (query->last_used_source != NULL)
 
306
    {
 
307
      hud_source_unuse(query->last_used_source);
 
308
      g_clear_object(&query->last_used_source);
 
309
    }
 
310
        hud_source_use(search_source);
 
311
        query->last_used_source = g_object_ref(search_source);
 
312
  }
 
313
 
 
314
  if (search_source != NULL) {
 
315
    hud_source_search (search_source, query->token_list, results_list_populate, query);
 
316
  } else {
 
317
    g_debug("Current source was null. This should usually not happen outside tests in regular user use");
 
318
  }
 
319
  g_debug("Num results: %d", g_sequence_get_length(query->results_list));
 
320
 
 
321
  g_sequence_foreach(query->results_list, results_list_max_usage, &query->max_usage);
 
322
  g_debug("Max Usage: %d", query->max_usage);
 
323
 
 
324
  /* Now that we have the max usage we can sort */
 
325
  g_sequence_sort(query->results_list, compare_func, query);
 
326
  g_sequence_foreach(query->results_list, results_list_to_model, query);
 
327
 
 
328
  /* NOTE: Not freeing the items as the references are picked up by the DeeModel */
 
329
  g_sequence_free(query->results_list);
 
330
  query->results_list = NULL;
 
331
 
 
332
  /* Reset for new data */
 
333
  dee_model_clear(query->appstack_model);
 
334
 
 
335
  /* Get the list of all applications that have data that is relevant
 
336
     to the current query, but just the app info. */
 
337
  GHashTable * appstack_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, appstack_item_free);
 
338
  hud_source_list_applications (query->all_sources, query->token_list, app_results_list_populate, appstack_hash);
 
339
 
 
340
  /* If we've selected a source, make sure it's in the list */
 
341
  appstack_hash_add_source(appstack_hash, query->current_source, HUD_SOURCE_ITEM_TYPE_BACKGROUND_APP);
 
342
 
 
343
  /* Always have the focused app in there too */
 
344
  HudSource * focused = hud_application_list_get_focused_app(query->app_list);
 
345
  appstack_hash_add_source(appstack_hash, focused, HUD_SOURCE_ITEM_TYPE_FOCUSED_APP);
 
346
 
 
347
  /* Always have the side stage app in there too */
 
348
  HudSource * side_stage = hud_application_list_get_side_stage_focused_app(query->app_list);
 
349
  appstack_hash_add_source(appstack_hash, side_stage, HUD_SOURCE_ITEM_TYPE_SIDESTAGE_APP);
 
350
 
 
351
  /* Now take the hash, having already deduplicated for us, and turn
 
352
     it into a shorted DeeModel */
 
353
  appstack_hash_to_model(appstack_hash, query->appstack_model);
 
354
 
 
355
  /* Thanks hash ol' friend */
 
356
  g_hash_table_unref(appstack_hash);
117
357
 
118
358
  g_debug ("query took %dus\n", (int) (g_get_monotonic_time () - start_time));
 
359
 
 
360
  g_object_set(G_OBJECT(query->skel), "current-query", query->search_string, NULL);
119
361
}
120
362
 
121
363
static gboolean
148
390
 
149
391
  g_debug ("Destroyed query '%s'", query->search_string);
150
392
 
 
393
  /* TODO: move to destroy */
 
394
  if (query->last_used_source != NULL)
 
395
  {
 
396
    hud_source_unuse(query->last_used_source);
 
397
    g_clear_object(&query->last_used_source);
 
398
  }
 
399
 
 
400
  g_clear_object(&query->skel);
 
401
  g_clear_object(&query->results_model);
 
402
  /* NOTE: ^^ Kills results_tag as well */
 
403
  g_clear_object(&query->appstack_model);
 
404
 
151
405
  if (query->refresh_id)
152
406
    g_source_remove (query->refresh_id);
153
407
 
154
 
  hud_source_unuse (query->source);
155
 
 
156
 
  g_object_unref (query->source);
157
 
  hud_token_list_free (query->token_list);
158
 
  g_free (query->search_string);
159
 
  g_ptr_array_unref (query->results);
 
408
  g_object_unref (query->all_sources);
 
409
  g_object_unref (query->app_list);
 
410
  g_clear_object (&query->current_source);
 
411
  if (query->token_list != NULL) {
 
412
    hud_token_list_free (query->token_list);
 
413
    query->token_list = NULL;
 
414
  }
 
415
  g_clear_pointer(&query->search_string, g_free);
 
416
 
 
417
  g_clear_pointer(&query->object_path, g_free);
 
418
  g_clear_pointer(&query->results_name, g_free);
 
419
  g_clear_pointer(&query->appstack_name, g_free);
 
420
 
 
421
  g_clear_object(&query->voice);
 
422
  g_clear_object(&query->watchdog);
160
423
 
161
424
  G_OBJECT_CLASS (hud_query_parent_class)
162
425
    ->finalize (object);
163
426
}
164
427
 
 
428
/* Handle the DBus function UpdateQuery */
 
429
static gboolean
 
430
handle_voice_query (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, gpointer user_data)
 
431
{
 
432
  g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
433
  HudQuery * query = HUD_QUERY(user_data);
 
434
  hud_watchdog_ping(query->watchdog);
 
435
 
 
436
  g_debug("Voice query is loading");
 
437
  hud_query_iface_com_canonical_hud_query_emit_voice_query_loading (
 
438
      HUD_QUERY_IFACE_COM_CANONICAL_HUD_QUERY (skel));
 
439
  gchar *voice_result;
 
440
  GError *error = NULL;
 
441
 
 
442
  HudSource * search_source = query->current_source;
 
443
  if (search_source == NULL) {
 
444
    search_source = hud_application_list_get_focused_app(query->app_list);
 
445
  }
 
446
 
 
447
  if (!hud_voice_query (query->voice, search_source, &voice_result, &error))
 
448
  {
 
449
    g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, error->message);
 
450
    g_error_free(error);
 
451
    return FALSE;
 
452
  }
 
453
 
 
454
  g_debug("Voice query is finished");
 
455
 
 
456
  if (voice_result == NULL)
 
457
    voice_result = g_strdup("");
 
458
 
 
459
  gchar *search_string = g_utf8_strdown(voice_result, -1);
 
460
  g_free(voice_result);
 
461
 
 
462
  g_debug("Updating Query to: '%s'", search_string);
 
463
 
 
464
  /* Clear the last query */
 
465
  g_clear_pointer(&query->search_string, g_free);
 
466
  if (query->token_list != NULL) {
 
467
    hud_token_list_free (query->token_list);
 
468
    query->token_list = NULL;
 
469
  }
 
470
 
 
471
  query->search_string = search_string;
 
472
 
 
473
  if (query->search_string[0] != '\0') {
 
474
    query->token_list = hud_token_list_new_from_string (query->search_string);
 
475
  }
 
476
 
 
477
  /* Refresh it all */
 
478
  hud_query_refresh (query);
 
479
 
 
480
  /* Tell DBus everything is going to be A-OK */
 
481
  hud_query_iface_com_canonical_hud_query_complete_voice_query(skel, invocation, 0, search_string);
 
482
 
 
483
  return TRUE;
 
484
}
 
485
 
 
486
/* Handle the DBus function UpdateQuery */
 
487
static gboolean
 
488
handle_update_query (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, const gchar * search_string, gpointer user_data)
 
489
{
 
490
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
491
        HudQuery * query = HUD_QUERY(user_data);
 
492
        hud_watchdog_ping(query->watchdog);
 
493
 
 
494
        g_debug("Updating Query to: '%s'", search_string);
 
495
 
 
496
        /* Clear the last query */
 
497
        g_clear_pointer(&query->search_string, g_free);
 
498
        if (query->token_list != NULL) {
 
499
                hud_token_list_free (query->token_list);
 
500
                query->token_list = NULL;
 
501
        }
 
502
 
 
503
        /* Grab the data from this one */
 
504
        query->search_string = g_strdup (search_string);
 
505
        query->search_string = g_strstrip(query->search_string);
 
506
 
 
507
        if (query->search_string[0] != '\0') {
 
508
                query->token_list = hud_token_list_new_from_string (query->search_string);
 
509
        }
 
510
 
 
511
        /* Refresh it all */
 
512
        hud_query_refresh (query);
 
513
 
 
514
        /* Tell DBus everything is going to be A-OK */
 
515
        hud_query_iface_com_canonical_hud_query_complete_update_query(skel, invocation, 0);
 
516
 
 
517
        return TRUE;
 
518
}
 
519
 
 
520
/* Handle the DBus function UpdateApp */
 
521
static gboolean
 
522
handle_update_app (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, const gchar * app_id, gpointer user_data)
 
523
{
 
524
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
525
        HudQuery * query = HUD_QUERY(user_data);
 
526
        hud_watchdog_ping(query->watchdog);
 
527
 
 
528
        g_debug("Updating App to: '%s'", app_id);
 
529
 
 
530
        g_clear_object (&query->current_source);
 
531
        query->current_source = hud_source_get(query->all_sources, app_id);
 
532
        if (query->current_source != NULL) {
 
533
                g_object_ref (query->current_source);
 
534
        }
 
535
 
 
536
        /* Refresh it all */
 
537
        hud_query_refresh (query);      
 
538
 
 
539
        /* Tell DBus everything is going to be A-OK */
 
540
        hud_query_iface_com_canonical_hud_query_complete_update_app(skel, invocation, 0);
 
541
 
 
542
        return TRUE;
 
543
}
 
544
 
 
545
/* Handle getting execute from DBus */
 
546
static gboolean
 
547
handle_execute (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, GVariant * command_id, guint timestamp, gpointer user_data)
 
548
{
 
549
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
550
        HudQuery * query = HUD_QUERY(user_data);
 
551
        hud_watchdog_ping(query->watchdog);
 
552
 
 
553
        /* Do good */
 
554
        GVariant * inner = g_variant_get_variant(command_id);
 
555
        guint64 id = g_variant_get_uint64(inner);
 
556
        g_variant_unref(inner);
 
557
 
 
558
        HudItem * item = hud_item_lookup(id);
 
559
 
 
560
        if (item == NULL) {
 
561
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Item specified by command key does not exist");
 
562
                return TRUE;
 
563
        }
 
564
 
 
565
        GVariantBuilder platform;
 
566
        g_variant_builder_init(&platform, G_VARIANT_TYPE_DICTIONARY);
 
567
 
 
568
        GVariantBuilder entry;
 
569
        g_variant_builder_init(&entry, G_VARIANT_TYPE_DICT_ENTRY);
 
570
        g_variant_builder_add_value(&entry, g_variant_new_string("desktop-startup-id"));
 
571
        gchar * timestr = g_strdup_printf("_TIME%d", timestamp);
 
572
        g_variant_builder_add_value(&entry, g_variant_new_variant(g_variant_new_string(timestr)));
 
573
        g_free(timestr);
 
574
 
 
575
        g_variant_builder_add_value(&platform, g_variant_builder_end(&entry));
 
576
 
 
577
        hud_item_activate(item, g_variant_builder_end(&platform));
 
578
 
 
579
        hud_query_iface_com_canonical_hud_query_complete_execute_command(skel, invocation);
 
580
 
 
581
        return TRUE;
 
582
}
 
583
 
 
584
/* Handle getting parameterized from DBus */
 
585
static gboolean
 
586
handle_parameterized (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, GVariant * command_id, guint timestamp, gpointer user_data)
 
587
{
 
588
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
589
        HudQuery * query = HUD_QUERY(user_data);
 
590
        hud_watchdog_ping(query->watchdog);
 
591
 
 
592
        GVariant * inner = g_variant_get_variant(command_id);
 
593
        guint64 id = g_variant_get_uint64(inner);
 
594
        g_variant_unref(inner);
 
595
 
 
596
        HudItem * item = hud_item_lookup(id);
 
597
 
 
598
        if (item == NULL) {
 
599
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Item specified by command key does not exist");
 
600
                return TRUE;
 
601
        }
 
602
 
 
603
        if (!HUD_IS_MODEL_ITEM(item)) {
 
604
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Item specified by command is not a menu model item");
 
605
                return TRUE;
 
606
        }
 
607
 
 
608
        if (!hud_model_item_is_parameterized(HUD_MODEL_ITEM(item))) {
 
609
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Item specified by command does not have parameterized actions");
 
610
                return TRUE;
 
611
        }
 
612
 
 
613
        const gchar * base_action = NULL;
 
614
        const gchar * action_path = NULL;
 
615
        const gchar * model_path = NULL;
 
616
        gint model_section = 0;
 
617
 
 
618
        hud_model_item_activate_parameterized(HUD_MODEL_ITEM(item), timestamp, &base_action, &action_path, &model_path, &model_section);
 
619
 
 
620
        if (base_action == NULL) {
 
621
                /* This value can be NULL, but variants require an empty string */
 
622
                base_action = "";
 
623
        }
 
624
 
 
625
        if (base_action == NULL ||
 
626
                        action_path == NULL || !g_variant_is_object_path(action_path) ||
 
627
                        model_path == NULL || !g_variant_is_object_path(model_path)) {
 
628
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Values returned by the model item are invalid");
 
629
                return TRUE;
 
630
        }
 
631
 
 
632
  hud_query_iface_com_canonical_hud_query_complete_execute_parameterized (skel,
 
633
      invocation, base_action, action_path, model_path, model_section);
 
634
        return TRUE;
 
635
}
 
636
 
 
637
static gboolean
 
638
handle_execute_toolbar (HudQueryIfaceComCanonicalHudQuery *object, GDBusMethodInvocation *invocation, const gchar *arg_item, guint arg_timestamp, gpointer user_data)
 
639
{
 
640
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
641
        HudQuery * query = HUD_QUERY(user_data);
 
642
        hud_watchdog_ping(query->watchdog);
 
643
 
 
644
        HudClientQueryToolbarItems item = hud_client_query_toolbar_items_get_value_from_nick(arg_item);
 
645
 
 
646
        if (item != HUD_CLIENT_QUERY_TOOLBAR_QUIT) {
 
647
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "TODO");
 
648
                return TRUE;
 
649
        }
 
650
 
 
651
        HudSource * search_source = query->current_source;
 
652
        if (search_source == NULL) {
 
653
                search_source = hud_application_list_get_focused_app(query->app_list);
 
654
        }
 
655
 
 
656
        if (search_source == NULL) {
 
657
                g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No source currently in use");
 
658
                return TRUE;
 
659
        }
 
660
 
 
661
        GVariantBuilder platform;
 
662
        g_variant_builder_init(&platform, G_VARIANT_TYPE_DICTIONARY);
 
663
 
 
664
        GVariantBuilder entry;
 
665
        g_variant_builder_init(&entry, G_VARIANT_TYPE_DICT_ENTRY);
 
666
        g_variant_builder_add_value(&entry, g_variant_new_string("desktop-startup-id"));
 
667
        gchar * timestr = g_strdup_printf("_TIME%d", arg_timestamp);
 
668
        g_variant_builder_add_value(&entry, g_variant_new_variant(g_variant_new_string(timestr)));
 
669
        g_free(timestr);
 
670
 
 
671
        g_variant_builder_add_value(&platform, g_variant_builder_end(&entry));
 
672
 
 
673
        hud_source_activate_toolbar(search_source, item, g_variant_builder_end(&platform));
 
674
        g_dbus_method_invocation_return_value(invocation, NULL);
 
675
        return TRUE;
 
676
}
 
677
 
 
678
/* Really this is just an unref, but let's put it in a nice function
 
679
   so that it's easier to change later if we need to. */
 
680
void
 
681
hud_query_close (HudQuery * query)
 
682
{
 
683
        g_return_if_fail(HUD_IS_QUERY(query));
 
684
        g_object_unref(query);
 
685
        return;
 
686
}
 
687
 
 
688
/* Handle the DBus function CloseQuery */
 
689
static gboolean
 
690
handle_close_query (HudQueryIfaceComCanonicalHudQuery * skel, GDBusMethodInvocation * invocation, gpointer user_data)
 
691
{
 
692
        g_return_val_if_fail(HUD_IS_QUERY(user_data), FALSE);
 
693
        HudQuery * query = HUD_QUERY(user_data);
 
694
        hud_watchdog_ping(query->watchdog);
 
695
 
 
696
        /* Close the query */
 
697
        hud_query_close(query);
 
698
 
 
699
        /* NOTE: Don't use the query after this, it may not exist */
 
700
        query = NULL;
 
701
 
 
702
        /* Tell DBus we're dying */
 
703
        hud_query_iface_com_canonical_hud_query_complete_close_query(skel, invocation);
 
704
 
 
705
        return TRUE;
 
706
}
 
707
 
 
708
static void
 
709
hud_query_init_real (HudQuery *query, GDBusConnection *connection, const guint querynumber)
 
710
{
 
711
  GError *error = NULL;
 
712
 
 
713
  query->querynumber = querynumber;
 
714
 
 
715
  query->skel = hud_query_iface_com_canonical_hud_query_skeleton_new();
 
716
 
 
717
  /* NOTE: Connect to the functions before putting on the bus. */
 
718
  g_signal_connect(G_OBJECT(query->skel), "handle-update-query", G_CALLBACK(handle_update_query), query);
 
719
  g_signal_connect(G_OBJECT(query->skel), "handle-update-app", G_CALLBACK(handle_update_app), query);
 
720
  g_signal_connect(G_OBJECT(query->skel), "handle-voice-query", G_CALLBACK(handle_voice_query), query);
 
721
  g_signal_connect(G_OBJECT(query->skel), "handle-close-query", G_CALLBACK(handle_close_query), query);
 
722
  g_signal_connect(G_OBJECT(query->skel), "handle-execute-command", G_CALLBACK(handle_execute), query);
 
723
  g_signal_connect(G_OBJECT(query->skel), "handle-execute-parameterized", G_CALLBACK(handle_parameterized), query);
 
724
  g_signal_connect(G_OBJECT(query->skel), "handle-execute-toolbar", G_CALLBACK(handle_execute_toolbar), query);
 
725
 
 
726
  query->object_path = g_strdup_printf("/com/canonical/hud/query%d", query->querynumber);
 
727
  if (!g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(query->skel),
 
728
                                   connection,
 
729
                                   query->object_path,
 
730
                                   &error))
 
731
  {
 
732
    g_warning ("%s %s\n", "g_dbus_interface_skeleton_export failed:", error->message);
 
733
    g_error_free(error);
 
734
  }
 
735
 
 
736
  GDBusInterfaceInfo* info = g_dbus_interface_skeleton_get_info (
 
737
      G_DBUS_INTERFACE_SKELETON(query->skel) );
 
738
  g_debug("Created interface skeleton: [%s] on [%s]", info->name, g_dbus_interface_skeleton_get_object_path(G_DBUS_INTERFACE_SKELETON(query->skel)));
 
739
 
 
740
  query->results_name = g_strdup_printf("com.canonical.hud.query%d.results", query->querynumber);
 
741
  query->results_model = dee_shared_model_new(query->results_name);
 
742
  dee_model_set_schema_full(query->results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
 
743
  query->results_tag = dee_model_register_tag(query->results_model, g_object_unref);
 
744
 
 
745
  query->appstack_name = g_strdup_printf("com.canonical.hud.query%d.appstack", query->querynumber);
 
746
  query->appstack_model = dee_shared_model_new(query->appstack_name);
 
747
  dee_model_set_schema_full(query->appstack_model, appstack_model_schema, G_N_ELEMENTS(appstack_model_schema));
 
748
 
 
749
  g_object_set(G_OBJECT(query->skel),
 
750
               "appstack-model", query->appstack_name,
 
751
               "results-model", query->results_name,
 
752
               NULL);
 
753
 
 
754
  g_dbus_interface_skeleton_flush(G_DBUS_INTERFACE_SKELETON(query->skel));
 
755
 
 
756
  error = NULL;
 
757
  query->voice = hud_voice_new(query->skel, NULL, &error);
 
758
  if (!query->voice)
 
759
  {
 
760
    g_warning ("%s %s\n", "Voice engine failed to initialize:", error->message);
 
761
    g_error_free(error);
 
762
  }
 
763
}
 
764
 
165
765
static void
166
766
hud_query_init (HudQuery *query)
167
767
{
201
801
 * Returns: the new #HudQuery
202
802
 **/
203
803
HudQuery *
204
 
hud_query_new (HudSource   *source,
 
804
hud_query_new (HudSource   *all_sources,
 
805
               HudWatchdog *watchdog,
 
806
               HudApplicationList *application_list,
205
807
               const gchar *search_string,
206
 
               gint         num_results)
 
808
               gint         num_results,
 
809
               GDBusConnection *connection,
 
810
               const guint  query_count)
207
811
{
208
812
  HudQuery *query;
209
813
 
210
814
  g_debug ("Created query '%s'", search_string);
211
815
 
212
816
  query = g_object_new (HUD_TYPE_QUERY, NULL);
213
 
  query->source = g_object_ref (source);
214
 
  query->results = g_ptr_array_new_with_free_func (g_object_unref);
 
817
  hud_query_init_real(query, connection, query_count);
 
818
  query->all_sources = g_object_ref (all_sources);
 
819
  query->app_list = g_object_ref (application_list);
215
820
  query->search_string = g_strdup (search_string);
216
 
  query->token_list = hud_token_list_new_from_string (query->search_string);
 
821
  query->token_list = NULL;
 
822
 
 
823
  if (watchdog != NULL) {
 
824
    query->watchdog = g_object_ref(watchdog);
 
825
  }
 
826
  
 
827
  if (query->search_string[0] != '\0') {
 
828
    query->token_list = hud_token_list_new_from_string (query->search_string);
 
829
  }
 
830
 
217
831
  query->num_results = num_results;
218
832
 
219
 
  hud_source_use (query->source);
220
 
 
221
833
  hud_query_refresh (query);
222
834
 
223
 
  g_signal_connect_object (source, "changed", G_CALLBACK (hud_query_source_changed), query, 0);
224
 
 
225
 
  g_clear_object (&last_created_query);
226
 
  last_created_query = g_object_ref (query);
 
835
  g_signal_connect_object (all_sources, "changed", G_CALLBACK (hud_query_source_changed), query, 0);
227
836
 
228
837
  return query;
229
838
}
230
839
 
231
840
/**
232
 
 * hud_query_get_query_key:
233
 
 * @query: a #HudQuery
234
 
 *
235
 
 * Returns the query key for @HudQuery.
236
 
 *
237
 
 * Each #HudQuery has a unique identifying key that is assigned when the
238
 
 * query is created.
239
 
 *
240
 
 * FIXME: This is a lie.
241
 
 *
242
 
 * Returns: (transfer none): the query key for @query
243
 
 **/
244
 
GVariant *
245
 
hud_query_get_query_key (HudQuery *query)
246
 
{
247
 
  static GVariant *query_key;
248
 
 
249
 
  if (query_key == NULL)
250
 
    query_key = g_variant_ref_sink (g_variant_new_string ("query key"));
251
 
 
252
 
  return query_key;
253
 
}
254
 
 
255
 
/**
256
 
 * hud_query_lookup:
257
 
 * @query_key: a query key
258
 
 *
259
 
 * Finds the query that has the given @query_key.
260
 
 *
261
 
 * Returns: (transfer none): the query, or %NULL if no such query exists
262
 
 **/
263
 
HudQuery *
264
 
hud_query_lookup (GVariant *query_key)
265
 
{
266
 
  return last_created_query;
267
 
}
268
 
 
269
 
/**
270
 
 * hud_query_close:
271
 
 * @query: a #HudQuery
272
 
 *
273
 
 * Closes a #HudQuery.
274
 
 *
275
 
 * This drops the query from the internal list of queries.  Future use
276
 
 * of hud_query_lookup() to find this query will fail.
277
 
 *
278
 
 * You must still release your own reference on @query, if you have one.
279
 
 * This only drops the internal reference.
280
 
 **/
281
 
void
282
 
hud_query_close (HudQuery *query)
283
 
{
284
 
  if (query == last_created_query)
285
 
    g_clear_object (&last_created_query);
286
 
}
287
 
 
288
 
/**
289
 
 * hud_query_get_n_results:
290
 
 * @query: a #HudQuery
291
 
 *
292
 
 * Gets the number of results in @query.
293
 
 *
294
 
 * Returns: the number of results
295
 
 **/
 
841
 * hud_query_get_path:
 
842
 * @query: a #HudQuery
 
843
 *
 
844
 * Gets the path that the query object is exported to DBus on.
 
845
 *
 
846
 * Return value: A dbus object path
 
847
 */
 
848
const gchar *
 
849
hud_query_get_path (HudQuery    *query)
 
850
{
 
851
        g_return_val_if_fail(HUD_IS_QUERY(query), NULL);
 
852
 
 
853
        return query->object_path;
 
854
}
 
855
 
 
856
/**
 
857
 * hud_query_get_results_name:
 
858
 * @query: a #HudQuery
 
859
 *
 
860
 * Gets the DBus name that the shared results model is using
 
861
 *
 
862
 * Return value: A dbus name
 
863
 */
 
864
const gchar *
 
865
hud_query_get_results_name (HudQuery    *query)
 
866
{
 
867
        g_return_val_if_fail(HUD_IS_QUERY(query), NULL);
 
868
 
 
869
        return query->results_name;
 
870
}
 
871
 
 
872
/**
 
873
 * hud_query_get_appstack_name:
 
874
 * @query: a #HudQuery
 
875
 *
 
876
 * Gets the DBus name that the appstack model is using
 
877
 *
 
878
 * Return value: A dbus name
 
879
 */
 
880
const gchar *
 
881
hud_query_get_appstack_name (HudQuery * query)
 
882
{
 
883
        g_return_val_if_fail(HUD_IS_QUERY(query), NULL);
 
884
 
 
885
        return query->appstack_name;
 
886
}
 
887
 
 
888
DeeModel *
 
889
hud_query_get_results_model(HudQuery *self)
 
890
{
 
891
  g_return_val_if_fail(HUD_IS_QUERY(self), NULL);
 
892
 
 
893
  return self->results_model;
 
894
 
 
895
}
 
896
 
 
897
DeeModel *
 
898
hud_query_get_appstack_model(HudQuery *self)
 
899
{
 
900
  g_return_val_if_fail(HUD_IS_QUERY(self), NULL);
 
901
 
 
902
  return self->appstack_model;
 
903
 
 
904
}
 
905
 
 
906
const gchar *
 
907
hud_query_get_query (HudQuery * query)
 
908
{
 
909
        g_return_val_if_fail(HUD_IS_QUERY(query), NULL);
 
910
 
 
911
        return query->search_string;
 
912
}
 
913
 
296
914
guint
297
 
hud_query_get_n_results (HudQuery *query)
 
915
hud_query_get_number (HudQuery * query)
298
916
{
299
 
  return query->results->len;
300
 
}
 
917
        g_return_val_if_fail(HUD_IS_QUERY(query), 0);
301
918
 
302
 
/**
303
 
 * hud_query_get_result_by_index:
304
 
 * @query: a #HudQuery
305
 
 * @i: the index of the result
306
 
 *
307
 
 * Gets the @i<!-- -->th result from @query.
308
 
 *
309
 
 * @i must be less than the number of results in the query.  See
310
 
 * hud_query_get_n_results().
311
 
 *
312
 
 * Returns: (transfer none): the #HudResult at position @i
313
 
 **/
314
 
HudResult *
315
 
hud_query_get_result_by_index (HudQuery *query,
316
 
                               guint     i)
317
 
{
318
 
  return query->results->pdata[i];
 
919
        return query->querynumber;
319
920
}