]> Pileus Git - ~andy/gtk/commitdiff
Update for the new API of the profiler.
authorFederico Mena Quintero <federico@ximian.com>
Fri, 29 Jul 2005 00:38:51 +0000 (00:38 +0000)
committerFederico Mena Quintero <federico@src.gnome.org>
Fri, 29 Jul 2005 00:38:51 +0000 (00:38 +0000)
2005-07-28  Federico Mena Quintero  <federico@ximian.com>

* perf/README: Update for the new API of the profiler.

* perf/gtkwidgetprofiler.[ch]: New files with a widget profiler
object.  This is the old content of timers.[ch] turned into a nice
object, with signals for creation and reporting.  The profiler
needs to maintain some state when reusing the widget, so it's
useful to turn it into a real object.

Break down timing show_all into GTK_WIDGET_PROFILER_REPORT_MAP and
GTK_WIDGET_PROFILER_REPORT_EXPOSE.

* perf/main.c: Refactor to use GtkWidgetProfiler.

* perf/appwindow.c (content_area_new): Make this just create a
notebook, instead of a complex arrangement of panes.

* perf/widgets.h: New header file for all the "create a widget"
utility functions.

* perf/treeview.c: New file.  Moved the tree view part from
appwindow.c over to here; GtkTreeView really needs its own tests.
(tree_view_new): Set the shadow type to IN.

* perf/textview.c: Likewise moved over from appwindow.c, but for
GtkTextView.
(text_view_new): Set the shadow type to IN.

* perf/Makefile.am (testperf_SOURCES): Add the new source files;
remove appwindow.h and timers.[ch].

* perf/timers.[ch]: Removed.

* perf/appwindow.h: Removed.

16 files changed:
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
perf/Makefile.am
perf/README
perf/appwindow.c
perf/appwindow.h [deleted file]
perf/gtkwidgetprofiler.c [new file with mode: 0644]
perf/gtkwidgetprofiler.h [new file with mode: 0644]
perf/main.c
perf/marshalers.list [new file with mode: 0644]
perf/textview.c [new file with mode: 0644]
perf/timers.c [deleted file]
perf/timers.h [deleted file]
perf/treeview.c [new file with mode: 0644]
perf/widgets.h [new file with mode: 0644]

index 58945460d8c7cbbdab4fe4466e4cae6f580d6d2a..ba8b33c0dd714a667cc64c6cdb1c71d3efbf0c02 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2005-07-28  Federico Mena Quintero  <federico@ximian.com>
+
+       * perf/README: Update for the new API of the profiler.
+
+       * perf/gtkwidgetprofiler.[ch]: New files with a widget profiler
+       object.  This is the old content of timers.[ch] turned into a nice
+       object, with signals for creation and reporting.  The profiler
+       needs to maintain some state when reusing the widget, so it's
+       useful to turn it into a real object.
+
+       Break down timing show_all into GTK_WIDGET_PROFILER_REPORT_MAP and
+       GTK_WIDGET_PROFILER_REPORT_EXPOSE.
+
+       * perf/main.c: Refactor to use GtkWidgetProfiler.
+
+       * perf/appwindow.c (content_area_new): Make this just create a
+       notebook, instead of a complex arrangement of panes.
+
+       * perf/widgets.h: New header file for all the "create a widget"
+       utility functions.
+
+       * perf/treeview.c: New file.  Moved the tree view part from
+       appwindow.c over to here; GtkTreeView really needs its own tests.
+       (tree_view_new): Set the shadow type to IN.
+
+       * perf/textview.c: Likewise moved over from appwindow.c, but for
+       GtkTextView.
+       (text_view_new): Set the shadow type to IN.
+
+       * perf/Makefile.am (testperf_SOURCES): Add the new source files;
+       remove appwindow.h and timers.[ch].
+
+       * perf/timers.[ch]: Removed.
+
+       * perf/appwindow.h: Removed.
+
 2005-07-29  Tor Lillqvist  <tml@novell.com>
 
        * gdk/win32/gdkevents-win32.c: Remove ifdeffed out code relating
index 58945460d8c7cbbdab4fe4466e4cae6f580d6d2a..ba8b33c0dd714a667cc64c6cdb1c71d3efbf0c02 100644 (file)
@@ -1,3 +1,39 @@
+2005-07-28  Federico Mena Quintero  <federico@ximian.com>
+
+       * perf/README: Update for the new API of the profiler.
+
+       * perf/gtkwidgetprofiler.[ch]: New files with a widget profiler
+       object.  This is the old content of timers.[ch] turned into a nice
+       object, with signals for creation and reporting.  The profiler
+       needs to maintain some state when reusing the widget, so it's
+       useful to turn it into a real object.
+
+       Break down timing show_all into GTK_WIDGET_PROFILER_REPORT_MAP and
+       GTK_WIDGET_PROFILER_REPORT_EXPOSE.
+
+       * perf/main.c: Refactor to use GtkWidgetProfiler.
+
+       * perf/appwindow.c (content_area_new): Make this just create a
+       notebook, instead of a complex arrangement of panes.
+
+       * perf/widgets.h: New header file for all the "create a widget"
+       utility functions.
+
+       * perf/treeview.c: New file.  Moved the tree view part from
+       appwindow.c over to here; GtkTreeView really needs its own tests.
+       (tree_view_new): Set the shadow type to IN.
+
+       * perf/textview.c: Likewise moved over from appwindow.c, but for
+       GtkTextView.
+       (text_view_new): Set the shadow type to IN.
+
+       * perf/Makefile.am (testperf_SOURCES): Add the new source files;
+       remove appwindow.h and timers.[ch].
+
+       * perf/timers.[ch]: Removed.
+
+       * perf/appwindow.h: Removed.
+
 2005-07-29  Tor Lillqvist  <tml@novell.com>
 
        * gdk/win32/gdkevents-win32.c: Remove ifdeffed out code relating
index 58945460d8c7cbbdab4fe4466e4cae6f580d6d2a..ba8b33c0dd714a667cc64c6cdb1c71d3efbf0c02 100644 (file)
@@ -1,3 +1,39 @@
+2005-07-28  Federico Mena Quintero  <federico@ximian.com>
+
+       * perf/README: Update for the new API of the profiler.
+
+       * perf/gtkwidgetprofiler.[ch]: New files with a widget profiler
+       object.  This is the old content of timers.[ch] turned into a nice
+       object, with signals for creation and reporting.  The profiler
+       needs to maintain some state when reusing the widget, so it's
+       useful to turn it into a real object.
+
+       Break down timing show_all into GTK_WIDGET_PROFILER_REPORT_MAP and
+       GTK_WIDGET_PROFILER_REPORT_EXPOSE.
+
+       * perf/main.c: Refactor to use GtkWidgetProfiler.
+
+       * perf/appwindow.c (content_area_new): Make this just create a
+       notebook, instead of a complex arrangement of panes.
+
+       * perf/widgets.h: New header file for all the "create a widget"
+       utility functions.
+
+       * perf/treeview.c: New file.  Moved the tree view part from
+       appwindow.c over to here; GtkTreeView really needs its own tests.
+       (tree_view_new): Set the shadow type to IN.
+
+       * perf/textview.c: Likewise moved over from appwindow.c, but for
+       GtkTextView.
+       (text_view_new): Set the shadow type to IN.
+
+       * perf/Makefile.am (testperf_SOURCES): Add the new source files;
+       remove appwindow.h and timers.[ch].
+
+       * perf/timers.[ch]: Removed.
+
+       * perf/appwindow.h: Removed.
+
 2005-07-29  Tor Lillqvist  <tml@novell.com>
 
        * gdk/win32/gdkevents-win32.c: Remove ifdeffed out code relating
index 8e7ae186116bad1e883daaf48ddd07e4d47bdcd8..046e544197301412abfe6eb72fe71fc9f49d8d8f 100644 (file)
@@ -28,12 +28,73 @@ testperf_DEPENDENCIES = $(TEST_DEPS)
 
 testperf_LDADD = $(LDADDS)
 
-testperf_SOURCES =     \
-       appwindow.c     \
-       appwindow.h     \
-       main.c          \
-       timers.c        \
-       timers.h
-
-EXTRA_DIST =   \
-       README
+testperf_SOURCES =             \
+       appwindow.c             \
+       gtkwidgetprofiler.c     \
+       gtkwidgetprofiler.h     \
+       main.c                  \
+       marshalers.c            \
+       marshalers.h            \
+       textview.c              \
+       treeview.c              \
+       typebuiltins.c          \
+       typebuiltins.h          \
+       widgets.h
+
+BUILT_SOURCES =                        \
+       marshalers.c            \
+       marshalers.h            \
+       typebuiltins.c          \
+       typebuiltins.h
+
+stamp_files =                  \
+       stamp-marshalers.h      \
+       stamp-typebuiltins.h
+
+headers_with_enums =           \
+       gtkwidgetprofiler.h
+
+MAINTAINERCLEANFILES = $(BUILT_SOURCES) $(stamp_files)
+
+marshalers.h: stamp-marshalers.h
+       @true
+
+stamp-marshalers.h: @REBUILD@ marshalers.list
+       $(GLIB_GENMARSHAL) --prefix=_gtk_marshal $(srcdir)/marshalers.list --header >> xgen-gmlh \
+       && (cmp -s xgen-gmlh marshalers.h || cp xgen-gmlh marshalers.h) \
+       && rm -f xgen-gmlh \
+       && echo timestamp > $(@F)       
+marshalers.c: @REBUILD@ marshalers.list
+       $(GLIB_GENMARSHAL) --prefix=_gtk_marshal $(srcdir)/marshalers.list --body >> xgen-gmlc \
+       && cp xgen-gmlc marshalers.c \
+       && rm -f xgen-gmlc
+
+typebuiltins.h: stamp-typebuiltins.h
+       @true
+stamp-typebuiltins.h: @REBUILD@ $(headers_with_enums) Makefile
+       ( cd $(srcdir) && glib-mkenums \
+                       --fhead "#ifndef __TYPE_BUILTINS_H__\n#define __TYPE_BUILTINS_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+                       --fprod "/* enumerations from \"@filename@\" */\n" \
+                       --vhead "GType @enum_name@_get_type (void) G_GNUC_CONST;\n#define GTK_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
+                       --ftail "G_END_DECLS\n\n#endif /* __TYPE_BUILTINS_H__ */" \
+               $(headers_with_enums) ) >> xgen-gtbh \
+       && (cmp -s xgen-gtbh typebuiltins.h || cp xgen-gtbh typebuiltins.h ) \
+       && rm -f xgen-gtbh \
+       && echo timestamp > $(@F)
+typebuiltins.c: @REBUILD@ $(headers_with_enums) Makefile
+       ( cd $(srcdir) && glib-mkenums \
+                       --fhead "#include \"gtkwidgetprofiler.h\"" \
+                       --ftail "#define __TYPE_BUILTINS_C__\n" \
+                       --fprod "\n/* enumerations from \"@filename@\" */" \
+                       --vhead "GType\n@enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G@Type@Value values[] = {" \
+                       --vprod "      { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+                       --vtail "      { 0, NULL, NULL }\n    };\n    etype = g_@type@_register_static (\"@EnumName@\", values);\n  }\n  return etype;\n}\n" \
+               $(headers_with_enums) ) > xgen-gtbc \
+       && cp xgen-gtbc typebuiltins.c  \
+       && rm -f xgen-gtbc
+
+
+EXTRA_DIST =           \
+       README          \
+       marshalers.list \
+       $(BUILT_SOURCES)
index 43aa9aa35132dfddb46d0786b7351729c5209622..7f2670d5466359d617fb7ab287c3f0c89d59930b 100644 (file)
@@ -6,63 +6,75 @@ performant does not only mean "paint widgets fast".  It also means
 things like the time needed to set up widgets, to map and draw a
 window for the first time, and emitting/propagating signals.
 
-The following is accurate as of 2005/07/26.
+The following is accurate as of 2005/07/28.
 
 
 Using the framework
 -------------------
 
 Right now the framework is very simple; it just has utility functions
-to time widget creation, drawing, and destruction.  To run such a
-test, you use the functions in timers.h.  You can call this:
+to time widget creation, mapping, exposure, and destruction.  To run
+such a test, you use the GtkWidgetProfiler object in
+gtkwidgetprofiler.h.
 
-  timer_time_widget (create_func, report_func, user_data);
+The gtk_widget_profiler_profile_boot() function will emit the
+"create-widget" signal so that you can create your widget for
+testing.  It will then take timings for the widget, and emit the
+"report" signal as appropriate.
 
-You must provide the create_funcn and report_func callbacks.
+The "create-widget" signal:
 
-The create_func:
+  The handler has this form:
 
-  This simply creates a toplevel window with some widgets inside it.
-  It is important that you do not show any of the widgets; the
-  framework will call gtk_widget_show_all() on the toplevel window
-  automatically at the right time.
+    GtkWidget *create_widget_callback (GtkWidgetProfiler *profiler, 
+                                      gpointer user_data);
 
-The report_func:
+  You need to create a widget in your handler, and return it.  Do not
+  show the widget; the profiler will do that by itself at the right
+  time, and will actually complain if you show the widget.
 
-  This function will get called when timer_time_widget() reaches an
-  interesting point in the lifecycle of your widget.  See timers.h and
-  the TimerReport enumeration; this is what gets passed as the
-  "report" argument to your report_func.  Right now, your function
-  will be called three times for each call to timer_time_widget():
 
-     1. With report = TIMER_REPORT_WIDGET_CREATION.  A timer gets
-        started right before timer_time_widget() calls create_func,
-        and it gets stopped when your create_func returns.  This
-        measures the time it takes to set up a toplevel window (but
-        not show it).
+The "report" signal:
 
-     2. With report = TIMER_REPORT_WIDGET_SHOW.  A timer gets started
-        right before timer_time_widget() calls gtk_widget_show_all()
-        on your toplevel window, and it gets stopped when the window
-        has been fully shown and painted to the screen.
+  This function will get called when the profiler wants to report that
+  it finished timing an important stage in the lifecycle of your
+  widget.  The handler has this form:
 
-     3. With report = TIMER_REPORT_WIDGET_DESTRUCTION.  A timer gets
-        started right before timer_time_widget() calls
-        gtk_widget_destroy() on your toplevel window, and it gets
-        stopped when gtk_widget_destroy() returns.
+    void report_callback (GtkWidgetProfiler      *profiler,
+                         GtkWidgetProfilerReport report,
+                         GtkWidget              *widget,
+                         gdouble                 elapsed,
+                         gpointer                user_data);
 
-As a very basic example of using timer_time_widget(), you can use
-something like this:
+  The "report" argument tells you what happened to your widget:
+
+    GTK_WIDGET_PROFILER_REPORT_CREATE.  A timer gets started right
+    before the profiler emits the "create-widget" signal,, and it gets
+    stopped when your callback returns with the new widget.  This
+    measures the time it takes to set up your widget, but not show it.
+
+    GTK_WIDGET_PROFILER_REPORT_MAP.  A timer gets started right before
+    the profiler calls gtk_widget_show_all() on your widget, and it
+    gets stopped when the the widget has been mapped.
+
+    GTK_WIDGET_PROFILER_REPORT_EXPOSE.  A timer gets started right before
+    the profiler starts waiting for GTK+ and the X server to finish
+    painting your widget, and it gets stopped when the widget is fully
+    painted to the screen.
+
+    GTK_WIDGET_PROFILER_REPORT_DESTROY.  A timer gets started right
+    before the profiler calls gtk_widget_destroy() on your widget, and
+    it gets stopped when gtk_widget_destroy() returns.
+
+As a very basic example of using GtkWidgetProfiler is this:
 
 ----------------------------------------------------------------------
 #include <stdio.h>
 #include <gtk/gtk.h>
-#include "timers.h"
-
-#define ITERS 20
+#include "gtkwidgetprofiler.h"
 
 static GtkWidget *
-create_cb (gpointer data)
+create_widget_cb (GtkWidgetProfiler *profiler, gpointer data)
 {
   GtkWidget *window;
 
@@ -73,47 +85,66 @@ create_cb (gpointer data)
 }
 
 static void
-report_cb (TimerReport report, gdouble elapsed, gpointer data)
+report_cb (GtkWidgetProfiler *profiler, GtkWidgetProfilerReport report, GtkWidget *widget, gdouble elapsed, gpointer data)
 {
   const char *type;
 
   switch (report) {
-  case TIMER_REPORT_WIDGET_CREATION:
+  case GTK_WIDGET_PROFILER_REPORT_CREATE:
     type = "widget creation";
     break;
 
-  case TIMER_REPORT_WIDGET_SHOW:
-    type = "widget show";
+  case GTK_WIDGET_PROFILER_REPORT_MAP:
+    type = "widget map";
     break;
 
-  case TIMER_REPORT_WIDGET_DESTRUCTION:
+  case GTK_WIDGET_PROFILER_REPORT_EXPOSE:
+    type = "widget expose";
+    break;
+
+  case GTK_WIDGET_PROFILER_REPORT_DESTROY:
     type = "widget destruction";
     break;
+
+  default:
+    g_assert_not_reached ();
+    type = NULL;
   }
 
   fprintf (stderr, "%s: %g sec\n", type, elapsed);
+
+  if (report == GTK_WIDGET_PROFILER_REPORT_DESTROY)
+    fputs ("\n", stderr);
 }
 
 int
 main (int argc, char **argv)
 {
-  int i;
+  GtkWidgetProfiler *profiler;
 
   gtk_init (&argc, &argv);
 
-  for (i = 0; i < ITERS; i++)
-    timer_time_widget (create_cb, report_cb, NULL);
+  profiler = gtk_widget_profiler_new ();
+  g_signal_connect (profiler, "create-widget",
+                   G_CALLBACK (create_widget_cb), NULL);
+  g_signal_connect (profiler, "report",
+                   G_CALLBACK (report_cb), NULL);
+
+  gtk_widget_profiler_set_num_iterations (profiler, 100);
+  gtk_widget_profiler_profile_boot (profiler);
   
   return 0;
-} 
+}
+
 ----------------------------------------------------------------------
 
 
 Getting meaningful results
 --------------------------
 
-Getting times for widget creation/drawing/destruction is interesting,
-but how do you actually find the places that need optimizing?
+Getting times for widget creation/mapping/exposing/destruction is
+interesting, but how do you actually find the places that need
+optimizing?
 
 Why, you run the tests under a profiler, of course.
 
index 6230c91dc2779cf2e1cbc16745186c0be4700b8b..cb239abc94746251617fe72fc06b507ac49080e0 100644 (file)
@@ -13,6 +13,8 @@
 #include <string.h>
 #include <gtk/gtk.h>
 
+#include "widgets.h"
+
 static void
 quit_cb (GtkWidget *widget, gpointer data)
 {
@@ -150,230 +152,38 @@ toolbar_new (GtkUIManager *ui)
   return gtk_ui_manager_get_widget (ui, "/MainToolbar");
 }
 
-struct row_data {
-  char *stock_id;
-  char *text1;
-  char *text2;
-};
-
-static struct row_data row_data[] = {
-  { GTK_STOCK_NEW,             "First",                "Here bygynneth the Book of the tales of Caunterbury." },
-  { GTK_STOCK_OPEN,            "Second",               "Whan that Aprille, with hise shoures soote," },
-  { GTK_STOCK_ABOUT,           "Third",                "The droghte of March hath perced to the roote" },
-  { GTK_STOCK_ADD,             "Fourth",               "And bathed every veyne in swich licour," },
-  { GTK_STOCK_APPLY,           "Fifth",                "Of which vertu engendred is the flour;" },
-  { GTK_STOCK_BOLD,            "Sixth",                "Whan Zephirus eek with his swete breeth" },
-  { GTK_STOCK_CANCEL,          "Seventh",              "Inspired hath in every holt and heeth" },
-  { GTK_STOCK_CDROM,           "Eighth",               "The tendre croppes, and the yonge sonne" },
-  { GTK_STOCK_CLEAR,           "Ninth",                "Hath in the Ram his halfe cours yronne," },
-  { GTK_STOCK_CLOSE,           "Tenth",                "And smale foweles maken melodye," },
-  { GTK_STOCK_COLOR_PICKER,    "Eleventh",             "That slepen al the nyght with open eye-" },
-  { GTK_STOCK_CONVERT,         "Twelfth",              "So priketh hem Nature in hir corages-" },
-  { GTK_STOCK_CONNECT,         "Thirteenth",           "Thanne longen folk to goon on pilgrimages" },
-  { GTK_STOCK_COPY,            "Fourteenth",           "And palmeres for to seken straunge strondes" },
-  { GTK_STOCK_CUT,             "Fifteenth",            "To ferne halwes, kowthe in sondry londes;" },
-  { GTK_STOCK_DELETE,          "Sixteenth",            "And specially, from every shires ende" },
-  { GTK_STOCK_DIRECTORY,       "Seventeenth",          "Of Engelond, to Caunturbury they wende," },
-  { GTK_STOCK_DISCONNECT,      "Eighteenth",           "The hooly blisful martir for the seke" },
-  { GTK_STOCK_EDIT,            "Nineteenth",           "That hem hath holpen, whan that they were seeke." },
-  { GTK_STOCK_EXECUTE,         "Twentieth",            "Bifil that in that seson, on a day," },
-  { GTK_STOCK_FILE,            "Twenty-first",         "In Southwerk at the Tabard as I lay," },
-  { GTK_STOCK_FIND,            "Twenty-second",        "Redy to wenden on my pilgrymage" },
-  { GTK_STOCK_FIND_AND_REPLACE,        "Twenty-third",         "To Caunterbury, with ful devout corage," },
-  { GTK_STOCK_FLOPPY,          "Twenty-fourth",        "At nyght were come into that hostelrye" },
-  { GTK_STOCK_FULLSCREEN,      "Twenty-fifth",         "Wel nyne and twenty in a compaignye" },
-  { GTK_STOCK_GOTO_BOTTOM,     "Twenty-sixth",         "Of sondry folk, by aventure yfalle" },
-};
-
-static GtkTreeModel *
-tree_model_new (void)
-{
-  GtkListStore *list;
-  int i;
-
-  list = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
-
-  for (i = 0; i < G_N_ELEMENTS (row_data); i++)
-    {
-      GtkTreeIter iter;
-
-      gtk_list_store_append (list, &iter);
-      gtk_list_store_set (list,
-                         &iter,
-                         0, row_data[i].stock_id,
-                         1, row_data[i].text1,
-                         2, row_data[i].text2,
-                         -1);
-    }
-
-  return GTK_TREE_MODEL (list);
-}
-
 static GtkWidget *
-tree_view_new (void)
+drawing_area_new (void)
 {
-  GtkWidget *sw;
-  GtkWidget *tree;
-  GtkTreeModel *model;
-  GtkTreeViewColumn *column;
-
-  sw = gtk_scrolled_window_new (NULL, NULL);
-
-  model = tree_model_new ();
-  tree = gtk_tree_view_new_with_model (model);
-  g_object_unref (model);
-
-  gtk_widget_set_size_request (tree, 300, 100);
-
-  column = gtk_tree_view_column_new_with_attributes ("Icon",
-                                                    gtk_cell_renderer_pixbuf_new (),
-                                                    "stock-id", 0,
-                                                    NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
-  column = gtk_tree_view_column_new_with_attributes ("Index",
-                                                    gtk_cell_renderer_text_new (),
-                                                    "text", 1,
-                                                    NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
-  column = gtk_tree_view_column_new_with_attributes ("Canterbury Tales",
-                                                    gtk_cell_renderer_text_new (),
-                                                    "text", 2,
-                                                    NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
-  gtk_container_add (GTK_CONTAINER (sw), tree);
-
-  return sw;
-}
-
-static GtkWidget *
-left_pane_new (void)
-{
-  return tree_view_new ();
-}
+  GtkWidget *darea;
 
-static GtkWidget *
-text_view_new (void)
-{
-  GtkWidget *sw;
-  GtkWidget *text_view;
-  GtkTextBuffer *buffer;
-
-  sw = gtk_scrolled_window_new (NULL, NULL);
-
-  text_view = gtk_text_view_new ();
-  gtk_widget_set_size_request (text_view, 400, 300);
-  gtk_container_add (GTK_CONTAINER (sw), text_view);
-
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
-
-  gtk_text_buffer_set_text (buffer,
-                           "In felaweshipe, and pilgrimes were they alle,\n"
-                           "That toward Caunterbury wolden ryde.\n"
-                           "The chambres and the stables weren wyde,\n"
-                           "And wel we weren esed atte beste;\n"
-                           "And shortly, whan the sonne was to reste,\n"
-                           "\n"
-                           "So hadde I spoken with hem everychon \n"
-                           "That I was of hir felaweshipe anon, \n"
-                           "And made forward erly for to ryse \n"
-                           "To take our wey, ther as I yow devyse. \n"
-                           "   But nathelees, whil I have tyme and space, \n"
-                           " \n"
-                           "Er that I ferther in this tale pace, \n"
-                           "Me thynketh it acordaunt to resoun \n"
-                           "To telle yow al the condicioun \n"
-                           "Of ech of hem, so as it semed me, \n"
-                           "And whiche they weren, and of what degree, \n"
-                           " \n"
-                           "And eek in what array that they were inne; \n"
-                           "And at a knyght than wol I first bigynne. \n"
-                           "   A knyght ther was, and that a worthy man, \n"
-                           "That fro the tyme that he first bigan \n"
-                           "To riden out, he loved chivalrie, \n"
-                           " \n"
-                           "Trouthe and honour, fredom and curteisie. \n"
-                           "Ful worthy was he in his lordes werre, \n"
-                           " \n"
-                           "And therto hadde he riden, no man ferre, \n"
-                           "As wel in Cristendom as in Hethenesse, \n"
-                           "And evere honoured for his worthynesse. \n"
-                           " \n"
-                           "   At Alisaundre he was, whan it was wonne; \n"
-                           "Ful ofte tyme he hadde the bord bigonne \n"
-                           "Aboven alle nacions in Pruce; \n"
-                           "In Lettow hadde he reysed, and in Ruce, \n"
-                           "No cristen man so ofte of his degree. \n",
-                           -1);
-
-  return sw;
+  darea = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (darea, 640, 480);
+  return darea;
 }
 
 static GtkWidget *
-upper_right_new (void)
+content_area_new (void)
 {
   GtkWidget *notebook;
 
   notebook = gtk_notebook_new ();
 
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
-                           text_view_new (),
+                           drawing_area_new (),
                            gtk_label_new ("First"));
 
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
-                           text_view_new (),
+                           drawing_area_new (),
                            gtk_label_new ("Second"));
 
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
-                           text_view_new (),
+                           drawing_area_new (),
                            gtk_label_new ("Third"));
 
   return notebook;
 }
 
-static GtkWidget *
-lower_right_new (void)
-{
-  return tree_view_new ();
-}
-
-static GtkWidget *
-right_pane_new (void)
-{
-  GtkWidget *paned;
-  GtkWidget *upper_right;
-  GtkWidget *lower_right;
-
-  paned = gtk_vpaned_new ();
-
-  upper_right = upper_right_new ();
-  gtk_paned_pack1 (GTK_PANED (paned), upper_right, TRUE, TRUE);
-
-  lower_right = lower_right_new ();
-  gtk_paned_pack2 (GTK_PANED (paned), lower_right, TRUE, TRUE);
-
-  return paned;
-}
-
-static GtkWidget *
-content_area_new (void)
-{
-  GtkWidget *hpaned;
-  GtkWidget *left, *right;
-
-  hpaned = gtk_hpaned_new ();
-
-  left = left_pane_new ();
-  gtk_paned_pack1 (GTK_PANED (hpaned), left, TRUE, TRUE);
-
-  right = right_pane_new ();
-  gtk_paned_pack2 (GTK_PANED (hpaned), right, TRUE, TRUE);
-
-  return hpaned;
-}
-
 static GtkWidget *
 status_bar_new (void)
 {
@@ -417,7 +227,7 @@ appwindow_new (void)
   gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
 
   widget = status_bar_new ();
-  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+  gtk_box_pack_end (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
 
   return window;
 }
diff --git a/perf/appwindow.h b/perf/appwindow.h
deleted file mode 100644 (file)
index 1975fe0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <gtk/gtkwidget.h>
-
-GtkWidget *appwindow_new (void);
diff --git a/perf/gtkwidgetprofiler.c b/perf/gtkwidgetprofiler.c
new file mode 100644 (file)
index 0000000..01ae842
--- /dev/null
@@ -0,0 +1,377 @@
+#include "config.h"
+#include <string.h>
+#include "gtkwidgetprofiler.h"
+#include "marshalers.h"
+#include "typebuiltins.h"
+
+typedef enum {
+  STATE_NOT_CREATED,
+  STATE_INSTRUMENTED_NOT_MAPPED,
+  STATE_INSTRUMENTED_MAPPED
+} State;
+
+struct _GtkWidgetProfilerPrivate {
+  State state;
+
+  GtkWidget *profiled_widget;
+  GtkWidget *toplevel;
+
+  int n_iterations;
+
+  GTimer *timer;
+
+  gulong toplevel_expose_event_id;
+  gulong toplevel_property_notify_event_id;
+
+  GdkAtom profiler_atom;
+
+  guint profiling : 1;
+};
+
+G_DEFINE_TYPE (GtkWidgetProfiler, gtk_widget_profiler, G_TYPE_OBJECT);
+
+static void gtk_widget_profiler_finalize (GObject *object);
+
+enum {
+  CREATE_WIDGET,
+  REPORT,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+gtk_widget_profiler_class_init (GtkWidgetProfilerClass *class)
+{
+  GObjectClass *object_class;
+
+  object_class = (GObjectClass *) class;
+
+  signals[CREATE_WIDGET] =
+    g_signal_new ("create-widget",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkWidgetProfilerClass, create_widget),
+                 NULL, NULL,
+                 _gtk_marshal_OBJECT__VOID,
+                 G_TYPE_OBJECT, 0);
+
+  signals[REPORT] =
+    g_signal_new ("report",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (GtkWidgetProfilerClass, report),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__ENUM_OBJECT_DOUBLE,
+                 G_TYPE_NONE, 3,
+                 GTK_TYPE_WIDGET_PROFILER_REPORT,
+                 G_TYPE_OBJECT,
+                 G_TYPE_DOUBLE);
+
+  object_class->finalize = gtk_widget_profiler_finalize;
+}
+
+static void
+gtk_widget_profiler_init (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+
+  priv = g_new0 (GtkWidgetProfilerPrivate, 1);
+  profiler->priv = priv;
+
+  priv->state = STATE_NOT_CREATED;
+  priv->n_iterations = 1;
+
+  priv->timer = g_timer_new ();
+
+  priv->profiler_atom = gdk_atom_intern ("GtkWidgetProfiler", FALSE);
+}
+
+static void
+reset_state (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+
+  priv = profiler->priv;
+
+  if (priv->toplevel)
+    {
+      g_signal_handler_disconnect (priv->toplevel, priv->toplevel_expose_event_id);
+      priv->toplevel_expose_event_id = 0;
+
+      g_signal_handler_disconnect (priv->toplevel, priv->toplevel_property_notify_event_id);
+      priv->toplevel_property_notify_event_id = 0;
+
+      gtk_widget_destroy (priv->toplevel);
+      priv->toplevel = NULL;
+      priv->profiled_widget = NULL;
+    }
+
+  priv->state = STATE_NOT_CREATED;
+}
+
+static void
+gtk_widget_profiler_finalize (GObject *object)
+{
+  GtkWidgetProfiler *profiler;
+  GtkWidgetProfilerPrivate *priv;
+
+  profiler = GTK_WIDGET_PROFILER (object);
+  priv = profiler->priv;
+
+  reset_state (profiler);
+  g_timer_destroy (priv->timer);
+
+  g_free (priv);
+
+  G_OBJECT_CLASS (gtk_widget_profiler_parent_class)->finalize (object);
+}
+
+GtkWidgetProfiler *
+gtk_widget_profiler_new (void)
+{
+  return g_object_new (GTK_TYPE_WIDGET_PROFILER, NULL);
+}
+
+void
+gtk_widget_profiler_set_num_iterations (GtkWidgetProfiler *profiler,
+                                       gint               n_iterations)
+{
+  GtkWidgetProfilerPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WIDGET_PROFILER (profiler));
+  g_return_if_fail (n_iterations > 0);
+
+  priv = profiler->priv;
+  priv->n_iterations = n_iterations;
+}
+
+static void
+report (GtkWidgetProfiler      *profiler,
+       GtkWidgetProfilerReport report,
+       gdouble                 elapsed)
+{
+  GtkWidgetProfilerPrivate *priv;
+
+  priv = profiler->priv;
+
+  g_signal_emit (profiler, signals[REPORT], 0, report, priv->profiled_widget, elapsed);
+}
+
+static GtkWidget *
+create_widget_via_emission (GtkWidgetProfiler *profiler)
+{
+  GtkWidget *widget;
+
+  widget = NULL;
+  g_signal_emit (profiler, signals[CREATE_WIDGET], 0, &widget);
+  if (!widget)
+    g_error ("The profiler emitted the \"create-widget\" signal but the signal handler returned no widget!");
+
+  if (GTK_WIDGET_VISIBLE (widget) || GTK_WIDGET_MAPPED (widget))
+    g_error ("The handler for \"create-widget\" must return an unmapped and unshown widget");
+
+  return widget;
+}
+
+static gboolean
+toplevel_property_notify_event_cb (GtkWidget *widget, GdkEventProperty *event, gpointer data)
+{
+  GtkWidgetProfiler *profiler;
+  GtkWidgetProfilerPrivate *priv;
+  gdouble elapsed;
+
+  profiler = GTK_WIDGET_PROFILER (data);
+  priv = profiler->priv;
+
+  if (event->atom != priv->profiler_atom)
+    return FALSE;
+
+  /* Finish timing map/expose */
+
+  elapsed = g_timer_elapsed (priv->timer, NULL);
+  report (profiler, GTK_WIDGET_PROFILER_REPORT_EXPOSE, elapsed);
+
+  gtk_main_quit (); /* This will get us back to the end of profile_map_expose() */
+  return TRUE;
+}
+
+static gboolean
+toplevel_idle_after_expose_cb (gpointer data)
+{
+  GtkWidgetProfiler *profiler;
+  GtkWidgetProfilerPrivate *priv;
+
+  profiler = GTK_WIDGET_PROFILER (data);
+  priv = profiler->priv;
+
+  gdk_property_change (priv->toplevel->window,
+                      priv->profiler_atom,
+                      gdk_atom_intern ("STRING", FALSE),
+                      8,
+                      GDK_PROP_MODE_REPLACE,
+                      "hello",
+                      strlen ("hello"));
+
+  return FALSE;
+}
+
+static gboolean
+toplevel_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+  GtkWidgetProfiler *profiler;
+
+  profiler = GTK_WIDGET_PROFILER (data);
+
+  g_idle_add_full (G_PRIORITY_HIGH, toplevel_idle_after_expose_cb, profiler, NULL);
+  return FALSE;
+}
+
+static void
+instrument_toplevel (GtkWidgetProfiler *profiler,
+                    GtkWidget         *toplevel)
+{
+  GtkWidgetProfilerPrivate *priv;
+
+  priv = profiler->priv;
+
+  priv->toplevel_expose_event_id = g_signal_connect (toplevel, "expose-event",
+                                                    G_CALLBACK (toplevel_expose_event_cb), profiler);
+
+  gtk_widget_add_events (toplevel, GDK_PROPERTY_CHANGE_MASK);
+  priv->toplevel_property_notify_event_id = g_signal_connect (toplevel, "property-notify-event",
+                                                             G_CALLBACK (toplevel_property_notify_event_cb), profiler);
+}
+
+static GtkWidget *
+ensure_and_get_toplevel (GtkWidget *widget)
+{
+       GtkWidget *toplevel;
+       GtkWidget *window;
+
+       toplevel = gtk_widget_get_toplevel (widget);
+       if (GTK_WIDGET_TOPLEVEL (toplevel))
+               return toplevel;
+
+       g_assert (toplevel == widget); /* we don't want extraneous ancestors */
+
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       gtk_container_add (GTK_CONTAINER (window), widget);
+
+       return window;
+}
+
+static GtkWidget *
+get_instrumented_toplevel (GtkWidgetProfiler *profiler,
+                          GtkWidget         *widget)
+{
+  GtkWidget *window;
+
+  window = ensure_and_get_toplevel (widget);
+  instrument_toplevel (profiler, window);
+
+  return window;
+}
+
+static void
+profile_map_expose (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+  gdouble elapsed;
+
+  priv = profiler->priv;
+
+  g_assert (priv->state == STATE_INSTRUMENTED_NOT_MAPPED);
+
+  /* Time map.
+   *
+   * FIXME: we are really timing a show_all(); we don't really wait for all the "map_event" signals
+   * to happen.  Should we rename GTK_WIDGET_PROFILER_REPORT_MAP report to something else?
+   */
+
+  g_timer_reset (priv->timer);
+
+  gtk_widget_show_all (priv->toplevel);
+  priv->state = STATE_INSTRUMENTED_MAPPED;
+
+  elapsed = g_timer_elapsed (priv->timer, NULL);
+  report (profiler, GTK_WIDGET_PROFILER_REPORT_MAP, elapsed);
+
+  /* Time expose; this gets recorded in toplevel_property_notify_event_cb() */
+
+  g_timer_reset (priv->timer);
+  gtk_main ();
+}
+
+static void
+profile_destroy (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+  gdouble elapsed;
+
+  priv = profiler->priv;
+
+  g_assert (priv->state != STATE_NOT_CREATED);
+
+  g_timer_reset (priv->timer);
+  reset_state (profiler);
+  elapsed = g_timer_elapsed (priv->timer, NULL);
+
+  report (profiler, GTK_WIDGET_PROFILER_REPORT_DESTROY, elapsed);
+}
+
+static void
+profile_boot (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+  gdouble elapsed;
+
+  priv = profiler->priv;
+
+  g_assert (priv->state == STATE_NOT_CREATED);
+
+  /* Time creation */
+
+  g_timer_reset (priv->timer);
+
+  priv->profiled_widget = create_widget_via_emission (profiler);
+  priv->toplevel = get_instrumented_toplevel (profiler, priv->profiled_widget);
+
+  priv->state = STATE_INSTRUMENTED_NOT_MAPPED;
+
+  /* Here we include the time to anchor the widget to a toplevel, if
+   * the toplevel was missing --- hopefully not a too-long extra time.
+   */
+
+  elapsed = g_timer_elapsed (priv->timer, NULL);
+  report (profiler, GTK_WIDGET_PROFILER_REPORT_CREATE, elapsed);
+
+  /* Start timing map/expose */
+
+  profile_map_expose (profiler);
+
+  /* Profile destruction */
+
+  profile_destroy (profiler);
+}
+
+void
+gtk_widget_profiler_profile_boot (GtkWidgetProfiler *profiler)
+{
+  GtkWidgetProfilerPrivate *priv;
+  int i, n;
+
+  g_return_if_fail (GTK_IS_WIDGET_PROFILER (profiler));
+
+  priv = profiler->priv;
+  g_return_if_fail (!priv->profiling);
+
+  reset_state (profiler);
+  priv->profiling = TRUE;
+
+  n = priv->n_iterations;
+  for (i = 0; i < n; i++)
+    profile_boot (profiler);
+
+  priv->profiling = FALSE;
+}
diff --git a/perf/gtkwidgetprofiler.h b/perf/gtkwidgetprofiler.h
new file mode 100644 (file)
index 0000000..62d19c8
--- /dev/null
@@ -0,0 +1,58 @@
+#include <gtk/gtk.h>
+
+#ifndef GTK_WIDGET_PROFILER_H
+#define GTK_WIDGET_PROFILER_H
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_WIDGET_PROFILER               (gtk_widget_profiler_get_type ())
+#define GTK_WIDGET_PROFILER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WIDGET_PROFILER, GtkWidgetProfiler))
+#define GTK_WIDGET_PROFILER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WIDGET_PROFILER, GtkWidgetProfilerClass))
+#define GTK_IS_WIDGET_PROFILER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WIDGET_PROFILER))
+#define GTK_IS_WIDGET_PROFILER_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WIDGET_PROFILER))
+#define GTK_WIDGET_PROFILER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WIDGET_PROFILER, GtkWidgetProfilerClass))
+
+typedef enum
+{
+  GTK_WIDGET_PROFILER_REPORT_CREATE,
+  GTK_WIDGET_PROFILER_REPORT_MAP,
+  GTK_WIDGET_PROFILER_REPORT_EXPOSE,
+  GTK_WIDGET_PROFILER_REPORT_DESTROY
+} GtkWidgetProfilerReport;
+
+typedef struct _GtkWidgetProfiler GtkWidgetProfiler;
+typedef struct _GtkWidgetProfilerClass GtkWidgetProfilerClass;
+typedef struct _GtkWidgetProfilerPrivate GtkWidgetProfilerPrivate;
+
+struct _GtkWidgetProfiler {
+       GObject object;
+
+       GtkWidgetProfilerPrivate *priv;
+};
+
+struct _GtkWidgetProfilerClass {
+       GObjectClass parent_class;
+
+       /* signals */
+
+       GtkWidget *(* create_widget) (GtkWidgetProfiler *profiler);
+
+       void (* report) (GtkWidgetProfiler      *profiler,
+                        GtkWidgetProfilerReport report,
+                        GtkWidget              *widget,
+                        gdouble                 elapsed);
+};
+
+GType gtk_widget_profiler_get_type (void) G_GNUC_CONST;
+
+GtkWidgetProfiler *gtk_widget_profiler_new ();
+
+void gtk_widget_profiler_set_num_iterations (GtkWidgetProfiler *profiler,
+                                            gint               n_iterations);
+
+void gtk_widget_profiler_profile_boot (GtkWidgetProfiler *profiler);
+
+
+G_END_DECLS
+
+#endif
index cbd8ded174ee8df59e06dff9017206e6d4838736..303775249df99877dd27c2e8a0ebe42449e4f310 100644 (file)
@@ -1,31 +1,35 @@
 #include <stdio.h>
 #include <gtk/gtk.h>
-#include "appwindow.h"
-#include "timers.h"
+#include "gtkwidgetprofiler.h"
+#include "widgets.h"
 
-#define ITERS 20
+#define ITERS 10
 
 static GtkWidget *
-create_cb (gpointer data)
+create_widget_cb (GtkWidgetProfiler *profiler, gpointer data)
 {
   return appwindow_new ();
 }
 
 static void
-report_cb (TimerReport report, gdouble elapsed, gpointer data)
+report_cb (GtkWidgetProfiler *profiler, GtkWidgetProfilerReport report, GtkWidget *widget, gdouble elapsed, gpointer data)
 {
   const char *type;
 
   switch (report) {
-  case TIMER_REPORT_WIDGET_CREATION:
+  case GTK_WIDGET_PROFILER_REPORT_CREATE:
     type = "widget creation";
     break;
 
-  case TIMER_REPORT_WIDGET_SHOW:
-    type = "widget show";
+  case GTK_WIDGET_PROFILER_REPORT_MAP:
+    type = "widget map";
     break;
 
-  case TIMER_REPORT_WIDGET_DESTRUCTION:
+  case GTK_WIDGET_PROFILER_REPORT_EXPOSE:
+    type = "widget expose";
+    break;
+
+  case GTK_WIDGET_PROFILER_REPORT_DESTROY:
     type = "widget destruction";
     break;
 
@@ -36,19 +40,25 @@ report_cb (TimerReport report, gdouble elapsed, gpointer data)
 
   fprintf (stderr, "%s: %g sec\n", type, elapsed);
 
-  if (report == TIMER_REPORT_WIDGET_DESTRUCTION)
+  if (report == GTK_WIDGET_PROFILER_REPORT_DESTROY)
     fputs ("\n", stderr);
 }
 
 int
 main (int argc, char **argv)
 {
-  int i;
+  GtkWidgetProfiler *profiler;
 
   gtk_init (&argc, &argv);
 
-  for (i = 0; i < ITERS; i++)
-    timer_time_widget (create_cb, report_cb, NULL);
+  profiler = gtk_widget_profiler_new ();
+  g_signal_connect (profiler, "create-widget",
+                   G_CALLBACK (create_widget_cb), NULL);
+  g_signal_connect (profiler, "report",
+                   G_CALLBACK (report_cb), NULL);
+
+  gtk_widget_profiler_set_num_iterations (profiler, ITERS);
+  gtk_widget_profiler_profile_boot (profiler);
   
   return 0;
 }
diff --git a/perf/marshalers.list b/perf/marshalers.list
new file mode 100644 (file)
index 0000000..413f248
--- /dev/null
@@ -0,0 +1,2 @@
+OBJECT:VOID
+VOID:ENUM,OBJECT,DOUBLE
diff --git a/perf/textview.c b/perf/textview.c
new file mode 100644 (file)
index 0000000..0590c8a
--- /dev/null
@@ -0,0 +1,60 @@
+#include <gtk/gtk.h>
+#include "widgets.h"
+
+GtkWidget *
+text_view_new (void)
+{
+  GtkWidget *sw;
+  GtkWidget *text_view;
+  GtkTextBuffer *buffer;
+
+  sw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+
+  text_view = gtk_text_view_new ();
+  gtk_widget_set_size_request (text_view, 400, 300);
+  gtk_container_add (GTK_CONTAINER (sw), text_view);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+  gtk_text_buffer_set_text (buffer,
+                           "In felaweshipe, and pilgrimes were they alle,\n"
+                           "That toward Caunterbury wolden ryde.\n"
+                           "The chambres and the stables weren wyde,\n"
+                           "And wel we weren esed atte beste;\n"
+                           "And shortly, whan the sonne was to reste,\n"
+                           "\n"
+                           "So hadde I spoken with hem everychon \n"
+                           "That I was of hir felaweshipe anon, \n"
+                           "And made forward erly for to ryse \n"
+                           "To take our wey, ther as I yow devyse. \n"
+                           "   But nathelees, whil I have tyme and space, \n"
+                           " \n"
+                           "Er that I ferther in this tale pace, \n"
+                           "Me thynketh it acordaunt to resoun \n"
+                           "To telle yow al the condicioun \n"
+                           "Of ech of hem, so as it semed me, \n"
+                           "And whiche they weren, and of what degree, \n"
+                           " \n"
+                           "And eek in what array that they were inne; \n"
+                           "And at a knyght than wol I first bigynne. \n"
+                           "   A knyght ther was, and that a worthy man, \n"
+                           "That fro the tyme that he first bigan \n"
+                           "To riden out, he loved chivalrie, \n"
+                           " \n"
+                           "Trouthe and honour, fredom and curteisie. \n"
+                           "Ful worthy was he in his lordes werre, \n"
+                           " \n"
+                           "And therto hadde he riden, no man ferre, \n"
+                           "As wel in Cristendom as in Hethenesse, \n"
+                           "And evere honoured for his worthynesse. \n"
+                           " \n"
+                           "   At Alisaundre he was, whan it was wonne; \n"
+                           "Ful ofte tyme he hadde the bord bigonne \n"
+                           "Aboven alle nacions in Pruce; \n"
+                           "In Lettow hadde he reysed, and in Ruce, \n"
+                           "No cristen man so ofte of his degree. \n",
+                           -1);
+
+  return sw;
+}
diff --git a/perf/timers.c b/perf/timers.c
deleted file mode 100644 (file)
index 042c66b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Utility functions for timing widgets
- *
- * Authors:
- *   Federico Mena-Quintero <federico@novell.com>
- *
- * To measure how long it takes to fully map and expose a toplevel window, we
- * use a trick which Owen Taylor described on IRC one day:
- *
- *   1. Start a timer.
- *   2. Call gtk_widget_show_all() on the toplevel window.
- *   3. In the expose_event handler of the window, queue an idle handler with
- *      G_PRIORITY_HIGH.
- *   4. In the idle handler, change a property on the toplevel window.
- *   5. In the property_notify_event handler, stop the timer.
- */
-
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtkmain.h>
-#include "timers.h"
-
-struct timer_closure
-{
-  GTimer *timer;
-  GtkWidget *widget;
-  TimerReportFunc report_func;
-  gpointer user_data;
-};
-
-static gboolean
-widget_property_notify_event_cb (GtkWidget *widget, GdkEventProperty *event, gpointer data)
-{
-  struct timer_closure *closure;
-  gdouble elapsed;
-
-  closure = data;
-
-  if (event->atom != gdk_atom_intern ("window_property_change", FALSE))
-    return FALSE;
-
-  /* Finish timing map/expose */
-
-  elapsed = g_timer_elapsed (closure->timer, NULL);
-  (* closure->report_func) (TIMER_REPORT_WIDGET_SHOW, elapsed, closure->user_data);
-
-  /* Time destruction */
-  
-  g_timer_reset (closure->timer);
-  gtk_widget_destroy (widget);
-  elapsed = g_timer_elapsed (closure->timer, NULL);
-  (* closure->report_func) (TIMER_REPORT_WIDGET_DESTRUCTION, elapsed, closure->user_data);
-
-  gtk_main_quit (); /* This will get us back to the end of timer_time_widget() */
-  return TRUE;
-}
-
-static gboolean
-idle_after_expose_cb (gpointer data)
-{
-  struct timer_closure *closure;
-
-  closure = data;
-
-  gdk_property_change (closure->widget->window,
-                      gdk_atom_intern ("window_property_change", FALSE),
-                      gdk_atom_intern ("STRING", FALSE),
-                      8,
-                      GDK_PROP_MODE_REPLACE,
-                      "hello",
-                      strlen ("hello"));
-
-  return FALSE;
-}
-
-static gboolean
-widget_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
-{
-  struct timer_closure *closure;
-
-  closure = data;
-
-  g_idle_add_full (G_PRIORITY_HIGH, idle_after_expose_cb, closure, NULL);
-  return FALSE;
-}
-
-static void
-instrument_widget (GtkWidget *widget,
-                  struct timer_closure *closure)
-{
-  g_signal_connect (widget, "expose-event",
-                   G_CALLBACK (widget_expose_event_cb), closure);
-
-  gtk_widget_add_events (widget, GDK_PROPERTY_CHANGE_MASK);
-  g_signal_connect (widget, "property-notify-event",
-                   G_CALLBACK (widget_property_notify_event_cb), closure);
-}
-
-void
-timer_time_widget (TimerWidgetCreateFunc create_func,
-                  TimerReportFunc       report_func,
-                  gpointer              user_data)
-{
-  GTimer *timer;
-  GtkWidget *widget;
-  gdouble elapsed;
-  struct timer_closure closure;
-
-  g_assert (create_func != NULL);
-  g_assert (report_func != NULL);
-
-  /* Time creation */
-
-  timer = g_timer_new ();
-  widget = (* create_func) (user_data);
-  g_assert (widget != NULL);
-  g_assert (!GTK_WIDGET_VISIBLE (widget) && !GTK_WIDGET_MAPPED (widget));
-  elapsed = g_timer_elapsed (timer, NULL);
-
-  (* report_func) (TIMER_REPORT_WIDGET_CREATION, elapsed, user_data);
-
-  /* Start timing map/expose */
-
-  closure.timer = timer;
-  closure.widget = widget;
-  closure.report_func = report_func;
-  closure.user_data = user_data;
-  instrument_widget (widget, &closure);
-
-  g_timer_reset (timer);
-  gtk_widget_show_all (widget);
-  gtk_main ();
-
-  /* Expose time and destruction time get recorded in widget_property_notify_event_cb() */
-}
diff --git a/perf/timers.h b/perf/timers.h
deleted file mode 100644 (file)
index d00d6cc..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <gtk/gtkwidget.h>
-
-typedef enum
-{
-  TIMER_REPORT_WIDGET_CREATION,
-  TIMER_REPORT_WIDGET_SHOW,
-  TIMER_REPORT_WIDGET_DESTRUCTION
-} TimerReport;
-
-typedef GtkWidget *(* TimerWidgetCreateFunc) (gpointer user_data);
-
-typedef void (* TimerReportFunc) (TimerReport report, gdouble elapsed, gpointer user_data);
-
-void timer_time_widget (TimerWidgetCreateFunc create_func,
-                       TimerReportFunc       report_func,
-                       gpointer              user_data);
diff --git a/perf/treeview.c b/perf/treeview.c
new file mode 100644 (file)
index 0000000..461a67a
--- /dev/null
@@ -0,0 +1,101 @@
+#include <gtk/gtk.h>
+#include "widgets.h"
+
+struct row_data {
+  char *stock_id;
+  char *text1;
+  char *text2;
+};
+
+static struct row_data row_data[] = {
+  { GTK_STOCK_NEW,             "First",                "Here bygynneth the Book of the tales of Caunterbury." },
+  { GTK_STOCK_OPEN,            "Second",               "Whan that Aprille, with hise shoures soote," },
+  { GTK_STOCK_ABOUT,           "Third",                "The droghte of March hath perced to the roote" },
+  { GTK_STOCK_ADD,             "Fourth",               "And bathed every veyne in swich licour," },
+  { GTK_STOCK_APPLY,           "Fifth",                "Of which vertu engendred is the flour;" },
+  { GTK_STOCK_BOLD,            "Sixth",                "Whan Zephirus eek with his swete breeth" },
+  { GTK_STOCK_CANCEL,          "Seventh",              "Inspired hath in every holt and heeth" },
+  { GTK_STOCK_CDROM,           "Eighth",               "The tendre croppes, and the yonge sonne" },
+  { GTK_STOCK_CLEAR,           "Ninth",                "Hath in the Ram his halfe cours yronne," },
+  { GTK_STOCK_CLOSE,           "Tenth",                "And smale foweles maken melodye," },
+  { GTK_STOCK_COLOR_PICKER,    "Eleventh",             "That slepen al the nyght with open eye-" },
+  { GTK_STOCK_CONVERT,         "Twelfth",              "So priketh hem Nature in hir corages-" },
+  { GTK_STOCK_CONNECT,         "Thirteenth",           "Thanne longen folk to goon on pilgrimages" },
+  { GTK_STOCK_COPY,            "Fourteenth",           "And palmeres for to seken straunge strondes" },
+  { GTK_STOCK_CUT,             "Fifteenth",            "To ferne halwes, kowthe in sondry londes;" },
+  { GTK_STOCK_DELETE,          "Sixteenth",            "And specially, from every shires ende" },
+  { GTK_STOCK_DIRECTORY,       "Seventeenth",          "Of Engelond, to Caunturbury they wende," },
+  { GTK_STOCK_DISCONNECT,      "Eighteenth",           "The hooly blisful martir for the seke" },
+  { GTK_STOCK_EDIT,            "Nineteenth",           "That hem hath holpen, whan that they were seeke." },
+  { GTK_STOCK_EXECUTE,         "Twentieth",            "Bifil that in that seson, on a day," },
+  { GTK_STOCK_FILE,            "Twenty-first",         "In Southwerk at the Tabard as I lay," },
+  { GTK_STOCK_FIND,            "Twenty-second",        "Redy to wenden on my pilgrymage" },
+  { GTK_STOCK_FIND_AND_REPLACE,        "Twenty-third",         "To Caunterbury, with ful devout corage," },
+  { GTK_STOCK_FLOPPY,          "Twenty-fourth",        "At nyght were come into that hostelrye" },
+  { GTK_STOCK_FULLSCREEN,      "Twenty-fifth",         "Wel nyne and twenty in a compaignye" },
+  { GTK_STOCK_GOTO_BOTTOM,     "Twenty-sixth",         "Of sondry folk, by aventure yfalle" },
+};
+
+static GtkTreeModel *
+tree_model_new (void)
+{
+  GtkListStore *list;
+  int i;
+
+  list = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+  for (i = 0; i < G_N_ELEMENTS (row_data); i++)
+    {
+      GtkTreeIter iter;
+
+      gtk_list_store_append (list, &iter);
+      gtk_list_store_set (list,
+                         &iter,
+                         0, row_data[i].stock_id,
+                         1, row_data[i].text1,
+                         2, row_data[i].text2,
+                         -1);
+    }
+
+  return GTK_TREE_MODEL (list);
+}
+
+GtkWidget *
+tree_view_new (void)
+{
+  GtkWidget *sw;
+  GtkWidget *tree;
+  GtkTreeModel *model;
+  GtkTreeViewColumn *column;
+
+  sw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+
+  model = tree_model_new ();
+  tree = gtk_tree_view_new_with_model (model);
+  g_object_unref (model);
+
+  gtk_widget_set_size_request (tree, 300, 100);
+
+  column = gtk_tree_view_column_new_with_attributes ("Icon",
+                                                    gtk_cell_renderer_pixbuf_new (),
+                                                    "stock-id", 0,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+  column = gtk_tree_view_column_new_with_attributes ("Index",
+                                                    gtk_cell_renderer_text_new (),
+                                                    "text", 1,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+  column = gtk_tree_view_column_new_with_attributes ("Canterbury Tales",
+                                                    gtk_cell_renderer_text_new (),
+                                                    "text", 2,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+  gtk_container_add (GTK_CONTAINER (sw), tree);
+
+  return sw;
+}
diff --git a/perf/widgets.h b/perf/widgets.h
new file mode 100644 (file)
index 0000000..349b131
--- /dev/null
@@ -0,0 +1,7 @@
+#include <gtk/gtkwidget.h>
+
+GtkWidget *appwindow_new (void);
+
+GtkWidget *text_view_new (void);
+
+GtkWidget *tree_view_new (void);