1 /*
   2  * Copyright 2010 Canonical Ltd.
   3  *
   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:
   6  *
   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.
  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, see
  20  * <http://www.gnu.org/licenses/>
  21  *
  22  * Authored by: Jason Smith <jason.smith@canonical.com>
  23  *              Neil Jagdish Patel <neil.patel@canonical.com>
  24  *
  25  */
  26 /**
  27  * SECTION:bamf-view
  28  * @short_description: The base class for all views
  29  *
  30  * #BamfView is the base class that all views need to derive from.
  31  */
  32 
  33 #if HAVE_CONFIG_H
  34 #include <config.h>
  35 #endif
  36 
  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"
  42 
  43 #include <dbus/dbus.h>
  44 #include <dbus/dbus-glib.h>
  45 #include <dbus/dbus-glib-lowlevel.h>
  46 
  47 G_DEFINE_TYPE (BamfView, bamf_view, G_TYPE_INITIALLY_UNOWNED);
  48 
  49 #define BAMF_VIEW_GET_PRIVATE(o) \
  50   (G_TYPE_INSTANCE_GET_PRIVATE ((o), BAMF_TYPE_VIEW, BamfViewPrivate))
  51 
  52 enum
  53 {
  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,
  58 };
  59 
  60 enum
  61 {
  62   ACTIVE_CHANGED,
  63   CLOSED,
  64   CHILD_ADDED,
  65   CHILD_REMOVED,
  66   RUNNING_CHANGED,
  67   URGENT_CHANGED,
  68   VISIBLE_CHANGED,
  69   NAME_CHANGED,
  70  
  71   LAST_SIGNAL,
  72 };
  73 
  74 enum
  75 {
  76   PROP_0,
  77 
  78   PROP_PATH,
  79   PROP_RUNNING,
  80   PROP_ACTIVE,
  81   PROP_USER_VISIBLE,
  82   PROP_URGENT,
  83 };
  84 
  85 static guint view_signals[LAST_SIGNAL] = { 0 };
  86 
  87 struct _BamfViewPrivate
  88 {
  89   DBusGConnection *connection;
  90   DBusGProxy      *proxy;
  91   gchar           *path;
  92   gchar           *type;
  93   gchar           *local_icon;
  94   gchar           *local_name;
  95   guint            checked_flags;
  96   guint            set_flags;
  97   gboolean         is_closed;
  98   gboolean         sticky;
  99   GList           *cached_children;
 100 };
 101 
 102 static void
 103 bamf_view_set_flag (BamfView *view, guint flag, gboolean value)
 104 {
 105   BamfViewPrivate *priv;
 106   
 107   g_return_if_fail (BAMF_IS_VIEW (view));
 108   
 109   priv = view->priv;
 110   
 111   if (value)
 112     priv->set_flags |= flag;
 113   else
 114     priv->set_flags = priv->set_flags & ~flag;
 115   
 116   priv->checked_flags |= flag;
 117 }
 118 
 119 static gboolean
 120 bamf_view_flag_is_set (BamfView *view, guint flag)
 121 {
 122   BamfViewPrivate *priv;
 123   
 124   g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
 125   
 126   priv = view->priv;
 127   
 128   return priv->checked_flags & flag;
 129 }
 130 
 131 static gboolean
 132 bamf_view_get_flag (BamfView *view, guint flag)
 133 {
 134   BamfViewPrivate *priv;
 135   
 136   g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
 137   
 138   priv = view->priv;
 139   
 140   return priv->set_flags & flag;
 141 }
 142 
 143 GList *
 144 bamf_view_get_children (BamfView *view)
 145 {
 146   char ** children;
 147   int i, len;
 148   GList *results = NULL;
 149   GError *error = NULL;
 150   BamfViewPrivate *priv;
 151 
 152   g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
 153   
 154   if (BAMF_VIEW_GET_CLASS (view)->get_children)
 155     return BAMF_VIEW_GET_CLASS (view)->get_children (view);
 156 
 157   if (!bamf_view_remote_ready (view))
 158     return NULL;
 159 
 160   priv = view->priv;
 161 
 162   if (priv->cached_children)
 163     return g_list_copy (priv->cached_children);
 164 
 165   if (!dbus_g_proxy_call (priv->proxy,
 166                           "Children",
 167                           &error,
 168                           G_TYPE_INVALID,
 169                           G_TYPE_STRV, &children,
 170                           G_TYPE_INVALID))
 171     {
 172       g_warning ("Unable to fetch children: %s\n", error->message);
 173       g_error_free (error);
 174       return NULL;
 175     }
 176 
 177   if (!children)
 178     return NULL;
 179 
 180   len = g_strv_length (children);
 181 
 182   for (i = len-1; i >= 0; i--)
 183     {
CID 10449 - PW.PARAMETER_HIDDEN
declaration hides parameter "view" (declared at line 144)
 184       BamfView *view = bamf_factory_view_for_path (bamf_factory_get_default (), children[i]);
 185       results = g_list_prepend (results, g_object_ref (view));
 186     }
 187 
 188   priv->cached_children = results;
 189   return g_list_copy (priv->cached_children);
 190 }
 191 
 192 static gboolean
 193 bamf_view_get_boolean (BamfView *self, const char *method_name, guint flag)
 194 {
 195   BamfViewPrivate *priv;
 196   gboolean result = FALSE;
 197   GError *error = NULL;
 198 
 199   g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
 200   priv = self->priv;
 201 
 202   if (bamf_view_flag_is_set (self, flag))
 203     return bamf_view_get_flag (self, flag);
 204 
 205   if (!bamf_view_remote_ready (self))
 206     return FALSE;
 207 
 208   if (!dbus_g_proxy_call (priv->proxy,
 209                           method_name,
 210                           &error,
 211                           G_TYPE_INVALID,
 212                           G_TYPE_BOOLEAN, &result,
 213                           G_TYPE_INVALID))
 214     {
 215       g_warning ("Failed to fetch boolean: %s", error->message);
 216       g_error_free (error);
 217 
 218       return FALSE;
 219     }
 220 
 221   bamf_view_set_flag (self, flag, result);
 222   return result;
 223 }
 224 
 225 gboolean
 226 bamf_view_is_closed (BamfView *view)
 227 {
 228   g_return_val_if_fail (BAMF_IS_VIEW (view), TRUE);
 229 
 230   return view->priv->is_closed;
 231 }
 232 
 233 gboolean
 234 bamf_view_is_active (BamfView *view)
 235 {
 236   g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
 237 
 238   if (BAMF_VIEW_GET_CLASS (view)->is_active)
 239     return BAMF_VIEW_GET_CLASS (view)->is_active (view);
 240 
 241   return bamf_view_get_boolean (view, "IsActive", BAMF_VIEW_ACTIVE_FLAG);
 242 
 243 }
 244 
 245 gboolean          
 246 bamf_view_user_visible (BamfView *self)
 247 {
 248   g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
 249   
 250   return bamf_view_get_boolean (self, "UserVisible", BAMF_VIEW_VISIBLE_FLAG);
 251 
 252 }
 253 
 254 gboolean
 255 bamf_view_is_running (BamfView *self)
 256 {
 257   g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
 258   
 259   if (BAMF_VIEW_GET_CLASS (self)->is_running)
 260     return BAMF_VIEW_GET_CLASS (self)->is_running (self);
 261 
 262   return bamf_view_get_boolean (self, "IsRunning", BAMF_VIEW_RUNNING_FLAG);
 263 }
 264 
 265 gboolean
 266 bamf_view_is_urgent (BamfView *self)
 267 {
 268   g_return_val_if_fail (BAMF_IS_VIEW (self), FALSE);
 269   
 270   if (BAMF_VIEW_GET_CLASS (self)->is_urgent)
 271     return BAMF_VIEW_GET_CLASS (self)->is_urgent (self);
 272 
 273   return bamf_view_get_boolean (self, "IsUrgent", BAMF_VIEW_URGENT_FLAG);
 274 }
 275 
 276 void
 277 bamf_view_set_name (BamfView *view, const char *name)
 278 {
 279   g_return_if_fail (BAMF_IS_VIEW (view));
 280   
 281   if (!g_strcmp0 (name, view->priv->local_name))
 282     return;
 283 
 284   g_free (view->priv->local_name);
 285 
 286   if (name && name[0] == '\0')
 287     {
 288       view->priv->local_name = NULL;
 289     }
 290   else
 291     {
 292       view->priv->local_name = g_strdup (name);
 293     }
 294 }
 295 
 296 void
 297 bamf_view_set_icon (BamfView *view, const char *icon)
 298 {
 299   g_return_if_fail (BAMF_IS_VIEW (view));
 300 
 301   g_free (view->priv->local_icon);
 302 
 303   if (icon && icon[0] == '\0')
 304     {
 305       view->priv->local_icon = NULL;
 306     }
 307   else
 308     {
 309       view->priv->local_icon = g_strdup (icon);
 310     }
 311 }
 312 
 313 gboolean 
 314 bamf_view_is_sticky (BamfView *view)
 315 {
 316   g_return_val_if_fail (BAMF_IS_VIEW (view), FALSE);
 317   
 318   return view->priv->sticky;
 319 }
 320 
 321 void 
 322 bamf_view_set_sticky (BamfView *view, gboolean value)
 323 {
 324   g_return_if_fail (BAMF_IS_VIEW (view));
 325   
 326   if (value == view->priv->sticky)
 327     return;
 328 
 329   view->priv->sticky = value;
 330   
 331   if (value)
 332     g_object_ref_sink (view);
 333   else
 334     g_object_unref (view);
 335 }
 336 
 337 gchar *
 338 bamf_view_get_icon (BamfView *self)
 339 {
 340   BamfViewPrivate *priv;
 341   char *icon = NULL;
 342   GError *error = NULL;
 343 
 344   g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
 345   priv = self->priv;
 346   
 347   if (BAMF_VIEW_GET_CLASS (self)->get_icon)
 348     return BAMF_VIEW_GET_CLASS (self)->get_icon (self);
 349 
 350   if (!bamf_view_remote_ready (self))
 351     return g_strdup (priv->local_icon);
 352 
 353   if (!dbus_g_proxy_call (priv->proxy,
 354                           "Icon",
 355                           &error,
 356                           G_TYPE_INVALID,
 357                           G_TYPE_STRING, &icon,
 358                           G_TYPE_INVALID))
 359     {
 360       g_warning ("Failed to fetch icon: %s", error->message);
 361       g_error_free (error);
 362       
 363       return NULL;
 364     }
 365 
 366   if (icon && icon[0] == '\0')
 367     {
 368       g_free (icon);
 369       return NULL;
 370     }
 371 
 372   return icon;
 373 }
 374 
 375 gchar *
 376 bamf_view_get_name (BamfView *self)
 377 {
 378   BamfViewPrivate *priv;
 379   char *name = NULL;
 380   GError *error = NULL;
 381 
 382   g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
 383   priv = self->priv;
 384   
 385   if (BAMF_VIEW_GET_CLASS (self)->get_name)
 386     return BAMF_VIEW_GET_CLASS (self)->get_name (self);
 387 
 388   if (!bamf_view_remote_ready (self))
 389     return g_strdup(priv->local_name);
 390     
 391   if (!dbus_g_proxy_call (priv->proxy,
 392                           "Name",
 393                           &error,
 394                           G_TYPE_INVALID,
 395                           G_TYPE_STRING, &name,
 396                           G_TYPE_INVALID))
 397     {
 398       g_warning ("Failed to fetch name: %s", error->message);
 399       g_error_free (error);
 400       
 401       return NULL;
 402     }
 403 
 404   if (name && name[0] == '\0')
 405     {
 406       g_free (name);
 407       return NULL;
 408     }
 409 
 410   return name;
 411 }
 412 
 413 gboolean 
 414 bamf_view_remote_ready (BamfView *view)
 415 {
 416   return BAMF_IS_VIEW (view) && view->priv->proxy;
 417 }
 418 
 419 const gchar *
 420 bamf_view_get_view_type (BamfView *self)
 421 {
 422   BamfViewPrivate *priv;
 423   char *type = NULL;
 424   GError *error = NULL;
 425 
 426   g_return_val_if_fail (BAMF_IS_VIEW (self), NULL);
 427   priv = self->priv;
 428   
 429   if (BAMF_VIEW_GET_CLASS (self)->view_type)
 430     return BAMF_VIEW_GET_CLASS (self)->view_type (self);
 431   
 432   if (priv->type)
 433     return priv->type;
 434 
 435   if (!dbus_g_proxy_call (priv->proxy,
 436                           "ViewType",
 437                           &error,
 438                           G_TYPE_INVALID,
 439                           G_TYPE_STRING, &type,
 440                           G_TYPE_INVALID))
 441     {
 442       g_warning ("Failed to fetch view type at %s: %s", dbus_g_proxy_get_path (priv->proxy), error->message);
 443       g_error_free (error);
 444       return NULL;
 445     }
 446 
 447   priv->type = type;
 448   return type;
 449 }
 450 
 451 BamfClickBehavior 
 452 bamf_view_get_click_suggestion (BamfView *self)
 453 {
 454   g_return_val_if_fail (BAMF_IS_VIEW (self), BAMF_CLICK_BEHAVIOR_NONE);
 455 
 456   if (BAMF_VIEW_GET_CLASS (self)->click_behavior)
 457     return BAMF_VIEW_GET_CLASS (self)->click_behavior (self);
 458     
 459   return BAMF_CLICK_BEHAVIOR_NONE;
 460 }
 461 
 462 static void
 463 bamf_view_on_child_added (DBusGProxy *proxy, char *path, BamfView *self)
 464 {
 465   BamfView *view;
 466   BamfViewPrivate *priv;
 467 
 468   view = bamf_factory_view_for_path (bamf_factory_get_default (), path);
 469   priv = self->priv;
 470 
 471   if (priv->cached_children)
 472     {
 473       g_list_free_full (priv->cached_children, g_object_unref);
 474       priv->cached_children = NULL;
 475     }
 476 
 477   g_signal_emit (G_OBJECT (self), view_signals[CHILD_ADDED], 0, view);
 478 }
 479 
 480 static void
 481 bamf_view_on_child_removed (DBusGProxy *proxy, char *path, BamfView *self)
 482 {
 483   BamfView *view;
 484   BamfViewPrivate *priv;
 485   view = bamf_factory_view_for_path (bamf_factory_get_default (), path);
 486   priv = self->priv;
 487 
 488   if (priv->cached_children)
 489     {
 490       g_list_free_full (priv->cached_children, g_object_unref);
 491       priv->cached_children = NULL;
 492     }
 493 
 494   g_signal_emit (G_OBJECT (self), view_signals[CHILD_REMOVED], 0, view);
 495 }
 496 
 497 static void
 498 bamf_view_on_active_changed (DBusGProxy *proxy, gboolean active, BamfView *self)
 499 {
 500   bamf_view_set_flag (self, BAMF_VIEW_ACTIVE_FLAG, active);
 501 
 502   g_signal_emit (G_OBJECT(self), view_signals[ACTIVE_CHANGED], 0, active);
 503   g_object_notify (G_OBJECT (self), "active");
 504 }
 505 
 506 static void
 507 bamf_view_on_name_changed (DBusGProxy*  proxy,
 508                            const gchar* old_name,
 509                            const gchar* new_name,
 510                            BamfView*    self)
 511 {
 512   g_free (self->priv->local_name);
 513   self->priv->local_name = g_strdup (new_name);
 514 
 515   g_signal_emit (self, view_signals[NAME_CHANGED], 0, old_name, new_name);
 516 }
 517 
 518 static void
 519 bamf_view_on_running_changed (DBusGProxy *proxy, gboolean running, BamfView *self)
 520 {
 521   bamf_view_set_flag (self, BAMF_VIEW_RUNNING_FLAG, running);
 522 
 523   g_signal_emit (G_OBJECT (self), view_signals[RUNNING_CHANGED], 0, running);
 524   g_object_notify (G_OBJECT (self), "running");
 525 }
 526 
 527 static void
 528 bamf_view_on_urgent_changed (DBusGProxy *proxy, gboolean urgent, BamfView *self)
 529 {
 530   bamf_view_set_flag (self, BAMF_VIEW_URGENT_FLAG, urgent);
 531 
 532   g_signal_emit (G_OBJECT (self), view_signals[URGENT_CHANGED], 0, urgent);
 533   g_object_notify (G_OBJECT (self), "urgent");
 534 }
 535 
 536 static void
 537 bamf_view_on_user_visible_changed (DBusGProxy *proxy, gboolean visible, BamfView *self)
 538 {
 539   bamf_view_set_flag (self, BAMF_VIEW_VISIBLE_FLAG, visible);
 540 
 541   g_signal_emit (G_OBJECT (self), view_signals[VISIBLE_CHANGED], 0, visible);
 542   g_object_notify (G_OBJECT (self), "user-visible");
 543 }
 544 
 545 static void
 546 bamf_view_on_closed (DBusGProxy *proxy, BamfView *self)
 547 {
 548   BamfViewPrivate *priv;
 549 
 550   priv = self->priv;
 551 
 552   priv->is_closed = TRUE;
 553 
 554   if (priv->cached_children)
 555     {
 556       g_list_free_full (priv->cached_children, g_object_unref);
 557       priv->cached_children = NULL;
 558     }
 559 
 560   if (priv->sticky && priv->proxy)
 561     {
 562       dbus_g_proxy_disconnect_signal (priv->proxy,
 563                                       "ActiveChanged",
 564                                       (GCallback) bamf_view_on_active_changed,
 565                                       self);
 566 
 567       dbus_g_proxy_disconnect_signal (priv->proxy,
 568                                       "Closed",
 569                                       (GCallback) bamf_view_on_closed,
 570                                       self);
 571 
 572       dbus_g_proxy_disconnect_signal (priv->proxy,
 573                                       "ChildAdded",
 574                                       (GCallback) bamf_view_on_child_added,
 575                                       self);
 576 
 577       dbus_g_proxy_disconnect_signal (priv->proxy,
 578                                       "ChildRemoved",
 579                                       (GCallback) bamf_view_on_child_removed,
 580                                       self);
 581 
 582       dbus_g_proxy_disconnect_signal (priv->proxy,
 583                                       "RunningChanged",
 584                                       (GCallback) bamf_view_on_running_changed,
 585                                       self);
 586 
 587       dbus_g_proxy_disconnect_signal (priv->proxy,
 588                                      "UrgentChanged",
 589                                      (GCallback) bamf_view_on_urgent_changed,
 590                                      self);
 591   
 592       dbus_g_proxy_disconnect_signal (priv->proxy,
 593                                      "UserVisibleChanged",
 594                                      (GCallback) bamf_view_on_user_visible_changed,
 595                                      self);
 596       g_object_unref (priv->proxy);
 597       priv->proxy = NULL;
 598     }
 599   
 600   g_object_ref (self);
 601   
 602   // must be emitted before path is cleared as path is utilized in cleanup
 603   g_signal_emit (G_OBJECT (self), view_signals[CLOSED], 0);
 604 
 605   if (priv->path)
 606     {
 607       g_free (priv->path);
 608       priv->path = NULL;
 609     }
 610     
 611   g_object_unref (self);
 612 }
 613 
 614 static void
 615 bamf_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 616 {
 617   switch (property_id)
 618     {
 619       default:
 620         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 621     }
 622 }
 623 
 624 static void
 625 bamf_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
 626 {
 627   BamfView *self;
 628 
 629   self = BAMF_VIEW (object);
 630 
 631   switch (property_id)
 632     {
 633       case PROP_PATH:
 634         g_value_set_string (value, self->priv->path);
 635         break;
 636       
 637       case PROP_ACTIVE:
 638         g_value_set_boolean (value, bamf_view_is_active (self));
 639         break;
 640       
 641       case PROP_RUNNING:
 642         g_value_set_boolean (value, bamf_view_is_running (self));
 643         break;
 644       
 645       case PROP_URGENT:
 646         g_value_set_boolean (value, bamf_view_is_urgent (self));
 647         break;
 648       
 649       case PROP_USER_VISIBLE:
 650         g_value_set_boolean (value, bamf_view_user_visible (self));
 651         break;
 652       
 653       default:
 654         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 655     }
 656 }
 657 
 658 static void
 659 bamf_view_dispose (GObject *object)
 660 {
 661   BamfView *view;
 662   BamfViewPrivate *priv;
 663 
 664   view = BAMF_VIEW (object);
 665 
 666   priv = view->priv;
 667 
 668   if (priv->path)
 669     {
 670       g_free (priv->path);
 671       priv->path = NULL;
 672     }
 673 
 674   if (priv->type)
 675     {
 676       g_free (priv->type);
 677       priv->type = NULL;
 678     }
 679 
 680   if (priv->cached_children)
 681     {
 682       g_list_free_full (priv->cached_children, g_object_unref);
 683       priv->cached_children = NULL;
 684     }
 685 
 686   if (priv->proxy)
 687     {
 688       dbus_g_proxy_disconnect_signal (priv->proxy,
 689                                       "ActiveChanged",
 690                                       (GCallback) bamf_view_on_active_changed,
 691                                       view);
 692 
 693       dbus_g_proxy_disconnect_signal (priv->proxy,
 694                                       "Closed",
 695                                       (GCallback) bamf_view_on_closed,
 696                                       view);
 697 
 698       dbus_g_proxy_disconnect_signal (priv->proxy,
 699                                       "ChildAdded",
 700                                       (GCallback) bamf_view_on_child_added,
 701                                       view);
 702 
 703       dbus_g_proxy_disconnect_signal (priv->proxy,
 704                                       "ChildRemoved",
 705                                       (GCallback) bamf_view_on_child_removed,
 706                                       view);
 707 
 708       dbus_g_proxy_disconnect_signal (priv->proxy,
 709                                       "RunningChanged",
 710                                       (GCallback) bamf_view_on_running_changed,
 711                                        view);
 712 
 713       dbus_g_proxy_disconnect_signal (priv->proxy,
 714                                      "UrgentChanged",
 715                                      (GCallback) bamf_view_on_urgent_changed,
 716                                      view);
 717   
 718       dbus_g_proxy_disconnect_signal (priv->proxy,
 719                                      "UserVisibleChanged",
 720                                      (GCallback) bamf_view_on_user_visible_changed,
 721                                      view);
 722 
 723       dbus_g_proxy_disconnect_signal (priv->proxy,
 724                                      "NameChanged",
 725                                      (GCallback) bamf_view_on_name_changed,
 726                                      view);
 727 
 728       g_object_unref (priv->proxy);
 729       priv->proxy = NULL;
 730     }
 731 }
 732 
 733 const char * 
 734 bamf_view_get_path (BamfView *view)
 735 {
 736   g_return_val_if_fail (BAMF_IS_VIEW (view), NULL);
 737   
 738   return view->priv->path;
 739 }
 740 
 741 void
 742 bamf_view_set_path (BamfView *view, const char *path)
 743 {
 744   BamfViewPrivate *priv;
 745   
 746   g_return_if_fail (BAMF_IS_VIEW (view));
 747   
 748   priv = view->priv;
 749   priv->is_closed = FALSE;
 750 
 751   if (priv->path)
 752     {
 753       g_free (priv->path);
 754     }
 755   
 756   priv->path = g_strdup (path);
 757   priv->proxy = dbus_g_proxy_new_for_name (priv->connection,
 758                                            "org.ayatana.bamf",
 759                                            priv->path,
 760                                            "org.ayatana.bamf.view");
 761   if (priv->proxy == NULL)
 762     {
 763       g_critical ("Unable to get org.ayatana.bamf.view view");
 764       return;
 765     }
 766 
 767   dbus_g_proxy_add_signal (priv->proxy,
 768                            "ActiveChanged",
 769                            G_TYPE_BOOLEAN,
 770                            G_TYPE_INVALID);
 771 
 772   dbus_g_proxy_add_signal (priv->proxy,
 773                            "Closed",
 774                            G_TYPE_INVALID);
 775 
 776   dbus_g_proxy_add_signal (priv->proxy,
 777                            "ChildAdded",
 778                            G_TYPE_STRING,
 779                            G_TYPE_INVALID);
 780 
 781   dbus_g_proxy_add_signal (priv->proxy,
 782                            "ChildRemoved",
 783                            G_TYPE_STRING,
 784                            G_TYPE_INVALID);
 785 
 786   dbus_g_proxy_add_signal (priv->proxy,
 787                            "RunningChanged",
 788                            G_TYPE_BOOLEAN,
 789                            G_TYPE_INVALID);
 790   
 791   dbus_g_proxy_add_signal (priv->proxy,
 792                            "UrgentChanged",
 793                            G_TYPE_BOOLEAN, 
 794                            G_TYPE_INVALID);
 795   
 796   dbus_g_proxy_add_signal (priv->proxy,
 797                            "UserVisibleChanged",
 798                            G_TYPE_BOOLEAN, 
 799                            G_TYPE_INVALID);
 800 
 801   dbus_g_proxy_add_signal (priv->proxy,
 802                            "NameChanged",
 803                            G_TYPE_STRING,
 804                            G_TYPE_STRING,
 805                            G_TYPE_INVALID);
 806 
 807   dbus_g_proxy_connect_signal (priv->proxy,
 808                                "ActiveChanged",
 809                                (GCallback) bamf_view_on_active_changed,
 810                                view,
 811                                NULL);
 812 
 813   dbus_g_proxy_connect_signal (priv->proxy,
 814                                "Closed",
 815                                (GCallback) bamf_view_on_closed,
 816                                view,
 817                                NULL);
 818 
 819   dbus_g_proxy_connect_signal (priv->proxy,
 820                                "ChildAdded",
 821                                (GCallback) bamf_view_on_child_added,
 822                                view,
 823                                NULL);
 824 
 825   dbus_g_proxy_connect_signal (priv->proxy,
 826                                "ChildRemoved",
 827                                (GCallback) bamf_view_on_child_removed,
 828                                view,
 829                                NULL);
 830 
 831   dbus_g_proxy_connect_signal (priv->proxy,
 832                                "RunningChanged",
 833                                (GCallback) bamf_view_on_running_changed,
 834                                view,
 835                                NULL);
 836 
 837   dbus_g_proxy_connect_signal (priv->proxy,
 838                                "UrgentChanged",
 839                                (GCallback) bamf_view_on_urgent_changed,
 840                                view,
 841                                NULL);
 842   
 843   dbus_g_proxy_connect_signal (priv->proxy,
 844                                "UserVisibleChanged",
 845                                (GCallback) bamf_view_on_user_visible_changed,
 846                                view,
 847                                NULL);
 848 
 849   dbus_g_proxy_connect_signal (priv->proxy,
 850                                "NameChanged",
 851                                (GCallback) bamf_view_on_name_changed,
 852                                view,
 853                                NULL);
 854 
 855   if (bamf_view_is_sticky (view))
 856     {
 857       priv->checked_flags = 0x0;
 858       
 859       if (bamf_view_user_visible (view))
 860         {
 861           g_signal_emit (G_OBJECT(view), view_signals[VISIBLE_CHANGED], 0, TRUE);
 862           g_object_notify (G_OBJECT (view), "user-visible");
 863         }
 864       
 865       if (bamf_view_is_active (view))
 866         {
 867           g_signal_emit (G_OBJECT(view), view_signals[ACTIVE_CHANGED], 0, TRUE);
 868           g_object_notify (G_OBJECT (view), "active");
 869         }
 870       
 871       if (bamf_view_is_running (view))
 872         {
 873           g_signal_emit (G_OBJECT(view), view_signals[RUNNING_CHANGED], 0, TRUE);
 874           g_object_notify (G_OBJECT (view), "running");
 875         }
 876         
 877       if (bamf_view_is_urgent (view))
 878         {
 879           g_signal_emit (G_OBJECT(view), view_signals[URGENT_CHANGED], 0, TRUE);
 880           g_object_notify (G_OBJECT (view), "urgent");
 881         }
 882     }
 883   if (BAMF_VIEW_GET_CLASS (view)->set_path)
 884     BAMF_VIEW_GET_CLASS (view)->set_path (view, path);
 885 }
 886 
 887 static void
 888 bamf_view_constructed (GObject *object)
 889 {
 890   if (G_OBJECT_CLASS (bamf_view_parent_class)->constructed)
 891     G_OBJECT_CLASS (bamf_view_parent_class)->constructed (object);
 892 }
 893 
 894 static void
 895 bamf_view_class_init (BamfViewClass *klass)
 896 {
 897   GParamSpec *pspec;
 898   GObjectClass *obj_class = G_OBJECT_CLASS (klass);
 899 
 900   obj_class->constructed  = bamf_view_constructed;
 901   obj_class->dispose      = bamf_view_dispose;
 902   obj_class->get_property = bamf_view_get_property;
 903   obj_class->set_property = bamf_view_set_property;
 904 
 905   pspec = g_param_spec_string ("path", "path", "path", NULL, G_PARAM_READABLE);
 906   g_object_class_install_property (obj_class, PROP_PATH, pspec);
 907   
 908   pspec = g_param_spec_boolean ("active", "active", "active", FALSE, G_PARAM_READABLE);
 909   g_object_class_install_property (obj_class, PROP_ACTIVE, pspec);
 910 
 911   pspec = g_param_spec_boolean ("urgent", "urgent", "urgent", FALSE, G_PARAM_READABLE);
 912   g_object_class_install_property (obj_class, PROP_URGENT, pspec);
 913   
 914   pspec = g_param_spec_boolean ("running", "running", "running", FALSE, G_PARAM_READABLE);
 915   g_object_class_install_property (obj_class, PROP_RUNNING, pspec);
 916   
 917   pspec = g_param_spec_boolean ("user-visible", "user-visible", "user-visible", FALSE, G_PARAM_READABLE);
 918   g_object_class_install_property (obj_class, PROP_USER_VISIBLE, pspec);
 919 
 920   g_type_class_add_private (obj_class, sizeof (BamfViewPrivate));
 921 
 922   view_signals [ACTIVE_CHANGED] = 
 923   	g_signal_new ("active-changed",
 924   	              G_OBJECT_CLASS_TYPE (klass),
 925   	              G_SIGNAL_RUN_FIRST,
 926   	              G_STRUCT_OFFSET (BamfViewClass, active_changed), 
 927   	              NULL, NULL,
 928   	              g_cclosure_marshal_VOID__BOOLEAN,
 929   	              G_TYPE_NONE, 1, 
 930   	              G_TYPE_BOOLEAN);
 931 
 932   view_signals [CLOSED] = 
 933   	g_signal_new ("closed",
 934   	              G_OBJECT_CLASS_TYPE (klass),
 935   	              G_SIGNAL_RUN_FIRST,
 936   	              G_STRUCT_OFFSET (BamfViewClass, closed), 
 937   	              NULL, NULL,
 938   	              g_cclosure_marshal_VOID__VOID,
 939   	              G_TYPE_NONE, 0);
 940 
 941   view_signals [CHILD_ADDED] = 
 942   	g_signal_new ("child-added",
 943   	              G_OBJECT_CLASS_TYPE (klass),
 944   	              G_SIGNAL_RUN_FIRST,
 945   	              G_STRUCT_OFFSET (BamfViewClass, child_added), 
 946   	              NULL, NULL,
 947   	              g_cclosure_marshal_VOID__OBJECT,
 948   	              G_TYPE_NONE, 1, 
 949   	              BAMF_TYPE_VIEW);
 950 
 951   view_signals [CHILD_REMOVED] = 
 952   	g_signal_new ("child-removed",
 953   	              G_OBJECT_CLASS_TYPE (klass),
 954   	              G_SIGNAL_RUN_FIRST,
 955   	              G_STRUCT_OFFSET (BamfViewClass, child_removed), 
 956   	              NULL, NULL,
 957   	              g_cclosure_marshal_VOID__OBJECT,
 958   	              G_TYPE_NONE, 1, 
 959   	              BAMF_TYPE_VIEW);
 960 
 961   view_signals [RUNNING_CHANGED] = 
 962   	g_signal_new ("running-changed",
 963   	              G_OBJECT_CLASS_TYPE (klass),
 964   	              G_SIGNAL_RUN_FIRST,
 965   	              G_STRUCT_OFFSET (BamfViewClass, running_changed), 
 966   	              NULL, NULL,
 967   	              g_cclosure_marshal_VOID__BOOLEAN,
 968   	              G_TYPE_NONE, 1, 
 969   	              G_TYPE_BOOLEAN);
 970 
 971   view_signals [URGENT_CHANGED] = 
 972   	g_signal_new ("urgent-changed",
 973   	              G_OBJECT_CLASS_TYPE (klass),
 974   	              G_SIGNAL_RUN_FIRST,
 975   	              G_STRUCT_OFFSET (BamfViewClass, urgent_changed), 
 976   	              NULL, NULL,
 977   	              g_cclosure_marshal_VOID__BOOLEAN,
 978   	              G_TYPE_NONE, 1, 
 979   	              G_TYPE_BOOLEAN);
 980   
 981   view_signals [VISIBLE_CHANGED] = 
 982   	g_signal_new ("user-visible-changed",
 983   	              G_OBJECT_CLASS_TYPE (klass),
 984   	              G_SIGNAL_RUN_FIRST,
 985   	              G_STRUCT_OFFSET (BamfViewClass, user_visible_changed), 
 986   	              NULL, NULL,
 987   	              g_cclosure_marshal_VOID__BOOLEAN,
 988   	              G_TYPE_NONE, 1, 
 989   	              G_TYPE_BOOLEAN);
 990 
 991   view_signals [NAME_CHANGED] =
 992         g_signal_new ("name-changed",
 993                       G_OBJECT_CLASS_TYPE (klass),
 994                       0,
 995                       0, NULL, NULL,
 996                       bamf_marshal_VOID__STRING_STRING,
 997   	              G_TYPE_NONE, 2,
 998   	              G_TYPE_STRING,
 999                       G_TYPE_STRING);
1000 }
1001 
1002 
1003 static void
1004 bamf_view_init (BamfView *self)
1005 {
1006   BamfViewPrivate *priv;
1007   GError *error = NULL;
1008 
1009   priv = self->priv = BAMF_VIEW_GET_PRIVATE (self);
1010 
1011   priv->is_closed = TRUE;
1012 
1013   priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1014   if (priv->connection == NULL)
1015     {
1016       g_critical ("Failed to open connection to bus: %s",
1017                error != NULL ? error->message : "Unknown");
1018       if (error)
1019         g_error_free (error);
1020       return;
1021     }
1022 }