Back to index

indicator-appmenu  12.10.0
hudwindowsource.c
Go to the documentation of this file.
00001 /*
00002  * Copyright © 2012 Canonical Ltd.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU General Public License version 3, as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranties of
00010  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
00011  * PURPOSE.  See the GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License along
00014  * with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Author: Ryan Lortie <desrt@desrt.ca>
00017  */
00018 
00019 #define G_LOG_DOMAIN "hudwindowsource"
00020 
00021 #include "hudwindowsource.h"
00022 
00023 #include <libbamf/libbamf.h>
00024 #include <string.h>
00025 
00026 #include "hudmenumodelcollector.h"
00027 #include "huddbusmenucollector.h"
00028 #include "hudsource.h"
00029 
00061 struct _HudWindowSource
00062 {
00063   GObject parent_instance;
00064 
00065   BamfMatcher *matcher;
00066 
00067   BamfWindow *active_window;
00068   BamfApplication *active_application;
00069   const gchar *active_desktop_file;
00070   gchar *active_icon;
00071   HudSource *active_collector;
00072   gint use_count;
00073 };
00074 
00075 typedef GObjectClass HudWindowSourceClass;
00076 
00077 static void hud_window_source_iface_init (HudSourceInterface *iface);
00078 G_DEFINE_TYPE_WITH_CODE (HudWindowSource, hud_window_source, G_TYPE_OBJECT,
00079                          G_IMPLEMENT_INTERFACE (HUD_TYPE_SOURCE, hud_window_source_iface_init))
00080 
00081 static gboolean
00082 hud_window_source_desktop_file_in_debug_list (const gchar *desktop_file)
00083 {
00084   static GStrv debug_list = NULL;
00085   gint i;
00086 
00087   /* Looks at the envvar to see if there is a list of items that we shouldn't
00088      view as focus changes so that we can use those tools for debugging */
00089   if (debug_list == NULL)
00090     {
00091       const gchar * dbgenv = g_getenv ("INDICATOR_APPMENU_DEBUG_APPS");
00092       if (dbgenv != NULL)
00093         debug_list = g_strsplit (dbgenv, ":", 0);
00094       else
00095         debug_list = g_new0 (gchar *, 1);
00096     }
00097 
00098   g_debug ("checking desktop file '%s'", desktop_file);
00099 
00100   for (i = 0; debug_list[i] != NULL; i++)
00101     if (debug_list[i][0] != '\0' && strstr (desktop_file, debug_list[i]))
00102       {
00103         g_debug ("desktop file name '%s' blocked (hit debug list item '%s')", desktop_file, debug_list[i]);
00104         return TRUE;
00105       }
00106 
00107   return FALSE;
00108 }
00109 
00110 static gboolean
00111 hud_window_source_name_in_ignore_list (BamfWindow *window)
00112 {
00113   static const gchar * const ignored_names[] = {
00114     "Hud Prototype Test",
00115     "Hud",
00116     "DNDCollectionWindow",
00117     "launcher",
00118     "dash",
00119     "Dash",
00120     "panel",
00121     "hud",
00122     "unity-2d-shell"
00123   };
00124   gboolean ignored = FALSE;
00125   gchar *window_name;
00126   gint i;
00127 
00128   window_name = bamf_view_get_name (BAMF_VIEW (window));
00129   g_debug ("checking window name '%s'", window_name);
00130 
00131   /* sometimes bamf returns NULL here... protect ourselves */
00132   if (window_name == NULL)
00133     return TRUE;
00134 
00135   for (i = 0; i < G_N_ELEMENTS (ignored_names); i++)
00136     if (g_str_equal (ignored_names[i], window_name))
00137       {
00138         g_debug ("window name '%s' blocked", window_name);
00139         ignored = TRUE;
00140         break;
00141       }
00142 
00143   g_free (window_name);
00144 
00145   return ignored;
00146 }
00147 
00148 static HudSource *
00149 hud_window_source_get_collector (HudWindowSource *source)
00150 {
00151   static GQuark menu_collector_quark;
00152   HudSource *collector;
00153 
00154   if (source->active_window == NULL)
00155     return NULL;
00156 
00157   if (!menu_collector_quark)
00158     menu_collector_quark = g_quark_from_string ("menu collector");
00159 
00160   collector = g_object_get_qdata (G_OBJECT (source->active_window), menu_collector_quark);
00161   if (collector == NULL)
00162     {
00163       HudMenuModelCollector *menumodel_collector;
00164 
00165       /* GMenuModel menus either exist at the start or will never exist.
00166        * dbusmenu menus can appear later.
00167        *
00168        * For that reason, we check first for GMenuModel and assume if it
00169        * doesn't exist then it must be dbusmenu.
00170        */
00171       menumodel_collector = hud_menu_model_collector_get (source->active_window,
00172                                                           source->active_desktop_file,
00173                                                           source->active_icon);
00174       if (menumodel_collector)
00175         collector = HUD_SOURCE (menumodel_collector);
00176       else
00177         collector = HUD_SOURCE (hud_dbusmenu_collector_new_for_window (source->active_window,
00178                                                                        source->active_desktop_file,
00179                                                                        source->active_icon));
00180 
00181       g_object_set_qdata_full (G_OBJECT (source->active_window), menu_collector_quark, collector, g_object_unref);
00182     }
00183 
00184   return collector;
00185 }
00186 
00187 static void
00188 hud_window_source_collector_changed (HudSource *collector,
00189                                      gpointer   user_data)
00190 {
00191   HudWindowSource *source = user_data;
00192 
00193   hud_source_changed (HUD_SOURCE (source));
00194 }
00195 
00196 static void
00197 hud_window_source_active_window_changed (BamfMatcher *matcher,
00198                                          BamfView    *oldview,
00199                                          BamfView    *newview,
00200                                          gpointer     user_data)
00201 {
00202   HudWindowSource *source = user_data;
00203   BamfWindow *window;
00204   BamfApplication *application;
00205   const gchar *desktop_file;
00206 
00207   g_debug ("Switching windows");
00208 
00209   if (!BAMF_IS_WINDOW (newview))
00210     {
00211       g_debug ("ignoring switch to non-window");
00212       return;
00213     }
00214 
00215   window = BAMF_WINDOW (newview);
00216 
00217   if (window == source->active_window)
00218     {
00219       g_debug ("this is already the active window");
00220       return;
00221     }
00222 
00223   if (hud_window_source_name_in_ignore_list (window))
00224     return;
00225 
00226   application = bamf_matcher_get_application_for_window (source->matcher, window);
00227 
00228   if (application == NULL)
00229     {
00230       g_debug ("ignoring window with no application");
00231       return;
00232     }
00233 
00234   desktop_file = bamf_application_get_desktop_file (application);
00235 
00236   if (desktop_file == NULL)
00237     {
00238       g_debug ("ignoring application with no desktop file");
00239       return;
00240     }
00241 
00242   if (hud_window_source_desktop_file_in_debug_list (desktop_file))
00243     return;
00244 
00245   g_debug ("new active window (xid %u)", bamf_window_get_xid (window));
00246 
00247 
00248   if (source->active_collector)
00249     {
00250       g_signal_handlers_disconnect_by_func (source->active_collector, hud_window_source_collector_changed, source);
00251       if (source->use_count)
00252         hud_source_unuse (source->active_collector);
00253     }
00254 
00255   g_clear_object (&source->active_collector);
00256   g_clear_object (&source->active_application);
00257   g_clear_object (&source->active_window);
00258   g_free (source->active_icon);
00259   source->active_window = g_object_ref (window);
00260   source->active_application = g_object_ref (application);
00261   source->active_desktop_file = desktop_file;
00262   source->active_icon = bamf_view_get_icon (BAMF_VIEW (application));
00263   source->active_collector = g_object_ref (hud_window_source_get_collector (source));
00264 
00265   if (source->use_count)
00266     hud_source_use (source->active_collector);
00267   g_signal_connect_object (source->active_collector, "changed",
00268                            G_CALLBACK (hud_window_source_collector_changed), source, 0);
00269 
00270   hud_source_changed (HUD_SOURCE (source));
00271 }
00272 
00273 static void
00274 hud_window_source_use (HudSource *hud_source)
00275 {
00276   HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
00277 
00278   if (source->use_count == 0)
00279     if (source->active_collector)
00280       hud_source_use (source->active_collector);
00281 
00282   source->use_count++;
00283 }
00284 
00285 static void
00286 hud_window_source_unuse (HudSource *hud_source)
00287 {
00288   HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
00289 
00290   g_return_if_fail (source->use_count > 0);
00291 
00292   source->use_count--;
00293 
00294   if (source->use_count == 0)
00295     if (source->active_collector)
00296       hud_source_unuse (source->active_collector);
00297 }
00298 
00299 static void
00300 hud_window_source_search (HudSource    *hud_source,
00301                           GPtrArray    *results_array,
00302                           HudTokenList *search_string)
00303 {
00304   HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
00305 
00306   if (source->active_collector)
00307     hud_source_search (source->active_collector, results_array, search_string);
00308 }
00309 
00310 static void
00311 hud_window_source_finalize (GObject *object)
00312 {
00313   HudWindowSource *source = HUD_WINDOW_SOURCE (object);
00314 
00315   g_assert_cmpint (source->use_count, ==, 0);
00316 
00317   /* bamf matcher signals already disconnected in dispose */
00318   g_clear_object (&source->active_collector);
00319   g_clear_object (&source->active_application);
00320   g_clear_object (&source->active_window);
00321   g_free (source->active_icon);
00322 
00323   G_OBJECT_CLASS (hud_window_source_parent_class)
00324     ->finalize (object);
00325 }
00326 
00327 static void
00328 hud_window_source_init (HudWindowSource *source)
00329 {
00330   BamfWindow *window;
00331 
00332   source->matcher = bamf_matcher_get_default ();
00333 
00334   g_signal_connect_object (source->matcher, "active-window-changed",
00335                            G_CALLBACK (hud_window_source_active_window_changed), source, 0);
00336   window = bamf_matcher_get_active_window (source->matcher);
00337   if (window != NULL)
00338     hud_window_source_active_window_changed (source->matcher, NULL, BAMF_VIEW (window), source);
00339 }
00340 
00341 static void
00342 hud_window_source_iface_init (HudSourceInterface *iface)
00343 {
00344   iface->use = hud_window_source_use;
00345   iface->unuse = hud_window_source_unuse;
00346   iface->search = hud_window_source_search;
00347 }
00348 
00349 static void
00350 hud_window_source_class_init (HudWindowSourceClass *class)
00351 {
00352   class->finalize = hud_window_source_finalize;
00353 }
00354 
00362 HudWindowSource *
00363 hud_window_source_new (void)
00364 {
00365   return g_object_new (HUD_TYPE_WINDOW_SOURCE, NULL);
00366 }