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"
|
2012-05-28 17:17:09 -04:00
|
|
|
#include "../common/fe.h"
|
|
|
|
#include "../common/util.h"
|
2012-10-24 15:33:02 -04:00
|
|
|
#include "../common/hexchatc.h"
|
2013-01-02 17:50:26 -05:00
|
|
|
#include "../common/url.h"
|
2015-02-11 13:01:29 -05:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include "marshal.h"
|
|
|
|
#else
|
2014-02-05 20:42:48 -05:00
|
|
|
#include "../common/marshal.h"
|
2015-02-11 13:01:29 -05:00
|
|
|
#endif
|
|
|
|
|
2012-05-28 17:17:09 -04:00
|
|
|
#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>
|
2011-12-11 11:34:02 -05:00
|
|
|
#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) \
|
2013-03-03 14:43:24 -05:00
|
|
|
(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;
|
2014-02-02 03:45:51 -05:00
|
|
|
GSList *slp;
|
|
|
|
GSList *sublines;
|
2011-02-23 22:14:30 -05:00
|
|
|
guchar tag;
|
|
|
|
guchar pad1;
|
|
|
|
guchar pad2; /* 32-bit align : 44 bytes total */
|
2012-05-28 17:17:09 -04:00
|
|
|
GList *marks; /* List of found strings */
|
2011-02-23 22:14:30 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
WORD_CLICK,
|
2014-02-05 18:08:40 -05:00
|
|
|
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);
|
2014-02-05 18:08:40 -05:00
|
|
|
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); */
|
2012-05-28 17:17:09 -04:00
|
|
|
/* For use by gtk_xtext_strip_color() and its callers -- */
|
2014-02-02 03:45:51 -05:00
|
|
|
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,
|
2014-02-02 03:45:51 -05:00
|
|
|
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);
|
2012-05-28 17:17:09 -04:00
|
|
|
static int gtk_xtext_search_offset (xtext_buffer *buf, textentry *ent, unsigned int off);
|
2012-08-28 22:10:03 -04:00
|
|
|
static GList * gtk_xtext_search_textentry (xtext_buffer *, textentry *);
|
|
|
|
static void gtk_xtext_search_textentry_add (xtext_buffer *, textentry *, GList *, gboolean);
|
2012-05-28 17:17:09 -04:00
|
|
|
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);
|
2014-08-23 14:08:10 -04:00
|
|
|
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
|
|
|
|
2013-11-12 18:02:38 -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;
|
|
|
|
}
|
2013-11-12 18:02:38 -05:00
|
|
|
#endif
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-09-26 23:24:27 -04: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 ============ */
|
|
|
|
/* ======================================= */
|
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
#define EMPH_ITAL 1
|
|
|
|
#define EMPH_BOLD 2
|
2014-05-19 01:23:19 -04:00
|
|
|
#define EMPH_HIDDEN 4
|
2014-02-02 03:45:51 -05:00
|
|
|
static PangoAttrList *attr_lists[4];
|
|
|
|
static int fontwidths[4][128];
|
|
|
|
|
|
|
|
static PangoAttribute *
|
|
|
|
xtext_pango_attr (PangoAttribute *attr)
|
2013-10-26 08:51:50 -04:00
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
attr->start_index = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
|
|
|
|
attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
|
|
|
|
return attr;
|
|
|
|
}
|
2013-10-26 08:51:50 -04:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
static void
|
|
|
|
xtext_pango_init (GtkXText *xtext)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
char buf[2] = "\000";
|
2013-10-26 08:51:50 -04:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
if (attr_lists[0])
|
2013-10-26 08:51:50 -04:00
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
for (i = 0; i < (EMPH_ITAL | EMPH_BOLD); i++)
|
|
|
|
pango_attr_list_unref (attr_lists[i]);
|
2013-10-26 08:51:50 -04:00
|
|
|
}
|
2014-02-02 03:45:51 -05:00
|
|
|
|
|
|
|
for (i = 0; i < sizeof attr_lists / sizeof attr_lists[0]; i++)
|
2013-10-26 08:51:50 -04:00
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
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;
|
|
|
|
}
|
2013-10-26 08:51:50 -04:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
/* 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);
|
|
|
|
}
|
2013-10-26 08:51:50 -04:00
|
|
|
}
|
2014-02-02 03:45:51 -05:00
|
|
|
xtext->space_width = fontwidths[0][' '];
|
2013-10-26 08:51:50 -04:00
|
|
|
}
|
|
|
|
|
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);
|
2014-02-02 03:45:51 -05:00
|
|
|
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
|
2014-02-02 03:45:51 -05:00
|
|
|
backend_get_text_width_emph (GtkXText *xtext, guchar *str, int len, int emphasis)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
int width;
|
2014-02-02 03:45:51 -05:00
|
|
|
int deltaw;
|
|
|
|
int mbl;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
|
|
|
if (*str == 0)
|
|
|
|
return 0;
|
|
|
|
|
2014-05-19 01:23:19 -04:00
|
|
|
if ((emphasis & EMPH_HIDDEN))
|
|
|
|
return 0;
|
|
|
|
emphasis &= (EMPH_ITAL | EMPH_BOLD);
|
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
static int
|
|
|
|
backend_get_text_width_slp (GtkXText *xtext, guchar *str, GSList *slp)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
int width = 0;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
while (slp)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
offlen_t *meta;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2014-02-02 03:45:51 -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
|
2014-02-02 03:45:51 -05:00
|
|
|
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;
|
2013-09-28 23:02:38 -04:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
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)
|
|
|
|
{
|
2013-09-26 23:24:27 -04:00
|
|
|
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;
|
2014-02-05 18:08:40 -05:00
|
|
|
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)
|
|
|
|
{
|
2013-10-09 13:59:07 -04:00
|
|
|
adj->lower = 0;
|
|
|
|
adj->upper = buf->num_lines;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
if (adj->upper == 0)
|
|
|
|
adj->upper = 1;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-10-09 13:59:07 -04: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
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
if (adj->value > adj->upper - adj->page_size)
|
2014-10-08 19:42:41 -04:00
|
|
|
{
|
|
|
|
buf->scrollbar_down = TRUE;
|
2013-10-09 13:59:07 -04:00
|
|
|
adj->value = adj->upper - adj->page_size;
|
2014-10-08 19:42:41 -04:00
|
|
|
}
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-10-09 13:59:07 -04: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)
|
|
|
|
{
|
2014-02-05 18:08:40 -05:00
|
|
|
if (!gtk_widget_get_realized (GTK_WIDGET (xtext)))
|
|
|
|
return;
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
if (xtext->buffer->old_value != xtext->adj->value)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2013-10-09 13:59:07 -04: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;
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2013-10-09 13:59:07 -04:00
|
|
|
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)
|
|
|
|
{
|
2013-09-26 23:24:27 -04:00
|
|
|
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 */
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
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 |
|
2013-10-09 13:59:07 -04:00
|
|
|
GDK_WA_COLORMAP);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
gdk_window_set_user_data (widget->window, widget);
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2013-10-09 13:59:07 -04: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;
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
xtext->bgc = gdk_gc_new_with_values (widget->window, &val,
|
2011-02-23 22:14:30 -05:00
|
|
|
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
2013-10-09 13:59:07 -04:00
|
|
|
xtext->fgc = gdk_gc_new_with_values (widget->window, &val,
|
2011-02-23 22:14:30 -05:00
|
|
|
GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
2013-10-09 13:59:07 -04:00
|
|
|
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);
|
2013-10-09 13:59:07 -04:00
|
|
|
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 */
|
2013-10-09 13:59:07 -04:00
|
|
|
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
|
|
|
|
2013-10-09 13:59:07 -04: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;
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
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;
|
|
|
|
|
2013-10-09 13:59:07 -04:00
|
|
|
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)
|
2013-10-09 13:59:07 -04:00
|
|
|
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
|
2014-02-02 03:45:51 -05:00
|
|
|
find_x (GtkXText *xtext, textentry *ent, int x, int subline, int indent)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
|
|
|
int xx = indent;
|
2014-02-02 03:45:51 -05:00
|
|
|
int suboff;
|
|
|
|
GSList *list;
|
2014-05-19 01:23:19 -04:00
|
|
|
GSList *hid = NULL;
|
2014-02-02 03:45:51 -05:00
|
|
|
offlen_t *meta;
|
|
|
|
int off, len, wid, mbl, mbw;
|
2011-02-23 22:14:30 -05:00
|
|
|
|
2014-02-02 03:45:51 -05:00
|
|
|
/* Skip to the first chunk of stuff for the subline */
|
|
|
|
if (subline > 0)
|
2011-02-23 22:14:30 -05:00
|
|
|
{
|
2014-02-02 03:45:51 -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
|
|
|
{
|
2014-02-02 03:45:51 -05:00
|
|
|
meta = list->data;
|
|
|
|
if (meta->off + meta->len > suboff)
|
2011-02-23 22:14:30 -05:00
|
|
|
break;
|
|
|
|
}
|
2014-02-02 03:45:51 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
suboff = 0;
|
|
|
|
list = ent->slp;
|
|
|
|
}
|
|
|
|
/* Step to the first character of the subline */
|
2015-08-19 18:23:17 -04:00
|
|
|
if (list == NULL)
|
|
|
|
return 0;
|
2014-02-02 03:45:51 -05:00
|
|
|
meta = list->data;
|
|
|
|
off = meta->off;
|
|
|
|
len = meta->len;
|
2014-05-19 01:23:19 -04:00
|
|
|
if (meta->emph & EMPH_HIDDEN)
|
|
|
|
hid = list;
|
2014-02-02 03:45:51 -05:00
|
|
|
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)
|
|
|
|
{
|
2014-05-19 01:23:19 -04:00
|
|
|
if (meta->emph & EMPH_HIDDEN)
|
|
|
|
hid = list;
|
2014-02-02 03:45:51 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-05-19 01:23:19 -04:00 |