Back to index

bamf  0.2.120
bamf-factory.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Canonical Ltd.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of either or both of the following licenses:
00006  *
00007  * 1) the GNU Lesser General Public License version 3, as published by the
00008  * Free Software Foundation; and/or
00009  * 2) the GNU Lesser General Public License version 2.1, as published by
00010  * the Free Software Foundation.
00011  *
00012  * This program is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranties of
00014  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00015  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00016  * License for more details.
00017  *
00018  * You should have received a copy of both the GNU Lesser General Public
00019  * License version 3 and version 2.1 along with this program.  If not, see
00020  * <http://www.gnu.org/licenses/>
00021  *
00022  * Authored by: Jason Smith <jason.smith@canonical.com>
00023  *              Neil Jagdish Patel <neil.patel@canonical.com>
00024  *
00025  */
00033 #if HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "bamf-factory.h"
00038 #include "bamf-view.h"
00039 #include "bamf-view-private.h"
00040 #include "bamf-window.h"
00041 #include "bamf-application.h"
00042 #include "bamf-application-private.h"
00043 #include "bamf-indicator.h"
00044 
00045 #include <dbus/dbus.h>
00046 #include <dbus/dbus-glib.h>
00047 #include <dbus/dbus-glib-lowlevel.h>
00048 #include <string.h>
00049 
00050 G_DEFINE_TYPE (BamfFactory, bamf_factory, G_TYPE_OBJECT);
00051 
00052 #define BAMF_FACTORY_GET_PRIVATE(o) \
00053   (G_TYPE_INSTANCE_GET_PRIVATE ((o), BAMF_TYPE_FACTORY, BamfFactoryPrivate))
00054 
00055 struct _BamfFactoryPrivate
00056 {
00057   GHashTable *views;
00058   GList *local_views;
00059   GList *registered_views;
00060 };
00061 
00062 static BamfFactory *factory = NULL;
00063 
00064 BamfApplication * bamf_application_new_favorite     (const char *favorite_path);
00065 
00066 BamfApplication * bamf_application_new              (const char *path);
00067 
00068 BamfWindow      * bamf_window_new                   (const char *path);
00069 
00070 BamfIndicator   * bamf_indicator_new                (const char *path);
00071 
00072 static void
00073 bamf_factory_class_init (BamfFactoryClass *klass)
00074 {
00075   GObjectClass *obj_class = G_OBJECT_CLASS (klass);
00076 
00077   g_type_class_add_private (obj_class, sizeof (BamfFactoryPrivate));
00078 }
00079 
00080 
00081 static void
00082 bamf_factory_init (BamfFactory *self)
00083 {
00084   BamfFactoryPrivate *priv;
00085 
00086   priv = self->priv = BAMF_FACTORY_GET_PRIVATE (self);
00087 
00088   priv->views = g_hash_table_new_full ((GHashFunc) g_str_hash, (GEqualFunc) g_str_equal, (GDestroyNotify) g_free, NULL);
00089 }
00090 
00091 static void
00092 on_view_closed (BamfView *view, BamfFactory *self)
00093 {
00094   const char *path;
00095   
00096   g_return_if_fail (BAMF_IS_VIEW (view));
00097   
00098   path = _bamf_view_get_path (view);
00099   if (path)
00100     g_hash_table_remove (self->priv->views, path);
00101   
00102   g_object_unref (view);
00103 }
00104 
00105 static void
00106 on_view_weak_unref (BamfFactory *self, BamfView *view)
00107 {
00108   g_return_if_fail (BAMF_IS_FACTORY (self));
00109   self->priv->local_views = g_list_remove (self->priv->local_views, view);
00110   self->priv->registered_views = g_list_remove (self->priv->registered_views, view);
00111 }
00112 
00113 static void
00114 bamf_factory_register_view (BamfFactory *self, BamfView *view, const char *path)
00115 {
00116   GHashTable *views;
00117   views = self->priv->views;
00118   
00119   g_hash_table_insert (views, g_strdup (path), view);
00120 
00121   if (g_list_find (self->priv->registered_views, view))
00122     return;
00123   
00124   self->priv->registered_views = g_list_prepend (self->priv->registered_views, view);
00125   
00126   g_signal_connect (G_OBJECT (view), "closed", (GCallback) on_view_closed, self);
00127   g_object_weak_ref (G_OBJECT (view), (GWeakNotify) on_view_weak_unref, self);
00128 }
00129 
00130 BamfApplication * 
00131 _bamf_factory_app_for_file (BamfFactory * factory,
00132                            const char * path,
00133                            gboolean create)
00134 {
00135   BamfApplication *result = NULL, *app;
00136   GList *l;
00137   
00138   /* check if result is available in known local_views */
00139   for (l = factory->priv->local_views; l; l = l->next)
00140     {
00141       if (!BAMF_IS_APPLICATION (l->data))
00142         continue;
00143 
00144       app = BAMF_APPLICATION (l->data);
00145       if (g_strcmp0 (bamf_application_get_desktop_file (app), path) == 0)
00146         {
00147           result = app;
00148           break;
00149         }
00150     }
00151   
00152   /* else create new */
00153   if (!result && create)
00154     {
00155       /* delay registration until match time */
00156       result = bamf_application_new_favorite (path);
00157       if (result)
00158         factory->priv->local_views = g_list_prepend (factory->priv->local_views, result);
00159     }
00160   
00161   return result;
00162 }
00163 
00164 static
00165 BamfFactoryViewType compute_factory_type_by_str (const char *type)
00166 {
00167   BamfFactoryViewType factory_type = BAMF_FACTORY_NONE;
00168 
00169   if (type && type[0] != '\0')
00170     {
00171       if (g_strcmp0 (type, "window") == 0)
00172         {
00173           factory_type = BAMF_FACTORY_WINDOW;
00174         }
00175       else if (g_strcmp0 (type, "application") == 0)
00176         {
00177           factory_type = BAMF_FACTORY_APPLICATION;
00178         }
00179       else if (g_strcmp0 (type, "indicator") == 0)
00180         {
00181           factory_type = BAMF_FACTORY_INDICATOR;
00182         }
00183       else if (g_strcmp0 (type, "view") == 0)
00184         {
00185           factory_type = BAMF_FACTORY_VIEW;
00186         }
00187     }
00188 
00189   return factory_type;
00190 }
00191 
00192 BamfView * 
00193 _bamf_factory_view_for_path (BamfFactory * factory, const char * path)
00194 {
00195   return _bamf_factory_view_for_path_type (factory, path, BAMF_FACTORY_NONE);
00196 }
00197 
00198 BamfView * 
00199 _bamf_factory_view_for_path_type_str (BamfFactory * factory, const char * path,
00200                                                             const char * type)
00201 {
00202   g_return_val_if_fail (BAMF_IS_FACTORY (factory), NULL);
00203   BamfFactoryViewType factory_type = compute_factory_type_by_str (type);
00204 
00205   return _bamf_factory_view_for_path_type (factory, path, factory_type);
00206 }
00207 
00208 BamfView *
00209 _bamf_factory_view_for_path_type (BamfFactory * factory, const char * path,
00210                                                          BamfFactoryViewType type)
00211 {
00212   GHashTable *views;
00213   BamfView *view;
00214   GList *l;
00215   gboolean created = FALSE;
00216 
00217   g_return_val_if_fail (BAMF_IS_FACTORY (factory), NULL);
00218   
00219   if (!path || path[0] == '\0')
00220     return NULL;
00221   
00222   views = factory->priv->views;
00223   view = g_hash_table_lookup (views, path);
00224   
00225   if (BAMF_IS_VIEW (view))
00226     return view;
00227 
00228   if (type == BAMF_FACTORY_NONE)
00229     {
00230       view = g_object_new (BAMF_TYPE_VIEW, NULL);
00231       _bamf_view_set_path (view, path);
00232       type = compute_factory_type_by_str (bamf_view_get_view_type (view));
00233       g_object_unref (view);
00234       view = NULL;
00235     }
00236 
00237   switch (type)
00238   {
00239     case BAMF_FACTORY_VIEW:
00240       view = g_object_new (BAMF_TYPE_VIEW, NULL);
00241       break;
00242     case BAMF_FACTORY_WINDOW:
00243       view = BAMF_VIEW (bamf_window_new (path));
00244       break;
00245     case BAMF_FACTORY_APPLICATION:
00246       view = BAMF_VIEW (bamf_application_new (path));
00247       break;
00248     case BAMF_FACTORY_INDICATOR:
00249       view = BAMF_VIEW (bamf_indicator_new (path));
00250       break;
00251     case BAMF_FACTORY_NONE:
00252       view = NULL;
00253   }
00254 
00255   created = TRUE;
00256   BamfView *matched_view = NULL;
00257 
00258   if (BAMF_IS_APPLICATION (view))
00259     {
00260       /* handle case where a favorite exists and this matches it */
00261       const char *local_desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
00262       GList *local_children = bamf_view_get_children (view);
00263 
00264       for (l = factory->priv->local_views; l; l = l->next)
00265         {
00266           if (!BAMF_IS_APPLICATION (l->data))
00267             continue;
00268 
00269           BamfView *list_view = BAMF_VIEW (l->data);
00270           BamfApplication *list_app = BAMF_APPLICATION (l->data);
00271 
00272           const char *list_desktop_file = bamf_application_get_desktop_file (list_app);
00273 
00274           /* We try to match applications by desktop files */
00275           if (local_desktop_file && g_strcmp0 (local_desktop_file, list_desktop_file) == 0)
00276             {
00277               matched_view = list_view;
00278               break;
00279             }
00280 
00281           /* If the primary search doesn't give out any result, we fallback
00282            * to children window comparison */
00283           if (!matched_view)
00284             {
00285               GList *list_children, *ll;
00286               list_children = _bamf_application_get_cached_xids (list_app);
00287 
00288               for (ll = local_children; ll; ll = ll->next)
00289                 {
00290                   if (!BAMF_IS_WINDOW (ll->data))
00291                     continue;
00292 
00293                   guint32 local_xid = bamf_window_get_xid (BAMF_WINDOW (ll->data));
00294 
00295                   if (g_list_find (list_children, GUINT_TO_POINTER (local_xid)))
00296                     {
00297                       matched_view = list_view;
00298                       break;
00299                     }
00300                 }
00301             }
00302         }
00303 
00304       g_list_free (local_children);
00305     }
00306   else if (BAMF_IS_WINDOW (view))
00307     {
00308       guint32 local_xid = bamf_window_get_xid (BAMF_WINDOW (view));
00309 
00310       for (l = factory->priv->local_views; l; l = l->next)
00311         {
00312           if (!BAMF_IS_WINDOW (l->data))
00313             continue;
00314 
00315           BamfView *list_view = BAMF_VIEW (l->data);
00316           BamfWindow *list_win = BAMF_WINDOW (l->data);
00317 
00318           guint32 list_xid = bamf_window_get_xid (list_win);
00319 
00320           /* We try to match windows by xid */
00321           if (local_xid != 0 && local_xid == list_xid)
00322             {
00323               matched_view = list_view;
00324               break;
00325             }
00326         }
00327     }
00328 
00329   if (matched_view)
00330     {
00331       created = FALSE;
00332       g_object_unref (view);
00333 
00334       view = matched_view;
00335       _bamf_view_set_path (view, path);
00336       g_object_ref_sink (view);
00337     }
00338 
00339   if (view)
00340     {
00341       bamf_factory_register_view (factory, view, path);
00342       
00343       if (created)
00344         {
00345           factory->priv->local_views = g_list_prepend (factory->priv->local_views, view);
00346           g_object_ref_sink (view);
00347         }
00348     }
00349 
00350   return view;
00351 }
00352 
00353 BamfFactory * 
00354 _bamf_factory_get_default (void)
00355 {
00356   
00357   if (BAMF_IS_FACTORY (factory))
00358     return factory;
00359   
00360   factory = (BamfFactory *) g_object_new (BAMF_TYPE_FACTORY, NULL);
00361   return factory;
00362 }