hexchat/src/fe-gtk/xtext.c

5020 lines
117 KiB
C
Raw Permalink Normal View History

2011-02-23 22:14:30 -05:00
/* X-Chat
* 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
2013-01-02 17:58:26 -05:00
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
2011-02-23 22:14:30 -05:00
* =========================================================================
*
* xtext, the text widget used by X-Chat.
* By Peter Zelezny <zed@xchat.org>.
*
*/
#define GDK_MULTIHEAD_SAFE
#define MARGIN 2 /* dont touch. */
#define REFRESH_TIMEOUT 20
#define WORDWRAP_LIMIT 24
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
2014-12-15 22:57:27 -05:00
#include "config.h"
2012-10-24 15:33:02 -04:00
#include "../common/hexchat.h"
#include "../common/fe.h"
#include "../common/util.h"
2012-10-24 15:33:02 -04:00
#include "../common/hexchatc.h"
#include "../common/url.h"
#ifdef WIN32
#include "marshal.h"
#else
#include "../common/marshal.h"
#endif
#include "fe-gtk.h"
2011-02-23 22:14:30 -05:00
#include "xtext.h"
2012-10-20 21:03:38 -04:00
#include "fkeys.h"
2011-02-23 22:14:30 -05:00
#define charlen(str) g_utf8_skip[*(guchar *)(str)]
#ifdef WIN32
#include <windows.h>
2012-07-21 08:26:19 -04:00
#include <io.h>
#include <gdk/gdk.h>
2011-02-23 22:14:30 -05:00
#include <gdk/gdkwin32.h>
#else
#include <unistd.h>
2014-01-18 03:06:33 -05:00
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
2011-02-23 22:14:30 -05:00
#endif
/* is delimiter */
#define is_del(c) \
(c == ' ' || c == '\n' || c == '>' || c == '<' || c == 0)
2011-02-23 22:14:30 -05:00
/* force scrolling off */
#define dontscroll(buf) (buf)->last_pixel_pos = 0x7fffffff
static GtkWidgetClass *parent_class = NULL;
struct textentry
{
struct textentry *next;
struct textentry *prev;
unsigned char *str;
time_t stamp;
gint16 str_width;
gint16 str_len;
gint16 mark_start;
gint16 mark_end;
gint16 indent;
gint16 left_len;
GSList *slp;
GSList *sublines;
2011-02-23 22:14:30 -05:00
guchar tag;
guchar pad1;
guchar pad2; /* 32-bit align : 44 bytes total */
GList *marks; /* List of found strings */
2011-02-23 22:14:30 -05:00
};
enum
{
WORD_CLICK,
SET_SCROLL_ADJUSTMENTS,
2011-02-23 22:14:30 -05:00
LAST_SIGNAL
};
/* values for selection info */
enum
{
TARGET_UTF8_STRING,
TARGET_STRING,
TARGET_TEXT,
TARGET_COMPOUND_TEXT
};
static guint xtext_signals[LAST_SIGNAL];
char *nocasestrstr (const char *text, const char *tofind); /* util.c */
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);
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,
GtkXText * xtext);
static void gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj,
GtkAdjustment *vadj);
2011-02-23 22:14:30 -05:00
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);
2012-11-10 11:19:55 -05:00
/* static char *gtk_xtext_conv_color (unsigned char *text, int len, int *newlen); */
/* For use by gtk_xtext_strip_color() and its callers -- */
struct offlen_s {
guint16 off;
guint16 len;
guint16 emph;
guint16 width;
};
typedef struct offlen_s offlen_t;
2011-02-23 22:14:30 -05:00
static unsigned char *
gtk_xtext_strip_color (unsigned char *text, int len, unsigned char *outbuf,
int *newlen, GSList **slp, int strip_hidden);
2011-02-23 22:14:30 -05:00
static gboolean gtk_xtext_check_ent_visibility (GtkXText * xtext, textentry *find_ent, int add);
static int gtk_xtext_render_page_timeout (GtkXText * xtext);
static int gtk_xtext_search_offset (xtext_buffer *buf, textentry *ent, unsigned int off);
static GList * gtk_xtext_search_textentry (xtext_buffer *, textentry *);
static void gtk_xtext_search_textentry_add (xtext_buffer *, textentry *, GList *, gboolean);
static void gtk_xtext_search_textentry_del (xtext_buffer *, textentry *);
static void gtk_xtext_search_textentry_fini (gpointer, gpointer);
static void gtk_xtext_search_fini (xtext_buffer *);
static gboolean gtk_xtext_search_init (xtext_buffer *buf, const gchar *text, gtk_xtext_search_flags flags, GError **perr);
static char * gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len, GSList **slp);
2011-02-23 22:14:30 -05:00
/* Avoid warning messages for this unused function */
#if 0
2011-02-23 22:14:30 -05:00
/* gives width of a 8bit string - with no mIRC codes in it */
static int
gtk_xtext_text_width_8bit (GtkXText *xtext, unsigned char *str, int len)
{
int width = 0;
while (len)
{
width += xtext->fontwidth[*str];
str++;
len--;
}
return width;
}
#endif
2011-02-23 22:14:30 -05:00
#define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc, 1, x, y, w, h);
2011-02-23 22:14:30 -05:00
/* ======================================= */
/* ============ PANGO BACKEND ============ */
/* ======================================= */
#define EMPH_ITAL 1
#define EMPH_BOLD 2
#define EMPH_HIDDEN 4
static PangoAttrList *attr_lists[4];
static int fontwidths[4][128];
static PangoAttribute *
xtext_pango_attr (PangoAttribute *attr)
{
attr->start_index = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
return attr;
}
static void
xtext_pango_init (GtkXText *xtext)
{
int i, j;
char buf[2] = "\000";
if (attr_lists[0])
{
for (i = 0; i < (EMPH_ITAL | EMPH_BOLD); i++)
pango_attr_list_unref (attr_lists[i]);
}
for (i = 0; i < sizeof attr_lists / sizeof attr_lists[0]; i++)
{
attr_lists[i] = pango_attr_list_new ();
switch (i)
{
case 0: /* Roman */
break;
case EMPH_ITAL: /* Italic */
pango_attr_list_insert (attr_lists[i],
xtext_pango_attr (pango_attr_style_new (PANGO_STYLE_ITALIC)));
break;
case EMPH_BOLD: /* Bold */
pango_attr_list_insert (attr_lists[i],
xtext_pango_attr (pango_attr_weight_new (PANGO_WEIGHT_BOLD)));
break;
case EMPH_ITAL | EMPH_BOLD: /* Italic Bold */
pango_attr_list_insert (attr_lists[i],
xtext_pango_attr (pango_attr_style_new (PANGO_STYLE_ITALIC)));
pango_attr_list_insert (attr_lists[i],
xtext_pango_attr (pango_attr_weight_new (PANGO_WEIGHT_BOLD)));
break;
}
/* Now initialize fontwidths[i] */
pango_layout_set_attributes (xtext->layout, attr_lists[i]);
for (j = 0; j < 128; j++)
{
buf[0] = j;
pango_layout_set_text (xtext->layout, buf, 1);
pango_layout_get_pixel_size (xtext->layout, &fontwidths[i][j], NULL);
}
}
xtext->space_width = fontwidths[0][' '];
}
2011-02-23 22:14:30 -05:00
static void
backend_font_close (GtkXText *xtext)
{
pango_font_description_free (xtext->font->font);
}
static void
backend_init (GtkXText *xtext)
{
if (xtext->layout == NULL)
{
xtext->layout = gtk_widget_create_pango_layout (GTK_WIDGET (xtext), 0);
if (xtext->font)
pango_layout_set_font_description (xtext->layout, xtext->font->font);
}
}
static void
backend_deinit (GtkXText *xtext)
{
if (xtext->layout)
{
g_object_unref (xtext->layout);
xtext->layout = NULL;
}
}
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");
}
if (!font)
font = pango_font_description_from_string ("sans 11");
return font;
}
static void
backend_font_open (GtkXText *xtext, char *name)
{
PangoLanguage *lang;
PangoContext *context;
PangoFontMetrics *metrics;
xtext->font = &xtext->pango_font;
xtext->font->font = backend_font_open_real (name);
if (!xtext->font->font)
{
xtext->font = NULL;
return;
}
backend_init (xtext);
pango_layout_set_font_description (xtext->layout, xtext->font->font);
xtext_pango_init (xtext);
2011-02-23 22:14:30 -05:00
/* 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);
}
static int
backend_get_text_width_emph (GtkXText *xtext, guchar *str, int len, int emphasis)
2011-02-23 22:14:30 -05:00
{
int width;
int deltaw;
int mbl;
2011-02-23 22:14:30 -05:00
if (*str == 0)
return 0;
if ((emphasis & EMPH_HIDDEN))
return 0;
emphasis &= (EMPH_ITAL | EMPH_BOLD);
width = 0;
pango_layout_set_attributes (xtext->layout, attr_lists[emphasis]);
while (len > 0)
{
mbl = charlen(str);
if (*str < 128)
deltaw = fontwidths[emphasis][*str];
else
{
pango_layout_set_text (xtext->layout, str, mbl);
pango_layout_get_pixel_size (xtext->layout, &deltaw, NULL);
}
width += deltaw;
str += mbl;
len -= mbl;
}
2011-02-23 22:14:30 -05:00
return width;
}
static int
backend_get_text_width_slp (GtkXText *xtext, guchar *str, GSList *slp)
2011-02-23 22:14:30 -05:00
{
int width = 0;
2011-02-23 22:14:30 -05:00
while (slp)
2011-02-23 22:14:30 -05:00
{
offlen_t *meta;
2011-02-23 22:14:30 -05:00
meta = slp->data;
width += backend_get_text_width_emph (xtext, str, meta->len, meta->emph);
str += meta->len;
slp = g_slist_next (slp);
}
2011-02-23 22:14:30 -05:00
return width;
}
/* simplified version of gdk_draw_layout_line_with_colors() */
static void
xtext_draw_layout_line (GdkDrawable *drawable,
GdkGC *gc,
gint x,
gint y,
PangoLayoutLine *line)
{
GSList *tmp_list = line->runs;
PangoRectangle logical_rect;
gint x_off = 0;
while (tmp_list)
{
PangoLayoutRun *run = tmp_list->data;
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
NULL, &logical_rect);
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;
}
}
static void
backend_draw_text_emph (GtkXText *xtext, int dofill, GdkGC *gc, int x, int y,
char *str, int len, int str_width, int emphasis)
2011-02-23 22:14:30 -05:00
{
GdkGCValues val;
GdkColor col;
PangoLayoutLine *line;
pango_layout_set_attributes (xtext->layout, attr_lists[emphasis]);
pango_layout_set_text (xtext->layout, str, len);
2011-02-23 22:14:30 -05:00
if (dofill)
{
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);
2011-02-23 22:14:30 -05:00
}
line = pango_layout_get_lines (xtext->layout)->data;
xtext_draw_layout_line (xtext->draw_buf, gc, x, y, line);
}
static void
xtext_set_fg (GtkXText *xtext, GdkGC *gc, int index)
{
2013-10-10 21:02:24 -04:00
gdk_gc_set_foreground (gc, &xtext->palette[index]);
2011-02-23 22:14:30 -05:00
}
static void
xtext_set_bg (GtkXText *xtext, GdkGC *gc, int index)
{
2013-10-10 21:02:24 -04:00
gdk_gc_set_background (gc, &xtext->palette[index]);
2011-02-23 22:14:30 -05:00
}
static void
gtk_xtext_init (GtkXText * xtext)
{
xtext->pixmap = NULL;
xtext->io_tag = 0;
xtext->add_io_tag = 0;
xtext->scroll_tag = 0;
xtext->max_lines = 0;
xtext->col_back = XTEXT_BG;
xtext->col_fore = XTEXT_FG;
xtext->nc = 0;
xtext->pixel_offset = 0;
xtext->underline = FALSE;
xtext->hidden = FALSE;
xtext->font = NULL;
xtext->layout = NULL;
xtext->jump_out_offset = 0;
xtext->jump_in_offset = 0;
xtext->ts_x = 0;
xtext->ts_y = 0;
xtext->clip_x = 0;
xtext->clip_x2 = 1000000;
xtext->clip_y = 0;
xtext->clip_y2 = 1000000;
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->recycle = FALSE;
xtext->dont_render = FALSE;
xtext->dont_render2 = FALSE;
gtk_xtext_scroll_adjustments (xtext, NULL, NULL);
2011-02-23 22:14:30 -05:00
{
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,
targets, n_targets);
}
}
static void
gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal)
{
GtkAdjustment *adj = buf->xtext->adj;
if (buf->xtext->buffer == buf)
{
adj->lower = 0;
adj->upper = buf->num_lines;
2011-02-23 22:14:30 -05:00
if (adj->upper == 0)
adj->upper = 1;
2011-02-23 22:14:30 -05:00
adj->page_size = GTK_WIDGET (buf->xtext)->allocation.height /
buf->xtext->fontsize;
adj->page_increment = adj->page_size;
2011-02-23 22:14:30 -05:00
if (adj->value > adj->upper - adj->page_size)
{
buf->scrollbar_down = TRUE;
adj->value = adj->upper - adj->page_size;
}
2011-02-23 22:14:30 -05:00
if (adj->value < 0)
adj->value = 0;
2011-02-23 22:14:30 -05:00
if (fire_signal)
gtk_adjustment_changed (adj);
}
}
static gint
gtk_xtext_adjustment_timeout (GtkXText * xtext)
{
gtk_xtext_render_page (xtext);
xtext->io_tag = 0;
return 0;
}
static void
gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext)
{
if (!gtk_widget_get_realized (GTK_WIDGET (xtext)))
return;
if (xtext->buffer->old_value != xtext->adj->value)
2011-02-23 22:14:30 -05:00
{
if (xtext->adj->value >= xtext->adj->upper - xtext->adj->page_size)
2011-02-23 22:14:30 -05:00
xtext->buffer->scrollbar_down = TRUE;
else
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? */
2011-02-23 22:14:30 -05:00
{
if (xtext->io_tag)
{
g_source_remove (xtext->io_tag);
xtext->io_tag = 0;
}
gtk_xtext_render_page (xtext);
} else
{
if (!xtext->io_tag)
xtext->io_tag = g_timeout_add (REFRESH_TIMEOUT,
(GSourceFunc)
gtk_xtext_adjustment_timeout,
xtext);
}
}
xtext->buffer->old_value = adj->value;
2011-02-23 22:14:30 -05:00
}
GtkWidget *
gtk_xtext_new (GdkColor palette[], int separator)
{
GtkXText *xtext;
xtext = g_object_new (gtk_xtext_get_type (), NULL);
xtext->separator = separator;
xtext->wordwrap = TRUE;
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);
}
static void
2014-01-18 21:48:41 -05:00
gtk_xtext_destroy (GtkObject * object)
2011-02-23 22:14:30 -05:00
{
GtkXText *xtext = GTK_XTEXT (object);
if (xtext->add_io_tag)
{
g_source_remove (xtext->add_io_tag);
xtext->add_io_tag = 0;
}
if (xtext->scroll_tag)
{
g_source_remove (xtext->scroll_tag);
xtext->scroll_tag = 0;
}
if (xtext->io_tag)
{
g_source_remove (xtext->io_tag);
xtext->io_tag = 0;
}
if (xtext->pixmap)
{
g_object_unref (xtext->pixmap);
2011-02-23 22:14:30 -05:00
xtext->pixmap = NULL;
}
if (xtext->font)
{
backend_font_close (xtext);
xtext->font = NULL;
}
if (xtext->adj)
{
g_signal_handlers_disconnect_matched (G_OBJECT (xtext->adj),
G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, xtext);
2014-01-18 04:08:32 -05:00
/* gtk_signal_disconnect_by_data (G_OBJECT (xtext->adj), xtext);*/
2011-02-23 22:14:30 -05:00
g_object_unref (G_OBJECT (xtext->adj));
xtext->adj = NULL;
}
if (xtext->bgc)
{
g_object_unref (xtext->bgc);
xtext->bgc = NULL;
}
if (xtext->fgc)
{
g_object_unref (xtext->fgc);
xtext->fgc = NULL;
}
if (xtext->light_gc)
{
g_object_unref (xtext->light_gc);
xtext->light_gc = NULL;
}
if (xtext->dark_gc)
{
g_object_unref (xtext->dark_gc);
xtext->dark_gc = NULL;
}
if (xtext->thin_gc)
{
g_object_unref (xtext->thin_gc);
xtext->thin_gc = NULL;
}
if (xtext->marker_gc)
{
g_object_unref (xtext->marker_gc);
xtext->marker_gc = NULL;
}
if (xtext->hand_cursor)
{
gdk_cursor_unref (xtext->hand_cursor);
xtext->hand_cursor = NULL;
}
if (xtext->resize_cursor)
{
gdk_cursor_unref (xtext->resize_cursor);
xtext->resize_cursor = NULL;
}
if (xtext->orig_buffer)
{
gtk_xtext_buffer_free (xtext->orig_buffer);
xtext->orig_buffer = NULL;
}
2014-01-20 01:25:35 -05:00
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2011-02-23 22:14:30 -05:00
}
static void
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);
2011-02-23 22:14:30 -05:00
if (parent_class->unrealize)
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
static void
gtk_xtext_realize (GtkWidget * widget)
{
GtkXText *xtext;
GdkWindowAttr attributes;
GdkGCValues val;
GdkColor col;
GdkColormap *cmap;
2014-01-18 04:08:32 -05:00
gtk_widget_set_realized (widget, TRUE);
2011-02-23 22:14:30 -05:00
xtext = GTK_XTEXT (widget);
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
2011-02-23 22:14:30 -05:00
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;
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,
2011-02-23 22:14:30 -05:00
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
GDK_WA_COLORMAP);
2011-02-23 22:14:30 -05:00
gdk_window_set_user_data (widget->window, widget);
2011-02-23 22:14:30 -05:00
xtext->depth = gdk_window_get_visual (widget->window)->depth;
2011-02-23 22:14:30 -05:00
val.subwindow_mode = GDK_INCLUDE_INFERIORS;
val.graphics_exposures = 0;
xtext->bgc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
xtext->fgc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
xtext->light_gc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
xtext->dark_gc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
xtext->thin_gc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
xtext->marker_gc = gdk_gc_new_with_values (widget->window, &val,
2011-02-23 22:14:30 -05:00
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) */
2013-10-10 21:02:24 -04:00
gdk_gc_set_foreground (xtext->marker_gc, &xtext->palette[XTEXT_MARKER]);
2011-02-23 22:14:30 -05:00
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;
2011-02-23 22:14:30 -05:00
if (xtext->pixmap)
{
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);
}
2014-01-18 03:06:33 -05:00
xtext->hand_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_HAND1);
xtext->resize_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_LEFT_SIDE);
2011-02-23 22:14:30 -05:00
gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
widget->style = gtk_style_attach (widget->style, widget->window);
2011-02-23 22:14:30 -05:00
backend_init (xtext);
}
static void
gtk_xtext_size_request (GtkWidget * widget, GtkRequisition * requisition)
{
requisition->width = 200;
requisition->height = 90;
}
static void
gtk_xtext_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
{
GtkXText *xtext = GTK_XTEXT (widget);
int height_only = FALSE;
if (allocation->width == xtext->buffer->window_width)
height_only = TRUE;
widget->allocation = *allocation;
2014-01-18 04:08:32 -05:00
if (gtk_widget_get_realized (GTK_WIDGET(widget)))
2011-02-23 22:14:30 -05:00
{
xtext->buffer->window_width = allocation->width;
xtext->buffer->window_height = allocation->height;
gdk_window_move_resize (widget->window, allocation->x, allocation->y,
2011-02-23 22:14:30 -05:00
allocation->width, allocation->height);
dontscroll (xtext->buffer); /* force scrolling off */
if (!height_only)
gtk_xtext_calc_lines (xtext->buffer, FALSE);
else
{
xtext->buffer->pagetop_ent = NULL;
gtk_xtext_adjustment_set (xtext->buffer, FALSE);
}
if (xtext->buffer->scrollbar_down)
gtk_adjustment_set_value (xtext->adj, xtext->adj->upper -
xtext->adj->page_size);
2011-02-23 22:14:30 -05:00
}
}
static int
gtk_xtext_selection_clear (xtext_buffer *buf)
{
textentry *ent;
int ret = 0;
ent = buf->last_ent_start;
while (ent)
{
if (ent->mark_start != -1)
ret = 1;
ent->mark_start = -1;
ent->mark_end = -1;
if (ent == buf->last_ent_end)
break;
ent = ent->next;
}
return ret;
}
static int
find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent)
2011-02-23 22:14:30 -05:00
{
int xx = indent;
int suboff;
GSList *list;
GSList *hid = NULL;
offlen_t *meta;
int off, len, wid, mbl, mbw;
2011-02-23 22:14:30 -05:00
/* Skip to the first chunk of stuff for the subline */
if (subline > 0)
2011-02-23 22:14:30 -05:00
{
suboff = GPOINTER_TO_INT (g_slist_nth_data (ent->sublines, subline - 1));
for (list = ent->slp; list; list = g_slist_next (list))
2011-02-23 22:14:30 -05:00
{
meta = list->data;
if (meta->off + meta->len > suboff)
2011-02-23 22:14:30 -05:00
break;
}
}
else
{
suboff = 0;
list = ent->slp;
}
/* Step to the first character of the subline */
if (list == NULL)
return 0;
meta = list->data;
off = meta->off;
len = meta->len;
if (meta->emph & EMPH_HIDDEN)
hid = list;
while (len > 0)
{
if (off >= suboff)
break;
mbl = charlen (ent->str + off);
len -= mbl;
off += mbl;
}
if (len < 0)
return ent->str_len; /* Bad char -- return max offset. */
/* Step through characters to find the one at the x position */
wid = x - indent;
len = meta->len - (off - meta->off);
while (wid > 0)
{
mbl = charlen (ent->str + off);
mbw = backend_get_text_width_emph (xtext, ent->str + off, mbl, meta->emph);
wid -= mbw;
xx += mbw;
if (xx >= x)
return off;
len -= mbl;
off += mbl;
if (len <= 0)
{
if (meta->emph & EMPH_HIDDEN)
hid = list;
list = g_slist_next (list);
if (list == NULL)
return ent->str_len;
meta = list->data;
off = meta->off;
len = meta->len;
}
2011-02-23 22:14:30 -05:00
}