Frame/iframe print miscalculates its height
[gtkhtml.git] / gtkhtml / htmlframe.c
blobd4564cd37973004f85c0a034def48742bea8b9ba
2 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* This file is part of the GtkHTML library.
5 * Copyright (C) 2000 Helix Code, Inc.
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.
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.
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.
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"
39 HTMLFrameClass html_frame_class;
40 static HTMLEmbeddedClass *parent_class = NULL;
42 static void
43 frame_url_requested (GtkHTML *html,
44 const gchar *url,
45 GtkHTMLStream *handle,
46 gpointer data)
48 HTMLFrame *frame = HTML_FRAME (data);
49 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
51 if (!html->engine->stopped)
52 g_signal_emit_by_name (parent->engine, "url_requested", url, handle);
55 static void
56 frame_set_base (GtkHTML *html,
57 const gchar *url,
58 gpointer data)
60 gchar *new_url = NULL;
62 new_url = gtk_html_get_url_base_relative (html, url);
63 gtk_html_set_base (html, new_url);
64 g_free (new_url);
67 static void
68 frame_submit (GtkHTML *html,
69 const gchar *method,
70 const gchar *action,
71 const gchar *encoding,
72 gpointer data)
74 HTMLFrame *frame = HTML_FRAME (data);
75 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
77 g_signal_emit_by_name (parent, "submit", method, action, encoding);
80 static void
81 frame_size_changed (GtkHTML *html,
82 gpointer data)
84 HTMLFrame *frame = HTML_FRAME (data);
85 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
87 html_engine_schedule_update (parent->engine);
90 static gboolean
91 frame_object_requested (GtkHTML *html,
92 GtkHTMLEmbedded *eb,
93 gpointer data)
95 HTMLFrame *frame = HTML_FRAME (data);
96 GtkHTML *parent = GTK_HTML (HTML_EMBEDDED (frame)->parent);
97 gboolean ret_val;
99 ret_val = FALSE;
100 g_signal_emit_by_name (parent, "object_requested", eb, &ret_val);
101 return ret_val;
104 static void
105 frame_set_gdk_painter (HTMLFrame *frame,
106 HTMLPainter *painter)
108 if (painter)
109 g_object_ref (G_OBJECT (painter));
111 if (frame->gdk_painter)
112 g_object_unref (G_OBJECT (frame->gdk_painter));
114 frame->gdk_painter = painter;
117 HTMLObject *
118 html_frame_new (GtkWidget *parent,
119 gchar *src,
120 gint width,
121 gint height,
122 gboolean border)
124 HTMLFrame *frame;
126 frame = g_new (HTMLFrame, 1);
128 html_frame_init (frame,
129 &html_frame_class,
130 parent,
131 src,
132 width,
133 height,
134 border);
136 return HTML_OBJECT (frame);
139 static gboolean
140 html_frame_grab_cursor (GtkWidget *frame,
141 GdkEvent *event)
143 /* Keep the focus! Fight the power */
144 return TRUE;
147 static gint
148 calc_min_width (HTMLObject *o,
149 HTMLPainter *painter)
151 gint min_width;
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;
158 return min_width;
161 static void
162 set_max_width (HTMLObject *o,
163 HTMLPainter *painter,
164 gint max_width)
166 HTMLEngine *e = GTK_HTML (HTML_FRAME (o)->html)->engine;
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)));
172 static void
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)
182 HTMLFrame *frame = HTML_FRAME (o);
183 HTMLEngine *e = GTK_HTML (frame->html)->engine;
184 GdkRectangle paint;
186 if (G_OBJECT_TYPE (e->painter) == HTML_TYPE_PRINTER) {
187 gint pixel_size = html_painter_get_pixel_size (e->painter);
189 if (!html_object_intersect (o, &paint, x, y, width, height))
190 return;
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);
201 static void
202 set_painter (HTMLObject *o,
203 HTMLPainter *painter)
205 HTMLFrame *frame;
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);
212 html_engine_set_painter (GTK_HTML (frame->html)->engine,
213 G_OBJECT_TYPE (painter) != HTML_TYPE_PRINTER ? frame->gdk_painter : painter);
216 static void
217 forall (HTMLObject *self,
218 HTMLEngine *e,
219 HTMLObjectForallFunc func,
220 gpointer data)
222 HTMLFrame *frame;
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);
229 static gint
230 check_page_split (HTMLObject *self,
231 HTMLPainter *p,
232 gint y)
234 return html_object_check_page_split (GTK_HTML (HTML_FRAME (self)->html)->engine->clue, p, y);
237 static gboolean
238 html_frame_real_calc_size (HTMLObject *o,
239 HTMLPainter *painter,
240 GList **changed_objs)
242 HTMLFrame *frame;
243 HTMLEngine *e;
244 gint old_width, old_ascent, old_descent;
246 old_width = o->width;
247 old_ascent = o->ascent;
248 old_descent = o->descent;
250 frame = HTML_FRAME (o);
251 e = GTK_HTML (frame->html)->engine;
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);
259 html_frame_set_scrolling (frame, GTK_POLICY_NEVER);
261 o->width = e->width;
262 o->ascent = e->height;
263 o->descent = 0;
265 if (G_OBJECT_TYPE (painter) == HTML_TYPE_PRINTER) {
266 o->ascent += html_painter_get_pixel_size (painter) * (html_engine_get_top_border (e) + html_engine_get_bottom_border (e));
268 } else
269 return (* HTML_OBJECT_CLASS (parent_class)->calc_size) (o, painter, changed_objs);
271 if (o->descent != old_descent
272 || o->ascent != old_ascent
273 || o->width != old_width)
274 return TRUE;
276 return FALSE;
279 static gboolean
280 search (HTMLObject *self,
281 HTMLSearch *info)
283 HTMLEngine *e = GTK_HTML (HTML_FRAME (self)->html)->engine;
285 /* printf ("search\n"); */
287 /* search_next? */
288 if (info->stack && HTML_OBJECT (info->stack->data) == e->clue) {
289 /* printf ("next\n"); */
290 info->engine = GTK_HTML (GTK_HTML (HTML_FRAME (self)->html)->iframe_parent)->engine;
291 html_search_pop (info);
292 html_engine_unselect_all (e);
293 return html_search_next_parent (info);
296 info->engine = e;
297 html_search_push (info, e->clue);
298 if (html_object_search (e->clue, info))
299 return TRUE;
300 html_search_pop (info);
302 info->engine = GTK_HTML (GTK_HTML (HTML_FRAME (self)->html)->iframe_parent)->engine;
303 /* printf ("FALSE\n"); */
305 return FALSE;
308 static HTMLObject *
309 head (HTMLObject *self)
311 return GTK_HTML (HTML_FRAME (self)->html)->engine->clue;
314 static HTMLObject *
315 tail (HTMLObject *self)
317 return GTK_HTML (HTML_FRAME (self)->html)->engine->clue;
320 static HTMLEngine *
321 get_engine (HTMLObject *self,
322 HTMLEngine *e)
324 return GTK_HTML (HTML_FRAME (self)->html)->engine;
327 static HTMLObject *
328 check_point (HTMLObject *self,
329 HTMLPainter *painter,
330 gint x,
331 gint y,
332 guint *offset_return,
333 gboolean for_cursor)
335 HTMLEngine *e = GTK_HTML (HTML_FRAME (self)->html)->engine;
337 if (x < self->x || x >= self->x + self->width
338 || y >= self->y + self->descent || y < self->y - self->ascent)
339 return NULL;
341 x -= self->x + html_engine_get_left_border (e) - e->x_offset;
342 y -= self->y - self->ascent + html_engine_get_top_border (e) - e->y_offset;
344 if (for_cursor && (x < 0 || y < e->clue->y - e->clue->ascent))
345 return html_object_check_point (e->clue, e->painter, 0, e->clue->y - e->clue->ascent,
346 offset_return, for_cursor);
348 if (for_cursor && (x > e->clue->width - 1 || y > e->clue->y + e->clue->descent - 1))
349 return html_object_check_point (e->clue, e->painter, e->clue->width - 1, e->clue->y + e->clue->descent - 1,
350 offset_return, for_cursor);
352 return html_object_check_point (e->clue, e->painter, x, y, offset_return, for_cursor);
355 static gboolean
356 is_container (HTMLObject *self)
358 return TRUE;
361 static void
362 append_selection_string (HTMLObject *self,
363 GString *buffer)
365 html_object_append_selection_string (GTK_HTML (HTML_FRAME (self)->html)->engine->clue, buffer);
368 static void
369 reparent (HTMLEmbedded *emb,
370 GtkWidget *html)
372 HTMLFrame *frame = HTML_FRAME (emb);
374 gtk_html_set_iframe_parent (GTK_HTML (frame->html),
375 html,
376 GTK_HTML (frame->html)->frame);
377 (* HTML_EMBEDDED_CLASS (parent_class)->reparent) (emb, html);
380 static gboolean
381 select_range (HTMLObject *self,
382 HTMLEngine *engine,
383 guint start,
384 gint length,
385 gboolean queue_draw)
387 return html_object_select_range (GTK_HTML (HTML_FRAME (self)->html)->engine->clue,
388 GTK_HTML (HTML_FRAME (self)->html)->engine,
389 start, length, queue_draw);
392 static void
393 destroy (HTMLObject *o)
395 HTMLFrame *frame = HTML_FRAME (o);
397 frame_set_gdk_painter (frame, NULL);
399 if (frame->html) {
400 g_signal_handlers_disconnect_matched (frame->html, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, o);
401 frame->html = NULL;
403 g_free ((frame)->url);
405 HTML_OBJECT_CLASS (parent_class)->destroy (o);
408 static HTMLAnchor *
409 find_anchor (HTMLObject *self,
410 const gchar *name,
411 gint *x,
412 gint *y)
414 HTMLFrame *frame;
415 HTMLAnchor *anchor;
417 g_return_val_if_fail (HTML_IS_FRAME (self), NULL);
419 frame = HTML_FRAME (self);
421 if (!frame || !frame->html || !GTK_IS_HTML (frame->html) || !GTK_HTML (frame->html)->engine || !GTK_HTML (frame->html)->engine->clue)
422 return NULL;
424 anchor = html_object_find_anchor (GTK_HTML (frame->html)->engine->clue, name, x, y);
426 if (anchor) {
427 *x += self->x;
428 *y += self->y - self->ascent;
431 return anchor;
434 void
435 html_frame_set_margin_width (HTMLFrame *frame,
436 gint margin_width)
438 HTMLEngine *e;
440 e = GTK_HTML (frame->html)->engine;
442 e->leftBorder = e->rightBorder = margin_width;
443 html_engine_schedule_redraw (e);
446 void
447 html_frame_set_margin_height (HTMLFrame *frame,
448 gint margin_height)
450 HTMLEngine *e;
452 e = GTK_HTML (frame->html)->engine;
454 e->bottomBorder = e->topBorder = margin_height;
455 html_engine_schedule_redraw (e);
458 void
459 html_frame_set_scrolling (HTMLFrame *frame,
460 GtkPolicyType scroll)
463 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (frame->scroll),
464 scroll, scroll);
467 void
468 html_frame_set_size (HTMLFrame *frame,
469 gint width,
470 gint height)
472 g_return_if_fail (frame != NULL);
474 if (width > 0)
475 frame->width = width;
477 if (height > 0)
478 frame->height = height;
480 gtk_widget_set_size_request (frame->scroll, width, height);
483 void
484 html_frame_init (HTMLFrame *frame,
485 HTMLFrameClass *klass,
486 GtkWidget *parent,
487 gchar *src,
488 gint width,
489 gint height,
490 gboolean border)
492 HTMLEmbedded *em = HTML_EMBEDDED (frame);
493 HTMLTokenizer *new_tokenizer;
494 GtkWidget *new_widget;
495 GtkHTML *new_html;
496 GtkHTML *parent_html;
497 GtkWidget *scrolled_window;
499 g_assert (GTK_IS_HTML (parent));
500 parent_html = GTK_HTML (parent);
502 html_embedded_init (em, HTML_EMBEDDED_CLASS (klass),
503 parent, NULL, NULL);
505 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
506 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
507 border ? GTK_SHADOW_IN : GTK_SHADOW_NONE);
509 new_widget = gtk_html_new ();
510 new_html = GTK_HTML (new_widget);
512 new_tokenizer = html_tokenizer_clone (parent_html->engine->ht);
514 html_engine_set_tokenizer (new_html->engine, new_tokenizer);
515 g_object_unref (G_OBJECT (new_tokenizer));
516 new_tokenizer = NULL;
518 gtk_html_set_default_content_type (new_html,
519 gtk_html_get_default_content_type (parent_html));
521 gtk_html_set_default_engine (new_html,
522 gtk_html_get_default_engine (parent_html));
524 frame->html = new_widget;
525 frame->url = g_strdup (src);
526 frame->width = width;
527 frame->height = height;
528 frame->gdk_painter = NULL;
529 gtk_html_set_base (new_html, src);
530 gtk_html_set_iframe_parent (new_html, parent, HTML_OBJECT (frame));
531 gtk_container_add (GTK_CONTAINER (scrolled_window), new_widget);
532 gtk_widget_show (new_widget);
534 g_signal_connect (new_html, "url_requested", G_CALLBACK (frame_url_requested), frame);
536 if (parent_html->engine->stopped) {
537 gtk_html_stop (new_html);
538 gtk_html_load_empty (new_html);
539 } else {
540 GtkHTMLStream *handle;
542 handle = gtk_html_begin (new_html);
543 g_signal_emit_by_name (parent_html->engine, "url_requested", src, handle);
546 new_html->engine->clue->parent = HTML_OBJECT (frame);
548 #if 0
549 /* NOTE: because of peculiarities of the frame/gtkhtml relationship
550 * on_url and link_clicked are emitted from the toplevel widget not
551 * proxied like url_requested is.
553 g_signal_connect (new_html, "on_url", G_CALLBACK (frame_on_url), frame);
554 g_signal_connect (new_html, "link_clicked", G_CALLBACK (frame_link_clicked), frame);
555 #endif
556 g_signal_connect (new_html, "size_changed", G_CALLBACK (frame_size_changed), frame);
557 g_signal_connect (new_html, "object_requested", G_CALLBACK (frame_object_requested), frame);
558 g_signal_connect (new_html, "submit", G_CALLBACK (frame_submit), frame);
559 g_signal_connect (new_html, "set_base", G_CALLBACK (frame_set_base), frame);
561 html_frame_set_margin_height (frame, 0);
562 html_frame_set_margin_width (frame, 0);
565 g_signal_connect (html, "button_press_event", G_CALLBACK (frame_button_press_event), frame);
568 gtk_widget_set_size_request (scrolled_window, width, height);
570 gtk_widget_show (scrolled_window);
571 frame->scroll = scrolled_window;
572 html_frame_set_scrolling (frame, GTK_POLICY_AUTOMATIC);
574 html_embedded_set_widget (em, scrolled_window);
576 g_signal_connect (scrolled_window, "button_press_event", G_CALLBACK (html_frame_grab_cursor), NULL);
578 /* inherit the current colors from our parent */
579 html_colorset_set_unchanged (new_html->engine->defaultSettings->color_set,
580 parent_html->engine->settings->color_set);
581 html_colorset_set_unchanged (new_html->engine->settings->color_set,
582 parent_html->engine->settings->color_set);
583 html_painter_set_focus (new_html->engine->painter, parent_html->engine->have_focus);
585 g_signal_connect (html, "title_changed", G_CALLBACK (title_changed_cb), app);
586 g_signal_connect (html, "button_press_event", G_CALLBACK (on_button_press_event), popup_menu);
587 g_signal_connect (html, "redirect", G_CALLBACK (on_redirect), NULL);
588 g_signal_connect (html, "object_requested", G_CALLBACK (object_requested_cmd), NULL);
592 void
593 html_frame_type_init (void)
595 html_frame_class_init (&html_frame_class, HTML_TYPE_FRAME, sizeof (HTMLFrame));
598 void
599 html_frame_class_init (HTMLFrameClass *klass,
600 HTMLType type,
601 guint size)
603 HTMLEmbeddedClass *embedded_class;
604 HTMLObjectClass *object_class;
606 g_return_if_fail (klass != NULL);
608 embedded_class = HTML_EMBEDDED_CLASS (klass);
609 object_class = HTML_OBJECT_CLASS (klass);
611 html_embedded_class_init (embedded_class, type, size);
612 parent_class = &html_embedded_class;
614 object_class->destroy = destroy;
615 object_class->calc_size = html_frame_real_calc_size;
616 object_class->calc_min_width = calc_min_width;
617 object_class->set_painter = set_painter;
618 /* object_class->reset = reset; */
619 object_class->draw = draw;
620 object_class->set_max_width = set_max_width;
621 object_class->forall = forall;
622 object_class->check_page_split = check_page_split;
623 object_class->search = search;
624 object_class->head = head;
625 object_class->tail = tail;
626 object_class->get_engine = get_engine;
627 object_class->check_point = check_point;
628 object_class->is_container = is_container;
629 object_class->append_selection_string = append_selection_string;
630 object_class->select_range = select_range;
631 object_class->find_anchor = find_anchor;
633 embedded_class->reparent = reparent;