12
|
1
|
1
|
2 /*
|
|
3 * gaim
|
|
4 *
|
|
5 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
|
|
6 *
|
|
7 * This program is free software; you can redistribute it and/or modify
|
|
8 * it under the terms of the GNU General Public License as published by
|
|
9 * the Free Software Foundation; either version 2 of the License, or
|
|
10 * (at your option) any later version.
|
|
11 *
|
|
12 * This program is distributed in the hope that it will be useful,
|
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 * GNU General Public License for more details.
|
|
16 *
|
|
17 * You should have received a copy of the GNU General Public License
|
|
18 * along with this program; if not, write to the Free Software
|
|
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
20 *
|
|
21 */
|
|
22
|
|
23 #include <stdio.h>
|
|
24 #include <stdlib.h>
|
|
25 #include <string.h>
|
|
26 #include <gtk/gtk.h>
|
|
27 #include <gdk/gdkprivate.h>
|
|
28 #include <gdk/gdkx.h>
|
|
29 #include <gdk/gdkkeysyms.h>
|
12
|
30
|
|
31 #ifndef _WIN32
|
1
|
32 #include <X11/Xlib.h>
|
|
33 #include <X11/Xatom.h>
|
12
|
34 #endif
|
|
35
|
69
|
36 #include "gaim.h"
|
1
|
37 #include "gtkhtml.h"
|
|
38
|
|
39 #define MAX_SIZE 7
|
|
40 #define MIN_HTML_WIDTH_LINES 20
|
|
41 #define MIN_HTML_HEIGHT_LINES 10
|
|
42 #define BORDER_WIDTH 2
|
|
43 #define SCROLL_TIME 100
|
|
44 #define SCROLL_PIXELS 5
|
|
45 #define KEY_SCROLL_PIXELS 10
|
|
46
|
|
47 int font_sizes[] = { 80, 100, 120, 140, 200, 300, 400 };
|
|
48
|
12
|
49 /*
|
1
|
50 GdkFont *fixed_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
51 GdkFont *fixed_bold_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
52 GdkFont *fixed_italic_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
12
|
53 GdkFont *fixed_bold_italic_font[] =
|
|
54 { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
1
|
55 GdkFont *prop_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
56 GdkFont *prop_bold_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
57 GdkFont *prop_italic_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
58 GdkFont *prop_bold_italic_font[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
12
|
59 */
|
|
60
|
|
61 GData * font_cache;
|
|
62 static gboolean cache_init = FALSE;
|
|
63
|
|
64 struct font_state
|
|
65 {
|
|
66 int size;
|
|
67 int owncolor;
|
|
68 int ownbg;
|
|
69 gchar font[1024];
|
|
70 GdkColor *color;
|
|
71 GdkColor *bgcol;
|
|
72 struct font_state *next;
|
1
|
73 };
|
|
74
|
|
75 struct font_state *push_state(struct font_state *current)
|
|
76 {
|
12
|
77 struct font_state *tmp;
|
|
78 tmp = (struct font_state *) g_new0(struct font_state, 1);
|
1
|
79 tmp->next = current;
|
|
80 tmp->color = current->color;
|
|
81 tmp->bgcol = current->bgcol;
|
|
82 tmp->size = current->size;
|
|
83 tmp->owncolor = 0;
|
|
84 tmp->ownbg = 0;
|
12
|
85 strcpy( tmp->font, current->font );
|
1
|
86 return tmp;
|
|
87 }
|
|
88
|
12
|
89 enum
|
|
90 {
|
|
91 ARG_0,
|
|
92 ARG_HADJUSTMENT,
|
|
93 ARG_VADJUSTMENT,
|
1
|
94 };
|
|
95
|
|
96
|
12
|
97 enum
|
|
98 {
|
|
99 TARGET_STRING,
|
|
100 TARGET_TEXT,
|
|
101 TARGET_COMPOUND_TEXT
|
1
|
102 };
|
|
103
|
|
104
|
12
|
105 static void gtk_html_class_init(GtkHtmlClass * klass);
|
|
106 static void gtk_html_set_arg(GtkObject * object, GtkArg * arg, guint arg_id);
|
|
107 static void gtk_html_get_arg(GtkObject * object, GtkArg * arg, guint arg_id);
|
|
108 static void gtk_html_init(GtkHtml * html);
|
|
109 static void gtk_html_destroy(GtkObject * object);
|
|
110 static void gtk_html_finalize(GtkObject * object);
|
|
111 static void gtk_html_realize(GtkWidget * widget);
|
|
112 static void gtk_html_unrealize(GtkWidget * widget);
|
|
113 static void gtk_html_style_set(GtkWidget * widget, GtkStyle * previous_style);
|
|
114 static void gtk_html_draw_focus(GtkWidget * widget);
|
|
115 static void gtk_html_size_request(GtkWidget * widget,
|
|
116 GtkRequisition * requisition);
|
|
117 static void gtk_html_size_allocate(GtkWidget * widget,
|
|
118 GtkAllocation * allocation);
|
|
119 static void gtk_html_adjustment(GtkAdjustment * adjustment, GtkHtml * html);
|
|
120 static void gtk_html_disconnect(GtkAdjustment * adjustment, GtkHtml * html);
|
|
121 static void gtk_html_add_seperator(GtkHtml * html);
|
|
122 static void gtk_html_add_pixmap(GtkHtml * html, GdkPixmap * pm, gint fit);
|
|
123 static void gtk_html_add_text(GtkHtml * html,
|
|
124 GdkFont * font,
|
|
125 GdkColor * fore,
|
|
126 GdkColor * back,
|
|
127 gchar * chars,
|
|
128 gint length,
|
|
129 gint uline, gint strike, gchar * url);
|
|
130 static void gtk_html_draw_bit(GtkHtml * html,
|
|
131 GtkHtmlBit * htmlbit, gint redraw);
|
|
132 static void gtk_html_selection_get(GtkWidget * widget,
|
|
133 GtkSelectionData * selection_data,
|
|
134 guint sel_info, guint32 time);
|
|
135 static gint gtk_html_selection_clear(GtkWidget * widget,
|
|
136 GdkEventSelection * event);
|
|
137 static gint gtk_html_visibility_notify(GtkWidget * widget,
|
|
138 GdkEventVisibility * event);
|
1
|
139
|
|
140
|
|
141 /* Event handlers */
|
12
|
142 static void gtk_html_draw(GtkWidget * widget, GdkRectangle * area);
|
|
143 static gint gtk_html_expose(GtkWidget * widget, GdkEventExpose * event);
|
|
144 static gint gtk_html_button_press(GtkWidget * widget, GdkEventButton * event);
|
|
145 static gint gtk_html_button_release(GtkWidget * widget, GdkEventButton * event);
|
|
146 static gint gtk_html_motion_notify(GtkWidget * widget, GdkEventMotion * event);
|
|
147 static gint gtk_html_key_press(GtkWidget * widget, GdkEventKey * event);
|
|
148 static gint gtk_html_leave_notify(GtkWidget * widget, GdkEventCrossing * event);
|
1
|
149
|
|
150 static gint gtk_html_tooltip_timeout(gpointer data);
|
|
151
|
|
152
|
12
|
153 static void clear_area(GtkHtml * html, GdkRectangle * area);
|
|
154 static void expose_html(GtkHtml * html, GdkRectangle * area, gboolean cursor);
|
|
155 static void scroll_down(GtkHtml * html, gint diff0);
|
|
156 static void scroll_up(GtkHtml * html, gint diff0);
|
|
157
|
|
158 static void adjust_adj(GtkHtml * html, GtkAdjustment * adj);
|
|
159 static void resize_html(GtkHtml * html);
|
|
160 static gint html_bit_is_onscreen(GtkHtml * html, GtkHtmlBit * hb);
|
|
161 static void draw_cursor(GtkHtml * html);
|
|
162 static void undraw_cursor(GtkHtml * html);
|
1
|
163
|
|
164 static GtkWidgetClass *parent_class = NULL;
|
|
165
|
|
166 GtkType gtk_html_get_type(void)
|
|
167 {
|
12
|
168 static GtkType html_type = 0;
|
|
169
|
|
170 if (!html_type)
|
|
171 {
|
|
172 static const GtkTypeInfo html_info = {
|
|
173 "GtkHtml",
|
|
174 sizeof(GtkHtml),
|
|
175 sizeof(GtkHtmlClass),
|
|
176 (GtkClassInitFunc) gtk_html_class_init,
|
|
177 (GtkObjectInitFunc) gtk_html_init,
|
|
178 NULL,
|
|
179 NULL,
|
|
180 NULL,
|
|
181 };
|
|
182 html_type = gtk_type_unique(GTK_TYPE_WIDGET, &html_info);
|
|
183 }
|
|
184 return html_type;
|
1
|
185 }
|
|
186
|
|
187
|
12
|
188 static void gtk_html_class_init(GtkHtmlClass * class)
|
1
|
189 {
|
12
|
190 GtkObjectClass *object_class;
|
|
191 GtkWidgetClass *widget_class;
|
|
192
|
|
193 object_class = (GtkObjectClass *) class;
|
|
194 widget_class = (GtkWidgetClass *) class;
|
|
195 parent_class = gtk_type_class(GTK_TYPE_WIDGET);
|
|
196
|
|
197
|
|
198 gtk_object_add_arg_type("GtkHtml::hadjustment",
|
|
199 GTK_TYPE_ADJUSTMENT,
|
|
200 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
|
|
201 ARG_HADJUSTMENT);
|
|
202
|
|
203 gtk_object_add_arg_type("GtkHtml::vadjustment",
|
|
204 GTK_TYPE_ADJUSTMENT,
|
|
205 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
|
|
206 ARG_VADJUSTMENT);
|
|
207
|
|
208 object_class->set_arg = gtk_html_set_arg;
|
|
209 object_class->get_arg = gtk_html_get_arg;
|
|
210 object_class->destroy = gtk_html_destroy;
|
|
211 object_class->finalize = gtk_html_finalize;
|
|
212
|
|
213 widget_class->realize = gtk_html_realize;
|
|
214 widget_class->unrealize = gtk_html_unrealize;
|
|
215 widget_class->style_set = gtk_html_style_set;
|
|
216 widget_class->draw_focus = gtk_html_draw_focus;
|
|
217 widget_class->size_request = gtk_html_size_request;
|
|
218 widget_class->size_allocate = gtk_html_size_allocate;
|
|
219 widget_class->draw = gtk_html_draw;
|
|
220 widget_class->expose_event = gtk_html_expose;
|
|
221 widget_class->button_press_event = gtk_html_button_press;
|
|
222 widget_class->button_release_event = gtk_html_button_release;
|
1
|
223 widget_class->motion_notify_event = gtk_html_motion_notify;
|
|
224 widget_class->leave_notify_event = gtk_html_leave_notify;
|
12
|
225 widget_class->selection_get = gtk_html_selection_get;
|
1
|
226 widget_class->selection_clear_event = gtk_html_selection_clear;
|
|
227 widget_class->key_press_event = gtk_html_key_press;
|
|
228 widget_class->visibility_notify_event = gtk_html_visibility_notify;
|
12
|
229
|
|
230
|
|
231 widget_class->set_scroll_adjustments_signal =
|
|
232 gtk_signal_new("set_scroll_adjustments",
|
|
233 GTK_RUN_LAST,
|
|
234 object_class->type,
|
|
235 GTK_SIGNAL_OFFSET(GtkHtmlClass, set_scroll_adjustments),
|
|
236 gtk_marshal_NONE__POINTER_POINTER,
|
|
237 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT,
|
|
238 GTK_TYPE_ADJUSTMENT);
|
|
239
|
|
240
|
|
241 class->set_scroll_adjustments = gtk_html_set_adjustments;
|
1
|
242
|
|
243 }
|
|
244
|
12
|
245 static void gtk_html_set_arg(GtkObject * object, GtkArg * arg, guint arg_id)
|
1
|
246 {
|
12
|
247 GtkHtml *html;
|
|
248
|
|
249 html = GTK_HTML(object);
|
|
250
|
|
251 switch (arg_id)
|
|
252 {
|
|
253 case ARG_HADJUSTMENT:
|
|
254 gtk_html_set_adjustments(html, GTK_VALUE_POINTER(*arg), html->vadj);
|
|
255 break;
|
|
256 case ARG_VADJUSTMENT:
|
|
257 gtk_html_set_adjustments(html, html->hadj, GTK_VALUE_POINTER(*arg));
|
|
258 break;
|
|
259 default:
|
|
260 break;
|
|
261 }
|
1
|
262 }
|
|
263
|
12
|
264 static void gtk_html_get_arg(GtkObject * object, GtkArg * arg, guint arg_id)
|
1
|
265 {
|
12
|
266 GtkHtml *html;
|
|
267
|
|
268 html = GTK_HTML(object);
|
|
269
|
|
270 switch (arg_id)
|
|
271 {
|
|
272 case ARG_HADJUSTMENT:
|
|
273 GTK_VALUE_POINTER(*arg) = html->hadj;
|
|
274 break;
|
|
275 case ARG_VADJUSTMENT:
|
|
276 GTK_VALUE_POINTER(*arg) = html->vadj;
|
|
277 break;
|
|
278 default:
|
|
279 arg->type = GTK_TYPE_INVALID;
|
|
280 break;
|
|
281 }
|
1
|
282 }
|
|
283
|
12
|
284 static void gtk_html_init(GtkHtml * html)
|
1
|
285 {
|
12
|
286 static const GtkTargetEntry targets[] = {
|
|
287 {"STRING", 0, TARGET_STRING},
|
|
288 {"TEXT", 0, TARGET_TEXT},
|
|
289 {"COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT}
|
|
290 };
|
|
291
|
|
292 static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
|
|
293
|
|
294 GTK_WIDGET_SET_FLAGS(html, GTK_CAN_FOCUS);
|
|
295
|
|
296 html->html_area = NULL;
|
|
297 html->hadj = NULL;
|
|
298 html->vadj = NULL;
|
1
|
299 html->current_x = 0;
|
|
300 html->current_y = 0;
|
12
|
301 html->start_sel = html->end_sel = NULL;
|
|
302 html->start_sel_x = html->start_sel_y = -1;
|
|
303 html->num_end = html->num_start = -1;
|
|
304
|
1
|
305 html->html_bits = NULL;
|
|
306 html->urls = NULL;
|
|
307 html->selected_text = NULL;
|
|
308 html->tooltip_hb = NULL;
|
|
309 html->tooltip_timer = -1;
|
|
310 html->tooltip_window = NULL;
|
12
|
311 html->cursor_hb = NULL;
|
1
|
312 html->cursor_pos = 0;
|
|
313
|
|
314 html->pm = NULL;
|
|
315
|
|
316 html->editable = 0;
|
|
317 html->transparent = 0;
|
|
318
|
12
|
319 html->frozen = 0;
|
|
320
|
|
321 gtk_selection_add_targets(GTK_WIDGET(html), GDK_SELECTION_PRIMARY,
|
|
322 targets, n_targets);
|
|
323
|
|
324
|
|
325
|
1
|
326 }
|
|
327
|
|
328
|
12
|
329 GtkWidget *gtk_html_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
|
1
|
330 {
|
12
|
331 GtkWidget *html;
|
|
332 if(!cache_init)
|
|
333 {
|
|
334 g_datalist_init(&font_cache);
|
|
335 cache_init = TRUE;
|
|
336 }
|
|
337
|
|
338 if (hadj)
|
|
339 g_return_val_if_fail(GTK_IS_ADJUSTMENT(hadj), NULL);
|
|
340 if (vadj)
|
|
341 g_return_val_if_fail(GTK_IS_ADJUSTMENT(vadj), NULL);
|
|
342
|
|
343 html = gtk_widget_new(GTK_TYPE_HTML,
|
|
344 "hadjustment", hadj, "vadjustment", vadj, NULL);
|
|
345
|
|
346 return html;
|
1
|
347 }
|
|
348
|
|
349
|
12
|
350 void gtk_html_set_editable(GtkHtml * html, gboolean is_editable)
|
1
|
351 {
|
12
|
352 g_return_if_fail(html != NULL);
|
|
353 g_return_if_fail(GTK_IS_HTML(html));
|
|
354
|
|
355
|
|
356 html->editable = (is_editable != FALSE);
|
|
357
|
|
358 if (is_editable)
|
|
359 draw_cursor(html);
|
|
360 else
|
|
361 undraw_cursor(html);
|
1
|
362
|
|
363 }
|
|
364
|
12
|
365 void gtk_html_set_transparent(GtkHtml * html, gboolean is_transparent)
|
1
|
366 {
|
12
|
367 GdkRectangle rect;
|
|
368 gint width,
|
|
369 height;
|
|
370 GtkWidget *widget;
|
|
371
|
|
372 g_return_if_fail(html != NULL);
|
|
373 g_return_if_fail(GTK_IS_HTML(html));
|
|
374
|
|
375
|
|
376 widget = GTK_WIDGET(html);
|
|
377 html->transparent = (is_transparent != FALSE);
|
|
378
|
|
379 if (!GTK_WIDGET_REALIZED(widget))
|
|
380 return;
|
|
381
|
|
382 html->bg_gc = NULL;
|
|
383 gdk_window_get_size(widget->window, &width, &height);
|
|
384 rect.x = 0;
|
|
385 rect.y = 0;
|
|
386 rect.width = width;
|
|
387 rect.height = height;
|
|
388 gdk_window_clear_area(widget->window, rect.x, rect.y, rect.width,
|
|
389 rect.height);
|
|
390
|
|
391 expose_html(html, &rect, FALSE);
|
|
392 gtk_html_draw_focus((GtkWidget *) html);
|
1
|
393 }
|
|
394
|
|
395
|
12
|
396 void gtk_html_set_adjustments(GtkHtml * html,
|
|
397 GtkAdjustment * hadj, GtkAdjustment * vadj)
|
1
|
398 {
|
12
|
399 g_return_if_fail(html != NULL);
|
|
400 g_return_if_fail(GTK_IS_HTML(html));
|
|
401 if (hadj)
|
|
402 g_return_if_fail(GTK_IS_ADJUSTMENT(hadj));
|
|
403 else
|
|
404 hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
|
405 if (vadj)
|
|
406 g_return_if_fail(GTK_IS_ADJUSTMENT(vadj));
|
|
407 else
|
|
408 vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
|
409
|
|
410 if (html->hadj && (html->hadj != hadj))
|
|
411 {
|
|
412 gtk_signal_disconnect_by_data(GTK_OBJECT(html->hadj), html);
|
|
413 gtk_object_unref(GTK_OBJECT(html->hadj));
|
|
414 }
|
|
415
|
|
416 if (html->vadj && (html->vadj != vadj))
|
|
417 {
|
|
418 gtk_signal_disconnect_by_data(GTK_OBJECT(html->vadj), html);
|
|
419 gtk_object_unref(GTK_OBJECT(html->vadj));
|
|
420 }
|
|
421
|
|
422 if (html->hadj != hadj)
|
|
423 {
|
|
424 html->hadj = hadj;
|
|
425 gtk_object_ref(GTK_OBJECT(html->hadj));
|
|
426 gtk_object_sink(GTK_OBJECT(html->hadj));
|
|
427
|
|
428 gtk_signal_connect(GTK_OBJECT(html->hadj), "changed",
|
|
429 (GtkSignalFunc) gtk_html_adjustment, html);
|
|
430 gtk_signal_connect(GTK_OBJECT(html->hadj), "value_changed",
|
|
431 (GtkSignalFunc) gtk_html_adjustment, html);
|
|
432 gtk_signal_connect(GTK_OBJECT(html->hadj), "disconnect",
|
|
433 (GtkSignalFunc) gtk_html_disconnect, html);
|
|
434 gtk_html_adjustment(hadj, html);
|
|
435 }
|
|
436
|
|
437 if (html->vadj != vadj)
|
|
438 {
|
|
439 html->vadj = vadj;
|
|
440 gtk_object_ref(GTK_OBJECT(html->vadj));
|
|
441 gtk_object_sink(GTK_OBJECT(html->vadj));
|
|
442
|
|
443 gtk_signal_connect(GTK_OBJECT(html->vadj), "changed",
|
|
444 (GtkSignalFunc) gtk_html_adjustment, html);
|
|
445 gtk_signal_connect(GTK_OBJECT(html->vadj), "value_changed",
|
|
446 (GtkSignalFunc) gtk_html_adjustment, html);
|
|
447 gtk_signal_connect(GTK_OBJECT(html->vadj), "disconnect",
|
|
448 (GtkSignalFunc) gtk_html_disconnect, html);
|
|
449 gtk_html_adjustment(vadj, html);
|
|
450 }
|
1
|
451 }
|
|
452
|
|
453
|
|
454
|
12
|
455 GdkColor *get_color(int colorv, GdkColormap * map)
|
1
|
456 {
|
|
457 GdkColor *color;
|
12
|
458 #if 0
|
|
459 fprintf(stdout, "color is %x\n", colorv);
|
|
460 #endif
|
|
461 color = (GdkColor *) g_new0(GdkColor, 1);
|
1
|
462 color->red = ((colorv & 0xff0000) >> 16) * 256;
|
|
463 color->green = ((colorv & 0xff00) >> 8) * 256;
|
|
464 color->blue = ((colorv & 0xff)) * 256;
|
|
465 #if 0
|
12
|
466 fprintf(stdout, "Colors are %d, %d, %d\n", color->red, color->green,
|
|
467 color->blue);
|
1
|
468 #endif
|
|
469 gdk_color_alloc(map, color);
|
|
470 return color;
|
|
471 }
|
|
472
|
|
473
|
286
|
474 int load_font_with_cache(const char *name, const char *weight, char slant,
|
|
475 int size, GdkFont **font_return)
|
1
|
476 {
|
286
|
477 gchar font_spec[1024];
|
|
478
|
|
479 g_snprintf(font_spec, sizeof font_spec,
|
|
480 "-*-%s-%s-%c-normal-*-*-%d-*-*-*-*-iso8859-1",
|
|
481 name, weight, slant, size);
|
|
482
|
|
483 if((*font_return = g_datalist_id_get_data(&font_cache,
|
|
484 g_quark_from_string(font_spec)))) {
|
|
485 return TRUE;
|
|
486 } else if ((*font_return = gdk_font_load(font_spec))) {
|
|
487 g_datalist_id_set_data(&font_cache,
|
|
488 g_quark_from_string(font_spec), *font_return);
|
|
489 return TRUE;
|
|
490 } else {
|
|
491 return FALSE;
|
12
|
492 }
|
286
|
493 }
|
|
494
|
|
495
|
|
496 GdkFont *getfont(const char *font, int bold, int italic, int fixed, int size)
|
|
497 {
|
|
498 GdkFont *my_font = NULL;
|
|
499 gchar *weight, slant;
|
|
500
|
|
501 if (!font || !strlen(font)) font = fixed ? "courier" : "helvetica";
|
|
502 weight = bold ? "bold" : "medium";
|
|
503 slant = italic ? 'i' : 'r';
|
|
504
|
|
505 if (size > MAX_SIZE) size = MAX_SIZE;
|
|
506 if (size < 1) size = 1;
|
|
507 size = font_sizes[size-1];
|
|
508
|
|
509 /* try both 'i'talic and 'o'blique for italic fonts, and keep
|
|
510 * increasing the size until we get one that works. */
|
|
511
|
|
512 while (size < 720) {
|
|
513 if (load_font_with_cache(font, weight, slant, size, &my_font))
|
|
514 return my_font;
|
|
515 if (italic && load_font_with_cache(font, weight, 'o', size, &my_font))
|
|
516 return my_font;
|
|
517 size += 10;
|
12
|
518 }
|
|
519
|
286
|
520 /* since we couldn't get any size up to 72, fall back to the
|
|
521 * default fonts. */
|
|
522
|
|
523 font = fixed ? "courier" : "helvetica";
|
|
524
|
|
525 if (load_font_with_cache(font, weight, slant, 120, &my_font))
|
12
|
526 return my_font;
|
286
|
527 else {
|
|
528 fprintf(stderr, "gaim: can't load default font\n");
|
|
529 exit(1);
|
12
|
530 }
|
1
|
531 }
|
|
532
|
|
533
|
|
534 /* 'Borrowed' from ETerm */
|
12
|
535 GdkWindow *get_desktop_window(GtkWidget * widget)
|
1
|
536 {
|
12
|
537 #ifndef _WIN32
|
|
538 GdkAtom prop,
|
|
539 type,
|
|
540 prop2;
|
|
541 int format;
|
|
542 gint length;
|
|
543 guchar *data;
|
1
|
544 GtkWidget *w;
|
|
545
|
12
|
546 prop = gdk_atom_intern("_XROOTPMAP_ID", 1);
|
|
547 prop2 = gdk_atom_intern("_XROOTCOLOR_PIXEL", 1);
|
|
548
|
|
549 if (prop == None && prop2 == None)
|
|
550 {
|
|
551 return NULL;
|
|
552 }
|
|
553
|
|
554
|
|
555
|
|
556 for (w = widget; w; w = w->parent)
|
|
557 {
|
|
558
|
|
559 if (prop != None)
|
|
560 {
|
1
|
561 gdk_property_get(w->window, prop, AnyPropertyType, 0L, 1L, 0,
|
12
|
562 &type, &format, &length, &data);
|
|
563 }
|
|
564 else if (prop2 != None)
|
|
565 {
|
1
|
566 gdk_property_get(w->window, prop2, AnyPropertyType, 0L, 1L, 0,
|
12
|
567 &type, &format, &length, &data);
|
|
568 }
|
|
569 else
|
|
570 {
|
1
|
571 continue;
|
|
572 }
|
12
|
573 if (type != None)
|
|
574 {
|
1
|
575 return (w->window);
|
|
576 }
|
|
577 }
|
12
|
578 #endif
|
1
|
579 return NULL;
|
|
580
|
|
581 }
|
|
582
|
|
583
|
|
584
|
12
|
585 GdkPixmap *get_desktop_pixmap(GtkWidget * widget)
|
1
|
586 {
|
12
|
587 #ifndef _WIN32
|
|
588 GdkPixmap *p;
|
|
589 GdkAtom prop,
|
|
590 type,
|
|
591 prop2;
|
|
592 int format;
|
|
593 gint length;
|
|
594 guint32 id;
|
|
595 guchar *data;
|
|
596
|
|
597 prop = gdk_atom_intern("_XROOTPMAP_ID", 1);
|
|
598 prop2 = gdk_atom_intern("_XROOTCOLOR_PIXEL", 1);
|
|
599
|
|
600
|
|
601 if (prop == None && prop2 == None)
|
|
602 {
|
|
603 return NULL;
|
|
604 }
|
|
605
|
|
606 if (prop != None)
|
|
607 {
|
|
608 gdk_property_get(get_desktop_window(widget), prop, AnyPropertyType, 0L,
|
|
609 1L, 0, &type, &format, &length, &data);
|
|
610 if (type == XA_PIXMAP)
|
|
611 {
|
1
|
612 id = data[0];
|
|
613 id += data[1] << 8;
|
|
614 id += data[2] << 16;
|
|
615 id += data[3] << 24;
|
12
|
616 p = gdk_pixmap_foreign_new(id);
|
|
617 return p;
|
|
618 }
|
|
619 }
|
|
620 if (prop2 != None)
|
|
621 {
|
|
622
|
1
|
623 /* XGetWindowProperty(Xdisplay, desktop_window, prop2, 0L, 1L, False, AnyPropertyType,
|
|
624 &type, &format, &length, &after, &data);*/
|
12
|
625
|
1
|
626 /* if (type == XA_CARDINAL) {*/
|
12
|
627 /*
|
|
628 * D_PIXMAP((" Solid color not yet supported.\n"));
|
|
629 */
|
|
630
|
1
|
631 /* return NULL;
|
|
632 }*/
|
12
|
633 }
|
|
634 /*
|
|
635 * D_PIXMAP(("No suitable attribute found.\n"));
|
|
636 */
|
|
637 #endif
|
|
638 return NULL;
|
1
|
639 }
|
|
640
|
|
641
|
12
|
642 static void clear_focus_area(GtkHtml * html,
|
|
643 gint area_x,
|
|
644 gint area_y, gint area_width, gint area_height)
|
1
|
645 {
|
12
|
646 GtkWidget *widget = GTK_WIDGET(html);
|
|
647 gint x,
|
|
648 y;
|
|
649
|
|
650 gint ythick = BORDER_WIDTH + widget->style->klass->ythickness;
|
|
651 gint xthick = BORDER_WIDTH + widget->style->klass->xthickness;
|
|
652
|
|
653 gint width,
|
|
654 height;
|
|
655
|
|
656 if (html->frozen > 0)
|
|
657 return;
|
|
658
|
|
659 if (html->transparent)
|
|
660 {
|
1
|
661 if (html->pm == NULL)
|
|
662 html->pm = get_desktop_pixmap(widget);
|
|
663
|
12
|
664 if (html->pm == NULL)
|
|
665 return;
|
|
666
|
|
667 if (html->bg_gc == NULL)
|
|
668 {
|
1
|
669 GdkGCValues values;
|
|
670
|
12
|
671 values.tile = html->pm;
|
|
672 values.fill = GDK_TILED;
|
|
673
|
|
674 html->bg_gc = gdk_gc_new_with_values(html->html_area, &values,
|
|
675 GDK_GC_FILL | GDK_GC_TILE);
|
|
676
|
|
677 }
|
|
678
|
|
679 gdk_window_get_deskrelative_origin(widget->window, &x, &y);
|
1
|
680
|
|
681 gdk_draw_pixmap(widget->window, html->bg_gc, html->pm,
|
12
|
682 x + area_x, y + area_y, area_x, area_y, area_width,
|
|
683 area_height);
|
|
684
|
|
685
|
|
686 }
|
|
687 else
|
|
688 {
|
|
689 gdk_window_get_size(widget->style->bg_pixmap[GTK_STATE_NORMAL], &width,
|
|
690 &height);
|
|
691
|
|
692 gdk_gc_set_ts_origin(html->bg_gc,
|
|
693 (-html->xoffset + xthick) % width,
|
|
694 (-html->yoffset + ythick) % height);
|
|
695
|
|
696 gdk_draw_rectangle(widget->window, html->bg_gc, TRUE,
|
|
697 area_x, area_y, area_width, area_height);
|
|
698 }
|
1
|
699 }
|
|
700
|
12
|
701 static void gtk_html_draw_focus(GtkWidget * widget)
|
1
|
702 {
|
12
|
703 GtkHtml *html;
|
|
704 gint width,
|
|
705 height;
|
|
706 gint x,
|
|
707 y;
|
|
708
|
|
709 g_return_if_fail(widget != NULL);
|
|
710 g_return_if_fail(GTK_IS_HTML(widget));
|
1
|
711
|
|
712 html = GTK_HTML(widget);
|
|
713
|
12
|
714 if (GTK_WIDGET_DRAWABLE(widget))
|
|
715 {
|
|
716 gint ythick = widget->style->klass->ythickness;
|
|
717 gint xthick = widget->style->klass->xthickness;
|
|
718 gint xextra = BORDER_WIDTH;
|
|
719 gint yextra = BORDER_WIDTH;
|
|
720
|
|
721 x = 0;
|
|
722 y = 0;
|
|
723 width = widget->allocation.width;
|
|
724 height = widget->allocation.height;
|
|
725
|
|
726 if (GTK_WIDGET_HAS_FOCUS(widget))
|
|
727 {
|
|
728 x += 1;
|
|
729 y += 1;
|
|
730 width -= 2;
|
|
731 height -= 2;
|
|
732 xextra -= 1;
|
|
733 yextra -= 1;
|
|
734
|
|
735 gtk_paint_focus(widget->style, widget->window,
|
|
736 NULL, widget, "text",
|
|
737 0, 0,
|
|
738 widget->allocation.width - 1,
|
|
739 widget->allocation.height - 1);
|
|
740 }
|
|
741
|
|
742 gtk_paint_shadow(widget->style, widget->window,
|
|
743 GTK_STATE_NORMAL, GTK_SHADOW_IN,
|
|
744 NULL, widget, "text", x, y, width, height);
|
|
745
|
|
746 x += xthick;
|
|
747 y += ythick;
|
|
748 width -= 2 * xthick;
|
|
749 height -= 2 * ythick;
|
|
750
|
|
751
|
|
752 if (widget->style->bg_pixmap[GTK_STATE_NORMAL] || html->transparent)
|
|
753 {
|
|
754 /*
|
|
755 * top rect
|
|
756 */
|
|
757 clear_focus_area(html, x, y, width, yextra);
|
|
758 /*
|
|
759 * left rect
|
|
760 */
|
|
761 clear_focus_area(html, x, y + yextra,
|
|
762 xextra, y + height - 2 * yextra);
|
|
763 /*
|
|
764 * right rect
|
|
765 */
|
|
766 clear_focus_area(html, x + width - xextra, y + yextra,
|
|
767 xextra, height - 2 * ythick);
|
|
768 /*
|
|
769 * bottom rect
|
|
770 */
|
|
771 clear_focus_area(html, x, x + height - yextra, width, yextra);
|
|
772 }
|
|
773 }
|
1
|
774 }
|
|
775
|
12
|
776 static void gtk_html_size_request(GtkWidget * widget,
|
|
777 GtkRequisition * requisition)
|
1
|
778 {
|
12
|
779 gint xthickness;
|
|
780 gint ythickness;
|
|
781 gint char_height;
|
|
782 gint char_width;
|
|
783
|
|
784 g_return_if_fail(widget != NULL);
|
|
785 g_return_if_fail(GTK_IS_HTML(widget));
|
|
786 g_return_if_fail(requisition != NULL);
|
|
787
|
|
788 xthickness = widget->style->klass->xthickness + BORDER_WIDTH;
|
|
789 ythickness = widget->style->klass->ythickness + BORDER_WIDTH;
|
|
790
|
|
791 char_height = MIN_HTML_HEIGHT_LINES * (widget->style->font->ascent +
|
|
792 widget->style->font->descent);
|
|
793
|
|
794 char_width = MIN_HTML_WIDTH_LINES * (gdk_text_width(widget->style->font,
|
|
795 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
796 26) / 26);
|
|
797
|
|
798 requisition->width = char_width + xthickness * 2;
|
|
799 requisition->height = char_height + ythickness * 2;
|
1
|
800 }
|
|
801
|
12
|
802 static void gtk_html_size_allocate(GtkWidget * widget,
|
|
803 GtkAllocation * allocation)
|
1
|
804 {
|
12
|
805 GtkHtml *html;
|
|
806
|
|
807 g_return_if_fail(widget != NULL);
|
|
808 g_return_if_fail(GTK_IS_HTML(widget));
|
|
809 g_return_if_fail(allocation != NULL);
|
|
810
|
|
811 html = GTK_HTML(widget);
|
|
812
|
|
813 widget->allocation = *allocation;
|
|
814 if (GTK_WIDGET_REALIZED(widget))
|
|
815 {
|
|
816 gdk_window_move_resize(widget->window,
|
|
817 allocation->x, allocation->y,
|
|
818 allocation->width, allocation->height);
|
|
819
|
|
820 gdk_window_move_resize(html->html_area,
|
|
821 widget->style->klass->xthickness + BORDER_WIDTH,
|
|
822 widget->style->klass->ythickness + BORDER_WIDTH,
|
|
823 MAX(1, (gint) widget->allocation.width -
|
|
824 (gint) (widget->style->klass->xthickness +
|
|
825 (gint) BORDER_WIDTH) * 2),
|
|
826 MAX(1, (gint) widget->allocation.height -
|
|
827 (gint) (widget->style->klass->ythickness +
|
|
828 (gint) BORDER_WIDTH) * 2));
|
|
829
|
|
830 resize_html(html);
|
|
831 }
|
|
832 }
|
|
833
|
|
834 static void gtk_html_draw(GtkWidget * widget, GdkRectangle * area)
|
|
835 {
|
|
836 g_return_if_fail(widget != NULL);
|
|
837 g_return_if_fail(GTK_IS_HTML(widget));
|
|
838 g_return_if_fail(area != NULL);
|
|
839
|
|
840 if (GTK_WIDGET_DRAWABLE(widget))
|
|
841 {
|
|
842 expose_html(GTK_HTML(widget), area, TRUE);
|
|
843 gtk_widget_draw_focus(widget);
|
|
844 }
|
|
845 }
|
|
846
|
|
847
|
|
848 static gint gtk_html_expose(GtkWidget * widget, GdkEventExpose * event)
|
|
849 {
|
|
850 GtkHtml *html;
|
|
851
|
|
852 g_return_val_if_fail(widget != NULL, FALSE);
|
|
853 g_return_val_if_fail(GTK_IS_HTML(widget), FALSE);
|
|
854 g_return_val_if_fail(event != NULL, FALSE);
|
|
855
|
|
856 html = GTK_HTML(widget);
|
|
857
|
|
858 if (event->window == html->html_area)
|
|
859 {
|
|
860 expose_html(html, &event->area, TRUE);
|
|
861 }
|
|
862 else if (event->count == 0)
|
|
863 {
|
|
864 gtk_widget_draw_focus(widget);
|
|
865 }
|
|
866
|
|
867 return FALSE;
|
1
|
868
|
|
869 }
|
|
870
|
|
871
|
12
|
872 static gint gtk_html_selection_clear(GtkWidget * widget,
|
|
873 GdkEventSelection * event)
|
1
|
874 {
|
12
|
875 GtkHtml *html;
|
|
876
|
|
877 g_return_val_if_fail(widget != NULL, FALSE);
|
|
878 g_return_val_if_fail(GTK_IS_HTML(widget), FALSE);
|
|
879 g_return_val_if_fail(event != NULL, FALSE);
|
|
880
|
|
881 /*
|
|
882 * Let the selection handling code know that the selection
|
|
883 * * has been changed, since we've overriden the default handler
|
|
884 */
|
|
885 if (!gtk_selection_clear(widget, event))
|
|
886 return FALSE;
|
|
887
|
|
888 html = GTK_HTML(widget);
|
|
889
|
|
890 if (event->selection == GDK_SELECTION_PRIMARY)
|
|
891 {
|
|
892 if (html->selected_text)
|
|
893 {
|
|
894 GList *hbits = html->html_bits;
|
|
895 GtkHtmlBit *hb;
|
|
896
|
1
|
897 g_free(html->selected_text);
|
|
898 html->selected_text = NULL;
|
|
899 html->start_sel = NULL;
|
|
900 html->end_sel = NULL;
|
|
901 html->num_start = 0;
|
|
902 html->num_end = 0;
|
12
|
903 while (hbits)
|
|
904 {
|
|
905 hb = (GtkHtmlBit *) hbits->data;
|
1
|
906 if (hb->was_selected)
|
|
907 gtk_html_draw_bit(html, hb, 1);
|
|
908 hbits = hbits->prev;
|
|
909 }
|
|
910 hbits = g_list_last(html->html_bits);
|
|
911 }
|
12
|
912 }
|
|
913
|
|
914 return TRUE;
|
1
|
915 }
|
|
916
|
|
917
|
|
918
|
12
|
919 static void gtk_html_selection_get(GtkWidget * widget,
|
|
920 GtkSelectionData * selection_data,
|
|
921 guint sel_info, guint32 time)
|
1
|
922 {
|
|
923 gchar *str;
|
12
|
924 gint len;
|
|
925 GtkHtml *html;
|
|
926
|
|
927 g_return_if_fail(widget != NULL);
|
|
928 g_return_if_fail(GTK_IS_HTML(widget));
|
|
929
|
|
930 html = GTK_HTML(widget);
|
|
931
|
|
932
|
1
|
933 if (selection_data->selection != GDK_SELECTION_PRIMARY)
|
|
934 return;
|
|
935
|
|
936 str = html->selected_text;
|
|
937
|
|
938 if (!str)
|
|
939 return;
|
12
|
940
|
1
|
941 len = strlen(str);
|
|
942
|
12
|
943 if (sel_info == TARGET_STRING)
|
|
944 {
|
1
|
945 gtk_selection_data_set(selection_data,
|
12
|
946 GDK_SELECTION_TYPE_STRING,
|
|
947 8 * sizeof(gchar), (guchar *) str, len);
|
|
948 }
|
|
949 else if ((sel_info == TARGET_TEXT) || (sel_info == TARGET_COMPOUND_TEXT))
|
|
950 {
|
1
|
951 guchar *text;
|
|
952 GdkAtom encoding;
|
|
953 gint format;
|
|
954 gint new_length;
|
|
955
|
12
|
956 gdk_string_to_compound_text(str, &encoding, &format, &text,
|
|
957 &new_length);
|
|
958 gtk_selection_data_set(selection_data, encoding, format, text,
|
|
959 new_length);
|
|
960 gdk_free_compound_text(text);
|
1
|
961 }
|
|
962
|
|
963
|
|
964
|
|
965 }
|
|
966
|
12
|
967 static void do_select(GtkHtml * html, int x, int y)
|
1
|
968 {
|
|
969 GList *hbits = g_list_last(html->html_bits);
|
12
|
970 int epos,
|
|
971 spos;
|
1
|
972 GtkHtmlBit *hb;
|
12
|
973
|
1
|
974 if (!hbits)
|
|
975 return;
|
12
|
976
|
|
977 hb = (GtkHtmlBit *) hbits->data;
|
|
978
|
|
979 while (hbits)
|
|
980 {
|
|
981 hb = (GtkHtmlBit *) hbits->data;
|
|
982 if (hb->type == HTML_BIT_TEXT)
|
1
|
983 break;
|
|
984 hbits = hbits->prev;
|
12
|
985 }
|
|
986
|
1
|
987 if (!hb)
|
12
|
988 return;
|
|
989
|
|
990
|
|
991 if (y > hb->y)
|
|
992 {
|
1
|
993 html->num_end = strlen(hb->text) - 1;
|
|
994 html->end_sel = hb;
|
12
|
995 }
|
|
996 else if (y < 0)
|
|
997 {
|
1
|
998 html->num_end = 0;
|
12
|
999 html->end_sel = (GtkHtmlBit *) html->html_bits->data;
|
|
1000 }
|
|
1001 else
|
|
1002 while (hbits)
|
|
1003 {
|
|
1004 hb = (GtkHtmlBit *) hbits->data;
|
|
1005 if ((y < hb->y && y > (hb->y - hb->height)) &&
|
|
1006 (x > hb->x + hb->width))
|
|
1007 {
|
|
1008 if (hb->type != HTML_BIT_TEXT)
|
|
1009 {
|
|
1010 html->num_end = 0;
|
|
1011 html->end_sel = hb;
|
|
1012 break;
|
|
1013 }
|
|
1014
|
|
1015 html->num_end = strlen(hb->text) - 1;
|
1
|
1016 html->end_sel = hb;
|
|
1017 break;
|
|
1018 }
|
12
|
1019 else if ((x > hb->x && x < (hb->x + hb->width)) &&
|
|
1020 (y < hb->y && y > (hb->y - hb->height)))
|
|
1021 {
|
|
1022 int i,
|
|
1023 len;
|
|
1024 int w = x - hb->x;
|
|
1025
|
|
1026 if (hb->type != HTML_BIT_TEXT)
|
|
1027 {
|
|
1028 html->num_end = 0;
|
1
|
1029 html->end_sel = hb;
|
|
1030 break;
|
|
1031 }
|
12
|
1032
|
|
1033 len = strlen(hb->text);
|
|
1034
|
|
1035 for (i = 1; i <= len; i++)
|
|
1036 {
|
|
1037 if (gdk_text_measure(hb->font, hb->text, i) > w)
|
|
1038 {
|
|
1039 html->num_end = i - 1;
|
|
1040 html->end_sel = hb;
|
|
1041 break;
|
|
1042 }
|
|
1043 }
|
|
1044 break;
|
1
|
1045 }
|
12
|
1046 hbits = hbits->prev;
|
1
|
1047 }
|
|
1048
|
|
1049 if (html->end_sel == NULL)
|
|
1050 return;
|
12
|
1051 if (html->start_sel == NULL)
|
|
1052 {
|
1
|
1053 html->start_sel = html->end_sel;
|
|
1054 html->num_start = html->num_end;
|
|
1055 }
|
12
|
1056
|
1
|
1057 epos = g_list_index(html->html_bits, html->end_sel);
|
|
1058 spos = g_list_index(html->html_bits, html->start_sel);
|
|
1059 g_free(html->selected_text);
|
|
1060 html->selected_text = NULL;
|
|
1061
|
12
|
1062 if (epos == spos)
|
|
1063 {
|
1
|
1064 char *str;
|
12
|
1065 if (html->start_sel->type != HTML_BIT_TEXT)
|
|
1066 {
|
1
|
1067 html->selected_text = NULL;
|
|
1068 return;
|
|
1069 }
|
12
|
1070 if (html->num_end == html->num_start)
|
|
1071 {
|
1
|
1072 str = g_malloc(2);
|
12
|
1073 if (strlen(html->start_sel->text))
|
1
|
1074 str[0] = html->start_sel->text[html->num_end];
|
|
1075 else
|
12
|
1076 str[0] = 0;
|
1
|
1077 str[1] = 0;
|
|
1078 gtk_html_draw_bit(html, html->start_sel, 0);
|
|
1079 html->selected_text = str;
|
12
|
1080 }
|
|
1081 else
|
|
1082 {
|
79
|
1083 size_t st,
|
12
|
1084 en;
|
1
|
1085 char *str;
|
12
|
1086 if (html->num_end > html->num_start)
|
|
1087 {
|
1
|
1088 en = html->num_end;
|
|
1089 st = html->num_start;
|
12
|
1090 }
|
|
1091 else
|
|
1092 {
|
1
|
1093 en = html->num_start;
|
|
1094 st = html->num_end;
|
|
1095 }
|
|
1096
|
|
1097 str = g_malloc(en - st + 2);
|
|
1098 strncpy(str, html->start_sel->text + st, (en - st + 1));
|
|
1099 str[en - st + 1] = 0;
|
12
|
1100 gtk_html_draw_bit(html, html->start_sel, 0);
|
1
|
1101 html->selected_text = str;
|
12
|
1102
|
1
|
1103 }
|
12
|
1104 }
|
|
1105 else
|
|
1106 {
|
|
1107 GtkHtmlBit *shb,
|
|
1108 *ehb;
|
79
|
1109 size_t en,
|
12
|
1110 st;
|
|
1111 int len,
|
|
1112 nlen;
|
1
|
1113 char *str;
|
12
|
1114 if (epos > spos)
|
|
1115 {
|
1
|
1116 shb = html->start_sel;
|
|
1117 ehb = html->end_sel;
|
|
1118 en = html->num_end;
|
|
1119 st = html->num_start;
|
12
|
1120 }
|
|
1121 else
|
|
1122 {
|
1
|
1123 shb = html->end_sel;
|
|
1124 ehb = html->start_sel;
|
|
1125 en = html->num_start;
|
|
1126 st = html->num_end;
|
|
1127 }
|
12
|
1128
|
1
|
1129 hbits = g_list_find(html->html_bits, shb);
|
|
1130
|
|
1131 if (!hbits)
|
|
1132 return;
|
12
|
1133
|
|
1134 if (shb->type == HTML_BIT_TEXT)
|
|
1135 {
|
1
|
1136 len = strlen(shb->text) - st + 1;
|
|
1137 str = g_malloc(len);
|
|
1138 strcpy(str, shb->text + st);
|
|
1139 str[len - 1] = 0;
|
|
1140 gtk_html_draw_bit(html, shb, 0);
|
12
|
1141 if (shb->newline)
|
|
1142 {
|
|
1143 len += 1;
|
1
|
1144 str = g_realloc(str, len);
|
|
1145 str[len - 2] = '\n';
|
|
1146 str[len - 1] = 0;
|
|
1147 }
|
12
|
1148 }
|
|
1149 else
|
|
1150 {
|
1
|
1151 len = 1;
|
|
1152 str = g_malloc(1);
|
|
1153 str[0] = 0;
|
|
1154 }
|
12
|
1155 if (hbits->next == NULL)
|
|
1156 {
|
1
|
1157 html->selected_text = str;
|
|
1158 return;
|
|
1159 }
|
|
1160
|
12
|
1161
|
|
1162 hbits = hbits->next;
|
|
1163 while (1)
|
|
1164 { /*
|
|
1165 * Yah I know is dangerous :P
|
|
1166 */
|
|
1167 hb = (GtkHtmlBit *) hbits->data;
|
|
1168 if (hb->type != HTML_BIT_TEXT)
|
|
1169 {
|
1
|
1170 if (hb == ehb)
|
|
1171 break;
|
|
1172 hbits = hbits->next;
|
|
1173 continue;
|
|
1174 }
|
12
|
1175 if (hb != ehb)
|
|
1176 {
|
1
|
1177 nlen = len + strlen(hb->text);
|
|
1178 str = g_realloc(str, nlen);
|
|
1179 strcpy(str + (len - 1), hb->text);
|
|
1180 len = nlen;
|
|
1181 str[len - 1] = 0;
|
|
1182 gtk_html_draw_bit(html, hb, 0);
|
12
|
1183 if (hb->newline)
|
|
1184 {
|
|
1185 len += 1;
|
1
|
1186 str = g_realloc(str, len);
|
|
1187 str[len - 2] = '\n';
|
|
1188 str[len - 1] = 0;
|
|
1189 }
|
12
|
1190 }
|
|
1191 else
|
|
1192 {
|
1
|
1193 nlen = len + en + 1;
|
|
1194 str = g_realloc(str, nlen);
|
|
1195 strncpy(str + (len - 1), hb->text, en + 1);
|
|
1196 len = nlen;
|
|
1197 str[len - 1] = 0;
|
12
|
1198
|
1
|
1199 gtk_html_draw_bit(html, hb, 0);
|
12
|
1200 if (hb->newline && en == strlen(hb->text))
|
|
1201 {
|
|
1202 len += 1;
|
1
|
1203 str = g_realloc(str, len);
|
|
1204 str[len - 2] = '\n';
|
|
1205 str[len - 1] = 0;
|
|
1206 }
|
|
1207 break;
|
|
1208 }
|
|
1209 hbits = hbits->next;
|
|
1210 }
|
|
1211 html->selected_text = str;
|
|
1212 }
|
|
1213
|
|
1214 }
|
|
1215
|
12
|
1216 static gint scroll_timeout(GtkHtml * html)
|
1
|
1217 {
|
12
|
1218 GdkEventMotion event;
|
|
1219 gint x,
|
|
1220 y;
|
|
1221 GdkModifierType mask;
|
1
|
1222
|
|
1223 html->timer = 0;
|
12
|
1224 gdk_window_get_pointer(html->html_area, &x, &y, &mask);
|
|
1225
|
1
|
1226 if (mask & GDK_BUTTON1_MASK)
|
|
1227 {
|
|
1228 event.is_hint = 0;
|
|
1229 event.x = x;
|
|
1230 event.y = y;
|
|
1231 event.state = mask;
|
|
1232
|
12
|
1233 gtk_html_motion_notify(GTK_WIDGET(html), &event);
|
1
|
1234 }
|
|
1235
|
|
1236 return FALSE;
|
|
1237
|
|
1238 }
|
|
1239
|
|
1240
|
12
|
1241 static gint gtk_html_tooltip_paint_window(GtkHtml * html)
|
1
|
1242 {
|
|
1243 GtkStyle *style;
|
12
|
1244 gint y,
|
|
1245 baseline_skip,
|
|
1246 gap;
|
1
|
1247
|
|
1248 style = html->tooltip_window->style;
|
|
1249
|
|
1250 gap = (style->font->ascent + style->font->descent) / 4;
|
|
1251 if (gap < 2)
|
|
1252 gap = 2;
|
|
1253 baseline_skip = style->font->ascent + style->font->descent + gap;
|
|
1254
|
|
1255 if (!html->tooltip_hb)
|
|
1256 return FALSE;
|
|
1257
|
|
1258 gtk_paint_flat_box(style, html->tooltip_window->window,
|
12
|
1259 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
|
|
1260 NULL, GTK_WIDGET(html->tooltip_window), "tooltip",
|
|
1261 0, 0, -1, -1);
|
1
|
1262
|
|
1263 y = style->font->ascent + 4;
|
|
1264
|
12
|
1265 gtk_paint_string(style, html->tooltip_window->window,
|
|
1266 GTK_STATE_NORMAL,
|
|
1267 NULL, GTK_WIDGET(html->tooltip_window), "tooltip",
|
|
1268 4, y, "HTML Link:");
|
1
|
1269 y += baseline_skip;
|
12
|
1270 gtk_paint_string(style, html->tooltip_window->window,
|
|
1271 GTK_STATE_NORMAL,
|
|
1272 NULL, GTK_WIDGET(html->tooltip_window), "tooltip",
|
|
1273 4, y, html->tooltip_hb->url);
|
|
1274
|
1
|
1275 return FALSE;
|
|
1276
|
|
1277
|
|
1278 }
|
|
1279
|
|
1280 static gint gtk_html_tooltip_timeout(gpointer data)
|
|
1281 {
|
12
|
1282 GtkHtml *html = (GtkHtml *) data;
|
|
1283
|
|
1284
|
1
|
1285 GDK_THREADS_ENTER();
|
|
1286
|
12
|
1287 if (html->tooltip_hb && GTK_WIDGET_DRAWABLE(GTK_WIDGET(html)))
|
|
1288 {
|
1
|
1289 GtkWidget *widget;
|
|
1290 GtkStyle *style;
|
12
|
1291 gint gap,
|
|
1292 x,
|
|
1293 y,
|
|
1294 w,
|
|
1295 h,
|
|
1296 scr_w,
|
|
1297 scr_h,
|
|
1298 baseline_skip;
|
1
|
1299
|
|
1300 if (html->tooltip_window)
|
|
1301 gtk_widget_destroy(html->tooltip_window);
|
12
|
1302
|
|
1303 html->tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
|
|
1304 gtk_widget_set_app_paintable(html->tooltip_window, TRUE);
|
|
1305 gtk_window_set_policy(GTK_WINDOW(html->tooltip_window), FALSE, FALSE,
|
|
1306 TRUE);
|
|
1307 gtk_widget_set_name(html->tooltip_window, "gtk-tooltips");
|
|
1308 gtk_signal_connect_object(GTK_OBJECT(html->tooltip_window),
|
|
1309 "expose_event",
|
|
1310 GTK_SIGNAL_FUNC
|
|
1311 (gtk_html_tooltip_paint_window),
|
|
1312 GTK_OBJECT(html));
|
|
1313 gtk_signal_connect_object(GTK_OBJECT(html->tooltip_window), "draw",
|
|
1314 GTK_SIGNAL_FUNC
|
|
1315 (gtk_html_tooltip_paint_window),
|
|
1316 GTK_OBJECT(html));
|
|
1317
|
|
1318 gtk_widget_ensure_style(html->tooltip_window);
|
1
|
1319 style = html->tooltip_window->style;
|
12
|
1320
|
1
|
1321 widget = GTK_WIDGET(html);
|
|
1322
|
12
|
1323 scr_w = gdk_screen_width();
|
|
1324 scr_h = gdk_screen_height();
|
1
|
1325
|
|
1326 gap = (style->font->ascent + style->font->descent) / 4;
|
|
1327 if (gap < 2)
|
|
1328 gap = 2;
|
|
1329 baseline_skip = style->font->ascent + style->font->descent + gap;
|
|
1330
|
|
1331 w = 8 + MAX(gdk_string_width(style->font, "HTML Link:"),
|
12
|
1332 gdk_string_width(style->font, html->tooltip_hb->url));
|
|
1333 ;
|
1
|
1334 h = 8 - gap;
|
12
|
1335 h += (baseline_skip * 2);
|
|
1336
|
|
1337 gdk_window_get_pointer(NULL, &x, &y, NULL);
|
|
1338 /*
|
|
1339 * gdk_window_get_origin (widget->window, NULL, &y);
|
|
1340 */
|
|
1341 if (GTK_WIDGET_NO_WINDOW(widget))
|
1
|
1342 y += widget->allocation.y;
|
|
1343
|
|
1344 x -= ((w >> 1) + 4);
|
|
1345
|
|
1346 if ((x + w) > scr_w)
|
|
1347 x -= (x + w) - scr_w;
|
|
1348 else if (x < 0)
|
|
1349 x = 0;
|
|
1350
|
|
1351 if ((y + h + 4) > scr_h)
|
12
|
1352 y =
|
|
1353 y - html->tooltip_hb->font->ascent +
|
|
1354 html->tooltip_hb->font->descent;
|
1
|
1355 else
|
12
|
1356 y =
|
|
1357 y + html->tooltip_hb->font->ascent +
|
|
1358 html->tooltip_hb->font->descent;
|
|
1359
|
|
1360 gtk_widget_set_usize(html->tooltip_window, w, h);
|
|
1361 gtk_widget_popup(html->tooltip_window, x, y);
|
|
1362
|
1
|
1363 }
|
|
1364
|
|
1365 html->tooltip_timer = -1;
|
12
|
1366
|
1
|
1367 GDK_THREADS_LEAVE();
|
|
1368
|
|
1369 return FALSE;
|
|
1370 }
|
|
1371
|
|
1372
|
12
|
1373 static gint gtk_html_leave_notify(GtkWidget * widget, GdkEventCrossing * event)
|
1
|
1374 {
|
12
|
1375 GtkHtml *html;
|
|
1376
|
|
1377 html = GTK_HTML(widget);
|
|
1378
|
|
1379 if (html->tooltip_timer != -1)
|
|
1380 gtk_timeout_remove(html->tooltip_timer);
|
|
1381 if (html->tooltip_window)
|
|
1382 {
|
|
1383 gtk_widget_destroy(html->tooltip_window);
|
|
1384 html->tooltip_window = NULL;
|
|
1385 }
|
|
1386
|
|
1387
|
|
1388 html->tooltip_hb = NULL;
|
|
1389 return TRUE;
|
1
|
1390 }
|
|
1391
|
|
1392
|
12
|
1393 static gint gtk_html_motion_notify(GtkWidget * widget, GdkEventMotion * event)
|
1
|
1394 {
|
12
|
1395 int x,
|
|
1396 y;
|
|
1397 gint width,
|
|
1398 height;
|
|
1399 GdkModifierType state;
|
|
1400 int realx,
|
|
1401 realy;
|
|
1402 GtkHtml *html = GTK_HTML(widget);
|
|
1403
|
|
1404 if (event->is_hint)
|
|
1405 gdk_window_get_pointer(event->window, &x, &y, &state);
|
|
1406 else
|
|
1407 {
|
|
1408 x = event->x;
|
|
1409 y = event->y;
|
|
1410 state = event->state;
|
|
1411 }
|
|
1412
|
|
1413 gdk_window_get_size(html->html_area, &width, &height);
|
|
1414
|
1
|
1415 realx = x;
|
|
1416 realy = y + html->yoffset;
|
|
1417
|
|
1418
|
12
|
1419 if (state & GDK_BUTTON1_MASK)
|
|
1420 {
|
|
1421 if (realx != html->start_sel_x || realy != html->start_sel_y)
|
|
1422 {
|
1
|
1423 char *tmp = NULL;
|
|
1424
|
12
|
1425 if (y < 0 || y > height)
|
|
1426 {
|
1
|
1427 int diff;
|
12
|
1428 if (html->timer == 0)
|
|
1429 {
|
1
|
1430 html->timer = gtk_timeout_add(100,
|
12
|
1431 (GtkFunction) scroll_timeout,
|
|
1432 html);
|
1
|
1433 if (y < 0)
|
|
1434 diff = y / 2;
|
|
1435 else
|
|
1436 diff = (y - height) / 2;
|
|
1437
|
|
1438 if (html->vadj->value + diff >
|
12
|
1439 html->vadj->upper - height + 20)
|
1
|
1440 gtk_adjustment_set_value(html->vadj,
|
12
|
1441 html->vadj->upper - height +
|
|
1442 20);
|
1
|
1443 else
|
|
1444 gtk_adjustment_set_value(html->vadj,
|
12
|
1445 html->vadj->value + diff);
|
1
|
1446
|
|
1447 }
|
|
1448 }
|
12
|
1449
|
1
|
1450 if (html->selected_text != NULL)
|
|
1451 tmp = g_strdup(html->selected_text);
|
|
1452 do_select(html, realx, realy);
|
12
|
1453 if (tmp)
|
|
1454 {
|
|
1455 if (!html->selected_text || strcmp(tmp, html->selected_text))
|
|
1456 {
|
1
|
1457 GtkHtmlBit *hb;
|
|
1458 GList *hbits = html->html_bits;
|
12
|
1459 while (hbits)
|
|
1460 {
|
|
1461 hb = (GtkHtmlBit *) hbits->data;
|
1
|
1462 if (hb->was_selected)
|
|
1463 gtk_html_draw_bit(html, hb, 0);
|
|
1464 hbits = hbits->next;
|
|
1465 }
|
|
1466 }
|
|
1467 g_free(tmp);
|
|
1468 }
|
|
1469 }
|
12
|
1470 }
|
|
1471 else
|
|
1472 {
|
1
|
1473 GtkHtmlBit *hb;
|
|
1474 GList *urls;
|
|
1475
|
|
1476 urls = html->urls;
|
12
|
1477 while (urls)
|
|
1478 {
|
|
1479 hb = (GtkHtmlBit *) urls->data;
|
1
|
1480 if ((realx > hb->x && realx < (hb->x + hb->width)) &&
|
12
|
1481 (realy < hb->y && realy > (hb->y - hb->height)))
|
|
1482 {
|
26
|
1483 GdkCursor *cursor = NULL;
|
|
1484
|
12
|
1485 if (html->tooltip_hb != hb)
|
|
1486 {
|
1
|
1487 html->tooltip_hb = hb;
|
|
1488 if (html->tooltip_timer != -1)
|
|
1489 gtk_timeout_remove(html->tooltip_timer);
|
12
|
1490 if (html->tooltip_window)
|
|
1491 {
|
1
|
1492 gtk_widget_destroy(html->tooltip_window);
|
|
1493 html->tooltip_window = NULL;
|
|
1494 }
|
12
|
1495 html->tooltip_timer =
|
|
1496 gtk_timeout_add(HTML_TOOLTIP_DELAY,
|
|
1497 gtk_html_tooltip_timeout, html);
|
1
|
1498 }
|
26
|
1499
|
|
1500 cursor = gdk_cursor_new(GDK_HAND2);
|
|
1501 gdk_window_set_cursor(html->html_area, cursor);
|
|
1502 gdk_cursor_destroy(cursor);
|
|
1503
|
1
|
1504 return TRUE;
|
|
1505 }
|
12
|
1506 urls = urls->next;
|
1
|
1507 }
|
|
1508 if (html->tooltip_timer != -1)
|
|
1509 gtk_timeout_remove(html->tooltip_timer);
|
12
|
1510 if (html->tooltip_window)
|
|
1511 {
|
1
|
1512 gtk_widget_destroy(html->tooltip_window);
|
|
1513 html->tooltip_window = NULL;
|
|
1514 }
|
12
|
1515
|
|
1516
|
|
1517 html->tooltip_hb = NULL;
|
1
|
1518 gdk_window_set_cursor(html->html_area, NULL);
|
|
1519
|
|
1520
|
|
1521 }
|
|
1522
|
|
1523 return TRUE;
|
|
1524 }
|
|
1525
|
12
|
1526 static gint gtk_html_button_release(GtkWidget * widget, GdkEventButton * event)
|
1
|
1527 {
|
12
|
1528 GtkHtml *html;
|
|
1529
|
|
1530 html = GTK_HTML(widget);
|
|
1531
|
|
1532 if (html->frozen > 0)
|
|
1533 return TRUE;
|
|
1534
|
|
1535 if (event->button == 1)
|
|
1536 {
|
|
1537 int realx,
|
|
1538 realy;
|
|
1539 GtkHtmlBit *hb;
|
|
1540 GList *urls = html->urls;
|
|
1541
|
|
1542 realx = event->x;
|
|
1543 realy = event->y + html->yoffset;
|
|
1544 if (realx != html->start_sel_x || realy != html->start_sel_y)
|
|
1545 {
|
|
1546 if (gtk_selection_owner_set(widget,
|
|
1547 GDK_SELECTION_PRIMARY, event->time))
|
|
1548 {
|
|
1549 }
|
|
1550 else
|
|
1551 {
|
|
1552 }
|
|
1553 }
|
|
1554 else
|
|
1555 {
|
|
1556 if (gdk_selection_owner_get(GDK_SELECTION_PRIMARY) ==
|
|
1557 widget->window)
|
1
|
1558 gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY,
|
12
|
1559 event->time);
|
|
1560
|
|
1561
|
|
1562 while (urls)
|
|
1563 {
|
|
1564 void open_url_nw(GtkWidget * w, char *url);
|
|
1565 hb = (GtkHtmlBit *) urls->data;
|
1
|
1566 if ((realx > hb->x && realx < (hb->x + hb->width)) &&
|
12
|
1567 (realy < hb->y && realy > (hb->y - hb->height)))
|
|
1568 {
|
|
1569 open_url_nw(NULL, hb->url);
|
|
1570 // else
|
|
1571 // open_url(NULL, hb->url);
|
1
|
1572 break;
|
|
1573 }
|
|
1574 urls = urls->next;
|
|
1575 }
|
|
1576 }
|
|
1577 }
|
|
1578 return TRUE;
|
|
1579 }
|
|
1580
|
|
1581
|
|
1582
|
12
|
1583 static gint gtk_html_button_press(GtkWidget * widget, GdkEventButton * event)
|
1
|
1584 {
|
12
|
1585 GtkHtml *html;
|
|
1586 gfloat value;
|
|
1587
|
|
1588
|
|
1589 html = GTK_HTML(widget);
|
|
1590 value = html->vadj->value;
|
|
1591
|
|
1592 if (html->frozen > 0)
|
|
1593 return TRUE;
|
|
1594
|
|
1595 if (event->button == 4)
|
|
1596 {
|
1
|
1597 value -= html->vadj->step_increment;
|
|
1598 if (value < html->vadj->lower)
|
|
1599 value = html->vadj->lower;
|
12
|
1600 gtk_adjustment_set_value(html->vadj, value);
|
|
1601 }
|
|
1602 else if (event->button == 5)
|
|
1603 {
|
1
|
1604 value += html->vadj->step_increment;
|
|
1605 if (value > html->vadj->upper)
|
|
1606 value = html->vadj->upper;
|
12
|
1607 gtk_adjustment_set_value(html->vadj, value);
|
|
1608
|
|
1609 }
|
|
1610 else if (event->button == 1)
|
|
1611 {
|
|
1612 GList *hbits = g_list_last(html->html_bits);
|
|
1613 int realx,
|
|
1614 realy;
|
1
|
1615 GtkHtmlBit *hb;
|
|
1616
|
|
1617 realx = event->x;
|
|
1618 realy = event->y + html->yoffset;
|
|
1619
|
|
1620 html->start_sel_x = realx;
|
|
1621 html->start_sel_y = realy;
|
|
1622
|
|
1623 if (!hbits)
|
|
1624 return TRUE;
|
|
1625
|
12
|
1626 if (html->selected_text)
|
|
1627 {
|
1
|
1628 g_free(html->selected_text);
|
|
1629 html->selected_text = NULL;
|
|
1630 html->start_sel = NULL;
|
|
1631 html->end_sel = NULL;
|
|
1632 html->num_start = 0;
|
|
1633 html->num_end = 0;
|
12
|
1634 while (hbits)
|
|
1635 {
|
|
1636 hb = (GtkHtmlBit *) hbits->data;
|
1
|
1637 if (hb->was_selected)
|
|
1638 gtk_html_draw_bit(html, hb, 1);
|
|
1639 hbits = hbits->prev;
|
|
1640 }
|
|
1641 hbits = g_list_last(html->html_bits);
|
|
1642 }
|
|
1643
|
12
|
1644 hb = (GtkHtmlBit *) hbits->data;
|
|
1645 if (realy > hb->y)
|
|
1646 {
|
1
|
1647 if (hb->text)
|
|
1648 html->num_start = strlen(hb->text) - 1;
|
|
1649 else
|
12
|
1650 html->num_start = 0;
|
1
|
1651 html->start_sel = hb;
|
12
|
1652 }
|
|
1653 else
|
|
1654 while (hbits)
|
|
1655 {
|
|
1656 hb = (GtkHtmlBit *) hbits->data;
|
|
1657 if ((realy < hb->y && realy > (hb->y - hb->height)) &&
|
|
1658 (realx > hb->x + hb->width))
|
|
1659 {
|
|
1660 if (hb->type != HTML_BIT_TEXT)
|
|
1661 {
|
|
1662 html->num_end = 0;
|
|
1663 html->end_sel = hb;
|
|
1664 break;
|
|
1665 }
|
|
1666
|
|
1667 if (hb->text)
|
|
1668 html->num_start = strlen(hb->text) - 1;
|
|
1669 else
|
|
1670 html->num_start = 0;
|
|
1671
|
|
1672 html->start_sel = hb;
|
1
|
1673 break;
|
|
1674 }
|
12
|
1675 else if ((realx > hb->x && realx < (hb->x + hb->width)) &&
|
|
1676 (realy < hb->y && realy > (hb->y - hb->height)))
|
|
1677 {
|
|
1678 int i,
|
|
1679 len;
|
|
1680 int w = realx - hb->x;
|
|
1681
|
|
1682 if (hb->type != HTML_BIT_TEXT)
|
|
1683 {
|
|
1684 html->num_end = 0;
|
|
1685 html->end_sel = hb;
|
|
1686 break;
|
|
1687 }
|
|
1688
|
|
1689 if (hb->text)
|
|
1690 len = strlen(hb->text);
|
|
1691 else
|
|
1692 len = 0;
|
|
1693
|
|
1694 for (i = 1; i <= len; i++)
|
|
1695 {
|
|
1696 if (gdk_text_measure(hb->font, hb->text, i) > w)
|
|
1697 {
|
|
1698 html->num_start = i - 1;
|
|
1699 html->start_sel = hb;
|
|
1700 break;
|
|
1701 }
|
|
1702 }
|
1
|
1703 break;
|
|
1704 }
|
12
|
1705 hbits = hbits->prev;
|
1
|
1706 }
|
12
|
1707 }
|
|
1708 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
|
|
1709 {
|
1
|
1710 GtkHtmlBit *hb = NULL;
|
12
|
1711 int realx,
|
|
1712 realy;
|
|
1713 GList *urls;
|
|
1714
|
1
|
1715 realx = event->x;
|
|
1716 realy = event->y + html->yoffset;
|
12
|
1717
|
1
|
1718 urls = html->urls;
|
12
|
1719 while (urls)
|
|
1720 {
|
|
1721 hb = (GtkHtmlBit *) urls->data;
|
1
|
1722 if ((realx > hb->x && realx < (hb->x + hb->width)) &&
|
12
|
1723 (realy < hb->y && realy > (hb->y - hb->height)))
|
|
1724 {
|
1
|
1725 break;
|
|
1726 }
|
12
|
1727 urls = urls->next;
|
1
|
1728 hb = NULL;
|
|
1729 }
|
12
|
1730
|
|
1731 if (hb != NULL)
|
|
1732 {
|
69
|
1733
|
|
1734 GtkWidget *menu, *button;
|
|
1735
|
|
1736 menu = gtk_menu_new();
|
|
1737
|
|
1738 if (web_browser == BROWSER_NETSCAPE) {
|
|
1739
|
|
1740 button = gtk_menu_item_new_with_label("Open URL in existing window");
|
|
1741 gtk_signal_connect(GTK_OBJECT(button), "activate",
|
|
1742 GTK_SIGNAL_FUNC(open_url), hb->url);
|
|
1743 gtk_menu_append(GTK_MENU(menu), button);
|
|
1744 gtk_widget_show(button);
|
|
1745
|
|
1746 }
|
|
1747
|
|
1748
|
|
1749 button = gtk_menu_item_new_with_label("Open URL in new window");
|
|
1750 gtk_signal_connect(GTK_OBJECT(button), "activate",
|
|
1751 GTK_SIGNAL_FUNC(open_url_nw), hb->url);
|
|
1752 gtk_menu_append(GTK_MENU(menu), button);
|
|
1753 gtk_widget_show(button);
|
|
1754
|
|
1755 if (web_browser == BROWSER_NETSCAPE) {
|
|
1756
|
|
1757 button = gtk_menu_item_new_with_label("Add URL as bookmark");
|
|
1758 gtk_signal_connect(GTK_OBJECT(button), "activate",
|
|
1759 GTK_SIGNAL_FUNC(add_bookmark), hb->url);
|
|
1760 gtk_menu_append(GTK_MENU(menu), button);
|
|
1761 gtk_widget_show(button);
|
|
1762
|
|
1763 }
|
|
1764
|
|
1765 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
|
|
1766 event->button, event->time);
|
|
1767
|
12
|
1768 }
|
1
|
1769 }
|
12
|
1770
|
1
|
1771 return TRUE;
|
|
1772 }
|
|
1773
|
|
1774
|
12
|
1775 static void gtk_html_draw_bit(GtkHtml * html, GtkHtmlBit * hb, int redraw)
|
1
|
1776 {
|
12
|
1777 int mypos,
|
|
1778 epos,
|
|
1779 spos;
|
|
1780 GdkGC *gc = html->gc;
|
1
|
1781 int shift;
|
12
|
1782 GtkStateType selected_state;
|
|
1783 GtkWidget *widget = GTK_WIDGET(html);
|
1
|
1784 GdkRectangle area;
|
|
1785
|
|
1786 if (html->frozen > 0)
|
|
1787 return;
|
|
1788
|
12
|
1789 if (hb->type == HTML_BIT_TEXT)
|
|
1790 {
|
1
|
1791
|
|
1792 if (!strlen(hb->text))
|
|
1793 return;
|
12
|
1794
|
1
|
1795 mypos = g_list_index(html->html_bits, hb);
|
|
1796 epos = g_list_index(html->html_bits, html->end_sel);
|
|
1797 spos = g_list_index(html->html_bits, html->start_sel);
|
|
1798
|
12
|
1799 if (((html->end_sel == NULL) || (html->start_sel == NULL)) ||
|
|
1800 ((epos < mypos) && (spos < mypos)) ||
|
|
1801 ((epos > mypos) && (spos > mypos)))
|
|
1802 {
|
|
1803 selected_state = GTK_STATE_NORMAL;
|
|
1804 }
|
|
1805 else
|
|
1806 {
|
1
|
1807 selected_state = GTK_STATE_SELECTED;
|
|
1808 }
|
|
1809
|
|
1810
|
|
1811 gdk_text_extents(hb->font, hb->text, 1, &shift, NULL, NULL, NULL, NULL);
|
|
1812
|
12
|
1813 if (selected_state == GTK_STATE_SELECTED)
|
|
1814 {
|
|
1815 int schar = 0,
|
|
1816 echar = 0;
|
|
1817 int startx = 0,
|
|
1818 xwidth = 0;
|
|
1819
|
|
1820 if (epos > spos ||
|
|
1821 (epos == spos && html->num_end >= html->num_start))
|
|
1822 {
|
|
1823 if (mypos == epos)
|
|
1824 {
|
1
|
1825 echar = html->num_end;
|
12
|
1826 xwidth =
|
|
1827 gdk_text_width(hb->font, hb->text, html->num_end + 1);
|
|
1828 }
|
|
1829 else
|
|
1830 {
|
1
|
1831 echar = strlen(hb->text);
|
|
1832 xwidth = hb->width;
|
|
1833 }
|
12
|
1834 if (mypos == spos)
|
|
1835 {
|
1
|
1836 schar = html->num_start;
|
12
|
1837 startx =
|
|
1838 gdk_text_width(hb->font, hb->text, html->num_start);
|
1
|
1839 xwidth -= startx;
|
|
1840 }
|
12
|
1841 }
|
|
1842 else
|
|
1843 {
|
|
1844 if (mypos == spos)
|
|
1845 {
|
1
|
1846 echar = html->num_start;
|
12
|
1847 xwidth =
|
|
1848 gdk_text_width(hb->font, hb->text,
|
|
1849 html->num_start + 1);
|
|
1850 }
|
|
1851 else
|
|
1852 {
|
1
|
1853 echar = strlen(hb->text);
|
|
1854 xwidth = hb->width;
|
|
1855 }
|
12
|
1856 if (mypos == epos)
|
|
1857 {
|
1
|
1858 schar = html->num_end;
|
12
|
1859 startx =
|
|
1860 gdk_text_width(hb->font, hb->text, html->num_end);
|
1
|
1861 xwidth -= startx;
|
|
1862 }
|
|
1863 }
|
|
1864
|
|
1865 if (!redraw && echar == hb->sel_e && schar == hb->sel_s)
|
|
1866 return;
|
12
|
1867
|
1
|
1868 hb->sel_e = echar;
|
|
1869 hb->sel_s = schar;
|
12
|
1870
|
1
|
1871 startx += hb->x;
|
|
1872
|
|
1873
|
12
|
1874 area.x = hb->x - html->xoffset;
|
|
1875 area.y = hb->y - hb->height + 3 - html->yoffset;
|
|
1876 area.width = hb->width + 2;
|
|
1877 area.height = hb->height;
|
|
1878 clear_area(html, &area);
|
|
1879
|
|
1880 gtk_paint_flat_box(widget->style, html->html_area,
|
|
1881 selected_state, GTK_SHADOW_NONE,
|
|
1882 NULL, widget, "text",
|
|
1883 startx,
|
|
1884 hb->y - hb->height + 3 - html->yoffset,
|
|
1885 xwidth + 2, hb->height);
|
|
1886 hb->was_selected = 1;
|
|
1887 }
|
|
1888 else if (hb->was_selected)
|
|
1889 {
|
|
1890 area.x = hb->x - html->xoffset;
|
|
1891 area.y = hb->y - hb->height + 3 - html->yoffset;
|
|
1892 area.width = hb->width + 2;
|
|
1893 area.height = hb->height;
|
|
1894 clear_area(html, &area);
|
|
1895
|
|
1896 hb->sel_e = -1;
|
|
1897 hb->sel_s = -1;
|
|
1898
|
1
|
1899 hb->was_selected = 0;
|
|
1900 }
|
12
|
1901
|
|
1902
|
|
1903
|
|
1904
|
|
1905 if (selected_state == GTK_STATE_SELECTED && (mypos == epos
|
|
1906 || mypos == spos))
|
|
1907 {
|
1
|
1908 char *s = hb->text;
|
12
|
1909 int num = 0,
|
|
1910 width = 0,
|
|
1911 fsel = 0,
|
|
1912 esel = strlen(hb->text);
|
|
1913 int lbearing,
|
|
1914 rbearing,
|
|
1915 w;
|
|
1916
|
|
1917 if (epos > spos ||
|
|
1918 (epos == spos && html->num_end >= html->num_start))
|
|
1919 {
|
1
|
1920 if (mypos == epos)
|
|
1921 esel = html->num_end;
|
|
1922 if (mypos == spos)
|
|
1923 fsel = html->num_start;
|
12
|
1924 }
|
|
1925 else
|
|
1926 {
|
1
|
1927 if (mypos == spos)
|
|
1928 esel = html->num_start;
|
12
|
1929 if (mypos == epos)
|
|
1930 fsel = html->num_end;
|
1
|
1931 }
|
|
1932
|
12
|
1933 while (*s)
|
|
1934 {
|
1
|
1935
|
|
1936 if (num < fsel || num > esel)
|
|
1937 selected_state = GTK_STATE_NORMAL;
|
|
1938 else
|
|
1939 selected_state = GTK_STATE_SELECTED;
|
|
1940 if (hb->fore != NULL)
|
|
1941 gdk_gc_set_foreground(gc, hb->fore);
|
|
1942 else
|
12
|
1943 gdk_gc_set_foreground(gc,
|
|
1944 &widget->style->fg[selected_state]);
|
1
|
1945 if (hb->back != NULL)
|
|
1946 gdk_gc_set_background(gc, hb->back);
|
|
1947 else
|
12
|
1948 gdk_gc_set_background(gc,
|
|
1949 &widget->style->bg[selected_state]);
|
1
|
1950
|
|
1951
|
|
1952 gdk_gc_set_font(gc, hb->font);
|
|
1953
|
12
|
1954 gdk_text_extents(hb->font, s, 1, &lbearing, &rbearing, &w, NULL,
|
|
1955 NULL);
|
|
1956
|
|
1957 gdk_draw_text(html->html_area, hb->font, gc,
|
|
1958 shift + hb->x + width, hb->y - html->yoffset, s,
|
|
1959 1);
|
|
1960
|
|
1961 if (hb->uline)
|
|
1962 gdk_draw_line(html->html_area, gc, shift + hb->x + width,
|
|
1963 hb->y - html->yoffset,
|
|
1964 shift + hb->x + width + w,
|
|
1965 hb->y - html->yoffset);
|
1
|
1966
|
|
1967 if (hb->strike)
|
12
|
1968 gdk_draw_line(html->html_area, gc, shift + hb->x + width,
|
|
1969 hb->y - html->yoffset - (hb->height / 3),
|
|
1970 shift + hb->x + width + w,
|
|
1971 hb->y - html->yoffset - (hb->height / 3));
|
1
|
1972
|
|
1973 width += w;
|
12
|
1974
|
1
|
1975 s++;
|
|
1976 num++;
|
|
1977 }
|
|
1978
|
|
1979
|
12
|
1980 }
|
|
1981 else
|
|
1982 {
|
|
1983 /*my stuff here*/
|
|
1984
|
|
1985 if(!hb->was_selected)
|
|
1986 {
|
|
1987 area.x = hb->x - html->xoffset;
|
|
1988 area.y = hb->y - hb->height + 3 - html->yoffset;
|
|
1989 area.width = hb->width + 2;
|
|
1990 area.height = hb->height;
|
|
1991 clear_area(html, &area);
|
|
1992 }
|
|
1993
|
|
1994 /*end my stuff*/
|
|
1995
|
1
|
1996
|
|
1997 if (hb->fore != NULL)
|
|
1998 gdk_gc_set_foreground(gc, hb->fore);
|
|
1999 else
|
12
|
2000 gdk_gc_set_foreground(gc, &widget->style->fg[selected_state]);
|
1
|
2001 if (hb->back != NULL)
|
|
2002 gdk_gc_set_background(gc, hb->back);
|
|
2003 else
|
|
2004 gdk_gc_set_background(gc, &widget->style->bg[selected_state]);
|
|
2005
|
|
2006
|
|
2007 gdk_gc_set_font(gc, hb->font);
|
|
2008
|
12
|
2009
|
|
2010 gdk_draw_string(html->html_area, hb->font, gc, shift + hb->x,
|
|
2011 hb->y - html->yoffset, hb->text);
|
1
|
2012 if (hb->uline)
|
12
|
2013 gdk_draw_line(html->html_area, gc, shift + hb->x,
|
|
2014 hb->y - html->yoffset,
|
|
2015 hb->x + gdk_string_measure(hb->font, hb->text),
|
|
2016 hb->y - html->yoffset);
|
1
|
2017
|
|
2018 if (hb->strike)
|
12
|
2019 gdk_draw_line(html->html_area, gc, shift + hb->x,
|
|
2020 hb->y - html->yoffset - (hb->height / 3),
|
|
2021 hb->x + gdk_string_measure(hb->font, hb->text),
|
|
2022 hb->y - html->yoffset - (hb->height / 3));
|
1
|
2023
|
|
2024 }
|
12
|
2025 }
|
|
2026 else if (hb->type == HTML_BIT_SEP)
|
|
2027 {
|
|
2028
|
|
2029 gdk_draw_line(html->html_area, gc, hb->x + 2,
|
|
2030 hb->y - html->yoffset - (hb->height / 2 - 1),
|
|
2031 hb->x + hb->width,
|
|
2032 hb->y - html->yoffset - (hb->height / 2 - 1));
|
|
2033
|
|
2034 }
|
|
2035 else if (hb->type == HTML_BIT_PIXMAP)
|
|
2036 {
|
1
|
2037 gdk_gc_set_background(gc, &widget->style->base[GTK_STATE_NORMAL]);
|
12
|
2038 gdk_draw_pixmap(html->html_area, gc, hb->pm, 0, 0, hb->x,
|
|
2039 hb->y - html->yoffset - (hb->height) + 4, hb->width,
|
|
2040 hb->height - 2);
|
1
|
2041 }
|
|
2042 }
|
|
2043
|
|
2044
|
|
2045
|
12
|
2046 gint compare_types(GtkHtmlBit * hb, GtkHtmlBit * hb2)
|
1
|
2047 {
|
12
|
2048 /*
|
|
2049 * In this function, it's OK to accidently return a
|
|
2050 * * 0, but will cause problems on an accidental 1
|
|
2051 */
|
1
|
2052
|
|
2053 if (!hb || !hb2)
|
|
2054 return 0;
|
12
|
2055
|
|
2056
|
1
|
2057 if (hb->uline != hb2->uline)
|
|
2058 return 0;
|
|
2059 if (hb->strike != hb2->strike)
|
12
|
2060 return 0;
|
|
2061 if (hb->font && hb2->font)
|
|
2062 {
|
1
|
2063 if (!gdk_font_equal(hb->font, hb2->font))
|
|
2064 return 0;
|
12
|
2065 }
|
|
2066 else if (hb->font && !hb2->font)
|
|
2067 {
|
1
|
2068 return 0;
|
12
|
2069 }
|
|
2070 else if (!hb->font && hb2->font)
|
|
2071 {
|
1
|
2072 return 0;
|
|
2073 }
|
|
2074 if (hb->type != hb2->type)
|
|
2075 return 0;
|
12
|
2076
|
|
2077 if (hb->fore && hb2->fore)
|
|
2078 {
|
1
|
2079 if (!gdk_color_equal(hb->fore, hb2->fore))
|
|
2080 return 0;
|
12
|
2081 }
|
|
2082 else if (hb->fore && !hb2->fore)
|
|
2083 {
|
1
|
2084 return 0;
|
12
|
2085 }
|
|
2086 else if (!hb->fore && hb2->fore)
|
|
2087 {
|
1
|
2088 return 0;
|
|
2089 }
|
|
2090
|
12
|
2091 if (hb->back && hb2->back)
|
|
2092 {
|
1
|
2093 if (!gdk_color_equal(hb->back, hb2->back))
|
|
2094 return 0;
|
12
|
2095 }
|
|
2096 else if (hb->back && !hb2->back)
|
|
2097 {
|
1
|
2098 return 0;
|
12
|
2099 }
|
|
2100 else if (!hb->back && hb2->back)
|
|
2101 {
|
1
|
2102 return 0;
|
|
2103 }
|
|
2104
|
|
2105 if ((hb->url != NULL && hb2->url == NULL) ||
|
12
|
2106 (hb->url == NULL && hb2->url != NULL))
|
1
|
2107 return 0;
|
12
|
2108
|
|
2109 if (hb->url != NULL && hb2->url != NULL)
|
1
|
2110 if (strcasecmp(hb->url, hb2->url))
|
|
2111 return 0;
|
12
|
2112
|
1
|
2113 return 1;
|
|
2114 }
|
|
2115
|
12
|
2116 static gint html_bit_is_onscreen(GtkHtml * html, GtkHtmlBit * hb)
|
1
|
2117 {
|
12
|
2118 gint width,
|
|
2119 height;
|
1
|
2120
|
|
2121 gdk_window_get_size(html->html_area, &width, &height);
|
12
|
2122
|
|
2123 if (hb->y < html->yoffset)
|
|
2124 {
|
1
|
2125 return 0;
|
|
2126 }
|
|
2127
|
12
|
2128 if ((hb->y - hb->height) > (html->yoffset + height))
|
|
2129 {
|
1
|
2130 return 0;
|
|
2131 }
|
|
2132 return 1;
|
|
2133 }
|
|
2134
|
12
|
2135 static void draw_cursor(GtkHtml * html)
|
1
|
2136 {
|
12
|
2137 if (html->editable &&
|
|
2138 html->cursor_hb &&
|
|
2139 GTK_WIDGET_DRAWABLE(html) &&
|
|
2140 html_bit_is_onscreen(html, html->cursor_hb))
|
|
2141 {
|
|
2142 gint x,
|
|
2143 y;
|
1
|
2144 gint width;
|
|
2145
|
|
2146 GdkFont *font = html->cursor_hb->font;
|
|
2147
|
12
|
2148 gdk_text_extents(font, html->cursor_hb->text, html->cursor_pos, NULL,
|
|
2149 NULL, &width, NULL, NULL);
|
|
2150
|
|
2151 gdk_gc_set_foreground(html->gc,
|
|
2152 >K_WIDGET(html)->style->text[GTK_STATE_NORMAL]);
|
1
|
2153
|
|
2154 y = html->cursor_hb->y - html->yoffset;
|
|
2155 x = html->cursor_hb->x + width;
|
|
2156
|
|
2157
|
12
|
2158 gdk_draw_line(html->html_area, html->gc, x, y, x, y - font->ascent);
|
1
|
2159
|
|
2160 }
|
|
2161 }
|
|
2162
|
12
|
2163 static void undraw_cursor(GtkHtml * html)
|
1
|
2164 {
|
12
|
2165 if (html->editable &&
|
|
2166 html->cursor_hb &&
|
|
2167 GTK_WIDGET_DRAWABLE(html) &&
|
|
2168 html_bit_is_onscreen(html, html->cursor_hb))
|
|
2169 {
|
|
2170 gint x,
|
|
2171 y;
|
1
|
2172 gint width;
|
12
|
2173 GdkRectangle area;
|
|
2174
|
1
|
2175 GdkFont *font = html->cursor_hb->font;
|
|
2176
|
12
|
2177 gdk_text_extents(font, html->cursor_hb->text, html->cursor_pos, NULL,
|
|
2178 NULL, &width, NULL, NULL);
|
1
|
2179
|
|
2180 y = html->cursor_hb->y - html->yoffset;
|
|
2181 x = html->cursor_hb->x + width;
|
|
2182
|
|
2183 area.x = x;
|
|
2184 area.y = y - font->ascent;
|
|
2185 area.height = font->ascent + 1;
|
|
2186 area.width = 1;
|
|
2187
|
|
2188
|
12
|
2189 clear_area(html, &area);
|
1
|
2190
|
|
2191 gtk_html_draw_bit(html, html->cursor_hb, 1);
|
12
|
2192
|
|
2193
|
|
2194 }
|
1
|
2195 }
|
|
2196
|
|
2197
|
12
|
2198 static void expose_html(GtkHtml * html, GdkRectangle * area, gboolean cursor)
|
1
|
2199 {
|
12
|
2200 GList *hbits;
|
|
2201 GtkHtmlBit *hb;
|
|
2202 gint width,
|
|
2203 height;
|
|
2204 gint realy;
|
|
2205
|
|
2206
|
|
2207 if (html->frozen > 0)
|
|
2208 return;
|
|
2209
|
|
2210
|
|
2211 hbits = html->html_bits;
|
1
|
2212
|
|
2213 gdk_window_get_size(html->html_area, &width, &height);
|
|
2214
|
12
|
2215 realy = area->y + html->yoffset;
|
|
2216
|
|
2217 clear_area(html, area);
|
|
2218
|
|
2219 while (hbits)
|
|
2220 {
|
|
2221
|
|
2222 hb = (GtkHtmlBit *) hbits->data;
|
1
|
2223
|
|
2224 if (html_bit_is_onscreen(html, hb))
|
12
|
2225 gtk_html_draw_bit(html, hb, 1);
|
|
2226
|
|
2227
|
|
2228 hbits = hbits->next;
|
|
2229 }
|
1
|
2230 }
|
|
2231
|
12
|
2232 static void resize_html(GtkHtml * html)
|
1
|
2233 {
|
|
2234 GList *hbits = html->html_bits;
|
|
2235 GList *html_bits = html->html_bits;
|
12
|
2236 GtkHtmlBit *hb,
|
|
2237 *hb2;
|
1
|
2238 char *str;
|
|
2239 gint height;
|
|
2240
|
12
|
2241 if (!hbits)
|
|
2242 return;
|
|
2243
|
|
2244
|
|
2245 html->html_bits = NULL;
|
|
2246
|
|
2247 html->current_x = 0;
|
1
|
2248 html->current_y = 0;
|
|
2249
|
12
|
2250 html->vadj->upper = 0;
|
|
2251
|
|
2252 gtk_html_freeze(html);
|
|
2253
|
|
2254 while (hbits)
|
|
2255 {
|
|
2256 hb = (GtkHtmlBit *) hbits->data;
|
|
2257 if (hb->type == HTML_BIT_SEP)
|
|
2258 {
|
|
2259
|
1
|
2260 gtk_html_add_seperator(html);
|
|
2261
|
|
2262 g_free(hb);
|
|
2263
|
|
2264 hbits = hbits->next;
|
|
2265 continue;
|
|
2266 }
|
12
|
2267 if (hb->type == HTML_BIT_PIXMAP)
|
|
2268 {
|
1
|
2269
|
|
2270 gtk_html_add_pixmap(html, hb->pm, hb->fit);
|
|
2271
|
|
2272 g_free(hb);
|
|
2273
|
|
2274 hbits = hbits->next;
|
|
2275 continue;
|
|
2276 }
|
12
|
2277
|
|
2278 if (hb->newline)
|
|
2279 {
|
1
|
2280 int i;
|
|
2281
|
12
|
2282 if (!hb->text)
|
|
2283 {
|
1
|
2284 hb->text = g_malloc(1);
|
|
2285 hb->text[0] = 0;
|
|
2286 }
|
12
|
2287 for (i = 0; i < hb->newline; i++)
|
|
2288 {
|
|
2289 str = hb->text;
|
1
|
2290 hb->text = g_strconcat(str, "\n", NULL);
|
|
2291 g_free(str);
|
|
2292 }
|
|
2293 }
|
|
2294
|
12
|
2295 if (hbits->next)
|
|
2296 {
|
|
2297 hb2 = (GtkHtmlBit *) hbits->next->data;
|
|
2298 }
|
|
2299 else
|
|
2300 {
|
|
2301 hb2 = NULL;
|
|
2302 }
|
|
2303
|
|
2304
|
|
2305
|
|
2306 if (!hb->newline && compare_types(hb, hb2))
|
|
2307 {
|
1
|
2308 str = hb2->text;
|
|
2309 hb2->text = g_strconcat(hb->text, hb2->text, NULL);
|
|
2310 g_free(str);
|
|
2311 hb2 = NULL;
|
12
|
2312 }
|
|
2313 else if (hb->text)
|
|
2314 {
|
1
|
2315 gtk_html_add_text(html, hb->font, hb->fore, hb->back,
|
12
|
2316 hb->text, strlen(hb->text), hb->uline, hb->strike,
|
|
2317 hb->url);
|
1
|
2318 }
|
|
2319
|
12
|
2320
|
|
2321
|
|
2322 /*
|
|
2323 * Font stays, so do colors (segfaults if I free)
|
|
2324 */
|
1
|
2325 if (hb->fore)
|
|
2326 gdk_color_free(hb->fore);
|
|
2327 if (hb->back)
|
|
2328 gdk_color_free(hb->back);
|
|
2329 if (hb->text)
|
|
2330 g_free(hb->text);
|
|
2331 if (hb->url)
|
|
2332 g_free(hb->url);
|
|
2333
|
12
|
2334 g_free(hb);
|
1
|
2335
|
|
2336 hbits = hbits->next;
|
|
2337 }
|
|
2338
|
12
|
2339 g_list_free(html_bits);
|
|
2340
|
|
2341
|
|
2342 gtk_html_thaw(html);
|
|
2343
|
1
|
2344 gdk_window_get_size(html->html_area, NULL, &height);
|
12
|
2345 gtk_adjustment_set_value(html->vadj, html->vadj->upper - height);
|
1
|
2346
|
|
2347 }
|
|
2348
|
12
|
2349 static GdkGC *create_bg_gc(GtkHtml * html)
|
1
|
2350 {
|
12
|
2351 GdkGCValues values;
|
|
2352
|
|
2353 values.tile = GTK_WIDGET(html)->style->bg_pixmap[GTK_STATE_NORMAL];
|
|
2354 values.fill = GDK_TILED;
|
|
2355
|
|
2356 return gdk_gc_new_with_values(html->html_area, &values,
|
|
2357 GDK_GC_FILL | GDK_GC_TILE);
|
1
|
2358 }
|
|
2359
|
12
|
2360 static void clear_area(GtkHtml * html, GdkRectangle * area)
|
1
|
2361 {
|
12
|
2362 GtkWidget *widget = GTK_WIDGET(html);
|
|
2363 gint x,
|
|
2364 y;
|
|
2365
|
|
2366
|
|
2367 if (html->transparent)
|
|
2368 {
|
1
|
2369 if (html->pm == NULL)
|
|
2370 html->pm = get_desktop_pixmap(widget);
|
|
2371
|
12
|
2372 if (html->pm == NULL)
|
|
2373 return;
|
|
2374
|
|
2375 if (html->bg_gc == NULL)
|
|
2376 {
|
|
2377 GdkGCValues values;
|
|
2378
|
|
2379 values.tile = html->pm;
|
|
2380 values.fill = GDK_TILED;
|
|
2381
|
|
2382 html->bg_gc = gdk_gc_new_with_values(html->html_area, &values,
|
|
2383 GDK_GC_FILL | GDK_GC_TILE);
|
|
2384
|
|
2385 }
|
|
2386
|
1
|
2387 gdk_window_get_deskrelative_origin(html->html_area, &x, &y);
|
|
2388
|
12
|
2389 gdk_draw_pixmap(html->html_area, html->bg_gc, html->pm,
|
|
2390 x + area->x, y + area->y, area->x, area->y, area->width,
|
|
2391 area->height);
|
1
|
2392
|
|
2393 return;
|
|
2394
|
|
2395 }
|
12
|
2396 if (html->bg_gc)
|
|
2397 {
|
|
2398
|
|
2399 gint width,
|
|
2400 height;
|
|
2401
|
|
2402 gdk_window_get_size(widget->style->bg_pixmap[GTK_STATE_NORMAL], &width,
|
|
2403 &height);
|
|
2404
|
|
2405 gdk_gc_set_ts_origin(html->bg_gc,
|
|
2406 (-html->xoffset) % width,
|
|
2407 (-html->yoffset) % height);
|
|
2408
|
|
2409 gdk_draw_rectangle(html->html_area, html->bg_gc, TRUE,
|
|
2410 area->x, area->y, area->width, area->height);
|
|
2411 }
|
|
2412 else
|
|
2413 gdk_window_clear_area(html->html_area, area->x, area->y, area->width,
|
|
2414 area->height);
|
1
|
2415 }
|
|
2416
|
|
2417
|
|
2418
|
|
2419
|
12
|
2420 static void gtk_html_destroy(GtkObject * object)
|
1
|
2421 {
|
12
|
2422 GtkHtml *html;
|
|
2423
|
|
2424 g_return_if_fail(object != NULL);
|
|
2425 g_return_if_fail(GTK_IS_HTML(object));
|
|
2426
|
|
2427 html = (GtkHtml *) object;
|
|
2428
|
|
2429
|
|
2430 gtk_signal_disconnect_by_data(GTK_OBJECT(html->hadj), html);
|
|
2431 gtk_signal_disconnect_by_data(GTK_OBJECT(html->vadj), html);
|
|
2432
|
|
2433 if (html->timer)
|
|
2434 {
|
|
2435 gtk_timeout_remove(html->timer);
|
|
2436 html->timer = 0;
|
1
|
2437 }
|
|
2438
|
12
|
2439 if (html->tooltip_timer)
|
|
2440 {
|
|
2441 gtk_timeout_remove(html->tooltip_timer);
|
1
|
2442 html->tooltip_timer = -1;
|
|
2443 }
|
|
2444
|
12
|
2445
|
|
2446 GTK_OBJECT_CLASS(parent_class)->destroy(object);
|
|
2447
|
1
|
2448 }
|
|
2449
|
12
|
2450 static void gtk_html_finalize(GtkObject * object)
|
1
|
2451 {
|
12
|
2452 GList *hbits;
|
|
2453 GtkHtml *html;
|
1
|
2454 GtkHtmlBit *hb;
|
|
2455
|
|
2456
|
12
|
2457 g_return_if_fail(object != NULL);
|
|
2458 g_return_if_fail(GTK_IS_HTML(object));
|
|
2459
|
|
2460 html = (GtkHtml *) object;
|
|
2461
|
|
2462 gtk_object_unref(GTK_OBJECT(html->hadj));
|
|
2463 gtk_object_unref(GTK_OBJECT(html->vadj));
|
|
2464
|
|
2465 hbits = html->html_bits;
|
|
2466
|
|
2467 while (hbits)
|
|
2468 {
|
|
2469 hb = (GtkHtmlBit *) hbits->data;
|
|
2470 if (hb->fore)
|
|
2471 gdk_color_free(hb->fore);
|
|
2472 if (hb->back)
|
|
2473 gdk_color_free(hb->back);
|
|
2474 if (hb->text)
|
|
2475 g_free(hb->text);
|
|
2476 if (hb->url)
|
|
2477 g_free(hb->url);
|
|
2478 if (hb->pm)
|
|
2479 gdk_pixmap_unref(hb->pm);
|
|
2480
|
|
2481 g_free(hb);
|
|
2482 hbits = hbits->next;
|
|
2483 }
|
|
2484 if (html->html_bits)
|
|
2485 g_list_free(html->html_bits);
|
|
2486
|
|
2487 if (html->urls)
|
|
2488 g_list_free(html->urls);
|
|
2489
|
|
2490 if (html->selected_text)
|
|
2491 g_free(html->selected_text);
|
|
2492
|
|
2493 if (html->gc)
|
|
2494 gdk_gc_destroy(html->gc);
|
|
2495
|
|
2496 if (html->bg_gc)
|
|
2497 gdk_gc_destroy(html->bg_gc);
|
1
|
2498
|
|
2499 if (html->tooltip_window)
|
|
2500 gtk_widget_destroy(html->tooltip_window);
|
12
|
2501
|
|
2502 GTK_OBJECT_CLASS(parent_class)->finalize(object);
|
1
|
2503 }
|
|
2504
|
12
|
2505 static void gtk_html_realize(GtkWidget * widget)
|
1
|
2506 {
|
12
|
2507 GtkHtml *html;
|
|
2508 GdkWindowAttr attributes;
|
|
2509 gint attributes_mask;
|
|
2510
|
|
2511 g_return_if_fail(widget != NULL);
|
|
2512 g_return_if_fail(GTK_IS_HTML(widget));
|
|
2513
|
|
2514 html = GTK_HTML(widget);
|
|
2515 GTK_WIDGET_SET_FLAGS(html, GTK_REALIZED);
|
|
2516
|
|
2517 attributes.window_type = GDK_WINDOW_CHILD;
|
|
2518 attributes.x = widget->allocation.x;
|
|
2519 attributes.y = widget->allocation.y;
|
|
2520 attributes.width = widget->allocation.width;
|
|
2521 attributes.height = widget->allocation.height;
|
|
2522 attributes.wclass = GDK_INPUT_OUTPUT;
|
|
2523 attributes.visual = gtk_widget_get_visual(widget);
|
|
2524 attributes.colormap = gtk_widget_get_colormap(widget);
|
|
2525 attributes.event_mask = gtk_widget_get_events(widget);
|
|
2526 attributes.event_mask |= (GDK_EXPOSURE_MASK |
|
|
2527 GDK_BUTTON_PRESS_MASK |
|
|
2528 GDK_BUTTON_RELEASE_MASK |
|
|
2529 GDK_BUTTON_MOTION_MASK |
|
|
2530 GDK_ENTER_NOTIFY_MASK |
|
|
2531 GDK_LEAVE_NOTIFY_MASK |
|
|
2532 GDK_POINTER_MOTION_MASK |
|
|
2533 GDK_POINTER_MOTION_HINT_MASK |
|
|
2534 GDK_VISIBILITY_NOTIFY_MASK | GDK_KEY_PRESS_MASK);
|
|
2535
|
|
2536 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
2537
|
|
2538 widget->window =
|
|
2539 gdk_window_new(gtk_widget_get_parent_window(widget), &attributes,
|
|
2540 attributes_mask);
|
|
2541 gdk_window_set_user_data(widget->window, html);
|
|
2542
|
|
2543 attributes.x = (widget->style->klass->xthickness + BORDER_WIDTH);
|
|
2544 attributes.y = (widget->style->klass->ythickness + BORDER_WIDTH);
|
|
2545 attributes.width =
|
|
2546 MAX(1, (gint) widget->allocation.width - (gint) attributes.x * 2);
|
|
2547 attributes.height =
|
|
2548 MAX(1, (gint) widget->allocation.height - (gint) attributes.y * 2);
|
|
2549
|
|
2550 html->html_area =
|
|
2551 gdk_window_new(widget->window, &attributes, attributes_mask);
|
|
2552 gdk_window_set_user_data(html->html_area, html);
|
|
2553
|
|
2554 widget->style = gtk_style_attach(widget->style, widget->window);
|
|
2555
|
|
2556 /*
|
|
2557 * Can't call gtk_style_set_background here because it's handled specially
|
|
2558 */
|
|
2559 gdk_window_set_background(widget->window,
|
|
2560 &widget->style->base[GTK_STATE_NORMAL]);
|
|
2561 gdk_window_set_background(html->html_area,
|
|
2562 &widget->style->base[GTK_STATE_NORMAL]);
|
|
2563
|
|
2564 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
|
|
2565 html->bg_gc = create_bg_gc(html);
|
|
2566
|
|
2567 html->gc = gdk_gc_new(html->html_area);
|
|
2568 gdk_gc_set_exposures(html->gc, TRUE);
|
|
2569 gdk_gc_set_foreground(html->gc, &widget->style->text[GTK_STATE_NORMAL]);
|
|
2570
|
|
2571 gdk_window_show(html->html_area);
|
1
|
2572
|
|
2573 }
|
|
2574
|
12
|
2575 static void gtk_html_style_set(GtkWidget * widget, GtkStyle * previous_style)
|
1
|
2576 {
|
12
|
2577 GtkHtml *html;
|
|
2578
|
|
2579 g_return_if_fail(widget != NULL);
|
|
2580 g_return_if_fail(GTK_IS_HTML(widget));
|
|
2581
|
|
2582 html = GTK_HTML(widget);
|
|
2583 if (GTK_WIDGET_REALIZED(widget))
|
|
2584 {
|
|
2585 gdk_window_set_background(widget->window,
|
|
2586 &widget->style->base[GTK_STATE_NORMAL]);
|
|
2587 gdk_window_set_background(html->html_area,
|
|
2588 &widget->style->base[GTK_STATE_NORMAL]);
|
|
2589
|
|
2590 if (html->bg_gc)
|
|
2591 {
|
|
2592 gdk_gc_destroy(html->bg_gc);
|
|
2593 html->bg_gc = NULL;
|
|
2594 }
|
|
2595
|
|
2596 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
|
|
2597 {
|
|
2598 html->bg_gc = create_bg_gc(html);
|
|
2599 }
|
|
2600
|
|
2601 }
|
1
|
2602 }
|
|
2603
|
12
|
2604 static void gtk_html_unrealize(GtkWidget * widget)
|
1
|
2605 {
|
12
|
2606 GtkHtml *html;
|
|
2607
|
|
2608 g_return_if_fail(widget != NULL);
|
|
2609 g_return_if_fail(GTK_IS_HTML(widget));
|
|
2610
|
|
2611 html = GTK_HTML(widget);
|
|
2612
|
|
2613 gdk_window_set_user_data(html->html_area, NULL);
|
|
2614 gdk_window_destroy(html->html_area);
|
|
2615 html->html_area = NULL;
|
|
2616
|
|
2617 gdk_gc_destroy(html->gc);
|
|
2618 html->gc = NULL;
|
|
2619
|
|
2620 if (html->bg_gc)
|
|
2621 {
|
|
2622 gdk_gc_destroy(html->bg_gc);
|
|
2623 html->bg_gc = NULL;
|
|
2624 }
|
|
2625
|
|
2626 if (GTK_WIDGET_CLASS(parent_class)->unrealize)
|
|
2627 (*GTK_WIDGET_CLASS(parent_class)->unrealize) (widget);
|
1
|
2628 }
|
|
2629
|
|
2630
|
|
2631
|
|
2632
|
|
2633
|
12
|
2634 static void gtk_html_add_pixmap(GtkHtml * html, GdkPixmap * pm, int fit)
|
1
|
2635 {
|
12
|
2636 GtkHtmlBit *last_hb;
|
|
2637 GtkHtmlBit *hb = g_new0(GtkHtmlBit, 1);
|
|
2638 GdkWindowPrivate *private = (GdkWindowPrivate *) pm;
|
|
2639
|
|
2640 last_hb = (GtkHtmlBit *) g_list_last(html->html_bits)->data;
|
1
|
2641
|
|
2642 hb->fit = fit;
|
|
2643 hb->x = html->current_x;
|
|
2644 hb->y = html->current_y;
|
12
|
2645 if (fit)
|
1
|
2646 hb->height = last_hb->height;
|
|
2647 else
|
|
2648 hb->height = private->height;
|
|
2649 hb->type = HTML_BIT_PIXMAP;
|
|
2650 hb->width = private->width;
|
|
2651 hb->text = NULL;
|
|
2652 hb->url = NULL;
|
|
2653 hb->fore = NULL;
|
|
2654 hb->back = NULL;
|
|
2655 hb->font = NULL;
|
12
|
2656 hb->uline = 0;
|
|
2657 hb->strike = 0;
|
1
|
2658 hb->was_selected = 0;
|
12
|
2659 hb->newline = 0;
|
|
2660 hb->pm = pm;
|
|
2661
|
|
2662 if (html->current_x == BORDER_WIDTH)
|
|
2663 {
|
1
|
2664 html->current_y += hb->height;
|
|
2665 hb->y += hb->height;
|
|
2666 }
|
|
2667
|
|
2668
|
12
|
2669 html->current_x += hb->width;
|
|
2670
|
1
|
2671 gtk_html_draw_bit(html, hb, 1);
|
|
2672
|
|
2673 html->html_bits = g_list_append(html->html_bits, hb);
|
|
2674
|
|
2675
|
|
2676 }
|
|
2677
|
12
|
2678 static void gtk_html_add_seperator(GtkHtml * html)
|
1
|
2679 {
|
12
|
2680 GtkHtmlBit *hb = g_new0(GtkHtmlBit, 1);
|
|
2681 gint width,
|
|
2682 height;
|
|
2683
|
1
|
2684 html->current_x = 0;
|
|
2685 html->current_y += 5;
|
|
2686
|
12
|
2687 gdk_window_get_size(html->html_area, &width, &height);
|
|
2688
|
1
|
2689 hb->x = html->current_x;
|
|
2690 hb->y = html->current_y;
|
|
2691 hb->height = 5;
|
|
2692 hb->type = HTML_BIT_SEP;
|
12
|
2693 hb->width =
|
|
2694 width -
|
|
2695 GTK_SCROLLED_WINDOW(GTK_WIDGET(html)->parent)->vscrollbar->allocation.
|
|
2696 width - 10;
|
1
|
2697 hb->text = NULL;
|
|
2698 hb->url = NULL;
|
|
2699 hb->fore = NULL;
|
|
2700 hb->back = NULL;
|
|
2701 hb->font = NULL;
|
12
|
2702 hb->uline = 0;
|
|
2703 hb->strike = 0;
|
1
|
2704 hb->was_selected = 0;
|
12
|
2705 hb->newline = 0;
|
|
2706 hb->pm = NULL;
|
1
|
2707
|
|
2708 gtk_html_draw_bit(html, hb, 1);
|
|
2709
|
|
2710 html->html_bits = g_list_append(html->html_bits, hb);
|
|
2711
|
|
2712 }
|
|
2713
|
|
2714
|
12
|
2715 static void gtk_html_add_text(GtkHtml * html,
|
|
2716 GdkFont * cfont,
|
|
2717 GdkColor * fore,
|
|
2718 GdkColor * back,
|
|
2719 char *chars,
|
|
2720 gint length, gint uline, gint strike, char *url)
|
1
|
2721 {
|
12
|
2722 char *nextline = NULL,
|
|
2723 *c,
|
|
2724 *text,
|
|
2725 *tmp;
|
|
2726 GdkGC *gc;
|
|
2727 int nl = 0,
|
|
2728 nl2 = 0;
|
|
2729 int maxwidth;
|
|
2730 gint lb;
|
|
2731 GList *hbits;
|
79
|
2732 size_t num = 0;
|
|
2733 int i,
|
12
|
2734 height;
|
|
2735 GtkHtmlBit *hb;
|
|
2736 gint hwidth,
|
|
2737 hheight;
|
|
2738
|
|
2739 if (length == 1 && chars[0] == '\n')
|
|
2740 {
|
|
2741 GtkHtmlBit *h;
|
|
2742 hbits = g_list_last(html->html_bits);
|
|
2743 if (!hbits)
|
|
2744 return;
|
|
2745 /*
|
|
2746 * I realize this loses a \n sometimes
|
|
2747 * * if it's the first thing in the widget.
|
|
2748 * * so fucking what.
|
|
2749 */
|
|
2750
|
|
2751 h = (GtkHtmlBit *) hbits->data;
|
|
2752 h->newline++;
|
|
2753 if (html->current_x > 0)
|
|
2754 html->current_x = 0;
|
|
2755 else
|
|
2756 html->current_y += cfont->ascent + cfont->descent + 2;
|
|
2757 return;
|
|
2758 }
|
|
2759
|
|
2760
|
|
2761
|
|
2762 c = text = g_malloc(length + 2);
|
|
2763 strncpy(text, chars, length);
|
|
2764 text[length] = 0;
|
|
2765
|
|
2766
|
|
2767 gc = html->gc;
|
|
2768
|
|
2769 if (gc == NULL)
|
|
2770 gc = html->gc = gdk_gc_new(html->html_area);
|
|
2771
|
|
2772 gdk_gc_set_font(gc, cfont);
|
|
2773
|
|
2774
|
|
2775 while (*c)
|
|
2776 {
|
|
2777 if (*c == '\n')
|
|
2778 {
|
|
2779 if (*(c + 1) == '\0')
|
|
2780 {
|
|
2781 nl = 1;
|
|
2782 length--;
|
|
2783 c[0] = '\0';
|
|
2784 break;
|
|
2785 }
|
|
2786 if (*c)
|
|
2787 {
|
|
2788 gtk_html_add_text(html, cfont, fore, back, text, num + 1, uline,
|
|
2789 strike, url);
|
|
2790 tmp = text;
|
|
2791 length -= (num + 1);
|
|
2792 text = g_malloc(length + 2);
|
|
2793 strncpy(text, (c + 1), length);
|
|
2794 text[length] = 0;
|
|
2795 c = text;
|
|
2796 num = 0;
|
|
2797 g_free(tmp);
|
1
|
2798 continue;
|
12
|
2799 }
|
|
2800 }
|
|
2801
|
|
2802 num++;
|
|
2803 c++;
|
|
2804 }
|
|
2805
|
|
2806 /*
|
|
2807 * Note, yG is chosen because G is damn high, and y is damn low,
|
|
2808 */
|
|
2809 /*
|
|
2810 * it should be just fine. :)
|
|
2811 */
|
|
2812
|
|
2813 gdk_window_get_size(html->html_area, &hwidth, &hheight);
|
|
2814
|
|
2815 num = strlen(text);
|
|
2816
|
|
2817 while (GTK_WIDGET(html)->allocation.width < 20)
|
|
2818 {
|
|
2819 while (gtk_events_pending())
|
1
|
2820 gtk_main_iteration();
|
|
2821 }
|
|
2822
|
12
|
2823 maxwidth = (hwidth - html->current_x - 8);
|
|
2824 /*
|
|
2825 * HTK_SCROLLED_WINDOW(GTK_WIDGET(layout)->parent)->vscrollbar->allocation.width) - 8;
|
|
2826 */
|
|
2827
|
|
2828 while (gdk_text_measure(cfont, text, num) > maxwidth)
|
|
2829 {
|
|
2830 if (num > 1)
|
|
2831 num--;
|
|
2832 else
|
|
2833 {
|
26
|
2834 if (html->current_x != 0) {
|
|
2835 html->current_x = 0;
|
|
2836 if (nl) {
|
|
2837 text[length] = '\n';
|
|
2838 length++;
|
|
2839 }
|
|
2840 gtk_html_add_text(html, cfont, fore, back, text, length, uline, strike, url);
|
|
2841 g_free(text);
|
|
2842 return;
|
|
2843 } else {
|
|
2844 num = strlen (text);
|
|
2845 break;
|
1
|
2846 }
|
|
2847 }
|
|
2848
|
|
2849 }
|
|
2850
|
12
|
2851 height = cfont->ascent + cfont->descent + 2;
|
|
2852
|
|
2853
|
|
2854 if ((int) (html->vadj->upper - html->current_y) < (int) (height * 2))
|
|
2855 {
|
|
2856 int val;
|
|
2857 val = (height * 2) + html->current_y;
|
|
2858 html->vadj->upper = val;
|
|
2859 adjust_adj(html, html->vadj);
|
1
|
2860 }
|
|
2861
|
12
|
2862
|
|
2863 if (html->current_x == 0)
|
|
2864 {
|
|
2865 html->current_y += height;
|
|
2866 gdk_text_extents(cfont, text, 1, &lb, NULL, NULL, NULL, NULL);
|
|
2867 html->current_x += (2 - lb);
|
|
2868 }
|
|
2869 else if ((hbits = g_list_last(html->html_bits)) != NULL)
|
|
2870 {
|
|
2871 int diff,
|
|
2872 y;
|
|
2873 hb = (GtkHtmlBit *) hbits->data;
|
|
2874 if (height > hb->height)
|
|
2875 {
|
1
|
2876 diff = height - hb->height;
|
|
2877 y = hb->y;
|
|
2878 html->current_y += diff;
|
12
|
2879 while (hbits)
|
|
2880 {
|
|
2881 hb = (GtkHtmlBit *) hbits->data;
|
1
|
2882 if (hb->y != y)
|
12
|
2883 break;
|
|
2884 hb->height = height;
|
|
2885 hb->y += diff; ////////////my thing here /////////////////
|
|
2886 gtk_html_draw_bit(html, hb, FALSE);
|
|
2887
|
|
2888 hbits = hbits->prev;
|
1
|
2889 }
|
|
2890 }
|
|
2891 }
|
|
2892
|
|
2893
|
|
2894
|
|
2895
|
12
|
2896 if (num != strlen(text))
|
|
2897 {
|
|
2898 /*
|
|
2899 * This is kinda cheesy but it may make things
|
|
2900 * * much better lookin
|
|
2901 */
|
26
|
2902
|
|
2903 for (i=2; (num - i > 0); i++) {
|
|
2904 if (text[num - i] == ' ') {
|
12
|
2905 num = num - (i - 1);
|
1
|
2906 nl2 = 1;
|
|
2907 break;
|
|
2908 }
|
|
2909 }
|
|
2910
|
|
2911 nextline = g_malloc(length - num + 2);
|
12
|
2912 strncpy(nextline, (char *) (text + num), length - num);
|
1
|
2913 nextline[length - num] = 0;
|
12
|
2914 if (nl)
|
|
2915 {
|
1
|
2916 nextline[length - num] = '\n';
|
|
2917 nextline[length - num + 1] = 0;
|
|
2918 nl = 0;
|
|
2919 }
|
|
2920
|
|
2921
|
|
2922 text[num] = 0;
|
|
2923 }
|
|
2924
|
|
2925
|
52
|
2926 if (url != NULL) {
|
53
|
2927 fore = get_color(3355647, gdk_window_get_colormap(html->html_area));
|
52
|
2928 }
|
1
|
2929
|
|
2930 hb = g_new0(GtkHtmlBit, 1);
|
|
2931
|
|
2932 hb->text = g_strdup(text);
|
|
2933
|
52
|
2934 if (fore)
|
|
2935 hb->fore = gdk_color_copy(fore);
|
|
2936 else
|
|
2937 hb->fore = NULL;
|
49
|
2938
|
1
|
2939 if (back)
|
|
2940 hb->back = gdk_color_copy(back);
|
|
2941 else
|
|
2942 hb->back = NULL;
|
|
2943 hb->font = cfont;
|
|
2944 hb->uline = uline;
|
|
2945 hb->strike = strike;
|
|
2946 hb->height = height;
|
|
2947 gdk_text_extents(cfont, text, num, &lb, NULL, &hb->width, NULL, NULL);
|
|
2948 hb->x = html->current_x;
|
|
2949 hb->y = html->current_y;
|
12
|
2950 hb->type = HTML_BIT_TEXT;
|
|
2951 hb->pm = NULL;
|
|
2952 if (url != NULL)
|
|
2953 {
|
1
|
2954 uline = 1;
|
|
2955 hb->uline = 1;
|
|
2956 hb->url = g_strdup(url);
|
12
|
2957 }
|
|
2958 else
|
|
2959 {
|
1
|
2960 hb->url = NULL;
|
|
2961 }
|
|
2962 html->current_x += hb->width;
|
|
2963
|
|
2964 html->html_bits = g_list_append(html->html_bits, hb);
|
12
|
2965 if (url != NULL)
|
|
2966 {
|
|
2967 html->urls = g_list_append(html->urls, hb);
|
|
2968 }
|
|
2969
|
|
2970
|
|
2971
|
|
2972 gtk_html_draw_bit(html, hb, 1);
|
|
2973
|
|
2974 if (nl || nl2)
|
|
2975 {
|
|
2976 if (nl)
|
|
2977 hb->newline = 1;
|
|
2978 html->current_x = 0;
|
|
2979 }
|
|
2980 else
|
|
2981 hb->newline = 0;
|
|
2982
|
|
2983
|
|
2984 if (nextline != NULL)
|
|
2985 {
|
|
2986 gtk_html_add_text(html, cfont, fore, back, nextline, strlen(nextline),
|
|
2987 uline, strike, url);
|
|
2988 g_free(nextline);
|
|
2989 }
|
|
2990
|
|
2991 g_free(text);
|
137
|
2992 if (url != NULL)
|
|
2993 g_free(fore);
|
1
|
2994 }
|
|
2995
|
12
|
2996 static char * html_strtok( char * input, char delim )
|
1
|
2997 {
|
12
|
2998 static char * end;
|
|
2999 static char * curr_offset;
|
|
3000 int i;
|
|
3001 int num_quotes=0;
|
|
3002
|
|
3003 if( input != NULL)
|
|
3004 {
|
|
3005 curr_offset = input;
|
|
3006 end = input+strlen(input);
|
|
3007 }
|
|
3008 else
|
|
3009 {
|
|
3010 if( curr_offset + strlen(curr_offset) < end )
|
|
3011 {
|
|
3012 curr_offset += strlen(curr_offset) + 1;
|
|
3013 }
|
|
3014 else
|
|
3015 {
|
|
3016 return NULL;
|
|
3017 }
|
|
3018 }
|
|
3019 for( i=0; curr_offset+i < end &&
|
|
3020 (curr_offset[i] != delim || num_quotes != 0)
|
|
3021 ; i++ )
|
|
3022 {
|
|
3023 if( curr_offset[i] == '\"' )
|
|
3024 {
|
|
3025 num_quotes = (num_quotes+1)%2;
|
|
3026 }
|
|
3027 }
|
|
3028 curr_offset[i] = '\0';
|
|
3029 return curr_offset;
|
|
3030 }
|
|
3031
|
|
3032
|
|
3033 void gtk_html_append_text(GtkHtml * html, char *text, gint options)
|
|
3034 {
|
|
3035 GdkColormap *map;
|
1
|
3036 GdkFont *cfont;
|
12
|
3037 GdkRectangle area;
|
|
3038 char ws[BUF_LONG],
|
|
3039 tag[BUF_LONG],
|
|
3040 *c,
|
|
3041 *url = NULL;
|
|
3042 gint intag = 0,
|
|
3043 wpos = 0,
|
|
3044 tpos = 0,
|
|
3045 colorv,
|
|
3046 bold = 0,
|
|
3047 italic = 0,
|
|
3048 fixed = 0,
|
|
3049 uline = 0,
|
|
3050 strike = 0,
|
|
3051 title = 0;
|
|
3052 gint height;
|
|
3053 struct font_state *current,
|
|
3054 *tmp;
|
|
3055 struct font_state def_state = { 3, 0, 0, "", NULL, NULL, NULL };
|
|
3056
|
|
3057 current = &def_state;
|
|
3058 map = gdk_window_get_colormap(html->html_area);
|
|
3059 cfont = getfont(current->font, bold, italic, fixed, current->size);
|
1
|
3060 c = text;
|
|
3061
|
|
3062
|
12
|
3063 while (*c)
|
|
3064 {
|
|
3065 if (*c == '<')
|
|
3066 {
|
|
3067 if (!intag)
|
|
3068 {
|
|
3069 ws[wpos] = 0;
|
|
3070 if (wpos)
|
|
3071 {
|
|
3072 if (title)
|
|
3073 {
|
|
3074 if (html->title)
|
|
3075 g_free(html->title);
|
|
3076 html->title = g_strdup(ws);
|
|
3077 }
|
|
3078 else
|
|
3079 gtk_html_add_text(html, cfont, current->color,
|
|
3080 current->bgcol, ws, strlen(ws), uline,
|
|
3081 strike, url);
|
|
3082 }
|
|
3083 wpos = 0;
|
|
3084 intag = 1;
|
|
3085 }
|
|
3086 else
|
|
3087 {
|
|
3088 /*
|
|
3089 * Assuming you NEVER have nested tags
|
|
3090 * * (and I mean <tag <tag>> by this, not
|
|
3091 * * <tag><tag2></tag2><tag>..
|
|
3092 */
|
|
3093 tag[tpos] = 0;
|
|
3094 gtk_html_add_text(html, cfont, current->color, current->bgcol,
|
|
3095 "<", 1, 0, 0, NULL);
|
|
3096 gtk_html_add_text(html, cfont, current->color, current->bgcol,
|
|
3097 tag, strlen(tag), 0, 0, NULL);
|
1
|
3098 tpos = 0;
|
12
|
3099
|
|
3100 tag[0] = *c;
|
1
|
3101 }
|
12
|
3102 }
|
|
3103 else if (*c == '>')
|
|
3104 {
|
|
3105 if (intag)
|
|
3106 {
|
|
3107 tag[tpos] = 0;
|
1
|
3108 if (!strcasecmp(tag, "B"))
|
|
3109 bold = 1;
|
|
3110 else if (!strcasecmp(tag, "STRIKE"))
|
|
3111 strike = 1;
|
|
3112 else if (!strcasecmp(tag, "I"))
|
|
3113 italic = 1;
|
|
3114 else if (!strcasecmp(tag, "U"))
|
|
3115 uline = 1;
|
|
3116 else if (!strcasecmp(tag, "PRE"))
|
|
3117 fixed = 1;
|
|
3118 else if (!strcasecmp(tag, "HR"))
|
|
3119 gtk_html_add_seperator(html);
|
|
3120 else if (!strcasecmp(tag, "/B"))
|
|
3121 bold = 0;
|
|
3122 else if (!strcasecmp(tag, "/STRIKE"))
|
|
3123 strike = 0;
|
|
3124 else if (!strcasecmp(tag, "/I"))
|
|
3125 italic = 0;
|
|
3126 else if (!strcasecmp(tag, "/U"))
|
|
3127 uline = 0;
|
|
3128 else if (!strcasecmp(tag, "/PRE"))
|
|
3129 fixed = 0;
|
|
3130 else if (!strcasecmp(tag, "TITLE"))
|
|
3131 title = 1;
|
|
3132 else if (!strcasecmp(tag, "/TITLE"))
|
|
3133 title = 0;
|
12
|
3134 else if (!strncasecmp(tag, "IMG", 3))
|
|
3135 {
|
|
3136
|
|
3137 }
|
|
3138 else if (!strcasecmp(tag, "H3"))
|
|
3139 {
|
1
|
3140 current = push_state(current);
|
|
3141 current->size = 4;
|
12
|
3142 }
|
|
3143 else if (!strcasecmp(tag, "/H3"))
|
|
3144 {
|
|
3145 gtk_html_add_text(html, cfont, current->color,
|
|
3146 current->bgcol, "\n", 1, 0, 0, NULL);
|
|
3147
|
|
3148 if (current->next)
|
|
3149 {
|
1
|
3150 if (current->ownbg)
|
|
3151 g_free(current->bgcol);
|
|
3152 if (current->owncolor)
|
|
3153 g_free(current->color);
|
12
|
3154 tmp = current;
|
|
3155 current = current->next;
|
|
3156 g_free(tmp);
|
1
|
3157 }
|
12
|
3158 }
|
|
3159 else if (!strcasecmp(tag, "TABLE"))
|
|
3160 {
|
|
3161 }
|
|
3162 else if (!strcasecmp(tag, "/TABLE"))
|
|
3163 {
|
|
3164 }
|
|
3165 else if (!strcasecmp(tag, "TR"))
|
|
3166 {
|
|
3167 }
|
|
3168 else if (!strcasecmp(tag, "/TR"))
|
|
3169 {
|
|
3170 }
|
|
3171 else if (!strcasecmp(tag, "/TD"))
|
|
3172 {
|
|
3173 }
|
|
3174 else if (!strcasecmp(tag, "TD"))
|
|
3175 {
|
|
3176 gtk_html_add_text(html, cfont, current->color,
|
|
3177 current->bgcol, " ", 2, 0, 0, NULL);
|
|
3178 }
|
|
3179 else if (!strncasecmp(tag, "A ", 2))
|
|
3180 {
|
1
|
3181 char *d;
|
|
3182 char *temp = d = g_strdup(tag);
|
|
3183 int flag = 0;
|
12
|
3184 strtok(tag, " ");
|
|
3185 while ((d = strtok(NULL, " ")))
|
|
3186 {
|
1
|
3187 if (strlen(d) < 7)
|
|
3188 break;
|
12
|
3189 if (!strncasecmp(d, "HREF=\"", strlen("HREF=\"")))
|
|
3190 {
|
|
3191 d += strlen("HREF=\"");
|
1
|
3192 d[strlen(d) - 1] = 0;
|
|
3193 url = g_malloc(strlen(d) + 1);
|
|
3194 strcpy(url, d);
|
|
3195 flag = 1;
|
12
|
3196 }
|
|
3197 }
|
1
|
3198 g_free(temp);
|
12
|
3199 if (!flag)
|
|
3200 {
|
|
3201 gtk_html_add_text(html, cfont, current->color,
|
|
3202 current->bgcol, "<", 1, 0, 0, NULL);
|
|
3203 gtk_html_add_text(html, cfont, current->color,
|
|
3204 current->bgcol, tag, strlen(tag), 0,
|
|
3205 0, NULL);
|
|
3206 gtk_html_add_text(html, cfont, current->color,
|
|
3207 current->bgcol, ">", 1, 0, 0, NULL);
|
1
|
3208 }
|
12
|
3209 }
|
|
3210 else if (!strcasecmp(tag, "/A"))
|
|
3211 {
|
|
3212 if (url)
|
|
3213 {
|
1
|
3214 g_free(url);
|
|
3215 url = NULL;
|
|
3216 }
|
12
|
3217 }
|
|
3218 else if (!strncasecmp(tag, "FONT", strlen("FONT")))
|
|
3219 {
|
|
3220 char *d;
|
|
3221 /*
|
|
3222 * Push a new state onto the stack, based on the old state
|
|
3223 */
|
|
3224 current = push_state(current);
|
|
3225 html_strtok(tag, ' ');
|
|
3226 while ((d = html_strtok(NULL, ' ')))
|
|
3227 {
|
|
3228 if (!strncasecmp(d, "COLOR=", strlen("COLOR=")))
|
|
3229 {
|
|
3230 d += strlen("COLOR=");
|
|
3231 if (*d == '\"')
|
|
3232 {
|
|
3233 d++;
|
|
3234 }
|
|
3235 if (*d == '#')
|
|
3236 d++;
|
|
3237 if (d[strlen(d) - 1] == '\"')
|
|
3238 d[strlen(d) - 1] = 0;
|
|
3239 if (sscanf(d, "%x", &colorv)
|
|
3240 && !(options & HTML_OPTION_NO_COLOURS))
|
|
3241 {
|
1
|
3242 current->color = get_color(colorv, map);
|
|
3243 current->owncolor = 1;
|
12
|
3244 }
|
|
3245 else
|
|
3246 {
|
1
|
3247 }
|
12
|
3248 }
|
|
3249 if (!strncasecmp(d, "FACE=", strlen("FACE=")))
|
|
3250 {
|
|
3251 d += strlen("FACE=");
|
|
3252 if (*d == '\"')
|
|
3253 {
|
|
3254 d++;
|
|
3255 }
|
1
|
3256 if (d[strlen(d) - 1] == '\"')
|
|
3257 d[strlen(d) - 1] = 0;
|
12
|
3258 strcpy(current->font, d);
|
|
3259 }
|
|
3260 else if (!strncasecmp(d, "BACK=", strlen("BACK=")))
|
|
3261 {
|
|
3262 d += strlen("BACK=");
|
|
3263 if (*d == '\"')
|
|
3264 d++;
|
|
3265 if (*d == '#')
|
|
3266 d++;
|
|
3267 if (d[strlen(d) - 1] == '\"')
|
|
3268 d[strlen(d) - 1] = 0;
|
|
3269 if (sscanf(d, "%x", &colorv)
|
|
3270 && !(options & HTML_OPTION_NO_COLOURS))
|
|
3271 {
|
1
|
3272 current->bgcol = get_color(colorv, map);
|
|
3273 current->ownbg = 1;
|
12
|
3274 }
|
|
3275 else
|
|
3276 {
|
|
3277 }
|
|
3278 }
|
|
3279 else if (!strncasecmp(d, "SIZE=", strlen("SIZE=")))
|
|
3280 {
|
|
3281 d += strlen("SIZE=");
|
|
3282 if (*d == '\"')
|
|
3283 d++;
|
|
3284 if (*d == '+')
|
|
3285 d++;
|
|
3286 if (sscanf(d, "%d", &colorv))
|
|
3287 {
|
|
3288 current->size = colorv;
|
|
3289 }
|
|
3290 else
|
|
3291 {
|
1
|
3292 }
|
12
|
3293 }
|
|
3294 else if (strncasecmp(d, "PTSIZE=", strlen("PTSIZE=")))
|
|
3295 {
|
|
3296 }
|
1
|
3297 }
|
12
|
3298 }
|
|
3299 else
|
|
3300 if (!strncasecmp
|
|
3301 (tag, "BODY BGCOLOR", strlen("BODY BGCOLOR")))
|
|
3302 {
|
|
3303
|
|
3304 /*
|
|
3305 * Ditch trailing \"
|
|
3306 */
|
|
3307 tag[strlen(tag) - 1] = 0;
|
|
3308 if (sscanf(tag + strlen("BODY BGCOLOR=\"#"), "%x", &colorv)
|
|
3309 && !(options & HTML_OPTION_NO_COLOURS))
|
|
3310 {
|
|
3311 current->bgcol = get_color(colorv, map);
|
|
3312 current->ownbg = 1;
|
|
3313 }
|
|
3314 }
|
|
3315 else if (!strncasecmp(tag, "/FONT", strlen("/FONT")))
|
|
3316 {
|
|
3317 /*
|
|
3318 * Pop a font state off the list if possible, freeing
|
|
3319 * any resources it used
|
|
3320 */
|
|
3321 if (current->next)
|
|
3322 {
|
1
|
3323 if (current->ownbg)
|
|
3324 g_free(current->bgcol);
|
|
3325 if (current->owncolor)
|
|
3326 g_free(current->color);
|
12
|
3327 tmp = current;
|
|
3328 current = current->next;
|
|
3329 g_free(tmp);
|
|
3330 }
|
|
3331
|
|
3332 }
|
|
3333 else if (!strcasecmp(tag, "/BODY"))
|
|
3334 {
|
|
3335 if (current->next)
|
|
3336 {
|
|
3337 if (current->ownbg)
|
|
3338 g_free(current->bgcol);
|
|
3339 if (current->owncolor)
|
|
3340 g_free(current->color);
|
|
3341 tmp = current;
|
|
3342 current = current->next;
|
1
|
3343 g_free(tmp);
|
12
|
3344 } /*
|
|
3345 * tags we ignore below
|
|
3346 */
|
|
3347 }
|
|
3348 else if (!strncasecmp(tag, "BR", 2))
|
|
3349 {
|
|
3350 gtk_html_add_text(html, cfont, current->color,
|
|
3351 current->bgcol, "\n", 1, 0, 0, NULL);
|
|
3352 }
|
|
3353 else if (strncasecmp(tag, "HTML", 4)
|
|
3354 && strncasecmp(tag, "/HTML", 5)
|
|
3355 && strncasecmp(tag, "BODY", 4)
|
|
3356 && strncasecmp(tag, "/BODY", 5)
|
|
3357 && strncasecmp(tag, "P", 1)
|
|
3358 && strncasecmp(tag, "/P", 2)
|
|
3359 && strncasecmp(tag, "HEAD", 4)
|
|
3360 && strncasecmp(tag, "/HEAD", 5))
|
|
3361 {
|
|
3362 if (tpos)
|
|
3363 {
|
|
3364 gtk_html_add_text(html, cfont, current->color,
|
|
3365 current->bgcol, "<", 1, 0, 0, NULL);
|
|
3366 gtk_html_add_text(html, cfont, current->color,
|
|
3367 current->bgcol, tag, strlen(tag), 0,
|
|
3368 0, NULL);
|
|
3369 gtk_html_add_text(html, cfont, current->color,
|
|
3370 current->bgcol, ">", 1, 0, 0, NULL);
|
1
|
3371
|
|
3372 }
|
|
3373 }
|
12
|
3374 cfont = getfont(current->font, bold, italic, fixed, current->size);
|
|
3375 tpos = 0;
|
1
|
3376 intag = 0;
|
|
3377 }
|
12
|
3378 else
|
|
3379 {
|
1
|
3380 ws[wpos++] = *c;
|
|
3381 }
|
12
|
3382 }
|
|
3383 else if (!intag && *c == '&')
|
|
3384 {
|
|
3385 if (!strncasecmp(c, "&", 5))
|
|
3386 {
|
|
3387 ws[wpos++] = '&';
|
|
3388 c += 4;
|
|
3389 }
|
|
3390 else if (!strncasecmp(c, "<", 4))
|
|
3391 {
|
|
3392 ws[wpos++] = '<';
|
|
3393 c += 3;
|
|
3394 }
|
|
3395 else if (!strncasecmp(c, ">", 4))
|
|
3396 {
|
|
3397 ws[wpos++] = '>';
|
|
3398 c += 3;
|
|
3399 }
|
|
3400 else if (!strncasecmp(c, " ", 6))
|
|
3401 {
|
|
3402 ws[wpos++] = ' ';
|
|
3403 c += 5;
|
|
3404 }
|
|
3405 else
|
|
3406 {
|
|
3407 ws[wpos++] = *c;
|
|
3408 }
|
|
3409 }
|
|
3410 else
|
|
3411 {
|
|
3412 if (intag)
|
|
3413 {
|
|
3414 tag[tpos++] = *c;
|
|
3415 }
|
|
3416 else
|
|
3417 {
|
|
3418 ws[wpos++] = *c;
|
1
|
3419 }
|
|
3420 }
|
|
3421 c++;
|
|
3422 }
|
12
|
3423 while (current->next)
|
|
3424 {
|
1
|
3425 if (current->ownbg)
|
|
3426 g_free(current->bgcol);
|
|
3427 if (current->owncolor)
|
|
3428 g_free(current->color);
|
|
3429 tmp = current;
|
|
3430 current = current->next;
|
|
3431 g_free(tmp);
|
|
3432 }
|
12
|
3433 ws[wpos] = 0;
|
|
3434 tag[tpos] = 0;
|
|
3435 if (wpos)
|
|
3436 {
|
|
3437 gtk_html_add_text(html, cfont, current->color, current->bgcol, ws,
|
|
3438 strlen(ws), uline, strike, url);
|
1
|
3439 }
|
12
|
3440 if (tpos)
|
|
3441 {
|
|
3442 gtk_html_add_text(html, cfont, current->color, current->bgcol, "<", 1,
|
|
3443 0, 0, NULL);
|
|
3444 gtk_html_add_text(html, cfont, current->color, current->bgcol, tag,
|
|
3445 strlen(tag), 0, 0, NULL);
|
|
3446 gtk_html_add_text(html, cfont, current->color, current->bgcol, ">", 1,
|
|
3447 0, 0, NULL);
|
|
3448 }
|
|
3449
|
|
3450
|
|
3451
|
|
3452 gdk_window_get_size(html->html_area, NULL, &height);
|
|
3453 area.height = height;
|
1
|
3454 gtk_adjustment_set_value(html->vadj, html->vadj->upper - area.height);
|
|
3455
|
12
|
3456 return;
|
1
|
3457 }
|
|
3458
|
|
3459
|
12
|
3460 static void adjust_adj(GtkHtml * html, GtkAdjustment * adj)
|
1
|
3461 {
|
12
|
3462 gint height;
|
|
3463
|
|
3464 gdk_window_get_size(html->html_area, NULL, &height);
|
|
3465
|
|
3466 adj->step_increment = MIN(adj->upper, (float) SCROLL_PIXELS);
|
|
3467 adj->page_increment = MIN(adj->upper, height - (float) KEY_SCROLL_PIXELS);
|
|
3468 adj->page_size = MIN(adj->upper, height);
|
|
3469 adj->value = MIN(adj->value, adj->upper - adj->page_size);
|
|
3470 adj->value = MAX(adj->value, 0.0);
|
|
3471
|
|
3472 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
|
1
|
3473 }
|
|
3474
|
|
3475
|
12
|
3476 static void scroll_down(GtkHtml * html, gint diff0)
|
1
|
3477 {
|
12
|
3478 GdkRectangle rect;
|
|
3479 gint width,
|
|
3480 height;
|
|
3481
|
|
3482 html->yoffset += diff0;
|
|
3483
|
|
3484 gdk_window_get_size(html->html_area, &width, &height);
|
|
3485
|
|
3486 if (html->transparent)
|
|
3487 {
|
1
|
3488 rect.x = 0;
|
|
3489 rect.y = 0;
|
|
3490 rect.width = width;
|
|
3491 rect.height = height;
|
12
|
3492 }
|
|
3493 else
|
|
3494 {
|
|
3495
|
1
|
3496
|
|
3497 if (height > diff0 && !html->transparent)
|
12
|
3498 gdk_draw_pixmap(html->html_area,
|
|
3499 html->gc,
|
|
3500 html->html_area,
|
|
3501 0, diff0, 0, 0, width, height - diff0);
|
|
3502
|
|
3503 rect.x = 0;
|
|
3504 rect.y = MAX(0, height - diff0);
|
|
3505 rect.width = width;
|
|
3506 rect.height = MIN(height, diff0);
|
1
|
3507 }
|
12
|
3508
|
|
3509 expose_html(html, &rect, FALSE);
|
|
3510 gtk_html_draw_focus((GtkWidget *) html);
|
1
|
3511
|
|
3512 }
|
|
3513
|
12
|
3514 static void scroll_up(GtkHtml * html, gint diff0)
|
1
|
3515 {
|
12
|
3516 GdkRectangle rect;
|
|
3517 gint width,
|
|
3518 height;
|
|
3519
|
1
|
3520 html->yoffset -= diff0;
|
|
3521
|
|
3522
|
12
|
3523 gdk_window_get_size(html->html_area, &width, &height);
|
|
3524
|
|
3525 if (html->transparent)
|
|
3526 {
|
1
|
3527 rect.x = 0;
|
|
3528 rect.y = 0;
|
|
3529 rect.width = width;
|
|
3530 rect.height = height;
|
12
|
3531 }
|
|
3532 else
|
|
3533 {
|
|
3534
|
1
|
3535 if (height > diff0)
|
12
|
3536 gdk_draw_pixmap(html->html_area,
|
|
3537 html->gc,
|
|
3538 html->html_area,
|
|
3539 0, 0, 0, diff0, width, height - diff0);
|
|
3540
|
|
3541 rect.x = 0;
|
|
3542 rect.y = 0;
|
|
3543 rect.width = width;
|
|
3544 rect.height = MIN(height, diff0);
|
1
|
3545 }
|
|
3546
|
12
|
3547 expose_html(html, &rect, FALSE);
|
|
3548 gtk_html_draw_focus((GtkWidget *) html);
|
1
|
3549
|
|
3550 }
|
|
3551
|
|
3552
|
|
3553
|
12
|
3554 static void gtk_html_adjustment(GtkAdjustment * adjustment, GtkHtml * html)
|
1
|
3555 {
|
12
|
3556 g_return_if_fail(adjustment != NULL);
|
|
3557 g_return_if_fail(GTK_IS_ADJUSTMENT(adjustment));
|
|
3558 g_return_if_fail(html != NULL);
|
|
3559 g_return_if_fail(GTK_IS_HTML(html));
|
|
3560
|
|
3561 /*
|
|
3562 * Just ignore it if we haven't been size-allocated and realized yet
|
|
3563 */
|
|
3564 if (html->html_area == NULL)
|
|
3565 return;
|
|
3566
|
|
3567 if (adjustment == html->hadj)
|
|
3568 {
|
|
3569 g_warning("horizontal scrolling not implemented");
|
|
3570 }
|
|
3571 else
|
|
3572 {
|
|
3573 gint diff = ((gint) adjustment->value) - html->last_ver_value;
|
|
3574
|
|
3575 if (diff != 0)
|
|
3576 {
|
|
3577 /*
|
|
3578 * undraw_cursor (text, FALSE);
|
|
3579 */
|
|
3580
|
|
3581 if (diff > 0)
|
|
3582 {
|
|
3583 scroll_down(html, diff);
|
|
3584 }
|
|
3585 else
|
|
3586 { /*
|
|
3587 * if (diff < 0)
|
|
3588 */
|
|
3589 scroll_up(html, -diff);
|
|
3590 }
|
|
3591 /*
|
|
3592 * draw_cursor (text, FALSE);
|
|
3593 */
|
|
3594
|
|
3595 html->last_ver_value = adjustment->value;
|
|
3596 }
|
|
3597 }
|
1
|
3598 }
|
12
|
3599
|
|
3600 static gint gtk_html_visibility_notify(GtkWidget * widget,
|
|
3601 GdkEventVisibility * event)
|
1
|
3602 {
|
|
3603 GtkHtml *html;
|
|
3604 GdkRectangle rect;
|
12
|
3605 gint width,
|
|
3606 height;
|
|
3607
|
|
3608 g_return_val_if_fail(widget != NULL, FALSE);
|
|
3609 g_return_val_if_fail(GTK_IS_HTML(widget), FALSE);
|
|
3610
|
|
3611 html = GTK_HTML(widget);
|
|
3612
|
|
3613 if (GTK_WIDGET_REALIZED(widget) && html->transparent)
|
|
3614 {
|
|
3615 gdk_window_get_size(html->html_area, &width, &height);
|
|
3616 rect.x = 0;
|
|
3617 rect.y = 0;
|
|
3618 rect.width = width;
|
|
3619 rect.height = height;
|
|
3620 expose_html(html, &rect, FALSE);
|
|
3621 gtk_html_draw_focus((GtkWidget *) html);
|
|
3622 }
|
|
3623 else
|
|
3624 {
|
1
|
3625 }
|
|
3626
|
|
3627
|
12
|
3628 return FALSE;
|
1
|
3629 }
|
|
3630
|
|
3631
|
|
3632
|
12
|
3633 static void gtk_html_disconnect(GtkAdjustment * adjustment, GtkHtml * html)
|
1
|
3634 {
|
12
|
3635 g_return_if_fail(adjustment != NULL);
|
|
3636 g_return_if_fail(GTK_IS_ADJUSTMENT(adjustment));
|
|
3637 g_return_if_fail(html != NULL);
|
|
3638 g_return_if_fail(GTK_IS_HTML(html));
|
|
3639
|
|
3640 if (adjustment == html->hadj)
|
|
3641 gtk_html_set_adjustments(html, NULL, html->vadj);
|
|
3642 if (adjustment == html->vadj)
|
|
3643 gtk_html_set_adjustments(html, html->hadj, NULL);
|
1
|
3644 }
|
|
3645
|
12
|
3646 static void move_cursor_ver(GtkHtml * html, int count)
|
1
|
3647 {
|
|
3648 GList *hbits = g_list_find(html->html_bits, html->cursor_hb);
|
12
|
3649 GtkHtmlBit *hb = NULL,
|
|
3650 *hb2 = NULL;
|
1
|
3651 gint y;
|
79
|
3652 size_t len,
|
12
|
3653 len2 = 0;
|
|
3654
|
1
|
3655 undraw_cursor(html);
|
|
3656
|
|
3657 if (!html->html_bits)
|
|
3658 return;
|
12
|
3659
|
1
|
3660 if (!html->cursor_hb)
|
12
|
3661 html->cursor_hb = (GtkHtmlBit *) html->html_bits->data;
|
1
|
3662
|
|
3663 hb = html->cursor_hb;
|
|
3664
|
|
3665 len = html->cursor_pos;
|
|
3666 hbits = hbits->prev;
|
12
|
3667 while (hbits)
|
|
3668 {
|
|
3669 hb2 = (GtkHtmlBit *) hbits->data;
|
1
|
3670
|
|
3671 if (hb2->y != hb->y)
|
|
3672 break;
|
|
3673
|
12
|
3674 len += strlen(hb2->text);
|
|
3675
|
1
|
3676 hbits = hbits->prev;
|
|
3677 }
|
|
3678
|
12
|
3679 hbits = g_list_find(html->html_bits, html->cursor_hb);
|
|
3680
|
|
3681 if (count < 0)
|
|
3682 {
|
|
3683 while (hbits)
|
|
3684 {
|
|
3685 hb2 = (GtkHtmlBit *) hbits->data;
|
1
|
3686
|
|
3687 if (hb2->y != hb->y)
|
|
3688 break;
|
12
|
3689
|
1
|
3690 hbits = hbits->prev;
|
|
3691 }
|
12
|
3692 if (!hbits)
|
|
3693 {
|
1
|
3694 draw_cursor(html);
|
|
3695 return;
|
|
3696 }
|
|
3697 y = hb2->y;
|
|
3698 hb = hb2;
|
12
|
3699 while (hbits)
|
|
3700 {
|
|
3701 hb2 = (GtkHtmlBit *) hbits->data;
|
1
|
3702
|
|
3703 if (hb2->y != y)
|
|
3704 break;
|
|
3705
|
|
3706 hb = hb2;
|
12
|
3707
|
1
|
3708 hbits = hbits->prev;
|
|
3709 }
|
|
3710 hbits = g_list_find(html->html_bits, hb);
|
12
|
3711 while (hbits)
|
|
3712 {
|
|
3713 hb2 = (GtkHtmlBit *) hbits->data;
|
|
3714
|
|
3715 if (hb->y != hb2->y)
|
|
3716 {
|
1
|
3717 html->cursor_hb = hb;
|
|
3718 html->cursor_pos = strlen(hb->text);
|
12
|
3719 break;
|
1
|
3720 }
|
|
3721
|
|
3722
|
12
|
3723 if (len < len2 + strlen(hb2->text))
|
|
3724 {
|
1
|
3725 html->cursor_hb = hb2;
|
|
3726 html->cursor_pos = len - len2;
|
|
3727 break;
|
|
3728 }
|
|
3729
|
|
3730 len2 += strlen(hb2->text);
|
|
3731
|
|
3732 hb = hb2;
|
|
3733
|
12
|
3734 hbits = hbits->next;
|
1
|
3735 }
|
12
|
3736 }
|
|
3737 else
|
|
3738 {
|
|
3739 while (hbits)
|
|
3740 {
|
|
3741 hb2 = (GtkHtmlBit *) hbits->data;
|
1
|
3742
|
|
3743 if (hb2->y != hb->y)
|
|
3744 break;
|
12
|
3745
|
1
|
3746 hbits = hbits->next;
|
|
3747 }
|
12
|
3748 if (!hbits)
|
|
3749 {
|
1
|
3750 draw_cursor(html);
|
|
3751 return;
|
|
3752 }
|
|
3753 hb = hb2;
|
12
|
3754 while (hbits)
|
|
3755 {
|
|
3756 hb2 = (GtkHtmlBit *) hbits->data;
|
|
3757
|
|
3758 if (hb->y != hb2->y)
|
|
3759 {
|
1
|
3760 html->cursor_hb = hb;
|
|
3761 html->cursor_pos = strlen(hb->text);
|
12
|
3762 break;
|
1
|
3763 }
|
|
3764
|
|
3765
|
12
|
3766 if (len < len2 + strlen(hb2->text))
|
|
3767 {
|
1
|
3768 html->cursor_hb = hb2;
|
|
3769 html->cursor_pos = len - len2;
|
|
3770 break;
|
|
3771 }
|
|
3772
|
|
3773 len2 += strlen(hb2->text);
|
|
3774
|
|
3775 hb = hb2;
|
|
3776
|
12
|
3777 hbits = hbits->next;
|
1
|
3778 }
|
|
3779 }
|
|
3780
|
|
3781 draw_cursor(html);
|
|
3782
|
|
3783 }
|
|
3784
|
12
|
3785 static void move_cursor_hor(GtkHtml * html, int count)
|
1
|
3786 {
|
|
3787 GList *hbits = g_list_find(html->html_bits, html->cursor_hb);
|
12
|
3788 GtkHtmlBit *hb,
|
|
3789 *hb2;
|
1
|
3790
|
|
3791 undraw_cursor(html);
|
|
3792
|
|
3793 if (!html->html_bits)
|
|
3794 return;
|
12
|
3795
|
1
|
3796 if (!html->cursor_hb)
|
12
|
3797 html->cursor_hb = (GtkHtmlBit *) html->html_bits->data;
|
|
3798
|
|
3799 html->cursor_pos += count;
|
|
3800
|
|
3801 if (html->cursor_pos < 0)
|
|
3802 {
|
|
3803 if (hbits->prev)
|
|
3804 {
|
1
|
3805 gint diff;
|
|
3806 hb = html->cursor_hb;
|
12
|
3807 hb2 = (GtkHtmlBit *) hbits->prev->data;
|
1
|
3808 diff = html->cursor_pos + strlen(hb2->text) + 1;
|
|
3809 if (hb->y == hb2->y)
|
|
3810 --diff;
|
12
|
3811
|
1
|
3812 html->cursor_pos = diff;
|
12
|
3813
|
|
3814 html->cursor_hb = (GtkHtmlBit *) hbits->prev->data;
|
|
3815 }
|
|
3816 else
|
|
3817 {
|
1
|
3818 html->cursor_pos = 0;
|
|
3819 }
|
12
|
3820 }
|
79
|
3821 else if ((unsigned) html->cursor_pos > strlen(html->cursor_hb->text))
|
12
|
3822 {
|
|
3823 if (hbits->next)
|
|
3824 {
|
1
|
3825 gint diff;
|
|
3826 hb = html->cursor_hb;
|
12
|
3827 hb2 = (GtkHtmlBit *) hbits->next->data;
|
1
|
3828
|
|
3829 diff = html->cursor_pos - strlen(html->cursor_hb->text) - 1;
|
|
3830 if (hb->y == hb2->y)
|
12
|
3831 ++diff;
|
1
|
3832 html->cursor_pos = diff;
|
12
|
3833 html->cursor_hb = (GtkHtmlBit *) hbits->next->data;
|
|
3834 }
|
|
3835 else
|
|
3836 {
|
1
|
3837 html->cursor_pos = strlen(html->cursor_hb->text);
|
|
3838 }
|
|
3839
|
|
3840 }
|
|
3841
|
|
3842 draw_cursor(html);
|
|
3843 }
|
|
3844
|
12
|
3845 static void move_beginning_of_line(GtkHtml * html)
|
1
|
3846 {
|
|
3847 GList *hbits = g_list_find(html->html_bits, html->cursor_hb);
|
|
3848 GtkHtmlBit *hb = NULL;
|
12
|
3849 gint y;
|
|
3850
|
1
|
3851 undraw_cursor(html);
|
|
3852
|
|
3853 if (!html->html_bits)
|
|
3854 return;
|
|
3855
|
|
3856 if (!html->cursor_hb)
|
12
|
3857 html->cursor_hb = (GtkHtmlBit *) html->html_bits->data;
|
1
|
3858
|
|
3859 y = html->cursor_hb->y;
|
12
|
3860
|
|
3861 while (hbits)
|
|
3862 {
|
|
3863 hb = (GtkHtmlBit *) hbits->data;
|
|
3864
|
|
3865 if (y != hb->y)
|
|
3866 {
|
|
3867 hb = (GtkHtmlBit *) hbits->next->data;
|
1
|
3868 break;
|
|
3869 }
|
12
|
3870
|
1
|
3871 hbits = hbits->prev;
|
|
3872 }
|
|
3873 if (!hbits)
|
12
|
3874 html->cursor_hb = (GtkHtmlBit *) html->html_bits->data;
|
1
|
3875 else
|
|
3876 html->cursor_hb = hb;
|
|
3877
|
|
3878 html->cursor_pos = 0;
|
|
3879
|
|
3880
|
|
3881 draw_cursor(html);
|
|
3882
|
|
3883
|
|
3884 }
|
|
3885
|
12
|
3886 static void move_end_of_line(GtkHtml * html)
|
1
|
3887 {
|
|
3888 GList *hbits = g_list_find(html->html_bits, html->cursor_hb);
|
|
3889 GtkHtmlBit *hb = NULL;
|
12
|
3890 gint y;
|
|
3891
|
1
|
3892 undraw_cursor(html);
|
|
3893
|
|
3894 if (!html->html_bits)
|
|
3895 return;
|
|
3896
|
|
3897 if (!html->cursor_hb)
|
12
|
3898 html->cursor_hb = (GtkHtmlBit *) html->html_bits->data;
|
1
|
3899
|
|
3900 y = html->cursor_hb->y;
|
12
|
3901
|
|
3902 while (hbits)
|
|
3903 {
|
|
3904 hb = (GtkHtmlBit *) hbits->data;
|
|
3905
|
|
3906 if (y != hb->y)
|
|
3907 {
|
|
3908 hb = (GtkHtmlBit *) hbits->prev->data;
|
1
|
3909 break;
|
|
3910 }
|
12
|
3911
|
1
|
3912 hbits = hbits->next;
|
|
3913 }
|
|
3914 if (!hbits)
|
12
|
3915 html->cursor_hb = (GtkHtmlBit *) g_list_last(html->html_bits)->data;
|
1
|
3916 else
|
|
3917 html->cursor_hb = hb;
|
|
3918
|
|
3919 html->cursor_pos = strlen(html->cursor_hb->text);
|
|
3920
|
|
3921
|
|
3922 draw_cursor(html);
|
|
3923
|
|
3924
|
|
3925 }
|
|
3926
|
|
3927
|
|
3928
|
12
|
3929 static gint gtk_html_key_press(GtkWidget * widget, GdkEventKey * event)
|
1
|
3930 {
|
|
3931 GtkHtml *html;
|
|
3932 gchar key;
|
|
3933 gint return_val;
|
12
|
3934
|
|
3935 g_return_val_if_fail(widget != NULL, FALSE);
|
|
3936 g_return_val_if_fail(GTK_IS_HTML(widget), FALSE);
|
|
3937 g_return_val_if_fail(event != NULL, FALSE);
|
|
3938
|
1
|
3939 return_val = FALSE;
|
12
|
3940
|
|
3941 html = GTK_HTML(widget);
|
|
3942
|
1
|
3943 key = event->keyval;
|
|
3944 return_val = TRUE;
|
|
3945
|
|
3946
|
12
|
3947 if (html->editable == FALSE)
|
|
3948 {
|
|
3949 /*
|
|
3950 * switch (event->keyval) {
|
|
3951 * case GDK_Home:
|
|
3952 * if (event->state & GDK_CONTROL_MASK)
|
|
3953 * scroll_int (text, -text->vadj->value);
|
|
3954 * else
|
|
3955 * return_val = FALSE;
|
|
3956 * break;
|
|
3957 * case GDK_End:
|
|
3958 * if (event->state & GDK_CONTROL_MASK)
|
|
3959 * scroll_int (text, +text->vadj->upper);
|
|
3960 * else
|
|
3961 * return_val = FALSE;
|
|
3962 * break;
|
|
3963 * case GDK_Page_Up: scroll_int (text, -text->vadj->page_increment); break;
|
|
3964 * case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break;
|
|
3965 * case GDK_Up: scroll_int (text, -KEY_SCROLL_PIXELS); break;
|
|
3966 * case GDK_Down: scroll_int (text, +KEY_SCROLL_PIXELS); break;
|
|
3967 * case GDK_Return:
|
|
3968 * if (event->state & GDK_CONTROL_MASK)
|
|
3969 * gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
|
|
3970 * else
|
|
3971 * return_val = FALSE;
|
|
3972 * break;
|
|
3973 * default:
|
|
3974 * return_val = FALSE;
|
|
3975 * break;
|
|
3976 * }
|
|
3977 */
|
|
3978 }
|
|
3979 else
|
|
3980 {
|
|
3981
|
|
3982 switch (event->keyval)
|
|
3983 {
|
1
|
3984 case GDK_Home:
|
12
|
3985 move_beginning_of_line(html);
|
1
|
3986 break;
|
|
3987 case GDK_End:
|
12
|
3988 move_end_of_line(html);
|
1
|
3989 break;
|
|
3990 /*
|
12
|
3991 * case GDK_Page_Up:
|
|
3992 * move_cursor_page_ver (html, -1);
|
|
3993 * break;
|
|
3994 * case GDK_Page_Down:
|
|
3995 * move_cursor_page_ver (html, +1);
|
|
3996 * break;
|
|
3997 */
|
|
3998 /*
|
|
3999 * CUA has Ctrl-Up/Ctrl-Down as paragraph up down
|
|
4000 */
|
1
|
4001 case GDK_Up:
|
12
|
4002 move_cursor_ver(html, -1);
|
1
|
4003 break;
|
|
4004 case GDK_Down:
|
12
|
4005 move_cursor_ver(html, +1);
|
1
|
4006 break;
|
|
4007 case GDK_Left:
|
12
|
4008 move_cursor_hor(html, -1);
|
1
|
4009 break;
|
|
4010 case GDK_Right:
|
12
|
4011 move_cursor_hor(html, +1);
|
1
|
4012 break;
|
|
4013 #if 0
|
|
4014 case GDK_BackSpace:
|
|
4015 if (event->state & GDK_CONTROL_MASK)
|
12
|
4016 gtk_text_delete_backward_word(text);
|
1
|
4017 else
|
12
|
4018 gtk_text_delete_backward_character(text);
|
1
|
4019 break;
|
|
4020 case GDK_Clear:
|
12
|
4021 gtk_text_delete_line(text);
|
1
|
4022 break;
|
|
4023 case GDK_Insert:
|
|
4024 if (event->state & GDK_SHIFT_MASK)
|
|
4025 {
|
|
4026 extend_selection = FALSE;
|
12
|
4027 gtk_editable_paste_clipboard(editable);
|
1
|
4028 }
|
|
4029 else if (event->state & GDK_CONTROL_MASK)
|
|
4030 {
|
12
|
4031 gtk_editable_copy_clipboard(editable);
|
1
|
4032 }
|
|
4033 else
|
|
4034 {
|
12
|
4035 /*
|
|
4036 * gtk_toggle_insert(text) -- IMPLEMENT
|
|
4037 */
|
1
|
4038 }
|
|
4039 break;
|
|
4040 case GDK_Delete:
|
|
4041 if (event->state & GDK_CONTROL_MASK)
|
12
|
4042 gtk_text_delete_forward_word(text);
|
1
|
4043 else if (event->state & GDK_SHIFT_MASK)
|
|
4044 {
|
|
4045 extend_selection = FALSE;
|
12
|
4046 gtk_editable_cut_clipboard(editable);
|
1
|
4047 }
|
|
4048 else
|
12
|
4049 gtk_text_delete_forward_character(text);
|
1
|
4050 break;
|
|
4051 case GDK_Tab:
|
|
4052 position = text->point.index;
|
12
|
4053 gtk_editable_insert_text(editable, "\t", 1, &position);
|
1
|
4054 break;
|
|
4055 case GDK_Return:
|
|
4056 if (event->state & GDK_CONTROL_MASK)
|
12
|
4057 gtk_signal_emit_by_name(GTK_OBJECT(text), "activate");
|
1
|
4058 else
|
|
4059 {
|
|
4060 position = text->point.index;
|
12
|
4061 gtk_editable_insert_text(editable, "\n", 1, &position);
|
1
|
4062 }
|
|
4063 break;
|
|
4064 case GDK_Escape:
|
12
|
4065 /*
|
|
4066 * Don't insert literally
|
|
4067 */
|
1
|
4068 return_val = FALSE;
|
|
4069 break;
|
|
4070 #endif
|
|
4071 default:
|
|
4072 return_val = FALSE;
|
|
4073
|
|
4074 #if 0
|
12
|
4075 if (event->state & GDK_CONTROL_MASK)
|
|
4076 {
|
1
|
4077 if ((key >= 'A') && (key <= 'Z'))
|
|
4078 key -= 'A' - 'a';
|
|
4079
|
12
|
4080 if ((key >= 'a') && (key <= 'z')
|
|
4081 && control_keys[(int) (key - 'a')])
|
1
|
4082 {
|
12
|
4083 (*control_keys[(int) (key - 'a')]) (editable, event->time);
|
1
|
4084 return_val = TRUE;
|
|
4085 }
|
|
4086
|
|
4087 break;
|
|
4088 }
|
|
4089 else if (event->state & GDK_MOD1_MASK)
|
|
4090 {
|
|
4091 if ((key >= 'A') && (key <= 'Z'))
|
|
4092 key -= 'A' - 'a';
|
|
4093
|
|
4094 if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')])
|
|
4095 {
|
12
|
4096 (*alt_keys[(int) (key - 'a')]) (editable, event->time);
|
1
|
4097 return_val = TRUE;
|
|
4098 }
|
|
4099 break;
|
|
4100 }
|
|
4101 #endif
|
|
4102 /*
|
12
|
4103 * if (event->length > 0) {
|
|
4104 * html->cursor_pos++;
|
|
4105 * gtk_editable_insert_text (editable, event->string, event->length, &position);
|
|
4106 *
|
|
4107 * return_val = TRUE;
|
|
4108 * }
|
|
4109 * else
|
|
4110 * return_val = FALSE;
|
|
4111 */
|
1
|
4112 }
|
|
4113
|
|
4114 }
|
|
4115
|
|
4116 return return_val;
|
|
4117 }
|
12
|
4118
|
|
4119 void gtk_html_freeze(GtkHtml * html)
|
1
|
4120 {
|
12
|
4121 g_return_if_fail(html != NULL);
|
|
4122 g_return_if_fail(GTK_IS_HTML(html));
|
1
|
4123
|
|
4124 html->frozen++;
|
|
4125 }
|
|
4126
|
12
|
4127 void gtk_html_thaw(GtkHtml * html)
|
1
|
4128 {
|
|
4129 GdkRectangle area;
|
12
|
4130
|
|
4131 g_return_if_fail(html != NULL);
|
|
4132 g_return_if_fail(GTK_IS_HTML(html));
|
1
|
4133
|
|
4134 html->frozen--;
|
|
4135
|
|
4136 if (html->frozen < 0)
|
12
|
4137 html->frozen = 0;
|
|
4138
|
|
4139 if (html->frozen == 0)
|
|
4140 {
|
|
4141 if (html->html_area)
|
|
4142 {
|
|
4143 gint width,
|
|
4144 height;
|
1
|
4145 area.x = 0;
|
|
4146 area.y = 0;
|
|
4147
|
|
4148 gdk_window_get_size(html->html_area, &width, &height);
|
|
4149
|
12
|
4150 area.width = width;
|
|
4151 area.height = height;
|
|
4152
|
1
|
4153 expose_html(html, &area, TRUE);
|
|
4154 }
|
|
4155 }
|
|
4156 }
|