1
2 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* This file is part of the GtkHTML library.
4 *
5 * Copyright (C) 2000 Helix Code, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <config.h>
24 #include <gtk/gtk.h>
25 #include <string.h>
26 #include "gtkhtml.h"
27 #include "gtkhtml-stream.h"
28 #include "htmltokenizer.h"
29 #include "gtkhtml-private.h"
30 #include "htmlcolorset.h"
31 #include "htmlgdkpainter.h"
32 #include "htmlprinter.h"
33 #include "htmlframe.h"
34 #include "htmlengine-search.h"
35 #include "htmlsearch.h"
36 #include "htmlselection.h"
37 #include "htmlsettings.h"
38
39 HTMLFrameClass html_frame_class;
40 static HTMLEmbeddedClass *parent_class = NULL;
41
42 static void
frame_url_requested(GtkHTML * html,const gchar * url,GtkHTMLStream * handle,gpointer data)43 frame_url_requested (GtkHTML *html,
44 const gchar *url,
45 GtkHTMLStream *handle,
46 gpointer data)
47 {
48 HTMLFrame *frame = HTML_FRAME (data);
49 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
50
51 if (!html->engine->stopped)
52 g_signal_emit_by_name (parent->engine, "url_requested", url, handle);
53 }
54
55 static void
frame_set_base(GtkHTML * html,const gchar * url,gpointer data)56 frame_set_base (GtkHTML *html,
57 const gchar *url,
58 gpointer data)
59 {
60 gchar *new_url = NULL;
61
62 new_url = gtk_html_get_url_base_relative (html, url);
63 gtk_html_set_base (html, new_url);
64 g_free (new_url);
65 }
66
67 static void
frame_submit(GtkHTML * html,const gchar * method,const gchar * action,const gchar * encoding,gpointer data)68 frame_submit (GtkHTML *html,
69 const gchar *method,
70 const gchar *action,
71 const gchar *encoding,
72 gpointer data)
73 {
74 HTMLFrame *frame = HTML_FRAME (data);
75 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
76
77 g_signal_emit_by_name (parent, "submit", method, action, encoding);
78 }
79
80 static void
frame_size_changed(GtkHTML * html,gpointer data)81 frame_size_changed (GtkHTML *html,
82 gpointer data)
83 {
84 HTMLFrame *frame = HTML_FRAME (data);
85 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
86
87 html_engine_schedule_update (parent->engine);
88 }
89
90 static gboolean
frame_object_requested(GtkHTML * html,GtkHTMLEmbedded * eb,gpointer data)91 frame_object_requested (GtkHTML *html,
92 GtkHTMLEmbedded *eb,
93 gpointer data)
94 {
95 HTMLFrame *frame = HTML_FRAME (data);
96 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
97 gboolean ret_val;
98
99 ret_val = FALSE;
100 g_signal_emit_by_name (parent, "object_requested", eb, &ret_val);
101 return ret_val;
102 }
103
104 static void
frame_set_gdk_painter(HTMLFrame * frame,HTMLPainter * painter)105 frame_set_gdk_painter (HTMLFrame *frame,
106 HTMLPainter *painter)
107 {
108 if (painter)
109 g_object_ref (G_OBJECT (painter));
110
111 if (frame->gdk_painter)
112 g_object_unref (G_OBJECT (frame->gdk_painter));
113
114 frame->gdk_painter = painter;
115 }
116
117 HTMLObject *
html_frame_new(GtkWidget * parent,gchar * src,gint width,gint height,gboolean border)118 html_frame_new (GtkWidget *parent,
119 gchar *src,
120 gint width,
121 gint height,
122 gboolean border)
123 {
124 HTMLFrame *frame;
125
126 frame = g_new (HTMLFrame, 1);
127
128 html_frame_init (frame,
129 &html_frame_class,
130 parent,
131 src,
132 width,
133 height,
134 border);
135
136 return HTML_OBJECT (frame);
137 }
138
139 static gboolean
html_frame_grab_cursor(GtkWidget * frame,GdkEvent * event)140 html_frame_grab_cursor (GtkWidget *frame,
141 GdkEvent *event)
142 {
143 /* Keep the focus! Fight the power */
144 return TRUE;
145 }
146
147 static gint
calc_min_width(HTMLObject * o,HTMLPainter * painter)148 calc_min_width (HTMLObject *o,
149 HTMLPainter *painter)
150 {
151 gint min_width;
152
153 if (HTML_FRAME (o)->width < 0)
154 min_width = html_engine_calc_min_width (GTK_HTML (HTML_FRAME (o)->html)->engine);
155 else
156 min_width = HTML_FRAME (o)->width;
157
158 return min_width;
159 }
160
161 static void
set_max_width(HTMLObject * o,HTMLPainter * painter,gint max_width)162 set_max_width (HTMLObject *o,
163 HTMLPainter *painter,
164 gint max_width)
165 {
166 HTMLEngine *e = GTK_HTML (HTML_FRAME (o)->html)->engine;
167
168 o->max_width = max_width;
169 html_object_set_max_width (e->clue, e->painter, max_width - (html_engine_get_left_border (e) + html_engine_get_right_border (e)));
170 }
171
172 static void
draw(HTMLObject * o,HTMLPainter * p,gint x,gint y,gint width,gint height,gint tx,gint ty)173 draw (HTMLObject *o,
174 HTMLPainter *p,
175 gint x,
176 gint y,
177 gint width,
178 gint height,
179 gint tx,
180 gint ty)
181 {
182 HTMLFrame *frame = HTML_FRAME (o);
183 HTMLEngine *e = GTK_HTML (frame->html)->engine;
184 GdkRectangle paint;
185
186 if (G_OBJECT_TYPE (e->painter) == HTML_TYPE_PRINTER) {
187 gint pixel_size = html_painter_get_pixel_size (e->painter);
188
189 if (!html_object_intersect (o, &paint, x, y, width, height))
190 return;
191
192 html_object_draw (e->clue, e->painter,
193 x, y,
194 width - pixel_size * (html_engine_get_left_border (e) + html_engine_get_right_border (e)),
195 height - pixel_size * (html_engine_get_top_border (e) + html_engine_get_bottom_border (e)),
196 tx + pixel_size * html_engine_get_left_border (e), ty + pixel_size * html_engine_get_top_border (e));
197 } else
198 (*HTML_OBJECT_CLASS (parent_class)->draw) (o, p, x, y, width, height, tx, ty);
199 }
200
201 static void
set_painter(HTMLObject * o,HTMLPainter * painter)202 set_painter (HTMLObject *o,
203 HTMLPainter *painter)
204 {
205 HTMLFrame *frame;
206
207 frame = HTML_FRAME (o);
208 if (G_OBJECT_TYPE (GTK_HTML (frame->html)->engine->painter) != HTML_TYPE_PRINTER) {
209 frame_set_gdk_painter (frame, GTK_HTML (frame->html)->engine->painter);
210 }
211
212 html_engine_set_painter (GTK_HTML (frame->html)->engine,
213 G_OBJECT_TYPE (painter) != HTML_TYPE_PRINTER ? frame->gdk_painter : painter);
214 }
215
216 static void
forall(HTMLObject * self,HTMLEngine * e,HTMLObjectForallFunc func,gpointer data)217 forall (HTMLObject *self,
218 HTMLEngine *e,
219 HTMLObjectForallFunc func,
220 gpointer data)
221 {
222 HTMLFrame *frame;
223
224 frame = HTML_FRAME (self);
225 (* func) (self, html_object_get_engine (self, e), data);
226 html_object_forall (GTK_HTML (frame->html)->engine->clue, html_object_get_engine (self, e), func, data);
227 }
228
229 static gint
check_page_split(HTMLObject * self,HTMLPainter * p,gint y)230 check_page_split (HTMLObject *self,
231 HTMLPainter *p,
232 gint y)
233 {
234 return html_object_check_page_split (GTK_HTML (HTML_FRAME (self)->html)->engine->clue, p, y);
235 }
236
237 static gboolean
html_frame_real_calc_size(HTMLObject * o,HTMLPainter * painter,GList ** changed_objs)238 html_frame_real_calc_size (HTMLObject *o,
239 HTMLPainter *painter,
240 GList **changed_objs)
241 {
242 HTMLFrame *frame;
243 HTMLEngine *e;
244 gint old_width, old_ascent, old_descent;
245
246 old_width = o->width;
247 old_ascent = o->ascent;
248 old_descent = o->descent;
249
250 frame = HTML_FRAME (o);
251 e = GTK_HTML (frame->html)->engine;
252
253 if ((frame->width < 0) && (frame->height < 0)) {
254 if (e->clue) {
255 html_engine_calc_size (e, changed_objs);
256 e->width = html_engine_get_doc_width (e);
257 e->height = html_engine_get_doc_height (e);
258 }
259 html_frame_set_scrolling (frame, GTK_POLICY_NEVER);
260
261 o->width = e->width;
262 o->ascent = e->height;
263 o->descent = 0;
264 } else
265 return (* HTML_OBJECT_CLASS (parent_class)->calc_size) (o, painter, changed_objs);
266
267 if (o->descent != old_descent
268 || o->ascent != old_ascent
269 || o->width != old_width)
270 return TRUE;
271
272 return FALSE;
273 }
274
275 static gboolean
search(HTMLObject * self,HTMLSearch * info)276 search (HTMLObject *self,
277 HTMLSearch *info)
278 {
279 HTMLEngine *e = GTK_HTML (HTML_FRAME (self)->html)->engine;
280
281 /* printf ("search\n"); */
282
283 /* search_next? */
284 if (info->stack && HTML_OBJECT (info->stack->data) == e->clue) {
285 /* printf ("next\n"); */
286 info->engine = GTK_HTML (GTK_HTML (HTML_FRAME (self)->html)->iframe_parent)->engine;
287 html_search_pop (info);
288 html_engine_unselect_all (e);
289 return html_search_next_parent (info);
290 }
291
292 info->engine = e;
293 html_search_push (info, e->clue);
294 if (html_object_search (e->clue, info))
295 return TRUE;
296 html_search_pop (info);
297
298 info->engine = GTK_HTML (GTK_HTML (HTML_FRAME (self)->html)->iframe_parent)->engine;
299 /* printf ("FALSE\n"); */
300
301 return FALSE;
302 }
303
304 static HTMLObject *
head(HTMLObject * self)305 head (HTMLObject *self)
306 {
307 return GTK_HTML (HTML_FRAME (self)->html)->engine->clue;
308 }
309
310 static HTMLObject *
tail(HTMLObject * self)311 tail (HTMLObject *self)
312 {
313 return GTK_HTML (HTML_FRAME (self)->html)->engine->clue;
314 }
315
316 static HTMLEngine *
get_engine(HTMLObject * self,HTMLEngine * e)317 get_engine (HTMLObject *self,
318 HTMLEngine *e)
319 {
320 return GTK_HTML (HTML_FRAME (self)->html)->engine;
321 }
322
323 static HTMLObject *
check_point(HTMLObject * self,HTMLPainter * painter,gint x,gint y,guint * offset_return,gboolean for_cursor)324 check_point (HTMLObject *self,
325 HTMLPainter *painter,
326 gint x,
327 gint y,
328 guint *offset_return,
329 gboolean for_cursor)
330 {
331 HTMLEngine *e = GTK_HTML (HTML_FRAME (self)->html)->engine;
332
333 if (x < self->x || x >= self->x + self->width
334 || y >= self->y + self->descent || y < self->y - self->ascent)
335 return NULL;
336
337 x -= self->x + html_engine_get_left_border (e) - e->x_offset;
338 y -= self->y - self->ascent + html_engine_get_top_border (e) - e->y_offset;
339
340 if (for_cursor && (x < 0 || y < e->clue->y - e->clue->ascent))
341 return html_object_check_point (e->clue, e->painter, 0, e->clue->y - e->clue->ascent,
342 offset_return, for_cursor);
343
344 if (for_cursor && (x > e->clue->width - 1 || y > e->clue->y + e->clue->descent - 1))
345 return html_object_check_point (e->clue, e->painter, e->clue->width - 1, e->clue->y + e->clue->descent - 1,
346 offset_return, for_cursor);
347
348 return html_object_check_point (e->clue, e->painter, x, y, offset_return, for_cursor);
349 }
350
351 static gboolean
is_container(HTMLObject * self)352 is_container (HTMLObject *self)
353 {
354 return TRUE;
355 }
356
357 static void
append_selection_string(HTMLObject * self,GString * buffer)358 append_selection_string (HTMLObject *self,
359 GString *buffer)
360 {
361 html_object_append_selection_string (GTK_HTML (HTML_FRAME (self)->html)->engine->clue, buffer);
362 }
363
364 static void
reparent(HTMLEmbedded * emb,GtkWidget * html)365 reparent (HTMLEmbedded *emb,
366 GtkWidget *html)
367 {
368 HTMLFrame *frame = HTML_FRAME (emb);
369
370 gtk_html_set_iframe_parent (GTK_HTML (frame->html),
371 html,
372 GTK_HTML (frame->html)->frame);
373 (* HTML_EMBEDDED_CLASS (parent_class)->reparent) (emb, html);
374 }
375
376 static gboolean
select_range(HTMLObject * self,HTMLEngine * engine,guint start,gint length,gboolean queue_draw)377 select_range (HTMLObject *self,
378 HTMLEngine *engine,
379 guint start,
380 gint length,
381 gboolean queue_draw)
382 {
383 return html_object_select_range (GTK_HTML (HTML_FRAME (self)->html)->engine->clue,
384 GTK_HTML (HTML_FRAME (self)->html)->engine,
385 start, length, queue_draw);
386 }
387
388 static void
destroy(HTMLObject * o)389 destroy (HTMLObject *o)
390 {
391 HTMLFrame *frame = HTML_FRAME (o);
392
393 frame_set_gdk_painter (frame, NULL);
394
395 if (frame->html) {
396 g_signal_handlers_disconnect_matched (frame->html, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, o);
397 frame->html = NULL;
398 }
399 g_free ((frame)->url);
400
401 HTML_OBJECT_CLASS (parent_class)->destroy (o);
402 }
403
404 static HTMLAnchor *
find_anchor(HTMLObject * self,const gchar * name,gint * x,gint * y)405 find_anchor (HTMLObject *self,
406 const gchar *name,
407 gint *x,
408 gint *y)
409 {
410 HTMLFrame *frame;
411 HTMLAnchor *anchor;
412
413 g_return_val_if_fail (HTML_IS_FRAME (self), NULL);
414
415 frame = HTML_FRAME (self);
416
417 if (!frame || !frame->html || !GTK_IS_HTML (frame->html) || !GTK_HTML (frame->html)->engine || !GTK_HTML (frame->html)->engine->clue)
418 return NULL;
419
420 anchor = html_object_find_anchor (GTK_HTML (frame->html)->engine->clue, name, x, y);
421
422 if (anchor) {
423 *x += self->x;
424 *y += self->y - self->ascent;
425 }
426
427 return anchor;
428 }
429
430 void
html_frame_set_margin_width(HTMLFrame * frame,gint margin_width)431 html_frame_set_margin_width (HTMLFrame *frame,
432 gint margin_width)
433 {
434 HTMLEngine *e;
435
436 e = GTK_HTML (frame->html)->engine;
437
438 e->leftBorder = e->rightBorder = margin_width;
439 html_engine_schedule_redraw (e);
440 }
441
442 void
html_frame_set_margin_height(HTMLFrame * frame,gint margin_height)443 html_frame_set_margin_height (HTMLFrame *frame,
444 gint margin_height)
445 {
446 HTMLEngine *e;
447
448 e = GTK_HTML (frame->html)->engine;
449
450 e->bottomBorder = e->topBorder = margin_height;
451 html_engine_schedule_redraw (e);
452 }
453
454 void
html_frame_set_scrolling(HTMLFrame * frame,GtkPolicyType scroll)455 html_frame_set_scrolling (HTMLFrame *frame,
456 GtkPolicyType scroll)
457 {
458
459 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (frame->scroll),
460 scroll, scroll);
461 }
462
463 void
html_frame_set_size(HTMLFrame * frame,gint width,gint height)464 html_frame_set_size (HTMLFrame *frame,
465 gint width,
466 gint height)
467 {
468 g_return_if_fail (frame != NULL);
469
470 if (width > 0)
471 frame->width = width;
472
473 if (height > 0)
474 frame->height = height;
475
476 gtk_widget_set_size_request (frame->scroll, width, height);
477 }
478
479 void
html_frame_init(HTMLFrame * frame,HTMLFrameClass * klass,GtkWidget * parent,gchar * src,gint width,gint height,gboolean border)480 html_frame_init (HTMLFrame *frame,
481 HTMLFrameClass *klass,
482 GtkWidget *parent,
483 gchar *src,
484 gint width,
485 gint height,
486 gboolean border)
487 {
488 HTMLEmbedded *em = HTML_EMBEDDED (frame);
489 HTMLTokenizer *new_tokenizer;
490 GtkWidget *new_widget;
491 GtkHTML *new_html;
492 GtkHTML *parent_html;
493 GtkWidget *scrolled_window;
494
495 g_assert (GTK_IS_HTML (parent));
496 parent_html = GTK_HTML (parent);
497
498 html_embedded_init (em, HTML_EMBEDDED_CLASS (klass),
499 parent, NULL, NULL);
500
501 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
502 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
503 border ? GTK_SHADOW_IN : GTK_SHADOW_NONE);
504
505 new_widget = gtk_html_new ();
506 new_html = GTK_HTML (new_widget);
507
508 new_tokenizer = html_tokenizer_clone (parent_html->engine->ht);
509
510 html_engine_set_tokenizer (new_html->engine, new_tokenizer);
511 g_object_unref (G_OBJECT (new_tokenizer));
512 new_tokenizer = NULL;
513
514 gtk_html_set_default_content_type (new_html,
515 gtk_html_get_default_content_type (parent_html));
516
517 gtk_html_set_default_engine (new_html,
518 gtk_html_get_default_engine (parent_html));
519
520 frame->html = new_widget;
521 frame->url = g_strdup (src);
522 frame->width = width;
523 frame->height = height;
524 frame->gdk_painter = NULL;
525 gtk_html_set_base (new_html, src);
526 gtk_html_set_iframe_parent (new_html, parent, HTML_OBJECT (frame));
527 gtk_container_add (GTK_CONTAINER (scrolled_window), new_widget);
528 gtk_widget_show (new_widget);
529
530 g_signal_connect (new_html, "url_requested", G_CALLBACK (frame_url_requested), frame);
531
532 if (parent_html->engine->stopped) {
533 gtk_html_stop (new_html);
534 gtk_html_load_empty (new_html);
535 } else {
536 GtkHTMLStream *handle;
537
538 handle = gtk_html_begin (new_html);
539 g_signal_emit_by_name (parent_html->engine, "url_requested", src, handle);
540 }
541
542 new_html->engine->clue->parent = HTML_OBJECT (frame);
543
544 #if 0
545 /* NOTE: because of peculiarities of the frame/gtkhtml relationship
546 * on_url and link_clicked are emitted from the toplevel widget not
547 * proxied like url_requested is.
548 */
549 g_signal_connect (new_html, "on_url", G_CALLBACK (frame_on_url), frame);
550 g_signal_connect (new_html, "link_clicked", G_CALLBACK (frame_link_clicked), frame);
551 #endif
552 g_signal_connect (new_html, "size_changed", G_CALLBACK (frame_size_changed), frame);
553 g_signal_connect (new_html, "object_requested", G_CALLBACK (frame_object_requested), frame);
554 g_signal_connect (new_html, "submit", G_CALLBACK (frame_submit), frame);
555 g_signal_connect (new_html, "set_base", G_CALLBACK (frame_set_base), frame);
556
557 html_frame_set_margin_height (frame, 0);
558 html_frame_set_margin_width (frame, 0);
559
560 /*
561 g_signal_connect (html, "button_press_event", G_CALLBACK (frame_button_press_event), frame);
562 */
563
564 gtk_widget_set_size_request (scrolled_window, width, height);
565
566 gtk_widget_show (scrolled_window);
567 frame->scroll = scrolled_window;
568 html_frame_set_scrolling (frame, GTK_POLICY_AUTOMATIC);
569
570 html_embedded_set_widget (em, scrolled_window);
571
572 g_signal_connect (scrolled_window, "button_press_event", G_CALLBACK (html_frame_grab_cursor), NULL);
573
574 /* inherit the current colors from our parent */
575 html_colorset_set_unchanged (new_html->engine->defaultSettings->color_set,
576 parent_html->engine->settings->color_set);
577 html_colorset_set_unchanged (new_html->engine->settings->color_set,
578 parent_html->engine->settings->color_set);
579 html_painter_set_focus (new_html->engine->painter, parent_html->engine->have_focus);
580 /*
581 g_signal_connect (html, "title_changed", G_CALLBACK (title_changed_cb), app);
582 g_signal_connect (html, "button_press_event", G_CALLBACK (on_button_press_event), popup_menu);
583 g_signal_connect (html, "redirect", G_CALLBACK (on_redirect), NULL);
584 g_signal_connect (html, "object_requested", G_CALLBACK (object_requested_cmd), NULL);
585 */
586 }
587
588 void
html_frame_type_init(void)589 html_frame_type_init (void)
590 {
591 html_frame_class_init (&html_frame_class, HTML_TYPE_FRAME, sizeof (HTMLFrame));
592 }
593
594 void
html_frame_class_init(HTMLFrameClass * klass,HTMLType type,guint size)595 html_frame_class_init (HTMLFrameClass *klass,
596 HTMLType type,
597 guint size)
598 {
599 HTMLEmbeddedClass *embedded_class;
600 HTMLObjectClass *object_class;
601
602 g_return_if_fail (klass != NULL);
603
604 embedded_class = HTML_EMBEDDED_CLASS (klass);
605 object_class = HTML_OBJECT_CLASS (klass);
606
607 html_embedded_class_init (embedded_class, type, size);
608 parent_class = &html_embedded_class;
609
610 object_class->destroy = destroy;
611 object_class->calc_size = html_frame_real_calc_size;
612 object_class->calc_min_width = calc_min_width;
613 object_class->set_painter = set_painter;
614 /* object_class->reset = reset; */
615 object_class->draw = draw;
616 object_class->set_max_width = set_max_width;
617 object_class->forall = forall;
618 object_class->check_page_split = check_page_split;
619 object_class->search = search;
620 object_class->head = head;
621 object_class->tail = tail;
622 object_class->get_engine = get_engine;
623 object_class->check_point = check_point;
624 object_class->is_container = is_container;
625 object_class->append_selection_string = append_selection_string;
626 object_class->select_range = select_range;
627 object_class->find_anchor = find_anchor;
628
629 embedded_class->reparent = reparent;
630 }
631
632