Back to index

bamf  0.2.120
bamf-legacy-window.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010-2012 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it 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,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Jason Smith <jason.smith@canonical.com>
00017  *              Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
00018  *
00019  */
00020 
00021 #include "config.h"
00022 
00023 #include "bamf-legacy-window.h"
00024 #include "bamf-legacy-screen.h"
00025 #include "bamf-xutils.h"
00026 #include <libgtop-2.0/glibtop.h>
00027 #include <glibtop/procargs.h>
00028 #include <glibtop/procuid.h>
00029 #include <stdio.h>
00030 
00031 G_DEFINE_TYPE (BamfLegacyWindow, bamf_legacy_window, G_TYPE_OBJECT);
00032 #define BAMF_LEGACY_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
00033 BAMF_TYPE_LEGACY_WINDOW, BamfLegacyWindowPrivate))
00034 
00035 enum
00036 {
00037   NAME_CHANGED,
00038   STATE_CHANGED,
00039   GEOMETRY_CHANGED,
00040   CLOSED,
00041 
00042   LAST_SIGNAL,
00043 };
00044 
00045 static guint legacy_window_signals[LAST_SIGNAL] = { 0 };
00046 
00047 struct _BamfLegacyWindowPrivate
00048 {
00049   WnckWindow * legacy_window;
00050   char       * mini_icon_path;
00051 #ifndef USE_GTK3
00052   char       * group_name;
00053   char       * instance_name;
00054 #endif
00055   gulong       closed_id;
00056   gulong       name_changed_id;
00057   gulong       state_changed_id;
00058   gulong       geometry_changed_id;
00059   gboolean     is_closed;
00060 };
00061 
00062 gboolean
00063 bamf_legacy_window_is_active (BamfLegacyWindow *self)
00064 {
00065   WnckWindow *active;
00066 
00067   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
00068 
00069   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_active)
00070     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_active (self);
00071 
00072   active = wnck_screen_get_active_window (wnck_screen_get_default ());
00073 
00074   return active == self->priv->legacy_window;
00075 }
00076 
00077 BamfWindowType
00078 bamf_legacy_window_get_window_type (BamfLegacyWindow *self)
00079 {
00080   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
00081   g_return_val_if_fail (self->priv->legacy_window, 0);
00082 
00083   return (BamfWindowType) wnck_window_get_window_type (self->priv->legacy_window);
00084 }
00085 
00086 gboolean
00087 bamf_legacy_window_needs_attention (BamfLegacyWindow *self)
00088 {
00089   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
00090 
00091 
00092   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->needs_attention)
00093     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->needs_attention (self);
00094 
00095   if (!self->priv->legacy_window)
00096     return FALSE;
00097   return wnck_window_needs_attention (self->priv->legacy_window);
00098 }
00099 
00100 gboolean
00101 bamf_legacy_window_is_skip_tasklist (BamfLegacyWindow *self)
00102 {
00103   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), FALSE);
00104 
00105   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_skip_tasklist)
00106     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->is_skip_tasklist (self);
00107 
00108   if (!self->priv->legacy_window)
00109     return FALSE;
00110   return wnck_window_is_skip_tasklist (self->priv->legacy_window);
00111 }
00112 
00113 const char *
00114 bamf_legacy_window_get_class_instance_name (BamfLegacyWindow *self)
00115 {
00116   WnckWindow *window;
00117 
00118   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00119 
00120   window = self->priv->legacy_window;
00121 
00122   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name)
00123     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_instance_name (self);
00124 
00125   if (!window)
00126     return NULL;
00127 
00128 #ifdef USE_GTK3
00129   return wnck_window_get_class_instance_name (window);
00130 
00131 #else
00132   if (!self->priv->instance_name)
00133     {
00134       Window xid = wnck_window_get_xid (window);
00135       bamf_xutils_get_window_class_hints (xid, &self->priv->instance_name, NULL);
00136     }
00137 
00138   return self->priv->instance_name;
00139 #endif
00140 }
00141 
00142 const char *
00143 bamf_legacy_window_get_class_name (BamfLegacyWindow *self)
00144 {
00145   WnckWindow *window;
00146 
00147   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00148 
00149   window = self->priv->legacy_window;
00150 
00151   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_name)
00152     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_class_name (self);
00153 
00154   if (!window)
00155     return NULL;
00156 
00157 #ifdef USE_GTK3
00158   return wnck_window_get_class_group_name (window);
00159 
00160 #else
00161   if (!self->priv->group_name)
00162     {
00163       Window xid = wnck_window_get_xid (window);
00164       bamf_xutils_get_window_class_hints (xid, NULL, &self->priv->group_name);
00165     }
00166 
00167   return self->priv->group_name;
00168 #endif
00169 }
00170 
00171 const char *
00172 bamf_legacy_window_get_name (BamfLegacyWindow *self)
00173 {
00174   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00175 
00176 
00177   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_name)
00178     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_name (self);
00179 
00180   if (!self->priv->legacy_window)
00181     return NULL;
00182   return wnck_window_get_name (self->priv->legacy_window);
00183 }
00184 
00185 char *
00186 bamf_legacy_window_get_exec_string (BamfLegacyWindow *self)
00187 {
00188   gchar *result = NULL;
00189   gint pid = 0, i = 0;
00190   gchar **argv = NULL;
00191   GString *exec = NULL;
00192   glibtop_proc_args buffer;
00193 
00194   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00195 
00196   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_exec_string)
00197     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_exec_string (self);
00198 
00199   pid = bamf_legacy_window_get_pid (self);
00200 
00201   if (pid == 0)
00202     return NULL;
00203 
00204   argv = glibtop_get_proc_argv (&buffer, pid, 0);
00205   exec = g_string_new ("");
00206 
00207   while (argv[i] != NULL)
00208     {
00209       g_string_append (exec, argv[i]);
00210       if (argv[i + 1] != NULL)
00211         g_string_append (exec, " ");
00212       g_free (argv[i]);
00213       i++;
00214     }
00215 
00216   g_free (argv);
00217 
00218   result = g_strdup (exec->str);
00219   g_string_free (exec, TRUE);
00220   return result;
00221 }
00222 
00223 const char *
00224 bamf_legacy_window_save_mini_icon (BamfLegacyWindow *self)
00225 {
00226   WnckWindow *window;
00227   GdkPixbuf *pbuf;
00228   char *tmp;
00229   
00230   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00231   
00232   if (self->priv->mini_icon_path)
00233     {
00234       if (g_file_test (self->priv->mini_icon_path, G_FILE_TEST_EXISTS))
00235         return self->priv->mini_icon_path;
00236       else
00237         g_free (self->priv->mini_icon_path);
00238     }
00239   
00240   window = self->priv->legacy_window;
00241   
00242   if (!window)
00243     return NULL;
00244   
00245   if (wnck_window_get_icon_is_fallback (window))
00246     return NULL;
00247   
00248   tmp = tmpnam (NULL);
00249   if (!tmp)
00250     return NULL;
00251   
00252   pbuf = wnck_window_get_icon (window);
00253   if (!gdk_pixbuf_save (pbuf, tmp, "png", NULL, NULL))
00254     return NULL;
00255   
00256   self->priv->mini_icon_path = g_strdup (tmp);
00257   return self->priv->mini_icon_path;
00258 }
00259 
00260 gint
00261 bamf_legacy_window_get_pid (BamfLegacyWindow *self)
00262 {
00263   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
00264 
00265   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_pid)
00266     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_pid (self);
00267 
00268   if (!self->priv->legacy_window)
00269     return 0;
00270   return wnck_window_get_pid (self->priv->legacy_window);
00271 }
00272 
00273 guint32
00274 bamf_legacy_window_get_xid (BamfLegacyWindow *self)
00275 {
00276   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), 0);
00277 
00278   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid)
00279     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_xid (self);
00280 
00281   if (!self->priv->legacy_window)
00282     return 0;
00283 
00284   return (guint32) wnck_window_get_xid (self->priv->legacy_window);
00285 }
00286 
00287 BamfLegacyWindow *
00288 bamf_legacy_window_get_transient (BamfLegacyWindow *self)
00289 {
00290   BamfLegacyScreen *screen;
00291   BamfLegacyWindow *other;
00292   GList *windows, *l;
00293   WnckWindow *transient_legacy;
00294   
00295   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00296   
00297   transient_legacy = wnck_window_get_transient (self->priv->legacy_window);
00298   if (transient_legacy == NULL)
00299     return NULL;
00300   
00301   screen = bamf_legacy_screen_get_default ();
00302   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), NULL);
00303   
00304   windows = bamf_legacy_screen_get_windows (screen);
00305   for (l = windows; l; l = l->next)
00306     {
00307       other = l->data;
00308       
00309       if (!BAMF_IS_LEGACY_WINDOW (other))
00310         continue;
00311       
00312       if (other->priv->legacy_window == transient_legacy)
00313         return other;
00314     }
00315   
00316   return NULL;
00317 }
00318 
00319 gint
00320 bamf_legacy_window_get_stacking_position (BamfLegacyWindow *self)
00321 {
00322   BamfLegacyScreen *screen;
00323   
00324   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), -1);
00325 
00326   screen = bamf_legacy_screen_get_default ();
00327   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), -1);
00328   
00329   return g_list_index (bamf_legacy_screen_get_windows (screen), self);
00330 }
00331 
00332 static void
00333 handle_name_changed (WnckWindow *window, BamfLegacyWindow *self)
00334 {
00335   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00336 
00337   g_signal_emit (self, legacy_window_signals[NAME_CHANGED], 0);
00338 }
00339 
00340 static void
00341 handle_state_changed (WnckWindow *window,
00342                       WnckWindowState change_mask,
00343                       WnckWindowState new_state,
00344                       BamfLegacyWindow *self)
00345 {
00346   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00347 
00348   g_signal_emit (self, legacy_window_signals[STATE_CHANGED], 0);
00349 }
00350 
00351 static void
00352 handle_geometry_changed (WnckWindow *window, BamfLegacyWindow *self)
00353 {
00354   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00355 
00356   g_signal_emit (self, legacy_window_signals[GEOMETRY_CHANGED], 0);
00357 }
00358 
00359 gboolean 
00360 bamf_legacy_window_is_closed (BamfLegacyWindow *self)
00361 {
00362   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), TRUE);
00363   
00364   return self->priv->is_closed;
00365 }
00366 
00367 void
00368 bamf_legacy_window_get_geometry (BamfLegacyWindow *self, gint *x, gint *y,
00369                                  gint *width, gint *height)
00370 {
00371   if (x) *x = 0;
00372   if (y) *y = 0;
00373   if (width) *width = 0;
00374   if (height) *height = 0;
00375 
00376   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00377 
00378   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_app_id)
00379     BAMF_LEGACY_WINDOW_GET_CLASS (self)->get_app_id (self);
00380 
00381   if (!self->priv->legacy_window)
00382     return;
00383 
00384   wnck_window_get_geometry (self->priv->legacy_window, x, y, width, height);
00385 }
00386 
00387 BamfWindowMaximizationType
00388 bamf_legacy_window_maximized (BamfLegacyWindow *self)
00389 {
00390   WnckWindowState window_state;
00391   BamfWindowMaximizationType maximization_type;
00392   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), BAMF_WINDOW_FLOATING);
00393 
00394   if (BAMF_LEGACY_WINDOW_GET_CLASS (self)->maximized)
00395     return BAMF_LEGACY_WINDOW_GET_CLASS (self)->maximized (self);
00396 
00397   if (!self->priv->legacy_window)
00398     return BAMF_WINDOW_FLOATING;
00399 
00400   window_state = wnck_window_get_state (self->priv->legacy_window);
00401 
00402   gboolean vertical = (window_state & WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY);
00403   gboolean horizontal = (window_state & WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY);
00404 
00405   if (vertical && horizontal)
00406     {
00407       maximization_type = BAMF_WINDOW_MAXIMIZED;
00408     }
00409   else if (horizontal)
00410     {
00411       maximization_type = BAMF_WINDOW_HORIZONTAL_MAXIMIZED;
00412     }
00413   else if (vertical)
00414     {
00415       maximization_type = BAMF_WINDOW_VERTICAL_MAXIMIZED;
00416     }
00417   else
00418     {
00419       maximization_type = BAMF_WINDOW_FLOATING;
00420     }
00421 
00422   return maximization_type;
00423 }
00424 
00425 char *
00426 bamf_legacy_window_get_utf8_xprop (BamfLegacyWindow *self, const char* prop)
00427 {
00428   g_return_val_if_fail (BAMF_IS_LEGACY_WINDOW (self), NULL);
00429 
00430   if (!self->priv->legacy_window)
00431     return NULL;
00432 
00433   guint xid = bamf_legacy_window_get_xid (self);
00434   return bamf_xutils_get_window_hint (xid, prop, XInternAtom(gdk_x11_get_default_xdisplay (), "UTF8_STRING", False));
00435 }
00436 
00437 static void
00438 handle_window_closed (WnckScreen *screen,
00439                       WnckWindow *window,
00440                       BamfLegacyWindow *self)
00441 {
00442   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00443   g_return_if_fail (WNCK_IS_WINDOW (window));
00444 
00445   if (self->priv->legacy_window == window)
00446     {
00447       self->priv->is_closed = TRUE;
00448       g_signal_emit (self, legacy_window_signals[CLOSED], 0);
00449     }
00450 }
00451 
00452 static void
00453 handle_destroy_notify (gpointer *data, BamfLegacyWindow *self_was_here)
00454 {
00455   BamfLegacyScreen *screen = bamf_legacy_screen_get_default ();
00456   bamf_legacy_screen_inject_window (screen, GPOINTER_TO_UINT (data));
00457 }
00458 
00459 /* This utility function allows to set a BamfLegacyWindow as closed, notifying
00460  * all its owners, and to reopen it once the current window has been destroyed.
00461  * This allows to remap particular windows to different applications.         */
00462 void
00463 bamf_legacy_window_reopen (BamfLegacyWindow *self)
00464 {
00465   g_return_if_fail (BAMF_IS_LEGACY_WINDOW (self));
00466   g_return_if_fail (WNCK_IS_WINDOW (self->priv->legacy_window));
00467 
00468   guint xid = bamf_legacy_window_get_xid (self);
00469 
00470   /* Adding a weak ref to this object, causes to get notified after the object
00471    * destruction, so once this BamfLegacyWindow has been closed and drestroyed
00472    * the handle_destroy_notify() function will be called, and that will
00473    * provide to iniject another window like this one to the BamfLegacyScreen  */
00474   g_object_weak_ref (G_OBJECT (self), (GWeakNotify) handle_destroy_notify,
00475                                                     GUINT_TO_POINTER (xid));
00476 
00477   self->priv->is_closed = TRUE;
00478   g_signal_emit (self, legacy_window_signals[CLOSED], 0);
00479 }
00480 
00481 static void
00482 bamf_legacy_window_dispose (GObject *object)
00483 {
00484   BamfLegacyWindow *self;
00485   GFile *file;
00486 
00487   self = BAMF_LEGACY_WINDOW (object);
00488 
00489   g_signal_handler_disconnect (wnck_screen_get_default (),
00490                                self->priv->closed_id);
00491                                
00492   if (self->priv->mini_icon_path)
00493     {
00494       file = g_file_new_for_path (self->priv->mini_icon_path);
00495       g_file_delete (file, NULL, NULL);
00496       g_object_unref (file);
00497       
00498       g_free (self->priv->mini_icon_path);
00499       self->priv->mini_icon_path = NULL;
00500     }
00501 
00502 #ifndef USE_GTK3
00503   if (self->priv->group_name)
00504     {
00505       g_free (self->priv->group_name);
00506       self->priv->group_name = NULL;
00507     }
00508 
00509   if (self->priv->instance_name)
00510     {
00511       g_free (self->priv->instance_name);
00512       self->priv->instance_name = NULL;
00513     }
00514 #endif
00515 
00516   if (self->priv->legacy_window)
00517     {
00518       g_signal_handler_disconnect (self->priv->legacy_window,
00519                                    self->priv->name_changed_id);
00520 
00521       g_signal_handler_disconnect (self->priv->legacy_window,
00522                                    self->priv->state_changed_id);
00523 
00524       g_signal_handler_disconnect (self->priv->legacy_window,
00525                                    self->priv->geometry_changed_id);
00526     }
00527 
00528   G_OBJECT_CLASS (bamf_legacy_window_parent_class)->dispose (object);
00529 }
00530 
00531 static void
00532 bamf_legacy_window_init (BamfLegacyWindow * self)
00533 {
00534   WnckScreen *screen;
00535 
00536   BamfLegacyWindowPrivate *priv;
00537   priv = self->priv = BAMF_LEGACY_WINDOW_GET_PRIVATE (self);
00538 
00539   screen = wnck_screen_get_default ();
00540 
00541   priv->closed_id = g_signal_connect (G_OBJECT (screen), "window-closed",
00542                                       (GCallback) handle_window_closed, self);
00543 }
00544 
00545 static void
00546 bamf_legacy_window_class_init (BamfLegacyWindowClass * klass)
00547 {
00548   GObjectClass *object_class = G_OBJECT_CLASS (klass);
00549 
00550   object_class->dispose      = bamf_legacy_window_dispose;
00551 
00552   g_type_class_add_private (klass, sizeof (BamfLegacyWindowPrivate));
00553 
00554   legacy_window_signals [NAME_CHANGED] =
00555     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_NAME_CHANGED,
00556                   G_OBJECT_CLASS_TYPE (klass),
00557                   G_SIGNAL_RUN_FIRST,
00558                   G_STRUCT_OFFSET (BamfLegacyWindowClass, name_changed),
00559                   NULL, NULL,
00560                   g_cclosure_marshal_VOID__VOID,
00561                   G_TYPE_NONE, 0);
00562 
00563   legacy_window_signals [STATE_CHANGED] =
00564     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_STATE_CHANGED,
00565                   G_OBJECT_CLASS_TYPE (klass),
00566                   G_SIGNAL_RUN_FIRST,
00567                   G_STRUCT_OFFSET (BamfLegacyWindowClass, state_changed),
00568                   NULL, NULL,
00569                   g_cclosure_marshal_VOID__VOID,
00570                   G_TYPE_NONE, 0);
00571 
00572   legacy_window_signals [GEOMETRY_CHANGED] =
00573     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_GEOMETRY_CHANGED,
00574                   G_OBJECT_CLASS_TYPE (klass),
00575                   G_SIGNAL_RUN_FIRST,
00576                   G_STRUCT_OFFSET (BamfLegacyWindowClass, geometry_changed),
00577                   NULL, NULL,
00578                   g_cclosure_marshal_VOID__VOID,
00579                   G_TYPE_NONE, 0);
00580 
00581   legacy_window_signals [CLOSED] =
00582     g_signal_new (BAMF_LEGACY_WINDOW_SIGNAL_CLOSED,
00583                   G_OBJECT_CLASS_TYPE (klass),
00584                   G_SIGNAL_RUN_FIRST,
00585                   G_STRUCT_OFFSET (BamfLegacyWindowClass, closed),
00586                   NULL, NULL,
00587                   g_cclosure_marshal_VOID__VOID,
00588                   G_TYPE_NONE, 0);
00589 }
00590 
00591 BamfLegacyWindow *
00592 bamf_legacy_window_new (WnckWindow *legacy_window)
00593 {
00594   BamfLegacyWindow *self;
00595   self = (BamfLegacyWindow *) g_object_new (BAMF_TYPE_LEGACY_WINDOW, NULL);
00596 
00597   self->priv->legacy_window = legacy_window;
00598 
00599   self->priv->name_changed_id = g_signal_connect (G_OBJECT (legacy_window), "name-changed",
00600                                                   (GCallback) handle_name_changed, self);
00601 
00602   self->priv->state_changed_id = g_signal_connect (G_OBJECT (legacy_window), "state-changed",
00603                                                    (GCallback) handle_state_changed, self);
00604 
00605   self->priv->geometry_changed_id = g_signal_connect (G_OBJECT (legacy_window), "geometry-changed",
00606                                                       (GCallback) handle_geometry_changed, self);
00607 
00608   return self;
00609 }