2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17 * =========================================================================
19 * xtext, the text widget used by X-Chat.
20 * By Peter Zelezny <zed@xchat.org>.
24 #define XCHAT /* using xchat */
25 #define TINT_VALUE 195 /* 195/255 of the brightness. */
26 #define MOTION_MONITOR /* URL hilights. */
27 #define SMOOTH_SCROLL /* line-by-line or pixel scroll? */
28 #define SCROLL_HACK /* use XCopyArea scroll, or full redraw? */
29 #undef COLOR_HILIGHT /* Color instead of underline? */
30 /* Italic is buggy because it assumes drawing an italic string will have
31 identical extents to the normal font. This is only true some of the
32 time, so we can't use this hack yet. */
33 #undef ITALIC /* support Italic? */
34 #define GDK_MULTIHEAD_SAFE
35 #define USE_DB /* double buffer */
37 #define MARGIN 2 /* dont touch. */
38 #define REFRESH_TIMEOUT 20
39 #define WORDWRAP_LIMIT 24
46 #include <gtk/gtkmain.h>
47 #include <gtk/gtksignal.h>
48 #include <gtk/gtkselection.h>
49 #include <gtk/gtkclipboard.h>
50 #include <gtk/gtkversion.h>
51 #include <gtk/gtkwindow.h>
61 #include <X11/Xatom.h>
66 #define charlen(str) g_utf8_skip[*(guchar *)(str)]
71 (c == ' ' || c == '\n' || c == ')' || c == '(' || \
72 c == '>' || c == '<' || c == ATTR_RESET || c == ATTR_BOLD || c == 0)
75 /* force scrolling off */
76 #define dontscroll(buf) (buf)->last_pixel_pos = 0x7fffffff
78 #define dontscroll(buf)
81 static GtkWidgetClass
*parent_class
= NULL
;
85 struct textentry
*next
;
86 struct textentry
*prev
;
96 #define RECORD_WRAPS 4
97 guint16 wrap_offset
[RECORD_WRAPS
];
98 guchar mb
; /* boolean: is multibyte? */
101 guchar pad2
; /* 32-bit align : 44 bytes total */
110 /* values for selection info */
119 static guint xtext_signals
[LAST_SIGNAL
];
122 char *nocasestrstr (const char *text
, const char *tofind
); /* util.c */
123 int xtext_get_stamp_str (time_t, char **);
125 static void gtk_xtext_render_page (GtkXText
* xtext
);
126 static void gtk_xtext_calc_lines (xtext_buffer
*buf
, int);
127 #if defined(USE_XLIB)
128 static void gtk_xtext_load_trans (GtkXText
* xtext
);
129 static void gtk_xtext_free_trans (GtkXText
* xtext
);
131 static char *gtk_xtext_selection_get_text (GtkXText
*xtext
, int *len_ret
);
132 static textentry
*gtk_xtext_nth (GtkXText
*xtext
, int line
, int *subline
);
133 static void gtk_xtext_adjustment_changed (GtkAdjustment
* adj
,
135 static int gtk_xtext_render_ents (GtkXText
* xtext
, textentry
*, textentry
*);
136 static void gtk_xtext_recalc_widths (xtext_buffer
*buf
, int);
137 static void gtk_xtext_fix_indent (xtext_buffer
*buf
);
138 static int gtk_xtext_find_subline (GtkXText
*xtext
, textentry
*ent
, int line
);
139 static char *gtk_xtext_conv_color (unsigned char *text
, int len
, int *newlen
);
140 static unsigned char *
141 gtk_xtext_strip_color (unsigned char *text
, int len
, unsigned char *outbuf
,
142 int *newlen
, int *mb_ret
, int strip_hidden
);
143 static gboolean
gtk_xtext_check_ent_visibility (GtkXText
* xtext
, textentry
*find_ent
, int add
);
144 static int gtk_xtext_render_page_timeout (GtkXText
* xtext
);
146 /* some utility functions first */
148 #ifndef XCHAT /* xchat has this in util.c */
151 nocasestrstr (const char *s
, const char *tofind
)
153 register const size_t len
= strlen (tofind
);
157 while (toupper(*s
) != toupper(*tofind
) || strncasecmp (s
, tofind
, len
))
165 /* gives width of a 8bit string - with no mIRC codes in it */
168 gtk_xtext_text_width_8bit (GtkXText
*xtext
, unsigned char *str
, int len
)
174 width
+= xtext
->fontwidth
[*str
];
182 #define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc, 1,x,y,w,h);
184 /* ========================================= */
185 /* ========== XFT 1 and 2 BACKEND ========== */
186 /* ========================================= */
191 backend_font_close (GtkXText
*xtext
)
193 XftFontClose (GDK_WINDOW_XDISPLAY (xtext
->draw_buf
), xtext
->font
);
195 XftFontClose (GDK_WINDOW_XDISPLAY (xtext
->draw_buf
), xtext
->ifont
);
200 backend_init (GtkXText
*xtext
)
202 if (xtext
->xftdraw
== NULL
)
204 xtext
->xftdraw
= XftDrawCreate (
205 GDK_WINDOW_XDISPLAY (xtext
->draw_buf
),
206 GDK_WINDOW_XWINDOW (xtext
->draw_buf
),
207 GDK_VISUAL_XVISUAL (gdk_drawable_get_visual (xtext
->draw_buf
)),
208 GDK_COLORMAP_XCOLORMAP (gdk_drawable_get_colormap (xtext
->draw_buf
)));
209 XftDrawSetSubwindowMode (xtext
->xftdraw
, IncludeInferiors
);
214 backend_deinit (GtkXText
*xtext
)
218 XftDrawDestroy (xtext
->xftdraw
);
219 xtext
->xftdraw
= NULL
;
224 backend_font_open_real (Display
*xdisplay
, char *name
, gboolean italics
)
226 XftFont
*font
= NULL
;
227 PangoFontDescription
*fontd
;
228 int weight
, slant
, screen
= DefaultScreen (xdisplay
);
230 fontd
= pango_font_description_from_string (name
);
232 if (pango_font_description_get_size (fontd
) != 0)
234 weight
= pango_font_description_get_weight (fontd
);
235 /* from pangoft2-fontmap.c */
236 if (weight
< (PANGO_WEIGHT_NORMAL
+ PANGO_WEIGHT_LIGHT
) / 2)
237 weight
= XFT_WEIGHT_LIGHT
;
238 else if (weight
< (PANGO_WEIGHT_NORMAL
+ 600) / 2)
239 weight
= XFT_WEIGHT_MEDIUM
;
240 else if (weight
< (600 + PANGO_WEIGHT_BOLD
) / 2)
241 weight
= XFT_WEIGHT_DEMIBOLD
;
242 else if (weight
< (PANGO_WEIGHT_BOLD
+ PANGO_WEIGHT_ULTRABOLD
) / 2)
243 weight
= XFT_WEIGHT_BOLD
;
245 weight
= XFT_WEIGHT_BLACK
;
247 slant
= pango_font_description_get_style (fontd
);
248 if (slant
== PANGO_STYLE_ITALIC
)
249 slant
= XFT_SLANT_ITALIC
;
250 else if (slant
== PANGO_STYLE_OBLIQUE
)
251 slant
= XFT_SLANT_OBLIQUE
;
253 slant
= XFT_SLANT_ROMAN
;
255 font
= XftFontOpen (xdisplay
, screen
,
256 XFT_FAMILY
, XftTypeString
, pango_font_description_get_family (fontd
),
257 XFT_CORE
, XftTypeBool
, False
,
258 XFT_SIZE
, XftTypeDouble
, (double)pango_font_description_get_size (fontd
)/PANGO_SCALE
,
259 XFT_WEIGHT
, XftTypeInteger
, weight
,
260 XFT_SLANT
, XftTypeInteger
, italics
? XFT_SLANT_ITALIC
: slant
,
263 pango_font_description_free (fontd
);
267 font
= XftFontOpenName (xdisplay
, screen
, name
);
269 font
= XftFontOpenName (xdisplay
, screen
, "sans-11");
276 backend_font_open (GtkXText
*xtext
, char *name
)
278 Display
*dis
= GDK_WINDOW_XDISPLAY (xtext
->draw_buf
);
280 xtext
->font
= backend_font_open_real (dis
, name
, FALSE
);
282 xtext
->ifont
= backend_font_open_real (dis
, name
, TRUE
);
287 backend_get_char_width (GtkXText
*xtext
, unsigned char *str
, int *mbl_ret
)
294 return xtext
->fontwidth
[*str
];
297 *mbl_ret
= charlen (str
);
298 XftTextExtentsUtf8 (GDK_WINDOW_XDISPLAY (xtext
->draw_buf
), xtext
->font
, str
, *mbl_ret
, &ext
);
304 backend_get_text_width (GtkXText
*xtext
, guchar
*str
, int len
, int is_mb
)
309 return gtk_xtext_text_width_8bit (xtext
, str
, len
);
311 XftTextExtentsUtf8 (GDK_WINDOW_XDISPLAY (xtext
->draw_buf
), xtext
->font
, str
, len
, &ext
);
316 backend_draw_text (GtkXText
*xtext
, int dofill
, GdkGC
*gc
, int x
, int y
,
317 char *str
, int len
, int str_width
, int is_mb
)
319 /*Display *xdisplay = GDK_WINDOW_XDISPLAY (xtext->draw_buf);*/
320 void (*draw_func
) (XftDraw
*, XftColor
*, XftFont
*, int, int, XftChar8
*, int) = (void *)XftDrawString8
;
323 /* if all ascii, use String8 to avoid the conversion penalty */
325 draw_func
= (void *)XftDrawStringUtf8
;
329 /* register GC xgc = GDK_GC_XGC (gc);
330 XSetForeground (xdisplay, xgc, xtext->xft_bg->pixel);
331 XFillRectangle (xdisplay, GDK_WINDOW_XWINDOW (xtext->draw_buf), xgc, x,
332 y - xtext->font->ascent, str_width, xtext->fontsize);*/
333 XftDrawRect (xtext
->xftdraw
, xtext
->xft_bg
, x
,
334 y
- xtext
->font
->ascent
, str_width
, xtext
->fontsize
);
343 draw_func (xtext
->xftdraw
, xtext
->xft_fg
, font
, x
, y
, str
, len
);
346 draw_func (xtext
->xftdraw
, xtext
->xft_fg
, font
, x
, y
, str
, len
);
349 draw_func (xtext
->xftdraw
, xtext
->xft_fg
, font
, x
+ 1, y
, str
, len
);
353 backend_set_clip (GtkXText *xtext, GdkRectangle *area)
355 gdk_gc_set_clip_rectangle (xtext->fgc, area);
356 gdk_gc_set_clip_rectangle (xtext->bgc, area);
360 backend_clear_clip (GtkXText *xtext)
362 gdk_gc_set_clip_rectangle (xtext->fgc, NULL);
363 gdk_gc_set_clip_rectangle (xtext->bgc, NULL);
367 backend_set_clip (GtkXText *xtext, GdkRectangle *area)
374 rect.width = area->width;
375 rect.height = area->height;
377 reg = XCreateRegion ();
378 XUnionRectWithRegion (&rect, reg, reg);
379 XftDrawSetClip (xtext->xftdraw, reg);
380 XDestroyRegion (reg);
382 gdk_gc_set_clip_rectangle (xtext->fgc, area);
386 backend_clear_clip (GtkXText *xtext)
388 XftDrawSetClip (xtext->xftdraw, NULL);
389 gdk_gc_set_clip_rectangle (xtext->fgc, NULL);
394 /* ======================================= */
395 /* ============ PANGO BACKEND ============ */
396 /* ======================================= */
399 backend_font_close (GtkXText
*xtext
)
401 pango_font_description_free (xtext
->font
->font
);
403 pango_font_description_free (xtext
->font
->ifont
);
408 backend_init (GtkXText
*xtext
)
410 if (xtext
->layout
== NULL
)
412 xtext
->layout
= gtk_widget_create_pango_layout (GTK_WIDGET (xtext
), 0);
414 pango_layout_set_font_description (xtext
->layout
, xtext
->font
->font
);
419 backend_deinit (GtkXText
*xtext
)
423 g_object_unref (xtext
->layout
);
424 xtext
->layout
= NULL
;
428 static PangoFontDescription
*
429 backend_font_open_real (char *name
)
431 PangoFontDescription
*font
;
433 font
= pango_font_description_from_string (name
);
434 if (font
&& pango_font_description_get_size (font
) == 0)
436 pango_font_description_free (font
);
437 font
= pango_font_description_from_string ("sans 11");
440 font
= pango_font_description_from_string ("sans 11");
446 backend_font_open (GtkXText
*xtext
, char *name
)
449 PangoContext
*context
;
450 PangoFontMetrics
*metrics
;
452 xtext
->font
= &xtext
->pango_font
;
453 xtext
->font
->font
= backend_font_open_real (name
);
454 if (!xtext
->font
->font
)
460 xtext
->font
->ifont
= backend_font_open_real (name
);
461 pango_font_description_set_style (xtext
->font
->ifont
, PANGO_STYLE_ITALIC
);
464 backend_init (xtext
);
465 pango_layout_set_font_description (xtext
->layout
, xtext
->font
->font
);
467 /* vte does it this way */
468 context
= gtk_widget_get_pango_context (GTK_WIDGET (xtext
));
469 lang
= pango_context_get_language (context
);
470 metrics
= pango_context_get_metrics (context
, xtext
->font
->font
, lang
);
471 xtext
->font
->ascent
= pango_font_metrics_get_ascent (metrics
) / PANGO_SCALE
;
472 xtext
->font
->descent
= pango_font_metrics_get_descent (metrics
) / PANGO_SCALE
;
473 pango_font_metrics_unref (metrics
);
477 backend_get_text_width (GtkXText
*xtext
, guchar
*str
, int len
, int is_mb
)
482 return gtk_xtext_text_width_8bit (xtext
, str
, len
);
487 pango_layout_set_text (xtext
->layout
, str
, len
);
488 pango_layout_get_pixel_size (xtext
->layout
, &width
, NULL
);
494 backend_get_char_width (GtkXText
*xtext
, unsigned char *str
, int *mbl_ret
)
501 return xtext
->fontwidth
[*str
];
504 *mbl_ret
= charlen (str
);
505 pango_layout_set_text (xtext
->layout
, str
, *mbl_ret
);
506 pango_layout_get_pixel_size (xtext
->layout
, &width
, NULL
);
511 /* simplified version of gdk_draw_layout_line_with_colors() */
514 xtext_draw_layout_line (GdkDrawable
*drawable
,
518 PangoLayoutLine
*line
)
520 GSList
*tmp_list
= line
->runs
;
521 PangoRectangle logical_rect
;
526 PangoLayoutRun
*run
= tmp_list
->data
;
528 pango_glyph_string_extents (run
->glyphs
, run
->item
->analysis
.font
,
529 NULL
, &logical_rect
);
531 gdk_draw_glyphs (drawable
, gc
, run
->item
->analysis
.font
,
532 x
+ x_off
/ PANGO_SCALE
, y
, run
->glyphs
);
534 x_off
+= logical_rect
.width
;
535 tmp_list
= tmp_list
->next
;
540 backend_draw_text (GtkXText
*xtext
, int dofill
, GdkGC
*gc
, int x
, int y
,
541 char *str
, int len
, int str_width
, int is_mb
)
545 PangoLayoutLine
*line
;
549 pango_layout_set_font_description (xtext
->layout
, xtext
->font
->ifont
);
552 pango_layout_set_text (xtext
->layout
, str
, len
);
556 gdk_gc_get_values (gc
, &val
);
557 col
.pixel
= val
.background
.pixel
;
558 gdk_gc_set_foreground (gc
, &col
);
559 gdk_draw_rectangle (xtext
->draw_buf
, gc
, 1, x
, y
-
560 xtext
->font
->ascent
, str_width
, xtext
->fontsize
);
561 col
.pixel
= val
.foreground
.pixel
;
562 gdk_gc_set_foreground (gc
, &col
);
565 line
= pango_layout_get_lines (xtext
->layout
)->data
;
567 xtext_draw_layout_line (xtext
->draw_buf
, gc
, x
, y
, line
);
570 xtext_draw_layout_line (xtext
->draw_buf
, gc
, x
, y
, line
);
573 xtext_draw_layout_line (xtext
->draw_buf
, gc
, x
+ 1, y
, line
);
577 pango_layout_set_font_description (xtext
->layout
, xtext
->font
->font
);
582 backend_set_clip (GtkXText *xtext, GdkRectangle *area)
584 gdk_gc_set_clip_rectangle (xtext->fgc, area);
585 gdk_gc_set_clip_rectangle (xtext->bgc, area);
589 backend_clear_clip (GtkXText *xtext)
591 gdk_gc_set_clip_rectangle (xtext->fgc, NULL);
592 gdk_gc_set_clip_rectangle (xtext->bgc, NULL);
595 #endif /* !USE_PANGO */
598 xtext_set_fg (GtkXText
*xtext
, GdkGC
*gc
, int index
)
602 col
.pixel
= xtext
->palette
[index
];
603 gdk_gc_set_foreground (gc
, &col
);
606 if (gc
== xtext
->fgc
)
607 xtext
->xft_fg
= &xtext
->color
[index
];
609 xtext
->xft_bg
= &xtext
->color
[index
];
615 #define xtext_set_bg(xt,gc,index) xt->xft_bg = &xt->color[index]
620 xtext_set_bg (GtkXText
*xtext
, GdkGC
*gc
, int index
)
624 col
.pixel
= xtext
->palette
[index
];
625 gdk_gc_set_background (gc
, &col
);
631 gtk_xtext_init (GtkXText
* xtext
)
633 xtext
->pixmap
= NULL
;
635 xtext
->add_io_tag
= 0;
636 xtext
->scroll_tag
= 0;
637 xtext
->max_lines
= 0;
638 xtext
->col_back
= XTEXT_BG
;
639 xtext
->col_fore
= XTEXT_FG
;
641 xtext
->pixel_offset
= 0;
643 xtext
->underline
= FALSE
;
644 xtext
->italics
= FALSE
;
645 xtext
->hidden
= FALSE
;
648 xtext
->xftdraw
= NULL
;
650 xtext
->layout
= NULL
;
652 xtext
->jump_out_offset
= 0;
653 xtext
->jump_in_offset
= 0;
657 xtext
->clip_x2
= 1000000;
659 xtext
->clip_y2
= 1000000;
660 xtext
->error_function
= NULL
;
661 xtext
->urlcheck_function
= NULL
;
662 xtext
->color_paste
= FALSE
;
663 xtext
->skip_border_fills
= FALSE
;
664 xtext
->skip_stamp
= FALSE
;
665 xtext
->render_hilights_only
= FALSE
;
666 xtext
->un_hilight
= FALSE
;
667 xtext
->recycle
= FALSE
;
668 xtext
->dont_render
= FALSE
;
669 xtext
->dont_render2
= FALSE
;
670 xtext
->overdraw
= FALSE
;
671 xtext
->tint_red
= xtext
->tint_green
= xtext
->tint_blue
= TINT_VALUE
;
673 xtext
->adj
= (GtkAdjustment
*) gtk_adjustment_new (0, 0, 1, 1, 1, 1);
674 g_object_ref (G_OBJECT (xtext
->adj
));
675 g_object_ref_sink (G_OBJECT (xtext
->adj
));
676 g_object_unref (G_OBJECT (xtext
->adj
));
678 xtext
->vc_signal_tag
= g_signal_connect (G_OBJECT (xtext
->adj
),
679 "value_changed", G_CALLBACK (gtk_xtext_adjustment_changed
), xtext
);
681 static const GtkTargetEntry targets
[] = {
682 { "UTF8_STRING", 0, TARGET_UTF8_STRING
},
683 { "STRING", 0, TARGET_STRING
},
684 { "TEXT", 0, TARGET_TEXT
},
685 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT
}
687 static const gint n_targets
= sizeof (targets
) / sizeof (targets
[0]);
689 gtk_selection_add_targets (GTK_WIDGET (xtext
), GDK_SELECTION_PRIMARY
,
693 if (getenv ("XCHAT_OVERDRAW"))
694 xtext
->overdraw
= TRUE
;
698 gtk_xtext_adjustment_set (xtext_buffer
*buf
, int fire_signal
)
700 GtkAdjustment
*adj
= buf
->xtext
->adj
;
702 if (buf
->xtext
->buffer
== buf
)
705 adj
->upper
= buf
->num_lines
;
711 (GTK_WIDGET (buf
->xtext
)->allocation
.height
-
712 buf
->xtext
->font
->descent
) / buf
->xtext
->fontsize
;
713 adj
->page_increment
= adj
->page_size
;
715 if (adj
->value
> adj
->upper
- adj
->page_size
)
716 adj
->value
= adj
->upper
- adj
->page_size
;
722 gtk_adjustment_changed (adj
);
727 gtk_xtext_adjustment_timeout (GtkXText
* xtext
)
729 gtk_xtext_render_page (xtext
);
735 gtk_xtext_adjustment_changed (GtkAdjustment
* adj
, GtkXText
* xtext
)
738 if (xtext
->buffer
->old_value
!= xtext
->adj
->value
)
740 if ((int) xtext
->buffer
->old_value
!= (int) xtext
->adj
->value
)
743 if (xtext
->adj
->value
>= xtext
->adj
->upper
- xtext
->adj
->page_size
)
744 xtext
->buffer
->scrollbar_down
= TRUE
;
746 xtext
->buffer
->scrollbar_down
= FALSE
;
748 if (xtext
->adj
->value
+ 1 == xtext
->buffer
->old_value
||
749 xtext
->adj
->value
- 1 == xtext
->buffer
->old_value
) /* clicked an arrow? */
753 g_source_remove (xtext
->io_tag
);
756 gtk_xtext_render_page (xtext
);
760 xtext
->io_tag
= g_timeout_add (REFRESH_TIMEOUT
,
762 gtk_xtext_adjustment_timeout
,
766 xtext
->buffer
->old_value
= adj
->value
;
770 gtk_xtext_new (GdkColor palette
[], int separator
)
774 xtext
= g_object_new (gtk_xtext_get_type (), NULL
);
775 xtext
->separator
= separator
;
776 xtext
->wordwrap
= TRUE
;
777 xtext
->buffer
= gtk_xtext_buffer_new (xtext
);
778 xtext
->orig_buffer
= xtext
->buffer
;
780 gtk_widget_set_double_buffered (GTK_WIDGET (xtext
), FALSE
);
781 gtk_xtext_set_palette (xtext
, palette
);
783 return GTK_WIDGET (xtext
);
787 gtk_xtext_destroy (GtkObject
* object
)
789 GtkXText
*xtext
= GTK_XTEXT (object
);
791 if (xtext
->add_io_tag
)
793 g_source_remove (xtext
->add_io_tag
);
794 xtext
->add_io_tag
= 0;
797 if (xtext
->scroll_tag
)
799 g_source_remove (xtext
->scroll_tag
);
800 xtext
->scroll_tag
= 0;
805 g_source_remove (xtext
->io_tag
);
811 #if defined(USE_XLIB)
812 if (xtext
->transparent
)
813 gtk_xtext_free_trans (xtext
);
816 g_object_unref (xtext
->pixmap
);
817 xtext
->pixmap
= NULL
;
822 backend_font_close (xtext
);
828 g_signal_handlers_disconnect_matched (G_OBJECT (xtext
->adj
),
829 G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, xtext
);
830 /* gtk_signal_disconnect_by_data (GTK_OBJECT (xtext->adj), xtext);*/
831 g_object_unref (G_OBJECT (xtext
->adj
));
837 g_object_unref (xtext
->bgc
);
843 g_object_unref (xtext
->fgc
);
849 g_object_unref (xtext
->light_gc
);
850 xtext
->light_gc
= NULL
;
855 g_object_unref (xtext
->dark_gc
);
856 xtext
->dark_gc
= NULL
;
861 g_object_unref (xtext
->thin_gc
);
862 xtext
->thin_gc
= NULL
;
865 if (xtext
->marker_gc
)
867 g_object_unref (xtext
->marker_gc
);
868 xtext
->marker_gc
= NULL
;
871 if (xtext
->hand_cursor
)
873 gdk_cursor_unref (xtext
->hand_cursor
);
874 xtext
->hand_cursor
= NULL
;
877 if (xtext
->resize_cursor
)
879 gdk_cursor_unref (xtext
->resize_cursor
);
880 xtext
->resize_cursor
= NULL
;
883 if (xtext
->orig_buffer
)
885 gtk_xtext_buffer_free (xtext
->orig_buffer
);
886 xtext
->orig_buffer
= NULL
;
889 if (GTK_OBJECT_CLASS (parent_class
)->destroy
)
890 (*GTK_OBJECT_CLASS (parent_class
)->destroy
) (object
);
894 gtk_xtext_unrealize (GtkWidget
* widget
)
896 backend_deinit (GTK_XTEXT (widget
));
898 /* if there are still events in the queue, this'll avoid segfault */
899 gdk_window_set_user_data (widget
->window
, NULL
);
901 if (parent_class
->unrealize
)
902 (* GTK_WIDGET_CLASS (parent_class
)->unrealize
) (widget
);
906 gtk_xtext_realize (GtkWidget
* widget
)
909 GdkWindowAttr attributes
;
914 GTK_WIDGET_SET_FLAGS (widget
, GTK_REALIZED
);
915 xtext
= GTK_XTEXT (widget
);
917 attributes
.x
= widget
->allocation
.x
;
918 attributes
.y
= widget
->allocation
.y
;
919 attributes
.width
= widget
->allocation
.width
;
920 attributes
.height
= widget
->allocation
.height
;
921 attributes
.wclass
= GDK_INPUT_OUTPUT
;
922 attributes
.window_type
= GDK_WINDOW_CHILD
;
923 attributes
.event_mask
= gtk_widget_get_events (widget
) |
924 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
925 #ifdef MOTION_MONITOR
926 | GDK_POINTER_MOTION_MASK
| GDK_LEAVE_NOTIFY_MASK
;
928 | GDK_POINTER_MOTION_MASK
;
931 cmap
= gtk_widget_get_colormap (widget
);
932 attributes
.colormap
= cmap
;
933 attributes
.visual
= gtk_widget_get_visual (widget
);
935 widget
->window
= gdk_window_new (widget
->parent
->window
, &attributes
,
936 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
|
939 gdk_window_set_user_data (widget
->window
, widget
);
941 xtext
->depth
= gdk_drawable_get_visual (widget
->window
)->depth
;
943 val
.subwindow_mode
= GDK_INCLUDE_INFERIORS
;
944 val
.graphics_exposures
= 0;
946 xtext
->bgc
= gdk_gc_new_with_values (widget
->window
, &val
,
947 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
948 xtext
->fgc
= gdk_gc_new_with_values (widget
->window
, &val
,
949 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
950 xtext
->light_gc
= gdk_gc_new_with_values (widget
->window
, &val
,
951 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
952 xtext
->dark_gc
= gdk_gc_new_with_values (widget
->window
, &val
,
953 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
954 xtext
->thin_gc
= gdk_gc_new_with_values (widget
->window
, &val
,
955 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
956 xtext
->marker_gc
= gdk_gc_new_with_values (widget
->window
, &val
,
957 GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
959 /* for the separator bar (light) */
960 col
.red
= 0xffff; col
.green
= 0xffff; col
.blue
= 0xffff;
961 gdk_colormap_alloc_color (cmap
, &col
, FALSE
, TRUE
);
962 gdk_gc_set_foreground (xtext
->light_gc
, &col
);
964 /* for the separator bar (dark) */
965 col
.red
= 0x1111; col
.green
= 0x1111; col
.blue
= 0x1111;
966 gdk_colormap_alloc_color (cmap
, &col
, FALSE
, TRUE
);
967 gdk_gc_set_foreground (xtext
->dark_gc
, &col
);
969 /* for the separator bar (thinline) */
970 col
.red
= 0x8e38; col
.green
= 0x8e38; col
.blue
= 0x9f38;
971 gdk_colormap_alloc_color (cmap
, &col
, FALSE
, TRUE
);
972 gdk_gc_set_foreground (xtext
->thin_gc
, &col
);
974 /* for the marker bar (marker) */
975 col
.pixel
= xtext
->palette
[XTEXT_MARKER
];
976 gdk_gc_set_foreground (xtext
->marker_gc
, &col
);
978 xtext_set_fg (xtext
, xtext
->fgc
, XTEXT_FG
);
979 xtext_set_bg (xtext
, xtext
->fgc
, XTEXT_BG
);
980 xtext_set_fg (xtext
, xtext
->bgc
, XTEXT_BG
);
982 /* draw directly to window */
983 xtext
->draw_buf
= widget
->window
;
985 #if defined(USE_XLIB)
986 if (xtext
->transparent
)
988 gtk_xtext_load_trans (xtext
);
993 gdk_gc_set_tile (xtext
->bgc
, xtext
->pixmap
);
994 gdk_gc_set_ts_origin (xtext
->bgc
, 0, 0);
995 xtext
->ts_x
= xtext
->ts_y
= 0;
996 gdk_gc_set_fill (xtext
->bgc
, GDK_TILED
);
999 xtext
->hand_cursor
= gdk_cursor_new_for_display (gdk_drawable_get_display (widget
->window
), GDK_HAND1
);
1000 xtext
->resize_cursor
= gdk_cursor_new_for_display (gdk_drawable_get_display (widget
->window
), GDK_LEFT_SIDE
);
1002 gdk_window_set_back_pixmap (widget
->window
, NULL
, FALSE
);
1003 widget
->style
= gtk_style_attach (widget
->style
, widget
->window
);
1005 backend_init (xtext
);
1009 gtk_xtext_size_request (GtkWidget
* widget
, GtkRequisition
* requisition
)
1011 requisition
->width
= 200;
1012 requisition
->height
= 90;
1016 gtk_xtext_size_allocate (GtkWidget
* widget
, GtkAllocation
* allocation
)
1018 GtkXText
*xtext
= GTK_XTEXT (widget
);
1019 int height_only
= FALSE
;
1020 int do_trans
= TRUE
;
1022 if (allocation
->width
== xtext
->buffer
->window_width
)
1025 if (allocation
->x
== widget
->allocation
.x
&&
1026 allocation
->y
== widget
->allocation
.y
&& xtext
->avoid_trans
)
1029 xtext
->avoid_trans
= FALSE
;
1031 widget
->allocation
= *allocation
;
1032 if (GTK_WIDGET_REALIZED (widget
))
1034 xtext
->buffer
->window_width
= allocation
->width
;
1035 xtext
->buffer
->window_height
= allocation
->height
;
1037 gdk_window_move_resize (widget
->window
, allocation
->x
, allocation
->y
,
1038 allocation
->width
, allocation
->height
);
1039 dontscroll (xtext
->buffer
); /* force scrolling off */
1041 gtk_xtext_calc_lines (xtext
->buffer
, FALSE
);
1044 xtext
->buffer
->pagetop_ent
= NULL
;
1045 gtk_xtext_adjustment_set (xtext
->buffer
, FALSE
);
1047 #if defined(USE_XLIB)
1048 if (do_trans
&& xtext
->transparent
&& xtext
->shaded
)
1050 gtk_xtext_free_trans (xtext
);
1051 gtk_xtext_load_trans (xtext
);
1054 if (xtext
->buffer
->scrollbar_down
)
1055 gtk_adjustment_set_value (xtext
->adj
, xtext
->adj
->upper
-
1056 xtext
->adj
->page_size
);
1061 gtk_xtext_selection_clear_full (xtext_buffer
*buf
)
1063 textentry
*ent
= buf
->text_first
;
1066 ent
->mark_start
= -1;
1073 gtk_xtext_selection_clear (xtext_buffer
*buf
)
1078 ent
= buf
->last_ent_start
;
1081 if (ent
->mark_start
!= -1)
1083 ent
->mark_start
= -1;
1085 if (ent
== buf
->last_ent_end
)
1094 find_x (GtkXText
*xtext
, textentry
*ent
, unsigned char *text
, int x
, int indent
)
1098 int rcol
= 0, bgcol
= 0;
1100 unsigned char *orig
= text
;
1107 if (rcol
> 0 && (isdigit (*text
) || (*text
== ',' && isdigit (text
[1]) && !bgcol
)))
1109 if (text
[1] != ',') rcol
--;
1127 case ATTR_UNDERLINE
:
1132 if (xtext
->ignore_hidden
)
1139 char_width
= backend_get_char_width (xtext
, text
, &mbl
);
1140 if (!hidden
) xx
+= char_width
;
1143 return i
+ (orig
- ent
->str
);
1148 if (text
- orig
>= ent
->str_len
)
1149 return ent
->str_len
;
1152 return ent
->str_len
;
1156 gtk_xtext_find_x (GtkXText
* xtext
, int x
, textentry
* ent
, int subline
,
1157 int line
, int *out_of_bounds
)
1163 indent
= ent
->indent
;
1165 indent
= xtext
->buffer
->indent
;
1167 if (line
> xtext
->adj
->page_size
|| line
< 0)
1170 if (xtext
->buffer
->grid_dirty
|| line
> 255)
1172 str
= ent
->str
+ gtk_xtext_find_subline (xtext
, ent
, subline
);
1173 if (str
>= ent
->str
+ ent
->str_len
)
1177 if (xtext
->buffer
->grid_offset
[line
] > ent
->str_len
)
1179 str
= ent
->str
+ xtext
->buffer
->grid_offset
[line
];
1185 return (str
- ent
->str
);
1190 return find_x (xtext
, ent
, str
, x
, indent
);
1194 gtk_xtext_find_char (GtkXText
* xtext
, int x
, int y
, int *off
,
1201 line
= (y
+ xtext
->pixel_offset
) / xtext
->fontsize
;
1202 ent
= gtk_xtext_nth (xtext
, line
+ (int)xtext
->adj
->value
, &subline
);
1207 *off
= gtk_xtext_find_x (xtext
, x
, ent
, subline
, line
, out_of_bounds
);
1213 gtk_xtext_draw_sep (GtkXText
* xtext
, int y
)
1216 GdkGC
*light
, *dark
;
1221 height
= GTK_WIDGET (xtext
)->allocation
.height
;
1224 height
= xtext
->fontsize
;
1227 /* draw the separator line */
1228 if (xtext
->separator
&& xtext
->buffer
->indent
)
1230 light
= xtext
->light_gc
;
1231 dark
= xtext
->dark_gc
;
1233 x
= xtext
->buffer
->indent
- ((xtext
->space_width
+ 1) / 2);
1237 if (xtext
->thinline
)
1239 if (xtext
->moving_separator
)
1240 gdk_draw_line (xtext
->draw_buf
, light
, x
, y
, x
, y
+ height
);
1242 gdk_draw_line (xtext
->draw_buf
, xtext
->thin_gc
, x
, y
, x
, y
+ height
);
1245 if (xtext
->moving_separator
)
1247 gdk_draw_line (xtext
->draw_buf
, light
, x
- 1, y
, x
- 1, y
+ height
);
1248 gdk_draw_line (xtext
->draw_buf
, dark
, x
, y
, x
, y
+ height
);
1251 gdk_draw_line (xtext
->draw_buf
, dark
, x
- 1, y
, x
- 1, y
+ height
);
1252 gdk_draw_line (xtext
->draw_buf
, light
, x
, y
, x
, y
+ height
);
1259 gtk_xtext_draw_marker (GtkXText
* xtext
, textentry
* ent
, int y
)
1261 int x
, width
, render_y
;
1263 if (!xtext
->marker
) return;
1265 if (xtext
->buffer
->marker_pos
== ent
)
1267 render_y
= y
+ xtext
->font
->descent
;
1269 else if (xtext
->buffer
->marker_pos
== ent
->next
&& ent
->next
!= NULL
)
1271 render_y
= y
+ xtext
->font
->descent
+ xtext
->fontsize
* ent
->lines_taken
;
1276 width
= GTK_WIDGET (xtext
)->allocation
.width
;
1278 gdk_draw_line (xtext
->draw_buf
, xtext
->marker_gc
, x
, render_y
, x
+ width
, render_y
);
1280 if (gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (xtext
)))))
1282 xtext
->buffer
->marker_seen
= TRUE
;
1288 have_shm_pixmaps(Display
*dpy
)
1291 static int checked
= 0;
1292 static int have
= FALSE
;
1296 XShmQueryVersion (dpy
, &major
, &minor
, &have
);
1305 gtk_xtext_paint (GtkWidget
*widget
, GdkRectangle
*area
)
1307 GtkXText
*xtext
= GTK_XTEXT (widget
);
1308 textentry
*ent_start
, *ent_end
;
1311 #if defined(USE_XLIB)
1312 if (xtext
->transparent
)
1314 gdk_window_get_origin (widget
->window
, &x
, &y
);
1315 /* update transparency only if it moved */
1316 if (xtext
->last_win_x
!= x
|| xtext
->last_win_y
!= y
)
1318 xtext
->last_win_x
= x
;
1319 xtext
->last_win_y
= y
;
1321 if (xtext
->shaded
&& !have_shm_pixmaps(GDK_WINDOW_XDISPLAY (xtext
->draw_buf
)))
1326 xtext
->recycle
= TRUE
;
1327 gtk_xtext_load_trans (xtext
);
1328 xtext
->recycle
= FALSE
;
1331 gtk_xtext_free_trans (xtext
);
1332 gtk_xtext_load_trans (xtext
);
1338 if (area
->x
== 0 && area
->y
== 0 &&
1339 area
->height
== widget
->allocation
.height
&&
1340 area
->width
== widget
->allocation
.width
)
1342 dontscroll (xtext
->buffer
); /* force scrolling off */
1343 gtk_xtext_render_page (xtext
);
1347 ent_start
= gtk_xtext_find_char (xtext
, area
->x
, area
->y
, NULL
, NULL
);
1350 xtext_draw_bg (xtext
, area
->x
, area
->y
, area
->width
, area
->height
);
1353 ent_end
= gtk_xtext_find_char (xtext
, area
->x
+ area
->width
,
1354 area
->y
+ area
->height
, NULL
, NULL
);
1356 ent_end
= xtext
->buffer
->text_last
;
1358 /* can't set a clip here, because fgc/bgc are used to draw the DB too */
1359 /* backend_set_clip (xtext, area);*/
1360 xtext
->clip_x
= area
->x
;
1361 xtext
->clip_x2
= area
->x
+ area
->width
;
1362 xtext
->clip_y
= area
->y
;
1363 xtext
->clip_y2
= area
->y
+ area
->height
;
1365 /* y is the last pixel y location it rendered text at */
1366 y
= gtk_xtext_render_ents (xtext
, ent_start
, ent_end
);
1368 if (y
&& y
< widget
->allocation
.height
&& !ent_end
->next
)
1374 rect
.width
= widget
->allocation
.width
;
1375 rect
.height
= widget
->allocation
.height
- y
;
1377 /* fill any space below the last line that also intersects with
1378 the exposure rectangle */
1379 if (gdk_rectangle_intersect (area
, &rect
, &rect
))
1381 xtext_draw_bg (xtext
, rect
.x
, rect
.y
, rect
.width
, rect
.height
);
1385 /*backend_clear_clip (xtext);*/
1387 xtext
->clip_x2
= 1000000;
1389 xtext
->clip_y2
= 1000000;
1392 x
= xtext
->buffer
->indent
- ((xtext
->space_width
+ 1) / 2);
1394 gtk_xtext_draw_sep (xtext
, -1);
1398 gtk_xtext_expose (GtkWidget
* widget
, GdkEventExpose
* event
)
1400 gtk_xtext_paint (widget
, &event
->area
);
1404 /* render a selection that has extended or contracted upward */
1407 gtk_xtext_selection_up (GtkXText
*xtext
, textentry
*start
, textentry
*end
,
1410 /* render all the complete lines */
1411 if (start
->next
== end
)
1412 gtk_xtext_render_ents (xtext
, end
, NULL
);
1414 gtk_xtext_render_ents (xtext
, start
->next
, end
);
1416 /* now the incomplete upper line */
1417 if (start
== xtext
->buffer
->last_ent_start
)
1418 xtext
->jump_in_offset
= xtext
->buffer
->last_offset_start
;
1420 xtext
->jump_in_offset
= start_offset
;
1421 gtk_xtext_render_ents (xtext
, start
, NULL
);
1422 xtext
->jump_in_offset
= 0;
1425 /* render a selection that has extended or contracted downward */
1428 gtk_xtext_selection_down (GtkXText
*xtext
, textentry
*start
, textentry
*end
,
1431 /* render all the complete lines */
1432 if (end
->prev
== start
)
1433 gtk_xtext_render_ents (xtext
, start
, NULL
);
1435 gtk_xtext_render_ents (xtext
, start
, end
->prev
);
1437 /* now the incomplete bottom line */
1438 if (end
== xtext
->buffer
->last_ent_end
)
1439 xtext
->jump_out_offset
= xtext
->buffer
->last_offset_end
;
1441 xtext
->jump_out_offset
= end_offset
;
1442 gtk_xtext_render_ents (xtext
, end
, NULL
);
1443 xtext
->jump_out_offset
= 0;
1447 gtk_xtext_selection_render (GtkXText
*xtext
,
1448 textentry
*start_ent
, int start_offset
,
1449 textentry
*end_ent
, int end_offset
)
1454 xtext
->skip_border_fills
= TRUE
;
1455 xtext
->skip_stamp
= TRUE
;
1457 /* force an optimized render if there was no previous selection */
1458 if (xtext
->buffer
->last_ent_start
== NULL
&& start_ent
== end_ent
)
1460 xtext
->buffer
->last_offset_start
= start_offset
;
1461 xtext
->buffer
->last_offset_end
= end_offset
;
1465 /* mark changed within 1 ent only? */
1466 if (xtext
->buffer
->last_ent_start
== start_ent
&&
1467 xtext
->buffer
->last_ent_end
== end_ent
)
1469 /* when only 1 end of the selection is changed, we can really
1470 save on rendering */
1471 if (xtext
->buffer
->last_offset_start
== start_offset
||
1472 xtext
->buffer
->last_offset_end
== end_offset
)
1476 /* figure out where to start and end the rendering */
1477 if (end_offset
> xtext
->buffer
->last_offset_end
)
1480 start
= xtext
->buffer
->last_offset_end
;
1481 } else if (end_offset
< xtext
->buffer
->last_offset_end
)
1483 end
= xtext
->buffer
->last_offset_end
;
1485 } else if (start_offset
< xtext
->buffer
->last_offset_start
)
1487 end
= xtext
->buffer
->last_offset_start
;
1488 start
= start_offset
;
1490 } else if (start_offset
> xtext
->buffer
->last_offset_start
)
1493 start
= xtext
->buffer
->last_offset_start
;
1496 { /* WORD selects end up here */
1498 start
= start_offset
;
1502 /* LINE selects end up here */
1503 /* so which ent actually changed? */
1505 if (xtext
->buffer
->last_offset_start
== start_offset
)
1508 end
= MAX (xtext
->buffer
->last_offset_end
, end_offset
);
1509 start
= MIN (xtext
->buffer
->last_offset_start
, start_offset
);
1512 xtext
->jump_out_offset
= end
;
1513 xtext
->jump_in_offset
= start
;
1514 gtk_xtext_render_ents (xtext
, ent
, NULL
);
1515 xtext
->jump_out_offset
= 0;
1516 xtext
->jump_in_offset
= 0;
1518 /* marking downward? */
1519 else if (xtext
->buffer
->last_ent_start
== start_ent
&&
1520 xtext
->buffer
->last_offset_start
== start_offset
)
1522 /* find the range that covers both old and new selection */
1526 if (ent
== xtext
->buffer
->last_ent_end
)
1528 gtk_xtext_selection_down (xtext
, ent
, end_ent
, end_offset
);
1529 /*gtk_xtext_render_ents (xtext, ent, end_ent);*/
1534 gtk_xtext_selection_down (xtext
, ent
, xtext
->buffer
->last_ent_end
, end_offset
);
1535 /*gtk_xtext_render_ents (xtext, ent, xtext->buffer->last_ent_end);*/
1541 /* marking upward? */
1542 else if (xtext
->buffer
->last_ent_end
== end_ent
&&
1543 xtext
->buffer
->last_offset_end
== end_offset
)
1548 if (ent
== start_ent
)
1550 gtk_xtext_selection_up (xtext
, xtext
->buffer
->last_ent_start
, ent
, start_offset
);
1551 /*gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, ent);*/
1554 if (ent
== xtext
->buffer
->last_ent_start
)
1556 gtk_xtext_selection_up (xtext
, start_ent
, ent
, start_offset
);
1557 /*gtk_xtext_render_ents (xtext, start_ent, ent);*/
1563 else /* cross-over mark (stretched or shrunk at both ends) */
1565 /* unrender the old mark */
1566 gtk_xtext_render_ents (xtext
, xtext
->buffer
->last_ent_start
, xtext
->buffer
->last_ent_end
);
1567 /* now render the new mark, but skip overlaps */
1568 if (start_ent
== xtext
->buffer
->last_ent_start
)
1570 /* if the new mark is a sub-set of the old, do nothing */
1571 if (start_ent
!= end_ent
)
1572 gtk_xtext_render_ents (xtext
, start_ent
->next
, end_ent
);
1573 } else if (end_ent
== xtext
->buffer
->last_ent_end
)
1575 /* if the new mark is a sub-set of the old, do nothing */
1576 if (start_ent
!= end_ent
)
1577 gtk_xtext_render_ents (xtext
, start_ent
, end_ent
->prev
);
1579 gtk_xtext_render_ents (xtext
, start_ent
, end_ent
);
1582 xtext
->buffer
->last_ent_start
= start_ent
;
1583 xtext
->buffer
->last_ent_end
= end_ent
;
1584 xtext
->buffer
->last_offset_start
= start_offset
;
1585 xtext
->buffer
->last_offset_end
= end_offset
;
1587 xtext
->skip_border_fills
= FALSE
;
1588 xtext
->skip_stamp
= FALSE
;
1592 gtk_xtext_selection_draw (GtkXText
* xtext
, GdkEventMotion
* event
, gboolean render
)
1596 textentry
*ent_start
;
1605 if (xtext
->select_start_y
> xtext
->select_end_y
)
1607 low_x
= xtext
->select_end_x
;
1608 low_y
= xtext
->select_end_y
;
1609 high_x
= xtext
->select_start_x
;
1610 high_y
= xtext
->select_start_y
;
1613 low_x
= xtext
->select_start_x
;
1614 low_y
= xtext
->select_start_y
;
1615 high_x
= xtext
->select_end_x
;
1616 high_y
= xtext
->select_end_y
;
1619 ent_start
= gtk_xtext_find_char (xtext
, low_x
, low_y
, &offset_start
, &tmp
);
1622 if (xtext
->adj
->value
!= xtext
->buffer
->old_value
)
1623 gtk_xtext_render_page (xtext
);
1627 ent_end
= gtk_xtext_find_char (xtext
, high_x
, high_y
, &offset_end
, &tmp
);
1630 ent_end
= xtext
->buffer
->text_last
;
1633 if (xtext
->adj
->value
!= xtext
->buffer
->old_value
)
1634 gtk_xtext_render_page (xtext
);
1637 offset_end
= ent_end
->str_len
;
1640 /* marking less than a complete line? */
1641 /* make sure "start" is smaller than "end" (swap them if need be) */
1642 if (ent_start
== ent_end
&& offset_start
> offset_end
)
1645 offset_start
= offset_end
;
1649 /* has the selection changed? Dont render unless necessary */
1650 if (xtext
->buffer
->last_ent_start
== ent_start
&&
1651 xtext
->buffer
->last_ent_end
== ent_end
&&
1652 xtext
->buffer
->last_offset_start
== offset_start
&&
1653 xtext
->buffer
->last_offset_end
== offset_end
)
1656 /* set all the old mark_ fields to -1 */
1657 gtk_xtext_selection_clear (xtext
->buffer
);
1659 ent_start
->mark_start
= offset_start
;
1660 ent_start
->mark_end
= offset_end
;
1662 if (ent_start
!= ent_end
)
1664 ent_start
->mark_end
= ent_start
->str_len
;
1665 if (offset_end
!= 0)
1667 ent_end
->mark_start
= 0;
1668 ent_end
->mark_end
= offset_end
;
1671 /* set all the mark_ fields of the ents within the selection */
1672 ent
= ent_start
->next
;
1673 while (ent
&& ent
!= ent_end
)
1675 ent
->mark_start
= 0;
1676 ent
->mark_end
= ent
->str_len
;
1682 gtk_xtext_selection_render (xtext
, ent_start
, offset_start
, ent_end
, offset_end
);
1686 gtk_xtext_scrolldown_timeout (GtkXText
* xtext
)
1688 int p_y
, win_height
;
1690 gdk_window_get_pointer (GTK_WIDGET (xtext
)->window
, 0, &p_y
, 0);
1691 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, 0, &win_height
);
1693 if (p_y
> win_height
&&
1694 xtext
->adj
->value
< (xtext
->adj
->upper
- xtext
->adj
->page_size
))
1696 xtext
->adj
->value
++;
1697 gtk_adjustment_changed (xtext
->adj
);
1698 gtk_xtext_render_page (xtext
);
1702 xtext
->scroll_tag
= 0;
1707 gtk_xtext_scrollup_timeout (GtkXText
* xtext
)
1711 gdk_window_get_pointer (GTK_WIDGET (xtext
)->window
, 0, &p_y
, 0);
1713 if (p_y
< 0 && xtext
->adj
->value
> 0.0)
1715 xtext
->adj
->value
--;
1716 gtk_adjustment_changed (xtext
->adj
);
1717 gtk_xtext_render_page (xtext
);
1721 xtext
->scroll_tag
= 0;
1726 gtk_xtext_selection_update (GtkXText
* xtext
, GdkEventMotion
* event
, int p_y
, gboolean render
)
1731 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, 0, &win_height
);
1733 /* selecting past top of window, scroll up! */
1734 if (p_y
< 0 && xtext
->adj
->value
>= 0)
1736 if (!xtext
->scroll_tag
)
1737 xtext
->scroll_tag
= g_timeout_add (100,
1739 gtk_xtext_scrollup_timeout
,
1744 /* selecting past bottom of window, scroll down! */
1745 if (p_y
> win_height
&&
1746 xtext
->adj
->value
< (xtext
->adj
->upper
- xtext
->adj
->page_size
))
1748 if (!xtext
->scroll_tag
)
1749 xtext
->scroll_tag
= g_timeout_add (100,
1751 gtk_xtext_scrolldown_timeout
,
1756 moved
= (int)xtext
->adj
->value
- xtext
->select_start_adj
;
1757 xtext
->select_start_y
-= (moved
* xtext
->fontsize
);
1758 xtext
->select_start_adj
= xtext
->adj
->value
;
1759 gtk_xtext_selection_draw (xtext
, event
, render
);
1763 gtk_xtext_get_word (GtkXText
* xtext
, int x
, int y
, textentry
** ret_ent
,
1764 int *ret_off
, int *ret_len
)
1769 unsigned char *word
;
1771 int out_of_bounds
= 0;
1773 ent
= gtk_xtext_find_char (xtext
, x
, y
, &offset
, &out_of_bounds
);
1780 if (offset
== ent
->str_len
)
1786 /*offset--;*/ /* FIXME: not all chars are 1 byte */
1788 str
= ent
->str
+ offset
;
1790 while (!is_del (*str
) && str
!= ent
->str
)
1796 while (!is_del (*str
) && len
!= ent
->str_len
)
1802 if (len
> 0 && word
[len
-1]=='.')
1811 *ret_off
= word
- ent
->str
;
1813 *ret_len
= str
- word
;
1815 return gtk_xtext_strip_color (word
, len
, xtext
->scratch_buffer
, NULL
, NULL
, FALSE
);
1818 #ifdef MOTION_MONITOR
1821 gtk_xtext_unrender_hilight (GtkXText
*xtext
)
1823 xtext
->render_hilights_only
= TRUE
;
1824 xtext
->skip_border_fills
= TRUE
;
1825 xtext
->skip_stamp
= TRUE
;
1826 xtext
->un_hilight
= TRUE
;
1828 gtk_xtext_render_ents (xtext
, xtext
->hilight_ent
, NULL
);
1830 xtext
->render_hilights_only
= FALSE
;
1831 xtext
->skip_border_fills
= FALSE
;
1832 xtext
->skip_stamp
= FALSE
;
1833 xtext
->un_hilight
= FALSE
;
1837 gtk_xtext_leave_notify (GtkWidget
* widget
, GdkEventCrossing
* event
)
1839 GtkXText
*xtext
= GTK_XTEXT (widget
);
1841 if (xtext
->cursor_hand
)
1843 gtk_xtext_unrender_hilight (xtext
);
1844 xtext
->hilight_start
= -1;
1845 xtext
->hilight_end
= -1;
1846 xtext
->cursor_hand
= FALSE
;
1847 gdk_window_set_cursor (widget
->window
, 0);
1848 xtext
->hilight_ent
= NULL
;
1851 if (xtext
->cursor_resize
)
1853 gtk_xtext_unrender_hilight (xtext
);
1854 xtext
->hilight_start
= -1;
1855 xtext
->hilight_end
= -1;
1856 xtext
->cursor_resize
= FALSE
;
1857 gdk_window_set_cursor (widget
->window
, 0);
1858 xtext
->hilight_ent
= NULL
;
1866 /* check if we should mark time stamps, and if a redraw is needed */
1869 gtk_xtext_check_mark_stamp (GtkXText
*xtext
, GdkModifierType mask
)
1871 gboolean redraw
= FALSE
;
1873 if ((mask
& GDK_SHIFT_MASK
))
1875 if (!xtext
->mark_stamp
)
1877 redraw
= TRUE
; /* must redraw all */
1878 xtext
->mark_stamp
= TRUE
;
1882 if (xtext
->mark_stamp
)
1884 redraw
= TRUE
; /* must redraw all */
1885 xtext
->mark_stamp
= FALSE
;
1892 gtk_xtext_motion_notify (GtkWidget
* widget
, GdkEventMotion
* event
)
1894 GtkXText
*xtext
= GTK_XTEXT (widget
);
1895 GdkModifierType mask
;
1896 int redraw
, tmp
, x
, y
, offset
, len
, line_x
;
1897 unsigned char *word
;
1898 textentry
*word_ent
;
1900 gdk_window_get_pointer (widget
->window
, &x
, &y
, &mask
);
1902 if (xtext
->moving_separator
)
1904 if (x
< (3 * widget
->allocation
.width
) / 5 && x
> 15)
1906 tmp
= xtext
->buffer
->indent
;
1907 xtext
->buffer
->indent
= x
;
1908 gtk_xtext_fix_indent (xtext
->buffer
);
1909 if (tmp
!= xtext
->buffer
->indent
)
1911 gtk_xtext_recalc_widths (xtext
->buffer
, FALSE
);
1912 if (xtext
->buffer
->scrollbar_down
)
1913 gtk_adjustment_set_value (xtext
->adj
, xtext
->adj
->upper
-
1914 xtext
->adj
->page_size
);
1916 xtext
->io_tag
= g_timeout_add (REFRESH_TIMEOUT
,
1918 gtk_xtext_adjustment_timeout
,
1925 if (xtext
->button_down
)
1927 redraw
= gtk_xtext_check_mark_stamp (xtext
, mask
);
1928 gtk_grab_add (widget
);
1929 /*gdk_pointer_grab (widget->window, TRUE,
1930 GDK_BUTTON_RELEASE_MASK |
1931 GDK_BUTTON_MOTION_MASK, NULL, NULL, 0);*/
1932 xtext
->select_end_x
= x
;
1933 xtext
->select_end_y
= y
;
1934 gtk_xtext_selection_update (xtext
, event
, y
, !redraw
);
1935 xtext
->hilighting
= TRUE
;
1937 /* user has pressed or released SHIFT, must redraw entire selection */
1940 xtext
->force_stamp
= TRUE
;
1941 gtk_xtext_render_ents (xtext
, xtext
->buffer
->last_ent_start
,
1942 xtext
->buffer
->last_ent_end
);
1943 xtext
->force_stamp
= FALSE
;
1947 #ifdef MOTION_MONITOR
1949 if (xtext
->separator
&& xtext
->buffer
->indent
)
1951 line_x
= xtext
->buffer
->indent
- ((xtext
->space_width
+ 1) / 2);
1952 if (line_x
== x
|| line_x
== x
+ 1 || line_x
== x
- 1)
1954 if (!xtext
->cursor_resize
)
1956 gdk_window_set_cursor (GTK_WIDGET (xtext
)->window
,
1957 xtext
->resize_cursor
);
1958 xtext
->cursor_resize
= TRUE
;
1964 if (xtext
->urlcheck_function
== NULL
)
1967 word
= gtk_xtext_get_word (xtext
, x
, y
, &word_ent
, &offset
, &len
);
1970 if (xtext
->urlcheck_function (GTK_WIDGET (xtext
), word
, len
) > 0)
1972 if (!xtext
->cursor_hand
||
1973 xtext
->hilight_ent
!= word_ent
||
1974 xtext
->hilight_start
!= offset
||
1975 xtext
->hilight_end
!= offset
+ len
)
1977 if (!xtext
->cursor_hand
)
1979 gdk_window_set_cursor (GTK_WIDGET (xtext
)->window
,
1980 xtext
->hand_cursor
);
1981 xtext
->cursor_hand
= TRUE
;
1984 /* un-render the old hilight */
1985 if (xtext
->hilight_ent
)
1986 gtk_xtext_unrender_hilight (xtext
);
1988 xtext
->hilight_ent
= word_ent
;
1989 xtext
->hilight_start
= offset
;
1990 xtext
->hilight_end
= offset
+ len
;
1992 xtext
->skip_border_fills
= TRUE
;
1993 xtext
->render_hilights_only
= TRUE
;
1994 xtext
->skip_stamp
= TRUE
;
1996 gtk_xtext_render_ents (xtext
, word_ent
, NULL
);
1998 xtext
->skip_border_fills
= FALSE
;
1999 xtext
->render_hilights_only
= FALSE
;
2000 xtext
->skip_stamp
= FALSE
;
2006 gtk_xtext_leave_notify (widget
, NULL
);
2014 gtk_xtext_set_clip_owner (GtkWidget
* xtext
, GdkEventButton
* event
)
2019 if (GTK_XTEXT (xtext
)->selection_buffer
&&
2020 GTK_XTEXT (xtext
)->selection_buffer
!= GTK_XTEXT (xtext
)->buffer
)
2021 gtk_xtext_selection_clear (GTK_XTEXT (xtext
)->selection_buffer
);
2023 GTK_XTEXT (xtext
)->selection_buffer
= GTK_XTEXT (xtext
)->buffer
;
2025 str
= gtk_xtext_selection_get_text (GTK_XTEXT (xtext
), &len
);
2028 gtk_clipboard_set_text (gtk_widget_get_clipboard (xtext
, GDK_SELECTION_CLIPBOARD
),
2033 gtk_selection_owner_set (xtext
, GDK_SELECTION_PRIMARY
, event
->time
);
2037 gtk_xtext_unselect (GtkXText
*xtext
)
2039 xtext_buffer
*buf
= xtext
->buffer
;
2041 xtext
->skip_border_fills
= TRUE
;
2042 xtext
->skip_stamp
= TRUE
;
2044 xtext
->jump_in_offset
= buf
->last_ent_start
->mark_start
;
2045 /* just a single ent was marked? */
2046 if (buf
->last_ent_start
== buf
->last_ent_end
)
2048 xtext
->jump_out_offset
= buf
->last_ent_start
->mark_end
;
2049 buf
->last_ent_end
= NULL
;
2052 gtk_xtext_selection_clear (xtext
->buffer
);
2054 /* FIXME: use jump_out on multi-line selects too! */
2055 gtk_xtext_render_ents (xtext
, buf
->last_ent_start
, buf
->last_ent_end
);
2057 xtext
->jump_in_offset
= 0;
2058 xtext
->jump_out_offset
= 0;
2060 xtext
->skip_border_fills
= FALSE
;
2061 xtext
->skip_stamp
= FALSE
;
2063 xtext
->buffer
->last_ent_start
= NULL
;
2064 xtext
->buffer
->last_ent_end
= NULL
;
2068 gtk_xtext_button_release (GtkWidget
* widget
, GdkEventButton
* event
)
2070 GtkXText
*xtext
= GTK_XTEXT (widget
);
2071 unsigned char *word
;
2074 if (xtext
->moving_separator
)
2076 xtext
->moving_separator
= FALSE
;
2077 old
= xtext
->buffer
->indent
;
2078 if (event
->x
< (4 * widget
->allocation
.width
) / 5 && event
->x
> 15)
2079 xtext
->buffer
->indent
= event
->x
;
2080 gtk_xtext_fix_indent (xtext
->buffer
);
2081 if (xtext
->buffer
->indent
!= old
)
2083 gtk_xtext_recalc_widths (xtext
->buffer
, FALSE
);
2084 gtk_xtext_adjustment_set (xtext
->buffer
, TRUE
);
2085 gtk_xtext_render_page (xtext
);
2087 gtk_xtext_draw_sep (xtext
, -1);
2091 if (xtext
->word_or_line_select
)
2093 xtext
->word_or_line_select
= FALSE
;
2094 xtext
->button_down
= FALSE
;
2098 if (event
->button
== 1)
2100 xtext
->button_down
= FALSE
;
2102 gtk_grab_remove (widget
);
2103 /*gdk_pointer_ungrab (0);*/
2105 /* got a new selection? */
2106 if (xtext
->buffer
->last_ent_start
)
2108 xtext
->color_paste
= FALSE
;
2109 if (event
->state
& GDK_CONTROL_MASK
)
2110 xtext
->color_paste
= TRUE
;
2111 gtk_xtext_set_clip_owner (GTK_WIDGET (xtext
), event
);
2114 if (xtext
->select_start_x
== event
->x
&&
2115 xtext
->select_start_y
== event
->y
&&
2116 xtext
->buffer
->last_ent_start
)
2118 gtk_xtext_unselect (xtext
);
2119 xtext
->mark_stamp
= FALSE
;
2123 if (!xtext
->hilighting
)
2125 word
= gtk_xtext_get_word (xtext
, event
->x
, event
->y
, 0, 0, 0);
2126 g_signal_emit (G_OBJECT (xtext
), xtext_signals
[WORD_CLICK
], 0, word
? word
: NULL
, event
);
2129 xtext
->hilighting
= FALSE
;
2138 gtk_xtext_button_press (GtkWidget
* widget
, GdkEventButton
* event
)
2140 GtkXText
*xtext
= GTK_XTEXT (widget
);
2141 GdkModifierType mask
;
2143 unsigned char *word
;
2144 int line_x
, x
, y
, offset
, len
;
2146 gdk_window_get_pointer (widget
->window
, &x
, &y
, &mask
);
2148 if (event
->button
== 3 || event
->button
== 2) /* right/middle click */
2150 word
= gtk_xtext_get_word (xtext
, x
, y
, 0, 0, 0);
2153 g_signal_emit (G_OBJECT (xtext
), xtext_signals
[WORD_CLICK
], 0,
2156 g_signal_emit (G_OBJECT (xtext
), xtext_signals
[WORD_CLICK
], 0,
2161 if (event
->button
!= 1) /* we only want left button */
2164 if (event
->type
== GDK_2BUTTON_PRESS
) /* WORD select */
2166 gtk_xtext_check_mark_stamp (xtext
, mask
);
2167 if (gtk_xtext_get_word (xtext
, x
, y
, &ent
, &offset
, &len
))
2171 gtk_xtext_selection_clear (xtext
->buffer
);
2172 ent
->mark_start
= offset
;
2173 ent
->mark_end
= offset
+ len
;
2174 gtk_xtext_selection_render (xtext
, ent
, offset
, ent
, offset
+ len
);
2175 xtext
->word_or_line_select
= TRUE
;
2176 gtk_xtext_set_clip_owner (GTK_WIDGET (xtext
), event
);
2182 if (event
->type
== GDK_3BUTTON_PRESS
) /* LINE select */
2184 gtk_xtext_check_mark_stamp (xtext
, mask
);
2185 if (gtk_xtext_get_word (xtext
, x
, y
, &ent
, 0, 0))
2187 gtk_xtext_selection_clear (xtext
->buffer
);
2188 ent
->mark_start
= 0;
2189 ent
->mark_end
= ent
->str_len
;
2190 gtk_xtext_selection_render (xtext
, ent
, 0, ent
, ent
->str_len
);
2191 xtext
->word_or_line_select
= TRUE
;
2192 gtk_xtext_set_clip_owner (GTK_WIDGET (xtext
), event
);
2198 /* check if it was a separator-bar click */
2199 if (xtext
->separator
&& xtext
->buffer
->indent
)
2201 line_x
= xtext
->buffer
->indent
- ((xtext
->space_width
+ 1) / 2);
2202 if (line_x
== x
|| line_x
== x
+ 1 || line_x
== x
- 1)
2204 xtext
->moving_separator
= TRUE
;
2205 /* draw the separator line */
2206 gtk_xtext_draw_sep (xtext
, -1);
2211 xtext
->button_down
= TRUE
;
2212 xtext
->select_start_x
= x
;
2213 xtext
->select_start_y
= y
;
2214 xtext
->select_start_adj
= xtext
->adj
->value
;
2219 /* another program has claimed the selection */
2222 gtk_xtext_selection_kill (GtkXText
*xtext
, GdkEventSelection
*event
)
2224 if (xtext
->buffer
->last_ent_start
)
2225 gtk_xtext_unselect (xtext
);
2230 gtk_xtext_selection_get_text (GtkXText
*xtext
, int *len_ret
)
2240 buf
= xtext
->selection_buffer
;
2244 /* first find out how much we need to malloc ... */
2246 ent
= buf
->last_ent_start
;
2249 if (ent
->mark_start
!= -1)
2251 /* include timestamp? */
2252 if (ent
->mark_start
== 0 && xtext
->mark_stamp
)
2255 int stamp_size
= xtext_get_stamp_str (ent
->stamp
, &time_str
);
2260 if (ent
->mark_end
- ent
->mark_start
> 0)
2261 len
+= (ent
->mark_end
- ent
->mark_start
) + 1;
2265 if (ent
== buf
->last_ent_end
)
2273 /* now allocate mem and copy buffer */
2274 pos
= txt
= malloc (len
);
2275 ent
= buf
->last_ent_start
;
2278 if (ent
->mark_start
!= -1)
2286 if (ent
->mark_end
- ent
->mark_start
> 0)
2288 /* include timestamp? */
2289 if (ent
->mark_start
== 0 && xtext
->mark_stamp
)
2292 int stamp_size
= xtext_get_stamp_str (ent
->stamp
, &time_str
);
2293 memcpy (pos
, time_str
, stamp_size
);
2298 memcpy (pos
, ent
->str
+ ent
->mark_start
,
2299 ent
->mark_end
- ent
->mark_start
);
2300 pos
+= ent
->mark_end
- ent
->mark_start
;
2303 if (ent
== buf
->last_ent_end
)
2309 if (xtext
->color_paste
)
2311 /*stripped = gtk_xtext_conv_color (txt, strlen (txt), &len);*/
2316 stripped
= gtk_xtext_strip_color (txt
, strlen (txt
), NULL
, &len
, 0, FALSE
);
2324 /* another program is asking for our selection */
2327 gtk_xtext_selection_get (GtkWidget
* widget
,
2328 GtkSelectionData
* selection_data_ptr
,
2329 guint info
, guint time
)
2331 GtkXText
*xtext
= GTK_XTEXT (widget
);
2337 stripped
= gtk_xtext_selection_get_text (xtext
, &len
);
2343 case TARGET_UTF8_STRING
:
2344 /* it's already in utf8 */
2345 gtk_selection_data_set_text (selection_data_ptr
, stripped
, len
);
2348 case TARGET_COMPOUND_TEXT
:
2354 gdk_string_to_compound_text_for_display (
2355 gdk_drawable_get_display (widget
->window
),
2356 stripped
, &encoding
, &format
, &new_text
,
2358 gtk_selection_data_set (selection_data_ptr
, encoding
, format
,
2359 new_text
, new_length
);
2360 gdk_free_compound_text (new_text
);
2364 new_text
= g_locale_from_utf8 (stripped
, len
, NULL
, &glen
, NULL
);
2365 gtk_selection_data_set (selection_data_ptr
, GDK_SELECTION_TYPE_STRING
,
2374 gtk_xtext_scroll (GtkWidget
*widget
, GdkEventScroll
*event
)
2376 GtkXText
*xtext
= GTK_XTEXT (widget
);
2379 if (event
->direction
== GDK_SCROLL_UP
) /* mouse wheel pageUp */
2381 new_value
= xtext
->adj
->value
- (xtext
->adj
->page_increment
/ 10);
2382 if (new_value
< xtext
->adj
->lower
)
2383 new_value
= xtext
->adj
->lower
;
2384 gtk_adjustment_set_value (xtext
->adj
, new_value
);
2386 else if (event
->direction
== GDK_SCROLL_DOWN
) /* mouse wheel pageDn */
2388 new_value
= xtext
->adj
->value
+ (xtext
->adj
->page_increment
/ 10);
2389 if (new_value
> (xtext
->adj
->upper
- xtext
->adj
->page_size
))
2390 new_value
= xtext
->adj
->upper
- xtext
->adj
->page_size
;
2391 gtk_adjustment_set_value (xtext
->adj
, new_value
);
2398 gtk_xtext_class_init (GtkXTextClass
* class)
2400 GtkObjectClass
*object_class
;
2401 GtkWidgetClass
*widget_class
;
2402 GtkXTextClass
*xtext_class
;
2404 object_class
= (GtkObjectClass
*) class;
2405 widget_class
= (GtkWidgetClass
*) class;
2406 xtext_class
= (GtkXTextClass
*) class;
2408 parent_class
= gtk_type_class (gtk_widget_get_type ());
2410 xtext_signals
[WORD_CLICK
] =
2411 g_signal_new ("word_click",
2412 G_TYPE_FROM_CLASS (object_class
),
2413 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
,
2414 G_STRUCT_OFFSET (GtkXTextClass
, word_click
),
2416 gtk_marshal_VOID__POINTER_POINTER
,
2418 2, G_TYPE_POINTER
, G_TYPE_POINTER
);
2419 object_class
->destroy
= gtk_xtext_destroy
;
2421 widget_class
->realize
= gtk_xtext_realize
;
2422 widget_class
->unrealize
= gtk_xtext_unrealize
;
2423 widget_class
->size_request
= gtk_xtext_size_request
;
2424 widget_class
->size_allocate
= gtk_xtext_size_allocate
;
2425 widget_class
->button_press_event
= gtk_xtext_button_press
;
2426 widget_class
->button_release_event
= gtk_xtext_button_release
;
2427 widget_class
->motion_notify_event
= gtk_xtext_motion_notify
;
2428 widget_class
->selection_clear_event
= (void *)gtk_xtext_selection_kill
;
2429 widget_class
->selection_get
= gtk_xtext_selection_get
;
2430 widget_class
->expose_event
= gtk_xtext_expose
;
2431 widget_class
->scroll_event
= gtk_xtext_scroll
;
2432 #ifdef MOTION_MONITOR
2433 widget_class
->leave_notify_event
= gtk_xtext_leave_notify
;
2436 xtext_class
->word_click
= NULL
;
2440 gtk_xtext_get_type (void)
2442 static GType xtext_type
= 0;
2446 static const GTypeInfo xtext_info
=
2448 sizeof (GtkXTextClass
),
2449 NULL
, /* base_init */
2450 NULL
, /* base_finalize */
2451 (GClassInitFunc
) gtk_xtext_class_init
,
2452 NULL
, /* class_finalize */
2453 NULL
, /* class_data */
2455 0, /* n_preallocs */
2456 (GInstanceInitFunc
) gtk_xtext_init
,
2459 xtext_type
= g_type_register_static (GTK_TYPE_WIDGET
, "GtkXText",
2466 /* strip MIRC colors and other attribs. */
2468 /* CL: needs to strip hidden when called by gtk_xtext_text_width, but not when copying text */
2470 static unsigned char *
2471 gtk_xtext_strip_color (unsigned char *text
, int len
, unsigned char *outbuf
,
2472 int *newlen
, int *mb_ret
, int strip_hidden
)
2475 int rcol
= 0, bgcol
= 0;
2477 unsigned char *new_str
;
2481 new_str
= malloc (len
+ 2);
2490 if (rcol
> 0 && (isdigit (*text
) || (*text
== ',' && isdigit (text
[1]) && !bgcol
)))
2492 if (text
[1] != ',') rcol
--;
2510 case ATTR_UNDERLINE
:
2517 if (!(hidden
&& strip_hidden
))
2518 new_str
[i
++] = *text
;
2536 /* GeEkMaN: converts mIRC control codes to literal control codes */
2539 gtk_xtext_conv_color (unsigned char *text
, int len
, int *newlen
)
2546 for (i
= 0; i
< len
;)
2554 case ATTR_UNDERLINE
:
2561 mbl
= charlen (text
+ i
);
2567 new_str
= malloc (j
);
2570 for (i
= 0; i
< len
;)
2586 case ATTR_UNDERLINE
:
2598 mbl
= charlen (text
+ i
);
2601 new_str
[j
] = text
[i
];
2606 /* invalid utf8 safe guard */
2609 memcpy (new_str
+ j
, text
+ i
, mbl
);
2617 new_str
[j
++] = cchar
;
2629 /* gives width of a string, excluding the mIRC codes */
2632 gtk_xtext_text_width (GtkXText
*xtext
, unsigned char *text
, int len
,
2635 unsigned char *new_buf
;
2638 new_buf
= gtk_xtext_strip_color (text
, len
, xtext
->scratch_buffer
,
2639 &new_len
, &mb
, !xtext
->ignore_hidden
);
2644 return backend_get_text_width (xtext
, new_buf
, new_len
, mb
);
2647 /* actually draw text to screen (one run with the same color/attribs) */
2650 gtk_xtext_render_flush (GtkXText
* xtext
, int x
, int y
, unsigned char *str
,
2651 int len
, GdkGC
*gc
, int is_mb
)
2653 int str_width
, dofill
;
2654 GdkDrawable
*pix
= NULL
;
2657 if (xtext
->dont_render
|| len
< 1 || xtext
->hidden
)
2660 str_width
= backend_get_text_width (xtext
, str
, len
, is_mb
);
2662 if (xtext
->dont_render2
)
2665 /* roll-your-own clipping (avoiding XftDrawString is always good!) */
2666 if (x
> xtext
->clip_x2
|| x
+ str_width
< xtext
->clip_x
)
2668 if (y
- xtext
->font
->ascent
> xtext
->clip_y2
|| (y
- xtext
->font
->ascent
) + xtext
->fontsize
< xtext
->clip_y
)
2671 if (xtext
->render_hilights_only
)
2673 if (!xtext
->in_hilight
) /* is it a hilight prefix? */
2675 #ifndef COLOR_HILIGHT
2676 if (!xtext
->un_hilight
) /* doing a hilight? no need to draw the text */
2683 pix
= gdk_pixmap_new (xtext
->draw_buf
, str_width
, xtext
->fontsize
, xtext
->depth
);
2687 XftDrawChange (xtext
->xftdraw
, GDK_WINDOW_XWINDOW (pix
));
2690 dest_y
= y
- xtext
->font
->ascent
;
2692 gdk_gc_set_ts_origin (xtext
->bgc
, xtext
->ts_x
- x
, xtext
->ts_y
- dest_y
);
2695 y
= xtext
->font
->ascent
;
2696 xtext
->draw_buf
= pix
;
2703 /* backcolor is always handled by XDrawImageString */
2704 if (!xtext
->backcolor
&& xtext
->pixmap
)
2706 /* draw the background pixmap behind the text - CAUSES FLICKER HERE!! */
2707 xtext_draw_bg (xtext
, x
, y
- xtext
->font
->ascent
, str_width
,
2709 dofill
= FALSE
; /* already drawn the background */
2712 backend_draw_text (xtext
, dofill
, gc
, x
, y
, str
, len
, str_width
, is_mb
);
2720 gdk_gc_set_ts_origin (xtext
->bgc
, xtext
->ts_x
, xtext
->ts_y
);
2721 xtext
->draw_buf
= GTK_WIDGET (xtext
)->window
;
2723 XftDrawChange (xtext
->xftdraw
, GDK_WINDOW_XWINDOW (xtext
->draw_buf
));
2726 gdk_draw_drawable (xtext
->draw_buf
, xtext
->bgc
, pix
, 0, 0, dest_x
,
2727 dest_y
, str_width
, xtext
->fontsize
);
2729 clip
.x
= xtext
->clip_x
;
2730 clip
.y
= xtext
->clip_y
;
2731 clip
.width
= xtext
->clip_x2
- xtext
->clip_x
;
2732 clip
.height
= xtext
->clip_y2
- xtext
->clip_y
;
2736 dest
.width
= str_width
;
2737 dest
.height
= xtext
->fontsize
;
2739 if (gdk_rectangle_intersect (&clip
, &dest
, &dest
))
2740 /* dump the DB to window, but only within the clip_x/x2/y/y2 */
2741 gdk_draw_drawable (xtext
->draw_buf
, xtext
->bgc
, pix
,
2742 dest
.x
- dest_x
, dest
.y
- dest_y
,
2743 dest
.x
, dest
.y
, dest
.width
, dest
.height
);
2745 g_object_unref (pix
);
2749 if (xtext
->underline
)
2755 #ifndef COLOR_HILIGHT
2760 col
.pixel
= xtext
->xft_fg
->pixel
;
2761 gdk_gc_set_foreground (gc
, &col
);
2764 y
= dest_y
+ xtext
->font
->ascent
+ 1;
2770 /* draw directly to window, it's out of the range of our DB */
2771 gdk_draw_line (xtext
->draw_buf
, gc
, dest_x
, y
, dest_x
+ str_width
- 1, y
);
2778 gtk_xtext_reset (GtkXText
* xtext
, int mark
, int attribs
)
2782 xtext
->underline
= FALSE
;
2783 xtext
->bold
= FALSE
;
2784 xtext
->italics
= FALSE
;
2785 xtext
->hidden
= FALSE
;
2789 xtext
->backcolor
= FALSE
;
2790 if (xtext
->col_fore
!= XTEXT_FG
)
2791 xtext_set_fg (xtext
, xtext
->fgc
, XTEXT_FG
);
2792 if (xtext
->col_back
!= XTEXT_BG
)
2793 xtext_set_bg (xtext
, xtext
->fgc
, XTEXT_BG
);
2795 xtext
->col_fore
= XTEXT_FG
;
2796 xtext
->col_back
= XTEXT_BG
;
2797 xtext
->parsing_color
= FALSE
;
2798 xtext
->parsing_backcolor
= FALSE
;
2802 /* render a single line, which WONT wrap, and parse mIRC colors */
2805 gtk_xtext_render_str (GtkXText
* xtext
, int y
, textentry
* ent
,
2806 unsigned char *str
, int len
, int win_width
, int indent
,
2807 int line
, int left_only
, int *x_size_ret
)
2810 int i
= 0, x
= indent
, j
= 0;
2811 unsigned char *pstr
= str
;
2817 xtext
->in_hilight
= FALSE
;
2819 offset
= str
- ent
->str
;
2821 if (line
< 255 && line
>= 0)
2822 xtext
->buffer
->grid_offset
[line
] = offset
;
2824 gc
= xtext
->fgc
; /* our foreground GC */
2826 if (ent
->mark_start
!= -1 &&
2827 ent
->mark_start
<= i
+ offset
&& ent
->mark_end
> i
+ offset
)
2829 xtext_set_bg (xtext
, gc
, XTEXT_MARK_BG
);
2830 xtext_set_fg (xtext
, gc
, XTEXT_MARK_FG
);
2831 xtext
->backcolor
= TRUE
;
2834 #ifdef MOTION_MONITOR
2835 if (xtext
->hilight_ent
== ent
&&
2836 xtext
->hilight_start
<= i
+ offset
&& xtext
->hilight_end
> i
+ offset
)
2838 if (!xtext
->un_hilight
)
2840 #ifdef COLOR_HILIGHT
2841 xtext_set_bg (xtext
, gc
, 2);
2843 xtext
->underline
= TRUE
;
2846 xtext
->in_hilight
= TRUE
;
2850 if (!xtext
->skip_border_fills
&& !xtext
->dont_render
)
2852 /* draw background to the left of the text */
2853 if (str
== ent
->str
&& indent
> MARGIN
&& xtext
->buffer
->time_stamp
)
2855 /* don't overwrite the timestamp */
2856 if (indent
> xtext
->stamp_width
)
2858 xtext_draw_bg (xtext
, xtext
->stamp_width
, y
- xtext
->font
->ascent
,
2859 indent
- xtext
->stamp_width
, xtext
->fontsize
);
2863 /* fill the indent area with background gc */
2864 if (indent
>= xtext
->clip_x
)
2866 xtext_draw_bg (xtext
, 0, y
- xtext
->font
->ascent
,
2867 MIN (indent
, xtext
->clip_x2
), xtext
->fontsize
);
2872 if (xtext
->jump_in_offset
> 0 && offset
< xtext
->jump_in_offset
)
2873 xtext
->dont_render2
= TRUE
;
2878 #ifdef MOTION_MONITOR
2879 if (xtext
->hilight_ent
== ent
&& xtext
->hilight_start
== (i
+ offset
))
2881 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
2884 if (!xtext
->un_hilight
)
2886 #ifdef COLOR_HILIGHT
2887 xtext_set_bg (xtext
, gc
, 2);
2889 xtext
->underline
= TRUE
;
2893 xtext
->in_hilight
= TRUE
;
2897 if ((xtext
->parsing_color
&& isdigit (str
[i
]) && xtext
->nc
< 2) ||
2898 (xtext
->parsing_color
&& str
[i
] == ',' && isdigit (str
[i
+1]) && xtext
->nc
< 3 && !xtext
->parsing_backcolor
))
2903 xtext
->parsing_backcolor
= TRUE
;
2906 xtext
->num
[xtext
->nc
] = 0;
2908 col_num
= atoi (xtext
->num
);
2909 if (col_num
== 99) /* mIRC lameness */
2912 col_num
= col_num
% XTEXT_MIRC_COLS
;
2913 xtext
->col_fore
= col_num
;
2915 xtext_set_fg (xtext
, gc
, col_num
);
2919 xtext
->num
[xtext
->nc
] = str
[i
];
2925 if (xtext
->parsing_color
)
2927 xtext
->parsing_color
= FALSE
;
2930 xtext
->num
[xtext
->nc
] = 0;
2932 col_num
= atoi (xtext
->num
);
2933 if (xtext
->parsing_backcolor
)
2935 if (col_num
== 99) /* mIRC lameness */
2938 col_num
= col_num
% XTEXT_MIRC_COLS
;
2939 if (col_num
== XTEXT_BG
)
2940 xtext
->backcolor
= FALSE
;
2942 xtext
->backcolor
= TRUE
;
2944 xtext_set_bg (xtext
, gc
, col_num
);
2945 xtext
->col_back
= col_num
;
2948 if (col_num
== 99) /* mIRC lameness */
2951 col_num
= col_num
% XTEXT_MIRC_COLS
;
2953 xtext_set_fg (xtext
, gc
, col_num
);
2954 xtext
->col_fore
= col_num
;
2956 xtext
->parsing_backcolor
= FALSE
;
2959 /* got a \003<non-digit>... i.e. reset colors */
2960 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
2963 gtk_xtext_reset (xtext
, mark
, FALSE
);
2973 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
2976 tmp
= xtext
->col_fore
;
2977 xtext
->col_fore
= xtext
->col_back
;
2978 xtext
->col_back
= tmp
;
2981 xtext_set_fg (xtext
, gc
, xtext
->col_fore
);
2982 xtext_set_bg (xtext
, gc
, xtext
->col_back
);
2984 if (xtext
->col_back
!= XTEXT_BG
)
2985 xtext
->backcolor
= TRUE
;
2987 xtext
->backcolor
= FALSE
;
2990 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
2991 xtext
->bold
= !xtext
->bold
;
2995 case ATTR_UNDERLINE
:
2996 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
2997 xtext
->underline
= !xtext
->underline
;
3002 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3003 xtext
->italics
= !xtext
->italics
;
3008 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3009 xtext
->hidden
= (!xtext
->hidden
) & (!xtext
->ignore_hidden
);
3014 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3017 gtk_xtext_reset (xtext
, mark
, !xtext
->in_hilight
);
3020 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3021 xtext
->parsing_color
= TRUE
;
3026 tmp
= charlen (str
+ i
);
3027 /* invalid utf8 safe guard */
3030 j
+= tmp
; /* move to the next utf8 char */
3033 i
+= charlen (str
+ i
); /* move to the next utf8 char */
3034 /* invalid utf8 safe guard */
3038 /* Separate the left part, the space and the right part
3039 into separate runs, and reset bidi state inbetween.
3040 Perform this only on the first line of the message.
3044 /* we've reached the end of the left part? */
3045 if ((pstr
-str
)+j
== ent
->left_len
)
3047 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3051 else if ((pstr
-str
)+j
== ent
->left_len
+1)
3053 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3059 /* have we been told to stop rendering at this point? */
3060 if (xtext
->jump_out_offset
> 0 && xtext
->jump_out_offset
<= (i
+ offset
))
3062 gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3063 ret
= 0; /* skip the rest of the lines, we're done. */
3068 if (xtext
->jump_in_offset
> 0 && xtext
->jump_in_offset
== (i
+ offset
))
3070 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3073 xtext
->dont_render2
= FALSE
;
3076 #ifdef MOTION_MONITOR
3077 if (xtext
->hilight_ent
== ent
&& xtext
->hilight_end
== (i
+ offset
))
3079 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3082 #ifdef COLOR_HILIGHT
3085 xtext_set_bg (xtext
, gc
, XTEXT_MARK_BG
);
3086 xtext
->backcolor
= TRUE
;
3089 xtext_set_bg (xtext
, gc
, xtext
->col_back
);
3090 if (xtext
->col_back
!= XTEXT_BG
)
3091 xtext
->backcolor
= TRUE
;
3093 xtext
->backcolor
= FALSE
;
3096 xtext
->underline
= FALSE
;
3098 xtext
->in_hilight
= FALSE
;
3099 if (xtext
->render_hilights_only
)
3101 /* stop drawing this ent */
3108 if (!mark
&& ent
->mark_start
== (i
+ offset
))
3110 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3113 xtext_set_bg (xtext
, gc
, XTEXT_MARK_BG
);
3114 xtext_set_fg (xtext
, gc
, XTEXT_MARK_FG
);
3115 xtext
->backcolor
= TRUE
;
3119 if (mark
&& ent
->mark_end
== (i
+ offset
))
3121 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3124 xtext_set_bg (xtext
, gc
, xtext
->col_back
);
3125 xtext_set_fg (xtext
, gc
, xtext
->col_fore
);
3126 if (xtext
->col_back
!= XTEXT_BG
)
3127 xtext
->backcolor
= TRUE
;
3129 xtext
->backcolor
= FALSE
;
3136 x
+= gtk_xtext_render_flush (xtext
, x
, y
, pstr
, j
, gc
, ent
->mb
);
3140 xtext_set_bg (xtext
, gc
, xtext
->col_back
);
3141 xtext_set_fg (xtext
, gc
, xtext
->col_fore
);
3142 if (xtext
->col_back
!= XTEXT_BG
)
3143 xtext
->backcolor
= TRUE
;
3145 xtext
->backcolor
= FALSE
;
3148 /* draw background to the right of the text */
3149 if (!left_only
&& !xtext
->dont_render
)
3151 /* draw separator now so it doesn't appear to flicker */
3152 gtk_xtext_draw_sep (xtext
, y
- xtext
->font
->ascent
);
3153 if (!xtext
->skip_border_fills
&& xtext
->clip_x2
>= x
)
3155 int xx
= MAX (x
, xtext
->clip_x
);
3157 xtext_draw_bg (xtext
,
3159 y
- xtext
->font
->ascent
, /* y */
3160 MIN (xtext
->clip_x2
- xx
, (win_width
+ MARGIN
) - xx
), /* width */
3161 xtext
->fontsize
); /* height */
3165 xtext
->dont_render2
= FALSE
;
3167 /* return how much we drew in the x direction */
3169 *x_size_ret
= x
- indent
;
3176 /* get the desktop/root window */
3178 static Window desktop_window
= None
;
3181 get_desktop_window (Display
*xdisplay
, Window the_window
)
3185 unsigned long length
, after
;
3186 unsigned char *data
;
3187 unsigned int nchildren
;
3188 Window w
, root
, *children
, parent
;
3190 prop
= XInternAtom (xdisplay
, "_XROOTPMAP_ID", True
);
3193 prop
= XInternAtom (xdisplay
, "_XROOTCOLOR_PIXEL", True
);
3198 for (w
= the_window
; w
; w
= parent
)
3200 if ((XQueryTree (xdisplay
, w
, &root
, &parent
, &children
,
3201 &nchildren
)) == False
)
3207 XGetWindowProperty (xdisplay
, w
, prop
, 0L, 1L, False
,
3208 AnyPropertyType
, &type
, &format
, &length
, &after
,
3214 return (desktop_window
= w
);
3217 return (desktop_window
= None
);
3220 /* find the root window (backdrop) Pixmap */
3223 get_pixmap_prop (Display
*xdisplay
, Window the_window
)
3227 unsigned long length
, after
;
3228 unsigned char *data
;
3230 static Atom prop
= None
;
3232 if (desktop_window
== None
)
3233 desktop_window
= get_desktop_window (xdisplay
, the_window
);
3234 if (desktop_window
== None
)
3235 desktop_window
= DefaultRootWindow (xdisplay
);
3238 prop
= XInternAtom (xdisplay
, "_XROOTPMAP_ID", True
);
3242 XGetWindowProperty (xdisplay
, desktop_window
, prop
, 0L, 1L, False
,
3243 AnyPropertyType
, &type
, &format
, &length
, &after
,
3247 if (type
== XA_PIXMAP
)
3248 pix
= *((Pixmap
*) data
);
3256 /* slow generic routine, for the depths/bpp we don't know about */
3259 shade_ximage_generic (GdkVisual
*visual
, XImage
*ximg
, int bpl
, int w
, int h
, int rm
, int gm
, int bm
, int bg
)
3262 int bgr
= (256 - rm
) * (bg
& visual
->red_mask
);
3263 int bgg
= (256 - gm
) * (bg
& visual
->green_mask
);
3264 int bgb
= (256 - bm
) * (bg
& visual
->blue_mask
);
3266 for (x
= 0; x
< w
; x
++)
3268 for (y
= 0; y
< h
; y
++)
3270 unsigned long pixel
= XGetPixel (ximg
, x
, y
);
3273 r
= rm
* (pixel
& visual
->red_mask
) + bgr
;
3274 g
= gm
* (pixel
& visual
->green_mask
) + bgg
;
3275 b
= bm
* (pixel
& visual
->blue_mask
) + bgb
;
3277 XPutPixel (ximg
, x
, y
,
3278 ((r
>> 8) & visual
->red_mask
) |
3279 ((g
>> 8) & visual
->green_mask
) |
3280 ((b
>> 8) & visual
->blue_mask
));
3287 /* Fast shading routine. Based on code by Willem Monsuwe <willem@stack.nl> */
3289 #define SHADE_IMAGE(bytes, type, rmask, gmask, bmask) \
3290 unsigned char *ptr; \
3292 int bgr = (256 - rm) * (bg & rmask); \
3293 int bgg = (256 - gm) * (bg & gmask); \
3294 int bgb = (256 - bm) * (bg & bmask); \
3295 ptr = (unsigned char *) data + (w * bytes); \
3296 for (y = h; --y >= 0;) \
3298 for (x = -w; x < 0; x++) \
3301 b = ((type *) ptr)[x]; \
3302 r = rm * (b & rmask) + bgr; \
3303 g = gm * (b & gmask) + bgg; \
3304 b = bm * (b & bmask) + bgb; \
3305 ((type *) ptr)[x] = ((r >> 8) & rmask) \
3306 | ((g >> 8) & gmask) \
3307 | ((b >> 8) & bmask); \
3314 shade_ximage_15 (void *data
, int bpl
, int w
, int h
, int rm
, int gm
, int bm
, int bg
)
3316 SHADE_IMAGE (2, guint16
, 0x7c00, 0x3e0, 0x1f);
3321 shade_ximage_16 (void *data
, int bpl
, int w
, int h
, int rm
, int gm
, int bm
, int bg
)
3323 SHADE_IMAGE (2, guint16
, 0xf800, 0x7e0, 0x1f);
3328 shade_ximage_24 (void *data
, int bpl
, int w
, int h
, int rm
, int gm
, int bm
, int bg
)
3330 /* 24 has to be a special case, there's no guint24, or 24bit MOV :) */
3333 int bgr
= (256 - rm
) * ((bg
& 0xff0000) >> 16);
3334 int bgg
= (256 - gm
) * ((bg
& 0xff00) >> 8);
3335 int bgb
= (256 - bm
) * (bg
& 0xff);
3337 ptr
= (unsigned char *) data
+ (w
* 3);
3338 for (y
= h
; --y
>= 0;)
3340 for (x
= -(w
* 3); x
< 0; x
+= 3)
3344 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
3345 r
= (ptr
[x
+ 0] * rm
+ bgr
) >> 8;
3346 g
= (ptr
[x
+ 1] * gm
+ bgg
) >> 8;
3347 b
= (ptr
[x
+ 2] * bm
+ bgb
) >> 8;
3352 r
= (ptr
[x
+ 2] * rm
+ bgr
) >> 8;
3353 g
= (ptr
[x
+ 1] * gm
+ bgg
) >> 8;
3354 b
= (ptr
[x
+ 0] * bm
+ bgb
) >> 8;
3366 shade_ximage_32 (void *data
, int bpl
, int w
, int h
, int rm
, int gm
, int bm
, int bg
)
3368 SHADE_IMAGE (4, guint32
, 0xff0000, 0xff00, 0xff);
3372 shade_image (GdkVisual
*visual
, void *data
, int bpl
, int bpp
, int w
, int h
,
3373 int rm
, int gm
, int bm
, int bg
, int depth
)
3375 int bg_r
, bg_g
, bg_b
;
3377 bg_r
= bg
& visual
->red_mask
;
3378 bg_g
= bg
& visual
->green_mask
;
3379 bg_b
= bg
& visual
->blue_mask
;
3384 shade_ximage_15 (data
, bpl
, w
, h
, rm
, gm
, bm
, bg
);
3387 shade_ximage_16 (data
, bpl
, w
, h
, rm
, gm
, bm
, bg
);
3392 shade_ximage_24 (data
, bpl
, w
, h
, rm
, gm
, bm
, bg
);
3396 shade_ximage_32 (data
, bpl
, w
, h
, rm
, gm
, bm
, bg
);
3405 get_shm_image (Display
*xdisplay
, XShmSegmentInfo
*shminfo
, int x
, int y
,
3406 int w
, int h
, int depth
, Pixmap pix
)
3410 shminfo
->shmid
= -1;
3411 shminfo
->shmaddr
= (char*) -1;
3412 ximg
= XShmCreateImage (xdisplay
, 0, depth
, ZPixmap
, 0, shminfo
, w
, h
);
3416 shminfo
->shmid
= shmget (IPC_PRIVATE
, ximg
->bytes_per_line
* ximg
->height
,
3418 if (shminfo
->shmid
== -1)
3420 XDestroyImage (ximg
);
3424 shminfo
->readOnly
= False
;
3425 ximg
->data
= shminfo
->shmaddr
= (char *)shmat (shminfo
->shmid
, 0, 0);
3426 if (shminfo
->shmaddr
== ((char *)-1))
3428 shmctl (shminfo
->shmid
, IPC_RMID
, 0);
3429 XDestroyImage (ximg
);
3433 XShmAttach (xdisplay
, shminfo
);
3434 XSync (xdisplay
, False
);
3435 shmctl (shminfo
->shmid
, IPC_RMID
, 0);
3436 XShmGetImage (xdisplay
, pix
, ximg
, x
, y
, AllPlanes
);
3442 get_image (GtkXText
*xtext
, Display
*xdisplay
, XShmSegmentInfo
*shminfo
,
3443 int x
, int y
, int w
, int h
, int depth
, Pixmap pix
)
3448 ximg
= get_shm_image (xdisplay
, shminfo
, x
, y
, w
, h
, depth
, pix
);
3452 ximg
= XGetImage (xdisplay
, pix
, x
, y
, w
, h
, -1, ZPixmap
);
3461 shade_pixmap (GtkXText
* xtext
, Pixmap p
, int x
, int y
, int w
, int h
)
3463 unsigned int dummy
, width
, height
, depth
;
3464 GdkPixmap
*shaded_pix
;
3470 Display
*xdisplay
= GDK_WINDOW_XDISPLAY (xtext
->draw_buf
);
3474 shm_pixmaps
= have_shm_pixmaps(xdisplay
);
3477 XGetGeometry (xdisplay
, p
, &root
, &dummy
, &dummy
, &width
, &height
,
3480 if (width
< x
+ w
|| height
< y
+ h
|| x
< 0 || y
< 0)
3482 gcv
.subwindow_mode
= IncludeInferiors
;
3483 gcv
.graphics_exposures
= False
;
3484 tgc
= XCreateGC (xdisplay
, p
, GCGraphicsExposures
|GCSubwindowMode
,
3486 tmp
= XCreatePixmap (xdisplay
, p
, w
, h
, depth
);
3487 XSetTile (xdisplay
, tgc
, p
);
3488 XSetFillStyle (xdisplay
, tgc
, FillTiled
);
3489 XSetTSOrigin (xdisplay
, tgc
, -x
, -y
);
3490 XFillRectangle (xdisplay
, tmp
, tgc
, 0, 0, w
, h
);
3491 XFreeGC (xdisplay
, tgc
);
3495 ximg
= get_image (xtext
, xdisplay
, &xtext
->shminfo
, 0, 0, w
, h
, depth
, tmp
);
3498 ximg
= XGetImage (xdisplay
, tmp
, 0, 0, w
, h
, -1, ZPixmap
);
3499 XFreePixmap (xdisplay
, tmp
);
3504 ximg
= get_image (xtext
, xdisplay
, &xtext
->shminfo
, x
, y
, w
, h
, depth
, p
);
3507 ximg
= XGetImage (xdisplay
, p
, x
, y
, w
, h
, -1, ZPixmap
);
3515 shade_ximage_generic (gdk_drawable_get_visual (GTK_WIDGET (xtext
)->window
),
3516 ximg
, ximg
->bytes_per_line
, w
, h
, xtext
->tint_red
,
3517 xtext
->tint_green
, xtext
->tint_blue
,
3518 xtext
->palette
[XTEXT_BG
]);
3521 shade_image (gdk_drawable_get_visual (GTK_WIDGET (xtext
)->window
),
3522 ximg
->data
, ximg
->bytes_per_line
, ximg
->bits_per_pixel
,
3523 w
, h
, xtext
->tint_red
, xtext
->tint_green
, xtext
->tint_blue
,
3524 xtext
->palette
[XTEXT_BG
], depth
);
3528 shaded_pix
= xtext
->pixmap
;
3532 if (xtext
->shm
&& shm_pixmaps
)
3534 shaded_pix
= gdk_pixmap_foreign_new_for_display (
3535 gdk_drawable_get_display (xtext
->draw_buf
),
3536 XShmCreatePixmap (xdisplay
, p
, ximg
->data
, &xtext
->shminfo
, w
, h
, depth
));
3540 shaded_pix
= gdk_pixmap_new (GTK_WIDGET (xtext
)->window
, w
, h
, depth
);
3545 if (!xtext
->shm
|| !shm_pixmaps
)
3547 XPutImage (xdisplay
, GDK_WINDOW_XWINDOW (shaded_pix
),
3548 GDK_GC_XGC (xtext
->fgc
), ximg
, 0, 0, 0, 0, w
, h
);
3549 XDestroyImage (ximg
);
3554 #endif /* !USE_XLIB */
3556 /* free transparency xtext->pixmap */
3557 #if defined(USE_XLIB)
3560 gtk_xtext_free_trans (GtkXText
* xtext
)
3565 if (xtext
->shm
&& have_shm_pixmaps(GDK_WINDOW_XDISPLAY (xtext
->draw_buf
)))
3567 XFreePixmap (GDK_WINDOW_XDISPLAY (xtext
->pixmap
),
3568 GDK_WINDOW_XWINDOW (xtext
->pixmap
));
3569 XShmDetach (GDK_WINDOW_XDISPLAY (xtext
->draw_buf
), &xtext
->shminfo
);
3570 shmdt (xtext
->shminfo
.shmaddr
);
3573 g_object_unref (xtext
->pixmap
);
3574 xtext
->pixmap
= NULL
;
3581 /* grab pixmap from root window and set xtext->pixmap */
3582 #if defined(USE_XLIB)
3585 gtk_xtext_load_trans (GtkXText
* xtext
)
3588 GtkWidget
*widget
= GTK_WIDGET (xtext
);
3591 rootpix
= get_pixmap_prop (GDK_WINDOW_XDISPLAY (widget
->window
), GDK_WINDOW_XWINDOW (widget
->window
));
3592 if (rootpix
== None
)
3594 if (xtext
->error_function
)
3595 xtext
->error_function (0);
3596 xtext
->transparent
= FALSE
;
3600 gdk_window_get_origin (widget
->window
, &x
, &y
);
3605 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &width
, &height
);
3606 xtext
->pixmap
= shade_pixmap (xtext
, rootpix
, x
, y
, width
+105, height
);
3607 if (xtext
->pixmap
== NULL
)
3612 gdk_gc_set_tile (xtext
->bgc
, xtext
->pixmap
);
3613 gdk_gc_set_ts_origin (xtext
->bgc
, 0, 0);
3614 xtext
->ts_x
= xtext
->ts_y
= 0;
3618 xtext
->pixmap
= gdk_pixmap_foreign_new_for_display (gdk_drawable_get_display (GTK_WIDGET (xtext
)->window
), rootpix
);
3619 gdk_gc_set_tile (xtext
->bgc
, xtext
->pixmap
);
3620 gdk_gc_set_ts_origin (xtext
->bgc
, -x
, -y
);
3624 gdk_gc_set_fill (xtext
->bgc
, GDK_TILED
);
3629 /* walk through str until this line doesn't fit anymore */
3632 find_next_wrap (GtkXText
* xtext
, textentry
* ent
, unsigned char *str
,
3633 int win_width
, int indent
)
3635 unsigned char *last_space
= str
;
3636 unsigned char *orig_str
= str
;
3637 int str_width
= indent
;
3638 int rcol
= 0, bgcol
= 0;
3643 int limit_offset
= 0;
3646 if (win_width
>= ent
->str_width
+ ent
->indent
)
3647 return ent
->str_len
;
3649 /* it does happen! */
3652 ret
= ent
->str_len
- (str
- ent
->str
);
3658 if (rcol
> 0 && (isdigit (*str
) || (*str
== ',' && isdigit (str
[1]) && !bgcol
)))
3660 if (str
[1] != ',') rcol
--;
3679 case ATTR_UNDERLINE
:
3685 if (xtext
->ignore_hidden
)
3693 char_width
= backend_get_char_width (xtext
, str
, &mbl
);
3694 if (!hidden
) str_width
+= char_width
;
3695 if (str_width
> win_width
)
3697 if (xtext
->wordwrap
)
3699 if (str
- last_space
> WORDWRAP_LIMIT
+ limit_offset
)
3700 ret
= str
- orig_str
; /* fall back to character wrap */
3703 if (*last_space
== ' ')
3705 ret
= last_space
- orig_str
;
3706 if (ret
== 0) /* fall back to character wrap */
3707 ret
= str
- orig_str
;
3711 ret
= str
- orig_str
;
3715 /* keep a record of the last space, for wordwrapping */
3722 /* progress to the next char */
3728 if (str
>= ent
->str
+ ent
->str_len
)
3730 ret
= str
- orig_str
;
3737 /* must make progress */
3744 /* find the offset, in bytes, that wrap number 'line' starts at */
3747 gtk_xtext_find_subline (GtkXText
*xtext
, textentry
*ent
, int line
)
3751 int indent
, str_pos
, line_pos
, len
;
3753 if (ent
->lines_taken
< 2 || line
< 1)
3756 /* we record the first 4 lines' wraps, so take a shortcut */
3757 if (line
<= RECORD_WRAPS
)
3758 return ent
->wrap_offset
[line
- 1];
3760 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &win_width
, 0);
3761 win_width
-= MARGIN
;
3763 /* indent = ent->indent;
3765 line_pos = str_pos = 0;*/
3767 /* start from the last recorded wrap, and move forward */
3768 indent
= xtext
->buffer
->indent
;
3769 str_pos
= ent
->wrap_offset
[RECORD_WRAPS
-1];
3770 str
= str_pos
+ ent
->str
;
3771 line_pos
= RECORD_WRAPS
;
3775 len
= find_next_wrap (xtext
, ent
, str
, win_width
, indent
);
3776 indent
= xtext
->buffer
->indent
;
3780 if (line_pos
>= line
)
3783 while (str
< ent
->str
+ ent
->str_len
);
3788 /* horrible hack for drawing time stamps */
3791 gtk_xtext_render_stamp (GtkXText
* xtext
, textentry
* ent
,
3792 char *text
, int len
, int line
, int win_width
)
3798 /* trashing ent here, so make a backup first */
3799 memcpy (&tmp_ent
, ent
, sizeof (tmp_ent
));
3800 ent
->mb
= TRUE
; /* make non-english days of the week work */
3801 jo
= xtext
->jump_out_offset
; /* back these up */
3802 ji
= xtext
->jump_in_offset
;
3803 hs
= xtext
->hilight_start
;
3804 xtext
->jump_out_offset
= 0;
3805 xtext
->jump_in_offset
= 0;
3806 xtext
->hilight_start
= 0xffff; /* temp disable */
3808 if (xtext
->mark_stamp
)
3810 /* if this line is marked, mark this stamp too */
3811 if (ent
->mark_start
== 0)
3813 ent
->mark_start
= 0;
3814 ent
->mark_end
= len
;
3818 ent
->mark_start
= -1;
3824 y
= (xtext
->fontsize
* line
) + xtext
->font
->ascent
- xtext
->pixel_offset
;
3825 gtk_xtext_render_str (xtext
, y
, ent
, text
, len
,
3826 win_width
, 2, line
, TRUE
, &xsize
);
3828 /* restore everything back to how it was */
3829 memcpy (ent
, &tmp_ent
, sizeof (tmp_ent
));
3830 xtext
->jump_out_offset
= jo
;
3831 xtext
->jump_in_offset
= ji
;
3832 xtext
->hilight_start
= hs
;
3834 /* with a non-fixed-width font, sometimes we don't draw enough
3835 background i.e. when this stamp is shorter than xtext->stamp_width */
3837 if (xsize
< xtext
->stamp_width
)
3839 y
-= xtext
->font
->ascent
;
3840 xtext_draw_bg (xtext
,
3843 xtext
->stamp_width
- xsize
, /* width */
3844 xtext
->fontsize
/* height */);
3848 /* render a single line, which may wrap to more lines */
3851 gtk_xtext_render_line (GtkXText
* xtext
, textentry
* ent
, int line
,
3852 int lines_max
, int subline
, int win_width
)
3855 int indent
, taken
, entline
, len
, y
, start_subline
;
3857 entline
= taken
= 0;
3859 indent
= ent
->indent
;
3860 start_subline
= subline
;
3863 /* draw the timestamp */
3864 if (xtext
->auto_indent
&& xtext
->buffer
->time_stamp
&&
3865 (!xtext
->skip_stamp
|| xtext
->mark_stamp
|| xtext
->force_stamp
))
3870 len
= xtext_get_stamp_str (ent
->stamp
, &time_str
);
3871 gtk_xtext_render_stamp (xtext
, ent
, time_str
, len
, line
, win_width
);
3876 /* draw each line one by one */
3879 /* if it's one of the first 4 wraps, we don't need to calculate it, it's
3880 recorded in ->wrap_offset. This saves us a loop. */
3881 if (entline
< RECORD_WRAPS
)
3883 if (ent
->lines_taken
< 2)
3888 len
= ent
->wrap_offset
[entline
] - ent
->wrap_offset
[entline
-1];
3890 len
= ent
->wrap_offset
[0];
3893 len
= find_next_wrap (xtext
, ent
, str
, win_width
, indent
);
3897 y
= (xtext
->fontsize
* line
) + xtext
->font
->ascent
- xtext
->pixel_offset
;
3900 if (!gtk_xtext_render_str (xtext
, y
, ent
, str
, len
, win_width
,
3901 indent
, line
, FALSE
, NULL
))
3903 /* small optimization */
3904 gtk_xtext_draw_marker (xtext
, ent
, y
- xtext
->fontsize
* (taken
+ start_subline
+ 1));
3905 return ent
->lines_taken
- subline
;
3909 xtext
->dont_render
= TRUE
;
3910 gtk_xtext_render_str (xtext
, y
, ent
, str
, len
, win_width
,
3911 indent
, line
, FALSE
, NULL
);
3912 xtext
->dont_render
= FALSE
;
3918 indent
= xtext
->buffer
->indent
;
3923 if (line
>= lines_max
)
3927 while (str
< ent
->str
+ ent
->str_len
);
3929 gtk_xtext_draw_marker (xtext
, ent
, y
- xtext
->fontsize
* (taken
+ start_subline
));
3935 gtk_xtext_set_palette (GtkXText
* xtext
, GdkColor palette
[])
3940 for (i
= (XTEXT_COLS
-1); i
>= 0; i
--)
3943 xtext
->color
[i
].color
.red
= palette
[i
].red
;
3944 xtext
->color
[i
].color
.green
= palette
[i
].green
;
3945 xtext
->color
[i
].color
.blue
= palette
[i
].blue
;
3946 xtext
->color
[i
].color
.alpha
= 0xffff;
3947 xtext
->color
[i
].pixel
= palette
[i
].pixel
;
3949 xtext
->palette
[i
] = palette
[i
].pixel
;
3952 if (GTK_WIDGET_REALIZED (xtext
))
3954 xtext_set_fg (xtext
, xtext
->fgc
, XTEXT_FG
);
3955 xtext_set_bg (xtext
, xtext
->fgc
, XTEXT_BG
);
3956 xtext_set_fg (xtext
, xtext
->bgc
, XTEXT_BG
);
3958 col
.pixel
= xtext
->palette
[XTEXT_MARKER
];
3959 gdk_gc_set_foreground (xtext
->marker_gc
, &col
);
3961 xtext
->col_fore
= XTEXT_FG
;
3962 xtext
->col_back
= XTEXT_BG
;
3966 gtk_xtext_fix_indent (xtext_buffer
*buf
)
3970 /* make indent a multiple of the space width */
3971 if (buf
->indent
&& buf
->xtext
->space_width
)
3974 while (j
< buf
->indent
)
3976 j
+= buf
->xtext
->space_width
;
3981 dontscroll (buf
); /* force scrolling off */
3985 gtk_xtext_recalc_widths (xtext_buffer
*buf
, int do_str_width
)
3989 /* since we have a new font, we have to recalc the text widths */
3990 ent
= buf
->text_first
;
3995 ent
->str_width
= gtk_xtext_text_width (buf
->xtext
, ent
->str
,
3996 ent
->str_len
, NULL
);
3998 if (ent
->left_len
!= -1)
4002 gtk_xtext_text_width (buf
->xtext
, ent
->str
,
4003 ent
->left_len
, NULL
)) - buf
->xtext
->space_width
;
4004 if (ent
->indent
< MARGIN
)
4005 ent
->indent
= MARGIN
;
4010 gtk_xtext_calc_lines (buf
, FALSE
);
4014 gtk_xtext_set_font (GtkXText
*xtext
, char *name
)
4020 backend_font_close (xtext
);
4022 /* realize now, so that font_open has a XDisplay */
4023 gtk_widget_realize (GTK_WIDGET (xtext
));
4025 backend_font_open (xtext
, name
);
4026 if (xtext
->font
== NULL
)
4029 /* measure the width of every char; only the ASCII ones for XFT */
4030 for (i
= 0; i
< sizeof(xtext
->fontwidth
)/sizeof(xtext
->fontwidth
[0]); i
++)
4033 xtext
->fontwidth
[i
] = backend_get_text_width (xtext
, &c
, 1, TRUE
);
4035 xtext
->space_width
= xtext
->fontwidth
[' '];
4036 xtext
->fontsize
= xtext
->font
->ascent
+ xtext
->font
->descent
;
4041 int stamp_size
= xtext_get_stamp_str (time(0), &time_str
);
4042 xtext
->stamp_width
=
4043 gtk_xtext_text_width (xtext
, time_str
, stamp_size
, NULL
) + MARGIN
;
4048 gtk_xtext_fix_indent (xtext
->buffer
);
4050 if (GTK_WIDGET_REALIZED (xtext
))
4051 gtk_xtext_recalc_widths (xtext
->buffer
, TRUE
);
4057 gtk_xtext_set_background (GtkXText
* xtext
, GdkPixmap
* pixmap
, gboolean trans
)
4060 gboolean shaded
= FALSE
;
4062 if (trans
&& (xtext
->tint_red
!= 255 || xtext
->tint_green
!= 255 || xtext
->tint_blue
!= 255))
4065 #if !defined(USE_XLIB)
4072 #if defined(USE_XLIB)
4073 if (xtext
->transparent
)
4074 gtk_xtext_free_trans (xtext
);
4077 g_object_unref (xtext
->pixmap
);
4078 xtext
->pixmap
= NULL
;
4081 xtext
->transparent
= trans
;
4083 #if defined(USE_XLIB)
4086 xtext
->shaded
= shaded
;
4087 if (GTK_WIDGET_REALIZED (xtext
))
4088 gtk_xtext_load_trans (xtext
);
4093 dontscroll (xtext
->buffer
);
4094 xtext
->pixmap
= pixmap
;
4098 g_object_ref (pixmap
);
4099 if (GTK_WIDGET_REALIZED (xtext
))
4101 gdk_gc_set_tile (xtext
->bgc
, pixmap
);
4102 gdk_gc_set_ts_origin (xtext
->bgc
, 0, 0);
4103 xtext
->ts_x
= xtext
->ts_y
= 0;
4104 gdk_gc_set_fill (xtext
->bgc
, GDK_TILED
);
4106 } else if (GTK_WIDGET_REALIZED (xtext
))
4108 g_object_unref (xtext
->bgc
);
4109 val
.subwindow_mode
= GDK_INCLUDE_INFERIORS
;
4110 val
.graphics_exposures
= 0;
4111 xtext
->bgc
= gdk_gc_new_with_values (GTK_WIDGET (xtext
)->window
,
4112 &val
, GDK_GC_EXPOSURES
| GDK_GC_SUBWINDOW
);
4113 xtext_set_fg (xtext
, xtext
->bgc
, XTEXT_BG
);
4118 gtk_xtext_save (GtkXText
* xtext
, int fh
)
4124 ent
= xtext
->buffer
->text_first
;
4127 buf
= gtk_xtext_strip_color (ent
->str
, ent
->str_len
, NULL
,
4128 &newlen
, NULL
, FALSE
);
4129 write (fh
, buf
, newlen
);
4130 write (fh
, "\n", 1);
4136 /* count how many lines 'ent' will take (with wraps) */
4139 gtk_xtext_lines_taken (xtext_buffer
*buf
, textentry
* ent
)
4142 int indent
, taken
, len
;
4145 win_width
= buf
->window_width
- MARGIN
;
4147 if (ent
->str_width
+ ent
->indent
< win_width
)
4150 indent
= ent
->indent
;
4156 len
= find_next_wrap (buf
->xtext
, ent
, str
, win_width
, indent
);
4157 if (taken
< RECORD_WRAPS
)
4158 ent
->wrap_offset
[taken
] = (str
+ len
) - ent
->str
;
4159 indent
= buf
->indent
;
4163 while (str
< ent
->str
+ ent
->str_len
);
4168 /* Calculate number of actual lines (with wraps), to set adj->lower. *
4169 * This should only be called when the window resizes. */
4172 gtk_xtext_calc_lines (xtext_buffer
*buf
, int fire_signal
)
4179 gdk_drawable_get_size (GTK_WIDGET (buf
->xtext
)->window
, &width
, &height
);
4182 if (width
< 30 || height
< buf
->xtext
->fontsize
|| width
< buf
->indent
+ 30)
4186 ent
= buf
->text_first
;
4189 ent
->lines_taken
= gtk_xtext_lines_taken (buf
, ent
);
4190 lines
+= ent
->lines_taken
;
4194 buf
->pagetop_ent
= NULL
;
4195 buf
->num_lines
= lines
;
4196 gtk_xtext_adjustment_set (buf
, fire_signal
);
4199 /* find the n-th line in the linked list, this includes wrap calculations */
4202 gtk_xtext_nth (GtkXText
*xtext
, int line
, int *subline
)
4207 ent
= xtext
->buffer
->text_first
;
4209 /* -- optimization -- try to make a short-cut using the pagetop ent */
4210 if (xtext
->buffer
->pagetop_ent
)
4212 if (line
== xtext
->buffer
->pagetop_line
)
4214 *subline
= xtext
->buffer
->pagetop_subline
;
4215 return xtext
->buffer
->pagetop_ent
;
4217 if (line
> xtext
->buffer
->pagetop_line
)
4219 /* lets start from the pagetop instead of the absolute beginning */
4220 ent
= xtext
->buffer
->pagetop_ent
;
4221 lines
= xtext
->buffer
->pagetop_line
- xtext
->buffer
->pagetop_subline
;
4223 else if (line
> xtext
->buffer
->pagetop_line
- line
)
4225 /* move backwards from pagetop */
4226 ent
= xtext
->buffer
->pagetop_ent
;
4227 lines
= xtext
->buffer
->pagetop_line
- xtext
->buffer
->pagetop_subline
;
4232 *subline
= line
- lines
;
4238 lines
-= ent
->lines_taken
;
4243 /* -- end of optimization -- */
4247 lines
+= ent
->lines_taken
;
4250 *subline
= ent
->lines_taken
- (lines
- line
);
4258 /* render enta (or an inclusive range enta->entb) */
4261 gtk_xtext_render_ents (GtkXText
* xtext
, textentry
* enta
, textentry
* entb
)
4263 textentry
*ent
, *orig_ent
, *tmp_ent
;
4269 int drawing
= FALSE
;
4271 if (xtext
->buffer
->indent
< MARGIN
)
4272 xtext
->buffer
->indent
= MARGIN
; /* 2 pixels is our left margin */
4274 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &width
, &height
);
4277 if (width
< 32 || height
< xtext
->fontsize
|| width
< xtext
->buffer
->indent
+ 30)
4280 lines_max
= ((height
+ xtext
->pixel_offset
) / xtext
->fontsize
) + 1;
4282 orig_ent
= xtext
->buffer
->pagetop_ent
;
4283 subline
= xtext
->buffer
->pagetop_subline
;
4285 /* used before a complete page is in buffer */
4286 if (orig_ent
== NULL
)
4287 orig_ent
= xtext
->buffer
->text_first
;
4289 /* check if enta is before the start of this page */
4295 if (tmp_ent
== enta
)
4297 if (tmp_ent
== entb
)
4302 tmp_ent
= tmp_ent
->next
;
4309 if (entb
&& ent
== enta
)
4312 if (drawing
|| ent
== entb
|| ent
== enta
)
4314 gtk_xtext_reset (xtext
, FALSE
, TRUE
);
4315 line
+= gtk_xtext_render_line (xtext
, ent
, line
, lines_max
,
4318 xtext
->jump_in_offset
= 0; /* jump_in_offset only for the 1st */
4321 if (ent
== orig_ent
)
4326 line
+= ent
->lines_taken
;
4332 if (line
>= lines_max
)
4338 /* space below last line */
4339 return (xtext
->fontsize
* line
) - xtext
->pixel_offset
;
4342 /* render a whole page/window, starting from 'startline' */
4345 gtk_xtext_render_page (GtkXText
* xtext
)
4353 int startline
= xtext
->adj
->value
;
4355 if(!GTK_WIDGET_REALIZED(xtext
))
4358 if (xtext
->buffer
->indent
< MARGIN
)
4359 xtext
->buffer
->indent
= MARGIN
; /* 2 pixels is our left margin */
4361 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &width
, &height
);
4363 if (width
< 34 || height
< xtext
->fontsize
|| width
< xtext
->buffer
->indent
+ 32)
4366 #ifdef SMOOTH_SCROLL
4367 xtext
->pixel_offset
= (xtext
->adj
->value
- startline
) * xtext
->fontsize
;
4369 xtext
->pixel_offset
= 0;
4373 ent
= xtext
->buffer
->text_first
;
4376 ent
= gtk_xtext_nth (xtext
, startline
, &subline
);
4378 xtext
->buffer
->pagetop_ent
= ent
;
4379 xtext
->buffer
->pagetop_subline
= subline
;
4380 xtext
->buffer
->pagetop_line
= startline
;
4387 if (xtext
->buffer
->num_lines
<= xtext
->adj
->page_size
)
4388 dontscroll (xtext
->buffer
);
4390 #ifdef SMOOTH_SCROLL
4391 pos
= xtext
->adj
->value
* xtext
->fontsize
;
4393 pos
= startline
* xtext
->fontsize
;
4395 overlap
= xtext
->buffer
->last_pixel_pos
- pos
;
4396 xtext
->buffer
->last_pixel_pos
= pos
;
4399 if (!xtext
->pixmap
&& abs (overlap
) < height
)
4401 /* dont scroll PageUp/Down without a DB, it looks ugly */
4402 if (!xtext
->pixmap
&& abs (overlap
) < height
- (3*xtext
->fontsize
))
4405 /* so the obscured regions are exposed */
4406 gdk_gc_set_exposures (xtext
->fgc
, TRUE
);
4407 if (overlap
< 1) /* DOWN */
4411 gdk_draw_drawable (xtext
->draw_buf
, xtext
->fgc
, xtext
->draw_buf
,
4412 0, -overlap
, 0, 0, width
, height
+ overlap
);
4413 remainder
= ((height
- xtext
->font
->descent
) % xtext
->fontsize
) +
4414 xtext
->font
->descent
;
4415 area
.y
= (height
+ overlap
) - remainder
;
4416 area
.height
= remainder
- overlap
;
4419 gdk_draw_drawable (xtext
->draw_buf
, xtext
->fgc
, xtext
->draw_buf
,
4420 0, 0, 0, overlap
, width
, height
- overlap
);
4422 area
.height
= overlap
;
4424 gdk_gc_set_exposures (xtext
->fgc
, FALSE
);
4426 if (area
.height
> 0)
4430 gtk_xtext_paint (GTK_WIDGET (xtext
), &area
);
4432 xtext
->buffer
->grid_dirty
= TRUE
;
4439 xtext
->buffer
->grid_dirty
= FALSE
;
4441 lines_max
= ((height
+ xtext
->pixel_offset
) / xtext
->fontsize
) + 1;
4445 gtk_xtext_reset (xtext
, FALSE
, TRUE
);
4446 line
+= gtk_xtext_render_line (xtext
, ent
, line
, lines_max
,
4450 if (line
>= lines_max
)
4456 line
= (xtext
->fontsize
* line
) - xtext
->pixel_offset
;
4457 /* fill any space below the last line with our background GC */
4458 xtext_draw_bg (xtext
, 0, line
, width
+ MARGIN
, height
- line
);
4460 /* draw the separator line */
4461 gtk_xtext_draw_sep (xtext
, -1);
4465 gtk_xtext_refresh (GtkXText
* xtext
, int do_trans
)
4467 if (GTK_WIDGET_REALIZED (GTK_WIDGET (xtext
)))
4469 #if defined(USE_XLIB)
4470 if (xtext
->transparent
&& do_trans
)
4472 gtk_xtext_free_trans (xtext
);
4473 gtk_xtext_load_trans (xtext
);
4476 gtk_xtext_render_page (xtext
);
4481 gtk_xtext_kill_ent (xtext_buffer
*buffer
, textentry
*ent
)
4485 /* Set visible to TRUE if this is the current buffer */
4486 /* and this ent shows up on the screen now */
4487 visible
= buffer
->xtext
->buffer
== buffer
&&
4488 gtk_xtext_check_ent_visibility (buffer
->xtext
, ent
, 0);
4490 if (ent
== buffer
->pagetop_ent
)
4491 buffer
->pagetop_ent
= NULL
;
4493 if (ent
== buffer
->last_ent_start
)
4495 buffer
->last_ent_start
= ent
->next
;
4496 buffer
->last_offset_start
= 0;
4499 if (ent
== buffer
->last_ent_end
)
4501 buffer
->last_ent_start
= NULL
;
4502 buffer
->last_ent_end
= NULL
;
4505 if (buffer
->marker_pos
== ent
) buffer
->marker_pos
= NULL
;
4511 /* remove the topline from the list */
4514 gtk_xtext_remove_top (xtext_buffer
*buffer
)
4518 ent
= buffer
->text_first
;
4521 buffer
->num_lines
-= ent
->lines_taken
;
4522 buffer
->pagetop_line
-= ent
->lines_taken
;
4523 buffer
->last_pixel_pos
-= (ent
->lines_taken
* buffer
->xtext
->fontsize
);
4524 buffer
->text_first
= ent
->next
;
4525 if (buffer
->text_first
)
4526 buffer
->text_first
->prev
= NULL
;
4528 buffer
->text_last
= NULL
;
4530 buffer
->old_value
-= ent
->lines_taken
;
4531 if (buffer
->xtext
->buffer
== buffer
) /* is it the current buffer? */
4533 buffer
->xtext
->adj
->value
-= ent
->lines_taken
;
4534 buffer
->xtext
->select_start_adj
-= ent
->lines_taken
;
4537 if (gtk_xtext_kill_ent (buffer
, ent
))
4539 if (!buffer
->xtext
->add_io_tag
)
4541 /* remove scrolling events */
4542 if (buffer
->xtext
->io_tag
)
4544 g_source_remove (buffer
->xtext
->io_tag
);
4545 buffer
->xtext
->io_tag
= 0;
4547 buffer
->xtext
->force_render
= TRUE
;
4548 buffer
->xtext
->add_io_tag
= g_timeout_add (REFRESH_TIMEOUT
* 2,
4550 gtk_xtext_render_page_timeout
,
4557 gtk_xtext_remove_bottom (xtext_buffer
*buffer
)
4561 ent
= buffer
->text_last
;
4564 buffer
->num_lines
-= ent
->lines_taken
;
4565 buffer
->text_last
= ent
->prev
;
4566 if (buffer
->text_last
)
4567 buffer
->text_last
->next
= NULL
;
4569 buffer
->text_first
= NULL
;
4571 gtk_xtext_kill_ent (buffer
, ent
);
4574 /* If lines=0 => clear all */
4577 gtk_xtext_clear (xtext_buffer
*buf
, int lines
)
4585 /* delete lines from bottom */
4589 gtk_xtext_remove_bottom (buf
);
4595 /* delete lines from top */
4598 gtk_xtext_remove_top (buf
);
4606 if (buf
->xtext
->auto_indent
)
4607 buf
->indent
= MARGIN
;
4608 buf
->scrollbar_down
= TRUE
;
4609 buf
->last_ent_start
= NULL
;
4610 buf
->last_ent_end
= NULL
;
4611 buf
->marker_pos
= NULL
;
4614 while (buf
->text_first
)
4616 next
= buf
->text_first
->next
;
4617 free (buf
->text_first
);
4618 buf
->text_first
= next
;
4620 buf
->text_last
= NULL
;
4623 if (buf
->xtext
->buffer
== buf
)
4625 gtk_xtext_calc_lines (buf
, TRUE
);
4626 gtk_xtext_refresh (buf
->xtext
, 0);
4629 gtk_xtext_calc_lines (buf
, FALSE
);
4634 gtk_xtext_check_ent_visibility (GtkXText
* xtext
, textentry
*find_ent
, int add
)
4642 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &width
, &height
);
4644 lines_max
= ((height
+ xtext
->pixel_offset
) / xtext
->fontsize
) + add
;
4645 ent
= xtext
->buffer
->pagetop_ent
;
4647 while (ent
&& line
< lines_max
)
4649 if (find_ent
== ent
)
4651 line
+= ent
->lines_taken
;
4659 gtk_xtext_check_marker_visibility (GtkXText
* xtext
)
4661 if (gtk_xtext_check_ent_visibility (xtext
, xtext
->buffer
->marker_pos
, 1))
4662 xtext
->buffer
->marker_seen
= TRUE
;
4666 gtk_xtext_search (GtkXText
* xtext
, const gchar
*text
, textentry
*start
, gboolean case_match
, gboolean backward
)
4668 textentry
*ent
, *fent
;
4670 gchar
*str
, *nee
, *hay
; /* needle in haystack */
4672 gtk_xtext_selection_clear_full (xtext
->buffer
);
4673 xtext
->buffer
->last_ent_start
= NULL
;
4674 xtext
->buffer
->last_ent_end
= NULL
;
4676 /* set up text comparand for Case Match or Ignore */
4678 nee
= g_strdup (text
);
4680 nee
= g_utf8_casefold (text
, strlen (text
));
4682 /* Validate that start gives a currently valid ent pointer */
4683 ent
= xtext
->buffer
->text_first
;
4693 /* Choose first ent to look at */
4695 ent
= backward
? start
->prev
: start
->next
;
4697 ent
= backward
? xtext
->buffer
->text_last
: xtext
->buffer
->text_first
;
4699 /* Search from there to one end or the other until found */
4702 /* If Case Ignore, fold before & free after calling strstr */
4704 hay
= g_strdup (ent
->str
);
4706 hay
= g_utf8_casefold (ent
->str
, strlen (ent
->str
));
4707 /* Try to find the needle in this haystack */
4708 str
= g_strstr_len (hay
, strlen (hay
), nee
);
4712 ent
= backward
? ent
->prev
: ent
->next
;
4716 /* Save distance to start, end of found string */
4719 ent
->mark_start
= str
- hay
;
4720 ent
->mark_end
= ent
->mark_start
+ strlen (nee
);
4722 /* is the match visible? Might need to scroll */
4723 if (!gtk_xtext_check_ent_visibility (xtext
, ent
, 0))
4725 ent
= xtext
->buffer
->text_first
;
4729 line
+= ent
->lines_taken
;
4734 while (line
> xtext
->adj
->upper
- xtext
->adj
->page_size
)
4737 line
-= xtext
->adj
->page_size
- ent
->lines_taken
;
4738 xtext
->adj
->value
= line
;
4739 xtext
->buffer
->scrollbar_down
= FALSE
;
4740 gtk_adjustment_changed (xtext
->adj
);
4745 gtk_widget_queue_draw (GTK_WIDGET (xtext
));
4751 gtk_xtext_render_page_timeout (GtkXText
* xtext
)
4753 GtkAdjustment
*adj
= xtext
->adj
;
4755 xtext
->add_io_tag
= 0;
4757 /* less than a complete page? */
4758 if (xtext
->buffer
->num_lines
<= adj
->page_size
)
4760 xtext
->buffer
->old_value
= 0;
4762 gtk_xtext_render_page (xtext
);
4763 } else if (xtext
->buffer
->scrollbar_down
)
4765 g_signal_handler_block (xtext
->adj
, xtext
->vc_signal_tag
);
4766 gtk_xtext_adjustment_set (xtext
->buffer
, FALSE
);
4767 gtk_adjustment_set_value (adj
, adj
->upper
- adj
->page_size
);
4768 g_signal_handler_unblock (xtext
->adj
, xtext
->vc_signal_tag
);
4769 xtext
->buffer
->old_value
= adj
->value
;
4770 gtk_xtext_render_page (xtext
);
4773 gtk_xtext_adjustment_set (xtext
->buffer
, TRUE
);
4774 if (xtext
->force_render
)
4776 xtext
->force_render
= FALSE
;
4777 gtk_xtext_render_page (xtext
);
4784 /* append a textentry to our linked list */
4787 gtk_xtext_append_entry (xtext_buffer
*buf
, textentry
* ent
, time_t stamp
)
4792 /* we don't like tabs */
4794 while (i
< ent
->str_len
)
4796 if (ent
->str
[i
] == '\t')
4803 ent
->stamp
= time (0);
4804 ent
->str_width
= gtk_xtext_text_width (buf
->xtext
, ent
->str
, ent
->str_len
, &mb
);
4808 ent
->mark_start
= -1;
4812 if (ent
->indent
< MARGIN
)
4813 ent
->indent
= MARGIN
; /* 2 pixels is the left margin */
4815 /* append to our linked list */
4817 buf
->text_last
->next
= ent
;
4819 buf
->text_first
= ent
;
4820 ent
->prev
= buf
->text_last
;
4821 buf
->text_last
= ent
;
4823 ent
->lines_taken
= gtk_xtext_lines_taken (buf
, ent
);
4824 buf
->num_lines
+= ent
->lines_taken
;
4826 if (buf
->reset_marker_pos
||
4827 ((buf
->marker_pos
== NULL
|| buf
->marker_seen
) && (buf
->xtext
->buffer
!= buf
||
4828 !gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (buf
->xtext
)))))))
4830 buf
->marker_pos
= ent
;
4831 dontscroll (buf
); /* force scrolling off */
4832 buf
->marker_seen
= FALSE
;
4833 buf
->reset_marker_pos
= FALSE
;
4836 if (buf
->xtext
->max_lines
> 2 && buf
->xtext
->max_lines
< buf
->num_lines
)
4838 gtk_xtext_remove_top (buf
);
4841 if (buf
->xtext
->buffer
== buf
)
4844 /* this could be improved */
4845 if ((buf
->num_lines
- 1) <= buf
->xtext
->adj
->page_size
)
4849 if (!buf
->xtext
->add_io_tag
)
4851 /* remove scrolling events */
4852 if (buf
->xtext
->io_tag
)
4854 g_source_remove (buf
->xtext
->io_tag
);
4855 buf
->xtext
->io_tag
= 0;
4857 buf
->xtext
->add_io_tag
= g_timeout_add (REFRESH_TIMEOUT
* 2,
4859 gtk_xtext_render_page_timeout
,
4862 } else if (buf
->scrollbar_down
)
4864 buf
->old_value
= buf
->num_lines
- buf
->xtext
->adj
->page_size
;
4865 if (buf
->old_value
< 0)
4870 /* the main two public functions */
4873 gtk_xtext_append_indent (xtext_buffer
*buf
,
4874 unsigned char *left_text
, int left_len
,
4875 unsigned char *right_text
, int right_len
,
4885 left_len
= strlen (left_text
);
4887 if (right_len
== -1)
4888 right_len
= strlen (right_text
);
4890 if (right_len
>= sizeof (buf
->xtext
->scratch_buffer
))
4891 right_len
= sizeof (buf
->xtext
->scratch_buffer
) - 1;
4893 if (right_text
[right_len
-1] == '\n')
4896 ent
= malloc (left_len
+ right_len
+ 2 + sizeof (textentry
));
4897 str
= (unsigned char *) ent
+ sizeof (textentry
);
4899 memcpy (str
, left_text
, left_len
);
4900 str
[left_len
] = ' ';
4901 memcpy (str
+ left_len
+ 1, right_text
, right_len
);
4902 str
[left_len
+ 1 + right_len
] = 0;
4904 left_width
= gtk_xtext_text_width (buf
->xtext
, left_text
, left_len
, NULL
);
4906 ent
->left_len
= left_len
;
4908 ent
->str_len
= left_len
+ 1 + right_len
;
4909 ent
->indent
= (buf
->indent
- left_width
) - buf
->xtext
->space_width
;
4911 if (buf
->time_stamp
)
4912 space
= buf
->xtext
->stamp_width
;
4916 /* do we need to auto adjust the separator position? */
4917 if (buf
->xtext
->auto_indent
&& ent
->indent
< MARGIN
+ space
)
4919 tempindent
= MARGIN
+ space
+ buf
->xtext
->space_width
+ left_width
;
4921 if (tempindent
> buf
->indent
)
4922 buf
->indent
= tempindent
;
4924 if (buf
->indent
> buf
->xtext
->max_auto_indent
)
4925 buf
->indent
= buf
->xtext
->max_auto_indent
;
4927 gtk_xtext_fix_indent (buf
);
4928 gtk_xtext_recalc_widths (buf
, FALSE
);
4930 ent
->indent
= (buf
->indent
- left_width
) - buf
->xtext
->space_width
;
4931 buf
->xtext
->force_render
= TRUE
;
4934 gtk_xtext_append_entry (buf
, ent
, stamp
);
4938 gtk_xtext_append (xtext_buffer
*buf
, unsigned char *text
, int len
)
4943 len
= strlen (text
);
4945 if (text
[len
-1] == '\n')
4948 if (len
>= sizeof (buf
->xtext
->scratch_buffer
))
4949 len
= sizeof (buf
->xtext
->scratch_buffer
) - 1;
4951 ent
= malloc (len
+ 1 + sizeof (textentry
));
4952 ent
->str
= (unsigned char *) ent
+ sizeof (textentry
);
4955 memcpy (ent
->str
, text
, len
);
4960 gtk_xtext_append_entry (buf
, ent
, 0);
4964 gtk_xtext_is_empty (xtext_buffer
*buf
)
4966 return buf
->text_first
== NULL
;
4970 gtk_xtext_lastlog (xtext_buffer
*out
, xtext_buffer
*search_area
,
4971 int (*cmp_func
) (char *, void *), void *userdata
)
4973 textentry
*ent
= search_area
->text_first
;
4978 if (cmp_func (ent
->str
, userdata
))
4981 /* copy the text over */
4982 if (search_area
->xtext
->auto_indent
)
4983 gtk_xtext_append_indent (out
, ent
->str
, ent
->left_len
,
4984 ent
->str
+ ent
->left_len
+ 1,
4985 ent
->str_len
- ent
->left_len
- 1, 0);
4987 gtk_xtext_append (out
, ent
->str
, ent
->str_len
);
4988 /* copy the timestamp over */
4989 out
->text_last
->stamp
= ent
->stamp
;
4998 gtk_xtext_foreach (xtext_buffer
*buf
, GtkXTextForeach func
, void *data
)
5000 textentry
*ent
= buf
->text_first
;
5004 (*func
) (buf
->xtext
, ent
->str
, data
);
5010 gtk_xtext_set_error_function (GtkXText
*xtext
, void (*error_function
) (int))
5012 xtext
->error_function
= error_function
;
5016 gtk_xtext_set_indent (GtkXText
*xtext
, gboolean indent
)
5018 xtext
->auto_indent
= indent
;
5022 gtk_xtext_set_max_indent (GtkXText
*xtext
, int max_auto_indent
)
5024 xtext
->max_auto_indent
= max_auto_indent
;
5028 gtk_xtext_set_max_lines (GtkXText
*xtext
, int max_lines
)
5030 xtext
->max_lines
= max_lines
;
5034 gtk_xtext_set_show_marker (GtkXText
*xtext
, gboolean show_marker
)
5036 xtext
->marker
= show_marker
;
5040 gtk_xtext_set_show_separator (GtkXText
*xtext
, gboolean show_separator
)
5042 xtext
->separator
= show_separator
;
5046 gtk_xtext_set_thin_separator (GtkXText
*xtext
, gboolean thin_separator
)
5048 xtext
->thinline
= thin_separator
;
5052 gtk_xtext_set_time_stamp (xtext_buffer
*buf
, gboolean time_stamp
)
5054 buf
->time_stamp
= time_stamp
;
5058 gtk_xtext_set_tint (GtkXText
*xtext
, int tint_red
, int tint_green
, int tint_blue
)
5060 xtext
->tint_red
= tint_red
;
5061 xtext
->tint_green
= tint_green
;
5062 xtext
->tint_blue
= tint_blue
;
5064 /*if (xtext->tint_red != 255 || xtext->tint_green != 255 || xtext->tint_blue != 255)
5069 gtk_xtext_set_urlcheck_function (GtkXText
*xtext
, int (*urlcheck_function
) (GtkWidget
*, char *, int))
5071 xtext
->urlcheck_function
= urlcheck_function
;
5075 gtk_xtext_set_wordwrap (GtkXText
*xtext
, gboolean wordwrap
)
5077 xtext
->wordwrap
= wordwrap
;
5081 gtk_xtext_reset_marker_pos (GtkXText
*xtext
)
5083 xtext
->buffer
->marker_pos
= NULL
;
5084 dontscroll (xtext
->buffer
); /* force scrolling off */
5085 gtk_xtext_render_page (xtext
);
5086 xtext
->buffer
->reset_marker_pos
= TRUE
;
5090 gtk_xtext_buffer_show (GtkXText
*xtext
, xtext_buffer
*buf
, int render
)
5096 if (xtext
->buffer
== buf
)
5099 /*printf("text_buffer_show: xtext=%p buffer=%p\n", xtext, buf);*/
5101 if (xtext
->add_io_tag
)
5103 g_source_remove (xtext
->add_io_tag
);
5104 xtext
->add_io_tag
= 0;
5109 g_source_remove (xtext
->io_tag
);
5113 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (xtext
)))
5114 gtk_widget_realize (GTK_WIDGET (xtext
));
5116 gdk_drawable_get_size (GTK_WIDGET (xtext
)->window
, &w
, &h
);
5118 /* after a font change */
5119 if (buf
->needs_recalc
)
5121 buf
->needs_recalc
= FALSE
;
5122 gtk_xtext_recalc_widths (buf
, TRUE
);
5125 /* now change to the new buffer */
5126 xtext
->buffer
= buf
;
5127 dontscroll (buf
); /* force scrolling off */
5128 xtext
->adj
->value
= buf
->old_value
;
5129 xtext
->adj
->upper
= buf
->num_lines
;
5130 if (xtext
->adj
->upper
== 0)
5131 xtext
->adj
->upper
= 1;
5133 else if (xtext
->adj
->value
> xtext
->adj
->upper
- xtext
->adj
->page_size
)
5135 /*buf->pagetop_ent = NULL;*/
5136 xtext
->adj
->value
= xtext
->adj
->upper
- xtext
->adj
->page_size
;
5137 if (xtext
->adj
->value
< 0)
5138 xtext
->adj
->value
= 0;
5143 /* did the window change size since this buffer was last shown? */
5144 if (buf
->window_width
!= w
)
5146 buf
->window_width
= w
;
5147 gtk_xtext_calc_lines (buf
, FALSE
);
5148 if (buf
->scrollbar_down
)
5149 gtk_adjustment_set_value (xtext
->adj
, xtext
->adj
->upper
-
5150 xtext
->adj
->page_size
);
5151 } else if (buf
->window_height
!= h
)
5153 buf
->window_height
= h
;
5154 buf
->pagetop_ent
= NULL
;
5155 gtk_xtext_adjustment_set (buf
, FALSE
);
5158 gtk_xtext_render_page (xtext
);
5159 gtk_adjustment_changed (xtext
->adj
);
5162 /* avoid redoing the transparency */
5163 xtext
->avoid_trans
= TRUE
;
5168 gtk_xtext_buffer_new (GtkXText
*xtext
)
5172 buf
= malloc (sizeof (xtext_buffer
));
5173 memset (buf
, 0, sizeof (xtext_buffer
));
5174 buf
->old_value
= -1;
5176 buf
->scrollbar_down
= TRUE
;
5177 buf
->indent
= xtext
->space_width
* 2;
5184 gtk_xtext_buffer_free (xtext_buffer
*buf
)
5186 textentry
*ent
, *next
;
5188 if (buf
->xtext
->buffer
== buf
)
5189 buf
->xtext
->buffer
= buf
->xtext
->orig_buffer
;
5191 if (buf
->xtext
->selection_buffer
== buf
)
5192 buf
->xtext
->selection_buffer
= NULL
;
5194 ent
= buf
->text_first
;