~ubuntu-branches/ubuntu/saucy/indicator-appmenu/saucy-updates

« back to all changes in this revision

Viewing changes to src/hudwindowsource.c

  • Committer: Package Import Robot
  • Author(s): Automatic PS uploader, Mathieu Trudel-Lapierre, Automatic PS uploader
  • Date: 2013-02-20 09:41:54 UTC
  • mfrom: (1.1.40)
  • Revision ID: package-import@ubuntu.com-20130220094154-zrxsx0vgay436wyt
Tags: 13.01.0daily13.02.20-0ubuntu1
[ Mathieu Trudel-Lapierre ]
* Artificially bump upstream major version to please hud.

[ Automatic PS uploader ]
* Automatic snapshot from revision 234

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2012 Canonical Ltd.
3
 
 *
4
 
 * This program is free software: you can redistribute it and/or modify it
5
 
 * 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, but
9
 
 * WITHOUT ANY WARRANTY; without even the implied warranties of
10
 
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
 
 * PURPOSE.  See the GNU General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU General Public License along
14
 
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 *
16
 
 * Author: Ryan Lortie <desrt@desrt.ca>
17
 
 */
18
 
 
19
 
#define G_LOG_DOMAIN "hudwindowsource"
20
 
 
21
 
#include "hudwindowsource.h"
22
 
 
23
 
#include <libbamf/libbamf.h>
24
 
#include <string.h>
25
 
 
26
 
#include "hudmenumodelcollector.h"
27
 
#include "huddbusmenucollector.h"
28
 
#include "hudsource.h"
29
 
 
30
 
/**
31
 
 * SECTION:hudwindowsource
32
 
 * @title: HudWindowSource
33
 
 * @short_description: a #HudSource for the menubars of windows
34
 
 *
35
 
 * #HudWindowSource is a #HudSource that allows searching for items in
36
 
 * the menubars of application windows.
37
 
 *
38
 
 * The source tracks which is the active window of the application,
39
 
 * using BAMF.  hud_source_search() calls will be redirected to an
40
 
 * appropriate source corresponding to the active window.  When the
41
 
 * active window changes, the HudSource::changed signal will be emitted.
42
 
 *
43
 
 * #GMenuModel and Dbusmenu-style menus are both understood.  They are
44
 
 * implemented via #HudMenuModelCollector and #HudDbusmenuCollector,
45
 
 * respectively.
46
 
 *
47
 
 * #HudWindowSource takes care to avoid various bits of desktop chrome
48
 
 * from becoming considered as the active window.  This is done via a
49
 
 * built-in blacklist.  It is also possible, for testing purposes, to
50
 
 * use the <envar>INDICATOR_APPMENU_DEBUG_APPS</envar> environment
51
 
 * variable to specify a list of desktop file names corresponding to
52
 
 * applications to ignore windows from (for example, the terminal).
53
 
 **/
54
 
 
55
 
/**
56
 
 * HudWindowSource:
57
 
 *
58
 
 * This is an opaque structure type.
59
 
 **/
60
 
 
61
 
struct _HudWindowSource
62
 
{
63
 
  GObject parent_instance;
64
 
 
65
 
  BamfMatcher *matcher;
66
 
 
67
 
  BamfWindow *active_window;
68
 
  BamfApplication *active_application;
69
 
  const gchar *active_desktop_file;
70
 
  gchar *active_icon;
71
 
  HudSource *active_collector;
72
 
  gint use_count;
73
 
};
74
 
 
75
 
typedef GObjectClass HudWindowSourceClass;
76
 
 
77
 
static void hud_window_source_iface_init (HudSourceInterface *iface);
78
 
G_DEFINE_TYPE_WITH_CODE (HudWindowSource, hud_window_source, G_TYPE_OBJECT,
79
 
                         G_IMPLEMENT_INTERFACE (HUD_TYPE_SOURCE, hud_window_source_iface_init))
80
 
 
81
 
static gboolean
82
 
hud_window_source_desktop_file_in_debug_list (const gchar *desktop_file)
83
 
{
84
 
  static GStrv debug_list = NULL;
85
 
  gint i;
86
 
 
87
 
  /* Looks at the envvar to see if there is a list of items that we shouldn't
88
 
     view as focus changes so that we can use those tools for debugging */
89
 
  if (debug_list == NULL)
90
 
    {
91
 
      const gchar * dbgenv = g_getenv ("INDICATOR_APPMENU_DEBUG_APPS");
92
 
      if (dbgenv != NULL)
93
 
        debug_list = g_strsplit (dbgenv, ":", 0);
94
 
      else
95
 
        debug_list = g_new0 (gchar *, 1);
96
 
    }
97
 
 
98
 
  g_debug ("checking desktop file '%s'", desktop_file);
99
 
 
100
 
  for (i = 0; debug_list[i] != NULL; i++)
101
 
    if (debug_list[i][0] != '\0' && strstr (desktop_file, debug_list[i]))
102
 
      {
103
 
        g_debug ("desktop file name '%s' blocked (hit debug list item '%s')", desktop_file, debug_list[i]);
104
 
        return TRUE;
105
 
      }
106
 
 
107
 
  return FALSE;
108
 
}
109
 
 
110
 
static gboolean
111
 
hud_window_source_name_in_ignore_list (BamfWindow *window)
112
 
{
113
 
  static const gchar * const ignored_names[] = {
114
 
    "Hud Prototype Test",
115
 
    "Hud",
116
 
    "DNDCollectionWindow",
117
 
    "launcher",
118
 
    "dash",
119
 
    "Dash",
120
 
    "panel",
121
 
    "hud",
122
 
    "unity-2d-shell"
123
 
  };
124
 
  gboolean ignored = FALSE;
125
 
  gchar *window_name;
126
 
  gint i;
127
 
 
128
 
  window_name = bamf_view_get_name (BAMF_VIEW (window));
129
 
  g_debug ("checking window name '%s'", window_name);
130
 
 
131
 
  /* sometimes bamf returns NULL here... protect ourselves */
132
 
  if (window_name == NULL)
133
 
    return TRUE;
134
 
 
135
 
  for (i = 0; i < G_N_ELEMENTS (ignored_names); i++)
136
 
    if (g_str_equal (ignored_names[i], window_name))
137
 
      {
138
 
        g_debug ("window name '%s' blocked", window_name);
139
 
        ignored = TRUE;
140
 
        break;
141
 
      }
142
 
 
143
 
  g_free (window_name);
144
 
 
145
 
  return ignored;
146
 
}
147
 
 
148
 
static HudSource *
149
 
hud_window_source_get_collector (HudWindowSource *source)
150
 
{
151
 
  static GQuark menu_collector_quark;
152
 
  HudSource *collector;
153
 
 
154
 
  if (source->active_window == NULL)
155
 
    return NULL;
156
 
 
157
 
  if (!menu_collector_quark)
158
 
    menu_collector_quark = g_quark_from_string ("menu collector");
159
 
 
160
 
  collector = g_object_get_qdata (G_OBJECT (source->active_window), menu_collector_quark);
161
 
  if (collector == NULL)
162
 
    {
163
 
      HudMenuModelCollector *menumodel_collector;
164
 
 
165
 
      /* GMenuModel menus either exist at the start or will never exist.
166
 
       * dbusmenu menus can appear later.
167
 
       *
168
 
       * For that reason, we check first for GMenuModel and assume if it
169
 
       * doesn't exist then it must be dbusmenu.
170
 
       */
171
 
      menumodel_collector = hud_menu_model_collector_get (source->active_window,
172
 
                                                          source->active_desktop_file,
173
 
                                                          source->active_icon);
174
 
      if (menumodel_collector)
175
 
        collector = HUD_SOURCE (menumodel_collector);
176
 
      else
177
 
        collector = HUD_SOURCE (hud_dbusmenu_collector_new_for_window (source->active_window,
178
 
                                                                       source->active_desktop_file,
179
 
                                                                       source->active_icon));
180
 
 
181
 
      g_object_set_qdata_full (G_OBJECT (source->active_window), menu_collector_quark, collector, g_object_unref);
182
 
    }
183
 
 
184
 
  return collector;
185
 
}
186
 
 
187
 
static void
188
 
hud_window_source_collector_changed (HudSource *collector,
189
 
                                     gpointer   user_data)
190
 
{
191
 
  HudWindowSource *source = user_data;
192
 
 
193
 
  hud_source_changed (HUD_SOURCE (source));
194
 
}
195
 
 
196
 
static void
197
 
hud_window_source_active_window_changed (BamfMatcher *matcher,
198
 
                                         BamfView    *oldview,
199
 
                                         BamfView    *newview,
200
 
                                         gpointer     user_data)
201
 
{
202
 
  HudWindowSource *source = user_data;
203
 
  BamfWindow *window;
204
 
  BamfApplication *application;
205
 
  const gchar *desktop_file;
206
 
 
207
 
  g_debug ("Switching windows");
208
 
 
209
 
  if (!BAMF_IS_WINDOW (newview))
210
 
    {
211
 
      g_debug ("ignoring switch to non-window");
212
 
      return;
213
 
    }
214
 
 
215
 
  window = BAMF_WINDOW (newview);
216
 
 
217
 
  if (window == source->active_window)
218
 
    {
219
 
      g_debug ("this is already the active window");
220
 
      return;
221
 
    }
222
 
 
223
 
  if (hud_window_source_name_in_ignore_list (window))
224
 
    return;
225
 
 
226
 
  application = bamf_matcher_get_application_for_window (source->matcher, window);
227
 
 
228
 
  if (application == NULL)
229
 
    {
230
 
      g_debug ("ignoring window with no application");
231
 
      return;
232
 
    }
233
 
 
234
 
  desktop_file = bamf_application_get_desktop_file (application);
235
 
 
236
 
  if (desktop_file == NULL)
237
 
    {
238
 
      g_debug ("ignoring application with no desktop file");
239
 
      return;
240
 
    }
241
 
 
242
 
  if (hud_window_source_desktop_file_in_debug_list (desktop_file))
243
 
    return;
244
 
 
245
 
  g_debug ("new active window (xid %u)", bamf_window_get_xid (window));
246
 
 
247
 
 
248
 
  if (source->active_collector)
249
 
    {
250
 
      g_signal_handlers_disconnect_by_func (source->active_collector, hud_window_source_collector_changed, source);
251
 
      if (source->use_count)
252
 
        hud_source_unuse (source->active_collector);
253
 
    }
254
 
 
255
 
  g_clear_object (&source->active_collector);
256
 
  g_clear_object (&source->active_application);
257
 
  g_clear_object (&source->active_window);
258
 
  g_free (source->active_icon);
259
 
  source->active_window = g_object_ref (window);
260
 
  source->active_application = g_object_ref (application);
261
 
  source->active_desktop_file = desktop_file;
262
 
  source->active_icon = bamf_view_get_icon (BAMF_VIEW (application));
263
 
  source->active_collector = g_object_ref (hud_window_source_get_collector (source));
264
 
 
265
 
  if (source->use_count)
266
 
    hud_source_use (source->active_collector);
267
 
  g_signal_connect_object (source->active_collector, "changed",
268
 
                           G_CALLBACK (hud_window_source_collector_changed), source, 0);
269
 
 
270
 
  hud_source_changed (HUD_SOURCE (source));
271
 
}
272
 
 
273
 
static void
274
 
hud_window_source_use (HudSource *hud_source)
275
 
{
276
 
  HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
277
 
 
278
 
  if (source->use_count == 0)
279
 
    if (source->active_collector)
280
 
      hud_source_use (source->active_collector);
281
 
 
282
 
  source->use_count++;
283
 
}
284
 
 
285
 
static void
286
 
hud_window_source_unuse (HudSource *hud_source)
287
 
{
288
 
  HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
289
 
 
290
 
  g_return_if_fail (source->use_count > 0);
291
 
 
292
 
  source->use_count--;
293
 
 
294
 
  if (source->use_count == 0)
295
 
    if (source->active_collector)
296
 
      hud_source_unuse (source->active_collector);
297
 
}
298
 
 
299
 
static void
300
 
hud_window_source_search (HudSource    *hud_source,
301
 
                          GPtrArray    *results_array,
302
 
                          HudTokenList *search_string)
303
 
{
304
 
  HudWindowSource *source = HUD_WINDOW_SOURCE (hud_source);
305
 
 
306
 
  if (source->active_collector)
307
 
    hud_source_search (source->active_collector, results_array, search_string);
308
 
}
309
 
 
310
 
static void
311
 
hud_window_source_finalize (GObject *object)
312
 
{
313
 
  HudWindowSource *source = HUD_WINDOW_SOURCE (object);
314
 
 
315
 
  g_assert_cmpint (source->use_count, ==, 0);
316
 
 
317
 
  /* bamf matcher signals already disconnected in dispose */
318
 
  g_clear_object (&source->active_collector);
319
 
  g_clear_object (&source->active_application);
320
 
  g_clear_object (&source->active_window);
321
 
  g_free (source->active_icon);
322
 
 
323
 
  G_OBJECT_CLASS (hud_window_source_parent_class)
324
 
    ->finalize (object);
325
 
}
326
 
 
327
 
static void
328
 
hud_window_source_init (HudWindowSource *source)
329
 
{
330
 
  BamfWindow *window;
331
 
 
332
 
  source->matcher = bamf_matcher_get_default ();
333
 
 
334
 
  g_signal_connect_object (source->matcher, "active-window-changed",
335
 
                           G_CALLBACK (hud_window_source_active_window_changed), source, 0);
336
 
  window = bamf_matcher_get_active_window (source->matcher);
337
 
  if (window != NULL)
338
 
    hud_window_source_active_window_changed (source->matcher, NULL, BAMF_VIEW (window), source);
339
 
}
340
 
 
341
 
static void
342
 
hud_window_source_iface_init (HudSourceInterface *iface)
343
 
{
344
 
  iface->use = hud_window_source_use;
345
 
  iface->unuse = hud_window_source_unuse;
346
 
  iface->search = hud_window_source_search;
347
 
}
348
 
 
349
 
static void
350
 
hud_window_source_class_init (HudWindowSourceClass *class)
351
 
{
352
 
  class->finalize = hud_window_source_finalize;
353
 
}
354
 
 
355
 
/**
356
 
 * hud_window_source_new:
357
 
 *
358
 
 * Creates a #HudWindowSource.
359
 
 *
360
 
 * Returns: a new #HudWindowSource
361
 
 **/
362
 
HudWindowSource *
363
 
hud_window_source_new (void)
364
 
{
365
 
  return g_object_new (HUD_TYPE_WINDOW_SOURCE, NULL);
366
 
}
367
 
 
368
 
guint32 
369
 
hud_window_source_get_active_xid (HudWindowSource *source)
370
 
{
371
 
  return bamf_window_get_xid (source->active_window);
372
 
}