2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
16 * =========================================================================
18 * xtext, the text widget used by X-Chat.
20 * By Peter Zelezny <zed@linux.com>.
21 * Some functions used from Zvt and Eterm (transparency stuff).
25 #define USE_XLIB /* turn this ON for non-xchat use. */
26 #undef XCHAT /* using xchat */
27 #define REFRESH_TIMEOUT 20
28 #define WORDWRAP_LIMIT 24
29 #define TINT_VALUE 195 /* 195/255 of the brightness. */
30 #define MOTION_MONITOR 1 /* URL hilights. */
31 #define MARGIN 2 /* dont touch. */
33 #include <config.h> /* can define USE_XLIB here */
39 #include <gtk/gtkmain.h>
40 #include <gtk/gtksignal.h>
41 #include <gtk/gtkselection.h>
46 #include <X11/Xatom.h>
52 #include <gdk-pixbuf/gdk-pixbuf.h>
56 #define GTK_WIDGET(n) ((GtkWidget*)n)
58 #define GTK_OBJECT(n) ((GtkObject*)n)
59 #undef GTK_OBJECT_CLASS
60 #define GTK_OBJECT_CLASS(n) ((GtkObjectClass*)n)
62 static GtkWidgetClass *parent_class = NULL;
69 static guint xtext_signals[LAST_SIGNAL] = { 0 };
72 char *nocasestrstr (char *text, char *tofind); /* util.c */
74 static void gtk_xtext_render_page (GtkXText * xtext);
75 static void gtk_xtext_calc_lines (GtkXText * xtext, int);
77 static void gtk_xtext_load_trans (GtkXText * xtext);
78 static void gtk_xtext_free_trans (GtkXText * xtext);
80 static textentry *gtk_xtext_nth (GtkXText * xtext, textentry * start_ent,
81 int line, int width, int *subline);
82 static gint gtk_xtext_selection_kill (GtkWidget * widget,
83 GdkEventSelection * event);
84 static void gtk_xtext_selection_get (GtkWidget * widget,
85 GtkSelectionData * selection_data_ptr,
86 guint info, guint time);
87 static int gtk_xtext_text_width (GtkXText * xtext, unsigned char *text,
89 static void gtk_xtext_adjustment_changed (GtkAdjustment * adj,
91 static void gtk_xtext_draw_sep (GtkXText * xtext, int height);
92 static void gtk_xtext_render_ents (GtkXText * xtext, textentry *, textentry *,
94 static void gtk_xtext_recalc_widths (GtkXText * xtext, int);
95 static void gtk_xtext_fix_indent (GtkXText * xtext);
97 /* some utility functions first */
99 #ifndef XCHAT /* xchat has this in util.c */
102 nocasestrstr (char *s, char *wanted)
104 register const size_t len = strlen (wanted);
108 while (toupper(*s) != toupper(*wanted) || strncasecmp (s, wanted, len))
136 xtext_set_fg (GdkGC *gc, gulong pixel)
141 gdk_gc_set_foreground (gc, &col);
145 xtext_set_bg (GdkGC *gc, gulong pixel)
150 gdk_gc_set_background (gc, &col);
154 gtk_xtext_init (GtkXText * xtext)
156 xtext->old_value = -1;
157 xtext->pixmap = NULL;
158 xtext->text_first = NULL;
159 xtext->text_last = NULL;
161 xtext->add_io_tag = -1;
162 xtext->scroll_tag = -1;
163 /* xtext->frozen = 0;*/
164 xtext->num_lines = 0;
165 xtext->max_lines = 0;
166 xtext->col_back = 19;
167 xtext->col_fore = 18;
169 xtext->scrollbar_down = TRUE;
171 xtext->underline = FALSE;
172 xtext->reverse = FALSE;
173 xtext->time_stamp = FALSE;
175 xtext->error_function = NULL;
176 xtext->urlcheck_function = NULL;
177 xtext->color_paste = FALSE;
178 xtext->skip_fills = FALSE;
179 xtext->skip_border_fills = FALSE;
180 xtext->do_underline_fills_only = FALSE;
181 xtext->tint_red = xtext->tint_green = xtext->tint_blue = TINT_VALUE;
183 xtext->adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 0, 1, 0, 0);
184 gtk_object_ref ((GtkObject *) xtext->adj);
185 gtk_object_sink ((GtkObject *) xtext->adj);
187 gtk_signal_connect (GTK_OBJECT (xtext->adj), "value_changed",
188 GTK_SIGNAL_FUNC (gtk_xtext_adjustment_changed), xtext);
189 gtk_signal_connect (GTK_OBJECT (xtext), "selection_clear_event",
190 GTK_SIGNAL_FUNC (gtk_xtext_selection_kill), xtext);
191 gtk_selection_add_target (GTK_WIDGET (xtext),
192 GDK_SELECTION_PRIMARY,
193 GDK_SELECTION_TYPE_STRING, 1);
194 gtk_signal_connect (GTK_OBJECT (xtext), "selection_get",
195 GTK_SIGNAL_FUNC (gtk_xtext_selection_get), xtext);
199 gtk_xtext_adjustment_set (GtkXText * xtext, int fire_signal)
201 GtkAdjustment *adj = xtext->adj;
204 adj->upper = xtext->num_lines;
207 (GTK_WIDGET (xtext)->allocation.height -
208 xtext->font->descent) / xtext->fontsize;
209 adj->page_increment = adj->page_size;
211 if (adj->value > adj->upper - adj->page_size)
212 adj->value = adj->upper - adj->page_size;
215 gtk_adjustment_changed (adj);
219 gtk_xtext_adjustment_timeout (GtkXText * xtext)
221 gtk_xtext_render_page (xtext);
227 gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext)
229 /* if (xtext->frozen)
232 if ((int) xtext->old_value != (int) xtext->adj->value)
234 if (xtext->adj->value >= xtext->adj->upper - xtext->adj->page_size)
235 xtext->scrollbar_down = TRUE;
237 xtext->scrollbar_down = FALSE;
239 if (xtext->adj->value + 1 == xtext->old_value ||
240 xtext->adj->value - 1 == xtext->old_value) /* clicked an arrow? */
242 if (xtext->io_tag != -1)
244 gtk_timeout_remove (xtext->io_tag);
247 gtk_xtext_render_page (xtext);
250 if (xtext->io_tag == -1)
251 xtext->io_tag = gtk_timeout_add (REFRESH_TIMEOUT,
253 gtk_xtext_adjustment_timeout,
257 xtext->old_value = adj->value;
261 gtk_xtext_new (int indent, int separator)
265 xtext = gtk_type_new (gtk_xtext_get_type ());
266 xtext->indent = indent;
267 xtext->separator = separator;
268 xtext->wordwrap = FALSE;
269 xtext->double_buffer = FALSE;
271 return GTK_WIDGET (xtext);
275 gtk_xtext_destroy (GtkObject * object)
277 GtkXText *xtext = GTK_XTEXT (object);
278 textentry *ent, *next;
280 if (xtext->add_io_tag != -1)
282 gtk_timeout_remove (xtext->add_io_tag);
283 xtext->add_io_tag = -1;
286 if (xtext->scroll_tag != -1)
288 gtk_timeout_remove (xtext->scroll_tag);
289 xtext->scroll_tag = -1;
292 if (xtext->io_tag != -1)
294 gtk_timeout_remove (xtext->io_tag);
301 if (xtext->transparent)
302 gtk_xtext_free_trans (xtext);
305 gdk_pixmap_unref (xtext->pixmap);
306 xtext->pixmap = NULL;
311 gdk_font_unref (xtext->font);
317 gtk_signal_disconnect_by_data (GTK_OBJECT (xtext->adj), xtext);
318 gtk_object_unref (GTK_OBJECT (xtext->adj));
324 gdk_gc_destroy (xtext->bgc);
330 gdk_gc_destroy (xtext->fgc);
336 gdk_gc_destroy (xtext->light_gc);
337 xtext->light_gc = NULL;
342 gdk_gc_destroy (xtext->dark_gc);
343 xtext->dark_gc = NULL;
346 if (xtext->hand_cursor)
348 gdk_cursor_destroy (xtext->hand_cursor);
349 xtext->hand_cursor = NULL;
352 ent = xtext->text_first;
359 xtext->text_first = NULL;
361 if (GTK_OBJECT_CLASS (parent_class)->destroy)
362 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
366 gtk_xtext_realize (GtkWidget * widget)
369 GdkWindowAttr attributes;
374 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
375 xtext = GTK_XTEXT (widget);
377 attributes.x = widget->allocation.x;
378 attributes.y = widget->allocation.y;
379 attributes.width = widget->allocation.width;
380 attributes.height = widget->allocation.height;
381 attributes.wclass = GDK_INPUT_OUTPUT;
382 attributes.window_type = GDK_WINDOW_CHILD;
383 attributes.event_mask = gtk_widget_get_events (widget) |
384 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
385 #ifdef MOTION_MONITOR
386 | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK;
388 | GDK_POINTER_MOTION_MASK;
391 cmap = gtk_widget_get_colormap (widget);
392 attributes.colormap = cmap;
393 attributes.visual = gtk_widget_get_visual (widget);
395 widget->window = gdk_window_new (widget->parent->window, &attributes,
396 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
399 gdk_window_set_user_data (widget->window, widget);
401 xtext->depth = gdk_window_get_visual (widget->window)->depth;
403 val.subwindow_mode = GDK_INCLUDE_INFERIORS;
404 val.graphics_exposures = 0;
406 xtext->bgc = gdk_gc_new_with_values (widget->window, &val,
407 GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
408 xtext->fgc = gdk_gc_new_with_values (widget->window, &val,
409 GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
410 xtext->light_gc = gdk_gc_new_with_values (widget->window, &val,
411 GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
412 xtext->dark_gc = gdk_gc_new_with_values (widget->window, &val,
413 GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
415 /* for the separator bar (light) */
416 col.red = 0xffff; col.green = 0xffff; col.blue = 0xffff;
417 /* is setting the pixel necessary (or even correct) ?? */
418 col.pixel = (gulong)((col.red & 0xff00) * 256 +
419 (col.green & 0xff00) +
420 (col.blue & 0xff00) / 256);
421 gdk_color_alloc (cmap, &col);
422 gdk_gc_set_foreground (xtext->light_gc, &col);
424 /* for the separator bar (dark) */
425 col.red = 0x8e38; col.green = 0x8e38; col.blue = 0x9f38;
426 col.pixel = (gulong)((col.red & 0xff00) * 256 +
427 (col.green & 0xff00) +
428 (col.blue & 0xff00) / 256);
429 gdk_color_alloc (cmap, &col);
430 gdk_gc_set_foreground (xtext->dark_gc, &col);
432 if (xtext->fonttype != FONT_SET && xtext->font != NULL)
433 gdk_gc_set_font (xtext->fgc, xtext->font);
435 xtext_set_fg (xtext->fgc, xtext->palette[18]);
436 xtext_set_bg (xtext->fgc, xtext->palette[19]);
437 xtext_set_fg (xtext->bgc, xtext->palette[19]);
440 if (xtext->transparent)
442 gtk_xtext_load_trans (xtext);
443 } else if (xtext->pixmap)
445 gdk_gc_set_tile (xtext->bgc, xtext->pixmap);
446 gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
447 gdk_gc_set_fill (xtext->bgc, GDK_TILED);
452 gdk_gc_set_tile (xtext->bgc, xtext->pixmap);
453 gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
454 gdk_gc_set_fill (xtext->bgc, GDK_TILED);
458 xtext->hand_cursor = gdk_cursor_new (GDK_HAND1);
460 gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
462 /* if not doublebuffer, draw directly to window */
463 if (!xtext->double_buffer)
464 xtext->draw_buf = widget->window;
466 if (xtext->auto_indent)
471 gtk_xtext_size_request (GtkWidget * widget, GtkRequisition * requisition)
473 requisition->width = GTK_XTEXT (widget)->fontwidth['Z'] * 20;
474 requisition->height = (GTK_XTEXT (widget)->fontsize * 10) + 3;
478 gtk_xtext_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
480 GtkXText *xtext = GTK_XTEXT (widget);
482 if (allocation->width == widget->allocation.width &&
483 allocation->height == widget->allocation.height &&
484 allocation->x == widget->allocation.x &&
485 allocation->y == widget->allocation.y)
488 widget->allocation = *allocation;
489 if (GTK_WIDGET_REALIZED (widget))
491 gdk_window_move_resize (widget->window,
492 allocation->x, allocation->y,
493 allocation->width, allocation->height);
494 gtk_xtext_calc_lines (xtext, FALSE);
499 gtk_xtext_draw (GtkWidget * widget, GdkRectangle * area)
502 GtkXText *xtext = GTK_XTEXT (widget);
505 if (xtext->transparent)
507 gdk_window_get_origin (widget->window, &x, &y);
508 /* update transparency only if it moved */
509 if (xtext->last_win_x != x || xtext->last_win_y != y)
511 xtext->last_win_x = x;
512 xtext->last_win_y = y;
513 gtk_xtext_free_trans (xtext);
514 gtk_xtext_load_trans (xtext);
519 if (xtext->scrollbar_down)
520 gtk_adjustment_set_value (xtext->adj,
521 xtext->adj->upper - xtext->adj->page_size);
522 gtk_xtext_render_page (xtext);
526 gtk_xtext_selection_clear (GtkXText * xtext)
531 ent = xtext->last_ent_start;
534 if (ent->mark_start != -1)
536 ent->mark_start = -1;
538 if (ent == xtext->last_ent_end)
547 find_x_8bit (GtkXText *xtext, textentry *ent, char *text, int x, int indent)
558 if ((col && isdigit (*text) && nc < 2) ||
559 (col && *text == ',' && nc < 3))
580 a = *((unsigned char *)text);
581 xx += xtext->fontwidth[a];
583 return i + (orig - ent->str);
588 if (text - orig >= ent->str_len)
596 find_x_general (GtkXText * xtext, textentry * ent, char *str, int x, int indent)
603 str_width = gtk_xtext_text_width (xtext, str, len);
604 if (str_width + indent >= x)
605 return (str + len) - ent->str;
607 if (len + (str - ent->str) > ent->str_len)
609 if (str_width + indent + 40 < x)
615 find_x (GtkXText * xtext, textentry * ent, char *str, int x, int indent)
617 if (xtext->fonttype == FONT_1BYTE)
618 return find_x_8bit (xtext, ent, str, x, indent);
620 return find_x_general (xtext, ent, str, x, indent);
624 gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int offset,
625 int line, int win_width, int *out_of_bounds)
631 indent = ent->indent;
633 indent = xtext->indent;
635 if (line > xtext->adj->page_size || line < 0)
638 if (xtext->grid_offset[line] > ent->str_len)
641 if (xtext->grid_offset[line] < 0)
644 str = ent->str + xtext->grid_offset[line];
649 return (str - ent->str);
654 return find_x (xtext, ent, str, x, indent);
658 gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off,
666 gdk_window_get_size (GTK_WIDGET (xtext)->window, &win_width, 0);
669 line = (y - xtext->font->descent) / xtext->fontsize;
671 subline = xtext->pagetop_subline;
672 ent = gtk_xtext_nth (xtext, xtext->pagetop_ent, line, win_width, &subline);
677 *off = gtk_xtext_find_x (xtext, x, ent, subline, line, win_width,
684 gtk_xtext_expose (GtkWidget * widget, GdkEventExpose * event)
686 GtkXText *xtext = GTK_XTEXT (widget);
687 textentry *ent_start, *ent_end;
689 if (xtext->double_buffer)
691 gtk_xtext_render_page (xtext);
695 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1,
696 event->area.x, event->area.y,
697 event->area.width, event->area.height);
699 ent_start = gtk_xtext_find_char (xtext, event->area.x, event->area.y,
701 ent_end = gtk_xtext_find_char (xtext, event->area.x + event->area.width,
702 event->area.y + event->area.height, NULL, NULL);
704 xtext->skip_fills = TRUE;
705 xtext->skip_border_fills = TRUE;
707 gtk_xtext_render_ents (xtext, ent_start, ent_end, TRUE);
709 xtext->skip_fills = FALSE;
710 xtext->skip_border_fills = FALSE;
716 gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event)
720 textentry *ent_start;
729 if (xtext->select_start_y > xtext->select_end_y)
731 low_x = xtext->select_end_x;
732 low_y = xtext->select_end_y;
733 high_x = xtext->select_start_x;
734 high_y = xtext->select_start_y;
737 low_x = xtext->select_start_x;
738 low_y = xtext->select_start_y;
739 high_x = xtext->select_end_x;
740 high_y = xtext->select_end_y;
743 ent_start = gtk_xtext_find_char (xtext, low_x, low_y, &offset_start, &tmp);
744 ent_end = gtk_xtext_find_char (xtext, high_x, high_y, &offset_end, &tmp);
746 if (ent_start && !ent_end)
748 ent_end = xtext->text_last;
749 offset_end = ent_end->str_len;
752 if (!ent_start || !ent_end)
754 if (xtext->adj->value != xtext->old_value)
755 gtk_xtext_render_page (xtext);
759 gtk_xtext_selection_clear (xtext);
761 /* marking less than a complete line? */
762 if (ent_start == ent_end)
764 ent_start->mark_start = MIN (offset_start, offset_end);
765 ent_start->mark_end = MAX (offset_end, offset_start);
766 if (offset_start == offset_end)
767 ent_start->mark_end++;
770 ent_start->mark_start = offset_start;
771 ent_start->mark_end = ent_start->str_len;
775 ent_end->mark_start = 0;
776 ent_end->mark_end = offset_end;
780 if (ent_start != ent_end)
782 ent = ent_start->next;
783 while (ent && ent != ent_end)
786 ent->mark_end = ent->str_len;
791 /* has the selection changed? Dont render unless necessary */
792 if (xtext->last_ent_start == ent_start &&
793 xtext->last_ent_end == ent_end &&
794 xtext->last_offset_start == offset_start &&
795 xtext->last_offset_end == offset_end)
798 gtk_selection_owner_set (GTK_WIDGET (xtext), GDK_SELECTION_PRIMARY,
801 if (xtext->double_buffer)
803 if (xtext->io_tag == -1)
804 xtext->io_tag = gtk_timeout_add (REFRESH_TIMEOUT,
806 gtk_xtext_adjustment_timeout,
810 ent = xtext->last_ent_end;
812 if (ent->next == ent_end)
814 xtext->skip_border_fills = TRUE;
815 gtk_xtext_render_ents (xtext, xtext->last_ent_start, ent, TRUE);
816 xtext->skip_border_fills = FALSE;
817 xtext->old_ent_start = xtext->last_ent_start;
818 xtext->old_ent_end = xtext->last_ent_end;
821 xtext->last_ent_start = ent_start;
822 xtext->last_ent_end = ent_end;
823 xtext->last_offset_start = offset_start;
824 xtext->last_offset_end = offset_end;
828 gtk_xtext_scrolldown_timeout (GtkXText * xtext)
832 gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0);
833 gdk_window_get_size (GTK_WIDGET (xtext)->window, 0, &win_height);
835 if (p_y > win_height &&
836 xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size))
839 gtk_adjustment_changed (xtext->adj);
840 gtk_xtext_render_page (xtext);
844 xtext->scroll_tag = -1;
849 gtk_xtext_scrollup_timeout (GtkXText * xtext)
853 gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0);
855 if (p_y < 0 && xtext->adj->value > 0.0)
858 gtk_adjustment_changed (xtext->adj);
859 gtk_xtext_render_page (xtext);
863 xtext->scroll_tag = -1;
868 gtk_xtext_selection_update (GtkXText * xtext, GdkEventMotion * event, int p_y)
873 gdk_window_get_size (GTK_WIDGET (xtext)->window, 0, &win_height);
875 /* selecting past top of window, scroll up! */
876 if (p_y < 0 && xtext->adj->value >= 0)
878 if (xtext->scroll_tag == -1)
879 xtext->scroll_tag = gtk_timeout_add (100,
881 gtk_xtext_scrollup_timeout,
886 /* selecting past bottom of window, scroll down! */
887 if (p_y > win_height &&
888 xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size))
890 if (xtext->scroll_tag == -1)
891 xtext->scroll_tag = gtk_timeout_add (100,
893 gtk_xtext_scrolldown_timeout,
898 moved = xtext->adj->value - xtext->select_start_adj;
899 xtext->select_start_y -= (moved * xtext->fontsize);
900 xtext->select_start_adj = xtext->adj->value;
901 gtk_xtext_selection_draw (xtext, event);
905 gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent,
906 int *ret_off, int *ret_len)
915 ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds);
922 if (offset == ent->str_len)
930 str = ent->str + offset;
932 while (!is_del (*str) && str != ent->str)
938 while (!is_del (*str) && len != ent->str_len)
947 *ret_off = word - ent->str;
949 *ret_len = str - word;
951 word = gtk_xtext_strip_color (word, len, NULL, NULL);
957 gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event)
959 #ifdef MOTION_MONITOR
960 GtkXText *xtext = GTK_XTEXT (widget);
962 if (xtext->cursor_hand)
964 xtext->hilight_start = -1;
965 xtext->hilight_end = -1;
966 xtext->cursor_hand = FALSE;
967 gdk_window_set_cursor (widget->window, 0);
968 xtext->skip_border_fills = TRUE;
969 xtext->do_underline_fills_only = TRUE;
970 gtk_xtext_render_ents (xtext, xtext->hilight_ent, NULL, FALSE);
971 xtext->skip_border_fills = FALSE;
972 xtext->do_underline_fills_only = FALSE;
973 xtext->hilight_ent = NULL;
980 gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
982 GtkXText *xtext = GTK_XTEXT (widget);
983 int tmp, x, y, offset, len;
985 textentry *word_ent, *old_ent;
987 gdk_window_get_pointer (widget->window, &x, &y, 0);
989 if (xtext->moving_separator)
991 if (x < (3 * widget->allocation.width) / 5 && x > 15)
995 gtk_xtext_fix_indent (xtext);
996 if (tmp != xtext->indent)
998 gtk_xtext_recalc_widths (xtext, FALSE);
999 if (xtext->scrollbar_down)
1000 gtk_adjustment_set_value (xtext->adj, xtext->adj->upper -
1001 xtext->adj->page_size);
1002 if (xtext->io_tag == -1)
1003 xtext->io_tag = gtk_timeout_add (REFRESH_TIMEOUT,
1005 gtk_xtext_adjustment_timeout,
1012 if (xtext->button_down)
1014 gtk_grab_add (widget);
1015 /*gdk_pointer_grab (widget->window, TRUE,
1016 GDK_BUTTON_RELEASE_MASK |
1017 GDK_BUTTON_MOTION_MASK, NULL, NULL, 0);*/
1018 xtext->select_end_x = x;
1019 xtext->select_end_y = y;
1020 gtk_xtext_selection_update (xtext, event, y);
1023 #ifdef MOTION_MONITOR
1025 if (xtext->urlcheck_function == NULL)
1028 word = gtk_xtext_get_word (xtext, x, y, &word_ent, &offset, &len);
1031 if (xtext->urlcheck_function (xtext, word) > 0)
1034 if (!xtext->cursor_hand ||
1035 xtext->hilight_ent != word_ent ||
1036 xtext->hilight_start != offset ||
1037 xtext->hilight_end != offset + len)
1039 if (!xtext->cursor_hand)
1041 gdk_window_set_cursor (GTK_WIDGET (xtext)->window,
1042 xtext->hand_cursor);
1043 xtext->cursor_hand = TRUE;
1045 old_ent = xtext->hilight_ent;
1046 xtext->hilight_ent = word_ent;
1047 xtext->hilight_start = offset;
1048 xtext->hilight_end = offset + len;
1049 xtext->skip_border_fills = TRUE;
1050 xtext->do_underline_fills_only = TRUE;
1051 gtk_xtext_render_ents (xtext, old_ent, word_ent, FALSE);
1052 xtext->skip_border_fills = FALSE;
1053 xtext->do_underline_fills_only = FALSE;
1060 gtk_xtext_leave_notify (widget, NULL);
1068 gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event)
1070 GtkXText *xtext = GTK_XTEXT (widget);
1073 if (xtext->moving_separator)
1075 xtext->moving_separator = FALSE;
1076 if (event->x < (4 * widget->allocation.width) / 5 && event->x > 15)
1078 xtext->indent = event->x;
1080 gtk_xtext_fix_indent (xtext);
1081 gtk_xtext_recalc_widths (xtext, FALSE);
1082 gtk_xtext_adjustment_set (xtext, TRUE);
1083 gtk_xtext_render_page (xtext);
1087 if (xtext->word_or_line_select)
1089 xtext->word_or_line_select = FALSE;
1090 xtext->button_down = FALSE;
1094 if (event->button == 1)
1096 xtext->button_down = FALSE;
1098 gtk_grab_remove (widget);
1099 /*gdk_pointer_ungrab (0);*/
1101 if (xtext->select_start_x == event->x &&
1102 xtext->select_start_y == event->y)
1104 if (gtk_xtext_selection_clear (xtext))
1105 gtk_xtext_render_page (xtext);
1108 word = gtk_xtext_get_word (xtext, event->x, event->y, 0, 0, 0);
1111 gtk_signal_emit (GTK_OBJECT (xtext), xtext_signals[WORD_CLICK],
1123 gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
1125 GtkXText *xtext = GTK_XTEXT (widget);
1128 int line_x, x, y, offset, len;
1131 gdk_window_get_pointer (widget->window, &x, &y, 0);
1133 if (event->button == 3) /* right click */
1135 word = gtk_xtext_get_word (xtext, x, y, 0, 0, 0);
1138 gtk_signal_emit (GTK_OBJECT (xtext), xtext_signals[WORD_CLICK],
1142 gtk_signal_emit (GTK_OBJECT (xtext), xtext_signals[WORD_CLICK],
1147 if (event->button == 4) /* mouse wheel pageUp */
1149 new_value = xtext->adj->value - xtext->adj->page_increment;
1150 if (new_value < xtext->adj->lower)
1151 new_value = xtext->adj->lower;
1152 gtk_adjustment_set_value (xtext->adj, new_value);
1156 if (event->button == 5) /* mouse wheel pageDn */
1158 new_value = xtext->adj->value + xtext->adj->page_increment;
1159 if (new_value > (xtext->adj->upper - xtext->adj->page_size))
1160 new_value = xtext->adj->upper - xtext->adj->page_size;
1161 gtk_adjustment_set_value (xtext->adj, new_value);
1165 if (event->button == 2)
1167 gtk_signal_emit (GTK_OBJECT (xtext), xtext_signals[WORD_CLICK], "", event);
1171 if (event->button != 1) /* we only want left button */
1174 if (event->type == GDK_2BUTTON_PRESS) /* WORD select */
1176 word = gtk_xtext_get_word (xtext, x, y, &ent, &offset, &len);
1182 gtk_xtext_selection_clear (xtext);
1183 ent->mark_start = offset;
1184 ent->mark_end = offset + len;
1185 xtext->last_ent_start = ent;
1186 xtext->last_ent_end = ent;
1187 gtk_xtext_render_page (xtext);
1188 xtext->word_or_line_select = TRUE;
1189 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time);
1195 if (event->type == GDK_3BUTTON_PRESS) /* LINE select */
1197 word = gtk_xtext_get_word (xtext, x, y, &ent, 0, 0);
1201 gtk_xtext_selection_clear (xtext);
1202 ent->mark_start = 0;
1203 ent->mark_end = ent->str_len;
1204 xtext->last_ent_start = ent;
1205 xtext->last_ent_end = ent;
1206 gtk_xtext_render_page (xtext);
1207 xtext->word_or_line_select = TRUE;
1208 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time);
1214 /* check if it was a separator-bar click */
1215 if (xtext->separator && xtext->indent)
1217 line_x = xtext->indent - ((xtext->space_width + 1) / 2);
1218 if (line_x == x || line_x == x + 1 || line_x == x - 1)
1220 xtext->moving_separator = TRUE;
1221 gtk_xtext_render_page (xtext);
1226 xtext->button_down = TRUE;
1228 xtext->select_start_x = x;
1229 xtext->select_start_y = y;
1231 xtext->select_start_adj = xtext->adj->value;
1236 /* another program has claimed the selection */
1239 gtk_xtext_selection_kill (GtkWidget * widget, GdkEventSelection * event)
1241 if (gtk_xtext_selection_clear (GTK_XTEXT (widget)))
1242 gtk_xtext_render_page (GTK_XTEXT (widget));
1246 /* another program is asking for our selection */
1249 gtk_xtext_selection_get (GtkWidget * widget,
1250 GtkSelectionData * selection_data_ptr,
1251 guint info, guint time)
1253 GtkXText *xtext = GTK_XTEXT (widget);
1261 /* first find out how much we need to malloc ... */
1263 ent = xtext->text_first;
1266 if (ent->mark_start != -1)
1268 if (ent->mark_end - ent->mark_start > 0)
1269 len += (ent->mark_end - ent->mark_start) + 1;
1276 /* now allocate mem and copy buffer */
1277 pos = txt = malloc (len);
1278 ent = xtext->text_first;
1281 if (ent->mark_start != -1)
1289 if (ent->mark_end - ent->mark_start > 0)
1291 memcpy (pos, ent->str + ent->mark_start,
1292 ent->mark_end - ent->mark_start);
1293 pos += ent->mark_end - ent->mark_start;
1300 if (xtext->color_paste)
1302 gtk_selection_data_set (selection_data_ptr, GDK_SELECTION_TYPE_STRING,
1303 8, txt, strlen (txt));
1306 stripped = gtk_xtext_strip_color (txt, strlen (txt), NULL, NULL);
1307 gtk_selection_data_set (selection_data_ptr, GDK_SELECTION_TYPE_STRING,
1308 8, stripped, strlen (stripped));
1316 gtk_xtext_class_init (GtkXTextClass * class)
1318 GtkObjectClass *object_class;
1319 GtkWidgetClass *widget_class;
1320 GtkXTextClass *xtext_class;
1322 object_class = (GtkObjectClass *) class;
1323 widget_class = (GtkWidgetClass *) class;
1324 xtext_class = (GtkXTextClass *) class;
1326 parent_class = gtk_type_class (gtk_widget_get_type ());
1328 xtext_signals[WORD_CLICK] =
1329 gtk_signal_new (/*name*/"word_click",
1330 /*GtkSignalRunType*/GTK_RUN_FIRST,
1331 /*GtkType*/object_class->type,
1332 /*funcoffset*/GTK_SIGNAL_OFFSET (GtkXTextClass, word_click),
1333 /*GtkSignalMarshaller*/gtk_marshal_NONE__POINTER_POINTER,
1334 /*returnval*/GTK_TYPE_NONE,
1335 /*num args*/2, /*args*/GTK_TYPE_POINTER, GTK_TYPE_POINTER);
1336 gtk_object_class_add_signals (object_class, xtext_signals, LAST_SIGNAL);
1338 object_class->destroy = gtk_xtext_destroy;
1340 widget_class->realize = gtk_xtext_realize;
1341 widget_class->size_request = gtk_xtext_size_request;
1342 widget_class->size_allocate = gtk_xtext_size_allocate;
1343 widget_class->button_press_event = gtk_xtext_button_press;
1344 widget_class->button_release_event = gtk_xtext_button_release;
1345 widget_class->motion_notify_event = gtk_xtext_motion_notify;
1346 widget_class->leave_notify_event = gtk_xtext_leave_notify;
1347 widget_class->draw = gtk_xtext_draw;
1348 widget_class->expose_event = gtk_xtext_expose;
1350 xtext_class->word_click = NULL;
1353 guint gtk_xtext_get_type ()
1355 static guint xtext_type = 0;
1359 GtkTypeInfo xtext_info = {
1362 sizeof (GtkXTextClass),
1363 (GtkClassInitFunc) gtk_xtext_class_init,
1364 (GtkObjectInitFunc) gtk_xtext_init,
1365 (GtkArgSetFunc) NULL,
1366 (GtkArgGetFunc) NULL,
1369 xtext_type = gtk_type_unique (gtk_widget_get_type (), &xtext_info);
1376 gtk_xtext_thaw (GtkXText *xtext)
1378 if (xtext->frozen > 0)
1381 if (xtext->frozen == 0)
1382 gtk_xtext_render_page (xtext);
1386 gtk_xtext_freeze (GtkXText *xtext)
1391 /* strip MIRC colors and other attribs. */
1394 gtk_xtext_strip_color (unsigned char *text, int len, char *outbuf, int *newlen)
1402 new_str = malloc (len + 2);
1408 if ((col && isdigit (*text) && nc < 2) ||
1409 (col && *text == ',' && nc < 3))
1428 case ATTR_UNDERLINE:
1447 /* gives width of a 8bit string - with no mIRC codes in it */
1450 gtk_xtext_text_width_simple (GtkXText * xtext, unsigned char *str, int len)
1454 if (xtext->fixed_width_font)
1455 return (xtext->space_width * len);
1459 width += xtext->fontwidth[*str];
1467 /* gives width of a string, excluding the mIRC codes */
1470 gtk_xtext_text_width (GtkXText * xtext, unsigned char *text, int len)
1472 unsigned char *tmp, *new_buf;
1475 new_buf = gtk_xtext_strip_color (text, len, xtext->scratch_buffer, &new_len);
1477 if (xtext->fonttype == FONT_1BYTE)
1479 if (xtext->fixed_width_font)
1481 width = xtext->space_width * new_len;
1488 width += xtext->fontwidth[*tmp];
1494 width = gdk_text_width (xtext->font, new_buf, new_len);
1500 /* actually draw text to screen */
1503 gtk_xtext_render_flush (GtkXText * xtext, int x, int y, char *str, int len,
1515 if (xtext->dont_render)
1518 if (xtext->fonttype == FONT_1BYTE)
1519 str_width = gtk_xtext_text_width_simple (xtext, str, len);
1521 str_width = gdk_text_width (xtext->font, str, len);
1526 if (!xtext->backcolor && xtext->pixmap)
1529 /* draw the background pixmap behind the text - CAUSES FLICKER HERE !! */
1530 if (!xtext->double_buffer && !xtext->skip_fills)
1532 if (xtext->do_underline_fills_only)
1534 gdk_draw_rectangle (GTK_WIDGET (xtext)->window, xtext->bgc, 1,
1535 x, y + 1, str_width, 1);
1536 if (xtext->underline) /* optimization */
1540 gdk_draw_rectangle (GTK_WIDGET (xtext)->window, xtext->bgc, 1,
1541 x, y - xtext->font->ascent, str_width,
1548 if (xtext->skip_fills && !xtext->backcolor)
1554 xgc = GDK_GC_XGC (gc);
1555 xdraw_buf = GDK_WINDOW_XWINDOW (xtext->draw_buf);
1556 xdisplay = GDK_WINDOW_XDISPLAY (GTK_WIDGET (xtext)->window);
1557 xfont = GDK_FONT_XFONT (xtext->font);
1559 switch (xtext->fonttype)
1563 XDrawImageString (xdisplay, xdraw_buf, xgc, x, y, str, len);
1565 XDrawString (xdisplay, xdraw_buf, xgc, x, y, str, len);
1567 XDrawString (xdisplay, xdraw_buf, xgc, x + 1, y, str, len);
1573 XDrawImageString16 (xdisplay, xdraw_buf,
1574 xgc, x, y, (XChar2b *) str, len);
1576 XDrawString16 (xdisplay, xdraw_buf,
1577 xgc, x, y, (XChar2b *) str, len);
1579 XDrawString16 (xdisplay, xdraw_buf,
1580 xgc, x + 1, y, (XChar2b *) str, len);
1585 XmbDrawImageString (xdisplay, xdraw_buf,
1586 (XFontSet) xfont, xgc, x, y, str, len);
1588 XmbDrawString (xdisplay, xdraw_buf,
1589 (XFontSet) xfont, xgc, x, y, str, len);
1591 XmbDrawString (xdisplay, xdraw_buf,
1592 (XFontSet) xfont, xgc, x + 1, y, str, len);
1597 /* don't have Xlib, gdk version --- */
1601 gdk_gc_get_values (gc, &val);
1602 xtext_set_fg (gc, val.background.pixel);
1603 gdk_draw_rectangle (xtext->draw_buf, gc, 1,
1604 x, y - xtext->font->ascent, str_width,
1606 xtext_set_fg (gc, val.foreground.pixel);
1608 gdk_draw_text (xtext->draw_buf, xtext->font, gc, x, y, str, len);
1610 gdk_draw_text (xtext->draw_buf, xtext->font, gc, x + 1, y, str, len);
1614 if (xtext->underline)
1616 gdk_draw_line (xtext->draw_buf, gc, x, y+1, x+str_width-1, y+1);
1622 gtk_xtext_reset (GtkXText * xtext, int mark, int attribs)
1626 xtext->underline = FALSE;
1627 xtext->bold = FALSE;
1631 xtext->backcolor = FALSE;
1632 if (xtext->col_fore != 18)
1633 xtext_set_fg (xtext->fgc, xtext->palette[18]);
1634 if (xtext->col_back != 19)
1635 xtext_set_bg (xtext->fgc, xtext->palette[19]);
1637 xtext->col_fore = 18;
1638 xtext->col_back = 19;
1641 /* render a single line, which WONT wrap, and parse mIRC colors */
1644 gtk_xtext_render_str (GtkXText * xtext, int y, textentry * ent, char *str,
1645 int len, int win_width, int indent, int line)
1648 int i = 0, x = indent, j = 0;
1653 int hilight = FALSE;
1655 offset = str - ent->str;
1657 if (line < 255 && line >= 0)
1658 xtext->grid_offset[line] = offset;
1660 gc = xtext->fgc; /* our foreground GC */
1662 if (ent->mark_start != -1 &&
1663 ent->mark_start <= i + offset && ent->mark_end > i + offset)
1665 xtext_set_bg (gc, xtext->palette[16]);
1666 xtext_set_fg (gc, xtext->palette[17]);
1667 xtext->backcolor = TRUE;
1670 #ifdef MOTION_MONITOR
1671 if (xtext->hilight_ent == ent &&
1672 xtext->hilight_start <= i + offset && xtext->hilight_end > i + offset)
1674 xtext->underline = TRUE;
1675 /* xtext->bold = TRUE;*/
1680 if (!xtext->double_buffer)
1682 /* draw background to the left of the text */
1683 if (str == ent->str && indent && xtext->time_stamp)
1685 /* don't overwrite the timestamp */
1686 if (indent > xtext->stamp_width)
1688 if (!xtext->skip_border_fills)
1689 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1,
1690 xtext->stamp_width, y - xtext->font->ascent,
1691 indent - xtext->stamp_width, xtext->fontsize);
1695 /* fill the indent area with background gc */
1696 if (!xtext->skip_border_fills)
1697 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1,
1698 0, y - xtext->font->ascent, indent, xtext->fontsize);
1705 #ifdef MOTION_MONITOR
1706 if (xtext->hilight_ent == ent && xtext->hilight_start == (i + offset))
1708 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1711 xtext->underline = TRUE;
1712 /* xtext->bold = TRUE;*/
1717 if (!mark && ent->mark_start == (i + offset))
1719 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1722 xtext_set_bg (gc, xtext->palette[16]);
1723 xtext_set_fg (gc, xtext->palette[17]);
1724 xtext->backcolor = TRUE;
1728 if ((xtext->parsing_color && isdigit (str[i]) && xtext->nc < 2) ||
1729 (xtext->parsing_color && str[i] == ',' && xtext->nc < 3))
1734 xtext->parsing_backcolor = TRUE;
1737 xtext->num[xtext->nc] = 0;
1739 col_num = atoi (xtext->num) % 16;
1740 xtext->col_fore = col_num;
1742 xtext_set_fg (gc, xtext->palette[col_num]);
1746 xtext->num[xtext->nc] = str[i];
1752 if (xtext->parsing_color)
1754 xtext->parsing_color = FALSE;
1757 xtext->num[xtext->nc] = 0;
1759 col_num = atoi (xtext->num);
1760 if (col_num == 99) /* mIRC lameness */
1763 col_num = col_num % 16;
1764 if (xtext->parsing_backcolor)
1767 xtext->backcolor = FALSE;
1769 xtext->backcolor = TRUE;
1771 xtext_set_bg (gc, xtext->palette[col_num]);
1772 xtext->col_back = col_num;
1776 xtext_set_fg (gc, xtext->palette[col_num]);
1777 xtext->col_fore = col_num;
1779 xtext->parsing_backcolor = FALSE;
1782 /* got a \003<non-digit>... i.e. reset colors */
1783 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1786 gtk_xtext_reset (xtext, mark, FALSE);
1800 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1803 tmp = xtext->col_fore;
1804 xtext->col_fore = xtext->col_back;
1805 xtext->col_back = tmp;
1808 xtext_set_fg (gc, xtext->palette[xtext->col_fore]);
1809 xtext_set_bg (gc, xtext->palette[xtext->col_back]);
1811 if (xtext->col_back != 19)
1812 xtext->backcolor = TRUE;
1814 xtext->backcolor = FALSE;
1817 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1818 xtext->bold = !xtext->bold;
1822 case ATTR_UNDERLINE:
1823 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1824 xtext->underline = !xtext->underline;
1829 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1832 gtk_xtext_reset (xtext, mark, !hilight);
1835 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1836 xtext->parsing_color = TRUE;
1846 #ifdef MOTION_MONITOR
1847 if (xtext->hilight_ent == ent && xtext->hilight_end == (i + offset))
1849 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1852 xtext->underline = FALSE;
1853 /* xtext->bold = FALSE;*/
1858 if (mark && ent->mark_end == (i + offset))
1860 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1863 xtext_set_bg (gc, xtext->palette[xtext->col_back]);
1864 xtext_set_fg (gc, xtext->palette[xtext->col_fore]);
1865 if (xtext->col_back != 19)
1866 xtext->backcolor = TRUE;
1868 xtext->backcolor = FALSE;
1874 x += gtk_xtext_render_flush (xtext, x, y, pstr, j, gc);
1876 if (!xtext->double_buffer)
1878 /* draw separator now so it doesn't appear to flicker */
1879 gtk_xtext_draw_sep (xtext, y + 1);
1880 /* draw background to the right of the text */
1881 if (!xtext->skip_border_fills)
1882 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1,
1883 x, y - xtext->font->ascent, (win_width + MARGIN) - x,
1890 /* get the desktop/root window - thanks Eterm */
1892 static Window desktop_window = None;
1895 get_desktop_window (Window the_window)
1897 Atom prop, type, prop2;
1899 unsigned long length, after;
1900 unsigned char *data;
1901 unsigned int nchildren;
1902 Window w, root, *children, parent;
1904 prop = XInternAtom (GDK_DISPLAY (), "_XROOTPMAP_ID", True);
1905 prop2 = XInternAtom (GDK_DISPLAY (), "_XROOTCOLOR_PIXEL", True);
1907 if (prop == None && prop2 == None)
1910 for (w = the_window; w; w = parent)
1912 if ((XQueryTree (GDK_DISPLAY (), w, &root, &parent, &children,
1913 &nchildren)) == False)
1921 XGetWindowProperty (GDK_DISPLAY (), w, prop, 0L, 1L, False,
1922 AnyPropertyType, &type, &format, &length, &after,
1926 XGetWindowProperty (GDK_DISPLAY (), w, prop2, 0L, 1L, False,
1927 AnyPropertyType, &type, &format, &length, &after,
1936 return (desktop_window = w);
1940 return (desktop_window = None);
1943 /* stolen from zvt, which was stolen from Eterm */
1946 get_pixmap_prop (Window the_window)
1950 unsigned long length, after;
1951 unsigned char *data;
1954 if (desktop_window == None)
1955 desktop_window = get_desktop_window (the_window);
1956 if (desktop_window == None)
1957 desktop_window = GDK_ROOT_WINDOW ();
1959 prop = XInternAtom (GDK_DISPLAY (), "_XROOTPMAP_ID", True);
1963 XGetWindowProperty (GDK_DISPLAY (), desktop_window, prop, 0L, 1L, False,
1964 AnyPropertyType, &type, &format, &length, &after,
1968 if (type == XA_PIXMAP)
1969 pix = *((Pixmap *) data);
1977 #ifdef USE_GDK_PIXBUF
1980 create_shaded_pixmap (GtkXText * xtext, Pixmap p, int x, int y, int w, int h)
1982 GdkPixmap *pp, *tmp, *shaded_pixmap;
1987 unsigned char *pbuf;
1988 int width, height, depth;
1996 pp = gdk_pixmap_foreign_new (p);
1997 cmap = gtk_widget_get_colormap (GTK_WIDGET (xtext));
1998 gdk_window_get_geometry (pp, NULL, NULL, &width, &height, &depth);
2000 if (width < x + w || height < y + h || x < 0 || y < 0)
2002 tgc = gdk_gc_new (pp);
2003 tmp = gdk_pixmap_new (pp, w, h, depth);
2004 gdk_gc_set_tile (tgc, pp);
2005 gdk_gc_set_fill (tgc, GDK_TILED);
2006 gdk_gc_set_ts_origin (tgc, -x, -y);
2007 gdk_draw_rectangle (tmp, tgc, TRUE, 0, 0, w, h);
2008 gdk_gc_destroy (tgc);
2010 pixbuf = gdk_pixbuf_get_from_drawable (NULL, tmp, cmap,
2012 gdk_pixmap_unref (tmp);
2015 pixbuf = gdk_pixbuf_get_from_drawable (NULL, pp, cmap,
2018 gdk_xid_table_remove (GDK_WINDOW_XWINDOW (pp));
2019 g_dataset_destroy (pp);
2025 buf = gdk_pixbuf_get_pixels (pixbuf);
2026 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
2027 pbwidth = gdk_pixbuf_get_width (pixbuf);
2028 pbheight = gdk_pixbuf_get_height (pixbuf);
2030 a = 128; /* alpha */
2031 r = xtext->tint_red;
2032 g = xtext->tint_green;
2033 b = xtext->tint_blue;
2035 if (gdk_pixbuf_get_has_alpha (pixbuf))
2040 for (i=0;i<pbheight;i++)
2043 for (j=0;j<pbwidth;j++)
2045 pbuf[0] = ((pbuf[0] * r) >> 8);
2046 pbuf[1] = ((pbuf[1] * g) >> 8);
2047 pbuf[2] = ((pbuf[2] * b) >> 8);
2053 gdk_pixbuf_render_pixmap_and_mask (pixbuf, &shaded_pixmap, NULL, 0);
2054 gdk_pixbuf_unref (pixbuf);
2056 return shaded_pixmap;
2061 /* free transparency xtext->pixmap */
2064 gtk_xtext_free_trans (GtkXText * xtext)
2070 gdk_pixmap_unref (xtext->pixmap);
2073 gdk_xid_table_remove (GDK_WINDOW_XWINDOW (xtext->pixmap));
2074 g_dataset_destroy (xtext->pixmap);
2075 g_free (xtext->pixmap);
2077 xtext->pixmap = NULL;
2081 /* grab pixmap from root window and set xtext->pixmap */
2084 gtk_xtext_load_trans (GtkXText * xtext)
2088 GtkWidget *widget = GTK_WIDGET (xtext);
2091 rootpix = get_pixmap_prop (GDK_WINDOW_XWINDOW (widget->window));
2092 if (rootpix == None)
2094 if (xtext->error_function)
2095 xtext->error_function ("Unable to get root window pixmap!\n\n"
2096 "You may need to use Esetroot or Gnome\n"
2097 "control-center to set your background.\n");
2098 xtext->transparent = FALSE;
2102 XTranslateCoordinates (GDK_WINDOW_XDISPLAY (widget->window),
2103 GDK_WINDOW_XWINDOW (widget->window),
2104 GDK_ROOT_WINDOW (), 0, 0, &x, &y, &childret);
2106 #ifdef USE_GDK_PIXBUF
2110 gdk_window_get_size (GTK_WIDGET (xtext)->window, &width, &height);
2112 create_shaded_pixmap (xtext, rootpix, x, y, width, height);
2113 gdk_gc_set_tile (xtext->bgc, xtext->pixmap);
2114 gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
2118 xtext->pixmap = gdk_pixmap_foreign_new (rootpix);
2119 gdk_gc_set_tile (xtext->bgc, xtext->pixmap);
2120 gdk_gc_set_ts_origin (xtext->bgc, -x, -y);
2121 #ifdef USE_GDK_PIXBUF
2124 gdk_gc_set_fill (xtext->bgc, GDK_TILED);
2129 /* render a single line, which may wrap to more lines */
2132 gtk_xtext_render_line (GtkXText * xtext, textentry * ent, char *str, int len,
2133 int line, int lines_max, int subline, int indent,
2150 gdk_window_get_size (GTK_WIDGET (xtext)->window, &width, 0);
2153 if (xtext->time_stamp)
2155 time_str = ctime (&ent->stamp) + 10;
2159 y = (xtext->fontsize * line) + xtext->font->ascent;
2160 gtk_xtext_render_str (xtext, y, ent, time_str, 10, width, 2, line);
2165 y = (xtext->fontsize * line) + xtext->font->ascent;
2167 if (str_width == -1)
2168 str_width = gtk_xtext_text_width (xtext, str, len);
2170 str_width += indent;
2173 while (str_width > width || (!is_del (str[len]) && xtext->wordwrap))
2175 if (str_width <= width && !tmp)
2178 if (xtext->wordwrap && tmp - len > WORDWRAP_LIMIT)
2181 str_width = gtk_xtext_text_width (xtext, str, len) + indent;
2187 /* this is quite a HACK but it speeds things up! */
2188 if (str_width > width + 256)
2192 str_width = gtk_xtext_text_width (xtext, str, len) + indent;
2197 gtk_xtext_render_str (xtext, y, ent, str, len, width, indent, line);
2200 xtext->dont_render = TRUE;
2201 gtk_xtext_render_str (xtext, y, ent, str, len, width, indent, line);
2202 xtext->dont_render = FALSE;
2208 if (xtext->wordwrap && str[len] == ' ')
2211 if (len != orig_len && lines_max > line + 1)
2212 { /* FIXME: recursion sux! */
2213 /* ret += gtk_xtext_render_line (xtext, ent, str + len, -1, line+1, lines_max, subline, xtext->indent, -1);*/
2216 len = orig_len = strlen (str);
2218 indent = xtext->indent;
2220 /* FIXME: gotos suck! */
2228 gtk_xtext_set_palette (GtkXText * xtext, GdkColor palette[])
2232 for (i = 0; i < 20; i++)
2233 xtext->palette[i] = palette[i].pixel;
2235 if (GTK_WIDGET_REALIZED (xtext))
2237 xtext_set_fg (xtext->fgc, xtext->palette[18]);
2238 xtext_set_bg (xtext->fgc, xtext->palette[19]);
2239 xtext_set_fg (xtext->bgc, xtext->palette[19]);
2241 xtext->col_fore = 18;
2242 xtext->col_back = 19;
2246 gtk_xtext_fix_indent (GtkXText * xtext)
2250 if (xtext->indent) /* make indent a multiple of the space width */
2253 while (j < xtext->indent)
2255 j += xtext->space_width;
2262 gtk_xtext_recalc_widths (GtkXText * xtext, int do_str_width)
2266 /* since we have a new font, we have to recalc the text widths */
2267 ent = xtext->text_first;
2273 gtk_xtext_text_width (xtext, ent->str, ent->str_len);
2275 if (ent->left_len != -1)
2279 gtk_xtext_text_width (xtext, ent->str,
2280 ent->left_len)) - xtext->space_width;
2281 if (ent->indent < MARGIN)
2282 ent->indent = MARGIN;
2287 gtk_xtext_calc_lines (xtext, FALSE);
2291 gtk_xtext_set_font (GtkXText * xtext, GdkFont * font, char *name)
2299 gdk_font_unref (xtext->font);
2304 gdk_font_ref (font);
2306 font = xtext->font = gdk_font_load (name);
2309 font = xtext->font = gdk_font_load ("fixed");
2314 xtext->fontsize = font->ascent + font->descent;
2316 xfont = GDK_FONT_XFONT (font);
2317 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
2319 xtext->fonttype = FONT_1BYTE;
2320 for (i = 0; i < 255; i++)
2322 xtext->fontwidth[i] = gdk_char_width (font, i);
2324 xtext->space_width = xtext->fontwidth[' '];
2328 /* without X11 pretend they are all 2BYTE- This is ok, just
2330 xtext->fonttype = FONT_2BYTE;
2331 xtext->space_width = gdk_char_width (font, ' ');
2337 case GDK_FONT_FONTSET:
2338 xtext->fontsize = gdk_text_height (font, " ", 1);
2339 xtext->fonttype = FONT_SET;
2340 xtext->space_width = gdk_char_width (font, ' ');
2345 xfont = GDK_FONT_XFONT (font);
2346 /* check if it's a fixed width font */
2347 if (xfont->min_bounds.width == xfont->max_bounds.width)
2348 xtext->fixed_width_font = TRUE;
2350 xtext->fixed_width_font = FALSE;
2352 /* kudgy fixed-width font checking */
2353 if (xtext->space_width == gdk_char_width (xtext->font, 'Z'))
2354 xtext->fixed_width_font = TRUE;
2356 xtext->fixed_width_font = FALSE;
2359 xtext->stamp_width =
2360 gtk_xtext_text_width (xtext, "[88:88:88]", 10) + MARGIN;
2362 gtk_xtext_fix_indent (xtext);
2364 if (GTK_WIDGET_REALIZED (xtext))
2366 if (xtext->fonttype != FONT_SET)
2367 gdk_gc_set_font (xtext->fgc, xtext->font);
2369 gtk_xtext_recalc_widths (xtext, TRUE);
2374 gtk_xtext_set_background (GtkXText * xtext, GdkPixmap * pixmap, int trans,
2379 #ifndef USE_GDK_PIXBUF
2391 if (xtext->transparent)
2392 gtk_xtext_free_trans (xtext);
2395 gdk_pixmap_unref (xtext->pixmap);
2396 xtext->pixmap = NULL;
2399 xtext->transparent = trans;
2404 xtext->shaded = shaded;
2405 if (GTK_WIDGET_REALIZED (xtext))
2406 gtk_xtext_load_trans (xtext);
2411 xtext->pixmap = pixmap;
2415 gdk_pixmap_ref (pixmap);
2416 if (GTK_WIDGET_REALIZED (xtext))
2418 gdk_gc_set_tile (xtext->bgc, pixmap);
2419 gdk_gc_set_ts_origin (xtext->bgc, 0, 0);
2420 gdk_gc_set_fill (xtext->bgc, GDK_TILED);
2424 if (GTK_WIDGET_REALIZED (xtext))
2426 gdk_gc_destroy (xtext->bgc);
2427 val.subwindow_mode = GDK_INCLUDE_INFERIORS;
2428 val.graphics_exposures = 0;
2429 xtext->bgc = gdk_gc_new_with_values (GTK_WIDGET (xtext)->window,
2430 &val, GDK_GC_EXPOSURES | GDK_GC_SUBWINDOW);
2431 xtext_set_fg (xtext->bgc, xtext->palette[19]);
2437 gtk_xtext_get_chars (GtkXText * xtext)
2441 textentry *tentry = xtext->text_first;
2442 while (tentry != NULL)
2444 lenght += tentry->str_len + 1;
2445 tentry = tentry->next;
2449 chars = g_malloc (lenght + 1);
2452 tentry = xtext->text_first;
2453 while (tentry != NULL)
2455 strcat (chars, tentry->str);
2456 strcat (chars, "\n");
2457 tentry = tentry->next;
2464 gtk_xtext_lines_taken (GtkXText * xtext, textentry * ent)
2466 int tmp, orig_len, indent, len, win_width, str_width, lines = 0;
2470 len = orig_len = ent->str_len;
2471 indent = ent->indent;
2476 win_width = GTK_WIDGET (xtext)->allocation.width - MARGIN;
2477 str_width = ent->str_width + indent;
2482 if (str_width <= win_width)
2485 while (str_width > win_width || (!is_del (str[len]) && xtext->wordwrap))
2487 if (str_width <= win_width && !tmp)
2490 if (xtext->wordwrap && tmp - len > WORDWRAP_LIMIT)
2493 str_width = gtk_xtext_text_width (xtext, str, len) + indent;
2498 if (str_width > win_width + 256) /* this might not work 100% but it */
2499 len -= 10; /* sure speeds things up ALOT! */
2500 str_width = gtk_xtext_text_width (xtext, str, len) + indent;
2503 if (len == orig_len)
2506 if (xtext->wordwrap && str[len] == ' ')
2510 indent = xtext->indent;
2512 str_width = gtk_xtext_text_width (xtext, str, len) + indent;
2517 /* Calculate number of actual lines (with wraps), to set adj->lower. *
2518 * This should only be called when the window resizes. */
2521 gtk_xtext_calc_lines (GtkXText * xtext, int fire_signal)
2528 width = GTK_WIDGET (xtext)->allocation.width - MARGIN;
2529 height = GTK_WIDGET (xtext)->allocation.height;
2531 if (width < 30 || height < xtext->fontsize || width < xtext->indent + 30)
2535 ent = xtext->text_first;
2538 ent->lines_taken = gtk_xtext_lines_taken (xtext, ent);
2539 lines += ent->lines_taken;
2543 xtext->pagetop_ent = NULL;
2544 xtext->num_lines = lines;
2545 gtk_xtext_adjustment_set (xtext, fire_signal);
2548 /* find the n-th line in the linked list, this includes wrap calculations */
2551 gtk_xtext_nth (GtkXText * xtext, textentry * ent, int line, int width,
2558 ent = xtext->text_first;
2559 line += xtext->adj->value;
2567 lines += ent->lines_taken;
2570 *subline = ent->lines_taken - (lines - line);
2579 gtk_xtext_draw_sep (GtkXText * xtext, int y)
2582 GdkGC *light, *dark;
2587 height = GTK_WIDGET (xtext)->allocation.height - 2;
2590 height = xtext->fontsize;
2593 /* draw the separator line */
2594 if (xtext->separator && xtext->indent)
2596 light = xtext->light_gc;
2597 dark = xtext->dark_gc;
2599 x = xtext->indent - ((xtext->space_width + 1) / 2);
2603 if (xtext->thinline)
2605 if (xtext->moving_separator)
2606 gdk_draw_line (xtext->draw_buf, light, x, y, x, height);
2608 gdk_draw_line (xtext->draw_buf, dark, x, y, x, height);
2611 if (xtext->moving_separator)
2613 gdk_draw_line (xtext->draw_buf, light, x - 1, y, x - 1, height);
2614 gdk_draw_line (xtext->draw_buf, dark, x, y, x, height);
2617 gdk_draw_line (xtext->draw_buf, dark, x - 1, y, x - 1, height);
2618 gdk_draw_line (xtext->draw_buf, light, x, y, x, height);
2624 /* render 2 ents (or an inclusive range) */
2627 gtk_xtext_render_ents (GtkXText * xtext, textentry * enta, textentry * entb,
2630 textentry *ent, *orig_ent, *tmp_ent;
2637 int drawing = FALSE;
2639 if (xtext->double_buffer)
2641 gtk_xtext_render_page (xtext);
2645 if (xtext->indent < MARGIN)
2646 xtext->indent = MARGIN; /* 2 pixels is our left margin */
2648 gdk_window_get_size (GTK_WIDGET (xtext)->window, &width, &height);
2651 if (width < 32 || height < xtext->fontsize || width < xtext->indent + 30)
2654 lines_max = (height - xtext->font->descent) / xtext->fontsize;
2656 orig_ent = xtext->pagetop_ent;
2657 subline = xtext->pagetop_subline;
2659 /* check if enta is before the start of this page */
2665 if (tmp_ent == enta)
2667 if (tmp_ent == entb)
2672 tmp_ent = tmp_ent->next;
2681 if (inclusive && ent == enta)
2684 if (drawing || ent == entb || ent == enta)
2686 gtk_xtext_reset (xtext, FALSE, TRUE);
2687 lines_taken = gtk_xtext_render_line (xtext, ent, ent->str,
2688 ent->str_len, line, lines_max,
2689 subline, ent->indent,
2691 line += ent->lines_taken;
2693 if (ent == orig_ent)
2697 if (ent == orig_ent)
2702 line += ent->lines_taken;
2705 if (inclusive && ent == entb)
2708 if (line >= lines_max)
2714 /* draw the separator line */
2715 gtk_xtext_draw_sep (xtext, -1);
2718 /* render a whole page/window, starting from 'startline' */
2721 gtk_xtext_render_page (GtkXText * xtext)
2729 int startline = xtext->adj->value;
2731 if (xtext->indent < MARGIN)
2732 xtext->indent = MARGIN; /* 2 pixels is our left margin */
2734 gdk_window_get_size (GTK_WIDGET (xtext)->window, &width, &height);
2737 if (width < 32 || height < xtext->fontsize || width < xtext->indent + 30)
2740 lines_max = (height - xtext->font->descent) / xtext->fontsize;
2743 ent = xtext->text_first;
2746 ent = gtk_xtext_nth (xtext, ent, startline, width, &subline);
2748 xtext->pagetop_ent = ent;
2749 xtext->pagetop_subline = subline;
2751 if (xtext->double_buffer)
2753 xtext->tmp_pix = gdk_pixmap_new (((GtkWidget*)xtext)->window,
2754 width + MARGIN, height, xtext->depth);
2755 xtext->draw_buf = xtext->tmp_pix;
2756 /* render the backdrop */
2757 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1, 0, 0,
2758 width + MARGIN, height);
2763 gtk_xtext_reset (xtext, FALSE, TRUE);
2765 gtk_xtext_render_line (xtext, ent, ent->str, ent->str_len, line,
2766 lines_max, subline, ent->indent,
2770 if (line >= lines_max)
2776 if (!xtext->double_buffer)
2778 line = (xtext->fontsize * line);
2779 /* fill any space below the last line with our background GC */
2780 gdk_draw_rectangle (xtext->draw_buf, xtext->bgc, 1,
2781 0, line, width + MARGIN, height - line);
2784 /* draw the separator line */
2785 gtk_xtext_draw_sep (xtext, -1);
2787 if (xtext->double_buffer)
2789 /* send our double buffer to the actual window */
2790 gdk_draw_pixmap (((GtkWidget*)xtext)->window, xtext->fgc, xtext->tmp_pix,
2791 0, 0, 0, 0, width + MARGIN, height);
2792 gdk_pixmap_unref (xtext->tmp_pix);
2797 gtk_xtext_refresh (GtkXText * xtext, int do_trans)
2799 if (GTK_WIDGET_REALIZED (GTK_WIDGET (xtext)))
2802 if (xtext->transparent && do_trans)
2804 gtk_xtext_free_trans (xtext);
2805 gtk_xtext_load_trans (xtext);
2808 gtk_xtext_render_page (xtext);
2812 /* remove the topline from the list */
2815 gtk_xtext_remove_top (GtkXText * xtext)
2819 ent = xtext->text_first;
2820 xtext->num_lines -= ent->lines_taken;
2821 xtext->pagetop_ent = NULL;
2822 xtext->text_first = ent->next;
2827 gtk_xtext_remove_lines (GtkXText * xtext, int lines, int refresh)
2831 while (xtext->text_first && lines)
2833 next = xtext->text_first->next;
2834 free (xtext->text_first);
2835 xtext->text_first = next;
2838 if (!xtext->text_first)
2839 xtext->text_last = NULL;
2843 gtk_xtext_calc_lines (xtext, TRUE);
2844 gtk_xtext_refresh (xtext, 0);
2849 gtk_xtext_search (GtkXText * xtext, char *text, void *start)
2851 textentry *ent, *fent;
2855 gtk_xtext_selection_clear (xtext);
2858 ent = ((textentry *) start)->next;
2860 ent = xtext->text_first;
2863 if ((str = nocasestrstr (ent->str, text)))
2865 ent->mark_start = str - ent->str;
2866 ent->mark_end = ent->mark_start + strlen (text);
2873 ent = xtext->text_first;
2877 line += ent->lines_taken;
2882 while (line > xtext->adj->upper - xtext->adj->page_size)
2887 xtext->adj->value = line;
2888 xtext->scrollbar_down = FALSE;
2889 gtk_adjustment_changed (xtext->adj);
2891 gtk_xtext_render_page (xtext);
2897 gtk_xtext_render_page_timeout (GtkXText * xtext)
2899 GtkAdjustment *adj = xtext->adj;
2902 if (xtext->scrollbar_down)
2904 gtk_xtext_adjustment_set (xtext, FALSE);
2905 gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
2909 gtk_xtext_adjustment_set (xtext, TRUE);
2910 gtk_adjustment_set_value (adj, val);
2913 if (adj->value >= adj->upper - adj->page_size || adj->value < 1)
2914 gtk_xtext_render_page (xtext);
2916 xtext->add_io_tag = -1;
2921 /* append a textentry to our linked list */
2924 gtk_xtext_append_entry (GtkXText * xtext, textentry * ent)
2926 ent->stamp = time (0);
2927 ent->str_width = gtk_xtext_text_width (xtext, ent->str, ent->str_len);
2928 ent->mark_start = -1;
2932 if (ent->indent < MARGIN)
2933 ent->indent = MARGIN; /* 2 pixels is the left margin */
2935 /* append to our linked list */
2936 if (xtext->text_last)
2937 xtext->text_last->next = ent;
2939 xtext->text_first = ent;
2940 xtext->text_last = ent;
2942 ent->lines_taken = gtk_xtext_lines_taken (xtext, ent);
2943 xtext->num_lines += ent->lines_taken;
2945 if (xtext->max_lines > 2 && xtext->max_lines < xtext->num_lines)
2947 gtk_xtext_remove_top (xtext);
2950 /* if (xtext->frozen == 0 && xtext->add_io_tag == -1)*/
2951 if (xtext->add_io_tag == -1)
2953 xtext->add_io_tag = gtk_timeout_add (REFRESH_TIMEOUT * 2,
2955 gtk_xtext_render_page_timeout,
2960 /* the main two public functions */
2963 gtk_xtext_append_indent (GtkXText * xtext,
2964 char *left_text, int left_len,
2965 char *right_text, int right_len)
2972 left_len = strlen (left_text);
2974 if (right_len == -1)
2975 right_len = strlen (right_text);
2977 ent = malloc (left_len + right_len + 2 + sizeof (textentry));
2978 str = (char *) ent + sizeof (textentry);
2980 space = xtext->indent - gtk_xtext_text_width (xtext, left_text, left_len);
2982 memcpy (str, left_text, left_len);
2983 str[left_len] = ' ';
2984 memcpy (str + left_len + 1, right_text, right_len);
2985 str[left_len + 1 + right_len] = 0;
2987 ent->left_len = left_len;
2989 ent->str_len = left_len + 1 + right_len;
2990 ent->indent = space - xtext->space_width;
2992 if (xtext->time_stamp)
2993 space = xtext->stamp_width;
2997 /* do we need to auto adjust the separator position? */
2998 if (xtext->auto_indent && ent->indent < MARGIN + space)
3000 xtext->indent -= ent->indent;
3001 xtext->indent += MARGIN;
3002 xtext->indent += space;
3003 if (xtext->indent > xtext->max_auto_indent)
3004 xtext->indent = xtext->max_auto_indent;
3005 gtk_xtext_fix_indent (xtext);
3006 gtk_xtext_recalc_widths (xtext, FALSE);
3008 xtext->indent - gtk_xtext_text_width (xtext, left_text, left_len);
3009 ent->indent = space - xtext->space_width;
3012 gtk_xtext_append_entry (xtext, ent);
3016 gtk_xtext_append (GtkXText * xtext, char *text, int len)
3021 len = strlen (text);
3023 ent = malloc (len + 1 + sizeof (textentry));
3024 ent->str = (char *) ent + sizeof (textentry);
3027 memcpy (ent->str, text, len);
3032 gtk_xtext_append_entry (xtext, ent);