grim/purple-plugin-pack
* Copyright (C) 1998 Peter Zelezny. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA * ========================================================================= * xtext, the text widget used by X-Chat. * By Peter Zelezny <zed@xchat.org>. #define TINT_VALUE 195 /* 195/255 of the brightness. */ #define MOTION_MONITOR /* URL hilights. */ #define SMOOTH_SCROLL /* line-by-line or pixel scroll? */ #define SCROLL_HACK /* use XCopyArea scroll, or full redraw? */ #undef COLOR_HILIGHT /* Color instead of underline? */ /* Italic is buggy because it assumes drawing an italic string will have identical extents to the normal font. This is only true some of the time, so we can't use this hack yet. */ #undef ITALIC /* support Italic? */ #define GDK_MULTIHEAD_SAFE #define USE_DB /* double buffer */ #define MARGIN 2 /* dont touch. */ #define REFRESH_TIMEOUT 20 #define WORDWRAP_LIMIT 24 #include <gtk/gtksignal.h> #include <gtk/gtkselection.h> #include <gtk/gtkclipboard.h> #include <gtk/gtkversion.h> #include <gtk/gtkwindow.h> #include "../../config.h" /* can define USE_XLIB here */ #define charlen(str) g_utf8_skip[*(guchar *)(str)] #include <gdk/gdkwin32.h> (c == ' ' || c == '\n' || c == ')' || c == '(' || \ c == '>' || c == '<' || c == ATTR_RESET || c == ATTR_BOLD || c == 0) /* force scrolling off */ #define dontscroll(buf) (buf)->last_pixel_pos = 0x7fffffff static GtkWidgetClass *parent_class = NULL; guint16 wrap_offset[RECORD_WRAPS]; unsigned int mb:1; /* is multibyte? */ /* values for selection info */ static guint xtext_signals[LAST_SIGNAL]; int xtext_get_stamp_str (time_t, char **); static void gtk_xtext_render_page (GtkXText * xtext); static void gtk_xtext_calc_lines (xtext_buffer *buf, int); #if defined(USE_XLIB) || defined(WIN32) static void gtk_xtext_load_trans (GtkXText * xtext); static void gtk_xtext_free_trans (GtkXText * xtext); static char *gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret); static textentry *gtk_xtext_nth (GtkXText *xtext, int line, int *subline); static void gtk_xtext_adjustment_changed (GtkAdjustment * adj, static int gtk_xtext_render_ents (GtkXText * xtext, textentry *, textentry *); static void gtk_xtext_recalc_widths (xtext_buffer *buf, int); static void gtk_xtext_fix_indent (xtext_buffer *buf); static int gtk_xtext_find_subline (GtkXText *xtext, textentry *ent, int line); gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf, int *newlen, int *mb_ret); /* gives width of a 8bit string - with no mIRC codes in it */ gtk_xtext_text_width_8bit (GtkXText *xtext, unsigned char *str, int len) width += xtext->fontwidth[*str]; win32_draw_bg (GtkXText *xtext, int x, int y, int width, int height) /* xtext->pixmap is really a GdkImage, created in win32_tint() */ gdk_draw_image (xtext->draw_buf, xtext->bgc, (GdkImage*)xtext->pixmap, x, y, x, y, width, height); hwnd = GDK_WINDOW_HWND (xtext->draw_buf); rgn = CreateRectRgn (x, y, x + width, y + height); SelectClipRgn (hdc, rgn); xtext_draw_bg (GtkXText *xtext, int x, int y, int width, int height) win32_draw_bg (xtext, x, y, width, height); gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1, x, y, width, height); #define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc, \ /* ========================================= */ /* ========== XFT 1 and 2 BACKEND ========== */ /* ========================================= */ backend_font_close (GtkXText *xtext) XftFontClose (GDK_WINDOW_XDISPLAY (xtext->draw_buf), xtext->font); XftFontClose (GDK_WINDOW_XDISPLAY (xtext->draw_buf), xtext->ifont); backend_init (GtkXText *xtext) if (xtext->xftdraw == NULL) xtext->xftdraw = XftDrawCreate ( GDK_WINDOW_XDISPLAY (xtext->draw_buf), GDK_WINDOW_XWINDOW (xtext->draw_buf), GDK_VISUAL_XVISUAL (gdk_drawable_get_visual (xtext->draw_buf)), GDK_COLORMAP_XCOLORMAP (gdk_drawable_get_colormap (xtext->draw_buf))); XftDrawSetSubwindowMode (xtext->xftdraw, IncludeInferiors); backend_deinit (GtkXText *xtext) XftDrawDestroy (xtext->xftdraw); backend_font_open_real (Display *xdisplay, char *name, gboolean italics) PangoFontDescription *fontd; int weight, slant, screen = DefaultScreen (xdisplay); fontd = pango_font_description_from_string (name); if (pango_font_description_get_size (fontd) != 0) weight = pango_font_description_get_weight (fontd); /* from pangoft2-fontmap.c */ if (weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2) weight = XFT_WEIGHT_LIGHT; else if (weight < (PANGO_WEIGHT_NORMAL + 600) / 2) weight = XFT_WEIGHT_MEDIUM; else if (weight < (600 + PANGO_WEIGHT_BOLD) / 2) weight = XFT_WEIGHT_DEMIBOLD; else if (weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2) weight = XFT_WEIGHT_BOLD; weight = XFT_WEIGHT_BLACK; slant = pango_font_description_get_style (fontd); if (slant == PANGO_STYLE_ITALIC) slant = XFT_SLANT_ITALIC; else if (slant == PANGO_STYLE_OBLIQUE) slant = XFT_SLANT_OBLIQUE; font = XftFontOpen (xdisplay, screen, XFT_FAMILY, XftTypeString, pango_font_description_get_family (fontd), XFT_CORE, XftTypeBool, False, XFT_SIZE, XftTypeDouble, (double)pango_font_description_get_size (fontd)/PANGO_SCALE, XFT_WEIGHT, XftTypeInteger, weight, XFT_SLANT, XftTypeInteger, italics ? XFT_SLANT_ITALIC : slant, pango_font_description_free (fontd); font = XftFontOpenName (xdisplay, screen, name); font = XftFontOpenName (xdisplay, screen, "sans-11"); backend_font_open (GtkXText *xtext, char *name) Display *dis = GDK_WINDOW_XDISPLAY (xtext->draw_buf); xtext->font = backend_font_open_real (dis, name, FALSE); xtext->ifont = backend_font_open_real (dis, name, TRUE); backend_get_char_width (GtkXText *xtext, unsigned char *str, int *mbl_ret) return xtext->fontwidth[*str]; *mbl_ret = charlen (str); XftTextExtentsUtf8 (GDK_WINDOW_XDISPLAY (xtext->draw_buf), xtext->font, str, *mbl_ret, &ext); backend_get_text_width (GtkXText *xtext, guchar *str, int len, int is_mb) return gtk_xtext_text_width_8bit (xtext, str, len); XftTextExtentsUtf8 (GDK_WINDOW_XDISPLAY (xtext->draw_buf), xtext->font, str, len, &ext); backend_draw_text (GtkXText *xtext, int dofill, GdkGC *gc, int x, int y, char *str, int len, int str_width, int is_mb) /*Display *xdisplay = GDK_WINDOW_XDISPLAY (xtext->draw_buf);*/ void (*draw_func) (XftDraw *, XftColor *, XftFont *, int, int, XftChar8 *, int) = (void *)XftDrawString8; /* if all ascii, use String8 to avoid the conversion penalty */ draw_func = (void *)XftDrawStringUtf8; /* register GC xgc = GDK_GC_XGC (gc); XSetForeground (xdisplay, xgc, xtext->xft_bg->pixel); XFillRectangle (xdisplay, GDK_WINDOW_XWINDOW (xtext->draw_buf), xgc, x, y - xtext->font->ascent, str_width, xtext->fontsize);*/ XftDrawRect (xtext->xftdraw, xtext->xft_bg, x, y - xtext->font->ascent, str_width, xtext->fontsize); draw_func (xtext->xftdraw, xtext->xft_fg, font, x, y, str, len); draw_func (xtext->xftdraw, xtext->xft_fg, font, x, y, str, len); draw_func (xtext->xftdraw, xtext->xft_fg, font, x + 1, y, str, len); backend_set_clip (GtkXText *xtext, GdkRectangle *area) gdk_gc_set_clip_rectangle (xtext->fgc, area); gdk_gc_set_clip_rectangle (xtext->bgc, area); backend_clear_clip (GtkXText *xtext) gdk_gc_set_clip_rectangle (xtext->fgc, NULL); gdk_gc_set_clip_rectangle (xtext->bgc, NULL); backend_set_clip (GtkXText *xtext, GdkRectangle *area) rect.width = area->width; rect.height = area->height; XUnionRectWithRegion (&rect, reg, reg); XftDrawSetClip (xtext->xftdraw, reg); gdk_gc_set_clip_rectangle (xtext->fgc, area); backend_clear_clip (GtkXText *xtext) XftDrawSetClip (xtext->xftdraw, NULL); gdk_gc_set_clip_rectangle (xtext->fgc, NULL); /* ======================================= */ /* ============ PANGO BACKEND ============ */ /* ======================================= */ backend_font_close (GtkXText *xtext) pango_font_description_free (xtext->font->font); pango_font_description_free (xtext->font->ifont); backend_init (GtkXText *xtext) if (xtext->layout == NULL) xtext->layout = gtk_widget_create_pango_layout (GTK_WIDGET (xtext), 0); pango_layout_set_font_description (xtext->layout, xtext->font->font); backend_deinit (GtkXText *xtext) g_object_unref (xtext->layout); static PangoFontDescription * backend_font_open_real (char *name) PangoFontDescription *font; font = pango_font_description_from_string (name); if (font && pango_font_description_get_size (font) == 0) pango_font_description_free (font); font = pango_font_description_from_string ("sans 11"); font = pango_font_description_from_string ("sans 11"); backend_font_open (GtkXText *xtext, char *name) PangoFontMetrics *metrics; xtext->font = &xtext->pango_font; xtext->font->font = backend_font_open_real (name); xtext->font->ifont = backend_font_open_real (name); pango_font_description_set_style (xtext->font->ifont, PANGO_STYLE_ITALIC); pango_layout_set_font_description (xtext->layout, xtext->font->font); /* vte does it this way */ context = gtk_widget_get_pango_context (GTK_WIDGET (xtext)); lang = pango_context_get_language (context); metrics = pango_context_get_metrics (context, xtext->font->font, lang); xtext->font->ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE; xtext->font->descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE; pango_font_metrics_unref (metrics); backend_get_text_width (GtkXText *xtext, guchar *str, int len, int is_mb) return gtk_xtext_text_width_8bit (xtext, str, len); pango_layout_set_text (xtext->layout, (gchar *)str, len); pango_layout_get_pixel_size (xtext->layout, &width, NULL); backend_get_char_width (GtkXText *xtext, unsigned char *str, int *mbl_ret) return xtext->fontwidth[*str]; *mbl_ret = charlen (str); pango_layout_set_text (xtext->layout, (char *)str, *mbl_ret); pango_layout_get_pixel_size (xtext->layout, &width, NULL); /* simplified version of gdk_draw_layout_line_with_colors() */ xtext_draw_layout_line (GdkDrawable *drawable, GSList *tmp_list = line->runs; PangoRectangle logical_rect; PangoLayoutRun *run = tmp_list->data; pango_glyph_string_extents (run->glyphs, run->item->analysis.font, gdk_draw_glyphs (drawable, gc, run->item->analysis.font, x + x_off / PANGO_SCALE, y, run->glyphs); x_off += logical_rect.width; tmp_list = tmp_list->next; backend_draw_text (GtkXText *xtext, int dofill, GdkGC *gc, int x, int y, char *str, int len, int str_width, int is_mb) pango_layout_set_font_description (xtext->layout, xtext->font->ifont); pango_layout_set_text (xtext->layout, str, len); if (xtext->transparent && !xtext->backcolor) win32_draw_bg (xtext, x, y - xtext->font->ascent, str_width, gdk_gc_get_values (gc, &val); col.pixel = val.background.pixel; gdk_gc_set_foreground (gc, &col); gdk_draw_rectangle (xtext->draw_buf, gc, 1, x, y - xtext->font->ascent, str_width, xtext->fontsize); col.pixel = val.foreground.pixel; gdk_gc_set_foreground (gc, &col); line = pango_layout_get_lines (xtext->layout)->data; xtext_draw_layout_line (xtext->draw_buf, gc, x, y, line); xtext_draw_layout_line (xtext->draw_buf, gc, x, y, line); xtext_draw_layout_line (xtext->draw_buf, gc, x + 1, y, line); pango_layout_set_font_description (xtext->layout, xtext->font->font); backend_set_clip (GtkXText *xtext, GdkRectangle *area) gdk_gc_set_clip_rectangle (xtext->fgc, area); gdk_gc_set_clip_rectangle (xtext->bgc, area); backend_clear_clip (GtkXText *xtext) gdk_gc_set_clip_rectangle (xtext->fgc, NULL); gdk_gc_set_clip_rectangle (xtext->bgc, NULL); xtext_set_fg (GtkXText *xtext, GdkGC *gc, int index) col.pixel = xtext->palette[index]; gdk_gc_set_foreground (gc, &col); xtext->xft_fg = &xtext->color[index]; xtext->xft_bg = &xtext->color[index]; void gtk_xtext_set_foreground_color (GtkXText *xtext, GdkColor *color) xtext->palette[XTEXT_FG] = color->pixel; void gtk_xtext_set_background_color (GtkXText *xtext, GdkColor *color) xtext->palette[XTEXT_BG] = color->pixel; #define xtext_set_bg(xt,gc,index) xt->xft_bg = &xt->color[index] xtext_set_bg (GtkXText *xtext, GdkGC *gc, int index) col.pixel = xtext->palette[index]; gdk_gc_set_background (gc, &col); gtk_xtext_init (GtkXText * xtext) xtext->col_back = XTEXT_BG; xtext->col_fore = XTEXT_FG; xtext->underline = FALSE; xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; xtext->clip_x2 = 1000000; xtext->clip_y2 = 1000000; xtext->error_function = NULL; xtext->urlcheck_function = NULL; xtext->color_paste = FALSE; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->render_hilights_only = FALSE; xtext->un_hilight = FALSE; xtext->dont_render = FALSE; xtext->dont_render2 = FALSE; xtext->tint_red = xtext->tint_green = xtext->tint_blue = TINT_VALUE; xtext->adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 1, 1, 1, 1); g_object_ref (G_OBJECT (xtext->adj)); gtk_object_sink ((GtkObject *) xtext->adj); xtext->vc_signal_tag = g_signal_connect (G_OBJECT (xtext->adj), "value_changed", G_CALLBACK (gtk_xtext_adjustment_changed), xtext); static const GtkTargetEntry targets[] = { { "UTF8_STRING", 0, TARGET_UTF8_STRING }, { "STRING", 0, TARGET_STRING }, { "TEXT", 0, TARGET_TEXT }, { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } static const gint n_targets = sizeof (targets) / sizeof (targets[0]); gtk_selection_add_targets (GTK_WIDGET (xtext), GDK_SELECTION_PRIMARY, if (getenv ("XCHAT_OVERDRAW")) gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal) GtkAdjustment *adj = buf->xtext->adj; if (buf->xtext->buffer == buf) adj->upper = buf->num_lines; (GTK_WIDGET (buf->xtext)->allocation.height - buf->xtext->font->descent) / buf->xtext->fontsize; adj->page_increment = adj->page_size; if (adj->value > adj->upper - adj->page_size) adj->value = adj->upper - adj->page_size; gtk_adjustment_changed (adj); gtk_xtext_adjustment_timeout (GtkXText * xtext) gtk_xtext_render_page (xtext); gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext) if (xtext->buffer->old_value != xtext->adj->value) if ((int) xtext->buffer->old_value != (int) xtext->adj->value) if (xtext->adj->value >= xtext->adj->upper - xtext->adj->page_size) xtext->buffer->scrollbar_down = TRUE; xtext->buffer->scrollbar_down = FALSE; if (xtext->adj->value + 1 == xtext->buffer->old_value || xtext->adj->value - 1 == xtext->buffer->old_value) /* clicked an arrow? */ g_source_remove (xtext->io_tag); gtk_xtext_render_page (xtext); xtext->io_tag = g_timeout_add (REFRESH_TIMEOUT, gtk_xtext_adjustment_timeout, xtext->buffer->old_value = adj->value; gtk_xtext_new (GdkColor palette[], int separator) xtext = g_object_new (gtk_xtext_get_type (), NULL); xtext->separator = separator; xtext->buffer = gtk_xtext_buffer_new (xtext); xtext->orig_buffer = xtext->buffer; gtk_widget_set_double_buffered (GTK_WIDGET (xtext), FALSE); gtk_xtext_set_palette (xtext, palette); return GTK_WIDGET (xtext); gtk_xtext_destroy (GtkObject * object) GtkXText *xtext = GTK_XTEXT (object); g_source_remove (xtext->add_io_tag); g_source_remove (xtext->scroll_tag); g_source_remove (xtext->io_tag); #if defined(USE_XLIB) || defined(WIN32) gtk_xtext_free_trans (xtext); g_object_unref (xtext->pixmap); backend_font_close (xtext); g_signal_handlers_disconnect_matched (G_OBJECT (xtext->adj), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, xtext); /* gtk_signal_disconnect_by_data (GTK_OBJECT (xtext->adj), xtext);*/ g_object_unref (G_OBJECT (xtext->adj)); g_object_unref (xtext->bgc); g_object_unref (xtext->fgc); g_object_unref (xtext->light_gc); g_object_unref (xtext->dark_gc); g_object_unref (xtext->thin_gc); g_object_unref (xtext->marker_gc); gdk_cursor_unref (xtext->hand_cursor); xtext->hand_cursor = NULL; if (xtext->resize_cursor) gdk_cursor_unref (xtext->resize_cursor); xtext->resize_cursor = NULL; gtk_xtext_buffer_free (xtext->orig_buffer); xtext->orig_buffer = NULL; if (GTK_OBJECT_CLASS (parent_class)->destroy) (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); gtk_xtext_unrealize (GtkWidget * widget) backend_deinit (GTK_XTEXT (widget)); /* if there are still events in the queue, this'll avoid segfault */ gdk_window_set_user_data (widget->window, NULL); if (parent_class->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); gtk_xtext_realize (GtkWidget * widget) GdkWindowAttr attributes; GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); xtext = GTK_XTEXT (widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK; | GDK_POINTER_MOTION_MASK; cmap = gtk_widget_get_colormap (widget); attributes.colormap = cmap; attributes.visual = gtk_widget_get_visual (widget); widget->window = gdk_window_new (widget->parent->window, &attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | gdk_window_set_user_data (widget->window, widget); xtext->depth = gdk_drawable_get_visual (widget->window)->depth; val.subwindow_mode = GDK_INCLUDE_INFERIORS; val.graphics_exposures = 0; xtext->bgc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->fgc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->light_gc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->dark_gc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->thin_gc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext->marker_gc = gdk_gc_new_with_values (widget->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); /* for the separator bar (light) */ col.red = 0xffff; col.green = 0xffff; col.blue = 0xffff; gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE); gdk_gc_set_foreground (xtext->light_gc, &col); /* for the separator bar (dark) */ col.red = 0x1111; col.green = 0x1111; col.blue = 0x1111; gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE); gdk_gc_set_foreground (xtext->dark_gc, &col); /* for the separator bar (thinline) */ col.red = 0x8e38; col.green = 0x8e38; col.blue = 0x9f38; gdk_colormap_alloc_color (cmap, &col, FALSE, TRUE); gdk_gc_set_foreground (xtext->thin_gc, &col); /* for the marker bar (marker) */ col.pixel = xtext->palette[XTEXT_MARKER]; gdk_gc_set_foreground (xtext->marker_gc, &col); xtext_set_fg (xtext, xtext->fgc, XTEXT_FG); xtext_set_bg (xtext, xtext->fgc, XTEXT_BG); xtext_set_fg (xtext, xtext->bgc, XTEXT_BG); /* draw directly to window */ xtext->draw_buf = widget->window; #if defined(USE_XLIB) || defined(WIN32) gtk_xtext_load_trans (xtext); gdk_gc_set_tile (xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin (xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; gdk_gc_set_fill (xtext->bgc, GDK_TILED); #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) xtext->hand_cursor = gdk_cursor_new (GDK_HAND1); xtext->resize_cursor = gdk_cursor_new (GDK_LEFT_SIDE); xtext->hand_cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (widget->window), GDK_HAND1); xtext->resize_cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (widget->window), GDK_LEFT_SIDE); gdk_window_set_back_pixmap (widget->window, NULL, FALSE); widget->style = gtk_style_attach (widget->style, widget->window); gtk_xtext_size_request (GtkWidget * widget, GtkRequisition * requisition) requisition->width = 200; requisition->height = 90; gtk_xtext_size_allocate (GtkWidget * widget, GtkAllocation * allocation) GtkXText *xtext = GTK_XTEXT (widget); if (allocation->width == xtext->buffer->window_width) if (allocation->x == widget->allocation.x && allocation->y == widget->allocation.y && xtext->avoid_trans) xtext->avoid_trans = FALSE; widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) xtext->buffer->window_width = allocation->width; xtext->buffer->window_height = allocation->height; gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); dontscroll (xtext->buffer); /* force scrolling off */ gtk_xtext_calc_lines (xtext->buffer, FALSE); xtext->buffer->pagetop_ent = NULL; gtk_xtext_adjustment_set (xtext->buffer, FALSE); #if defined(USE_XLIB) || defined(WIN32) if (do_trans && xtext->transparent && xtext->shaded) gtk_xtext_free_trans (xtext); gtk_xtext_load_trans (xtext); if (xtext->buffer->scrollbar_down) gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - gtk_xtext_selection_clear_full (xtext_buffer *buf) textentry *ent = buf->text_first; gtk_xtext_selection_clear (xtext_buffer *buf) ent = buf->last_ent_start; if (ent->mark_start != -1) if (ent == buf->last_ent_end) find_x (GtkXText *xtext, textentry *ent, unsigned char *text, int x, int indent) unsigned char *orig = text; if ((col && isdigit (*text) && nc < 2) || (col && *text == ',' && isdigit (*(text+1)) && nc < 3)) xx += backend_get_char_width (xtext, text, &mbl); return i + (orig - ent->str); if (text - orig >= ent->str_len) gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline, int line, int *out_of_bounds) indent = xtext->buffer->indent; if (line > xtext->adj->page_size || line < 0) if (xtext->buffer->grid_dirty || line > 255) str = ent->str + gtk_xtext_find_subline (xtext, ent, subline); if (str >= ent->str + ent->str_len) if (xtext->buffer->grid_offset[line] > ent->str_len) str = ent->str + xtext->buffer->grid_offset[line]; return find_x (xtext, ent, str, x, indent); gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, line = (y + xtext->pixel_offset) / xtext->fontsize; ent = gtk_xtext_nth (xtext, line + (int)xtext->adj->value, &subline); *off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds); gtk_xtext_draw_sep (GtkXText * xtext, int y) height = GTK_WIDGET (xtext)->allocation.height; height = xtext->fontsize; /* draw the separator line */ if (xtext->separator && xtext->buffer->indent) x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (xtext->moving_separator) gdk_draw_line (xtext->draw_buf, light, x, y, x, y + height); gdk_draw_line (xtext->draw_buf, xtext->thin_gc, x, y, x, y + height); if (xtext->moving_separator) gdk_draw_line (xtext->draw_buf, light, x - 1, y, x - 1, y + height); gdk_draw_line (xtext->draw_buf, dark, x, y, x, y + height); gdk_draw_line (xtext->draw_buf, dark, x - 1, y, x - 1, y + height); gdk_draw_line (xtext->draw_buf, light, x, y, x, y + height); gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y) if (!xtext->marker) return; if (xtext->buffer->marker_pos == ent) render_y = y + xtext->font->descent; else if (xtext->buffer->marker_pos == ent->next && ent->next != NULL) render_y = y + xtext->font->descent + xtext->fontsize * ent->lines_taken; width = GTK_WIDGET (xtext)->allocation.width; gdk_draw_line (xtext->draw_buf, xtext->marker_gc, x, render_y, x + width, render_y); #if GTK_CHECK_VERSION(2,4,0) if (gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (xtext))))) if (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (xtext)))->has_focus) xtext->buffer->marker_seen = TRUE; gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) GtkXText *xtext = GTK_XTEXT (widget); textentry *ent_start, *ent_end; #if defined(USE_XLIB) || defined(WIN32) gdk_window_get_origin (widget->window, &x, &y); /* update transparency only if it moved */ if (xtext->last_win_x != x || xtext->last_win_y != y) #if !defined(USE_SHM) && !defined(WIN32) gtk_xtext_load_trans (xtext); gtk_xtext_free_trans (xtext); gtk_xtext_load_trans (xtext); if (area->x == 0 && area->y == 0 && area->height == widget->allocation.height && area->width == widget->allocation.width) dontscroll (xtext->buffer); /* force scrolling off */ gtk_xtext_render_page (xtext); ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL); xtext_draw_bg (xtext, area->x, area->y, area->width, area->height); ent_end = gtk_xtext_find_char (xtext, area->x + area->width, area->y + area->height, NULL, NULL); ent_end = xtext->buffer->text_last; /* can't set a clip here, because fgc/bgc are used to draw the DB too */ /* backend_set_clip (xtext, area);*/ xtext->clip_x2 = area->x + area->width; xtext->clip_y2 = area->y + area->height; /* y is the last pixel y location it rendered text at */ y = gtk_xtext_render_ents (xtext, ent_start, ent_end); if (y && y < widget->allocation.height && !ent_end->next) rect.width = widget->allocation.width; rect.height = widget->allocation.height - y; /* fill any space below the last line that also intersects with the exposure rectangle */ if (gdk_rectangle_intersect (area, &rect, &rect)) xtext_draw_bg (xtext, rect.x, rect.y, rect.width, rect.height); /*backend_clear_clip (xtext);*/ xtext->clip_x2 = 1000000; xtext->clip_y2 = 1000000; x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); gtk_xtext_draw_sep (xtext, -1); gtk_xtext_expose (GtkWidget * widget, GdkEventExpose * event) gtk_xtext_paint (widget, &event->area); /* render a selection that has extended or contracted upward */ gtk_xtext_selection_up (GtkXText *xtext, textentry *start, textentry *end, /* render all the complete lines */ gtk_xtext_render_ents (xtext, end, NULL); gtk_xtext_render_ents (xtext, start->next, end); /* now the incomplete upper line */ if (start == xtext->buffer->last_ent_start) xtext->jump_in_offset = xtext->buffer->last_offset_start; xtext->jump_in_offset = start_offset; gtk_xtext_render_ents (xtext, start, NULL); xtext->jump_in_offset = 0; /* render a selection that has extended or contracted downward */ gtk_xtext_selection_down (GtkXText *xtext, textentry *start, textentry *end, /* render all the complete lines */ gtk_xtext_render_ents (xtext, start, NULL); gtk_xtext_render_ents (xtext, start, end->prev); /* now the incomplete bottom line */ if (end == xtext->buffer->last_ent_end) xtext->jump_out_offset = xtext->buffer->last_offset_end; xtext->jump_out_offset = end_offset; gtk_xtext_render_ents (xtext, end, NULL); xtext->jump_out_offset = 0; gtk_xtext_selection_render (GtkXText *xtext, textentry *start_ent, int start_offset, textentry *end_ent, int end_offset) xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; /* force an optimized render if there was no previous selection */ if (xtext->buffer->last_ent_start == NULL && start_ent == end_ent) xtext->buffer->last_offset_start = start_offset; xtext->buffer->last_offset_end = end_offset; /* mark changed within 1 ent only? */ if (xtext->buffer->last_ent_start == start_ent && xtext->buffer->last_ent_end == end_ent) /* when only 1 end of the selection is changed, we can really if (xtext->buffer->last_offset_start == start_offset || xtext->buffer->last_offset_end == end_offset) /* figure out where to start and end the rendering */ if (end_offset > xtext->buffer->last_offset_end) start = xtext->buffer->last_offset_end; } else if (end_offset < xtext->buffer->last_offset_end) end = xtext->buffer->last_offset_end; } else if (start_offset < xtext->buffer->last_offset_start) end = xtext->buffer->last_offset_start; } else if (start_offset > xtext->buffer->last_offset_start) start = xtext->buffer->last_offset_start; { /* WORD selects end up here */ /* LINE selects end up here */ /* so which ent actually changed? */ if (xtext->buffer->last_offset_start == start_offset) end = MAX (xtext->buffer->last_offset_end, end_offset); start = MIN (xtext->buffer->last_offset_start, start_offset); xtext->jump_out_offset = end; xtext->jump_in_offset = start; gtk_xtext_render_ents (xtext, ent, NULL); xtext->jump_out_offset = 0; xtext->jump_in_offset = 0; else if (xtext->buffer->last_ent_start == start_ent && xtext->buffer->last_offset_start == start_offset) /* find the range that covers both old and new selection */ if (ent == xtext->buffer->last_ent_end) gtk_xtext_selection_down (xtext, ent, end_ent, end_offset); /*gtk_xtext_render_ents (xtext, ent, end_ent);*/ gtk_xtext_selection_down (xtext, ent, xtext->buffer->last_ent_end, end_offset); /*gtk_xtext_render_ents (xtext, ent, xtext->buffer->last_ent_end);*/ else if (xtext->buffer->last_ent_end == end_ent && xtext->buffer->last_offset_end == end_offset) gtk_xtext_selection_up (xtext, xtext->buffer->last_ent_start, ent, start_offset); /*gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, ent);*/ if (ent == xtext->buffer->last_ent_start) gtk_xtext_selection_up (xtext, start_ent, ent, start_offset); /*gtk_xtext_render_ents (xtext, start_ent, ent);*/ else /* cross-over mark (stretched or shrunk at both ends) */ /* unrender the old mark */ gtk_xtext_render_ents (xtext, xtext->buffer->last_ent_start, xtext->buffer->last_ent_end); /* now render the new mark, but skip overlaps */ if (start_ent == xtext->buffer->last_ent_start) /* if the new mark is a sub-set of the old, do nothing */ if (start_ent != end_ent) gtk_xtext_render_ents (xtext, start_ent->next, end_ent); } else if (end_ent == xtext->buffer->last_ent_end) /* if the new mark is a sub-set of the old, do nothing */ if (start_ent != end_ent) gtk_xtext_render_ents (xtext, start_ent, end_ent->prev); gtk_xtext_render_ents (xtext, start_ent, end_ent); xtext->buffer->last_ent_start = start_ent; xtext->buffer->last_ent_end = end_ent; xtext->buffer->last_offset_start = start_offset; xtext->buffer->last_offset_end = end_offset; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event) if (xtext->select_start_y > xtext->select_end_y) low_x = xtext->select_end_x; low_y = xtext->select_end_y; high_x = xtext->select_start_x; high_y = xtext->select_start_y; low_x = xtext->select_start_x; low_y = xtext->select_start_y; high_x = xtext->select_end_x; high_y = xtext->select_end_y; ent_start = gtk_xtext_find_char (xtext, low_x, low_y, &offset_start, &tmp); if (xtext->adj->value != xtext->buffer->old_value) gtk_xtext_render_page (xtext); ent_end = gtk_xtext_find_char (xtext, high_x, high_y, &offset_end, &tmp); ent_end = xtext->buffer->text_last; if (xtext->adj->value != xtext->buffer->old_value) gtk_xtext_render_page (xtext); offset_end = ent_end->str_len; /* marking less than a complete line? */ /* make sure "start" is smaller than "end" (swap them if need be) */ if (ent_start == ent_end && offset_start > offset_end) offset_start = offset_end; /* has the selection changed? Dont render unless necessary */ if (xtext->buffer->last_ent_start == ent_start && xtext->buffer->last_ent_end == ent_end && xtext->buffer->last_offset_start == offset_start && xtext->buffer->last_offset_end == offset_end) /* set all the old mark_ fields to -1 */ gtk_xtext_selection_clear (xtext->buffer); ent_start->mark_start = offset_start; ent_start->mark_end = offset_end; if (ent_start != ent_end) ent_start->mark_end = ent_start->str_len; ent_end->mark_end = offset_end; /* set all the mark_ fields of the ents within the selection */ while (ent && ent != ent_end) ent->mark_end = ent->str_len; gtk_xtext_selection_render (xtext, ent_start, offset_start, ent_end, offset_end); gtk_xtext_scrolldown_timeout (GtkXText * xtext) gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); gdk_drawable_get_size (GTK_WIDGET (xtext)->window, 0, &win_height); xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) gtk_adjustment_changed (xtext->adj); gtk_xtext_render_page (xtext); gtk_xtext_scrollup_timeout (GtkXText * xtext) gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); if (p_y < 0 && xtext->adj->value > 0.0) gtk_adjustment_changed (xtext->adj); gtk_xtext_render_page (xtext); gtk_xtext_selection_update (GtkXText * xtext, GdkEventMotion * event, int p_y) gdk_drawable_get_size (GTK_WIDGET (xtext)->window, 0, &win_height); /* selecting past top of window, scroll up! */ if (p_y < 0 && xtext->adj->value >= 0) xtext->scroll_tag = g_timeout_add (100, gtk_xtext_scrollup_timeout, /* selecting past bottom of window, scroll down! */ xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) xtext->scroll_tag = g_timeout_add (100, gtk_xtext_scrolldown_timeout, moved = (int)xtext->adj->value - xtext->select_start_adj; xtext->select_start_y -= (moved * xtext->fontsize); xtext->select_start_adj = xtext->adj->value; gtk_xtext_selection_draw (xtext, event); gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len) ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds); if (offset == ent->str_len) /*offset--;*/ /* FIXME: not all chars are 1 byte */ while (!is_del (*str) && str != ent->str) while (!is_del (*str) && len != ent->str_len) if (len > 0 && word[len-1]=='.') *ret_off = word - ent->str; return gtk_xtext_strip_color (word, len, xtext->scratch_buffer, NULL, NULL); gtk_xtext_unrender_hilight (GtkXText *xtext) xtext->render_hilights_only = TRUE; xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; xtext->un_hilight = TRUE; gtk_xtext_render_ents (xtext, xtext->hilight_ent, NULL); xtext->render_hilights_only = FALSE; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->un_hilight = FALSE; gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event) GtkXText *xtext = GTK_XTEXT (widget); gtk_xtext_unrender_hilight (xtext); xtext->hilight_start = -1; xtext->cursor_hand = FALSE; gdk_window_set_cursor (widget->window, 0); xtext->hilight_ent = NULL; if (xtext->cursor_resize) gtk_xtext_unrender_hilight (xtext); xtext->hilight_start = -1; xtext->cursor_resize = FALSE; gdk_window_set_cursor (widget->window, 0); xtext->hilight_ent = NULL; gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event) GtkXText *xtext = GTK_XTEXT (widget); int tmp, x, y, offset, len, line_x; gdk_window_get_pointer (widget->window, &x, &y, 0); if (xtext->moving_separator) if (x < (3 * widget->allocation.width) / 5 && x > 15) tmp = xtext->buffer->indent; xtext->buffer->indent = x; gtk_xtext_fix_indent (xtext->buffer); if (tmp != xtext->buffer->indent) gtk_xtext_recalc_widths (xtext->buffer, FALSE); if (xtext->buffer->scrollbar_down) gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - xtext->io_tag = g_timeout_add (REFRESH_TIMEOUT, gtk_xtext_adjustment_timeout, /*gdk_pointer_grab (widget->window, TRUE, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, NULL, NULL, 0);*/ gtk_xtext_selection_update (xtext, event, y); xtext->hilighting = TRUE; if (xtext->separator && xtext->buffer->indent) line_x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (line_x == x || line_x == x + 1 || line_x == x - 1) if (!xtext->cursor_resize) gdk_window_set_cursor (GTK_WIDGET (xtext)->window, xtext->cursor_resize = TRUE; if (xtext->urlcheck_function == NULL) word = gtk_xtext_get_word (xtext, x, y, &word_ent, &offset, &len); if (xtext->urlcheck_function (GTK_WIDGET (xtext), word, len) > 0) if (!xtext->cursor_hand || xtext->hilight_ent != word_ent || xtext->hilight_start != offset || xtext->hilight_end != offset + len) gdk_window_set_cursor (GTK_WIDGET (xtext)->window, xtext->cursor_hand = TRUE; /* un-render the old hilight */ gtk_xtext_unrender_hilight (xtext); xtext->hilight_ent = word_ent; xtext->hilight_start = offset; xtext->hilight_end = offset + len; xtext->skip_border_fills = TRUE; xtext->render_hilights_only = TRUE; xtext->skip_stamp = TRUE; gtk_xtext_render_ents (xtext, word_ent, NULL); xtext->skip_border_fills = FALSE; xtext->render_hilights_only = FALSE; xtext->skip_stamp = FALSE; gtk_xtext_leave_notify (widget, NULL); gtk_xtext_set_clip_owner (GtkWidget * xtext, GdkEventButton * event) if (GTK_XTEXT (xtext)->selection_buffer && GTK_XTEXT (xtext)->selection_buffer != GTK_XTEXT (xtext)->buffer) gtk_xtext_selection_clear (GTK_XTEXT (xtext)->selection_buffer); GTK_XTEXT (xtext)->selection_buffer = GTK_XTEXT (xtext)->buffer; str = gtk_xtext_selection_get_text (GTK_XTEXT (xtext), &len); #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), gtk_clipboard_set_text (gtk_widget_get_clipboard (xtext, GDK_SELECTION_CLIPBOARD), gtk_selection_owner_set (xtext, GDK_SELECTION_PRIMARY, event->time); gtk_xtext_unselect (GtkXText *xtext) xtext_buffer *buf = xtext->buffer; xtext->skip_border_fills = TRUE; xtext->skip_stamp = TRUE; xtext->jump_in_offset = buf->last_ent_start->mark_start; /* just a single ent was marked? */ if (buf->last_ent_start == buf->last_ent_end) xtext->jump_out_offset = buf->last_ent_start->mark_end; buf->last_ent_end = NULL; gtk_xtext_selection_clear (xtext->buffer); /* FIXME: use jump_out on multi-line selects too! */ gtk_xtext_render_ents (xtext, buf->last_ent_start, buf->last_ent_end); xtext->jump_in_offset = 0; xtext->jump_out_offset = 0; xtext->skip_border_fills = FALSE; xtext->skip_stamp = FALSE; xtext->buffer->last_ent_start = NULL; xtext->buffer->last_ent_end = NULL; gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event) GtkXText *xtext = GTK_XTEXT (widget); if (xtext->moving_separator) xtext->moving_separator = FALSE; old = xtext->buffer->indent; if (event->x < (4 * widget->allocation.width) / 5 && event->x > 15) xtext->buffer->indent = event->x; gtk_xtext_fix_indent (xtext->buffer); if (xtext->buffer->indent != old) gtk_xtext_recalc_widths (xtext->buffer, FALSE); gtk_xtext_adjustment_set (xtext->buffer, TRUE); gtk_xtext_render_page (xtext); gtk_xtext_draw_sep (xtext, -1); if (xtext->word_or_line_select) xtext->word_or_line_select = FALSE; xtext->button_down = FALSE; xtext->button_down = FALSE; gtk_grab_remove (widget); /*gdk_pointer_ungrab (0);*/ if (xtext->buffer->last_ent_start) gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event); if (xtext->select_start_x == event->x && xtext->select_start_y == event->y && xtext->buffer->last_ent_start) gtk_xtext_unselect (xtext); word = gtk_xtext_get_word (xtext, event->x, event->y, 0, 0, 0); g_signal_emit (G_OBJECT (xtext), xtext_signals[WORD_CLICK], 0, word ? word : NULL, event); xtext->hilighting = FALSE; gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event) GtkXText *xtext = GTK_XTEXT (widget); int line_x, x, y, offset, len; gdk_window_get_pointer (widget->window, &x, &y, 0); if (event->button == 3 || event->button == 2) /* right/middle click */ word = gtk_xtext_get_word (xtext, x, y, 0, 0, 0); g_signal_emit (G_OBJECT (xtext), xtext_signals[WORD_CLICK], 0, g_signal_emit (G_OBJECT (xtext), xtext_signals[WORD_CLICK], 0, if (event->button != 1) /* we only want left button */ if (event->type == GDK_2BUTTON_PRESS) /* WORD select */ if (gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len)) gtk_xtext_selection_clear (xtext->buffer); ent->mark_start = offset; ent->mark_end = offset + len; gtk_xtext_selection_render (xtext, ent, offset, ent, offset + len); xtext->word_or_line_select = TRUE; gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event); if (event->type == GDK_3BUTTON_PRESS) /* LINE select */ if (gtk_xtext_get_word (xtext, x, y, &ent, 0, 0)) gtk_xtext_selection_clear (xtext->buffer); ent->mark_end = ent->str_len; gtk_xtext_selection_render (xtext, ent, 0, ent, ent->str_len); xtext->word_or_line_select = TRUE; gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event); /* check if it was a separator-bar click */ if (xtext->separator && xtext->buffer->indent) line_x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (line_x == x || line_x == x + 1 || line_x == x - 1) xtext->moving_separator = TRUE; /* draw the separator line */ gtk_xtext_draw_sep (xtext, -1); xtext->button_down = TRUE; xtext->select_start_x = x; xtext->select_start_y = y; xtext->select_start_adj = xtext->adj->value; /* another program has claimed the selection */ gtk_xtext_selection_kill (GtkXText *xtext, GdkEventSelection *event) if (xtext->buffer->last_ent_start) gtk_xtext_unselect (xtext); gtk_xtext_selection_get_text (GtkXText *xtext, int *len_ret) buf = xtext->selection_buffer; /* first find out how much we need to malloc ... */ ent = buf->last_ent_start; if (ent->mark_start != -1) if (ent->mark_end - ent->mark_start > 0) len += (ent->mark_end - ent->mark_start) + 1; if (ent == buf->last_ent_end) /* now allocate mem and copy buffer */ pos = txt = malloc (len); ent = buf->last_ent_start; if (ent->mark_start != -1) if (ent->mark_end - ent->mark_start > 0) memcpy (pos, ent->str + ent->mark_start, ent->mark_end - ent->mark_start); pos += ent->mark_end - ent->mark_start; if (ent == buf->last_ent_end) stripped = gtk_xtext_strip_color ((unsigned char *)txt, strlen (txt), NULL, &len, 0); /* another program is asking for our selection */ gtk_xtext_selection_get (GtkWidget * widget, GtkSelectionData * selection_data_ptr, GtkXText *xtext = GTK_XTEXT (widget); stripped = gtk_xtext_selection_get_text (xtext, &len); /* it's already in utf8 */ gtk_selection_data_set_text (selection_data_ptr, stripped, len); case TARGET_COMPOUND_TEXT: #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) gdk_string_to_compound_text ( gdk_string_to_compound_text_for_display ( gdk_drawable_get_display (widget->window), stripped, &encoding, &format, &new_text, gtk_selection_data_set (selection_data_ptr, encoding, format, gdk_free_compound_text (new_text); new_text =(guchar *) g_locale_from_utf8 (stripped, len, NULL, &glen, NULL); gtk_selection_data_set (selection_data_ptr, GDK_SELECTION_TYPE_STRING, gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event) GtkXText *xtext = GTK_XTEXT (widget); if (event->direction == GDK_SCROLL_UP) /* mouse wheel pageUp */ new_value = xtext->adj->value - (xtext->adj->page_increment / 10); if (new_value < xtext->adj->lower) new_value = xtext->adj->lower; gtk_adjustment_set_value (xtext->adj, new_value); else if (event->direction == GDK_SCROLL_DOWN) /* mouse wheel pageDn */ new_value = xtext->adj->value + (xtext->adj->page_increment / 10); if (new_value > (xtext->adj->upper - xtext->adj->page_size)) new_value = xtext->adj->upper - xtext->adj->page_size; gtk_adjustment_set_value (xtext->adj, new_value); gtk_xtext_class_init (GtkXTextClass * class) GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkXTextClass *xtext_class; object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; xtext_class = (GtkXTextClass *) class; parent_class = gtk_type_class (gtk_widget_get_type ()); xtext_signals[WORD_CLICK] = g_signal_new ("word_click", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GtkXTextClass, word_click), gtk_marshal_VOID__POINTER_POINTER, 2, G_TYPE_POINTER, G_TYPE_POINTER); object_class->destroy = gtk_xtext_destroy; widget_class->realize = gtk_xtext_realize; widget_class->unrealize = gtk_xtext_unrealize; widget_class->size_request = gtk_xtext_size_request; widget_class->size_allocate = gtk_xtext_size_allocate; widget_class->button_press_event = gtk_xtext_button_press; widget_class->button_release_event = gtk_xtext_button_release; widget_class->motion_notify_event = gtk_xtext_motion_notify; widget_class->selection_clear_event = (void *)gtk_xtext_selection_kill; widget_class->selection_get = gtk_xtext_selection_get; widget_class->expose_event = gtk_xtext_expose; widget_class->scroll_event = gtk_xtext_scroll; widget_class->leave_notify_event = gtk_xtext_leave_notify; xtext_class->word_click = NULL; gtk_xtext_get_type (void) static GtkType xtext_type = 0; static const GTypeInfo xtext_info = NULL, /* base_finalize */ (GClassInitFunc) gtk_xtext_class_init, NULL, /* class_finalize */ (GInstanceInitFunc) gtk_xtext_init, xtext_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkXText", /* strip MIRC colors and other attribs. */ gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf, int *newlen, int *mb_ret) new_str = malloc (len + 2); if ((col && isdigit (*text) && nc < 2) || (col && *text == ',' && isdigit (*(text+1)) && nc < 3)) /* gives width of a string, excluding the mIRC codes */ gtk_xtext_text_width (GtkXText *xtext, unsigned char *text, int len, new_buf = (unsigned char *)gtk_xtext_strip_color (text, len, xtext->scratch_buffer, return backend_get_text_width (xtext, new_buf, new_len, mb); /* actually draw text to screen (one run with the same color/attribs) */ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str, int len, GdkGC *gc, int is_mb) int dest_x = 0, dest_y = 0; if (xtext->dont_render || len < 1) str_width = backend_get_text_width (xtext, str, len, is_mb); /* roll-your-own clipping (avoiding XftDrawString is always good!) */ if (x > xtext->clip_x2 || x + str_width < xtext->clip_x) if (y - xtext->font->ascent > xtext->clip_y2 || (y - xtext->font->ascent) + xtext->fontsize < xtext->clip_y) if (xtext->render_hilights_only) if (!xtext->in_hilight) /* is it a hilight prefix? */ if (!xtext->un_hilight) /* doing a hilight? no need to draw the text */ pix = gdk_pixmap_new (xtext->draw_buf, str_width, xtext->fontsize, xtext->depth); XftDrawChange (xtext->xftdraw, GDK_WINDOW_XWINDOW (pix)); dest_y = y - xtext->font->ascent; gdk_gc_set_ts_origin (xtext->bgc, xtext->ts_x - x, xtext->ts_y - dest_y); /* backcolor is always handled by XDrawImageString */ if (!xtext->backcolor && xtext->pixmap) /* draw the background pixmap behind the text - CAUSES FLICKER HERE!! */ xtext_draw_bg (xtext, x, y - xtext->font->ascent, str_width, dofill = FALSE; /* already drawn the background */ backend_draw_text (xtext, dofill, gc, x, y, (char *)str, len, str_width, is_mb); gdk_gc_set_ts_origin (xtext->bgc, xtext->ts_x, xtext->ts_y); xtext->draw_buf = GTK_WIDGET (xtext)->window; XftDrawChange (xtext->xftdraw, GDK_WINDOW_XWINDOW (xtext->draw_buf)); gdk_draw_drawable (xtext->draw_buf, xtext->bgc, pix, 0, 0, dest_x, dest_y, str_width, xtext->fontsize); clip.width = xtext->clip_x2 - xtext->clip_x; clip.height = xtext->clip_y2 - xtext->clip_y; dest.height = xtext->fontsize; if (gdk_rectangle_intersect (&clip, &dest, &dest)) /* dump the DB to window, but only within the clip_x/x2/y/y2 */ gdk_draw_drawable (xtext->draw_buf, xtext->bgc, pix, dest.x - dest_x, dest.y - dest_y, dest.x, dest.y, dest.width, dest.height); col.pixel = xtext->xft_fg->pixel; gdk_gc_set_foreground (gc, &col); y = dest_y + xtext->font->ascent + 1; /* draw directly to window, it's out of the range of our DB */ gdk_draw_line (xtext->draw_buf, gc, dest_x, y, dest_x + str_width - 1, y); gtk_xtext_reset (GtkXText * xtext, int mark, int attribs) xtext->underline = FALSE; xtext->backcolor = FALSE; if (xtext->col_fore != XTEXT_FG) xtext_set_fg (xtext, xtext->fgc, XTEXT_FG); if (xtext->col_back != XTEXT_BG) xtext_set_bg (xtext, xtext->fgc, XTEXT_BG); xtext->col_fore = XTEXT_FG; xtext->col_back = XTEXT_BG; xtext->parsing_color = FALSE; xtext->parsing_backcolor = FALSE; /* render a single line, which WONT wrap, and parse mIRC colors */ gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent, unsigned char *str, int len, int win_width, int indent, int i = 0, x = indent, j = 0; unsigned char *pstr = str; xtext->in_hilight = FALSE; if (line < 255 && line >= 0) xtext->buffer->grid_offset[line] = offset; gc = xtext->fgc; /* our foreground GC */ if (ent->mark_start != -1 && ent->mark_start <= i + offset && ent->mark_end > i + offset) xtext_set_bg (xtext, gc, XTEXT_MARK_BG); xtext_set_fg (xtext, gc, XTEXT_MARK_FG); if (xtext->hilight_ent == ent && xtext->hilight_start <= i + offset && xtext->hilight_end > i + offset) xtext_set_bg (xtext, gc, 2); xtext->in_hilight = TRUE; if (!xtext->skip_border_fills && !xtext->dont_render) /* draw background to the left of the text */ if (str == ent->str && indent > MARGIN && xtext->buffer->time_stamp) /* don't overwrite the timestamp */ if (indent > xtext->stamp_width) xtext_draw_bg (xtext, xtext->stamp_width, y - xtext->font->ascent, indent - xtext->stamp_width, xtext->fontsize); /* fill the indent area with background gc */ if (indent >= xtext->clip_x) xtext_draw_bg (xtext, 0, y - xtext->font->ascent, MIN (indent, xtext->clip_x2), xtext->fontsize); if (xtext->jump_in_offset > 0 && offset < xtext->jump_in_offset) xtext->dont_render2 = TRUE; if (xtext->hilight_ent == ent && xtext->hilight_start == (i + offset)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext_set_bg (xtext, gc, 2); xtext->in_hilight = TRUE; if ((xtext->parsing_color && isdigit (str[i]) && xtext->nc < 2) || (xtext->parsing_color && str[i] == ',' && isdigit (str[i+1]) && xtext->nc < 3)) xtext->parsing_backcolor = TRUE; xtext->num[xtext->nc] = 0; col_num = atoi (xtext->num); if (col_num == 99) /* mIRC lameness */ col_num = col_num % XTEXT_MIRC_COLS; xtext->col_fore = col_num; /*xtext_set_fg (xtext, gc, col_num);*/ xtext->num[xtext->nc] = str[i]; if (xtext->parsing_color) xtext->parsing_color = FALSE; xtext->num[xtext->nc] = 0; col_num = atoi (xtext->num); if (xtext->parsing_backcolor) if (col_num == 99) /* mIRC lameness */ col_num = col_num % XTEXT_MIRC_COLS; xtext->backcolor = FALSE; /*xtext_set_bg (xtext, gc, col_num);*/ /*xtext->col_back = col_num;*/ if (col_num == 99) /* mIRC lameness */ col_num = col_num % XTEXT_MIRC_COLS; /*xtext_set_fg (xtext, gc, col_num);*/ /*xtext->col_fore = col_num;*/ xtext->parsing_backcolor = FALSE; /* got a \003<non-digit>... i.e. reset colors */ x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); /*gtk_xtext_reset (xtext, mark, FALSE);*/ if (offset +i < ent->left_len) GdkColor temp = {ent->left_color, 0, 0, 0}; gdk_gc_set_foreground(xtext->fgc, &temp); GdkColor temp = {ent->right_color, 0, 0, 0}; gdk_gc_set_foreground(xtext->fgc, &temp); x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->col_fore = xtext->col_back; xtext_set_fg (xtext, gc, xtext->col_fore); xtext_set_bg (xtext, gc, xtext->col_back); if (xtext->col_back != XTEXT_BG) xtext->backcolor = FALSE; x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->bold = !xtext->bold; x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->underline = !xtext->underline; x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->italics = !xtext->italics; x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); gtk_xtext_reset (xtext, mark, !xtext->in_hilight); x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->parsing_color = TRUE; /* invalid utf8 safe guard */ j += tmp; /* move to the next utf8 char */ i += charlen (str + i); /* move to the next utf8 char */ /* invalid utf8 safe guard */ /* Separate the left part, the space and the right part into separate runs, and reset bidi state inbetween. Perform this only on the first line of the message. /* we've reached the end of the left part? */ if (((pstr-str)+j == ent->left_len) || ((pstr-str)+j == ent->left_len+1)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); /*xtext_set_bg(xtext, gc, XTEXT_FG);*/ /*xtext_set_fg(xtext, gc, XTEXT_BG);*/ /* have we been told to stop rendering at this point? */ if (xtext->jump_out_offset > 0 && xtext->jump_out_offset <= (i + offset)) gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); ret = 0; /* skip the rest of the lines, we're done. */ if (xtext->jump_in_offset > 0 && xtext->jump_in_offset == (i + offset)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext->dont_render2 = FALSE; if (xtext->hilight_ent == ent && xtext->hilight_end == (i + offset)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext_set_bg (xtext, gc, XTEXT_MARK_BG); xtext_set_bg (xtext, gc, xtext->col_back); if (xtext->col_back != XTEXT_BG) xtext->backcolor = FALSE; xtext->underline = FALSE; xtext->in_hilight = FALSE; if (xtext->render_hilights_only) /* stop drawing this ent */ if (!mark && ent->mark_start == (i + offset)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext_set_bg (xtext, gc, XTEXT_MARK_BG); xtext_set_fg (xtext, gc, XTEXT_MARK_FG); if (mark && ent->mark_end == (i + offset)) x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext_set_bg (xtext, gc, xtext->col_back); xtext_set_fg (xtext, gc, xtext->col_fore); if (xtext->col_back != XTEXT_BG) xtext->backcolor = FALSE; x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc, ent->mb); xtext_set_bg (xtext, gc, xtext->col_back); xtext_set_fg (xtext, gc, xtext->col_fore); if (xtext->col_back != XTEXT_BG) xtext->backcolor = FALSE; /* draw background to the right of the text */ if (!left_only && !xtext->dont_render) /* draw separator now so it doesn't appear to flicker */ gtk_xtext_draw_sep (xtext, y - xtext->font->ascent); if (!xtext->skip_border_fills && xtext->clip_x2 >= x) int xx = MAX (x, xtext->clip_x); y - xtext->font->ascent, /* y */ MIN (xtext->clip_x2 - xx, (win_width + MARGIN) - xx), /* width */ xtext->fontsize); /* height */ xtext->dont_render2 = FALSE; /* get the desktop/root window */ static Window desktop_window = None; get_desktop_window (Display *xdisplay, Window the_window) unsigned long length, after; Window w, root, *children, parent; prop = XInternAtom (xdisplay, "_XROOTPMAP_ID", True); prop = XInternAtom (xdisplay, "_XROOTCOLOR_PIXEL", True); for (w = the_window; w; w = parent) if ((XQueryTree (xdisplay, w, &root, &parent, &children, XGetWindowProperty (xdisplay, w, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, return (desktop_window = w); return (desktop_window = None); /* find the root window (backdrop) Pixmap */ get_pixmap_prop (Display *xdisplay, Window the_window) unsigned long length, after; if (desktop_window == None) desktop_window = get_desktop_window (xdisplay, the_window); if (desktop_window == None) desktop_window = DefaultRootWindow (xdisplay); prop = XInternAtom (xdisplay, "_XROOTPMAP_ID", True); XGetWindowProperty (xdisplay, desktop_window, prop, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, pix = *((Pixmap *) data); /* slow generic routine, for the depths/bpp we don't know about */ shade_ximage_generic (GdkVisual *visual, XImage *ximg, int bpl, int w, int h, int rm, int gm, int bm, int bg) int bgr = (256 - rm) * (bg & visual->red_mask); int bgg = (256 - gm) * (bg & visual->green_mask); int bgb = (256 - bm) * (bg & visual->blue_mask); unsigned long pixel = XGetPixel (ximg, x, y); r = rm * (pixel & visual->red_mask) + bgr; g = gm * (pixel & visual->green_mask) + bgg; b = bm * (pixel & visual->blue_mask) + bgb; ((r >> 8) & visual->red_mask) | ((g >> 8) & visual->green_mask) | ((b >> 8) & visual->blue_mask)); /* Fast shading routine. Based on code by Willem Monsuwe <willem@stack.nl> */ #define SHADE_IMAGE(bytes, type, rmask, gmask, bmask) \ int bgr = (256 - rm) * (bg & rmask); \ int bgg = (256 - gm) * (bg & gmask); \ int bgb = (256 - bm) * (bg & bmask); \ ptr = (unsigned char *) data + (w * bytes); \ for (x = -w; x < 0; x++) \ r = rm * (b & rmask) + bgr; \ g = gm * (b & gmask) + bgg; \ b = bm * (b & bmask) + bgb; \ ((type *) ptr)[x] = ((r >> 8) & rmask) \ shade_ximage_15 (void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) SHADE_IMAGE (2, guint16, 0x7c00, 0x3e0, 0x1f); shade_ximage_16 (void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) SHADE_IMAGE (2, guint16, 0xf800, 0x7e0, 0x1f); shade_ximage_24 (void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) /* 24 has to be a special case, there's no guint24, or 24bit MOV :) */ int bgr = (256 - rm) * ((bg & 0xff0000) >> 16); int bgg = (256 - gm) * ((bg & 0xff00) >> 8); int bgb = (256 - bm) * (bg & 0xff); ptr = (unsigned char *) data + (w * 3); for (x = -(w * 3); x < 0; x += 3) #if (G_BYTE_ORDER == G_BIG_ENDIAN) r = (ptr[x + 0] * rm + bgr) >> 8; g = (ptr[x + 1] * gm + bgg) >> 8; b = (ptr[x + 2] * bm + bgb) >> 8; r = (ptr[x + 2] * rm + bgr) >> 8; g = (ptr[x + 1] * gm + bgg) >> 8; b = (ptr[x + 0] * bm + bgb) >> 8; shade_ximage_32 (void *data, int bpl, int w, int h, int rm, int gm, int bm, int bg) SHADE_IMAGE (4, guint32, 0xff0000, 0xff00, 0xff); shade_image (GdkVisual *visual, void *data, int bpl, int bpp, int w, int h, int rm, int gm, int bm, int bg, int depth) bg_r = bg & visual->red_mask; bg_g = bg & visual->green_mask; bg_b = bg & visual->blue_mask; /* the MMX routines are about 50% faster at 16-bit. */ /* only use MMX routines with a pure black background */ if (bg_r == 0 && bg_g == 0 && bg_b == 0 && have_mmx ()) /* do a runtime check too! */ shade_ximage_15_mmx (data, bpl, w, h, rm, gm, bm); shade_ximage_16_mmx (data, bpl, w, h, rm, gm, bm); shade_ximage_32_mmx (data, bpl, w, h, rm, gm, bm); shade_ximage_15 (data, bpl, w, h, rm, gm, bm, bg); shade_ximage_16 (data, bpl, w, h, rm, gm, bm, bg); shade_ximage_24 (data, bpl, w, h, rm, gm, bm, bg); shade_ximage_32 (data, bpl, w, h, rm, gm, bm, bg); get_shm_image (Display *xdisplay, XShmSegmentInfo *shminfo, int x, int y, int w, int h, int depth, Pixmap pix) shminfo->shmaddr = (char*) -1; ximg = XShmCreateImage (xdisplay, 0, depth, ZPixmap, 0, shminfo, w, h); shminfo->shmid = shmget (IPC_PRIVATE, ximg->bytes_per_line * ximg->height, if (shminfo->shmid == -1) shminfo->readOnly = False; ximg->data = shminfo->shmaddr = (char *)shmat (shminfo->shmid, 0, 0); if (shminfo->shmaddr == ((char *)-1)) shmctl (shminfo->shmid, IPC_RMID, 0); XShmAttach (xdisplay, shminfo); shmctl (shminfo->shmid, IPC_RMID, 0); XShmGetImage (xdisplay, pix, ximg, x, y, AllPlanes); get_image (GtkXText *xtext, Display *xdisplay, XShmSegmentInfo *shminfo, int x, int y, int w, int h, int depth, Pixmap pix) ximg = get_shm_image (xdisplay, shminfo, x, y, w, h, depth, pix); ximg = XGetImage (xdisplay, pix, x, y, w, h, -1, ZPixmap); shade_pixmap (GtkXText * xtext, Pixmap p, int x, int y, int w, int h) unsigned int width, height, depth, udummy; Display *xdisplay = GDK_WINDOW_XDISPLAY (xtext->draw_buf); XGetGeometry (xdisplay, p, &root, &dummy, &dummy, &width, &height, if (width < x + w || height < y + h || x < 0 || y < 0) gcv.subwindow_mode = IncludeInferiors; gcv.graphics_exposures = False; tgc = XCreateGC (xdisplay, p, GCGraphicsExposures|GCSubwindowMode, tmp = XCreatePixmap (xdisplay, p, w, h, depth); XSetTile (xdisplay, tgc, p); XSetFillStyle (xdisplay, tgc, FillTiled); XSetTSOrigin (xdisplay, tgc, -x, -y); XFillRectangle (xdisplay, tmp, tgc, 0, 0, w, h); ximg = get_image (xtext, xdisplay, &xtext->shminfo, 0, 0, w, h, depth, tmp); ximg = XGetImage (xdisplay, tmp, 0, 0, w, h, -1, ZPixmap); XFreePixmap (xdisplay, tmp); ximg = get_image (xtext, xdisplay, &xtext->shminfo, x, y, w, h, depth, p); ximg = XGetImage (xdisplay, p, x, y, w, h, -1, ZPixmap); shade_ximage_generic (gdk_drawable_get_visual (GTK_WIDGET (xtext)->window), ximg, ximg->bytes_per_line, w, h, xtext->tint_red, xtext->tint_green, xtext->tint_blue, xtext->palette[XTEXT_BG]); shade_image (gdk_drawable_get_visual (GTK_WIDGET (xtext)->window), ximg->data, ximg->bytes_per_line, ximg->bits_per_pixel, w, h, xtext->tint_red, xtext->tint_green, xtext->tint_blue, xtext->palette[XTEXT_BG], depth); shaded_pix = xtext->pixmap; #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) shaded_pix = gdk_pixmap_foreign_new ( XShmCreatePixmap (xdisplay, p, ximg->data, &xtext->shminfo, w, h, depth)); shaded_pix = gdk_pixmap_foreign_new_for_display ( gdk_drawable_get_display (xtext->draw_buf), XShmCreatePixmap (xdisplay, p, ximg->data, &xtext->shminfo, w, h, depth)); shaded_pix = gdk_pixmap_new (GTK_WIDGET (xtext)->window, w, h, depth); XPutImage (xdisplay, GDK_WINDOW_XWINDOW (shaded_pix), GDK_GC_XGC (xtext->fgc), ximg, 0, 0, 0, 0, w, h); /* free transparency xtext->pixmap */ #if defined(USE_XLIB) || defined(WIN32) gtk_xtext_free_trans (GtkXText * xtext) XFreePixmap (GDK_WINDOW_XDISPLAY (xtext->pixmap), GDK_WINDOW_XWINDOW (xtext->pixmap)); XShmDetach (GDK_WINDOW_XDISPLAY (xtext->draw_buf), &xtext->shminfo); shmdt (xtext->shminfo.shmaddr); g_object_unref (xtext->pixmap); win32_tint (GtkXText *xtext, GdkImage *img, int width, int height) GdkVisual *visual = gdk_drawable_get_visual (GTK_WIDGET (xtext)->window); /* slow generic routine */ for (y = 0; y < height; y++) for (x = 0; x < width; x++) pixel = (((guchar *) img->mem)[y * img->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0; pixelp = (guchar *) img->mem + y * img->bpl + (x >> 1); pixel = (*pixelp) & 0x0F; pixelp = (guchar *) img->mem + y * img->bpl + x * img->bpp; /* Windows is always LSB, no need to check img->byte_order. */ pixel = pixelp[0] | (pixelp[1] << 8); break; pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); break; pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16); break; r = (pixel & visual->red_mask) >> visual->red_shift; g = (pixel & visual->green_mask) >> visual->green_shift; b = (pixel & visual->blue_mask) >> visual->blue_shift; /* actual tinting is only these 3 lines */ pixel = ((r * xtext->tint_red) >> 8) << visual->red_shift | ((g * xtext->tint_green) >> 8) << visual->green_shift | ((b * xtext->tint_blue) >> 8) << visual->blue_shift; ((guchar *) img->mem)[y * img->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7))); ((guchar *) img->mem)[y * img->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7))); else if (img->depth == 4) pixelp = (guchar *) img->mem + y * img->bpl + (x >> 1); *pixelp |= (pixel & 0x0F); pixelp = (guchar *) img->mem + y * img->bpl + x * img->bpp; /* Windows is always LSB, no need to check img->byte_order. */ pixelp[2] = ((pixel >> 16) & 0xFF); pixelp[1] = ((pixel >> 8) & 0xFF); pixelp[0] = (pixel & 0xFF); shade_image (visual, img->mem, img->bpl, img->bpp, width, height, xtext->tint_red, xtext->tint_green, xtext->tint_blue, xtext->palette[XTEXT_BG], visual->depth); /* no need to dump it to a Pixmap, it's one and the same on win32 */ /* grab pixmap from root window and set xtext->pixmap */ #if defined(USE_XLIB) || defined(WIN32) gtk_xtext_load_trans (GtkXText * xtext) /* if not shaded, we paint directly with PaintDesktop() */ hwnd = GDK_WINDOW_HWND (GTK_WIDGET (xtext)->window); gdk_window_get_size (GTK_WIDGET (xtext)->window, &width, &height); img = gdk_image_get (GTK_WIDGET (xtext)->window, 0, 0, width+128, height); xtext->pixmap = win32_tint (xtext, img, img->width, img->height); GtkWidget *widget = GTK_WIDGET (xtext); rootpix = get_pixmap_prop (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XWINDOW (widget->window)); if (xtext->error_function) xtext->error_function (0); xtext->transparent = FALSE; gdk_window_get_origin (widget->window, &x, &y); gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &width, &height); xtext->pixmap = shade_pixmap (xtext, rootpix, x, y, width+105, height); if (xtext->pixmap == NULL) gdk_gc_set_tile (xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin (xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; #if (GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION == 0) xtext->pixmap = gdk_pixmap_foreign_new (rootpix); xtext->pixmap = gdk_pixmap_foreign_new_for_display (gdk_drawable_get_display (GTK_WIDGET (xtext)->window), rootpix); gdk_gc_set_tile (xtext->bgc, xtext->pixmap); gdk_gc_set_ts_origin (xtext->bgc, -x, -y); gdk_gc_set_fill (xtext->bgc, GDK_TILED); #endif /* ! XLIB || WIN32 */ /* walk through str until this line doesn't fit anymore */ find_next_wrap (GtkXText * xtext, textentry * ent, unsigned char *str, int win_width, int indent) unsigned char *last_space = str; unsigned char *orig_str = str; if (win_width >= ent->str_width + ent->indent) ret = ent->str_len - (str - ent->str); if ((col && isdigit (*str) && nc < 2) || (col && *str == ',' && isdigit (*(str+1)) && nc < 3)) str_width += backend_get_char_width (xtext, str, &mbl); if (str_width > win_width) if (str - last_space > WORDWRAP_LIMIT + limit_offset) ret = str - orig_str; /* fall back to character wrap */ ret = last_space - orig_str; if (ret == 0) /* fall back to character wrap */ /* keep a record of the last space, for wordwrapping */ /* progress to the next char */ if (str >= ent->str + ent->str_len) /* find the offset, in bytes, that wrap number 'line' starts at */ gtk_xtext_find_subline (GtkXText *xtext, textentry *ent, int line) int indent, str_pos, line_pos, len; if (ent->lines_taken < 2 || line < 1) /* we record the first 4 lines' wraps, so take a shortcut */ if (line <= RECORD_WRAPS) return ent->wrap_offset[line - 1]; gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &win_width, 0); line_pos = str_pos = 0;*/ /* start from the last recorded wrap, and move forward */ indent = xtext->buffer->indent; str_pos = ent->wrap_offset[RECORD_WRAPS-1]; str = str_pos + ent->str; len = find_next_wrap (xtext, ent, str, win_width, indent); indent = xtext->buffer->indent; while (str < ent->str + ent->str_len); /* render a single line, which may wrap to more lines */ gtk_xtext_render_line (GtkXText * xtext, textentry * ent, int line, int lines_max, int subline, int win_width) int indent, taken, entline, len, y, start_subline; if (xtext->auto_indent && xtext->buffer->time_stamp && !xtext->skip_stamp) int stamp_size = xtext_get_stamp_str (ent->stamp, &time_str); y = (xtext->fontsize * line) + xtext->font->ascent - xtext->pixel_offset; /* XXX: Set up the color here first? */ gtk_xtext_render_str (xtext, y, ent, time_str, stamp_size, win_width, 2, line, TRUE); /* draw each line one by one */ /* if it's one of the first 4 wraps, we don't need to calculate it, it's recorded in ->wrap_offset. This saves us a loop. */ if (entline < RECORD_WRAPS) if (ent->lines_taken < 2) len = ent->wrap_offset[entline] - ent->wrap_offset[entline-1]; len = ent->wrap_offset[0]; len = find_next_wrap (xtext, ent, str, win_width, indent); y = (xtext->fontsize * line) + xtext->font->ascent - xtext->pixel_offset; if (!gtk_xtext_render_str (xtext, y, ent, str, len, win_width, gtk_xtext_draw_marker (xtext, ent, y - xtext->fontsize * (taken + start_subline + 1)); return ent->lines_taken - subline; xtext->dont_render = TRUE; gtk_xtext_render_str (xtext, y, ent, str, len, win_width, xtext->dont_render = FALSE; indent = xtext->buffer->indent; while (str < ent->str + ent->str_len); gtk_xtext_draw_marker (xtext, ent, y - xtext->fontsize * (taken + start_subline)); gtk_xtext_set_palette (GtkXText * xtext, GdkColor palette[]) for (i = (XTEXT_COLS-1); i >= 0; i--) xtext->color[i].color.red = palette[i].red; xtext->color[i].color.green = palette[i].green; xtext->color[i].color.blue = palette[i].blue; xtext->color[i].color.alpha = 0xffff; xtext->color[i].pixel = palette[i].pixel; xtext->palette[i] = palette[i].pixel; if (GTK_WIDGET_REALIZED (xtext)) xtext_set_fg (xtext, xtext->fgc, XTEXT_FG); xtext_set_bg (xtext, xtext->fgc, XTEXT_BG); xtext_set_fg (xtext, xtext->bgc, XTEXT_BG); col.pixel = xtext->palette[XTEXT_MARKER]; gdk_gc_set_foreground (xtext->marker_gc, &col); xtext->col_fore = XTEXT_FG; xtext->col_back = XTEXT_BG; gtk_xtext_fix_indent (xtext_buffer *buf) /* make indent a multiple of the space width */ if (buf->indent && buf->xtext->space_width) j += buf->xtext->space_width; dontscroll (buf); /* force scrolling off */ gtk_xtext_recalc_widths (xtext_buffer *buf, int do_str_width) /* since we have a new font, we have to recalc the text widths */ ent->str_width = gtk_xtext_text_width (buf->xtext, ent->str, gtk_xtext_text_width (buf->xtext, ent->str, ent->left_len, NULL)) - buf->xtext->space_width; if (ent->indent < MARGIN) gtk_xtext_calc_lines (buf, FALSE); gtk_xtext_set_font (GtkXText *xtext, char *name) backend_font_close (xtext); /* realize now, so that font_open has a XDisplay */ gtk_widget_realize (GTK_WIDGET (xtext)); backend_font_open (xtext, name); /* measure the width of every char; only the ASCII ones for XFT */ for (i = 0; i < sizeof(xtext->fontwidth)/sizeof(xtext->fontwidth[0]); i++) xtext->fontwidth[i] = backend_get_text_width (xtext, &c, 1, TRUE); xtext->space_width = xtext->fontwidth[' ']; xtext->fontsize = xtext->font->ascent + xtext->font->descent; int stamp_size = xtext_get_stamp_str (time(0), &time_str); gtk_xtext_text_width (xtext, time_str, stamp_size, NULL) + MARGIN; gtk_xtext_fix_indent (xtext->buffer); if (GTK_WIDGET_REALIZED (xtext)) gtk_xtext_recalc_widths (xtext->buffer, TRUE); gtk_xtext_set_background (GtkXText * xtext, GdkPixmap * pixmap, gboolean trans) if (trans && (xtext->tint_red != 255 || xtext->tint_green != 255 || xtext->tint_blue != 255)) #if !defined(USE_XLIB) && !defined(WIN32) #if defined(USE_XLIB) || defined(WIN32) gtk_xtext_free_trans (xtext); g_object_unref (xtext->pixmap); xtext->transparent = trans; #if defined(USE_XLIB) || defined(WIN32) if (GTK_WIDGET_REALIZED (xtext)) gtk_xtext_load_trans (xtext); dontscroll (xtext->buffer); if (GTK_WIDGET_REALIZED (xtext)) gdk_gc_set_tile (xtext->bgc, pixmap); gdk_gc_set_ts_origin (xtext->bgc, 0, 0); xtext->ts_x = xtext->ts_y = 0; gdk_gc_set_fill (xtext->bgc, GDK_TILED); } else if (GTK_WIDGET_REALIZED (xtext)) g_object_unref (xtext->bgc); val.subwindow_mode = GDK_INCLUDE_INFERIORS; val.graphics_exposures = 0; xtext->bgc = gdk_gc_new_with_values (GTK_WIDGET (xtext)->window, &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW); xtext_set_fg (xtext, xtext->bgc, XTEXT_BG); gtk_xtext_save (GtkXText * xtext, int fh) ent = xtext->buffer->text_first; buf = gtk_xtext_strip_color (ent->str, ent->str_len, NULL, /* count how many lines 'ent' will take (with wraps) */ gtk_xtext_lines_taken (xtext_buffer *buf, textentry * ent) win_width = buf->window_width - MARGIN; if (ent->str_width + ent->indent < win_width) len = find_next_wrap (buf->xtext, ent, str, win_width, indent); if (taken < RECORD_WRAPS) ent->wrap_offset[taken] = (str + len) - ent->str; while (str < ent->str + ent->str_len); /* Calculate number of actual lines (with wraps), to set adj->lower. * * This should only be called when the window resizes. */ gtk_xtext_calc_lines (xtext_buffer *buf, int fire_signal) gdk_drawable_get_size (GTK_WIDGET (buf->xtext)->window, &width, &height); if (width < 30 || height < buf->xtext->fontsize || width < buf->indent + 30) ent->lines_taken = gtk_xtext_lines_taken (buf, ent); lines += ent->lines_taken; gtk_xtext_adjustment_set (buf, fire_signal); /* find the n-th line in the linked list, this includes wrap calculations */ gtk_xtext_nth (GtkXText *xtext, int line, int *subline) ent = xtext->buffer->text_first; /* -- optimization -- try to make a short-cut using the pagetop ent */ if (xtext->buffer->pagetop_ent) if (line == xtext->buffer->pagetop_line) *subline = xtext->buffer->pagetop_subline; return xtext->buffer->pagetop_ent; if (line > xtext->buffer->pagetop_line) /* lets start from the pagetop instead of the absolute beginning */ ent = xtext->buffer->pagetop_ent; lines = xtext->buffer->pagetop_line - xtext->buffer->pagetop_subline; else if (line > xtext->buffer->pagetop_line - line) /* move backwards from pagetop */ ent = xtext->buffer->pagetop_ent; lines = xtext->buffer->pagetop_line - xtext->buffer->pagetop_subline; lines -= ent->lines_taken; /* -- end of optimization -- */ lines += ent->lines_taken; *subline = ent->lines_taken - (lines - line); /* render enta (or an inclusive range enta->entb) */ gtk_xtext_render_ents (GtkXText * xtext, textentry * enta, textentry * entb) textentry *ent, *orig_ent, *tmp_ent; if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &width, &height); if (width < 32 || height < xtext->fontsize || width < xtext->buffer->indent + 30) lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1; orig_ent = xtext->buffer->pagetop_ent; subline = xtext->buffer->pagetop_subline; /* used before a complete page is in buffer */ orig_ent = xtext->buffer->text_first; /* check if enta is before the start of this page */ if (drawing || ent == entb || ent == enta) gtk_xtext_reset (xtext, FALSE, TRUE); line += gtk_xtext_render_line (xtext, ent, line, lines_max, xtext->jump_in_offset = 0; /* jump_in_offset only for the 1st */ line += ent->lines_taken; /* space below last line */ return (xtext->fontsize * line) - xtext->pixel_offset; /* render a whole page/window, starting from 'startline' */ gtk_xtext_render_page (GtkXText * xtext) int startline = xtext->adj->value; if(!GTK_WIDGET_REALIZED(xtext)) if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &width, &height); if (width < 34 || height < xtext->fontsize || width < xtext->buffer->indent + 32) xtext->pixel_offset = (xtext->adj->value - startline) * xtext->fontsize; ent = xtext->buffer->text_first; ent = gtk_xtext_nth (xtext, startline, &subline); xtext->buffer->pagetop_ent = ent; xtext->buffer->pagetop_subline = subline; xtext->buffer->pagetop_line = startline; if (xtext->buffer->num_lines <= xtext->adj->page_size) dontscroll (xtext->buffer); pos = xtext->adj->value * xtext->fontsize; pos = startline * xtext->fontsize; overlap = xtext->buffer->last_pixel_pos - pos; xtext->buffer->last_pixel_pos = pos; if (!xtext->transparent && !xtext->pixmap && abs (overlap) < height) if (!xtext->pixmap && abs (overlap) < height) /* dont scroll PageUp/Down without a DB, it looks ugly */ if (!xtext->transparent && !xtext->pixmap && abs (overlap) < height - (3*xtext->fontsize)) if (!xtext->pixmap && abs (overlap) < height - (3*xtext->fontsize)) /* so the obscured regions are exposed */ gdk_gc_set_exposures (xtext->fgc, TRUE); if (overlap < 1) /* DOWN */ gdk_draw_drawable (xtext->draw_buf, xtext->fgc, xtext->draw_buf, 0, -overlap, 0, 0, width, height + overlap); remainder = ((height - xtext->font->descent) % xtext->fontsize) + area.y = (height + overlap) - remainder; area.height = remainder - overlap; gdk_draw_drawable (xtext->draw_buf, xtext->fgc, xtext->draw_buf, 0, 0, 0, overlap, width, height - overlap); gdk_gc_set_exposures (xtext->fgc, FALSE); gtk_xtext_paint (GTK_WIDGET (xtext), &area); xtext->buffer->grid_dirty = TRUE; xtext->buffer->grid_dirty = FALSE; lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + 1; gtk_xtext_reset (xtext, FALSE, TRUE); line += gtk_xtext_render_line (xtext, ent, line, lines_max, line = (xtext->fontsize * line) - xtext->pixel_offset; /* fill any space below the last line with our background GC */ xtext_draw_bg (xtext, 0, line, width + MARGIN, height - line); /* draw the separator line */ gtk_xtext_draw_sep (xtext, -1); gtk_xtext_refresh (GtkXText * xtext, int do_trans) if (GTK_WIDGET_REALIZED (GTK_WIDGET (xtext))) #if defined(USE_XLIB) || defined(WIN32) if (xtext->transparent && do_trans) gtk_xtext_free_trans (xtext); gtk_xtext_load_trans (xtext); gtk_xtext_render_page (xtext); /* remove the topline from the list */ gtk_xtext_remove_top (xtext_buffer *buffer) ent = buffer->text_first; buffer->num_lines -= ent->lines_taken; buffer->pagetop_line -= ent->lines_taken; buffer->last_pixel_pos -= (ent->lines_taken * buffer->xtext->fontsize); buffer->text_first = ent->next; buffer->text_first->prev = NULL; buffer->old_value -= ent->lines_taken; if (buffer->xtext->buffer == buffer) /* is it the current buffer? */ buffer->xtext->adj->value -= ent->lines_taken; buffer->xtext->select_start_adj -= ent->lines_taken; if (ent == buffer->pagetop_ent) buffer->pagetop_ent = NULL; if (ent == buffer->last_ent_start) buffer->last_ent_start = ent->next; if (ent == buffer->last_ent_end) buffer->last_ent_start = NULL; buffer->last_ent_end = NULL; if (buffer->marker_pos == ent) buffer->marker_pos = NULL; gtk_xtext_clear (xtext_buffer *buf) buf->scrollbar_down = TRUE; buf->last_ent_start = NULL; buf->last_ent_end = NULL; next = buf->text_first->next; if (buf->xtext->buffer == buf) gtk_xtext_calc_lines (buf, TRUE); gtk_xtext_refresh (buf->xtext, 0); gtk_xtext_calc_lines (buf, FALSE); if (buf->xtext->auto_indent) buf->xtext->buffer->indent = 1; gtk_xtext_check_ent_visibility (GtkXText * xtext, textentry *find_ent, int add) gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &width, &height); lines_max = ((height + xtext->pixel_offset) / xtext->fontsize) + add; ent = xtext->buffer->pagetop_ent; while (ent && line < lines_max) line += ent->lines_taken; gtk_xtext_check_marker_visibility (GtkXText * xtext) if (gtk_xtext_check_ent_visibility (xtext, xtext->buffer->marker_pos, 1)) xtext->buffer->marker_seen = TRUE; gtk_xtext_search (GtkXText * xtext, const gchar *text, textentry *start, gboolean case_match, gboolean backward) gchar *str = NULL, *nee = NULL, *hay = NULL; /* needle in haystack */ gtk_xtext_selection_clear_full (xtext->buffer); xtext->buffer->last_ent_start = NULL; xtext->buffer->last_ent_end = NULL; /* set up text comparand for Case Match or Ignore */ nee = g_utf8_casefold (text, strlen (text)); /* Validate that start gives a currently valid ent pointer */ ent = xtext->buffer->text_first; /* Choose first ent to look at */ ent = backward? start->prev: start->next; ent = backward? xtext->buffer->text_last: xtext->buffer->text_first; /* Search from there to one end or the other until found */ /* If Case Ignore, fold before & free after calling strstr */ hay = g_strdup ((char *)ent->str); hay = g_utf8_casefold ((char *)ent->str, strlen ((char *)ent->str)); /* Try to find the needle in this haystack */ str = g_strstr_len (hay, strlen (hay), nee); ent = backward? ent->prev: ent->next; /* Save distance to start, end of found string */ ent->mark_start = str - hay; ent->mark_end = ent->mark_start + strlen (nee); /* is the match visible? Might need to scroll */ if (!gtk_xtext_check_ent_visibility (xtext, ent, 0)) ent = xtext->buffer->text_first; line += ent->lines_taken; while (line > xtext->adj->upper - xtext->adj->page_size) xtext->adj->value = line; xtext->buffer->scrollbar_down = FALSE; gtk_adjustment_changed (xtext->adj); gtk_widget_queue_draw (GTK_WIDGET (xtext)); gtk_xtext_render_page_timeout (GtkXText * xtext) GtkAdjustment *adj = xtext->adj; /* less than a complete page? */ if (xtext->buffer->num_lines <= adj->page_size) xtext->buffer->old_value = 0; gtk_xtext_render_page (xtext); } else if (xtext->buffer->scrollbar_down) g_signal_handler_block (xtext->adj, xtext->vc_signal_tag); gtk_xtext_adjustment_set (xtext->buffer, FALSE); gtk_adjustment_set_value (adj, adj->upper - adj->page_size); g_signal_handler_unblock (xtext->adj, xtext->vc_signal_tag); xtext->buffer->old_value = adj->value; gtk_xtext_render_page (xtext); gtk_xtext_adjustment_set (xtext->buffer, TRUE); if (xtext->indent_changed) xtext->indent_changed = FALSE; gtk_xtext_render_page (xtext); /* append a textentry to our linked list */ gtk_xtext_append_entry (xtext_buffer *buf, textentry * ent) ent->str_width = gtk_xtext_text_width (buf->xtext, ent->str, ent->str_len, &mb); if (ent->indent < MARGIN) ent->indent = MARGIN; /* 2 pixels is the left margin */ /* append to our linked list */ buf->text_last->next = ent; ent->prev = buf->text_last; ent->lines_taken = gtk_xtext_lines_taken (buf, ent); buf->num_lines += ent->lines_taken; if (buf->reset_marker_pos || ((buf->marker_pos == NULL || buf->marker_seen) && (buf->xtext->buffer != buf || #if GTK_CHECK_VERSION(2,4,0) !gtk_window_has_toplevel_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (buf->xtext))))))) !(GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (buf->xtext))))->has_focus))) dontscroll (buf); /* force scrolling off */ buf->marker_seen = FALSE; buf->reset_marker_pos = FALSE; if (buf->xtext->max_lines > 2 && buf->xtext->max_lines < buf->num_lines) gtk_xtext_remove_top (buf); if (buf->xtext->buffer == buf) /* this could be improved */ if ((buf->num_lines - 1) <= buf->xtext->adj->page_size) if (!buf->xtext->add_io_tag) /* remove scrolling events */ g_source_remove (buf->xtext->io_tag); buf->xtext->add_io_tag = g_timeout_add (REFRESH_TIMEOUT * 2, gtk_xtext_render_page_timeout, } else if (buf->scrollbar_down) buf->old_value = buf->num_lines - buf->xtext->adj->page_size; /* the main two public functions */ gtk_xtext_append_indent (xtext_buffer *buf, unsigned char *left_text, int left_len, int left_color, unsigned char *right_text, int right_len, int right_color) left_len = strlen ((char *)left_text); right_len = strlen ((char *)right_text); if (right_len >= sizeof (buf->xtext->scratch_buffer)) right_len = sizeof (buf->xtext->scratch_buffer) - 1; if (right_text[right_len-1] == '\n') ent = malloc (left_len + right_len + 2 + sizeof (textentry)); str = (unsigned char *) ent + sizeof (textentry); memcpy (str, left_text, left_len); memcpy (str + left_len + 1, right_text, right_len); str[left_len + 1 + right_len] = 0; left_width = gtk_xtext_text_width (buf->xtext, left_text, left_len, NULL); ent->left_len = left_len; ent->str_len = left_len + 1 + right_len; ent->indent = (buf->indent - left_width) - buf->xtext->space_width; ent->left_color = left_color; ent->right_color = right_color; space = buf->xtext->stamp_width; /* do we need to auto adjust the separator position? */ if (buf->xtext->auto_indent && ent->indent < MARGIN + space) tempindent = MARGIN + space + buf->xtext->space_width + left_width; if (tempindent > buf->indent) buf->indent = tempindent; if (buf->indent > buf->xtext->max_auto_indent) buf->indent = buf->xtext->max_auto_indent; gtk_xtext_fix_indent (buf); gtk_xtext_recalc_widths (buf, FALSE); ent->indent = (buf->indent - left_width) - buf->xtext->space_width; buf->xtext->indent_changed = TRUE; gtk_xtext_append_entry (buf, ent); gtk_xtext_append (xtext_buffer *buf, unsigned char *text, int len) len = strlen ((char *)text); if (len >= sizeof (buf->xtext->scratch_buffer)) len = sizeof (buf->xtext->scratch_buffer) - 1; ent = malloc (len + 1 + sizeof (textentry)); ent->str = (unsigned char *) ent + sizeof (textentry); memcpy (ent->str, text, len); gtk_xtext_append_entry (buf, ent); gtk_xtext_is_empty (xtext_buffer *buf) return buf->text_first == NULL; gtk_xtext_foreach (xtext_buffer *buf, GtkXTextForeach func, void *data) textentry *ent = buf->text_first; (*func) (buf->xtext, ent->str, data); gtk_xtext_set_error_function (GtkXText *xtext, void (*error_function) (int)) xtext->error_function = error_function; gtk_xtext_set_indent (GtkXText *xtext, gboolean indent) xtext->auto_indent = indent; gtk_xtext_set_max_indent (GtkXText *xtext, int max_auto_indent) xtext->max_auto_indent = max_auto_indent; gtk_xtext_set_max_lines (GtkXText *xtext, int max_lines) xtext->max_lines = max_lines; gtk_xtext_set_show_marker (GtkXText *xtext, gboolean show_marker) xtext->marker = show_marker; gtk_xtext_set_show_separator (GtkXText *xtext, gboolean show_separator) xtext->separator = show_separator; gtk_xtext_set_thin_separator (GtkXText *xtext, gboolean thin_separator) xtext->thinline = thin_separator; gtk_xtext_set_time_stamp (xtext_buffer *buf, gboolean time_stamp) buf->time_stamp = time_stamp; gtk_xtext_set_tint (GtkXText *xtext, int tint_red, int tint_green, int tint_blue) xtext->tint_red = tint_red; xtext->tint_green = tint_green; xtext->tint_blue = tint_blue; /*if (xtext->tint_red != 255 || xtext->tint_green != 255 || xtext->tint_blue != 255) gtk_xtext_set_urlcheck_function (GtkXText *xtext, int (*urlcheck_function) (GtkWidget *, char *, int)) xtext->urlcheck_function = urlcheck_function; gtk_xtext_set_wordwrap (GtkXText *xtext, gboolean wordwrap) xtext->wordwrap = wordwrap; gtk_xtext_reset_marker_pos (GtkXText *xtext) xtext->buffer->marker_pos = NULL; dontscroll (xtext->buffer); /* force scrolling off */ gtk_xtext_render_page (xtext); xtext->buffer->reset_marker_pos = TRUE; gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) if (xtext->buffer == buf) /*printf("text_buffer_show: xtext=%p buffer=%p\n", xtext, buf);*/ g_source_remove (xtext->add_io_tag); g_source_remove (xtext->io_tag); if (!GTK_WIDGET_REALIZED (GTK_WIDGET (xtext))) gtk_widget_realize (GTK_WIDGET (xtext)); gdk_drawable_get_size (GTK_WIDGET (xtext)->window, &w, &h); /* after a font change */ buf->needs_recalc = FALSE; gtk_xtext_recalc_widths (buf, TRUE); /* now change to the new buffer */ dontscroll (buf); /* force scrolling off */ xtext->adj->value = buf->old_value; xtext->adj->upper = buf->num_lines; if (xtext->adj->upper == 0) else if (xtext->adj->value > xtext->adj->upper - xtext->adj->page_size) /*buf->pagetop_ent = NULL;*/ xtext->adj->value = xtext->adj->upper - xtext->adj->page_size; if (xtext->adj->value < 0) /* did the window change size since this buffer was last shown? */ if (buf->window_width != w) gtk_xtext_calc_lines (buf, FALSE); gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - } else if (buf->window_height != h) gtk_xtext_adjustment_set (buf, FALSE); gtk_xtext_render_page (xtext); gtk_adjustment_changed (xtext->adj); /* avoid redoing the transparency */ xtext->avoid_trans = TRUE; gtk_xtext_buffer_new (GtkXText *xtext) buf = malloc (sizeof (xtext_buffer)); memset (buf, 0, sizeof (xtext_buffer)); buf->scrollbar_down = TRUE; buf->indent = xtext->space_width * 2; gtk_xtext_buffer_free (xtext_buffer *buf) if (buf->xtext->buffer == buf) buf->xtext->buffer = buf->xtext->orig_buffer; if (buf->xtext->selection_buffer == buf) buf->xtext->selection_buffer = NULL;