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