]> Pileus Git - ~andy/gtk/blob - perf/timers.c
Cosmetics.
[~andy/gtk] / perf / timers.c
1 /* Utility functions for timing widgets
2  *
3  * Authors:
4  *   Federico Mena-Quintero <federico@novell.com>
5  *
6  * To measure how long it takes to fully map and expose a toplevel window, we
7  * use a trick which Owen Taylor described on IRC one day:
8  *
9  *   1. Start a timer.
10  *   2. Call gtk_widget_show_all() on the toplevel window.
11  *   3. In the expose_event handler of the window, queue an idle handler with
12  *      G_PRIORITY_HIGH.
13  *   4. In the idle handler, change a property on the toplevel window.
14  *   5. In the property_notify_event handler, stop the timer.
15  */
16
17 #include <string.h>
18 #include <glib.h>
19 #include <gtk/gtkmain.h>
20 #include "timers.h"
21
22 struct timer_closure
23 {
24   GTimer *timer;
25   GtkWidget *widget;
26   TimerReportFunc report_func;
27   gpointer user_data;
28 };
29
30 static gboolean
31 widget_property_notify_event_cb (GtkWidget *widget, GdkEventProperty *event, gpointer data)
32 {
33   struct timer_closure *closure;
34   gdouble elapsed;
35
36   closure = data;
37
38   if (event->atom != gdk_atom_intern ("window_property_change", FALSE))
39     return FALSE;
40
41   /* Finish timing map/expose */
42
43   elapsed = g_timer_elapsed (closure->timer, NULL);
44   (* closure->report_func) (TIMER_REPORT_WIDGET_SHOW, elapsed, closure->user_data);
45
46   /* Time destruction */
47   
48   g_timer_reset (closure->timer);
49   gtk_widget_destroy (widget);
50   elapsed = g_timer_elapsed (closure->timer, NULL);
51   (* closure->report_func) (TIMER_REPORT_WIDGET_DESTRUCTION, elapsed, closure->user_data);
52
53   gtk_main_quit (); /* This will get us back to the end of timer_time_widget() */
54   return TRUE;
55 }
56
57 static gboolean
58 idle_after_expose_cb (gpointer data)
59 {
60   struct timer_closure *closure;
61
62   closure = data;
63
64   gdk_property_change (closure->widget->window,
65                        gdk_atom_intern ("window_property_change", FALSE),
66                        gdk_atom_intern ("STRING", FALSE),
67                        8,
68                        GDK_PROP_MODE_REPLACE,
69                        "hello",
70                        strlen ("hello"));
71
72   return FALSE;
73 }
74
75 static gboolean
76 widget_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
77 {
78   struct timer_closure *closure;
79
80   closure = data;
81
82   g_idle_add_full (G_PRIORITY_HIGH, idle_after_expose_cb, closure, NULL);
83   return FALSE;
84 }
85
86 static void
87 instrument_widget (GtkWidget *widget,
88                    struct timer_closure *closure)
89 {
90   g_signal_connect (widget, "expose-event",
91                     G_CALLBACK (widget_expose_event_cb), closure);
92
93   gtk_widget_add_events (widget, GDK_PROPERTY_CHANGE_MASK);
94   g_signal_connect (widget, "property-notify-event",
95                     G_CALLBACK (widget_property_notify_event_cb), closure);
96 }
97
98 void
99 timer_time_widget (TimerWidgetCreateFunc create_func,
100                    TimerReportFunc       report_func,
101                    gpointer              user_data)
102 {
103   GTimer *timer;
104   GtkWidget *widget;
105   gdouble elapsed;
106   struct timer_closure closure;
107
108   g_assert (create_func != NULL);
109   g_assert (report_func != NULL);
110
111   /* Time creation */
112
113   timer = g_timer_new ();
114   widget = (* create_func) (user_data);
115   g_assert (widget != NULL);
116   g_assert (!GTK_WIDGET_VISIBLE (widget) && !GTK_WIDGET_MAPPED (widget));
117   elapsed = g_timer_elapsed (timer, NULL);
118
119   (* report_func) (TIMER_REPORT_WIDGET_CREATION, elapsed, user_data);
120
121   /* Start timing map/expose */
122
123   closure.timer = timer;
124   closure.widget = widget;
125   closure.report_func = report_func;
126   closure.user_data = user_data;
127   instrument_widget (widget, &closure);
128
129   g_timer_reset (timer);
130   gtk_widget_show_all (widget);
131   gtk_main ();
132
133   /* Expose time and destruction time get recorded in widget_property_notify_event_cb() */
134 }