1 /*
2 * Copyright (C) 2010-2011 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Jason Smith <jason.smith@canonical.com>
17 * Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
18 *
19 */
20
21 #include "bamf-view.h"
22
23 #define BAMF_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
24 BAMF_TYPE_VIEW, BamfViewPrivate))
25
26 static void bamf_view_dbus_view_iface_init (BamfDBusItemViewIface *iface);
27 G_DEFINE_TYPE_WITH_CODE (BamfView, bamf_view, BAMF_DBUS_ITEM_TYPE_OBJECT_SKELETON,
28 G_IMPLEMENT_INTERFACE (BAMF_DBUS_ITEM_TYPE_VIEW,
29 bamf_view_dbus_view_iface_init));
30
31 #define STARTING_MAX_WAIT 15
32
33 enum
34 {
35 PROP_0,
36
37 PROP_NAME,
38 PROP_ICON,
39 PROP_ACTIVE,
40 PROP_STARTING,
41 PROP_RUNNING,
42 PROP_URGENT,
43 PROP_USER_VISIBLE,
44 };
45
46 enum
47 {
48 CLOSED_INTERNAL,
49 EXPORTED,
50
51 LAST_SIGNAL,
52 };
53
54 static guint view_signals[LAST_SIGNAL] = { 0 };
55
56 typedef struct _BamfViewPropCache
57 {
58 /* FIXME: temporary cache these properties until we don't export the view
59 * to the bus, we need this until the skeleton won't be smart enough to emit
60 * signals as soon as the object is exported */
61 gboolean starting;
62 gboolean running;
63 gboolean user_visible;
64 gboolean urgent;
65 gboolean active;
66
67 gchar *name;
68 gchar *icon;
69 } BamfViewPropCache;
70
71 struct _BamfViewPrivate
72 {
73 BamfDBusItemView * dbus_iface;
74 BamfViewPropCache * props;
75 char * path;
76 GList * children;
77 GList * parents;
78 gboolean closed;
79 guint starting_timeout;
80
81 SnStartupSequence *startup_sequence;
82
83 /* FIXME: remove this as soon as we move to properties on library as well */
84 guint active_changed_idle;
85 };
86
87 static gboolean
on_active_changed_idle(gpointer data)88 on_active_changed_idle (gpointer data)
89 {
90 g_return_val_if_fail (BAMF_IS_VIEW (data), FALSE);
91
92 BamfView *self = BAMF_VIEW (data);
93 gboolean active = bamf_view_is_active (self);
94
95 g_signal_emit_by_name (self, "active-changed", active);
96 self->priv->active_changed_idle = 0;
97
98 return FALSE;
99 }
100
101 static void
bamf_view_active_changed(BamfView * view,gboolean active)102 bamf_view_active_changed (BamfView *view, gboolean active)
103 {
104 g_return_if_fail (BAMF_IS_VIEW (view));
105
106 gboolean emit = TRUE;
107 if (BAMF_VIEW_GET_CLASS (view)->active_changed)
108 {
109 emit = !BAMF_VIEW_GET_CLASS (view)->active_changed (view, active);
110 }
111
112 if (emit)
113 {
114 if (view->priv->active_changed_idle)
115 g_source_remove (view->priv->active_changed_idle);
116
117 guint idle = g_idle_add_full (G_PRIORITY_DEFAULT, on_active_changed_idle, view, NULL);
118 view->priv->active_changed_idle = idle;
119 }
120
121 if (active)
122 bamf_view_set_starting (view, NULL, FALSE);
123 }
124
125 static void
bamf_view_name_changed(BamfView * view,const gchar * new_name)126 bamf_view_name_changed (BamfView *view, const gchar *new_name)
127 {
128 g_return_if_fail (BAMF_IS_VIEW (view));
129
130 const gchar *old_name = bamf_view_get_name (view);
131 g_signal_emit_by_name (view, "name-changed", old_name, new_name);
132 }
133
134 static void
bamf_view_icon_changed(BamfView * view,const gchar * new_icon)135 bamf_view_icon_changed (BamfView *view, const gchar *new_icon)
136 {
137 g_object_notify (G_OBJECT (view), "icon");
138 }
139
140 static void
bamf_view_user_visible_changed(BamfView * view,gboolean user_visible)141 bamf_view_user_visible_changed (BamfView *view, gboolean user_visible)
142 {
143 g_return_if_fail (BAMF_IS_VIEW (view));
144
145 gboolean emit = TRUE;
146 if (BAMF_VIEW_GET_CLASS (view)->user_visible_changed)
147 {
148 emit = !BAMF_VIEW_GET_CLASS (view)->user_visible_changed (view, user_visible);
149 }
150
151 if (emit)
152 g_signal_emit_by_name (view, "user-visible-changed", user_visible);
153 }
154
155 static gboolean
on_starting_timeout(gpointer data)156 on_starting_timeout (gpointer data)
157 {
158 BamfView *view = data;
159
160 bamf_view_set_starting (view, NULL, FALSE);
161 view->priv->starting_timeout = 0;
162
163 return FALSE;
164 }
165
166 static void
bamf_view_starting_changed(BamfView * view,gboolean starting)167 bamf_view_starting_changed (BamfView *view, gboolean starting)
168 {
169 BamfViewPrivate *priv;
170
171 g_return_if_fail (BAMF_IS_VIEW (view));
172
173 priv = view->priv;
174
175 if (BAMF_VIEW_GET_CLASS (view)->starting_changed)
176 {
177 BAMF_VIEW_GET_CLASS (view)->starting_changed (view, starting);
178 }
179
180 if (priv->starting_timeout)
181 {
182 g_source_remove (priv->starting_timeout);
183 priv->starting_timeout = 0;
184 }
185
186 if (starting)
187 priv->starting_timeout = g_timeout_add_seconds (STARTING_MAX_WAIT, on_starting_timeout, view);
188 }
189
190 static void
bamf_view_running_changed(BamfView * view,gboolean running)191 bamf_view_running_changed (BamfView *view, gboolean running)
192 {
193 g_return_if_fail (BAMF_IS_VIEW (view));
194
195 gboolean emit = TRUE;
196 if (BAMF_VIEW_GET_CLASS (view)->running_changed)
197 {
198 emit = !BAMF_VIEW_GET_CLASS (view)->running_changed (view, running);
199 }
200
201 if (emit)
202 g_signal_emit_by_name (view, "running-changed", running);
203
204 if (running)
205 bamf_view_set_starting (view, NULL, FALSE);
206 }
207
208 static void
bamf_view_urgent_changed(BamfView * view,gboolean urgent)209 bamf_view_urgent_changed (BamfView *view, gboolean urgent)
210 {
211 g_return_if_fail (BAMF_IS_VIEW (view));
212
213 gboolean emit = TRUE;
214 if (BAMF_VIEW_GET_CLASS (view)->urgent_changed)
215 {
216 emit = !BAMF_VIEW_GET_CLASS (view)->urgent_changed (view, urgent);
217 }
218
219 if (emit)
220 g_signal_emit_by_name (view, "urgent-changed", urgent);
221
222 if (urgent)
223 bamf_view_set_starting (view, NULL, FALSE);
224 }
225
226 void
bamf_view_close(BamfView * view)227 bamf_view_close (BamfView *view)
228 {
229 BamfViewPrivate *priv;
230 gboolean emit = TRUE;
231 GList *l;
232
233 g_return_if_fail (BAMF_IS_VIEW (view));
234 priv = view->priv;
235
236 if (priv->closed)
237 return;
238
239 priv->closed = TRUE;
240
241 if (BAMF_VIEW_GET_CLASS (view)->closed)
242 {
243 emit = !BAMF_VIEW_GET_CLASS (view)->closed (view);
244 }
245
246 if (priv->children)
247 {
248 for (l = priv->children; l; l = l->next)
249 {
250 if (BAMF_IS_VIEW (l->data))
251 bamf_view_remove_child (view, l->data);
252 }
253 g_list_free (priv->children);
254 priv->children = NULL;
255 }
256
257 if (emit)
258 {
259 g_object_ref (view);
260 g_signal_emit (view, view_signals[CLOSED_INTERNAL], 0);
261 g_signal_emit_by_name (view, "closed");
262 g_object_unref (view);
263 }
264 }
265
266 const char *
bamf_view_get_path(BamfView * view)267 bamf_view_get_path (BamfView *view)
268 {
269 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
270
271 return view->priv->path;
272 }
273
274 GVariant *
bamf_view_get_children_paths(BamfView * view)275 bamf_view_get_children_paths (BamfView *view)
276 {
277 GVariantBuilder b;
278 GList *l;
279
280 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
281
282 g_variant_builder_init (&b, G_VARIANT_TYPE ("(as)"));
283 g_variant_builder_open (&b, G_VARIANT_TYPE ("as"));
284
285 for (l = view->priv->children; l; l = l->next)
286 {
287 BamfView *child = l->data;
288 const char *path = bamf_view_get_path (child);
289
290 if (!path)
291 continue;
292
293 g_variant_builder_add (&b, "s", path);
294 }
295
296 g_variant_builder_close (&b);
297
298 return g_variant_builder_end (&b);
299 }
300
301 GList *
bamf_view_get_children(BamfView * view)302 bamf_view_get_children (BamfView *view)
303 {
304 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
305
306 return view->priv->children;
307 }
308
309 GVariant *
bamf_view_get_parent_paths(BamfView * view)310 bamf_view_get_parent_paths (BamfView *view)
311 {
312 GVariantBuilder b;
313 GList *l;
314
315 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
316
317 g_variant_builder_init (&b, G_VARIANT_TYPE ("(as)"));
318 g_variant_builder_open (&b, G_VARIANT_TYPE ("as"));
319
320 for (l = view->priv->parents; l; l = l->next)
321 {
322 BamfView *parent = l->data;
323 const char *path = bamf_view_get_path (parent);
324
325 if (!path)
326 continue;
327
328 g_variant_builder_add (&b, "s", path);
329 }
330
331 g_variant_builder_close (&b);
332
333 return g_variant_builder_end (&b);
334 }
335
336 GList *
bamf_view_get_parents(BamfView * view)337 bamf_view_get_parents (BamfView *view)
338 {
339 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
340
341 return view->priv->parents;
342 }
343
344 static void
bamf_view_handle_child_closed(BamfView * child,BamfView * view)345 bamf_view_handle_child_closed (BamfView *child,
346 BamfView *view)
347 {
348 bamf_view_remove_child (view, child);
349 }
350
351 static void
on_child_view_exported(BamfView * child,BamfView * view)352 on_child_view_exported (BamfView *child, BamfView *view)
353 {
354 g_signal_emit_by_name (view, "child-added", bamf_view_get_path (child));
355 g_signal_handlers_disconnect_by_func (child, on_child_view_exported, view);
356 }
357
358 void
bamf_view_add_child(BamfView * view,BamfView * child)359 bamf_view_add_child (BamfView *view,
360 BamfView *child)
361 {
362 const char * added;
363
364 g_return_if_fail (BAMF_IS_VIEW (view));
365 g_return_if_fail (BAMF_IS_VIEW (child));
366
367 g_signal_connect (G_OBJECT (child), "closed-internal",
368 G_CALLBACK (bamf_view_handle_child_closed), view);
369
370 /* Make sure our parent child lists are ok, pay attention to whose list you add parents to */
371 view->priv->children = g_list_prepend (view->priv->children, child);
372 child->priv->parents = g_list_prepend (child->priv->parents, view);
373
374 if (bamf_view_is_on_bus (child))
375 {
376 added = bamf_view_get_path (child);
377 g_signal_emit_by_name (view, "child-added", added);
378 }
379 else
380 {
381 g_signal_connect (G_OBJECT (child), "exported",
382 G_CALLBACK (on_child_view_exported), view);
383 }
384
385 // Do this by hand so we can pass and object instead of a string
386 if (BAMF_VIEW_GET_CLASS (view)->child_added)
387 BAMF_VIEW_GET_CLASS (view)->child_added (view, child);
388 }
389
390 void
bamf_view_remove_child(BamfView * view,BamfView * child)391 bamf_view_remove_child (BamfView *view, BamfView *child)
392 {
393 const char *removed;
394
395 g_return_if_fail (BAMF_IS_VIEW (view));
396 g_return_if_fail (BAMF_IS_VIEW (child));
397
398 g_signal_handlers_disconnect_by_data (child, view);
399
400 /* Make sure our parent child lists are ok, pay attention to whose list you add parents to */
401 view->priv->children = g_list_remove (view->priv->children, child);
402 child->priv->parents = g_list_remove (child->priv->parents, view);
403
404 removed = bamf_view_get_path (child);
405 g_signal_emit_by_name (view, "child-removed", removed);
406
407 /* Do this by hand so we can pass and object instead of a string */
408 if (BAMF_VIEW_GET_CLASS (view)->child_removed)
409 BAMF_VIEW_GET_CLASS (view)->child_removed (view, child);
410 }
411
412 #define BAMF_VIEW_GET_PROPERTY(v, property, ret_val) \
413 g_return_val_if_fail (BAMF_IS_VIEW (v), ret_val); \
414 \
415 if (v->priv->props) \
416 return v->priv->props->property; \
417 \
418 return _bamf_dbus_item_view_get_##property (v->priv->dbus_iface);
419
420 #define BAMF_VIEW_SET_BOOL_PROPERTY(v, property) \
421 g_return_if_fail (BAMF_IS_VIEW (v)); \
422 \
423 if (property == bamf_view_is_##property (v)) \
424 return; \
425 \
426 if (v->priv->props) \
427 { \
428 v->priv->props->property = property; \
429 } \
430 else \
431 { \
432 _bamf_dbus_item_view_set_##property (v->priv->dbus_iface, property); \
433 } \
434 \
435 bamf_view_##property##_changed (v, property);
436
437 #define BAMF_VIEW_SET_STRING_PROPERTY(v, property) \
438 g_return_if_fail (BAMF_IS_VIEW (v)); \
439 \
440 const gchar *current_value = bamf_view_get_##property (v); \
441 \
442 if (current_value == property || g_strcmp0 (current_value, property) == 0) \
443 return; \
444 \
445 bamf_view_##property##_changed (v, property); \
446 \
447 if (v->priv->props) \
448 { \
449 g_free (v->priv->props->property); \
450 v->priv->props->property = g_strdup (property); \
451 } \
452 else \
453 { \
454 _bamf_dbus_item_view_set_##property (v->priv->dbus_iface, property); \
455 }
456
457 gboolean
bamf_view_is_active(BamfView * view)458 bamf_view_is_active (BamfView *view)
459 {
460 BAMF_VIEW_GET_PROPERTY (view, active, FALSE);
461 }
462
463 void
bamf_view_set_active(BamfView * view,gboolean active)464 bamf_view_set_active (BamfView *view,
465 gboolean active)
466 {
467 BAMF_VIEW_SET_BOOL_PROPERTY (view, active);
468 }
469
470 gboolean
bamf_view_is_urgent(BamfView * view)471 bamf_view_is_urgent (BamfView *view)
472 {
473 BAMF_VIEW_GET_PROPERTY (view, urgent, FALSE);
474 }
475
476 void
bamf_view_set_urgent(BamfView * view,gboolean urgent)477 bamf_view_set_urgent (BamfView *view,
478 gboolean urgent)
479 {
480 BAMF_VIEW_SET_BOOL_PROPERTY (view, urgent);
481 }
482
483 gboolean
bamf_view_is_starting(BamfView * view)484 bamf_view_is_starting (BamfView *view)
485 {
486 BAMF_VIEW_GET_PROPERTY (view, starting, FALSE);
487 }
488
489 void
bamf_view_set_starting(BamfView * view,SnStartupSequence * startup_sequence,gboolean starting)490 bamf_view_set_starting (BamfView *view,
491 SnStartupSequence *startup_sequence,
492 gboolean starting)
493 {
494 if (!bamf_view_is_starting (view) && starting)
495 {
496 if (view->priv->startup_sequence)
497 {
498 sn_startup_sequence_unref (view->priv->startup_sequence);
499 view->priv->startup_sequence = NULL;
500 }
501
502 if (startup_sequence)
503 {
504 view->priv->startup_sequence = startup_sequence;
505 sn_startup_sequence_ref (view->priv->startup_sequence);
506 }
507 }
508 else if (!starting)
509 {
510 if (view->priv->startup_sequence)
511 {
512 sn_startup_sequence_complete (view->priv->startup_sequence);
513 sn_startup_sequence_unref (view->priv->startup_sequence);
514 view->priv->startup_sequence = NULL;
515 }
516 }
517
518 BAMF_VIEW_SET_BOOL_PROPERTY (view, starting);
519 }
520
521 gboolean
bamf_view_is_running(BamfView * view)522 bamf_view_is_running (BamfView *view)
523 {
524 BAMF_VIEW_GET_PROPERTY (view, running, FALSE);
525 }
526
527 void
bamf_view_set_running(BamfView * view,gboolean running)528 bamf_view_set_running (BamfView *view,
529 gboolean running)
530 {
531 BAMF_VIEW_SET_BOOL_PROPERTY (view, running);
532 }
533
534 gboolean
bamf_view_is_user_visible(BamfView * view)535 bamf_view_is_user_visible (BamfView *view)
536 {
537 BAMF_VIEW_GET_PROPERTY (view, user_visible, FALSE);
538 }
539
540 void
bamf_view_set_user_visible(BamfView * view,gboolean user_visible)541 bamf_view_set_user_visible (BamfView *view, gboolean user_visible)
542 {
543 BAMF_VIEW_SET_BOOL_PROPERTY (view, user_visible);
544 }
545
546 const char *
bamf_view_get_icon(BamfView * view)547 bamf_view_get_icon (BamfView *view)
548 {
549 BAMF_VIEW_GET_PROPERTY (view, icon, NULL);
550 }
551
552 void
bamf_view_set_icon(BamfView * view,const char * icon)553 bamf_view_set_icon (BamfView *view, const char *icon)
554 {
555 BAMF_VIEW_SET_STRING_PROPERTY (view, icon);
556 }
557
558 const char *
bamf_view_get_name(BamfView * view)559 bamf_view_get_name (BamfView *view)
560 {
561 BAMF_VIEW_GET_PROPERTY (view, name, NULL);
562 }
563
564 void
bamf_view_set_name(BamfView * view,const char * name)565 bamf_view_set_name (BamfView *view, const char *name)
566 {
567 BAMF_VIEW_SET_STRING_PROPERTY (view, name);
568 }
569
570 const char *
bamf_view_get_view_type(BamfView * view)571 bamf_view_get_view_type (BamfView *view)
572 {
573 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
574
575 if (BAMF_VIEW_GET_CLASS (view)->view_type)
576 return BAMF_VIEW_GET_CLASS (view)->view_type (view);
577
578 return "view";
579 }
580
581 static char *
bamf_view_get_stable_bus_name(BamfView * view)582 bamf_view_get_stable_bus_name (BamfView *view)
583 {
584 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
585
586 if (BAMF_VIEW_GET_CLASS (view)->stable_bus_name)
587 return BAMF_VIEW_GET_CLASS (view)->stable_bus_name (view);
588
589 return g_strdup_printf ("view/%p", view);
590 }
591
592 static void
bamf_view_cached_properties_clear(BamfView * view)593 bamf_view_cached_properties_clear (BamfView *view)
594 {
595 if (!view->priv->props)
596 return;
597
598 g_free (view->priv->props->name);
599 g_free (view->priv->props->icon);
600 g_free (view->priv->props);
601 view->priv->props = NULL;
602 }
603
604 static void
bamf_view_cached_properties_notify(BamfView * view)605 bamf_view_cached_properties_notify (BamfView *view)
606 {
607 if (!view->priv->props || !bamf_view_is_on_bus (view))
608 return;
609
610 /* Temporary disable the cache so that cached values will be set on the skeleton */
611 BamfViewPropCache *cache = view->priv->props;
612 view->priv->props = NULL;
613
614 bamf_view_set_name (view, cache->name);
615 bamf_view_set_icon (view, cache->icon);
616 bamf_view_set_active (view, cache->active);
617 bamf_view_set_starting (view, NULL, cache->starting);
618 bamf_view_set_running (view, cache->running);
619 bamf_view_set_user_visible (view, cache->user_visible);
620 bamf_view_set_urgent (view, cache->urgent);
621
622 view->priv->props = cache;
623 }
624
625 const char *
bamf_view_export_on_bus(BamfView * view,GDBusConnection * connection)626 bamf_view_export_on_bus (BamfView *view, GDBusConnection *connection)
627 {
628 char *path = NULL;
629 GList *ifaces, *l;
630 GError *error = NULL;
631
632 g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
633 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
634
635 if (!view->priv->path)
636 {
637 gboolean exported = TRUE;
638 char *stable_name = bamf_view_get_stable_bus_name (view);
639 path = g_strconcat (BAMF_DBUS_BASE_PATH, "/", stable_name, NULL);
640 g_free (stable_name);
641
642 BAMF_VIEW_GET_CLASS (view)->names = g_list_prepend (BAMF_VIEW_GET_CLASS (view)->names, path);
643 view->priv->path = path;
644
645 ifaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (view));
646
647 /* The dbus object interface list is in reversed order, we try to export
648 * the interfaces in bottom to top order (BamfView should be the first) */
649 for (l = g_list_last (ifaces); l; l = l->prev)
650 {
651 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (l->data),
652 connection, path, &error);
653 if (error)
654 {
655 g_critical ("Can't register BAMF view interface: %s", error->message);
656 g_clear_error (&error);
657 exported = FALSE;
658 }
659 }
660
661 if (exported)
662 {
663 /* FIXME: if we change the properties before that the view has been
664 * exported, the skeleton doesn't emit the proper signals to notify
665 * the proxy that the values have been changed, and this causes
666 * the properties not to be updated on the client side.
667 * So we store the values locally until the proxy is not exported,
668 * then we notify our clients. */
669 bamf_view_cached_properties_notify (view);
670 bamf_view_cached_properties_clear (view);
671
672 g_signal_emit (view, view_signals[EXPORTED], 0);
673 }
674
675 g_list_free_full (ifaces, g_object_unref);
676 }
677
678 return view->priv->path;
679 }
680
681 gboolean
bamf_view_is_on_bus(BamfView * view)682 bamf_view_is_on_bus (BamfView *view)
683 {
684 g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
685 GDBusInterfaceSkeleton *dbus_iface;
686 const gchar *exported_path;
687
688 if (!view->priv->path)
689 return FALSE;
690
691 dbus_iface = G_DBUS_INTERFACE_SKELETON (view->priv->dbus_iface);
692 exported_path = g_dbus_interface_skeleton_get_object_path (dbus_iface);
693
694 return (exported_path != NULL);
695 }
696
697 static void
on_view_active_changed(BamfView * view,gboolean active,gpointer _not_used)698 on_view_active_changed (BamfView *view, gboolean active, gpointer _not_used)
699 {
700 g_return_if_fail (BAMF_IS_VIEW (view));
701 g_signal_emit_by_name (view->priv->dbus_iface, "active-changed", active);
702 }
703
704 static void
on_view_running_changed(BamfView * view,gboolean running,gpointer _not_used)705 on_view_running_changed (BamfView *view, gboolean running, gpointer _not_used)
706 {
707 g_return_if_fail (BAMF_IS_VIEW (view));
708 g_signal_emit_by_name (view->priv->dbus_iface, "running-changed", running);
709 }
710
711 static void
on_view_urgent_changed(BamfView * view,gboolean urgent,gpointer _not_used)712 on_view_urgent_changed (BamfView *view, gboolean urgent, gpointer _not_used)
713 {
714 g_return_if_fail (BAMF_IS_VIEW (view));
715 g_signal_emit_by_name (view->priv->dbus_iface, "urgent-changed", urgent);
716 }
717
718 static void
on_view_user_visible_changed(BamfView * view,gboolean user_visible,gpointer _not_used)719 on_view_user_visible_changed (BamfView *view, gboolean user_visible, gpointer _not_used)
720 {
721 g_return_if_fail (BAMF_IS_VIEW (view));
722 g_signal_emit_by_name (view->priv->dbus_iface, "user-visible-changed", user_visible);
723 }
724
725 static void
on_view_name_changed(BamfView * view,const gchar * old_name,const gchar * new_name,gpointer _not_used)726 on_view_name_changed (BamfView *view, const gchar *old_name, const gchar *new_name, gpointer _not_used)
727 {
728 g_return_if_fail (BAMF_IS_VIEW (view));
729 g_signal_emit_by_name (view->priv->dbus_iface, "name-changed",
730 old_name ? old_name : "", new_name ? new_name : "");
731 }
732
733 static void
on_view_child_added(BamfView * view,const gchar * child_path,gpointer _not_used)734 on_view_child_added (BamfView *view, const gchar *child_path, gpointer _not_used)
735 {
736 g_return_if_fail (BAMF_IS_VIEW (view));
737 g_signal_emit_by_name (view->priv->dbus_iface, "child-added",
738 child_path ? child_path : "");
739 }
740
741 static void
on_view_child_removed(BamfView * view,const gchar * child_path,gpointer _not_used)742 on_view_child_removed (BamfView *view, const gchar *child_path, gpointer _not_used)
743 {
744 g_return_if_fail (BAMF_IS_VIEW (view));
745 g_signal_emit_by_name (view->priv->dbus_iface, "child-removed",
746 child_path ? child_path : "");
747 }
748
749 static void
on_view_closed(BamfView * view,gpointer _not_used)750 on_view_closed (BamfView *view, gpointer _not_used)
751 {
752 g_return_if_fail (BAMF_IS_VIEW (view));
753 g_dbus_object_skeleton_flush (G_DBUS_OBJECT_SKELETON (view));
754 g_signal_emit_by_name (view->priv->dbus_iface, "closed");
755 }
756
757 static gboolean
on_dbus_handle_view_type(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)758 on_dbus_handle_view_type (BamfDBusItemView *interface,
759 GDBusMethodInvocation *invocation,
760 BamfView *view)
761 {
762 const char *type = bamf_view_get_view_type (view);
763 g_dbus_method_invocation_return_value (invocation,
764 g_variant_new ("(s)", type));
765
766 return TRUE;
767 }
768
769 static gboolean
on_dbus_handle_user_visible(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)770 on_dbus_handle_user_visible (BamfDBusItemView *interface,
771 GDBusMethodInvocation *invocation,
772 BamfView *view)
773 {
774 gboolean user_visible = bamf_view_is_user_visible (view);
775 g_dbus_method_invocation_return_value (invocation,
776 g_variant_new ("(b)", user_visible));
777
778 return TRUE;
779 }
780
781 static gboolean
on_dbus_handle_icon(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)782 on_dbus_handle_icon (BamfDBusItemView *interface,
783 GDBusMethodInvocation *invocation,
784 BamfView *view)
785 {
786 const char *icon = bamf_view_get_icon (view);
787 g_dbus_method_invocation_return_value (invocation,
788 g_variant_new ("(s)", icon ? icon : ""));
789
790 return TRUE;
791 }
792
793 static gboolean
on_dbus_handle_name(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)794 on_dbus_handle_name (BamfDBusItemView *interface,
795 GDBusMethodInvocation *invocation,
796 BamfView *view)
797 {
798 const char *name = bamf_view_get_name (view);
799 g_dbus_method_invocation_return_value (invocation,
800 g_variant_new ("(s)", name ? name : ""));
801
802 return TRUE;
803 }
804
805 static gboolean
on_dbus_handle_is_urgent(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)806 on_dbus_handle_is_urgent (BamfDBusItemView *interface,
807 GDBusMethodInvocation *invocation,
808 BamfView *view)
809 {
810 gboolean is_urgent = bamf_view_is_urgent (view);
811 g_dbus_method_invocation_return_value (invocation,
812 g_variant_new ("(b)", is_urgent));
813
814 return TRUE;
815 }
816
817 static gboolean
on_dbus_handle_is_running(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)818 on_dbus_handle_is_running (BamfDBusItemView *interface,
819 GDBusMethodInvocation *invocation,
820 BamfView *view)
821 {
822 gboolean is_running = bamf_view_is_running (view);
823 g_dbus_method_invocation_return_value (invocation,
824 g_variant_new ("(b)", is_running));
825
826 return TRUE;
827 }
828
829 static gboolean
on_dbus_handle_is_active(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)830 on_dbus_handle_is_active (BamfDBusItemView *interface,
831 GDBusMethodInvocation *invocation,
832 BamfView *view)
833 {
834 gboolean is_active = bamf_view_is_active (view);
835 g_dbus_method_invocation_return_value (invocation,
836 g_variant_new ("(b)", is_active));
837
838 return TRUE;
839 }
840
841 static gboolean
on_dbus_handle_parents(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)842 on_dbus_handle_parents (BamfDBusItemView *interface,
843 GDBusMethodInvocation *invocation,
844 BamfView *view)
845 {
846 GVariant *parents = bamf_view_get_parent_paths (view);
847 g_dbus_method_invocation_return_value (invocation, parents);
848
849 return TRUE;
850 }
851
852 static gboolean
on_dbus_handle_children(BamfDBusItemView * interface,GDBusMethodInvocation * invocation,BamfView * view)853 on_dbus_handle_children (BamfDBusItemView *interface,
854 GDBusMethodInvocation *invocation,
855 BamfView *view)
856 {
857 GVariant *children = bamf_view_get_children_paths (view);
858 g_dbus_method_invocation_return_value (invocation, children);
859
860 return TRUE;
861 }
862
863 static void
bamf_view_dispose(GObject * object)864 bamf_view_dispose (GObject *object)
865 {
866 BamfView *view = BAMF_VIEW (object);
867 BamfViewPrivate *priv = view->priv;
868
869 if (priv->path)
870 {
871 g_free (priv->path);
872 priv->path = NULL;
873 }
874
875 if (priv->children)
876 {
877 g_list_free (priv->children);
878 priv->children = NULL;
879 }
880
881 if (priv->parents)
882 {
883 g_list_free (priv->parents);
884 priv->parents = NULL;
885 }
886
887 if (priv->starting_timeout)
888 {
889 g_source_remove (priv->starting_timeout);
890 priv->starting_timeout = 0;
891 }
892
893 if (priv->active_changed_idle)
894 {
895 g_source_remove (priv->active_changed_idle);
896 priv->active_changed_idle = 0;
897 }
898
899 if (priv->startup_sequence)
900 {
901 sn_startup_sequence_unref (priv->startup_sequence);
902 priv->startup_sequence = NULL;
903 }
904
905 bamf_view_cached_properties_clear (view);
906 g_dbus_object_skeleton_flush (G_DBUS_OBJECT_SKELETON (view));
907
908 G_OBJECT_CLASS (bamf_view_parent_class)->dispose (object);
909 }
910
911 static void
bamf_view_finalize(GObject * object)912 bamf_view_finalize (GObject *object)
913 {
914 BamfView *view = BAMF_VIEW (object);
915
916 g_object_unref (view->priv->dbus_iface);
917
918 G_OBJECT_CLASS (bamf_view_parent_class)->finalize (object);
919 }
920
921 static void
bamf_view_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)922 bamf_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
923 {
924 BamfView *view = BAMF_VIEW (object);
925
926 switch (property_id)
927 {
928 case PROP_NAME:
929 g_value_set_string (value, bamf_view_get_name (view));
930 break;
931 case PROP_ICON:
932 g_value_set_string (value, bamf_view_get_icon (view));
933 break;
934 case PROP_ACTIVE:
935 g_value_set_boolean (value, bamf_view_is_active (view));
936 break;
937 case PROP_URGENT:
938 g_value_set_boolean (value, bamf_view_is_urgent (view));
939 break;
940 case PROP_USER_VISIBLE:
941 g_value_set_boolean (value, bamf_view_is_user_visible (view));
942 break;
943 case PROP_STARTING:
944 g_value_set_boolean (value, bamf_view_is_starting (view));
945 break;
946 case PROP_RUNNING:
947 g_value_set_boolean (value, bamf_view_is_running (view));
948 break;
949 default:
950 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
951 }
952 }
953
954 static void
bamf_view_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)955 bamf_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
956 {
957 switch (property_id)
958 {
959 default:
960 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
961 }
962 }
963
964 static void
bamf_view_init(BamfView * self)965 bamf_view_init (BamfView * self)
966 {
967 self->priv = BAMF_VIEW_GET_PRIVATE (self);
968
969 /* Initializing the dbus interface */
970 self->priv->dbus_iface = _bamf_dbus_item_view_skeleton_new ();
971 self->priv->props = g_new0 (BamfViewPropCache, 1);
972
973 self->priv->startup_sequence = NULL;
974
975 /* We need to connect to the object own signals to redirect them to the dbus
976 * interface */
977 g_signal_connect (self, "active-changed", G_CALLBACK (on_view_active_changed), NULL);
978 g_signal_connect (self, "running-changed", G_CALLBACK (on_view_running_changed), NULL);
979 g_signal_connect (self, "urgent-changed", G_CALLBACK (on_view_urgent_changed), NULL);
980 g_signal_connect (self, "user-visible-changed", G_CALLBACK (on_view_user_visible_changed), NULL);
981 g_signal_connect (self, "name-changed", G_CALLBACK (on_view_name_changed), NULL);
982 g_signal_connect (self, "child-added", G_CALLBACK (on_view_child_added), NULL);
983 g_signal_connect (self, "child-removed", G_CALLBACK (on_view_child_removed), NULL);
984 g_signal_connect (self, "closed", G_CALLBACK (on_view_closed), NULL);
985
986 /* Registering signal callbacks to reply to dbus method calls */
987 g_signal_connect (self->priv->dbus_iface, "handle-view-type",
988 G_CALLBACK (on_dbus_handle_view_type), self);
989
990 g_signal_connect (self->priv->dbus_iface, "handle-user-visible",
991 G_CALLBACK (on_dbus_handle_user_visible), self);
992
993 g_signal_connect (self->priv->dbus_iface, "handle-icon",
994 G_CALLBACK (on_dbus_handle_icon), self);
995
996 g_signal_connect (self->priv->dbus_iface, "handle-name",
997 G_CALLBACK (on_dbus_handle_name), self);
998
999 g_signal_connect (self->priv->dbus_iface, "handle-is-urgent",
1000 G_CALLBACK (on_dbus_handle_is_urgent), self);
1001
1002 g_signal_connect (self->priv->dbus_iface, "handle-is-running",
1003 G_CALLBACK (on_dbus_handle_is_running), self);
1004
1005 g_signal_connect (self->priv->dbus_iface, "handle-is-active",
1006 G_CALLBACK (on_dbus_handle_is_active), self);
1007
1008 g_signal_connect (self->priv->dbus_iface, "handle-parents",
1009 G_CALLBACK (on_dbus_handle_parents), self);
1010
1011 g_signal_connect (self->priv->dbus_iface, "handle-children",
1012 G_CALLBACK (on_dbus_handle_children), self);
1013
1014 /* Setting the interface for the dbus object */
1015 _bamf_dbus_item_object_skeleton_set_view (BAMF_DBUS_ITEM_OBJECT_SKELETON (self),
1016 self->priv->dbus_iface);
1017 }
1018
1019 static void
bamf_view_dbus_view_iface_init(BamfDBusItemViewIface * iface)1020 bamf_view_dbus_view_iface_init (BamfDBusItemViewIface *iface)
1021 {
1022 }
1023
1024 static void
bamf_view_class_init(BamfViewClass * klass)1025 bamf_view_class_init (BamfViewClass * klass)
1026 {
1027 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1028
1029 object_class->dispose = bamf_view_dispose;
1030 object_class->finalize = bamf_view_finalize;
1031 object_class->get_property = bamf_view_get_property;
1032 object_class->set_property = bamf_view_set_property;
1033
1034 g_type_class_add_private (klass, sizeof (BamfViewPrivate));
1035
1036 /* Overriding the properties defined in the interface, this is needed
1037 * but we actually don't use these properties, as we act like a proxy */
1038 g_object_class_override_property (object_class, PROP_NAME, "name");
1039 g_object_class_override_property (object_class, PROP_ICON, "icon");
1040 g_object_class_override_property (object_class, PROP_ACTIVE, "active");
1041 g_object_class_override_property (object_class, PROP_URGENT, "urgent");
1042 g_object_class_override_property (object_class, PROP_STARTING, "starting");
1043 g_object_class_override_property (object_class, PROP_RUNNING, "running");
1044 g_object_class_override_property (object_class, PROP_USER_VISIBLE, "user-visible");
1045
1046 view_signals [CLOSED_INTERNAL] =
1047 g_signal_new ("closed-internal",
1048 G_OBJECT_CLASS_TYPE (klass),
1049 G_SIGNAL_RUN_LAST,
1050 G_STRUCT_OFFSET (BamfViewClass, closed_internal),
1051 NULL, NULL, NULL,
1052 G_TYPE_NONE, 0);
1053
1054 view_signals [EXPORTED] =
1055 g_signal_new ("exported",
1056 G_OBJECT_CLASS_TYPE (klass),
1057 G_SIGNAL_RUN_FIRST,
1058 G_STRUCT_OFFSET (BamfViewClass, exported),
1059 NULL, NULL, NULL,
1060 G_TYPE_NONE, 0);
1061 }
1062