Back to index

bamf  0.2.120
bamf-legacy-screen.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 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  *
00018  */
00019 
00020 #include "bamf-legacy-screen.h"
00021 #include "bamf-legacy-window-test.h"
00022 #include <gio/gio.h>
00023 
00024 G_DEFINE_TYPE (BamfLegacyScreen, bamf_legacy_screen, G_TYPE_OBJECT);
00025 #define BAMF_LEGACY_SCREEN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
00026 BAMF_TYPE_LEGACY_SCREEN, BamfLegacyScreenPrivate))
00027 
00028 enum
00029 {
00030   WINDOW_OPENED,
00031   WINDOW_CLOSED,
00032   STACKING_CHANGED,
00033   ACTIVE_WINDOW_CHANGED,
00034 
00035   LAST_SIGNAL,
00036 };
00037 
00038 static guint legacy_screen_signals[LAST_SIGNAL] = { 0 };
00039 
00040 struct _BamfLegacyScreenPrivate
00041 {
00042   WnckScreen * legacy_screen;
00043   GList *windows;
00044   GFile *file;
00045   GDataInputStream *stream;
00046 };
00047 
00048 static void
00049 handle_window_closed (BamfLegacyWindow *window, BamfLegacyScreen *self)
00050 {
00051   self->priv->windows = g_list_remove (self->priv->windows, window);
00052 
00053   g_signal_emit (self, legacy_screen_signals[WINDOW_CLOSED], 0, window);
00054 
00055   g_object_unref (window);
00056 }
00057 
00058 static gboolean
00059 on_state_file_load_timeout (BamfLegacyScreen *self)
00060 {
00061   BamfLegacyWindow *window;
00062   GDataInputStream *stream;
00063   gchar *line, *name, *class, *exec;
00064   GList *l;
00065   gchar **parts;
00066   gsize parts_size;
00067   guint32 xid;
00068 
00069   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (self), FALSE);
00070 
00071   stream = self->priv->stream;
00072 
00073   line = g_data_input_stream_read_line (stream, NULL, NULL, NULL);
00074 
00075   if (!line)
00076     return FALSE;
00077 
00078   // Line format:
00079   // open     <xid>  <name> <wmclass> <exec>
00080   // close    <xid>
00081   // attention       <xid>  <true/false>
00082   // skip     <xid>  <true/false>
00083   // geometry <xid> <x> <y> <width> <height>
00084   // maximized <xid> <maximized/vmaximized/hmaximized/floating>
00085 
00086   parts = g_strsplit (line, "\t", 0);
00087   g_free (line);
00088 
00089   parts_size = 0;
00090   while (parts[parts_size] != NULL)
00091     parts_size++;
00092 
00093   if (parts_size < 2)
00094     return FALSE;
00095 
00096   xid = (guint32) atol (parts[1]);
00097   if (g_strcmp0 (parts[0], "open") == 0 && parts_size == 5)
00098     {
00099       name  = parts[2];
00100       class = parts[3];
00101       exec  = parts[4];
00102 
00103       window = BAMF_LEGACY_WINDOW (bamf_legacy_window_test_new (xid, name, class, exec));
00104       self->priv->windows = g_list_append (self->priv->windows, window);
00105       g_signal_emit (window, legacy_screen_signals[STACKING_CHANGED], 0);
00106 
00107       g_signal_connect (G_OBJECT (window), "closed",
00108                         (GCallback) handle_window_closed, self);
00109 
00110       g_signal_emit (self, legacy_screen_signals[WINDOW_OPENED], 0, window);
00111     }
00112   else if (g_strcmp0 (parts[0], "close") == 0 && parts_size == 2)
00113     {
00114       for (l = self->priv->windows; l; l = l->next)
00115         {
00116           window = l->data;
00117           if (bamf_legacy_window_get_xid (window) == xid)
00118             {
00119               bamf_legacy_window_test_close (BAMF_LEGACY_WINDOW_TEST (window));
00120               break;
00121             }
00122         }
00123     }
00124   else if (g_strcmp0 (parts[0], "attention") == 0 && parts_size == 3)
00125     {
00126       gboolean attention = FALSE;
00127       if (g_strcmp0 (parts[2], "true") == 0)
00128         attention = TRUE;
00129       else if (g_strcmp0 (parts[2], "false") == 0)
00130         attention = FALSE;
00131       else
00132         return TRUE;
00133 
00134       for (l = self->priv->windows; l; l = l->next)
00135         {
00136           if (bamf_legacy_window_get_xid (l->data) == xid)
00137             {
00138               bamf_legacy_window_test_set_attention (l->data, attention);
00139               break;
00140             }
00141         }
00142     }
00143   else if (g_strcmp0 (parts[0], "skip") == 0 && parts_size ==  3)
00144     {
00145       gboolean skip = FALSE;
00146       if (g_strcmp0 (parts[2], "true") == 0)
00147         skip = TRUE;
00148       else if (g_strcmp0 (parts[2], "false") == 0)
00149         skip = FALSE;
00150       else
00151         return TRUE;
00152 
00153       for (l = self->priv->windows; l; l = l->next)
00154         {
00155           if (bamf_legacy_window_get_xid (l->data) == xid)
00156             {
00157               bamf_legacy_window_test_set_skip (l->data, skip);
00158               break;
00159             }
00160         }
00161     }
00162   else if (g_strcmp0 (parts[0], "geometry") == 0 && parts_size == 6)
00163     {
00164       int x = atoi (parts[2]);
00165       int y = atoi (parts[3]);
00166       int width = atoi (parts[4]);
00167       int height = atoi (parts[5]);
00168 
00169       for (l = self->priv->windows; l; l = l->next)
00170         {
00171           if (bamf_legacy_window_get_xid (l->data) == xid)
00172             {
00173               bamf_legacy_window_test_set_geometry (l->data, x, y, width, height);
00174               break;
00175             }
00176         }
00177     }
00178   else if (g_strcmp0 (parts[0], "maximized") == 0 && parts_size == 3)
00179     {
00180       BamfWindowMaximizationType maximized;
00181 
00182       if (g_strcmp0 (parts[2], "maximized") == 0)
00183         maximized = BAMF_WINDOW_MAXIMIZED;
00184       else if (g_strcmp0 (parts[2], "vmaximized") == 0)
00185         maximized = BAMF_WINDOW_VERTICAL_MAXIMIZED;
00186       else if (g_strcmp0 (parts[2], "hmaximized") == 0)
00187         maximized = BAMF_WINDOW_HORIZONTAL_MAXIMIZED;
00188       else if (g_strcmp0 (parts[2], "floating") == 0)
00189         maximized = BAMF_WINDOW_FLOATING;
00190       else
00191         return TRUE;
00192 
00193       for (l = self->priv->windows; l; l = l->next)
00194         {
00195           if (bamf_legacy_window_get_xid (l->data) == xid)
00196             {
00197               bamf_legacy_window_test_set_maximized (l->data, maximized);
00198               break;
00199             }
00200         }
00201     }
00202   else
00203     {
00204       g_warning ("Could not parse line\n");
00205     }
00206 
00207   g_strfreev (parts);
00208   return TRUE;
00209 }
00210 
00211 static gint
00212 compare_windows_by_stack_order (gconstpointer a, gconstpointer b, gpointer data)
00213 {
00214   BamfLegacyScreen *self;
00215   GList *l;
00216   guint xid_a, xid_b;
00217   guint idx_a, idx_b;
00218 
00219   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (data), 1);
00220   self = BAMF_LEGACY_SCREEN (data);
00221 
00222   xid_a = bamf_legacy_window_get_xid (BAMF_LEGACY_WINDOW (a));
00223   xid_b = bamf_legacy_window_get_xid (BAMF_LEGACY_WINDOW (b));
00224 
00225   gboolean idx_a_found = FALSE;
00226   gboolean idx_b_found = FALSE;
00227   idx_a = 0;
00228   idx_b = 0;
00229 
00230   for (l = wnck_screen_get_windows_stacked (self->priv->legacy_screen); l; l = l->next)
00231   {
00232     gulong legacy_xid = wnck_window_get_xid (WNCK_WINDOW (l->data));
00233 
00234     if (!idx_a_found)
00235       {
00236         if (xid_a != legacy_xid)
00237           idx_a++;
00238         else
00239           idx_a_found = TRUE;
00240       }
00241 
00242     if (!idx_b_found)
00243       {
00244         if (xid_b != legacy_xid)
00245           idx_b++;
00246         else
00247           idx_b_found = TRUE;
00248       }
00249 
00250     if (idx_a_found && idx_b_found)
00251       break;
00252   }
00253 
00254   return (idx_a < idx_b) ? -1 : 1;
00255 }
00256 
00257 static void
00258 handle_window_opened (WnckScreen *screen, WnckWindow *window, BamfLegacyScreen *legacy)
00259 {
00260   BamfLegacyWindow *legacy_window;
00261   g_return_if_fail (WNCK_IS_WINDOW (window));
00262 
00263   legacy_window = bamf_legacy_window_new (window);
00264 
00265   g_signal_connect (G_OBJECT (legacy_window), "closed",
00266                     (GCallback) handle_window_closed, legacy);
00267 
00268   legacy->priv->windows = g_list_insert_sorted_with_data (legacy->priv->windows, legacy_window, 
00269                                                           compare_windows_by_stack_order,
00270                                                           legacy);
00271 
00272   g_signal_emit (legacy, legacy_screen_signals[WINDOW_OPENED], 0, legacy_window);
00273 }
00274 
00275 static void
00276 handle_stacking_changed (WnckScreen *screen, BamfLegacyScreen *legacy)
00277 {
00278   legacy->priv->windows = g_list_sort_with_data (legacy->priv->windows,
00279                                                  compare_windows_by_stack_order,
00280                                                  legacy);
00281 
00282   g_signal_emit (legacy, legacy_screen_signals[STACKING_CHANGED], 0);
00283 }
00284 
00285 /* This function allows to push into the screen a window by its xid.
00286  * If the window is already known, it's just ignored, otherwise it gets added
00287  * to the windows list. The BamfLegacyScreen should automatically update its
00288  * windows list when they are added/removed from the screen, but if a child
00289  * BamfLegacyWindow is closed, then it could be possible to re-add it.        */
00290 void
00291 bamf_legacy_screen_inject_window (BamfLegacyScreen *self, guint xid)
00292 {
00293   g_return_if_fail (BAMF_IS_LEGACY_SCREEN (self));
00294   BamfLegacyWindow *window;
00295   GList *l;
00296 
00297   for (l = self->priv->windows; l; l = l->next)
00298     {
00299       window = l->data;
00300 
00301       if (bamf_legacy_window_get_xid (window) == xid)
00302         {
00303           return;
00304         }
00305     }
00306 
00307   WnckWindow *legacy_window = wnck_window_get(xid);
00308 
00309   if (WNCK_IS_WINDOW (legacy_window))
00310     {
00311       handle_window_opened(NULL, legacy_window, self);
00312     }
00313 }
00314 
00315 void
00316 bamf_legacy_screen_set_state_file (BamfLegacyScreen *self,
00317                                    const char *file)
00318 {
00319   GFile *gfile;
00320   GDataInputStream *stream;
00321 
00322   g_return_if_fail (BAMF_IS_LEGACY_SCREEN (self));
00323 
00324   // Disconnect our handlers so we can work purely on the file
00325   g_signal_handlers_disconnect_by_func (self->priv->legacy_screen, handle_window_opened, self);
00326   g_signal_handlers_disconnect_by_func (self->priv->legacy_screen, handle_window_closed, self);
00327   g_signal_handlers_disconnect_by_func (self->priv->legacy_screen, handle_stacking_changed, self);
00328 
00329   gfile = g_file_new_for_path (file);
00330 
00331   if (!file)
00332     {
00333       g_error ("Could not open file %s", file);
00334     }
00335 
00336   stream = g_data_input_stream_new (G_INPUT_STREAM (g_file_read (gfile, NULL, NULL)));
00337 
00338   if (!stream)
00339     {
00340       g_error ("Could not open file stream for %s", file);
00341     }
00342 
00343   self->priv->file = gfile;
00344   self->priv->stream = stream;
00345 
00346   g_timeout_add (500, (GSourceFunc) on_state_file_load_timeout, self);
00347 }
00348 
00349 GList *
00350 bamf_legacy_screen_get_windows (BamfLegacyScreen *screen)
00351 {
00352   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), NULL);
00353 
00354   return screen->priv->windows;
00355 }
00356 
00357 BamfLegacyWindow *
00358 bamf_legacy_screen_get_active_window (BamfLegacyScreen *screen)
00359 {
00360   BamfLegacyWindow *window;
00361   GList *l;
00362 
00363   g_return_val_if_fail (BAMF_IS_LEGACY_SCREEN (screen), NULL);
00364 
00365   for (l = screen->priv->windows; l; l = l->next)
00366     {
00367       window = l->data;
00368 
00369       if (bamf_legacy_window_is_active (window))
00370         return window;
00371     }
00372 
00373   return NULL;
00374 }
00375 
00376 static void
00377 handle_active_window_changed (WnckScreen *screen, WnckWindow *previous, BamfLegacyScreen *self)
00378 {
00379   g_return_if_fail (BAMF_IS_LEGACY_SCREEN (self));
00380 
00381   g_signal_emit (self, legacy_screen_signals[ACTIVE_WINDOW_CHANGED], 0);
00382 }
00383 
00384 static void
00385 bamf_legacy_screen_dispose (GObject *object)
00386 {
00387   G_OBJECT_CLASS (bamf_legacy_screen_parent_class)->dispose (object);
00388 }
00389 
00390 static void
00391 bamf_legacy_screen_init (BamfLegacyScreen * self)
00392 {
00393   self->priv = BAMF_LEGACY_SCREEN_GET_PRIVATE (self);
00394 }
00395 
00396 static void
00397 bamf_legacy_screen_class_init (BamfLegacyScreenClass * klass)
00398 {
00399   GObjectClass *object_class = G_OBJECT_CLASS (klass);
00400 
00401   object_class->dispose      = bamf_legacy_screen_dispose;
00402 
00403   g_type_class_add_private (klass, sizeof (BamfLegacyScreenPrivate));
00404 
00405   legacy_screen_signals [WINDOW_OPENED] =
00406     g_signal_new (BAMF_LEGACY_SCREEN_SIGNAL_WINDOW_OPENED,
00407                   G_OBJECT_CLASS_TYPE (klass),
00408                   G_SIGNAL_RUN_FIRST,
00409                   G_STRUCT_OFFSET (BamfLegacyScreenClass, window_opened),
00410                   NULL, NULL,
00411                   g_cclosure_marshal_VOID__OBJECT,
00412                   G_TYPE_NONE, 1,
00413                   BAMF_TYPE_LEGACY_WINDOW);
00414 
00415   legacy_screen_signals [WINDOW_CLOSED] =
00416     g_signal_new (BAMF_LEGACY_SCREEN_SIGNAL_WINDOW_CLOSED,
00417                   G_OBJECT_CLASS_TYPE (klass),
00418                   G_SIGNAL_RUN_FIRST,
00419                   G_STRUCT_OFFSET (BamfLegacyScreenClass, window_closed),
00420                   NULL, NULL,
00421                   g_cclosure_marshal_VOID__OBJECT,
00422                   G_TYPE_NONE, 1,
00423                   BAMF_TYPE_LEGACY_WINDOW);
00424 
00425   legacy_screen_signals [STACKING_CHANGED] =
00426     g_signal_new (BAMF_LEGACY_SCREEN_SIGNAL_STACKING_CHANGED,
00427                   G_OBJECT_CLASS_TYPE (klass),
00428                   G_SIGNAL_RUN_FIRST,
00429                   G_STRUCT_OFFSET (BamfLegacyScreenClass, stacking_changed),
00430                   NULL, NULL,
00431                   g_cclosure_marshal_VOID__VOID,
00432                   G_TYPE_NONE, 0);
00433 
00434   legacy_screen_signals [ACTIVE_WINDOW_CHANGED] =
00435     g_signal_new (BAMF_LEGACY_SCREEN_SIGNAL_ACTIVE_WINDOW_CHANGED,
00436                   G_OBJECT_CLASS_TYPE (klass),
00437                   G_SIGNAL_RUN_FIRST,
00438                   G_STRUCT_OFFSET (BamfLegacyScreenClass, active_window_changed),
00439                   NULL, NULL,
00440                   g_cclosure_marshal_VOID__VOID,
00441                   G_TYPE_NONE, 0);
00442 }
00443 
00444 static BamfLegacyScreen *self = NULL;
00445 
00446 BamfLegacyScreen *
00447 bamf_legacy_screen_get_default ()
00448 {
00449   if (self)
00450     return self;
00451 
00452   self = (BamfLegacyScreen *) g_object_new (BAMF_TYPE_LEGACY_SCREEN, NULL);
00453 
00454   self->priv->legacy_screen = wnck_screen_get_default ();
00455 
00456   g_signal_connect (G_OBJECT (self->priv->legacy_screen), "window-opened",
00457                     (GCallback) handle_window_opened, self);
00458 
00459   g_signal_connect (G_OBJECT (self->priv->legacy_screen), "window-stacking-changed",
00460                     (GCallback) handle_stacking_changed, self);
00461 
00462   g_signal_connect (G_OBJECT (self->priv->legacy_screen), "active-window-changed",
00463                     (GCallback) handle_active_window_changed, self);
00464 
00465   return self;
00466 }