X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktextdisplay.c;h=24cc0ec6b4850970c08c3b46f341184232b7b328;hb=d97861bd8b338c3d25d7ffb5496edee9eee9bfbb;hp=67938280bd61e161766712f22c34343ad5609dd0;hpb=82f521b514251be6075ac5386f03228e3f86b18c;p=~andy%2Fgtk diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c index 67938280b..24cc0ec6b 100644 --- a/gtk/gtktextdisplay.c +++ b/gtk/gtktextdisplay.c @@ -21,8 +21,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * License along with this library. If not, see .Free * * Original Tk license: * @@ -77,7 +76,10 @@ #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API #include "config.h" #include "gtktextdisplay.h" +#include "gtkwidgetprivate.h" +#include "gtkstylecontextprivate.h" #include "gtkintl.h" + /* DO NOT go putting private headers in here. This file should only * use the semi-public headers, as with gtktextview.c. */ @@ -105,10 +107,13 @@ struct _GtkTextRenderer GtkWidget *widget; cairo_t *cr; - GdkColor *error_color; /* Error underline color for this widget */ - GList *widgets; /* widgets encountered when drawing */ - - int state; + GdkRGBA *error_color; /* Error underline color for this widget */ + GList *widgets; /* widgets encountered when drawing */ + + GdkRGBA rgba[4]; + guint8 rgba_set[4]; + + guint state : 2; }; struct _GtkTextRendererClass @@ -116,44 +121,27 @@ struct _GtkTextRendererClass PangoRendererClass parent_class; }; -G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, PANGO_TYPE_RENDERER) - -static GdkColor * -text_renderer_get_error_color (GtkTextRenderer *text_renderer) -{ - static const GdkColor red = { 0, 0xffff, 0, 0 }; - - if (!text_renderer->error_color) - gtk_widget_style_get (text_renderer->widget, - "error-underline-color", &text_renderer->error_color, - NULL); - - if (!text_renderer->error_color) - text_renderer->error_color = gdk_color_copy (&red); +GType _gtk_text_renderer_get_type (void); - return text_renderer->error_color; -} +G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, PANGO_TYPE_RENDERER) static void -text_renderer_set_gdk_color (GtkTextRenderer *text_renderer, - PangoRenderPart part, - GdkColor *gdk_color) +text_renderer_set_rgba (GtkTextRenderer *text_renderer, + PangoRenderPart part, + const GdkRGBA *rgba) { PangoRenderer *renderer = PANGO_RENDERER (text_renderer); + PangoColor dummy = { 0, }; - if (gdk_color) + if (rgba) { - PangoColor color; - - color.red = gdk_color->red; - color.green = gdk_color->green; - color.blue = gdk_color->blue; - - pango_renderer_set_color (renderer, part, &color); + text_renderer->rgba[part] = *rgba; + pango_renderer_set_color (renderer, part, &dummy); } else pango_renderer_set_color (renderer, part, NULL); - + + text_renderer->rgba_set[part] = (rgba != NULL); } static GtkTextAppearance * @@ -178,9 +166,11 @@ static void gtk_text_renderer_prepare_run (PangoRenderer *renderer, PangoLayoutRun *run) { + GtkStyleContext *context; + GtkStateFlags state; GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer); - GtkStyle *style; - GdkColor *bg_color, *fg_color, *underline_color; + GdkRGBA *bg_rgba = NULL; + GdkRGBA *fg_rgba = NULL; GtkTextAppearance *appearance; PANGO_RENDERER_CLASS (_gtk_text_renderer_parent_class)->prepare_run (renderer, run); @@ -188,51 +178,80 @@ gtk_text_renderer_prepare_run (PangoRenderer *renderer, appearance = get_item_appearance (run->item); g_assert (appearance != NULL); + context = gtk_widget_get_style_context (text_renderer->widget); + state = gtk_widget_get_state_flags (text_renderer->widget); + if (appearance->draw_bg && text_renderer->state == NORMAL) - bg_color = &appearance->bg_color; + bg_rgba = appearance->rgba[0]; else - bg_color = NULL; + bg_rgba = NULL; - text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_color); + text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_rgba); - style = gtk_widget_get_style (text_renderer->widget); if (text_renderer->state == SELECTED) { - if (gtk_widget_has_focus (text_renderer->widget)) - fg_color = &style->text[GTK_STATE_SELECTED]; - else - fg_color = &style->text[GTK_STATE_ACTIVE]; + state |= GTK_STATE_FLAG_SELECTED; + + gtk_style_context_get (context, state, "color", &fg_rgba, NULL); } else if (text_renderer->state == CURSOR && gtk_widget_has_focus (text_renderer->widget)) - fg_color = &style->base[GTK_STATE_NORMAL]; + { + gtk_style_context_get (context, state, + "background-color", &fg_rgba, + NULL); + } else - fg_color = &appearance->fg_color; + fg_rgba = appearance->rgba[1]; - text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_color); - text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_color); + text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba); + text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_rgba); if (appearance->underline == PANGO_UNDERLINE_ERROR) - underline_color = text_renderer_get_error_color (text_renderer); + { + if (!text_renderer->error_color) + { + GdkColor *color = NULL; + + gtk_style_context_get_style (context, + "error-underline-color", &color, + NULL); + + if (color) + { + GdkRGBA rgba; + + rgba.red = color->red / 65535.; + rgba.green = color->green / 65535.; + rgba.blue = color->blue / 65535.; + rgba.alpha = 1; + gdk_color_free (color); + + text_renderer->error_color = gdk_rgba_copy (&rgba); + } + else + { + static const GdkRGBA red = { 1, 0, 0, 1 }; + text_renderer->error_color = gdk_rgba_copy (&red); + } + } + + text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color); + } else - underline_color = fg_color; + text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba); - text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, underline_color); + if (fg_rgba != appearance->rgba[1]) + gdk_rgba_free (fg_rgba); } static void set_color (GtkTextRenderer *text_renderer, PangoRenderPart part) { - PangoColor *color; - cairo_save (text_renderer->cr); - color = pango_renderer_get_color (PANGO_RENDERER (text_renderer), part); - if (color) - cairo_set_source_rgb (text_renderer->cr, - color->red / 65535., - color->green / 65535., - color->blue / 65535.); + if (text_renderer->rgba_set[part]) + gdk_cairo_set_source_rgba (text_renderer->cr, &text_renderer->rgba[part]); } static void @@ -354,21 +373,6 @@ gtk_text_renderer_draw_shape (PangoRenderer *renderer, int y) { GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer); - GtkStyle *style; - GdkColor *fg; - - style = gtk_widget_get_style (text_renderer->widget); - if (text_renderer->state == SELECTED) - { - if (gtk_widget_has_focus (text_renderer->widget)) - fg = &style->text[GTK_STATE_SELECTED]; - else - fg = &style->text[GTK_STATE_SELECTED]; - } - else if (text_renderer->state == CURSOR && gtk_widget_has_focus (text_renderer->widget)) - fg = &style->base[GTK_STATE_NORMAL]; - else - fg = &style->text[GTK_STATE_NORMAL]; if (attr->data == NULL) { @@ -377,18 +381,17 @@ gtk_text_renderer_draw_shape (PangoRenderer *renderer, */ GdkRectangle shape_rect; cairo_t *cr; - + shape_rect.x = PANGO_PIXELS (x); shape_rect.y = PANGO_PIXELS (y + attr->logical_rect.y); shape_rect.width = PANGO_PIXELS (x + attr->logical_rect.width) - shape_rect.x; shape_rect.height = PANGO_PIXELS (y + attr->logical_rect.y + attr->logical_rect.height) - shape_rect.y; - - cr = text_renderer->cr; - cairo_save (cr); + set_color (text_renderer, PANGO_RENDER_PART_FOREGROUND); + + cr = text_renderer->cr; cairo_set_line_width (cr, 1.0); - gdk_cairo_set_source_color (cr, fg); cairo_rectangle (cr, shape_rect.x + 0.5, shape_rect.y + 0.5, @@ -403,8 +406,8 @@ gtk_text_renderer_draw_shape (PangoRenderer *renderer, shape_rect.y + 0.5); cairo_stroke (cr); - - cairo_restore (cr); + + unset_color (text_renderer); } else if (GDK_IS_PIXBUF (attr->data)) { @@ -474,8 +477,24 @@ text_renderer_begin (GtkTextRenderer *text_renderer, GtkWidget *widget, cairo_t *cr) { + GtkStyleContext *context; + GtkStateFlags state; + GdkRGBA color; + text_renderer->widget = widget; text_renderer->cr = cr; + + context = gtk_widget_get_style_context (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW); + + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_color (context, state, &color); + + cairo_save (cr); + + gdk_cairo_set_source_rgba (cr, &color); } /* Returns a GSList of (referenced) widgets encountered while drawing. @@ -483,8 +502,15 @@ text_renderer_begin (GtkTextRenderer *text_renderer, static GList * text_renderer_end (GtkTextRenderer *text_renderer) { + GtkStyleContext *context; GList *widgets = text_renderer->widgets; + cairo_restore (text_renderer->cr); + + context = gtk_widget_get_style_context (text_renderer->widget); + + gtk_style_context_restore (context); + text_renderer->widget = NULL; text_renderer->cr = NULL; @@ -492,14 +518,13 @@ text_renderer_end (GtkTextRenderer *text_renderer) if (text_renderer->error_color) { - gdk_color_free (text_renderer->error_color); + gdk_rgba_free (text_renderer->error_color); text_renderer->error_color = NULL; } return widgets; } - static cairo_region_t * get_selected_clip (GtkTextRenderer *text_renderer, PangoLayout *layout, @@ -535,24 +560,19 @@ get_selected_clip (GtkTextRenderer *text_renderer, static void render_para (GtkTextRenderer *text_renderer, GtkTextLineDisplay *line_display, - /* Top-left corner of paragraph including all margins */ - int x, - int y, int selection_start_index, int selection_end_index) { - GtkStyle *style; + GtkStyleContext *context; + GtkStateFlags state; PangoLayout *layout = line_display->layout; int byte_offset = 0; PangoLayoutIter *iter; PangoRectangle layout_logical; int screen_width; - GdkColor *selection; - gint state; + GdkRGBA selection; gboolean first = TRUE; - style = gtk_widget_get_style (text_renderer->widget); - iter = pango_layout_get_iter (layout); pango_layout_iter_get_layout_extents (iter, NULL, &layout_logical); @@ -563,13 +583,13 @@ render_para (GtkTextRenderer *text_renderer, layout_logical.y += line_display->top_margin * PANGO_SCALE; screen_width = line_display->total_width; - - if (gtk_widget_has_focus (text_renderer->widget)) - state = GTK_STATE_SELECTED; - else - state = GTK_STATE_ACTIVE; - selection = &style->base [state]; + context = gtk_widget_get_style_context (text_renderer->widget); + state = gtk_widget_get_state_flags (text_renderer->widget); + + state |= GTK_STATE_FLAG_SELECTED; + + gtk_style_context_get_background_color (context, state, &selection); do { @@ -593,7 +613,7 @@ render_para (GtkTextRenderer *text_renderer, /* Selection is the height of the line, plus top/bottom * margin if we're the first/last line */ - selection_y = y + PANGO_PIXELS (first_y) + line_display->top_margin; + selection_y = PANGO_PIXELS (first_y) + line_display->top_margin; selection_height = PANGO_PIXELS (last_y) - PANGO_PIXELS (first_y); if (first) @@ -614,9 +634,9 @@ render_para (GtkTextRenderer *text_renderer, cairo_t *cr = text_renderer->cr; cairo_save (cr); - gdk_cairo_set_source_color (cr, selection); + gdk_cairo_set_source_rgba (cr, &selection); cairo_rectangle (cr, - x + line_display->left_margin, selection_y, + line_display->left_margin, selection_y, screen_width, selection_height); cairo_fill (cr); cairo_restore(cr); @@ -624,20 +644,20 @@ render_para (GtkTextRenderer *text_renderer, text_renderer_set_state (text_renderer, SELECTED); pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer), line, - PANGO_SCALE * x + line_rect.x, - PANGO_SCALE * y + baseline); + line_rect.x, + baseline); } else { - if (line_display->pg_bg_color) + if (line_display->pg_bg_rgba) { cairo_t *cr = text_renderer->cr; cairo_save (cr); - - gdk_cairo_set_source_color (cr, line_display->pg_bg_color); + + gdk_cairo_set_source_rgba (text_renderer->cr, line_display->pg_bg_rgba); cairo_rectangle (cr, - x + line_display->left_margin, selection_y, + line_display->left_margin, selection_y, screen_width, selection_height); cairo_fill (cr); @@ -647,8 +667,8 @@ render_para (GtkTextRenderer *text_renderer, text_renderer_set_state (text_renderer, NORMAL); pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer), line, - PANGO_SCALE * x + line_rect.x, - PANGO_SCALE * y + baseline); + line_rect.x, + baseline); /* Check if some part of the line is selected; the newline * that is after line->length for the last line of the @@ -660,7 +680,7 @@ render_para (GtkTextRenderer *text_renderer, { cairo_t *cr = text_renderer->cr; cairo_region_t *clip_region = get_selected_clip (text_renderer, layout, line, - x + line_display->x_offset, + line_display->x_offset, selection_y, selection_height, selection_start_index, selection_end_index); @@ -670,9 +690,9 @@ render_para (GtkTextRenderer *text_renderer, cairo_clip (cr); cairo_region_destroy (clip_region); - gdk_cairo_set_source_color (cr, selection); + gdk_cairo_set_source_rgba (cr, &selection); cairo_rectangle (cr, - x + PANGO_PIXELS (line_rect.x), + PANGO_PIXELS (line_rect.x), selection_y, PANGO_PIXELS (line_rect.width), selection_height); @@ -681,8 +701,8 @@ render_para (GtkTextRenderer *text_renderer, text_renderer_set_state (text_renderer, SELECTED); pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer), line, - PANGO_SCALE * x + line_rect.x, - PANGO_SCALE * y + baseline); + line_rect.x, + baseline); cairo_restore (cr); @@ -693,9 +713,9 @@ render_para (GtkTextRenderer *text_renderer, { cairo_save (cr); - gdk_cairo_set_source_color (cr, selection); + gdk_cairo_set_source_rgba (cr, &selection); cairo_rectangle (cr, - x + line_display->left_margin, + line_display->left_margin, selection_y, PANGO_PIXELS (line_rect.x) - line_display->left_margin, selection_height); @@ -717,9 +737,9 @@ render_para (GtkTextRenderer *text_renderer, cairo_save (cr); - gdk_cairo_set_source_color (cr, selection); + gdk_cairo_set_source_rgba (cr, &selection); cairo_rectangle (cr, - x + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width), + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width), selection_y, nonlayout_width, selection_height); @@ -735,15 +755,15 @@ render_para (GtkTextRenderer *text_renderer, (at_last_line && line_display->insert_index == byte_offset + line->length))) { GdkRectangle cursor_rect; - GdkColor cursor_color; + GdkRGBA cursor_color; cairo_t *cr = text_renderer->cr; - /* we draw text using base color on filled cursor rectangle of cursor color - * (normally white on black) */ - _gtk_widget_get_cursor_color (text_renderer->widget, &cursor_color); + /* we draw text using base color on filled cursor rectangle of cursor color + * (normally white on black) */ + _gtk_style_context_get_cursor_color (context, &cursor_color, NULL); - cursor_rect.x = x + line_display->x_offset + line_display->block_cursor.x; - cursor_rect.y = y + line_display->block_cursor.y + line_display->top_margin; + cursor_rect.x = line_display->x_offset + line_display->block_cursor.x; + cursor_rect.y = line_display->block_cursor.y + line_display->top_margin; cursor_rect.width = line_display->block_cursor.width; cursor_rect.height = line_display->block_cursor.height; @@ -752,27 +772,26 @@ render_para (GtkTextRenderer *text_renderer, gdk_cairo_rectangle (cr, &cursor_rect); cairo_clip (cr); - gdk_cairo_set_source_color (cr, &cursor_color); + gdk_cairo_set_source_rgba (cr, &cursor_color); cairo_paint (cr); - /* draw text under the cursor if any */ - if (!line_display->cursor_at_line_end) - { - GtkStateType state; - GtkStyle *style; + /* draw text under the cursor if any */ + if (!line_display->cursor_at_line_end) + { + GdkRGBA color; + + state = gtk_widget_get_state_flags (text_renderer->widget); + gtk_style_context_get_background_color (context, state, &color); - style = gtk_widget_get_style (text_renderer->widget); - state = gtk_widget_get_state (text_renderer->widget); - gdk_cairo_set_source_color (cr, &style->base[state]); + gdk_cairo_set_source_rgba (cr, &color); text_renderer_set_state (text_renderer, CURSOR); pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer), line, - PANGO_SCALE * x + line_rect.x, - PANGO_SCALE * y + baseline); - - } + line_rect.x, + baseline); + } cairo_restore (cr); } @@ -799,69 +818,45 @@ get_text_renderer (void) void gtk_text_layout_draw (GtkTextLayout *layout, GtkWidget *widget, - GdkDrawable *drawable, - gpointer cursor_gc, - /* Location of the drawable - in layout coordinates */ - gint x_offset, - gint y_offset, - /* Region of the layout to - render */ - gint x, - gint y, - gint width, - gint height, - /* widgets to expose */ + cairo_t *cr, GList **widgets) { - GdkRectangle clip; - gint current_y; - GSList *cursor_list; + GtkStyleContext *context; + gint offset_y; GtkTextRenderer *text_renderer; GtkTextIter selection_start, selection_end; - gboolean have_selection = FALSE; + gboolean have_selection; GSList *line_list; GSList *tmp_list; GList *tmp_widgets; - cairo_t *cr; - + GdkRectangle clip; + g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); g_return_if_fail (layout->default_style != NULL); g_return_if_fail (layout->buffer != NULL); - g_return_if_fail (drawable != NULL); - g_return_if_fail (width >= 0); - g_return_if_fail (height >= 0); + g_return_if_fail (cr != NULL); - if (width == 0 || height == 0) + if (!gdk_cairo_get_clip_rectangle (cr, &clip)) return; - line_list = gtk_text_layout_get_lines (layout, y + y_offset, y + y_offset + height, ¤t_y); - current_y -= y_offset; + context = gtk_widget_get_style_context (widget); + + line_list = gtk_text_layout_get_lines (layout, clip.y, clip.y + clip.height, &offset_y); if (line_list == NULL) return; /* nothing on the screen */ - cr = gdk_cairo_create (drawable); - cairo_rectangle (cr, x, y, width, height); - cairo_clip (cr); - - /* cursor code needs this */ - clip.x = x; - clip.y = y; - clip.width = width; - clip.height = height; - - gdk_cairo_set_source_color (cr, >k_widget_get_style (widget)->text[gtk_widget_get_state (widget)]); - text_renderer = get_text_renderer (); text_renderer_begin (text_renderer, widget, cr); + /* text_renderer_begin/end does cairo_save/restore */ + cairo_translate (cr, 0, offset_y); + gtk_text_layout_wrap_loop_start (layout); - if (gtk_text_buffer_get_selection_bounds (layout->buffer, - &selection_start, - &selection_end)) - have_selection = TRUE; + have_selection = gtk_text_buffer_get_selection_bounds (layout->buffer, + &selection_start, + &selection_end); tmp_list = line_list; while (tmp_list != NULL) @@ -869,8 +864,6 @@ gtk_text_layout_draw (GtkTextLayout *layout, GtkTextLineDisplay *line_display; gint selection_start_index = -1; gint selection_end_index = -1; - gboolean have_strong; - gboolean have_weak; GtkTextLine *line = tmp_list->data; @@ -909,56 +902,30 @@ gtk_text_layout_draw (GtkTextLayout *layout, } render_para (text_renderer, line_display, - - x_offset, - current_y, selection_start_index, selection_end_index); /* We paint the cursors last, because they overlap another chunk - and need to appear on top. */ - - have_strong = FALSE; - have_weak = FALSE; - - cursor_list = line_display->cursors; - while (cursor_list) - { - GtkTextCursorDisplay *cursor = cursor_list->data; - if (cursor->is_strong) - have_strong = TRUE; - else - have_weak = TRUE; - - cursor_list = cursor_list->next; - } - - cursor_list = line_display->cursors; - while (cursor_list) + * and need to appear on top. + */ + if (line_display->cursors != NULL) { - GtkTextCursorDisplay *cursor = cursor_list->data; - GtkTextDirection dir; - GdkRectangle cursor_location; - - dir = line_display->direction; - if (have_strong && have_weak) - { - if (!cursor->is_strong) - dir = (dir == GTK_TEXT_DIR_RTL) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; - } - - cursor_location.x = line_display->x_offset + cursor->x - x_offset; - cursor_location.y = current_y + line_display->top_margin + cursor->y; - cursor_location.width = 0; - cursor_location.height = cursor->height; + int i; - gtk_draw_insertion_cursor (widget, drawable, &clip, &cursor_location, - cursor->is_strong, - dir, have_strong && have_weak); - - cursor_list = cursor_list->next; + for (i = 0; i < line_display->cursors->len; i++) + { + int index; + PangoDirection dir; + + index = g_array_index(line_display->cursors, int, i); + dir = (line_display->direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; + gtk_render_insertion_cursor (context, cr, + line_display->x_offset, line_display->top_margin, + line_display->layout, index, dir); + } } } /* line_display->height > 0 */ - - current_y += line_display->height; + + cairo_translate (cr, 0, line_display->height); gtk_text_layout_free_line_display (layout, line_display); tmp_list = g_slist_next (tmp_list); @@ -970,12 +937,7 @@ gtk_text_layout_draw (GtkTextLayout *layout, if (widgets) *widgets = tmp_widgets; else - { - g_list_foreach (tmp_widgets, (GFunc)g_object_unref, NULL); - g_list_free (tmp_widgets); - } - - cairo_destroy (cr); + g_list_free_full (tmp_widgets, g_object_unref); g_slist_free (line_list); }