static void hildon_viewport_finalize (GObject *object);
static void hildon_viewport_destroy (GtkObject *object);
-static void hildon_viewport_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void hildon_viewport_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void hildon_viewport_set_scroll_adjustments (HildonViewport *viewport,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment);
+static void hildon_viewport_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void hildon_viewport_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void hildon_viewport_set_scroll_adjustments (HildonViewport *viewport,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
static void hildon_viewport_realize (GtkWidget *widget);
static void hildon_viewport_unrealize (GtkWidget *widget);
static void hildon_viewport_paint (GtkWidget *widget,
GtkAllocation *allocation);
static void hildon_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
gpointer data);
-static void hildon_viewport_style_set (GtkWidget *widget,
- GtkStyle *previous_style);
+static void hildon_viewport_style_set (GtkWidget *widget,
+ GtkStyle *previous_style);
+static void hildon_viewport_paint_offscreen_children (cairo_t *cr,
+ GdkWindow *window,
+ GdkEventExpose *event,
+ gint orig_x,
+ gint orig_y);
+static void hildon_viewport_expose_window (GdkWindow *window);
+
G_DEFINE_TYPE (HildonViewport, hildon_viewport, GTK_TYPE_BIN)
return viewport->shadow_type;
}
+static void
+hildon_viewport_expose_window (GdkWindow *window)
+{
+ GList *l, *children;
+ gpointer user_data;
+ gboolean is_double_buffered;
+ GdkEvent event;
+
+ gdk_window_get_user_data (window, &user_data);
+
+ event.expose.type = GDK_EXPOSE;
+ event.expose.window = g_object_ref (window);
+ event.expose.send_event = FALSE;
+ event.expose.count = 0;
+ event.expose.area.x = 0;
+ event.expose.area.y = 0;
+ gdk_drawable_get_size (GDK_DRAWABLE (window),
+ &event.expose.area.width,
+ &event.expose.area.height);
+ event.expose.region = gdk_region_rectangle (&event.expose.area);
+
+ if (user_data)
+ is_double_buffered = GTK_WIDGET_DOUBLE_BUFFERED (GTK_WIDGET (user_data));
+ else
+ is_double_buffered = FALSE;
+
+ /* If this is not double buffered, force a double buffer so that
+ redirection works. */
+ if (!is_double_buffered)
+ gdk_window_begin_paint_region (window, event.expose.region);
+
+ gtk_main_do_event (&event);
+
+ if (!is_double_buffered)
+ gdk_window_end_paint (window);
+
+ children = gdk_window_peek_children (window);
+ for (l = children; l != NULL; l = l->next)
+ {
+ GdkWindow *child = l->data;
+
+ /* Don't expose input-only windows */
+ if (gdk_drawable_get_depth (GDK_DRAWABLE (child)) != 0)
+ hildon_viewport_expose_window (l->data);
+ }
+}
+
void
hildon_viewport_freeze (HildonViewport *viewport)
{
GtkBin *bin;
GtkWidget *child;
GtkWidget *widget;
+ gint w, h;
+ cairo_t *cr;
+ GdkEvent event;
g_return_if_fail (GTK_WIDGET_REALIZED (viewport));
g_return_if_fail (priv->pixmap == NULL);
bin = GTK_BIN (viewport);
child = gtk_bin_get_child (bin);
- priv->pixmap = gtk_widget_get_snapshot (child, NULL);
+ gdk_drawable_get_size (viewport->bin_window, &w, &h);
-#if 0
- {
- GtkWidget *image;
- GtkWidget *window, *sw;
+ event.expose.type = GDK_EXPOSE;
+ event.expose.window = g_object_ref (viewport->bin_window);
+ event.expose.send_event = FALSE;
+ event.expose.count = 0;
+ event.expose.area.x = 0;
+ event.expose.area.y = 0;
+ event.expose.area.width = w;
+ event.expose.area.height = h;
+ event.expose.region = gdk_region_rectangle (&event.expose.area);
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- sw = gtk_scrolled_window_new (NULL, NULL);
+ /* ensure the children are drawn in their offscreen windows */
+ hildon_viewport_expose_window (viewport->bin_window);
- gtk_widget_realize (window);
+ cr = gdk_cairo_create (viewport->bin_window);
- image = gtk_image_new_from_pixmap (priv->pixmap, NULL);
+ /* blit the children to the bin window */
+ hildon_viewport_paint_offscreen_children (cr,
+ viewport->bin_window,
+ (GdkEventExpose *)&event,
+ 0, 0);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), image);
- gtk_container_add (GTK_CONTAINER (window), sw);
- gtk_widget_show_all (window);
+ g_object_unref (viewport->bin_window);
- gtk_widget_show (image);
- }
-#endif
+ cairo_destroy (cr);
+
+ priv->pixmap = gdk_pixmap_new (viewport->bin_window,
+ w, h, -1);
+
+ /* copy the bin window to a pixmap, consider XCompositeNameWindowPixmap */
+ gdk_draw_drawable (priv->pixmap,
+ widget->style->bg_gc[GTK_STATE_NORMAL],
+ viewport->bin_window,
+ 0, 0, 0, 0, w, h);
gdk_window_hide (viewport->bin_window);
gtk_widget_queue_draw (widget);
widget = GTK_WIDGET (viewport);
- /* leak? */
- g_object_unref (priv->pixmap);
+ if (priv->pixmap) {
+ g_object_unref (priv->pixmap);
- priv->pixmap = NULL;
+ priv->pixmap = NULL;
- new_x = - hadjustment->value;
- new_y = - vadjustment->value;
+ new_x = - hadjustment->value;
+ new_y = - vadjustment->value;
- gdk_window_show (viewport->bin_window);
- gdk_window_move (viewport->bin_window, new_x, new_y);
+ gdk_window_show (viewport->bin_window);
+ gdk_window_move (viewport->bin_window, new_x, new_y);
+ }
}
static void
NULL, widget, "viewportbin",
0, 0, -1, -1);
+ gdk_window_set_composited (viewport->bin_window, TRUE);
+
gdk_window_show (viewport->bin_window);
gdk_window_show (viewport->view_window);
}
}
}
+static void
+hildon_viewport_paint_offscreen_children (cairo_t *cr,
+ GdkWindow *window,
+ GdkEventExpose *event,
+ gint orig_x,
+ gint orig_y)
+{
+ GList *subwindow;
+
+ for (subwindow = gdk_window_peek_children (window);
+ subwindow;
+ subwindow = subwindow->next)
+ {
+ /* avoid input-only windows */
+ if (gdk_drawable_get_depth (GDK_DRAWABLE (subwindow->data)) != 0)
+ {
+ gint x, y, w, h;
+
+ gdk_window_get_position (subwindow->data,
+ &x, &y);
+
+ x += orig_x;
+ y += orig_y;
+
+ gdk_drawable_get_size (subwindow->data, &w, &h);
+
+ /* do not draw the widgets outside the event */
+ if ((x+w < event->area.x) ||
+ (y+h < event->area.y) ||
+ (x > event->area.x+event->area.width) ||
+ (y > event->area.y+event->area.height))
+ continue;
+
+ gdk_cairo_set_source_pixmap (cr, subwindow->data, x, y);
+
+ cairo_rectangle (cr, x, y, w, h);
+
+ cairo_fill (cr);
+
+
+ hildon_viewport_paint_offscreen_children (cr,
+ subwindow->data,
+ event,
+ x, y);
+ }
+ }
+}
+
static gint
hildon_viewport_expose (GtkWidget *widget,
GdkEventExpose *event)
{
if (event->window == widget->window)
hildon_viewport_paint (widget, &event->area);
- else if ((event->window == viewport->bin_window) ||
- (event->window == viewport->view_window))
+ else if ((event->window == viewport->bin_window))
{
- if (priv->pixmap)
- {
- GtkAdjustment *vadjustment = hildon_viewport_get_vadjustment (viewport);
- GtkAdjustment *hadjustment = hildon_viewport_get_hadjustment (viewport);
-
- gdk_draw_drawable (viewport->view_window,
- widget->style->bg_gc[GTK_STATE_NORMAL], priv->pixmap,
- hadjustment->value + event->area.x,
- vadjustment->value + event->area.y,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- }
- else
- {
- gtk_paint_flat_box(widget->style,
- viewport->bin_window,
- GTK_STATE_NORMAL, GTK_SHADOW_NONE,
- &event->area, widget, "viewportbin",
- 0, 0, -1, -1);
- }
+ cairo_t *cr;
+
+ gtk_paint_flat_box(widget->style,
+ viewport->bin_window,
+ GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &event->area, widget, "viewportbin",
+ 0, 0, -1, -1);
(* GTK_WIDGET_CLASS (hildon_viewport_parent_class)->expose_event) (widget, event);
+
+ cr = gdk_cairo_create (viewport->bin_window);
+
+ hildon_viewport_paint_offscreen_children (cr,
+ viewport->bin_window,
+ event, 0, 0);
+
+ cairo_destroy (cr);
+ }
+ else if (event->window == viewport->view_window)
+ {
+ GtkAdjustment *vadjustment = hildon_viewport_get_vadjustment (viewport);
+ GtkAdjustment *hadjustment = hildon_viewport_get_hadjustment (viewport);
+
+ gdk_draw_drawable (viewport->view_window,
+ widget->style->bg_gc[GTK_STATE_NORMAL],
+ priv->pixmap ? priv->pixmap : viewport->bin_window,
+ hadjustment->value + event->area.x,
+ vadjustment->value + event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
}
}