Created
August 15, 2013 08:02
-
-
Save chergert/6239104 to your computer and use it in GitHub Desktop.
Use GtkPixelCache inside of GtkTextView. This still doesn't feel interactive enough for me. There needs to be some tweaks on the size of the area to pre-render. Likely in the half-page or so on each boundary.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| testdiff --git a/gtk/gtktextview.c b/gtk/gtktextview.c | |
| index 3aa1047..1dff1e2 100644 | |
| --- a/gtk/gtktextview.c | |
| +++ b/gtk/gtktextview.c | |
| @@ -53,6 +53,7 @@ | |
| #include "gtkcssstylepropertyprivate.h" | |
| #include "gtkbubblewindowprivate.h" | |
| #include "gtktoolbar.h" | |
| +#include "gtkpixelcacheprivate.h" | |
| #include "a11y/gtktextviewaccessibleprivate.h" | |
| @@ -201,6 +202,8 @@ struct _GtkTextViewPrivate | |
| GtkTextPendingScroll *pending_scroll; | |
| + GtkPixelCache *pixel_cache; | |
| + | |
| /* Default style settings */ | |
| gint pixels_above_lines; | |
| gint pixels_below_lines; | |
| @@ -239,6 +242,8 @@ struct _GtkTextViewPrivate | |
| guint cursor_handle_dragged : 1; | |
| guint selection_handle_dragged : 1; | |
| guint populate_all : 1; | |
| + | |
| + gboolean in_scroll : 1; | |
| }; | |
| struct _GtkTextPendingScroll | |
| @@ -525,6 +530,9 @@ static void gtk_text_view_update_handles (GtkTextView *text_view | |
| static void gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view); | |
| static void gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view); | |
| +static void gtk_text_view_queue_draw_region (GtkWidget *widget, | |
| + const cairo_region_t *region); | |
| + | |
| /* FIXME probably need the focus methods. */ | |
| @@ -663,6 +671,8 @@ gtk_text_view_class_init (GtkTextViewClass *klass) | |
| widget_class->popup_menu = gtk_text_view_popup_menu; | |
| + widget_class->queue_draw_region = gtk_text_view_queue_draw_region; | |
| + | |
| container_class->add = gtk_text_view_add; | |
| container_class->remove = gtk_text_view_remove; | |
| container_class->forall = gtk_text_view_forall; | |
| @@ -1460,6 +1470,8 @@ gtk_text_view_init (GtkTextView *text_view) | |
| gtk_widget_set_can_focus (widget, TRUE); | |
| + priv->pixel_cache = _gtk_pixel_cache_new (); | |
| + | |
| /* Set up default style */ | |
| priv->wrap_mode = GTK_WRAP_NONE; | |
| priv->pixels_above_lines = 0; | |
| @@ -3134,6 +3146,12 @@ gtk_text_view_destroy (GtkWidget *widget) | |
| priv->im_spot_idle = 0; | |
| } | |
| + if (priv->pixel_cache) | |
| + { | |
| + _gtk_pixel_cache_free (priv->pixel_cache); | |
| + priv->pixel_cache = NULL; | |
| + } | |
| + | |
| GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget); | |
| } | |
| @@ -5215,10 +5233,33 @@ gtk_text_view_paint (GtkWidget *widget, | |
| cairo_restore (cr); | |
| } | |
| +static void | |
| +draw_text (cairo_t *cr, | |
| + gpointer user_data) | |
| +{ | |
| + GtkStyleContext *context; | |
| + GtkAllocation alloc; | |
| + GtkTextView *text_view = user_data; | |
| + GtkWidget *widget = user_data; | |
| + | |
| + gtk_widget_get_allocation (widget, &alloc); | |
| + alloc.width = MAX (alloc.width, text_view->priv->layout->width); | |
| + alloc.height = MAX (alloc.height, text_view->priv->layout->height); | |
| + | |
| + context = gtk_widget_get_style_context (widget); | |
| + gtk_style_context_save (context); | |
| + gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW); | |
| + gtk_render_background (context, cr, 0, -200, alloc.width, alloc.height+200); | |
| + gtk_style_context_restore (context); | |
| + | |
| + gtk_text_view_paint (widget, cr); | |
| +} | |
| + | |
| static gboolean | |
| gtk_text_view_draw (GtkWidget *widget, | |
| cairo_t *cr) | |
| { | |
| + GtkTextViewPrivate *priv = ((GtkTextView *)widget)->priv; | |
| GSList *tmp_list; | |
| GdkWindow *window; | |
| GtkStyleContext *context; | |
| @@ -5242,10 +5283,29 @@ gtk_text_view_draw (GtkWidget *widget, | |
| GTK_TEXT_WINDOW_TEXT); | |
| if (gtk_cairo_should_draw_window (cr, window)) | |
| { | |
| + cairo_rectangle_int_t view_rect; | |
| + cairo_rectangle_int_t canvas_rect; | |
| + GtkAllocation alloc; | |
| + | |
| DV(g_print (">Exposed ("G_STRLOC")\n")); | |
| + | |
| + gtk_widget_get_allocation (widget, &alloc); | |
| + | |
| + view_rect.x = 0; | |
| + view_rect.y = 0; | |
| + view_rect.width = gdk_window_get_width (window); | |
| + view_rect.height = gdk_window_get_height (window); | |
| + | |
| + gdk_window_get_position (window, &canvas_rect.x, &canvas_rect.y); | |
| + canvas_rect.y = -gtk_adjustment_get_value (priv->vadjustment); | |
| + canvas_rect.width = priv->cached_size_request.width; | |
| + canvas_rect.height = priv->cached_size_request.height; | |
| + | |
| cairo_save (cr); | |
| gtk_cairo_transform_to_window (cr, widget, window); | |
| - gtk_text_view_paint (widget, cr); | |
| + _gtk_pixel_cache_draw (priv->pixel_cache, cr, window, | |
| + &view_rect, &canvas_rect, | |
| + draw_text, widget); | |
| cairo_restore (cr); | |
| } | |
| @@ -8878,6 +8938,45 @@ text_window_free (GtkTextWindow *win) | |
| } | |
| static void | |
| +gtk_text_view_queue_draw_region (GtkWidget *widget, | |
| + const cairo_region_t *region) | |
| +{ | |
| + GtkTextView *text_view = GTK_TEXT_VIEW (widget); | |
| + | |
| + /* There is no way we can know if a region targets the | |
| + not-currently-visible but in pixel cache region, so we | |
| + always just invalidate the whole thing whenever the | |
| + text view gets a queue draw. This doesn't normally happen | |
| + in normal scrolling cases anyway. */ | |
| + _gtk_pixel_cache_invalidate (text_view->priv->pixel_cache, NULL); | |
| + | |
| + GTK_WIDGET_CLASS (gtk_text_view_parent_class)->queue_draw_region (widget, | |
| + region); | |
| +} | |
| + | |
| +static void | |
| +text_window_invalidate_handler (GdkWindow *window, | |
| + cairo_region_t *region) | |
| +{ | |
| + gpointer widget; | |
| + GtkTextView *text_view; | |
| + int y; | |
| + | |
| + gdk_window_get_user_data (window, &widget); | |
| + text_view = GTK_TEXT_VIEW (widget); | |
| + | |
| + /* Scrolling will invalidate everything in the bin window, | |
| + * but we already have it in the cache, so we can ignore that */ | |
| + if (text_view->priv->in_scroll) | |
| + return; | |
| + | |
| + y = gtk_adjustment_get_value (text_view->priv->vadjustment); | |
| + cairo_region_translate (region, 0, y); | |
| + _gtk_pixel_cache_invalidate (text_view->priv->pixel_cache, region); | |
| + cairo_region_translate (region, 0, -y); | |
| +} | |
| + | |
| +static void | |
| text_window_realize (GtkTextWindow *win, | |
| GtkWidget *widget) | |
| { | |
| @@ -8905,6 +9004,9 @@ text_window_realize (GtkTextWindow *win, | |
| win->window = gdk_window_new (window, | |
| &attributes, attributes_mask); | |
| + gdk_window_set_invalidate_handler (win->window, | |
| + text_window_invalidate_handler); | |
| + | |
| gdk_window_show (win->window); | |
| gtk_widget_register_window (win->widget, win->window); | |
| gdk_window_lower (win->window); | |
| @@ -9016,7 +9118,9 @@ text_window_scroll (GtkTextWindow *win, | |
| { | |
| if (priv->selection_bubble) | |
| _gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble)); | |
| + view->priv->in_scroll = TRUE; | |
| gdk_window_scroll (win->bin_window, dx, dy); | |
| + view->priv->in_scroll = FALSE; | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment