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-application.h"
  22 #include "bamf-window.h"
  23 #include "bamf-matcher.h"
  24 #include "bamf-legacy-window.h"
  25 #include "bamf-legacy-screen.h"
  26 #include "bamf-tab.h"
  27 #include <string.h>
  28 #include <gio/gdesktopappinfo.h>
  29 
  30 #define BAMF_APPLICATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
  31 BAMF_TYPE_APPLICATION, BamfApplicationPrivate))
  32 
  33 static void bamf_application_dbus_application_iface_init (BamfDBusItemApplicationIface *iface);
  34 G_DEFINE_TYPE_WITH_CODE (BamfApplication, bamf_application, BAMF_TYPE_VIEW,
  35                          G_IMPLEMENT_INTERFACE (BAMF_DBUS_ITEM_TYPE_APPLICATION,
  36                                                 bamf_application_dbus_application_iface_init));
  37 
  38 struct _BamfApplicationPrivate
  39 {
  40   BamfDBusItemApplication *dbus_iface;
  41   char * desktop_file;
  42   GList * desktop_file_list;
  43   char * app_type;
  44   char * icon;
  45   char * wmclass;
  46   char ** mimes;
  47   gboolean is_tab_container;
  48   gboolean show_stubs;
  49 };
  50 
  51 enum {
  52   SUPPORTED_MIMES_CHANGED,
  53   LAST_SIGNAL
  54 };
  55 
  56 static guint application_signals[LAST_SIGNAL] = { 0 };
  57 
  58 #define STUB_KEY  "X-Ayatana-Appmenu-Show-Stubs"
  59 
  60 static const char *
  61 bamf_application_get_icon (BamfView *view)
  62 {
  63   g_return_val_if_fail (BAMF_IS_APPLICATION (view), NULL);
  64 
  65   return BAMF_APPLICATION (view)->priv->icon;
  66 }
  67 
  68 void
  69 bamf_application_supported_mime_types_changed (BamfApplication *application,
  70                                                const gchar **new_mimes)
  71 {
  72   gchar **mimes = (gchar **) new_mimes;
  73 
  74   if (!new_mimes)
  75     {
  76       gchar *empty[] = {NULL};
  77       mimes = g_strdupv (empty);
  78     }
  79 
  80   g_signal_emit_by_name (application->priv->dbus_iface, "supported-mime-types-changed", mimes);
  81 
  82   if (!new_mimes)
  83   {
  84     g_strfreev (mimes);
  85     mimes = NULL;
  86   }
  87 
  88   if (application->priv->mimes)
  89     g_strfreev (application->priv->mimes);
  90 
  91   application->priv->mimes = mimes;
  92 }
  93 
  94 static gboolean
  95 bamf_application_default_get_close_when_empty (BamfApplication *application)
  96 {
  97   return TRUE;
  98 }
  99 
 100 static gchar **
 101 bamf_application_default_get_supported_mime_types (BamfApplication *application)
 102 {
 103   const char *desktop_file = bamf_application_get_desktop_file (application);
 104 
{CovLStrv2{{t{Condition {0}, taking false branch}{"!desktop_file"}}}}
 105   if (!desktop_file)
 106     return NULL;
 107 
 108   GKeyFile* key_file = g_key_file_new ();
 109   GError *error = NULL;
 110 
CID 12652 - CHECKED_RETURN
{CovLStrv2{{t{Calling function {0} without checking return value (as is done elsewhere {1} out of {2} times).}{"g_key_file_load_from_file(GKeyFile *, gchar const *, GKeyFileFlags, GError **)"}{4}{5}}}}
{CovLStrv2{{t{No check of the return value of {0}.}{"g_key_file_load_from_file(key_file, desktop_file, G_KEY_FILE_NONE, &error)"}}}}
 111   g_key_file_load_from_file (key_file, desktop_file, (GKeyFileFlags) 0, &error);
 112 
 113   if (error)
 114     {
 115       g_key_file_free (key_file);
 116       g_error_free (error);
 117       return NULL;
 118     }
 119 
 120   char** mimes = g_key_file_get_string_list (key_file, "Desktop Entry", "MimeType", NULL, NULL);
 121   g_signal_emit (application, application_signals[SUPPORTED_MIMES_CHANGED], 0, mimes);
 122 
 123   g_key_file_free (key_file);
 124 
 125   return mimes;
 126 }
 127 
 128 char **
 129 bamf_application_get_supported_mime_types (BamfApplication *application)
 130 {
 131   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
 132 
 133   if (application->priv->mimes)
 134     return g_strdupv (application->priv->mimes);
 135 
 136   gchar **mimes = BAMF_APPLICATION_GET_CLASS (application)->get_supported_mime_types (application);
 137   application->priv->mimes = mimes;
 138 
 139   return g_strdupv (mimes);
 140 }
 141 
 142 char *
 143 bamf_application_get_application_type (BamfApplication *application)
 144 {
 145   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
 146 
 147   return g_strdup (application->priv->app_type);
 148 }
 149 
 150 void
 151 bamf_application_set_application_type (BamfApplication *application, const gchar *type)
 152 {
 153   g_return_if_fail (BAMF_IS_APPLICATION (application));
 154   
 155   if (application->priv->app_type)
 156     g_free (application->priv->app_type);
 157   
 158   application->priv->app_type = g_strdup (type);
 159 }
 160 
 161 const char *
 162 bamf_application_get_desktop_file (BamfApplication *application)
 163 {
 164   BamfApplicationPrivate *priv;
 165 
 166   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
 167   priv = application->priv;
 168 
 169   return priv->desktop_file;
 170 }
 171 
 172 const char *
 173 bamf_application_get_wmclass (BamfApplication *application)
 174 {
 175   BamfApplicationPrivate *priv;
 176 
 177   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
 178   priv = application->priv;
 179 
 180   return priv->wmclass;
 181 }
 182 
 183 static gboolean
 184 icon_name_is_valid (char *name)
 185 {
 186   GtkIconTheme *icon_theme;
 187 
 188   if (name == NULL)
 189     return FALSE;
 190 
 191   icon_theme = gtk_icon_theme_get_default ();
 192   return gtk_icon_theme_has_icon (icon_theme, name);
 193 }
 194 
 195 static void
 196 bamf_application_setup_icon_and_name (BamfApplication *self)
 197 {
 198   BamfView *view;
 199   BamfWindow *window = NULL;
 200   GDesktopAppInfo *desktop;
 201   GKeyFile * keyfile;
 202   GIcon *gicon;
 203   GList *children, *l;
 204   const char *class;
 205   char *icon = NULL, *name = NULL;
 206   GError *error;
 207 
 208   g_return_if_fail (BAMF_IS_APPLICATION (self));
 209 
 210   if (self->priv->icon && bamf_view_get_name (BAMF_VIEW (self)))
 211     return;
 212 
 213   if (self->priv->desktop_file)
 214     {
 215       keyfile = g_key_file_new();
 216 
CID 12652 - CHECKED_RETURN
{CovLStrv2{{t{Example3: }}{t{{0} has its value checked in {1}.}{"g_key_file_load_from_file(keyfile, self->priv->desktop_file, G_KEY_FILE_NONE, NULL)"}{"g_key_file_load_from_file(keyfile, self->priv->desktop_file, G_KEY_FILE_NONE, NULL)"}}}}
 217       if (!g_key_file_load_from_file(keyfile, self->priv->desktop_file, G_KEY_FILE_NONE, NULL))
 218         {
 219           g_key_file_free(keyfile);
 220           return;
 221         }
 222 
 223       desktop = g_desktop_app_info_new_from_keyfile (keyfile);
 224 
 225       if (!G_IS_APP_INFO (desktop))
 226         {
 227           g_key_file_free(keyfile);
 228           return;
 229         }
 230 
 231       gicon = g_app_info_get_icon (G_APP_INFO (desktop));
 232 
 233       name = g_strdup (g_app_info_get_display_name (G_APP_INFO (desktop)));
 234 
 235       if (gicon)
 236         {
 237           icon = g_icon_to_string (gicon);
 238         }
 239       else
 240         {
 241           icon = g_strdup ("application-default-icon");
 242         }
 243 
 244       if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, STUB_KEY, NULL))
 245         {
 246           /* This will error to return false, which is okay as it seems
 247              unlikely anyone will want to set this flag except to turn
 248              off the stub menus. */
 249           self->priv->show_stubs = g_key_file_get_boolean (keyfile,
 250                                                            G_KEY_FILE_DESKTOP_GROUP,
 251                                                            STUB_KEY, NULL);
 252         }
 253 
 254       if (g_key_file_has_key (keyfile, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-FullName", NULL))
 255         {
 256           /* Grab the better name if its available */
 257           gchar *fullname = NULL;
 258           error = NULL;
 259           fullname = g_key_file_get_locale_string (keyfile,
 260                                                    G_KEY_FILE_DESKTOP_GROUP,
 261                                                    "X-GNOME-FullName", NULL,
 262                                                    &error);
 263           if (error != NULL)
 264             {
 265               g_error_free (error);
 266               if (fullname)
 267                 g_free (fullname);
 268             }
 269           else
 270             {
 271               g_free (name);
 272               name = fullname;
 273             }
 274         }
 275 
 276       g_object_unref (desktop);
 277       g_key_file_free(keyfile);
 278     }
 279   else if ((children = bamf_view_get_children (BAMF_VIEW (self))) != NULL)
 280     {
 281       for (l = children; l && !icon; l = l->next)
 282         {
 283           view = l->data;
 284           if (!BAMF_IS_WINDOW (view))
 285             continue;
 286 
 287           window = BAMF_WINDOW (view);
 288 
 289           do
 290             {
 291               class = bamf_legacy_window_get_class_name (bamf_window_get_window (window));
 292               
 293               if (class == NULL)
 294                 break;
 295 
 296               icon = g_utf8_strdown (class, -1);
 297 
 298               if (icon_name_is_valid (icon))
 299                 break;
 300 
 301               g_free (icon);
 302               icon = bamf_legacy_window_get_exec_string (bamf_window_get_window (window));
 303 
 304               if (icon_name_is_valid (icon))
 305                 break;
 306 
 307               g_free (icon);
 308               icon = NULL;
 309             }
 310           while (FALSE);
 311 
 312           name = g_strdup (bamf_legacy_window_get_name (bamf_window_get_window (window)));
 313         }
 314 
 315       if (!icon)
 316         {
 317           if (window)
 318             {
 319               icon = g_strdup (bamf_legacy_window_save_mini_icon (bamf_window_get_window (window)));
 320             }
 321 
 322           if (!icon)
 323             {
 324               icon = g_strdup ("application-default-icon");
 325             }
 326         }
 327     }
 328   else
 329     {
 330       /* we do nothing as we have nothing to go on */
 331     }
 332 
 333   if (icon)
 334     {
 335       if (self->priv->icon)
 336         g_free (self->priv->icon);
 337 
 338       self->priv->icon = icon;
 339     }
 340 
 341   if (name)
 342     bamf_view_set_name (BAMF_VIEW (self), name);
 343 
 344   g_free (name);
 345 }
 346 
 347 void
 348 bamf_application_set_desktop_file (BamfApplication *application,
 349                                    const char * desktop_file)
 350 {
 351   g_return_if_fail (BAMF_IS_APPLICATION (application));
 352 
 353   if (application->priv->desktop_file)
 354     g_free (application->priv->desktop_file);
 355 
 356   if (desktop_file && desktop_file[0] != '\0')
 357     application->priv->desktop_file = g_strdup (desktop_file);
 358   else
 359     application->priv->desktop_file = NULL;
 360 
 361   bamf_application_setup_icon_and_name (application);
 362 }
 363 
 364 gboolean
 365 bamf_application_set_desktop_file_from_id (BamfApplication *application,
 366                                            const char *desktop_id)
 367 {
 368   GDesktopAppInfo *info;
 369   const char *filename;
 370   
 371   info = g_desktop_app_info_new (desktop_id);
 372   
 373   if (info == NULL)
 374     {
 375       g_warning ("Failed to load desktop file from desktop ID: %s", desktop_id);
 376       return FALSE;
 377     }
 378   filename = g_desktop_app_info_get_filename (info);
 379   bamf_application_set_desktop_file (application, filename);
 380   
 381   g_object_unref (G_OBJECT (info));
 382   
 383   return TRUE;
 384 }
 385 
 386 void
 387 bamf_application_set_wmclass (BamfApplication *application,
 388                               const char *wmclass)
 389 {
 390   g_return_if_fail (BAMF_IS_APPLICATION (application));
 391 
 392   if (application->priv->wmclass)
 393     g_free (application->priv->wmclass);
 394 
 395   if (wmclass && wmclass[0] != '\0')
 396     application->priv->wmclass = g_strdup (wmclass);
 397   else
 398     application->priv->wmclass = NULL;
 399 }
 400 
 401 GVariant *
 402 bamf_application_get_xids (BamfApplication *application)
 403 {
 404   GList *l;
 405   GVariantBuilder b;
 406   BamfView *view;
 407   guint32 xid;
 408 
 409   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
 410 
 411   g_variant_builder_init (&b, G_VARIANT_TYPE ("(au)"));
 412   g_variant_builder_open (&b, G_VARIANT_TYPE ("au"));
 413 
 414   for (l = bamf_view_get_children (BAMF_VIEW (application)); l; l = l->next)
 415     {
 416       view = l->data;
 417 
 418       if (BAMF_IS_WINDOW (view))
 419         xid = bamf_window_get_xid (BAMF_WINDOW (view));
 420       else if (BAMF_IS_TAB (view))
 421         xid = bamf_tab_get_xid (BAMF_TAB (view));
 422       else
 423         continue;
 424       g_variant_builder_add (&b, "u", xid);
 425     }
 426 
 427   g_variant_builder_close (&b);
 428 
 429   return g_variant_builder_end (&b);
 430 }
 431 
 432 gboolean
 433 bamf_application_contains_similar_to_window (BamfApplication *self,
 434                                              BamfWindow *bamf_window)
 435 {
 436   GList *children, *l;
 437   BamfView *child;
 438 
 439   g_return_val_if_fail (BAMF_IS_APPLICATION (self), FALSE);
 440   g_return_val_if_fail (BAMF_IS_WINDOW (bamf_window), FALSE);
 441 
 442   BamfLegacyWindow *window = bamf_window_get_window (bamf_window);
 443   const char *window_class = bamf_legacy_window_get_class_name (window);
 444   const char *instance_name = bamf_legacy_window_get_class_instance_name (window);
 445 
 446   if (!window_class && !instance_name)
 447     return FALSE;
 448 
 449   children = bamf_view_get_children (BAMF_VIEW (self));
 450   for (l = children; l; l = l->next)
 451     {
 452       child = l->data;
 453 
 454       if (!BAMF_IS_WINDOW (child))
 455         continue;
 456 
 457       window = bamf_window_get_window (BAMF_WINDOW (child));
 458       const char *owned_win_class = bamf_legacy_window_get_class_name (window);
 459       const char *owned_instance = bamf_legacy_window_get_class_instance_name (window);
 460 
 461       if (g_strcmp0 (window_class, owned_win_class) == 0 &&
 462           g_strcmp0 (instance_name, owned_instance) == 0)
 463         {
 464           return TRUE;
 465         }
 466     }
 467 
 468   return FALSE;
 469 }
 470 
 471 gboolean
 472 bamf_application_manages_xid (BamfApplication *application,
 473                               guint32 xid)
 474 {
 475   GList *l;
 476   gboolean result = FALSE;
 477 
 478   g_return_val_if_fail (BAMF_IS_APPLICATION (application), FALSE);
 479 
 480   for (l = bamf_view_get_children (BAMF_VIEW (application)); l; l = l->next)
 481     {
 482       BamfView *view = l->data;
 483 
 484       if (!BAMF_IS_WINDOW (view))
 485         continue;
 486 
 487       if (bamf_window_get_xid (BAMF_WINDOW (view)) == xid)
 488         {
 489           result = TRUE;
 490           break;
 491         }
 492     }
 493 
 494   return result;
 495 }
 496 
 497 static const char *
 498 bamf_application_get_view_type (BamfView *view)
 499 {
 500   return "application";
 501 }
 502 
 503 static char *
 504 bamf_application_get_stable_bus_name (BamfView *view)
 505 {
 506   BamfApplication *self;
 507   GList *children, *l;
 508   BamfView *child;
 509 
 510   g_return_val_if_fail (BAMF_IS_APPLICATION (view), NULL);
 511   self = BAMF_APPLICATION (view);
 512 
 513   if (self->priv->desktop_file)
 514     return g_strdup_printf ("application%i", abs (g_str_hash (self->priv->desktop_file)));
 515 
 516   children = bamf_view_get_children (BAMF_VIEW (self));
 517   for (l = children; l; l = l->next)
 518     {
 519       child = l->data;
 520 
 521       if (!BAMF_IS_WINDOW (child))
 522         continue;
 523 
 524       return g_strdup_printf ("application%s",
 525                               bamf_legacy_window_get_class_name (bamf_window_get_window (BAMF_WINDOW (child))));
 526     }
 527 
 528   return g_strdup_printf ("application%p", view);
 529 }
 530 
 531 static void
 532 bamf_application_ensure_flags (BamfApplication *self)
 533 {
 534   gboolean urgent = FALSE, visible = FALSE, running = FALSE, active = FALSE, close_when_empty;
 535   GList *l;
 536   BamfView *view;
 537 
 538   for (l = bamf_view_get_children (BAMF_VIEW (self)); l; l = l->next)
 539     {
 540       view = l->data;
 541 
 542       if (!BAMF_IS_VIEW (view))
 543         continue;
 544 
 545       running = TRUE;
 546 
 547       if (!BAMF_IS_WINDOW (view) && !BAMF_IS_TAB (view))
 548         continue;
 549 
 550       if (bamf_view_is_urgent (view))
 551         urgent = TRUE;
 552       if (bamf_view_user_visible (view))
 553         visible = TRUE;
 554       if (bamf_view_is_active (view))
 555         active = TRUE;
 556 
 557       if (urgent && visible && active)
 558         break;
 559     }
 560 
 561   close_when_empty = bamf_application_get_close_when_empty (self);
 562   bamf_view_set_urgent (BAMF_VIEW (self), urgent);
 563   bamf_view_set_user_visible (BAMF_VIEW (self), (visible || !close_when_empty));
 564   bamf_view_set_running (BAMF_VIEW (self), (running || !close_when_empty));
 565   bamf_view_set_active (BAMF_VIEW (self), active);
 566 }
 567 
 568 static void
 569 view_active_changed (BamfView *view, gboolean active, BamfApplication *self)
 570 {
 571   bamf_application_ensure_flags (self);
 572 }
 573 
 574 static void
 575 view_urgent_changed (BamfView *view, gboolean urgent, BamfApplication *self)
 576 {
 577   bamf_application_ensure_flags (self);
 578 }
 579 
 580 static void
 581 view_visible_changed (BamfView *view, gboolean visible, BamfApplication *self)
 582 {
 583   bamf_application_ensure_flags (self);
 584 }
 585 
 586 static void
 587 view_xid_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
 588 {
 589   BamfApplication *self;
 590   
 591   self = (BamfApplication *)user_data;
 592   bamf_application_ensure_flags (self);
 593 }
 594 
 595 static void
 596 view_exported (BamfView *view, BamfApplication *self)
 597 {
 598   g_signal_emit_by_name (self, "window-added", bamf_view_get_path (view));
 599 }
 600 
 601 static void
 602 bamf_application_child_added (BamfView *view, BamfView *child)
 603 {
 604   BamfApplication *application;
 605 
 606   application = BAMF_APPLICATION (view);
 607 
 608   if (BAMF_IS_WINDOW (child))
 609     {
 610       if (bamf_view_is_on_bus (child))
 611         g_signal_emit_by_name (BAMF_APPLICATION (view), "window-added", bamf_view_get_path (child));
 612       else
 613         g_signal_connect (G_OBJECT (child), "exported",
 614                           (GCallback) view_exported, view);
 615     }
 616 
 617   g_signal_connect (G_OBJECT (child), "active-changed",
 618                     (GCallback) view_active_changed, view);
 619   g_signal_connect (G_OBJECT (child), "urgent-changed",
 620                     (GCallback) view_urgent_changed, view);
 621   g_signal_connect (G_OBJECT (child), "user-visible-changed",
 622                     (GCallback) view_visible_changed, view);
 623 
 624   if (BAMF_IS_TAB (child))
 625     {
 626       g_signal_connect (G_OBJECT (child), "notify::xid",
 627                         (GCallback) view_xid_changed, view);
 628     }
 629 
 630   bamf_application_ensure_flags (BAMF_APPLICATION (view));
 631 
 632   bamf_application_setup_icon_and_name (application);
 633 }
 634 
 635 static char *
 636 bamf_application_favorite_from_list (BamfApplication *self, GList *desktop_list)
 637 {
 638   BamfMatcher *matcher;
 639   GList *favs, *l;
 640   char *result = NULL;
 641   const char *desktop_class;
 642 
 643   g_return_val_if_fail (BAMF_IS_APPLICATION (self), NULL);
 644 
 645   matcher = bamf_matcher_get_default ();
 646   favs = bamf_matcher_get_favorites (matcher);
 647 
 648   if (favs)
 649     {
 650       for (l = favs; l; l = l->next)
 651         {
 652           if (g_list_find_custom (desktop_list, l->data, (GCompareFunc) g_strcmp0))
 653             {
 654               desktop_class = bamf_matcher_get_desktop_file_class (matcher, l->data);
 655 
 656               if (!desktop_class || g_strcmp0 (self->priv->wmclass, desktop_class) == 0)
 657                 {
 658                   result = l->data;
 659                   break;
 660                 }
 661             }
 662         }
 663     }
 664 
 665   return result;
 666 }
 667 
 668 static void
 669 bamf_application_set_desktop_file_from_list (BamfApplication *self, GList *list)
 670 {
 671   BamfApplicationPrivate *priv;
 672   GList *l;
 673   char *desktop_file;
 674 
 675   g_return_if_fail (BAMF_IS_APPLICATION (self));
 676   g_return_if_fail (list);
 677 
 678   priv = self->priv;
 679 
 680   if (priv->desktop_file_list)
 681     {
 682       g_list_free_full (priv->desktop_file_list, g_free);
 683       priv->desktop_file_list = NULL;
 684     }
 685 
 686   for (l = list; l; l = l->next)
 687     priv->desktop_file_list = g_list_prepend (priv->desktop_file_list, g_strdup (l->data));
 688 
 689   priv->desktop_file_list = g_list_reverse (priv->desktop_file_list);
 690 
 691   desktop_file = bamf_application_favorite_from_list (self, priv->desktop_file_list);
 692 
 693   /* items, after reversing them, are in priority order */
 694   if (!desktop_file)
 695     desktop_file = list->data;
 696 
 697   bamf_application_set_desktop_file (self, desktop_file);
 698 }
 699 
 700 static void
 701 bamf_application_child_removed (BamfView *view, BamfView *child)
 702 {
 703   BamfApplication *self = BAMF_APPLICATION (view);
 704   if (BAMF_IS_WINDOW (child))
 705     {
 706       if (bamf_view_is_on_bus (child))
 707         g_signal_emit_by_name (BAMF_APPLICATION (view), "window-removed",
 708                                bamf_view_get_path (child));
 709     }
 710 
 711   g_signal_handlers_disconnect_by_func (G_OBJECT (child), view_active_changed, view);
 712   g_signal_handlers_disconnect_by_func (G_OBJECT (child), view_urgent_changed, view);
 713   g_signal_handlers_disconnect_by_func (G_OBJECT (child), view_visible_changed, view);
 714 
 715   bamf_application_ensure_flags (self);
 716 
 717   if (!bamf_view_get_children (view) && bamf_application_get_close_when_empty (self))
 718     {
 719       bamf_view_close (view);
 720     }
 721 }
 722 
 723 static void
 724 matcher_favorites_changed (BamfMatcher *matcher, BamfApplication *self)
 725 {
 726   char *new_desktop_file = NULL;
 727 
 728   g_return_if_fail (BAMF_IS_APPLICATION (self));
 729   g_return_if_fail (BAMF_IS_MATCHER (matcher));
 730 
 731   new_desktop_file = bamf_application_favorite_from_list (self, self->priv->desktop_file_list);
 732 
 733   if (new_desktop_file)
 734     {
 735       bamf_application_set_desktop_file (self, new_desktop_file);
 736     }
 737 }
 738 
 739 static void
 740 on_window_added (BamfApplication *self, const gchar *win_path, gpointer _not_used)
 741 {
 742   g_return_if_fail (BAMF_IS_APPLICATION (self));
 743   g_signal_emit_by_name (self->priv->dbus_iface, "window-added", win_path);
 744 }
 745 
 746 static void
 747 on_window_removed (BamfApplication *self, const gchar *win_path, gpointer _not_used)
 748 {
 749   g_return_if_fail (BAMF_IS_APPLICATION (self));
 750   g_signal_emit_by_name (self->priv->dbus_iface, "window-removed", win_path);
 751 }
 752 
 753 static gboolean
 754 on_dbus_handle_show_stubs (BamfDBusItemApplication *interface,
 755                            GDBusMethodInvocation *invocation,
 756                            BamfApplication *self)
 757 {
 758   gboolean show_stubs = bamf_application_get_show_stubs (self);
 759   g_dbus_method_invocation_return_value (invocation,
 760                                          g_variant_new ("(b)", show_stubs));
 761 
 762   return TRUE;
 763 }
 764 
 765 static gboolean
 766 on_dbus_handle_xids (BamfDBusItemApplication *interface,
 767                      GDBusMethodInvocation *invocation,
 768                      BamfApplication *self)
 769 {
 770   GVariant *xids = bamf_application_get_xids (self);
 771   g_dbus_method_invocation_return_value (invocation, xids);
 772 
 773   return TRUE;
 774 }
 775 
 776 static gboolean
 777 on_dbus_handle_focusable_child (BamfDBusItemApplication *interface,
 778                            GDBusMethodInvocation *invocation,
 779                            BamfApplication *self)
 780 {
 781   GVariant *out_variant;
 782   BamfView *focusable_child;
 783 
 784   out_variant = NULL;
 785 
 786   focusable_child = bamf_application_get_focusable_child (self);
 787 
 788   if (focusable_child == NULL)
 789     {
 790       out_variant = g_variant_new("(s)", "");
 791     }
 792   else
 793     {
 794       const gchar *path;
 795 
 796       path = bamf_view_get_path (BAMF_VIEW (focusable_child));
 797 
 798       out_variant = g_variant_new("(s)", path);
 799     }
 800 
 801   g_dbus_method_invocation_return_value (invocation, out_variant);
 802 
 803   return TRUE;
 804 }
 805 
 806 static gboolean
 807 on_dbus_handle_desktop_file (BamfDBusItemApplication *interface,
 808                              GDBusMethodInvocation *invocation,
 809                              BamfApplication *self)
 810 {
 811   const char *desktop_file = self->priv->desktop_file ? self->priv->desktop_file : "";
 812   g_dbus_method_invocation_return_value (invocation,
 813                                          g_variant_new ("(s)", desktop_file));
 814 
 815   return TRUE;
 816 }
 817 
 818 static gboolean
 819 on_dbus_handle_supported_mime_types (BamfDBusItemApplication *interface,
 820                                      GDBusMethodInvocation *invocation,
 821                                      BamfApplication *self)
 822 {
 823   GVariant *list;
 824   GVariant *value;
 825 
 826   gchar **mimes = bamf_application_get_supported_mime_types (self);
 827 
 828   if (mimes)
 829     {
 830       list = g_variant_new_strv ((const gchar**) mimes, -1);
 831       g_strfreev (mimes);
 832     }
 833   else
 834     {
 835       list = g_variant_new_strv (NULL, 0);
 836     }
 837 
 838   value = g_variant_new ("(@as)", list);
 839   g_dbus_method_invocation_return_value (invocation, value);
 840 
 841   return TRUE;
 842 }
 843 
 844 static gboolean
 845 on_dbus_handle_application_menu (BamfDBusItemApplication *interface,
 846                                  GDBusMethodInvocation *invocation,
 847                                  BamfApplication *self)
 848 {
 849   gchar *name, *path;
 850 
 851   bamf_application_get_application_menu (self, &name, &path);
 852 
 853   name = name ? name : "";
 854   path = path ? path : "";
 855 
 856   g_dbus_method_invocation_return_value (invocation,
 857                                          g_variant_new ("(ss)", name, path));
 858 
 859   return TRUE;
 860 }
 861 
 862 static gboolean
 863 on_dbus_handle_application_type (BamfDBusItemApplication *interface,
 864                                  GDBusMethodInvocation *invocation,
 865                                  BamfApplication *self)
 866 {
 867   const char *type = self->priv->app_type ? self->priv->app_type : "";
 868   g_dbus_method_invocation_return_value (invocation,
 869                                          g_variant_new ("(s)", type));
 870 
 871   return TRUE;
 872 }
 873 
 874 static void
 875 bamf_application_dispose (GObject *object)
 876 {
 877   BamfApplication *app;
 878   BamfApplicationPrivate *priv;
 879 
 880   app = BAMF_APPLICATION (object);
 881   priv = app->priv;
 882 
 883   if (priv->desktop_file)
 884     {
 885       g_free (priv->desktop_file);
 886       priv->desktop_file = NULL;
 887     }
 888 
 889   if (priv->desktop_file_list)
 890     {
 891       g_list_free_full (priv->desktop_file_list, g_free);
 892       priv->desktop_file_list = NULL;
 893     }
 894 
 895   if (priv->app_type)
 896     {
 897       g_free (priv->app_type);
 898       priv->app_type = NULL;
 899     }
 900 
 901   if (priv->icon)
 902     {
 903       g_free (priv->icon);
 904       priv->icon = NULL;
 905     }
 906 
 907   if (priv->wmclass)
 908     {
 909       g_free (priv->wmclass);
 910       priv->wmclass = NULL;
 911     }
 912 
 913   g_strfreev (priv->mimes);
 914   priv->mimes = NULL;
 915 
 916   g_signal_handlers_disconnect_by_func (G_OBJECT (bamf_matcher_get_default ()),
 917                                         matcher_favorites_changed, object);
 918 
 919   G_OBJECT_CLASS (bamf_application_parent_class)->dispose (object);
 920 }
 921 
 922 static void
 923 bamf_application_finalize (GObject *object)
 924 {
 925   BamfApplication *self;
 926   self = BAMF_APPLICATION (object);
 927 
 928   g_object_unref (self->priv->dbus_iface);
 929 
 930   G_OBJECT_CLASS (bamf_application_parent_class)->finalize (object);
 931 }
 932 
 933 static void
 934 bamf_application_init (BamfApplication * self)
 935 {
 936   BamfApplicationPrivate *priv;
 937   priv = self->priv = BAMF_APPLICATION_GET_PRIVATE (self);
 938 
 939   priv->is_tab_container = FALSE;
 940   priv->app_type = g_strdup ("system");
 941   priv->show_stubs = TRUE;
 942   priv->wmclass = NULL;
 943 
 944   /* Initializing the dbus interface */
 945   priv->dbus_iface = bamf_dbus_item_application_skeleton_new ();
 946 
 947   /* We need to connect to the object own signals to redirect them to the dbus
 948    * interface                                                                */
 949   g_signal_connect (self, "window-added", G_CALLBACK (on_window_added), NULL);
 950   g_signal_connect (self, "window-removed", G_CALLBACK (on_window_removed), NULL);
 951 
 952   /* Registering signal callbacks to reply to dbus method calls */
 953   g_signal_connect (priv->dbus_iface, "handle-show-stubs",
 954                     G_CALLBACK (on_dbus_handle_show_stubs), self);
 955 
 956   g_signal_connect (priv->dbus_iface, "handle-xids",
 957                     G_CALLBACK (on_dbus_handle_xids), self);
 958 
 959   g_signal_connect (priv->dbus_iface, "handle-focusable-child",
 960                     G_CALLBACK (on_dbus_handle_focusable_child), self);
 961 
 962   g_signal_connect (priv->dbus_iface, "handle-desktop-file",
 963                     G_CALLBACK (on_dbus_handle_desktop_file), self);
 964 
 965   g_signal_connect (priv->dbus_iface, "handle-supported-mime-types",
 966                     G_CALLBACK (on_dbus_handle_supported_mime_types), self);
 967 
 968   g_signal_connect (priv->dbus_iface, "handle-application-menu",
 969                     G_CALLBACK (on_dbus_handle_application_menu), self);
 970 
 971   g_signal_connect (priv->dbus_iface, "handle-application-type",
 972                     G_CALLBACK (on_dbus_handle_application_type), self);
 973 
 974   /* Setting the interface for the dbus object */
 975   bamf_dbus_item_object_skeleton_set_application (BAMF_DBUS_ITEM_OBJECT_SKELETON (self),
 976                                                   priv->dbus_iface);
 977 
 978   g_signal_connect (G_OBJECT (bamf_matcher_get_default ()), "favorites-changed",
 979                     (GCallback) matcher_favorites_changed, self);
 980 }
 981 
 982 static void
 983 bamf_application_dbus_application_iface_init (BamfDBusItemApplicationIface *iface)
 984 {
 985 }
 986 
 987 static void
 988 bamf_application_class_init (BamfApplicationClass * klass)
 989 {
 990   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 991   BamfViewClass *view_class = BAMF_VIEW_CLASS (klass);
 992 
 993   object_class->dispose = bamf_application_dispose;
 994   object_class->finalize = bamf_application_finalize;
 995 
 996   view_class->view_type = bamf_application_get_view_type;
 997   view_class->child_added = bamf_application_child_added;
 998   view_class->child_removed = bamf_application_child_removed;
 999   view_class->get_icon = bamf_application_get_icon;
1000   view_class->stable_bus_name = bamf_application_get_stable_bus_name;
1001 
1002   klass->get_supported_mime_types = bamf_application_default_get_supported_mime_types;
1003   klass->get_close_when_empty = bamf_application_default_get_close_when_empty;
1004   klass->supported_mimes_changed = bamf_application_supported_mime_types_changed;
1005 
1006   g_type_class_add_private (klass, sizeof (BamfApplicationPrivate));
1007 
1008   application_signals[SUPPORTED_MIMES_CHANGED] =
1009     g_signal_new ("supported-mimes-changed",
1010                   G_OBJECT_CLASS_TYPE (klass),
1011                   G_SIGNAL_RUN_FIRST,
1012                   G_STRUCT_OFFSET (BamfApplicationClass, supported_mimes_changed),
1013                   NULL, NULL,
1014                   g_cclosure_marshal_generic,
1015                   G_TYPE_NONE, 1,
1016                   G_TYPE_STRV);
1017 }
1018 
1019 BamfApplication *
1020 bamf_application_new (void)
1021 {
1022   BamfApplication *application;
1023   application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL);
1024 
1025   return application;
1026 }
1027 
1028 BamfApplication *
1029 bamf_application_new_from_desktop_file (const char * desktop_file)
1030 {
1031   BamfApplication *application;
1032   application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL);
1033 
1034   bamf_application_set_desktop_file (application, desktop_file);
1035 
1036   return application;
1037 }
1038 
1039 BamfApplication *
1040 bamf_application_new_from_desktop_files (GList *desktop_files)
1041 {
1042   BamfApplication *application;
1043   application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL);
1044 
1045   bamf_application_set_desktop_file_from_list (application, desktop_files);
1046 
1047   return application;
1048 }
1049 
1050 BamfApplication *
1051 bamf_application_new_with_wmclass (const char *wmclass)
1052 {
1053   BamfApplication *application;
1054   application = (BamfApplication *) g_object_new (BAMF_TYPE_APPLICATION, NULL);
1055 
1056   bamf_application_set_wmclass (application, wmclass);
1057 
1058   return application;
1059 }
1060 
1061 /**
1062     bamf_application_get_show_stubs:
1063     @application: Application to check for menu stubs
1064 
1065     Checks to see if the application should show menu stubs or not.
1066     This is specified with the "X-Ayatana-Appmenu-Show-Stubs" desktop
1067     file key.
1068 
1069     Return Value: Defaults to TRUE, else FALSE if specified in
1070       .desktop file.
1071 */
1072 gboolean
1073 bamf_application_get_show_stubs (BamfApplication *application)
1074 {
1075     g_return_val_if_fail(BAMF_IS_APPLICATION(application), TRUE);
1076     return application->priv->show_stubs;
1077 }
1078 
1079 
1080 gboolean
1081 bamf_application_get_close_when_empty (BamfApplication *application)
1082 {
1083   g_return_val_if_fail (BAMF_IS_APPLICATION(application), FALSE);
1084   
1085   if (BAMF_APPLICATION_GET_CLASS (application)->get_close_when_empty)
1086     {
1087       return BAMF_APPLICATION_GET_CLASS (application)->get_close_when_empty(application);
1088     }
1089   return TRUE;
1090 }
1091 
1092 void
1093 bamf_application_get_application_menu (BamfApplication *application, gchar **name, gchar **object_path)
1094 {
1095   g_return_if_fail (BAMF_IS_APPLICATION (application));
1096   
1097   if (BAMF_APPLICATION_GET_CLASS (application)->get_application_menu)
1098     {
1099       BAMF_APPLICATION_GET_CLASS (application)->get_application_menu (application, name, object_path);
1100     }
1101   else
1102     {
1103       *name = NULL;
1104       *object_path = NULL;
1105     }
1106 }
1107 
1108 BamfView *
1109 bamf_application_get_focusable_child (BamfApplication *application)
1110 {
1111   g_return_val_if_fail (BAMF_IS_APPLICATION (application), NULL);
1112   
1113   if (BAMF_APPLICATION_GET_CLASS (application)->get_focusable_child)
1114     {
1115       return BAMF_APPLICATION_GET_CLASS (application)->get_focusable_child (application);
1116     }
1117   
1118   return NULL;
1119 }