1 /*
2  * Copyright (C) 2010-2012 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 "config.h"
22 
23 #include "bamf-legacy-window.h"
24 #include "bamf-legacy-screen.h"
25 #include "bamf-xutils.h"
26 #include <libgtop-2.0/glibtop.h>
27 #include <libgtop-2.0/glibtop/procwd.h>
28 #include <glibtop/procargs.h>
29 #include <glibtop/procuid.h>
30 #include <stdio.h>
31 
32 G_DEFINE_TYPE (BamfLegacyWindow, bamf_legacy_window, G_TYPE_OBJECT);
33 #define BAMF_LEGACY_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
34 BAMF_TYPE_LEGACY_WINDOW, BamfLegacyWindowPrivate))
35 
36 #define WNCK_WINDOW_BAMF_DATA "bamf-legacy-window"
37 
38 enum
39 {
40   NAME_CHANGED,
41   ROLE_CHANGED,
42   CLASS_CHANGED,
43   STATE_CHANGED,
44   GEOMETRY_CHANGED,
45   CLOSED,
46 
47   LAST_SIGNAL,
48 };
49 
50 static guint legacy_window_signals[LAST_SIGNAL] = { 0 };
51 
52 struct _BamfLegacyWindowPrivate
53 {
54   WnckWindow * legacy_window;
55   GtkWidget  * action_menu;
56   GFile      * mini_icon;
57   gchar      * exec_string;
58   gchar      * working_dir;
59   gboolean     is_closed;
60 };
61 
62 gboolean
bamf_legacy_window_is_active(BamfLegacyWindow * self)63 bamf_legacy_window_is_active (BamfLegacyWindow *self)
64 {
65   WnckWindow *active;
66 
67   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
68 
69   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_active)
70     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_active (self);
71 
72   active = wnck_screen_get_active_window (wnck_screen_get_default ());
73 
74   return active == self->priv->legacy_window;
75 }
76 
77 BamfWindowType
bamf_legacy_window_get_window_type(BamfLegacyWindow * self)78 bamf_legacy_window_get_window_type (BamfLegacyWindow *self)
79 {
80   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
81 
82   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_window_type)
83     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_window_type (self);
84 
85   g_return_val_if_fail (self->priv->legacy_window, 0);
86 
87   return (BamfWindowType) wnck_window_get_window_type (self->priv->legacy_window);
88 }
89 
90 gboolean
bamf_legacy_window_needs_attention(BamfLegacyWindow * self)91 bamf_legacy_window_needs_attention (BamfLegacyWindow *self)
92 {
93   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
94 
95   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->needs_attention)
96     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->needs_attention (self);
97 
98   if (!self->priv->legacy_window)
99     return FALSE;
100   return wnck_window_needs_attention (self->priv->legacy_window);
101 }
102 
103 gboolean
bamf_legacy_window_is_skip_tasklist(BamfLegacyWindow * self)104 bamf_legacy_window_is_skip_tasklist (BamfLegacyWindow *self)
105 {
106   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
107 
108   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_skip_tasklist)
109     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_skip_tasklist (self);
110 
111   if (!self->priv->legacy_window)
112     return FALSE;
113   return wnck_window_is_skip_tasklist (self->priv->legacy_window);
114 }
115 
116 const char *
bamf_legacy_window_get_class_instance_name(BamfLegacyWindow * self)117 bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self)
118 {
119   WnckWindow *window;
120 
121   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
122 
123   window = self->priv->legacy_window;
124 
125   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name)
126     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name (self);
127 
128   if (!window)
129     return NULL;
130 
131   return wnck_window_get_class_instance_name (window);
132 }
133 
134 const char *
bamf_legacy_window_get_class_name(BamfLegacyWindow * self)135 bamf_legacy_window_get_class_name (BamfLegacyWindow *self)
136 {
137   WnckWindow *window;
138 
139   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
140 
141   window = self->priv->legacy_window;
142 
143   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_name)
144     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_name (self);
145 
146   if (!window)
147     return NULL;
148 
149   return wnck_window_get_class_group_name (window);
150 }
151 
152 const char *
bamf_legacy_window_get_name(BamfLegacyWindow * self)153 bamf_legacy_window_get_name (BamfLegacyWindow *self)
154 {
155   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
156 
157   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_name)
158     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_name (self);
159 
160   if (!self->priv->legacy_window)
161     return NULL;
162 
163   return wnck_window_get_name (self->priv->legacy_window);
164 }
165 
166 const char *
bamf_legacy_window_get_role(BamfLegacyWindow * self)167 bamf_legacy_window_get_role (BamfLegacyWindow *self)
168 {
169   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
170 
171   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_role)
172     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_role (self);
173 
174   if (!self->priv->legacy_window)
175     return NULL;
176 
177   return wnck_window_get_role (self->priv->legacy_window);
178 }
179 
180 char *
bamf_legacy_window_get_process_name(BamfLegacyWindow * self)181 bamf_legacy_window_get_process_name (BamfLegacyWindow *self)
182 {
183   gchar *stat_path;
184   gchar *contents;
185   gchar **lines;
186   gchar **sections;
187   gchar *result = NULL;
188   guint pid;
189 
190   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
191 
192   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_process_name)
193     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_process_name (self);
194 
195   pid = bamf_legacy_window_get_pid (self);
196 
197   if (pid < 2)
198     return NULL;
199 
200   stat_path = g_strdup_printf ("/proc/%i/status", pid);
201 
202   if (g_file_get_contents (stat_path, &contents, NULL, NULL))
203     {
204       lines = g_strsplit (contents, "\n", 2);
205 
206       if (lines && g_strv_length (lines) > 0)
207         {
208           sections = g_strsplit (lines[0], "\t", 0);
209           if (sections)
210             {
211               if (g_strv_length (sections) > 1)
212                 result = g_strdup (sections[1]);
213 
214               g_strfreev (sections);
215             }
216           g_strfreev (lines);
217         }
218       g_free (contents);
219     }
220   g_free (stat_path);
221 
222   return result;
223 }
224 
225 const char *
bamf_legacy_window_get_exec_string(BamfLegacyWindow * self)226 bamf_legacy_window_get_exec_string (BamfLegacyWindow *self)
227 {
228   guint pid;
229   gchar **argv;
230   glibtop_proc_args buffer;
231 
232   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
233 
234   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_exec_string)
235     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_exec_string (self);
236 
237   if (self->priv->exec_string)
238     return self->priv->exec_string;
239 
240   pid = bamf_legacy_window_get_pid (self);
241 
242   if (pid == 0)
243     return NULL;
244 
245   argv = glibtop_get_proc_argv (&buffer, pid, 0);
246   self->priv->exec_string = g_strstrip (g_strjoinv (" ", argv));
247   g_strfreev (argv);
248 
249   return self->priv->exec_string;
250 }
251 
252 const char *
bamf_legacy_window_get_working_dir(BamfLegacyWindow * self)253 bamf_legacy_window_get_working_dir (BamfLegacyWindow *self)
254 {
255   guint pid = 0;
256   gchar **dirs;
257   glibtop_proc_wd buffer_wd;
258 
259   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
260 
261   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_working_dir)
262     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_working_dir (self);
263 
264   if (self->priv->working_dir)
265     return self->priv->working_dir;
266 
267   pid = bamf_legacy_window_get_pid (self);
268 
269   if (pid == 0)
270     return NULL;
271 
272   dirs = glibtop_get_proc_wd (&buffer_wd, pid);
273 
274   if (!dirs)
275     return NULL;
276 
277   self->priv->working_dir = g_strdup (dirs[0] ? g_strstrip (dirs[0]) : NULL);
278   g_strfreev (dirs);
279 
280   return self->priv->working_dir;
281 }
282 
283 char *
bamf_legacy_window_save_mini_icon(BamfLegacyWindow * self)284 bamf_legacy_window_save_mini_icon (BamfLegacyWindow *self)
285 {
286   WnckWindow *window;
287   GdkPixbuf *pbuf;
288   GFile *tmp;
289   GFileIOStream *iostream;
290   GOutputStream *output;
291 
292   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
293 
294   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->save_mini_icon)
295     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->save_mini_icon (self);
296 
297   if (self->priv->mini_icon)
298     {
299       if (g_file_query_exists (self->priv->mini_icon, NULL))
300         {
301           return g_file_get_path (self->priv->mini_icon);
302         }
303       else
304         {
305           g_object_unref (self->priv->mini_icon);
306           self->priv->mini_icon = NULL;
307         }
308     }
309 
310   window = self->priv->legacy_window;
311 
312   if (!window)
313     return NULL;
314 
315   if (wnck_window_get_icon_is_fallback (window))
316     return NULL;
317 
318   tmp = g_file_new_tmp (".bamficonXXXXXX", &iostream, NULL);
319 
320   if (!tmp)
321     return NULL;
322 
323   output = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
324   pbuf = wnck_window_get_icon (window);
325 
326   if (gdk_pixbuf_save_to_stream (pbuf, output, "png", NULL, NULL, NULL))
327     {
328       self->priv->mini_icon = g_object_ref (tmp);
329     }
330 
331   g_object_unref (iostream);
332   g_object_unref (tmp);
333 
334   return g_file_get_path (self->priv->mini_icon);
335 }
336 
337 GFile *
bamf_legacy_window_get_saved_mini_icon(BamfLegacyWindow * self)338 bamf_legacy_window_get_saved_mini_icon (BamfLegacyWindow *self)
339 {
340   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
341 
342   return self->priv->mini_icon;
343 }
344 
345 guint
bamf_legacy_window_get_pid(BamfLegacyWindow * self)346 bamf_legacy_window_get_pid (BamfLegacyWindow *self)
347 {
348   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
349 
350   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_pid)
351     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_pid (self);
352 
353   if (!self->priv->legacy_window)
354     return 0;
355 
356   int pid = wnck_window_get_pid (self->priv->legacy_window);
357   return G_LIKELY (pid >= 0) ? pid : 0;
358 }
359 
360 guint32
bamf_legacy_window_get_xid(BamfLegacyWindow * self)361 bamf_legacy_window_get_xid (BamfLegacyWindow *self)
362 {
363   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
364 
365   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid)
366     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid (self);
367 
368   if (!self->priv->legacy_window)
369     return 0;
370 
371   return (guint32) wnck_window_get_xid (self->priv->legacy_window);
372 }
373 
374 BamfLegacyWindow *
bamf_legacy_window_get_transient(BamfLegacyWindow * self)375 bamf_legacy_window_get_transient (BamfLegacyWindow *self)
376 {
377   BamfLegacyScreen *screen;
378   BamfLegacyWindow *other;
379   GList *windows, *l;
380   WnckWindow *transient_legacy;
381 
382   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
383 
384   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_transient)
385     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_transient (self);
386 
387   g_return_val_if_fail (self->priv->legacy_window, NULL);
388 
389   transient_legacy = wnck_window_get_transient (self->priv->legacy_window);
390   screen = bamf_legacy_screen_get_default ();
391   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), NULL);
392 
393   windows = bamf_legacy_screen_get_windows (screen);
394   for (l = windows; l; l = l->next)
395     {
396       other = l->data;
397 
398       if (!BAMF_IS_LEGACY_WINDOW (other))
399         continue;
400 
401       if (other->priv->legacy_window == transient_legacy)
402         return other;
403     }
404 
405   return NULL;
406 }
407 
408 gint
bamf_legacy_window_get_stacking_position(BamfLegacyWindow * self)409 bamf_legacy_window_get_stacking_position (BamfLegacyWindow *self)
410 {
411   BamfLegacyScreen *screen;
412 
413   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), -1);
414 
415   screen = bamf_legacy_screen_get_default ();
416   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), -1);
417 
418   return g_list_index (bamf_legacy_screen_get_windows (screen), self);
419 }
420 
421 static void
handle_window_signal(WnckWindow * window,gpointer data)422 handle_window_signal (WnckWindow *window, gpointer data)
423 {
424   BamfLegacyWindow *self = g_object_get_data (G_OBJECT (window), WNCK_WINDOW_BAMF_DATA);
425   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
426 
427   g_signal_emit (self, legacy_window_signals[GPOINTER_TO_UINT (data)], 0);
428 }
429 
430 static void
handle_state_changed(WnckWindow * window,WnckWindowState change_mask,WnckWindowState new_state,BamfLegacyWindow * self)431 handle_state_changed (WnckWindow *window,
432                       WnckWindowState change_mask,
433                       WnckWindowState new_state,
434                       BamfLegacyWindow *self)
435 {
436   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
437 
438   g_signal_emit (self, legacy_window_signals[STATE_CHANGED], 0);
439 }
440 
441 gboolean
bamf_legacy_window_is_closed(BamfLegacyWindow * self)442 bamf_legacy_window_is_closed (BamfLegacyWindow *self)
443 {
444   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), TRUE);
445 
446   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_closed)
447     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_closed (self);
448 
449   return self->priv->is_closed;
450 }
451 
452 void
bamf_legacy_window_get_geometry(BamfLegacyWindow * self,gint * x,gint * y,gint * width,gint * height)453 bamf_legacy_window_get_geometry (BamfLegacyWindow *self, gint *x, gint *y,
454                                  gint *width, gint *height)
455 {
456   if (x) *x = 0;
457   if (y) *y = 0;
458   if (width) *width = 0;
459   if (height) *height = 0;
460 
461   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
462 
463   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_app_id)
464     BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_app_id (self);
465 
466   if (!self->priv->legacy_window)
467     return;
468 
469   wnck_window_get_geometry (self->priv->legacy_window, x, y, width, height);
470 }
471 
472 BamfWindowMaximizationType
bamf_legacy_window_maximized(BamfLegacyWindow * self)473 bamf_legacy_window_maximized (BamfLegacyWindow *self)
474 {
475   WnckWindowState window_state;
476   BamfWindowMaximizationType maximization_type;
477   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), BAMF_WINDOW_FLOATING);
478 
479   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->maximized)
480     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->maximized (self);
481 
482   if (!self->priv->legacy_window)
483     return BAMF_WINDOW_FLOATING;
484 
485   window_state = wnck_window_get_state (self->priv->legacy_window);
486 
487   gboolean vertical = (window_state & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY);
488   gboolean horizontal = (window_state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY);
489 
490   if (vertical && horizontal)
491     {
492       maximization_type = BAMF_WINDOW_MAXIMIZED;
493     }
494   else if (horizontal)
495     {
496       maximization_type = BAMF_WINDOW_HORIZONTAL_MAXIMIZED;
497     }
498   else if (vertical)
499     {
500       maximization_type = BAMF_WINDOW_VERTICAL_MAXIMIZED;
501     }
502   else
503     {
504       maximization_type = BAMF_WINDOW_FLOATING;
505     }
506 
507   return maximization_type;
508 }
509 
510 char *
bamf_legacy_window_get_hint(BamfLegacyWindow * self,const char * name)511 bamf_legacy_window_get_hint (BamfLegacyWindow *self, const char *name)
512 {
513   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
514   g_return_val_if_fail (name, NULL);
515 
516   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_hint)
517     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_hint (self, name);
518 
519   g_return_val_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window), NULL);
520 
521   guint xid = bamf_legacy_window_get_xid (self);
522 
523   return bamf_xutils_get_string_window_hint (xid, name);
524 }
525 
526 void
bamf_legacy_window_set_hint(BamfLegacyWindow * self,const char * name,const char * value)527 bamf_legacy_window_set_hint (BamfLegacyWindow *self, const char *name, const char *value)
528 {
529   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
530   g_return_if_fail (name);
531 
532   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->set_hint)
533     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->set_hint (self, name, value);
534 
535   g_return_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window));
536 
537   guint xid = bamf_legacy_window_get_xid (self);
538 
539   bamf_xutils_set_string_window_hint (xid, name, value);
540 }
541 
542 static void
top_window_action_menu(GtkMenu * menu,gint * x,gint * y,gboolean * push,gpointer data)543 top_window_action_menu (GtkMenu *menu, gint *x, gint *y, gboolean *push, gpointer data)
544 {
545   BamfLegacyWindow *self = data;
546   gint w, h, scale;
547 
548   scale = gdk_screen_get_monitor_scale_factor (gdk_screen_get_default (), 0);
549   scale = !scale ? 1: scale;
550 
551   wnck_window_get_client_window_geometry (self->priv->legacy_window, x, y, &w, &h);
552   *x /= scale;
553   *y /= scale;
554 
555   *push = TRUE;
556 }
557 
558 GtkWidget *
bamf_legacy_window_get_action_menu(BamfLegacyWindow * self)559 bamf_legacy_window_get_action_menu (BamfLegacyWindow *self)
560 {
561   BamfLegacyWindowPrivate *priv;
562 
563   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
564 
565   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_action_menu)
566     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_action_menu (self);
567 
568   priv = self->priv;
569   g_return_val_if_fail (WNCK_IS_WINDOW (priv->legacy_window), NULL);
570 
571   if (!priv->action_menu)
572     {
573       priv->action_menu = wnck_action_menu_new (priv->legacy_window);
574       g_object_add_weak_pointer (G_OBJECT (priv->action_menu),
575                                  (gpointer *) &priv->action_menu);
576     }
577 
578   return priv->action_menu;
579 }
580 
bamf_legacy_window_show_action_menu(BamfLegacyWindow * self,guint32 time,guint button,gint x,gint y)581 void bamf_legacy_window_show_action_menu (BamfLegacyWindow *self, guint32 time,
582                                           guint button, gint x, gint y)
583 {
584   BamfLegacyWindowPrivate *priv;
585   GtkWidget *menu;
586 
587   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
588 
589   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->show_action_menu)
590     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->show_action_menu (self, button, time, x, y);
591 
592   g_return_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window));
593 
594   priv = self->priv;
595 
596   if (priv->action_menu && gtk_widget_is_visible (GTK_WIDGET (priv->action_menu)))
597     return;
598 
599   menu = bamf_legacy_window_get_action_menu (self);
600 
601   g_object_ref_sink (menu);
602   g_signal_handlers_disconnect_by_func (menu, g_object_unref, self);
603   g_signal_connect (G_OBJECT (menu), "unmap", G_CALLBACK (g_object_unref), self);
604 
605   gtk_menu_set_screen (GTK_MENU (menu), gdk_screen_get_default ());
606   gtk_widget_show (menu);
607 
608   GtkMenuPositionFunc position = button ? NULL : top_window_action_menu;
609   gtk_menu_popup (GTK_MENU (menu), NULL, NULL, position, self, button, time);
610 }
611 
612 static void
handle_window_closed(WnckScreen * screen,WnckWindow * window,BamfLegacyWindow * self)613 handle_window_closed (WnckScreen *screen,
614                       WnckWindow *window,
615                       BamfLegacyWindow *self)
616 {
617   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
618   g_return_if_fail (WNCK_IS_WINDOW (window));
619 
620   if (self->priv->legacy_window == window)
621     {
622       self->priv->is_closed = TRUE;
623       g_signal_emit (self, legacy_window_signals[CLOSED], 0);
624     }
625 }
626 
627 static void
handle_destroy_notify(gpointer * data,BamfLegacyWindow * self_was_here)628 handle_destroy_notify (gpointer *data, BamfLegacyWindow *self_was_here)
629 {
630   BamfLegacyScreen *screen = bamf_legacy_screen_get_default ();
631   bamf_legacy_screen_inject_window (screen, GPOINTER_TO_UINT (data));
632 }
633 
634 /* This utility function allows to set a BamfLegacyWindow as closed, notifying
635  * all its owners, and to reopen it once the current window has been destroyed.
636  * This allows to remap particular windows to different applications.         */
637 void
bamf_legacy_window_reopen(BamfLegacyWindow * self)638 bamf_legacy_window_reopen (BamfLegacyWindow *self)
639 {
640   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
641 
642   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->reopen)
643     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->reopen (self);
644 
645   g_return_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window));
646 
647   guint xid = bamf_legacy_window_get_xid (self);
648 
649   /* Adding a weak ref to this object, causes to get notified after the object
650    * destruction, so once this BamfLegacyWindow has been closed and destroyed
651    * the handle_destroy_notify() function will be called, and that will
652    * provide to inject another window like this one to the BamfLegacyScreen  */
653   g_object_weak_ref (G_OBJECT (self), (GWeakNotify) handle_destroy_notify,
654                                                     GUINT_TO_POINTER (xid));
655 
656   self->priv->is_closed = TRUE;
657   g_signal_emit (self, legacy_window_signals[CLOSED], 0);
658 }
659 
660 static void
bamf_legacy_window_dispose(GObject * object)661 bamf_legacy_window_dispose (GObject *object)
662 {
663   BamfLegacyWindow *self;
664   guint i;
665 
666   self = BAMF_LEGACY_WINDOW (object);
667 
668   if (self->priv->mini_icon)
669     {
670       g_file_delete (self->priv->mini_icon, NULL, NULL);
671       g_clear_object (&self->priv->mini_icon);
672     }
673 
674   g_clear_pointer (&self->priv->exec_string, g_free);
675   g_clear_pointer (&self->priv->working_dir, g_free);
676 
677   g_signal_handlers_disconnect_by_data (wnck_screen_get_default (), self);
678 
679   if (self->priv->legacy_window)
680     {
681       g_object_set_data (G_OBJECT (self->priv->legacy_window), WNCK_WINDOW_BAMF_DATA, NULL);
682       g_signal_handlers_disconnect_by_data (self->priv->legacy_window, self);
683 
684       for (i = 0; i < LAST_SIGNAL; ++i)
685         {
686           g_signal_handlers_disconnect_by_func (self->priv->legacy_window,
687                                                 handle_window_signal,
688                                                 GUINT_TO_POINTER (NAME_CHANGED));
689         }
690 
691       self->priv->legacy_window = NULL;
692     }
693 
694   if (self->priv->action_menu)
695     {
696       g_signal_handlers_disconnect_by_data (self->priv->action_menu, self);
697       g_object_remove_weak_pointer (G_OBJECT (self->priv->action_menu),
698                                     (gpointer*) &self->priv->action_menu);
699     }
700 
701   G_OBJECT_CLASS (bamf_legacy_window_parent_class)->dispose (object);
702 }
703 
704 static void
bamf_legacy_window_init(BamfLegacyWindow * self)705 bamf_legacy_window_init (BamfLegacyWindow * self)
706 {
707   self->priv = BAMF_LEGACY_WINDOW_GET_PRIVATE (self);
708 
709   g_signal_connect (wnck_screen_get_default (), "window-closed",
710                     (GCallback) handle_window_closed, self);
711 }
712 
713 static void
bamf_legacy_window_class_init(BamfLegacyWindowClass * klass)714 bamf_legacy_window_class_init (BamfLegacyWindowClass * klass)
715 {
716   GObjectClass *object_class = G_OBJECT_CLASS (klass);
717 
718   object_class->dispose = bamf_legacy_window_dispose;
719 
720   g_type_class_add_private (klass, sizeof (BamfLegacyWindowPrivate));
721 
722   legacy_window_signals [NAME_CHANGED] =
723     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_NAME_CHANGED,
724                   G_OBJECT_CLASS_TYPE (klass),
725                   G_SIGNAL_RUN_FIRST,
726                   G_STRUCT_OFFSET (BamfLegacyWindowClass, name_changed),
727                   NULL, NULL, NULL, G_TYPE_NONE, 0);
728 
729   legacy_window_signals [ROLE_CHANGED] =
730     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_ROLE_CHANGED,
731                   G_OBJECT_CLASS_TYPE (klass),
732                   G_SIGNAL_RUN_FIRST,
733                   G_STRUCT_OFFSET (BamfLegacyWindowClass, role_changed),
734                   NULL, NULL, NULL, G_TYPE_NONE, 0);
735 
736   legacy_window_signals [CLASS_CHANGED] =
737     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_CLASS_CHANGED,
738                   G_OBJECT_CLASS_TYPE (klass),
739                   G_SIGNAL_RUN_FIRST,
740                   G_STRUCT_OFFSET (BamfLegacyWindowClass, class_changed),
741                   NULL, NULL, NULL, G_TYPE_NONE, 0);
742 
743   legacy_window_signals [STATE_CHANGED] =
744     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_STATE_CHANGED,
745                   G_OBJECT_CLASS_TYPE (klass),
746                   G_SIGNAL_RUN_FIRST,
747                   G_STRUCT_OFFSET (BamfLegacyWindowClass, state_changed),
748                   NULL, NULL, NULL, G_TYPE_NONE, 0);
749 
750   legacy_window_signals [GEOMETRY_CHANGED] =
751     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_GEOMETRY_CHANGED,
752                   G_OBJECT_CLASS_TYPE (klass),
753                   G_SIGNAL_RUN_FIRST,
754                   G_STRUCT_OFFSET (BamfLegacyWindowClass, geometry_changed),
755                   NULL, NULL, NULL, G_TYPE_NONE, 0);
756 
757   legacy_window_signals [CLOSED] =
758     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_CLOSED,
759                   G_OBJECT_CLASS_TYPE (klass),
760                   G_SIGNAL_RUN_FIRST,
761                   G_STRUCT_OFFSET (BamfLegacyWindowClass, closed),
762                   NULL, NULL, NULL, G_TYPE_NONE, 0);
763 }
764 
765 BamfLegacyWindow *
bamf_legacy_window_new(WnckWindow * legacy_window)766 bamf_legacy_window_new (WnckWindow *legacy_window)
767 {
768   BamfLegacyWindow *self;
769   self = (BamfLegacyWindow *) g_object_new (BAMF_TYPE_LEGACY_WINDOW, NULL);
770 
771   self->priv->legacy_window = legacy_window;
772 
773   g_return_val_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window), self);
774   g_warn_if_fail (!g_object_get_data (G_OBJECT (legacy_window), WNCK_WINDOW_BAMF_DATA));
775 
776   g_object_set_data (G_OBJECT (legacy_window), WNCK_WINDOW_BAMF_DATA, self);
777 
778   g_signal_connect (G_OBJECT (legacy_window), "name-changed",
779                     G_CALLBACK (handle_window_signal),
780                     GUINT_TO_POINTER (NAME_CHANGED));
781 
782   g_signal_connect (G_OBJECT (legacy_window), "role-changed",
783                     G_CALLBACK (handle_window_signal),
784                     GUINT_TO_POINTER (ROLE_CHANGED));
785 
786   g_signal_connect (G_OBJECT (legacy_window), "class-changed",
787                     G_CALLBACK (handle_window_signal),
788                     GUINT_TO_POINTER (CLASS_CHANGED));
789 
790   g_signal_connect (G_OBJECT (legacy_window), "geometry-changed",
791                     G_CALLBACK (handle_window_signal),
792                     GUINT_TO_POINTER (GEOMETRY_CHANGED));
793 
794   g_signal_connect (G_OBJECT (legacy_window), "state-changed",
795                     G_CALLBACK (handle_state_changed), self);
796 
797   return self;
798 }
799