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

« back to all changes in this revision

Viewing changes to libhud/action-publisher.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:
 
1
/*
 
2
 * Copyright © 2012 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of either or both of the following licences:
 
6
 *
 
7
 * 1) the GNU Lesser General Public License version 3, as published by
 
8
 * the Free Software Foundation; and/or
 
9
 * 2) the GNU Lesser General Public License version 2.1, as published by
 
10
 * the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
14
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
 
15
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 
16
 * License for more details.
 
17
 *
 
18
 * You should have received a copy of both the GNU Lesser General Public
 
19
 * License version 3 and version 2.1 along with this program.  If not,
 
20
 * see <http://www.gnu.org/licenses/>
 
21
 *
 
22
 * Author: Ryan Lortie <desrt@desrt.ca>
 
23
 */
 
24
 
 
25
#include "action-publisher.h"
 
26
 
 
27
#include "manager.h"
 
28
#include "marshal.h"
 
29
 
 
30
#include <string.h>
 
31
 
 
32
typedef GMenuModelClass HudAuxClass;
 
33
 
 
34
typedef struct
 
35
{
 
36
  GMenuModel parent_instance;
 
37
 
 
38
  HudActionPublisher *publisher;
 
39
} HudAux;
 
40
 
 
41
static void hud_aux_init_action_group_iface (GActionGroupInterface *iface);
 
42
static void hud_aux_init_remote_action_group_iface (GRemoteActionGroupInterface *iface);
 
43
G_DEFINE_TYPE_WITH_CODE (HudAux, _hud_aux, G_TYPE_MENU_MODEL,
 
44
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, hud_aux_init_action_group_iface)
 
45
                         G_IMPLEMENT_INTERFACE (G_TYPE_REMOTE_ACTION_GROUP, hud_aux_init_remote_action_group_iface))
 
46
 
 
47
typedef GObjectClass HudActionPublisherClass;
 
48
 
 
49
struct _HudActionPublisher
 
50
{
 
51
  GObject parent_instance;
 
52
 
 
53
  GDBusConnection *bus;
 
54
  GApplication *application;
 
55
  GVariant * id;
 
56
  gint export_id;
 
57
  gchar *path;
 
58
 
 
59
  GSequence *descriptions;
 
60
  HudAux *aux;
 
61
 
 
62
  GList * action_groups;
 
63
};
 
64
 
 
65
enum
 
66
{
 
67
  SIGNAL_ACTION_GROUP_ADDED,
 
68
  SIGNAL_ACTION_GROUP_REMOVED,
 
69
  N_SIGNALS
 
70
};
 
71
 
 
72
guint hud_action_publisher_signals[N_SIGNALS];
 
73
 
 
74
G_DEFINE_TYPE (HudActionPublisher, hud_action_publisher, G_TYPE_OBJECT)
 
75
 
 
76
typedef GObjectClass HudActionDescriptionClass;
 
77
 
 
78
struct _HudActionDescription
 
79
{
 
80
  GObject parent_instance;
 
81
 
 
82
  gchar *identifier;
 
83
  gchar *action;
 
84
  GVariant *target;
 
85
  GHashTable *attrs;
 
86
  GHashTable *links;
 
87
};
 
88
 
 
89
guint hud_action_description_changed_signal;
 
90
 
 
91
G_DEFINE_TYPE (HudActionDescription, hud_action_description, G_TYPE_OBJECT)
 
92
 
 
93
 
 
94
static gboolean
 
95
hud_aux_is_mutable (GMenuModel *model)
 
96
{
 
97
  return TRUE;
 
98
}
 
99
 
 
100
static gint
 
101
hud_aux_get_n_items (GMenuModel *model)
 
102
{
 
103
  HudAux *aux = (HudAux *) model;
 
104
 
 
105
  return g_sequence_get_length (aux->publisher->descriptions);
 
106
}
 
107
 
 
108
static void
 
109
hud_aux_get_item_attributes (GMenuModel  *model,
 
110
                             gint         item_index,
 
111
                             GHashTable **attributes)
 
112
{
 
113
  HudAux *aux = (HudAux *) model;
 
114
  GSequenceIter *iter;
 
115
  HudActionDescription *description;
 
116
 
 
117
  iter = g_sequence_get_iter_at_pos (aux->publisher->descriptions, item_index);
 
118
  description = g_sequence_get (iter);
 
119
 
 
120
  *attributes = g_hash_table_ref (description->attrs);
 
121
}
 
122
 
 
123
static void
 
124
hud_aux_get_item_links (GMenuModel  *model,
 
125
                        gint         item_index,
 
126
                        GHashTable **links)
 
127
{
 
128
  HudAux *aux = (HudAux *) model;
 
129
  GSequenceIter *iter;
 
130
  HudActionDescription *description;
 
131
 
 
132
  iter = g_sequence_get_iter_at_pos (aux->publisher->descriptions, item_index);
 
133
  description = g_sequence_get (iter);
 
134
 
 
135
  if (description->links != NULL)
 
136
    *links = g_hash_table_ref(description->links);
 
137
  else
 
138
    *links = g_hash_table_new (NULL, NULL);
 
139
}
 
140
 
 
141
static void
 
142
_hud_aux_init (HudAux *aux)
 
143
{
 
144
}
 
145
 
 
146
static void
 
147
hud_aux_init_action_group_iface (GActionGroupInterface *iface)
 
148
{
 
149
}
 
150
 
 
151
static void
 
152
hud_aux_init_remote_action_group_iface (GRemoteActionGroupInterface *iface)
 
153
{
 
154
}
 
155
 
 
156
static void
 
157
_hud_aux_class_init (HudAuxClass *class)
 
158
{
 
159
  class->is_mutable = hud_aux_is_mutable;
 
160
  class->get_n_items = hud_aux_get_n_items;
 
161
  class->get_item_attributes = hud_aux_get_item_attributes;
 
162
  class->get_item_links = hud_aux_get_item_links;
 
163
}
 
164
 
 
165
static void
 
166
hud_action_publisher_dispose (GObject *object)
 
167
{
 
168
  HudActionPublisher *self = HUD_ACTION_PUBLISHER(object);
 
169
 
 
170
  g_clear_pointer(&self->id, g_variant_unref);
 
171
 
 
172
  g_clear_object(&self->aux);
 
173
  g_clear_object(&self->application);
 
174
 
 
175
  g_debug("Un-exporting menu model at with id [%d]", self->export_id);
 
176
  g_dbus_connection_unexport_menu_model (self->bus, self->export_id);
 
177
 
 
178
  g_clear_pointer(&self->path, g_free);
 
179
  g_clear_pointer(&self->descriptions, g_sequence_free);
 
180
 
 
181
  g_list_free_full(self->action_groups, g_free);
 
182
 
 
183
  g_clear_object(&self->bus);
 
184
 
 
185
  G_OBJECT_CLASS (hud_action_publisher_parent_class)->dispose (object);
 
186
}
 
187
 
 
188
static void
 
189
hud_action_publisher_finalize (GObject *object)
 
190
{
 
191
  G_OBJECT_CLASS (hud_action_publisher_parent_class)->finalize (object);
 
192
  return;
 
193
}
 
194
 
 
195
static void
 
196
hud_action_publisher_init (HudActionPublisher *publisher)
 
197
{
 
198
  static guint64 next_id;
 
199
 
 
200
  publisher->descriptions = g_sequence_new (g_object_unref);
 
201
  publisher->aux = g_object_new (_hud_aux_get_type (), NULL);
 
202
  publisher->aux->publisher = publisher;
 
203
  publisher->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
 
204
 
 
205
  if (!publisher->bus)
 
206
    return;
 
207
 
 
208
  do
 
209
    {
 
210
      guint64 id = next_id++;
 
211
 
 
212
      if (id)
 
213
        publisher->path = g_strdup_printf ("/com/canonical/hud/publisher");
 
214
      else
 
215
        publisher->path = g_strdup_printf ("/com/canonical/hud/publisher%" G_GUINT64_FORMAT, id);
 
216
 
 
217
      publisher->export_id = g_dbus_connection_export_menu_model (publisher->bus, publisher->path,
 
218
                                                                  G_MENU_MODEL (publisher->aux), NULL);
 
219
      g_debug("Exporting menu model at [%s] with id [%d]", publisher->path, publisher->export_id);
 
220
 
 
221
      if (!publisher->export_id)
 
222
        /* try again... */
 
223
        g_free (publisher->path);
 
224
    }
 
225
  while (publisher->path == NULL);
 
226
}
 
227
 
 
228
static void
 
229
hud_action_publisher_class_init (HudActionPublisherClass *class)
 
230
{
 
231
  class->dispose = hud_action_publisher_dispose;
 
232
  class->finalize = hud_action_publisher_finalize;
 
233
 
 
234
  /**
 
235
   * HudActionPublisher::action-group-added:
 
236
   * @param1: Prefix for the action group
 
237
   * @param2: Path group is exported on DBus
 
238
   *
 
239
   * Emitted when a new action group is added to the publisher
 
240
   */
 
241
  hud_action_publisher_signals[SIGNAL_ACTION_GROUP_ADDED] = g_signal_new (HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_ADDED, HUD_TYPE_ACTION_PUBLISHER,
 
242
                                                                  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 
243
                                                                  _hud_marshal_VOID__STRING_STRING,
 
244
                                                                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 
245
  /**
 
246
   * HudActionPublisher::action-group-removed:
 
247
   * @param1: Prefix for the action group
 
248
   * @param2: Path group is exported on DBus
 
249
   *
 
250
   * Emitted when a new action group is removed from the publisher
 
251
   */
 
252
  hud_action_publisher_signals[SIGNAL_ACTION_GROUP_REMOVED] = g_signal_new (HUD_ACTION_PUBLISHER_SIGNAL_ACTION_GROUP_REMOVED, HUD_TYPE_ACTION_PUBLISHER,
 
253
                                                                  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 
254
                                                                  _hud_marshal_VOID__STRING_STRING,
 
255
                                                                  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 
256
}
 
257
 
 
258
/**
 
259
 * hud_action_publisher_new_for_application:
 
260
 * @application: A #GApplication object
 
261
 *
 
262
 * Creates a new #HudActionPublisher and automatically registers the
 
263
 * default actions under the "app" prefix.
 
264
 *
 
265
 * Return value: (transfer full): A new #HudActionPublisher object
 
266
 */
 
267
HudActionPublisher *
 
268
hud_action_publisher_new_for_application (GApplication *application)
 
269
{
 
270
  HudActionPublisher *publisher;
 
271
 
 
272
  g_return_val_if_fail (G_IS_APPLICATION (application), NULL);
 
273
  g_return_val_if_fail (g_application_get_application_id (application), NULL);
 
274
  g_return_val_if_fail (g_application_get_is_registered (application), NULL);
 
275
  g_return_val_if_fail (!g_application_get_is_remote (application), NULL);
 
276
 
 
277
  publisher = g_object_new (HUD_TYPE_ACTION_PUBLISHER, NULL);
 
278
  publisher->application = g_object_ref (application);
 
279
 
 
280
  hud_action_publisher_add_action_group (publisher, "app",
 
281
                           g_application_get_dbus_object_path (application));
 
282
 
 
283
  return publisher;
 
284
}
 
285
 
 
286
/**
 
287
 * hud_action_publisher_new_for_id:
 
288
 * @id: A window ID
 
289
 *
 
290
 * Creates a new #HudActionPublisher based on the window ID passed
 
291
 * in via @id.
 
292
 *
 
293
 * Return value: (transfer full): A new #HudActionPublisher object
 
294
 */
 
295
HudActionPublisher *
 
296
hud_action_publisher_new_for_id (GVariant * id)
 
297
{
 
298
        HudActionPublisher * publisher;
 
299
        publisher = g_object_new (HUD_TYPE_ACTION_PUBLISHER, NULL);
 
300
        if (id != NULL)
 
301
        {
 
302
          publisher->id = g_variant_ref_sink(id);
 
303
        }
 
304
        else
 
305
        {
 
306
          publisher->id = g_variant_ref_sink(g_variant_new_int32(-1));
 
307
        }
 
308
 
 
309
        return publisher;
 
310
}
 
311
 
 
312
static gchar *
 
313
format_identifier (const gchar *action_name,
 
314
                   GVariant    *action_target)
 
315
{
 
316
  gchar *targetstr;
 
317
  gchar *identifier;
 
318
 
 
319
  if (action_target)
 
320
    {
 
321
      targetstr = g_variant_print (action_target, TRUE);
 
322
      identifier = g_strdup_printf ("%s(%s)", action_name, targetstr);
 
323
      g_free (targetstr);
 
324
    }
 
325
 
 
326
  else
 
327
    identifier = g_strdup_printf ("%s()", action_name);
 
328
 
 
329
  return identifier;
 
330
}
 
331
 
 
332
static gint
 
333
compare_descriptions (gconstpointer a,
 
334
                      gconstpointer b,
 
335
                      gpointer      user_data)
 
336
{
 
337
  const HudActionDescription *da = a;
 
338
  const HudActionDescription *db = b;
 
339
 
 
340
  return strcmp (da->identifier, db->identifier);
 
341
}
 
342
 
 
343
static void
 
344
description_changed (HudActionDescription *description,
 
345
                     const gchar          *attribute_name,
 
346
                     gpointer              user_data)
 
347
{
 
348
  HudActionPublisher *publisher = user_data;
 
349
  GSequenceIter *iter;
 
350
 
 
351
  iter = g_sequence_lookup (publisher->descriptions, description, compare_descriptions, NULL);
 
352
  g_assert (g_sequence_get (iter) == description);
 
353
 
 
354
  g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 1, 1);
 
355
}
 
356
 
 
357
static void
 
358
disconnect_handler (gpointer data,
 
359
                    gpointer user_data)
 
360
{
 
361
  HudActionPublisher *publisher = user_data;
 
362
  HudActionDescription *description = data;
 
363
 
 
364
  g_signal_handlers_disconnect_by_func (description, description_changed, publisher);
 
365
}
 
366
 
 
367
/**
 
368
 * hud_action_publisher_add_description:
 
369
 * @publisher: the #HudActionPublisher
 
370
 * @description: an action description
 
371
 *
 
372
 * Adds @description to the list of actions that the application exports
 
373
 * to the HUD.
 
374
 *
 
375
 * If the application is already exporting an action with the same name
 
376
 * and target value as @description then it will be replaced.
 
377
 *
 
378
 * You should only use this API for situations like recent documents and
 
379
 * bookmarks.
 
380
 */
 
381
void
 
382
hud_action_publisher_add_description (HudActionPublisher   *publisher,
 
383
                                      HudActionDescription *description)
 
384
{
 
385
  GSequenceIter *iter;
 
386
 
 
387
  iter = g_sequence_lookup (publisher->descriptions, description, compare_descriptions, NULL);
 
388
 
 
389
  if (iter == NULL)
 
390
    {
 
391
      /* We are not replacing -- add new. */
 
392
      iter = g_sequence_insert_sorted (publisher->descriptions, description, compare_descriptions, NULL);
 
393
 
 
394
      /* Signal that we added the items */
 
395
      g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 0, 1);
 
396
    }
 
397
  else
 
398
    {
 
399
      /* We are replacing an existing item. */
 
400
      disconnect_handler (g_sequence_get (iter), publisher);
 
401
      g_sequence_set (iter, description);
 
402
 
 
403
      /* A replace is 1 remove and 1 add */
 
404
      g_menu_model_items_changed (G_MENU_MODEL (publisher->aux), g_sequence_iter_get_position (iter), 1, 1);
 
405
    }
 
406
 
 
407
  g_object_ref (description);
 
408
 
 
409
  g_signal_connect (description, "changed", G_CALLBACK (description_changed), publisher);
 
410
}
 
411
 
 
412
/**
 
413
 * hud_action_publisher_add_action_group:
 
414
 * @publisher: a #HudActionPublisher
 
415
 * @prefix: the action prefix for the group (like "app")
 
416
 * @object_path: the object path of the exported group
 
417
 *
 
418
 * Informs the HUD of the existance of an action group.
 
419
 *
 
420
 * The action group must be published on the shared session bus
 
421
 * connection of this process at @object_path.
 
422
 *
 
423
 * The @prefix defines the type of action group.  Currently "app" and
 
424
 * "win" are supported.  For example, if the exported action group
 
425
 * contained a "quit" action and you wanted to refer to it as "app.quit"
 
426
 * from action descriptions, then you would use the @prefix "app" here.
 
427
 *
 
428
 * @identifier is a piece of identifying information, depending on which
 
429
 * @prefix is used.  Currently, this should be %NULL for the "app"
 
430
 * @prefix and should be a uint32 specifying the window ID (eg: XID) for
 
431
 * the "win" @prefix.
 
432
 *
 
433
 * You do not need to manually export your action groups if you are
 
434
 * using #GApplication.
 
435
 **/
 
436
void
 
437
hud_action_publisher_add_action_group (HudActionPublisher *publisher,
 
438
                                       const gchar        *prefix,
 
439
                                       const gchar        *object_path)
 
440
{
 
441
        g_return_if_fail(HUD_IS_ACTION_PUBLISHER(publisher));
 
442
        g_return_if_fail(prefix != NULL);
 
443
        g_return_if_fail(object_path != NULL);
 
444
 
 
445
        HudActionPublisherActionGroupSet * group = g_new0(HudActionPublisherActionGroupSet, 1);
 
446
 
 
447
        group->prefix = g_strdup(prefix);
 
448
        group->path = g_strdup(object_path);
 
449
 
 
450
        publisher->action_groups = g_list_prepend(publisher->action_groups, group);
 
451
 
 
452
        return;
 
453
}
 
454
 
 
455
/**
 
456
 * hud_action_publisher_remove_action_group:
 
457
 * @publisher: a #HudActionPublisher
 
458
 * @prefix: the action prefix for the group (like "app")
 
459
 * @identifier: (allow none): an identifier, or %NULL
 
460
 *
 
461
 * Informs the HUD that an action group no longer exists.
 
462
 *
 
463
 * This reverses the effect of a previous call to
 
464
 * hud_action_publisher_add_action_group() with the same parameters.
 
465
 */
 
466
void
 
467
hud_action_publisher_remove_action_group (HudActionPublisher *publisher,
 
468
                                          const gchar        *prefix,
 
469
                                          GVariant           *identifier)
 
470
{
 
471
  //hud_manager_remove_actions (publisher->application_id, prefix, identifier);
 
472
}
 
473
 
 
474
/**
 
475
 * hud_action_publisher_get_id:
 
476
 * @publisher: A #HudActionPublisher object
 
477
 *
 
478
 * Grabs the ID for this publisher
 
479
 *
 
480
 * Return value: (transfer none): The ID this publisher was created with
 
481
 */
 
482
GVariant *
 
483
hud_action_publisher_get_id (HudActionPublisher    *publisher)
 
484
{
 
485
        g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), NULL);
 
486
        return publisher->id;
 
487
}
 
488
 
 
489
/**
 
490
 * hud_action_publisher_get_action_groups:
 
491
 * @publisher: A #HudActionPublisher object
 
492
 *
 
493
 * Grabs the action groups for this publisher
 
494
 *
 
495
 * Return value: (transfer container) (element-type HudActionPublisherActionGroupSet *): The groups in this publisher
 
496
 */
 
497
GList *
 
498
hud_action_publisher_get_action_groups (HudActionPublisher    *publisher)
 
499
{
 
500
        g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), NULL);
 
501
        /* TODO: Flesh out */
 
502
 
 
503
        return publisher->action_groups;
 
504
}
 
505
 
 
506
/**
 
507
 * hud_action_publisher_get_description_path:
 
508
 * @publisher: A #HudActionPublisher object
 
509
 *
 
510
 * Grabs the object path of the description for this publisher
 
511
 *
 
512
 * Return value: The object path of the descriptions
 
513
 */
 
514
const gchar *
 
515
hud_action_publisher_get_description_path (HudActionPublisher    *publisher)
 
516
{
 
517
        g_return_val_if_fail(HUD_IS_ACTION_PUBLISHER(publisher), NULL);
 
518
        return publisher->path;
 
519
}
 
520
 
 
521
/**
 
522
 * HudActionDescription:
 
523
 *
 
524
 * A description of an action that is accessible from the HUD.  This is
 
525
 * an opaque structure type and all accesses must be made via the API.
 
526
 **/
 
527
 
 
528
static void
 
529
hud_action_description_finalize (GObject *object)
 
530
{
 
531
  HudActionDescription *description = HUD_ACTION_DESCRIPTION (object);
 
532
 
 
533
  g_free (description->identifier);
 
534
  g_free (description->action);
 
535
  if (description->target)
 
536
    g_variant_unref (description->target);
 
537
  g_hash_table_unref (description->attrs);
 
538
  g_clear_pointer(&description->links, g_hash_table_unref);
 
539
 
 
540
  G_OBJECT_CLASS (hud_action_description_parent_class)
 
541
    ->finalize (object);
 
542
}
 
543
 
 
544
static void
 
545
hud_action_description_init (HudActionDescription *description)
 
546
{
 
547
  description->attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
 
548
}
 
549
 
 
550
static void
 
551
hud_action_description_class_init (HudActionDescriptionClass *class)
 
552
{
 
553
  class->finalize = hud_action_description_finalize;
 
554
 
 
555
  /**
 
556
   * HudActionDescription::changed:
 
557
   * @param1: Name of changed property
 
558
   *
 
559
   * Emitted when a property of the action description gets
 
560
   * changed.
 
561
   */
 
562
  hud_action_description_changed_signal = g_signal_new ("changed", HUD_TYPE_ACTION_DESCRIPTION,
 
563
                                                        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL,
 
564
                                                        g_cclosure_marshal_VOID__STRING,
 
565
                                                        G_TYPE_NONE, 1, G_TYPE_STRING);
 
566
}
 
567
 
 
568
/**
 
569
 * hud_action_description_new:
 
570
 * @action_name: a (namespaced) action name
 
571
 * @action_target: an action target
 
572
 *
 
573
 * Creates a new #HudActionDescription.
 
574
 *
 
575
 * The situations in which you want to do this are limited to "dynamic"
 
576
 * types of actions -- things like bookmarks or recent documents.
 
577
 *
 
578
 * Use hud_action_publisher_add_descriptions_from_file() to take care of
 
579
 * the bulk of the actions in your application.
 
580
 *
 
581
 * Returns: a new #HudActionDescription with no attributes
 
582
 **/
 
583
HudActionDescription *
 
584
hud_action_description_new (const gchar *action_name,
 
585
                            GVariant    *action_target)
 
586
{
 
587
  HudActionDescription *description;
 
588
 
 
589
  g_return_val_if_fail (action_name != NULL, NULL);
 
590
 
 
591
  description = g_object_new (HUD_TYPE_ACTION_DESCRIPTION, NULL);
 
592
  description->action = g_strdup (action_name);
 
593
  description->target = action_target ? g_variant_ref_sink (action_target) : NULL;
 
594
  description->identifier = format_identifier (action_name, action_target);
 
595
 
 
596
  g_hash_table_insert (description->attrs, g_strdup ("action"),
 
597
                       g_variant_ref_sink (g_variant_new_string (action_name)));
 
598
 
 
599
  if (action_target)
 
600
    g_hash_table_insert (description->attrs, g_strdup ("target"), g_variant_ref_sink (action_target));
 
601
 
 
602
  return description;
 
603
}
 
604
 
 
605
/**
 
606
 * hud_action_description_set_attribute_value:
 
607
 * @description: a #HudActionDescription
 
608
 * @attribute_name: an attribute name
 
609
 * @value: (allow none): the new value for the attribute
 
610
 *
 
611
 * Sets or unsets an attribute on @description.
 
612
 *
 
613
 * You may not change the "action" or "target" attributes.
 
614
 *
 
615
 * If @value is non-%NULL then it is the new value for attribute.  A
 
616
 * %NULL @value unsets @attribute_name.
 
617
 *
 
618
 * @value is consumed if it is floating.
 
619
 **/
 
620
void
 
621
hud_action_description_set_attribute_value (HudActionDescription *description,
 
622
                                            const gchar          *attribute_name,
 
623
                                            GVariant             *value)
 
624
{
 
625
  /* Don't allow setting the action or target as these form the
 
626
   * identity of the description and are stored separately...
 
627
   */
 
628
  g_return_if_fail (!g_str_equal (attribute_name, "action"));
 
629
  g_return_if_fail (!g_str_equal (attribute_name, "target"));
 
630
 
 
631
  if (value)
 
632
    g_hash_table_insert (description->attrs, g_strdup (attribute_name), g_variant_ref_sink (value));
 
633
  else
 
634
    g_hash_table_remove (description->attrs, attribute_name);
 
635
 
 
636
  g_signal_emit (description, hud_action_description_changed_signal,
 
637
                 g_quark_try_string (attribute_name), attribute_name);
 
638
}
 
639
 
 
640
/**
 
641
 * hud_action_description_set_attribute:
 
642
 * @description: a #HudActionDescription
 
643
 * @attribute_name: an attribute name
 
644
 * @format_string: (allow none): a #GVariant format string
 
645
 * @...: arguments to @format_string
 
646
 *
 
647
 * Sets or unsets an attribute on @description.
 
648
 *
 
649
 * You may not change the "action" or "target" attributes.
 
650
 *
 
651
 * If @format_string is non-%NULL then this call is equivalent to
 
652
 * g_variant_new() and hud_action_description_set_attribute_value().
 
653
 *
 
654
 * If @format_string is %NULL then this call is equivalent to
 
655
 * hud_action_description_set_attribute_value() with a %NULL value.
 
656
 **/
 
657
void
 
658
hud_action_description_set_attribute (HudActionDescription *description,
 
659
                                      const gchar          *attribute_name,
 
660
                                      const gchar          *format_string,
 
661
                                      ...)
 
662
{
 
663
  GVariant *value;
 
664
 
 
665
  if (format_string != NULL)
 
666
    {
 
667
      va_list ap;
 
668
 
 
669
      va_start (ap, format_string);
 
670
      value = g_variant_new_va (format_string, NULL, &ap);
 
671
      va_end (ap);
 
672
    }
 
673
  else
 
674
    value = NULL;
 
675
 
 
676
  hud_action_description_set_attribute_value (description, attribute_name, value);
 
677
}
 
678
 
 
679
/**
 
680
 * hud_action_description_get_action_name:
 
681
 * @description: a #HudActionDescription
 
682
 *
 
683
 * Gets the action name of @description.
 
684
 *
 
685
 * This, together with the action target, uniquely identify an action
 
686
 * description.
 
687
 *
 
688
 * Returns: (transfer none): the action name
 
689
 **/
 
690
const gchar *
 
691
hud_action_description_get_action_name (HudActionDescription *description)
 
692
{
 
693
  return description->action;
 
694
}
 
695
 
 
696
/**
 
697
 * hud_action_description_get_action_target:
 
698
 * @description: a #HudActionDescription
 
699
 *
 
700
 * Gets the action target of @description (ie: the #GVariant that will
 
701
 * be passed to invocations of the action).
 
702
 *
 
703
 * This may be %NULL.
 
704
 *
 
705
 * This, together with the action name, uniquely identify an action
 
706
 * description.
 
707
 *
 
708
 * Returns: (transfer none): the target value
 
709
 **/
 
710
GVariant *
 
711
hud_action_description_get_action_target (HudActionDescription *description)
 
712
{
 
713
  return description->target;
 
714
}
 
715
 
 
716
/**
 
717
 * hud_action_description_set_parameterized:
 
718
 * @parent: a #HudActionDescription
 
719
 * @child: The child #GMenuModel to add
 
720
 *
 
721
 * A function to put one action description as a child for the first
 
722
 * one.  This is used for parameterized actions where one can set up
 
723
 * children that are displayed on the 'dialog' mode of the HUD.
 
724
 */
 
725
void
 
726
hud_action_description_set_parameterized (HudActionDescription * parent, GMenuModel * child)
 
727
{
 
728
        g_return_if_fail(HUD_IS_ACTION_DESCRIPTION(parent));
 
729
        g_return_if_fail(child == NULL || G_IS_MENU_MODEL(child)); /* NULL is allowed to clear it */
 
730
 
 
731
        if (parent->links == NULL) {
 
732
                parent->links = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
 
733
        }
 
734
 
 
735
        if (child != NULL) {
 
736
                g_hash_table_insert(parent->links, g_strdup(G_MENU_LINK_SUBMENU), g_object_ref(child));
 
737
        } else {
 
738
                g_hash_table_remove(parent->links, G_MENU_LINK_SUBMENU);
 
739
        }
 
740
 
 
741
        g_signal_emit (parent, hud_action_description_changed_signal,
 
742
                       g_quark_try_string (G_MENU_LINK_SUBMENU), G_MENU_LINK_SUBMENU);
 
743
 
 
744
        return;
 
745
}
 
746
 
 
747
/**
 
748
 * hud_action_description_ref:
 
749
 * @description: A #HudActionDescription
 
750
 *
 
751
 * Increase the reference count to an action description
 
752
 *
 
753
 * Return value: (transfer none): Value of @description
 
754
 */
 
755
HudActionDescription *
 
756
hud_action_description_ref (HudActionDescription  * description)
 
757
{
 
758
        g_return_val_if_fail(HUD_IS_ACTION_DESCRIPTION(description), NULL);
 
759
 
 
760
        return HUD_ACTION_DESCRIPTION(g_object_ref(description));
 
761
}
 
762
 
 
763
/**
 
764
 * hud_action_description_unref:
 
765
 * @description: A #HudActionDescription
 
766
 *
 
767
 * Decrease the reference count to an action description
 
768
 */
 
769
void
 
770
hud_action_description_unref (HudActionDescription * description)
 
771
{
 
772
        g_return_if_fail(HUD_IS_ACTION_DESCRIPTION(description));
 
773
 
 
774
        return g_object_unref(description);
 
775
}