]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextdisplay.c
Fix ZWJ => ZWN typo. (#83092, Tino Meinen)
[~andy/gtk] / gtk / gtktextdisplay.c
index 0053f1b2ec539225114a453d392af1ff6f57a3d1..75b3fc932cbb8b76daa50a75c13c371313a058d9 100644 (file)
@@ -74,6 +74,7 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
+#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include "gtktextdisplay.h"
 /* DO NOT go putting private headers in here. This file should only
  * use the semi-public headers, as with gtktextview.c.
@@ -142,6 +143,8 @@ static void
 gtk_text_render_state_update (GtkTextRenderState *state,
                               GtkTextAppearance  *new_appearance)
 {
+  GdkScreen *screen = gtk_widget_get_screen (state->widget);
+  
   if (!state->last_appearance ||
       !gdk_color_equal (&new_appearance->fg_color, &state->last_appearance->fg_color))
     gtk_text_render_state_set_color (state, state->fg_gc, &new_appearance->fg_color);
@@ -151,8 +154,15 @@ gtk_text_render_state_update (GtkTextRenderState *state,
     {
       if (new_appearance->fg_stipple)
         {
-          gdk_gc_set_fill (state->fg_gc, GDK_STIPPLED);
-          gdk_gc_set_stipple (state->fg_gc, new_appearance->fg_stipple);
+         if (screen == gdk_drawable_get_screen (new_appearance->fg_stipple))
+           {
+             gdk_gc_set_fill (state->fg_gc, GDK_STIPPLED);
+             gdk_gc_set_stipple (state->fg_gc, new_appearance->fg_stipple);
+           }
+         else
+           g_warning ("gtk_text_render_state_update:\n"
+                      "The foreground stipple bitmap has been created on the wrong screen.\n"
+                      "Ignoring the stipple bitmap information.");
         }
       else
         {
@@ -171,8 +181,16 @@ gtk_text_render_state_update (GtkTextRenderState *state,
         {
           if (new_appearance->bg_stipple)
             {
-              gdk_gc_set_fill (state->bg_gc, GDK_STIPPLED);
-              gdk_gc_set_stipple (state->bg_gc, new_appearance->bg_stipple);
+             if (screen == gdk_drawable_get_screen (new_appearance->bg_stipple))
+               {
+                 gdk_gc_set_fill (state->bg_gc, GDK_STIPPLED);
+                 gdk_gc_set_stipple (state->bg_gc, new_appearance->bg_stipple);
+               }
+             else
+               g_warning ("gtk_text_render_state_update:\n"
+                          "The background stipple bitmap has been created on the wrong screen.\n"
+                          "Ignoring the stipple bitmap information.");
+
             }
           else
             {
@@ -221,7 +239,8 @@ render_layout_line (GdkDrawable        *drawable,
                     GSList            **shaped_pointer,
                     int                 x,
                     int                 y,
-                    gboolean            selected)
+                    gboolean            selected,
+                    GList             **widgets)
 {
   GSList *tmp_list = line->runs;
   PangoRectangle overall_rect;
@@ -250,7 +269,10 @@ render_layout_line (GdkDrawable        *drawable,
       
       if (selected)
         {
-          fg_gc = render_state->widget->style->text_gc[GTK_STATE_SELECTED];
+         if (GTK_WIDGET_HAS_FOCUS (render_state->widget))
+           fg_gc = render_state->widget->style->text_gc[GTK_STATE_SELECTED];
+         else
+           fg_gc = render_state->widget->style->text_gc [GTK_STATE_ACTIVE];
         }
       else
         {
@@ -297,8 +319,40 @@ render_layout_line (GdkDrawable        *drawable,
           GObject *shaped = (*shaped_pointer)->data;
 
           *shaped_pointer = (*shaped_pointer)->next;
-          
-          if (GDK_IS_PIXBUF (shaped))
+
+          if (shaped == NULL)
+            {
+              /* This happens if we have an empty widget anchor. Draw
+               * something empty-looking.
+               */
+              GdkRectangle shape_rect, draw_rect;
+
+              shape_rect.x = x + x_off / PANGO_SCALE;
+              shape_rect.y = risen_y - PANGO_PIXELS (logical_rect.height);
+              shape_rect.width = PANGO_PIXELS (logical_rect.width);
+              shape_rect.height = PANGO_PIXELS (logical_rect.height);
+
+              if (gdk_rectangle_intersect (&shape_rect, &render_state->clip_rect,
+                                           &draw_rect))
+                {
+                  gdk_draw_rectangle (drawable, render_state->fg_gc,
+                                      FALSE, shape_rect.x, shape_rect.y,
+                                      shape_rect.width, shape_rect.height);
+
+                  gdk_draw_line (drawable, render_state->fg_gc,
+                                 shape_rect.x, shape_rect.y,
+                                 shape_rect.x + shape_rect.width,
+                                 shape_rect.y + shape_rect.height);
+
+                  gdk_draw_line (drawable, render_state->fg_gc,
+                                 shape_rect.x + shape_rect.width, shape_rect.y,
+                                 shape_rect.x,
+                                 shape_rect.y + shape_rect.height);
+                }
+
+              shaped_width_pixels = shape_rect.width;
+            }
+          else if (GDK_IS_PIXBUF (shaped))
             {
               gint width, height;
               GdkRectangle pixbuf_rect, draw_rect;
@@ -364,37 +418,17 @@ render_layout_line (GdkDrawable        *drawable,
             }
           else if (GTK_IS_WIDGET (shaped))
             {
-              gint width, height;
-              GdkRectangle draw_rect;
               GtkWidget *widget;
               
               widget = GTK_WIDGET (shaped);
               
-              width = widget->allocation.width;
-              height = widget->allocation.height;
-
-              g_print ("widget allocation at %d,%d %d x %d\n",
-                      widget->allocation.x,
-                      widget->allocation.y,
-                      widget->allocation.width,
-                      widget->allocation.height);
-              
-              if (GTK_WIDGET_DRAWABLE (widget) &&
-                  gdk_rectangle_intersect (&widget->allocation,
-                                           &render_state->clip_rect,
-                                           &draw_rect))
+              shaped_width_pixels = widget->allocation.width;
 
+              if (widgets)
                 {
-                  g_print ("drawing widget area %d,%d %d x %d\n",
-                          draw_rect.x,
-                          draw_rect.y,
-                          draw_rect.width,
-                          draw_rect.height);
-
-                  gtk_widget_draw (widget, &draw_rect);
+                  g_object_ref (G_OBJECT (widget));
+                  *widgets = g_list_prepend (*widgets, widget);
                 }
-
-              shaped_width_pixels = width;
             }
           else
             g_assert_not_reached (); /* not a pixbuf or widget */
@@ -456,7 +490,8 @@ render_para (GdkDrawable        *drawable,
              int                 x,
              int                 y,
              int                 selection_start_index,
-             int                 selection_end_index)
+             int                 selection_end_index,
+             GList             **widgets)
 {
   GSList *shaped_pointer = line_display->shaped_objects;
   PangoLayout *layout = line_display->layout;
@@ -464,6 +499,8 @@ render_para (GdkDrawable        *drawable,
   PangoLayoutIter *iter;
   PangoRectangle layout_logical;
   int screen_width;
+  GdkGC *fg_gc, *bg_gc;
+  gint state;
   
   gboolean first = TRUE;
 
@@ -478,6 +515,14 @@ render_para (GdkDrawable        *drawable,
 
   screen_width = line_display->total_width;
   
+  if (GTK_WIDGET_HAS_FOCUS (render_state->widget))
+    state = GTK_STATE_SELECTED;
+  else
+    state = GTK_STATE_ACTIVE;
+
+  fg_gc = render_state->widget->style->text_gc [state];
+  bg_gc = render_state->widget->style->base_gc [state];
+
   do
     {
       PangoLayoutLine *line = pango_layout_iter_get_line (iter);
@@ -517,7 +562,7 @@ render_para (GdkDrawable        *drawable,
           selection_end_index > line->length + byte_offset) /* All selected */
         {
           gdk_draw_rectangle (drawable,
-                              render_state->widget->style->base_gc[GTK_STATE_SELECTED],
+                              bg_gc,
                               TRUE,
                               x + line_display->left_margin,
                               selection_y,
@@ -527,7 +572,8 @@ render_para (GdkDrawable        *drawable,
           render_layout_line (drawable, render_state, line, &shaped_pointer,
                               x + PANGO_PIXELS (line_rect.x),
                               y + PANGO_PIXELS (baseline),
-                              TRUE);
+                              TRUE,
+                              widgets);
         }
       else
         {
@@ -537,9 +583,10 @@ render_para (GdkDrawable        *drawable,
                               line, &shaped_pointer,
                               x + PANGO_PIXELS (line_rect.x),
                               y + PANGO_PIXELS (baseline),
-                              FALSE);
+                              FALSE,
+                              widgets);
 
-          if (selection_start_index < byte_offset + line->length &&
+          if (selection_start_index <= byte_offset + line->length &&
               selection_end_index > byte_offset) /* Some selected */
             {
               GdkRegion *clip_region = get_selected_clip (render_state, layout, line,
@@ -547,12 +594,11 @@ render_para (GdkDrawable        *drawable,
                                                           selection_y,
                                                           selection_height,
                                                           selection_start_index, selection_end_index);
-
-              gdk_gc_set_clip_region (render_state->widget->style->text_gc [GTK_STATE_SELECTED], clip_region);
-              gdk_gc_set_clip_region (render_state->widget->style->base_gc [GTK_STATE_SELECTED], clip_region);
+              gdk_gc_set_clip_region (fg_gc, clip_region);
+              gdk_gc_set_clip_region (bg_gc, clip_region);
 
               gdk_draw_rectangle (drawable,
-                                  render_state->widget->style->base_gc[GTK_STATE_SELECTED],
+                                  bg_gc,
                                   TRUE,
                                   x + PANGO_PIXELS (line_rect.x),
                                   selection_y,
@@ -562,10 +608,11 @@ render_para (GdkDrawable        *drawable,
               render_layout_line (drawable, render_state, line, &shaped_pointer_tmp,
                                   x + PANGO_PIXELS (line_rect.x),
                                   y + PANGO_PIXELS (baseline),
-                                  TRUE);
+                                  TRUE,
+                                  widgets);
 
-              gdk_gc_set_clip_region (render_state->widget->style->text_gc [GTK_STATE_SELECTED], NULL);
-              gdk_gc_set_clip_region (render_state->widget->style->base_gc [GTK_STATE_SELECTED], NULL);
+              gdk_gc_set_clip_region (fg_gc, NULL);
+              gdk_gc_set_clip_region (bg_gc, NULL);
 
               gdk_region_destroy (clip_region);
 
@@ -575,7 +622,7 @@ render_para (GdkDrawable        *drawable,
                    (line_display->direction == GTK_TEXT_DIR_RTL && selection_end_index > byte_offset + line->length)))
                 {
                   gdk_draw_rectangle (drawable,
-                                      render_state->widget->style->base_gc[GTK_STATE_SELECTED],
+                                      bg_gc,
                                       TRUE,
                                       x + line_display->left_margin,
                                       selection_y,
@@ -595,7 +642,7 @@ render_para (GdkDrawable        *drawable,
                     PANGO_PIXELS (line_rect.x) - PANGO_PIXELS (line_rect.width);
 
                   gdk_draw_rectangle (drawable,
-                                      render_state->widget->style->base_gc[GTK_STATE_SELECTED],
+                                      bg_gc,
                                       TRUE,
                                       x + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width),
                                       selection_y,
@@ -674,6 +721,7 @@ void
 gtk_text_layout_draw (GtkTextLayout *layout,
                       GtkWidget *widget,
                       GdkDrawable *drawable,
+                     GdkGC       *cursor_gc,
                       /* Location of the drawable
                          in layout coordinates */
                       gint x_offset,
@@ -683,7 +731,9 @@ gtk_text_layout_draw (GtkTextLayout *layout,
                       gint x,
                       gint y,
                       gint width,
-                      gint height)
+                      gint height,
+                      /* widgets to expose */
+                      GList **widgets)
 {
   GdkRectangle clip;
   gint current_y;
@@ -733,6 +783,8 @@ 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;
 
@@ -746,19 +798,16 @@ gtk_text_layout_draw (GtkTextLayout *layout,
             {
               GtkTextIter line_start, line_end;
               gint byte_count;
-
+              
               gtk_text_layout_get_iter_at_line (layout,
                                                 &line_start,
                                                 line, 0);
-              byte_count = gtk_text_iter_get_bytes_in_line (&line_start);
-          
-              /* FIXME the -1 assumes a newline I think */
-              gtk_text_layout_get_iter_at_line (layout,
-                                                &line_end,
-                                                line, byte_count - 1);
+              line_end = line_start;
+              gtk_text_iter_forward_to_line_end (&line_end);
+              byte_count = gtk_text_iter_get_line_index (&line_end);     
 
-              if (gtk_text_iter_compare (&selection_start, &line_end) < 0 &&
-                  gtk_text_iter_compare (&selection_end, &line_start) > 0)
+              if (gtk_text_iter_compare (&selection_start, &line_end) <= 0 &&
+                  gtk_text_iter_compare (&selection_end, &line_start) >= 0)
                 {
                   if (gtk_text_iter_compare (&selection_start, &line_start) >= 0)
                     selection_start_index = gtk_text_iter_get_line_index (&selection_start);
@@ -775,30 +824,54 @@ gtk_text_layout_draw (GtkTextLayout *layout,
           render_para (drawable, render_state, line_display,
                        - x_offset,
                        current_y,
-                       selection_start_index, selection_end_index);
-
+                       selection_start_index, selection_end_index,
+                       widgets);
 
           /* 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)
             {
               GtkTextCursorDisplay *cursor = cursor_list->data;
+             GtkTextDirection dir;
+             GdkRectangle cursor_location;
               GdkGC *gc;
 
-              if (cursor->is_strong)
-                gc = widget->style->base_gc[GTK_STATE_SELECTED];
-              else
-                gc = widget->style->text_gc[GTK_STATE_NORMAL];
-
-              gdk_gc_set_clip_rectangle(gc, &clip);
-              gdk_draw_line (drawable, gc,
-                             line_display->x_offset + cursor->x - x_offset,
-                             current_y + line_display->top_margin + cursor->y,
-                             line_display->x_offset + cursor->x - x_offset,
-                             current_y + line_display->top_margin + cursor->y + cursor->height - 1);
-              gdk_gc_set_clip_rectangle(gc, NULL);
+              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;
+             gc = _gtk_get_insertion_cursor_gc (widget, cursor->is_strong);
+             gdk_gc_set_clip_rectangle(gc, &clip);
+             _gtk_draw_insertion_cursor (widget, drawable, gc, &cursor_location,
+                                          dir, have_strong && have_weak);
+              gdk_gc_set_clip_rectangle (gc, NULL);
+
+             g_object_unref (gc);
 
               cursor_list = cursor_list->next;
             }