]> Pileus Git - ~andy/gtk/blob - gtk/gtktextdisplay.c
Applied patch from maemo-gtk that addresses many issues wrt display
[~andy/gtk] / gtk / gtktextdisplay.c
1 /* gtktextdisplay.c - display layed-out text
2  *
3  * Copyright (c) 1992-1994 The Regents of the University of California.
4  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
5  * Copyright (c) 2000 Red Hat, Inc.
6  * Tk->Gtk port by Havoc Pennington
7  *
8  * This file can be used under your choice of two licenses, the LGPL
9  * and the original Tk license.
10  *
11  * LGPL:
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free
25  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  * Original Tk license:
28  *
29  * This software is copyrighted by the Regents of the University of
30  * California, Sun Microsystems, Inc., and other parties.  The
31  * following terms apply to all files associated with the software
32  * unless explicitly disclaimed in individual files.
33  *
34  * The authors hereby grant permission to use, copy, modify,
35  * distribute, and license this software and its documentation for any
36  * purpose, provided that existing copyright notices are retained in
37  * all copies and that this notice is included verbatim in any
38  * distributions. No written agreement, license, or royalty fee is
39  * required for any of the authorized uses.  Modifications to this
40  * software may be copyrighted by their authors and need not follow
41  * the licensing terms described here, provided that the new terms are
42  * clearly indicated on the first page of each file where they apply.
43  *
44  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
45  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
46  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
47  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
48  * OF THE POSSIBILITY OF SUCH DAMAGE.
49  *
50  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
51  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
53  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
54  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
55  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
56  *
57  * GOVERNMENT USE: If you are acquiring this software on behalf of the
58  * U.S. government, the Government shall have only "Restricted Rights"
59  * in the software and related documentation as defined in the Federal
60  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
61  * are acquiring the software on behalf of the Department of Defense,
62  * the software shall be classified as "Commercial Computer Software"
63  * and the Government shall have only "Restricted Rights" as defined
64  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
65  * foregoing, the authors grant the U.S. Government and others acting
66  * in its behalf permission to use and distribute the software in
67  * accordance with the terms specified in this license.
68  *
69  */
70 /*
71  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
72  * file for a list of people on the GTK+ Team.  See the ChangeLog
73  * files for a list of changes.  These files are distributed with
74  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
75  */
76
77 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
78 #include <config.h>
79 #include "gtktextdisplay.h"
80 #include "gtkintl.h"
81 #include "gtkalias.h"
82 /* DO NOT go putting private headers in here. This file should only
83  * use the semi-public headers, as with gtktextview.c.
84  */
85
86 #define GTK_TYPE_TEXT_RENDERER            (_gtk_text_renderer_get_type())
87 #define GTK_TEXT_RENDERER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_TEXT_RENDERER, GtkTextRenderer))
88 #define GTK_IS_TEXT_RENDERER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GTK_TYPE_TEXT_RENDERER))
89 #define GTK_TEXT_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TEXT_RENDERER, GtkTextRendererClass))
90 #define GTK_IS_TEXT_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TEXT_RENDERER))
91 #define GTK_TEXT_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TEXT_RENDERER, GtkTextRendererClass))
92
93 typedef struct _GtkTextRenderer      GtkTextRenderer;
94 typedef struct _GtkTextRendererClass GtkTextRendererClass;
95
96 struct _GtkTextRenderer
97 {
98   GdkPangoRenderer parent_instance;
99
100   GdkScreen *screen;
101
102   GtkWidget *widget;
103   GdkDrawable *drawable;
104   GdkRectangle clip_rect;
105   
106   GdkColor *error_color;        /* Error underline color for this widget */
107   GList *widgets;               /* widgets encountered when drawing */
108   
109   gboolean selected;
110 };
111
112 struct _GtkTextRendererClass
113 {
114   GdkPangoRendererClass parent_class;
115 };
116
117 G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, GDK_TYPE_PANGO_RENDERER)
118
119 static GdkColor *
120 text_renderer_get_error_color (GtkTextRenderer *text_renderer)
121 {
122   static const GdkColor red = { 0, 0xffff, 0, 0 };
123
124   if (!text_renderer->error_color)
125     gtk_widget_style_get (text_renderer->widget,
126                           "error-underline_color", &text_renderer->error_color,
127                           NULL);
128   
129   if (!text_renderer->error_color)
130     text_renderer->error_color = gdk_color_copy (&red);
131
132   return text_renderer->error_color;
133 }
134
135 static void
136 text_renderer_set_gdk_color (GtkTextRenderer *text_renderer,
137                              PangoRenderPart  part,
138                              GdkColor        *gdk_color)
139 {
140   PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
141
142   if (gdk_color)
143     {
144       PangoColor color;
145
146       color.red = gdk_color->red;
147       color.green = gdk_color->green;
148       color.blue = gdk_color->blue;
149       
150       pango_renderer_set_color (renderer, part, &color);
151     }
152   else
153     pango_renderer_set_color (renderer, part, NULL);
154            
155 }
156
157 static GtkTextAppearance *
158 get_item_appearance (PangoItem *item)
159 {
160   GSList *tmp_list = item->analysis.extra_attrs;
161
162   while (tmp_list)
163     {
164       PangoAttribute *attr = tmp_list->data;
165
166       if (attr->klass->type == gtk_text_attr_appearance_type)
167         return &((GtkTextAttrAppearance *)attr)->appearance;
168
169       tmp_list = tmp_list->next;
170     }
171
172   return NULL;
173 }
174
175 static void
176 gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
177                                PangoLayoutRun *run)
178 {
179   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
180   GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
181   GdkColor *bg_color, *fg_color, *underline_color;
182   GdkPixmap *fg_stipple, *bg_stipple;
183   GtkTextAppearance *appearance;
184
185   PANGO_RENDERER_CLASS (_gtk_text_renderer_parent_class)->prepare_run (renderer, run);
186
187   appearance = get_item_appearance (run->item);
188   g_assert (appearance != NULL);
189   
190   if (appearance->draw_bg && !text_renderer->selected)
191     bg_color = &appearance->bg_color;
192   else
193     bg_color = NULL;
194   
195   text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_color);
196
197   if (text_renderer->selected)
198     {
199       if (GTK_WIDGET_HAS_FOCUS (text_renderer->widget))
200         fg_color = &text_renderer->widget->style->text[GTK_STATE_SELECTED];
201       else
202         fg_color = &text_renderer->widget->style->text[GTK_STATE_ACTIVE];
203     }
204   else
205     fg_color = &appearance->fg_color;
206
207   text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_color);
208   text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_color);
209
210   if (appearance->underline == PANGO_UNDERLINE_ERROR)
211     underline_color = text_renderer_get_error_color (text_renderer);
212   else
213     underline_color = fg_color;
214
215   text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, underline_color);
216
217   fg_stipple = appearance->fg_stipple;
218   if (fg_stipple && text_renderer->screen != gdk_drawable_get_screen (fg_stipple))
219     {
220       g_warning ("gtk_text_renderer_prepare_run:\n"
221                  "The foreground stipple bitmap has been created on the wrong screen.\n"
222                  "Ignoring the stipple bitmap information.");
223       fg_stipple = NULL;
224     }
225       
226   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, fg_stipple);
227   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_stipple);
228   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, fg_stipple);
229
230   bg_stipple = appearance->draw_bg ? appearance->bg_stipple : NULL;
231   
232   if (bg_stipple && text_renderer->screen != gdk_drawable_get_screen (bg_stipple))
233     {
234       g_warning ("gtk_text_renderer_prepare_run:\n"
235                  "The background stipple bitmap has been created on the wrong screen.\n"
236                  "Ignoring the stipple bitmap information.");
237       bg_stipple = NULL;
238     }
239   
240   gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, bg_stipple);
241 }
242
243 static void
244 gtk_text_renderer_draw_shape (PangoRenderer   *renderer,
245                               PangoAttrShape  *attr,
246                               int              x,
247                               int              y)
248 {
249   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
250   GdkGC *fg_gc;
251
252   if (text_renderer->selected)
253     {
254       if (GTK_WIDGET_HAS_FOCUS (text_renderer->widget))
255         fg_gc = text_renderer->widget->style->text_gc[GTK_STATE_SELECTED];
256       else
257         fg_gc = text_renderer->widget->style->text_gc[GTK_STATE_SELECTED];
258     }
259   else
260     fg_gc = text_renderer->widget->style->text_gc[GTK_STATE_NORMAL];
261   
262   if (attr->data == NULL)
263     {
264       /* This happens if we have an empty widget anchor. Draw
265        * something empty-looking.
266        */
267       GdkRectangle shape_rect, draw_rect;
268       
269       shape_rect.x = PANGO_PIXELS (x);
270       shape_rect.y = PANGO_PIXELS (y + attr->logical_rect.y);
271       shape_rect.width = PANGO_PIXELS (x + attr->logical_rect.width) - shape_rect.x;
272       shape_rect.height = PANGO_PIXELS (y + attr->logical_rect.y + attr->logical_rect.height) - shape_rect.y;
273       
274       if (gdk_rectangle_intersect (&shape_rect, &text_renderer->clip_rect,
275                                    &draw_rect))
276         {
277           gdk_draw_rectangle (text_renderer->drawable, fg_gc,
278                               FALSE, shape_rect.x, shape_rect.y,
279                               shape_rect.width, shape_rect.height);
280           
281           gdk_draw_line (text_renderer->drawable, fg_gc,
282                          shape_rect.x, shape_rect.y,
283                          shape_rect.x + shape_rect.width,
284                          shape_rect.y + shape_rect.height);
285           
286           gdk_draw_line (text_renderer->drawable, fg_gc,
287                          shape_rect.x + shape_rect.width, shape_rect.y,
288                          shape_rect.x,
289                          shape_rect.y + shape_rect.height);
290         }
291     }
292   else if (GDK_IS_PIXBUF (attr->data))
293     {
294       gint width, height;
295       GdkRectangle pixbuf_rect, draw_rect;
296       GdkPixbuf *pixbuf;
297       
298       pixbuf = GDK_PIXBUF (attr->data);
299       
300       width = gdk_pixbuf_get_width (pixbuf);
301       height = gdk_pixbuf_get_height (pixbuf);
302       
303       pixbuf_rect.x = PANGO_PIXELS (x);
304       pixbuf_rect.y = PANGO_PIXELS (y) - height;
305       pixbuf_rect.width = width;
306       pixbuf_rect.height = height;
307       
308       if (gdk_rectangle_intersect (&pixbuf_rect, &text_renderer->clip_rect,
309                                    &draw_rect))
310         {
311           gdk_draw_pixbuf (text_renderer->drawable,
312                            fg_gc,
313                            pixbuf,
314                            draw_rect.x - pixbuf_rect.x,
315                            draw_rect.y - pixbuf_rect.y,
316                            draw_rect.x, draw_rect.y,
317                            draw_rect.width,
318                            draw_rect.height,
319                            GDK_RGB_DITHER_NORMAL,
320                            0, 0);
321         }
322     }
323   else if (GTK_IS_WIDGET (attr->data))
324     {
325       GtkWidget *widget;
326       
327       widget = GTK_WIDGET (attr->data);
328
329       text_renderer->widgets = g_list_prepend (text_renderer->widgets,
330                                                g_object_ref (widget));
331     }
332   else
333     g_assert_not_reached (); /* not a pixbuf or widget */
334 }
335
336 static void
337 gtk_text_renderer_finalize (GObject *object)
338 {
339   G_OBJECT_CLASS (_gtk_text_renderer_parent_class)->finalize (object);
340 }
341
342 static void
343 _gtk_text_renderer_init (GtkTextRenderer *renderer)
344 {
345 }
346
347 static void
348 _gtk_text_renderer_class_init (GtkTextRendererClass *klass)
349 {
350   GObjectClass *object_class = G_OBJECT_CLASS (klass);
351   
352   PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
353   
354   renderer_class->prepare_run = gtk_text_renderer_prepare_run;
355   renderer_class->draw_shape = gtk_text_renderer_draw_shape;
356
357   object_class->finalize = gtk_text_renderer_finalize;
358 }
359
360 static void
361 text_renderer_set_selected (GtkTextRenderer *text_renderer,
362                             gboolean         selected)
363 {
364   text_renderer->selected = selected;
365 }
366
367 static void
368 text_renderer_begin (GtkTextRenderer *text_renderer,
369                      GtkWidget       *widget,
370                      GdkDrawable     *drawable,
371                      GdkRectangle    *clip_rect)
372 {
373   text_renderer->widget = widget;
374   text_renderer->drawable = drawable;
375   text_renderer->clip_rect = *clip_rect;
376
377   gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (text_renderer), drawable);
378   gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer),
379                              widget->style->text_gc[widget->state]);
380 }
381
382 /* Returns a GSList of (referenced) widgets encountered while drawing.
383  */
384 static GList *
385 text_renderer_end (GtkTextRenderer *text_renderer)
386 {
387   GList *widgets = text_renderer->widgets;
388
389   text_renderer->widget = NULL;
390   text_renderer->drawable = NULL;
391
392   text_renderer->widgets = NULL;
393
394   if (text_renderer->error_color)
395     {
396       gdk_color_free (text_renderer->error_color);
397       text_renderer->error_color = NULL;
398     }
399
400   gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (text_renderer), NULL);
401   gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer), NULL);
402
403   return widgets;
404 }
405
406
407 static GdkRegion *
408 get_selected_clip (GtkTextRenderer    *text_renderer,
409                    PangoLayout        *layout,
410                    PangoLayoutLine    *line,
411                    int                 x,
412                    int                 y,
413                    int                 height,
414                    int                 start_index,
415                    int                 end_index)
416 {
417   gint *ranges;
418   gint n_ranges, i;
419   GdkRegion *clip_region = gdk_region_new ();
420   GdkRegion *tmp_region;
421
422   pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges);
423
424   for (i=0; i < n_ranges; i++)
425     {
426       GdkRectangle rect;
427
428       rect.x = x + PANGO_PIXELS (ranges[2*i]);
429       rect.y = y;
430       rect.width = PANGO_PIXELS (ranges[2*i + 1]) - PANGO_PIXELS (ranges[2*i]);
431       rect.height = height;
432       
433       gdk_region_union_with_rect (clip_region, &rect);
434     }
435
436   tmp_region = gdk_region_rectangle (&text_renderer->clip_rect);
437   gdk_region_intersect (clip_region, tmp_region);
438   gdk_region_destroy (tmp_region);
439
440   g_free (ranges);
441   return clip_region;
442 }
443
444 static void
445 render_para (GtkTextRenderer    *text_renderer,
446              GtkTextLineDisplay *line_display,
447              /* Top-left corner of paragraph including all margins */
448              int                 x,
449              int                 y,
450              int                 selection_start_index,
451              int                 selection_end_index)
452 {
453   PangoLayout *layout = line_display->layout;
454   int byte_offset = 0;
455   PangoLayoutIter *iter;
456   PangoRectangle layout_logical;
457   int screen_width;
458   GdkGC *selection_gc, *fg_gc;
459   gint state;
460   
461   gboolean first = TRUE;
462
463   iter = pango_layout_get_iter (layout);
464
465   pango_layout_iter_get_layout_extents (iter, NULL, &layout_logical);
466
467   /* Adjust for margins */
468   
469   layout_logical.x += line_display->x_offset * PANGO_SCALE;
470   layout_logical.y += line_display->top_margin * PANGO_SCALE;
471
472   screen_width = line_display->total_width;
473   
474   if (GTK_WIDGET_HAS_FOCUS (text_renderer->widget))
475     state = GTK_STATE_SELECTED;
476   else
477     state = GTK_STATE_ACTIVE;
478
479   selection_gc = text_renderer->widget->style->base_gc [state];
480   fg_gc = text_renderer->widget->style->text_gc[text_renderer->widget->state];
481
482   do
483     {
484       PangoLayoutLine *line = pango_layout_iter_get_line (iter);
485       int selection_y, selection_height;
486       int first_y, last_y;
487       PangoRectangle line_rect;
488       int baseline;
489       
490       pango_layout_iter_get_line_extents (iter, NULL, &line_rect);
491       baseline = pango_layout_iter_get_baseline (iter);
492       pango_layout_iter_get_line_yrange (iter, &first_y, &last_y);
493       
494       /* Adjust for margins */
495
496       line_rect.x += line_display->x_offset * PANGO_SCALE;
497       line_rect.y += line_display->top_margin * PANGO_SCALE;
498       baseline += line_display->top_margin * PANGO_SCALE;
499
500       /* Selection is the height of the line, plus top/bottom
501        * margin if we're the first/last line
502        */
503       selection_y = y + PANGO_PIXELS (first_y) + line_display->top_margin;
504       selection_height = PANGO_PIXELS (last_y) - PANGO_PIXELS (first_y);
505
506       if (first)
507         {
508           selection_y -= line_display->top_margin;
509           selection_height += line_display->top_margin;
510         }
511       
512       if (pango_layout_iter_at_last_line (iter))
513         selection_height += line_display->bottom_margin;
514       
515       first = FALSE;
516
517       if (selection_start_index < byte_offset &&
518           selection_end_index > line->length + byte_offset) /* All selected */
519         {
520           gdk_draw_rectangle (text_renderer->drawable,
521                               selection_gc,
522                               TRUE,
523                               x + line_display->left_margin,
524                               selection_y,
525                               screen_width,
526                               selection_height);
527
528           text_renderer_set_selected (text_renderer, TRUE);
529           pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
530                                            line, 
531                                            PANGO_SCALE * x + line_rect.x,
532                                            PANGO_SCALE * y + baseline);
533         }
534       else
535         {
536           if (line_display->pg_bg_color)
537             {
538               GdkGC *bg_gc;
539               
540               bg_gc = gdk_gc_new (text_renderer->drawable);
541               gdk_gc_set_fill (bg_gc, GDK_SOLID);
542               gdk_gc_set_rgb_fg_color (bg_gc, line_display->pg_bg_color);
543             
544               gdk_draw_rectangle (text_renderer->drawable,
545                                   bg_gc,
546                                   TRUE,
547                                   x + line_display->left_margin,
548                                   selection_y,
549                                   screen_width,
550                                   selection_height);
551               
552               g_object_unref (bg_gc);
553             }
554         
555           text_renderer_set_selected (text_renderer, FALSE);
556           pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
557                                            line, 
558                                            PANGO_SCALE * x + line_rect.x,
559                                            PANGO_SCALE * y + baseline);
560
561           /* Check if some part of the line is selected; the newline
562            * that is after line->length for the last line of the
563            * paragraph counts as part of the line for this
564            */
565           if ((selection_start_index < byte_offset + line->length ||
566                (selection_start_index == byte_offset + line->length && pango_layout_iter_at_last_line (iter))) &&
567               selection_end_index > byte_offset)
568             {
569               GdkRegion *clip_region = get_selected_clip (text_renderer, layout, line,
570                                                           x + line_display->x_offset,
571                                                           selection_y,
572                                                           selection_height,
573                                                           selection_start_index, selection_end_index);
574
575               /* When we change the clip on the foreground GC, we have to set
576                * it on the rendererer again, since the rendererer might have
577                * copied the GC to change attributes.
578                */
579               gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer), NULL);
580               gdk_gc_set_clip_region (selection_gc, clip_region);
581               gdk_gc_set_clip_region (fg_gc, clip_region);
582               gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer), fg_gc);
583
584               gdk_draw_rectangle (text_renderer->drawable,
585                                   selection_gc,
586                                   TRUE,
587                                   x + PANGO_PIXELS (line_rect.x),
588                                   selection_y,
589                                   PANGO_PIXELS (line_rect.width),
590                                   selection_height);
591
592               text_renderer_set_selected (text_renderer, TRUE);
593               pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
594                                                line, 
595                                                PANGO_SCALE * x + line_rect.x,
596                                                PANGO_SCALE * y + baseline);
597
598               gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer), NULL);
599               gdk_gc_set_clip_region (selection_gc, NULL);
600               gdk_gc_set_clip_region (fg_gc, NULL);
601               gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (text_renderer), fg_gc);
602               
603               gdk_region_destroy (clip_region);
604
605               /* Paint in the ends of the line */
606               if (line_rect.x > line_display->left_margin * PANGO_SCALE &&
607                   ((line_display->direction == GTK_TEXT_DIR_LTR && selection_start_index < byte_offset) ||
608                    (line_display->direction == GTK_TEXT_DIR_RTL && selection_end_index > byte_offset + line->length)))
609                 {
610                   gdk_draw_rectangle (text_renderer->drawable,
611                                       selection_gc,
612                                       TRUE,
613                                       x + line_display->left_margin,
614                                       selection_y,
615                                       PANGO_PIXELS (line_rect.x) - line_display->left_margin,
616                                       selection_height);
617                 }
618
619               if (line_rect.x + line_rect.width <
620                   (screen_width + line_display->left_margin) * PANGO_SCALE &&
621                   ((line_display->direction == GTK_TEXT_DIR_LTR && selection_end_index > byte_offset + line->length) ||
622                    (line_display->direction == GTK_TEXT_DIR_RTL && selection_start_index < byte_offset)))
623                 {
624                   int nonlayout_width;
625
626                   nonlayout_width =
627                     line_display->left_margin + screen_width -
628                     PANGO_PIXELS (line_rect.x) - PANGO_PIXELS (line_rect.width);
629
630                   gdk_draw_rectangle (text_renderer->drawable,
631                                       selection_gc,
632                                       TRUE,
633                                       x + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width),
634                                       selection_y,
635                                       nonlayout_width,
636                                       selection_height);
637                 }
638             }
639         }
640
641       byte_offset += line->length;
642     }
643   while (pango_layout_iter_next_line (iter));
644
645   pango_layout_iter_free (iter);
646 }
647
648 static void
649 on_renderer_display_closed (GdkDisplay       *display,
650                             gboolean          is_error,
651                             GtkTextRenderer  *text_renderer)
652 {
653   g_signal_handlers_disconnect_by_func (text_renderer->screen,
654                                         (gpointer)on_renderer_display_closed,
655                                         text_renderer);
656   g_object_set_data (G_OBJECT (text_renderer->screen), I_("gtk-text-renderer"), NULL);
657 }
658
659 static GtkTextRenderer *
660 get_text_renderer (GdkScreen *screen)
661 {
662   GtkTextRenderer *text_renderer;
663
664   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
665   
666   text_renderer = g_object_get_data (G_OBJECT (screen), "gtk-text-renderer");
667   if (!text_renderer)
668     {
669       text_renderer = g_object_new (GTK_TYPE_TEXT_RENDERER, "screen", screen, NULL);
670       text_renderer->screen = screen;
671       
672       g_object_set_data_full (G_OBJECT (screen), I_("gtk-text-renderer"), text_renderer,
673                               (GDestroyNotify)g_object_unref);
674
675       g_signal_connect_object (gdk_screen_get_display (screen), "closed",
676                                G_CALLBACK (on_renderer_display_closed),
677                                text_renderer, 0);
678     }
679
680   return text_renderer;
681 }
682
683 void
684 gtk_text_layout_draw (GtkTextLayout *layout,
685                       GtkWidget *widget,
686                       GdkDrawable *drawable,
687                       GdkGC       *cursor_gc,
688                       /* Location of the drawable
689                          in layout coordinates */
690                       gint x_offset,
691                       gint y_offset,
692                       /* Region of the layout to
693                          render */
694                       gint x,
695                       gint y,
696                       gint width,
697                       gint height,
698                       /* widgets to expose */
699                       GList **widgets)
700 {
701   GdkRectangle clip;
702   gint current_y;
703   GSList *cursor_list;
704   GtkTextRenderer *text_renderer;
705   GtkTextIter selection_start, selection_end;
706   gboolean have_selection = FALSE;
707   GSList *line_list;
708   GSList *tmp_list;
709   GList *tmp_widgets;
710   
711   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
712   g_return_if_fail (layout->default_style != NULL);
713   g_return_if_fail (layout->buffer != NULL);
714   g_return_if_fail (drawable != NULL);
715   g_return_if_fail (width >= 0);
716   g_return_if_fail (height >= 0);
717
718   if (width == 0 || height == 0)
719     return;
720
721   line_list =  gtk_text_layout_get_lines (layout, y + y_offset, y + y_offset + height, &current_y);
722   current_y -= y_offset;
723
724   if (line_list == NULL)
725     return; /* nothing on the screen */
726
727   clip.x = x;
728   clip.y = y;
729   clip.width = width;
730   clip.height = height;
731
732   text_renderer = get_text_renderer (gdk_drawable_get_screen (drawable));
733
734   text_renderer_begin (text_renderer, widget, drawable, &clip);
735
736   gtk_text_layout_wrap_loop_start (layout);
737
738   if (gtk_text_buffer_get_selection_bounds (layout->buffer,
739                                             &selection_start,
740                                             &selection_end))
741     have_selection = TRUE;
742
743   tmp_list = line_list;
744   while (tmp_list != NULL)
745     {
746       GtkTextLineDisplay *line_display;
747       gint selection_start_index = -1;
748       gint selection_end_index = -1;
749       gboolean have_strong;
750       gboolean have_weak;
751
752       GtkTextLine *line = tmp_list->data;
753
754       line_display = gtk_text_layout_get_line_display (layout, line, FALSE);
755
756       if (line_display->height > 0)
757         {
758           g_assert (line_display->layout != NULL);
759           
760           if (have_selection)
761             {
762               GtkTextIter line_start, line_end;
763               gint byte_count;
764               
765               gtk_text_layout_get_iter_at_line (layout,
766                                                 &line_start,
767                                                 line, 0);
768               line_end = line_start;
769               if (!gtk_text_iter_ends_line (&line_end))
770                 gtk_text_iter_forward_to_line_end (&line_end);
771               byte_count = gtk_text_iter_get_visible_line_index (&line_end);     
772
773               if (gtk_text_iter_compare (&selection_start, &line_end) <= 0 &&
774                   gtk_text_iter_compare (&selection_end, &line_start) >= 0)
775                 {
776                   if (gtk_text_iter_compare (&selection_start, &line_start) >= 0)
777                     selection_start_index = gtk_text_iter_get_visible_line_index (&selection_start);
778                   else
779                     selection_start_index = -1;
780
781                   if (gtk_text_iter_compare (&selection_end, &line_end) <= 0)
782                     selection_end_index = gtk_text_iter_get_visible_line_index (&selection_end);
783                   else
784                     selection_end_index = byte_count + 1; /* + 1 to flag past-the-end */
785                 }
786             }
787
788           render_para (text_renderer, line_display,
789                        - x_offset,
790                        current_y,
791                        selection_start_index, selection_end_index);
792
793           /* We paint the cursors last, because they overlap another chunk
794          and need to appear on top. */
795
796           have_strong = FALSE;
797           have_weak = FALSE;
798           
799           cursor_list = line_display->cursors;
800           while (cursor_list)
801             {
802               GtkTextCursorDisplay *cursor = cursor_list->data;
803               if (cursor->is_strong)
804                 have_strong = TRUE;
805               else
806                 have_weak = TRUE;
807               
808               cursor_list = cursor_list->next;
809             }
810           
811           cursor_list = line_display->cursors;
812           while (cursor_list)
813             {
814               GtkTextCursorDisplay *cursor = cursor_list->data;
815               GtkTextDirection dir;
816               GdkRectangle cursor_location;
817
818               dir = line_display->direction;
819               if (have_strong && have_weak)
820                 {
821                   if (!cursor->is_strong)
822                     dir = (dir == GTK_TEXT_DIR_RTL) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
823                 }
824  
825               cursor_location.x = line_display->x_offset + cursor->x - x_offset;
826               cursor_location.y = current_y + line_display->top_margin + cursor->y;
827               cursor_location.width = 0;
828               cursor_location.height = cursor->height;
829
830               gtk_draw_insertion_cursor (widget, drawable, &clip, &cursor_location,
831                                          cursor->is_strong,
832                                          dir, have_strong && have_weak);
833
834               cursor_list = cursor_list->next;
835             }
836         } /* line_display->height > 0 */
837           
838       current_y += line_display->height;
839       gtk_text_layout_free_line_display (layout, line_display);
840       
841       tmp_list = g_slist_next (tmp_list);
842     }
843
844   gtk_text_layout_wrap_loop_end (layout);
845
846   tmp_widgets = text_renderer_end (text_renderer);
847   if (widgets)
848     *widgets = tmp_widgets;
849   else
850     {
851       g_list_foreach (tmp_widgets, (GFunc)g_object_unref, NULL);
852       g_list_free (tmp_widgets);
853     }
854
855   g_slist_free (line_list);
856 }
857
858 #define __GTK_TEXT_DISPLAY_C__
859 #include "gtkaliasdef.c"