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