gnome-shell-3.6.3.1/src/shell-perf-helper.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 
  3 /* gnome-shell-perf-helper: a program to create windows for performance tests
  4  *
  5  * Running performance tests with whatever windows a user has open results
  6  * in unreliable results, so instead we hide all other windows and talk
  7  * to this program over D-Bus to create just the windows we want.
  8  */
  9 
 10 #include "config.h"
 11 
 12 #include <gtk/gtk.h>
 13 #include <gdk/gdkx.h>
 14 
 15 #define BUS_NAME "org.gnome.Shell.PerfHelper"
 16 
 17 static void destroy_windows           (void);
 18 static void finish_wait_windows       (void);
 19 static void check_finish_wait_windows (void);
 20 
 21 static const gchar introspection_xml[] =
 22 	  "<node>"
 23 	  "  <interface name='org.gnome.Shell.PerfHelper'>"
 24 	  "    <method name='Exit'/>"
 25 	  "    <method name='CreateWindow'>"
 26 	  "      <arg type='i' name='width' direction='in'/>"
 27 	  "      <arg type='i' name='height' direction='in'/>"
 28 	  "      <arg type='b' name='alpha' direction='in'/>"
 29 	  "      <arg type='b' name='maximized' direction='in'/>"
 30 	  "    </method>"
 31 	  "    <method name='WaitWindows'/>"
 32 	  "    <method name='DestroyWindows'/>"
 33 	  "  </interface>"
 34 	"</node>";
 35 
 36 typedef struct {
 37   GtkWidget *window;
 38   int width;
 39   int height;
 40 
 41   guint alpha : 1;
 42   guint maximized : 1;
 43   guint mapped : 1;
 44   guint exposed : 1;
 45   guint pending : 1;
 46 } WindowInfo;
 47 
 48 static int opt_idle_timeout = 30;
 49 
 50 static GOptionEntry opt_entries[] =
 51   {
 52     { "idle-timeout", 'r', 0, G_OPTION_ARG_INT, &opt_idle_timeout, "Exit after N seconds", "N" },
 53     { NULL }
 54   };
 55 
 56 static Display *xdisplay;
 57 static Window xroot;
 58 static Atom atom_wm_state;
 59 static Atom atom__net_wm_name;
 60 static Atom atom_utf8_string;
 61 
 62 static guint timeout_id;
 63 static GList *our_windows;
 64 static GList *wait_windows_invocations;
 65 
 66 static gboolean
 67 on_timeout (gpointer data)
 68 {
 69   timeout_id = 0;
 70 
 71   destroy_windows ();
 72   gtk_main_quit ();
 73 
 74   return FALSE;
 75 }
 76 
 77 static void
 78 establish_timeout ()
 79 {
 80   if (timeout_id != 0)
 81     g_source_remove (timeout_id);
 82 
 83   timeout_id = g_timeout_add (opt_idle_timeout * 1000, on_timeout, NULL);
 84 }
 85 
 86 static void
 87 destroy_windows (void)
 88 {
 89   GList *l;
 90 
 91   for (l = our_windows; l; l = l->next)
 92     {
 93       WindowInfo *info = l->data;
 94       gtk_widget_destroy (info->window);
 95       g_free (info);
 96     }
 97 
 98   g_list_free (our_windows);
 99   our_windows = NULL;
100 
101   check_finish_wait_windows ();
102 }
103 
104 static gboolean
105 on_window_map_event (GtkWidget   *window,
106                      GdkEventAny *event,
107                      WindowInfo  *info)
108 {
109   info->mapped = TRUE;
110 
111   return FALSE;
112 }
113 
114 static gboolean
115 on_window_draw (GtkWidget  *window,
116 		cairo_t    *cr,
117                 WindowInfo *info)
118 {
119   cairo_rectangle_int_t allocation;
120   gtk_widget_get_allocation (window, &allocation);
121 
122   /* We draw an arbitrary pattern of red lines near the border of the
123    * window to make it more clear than empty windows if something
124    * is drastrically wrong.
125    */
126 
127   cairo_save (cr);
128   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
129 
130   if (info->alpha)
131     cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
132   else
133     cairo_set_source_rgb (cr, 1, 1, 1);
134 
135   cairo_paint (cr);
136   cairo_restore (cr);
137 
138   cairo_set_source_rgb (cr, 1, 0, 0);
139   cairo_set_line_width (cr, 10);
140   cairo_move_to (cr, 0, 40);
141   cairo_line_to (cr, allocation.width, 40);
142   cairo_move_to (cr, 0, allocation.height - 40);
143   cairo_line_to (cr, allocation.width, allocation.height - 40);
144   cairo_move_to (cr, 40, 0);
145   cairo_line_to (cr, 40, allocation.height);
146   cairo_move_to (cr, allocation.width - 40, 0);
147   cairo_line_to (cr, allocation.width - 40, allocation.height);
148   cairo_stroke (cr);
149 
150   info->exposed = TRUE;
151 
152   if (info->exposed && info->mapped && info->pending)
153     {
154       info->pending = FALSE;
155       check_finish_wait_windows ();
156     }
157 
158   return FALSE;
159 }
160 
161 static void
162 create_window (int      width,
163 	       int      height,
164                gboolean alpha,
165                gboolean maximized)
166 {
167   WindowInfo *info;
168 
169   info = g_new0 (WindowInfo, 1);
170   info->width = width;
171   info->height = height;
172   info->alpha = alpha;
173   info->maximized = maximized;
174   info->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
175   if (alpha)
176     gtk_widget_set_visual (info->window, gdk_screen_get_rgba_visual (gdk_screen_get_default ()));
177   if (maximized)
178     gtk_window_maximize (GTK_WINDOW (info->window));
179   info->pending = TRUE;
180 
181   gtk_widget_set_size_request (info->window, width, height);
182   gtk_widget_set_app_paintable (info->window, TRUE);
183   g_signal_connect (info->window, "map-event", G_CALLBACK (on_window_map_event), info);
184   g_signal_connect (info->window, "draw", G_CALLBACK (on_window_draw), info);
185   gtk_widget_show (info->window);
186 
187   our_windows = g_list_prepend (our_windows, info);
188 }
189 
190 static void
191 finish_wait_windows (void)
192 {
193   GList *l;
194 
195   for (l = wait_windows_invocations; l; l = l->next)
196     g_dbus_method_invocation_return_value (l->data, NULL);
197 
198   g_list_free (wait_windows_invocations);
199   wait_windows_invocations = NULL;
200 }
201 
202 static void
203 check_finish_wait_windows (void)
204 {
205   GList *l;
206   gboolean have_pending = FALSE;
207 
208   for (l = our_windows; l; l = l->next)
209     {
210       WindowInfo *info = l->data;
211       if (info->pending)
212         have_pending = TRUE;
213     }
214 
215   if (!have_pending)
216     finish_wait_windows ();
217 }
218 
219 static void
220 handle_method_call (GDBusConnection       *connection,
221 		    const gchar           *sender,
222 		    const gchar           *object_path,
223 		    const gchar           *interface_name,
224 		    const gchar           *method_name,
225 		    GVariant              *parameters,
226 		    GDBusMethodInvocation *invocation,
227 		    gpointer               user_data)
228 {
229   /* Push off the idle timeout */
230   establish_timeout ();
231 
232   if (g_strcmp0 (method_name, "Exit") == 0)
233     {
234       destroy_windows ();
235 
236       g_dbus_method_invocation_return_value (invocation, NULL);
237       g_dbus_connection_flush_sync (connection, NULL, NULL);
238 
239       gtk_main_quit ();
240     }
241   else if (g_strcmp0 (method_name, "CreateWindow") == 0)
242     {
243       int width, height;
244       gboolean alpha, maximized;
245 
246       g_variant_get (parameters, "(iibb)", &width, &height, &alpha, &maximized);
247 
248       create_window (width, height, alpha, maximized);
249       g_dbus_method_invocation_return_value (invocation, NULL);
250     }
251   else if (g_strcmp0 (method_name, "WaitWindows") == 0)
252     {
253       wait_windows_invocations = g_list_prepend (wait_windows_invocations, invocation);
254       check_finish_wait_windows ();
255     }
256   else if (g_strcmp0 (method_name, "DestroyWindows") == 0)
257     {
258       destroy_windows ();
259       g_dbus_method_invocation_return_value (invocation, NULL);
260     }
261 }
262 
263 static const GDBusInterfaceVTable interface_vtable =
264 {
265   handle_method_call,
266   NULL,
267   NULL
268 };
269 
270 static void
271 on_bus_acquired (GDBusConnection *connection,
272 		 const gchar     *name,
273 		 gpointer         user_data)
274 {
275   GDBusNodeInfo *introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
276 
277   g_dbus_connection_register_object (connection,
278 				     "/org/gnome/Shell/PerfHelper",
279 				     introspection_data->interfaces[0],
280 				     &interface_vtable,
281 				     NULL,  /* user_data */
282 				     NULL,  /* user_data_free_func */
283 				     NULL); /* GError** */
284 }
285 
286 static void
287 on_name_acquired (GDBusConnection *connection,
288 		  const gchar     *name,
289 		  gpointer         user_data)
290 {
291 }
292 
293 static void
294 on_name_lost  (GDBusConnection *connection,
295 	       const gchar     *name,
296 	       gpointer         user_data)
297 {
298   destroy_windows ();
299   gtk_main_quit ();
300 }
301 
302 int
303 main (int argc, char **argv)
304 {
305   GdkDisplay *display;
306   GdkScreen *screen;
307   GOptionContext *context;
308   GError *error = NULL;
309 
310   /* Since we depend on this, avoid the possibility of lt-gnome-shell-perf-helper */
311   g_set_prgname ("gnome-shell-perf-helper");
312 
313   context = g_option_context_new (" - server to create windows for performance testing");
314   g_option_context_add_main_entries (context, opt_entries, NULL);
315   g_option_context_add_group (context, gtk_get_option_group (TRUE));
316   if (!g_option_context_parse (context, &argc, &argv, &error))
317     {
318       g_print ("option parsing failed: %s\n", error->message);
319       return 1;
320     }
321 
322   display = gdk_display_get_default ();
323   screen = gdk_screen_get_default ();
324 
325   xdisplay = gdk_x11_display_get_xdisplay (display);
326   xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen));
327   atom_wm_state = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
328   atom__net_wm_name = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
329   atom_utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
330 
331   g_bus_own_name (G_BUS_TYPE_SESSION,
332                   BUS_NAME,
333                   G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
334                   G_BUS_NAME_OWNER_FLAGS_REPLACE,
335                   on_bus_acquired,
336                   on_name_acquired,
337                   on_name_lost,
338                   NULL,
339                   NULL);
340 
341   establish_timeout ();
342 
343   gtk_main ();
344 
345   return 0;
346 }