widget: Add draw signal

For now, the draw signal is emitted by default from the expose event, so
widgets can chose to either implement the expose event or the draw
function.
This is for the transitional period from expose event to draw signal.

Note that for now subclasses can only implement the draw function when
none of their parents implemented the expose event.
This commit is contained in:
Benjamin Otte 2010-09-01 20:13:44 +02:00
parent 9507670db4
commit 7108586b16
2 changed files with 93 additions and 1 deletions

View File

@ -49,6 +49,7 @@
#include "gdk/gdkprivate.h" /* Used in gtk_reset_shapes_recurse to avoid copy */ #include "gdk/gdkprivate.h" /* Used in gtk_reset_shapes_recurse to avoid copy */
#include <gobject/gvaluecollector.h> #include <gobject/gvaluecollector.h>
#include <gobject/gobjectnotifyqueue.c> #include <gobject/gobjectnotifyqueue.c>
#include <cairo-gobject.h>
#include "gdk/gdkkeysyms.h" #include "gdk/gdkkeysyms.h"
#include "gtkaccessible.h" #include "gtkaccessible.h"
#include "gtktooltip.h" #include "gtktooltip.h"
@ -198,6 +199,7 @@ enum {
DIRECTION_CHANGED, DIRECTION_CHANGED,
GRAB_NOTIFY, GRAB_NOTIFY,
CHILD_NOTIFY, CHILD_NOTIFY,
DRAW,
MNEMONIC_ACTIVATE, MNEMONIC_ACTIVATE,
GRAB_FOCUS, GRAB_FOCUS,
FOCUS, FOCUS,
@ -340,6 +342,8 @@ static gboolean gtk_widget_real_show_help (GtkWidget *widget,
static void gtk_widget_dispatch_child_properties_changed (GtkWidget *object, static void gtk_widget_dispatch_child_properties_changed (GtkWidget *object,
guint n_pspecs, guint n_pspecs,
GParamSpec **pspecs); GParamSpec **pspecs);
static gboolean gtk_widget_real_expose_event (GtkWidget *widget,
GdkEventExpose *event);
static gboolean gtk_widget_real_key_press_event (GtkWidget *widget, static gboolean gtk_widget_real_key_press_event (GtkWidget *widget,
GdkEventKey *event); GdkEventKey *event);
static gboolean gtk_widget_real_key_release_event (GtkWidget *widget, static gboolean gtk_widget_real_key_release_event (GtkWidget *widget,
@ -527,6 +531,32 @@ child_property_notify_dispatcher (GObject *object,
GTK_WIDGET_GET_CLASS (object)->dispatch_child_properties_changed (GTK_WIDGET (object), n_pspecs, pspecs); GTK_WIDGET_GET_CLASS (object)->dispatch_child_properties_changed (GTK_WIDGET (object), n_pspecs, pspecs);
} }
/* We guard against the draw signal callbacks modifying the state of the
* cairo context by surounding it with save/restore.
* Maybe we should also cairo_new_path() just to be sure?
*/
static void
gtk_widget_draw_marshaller (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
cairo_t *cr = g_value_get_boxed (&param_values[1]);
cairo_save (cr);
_gtk_marshal_BOOLEAN__BOXED (closure,
return_value,
n_param_values,
param_values,
invocation_hint,
marshal_data);
cairo_restore (cr);
}
static void static void
gtk_widget_class_init (GtkWidgetClass *klass) gtk_widget_class_init (GtkWidgetClass *klass)
{ {
@ -589,6 +619,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->direction_changed = gtk_widget_real_direction_changed; klass->direction_changed = gtk_widget_real_direction_changed;
klass->grab_notify = NULL; klass->grab_notify = NULL;
klass->child_notify = NULL; klass->child_notify = NULL;
klass->draw = NULL;
klass->mnemonic_activate = gtk_widget_real_mnemonic_activate; klass->mnemonic_activate = gtk_widget_real_mnemonic_activate;
klass->grab_focus = gtk_widget_real_grab_focus; klass->grab_focus = gtk_widget_real_grab_focus;
klass->focus = gtk_widget_real_focus; klass->focus = gtk_widget_real_focus;
@ -598,7 +629,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->motion_notify_event = NULL; klass->motion_notify_event = NULL;
klass->delete_event = NULL; klass->delete_event = NULL;
klass->destroy_event = NULL; klass->destroy_event = NULL;
klass->expose_event = NULL; klass->expose_event = gtk_widget_real_expose_event;
klass->key_press_event = gtk_widget_real_key_press_event; klass->key_press_event = gtk_widget_real_key_press_event;
klass->key_release_event = gtk_widget_real_key_release_event; klass->key_release_event = gtk_widget_real_key_release_event;
klass->enter_notify_event = NULL; klass->enter_notify_event = NULL;
@ -1249,6 +1280,32 @@ gtk_widget_class_init (GtkWidgetClass *klass)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
G_TYPE_PARAM); G_TYPE_PARAM);
/**
* GtkWidget::draw:
* @widget: the object which received the signal
* @cr: the cairo context to draw to
* @width: width of the widget
* @height: height of the widget
*
* This signal is emitted when a widget is supposed to render itself.
* The @widget's top left corner must be painted at the origin of
* the passed in context and be sized in the given @width and @height.
*
* Signal handlers connected to this signal can modify the cairo
* context passed as @cr in any way they like and don't need to
* restore it. The signal emission takes care of calling cairo_save()
* before and cairo_restore() after invoking the handler.
*/
widget_signals[DRAW] =
g_signal_new (I_("draw"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkWidgetClass, draw),
_gtk_boolean_handled_accumulator, NULL,
gtk_widget_draw_marshaller,
G_TYPE_BOOLEAN, 1,
CAIRO_GOBJECT_TYPE_CONTEXT);
/** /**
* GtkWidget::mnemonic-activate: * GtkWidget::mnemonic-activate:
* @widget: the object which received the signal. * @widget: the object which received the signal.
@ -5013,6 +5070,36 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget,
return TRUE; return TRUE;
} }
static gboolean
gtk_widget_real_expose_event (GtkWidget *widget,
GdkEventExpose *expose)
{
gboolean result = FALSE;
cairo_t *cr;
if (!gtk_widget_is_drawable (widget))
return FALSE;
cr = gdk_cairo_create (expose->window);
gdk_cairo_region (cr, expose->region);
cairo_clip (cr);
if (!gtk_widget_get_has_window (widget))
{
cairo_translate (cr,
widget->priv->allocation.x,
widget->priv->allocation.y);
}
g_signal_emit (widget, widget_signals[DRAW],
0, cr,
&result);
cairo_destroy (cr);
return result;
}
static gboolean static gboolean
gtk_widget_real_key_press_event (GtkWidget *widget, gtk_widget_real_key_press_event (GtkWidget *widget,
GdkEventKey *event) GdkEventKey *event)

View File

@ -348,6 +348,8 @@ struct _GtkWidgetClass
gboolean was_grabbed); gboolean was_grabbed);
void (* child_notify) (GtkWidget *widget, void (* child_notify) (GtkWidget *widget,
GParamSpec *pspec); GParamSpec *pspec);
gboolean (* draw) (GtkWidget *widget,
cairo_t *cr);
/* Mnemonics */ /* Mnemonics */
gboolean (* mnemonic_activate) (GtkWidget *widget, gboolean (* mnemonic_activate) (GtkWidget *widget,
@ -937,6 +939,9 @@ void gtk_widget_set_has_tooltip (GtkWidget *widget,
gboolean has_tooltip); gboolean has_tooltip);
gboolean gtk_widget_get_has_tooltip (GtkWidget *widget); gboolean gtk_widget_get_has_tooltip (GtkWidget *widget);
gboolean gtk_cairo_should_draw_window (cairo_t *cr,
GdkWindow *window);
GType gtk_requisition_get_type (void) G_GNUC_CONST; GType gtk_requisition_get_type (void) G_GNUC_CONST;
GtkRequisition *gtk_requisition_new (void) G_GNUC_MALLOC; GtkRequisition *gtk_requisition_new (void) G_GNUC_MALLOC;
GtkRequisition *gtk_requisition_copy (const GtkRequisition *requisition); GtkRequisition *gtk_requisition_copy (const GtkRequisition *requisition);