2
* Copyright 2010 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of either or both of the following licenses:
7
* 1) the GNU Lesser General Public License version 3, as published by the
8
* Free Software Foundation; and/or
9
* 2) the GNU Lesser General Public License version 2.1, as published by
10
* the Free Software Foundation.
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.
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, see
20
* <http://www.gnu.org/licenses/>
22
* Authored by: Jason Smith <jason.smith@canonical.com>
23
* Neil Jagdish Patel <neil.patel@canonical.com>
28
* @short_description: The base class for all views
30
* #BamfView is the base class that all views need to derive from.
37
#include "bamf-view.h"
38
#include "bamf-view-private.h"
39
#include "bamf-factory.h"
40
#include "bamf-window.h"
41
#include "bamf-marshal.h"
43
#include <dbus/dbus.h>
44
#include <dbus/dbus-glib.h>
45
#include <dbus/dbus-glib-lowlevel.h>
47
G_DEFINE_TYPE (BamfView, bamf_view, G_TYPE_INITIALLY_UNOWNED);
49
#define BAMF_VIEW_GET_PRIVATE(o) \
50
(G_TYPE_INSTANCE_GET_PRIVATE ((o), BAMF_TYPE_VIEW, BamfViewPrivate))
54
BAMF_VIEW_RUNNING_FLAG = 1 << 0,
55
BAMF_VIEW_URGENT_FLAG = 1 << 1,
56
BAMF_VIEW_VISIBLE_FLAG = 1 << 2,
57
BAMF_VIEW_ACTIVE_FLAG = 1 << 3,
85
static guint view_signals[LAST_SIGNAL] = { 0 };
87
struct _BamfViewPrivate
89
DBusGConnection *connection;
102
bamf_view_set_flag (BamfView *view, guint flag, gboolean value)
104
BamfViewPrivate *priv;
106
g_return_if_fail (BAMF_IS_VIEW (view));
111
priv->set_flags |= flag;
113
priv->set_flags = priv->set_flags & ~flag;
115
priv->checked_flags |= flag;
119
bamf_view_flag_is_set (BamfView *view, guint flag)
121
BamfViewPrivate *priv;
123
g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
127
return priv->checked_flags & flag;
131
bamf_view_get_flag (BamfView *view, guint flag)
133
BamfViewPrivate *priv;
135
g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
139
return priv->set_flags & flag;
143
bamf_view_get_children (BamfView *view)
147
GList *results = NULL;
148
GError *error = NULL;
149
BamfViewPrivate *priv;
151
g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
153
if (BAMF_VIEW_GET_CLASS (view)->get_children)
154
return BAMF_VIEW_GET_CLASS (view)->get_children (view);
156
if (!bamf_view_remote_ready (view))
161
if (!dbus_g_proxy_call (priv->proxy,
165
G_TYPE_STRV, &children,
168
g_warning ("Unable to fetch children: %s\n", error->message);
175
len = g_strv_length (children);
177
for (i = 0; i < len; i++)
179
BamfView *view = bamf_factory_view_for_path (bamf_factory_get_default (), children[i]);
180
results = g_list_prepend (results, view);
187
bamf_view_get_boolean (BamfView *self, const char *method_name, guint flag)
189
BamfViewPrivate *priv;
190
gboolean result = FALSE;
191
GError *error = NULL;
193
g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
196
if (bamf_view_flag_is_set (self, flag))
197
return bamf_view_get_flag (self, flag);
199
if (!bamf_view_remote_ready (self))
202
if (!dbus_g_proxy_call (priv->proxy,
206
G_TYPE_BOOLEAN, &result,
209
g_warning ("Failed to fetch boolean: %s", error->message);
210
g_error_free (error);
215
bamf_view_set_flag (self, flag, result);
220
bamf_view_is_closed (BamfView *view)
222
g_return_val_if_fail (BAMF_IS_VIEW (view), TRUE);
224
return view->priv->is_closed;
228
bamf_view_is_active (BamfView *view)
230
g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
232
if (BAMF_VIEW_GET_CLASS (view)->is_active)
233
return BAMF_VIEW_GET_CLASS (view)->is_active (view);
235
return bamf_view_get_boolean (view, "IsActive", BAMF_VIEW_ACTIVE_FLAG);
240
bamf_view_user_visible (BamfView *self)
242
g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
244
return bamf_view_get_boolean (self, "UserVisible", BAMF_VIEW_VISIBLE_FLAG);
249
bamf_view_is_running (BamfView *self)
251
g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
253
if (BAMF_VIEW_GET_CLASS (self)->is_running)
254
return BAMF_VIEW_GET_CLASS (self)->is_running (self);
256
return bamf_view_get_boolean (self, "IsRunning", BAMF_VIEW_RUNNING_FLAG);
260
bamf_view_is_urgent (BamfView *self)
262
g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
264
if (BAMF_VIEW_GET_CLASS (self)->is_urgent)
265
return BAMF_VIEW_GET_CLASS (self)->is_urgent (self);
267
return bamf_view_get_boolean (self, "IsUrgent", BAMF_VIEW_URGENT_FLAG);
271
bamf_view_set_name (BamfView *view, const char *name)
273
g_return_if_fail (BAMF_IS_VIEW (view));
275
if (!g_strcmp0 (name, view->priv->local_name))
278
view->priv->local_name = g_strdup (name);
282
bamf_view_set_icon (BamfView *view, const char *icon)
284
g_return_if_fail (BAMF_IS_VIEW (view));
286
view->priv->local_icon = g_strdup (icon);
290
bamf_view_is_sticky (BamfView *view)
292
g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
294
return view->priv->sticky;
298
bamf_view_set_sticky (BamfView *view, gboolean value)
300
g_return_if_fail (BAMF_IS_VIEW (view));
302
if (value == view->priv->sticky)
306
g_object_ref_sink (view);
308
g_object_unref (view);
310
view->priv->sticky = value;
314
bamf_view_get_icon (BamfView *self)
316
BamfViewPrivate *priv;
318
GError *error = NULL;
320
g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
323
if (BAMF_VIEW_GET_CLASS (self)->get_icon)
324
return BAMF_VIEW_GET_CLASS (self)->get_icon (self);
326
if (!bamf_view_remote_ready (self))
327
return g_strdup (priv->local_icon);
329
if (!dbus_g_proxy_call (priv->proxy,
333
G_TYPE_STRING, &icon,
336
g_warning ("Failed to fetch icon: %s", error->message);
337
g_error_free (error);
346
bamf_view_get_name (BamfView *self)
348
BamfViewPrivate *priv;
350
GError *error = NULL;
352
g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
355
if (BAMF_VIEW_GET_CLASS (self)->get_name)
356
return BAMF_VIEW_GET_CLASS (self)->get_name (self);
358
if (!bamf_view_remote_ready (self))
359
return g_strdup(priv->local_name);
361
if (!dbus_g_proxy_call (priv->proxy,
365
G_TYPE_STRING, &name,
368
g_warning ("Failed to fetch name: %s", error->message);
369
g_error_free (error);
378
bamf_view_remote_ready (BamfView *view)
380
return BAMF_IS_VIEW (view) && view->priv->proxy;
384
bamf_view_get_view_type (BamfView *self)
386
BamfViewPrivate *priv;
388
GError *error = NULL;
390
g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
393
if (BAMF_VIEW_GET_CLASS (self)->view_type)
394
return BAMF_VIEW_GET_CLASS (self)->view_type (self);
399
if (!dbus_g_proxy_call (priv->proxy,
403
G_TYPE_STRING, &type,
406
g_warning ("Failed to fetch view type at %s: %s", dbus_g_proxy_get_path (priv->proxy), error->message);
407
g_error_free (error);
416
bamf_view_get_click_suggestion (BamfView *self)
418
g_return_val_if_fail (BAMF_IS_VIEW (self), BAMF_CLICK_BEHAVIOR_NONE);
420
if (BAMF_VIEW_GET_CLASS (self)->click_behavior)
421
return BAMF_VIEW_GET_CLASS (self)->click_behavior (self);
423
return BAMF_CLICK_BEHAVIOR_NONE;
427
bamf_view_on_child_added (DBusGProxy *proxy, char *path, BamfView *self)
431
view = bamf_factory_view_for_path (bamf_factory_get_default (), path);
433
g_signal_emit (G_OBJECT (self), view_signals[CHILD_ADDED], 0, view);
437
bamf_view_on_child_removed (DBusGProxy *proxy, char *path, BamfView *self)
441
view = bamf_factory_view_for_path (bamf_factory_get_default (), path);
443
g_signal_emit (G_OBJECT (self), view_signals[CHILD_REMOVED], 0, view);
447
bamf_view_on_active_changed (DBusGProxy *proxy, gboolean active, BamfView *self)
449
bamf_view_set_flag (self, BAMF_VIEW_ACTIVE_FLAG, active);
451
g_signal_emit (G_OBJECT(self), view_signals[ACTIVE_CHANGED], 0, active);
452
g_object_notify (G_OBJECT (self), "active");
456
bamf_view_on_name_changed (DBusGProxy* proxy,
457
const gchar* old_name,
458
const gchar* new_name,
461
self->priv->local_name = g_strdup (new_name);
463
g_signal_emit (self, view_signals[NAME_CHANGED], 0, old_name, new_name);
467
bamf_view_on_running_changed (DBusGProxy *proxy, gboolean running, BamfView *self)
469
bamf_view_set_flag (self, BAMF_VIEW_RUNNING_FLAG, running);
471
g_signal_emit (G_OBJECT (self), view_signals[RUNNING_CHANGED], 0, running);
472
g_object_notify (G_OBJECT (self), "running");
476
bamf_view_on_urgent_changed (DBusGProxy *proxy, gboolean urgent, BamfView *self)
478
bamf_view_set_flag (self, BAMF_VIEW_URGENT_FLAG, urgent);
480
g_signal_emit (G_OBJECT (self), view_signals[URGENT_CHANGED], 0, urgent);
481
g_object_notify (G_OBJECT (self), "urgent");
485
bamf_view_on_user_visible_changed (DBusGProxy *proxy, gboolean visible, BamfView *self)
487
bamf_view_set_flag (self, BAMF_VIEW_VISIBLE_FLAG, visible);
489
g_signal_emit (G_OBJECT (self), view_signals[VISIBLE_CHANGED], 0, visible);
490
g_object_notify (G_OBJECT (self), "user-visible");
494
bamf_view_on_closed (DBusGProxy *proxy, BamfView *self)
496
BamfViewPrivate *priv;
500
priv->is_closed = TRUE;
502
if (priv->sticky && priv->proxy)
504
dbus_g_proxy_disconnect_signal (priv->proxy,
506
(GCallback) bamf_view_on_active_changed,
509
dbus_g_proxy_disconnect_signal (priv->proxy,
511
(GCallback) bamf_view_on_closed,
514
dbus_g_proxy_disconnect_signal (priv->proxy,
516
(GCallback) bamf_view_on_child_added,
519
dbus_g_proxy_disconnect_signal (priv->proxy,
521
(GCallback) bamf_view_on_child_removed,
524
dbus_g_proxy_disconnect_signal (priv->proxy,
526
(GCallback) bamf_view_on_running_changed,
529
dbus_g_proxy_disconnect_signal (priv->proxy,
531
(GCallback) bamf_view_on_urgent_changed,
534
dbus_g_proxy_disconnect_signal (priv->proxy,
535
"UserVisibleChanged",
536
(GCallback) bamf_view_on_user_visible_changed,
538
g_object_unref (priv->proxy);
544
// must be emitted before path is cleared as path is utilized in cleanup
545
g_signal_emit (G_OBJECT (self), view_signals[CLOSED], 0);
553
g_object_unref (self);
557
bamf_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
562
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
567
bamf_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
571
self = BAMF_VIEW (object);
576
g_value_set_string (value, self->priv->path);
580
g_value_set_boolean (value, bamf_view_is_active (self));
584
g_value_set_boolean (value, bamf_view_is_running (self));
588
g_value_set_boolean (value, bamf_view_is_urgent (self));
591
case PROP_USER_VISIBLE:
592
g_value_set_boolean (value, bamf_view_user_visible (self));
596
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
601
bamf_view_dispose (GObject *object)
604
BamfViewPrivate *priv;
606
view = BAMF_VIEW (object);
625
dbus_g_proxy_disconnect_signal (priv->proxy,
627
(GCallback) bamf_view_on_active_changed,
630
dbus_g_proxy_disconnect_signal (priv->proxy,
632
(GCallback) bamf_view_on_closed,
635
dbus_g_proxy_disconnect_signal (priv->proxy,
637
(GCallback) bamf_view_on_child_added,
640
dbus_g_proxy_disconnect_signal (priv->proxy,
642
(GCallback) bamf_view_on_child_removed,
645
dbus_g_proxy_disconnect_signal (priv->proxy,
647
(GCallback) bamf_view_on_running_changed,
650
dbus_g_proxy_disconnect_signal (priv->proxy,
652
(GCallback) bamf_view_on_urgent_changed,
655
dbus_g_proxy_disconnect_signal (priv->proxy,
656
"UserVisibleChanged",
657
(GCallback) bamf_view_on_user_visible_changed,
660
dbus_g_proxy_disconnect_signal (priv->proxy,
662
(GCallback) bamf_view_on_name_changed,
665
g_object_unref (priv->proxy);
671
bamf_view_get_path (BamfView *view)
673
g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
675
return view->priv->path;
679
bamf_view_set_path (BamfView *view, const char *path)
681
BamfViewPrivate *priv;
683
g_return_if_fail (BAMF_IS_VIEW (view));
686
priv->is_closed = FALSE;
693
priv->path = g_strdup (path);
694
priv->proxy = dbus_g_proxy_new_for_name (priv->connection,
697
"org.ayatana.bamf.view");
698
if (priv->proxy == NULL)
700
g_critical ("Unable to get org.ayatana.bamf.view view");
704
dbus_g_proxy_add_signal (priv->proxy,
709
dbus_g_proxy_add_signal (priv->proxy,
713
dbus_g_proxy_add_signal (priv->proxy,
718
dbus_g_proxy_add_signal (priv->proxy,
723
dbus_g_proxy_add_signal (priv->proxy,
728
dbus_g_proxy_add_signal (priv->proxy,
733
dbus_g_proxy_add_signal (priv->proxy,
734
"UserVisibleChanged",
738
dbus_g_proxy_add_signal (priv->proxy,
744
dbus_g_proxy_connect_signal (priv->proxy,
746
(GCallback) bamf_view_on_active_changed,
750
dbus_g_proxy_connect_signal (priv->proxy,
752
(GCallback) bamf_view_on_closed,
756
dbus_g_proxy_connect_signal (priv->proxy,
758
(GCallback) bamf_view_on_child_added,
762
dbus_g_proxy_connect_signal (priv->proxy,
764
(GCallback) bamf_view_on_child_removed,
768
dbus_g_proxy_connect_signal (priv->proxy,
770
(GCallback) bamf_view_on_running_changed,
774
dbus_g_proxy_connect_signal (priv->proxy,
776
(GCallback) bamf_view_on_urgent_changed,
780
dbus_g_proxy_connect_signal (priv->proxy,
781
"UserVisibleChanged",
782
(GCallback) bamf_view_on_user_visible_changed,
786
dbus_g_proxy_connect_signal (priv->proxy,
788
(GCallback) bamf_view_on_name_changed,
792
if (bamf_view_is_sticky (view))
794
priv->checked_flags = 0x0;
796
if (bamf_view_user_visible (view))
798
g_signal_emit (G_OBJECT(view), view_signals[VISIBLE_CHANGED], 0, TRUE);
799
g_object_notify (G_OBJECT (view), "user-visible");
802
if (bamf_view_is_active (view))
804
g_signal_emit (G_OBJECT(view), view_signals[ACTIVE_CHANGED], 0, TRUE);
805
g_object_notify (G_OBJECT (view), "active");
808
if (bamf_view_is_running (view))
810
g_signal_emit (G_OBJECT(view), view_signals[RUNNING_CHANGED], 0, TRUE);
811
g_object_notify (G_OBJECT (view), "running");
814
if (bamf_view_is_urgent (view))
816
g_signal_emit (G_OBJECT(view), view_signals[URGENT_CHANGED], 0, TRUE);
817
g_object_notify (G_OBJECT (view), "urgent");
820
if (BAMF_VIEW_GET_CLASS (view)->set_path)
821
BAMF_VIEW_GET_CLASS (view)->set_path (view, path);
825
bamf_view_constructed (GObject *object)
827
if (G_OBJECT_CLASS (bamf_view_parent_class)->constructed)
828
G_OBJECT_CLASS (bamf_view_parent_class)->constructed (object);
832
bamf_view_class_init (BamfViewClass *klass)
835
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
837
obj_class->constructed = bamf_view_constructed;
838
obj_class->dispose = bamf_view_dispose;
839
obj_class->get_property = bamf_view_get_property;
840
obj_class->set_property = bamf_view_set_property;
842
pspec = g_param_spec_string ("path", "path", "path", NULL, G_PARAM_READABLE);
843
g_object_class_install_property (obj_class, PROP_PATH, pspec);
845
pspec = g_param_spec_boolean ("active", "active", "active", FALSE, G_PARAM_READABLE);
846
g_object_class_install_property (obj_class, PROP_ACTIVE, pspec);
848
pspec = g_param_spec_boolean ("urgent", "urgent", "urgent", FALSE, G_PARAM_READABLE);
849
g_object_class_install_property (obj_class, PROP_URGENT, pspec);
851
pspec = g_param_spec_boolean ("running", "running", "running", FALSE, G_PARAM_READABLE);
852
g_object_class_install_property (obj_class, PROP_RUNNING, pspec);
854
pspec = g_param_spec_boolean ("user-visible", "user-visible", "user-visible", FALSE, G_PARAM_READABLE);
855
g_object_class_install_property (obj_class, PROP_USER_VISIBLE, pspec);
857
g_type_class_add_private (obj_class, sizeof (BamfViewPrivate));
859
view_signals [ACTIVE_CHANGED] =
860
g_signal_new ("active-changed",
861
G_OBJECT_CLASS_TYPE (klass),
863
G_STRUCT_OFFSET (BamfViewClass, active_changed),
865
g_cclosure_marshal_VOID__BOOLEAN,
869
view_signals [CLOSED] =
870
g_signal_new ("closed",
871
G_OBJECT_CLASS_TYPE (klass),
873
G_STRUCT_OFFSET (BamfViewClass, closed),
875
g_cclosure_marshal_VOID__VOID,
878
view_signals [CHILD_ADDED] =
879
g_signal_new ("child-added",
880
G_OBJECT_CLASS_TYPE (klass),
882
G_STRUCT_OFFSET (BamfViewClass, child_added),
884
g_cclosure_marshal_VOID__OBJECT,
888
view_signals [CHILD_REMOVED] =
889
g_signal_new ("child-removed",
890
G_OBJECT_CLASS_TYPE (klass),
892
G_STRUCT_OFFSET (BamfViewClass, child_removed),
894
g_cclosure_marshal_VOID__OBJECT,
898
view_signals [RUNNING_CHANGED] =
899
g_signal_new ("running-changed",
900
G_OBJECT_CLASS_TYPE (klass),
902
G_STRUCT_OFFSET (BamfViewClass, running_changed),
904
g_cclosure_marshal_VOID__BOOLEAN,
908
view_signals [URGENT_CHANGED] =
909
g_signal_new ("urgent-changed",
910
G_OBJECT_CLASS_TYPE (klass),
912
G_STRUCT_OFFSET (BamfViewClass, urgent_changed),
914
g_cclosure_marshal_VOID__BOOLEAN,
918
view_signals [VISIBLE_CHANGED] =
919
g_signal_new ("user-visible-changed",
920
G_OBJECT_CLASS_TYPE (klass),
922
G_STRUCT_OFFSET (BamfViewClass, user_visible_changed),
924
g_cclosure_marshal_VOID__BOOLEAN,
928
view_signals [NAME_CHANGED] =
929
g_signal_new ("name-changed",
930
G_OBJECT_CLASS_TYPE (klass),
933
bamf_marshal_VOID__STRING_STRING,
941
bamf_view_init (BamfView *self)
943
BamfViewPrivate *priv;
944
GError *error = NULL;
946
priv = self->priv = BAMF_VIEW_GET_PRIVATE (self);
948
priv->is_closed = TRUE;
950
priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
951
if (priv->connection == NULL)
953
g_critical ("Failed to open connection to bus: %s",
954
error != NULL ? error->message : "Unknown");
956
g_error_free (error);