1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library.
4 * Copyright 1999, 2000 Helix Code, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
25 #include <gdk/gdkkeysyms.h>
26 #include <glib/gi18n-lib.h>
29 #include "../a11y/object.h"
31 #include "htmlcolorset.h"
32 #include "htmlcluev.h"
33 #include "htmlcursor.h"
34 #include "htmldrawqueue.h"
35 #include "htmlengine-edit.h"
36 #include "htmlengine-edit-clueflowstyle.h"
37 #include "htmlengine-edit-cut-and-paste.h"
38 #include "htmlengine-edit-fontstyle.h"
39 #include "htmlengine-edit-rule.h"
40 #include "htmlengine-edit-movement.h"
41 #include "htmlengine-edit-cursor.h"
42 #include "htmlengine-edit-table.h"
43 #include "htmlengine-edit-tablecell.h"
44 #include "htmlengine-edit-text.h"
45 #include "htmlengine-edit-selection-updater.h"
46 #include "htmlengine-print.h"
47 #include "htmlengine-save.h"
49 #include "htmlframe.h"
50 #include "htmlframeset.h"
51 #include "htmliframe.h"
52 #include "htmlimage.h"
53 #include "htmlinterval.h"
54 #include "htmlmarshal.h"
55 #include "htmlplainpainter.h"
56 #include "htmlsettings.h"
57 #include "htmltable.h"
59 #include "htmltextslave.h"
60 #include "htmlselection.h"
64 #include "gtkhtml-embedded.h"
65 #include "gtkhtml-keybinding.h"
66 #include "gtkhtml-search.h"
67 #include "gtkhtml-stream.h"
68 #include "gtkhtml-private.h"
69 #include "gtkhtml-properties.h"
73 DND_TARGET_TYPE_TEXT_URI_LIST
,
74 DND_TARGET_TYPE_MOZILLA_URL
,
75 DND_TARGET_TYPE_TEXT_HTML
,
76 DND_TARGET_TYPE_UTF8_STRING
,
77 DND_TARGET_TYPE_TEXT_PLAIN
,
78 DND_TARGET_TYPE_STRING
81 static GtkTargetEntry drag_dest_targets
[] = {
82 { (gchar
*) "text/uri-list", 0, DND_TARGET_TYPE_TEXT_URI_LIST
},
83 { (gchar
*) "_NETSCAPE_URL", 0, DND_TARGET_TYPE_MOZILLA_URL
},
84 { (gchar
*) "text/html", 0, DND_TARGET_TYPE_TEXT_HTML
},
85 { (gchar
*) "UTF8_STRING", 0, DND_TARGET_TYPE_UTF8_STRING
},
86 { (gchar
*) "text/plain", 0, DND_TARGET_TYPE_TEXT_PLAIN
},
87 { (gchar
*) "STRING", 0, DND_TARGET_TYPE_STRING
},
90 static GtkTargetEntry drag_source_targets
[] = {
91 { (gchar
*) "text/uri-list", 0, DND_TARGET_TYPE_TEXT_URI_LIST
},
92 { (gchar
*) "_NETSCAPE_URL", 0, DND_TARGET_TYPE_MOZILLA_URL
},
93 { (gchar
*) "text/html", 0, DND_TARGET_TYPE_TEXT_HTML
},
94 { (gchar
*) "UTF8_STRING", 0, DND_TARGET_TYPE_UTF8_STRING
},
95 { (gchar
*) "text/plain", 0, DND_TARGET_TYPE_TEXT_PLAIN
},
96 { (gchar
*) "STRING", 0, DND_TARGET_TYPE_STRING
},
102 TARGET_COMPOUND_TEXT
,
107 typedef enum _TargetInfo TargetInfo
;
109 static const GtkTargetEntry selection_targets
[] = {
110 { (gchar
*) "text/html", GTK_TARGET_SAME_APP
, TARGET_HTML
},
111 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
112 { (gchar
*) "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT
},
113 { (gchar
*) "STRING", 0, TARGET_STRING
},
114 { (gchar
*) "TEXT", 0, TARGET_TEXT
}
117 static const guint n_selection_targets
= G_N_ELEMENTS (selection_targets
);
119 typedef struct _ClipboardContents ClipboardContents
;
121 struct _ClipboardContents
{
129 static GtkLayoutClass
*parent_class
= NULL
;
142 CURRENT_PARAGRAPH_STYLE_CHANGED
,
143 CURRENT_PARAGRAPH_INDENTATION_CHANGED
,
144 CURRENT_PARAGRAPH_ALIGNMENT_CHANGED
,
145 INSERTION_FONT_STYLE_CHANGED
,
146 INSERTION_COLOR_CHANGED
,
149 /* keybindings signals */
156 /* now only last signal */
160 /* #define USE_PROPS */
170 static void gtk_html_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
171 static void gtk_html_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
174 static guint signals
[LAST_SIGNAL
] = { 0 };
177 gtk_html_update_scrollbars_on_resize (GtkHTML
*html
,
178 gdouble old_doc_width
,
179 gdouble old_doc_height
,
183 gboolean
*changed_y
);
185 static void update_primary_selection (GtkHTML
*html
);
186 static void clipboard_paste_received_cb (GtkClipboard
*clipboard
,
187 GtkSelectionData
*selection_data
,
189 static gboolean
motion_notify_event (GtkWidget
*widget
,
190 GdkEventMotion
*event
);
192 /* keybindings signal hadlers */
193 static void scroll (GtkHTML
*html
,
194 GtkOrientation orientation
,
195 GtkScrollType scroll_type
,
197 static void cursor_move (GtkHTML
*html
,
198 GtkDirectionType dir_type
,
199 GtkHTMLCursorSkipType skip
);
200 static gboolean
command (GtkHTML
*html
,
201 GtkHTMLCommandType com_type
);
202 static gint
mouse_change_pos (GtkWidget
*widget
,
207 static void add_bindings (GtkHTMLClass
*klass
);
208 static const gchar
*get_value_nick (GtkHTMLCommandType com_type
);
209 static void gtk_html_adjust_cursor_position (GtkHTML
*html
);
210 static gboolean
any_has_cursor_moved (GtkHTML
*html
);
211 static gboolean
any_has_skip_update_cursor (GtkHTML
*html
);
213 /* Interval for scrolling during selection. */
214 #define SCROLL_TIMEOUT_INTERVAL 10
217 GtkHTMLParagraphStyle
218 clueflow_style_to_paragraph_style (HTMLClueFlowStyle style
,
219 HTMLListType item_type
)
222 case HTML_CLUEFLOW_STYLE_NORMAL
:
223 return GTK_HTML_PARAGRAPH_STYLE_NORMAL
;
224 case HTML_CLUEFLOW_STYLE_H1
:
225 return GTK_HTML_PARAGRAPH_STYLE_H1
;
226 case HTML_CLUEFLOW_STYLE_H2
:
227 return GTK_HTML_PARAGRAPH_STYLE_H2
;
228 case HTML_CLUEFLOW_STYLE_H3
:
229 return GTK_HTML_PARAGRAPH_STYLE_H3
;
230 case HTML_CLUEFLOW_STYLE_H4
:
231 return GTK_HTML_PARAGRAPH_STYLE_H4
;
232 case HTML_CLUEFLOW_STYLE_H5
:
233 return GTK_HTML_PARAGRAPH_STYLE_H5
;
234 case HTML_CLUEFLOW_STYLE_H6
:
235 return GTK_HTML_PARAGRAPH_STYLE_H6
;
236 case HTML_CLUEFLOW_STYLE_ADDRESS
:
237 return GTK_HTML_PARAGRAPH_STYLE_ADDRESS
;
238 case HTML_CLUEFLOW_STYLE_PRE
:
239 return GTK_HTML_PARAGRAPH_STYLE_PRE
;
240 case HTML_CLUEFLOW_STYLE_LIST_ITEM
:
242 case HTML_LIST_TYPE_UNORDERED
:
243 return GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED
;
244 case HTML_LIST_TYPE_ORDERED_ARABIC
:
245 return GTK_HTML_PARAGRAPH_STYLE_ITEMDIGIT
;
246 case HTML_LIST_TYPE_ORDERED_LOWER_ROMAN
:
247 case HTML_LIST_TYPE_ORDERED_UPPER_ROMAN
:
248 return GTK_HTML_PARAGRAPH_STYLE_ITEMROMAN
;
249 case HTML_LIST_TYPE_ORDERED_LOWER_ALPHA
:
250 case HTML_LIST_TYPE_ORDERED_UPPER_ALPHA
:
251 return GTK_HTML_PARAGRAPH_STYLE_ITEMALPHA
;
253 return GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED
;
255 default: /* This should not really happen, though. */
256 return GTK_HTML_PARAGRAPH_STYLE_NORMAL
;
261 paragraph_style_to_clueflow_style (GtkHTMLParagraphStyle style
,
262 HTMLClueFlowStyle
*flow_style
,
263 HTMLListType
*item_type
)
265 *item_type
= HTML_LIST_TYPE_BLOCKQUOTE
;
266 *flow_style
= HTML_CLUEFLOW_STYLE_LIST_ITEM
;
269 case GTK_HTML_PARAGRAPH_STYLE_NORMAL
:
270 *flow_style
= HTML_CLUEFLOW_STYLE_NORMAL
;
272 case GTK_HTML_PARAGRAPH_STYLE_H1
:
273 *flow_style
= HTML_CLUEFLOW_STYLE_H1
;
275 case GTK_HTML_PARAGRAPH_STYLE_H2
:
276 *flow_style
= HTML_CLUEFLOW_STYLE_H2
;
278 case GTK_HTML_PARAGRAPH_STYLE_H3
:
279 *flow_style
= HTML_CLUEFLOW_STYLE_H3
;
281 case GTK_HTML_PARAGRAPH_STYLE_H4
:
282 *flow_style
= HTML_CLUEFLOW_STYLE_H4
;
284 case GTK_HTML_PARAGRAPH_STYLE_H5
:
285 *flow_style
= HTML_CLUEFLOW_STYLE_H5
;
287 case GTK_HTML_PARAGRAPH_STYLE_H6
:
288 *flow_style
= HTML_CLUEFLOW_STYLE_H6
;
290 case GTK_HTML_PARAGRAPH_STYLE_ADDRESS
:
291 *flow_style
= HTML_CLUEFLOW_STYLE_ADDRESS
;
293 case GTK_HTML_PARAGRAPH_STYLE_PRE
:
294 *flow_style
= HTML_CLUEFLOW_STYLE_PRE
;
296 case GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED
:
297 *item_type
= HTML_LIST_TYPE_UNORDERED
;
299 case GTK_HTML_PARAGRAPH_STYLE_ITEMROMAN
:
300 *item_type
= HTML_LIST_TYPE_ORDERED_UPPER_ROMAN
;
302 case GTK_HTML_PARAGRAPH_STYLE_ITEMALPHA
:
303 *item_type
= HTML_LIST_TYPE_ORDERED_UPPER_ALPHA
;
305 case GTK_HTML_PARAGRAPH_STYLE_ITEMDIGIT
:
306 *item_type
= HTML_LIST_TYPE_ORDERED_ARABIC
;
308 default: /* This should not really happen, though. */
309 *flow_style
= HTML_CLUEFLOW_STYLE_NORMAL
;
314 paragraph_alignment_to_html (GtkHTMLParagraphAlignment alignment
)
317 case GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT
:
318 return HTML_HALIGN_LEFT
;
319 case GTK_HTML_PARAGRAPH_ALIGNMENT_RIGHT
:
320 return HTML_HALIGN_RIGHT
;
321 case GTK_HTML_PARAGRAPH_ALIGNMENT_CENTER
:
322 return HTML_HALIGN_CENTER
;
324 return HTML_HALIGN_LEFT
;
328 GtkHTMLParagraphAlignment
329 html_alignment_to_paragraph (HTMLHAlignType alignment
)
332 case HTML_HALIGN_LEFT
:
333 return GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT
;
334 case HTML_HALIGN_CENTER
:
335 return GTK_HTML_PARAGRAPH_ALIGNMENT_CENTER
;
336 case HTML_HALIGN_RIGHT
:
337 return GTK_HTML_PARAGRAPH_ALIGNMENT_RIGHT
;
339 return GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT
;
344 gtk_html_update_styles (GtkHTML
*html
)
346 GtkHTMLParagraphStyle paragraph_style
;
347 GtkHTMLParagraphAlignment alignment
;
349 HTMLClueFlowStyle flow_style
;
350 HTMLListType item_type
;
353 /* printf ("gtk_html_update_styles called\n"); */
355 if (!html_engine_get_editable (html
->engine
))
358 engine
= html
->engine
;
359 html_engine_get_current_clueflow_style (engine
, &flow_style
, &item_type
);
360 paragraph_style
= clueflow_style_to_paragraph_style (flow_style
, item_type
);
362 if (paragraph_style
!= html
->priv
->paragraph_style
) {
363 html
->priv
->paragraph_style
= paragraph_style
;
364 g_signal_emit (html
, signals
[CURRENT_PARAGRAPH_STYLE_CHANGED
], 0, paragraph_style
);
367 indentation
= html_engine_get_current_clueflow_indentation (engine
);
368 if (indentation
!= html
->priv
->paragraph_indentation
) {
369 html
->priv
->paragraph_indentation
= indentation
;
370 g_signal_emit (html
, signals
[CURRENT_PARAGRAPH_INDENTATION_CHANGED
], 0, indentation
);
373 alignment
= html_alignment_to_paragraph (html_engine_get_current_clueflow_alignment (engine
));
374 if (alignment
!= html
->priv
->paragraph_alignment
) {
375 html
->priv
->paragraph_alignment
= alignment
;
376 g_signal_emit (html
, signals
[CURRENT_PARAGRAPH_ALIGNMENT_CHANGED
], 0, alignment
);
379 if (html_engine_update_insertion_font_style (engine
))
380 g_signal_emit (html
, signals
[INSERTION_FONT_STYLE_CHANGED
], 0, engine
->insertion_font_style
);
381 if (html_engine_update_insertion_color (engine
))
382 g_signal_emit (html
, signals
[INSERTION_COLOR_CHANGED
], 0, engine
->insertion_color
);
384 /* TODO add insertion_url_or_targed_changed signal */
385 html_engine_update_insertion_url_and_target (engine
);
389 /* GTK+ idle loop handler. */
392 idle_handler (gpointer data
)
396 gboolean also_update_cursor
;
398 html
= GTK_HTML (data
);
399 engine
= html
->engine
;
401 also_update_cursor
= any_has_cursor_moved (html
) || !any_has_skip_update_cursor (html
);
403 if (html
->engine
->thaw_idle_id
== 0 && !html_engine_frozen (html
->engine
))
404 html_engine_flush_draw_queue (engine
);
406 if (also_update_cursor
)
407 gtk_html_adjust_cursor_position (html
);
409 html
->priv
->idle_handler_id
= 0;
410 html
->priv
->skip_update_cursor
= FALSE
;
411 html
->priv
->cursor_moved
= FALSE
;
413 while (html
->iframe_parent
) {
414 html
= GTK_HTML (html
->iframe_parent
);
417 html
->priv
->skip_update_cursor
= FALSE
;
418 html
->priv
->cursor_moved
= FALSE
;
421 if (also_update_cursor
)
422 gtk_html_adjust_cursor_position (html
);
429 gtk_html_adjust_cursor_position (GtkHTML
*html
)
432 GtkAdjustment
*hadjustment
;
433 GtkAdjustment
*vadjustment
;
436 if (html
->priv
->scroll_timeout_id
== 0 &&
437 html
->engine
->thaw_idle_id
== 0 &&
438 !html_engine_frozen (html
->engine
))
439 html_engine_make_cursor_visible (e
);
441 hadjustment
= gtk_layout_get_hadjustment (GTK_LAYOUT (html
));
442 vadjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
444 gtk_adjustment_set_value (hadjustment
, (gfloat
) e
->x_offset
);
445 gtk_adjustment_set_value (vadjustment
, (gfloat
) e
->y_offset
);
446 gtk_html_private_calc_scrollbars (html
, NULL
, NULL
);
451 queue_draw (GtkHTML
*html
)
453 if (html
->priv
->idle_handler_id
== 0)
454 html
->priv
->idle_handler_id
=
455 /* schedule with priority higher than gtk+ uses for animations (check docs for G_PRIORITY_HIGH_IDLE) */
456 g_idle_add_full (G_PRIORITY_HIGH_IDLE
, idle_handler
, html
, NULL
);
460 /* HTMLEngine callbacks. */
463 html_engine_title_changed_cb (HTMLEngine
*engine
,
468 gtk_html
= GTK_HTML (data
);
469 g_signal_emit (gtk_html
, signals
[TITLE_CHANGED
], 0, engine
->title
->str
);
473 html_engine_set_base_cb (HTMLEngine
*engine
,
479 gtk_html
= GTK_HTML (data
);
480 gtk_html_set_base (gtk_html
, base
);
481 g_signal_emit (gtk_html
, signals
[SET_BASE
], 0, base
);
485 html_engine_set_base_target_cb (HTMLEngine
*engine
,
486 const gchar
*base_target
,
491 gtk_html
= GTK_HTML (data
);
492 g_signal_emit (gtk_html
, signals
[SET_BASE_TARGET
], 0, base_target
);
496 html_engine_load_done_cb (HTMLEngine
*engine
,
501 gtk_html
= GTK_HTML (data
);
502 g_signal_emit (gtk_html
, signals
[LOAD_DONE
], 0);
506 html_engine_url_requested_cb (HTMLEngine
*engine
,
508 GtkHTMLStream
*handle
,
512 gchar
*expanded
= NULL
;
513 gtk_html
= GTK_HTML (data
);
518 expanded
= gtk_html_get_url_base_relative (gtk_html
, url
);
519 g_signal_emit (gtk_html
, signals
[URL_REQUESTED
], 0, expanded
, handle
);
524 html_engine_draw_pending_cb (HTMLEngine
*engine
,
529 html
= GTK_HTML (data
);
530 html
->priv
->skip_update_cursor
= TRUE
;
535 html_engine_redirect_cb (HTMLEngine
*engine
,
542 gtk_html
= GTK_HTML (data
);
544 g_signal_emit (gtk_html
, signals
[REDIRECT
], 0, url
, delay
);
548 html_engine_submit_cb (HTMLEngine
*engine
,
551 const gchar
*encoding
,
556 gtk_html
= GTK_HTML (data
);
558 g_signal_emit (gtk_html
, signals
[SUBMIT
], 0, method
, url
, encoding
);
562 html_engine_object_requested_cb (HTMLEngine
*engine
,
567 gboolean object_found
= FALSE
;
569 gtk_html
= GTK_HTML (data
);
571 object_found
= FALSE
;
572 g_signal_emit (gtk_html
, signals
[OBJECT_REQUESTED
], 0, eb
, &object_found
);
577 /* GtkAdjustment handling. */
580 scroll_update_mouse (GtkWidget
*widget
)
583 GdkWindow
*bin_window
;
586 if (!gtk_widget_get_realized (widget
))
589 window
= gtk_widget_get_window (widget
);
590 bin_window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
592 gdk_window_get_pointer (bin_window
, &x
, &y
, NULL
);
593 mouse_change_pos (widget
, window
, x
, y
, 0);
597 vertical_scroll_cb (GtkAdjustment
*adjustment
,
600 GtkHTML
*html
= GTK_HTML (data
);
602 if (html
->engine
->keep_scroll
)
605 html
->engine
->y_offset
= (gint
) gtk_adjustment_get_value (adjustment
);
606 scroll_update_mouse (GTK_WIDGET (data
));
610 horizontal_scroll_cb (GtkAdjustment
*adjustment
,
613 GtkHTML
*html
= GTK_HTML (data
);
615 if (html
->engine
->keep_scroll
)
618 html
->engine
->x_offset
= (gint
) gtk_adjustment_get_value (adjustment
);
619 scroll_update_mouse (GTK_WIDGET (data
));
623 hadjustment_notify_cb (GtkHTML
*html
)
625 GtkScrollable
*scrollable
;
626 GtkAdjustment
*hadjustment
;
631 scrollable
= GTK_SCROLLABLE (html
);
632 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
634 if (html
->hadj_connection
> 0) {
635 g_signal_handler_disconnect (
636 html
->priv
->hadjustment
, html
->hadj_connection
);
637 g_object_unref (html
->priv
->hadjustment
);
640 if (hadjustment
!= NULL
) {
641 html
->hadj_connection
= g_signal_connect (
642 hadjustment
, "value_changed",
643 G_CALLBACK (horizontal_scroll_cb
), html
);
644 html
->priv
->hadjustment
= g_object_ref (hadjustment
);
646 html
->hadj_connection
= 0;
647 html
->priv
->hadjustment
= NULL
;
652 vadjustment_notify_cb (GtkHTML
*html
)
654 GtkScrollable
*scrollable
;
655 GtkAdjustment
*vadjustment
;
660 scrollable
= GTK_SCROLLABLE (html
);
661 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
663 if (html
->vadj_connection
!= 0) {
664 g_signal_handler_disconnect (
665 html
->priv
->vadjustment
, html
->vadj_connection
);
666 g_object_unref (html
->priv
->vadjustment
);
669 if (vadjustment
!= NULL
) {
670 html
->vadj_connection
= g_signal_connect (
671 vadjustment
, "value_changed",
672 G_CALLBACK (vertical_scroll_cb
), html
);
673 html
->priv
->vadjustment
= g_object_ref (vadjustment
);
675 html
->vadj_connection
= 0;
676 html
->priv
->vadjustment
= NULL
;
681 /* Scroll timeout handling. */
684 inc_adjustment (GtkAdjustment
*adj
,
692 value
= gtk_adjustment_get_value (adj
) + (gfloat
) inc
;
694 if (doc_width
> alloc_width
)
695 max
= doc_width
- alloc_width
;
699 if (value
> (gfloat
) max
)
700 value
= (gfloat
) max
;
704 gtk_adjustment_set_value (adj
, value
);
708 scroll_timeout_cb (gpointer data
)
714 GtkAllocation allocation
;
715 GtkAdjustment
*hadjustment
;
716 GtkAdjustment
*vadjustment
;
717 gint x_scroll
, y_scroll
;
720 widget
= GTK_WIDGET (data
);
721 html
= GTK_HTML (data
);
722 engine
= html
->engine
;
724 window
= gtk_widget_get_window (widget
);
725 gdk_window_get_pointer (window
, &x
, &y
, NULL
);
727 gtk_widget_get_allocation (widget
, &allocation
);
731 if (x
+ engine
->x_offset
>= 0)
733 } else if (x
>= allocation
.width
) {
734 x_scroll
= x
- allocation
.width
+ 1;
735 x
= allocation
.width
;
743 if (y
+ engine
->y_offset
>= 0)
745 } else if (y
>= allocation
.height
) {
746 y_scroll
= y
- allocation
.height
+ 1;
747 y
= allocation
.height
;
753 if (html
->in_selection
&& (x_scroll
!= 0 || y_scroll
!= 0))
754 html_engine_select_region (engine
, html
->selection_x1
, html
->selection_y1
,
755 x
+ engine
->x_offset
, y
+ engine
->y_offset
);
757 hadjustment
= gtk_layout_get_hadjustment (GTK_LAYOUT (widget
));
758 vadjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (widget
));
760 inc_adjustment (hadjustment
, html_engine_get_doc_width (html
->engine
),
761 allocation
.width
, x_scroll
);
762 inc_adjustment (vadjustment
, html_engine_get_doc_height (html
->engine
),
763 allocation
.height
, y_scroll
);
769 setup_scroll_timeout (GtkHTML
*html
)
771 if (html
->priv
->scroll_timeout_id
!= 0)
774 html
->priv
->scroll_timeout_id
= g_timeout_add (SCROLL_TIMEOUT_INTERVAL
,
775 scroll_timeout_cb
, html
);
777 scroll_timeout_cb (html
);
781 remove_scroll_timeout (GtkHTML
*html
)
783 if (html
->priv
->scroll_timeout_id
== 0)
786 g_source_remove (html
->priv
->scroll_timeout_id
);
787 html
->priv
->scroll_timeout_id
= 0;
791 /* GObject methods. */
794 dispose (GObject
*object
)
798 html
= GTK_HTML (object
);
800 g_free (html
->pointer_url
);
801 html
->pointer_url
= NULL
;
803 if (html
->hand_cursor
) {
804 g_object_unref (html
->hand_cursor
);
805 html
->hand_cursor
= NULL
;
808 if (html
->ibeam_cursor
) {
809 g_object_unref (html
->ibeam_cursor
);
810 html
->ibeam_cursor
= NULL
;
813 gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (html
), NULL
);
814 gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (html
), NULL
);
816 hadjustment_notify_cb (html
);
817 vadjustment_notify_cb (html
);
819 g_signal_handlers_disconnect_by_func (html
, hadjustment_notify_cb
, NULL
);
820 g_signal_handlers_disconnect_by_func (html
, vadjustment_notify_cb
, NULL
);
822 if (html
->priv
->idle_handler_id
!= 0) {
823 g_source_remove (html
->priv
->idle_handler_id
);
824 html
->priv
->idle_handler_id
= 0;
827 if (html
->priv
->scroll_timeout_id
!= 0) {
828 g_source_remove (html
->priv
->scroll_timeout_id
);
829 html
->priv
->scroll_timeout_id
= 0;
832 if (html
->priv
->desktop_interface
!= NULL
) {
833 g_signal_handlers_disconnect_matched (
834 html
->priv
->desktop_interface
,
835 G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, html
);
836 g_object_unref (html
->priv
->desktop_interface
);
837 html
->priv
->desktop_interface
= NULL
;
840 if (html
->priv
->resize_cursor
) {
841 g_object_unref (html
->priv
->resize_cursor
);
842 html
->priv
->resize_cursor
= NULL
;
845 if (html
->priv
->im_context
) {
846 g_object_unref (html
->priv
->im_context
);
847 html
->priv
->im_context
= NULL
;
850 g_free (html
->priv
->base_url
);
851 html
->priv
->base_url
= NULL
;
853 g_free (html
->priv
->caret_first_focus_anchor
);
854 html
->priv
->caret_first_focus_anchor
= NULL
;
857 g_object_unref (html
->engine
);
861 /* Chain up to parent's dispose() method. */
862 G_OBJECT_CLASS (parent_class
)->dispose (object
);
866 gtk_html_get_top_html (GtkHTML
*html
)
868 while (html
->iframe_parent
)
869 html
= GTK_HTML (html
->iframe_parent
);
875 gtk_html_set_fonts (GtkHTML
*html
,
876 HTMLPainter
*painter
)
878 GtkWidget
*top_level
;
879 GtkStyleContext
*style_context
;
881 PangoFontDescription
*fixed_desc
= NULL
;
882 const PangoFontDescription
*font_desc
;
883 gchar
*fixed_name
= NULL
;
884 const gchar
*fixed_family
= NULL
;
886 gboolean fixed_points
= FALSE
;
887 const gchar
*font_var
= NULL
;
888 gint font_var_size
= 0;
889 gboolean font_var_points
= FALSE
;
891 top_level
= GTK_WIDGET (gtk_html_get_top_html (html
));
892 style_context
= gtk_widget_get_style_context (top_level
);
893 font_desc
= gtk_style_context_get_font (style_context
, GTK_STATE_FLAG_NORMAL
);
895 font_var
= pango_font_description_get_family (font_desc
);
896 font_var_size
= pango_font_description_get_size (font_desc
);
897 font_var_points
= !pango_font_description_get_size_is_absolute (font_desc
);
899 gtk_widget_style_get (GTK_WIDGET (top_level
), "fixed_font_name", &fixed_name
, NULL
);
901 fixed_desc
= pango_font_description_from_string (fixed_name
);
902 if (pango_font_description_get_family (fixed_desc
)) {
903 fixed_size
= pango_font_description_get_size (fixed_desc
);
904 fixed_points
= !pango_font_description_get_size_is_absolute (fixed_desc
);
905 fixed_family
= pango_font_description_get_family (fixed_desc
);
915 settings
= g_settings_new ("org.gnome.desktop.interface");
916 fixed_name
= g_settings_get_string (settings
, "monospace-font-name");
917 g_object_unref (settings
);
920 fixed_desc
= pango_font_description_from_string (fixed_name
);
922 fixed_size
= pango_font_description_get_size (fixed_desc
);
923 fixed_points
= !pango_font_description_get_size_is_absolute (fixed_desc
);
924 fixed_family
= pango_font_description_get_family (fixed_desc
);
933 fixed_family
= "Monospace";
934 fixed_size
= font_var_size
;
937 html_font_manager_set_default (&painter
->font_manager
,
938 (gchar
*) font_var
, (gchar
*) fixed_family
,
939 font_var_size
, font_var_points
,
940 fixed_size
, fixed_points
);
942 pango_font_description_free (fixed_desc
);
944 screen
= gtk_widget_get_screen (GTK_WIDGET (html
));
946 pango_cairo_context_set_font_options (
947 painter
->pango_context
,
948 gdk_screen_get_font_options (screen
));
954 set_caret_mode (HTMLEngine
*engine
,
957 if (engine
->editable
)
960 if (!caret_mode
&& engine
->blinking_timer_id
)
961 html_engine_stop_blinking_cursor (engine
);
963 engine
->caret_mode
= caret_mode
;
965 if (caret_mode
&& !engine
->parsing
&& !engine
->timerId
== 0)
966 gtk_html_edit_make_cursor_visible (engine
->widget
);
968 /* Normally, blink cursor handler is setup in focus in event.
969 * However, in the case focus already in this engine, and user
970 * type F7 to enable cursor, we must setup the handler by
973 if (caret_mode
&& !engine
->blinking_timer_id
&& engine
->have_focus
)
974 html_engine_setup_blinking_cursor (engine
);
979 /* GtkWidget methods. */
982 style_updated (GtkWidget
*widget
)
984 HTMLEngine
*engine
= GTK_HTML (widget
)->engine
;
986 /* we don't need to set font's in idle time so call idle callback directly to avoid
987 * recalculating whole document
990 gtk_html_set_fonts (GTK_HTML (widget
), engine
->painter
);
991 html_engine_refresh_fonts (engine
);
994 html_colorset_set_style (engine
->defaultSettings
->color_set
, widget
);
995 html_colorset_set_unchanged (engine
->settings
->color_set
,
996 engine
->defaultSettings
->color_set
);
998 /* link and quotation colors might changed => need to refresh pango info in text objects */
1000 html_object_change_set_down (engine
->clue
, HTML_CHANGE_RECALC_PI
);
1001 html_engine_schedule_update (engine
);
1005 update_mouse_cursor (GtkWidget
*widget
,
1008 GdkEventMotion event
;
1010 /* a bit hacky here */
1011 memset (&event
, 0, sizeof (GdkEventMotion
));
1012 event
.type
= GDK_MOTION_NOTIFY
;
1013 event
.window
= gtk_widget_get_window (widget
);
1014 event
.send_event
= FALSE
;
1015 event
.state
= state
;
1017 motion_notify_event (widget
, &event
);
1021 key_press_event (GtkWidget
*widget
,
1024 GtkHTML
*html
= GTK_HTML (widget
);
1025 GtkHTMLClass
*html_class
= GTK_HTML_CLASS (GTK_WIDGET_GET_CLASS (html
));
1026 gboolean retval
= FALSE
, update
= TRUE
;
1027 HTMLObject
*focus_object
;
1028 gint focus_object_offset
;
1029 gboolean url_test_mode
;
1031 html
->binding_handled
= FALSE
;
1032 html
->priv
->update_styles
= FALSE
;
1033 html
->priv
->event_time
= event
->time
;
1035 if ((event
->keyval
== GDK_KEY_Control_L
|| event
->keyval
== GDK_KEY_Control_R
)
1036 && html_engine_get_editable (html
->engine
))
1037 url_test_mode
= TRUE
;
1039 url_test_mode
= FALSE
;
1041 if (html
->priv
->in_url_test_mode
!= url_test_mode
) {
1042 html
->priv
->in_url_test_mode
= url_test_mode
;
1043 update_mouse_cursor (widget
, event
->state
);
1046 if (html_engine_get_editable (html
->engine
)) {
1047 if (gtk_im_context_filter_keypress (html
->priv
->im_context
, event
)) {
1048 html_engine_reset_blinking_cursor (html
->engine
);
1049 html
->priv
->need_im_reset
= TRUE
;
1054 if (html_class
->use_emacs_bindings
&& html_class
->emacs_bindings
&& !html
->binding_handled
)
1055 gtk_binding_set_activate (html_class
->emacs_bindings
, event
->keyval
, event
->state
, G_OBJECT (widget
));
1057 if (!html
->binding_handled
) {
1058 html
->priv
->in_key_binding
= TRUE
;
1059 retval
= GTK_WIDGET_CLASS (parent_class
)->key_press_event (widget
, event
);
1060 html
->priv
->in_key_binding
= FALSE
;
1063 retval
= retval
|| html
->binding_handled
;
1064 update
= html
->priv
->update_styles
;
1066 if (retval
&& update
)
1067 gtk_html_update_styles (html
);
1069 html
->priv
->event_time
= 0;
1071 /* FIXME: use bindings */
1072 if (!html_engine_get_editable (html
->engine
)) {
1073 switch (event
->keyval
) {
1074 case GDK_KEY_Return
:
1075 case GDK_KEY_KP_Enter
:
1076 /* the toplevel gtkhtml's focus object may be a frame or ifame */
1077 focus_object
= html_engine_get_focus_object (html
->engine
, &focus_object_offset
);
1081 url
= html_object_get_complete_url (focus_object
, focus_object_offset
);
1083 /* printf ("link clicked: %s\n", url); */
1084 if (HTML_IS_TEXT (focus_object
)) {
1085 html_text_set_link_visited (HTML_TEXT (focus_object
), focus_object_offset
, html
->engine
, TRUE
);
1086 g_signal_emit (html
, signals
[LINK_CLICKED
], 0, url
);
1097 if (retval
&& (html_engine_get_editable (html
->engine
) || html
->engine
->caret_mode
))
1098 html_engine_reset_blinking_cursor (html
->engine
);
1100 /* printf ("retval: %d\n", retval); */
1106 key_release_event (GtkWidget
*widget
,
1109 GtkHTML
*html
= GTK_HTML (widget
);
1111 if (html
->priv
->in_url_test_mode
) {
1112 html
->priv
->in_url_test_mode
= FALSE
;
1113 update_mouse_cursor (widget
, event
->state
);
1116 if (!html
->binding_handled
&& html_engine_get_editable (html
->engine
)) {
1117 if (gtk_im_context_filter_keypress (html
->priv
->im_context
, event
)) {
1118 html
->priv
->need_im_reset
= TRUE
;
1123 return GTK_WIDGET_CLASS (parent_class
)->key_release_event (widget
, event
);
1127 gtk_html_drag_dest_set (GtkHTML
*html
)
1129 if (html_engine_get_editable (html
->engine
))
1132 GTK_DEST_DEFAULT_HIGHLIGHT
| GTK_DEST_DEFAULT_DROP
,
1133 drag_dest_targets
, G_N_ELEMENTS (drag_dest_targets
),
1134 GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_LINK
);
1136 gtk_drag_dest_unset (GTK_WIDGET (html
));
1140 realize (GtkWidget
*widget
)
1144 GdkWindow
*bin_window
;
1145 GtkAdjustment
*hadjustment
;
1146 GtkAdjustment
*vadjustment
;
1148 g_return_if_fail (widget
!= NULL
);
1149 g_return_if_fail (GTK_IS_HTML (widget
));
1151 html
= GTK_HTML (widget
);
1152 hadjustment
= gtk_layout_get_hadjustment (GTK_LAYOUT (widget
));
1153 vadjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (widget
));
1155 if (GTK_WIDGET_CLASS (parent_class
)->realize
)
1156 (* GTK_WIDGET_CLASS (parent_class
)->realize
) (widget
);
1158 window
= gtk_widget_get_window (widget
);
1159 bin_window
= gtk_layout_get_bin_window (&html
->layout
);
1161 gdk_window_set_events (bin_window
,
1162 (gdk_window_get_events (bin_window
)
1163 | GDK_EXPOSURE_MASK
| GDK_POINTER_MOTION_MASK
1164 | GDK_ENTER_NOTIFY_MASK
1165 | GDK_BUTTON_PRESS_MASK
1166 | GDK_BUTTON_RELEASE_MASK
1167 | GDK_VISIBILITY_NOTIFY_MASK
1168 | GDK_KEY_PRESS_MASK
| GDK_KEY_RELEASE_MASK
));
1170 html_engine_realize (html
->engine
, bin_window
);
1172 gdk_window_set_cursor (window
, NULL
);
1174 /* This sets the backing pixmap to None, so that scrolling does not
1175 * erase the newly exposed area, thus making the thing smoother. */
1176 gdk_window_set_background_pattern (bin_window
, NULL
);
1178 /* If someone was silly enough to stick us in something that doesn't
1179 * have adjustments, go ahead and create them now since we expect them
1180 * and love them and pat them
1182 if (hadjustment
== NULL
) {
1183 hadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1184 gtk_layout_set_hadjustment (GTK_LAYOUT (widget
), hadjustment
);
1187 if (vadjustment
== NULL
) {
1188 vadjustment
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1189 gtk_layout_set_vadjustment (GTK_LAYOUT (widget
), vadjustment
);
1192 gtk_html_drag_dest_set (html
);
1194 gtk_im_context_set_client_window (html
->priv
->im_context
, window
);
1196 html_image_factory_start_animations (html
->engine
->image_factory
);
1200 unrealize (GtkWidget
*widget
)
1202 GtkHTML
*html
= GTK_HTML (widget
);
1204 html_engine_unrealize (html
->engine
);
1206 gtk_im_context_set_client_window (html
->priv
->im_context
, NULL
);
1208 html_image_factory_stop_animations (html
->engine
->image_factory
);
1210 if (GTK_WIDGET_CLASS (parent_class
)->unrealize
)
1211 (* GTK_WIDGET_CLASS (parent_class
)->unrealize
) (widget
);
1215 draw (GtkWidget
*widget
,
1218 html_engine_draw_cb (GTK_HTML (widget
)->engine
, cr
);
1220 if (GTK_WIDGET_CLASS (parent_class
)->draw
)
1221 (* GTK_WIDGET_CLASS (parent_class
)->draw
) (widget
, cr
);
1227 gtk_html_get_preferred_height (GtkWidget
*widget
,
1228 gint
*minimum_height
,
1229 gint
*natural_height
)
1231 HTMLEngine
*e
= GTK_HTML (widget
)->engine
;
1235 old_height
= e
->height
;
1236 e
->height
= *minimum_height
;
1237 html_engine_calc_size (e
, NULL
);
1238 *minimum_height
= *natural_height
= html_engine_get_doc_height (e
);
1239 e
->height
= old_height
;
1240 html_engine_calc_size (e
, NULL
);
1242 *minimum_height
= *natural_height
= html_engine_get_doc_height (e
);
1247 gtk_html_get_preferred_width (GtkWidget
*widget
,
1248 gint
*minimum_width
,
1249 gint
*natural_width
)
1251 HTMLEngine
*e
= GTK_HTML (widget
)->engine
;
1255 old_width
= e
->width
;
1256 e
->width
= *minimum_width
;
1257 html_engine_calc_size (e
, NULL
);
1258 *minimum_width
= *natural_width
= html_engine_get_doc_width (e
);
1259 e
->width
= old_width
;
1260 html_engine_calc_size (e
, NULL
);
1262 *minimum_width
= *natural_width
= html_engine_get_doc_width (e
);
1267 child_size_allocate (HTMLObject
*o
,
1271 if (html_object_is_embedded (o
)) {
1272 HTMLEmbedded
*eo
= HTML_EMBEDDED (o
);
1275 GtkAllocation allocation
;
1277 html_object_calc_abs_position_in_frame (o
, &allocation
.x
, &allocation
.y
);
1278 allocation
.y
-= o
->ascent
;
1279 allocation
.width
= o
->width
;
1280 allocation
.height
= o
->ascent
+ o
->descent
;
1281 gtk_widget_size_allocate (eo
->widget
, &allocation
);
1287 set_adjustment_upper (GtkAdjustment
*adjustment
,
1294 /* XXX Stolen from gtklayout.c and simplified. */
1296 value
= gtk_adjustment_get_value (adjustment
);
1297 page_size
= gtk_adjustment_get_page_size (adjustment
);
1298 min
= MAX (0., upper
- page_size
);
1300 gtk_adjustment_set_upper (adjustment
, upper
);
1303 gtk_adjustment_set_value (adjustment
, min
);
1307 gtk_layout_faux_size_allocate (GtkWidget
*widget
,
1308 GtkAllocation
*allocation
)
1310 GtkLayout
*layout
= GTK_LAYOUT (widget
);
1311 GtkAdjustment
*adjustment
;
1312 guint width
, height
;
1314 /* XXX This is essentially a copy of GtkLayout's size_allocate()
1315 * method, but with the GtkLayoutChild loop removed. We call
1316 * this instead of chaining up to GtkLayout. */
1318 gtk_widget_set_allocation (widget
, allocation
);
1319 gtk_layout_get_size (layout
, &width
, &height
);
1321 if (gtk_widget_get_realized (widget
)) {
1322 gdk_window_move_resize (
1323 gtk_widget_get_window (widget
),
1324 allocation
->x
, allocation
->y
,
1325 allocation
->width
, allocation
->height
);
1328 gtk_layout_get_bin_window (layout
),
1329 MAX (width
, allocation
->width
),
1330 MAX (height
, allocation
->height
));
1333 /* XXX Does the previous logic alter the GtkLayout size?
1334 * Not sure, so best refetch the size just to be safe. */
1335 gtk_layout_get_size (layout
, &width
, &height
);
1337 adjustment
= gtk_layout_get_hadjustment (layout
);
1338 g_object_freeze_notify (G_OBJECT (adjustment
));
1339 gtk_adjustment_set_page_size (adjustment
, allocation
->width
);
1340 gtk_adjustment_set_page_increment (adjustment
, allocation
->width
* 0.9);
1341 gtk_adjustment_set_lower (adjustment
, 0);
1342 set_adjustment_upper (adjustment
, MAX (allocation
->width
, width
));
1343 g_object_thaw_notify (G_OBJECT (adjustment
));
1345 adjustment
= gtk_layout_get_vadjustment (layout
);
1346 g_object_freeze_notify (G_OBJECT (adjustment
));
1347 gtk_adjustment_set_page_size (adjustment
, allocation
->height
);
1348 gtk_adjustment_set_page_increment (adjustment
, allocation
->height
* 0.9);
1349 gtk_adjustment_set_lower (adjustment
, 0);
1350 set_adjustment_upper (adjustment
, MAX (allocation
->height
, height
));
1351 g_object_thaw_notify (G_OBJECT (adjustment
));
1355 size_allocate (GtkWidget
*widget
,
1356 GtkAllocation
*allocation
)
1359 gboolean changed_x
= FALSE
, changed_y
= FALSE
;
1361 g_return_if_fail (widget
!= NULL
);
1362 g_return_if_fail (GTK_IS_HTML (widget
));
1363 g_return_if_fail (allocation
!= NULL
);
1365 html
= GTK_HTML (widget
);
1367 /* isolate children from layout - we want to set them after calc size is performed
1368 * and we know the position of the children */
1370 gtk_layout_faux_size_allocate (widget
, allocation
);
1372 if (html
->engine
->width
!= allocation
->width
1373 || html
->engine
->height
!= allocation
->height
) {
1374 HTMLEngine
*e
= html
->engine
;
1375 gint old_doc_width
, old_doc_height
, old_width
, old_height
;
1377 old_doc_width
= html_engine_get_doc_width (html
->engine
);
1378 old_doc_height
= html_engine_get_doc_height (html
->engine
);
1379 old_width
= e
->width
;
1380 old_height
= e
->height
;
1382 e
->width
= allocation
->width
;
1383 e
->height
= allocation
->height
;
1385 html_engine_calc_size (html
->engine
, NULL
);
1386 gtk_html_update_scrollbars_on_resize (html
, old_doc_width
, old_doc_height
, old_width
, old_height
,
1387 &changed_x
, &changed_y
);
1390 if (!html
->engine
->keep_scroll
)
1391 gtk_html_private_calc_scrollbars (html
, &changed_x
, &changed_y
);
1393 if (html
->engine
->clue
)
1394 html_object_forall (html
->engine
->clue
, html
->engine
, child_size_allocate
, NULL
);
1398 set_pointer_url (GtkHTML
*html
,
1401 if (url
== html
->pointer_url
)
1404 if (url
&& html
->pointer_url
&& !strcmp (url
, html
->pointer_url
))
1407 g_free (html
->pointer_url
);
1408 html
->pointer_url
= url
? g_strdup (url
) : NULL
;
1409 g_signal_emit (html
, signals
[ON_URL
], 0, html
->pointer_url
);
1413 dnd_link_set (GtkWidget
*widget
,
1417 if (!html_engine_get_editable (GTK_HTML (widget
)->engine
)) {
1418 /* printf ("dnd_link_set %p\n", o); */
1420 gtk_drag_source_set (
1421 widget
, GDK_BUTTON1_MASK
,
1422 drag_source_targets
, G_N_ELEMENTS (drag_source_targets
),
1423 GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_LINK
);
1424 GTK_HTML (widget
)->priv
->dnd_object
= o
;
1425 GTK_HTML (widget
)->priv
->dnd_object_offset
= offset
;
1430 dnd_link_unset (GtkWidget
*widget
)
1432 if (!html_engine_get_editable (GTK_HTML (widget
)->engine
)) {
1433 /* printf ("dnd_link_unset\n"); */
1435 gtk_drag_source_unset (widget
);
1436 GTK_HTML (widget
)->priv
->dnd_object
= NULL
;
1441 on_object (GtkWidget
*widget
,
1448 GtkHTML
*html
= GTK_HTML (widget
);
1453 if (gtk_html_get_editable (html
)) {
1454 if (HTML_IS_IMAGE (obj
)) {
1457 html_object_calc_abs_position (obj
, &ox
, &oy
);
1458 if (ox
+ obj
->width
- 5 <= x
&& oy
+ obj
->descent
- 5 <= y
) {
1459 gdk_window_set_cursor (window
, html
->priv
->resize_cursor
);
1466 url
= gtk_html_get_url_object_relative (html
, obj
,
1467 html_object_get_url (obj
, offset
));
1469 set_pointer_url (html
, url
);
1470 dnd_link_set (widget
, obj
, offset
);
1472 if (html
->engine
->editable
&& !html
->priv
->in_url_test_mode
)
1473 gdk_window_set_cursor (window
, html
->ibeam_cursor
);
1475 gdk_window_set_cursor (window
, html
->hand_cursor
);
1478 set_pointer_url (html
, NULL
);
1479 dnd_link_unset (widget
);
1481 if (html_object_is_text (obj
) && html
->allow_selection
)
1482 gdk_window_set_cursor (window
, html
->ibeam_cursor
);
1484 gdk_window_set_cursor (window
, NULL
);
1489 set_pointer_url (html
, NULL
);
1490 dnd_link_unset (widget
);
1492 gdk_window_set_cursor (window
, NULL
);
1496 #define HTML_DIST(x,y) sqrt(x*x + y*y)
1499 mouse_change_pos (GtkWidget
*widget
,
1511 if (!gtk_widget_get_realized (widget
))
1514 html
= GTK_HTML (widget
);
1515 engine
= html
->engine
;
1516 obj
= html_engine_get_object_at (engine
, x
, y
, (guint
*) &offset
, FALSE
);
1518 if ((html
->in_selection
|| html
->in_selection_drag
) && html
->allow_selection
) {
1519 GtkAllocation allocation
;
1520 gboolean need_scroll
;
1522 gtk_widget_get_allocation (widget
, &allocation
);
1525 type
= HTML_OBJECT_TYPE (obj
);
1527 /* FIXME this is broken */
1529 if (type
== HTML_TYPE_BUTTON
||
1530 type
== HTML_TYPE_CHECKBOX
||
1531 type
== HTML_TYPE_EMBEDDED
||
1532 type
== HTML_TYPE_HIDDEN
||
1533 type
== HTML_TYPE_IMAGEINPUT
||
1534 type
== HTML_TYPE_RADIO
||
1535 type
== HTML_TYPE_SELECT
||
1536 type
== HTML_TYPE_TEXTAREA
||
1537 type
== HTML_TYPE_TEXTINPUT
) {
1542 if (HTML_DIST ((x
- html
->selection_x1
), (y
- html
->selection_y1
))
1543 > html_painter_get_space_width (engine
->painter
, GTK_HTML_FONT_STYLE_SIZE_3
, NULL
)) {
1544 html
->in_selection
= TRUE
;
1545 html
->in_selection_drag
= TRUE
;
1548 need_scroll
= FALSE
;
1550 if (x
< html
->engine
->x_offset
) {
1552 } else if (x
>= allocation
.width
) {
1556 if (y
< html
->engine
->y_offset
) {
1558 } else if (y
>= allocation
.height
) {
1563 setup_scroll_timeout (html
);
1565 remove_scroll_timeout (html
);
1567 /* This will put the mark at the position of the
1568 * previous click. */
1569 if (engine
->mark
== NULL
&& engine
->editable
)
1570 html_engine_set_mark (engine
);
1572 html_engine_select_region (engine
, html
->selection_x1
, html
->selection_y1
, x
, y
);
1575 if (html
->priv
->in_object_resize
) {
1576 HTMLObject
*o
= html
->priv
->resize_object
;
1579 html_object_calc_abs_position (o
, &ox
, &oy
);
1581 g_assert (HTML_IS_IMAGE (o
));
1582 if (x
> ox
&& y
> oy
) {
1587 if (!(state
& GDK_SHIFT_MASK
)) {
1591 html_image_set_size (HTML_IMAGE (o
), w
, h
, FALSE
, FALSE
);
1594 on_object (widget
, window
, obj
, offset
, x
, y
);
1599 static const gchar
*
1600 skip_host (const gchar
*url
)
1605 while (*host
&& (*host
!= '/') && (*host
!= ':'))
1619 while (*host
&& (*host
!= '/'))
1630 path_len (const gchar
*base
,
1637 start
= last
= skip_host (base
);
1639 cur
= strrchr (start
, '/');
1650 collapse_path (gchar
*url
)
1657 start
= skip_host (url
);
1660 while ((cur
= strstr (cur
, "/../"))) {
1663 /* handle the case of a rootlevel /../ specialy */
1666 memmove (cur
, end
, len
+ 1);
1669 while (cur
> start
) {
1671 if ((*cur
== '/') || (cur
== start
)) {
1673 memmove (cur
, end
, len
+ 1);
1683 url_is_absolute (const gchar
*url
)
1686 * URI Syntactic Components
1688 * The URI syntax is dependent upon the scheme. In general, absolute
1689 * URI are written as follows:
1691 * <scheme>:<scheme-specific-part>
1693 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
1699 if (!isalpha (*url
))
1703 while (*url
&& (isalnum (*url
) || *url
== '+' || *url
== '-' || *url
== '.'))
1706 return *url
&& *url
== ':';
1710 expand_relative (const gchar
*base
,
1713 gchar
*new_url
= NULL
;
1714 gsize base_len
, url_len
;
1715 gboolean absolute
= FALSE
;
1717 if (!base
|| url_is_absolute (url
)) {
1719 g_warning ("base = %s url = %s new_url = %s",
1720 base, url, new_url);
1722 return g_strdup (url
);
1729 base_len
= path_len (base
, absolute
);
1730 url_len
= strlen (url
);
1732 new_url
= g_malloc (base_len
+ url_len
+ 2);
1735 memcpy (new_url
, base
, base_len
);
1737 if (base
[base_len
- 1] != '/')
1738 new_url
[base_len
++] = '/';
1743 memcpy (new_url
+ base_len
, url
, url_len
);
1744 new_url
[base_len
+ url_len
] = '\0';
1747 * g_warning ("base = %s url = %s new_url = %s",
1748 * base, url, new_url);
1754 gtk_html_get_url_base_relative (GtkHTML
*html
,
1757 return expand_relative (gtk_html_get_base (html
), url
);
1761 expand_frame_url (GtkHTML
*html
,
1766 new_url
= gtk_html_get_url_base_relative (html
, url
);
1767 while (html
->iframe_parent
) {
1770 expanded
= gtk_html_get_url_base_relative (GTK_HTML (html
->iframe_parent
),
1775 html
= GTK_HTML (html
->iframe_parent
);
1781 gtk_html_get_url_object_relative (GtkHTML
*html
,
1788 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
1790 /* start at the top always */
1791 while (html
->iframe_parent
)
1792 html
= GTK_HTML (html
->iframe_parent
);
1795 while (parent
->parent
) {
1796 parent
= parent
->parent
;
1797 if ((HTML_OBJECT_TYPE (parent
) == HTML_TYPE_FRAME
)
1798 || (HTML_OBJECT_TYPE (parent
) == HTML_TYPE_IFRAME
))
1802 e
= html_object_get_engine (parent
, html
->engine
);
1805 g_warning ("Cannot find object for url");
1810 if (e == html->engine)
1811 g_warning ("engine matches engine");
1813 return url
? expand_frame_url (e
->widget
, url
) : NULL
;
1817 shift_to_iframe_parent (GtkWidget
*widget
,
1821 while (GTK_HTML (widget
)->iframe_parent
) {
1822 GtkWidget
*scrolled_window
;
1823 GtkAllocation allocation
;
1825 scrolled_window
= gtk_widget_get_parent (widget
);
1827 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window
), widget
);
1829 gtk_widget_get_allocation (scrolled_window
, &allocation
);
1832 *x
+= allocation
.x
- GTK_HTML (widget
)->engine
->x_offset
;
1834 *y
+= allocation
.y
- GTK_HTML (widget
)->engine
->y_offset
;
1836 widget
= GTK_HTML (widget
)->iframe_parent
;
1844 motion_notify_event (GtkWidget
*widget
,
1845 GdkEventMotion
*event
)
1848 GdkWindow
*bin_window
;
1852 g_return_val_if_fail (widget
!= NULL
, 0);
1853 g_return_val_if_fail (GTK_IS_HTML (widget
), 0);
1854 g_return_val_if_fail (event
!= NULL
, 0);
1856 /* printf ("motion_notify_event\n"); */
1858 if (GTK_HTML (widget
)->priv
->dnd_in_progress
)
1861 widget
= shift_to_iframe_parent (widget
, &x
, &y
);
1863 window
= gtk_widget_get_window (widget
);
1864 bin_window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
1866 gdk_window_get_pointer (bin_window
, &x
, &y
, NULL
);
1868 if (!mouse_change_pos (widget
, window
, x
, y
, event
->state
))
1871 engine
= GTK_HTML (widget
)->engine
;
1872 if (GTK_HTML (widget
)->in_selection_drag
&& html_engine_get_editable (engine
))
1873 html_engine_jump_at (engine
, x
, y
);
1878 toplevel_unmap (GtkWidget
*widget
,
1882 html_image_factory_stop_animations (html
->engine
->image_factory
);
1888 hierarchy_changed (GtkWidget
*widget
,
1889 GtkWidget
*old_toplevel
)
1891 GtkWidget
*toplevel
;
1892 GtkHTMLPrivate
*priv
= GTK_HTML (widget
)->priv
;
1894 if (old_toplevel
&& priv
->toplevel_unmap_handler
) {
1895 g_signal_handler_disconnect (old_toplevel
,
1896 priv
->toplevel_unmap_handler
);
1897 priv
->toplevel_unmap_handler
= 0;
1900 toplevel
= gtk_widget_get_toplevel (widget
);
1902 if (gtk_widget_is_toplevel (toplevel
) && priv
->toplevel_unmap_handler
== 0) {
1903 priv
->toplevel_unmap_handler
= g_signal_connect (G_OBJECT (toplevel
), "unmap-event",
1904 G_CALLBACK (toplevel_unmap
), widget
);
1909 visibility_notify_event (GtkWidget
*widget
,
1910 GdkEventVisibility
*event
)
1912 if (event
->state
== GDK_VISIBILITY_FULLY_OBSCURED
)
1913 html_image_factory_stop_animations (GTK_HTML (widget
)->engine
->image_factory
);
1915 html_image_factory_start_animations (GTK_HTML (widget
)->engine
->image_factory
);
1921 button_press_event (GtkWidget
*widget
,
1922 GdkEventButton
*event
)
1925 GtkWidget
*orig_widget
= widget
;
1929 /* printf ("button_press_event\n"); */
1934 widget
= shift_to_iframe_parent (widget
, &x
, &y
);
1935 html
= GTK_HTML (widget
);
1936 engine
= html
->engine
;
1938 if (event
->button
== 1 || ((event
->button
== 2 || event
->button
== 3) && html_engine_get_editable (engine
))) {
1939 html
->priv
->is_first_focus
= FALSE
;
1940 html
->priv
->skip_update_cursor
= TRUE
;
1941 html
->priv
->cursor_moved
= FALSE
;
1942 gtk_widget_grab_focus (widget
);
1945 if (event
->type
== GDK_BUTTON_PRESS
) {
1946 GtkAdjustment
*adjustment
;
1951 gdouble step_increment
;
1953 adjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (widget
));
1954 adj_value
= gtk_adjustment_get_value (adjustment
);
1955 lower
= gtk_adjustment_get_lower (adjustment
);
1956 upper
= gtk_adjustment_get_upper (adjustment
);
1957 page_size
= gtk_adjustment_get_page_size (adjustment
);
1958 step_increment
= gtk_adjustment_get_step_increment (adjustment
);
1960 switch (event
->button
) {
1962 /* Mouse wheel scroll up. */
1963 if (event
->state
& GDK_CONTROL_MASK
)
1964 gtk_html_command (html
, "zoom-out");
1966 value
= adj_value
- step_increment
* 3;
1971 gtk_adjustment_set_value (adjustment
, value
);
1975 /* Mouse wheel scroll down. */
1976 if (event
->state
& GDK_CONTROL_MASK
)
1977 gtk_html_command (html
, "zoom-in");
1979 value
= adj_value
+ step_increment
* 3;
1981 if (value
> (upper
- page_size
))
1982 value
= upper
- page_size
;
1984 gtk_adjustment_set_value (adjustment
, value
);
1988 if (html_engine_get_editable (engine
)) {
1990 html_engine_disable_selection (html
->engine
);
1991 html_engine_jump_at (engine
, x
, y
);
1992 gtk_html_update_styles (html
);
1993 html
->priv
->selection_as_cite
= event
->state
& GDK_SHIFT_MASK
;
1994 type
= event
->state
& GDK_CONTROL_MASK
? 1 : 0;
1995 gtk_clipboard_request_contents (
1996 gtk_widget_get_clipboard (GTK_WIDGET (html
), GDK_SELECTION_PRIMARY
),
1997 gdk_atom_intern (selection_targets
[type
].target
, FALSE
),
1998 clipboard_paste_received_cb
, html
);
2003 html
->in_selection_drag
= TRUE
;
2004 if (html_engine_get_editable (engine
)) {
2007 obj
= html_engine_get_object_at (engine
, x
, y
, NULL
, FALSE
);
2009 if (obj
&& HTML_IS_IMAGE (obj
)) {
2012 html_object_calc_abs_position (obj
, &ox
, &oy
);
2013 if (ox
+ obj
->width
- 5 <= x
&& oy
+ obj
->descent
- 5 <= y
) {
2014 html
->priv
->in_object_resize
= TRUE
;
2015 html
->priv
->resize_object
= obj
;
2016 html
->in_selection_drag
= FALSE
;
2020 if (html
->allow_selection
&& !html
->priv
->in_object_resize
)
2021 if (!(event
->state
& GDK_SHIFT_MASK
)
2022 || (!engine
->mark
&& event
->state
& GDK_SHIFT_MASK
))
2023 html_engine_set_mark (engine
);
2024 html_engine_jump_at (engine
, x
, y
);
2031 orig_e
= GTK_HTML (orig_widget
)->engine
;
2032 obj
= html_engine_get_object_at (engine
, x
, y
, (guint
*) &offset
, FALSE
);
2033 if (obj
&& ((HTML_IS_IMAGE (obj
) && HTML_IMAGE (obj
)->url
&& *HTML_IMAGE (obj
)->url
)
2034 || (HTML_IS_TEXT (obj
) && (url
= html_object_get_complete_url (obj
, offset
))))) {
2036 html_engine_set_focus_object (orig_e
, obj
, offset
);
2038 html_engine_set_focus_object (orig_e
, NULL
, 0);
2039 if (orig_e
->caret_mode
|| engine
->caret_mode
)
2040 html_engine_jump_at (engine
, x
, y
);
2043 if (html
->allow_selection
&& !html
->priv
->in_object_resize
) {
2044 if (event
->state
& GDK_SHIFT_MASK
)
2045 html_engine_select_region (engine
,
2046 html
->selection_x1
, html
->selection_y1
, x
, y
);
2048 GdkWindow
*bin_window
;
2050 bin_window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
2051 html_engine_disable_selection (engine
);
2052 if (gdk_pointer_grab (bin_window
, FALSE
,
2053 (GDK_BUTTON_RELEASE_MASK
2054 | GDK_BUTTON_MOTION_MASK
2055 | GDK_POINTER_MOTION_HINT_MASK
),
2056 NULL
, NULL
, event
->time
) == 0) {
2057 html
->selection_x1
= x
;
2058 html
->selection_y1
= y
;
2063 engine
->selection_mode
= FALSE
;
2064 if (html_engine_get_editable (engine
))
2065 gtk_html_update_styles (html
);
2070 } else if (event
->button
== 1 && html
->allow_selection
) {
2071 if (event
->type
== GDK_2BUTTON_PRESS
) {
2072 html
->in_selection_drag
= FALSE
;
2073 gtk_html_select_word (html
);
2074 html
->in_selection
= TRUE
;
2076 else if (event
->type
== GDK_3BUTTON_PRESS
) {
2077 html
->in_selection_drag
= FALSE
;
2078 gtk_html_select_line (html
);
2079 html
->in_selection
= TRUE
;
2087 any_has_cursor_moved (GtkHTML
*html
)
2090 if (html
->priv
->cursor_moved
)
2093 html
= html
->iframe_parent
? GTK_HTML (html
->iframe_parent
) : NULL
;
2100 any_has_skip_update_cursor (GtkHTML
*html
)
2103 if (html
->priv
->skip_update_cursor
)
2106 html
= html
->iframe_parent
? GTK_HTML (html
->iframe_parent
) : NULL
;
2113 button_release_event (GtkWidget
*initial_widget
,
2114 GdkEventButton
*event
)
2120 HTMLObject
*focus_object
;
2121 gint focus_object_offset
;
2123 /* printf ("button_release_event\n"); */
2127 widget
= shift_to_iframe_parent (initial_widget
, &x
, &y
);
2128 html
= GTK_HTML (widget
);
2130 remove_scroll_timeout (html
);
2131 gtk_grab_remove (widget
);
2132 gdk_pointer_ungrab (event
->time
);
2134 engine
= html
->engine
;
2136 if (html
->in_selection
&& !html
->priv
->dnd_in_progress
) {
2137 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
2138 if (html
->in_selection_drag
)
2139 html_engine_select_region (engine
, html
->selection_x1
, html
->selection_y1
,
2141 gtk_html_update_styles (html
);
2142 update_primary_selection (html
);
2146 if (event
->button
== 1) {
2148 if (html
->in_selection_drag
&& html_engine_get_editable (engine
))
2149 html_engine_jump_at (engine
, x
, y
);
2151 html
->in_selection_drag
= FALSE
;
2153 if (!html
->priv
->dnd_in_progress
2154 && html
->pointer_url
!= NULL
&& !html
->in_selection
2155 && (!gtk_html_get_editable (html
) || html
->priv
->in_url_test_mode
)) {
2156 g_signal_emit (widget
, signals
[LINK_CLICKED
], 0, html
->pointer_url
);
2157 focus_object
= html_engine_get_focus_object (html
->engine
, &focus_object_offset
);
2158 if (HTML_IS_TEXT (focus_object
)) {
2159 html_text_set_link_visited (HTML_TEXT (focus_object
), focus_object_offset
, html
->engine
, TRUE
);
2162 if (html
->priv
->in_url_test_mode
) {
2166 memset (&arg
, 0, sizeof (GValue
));
2167 g_value_init (&arg
, G_TYPE_STRING
);
2168 g_value_set_string (&arg
, html
->pointer_url
);
2170 gtk_html_editor_event (html
, GTK_HTML_EDITOR_EVENT_LINK_CLICKED
, &arg
);
2172 g_value_unset (&arg
);
2174 focus_object
= html_engine_get_object_at (html
->engine
, x
, y
, &offset
, TRUE
);
2175 if (HTML_IS_TEXT (focus_object
))
2176 html_text_set_link_visited (HTML_TEXT (focus_object
), (gint
) offset
, html
->engine
, TRUE
);
2179 html
->priv
->skip_update_cursor
= TRUE
;
2183 html
->in_selection
= FALSE
;
2184 html
->priv
->in_object_resize
= FALSE
;
2190 gtk_html_keymap_direction_changed (GdkKeymap
*keymap
,
2193 if (html_engine_get_editable (html
->engine
)) {
2194 html_engine_edit_set_direction (html
->engine
, html_text_direction_pango_to_html (gdk_keymap_get_direction (keymap
)));
2199 goto_caret_anchor (GtkHTML
*html
)
2203 g_return_val_if_fail (html
!= NULL
, FALSE
);
2204 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
2206 if (!html
->priv
->is_first_focus
)
2209 html
->priv
->is_first_focus
= FALSE
;
2211 if (html
->priv
->caret_first_focus_anchor
&& html_object_find_anchor (html
->engine
->clue
, html
->priv
->caret_first_focus_anchor
, &x
, &y
)) {
2212 GtkAdjustment
*adjustment
;
2217 html_engine_jump_at (html
->engine
, x
, y
);
2219 layout
= GTK_LAYOUT (html
->engine
->widget
);
2220 adjustment
= gtk_layout_get_vadjustment (layout
);
2221 page_size
= gtk_adjustment_get_page_size (adjustment
);
2222 value
= gtk_adjustment_get_value (adjustment
);
2224 /* scroll to the position on screen if not visible */
2225 if (y
< value
|| y
> value
+ page_size
)
2226 gtk_adjustment_set_value (adjustment
, y
);
2235 focus_in_event (GtkWidget
*widget
,
2236 GdkEventFocus
*event
)
2238 GtkHTML
*html
= GTK_HTML (widget
);
2240 /* printf ("focus in\n"); */
2241 if (!html
->iframe_parent
) {
2242 if (html
->engine
->cursor
&& html
->engine
->cursor
->position
== 0 && html
->engine
->caret_mode
)
2243 goto_caret_anchor (html
);
2244 html_engine_set_focus (html
->engine
, TRUE
);
2246 GtkWidget
*window
= gtk_widget_get_ancestor (widget
, gtk_window_get_type ());
2248 gtk_window_set_focus (GTK_WINDOW (window
), html
->iframe_parent
);
2251 html
->priv
->need_im_reset
= TRUE
;
2252 gtk_im_context_focus_in (html
->priv
->im_context
);
2254 gtk_html_keymap_direction_changed (gdk_keymap_get_for_display (gtk_widget_get_display (widget
)),
2256 g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget
)),
2257 "direction_changed", G_CALLBACK (gtk_html_keymap_direction_changed
), html
);
2263 focus_out_event (GtkWidget
*widget
,
2264 GdkEventFocus
*event
)
2266 GtkHTML
*html
= GTK_HTML (widget
);
2268 html_painter_set_focus (html
->engine
->painter
, FALSE
);
2269 html_engine_redraw_selection (html
->engine
);
2270 /* printf ("focus out\n"); */
2271 if (!html
->iframe_parent
) {
2272 html_engine_set_focus (html
->engine
, FALSE
);
2275 html
->priv
->need_im_reset
= TRUE
;
2276 gtk_im_context_focus_out (html
->priv
->im_context
);
2278 g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget
)),
2279 gtk_html_keymap_direction_changed
, html
);
2285 enter_notify_event (GtkWidget
*widget
,
2286 GdkEventCrossing
*event
)
2293 window
= gtk_widget_get_window (widget
);
2294 widget
= shift_to_iframe_parent (widget
, &x
, &y
);
2296 mouse_change_pos (widget
, window
, x
, y
, event
->state
);
2301 /* X11 selection support. */
2303 static const gchar
*
2304 utf16_order (gboolean swap
)
2309 * FIXME owen tells me this logic probably isn't needed
2310 * because smart iconvs will notice the BOM and act accordingly
2311 * I don't have as much faith in the various iconv implementations
2312 * so I am leaving it in for now
2315 be
= G_BYTE_ORDER
== G_BIG_ENDIAN
;
2316 be
= swap
? be
: !be
;
2326 get_selection_string (GtkHTML
*html
,
2330 gboolean html_format
)
2332 HTMLObject
*selection_object
= NULL
;
2333 gchar
*selection_string
= NULL
;
2334 gboolean free_object
= FALSE
;
2336 if (selection
&& html_engine_is_selection_active (html
->engine
)) {
2337 guint selection_len
;
2338 html_engine_copy_object (html
->engine
, &selection_object
, &selection_len
);
2342 if (html
->engine
->primary
) {
2343 selection_object
= html
->engine
->primary
;
2345 } else /* CLIPBOARD */ {
2346 if (html
->engine
->clipboard
) {
2347 selection_object
= html
->engine
->clipboard
;
2353 if (selection_object
) {
2354 HTMLEngineSaveState
*state
;
2357 state
= html_engine_save_buffer_new (html
->engine
, TRUE
);
2358 buffer
= (GString
*) state
->user_data
;
2360 html_object_save (selection_object
, state
);
2361 g_string_append_unichar (buffer
, 0x0000);
2365 selection_string
= html_engine_save_buffer_free (state
, FALSE
);
2368 if (selection_object
)
2369 selection_string
= html_object_get_selection_string (selection_object
, html
->engine
);
2370 if (len
&& selection_string
)
2371 *len
= strlen (selection_string
);
2374 if (selection_object
&& free_object
)
2375 html_object_destroy (selection_object
);
2377 return selection_string
;
2380 /* returned pointer should be freed with g_free */
2382 gtk_html_get_selection_html (GtkHTML
*html
,
2385 return get_selection_string (html
, len
, TRUE
, FALSE
, TRUE
);
2388 /* returned pointer should be freed with g_free */
2390 gtk_html_get_selection_plain_text (GtkHTML
*html
,
2393 return get_selection_string (html
, len
, TRUE
, FALSE
, FALSE
);
2397 utf16_to_utf8_with_bom_check (guchar
*data
,
2400 const gchar
*fromcode
= NULL
;
2401 GError
*error
= NULL
;
2408 * Unicode Techinical Report 20
2409 * (http://www.unicode.org/unicode/reports/tr20/) says to treat an
2410 * initial 0xfeff (ZWNBSP) as a byte order indicator so that is
2411 * what we do. If there is no indicator assume it is in the default
2415 memcpy (&c
, data
, 2);
2420 fromcode
= utf16_order (c
== 0xfeff);
2425 fromcode
= "UTF-16";
2429 utf8_ret
= g_convert ((gchar
*) data
,
2438 g_warning ("g_convert error: %s\n", error
->message
);
2439 g_error_free (error
);
2444 /* removes useless leading BOM from UTF-8 string if present */
2446 utf8_filter_out_bom (gchar
*str
)
2451 /* input is always valid, NUL-terminated UTF-8 sequence, we don't need
2452 * to validated it again */
2453 if (g_utf8_get_char (str
) == 0xfeff) {
2454 gchar
*out
= g_strdup (g_utf8_next_char (str
));
2462 /* Initialization. */
2464 set_focus_child (GtkContainer
*containter
,
2467 HTMLObject
*o
= NULL
;
2469 while (w
&& !(o
= g_object_get_data (G_OBJECT (w
), "embeddedelement")))
2470 w
= gtk_widget_get_parent (w
);
2472 if (o
&& !html_object_is_frame (o
))
2473 html_engine_set_focus_object (GTK_HTML (containter
)->engine
, o
, 0);
2475 (*GTK_CONTAINER_CLASS (parent_class
)->set_focus_child
) (containter
, w
);
2479 focus (GtkWidget
*w
,
2480 GtkDirectionType direction
)
2482 HTMLEngine
*e
= GTK_HTML (w
)->engine
;
2484 if (html_engine_get_editable (e
)) {
2487 rv
= (*GTK_WIDGET_CLASS (parent_class
)->focus
) (w
, direction
);
2488 html_engine_set_focus (GTK_HTML (w
)->engine
, rv
);
2492 /* Reset selection. */
2493 if (e
->shift_selection
|| e
->mark
) {
2494 html_engine_disable_selection (e
);
2495 html_engine_edit_selection_updater_schedule (e
->selection_updater
);
2496 e
->shift_selection
= FALSE
;
2499 if (!gtk_widget_has_focus (w
) && e
->caret_mode
) {
2500 if (goto_caret_anchor (GTK_HTML (w
))) {
2501 gtk_widget_grab_focus (w
);
2503 update_primary_selection (GTK_HTML (w
));
2504 g_signal_emit (GTK_HTML (w
), signals
[CURSOR_CHANGED
], 0);
2510 if (((e
->focus_object
&& !(gtk_widget_has_focus (w
))) || html_engine_focus (e
, direction
)) && e
->focus_object
) {
2512 HTMLObject
*obj
= html_engine_get_focus_object (e
, &offset
);
2513 gint x1
, y1
, x2
, y2
, xo
, yo
;
2518 if (HTML_IS_TEXT (obj
)) {
2519 if (!html_text_get_link_rectangle (HTML_TEXT (obj
), e
->painter
, offset
, &x1
, &y1
, &x2
, &y2
))
2522 html_object_calc_abs_position (obj
, &x1
, &y1
);
2523 y2
= y1
+ obj
->descent
;
2524 x2
= x1
+ obj
->width
;
2528 /* printf ("child pos: %d,%d x %d,%d\n", x1, y1, x2, y2); */
2530 if (x2
> e
->x_offset
+ e
->width
)
2531 e
->x_offset
= x2
- e
->width
;
2532 if (x1
< e
->x_offset
)
2534 if (e
->width
> 2 * RIGHT_BORDER
&& e
->x_offset
== x2
- e
->width
)
2535 e
->x_offset
= MIN (x2
- e
->width
+ RIGHT_BORDER
+ 1,
2536 html_engine_get_doc_width (e
) - e
->width
);
2537 if (e
->width
> 2 * LEFT_BORDER
&& e
->x_offset
>= x1
)
2538 e
->x_offset
= MAX (x1
- LEFT_BORDER
, 0);
2540 if (y2
>= e
->y_offset
+ e
->height
)
2541 e
->y_offset
= y2
- e
->height
+ 1;
2542 if (y1
< e
->y_offset
)
2544 if (e
->height
> 2 * BOTTOM_BORDER
&& e
->y_offset
== y2
- e
->height
+ 1)
2545 e
->y_offset
= MIN (y2
- e
->height
+ BOTTOM_BORDER
+ 1,
2546 html_engine_get_doc_height (e
) - e
->height
);
2547 if (e
->height
> 2 * TOP_BORDER
&& e
->y_offset
>= y1
)
2548 e
->y_offset
= MAX (y1
- TOP_BORDER
, 0);
2550 if (e
->x_offset
!= xo
) {
2551 GtkAdjustment
*adjustment
;
2553 adjustment
= gtk_layout_get_hadjustment (GTK_LAYOUT (w
));
2554 gtk_adjustment_set_value (adjustment
, (gfloat
) e
->x_offset
);
2556 if (e
->y_offset
!= yo
) {
2557 GtkAdjustment
*adjustment
;
2559 adjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (w
));
2560 gtk_adjustment_set_value (adjustment
, (gfloat
) e
->y_offset
);
2562 /* printf ("engine pos: %d,%d x %d,%d\n",
2563 * e->x_offset, e->y_offset, e->x_offset + e->width, e->y_offset + e->height); */
2565 if (!gtk_widget_has_focus (w
) && !html_object_is_embedded (obj
))
2566 gtk_widget_grab_focus (w
);
2567 if (e
->caret_mode
) {
2568 html_engine_jump_to_object (e
, obj
, offset
);
2571 update_primary_selection (GTK_HTML (w
));
2572 g_signal_emit (GTK_HTML (w
), signals
[CURSOR_CHANGED
], 0);
2583 drag_begin (GtkWidget
*widget
,
2584 GdkDragContext
*context
)
2589 /* printf ("drag_begin\n"); */
2590 GTK_HTML (widget
)->priv
->dnd_real_object
= o
= GTK_HTML (widget
)->priv
->dnd_object
;
2591 GTK_HTML (widget
)->priv
->dnd_real_object_offset
= GTK_HTML (widget
)->priv
->dnd_object_offset
;
2592 GTK_HTML (widget
)->priv
->dnd_in_progress
= TRUE
;
2594 i
= html_interval_new (o
, o
, 0, html_object_get_length (o
));
2595 html_engine_select_interval (GTK_HTML (widget
)->engine
, i
);
2599 drag_end (GtkWidget
*widget
,
2600 GdkDragContext
*context
)
2604 /* printf ("drag_end\n"); */
2605 g_return_if_fail (GTK_IS_HTML (widget
));
2607 html
= GTK_HTML (widget
);
2609 html
->priv
->dnd_in_progress
= FALSE
;
2613 drag_data_get (GtkWidget
*widget
,
2614 GdkDragContext
*context
,
2615 GtkSelectionData
*selection_data
,
2619 /* printf ("drag_data_get\n"); */
2621 case DND_TARGET_TYPE_MOZILLA_URL
:
2622 case DND_TARGET_TYPE_TEXT_URI_LIST
:
2623 /* printf ("\ttext/uri-list\n"); */
2624 case DND_TARGET_TYPE_TEXT_HTML
:
2625 case DND_TARGET_TYPE_TEXT_PLAIN
:
2626 case DND_TARGET_TYPE_UTF8_STRING
:
2627 case DND_TARGET_TYPE_STRING
: {
2628 HTMLObject
*obj
= GTK_HTML (widget
)->priv
->dnd_real_object
;
2629 gint offset
= GTK_HTML (widget
)->priv
->dnd_real_object_offset
;
2630 const gchar
*url
, *target
;
2631 gchar
*complete_url
;
2633 /* printf ("\ttext/plain\n"); */
2635 /* printf ("obj %p\n", obj); */
2636 url
= html_object_get_url (obj
, offset
);
2637 target
= html_object_get_target (obj
, offset
);
2640 complete_url
= g_strconcat (url
, target
&& *target
? "#" : NULL
, target
, NULL
);
2642 if (info
== DND_TARGET_TYPE_MOZILLA_URL
) {
2643 /* MOZ_URL is in UTF-16 but in format 8. BROKEN!
2645 * The data contains the URL, a \n, then the
2646 * title of the web page.
2653 if (HTML_IS_TEXT (obj
)) {
2654 Link
*link
= html_text_get_link_at_offset (HTML_TEXT (obj
), offset
);
2657 g_return_if_fail (link
);
2658 text
= g_strndup (HTML_TEXT (obj
)->text
+ link
->start_index
, link
->end_index
- link
->start_index
);
2659 utf8
= g_strconcat (complete_url
, "\n", text
, NULL
);
2661 utf8
= g_strconcat (complete_url
, "\n", complete_url
, NULL
);
2663 utf16
= g_convert (utf8
, strlen (utf8
), "UTF-16", "UTF-8", NULL
, &written_len
, NULL
);
2664 atom
= gtk_selection_data_get_target (selection_data
);
2665 gtk_selection_data_set (selection_data
, atom
, 8,
2666 (guchar
*) utf16
, written_len
);
2668 g_free (complete_url
);
2669 GTK_HTML (widget
)->priv
->dnd_url
= utf16
;
2673 atom
= gtk_selection_data_get_target (selection_data
);
2674 gtk_selection_data_set (selection_data
, atom
, 8,
2675 (guchar
*) complete_url
, strlen (complete_url
));
2676 /* printf ("complete URL %s\n", complete_url); */
2677 GTK_HTML (widget
)->priv
->dnd_url
= complete_url
;
2687 drag_data_delete (GtkWidget
*widget
,
2688 GdkDragContext
*context
)
2690 g_free (GTK_HTML (widget
)->priv
->dnd_url
);
2691 GTK_HTML (widget
)->priv
->dnd_url
= NULL
;
2695 next_uri (guchar
**uri_list
,
2699 guchar
*uri
, *begin
;
2703 while (**uri_list
&& **uri_list
!= '\n' && **uri_list
!= '\r' && *list_len
) {
2709 uri
= (guchar
*) g_strndup ((gchar
*) begin
, *len
);
2711 while ((!**uri_list
|| **uri_list
== '\n' || **uri_list
== '\r') && *list_len
) {
2716 return (gchar
*) uri
;
2720 new_img_obj_from_uri (HTMLEngine
*e
,
2725 if (!strncmp (uri
, "file:", 5)) {
2726 if (!HTML_IS_PLAIN_PAINTER (e
->painter
)) {
2727 GdkPixbuf
*pixbuf
= NULL
;
2728 gchar
*img_path
= g_filename_from_uri (uri
, NULL
, NULL
);
2730 pixbuf
= gdk_pixbuf_new_from_file (img_path
, NULL
);
2734 g_object_unref (pixbuf
);
2735 return html_image_new (html_engine_get_image_factory (e
), uri
,
2736 NULL
, NULL
, -1, -1, FALSE
, FALSE
, 0,
2737 html_colorset_get_color (e
->settings
->color_set
, HTMLTextColor
),
2738 HTML_VALIGN_BOTTOM
, TRUE
);
2746 move_before_paste (GtkWidget
*widget
,
2750 HTMLEngine
*engine
= GTK_HTML (widget
)->engine
;
2752 if (html_engine_is_selection_active (engine
)) {
2756 obj
= html_engine_get_object_at (engine
, x
, y
, &offset
, FALSE
);
2757 if (!html_engine_point_in_selection (engine
, obj
, offset
)) {
2758 html_engine_disable_selection (engine
);
2759 html_engine_edit_selection_updater_update_now (engine
->selection_updater
);
2762 if (!html_engine_is_selection_active (engine
)) {
2764 html_engine_jump_at (engine
, x
, y
);
2765 gtk_html_update_styles (GTK_HTML (widget
));
2770 drag_data_received (GtkWidget
*widget
,
2771 GdkDragContext
*context
,
2774 GtkSelectionData
*selection_data
,
2778 HTMLEngine
*engine
= GTK_HTML (widget
)->engine
;
2779 GdkWindow
*bin_window
;
2780 gboolean pasted
= FALSE
;
2784 /* printf ("drag data received at %d,%d\n", x, y); */
2786 data
= gtk_selection_data_get_data (selection_data
);
2787 length
= gtk_selection_data_get_length (selection_data
);
2789 if (!data
|| length
< 0 || !html_engine_get_editable (engine
))
2792 bin_window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
2793 gdk_window_get_pointer (bin_window
, &x
, &y
, NULL
);
2794 move_before_paste (widget
, x
, y
);
2797 case DND_TARGET_TYPE_TEXT_PLAIN
:
2798 case DND_TARGET_TYPE_UTF8_STRING
:
2799 case DND_TARGET_TYPE_STRING
:
2800 case DND_TARGET_TYPE_TEXT_HTML
:
2801 clipboard_paste_received_cb (
2802 gtk_widget_get_clipboard (GTK_WIDGET (widget
), GDK_SELECTION_PRIMARY
),
2803 selection_data
, widget
);
2806 case DND_TARGET_TYPE_MOZILLA_URL
:
2808 case DND_TARGET_TYPE_TEXT_URI_LIST
:
2809 if (!HTML_IS_PLAIN_PAINTER (engine
->painter
)) {
2813 html_undo_level_begin (engine
->undo
, "Dropped URI(s)", "Remove Dropped URI(s)");
2816 uri
= next_uri ((guchar
**) &data
, &len
, &list_len
);
2817 obj
= new_img_obj_from_uri (engine
, uri
, NULL
, -1);
2819 html_engine_paste_object (engine
, obj
, html_object_get_length (obj
));
2823 html_undo_level_end (engine
->undo
, engine
);
2827 gtk_drag_finish (context
, pasted
, FALSE
, time
);
2831 drag_motion (GtkWidget
*widget
,
2832 GdkDragContext
*context
,
2838 GdkWindow
*bin_window
;
2840 if (!gtk_html_get_editable (GTK_HTML (widget
)))
2843 window
= gtk_widget_get_window (widget
);
2844 bin_window
= gtk_layout_get_bin_window (GTK_LAYOUT (widget
));
2845 gdk_window_get_pointer (bin_window
, &x
, &y
, NULL
);
2847 html_engine_disable_selection (GTK_HTML (widget
)->engine
);
2848 html_engine_jump_at (GTK_HTML (widget
)->engine
, x
, y
);
2849 html_engine_show_cursor (GTK_HTML (widget
)->engine
);
2851 mouse_change_pos (widget
, window
, x
, y
, 0);
2859 settings_key_theme_changed (GSettings
*settings
,
2861 GtkHTMLClass
*html_class
)
2865 key_theme
= g_settings_get_string (settings
, key
);
2866 html_class
->use_emacs_bindings
= (g_strcmp0 (key_theme
, "Emacs") == 0);
2871 settings_monospace_font_name_changed (GSettings
*settings
,
2875 if (html
->engine
!= NULL
&& html
->engine
->painter
!= NULL
) {
2876 gtk_html_set_fonts (html
, html
->engine
->painter
);
2877 html_engine_refresh_fonts (html
->engine
);
2882 settings_cursor_blink_changed (GSettings
*settings
,
2884 GtkHTMLClass
*html_class
)
2886 gint blink_time
= 0;
2888 if (g_settings_get_boolean (settings
, "cursor-blink"))
2889 blink_time
= g_settings_get_int (settings
, "cursor-blink-time");
2891 html_engine_set_cursor_blink_timeout (blink_time
/ 2);
2895 gtk_html_direction_changed (GtkWidget
*widget
,
2896 GtkTextDirection previous_dir
)
2898 GtkHTML
*html
= GTK_HTML (widget
);
2900 if (html
->engine
->clue
) {
2901 HTMLDirection old_direction
= html_object_get_direction (html
->engine
->clue
);
2903 switch (gtk_widget_get_direction (widget
)) {
2904 case GTK_TEXT_DIR_NONE
:
2905 HTML_CLUEV (html
->engine
->clue
)->dir
= HTML_DIRECTION_DERIVED
;
2907 case GTK_TEXT_DIR_LTR
:
2908 HTML_CLUEV (html
->engine
->clue
)->dir
= HTML_DIRECTION_LTR
;
2910 case GTK_TEXT_DIR_RTL
:
2911 HTML_CLUEV (html
->engine
->clue
)->dir
= HTML_DIRECTION_RTL
;
2915 if (old_direction
!= html_object_get_direction (html
->engine
->clue
))
2916 html_engine_schedule_update (html
->engine
);
2919 GTK_WIDGET_CLASS (parent_class
)->direction_changed (widget
, previous_dir
);
2923 gtk_html_class_init (GtkHTMLClass
*klass
)
2925 GObjectClass
*object_class
;
2926 GtkHTMLClass
*html_class
;
2927 GtkWidgetClass
*widget_class
;
2928 GtkContainerClass
*container_class
;
2930 GSettings
*settings
;
2932 g_type_class_add_private (klass
, sizeof (GtkHTMLPrivate
));
2934 html_class
= (GtkHTMLClass
*) klass
;
2935 object_class
= (GObjectClass
*) klass
;
2936 widget_class
= (GtkWidgetClass
*) klass
;
2937 container_class
= (GtkContainerClass
*) klass
;
2939 parent_class
= g_type_class_peek_parent (klass
);
2941 signals
[TITLE_CHANGED
] =
2942 g_signal_new ("title_changed",
2943 G_TYPE_FROM_CLASS (object_class
),
2945 G_STRUCT_OFFSET (GtkHTMLClass
, title_changed
),
2947 g_cclosure_marshal_VOID__STRING
,
2950 signals
[URL_REQUESTED
] =
2951 g_signal_new ("url_requested",
2952 G_TYPE_FROM_CLASS (object_class
),
2954 G_STRUCT_OFFSET (GtkHTMLClass
, url_requested
),
2956 html_g_cclosure_marshal_VOID__STRING_POINTER
,
2960 signals
[LOAD_DONE
] =
2961 g_signal_new ("load_done",
2962 G_TYPE_FROM_CLASS (object_class
),
2964 G_STRUCT_OFFSET (GtkHTMLClass
, load_done
),
2966 g_cclosure_marshal_VOID__VOID
,
2968 signals
[LINK_CLICKED
] =
2969 g_signal_new ("link_clicked",
2970 G_TYPE_FROM_CLASS (object_class
),
2972 G_STRUCT_OFFSET (GtkHTMLClass
, link_clicked
),
2974 g_cclosure_marshal_VOID__STRING
,
2978 g_signal_new ("set_base",
2979 G_TYPE_FROM_CLASS (object_class
),
2981 G_STRUCT_OFFSET (GtkHTMLClass
, set_base
),
2983 g_cclosure_marshal_VOID__STRING
,
2986 signals
[SET_BASE_TARGET
] =
2987 g_signal_new ("set_base_target",
2988 G_TYPE_FROM_CLASS (object_class
),
2990 G_STRUCT_OFFSET (GtkHTMLClass
, set_base_target
),
2992 g_cclosure_marshal_VOID__STRING
,
2997 g_signal_new ("on_url",
2998 G_TYPE_FROM_CLASS (object_class
),
3000 G_STRUCT_OFFSET (GtkHTMLClass
, on_url
),
3002 g_cclosure_marshal_VOID__STRING
,
3007 g_signal_new ("redirect",
3008 G_TYPE_FROM_CLASS (object_class
),
3010 G_STRUCT_OFFSET (GtkHTMLClass
, redirect
),
3012 html_g_cclosure_marshal_VOID__POINTER_INT
,
3018 g_signal_new ("submit",
3019 G_TYPE_FROM_CLASS (object_class
),
3021 G_STRUCT_OFFSET (GtkHTMLClass
, submit
),
3023 html_g_cclosure_marshal_VOID__STRING_STRING_STRING
,
3029 signals
[OBJECT_REQUESTED
] =
3030 g_signal_new ("object_requested",
3031 G_TYPE_FROM_CLASS (object_class
),
3033 G_STRUCT_OFFSET (GtkHTMLClass
, object_requested
),
3035 html_g_cclosure_marshal_BOOL__OBJECT
,
3039 signals
[CURRENT_PARAGRAPH_STYLE_CHANGED
] =
3040 g_signal_new ("current_paragraph_style_changed",
3041 G_TYPE_FROM_CLASS (object_class
),
3043 G_STRUCT_OFFSET (GtkHTMLClass
, current_paragraph_style_changed
),
3045 g_cclosure_marshal_VOID__INT
,
3049 signals
[CURRENT_PARAGRAPH_INDENTATION_CHANGED
] =
3050 g_signal_new ("current_paragraph_indentation_changed",
3051 G_TYPE_FROM_CLASS (object_class
),
3053 G_STRUCT_OFFSET (GtkHTMLClass
, current_paragraph_indentation_changed
),
3055 g_cclosure_marshal_VOID__INT
,
3059 signals
[CURRENT_PARAGRAPH_ALIGNMENT_CHANGED
] =
3060 g_signal_new ("current_paragraph_alignment_changed",
3061 G_TYPE_FROM_CLASS (object_class
),
3063 G_STRUCT_OFFSET (GtkHTMLClass
, current_paragraph_alignment_changed
),
3065 g_cclosure_marshal_VOID__INT
,
3069 signals
[INSERTION_FONT_STYLE_CHANGED
] =
3070 g_signal_new ("insertion_font_style_changed",
3071 G_TYPE_FROM_CLASS (object_class
),
3073 G_STRUCT_OFFSET (GtkHTMLClass
, insertion_font_style_changed
),
3075 g_cclosure_marshal_VOID__INT
,
3079 signals
[INSERTION_COLOR_CHANGED
] =
3080 g_signal_new ("insertion_color_changed",
3081 G_TYPE_FROM_CLASS (object_class
),
3083 G_STRUCT_OFFSET (GtkHTMLClass
, insertion_color_changed
),
3085 g_cclosure_marshal_VOID__POINTER
,
3089 signals
[SIZE_CHANGED
] =
3090 g_signal_new ("size_changed",
3091 G_TYPE_FROM_CLASS (object_class
),
3093 G_STRUCT_OFFSET (GtkHTMLClass
, size_changed
),
3095 g_cclosure_marshal_VOID__VOID
,
3097 signals
[IFRAME_CREATED
] =
3098 g_signal_new ("iframe_created",
3099 G_TYPE_FROM_CLASS (object_class
),
3101 G_STRUCT_OFFSET (GtkHTMLClass
, iframe_created
),
3103 g_cclosure_marshal_VOID__OBJECT
,
3108 g_signal_new ("scroll",
3109 G_TYPE_FROM_CLASS (object_class
),
3110 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
3111 G_STRUCT_OFFSET (GtkHTMLClass
, scroll
),
3113 html_g_cclosure_marshal_VOID__ENUM_ENUM_FLOAT
,
3115 GTK_TYPE_ORIENTATION
,
3116 GTK_TYPE_SCROLL_TYPE
, G_TYPE_FLOAT
);
3118 signals
[CURSOR_MOVE
] =
3119 g_signal_new ("cursor_move",
3120 G_TYPE_FROM_CLASS (object_class
),
3121 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
3122 G_STRUCT_OFFSET (GtkHTMLClass
, cursor_move
),
3124 html_g_cclosure_marshal_VOID__ENUM_ENUM
,
3125 G_TYPE_NONE
, 2, GTK_TYPE_DIRECTION_TYPE
, GTK_TYPE_HTML_CURSOR_SKIP
);
3128 g_signal_new ("command",
3129 G_TYPE_FROM_CLASS (object_class
),
3130 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
3131 G_STRUCT_OFFSET (GtkHTMLClass
, command
),
3133 html_g_cclosure_marshal_BOOL__ENUM
,
3134 G_TYPE_BOOLEAN
, 1, GTK_TYPE_HTML_COMMAND
);
3136 signals
[CURSOR_CHANGED
] =
3137 g_signal_new ("cursor_changed",
3138 G_TYPE_FROM_CLASS (object_class
),
3140 G_STRUCT_OFFSET (GtkHTMLClass
, cursor_changed
),
3142 g_cclosure_marshal_VOID__VOID
,
3145 signals
[OBJECT_INSERTED
] =
3146 g_signal_new ("object_inserted",
3147 G_TYPE_FROM_CLASS (object_class
),
3149 G_STRUCT_OFFSET (GtkHTMLClass
, object_inserted
),
3151 html_g_cclosure_marshal_VOID__INT_INT
,
3153 G_TYPE_INT
, G_TYPE_INT
);
3155 signals
[OBJECT_DELETE
] =
3156 g_signal_new ("object_delete",
3157 G_TYPE_FROM_CLASS (object_class
),
3159 G_STRUCT_OFFSET (GtkHTMLClass
, object_delete
),
3161 html_g_cclosure_marshal_VOID__INT_INT
,
3163 G_TYPE_INT
, G_TYPE_INT
);
3164 object_class
->dispose
= dispose
;
3167 object_class
->get_property
= gtk_html_get_property
;
3168 object_class
->set_property
= gtk_html_set_property
;
3170 g_object_class_install_property (object_class
,
3172 g_param_spec_boolean ("editable",
3174 "Whether the html can be edited",
3176 G_PARAM_READABLE
| G_PARAM_WRITABLE
));
3177 g_object_class_install_property (object_class
,
3179 g_param_spec_string ("title",
3181 "The title of the current document",
3183 G_PARAM_WRITABLE
| G_PARAM_READABLE
));
3184 g_object_class_install_property (object_class
,
3186 g_param_spec_string ("document_base",
3188 "The base URL for relative references",
3190 G_PARAM_WRITABLE
| G_PARAM_READABLE
));
3191 g_object_class_install_property (object_class
,
3193 g_param_spec_string ("target_base",
3195 "The base URL of the target frame",
3197 G_PARAM_WRITABLE
| G_PARAM_READABLE
));
3201 gtk_widget_class_install_style_property (widget_class
,
3202 g_param_spec_string ("fixed_font_name",
3204 "The Monospace font to use for typewriter text",
3208 gtk_widget_class_install_style_property (widget_class
,
3209 g_param_spec_boxed ("link_color",
3211 "The color of new link elements",
3214 gtk_widget_class_install_style_property (widget_class
,
3215 g_param_spec_boxed ("vlink_color",
3216 "Visited Link Color",
3217 "The color of visited link elements",
3220 gtk_widget_class_install_style_property (widget_class
,
3221 g_param_spec_boxed ("alink_color",
3222 "Active Link Color",
3223 "The color of active link elements",
3226 gtk_widget_class_install_style_property (widget_class
,
3227 g_param_spec_boxed ("spell_error_color",
3228 "Spelling Error Color",
3229 "The color of the spelling error markers",
3232 gtk_widget_class_install_style_property (widget_class
,
3233 g_param_spec_boxed ("cite_color",
3234 "Cite Quotation Color",
3235 "The color of the cited text",
3239 widget_class
->realize
= realize
;
3240 widget_class
->unrealize
= unrealize
;
3241 widget_class
->style_updated
= style_updated
;
3242 widget_class
->key_press_event
= key_press_event
;
3243 widget_class
->key_release_event
= key_release_event
;
3244 widget_class
->draw
= draw
;
3245 widget_class
->get_preferred_width
= gtk_html_get_preferred_width
;
3246 widget_class
->get_preferred_height
= gtk_html_get_preferred_height
;
3247 widget_class
->size_allocate
= size_allocate
;
3248 widget_class
->motion_notify_event
= motion_notify_event
;
3249 widget_class
->visibility_notify_event
= visibility_notify_event
;
3250 widget_class
->hierarchy_changed
= hierarchy_changed
;
3251 widget_class
->button_press_event
= button_press_event
;
3252 widget_class
->button_release_event
= button_release_event
;
3253 widget_class
->focus_in_event
= focus_in_event
;
3254 widget_class
->focus_out_event
= focus_out_event
;
3255 widget_class
->enter_notify_event
= enter_notify_event
;
3256 widget_class
->drag_data_get
= drag_data_get
;
3257 widget_class
->drag_data_delete
= drag_data_delete
;
3258 widget_class
->drag_begin
= drag_begin
;
3259 widget_class
->drag_end
= drag_end
;
3260 widget_class
->drag_data_received
= drag_data_received
;
3261 widget_class
->drag_motion
= drag_motion
;
3262 widget_class
->focus
= focus
;
3263 widget_class
->direction_changed
= gtk_html_direction_changed
;
3265 container_class
->set_focus_child
= set_focus_child
;
3267 html_class
->scroll
= scroll
;
3268 html_class
->cursor_move
= cursor_move
;
3269 html_class
->command
= command
;
3270 html_class
->properties
= gtk_html_class_properties_new ();
3272 add_bindings (klass
);
3273 gtk_widget_class_set_accessible_type (widget_class
, G_TYPE_GTK_HTML_A11Y
);
3275 filename
= g_build_filename (PREFIX
, "share", GTKHTML_RELEASE_STRING
, "keybindingsrc.emacs", NULL
);
3276 gtk_rc_parse (filename
);
3278 html_class
->emacs_bindings
= gtk_binding_set_find ("gtkhtml-bindings-emacs");
3280 /* XXX We leak this GSettings reference but...
3281 * meh, GtkHTML will be orphaned soon. */
3282 settings
= g_settings_new ("org.gnome.desktop.interface");
3284 settings_key_theme_changed (settings
, "gtk-key-theme", html_class
);
3287 settings
, "changed::gtk-key-theme",
3288 G_CALLBACK (settings_key_theme_changed
), html_class
);
3291 settings
, "changed::cursor-blink",
3292 G_CALLBACK (settings_cursor_blink_changed
), html_class
);
3294 settings
, "changed::cursor-blink-time",
3295 G_CALLBACK (settings_cursor_blink_changed
), html_class
);
3297 settings_cursor_blink_changed (settings
, "cursor-blink", html_class
);
3301 gtk_html_im_reset (GtkHTML
*html
)
3303 if (!html
->priv
->im_block_reset
) {
3304 D_IM (printf ("IM reset requested\n");)
3305 if (html
->priv
->need_im_reset
) {
3306 if (html
->engine
->freeze_count
== 1)
3307 html_engine_thaw_idle_flush (html
->engine
);
3308 html
->priv
->need_im_reset
= FALSE
;
3309 gtk_im_context_reset (html
->priv
->im_context
);
3310 D_IM (printf ("IM reset called\n");)
3316 gtk_html_im_commit_cb (GtkIMContext
*context
,
3320 gboolean state
= html
->priv
->im_block_reset
;
3323 html
->priv
->im_block_reset
= TRUE
;
3325 if (html
->priv
->im_pre_len
> 0) {
3326 D_IM (printf ("IM delete last preedit %d + %d\n", html
->priv
->im_pre_pos
, html
->priv
->im_pre_len
);)
3328 html_undo_freeze (html
->engine
->undo
);
3329 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, html
->priv
->im_pre_pos
);
3330 html_engine_set_mark (html
->engine
);
3331 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, html
->priv
->im_pre_pos
+ html
->priv
->im_pre_len
);
3332 html_engine_delete (html
->engine
);
3333 html
->priv
->im_pre_len
= 0;
3334 html_undo_thaw (html
->engine
->undo
);
3337 pos
= html
->engine
->cursor
->position
;
3338 if (html
->engine
->mark
&& html
->engine
->mark
->position
> pos
)
3339 pos
= html
->engine
->mark
->position
;
3341 D_IM (printf ("IM commit %s\n", str
);)
3342 html_engine_paste_text (html
->engine
, str
, g_utf8_strlen (str
, -1));
3343 html
->priv
->im_block_reset
= state
;
3345 D_IM (printf ("IM commit pos: %d pre_pos: %d\n", pos
, html
->priv
->im_pre_pos
);)
3346 if (html
->priv
->im_pre_pos
>= pos
)
3347 html
->priv
->im_pre_pos
+= html
->engine
->cursor
->position
- pos
;
3351 gtk_html_im_preedit_start_cb (GtkIMContext
*context
,
3354 html
->priv
->im_pre_len
= 0;
3358 gtk_html_im_preedit_changed_cb (GtkIMContext
*context
,
3361 PangoAttrList
*attrs
;
3362 gchar
*preedit_string
;
3363 gint cursor_pos
, initial_position
;
3364 gboolean state
= html
->priv
->im_block_reset
;
3365 gboolean pop_selection
= FALSE
;
3368 D_IM (printf ("IM preedit changed cb [begin] cursor %d(%p) mark %d(%p) active: %d\n",
3369 html
->engine
->cursor
? html
->engine
->cursor
->position
: 0, html
->engine
->cursor
,
3370 html
->engine
->mark
? html
->engine
->mark
->position
: 0, html
->engine
->mark
,
3371 html_engine_is_selection_active (html
->engine
));)
3373 if (!html
->engine
->cursor
) {
3377 html
->priv
->im_block_reset
= TRUE
;
3379 if (html
->engine
->mark
&& html_engine_is_selection_active (html
->engine
)) {
3380 D_IM (printf ("IM push selection\n");)
3381 html_engine_selection_push (html
->engine
);
3382 html_engine_disable_selection (html
->engine
);
3383 html_engine_edit_selection_updater_update_now (html
->engine
->selection_updater
);
3384 pop_selection
= TRUE
;
3386 initial_position
= html
->engine
->cursor
->position
;
3387 D_IM (printf ("IM initial position %d\n", initial_position
);)
3389 html_undo_freeze (html
->engine
->undo
);
3391 if (html
->priv
->im_pre_len
> 0) {
3392 D_IM (printf ("IM delete last preedit %d + %d\n", html
->priv
->im_pre_pos
, html
->priv
->im_pre_len
);)
3394 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, html
->priv
->im_pre_pos
);
3395 html_engine_set_mark (html
->engine
);
3396 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, html
->priv
->im_pre_pos
+ html
->priv
->im_pre_len
);
3397 html_engine_delete (html
->engine
);
3398 deleted
= html
->priv
->im_pre_len
;
3400 html
->priv
->im_orig_style
= html_engine_get_font_style (html
->engine
);
3402 gtk_im_context_get_preedit_string (html
->priv
->im_context
, &preedit_string
, &attrs
, &cursor_pos
);
3404 D_IM (printf ("IM preedit changed to %s\n", preedit_string
);)
3405 html
->priv
->im_pre_len
= g_utf8_strlen (preedit_string
, -1);
3407 if (html
->priv
->im_pre_len
> 0) {
3408 cursor_pos
= CLAMP (cursor_pos
, 0, html
->priv
->im_pre_len
);
3409 html
->priv
->im_pre_pos
= html
->engine
->cursor
->position
;
3410 html_engine_paste_text_with_extra_attributes (html
->engine
, preedit_string
, html
->priv
->im_pre_len
, attrs
);
3411 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, html
->priv
->im_pre_pos
+ cursor_pos
);
3413 html_engine_set_font_style (html
->engine
, 0, html
->priv
->im_orig_style
);
3414 g_free (preedit_string
);
3416 if (pop_selection
) {
3417 gint position
= html
->engine
->cursor
->position
, cpos
, mpos
;
3418 D_IM (printf ("IM pop selection\n");)
3419 g_assert (html_engine_selection_stack_top (html
->engine
, &cpos
, &mpos
));
3420 if (position
< MAX (cpos
, mpos
) + html
->priv
->im_pre_len
- deleted
)
3421 g_assert (html_engine_selection_stack_top_modify (html
->engine
, html
->priv
->im_pre_len
- deleted
));
3422 html_engine_selection_pop (html
->engine
);
3424 /* that works for now, but idealy we should be able to have cursor positioned outside selection, so that preedit
3425 * cursor is in the right place */
3426 if (html
->priv
->im_pre_len
== 0)
3427 html_cursor_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
,
3428 initial_position
>= html
->priv
->im_pre_pos
+ deleted
? initial_position
- deleted
: initial_position
);
3430 if (html
->engine
->freeze_count
== 1)
3431 html_engine_thaw_idle_flush (html
->engine
);
3432 /* FIXME gtk_im_context_set_cursor_location (im_context, &area); */
3433 html
->priv
->im_block_reset
= state
;
3435 html_undo_thaw (html
->engine
->undo
);
3437 D_IM (printf ("IM preedit changed cb [end] cursor %d(%p) mark %d(%p) active: %d\n",
3438 html
->engine
->cursor
? html
->engine
->cursor
->position
: 0, html
->engine
->cursor
,
3439 html
->engine
->mark
? html
->engine
->mark
->position
: 0, html
->engine
->mark
,
3440 html_engine_is_selection_active (html
->engine
));)
3444 get_surrounding_text (HTMLEngine
*e
,
3447 HTMLObject
*o
= e
->cursor
->object
;
3451 if (!html_object_is_text (o
)) {
3453 if (e
->cursor
->offset
== 0) {
3454 prev
= html_object_prev_not_slave (o
);
3455 if (html_object_is_text (prev
)) {
3459 } else if (e
->cursor
->offset
== html_object_get_length (e
->cursor
->object
)) {
3462 next
= html_object_next_not_slave (o
);
3463 if (html_object_is_text (next
)) {
3469 *offset
= e
->cursor
->offset
;
3471 while ((prev
= html_object_prev_not_slave (o
)) && html_object_is_text (prev
)) {
3473 *offset
+= HTML_TEXT (o
)->text_len
;
3477 if (html_object_is_text (o
)) {
3479 text
= g_strdup (HTML_TEXT (o
)->text
);
3481 gchar
*concat
= g_strconcat (text
, HTML_TEXT (o
)->text
, NULL
);
3486 o
= html_object_next_not_slave (o
);
3493 gtk_html_im_retrieve_surrounding_cb (GtkIMContext
*context
,
3499 D_IM (printf ("IM gtk_html_im_retrieve_surrounding_cb\n");)
3501 text
= get_surrounding_text (html
->engine
, &offset
);
3503 /* convert gchar offset to byte offset */
3504 offset
= g_utf8_offset_to_pointer (text
, offset
) - text
;
3505 gtk_im_context_set_surrounding (context
, text
, -1, offset
);
3508 gtk_im_context_set_surrounding (context
, NULL
, 0, 0);
3514 gtk_html_im_delete_surrounding_cb (GtkIMContext
*slave
,
3519 D_IM (printf ("IM gtk_html_im_delete_surrounding_cb\n");)
3520 if (html_engine_get_editable (html
->engine
) && !html_engine_is_selection_active (html
->engine
)) {
3521 gint orig_position
= html
->engine
->cursor
->position
;
3523 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, orig_position
+ offset
);
3524 html_engine_set_mark (html
->engine
);
3525 html_cursor_exactly_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, orig_position
+ offset
+ n_chars
);
3526 html_engine_delete (html
->engine
);
3528 orig_position
-= MIN (n_chars
, - offset
);
3529 html_cursor_jump_to_position_no_spell (html
->engine
->cursor
, html
->engine
, orig_position
);
3535 gtk_html_init (GtkHTML
*html
)
3537 GSettings
*settings
;
3539 gtk_widget_set_can_focus (GTK_WIDGET (html
), TRUE
);
3540 gtk_widget_set_app_paintable (GTK_WIDGET (html
), TRUE
);
3541 gtk_widget_set_double_buffered (GTK_WIDGET (html
), TRUE
);
3543 html
->editor_api
= NULL
;
3544 html
->debug
= FALSE
;
3545 html
->allow_selection
= TRUE
;
3547 html
->pointer_url
= NULL
;
3548 html
->hand_cursor
= gdk_cursor_new (GDK_HAND2
);
3549 html
->ibeam_cursor
= gdk_cursor_new (GDK_XTERM
);
3550 html
->hadj_connection
= 0;
3551 html
->vadj_connection
= 0;
3553 html
->selection_x1
= 0;
3554 html
->selection_y1
= 0;
3556 html
->in_selection
= FALSE
;
3557 html
->in_selection_drag
= FALSE
;
3559 html
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (
3560 html
, GTK_TYPE_HTML
, GtkHTMLPrivate
);
3562 html
->priv
->idle_handler_id
= 0;
3563 html
->priv
->scroll_timeout_id
= 0;
3564 html
->priv
->skip_update_cursor
= FALSE
;
3565 html
->priv
->cursor_moved
= FALSE
;
3566 html
->priv
->paragraph_style
= GTK_HTML_PARAGRAPH_STYLE_NORMAL
;
3567 html
->priv
->paragraph_alignment
= GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT
;
3568 html
->priv
->paragraph_indentation
= 0;
3569 html
->priv
->insertion_font_style
= GTK_HTML_FONT_STYLE_DEFAULT
;
3570 html
->priv
->selection_type
= -1;
3571 html
->priv
->selection_as_cite
= FALSE
;
3572 html
->priv
->search_input_line
= NULL
;
3573 html
->priv
->in_object_resize
= FALSE
;
3574 html
->priv
->resize_cursor
= gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER
);
3575 html
->priv
->in_url_test_mode
= FALSE
;
3576 html
->priv
->in_key_binding
= FALSE
;
3578 html
->priv
->caret_first_focus_anchor
= NULL
;
3579 html
->priv
->is_first_focus
= TRUE
;
3581 html
->priv
->hadjustment
= NULL
;
3582 html
->priv
->vadjustment
= NULL
;
3585 html
->priv
->im_context
= gtk_im_multicontext_new ();
3586 html
->priv
->need_im_reset
= FALSE
;
3587 html
->priv
->im_block_reset
= FALSE
;
3588 html
->priv
->im_pre_len
= 0;
3591 html
, "notify::hadjustment",
3592 G_CALLBACK (hadjustment_notify_cb
), NULL
);
3595 html
, "notify::vadjustment",
3596 G_CALLBACK (vadjustment_notify_cb
), NULL
);
3599 html
->priv
->im_context
, "commit",
3600 G_CALLBACK (gtk_html_im_commit_cb
), html
);
3603 html
->priv
->im_context
, "preedit_start",
3604 G_CALLBACK (gtk_html_im_preedit_start_cb
), html
);
3607 html
->priv
->im_context
, "preedit_changed",
3608 G_CALLBACK (gtk_html_im_preedit_changed_cb
), html
);
3611 html
->priv
->im_context
, "retrieve_surrounding",
3612 G_CALLBACK (gtk_html_im_retrieve_surrounding_cb
), html
);
3615 html
->priv
->im_context
, "delete_surrounding",
3616 G_CALLBACK (gtk_html_im_delete_surrounding_cb
), html
);
3618 settings
= g_settings_new ("org.gnome.desktop.interface");
3621 settings
, "changed::monospace-font-name",
3622 G_CALLBACK (settings_monospace_font_name_changed
), html
);
3624 /* The signal is disconnected and the GSettings
3625 * object unreferenced in our dispose() method. */
3626 html
->priv
->desktop_interface
= settings
;
3628 gtk_html_construct (html
);
3632 gtk_html_get_type (void)
3634 static GType html_type
= 0;
3637 static const GTypeInfo html_info
= {
3638 sizeof (GtkHTMLClass
),
3639 NULL
, /* base_init */
3640 NULL
, /* base_finalize */
3641 (GClassInitFunc
) gtk_html_class_init
,
3642 NULL
, /* class_finalize */
3643 NULL
, /* class_data */
3645 1, /* n_preallocs */
3646 (GInstanceInitFunc
) gtk_html_init
,
3649 html_type
= g_type_register_static (GTK_TYPE_LAYOUT
, "GtkHTML", &html_info
, 0);
3659 * GtkHTML widget contructor. It creates an empty GtkHTML widget.
3661 * Return value: A GtkHTML widget, newly created and empty.
3669 html
= g_object_new (GTK_TYPE_HTML
, NULL
);
3675 * gtk_html_new_from_string:
3676 * @str: A string containing HTML source.
3677 * @len: A length of @str, if @len == -1 then it will be computed using strlen.
3679 * GtkHTML widget constructor. It creates an new GtkHTML widget and loads HTML source from @str.
3680 * It is intended for simple creation. For more complicated loading you probably want to use
3681 * #GtkHTMLStream. See #gtk_html_begin.
3683 * Return value: A GtkHTML widget, newly created, containing document loaded from input @str.
3687 gtk_html_new_from_string (const gchar
*str
,
3692 html
= g_object_new (GTK_TYPE_HTML
, NULL
);
3693 gtk_html_load_from_string (GTK_HTML (html
), str
, len
);
3699 gtk_html_construct (GtkHTML
*html
)
3701 g_return_if_fail (html
!= NULL
);
3702 g_return_if_fail (GTK_IS_HTML (html
));
3704 html
->engine
= html_engine_new (GTK_WIDGET (html
));
3705 html
->iframe_parent
= NULL
;
3707 g_signal_connect (G_OBJECT (html
->engine
), "title_changed",
3708 G_CALLBACK (html_engine_title_changed_cb
), html
);
3709 g_signal_connect (G_OBJECT (html
->engine
), "set_base",
3710 G_CALLBACK (html_engine_set_base_cb
), html
);
3711 g_signal_connect (G_OBJECT (html
->engine
), "set_base_target",
3712 G_CALLBACK (html_engine_set_base_target_cb
), html
);
3713 g_signal_connect (G_OBJECT (html
->engine
), "load_done",
3714 G_CALLBACK (html_engine_load_done_cb
), html
);
3715 g_signal_connect (G_OBJECT (html
->engine
), "url_requested",
3716 G_CALLBACK (html_engine_url_requested_cb
), html
);
3717 g_signal_connect (G_OBJECT (html
->engine
), "draw_pending",
3718 G_CALLBACK (html_engine_draw_pending_cb
), html
);
3719 g_signal_connect (G_OBJECT (html
->engine
), "redirect",
3720 G_CALLBACK (html_engine_redirect_cb
), html
);
3721 g_signal_connect (G_OBJECT (html
->engine
), "submit",
3722 G_CALLBACK (html_engine_submit_cb
), html
);
3723 g_signal_connect (G_OBJECT (html
->engine
), "object_requested",
3724 G_CALLBACK (html_engine_object_requested_cb
), html
);
3729 gtk_html_enable_debug (GtkHTML
*html
,
3732 g_return_if_fail (html
!= NULL
);
3733 g_return_if_fail (GTK_IS_HTML (html
));
3735 html
->debug
= debug
;
3740 gtk_html_allow_selection (GtkHTML
*html
,
3743 g_return_if_fail (html
!= NULL
);
3744 g_return_if_fail (GTK_IS_HTML (html
));
3746 html
->allow_selection
= allow
;
3750 * gtk_html_begin_full:
3751 * @html: the GtkHTML widget to operate on.
3752 * @target_frame: the string identifying the frame to load the data into
3753 * @content_type: the content_type of the data that we will be loading
3754 * @flags: the GtkHTMLBeginFlags that control the reload behavior handling
3756 * Opens a new stream of type @content_type to the frame named @target_frame.
3757 * the flags in @flags allow control over what data is reloaded.
3759 * Returns: a new GtkHTMLStream to specified frame
3762 gtk_html_begin_full (GtkHTML
*html
,
3763 gchar
*target_frame
,
3764 const gchar
*content_type
,
3765 GtkHTMLBeginFlags flags
)
3767 GtkHTMLStream
*handle
;
3769 g_return_val_if_fail (!gtk_html_get_editable (html
), NULL
);
3771 if (flags
& GTK_HTML_BEGIN_BLOCK_UPDATES
)
3772 gtk_html_set_blocking (html
, TRUE
);
3774 gtk_html_set_blocking (html
, FALSE
);
3776 if (flags
& GTK_HTML_BEGIN_BLOCK_IMAGES
)
3777 gtk_html_set_images_blocking (html
, TRUE
);
3779 gtk_html_set_images_blocking (html
, FALSE
);
3781 if (flags
& GTK_HTML_BEGIN_KEEP_IMAGES
)
3782 gtk_html_images_ref (html
);
3784 if (flags
& GTK_HTML_BEGIN_KEEP_SCROLL
)
3785 html
->engine
->keep_scroll
= TRUE
;
3787 html
->engine
->keep_scroll
= FALSE
;
3789 html
->priv
->is_first_focus
= TRUE
;
3791 handle
= html_engine_begin (html
->engine
, content_type
);
3795 html_engine_parse (html
->engine
);
3797 if (flags
& GTK_HTML_BEGIN_KEEP_IMAGES
)
3798 gtk_html_images_unref (html
);
3800 if (flags
& GTK_HTML_BEGIN_KEEP_SCROLL
)
3801 html
->engine
->newPage
= FALSE
;
3803 /* Enable change content type in engine */
3804 if (flags
& GTK_HTML_BEGIN_CHANGECONTENTTYPE
)
3805 gtk_html_set_default_engine (html
, TRUE
);
3812 * @html: the html widget to operate on.
3814 * Opens a new stream to load new content into the GtkHTML widget @html.
3816 * Returns: a new GtkHTMLStream to store new content.
3819 gtk_html_begin (GtkHTML
*html
)
3821 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
3823 return gtk_html_begin_full (html
, NULL
, NULL
, 0);
3827 * gtk_html_begin_content:
3828 * @html: the html widget to operate on.
3829 * @content_type: a string listing the type of content to expect on the stream.
3831 * Opens a new stream to load new content of type @content_type into
3832 * the GtkHTML widget given in @html.
3834 * Returns: a new GtkHTMLStream to store new content.
3837 gtk_html_begin_content (GtkHTML
*html
,
3838 const gchar
*content_type
)
3840 g_return_val_if_fail (!gtk_html_get_editable (html
), NULL
);
3842 return gtk_html_begin_full (html
, NULL
, content_type
, 0);
3847 * @html: the GtkHTML widget the stream belongs to (unused)
3848 * @handle: the GkHTMLStream to write to.
3849 * @buffer: the data to write to the stream.
3850 * @size: the length of data to read from @buffer
3852 * Writes @size bytes of @buffer to the stream pointed to by @stream.
3855 gtk_html_write (GtkHTML
*html
,
3856 GtkHTMLStream
*handle
,
3857 const gchar
*buffer
,
3860 gtk_html_stream_write (handle
, buffer
, size
);
3865 * @html: the GtkHTML widget the stream belongs to.
3866 * @handle: the GtkHTMLStream to close.
3867 * @status: the GtkHTMLStreamStatus representing the state of the stream when closed.
3869 * Close the GtkHTMLStream represented by @stream and notify @html that is
3870 * should not expect any more content from that stream.
3873 gtk_html_end (GtkHTML
*html
,
3874 GtkHTMLStream
*handle
,
3875 GtkHTMLStreamStatus status
)
3877 gtk_html_stream_close (handle
, status
);
3882 * @html: the GtkHTML widget.
3884 * Stop requesting any more data by url_requested signal.
3887 gtk_html_stop (GtkHTML
*html
)
3889 g_return_if_fail (GTK_IS_HTML (html
));
3891 html_engine_stop (html
->engine
);
3896 * gtk_html_get_title:
3897 * @html: The GtkHTML widget.
3899 * Retrieve the title of the document currently loaded in the GtkHTML widget.
3901 * Returns: the title of the current document
3904 gtk_html_get_title (GtkHTML
*html
)
3906 g_return_val_if_fail (html
!= NULL
, NULL
);
3907 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
3909 if (html
->engine
->title
== NULL
)
3912 return html
->engine
->title
->str
;
3916 * gtk_html_set_title:
3917 * @html: The GtkHTML widget.
3919 * Set the title of the document currently loaded in the GtkHTML widget.
3923 gtk_html_set_title (GtkHTML
*html
,
3926 g_return_if_fail (html
!= NULL
);
3927 g_return_if_fail (GTK_IS_HTML (html
));
3929 html_engine_set_title (html
->engine
, title
);
3934 * gtk_html_jump_to_anchor:
3935 * @html: the GtkHTML widget.
3936 * @anchor: a string containing the name of the anchor.
3938 * Scroll the document display to show the HTML anchor listed in @anchor
3940 * Returns: TRUE if the anchor is found, FALSE otherwise.
3943 gtk_html_jump_to_anchor (GtkHTML
*html
,
3944 const gchar
*anchor
)
3946 g_return_val_if_fail (html
!= NULL
, FALSE
);
3947 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
3949 return html_engine_goto_anchor (html
->engine
, anchor
);
3954 gtk_html_save (GtkHTML
*html
,
3955 GtkHTMLSaveReceiverFn receiver
,
3958 g_return_val_if_fail (html
!= NULL
, FALSE
);
3959 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
3960 g_return_val_if_fail (receiver
!= NULL
, FALSE
);
3962 return html_engine_save (html
->engine
, receiver
, data
);
3967 * @html: the GtkHTML widget
3968 * @content_type: the expected content_type
3970 * @user_data: pointer to maintain user state.
3972 * Export the current document into the content type given by @content_type,
3973 * by calling the function listed in @receiver data becomes avaiable. When @receiver is
3974 * called @user_data is passed in as the user_data parameter.
3976 * Returns: TRUE if the export was successful, FALSE otherwise.
3979 gtk_html_export (GtkHTML
*html
,
3980 const gchar
*content_type
,
3981 GtkHTMLSaveReceiverFn receiver
,
3984 g_return_val_if_fail (html
!= NULL
, FALSE
);
3985 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
3986 g_return_val_if_fail (receiver
!= NULL
, FALSE
);
3988 if (strcmp (content_type
, "text/html") == 0) {
3989 return html_engine_save (html
->engine
, receiver
, user_data
);
3990 } else if (strcmp (content_type
, "text/plain") == 0) {
3991 return html_engine_save_plain (html
->engine
, receiver
,
4001 gtk_html_update_scrollbars_on_resize (GtkHTML
*html
,
4002 gdouble old_doc_width
,
4003 gdouble old_doc_height
,
4006 gboolean
*changed_x
,
4007 gboolean
*changed_y
)
4009 GtkAdjustment
*vadj
, *hadj
;
4010 gdouble doc_width
, doc_height
;
4012 /* printf ("update on resize\n"); */
4014 hadj
= gtk_layout_get_hadjustment (GTK_LAYOUT (html
));
4015 vadj
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
4017 doc_height
= html_engine_get_doc_height (html
->engine
);
4018 doc_width
= html_engine_get_doc_width (html
->engine
);
4020 if (!html
->engine
->keep_scroll
) {
4021 if (old_doc_width
- old_width
> 0) {
4024 value
= gtk_adjustment_get_value (hadj
);
4025 html
->engine
->x_offset
= (gint
) (value
* (doc_width
- html
->engine
->width
)
4026 / (old_doc_width
- old_width
));
4028 gtk_adjustment_set_value (hadj
, html
->engine
->x_offset
);
4031 if (old_doc_height
- old_height
> 0) {
4034 value
= gtk_adjustment_get_value (vadj
);
4035 html
->engine
->y_offset
= (gint
) (value
* (doc_height
- html
->engine
->height
)
4036 / (old_doc_height
- old_height
));
4037 gtk_adjustment_set_value (vadj
, html
->engine
->y_offset
);
4043 gtk_html_private_calc_scrollbars (GtkHTML
*html
,
4044 gboolean
*changed_x
,
4045 gboolean
*changed_y
)
4048 GtkAdjustment
*vadj
, *hadj
;
4049 guint layout_width
, layout_height
;
4053 if (!gtk_widget_get_realized (GTK_WIDGET (html
)))
4056 /* printf ("calc scrollbars\n"); */
4058 height
= html_engine_get_doc_height (html
->engine
);
4059 width
= html_engine_get_doc_width (html
->engine
);
4061 layout
= GTK_LAYOUT (html
);
4062 hadj
= gtk_layout_get_hadjustment (layout
);
4063 vadj
= gtk_layout_get_vadjustment (layout
);
4065 gtk_adjustment_set_page_size (vadj
, html
->engine
->height
);
4066 gtk_adjustment_set_step_increment (vadj
, 14); /* FIXME */
4067 gtk_adjustment_set_page_increment (vadj
, html
->engine
->height
);
4069 value
= gtk_adjustment_get_value (vadj
);
4070 if (value
> height
- html
->engine
->height
) {
4071 gtk_adjustment_set_value (vadj
, height
- html
->engine
->height
);
4076 gtk_adjustment_set_page_size (hadj
, html
->engine
->width
);
4077 gtk_adjustment_set_step_increment (hadj
, 14); /* FIXME */
4078 gtk_adjustment_set_page_increment (hadj
, html
->engine
->width
);
4080 gtk_layout_get_size (layout
, &layout_width
, &layout_height
);
4081 if ((width
!= layout_width
) || (height
!= layout_height
)) {
4082 g_signal_emit (html
, signals
[SIZE_CHANGED
], 0);
4083 gtk_layout_set_size (layout
, width
, height
);
4086 value
= gtk_adjustment_get_value (hadj
);
4087 if (value
> width
- html
->engine
->width
|| value
> MAX_WIDGET_WIDTH
- html
->engine
->width
) {
4088 gtk_adjustment_set_value (hadj
, MIN (width
- html
->engine
->width
, MAX_WIDGET_WIDTH
- html
->engine
->width
));
4099 gtk_html_set_property (GObject
*object
,
4101 const GValue
*value
,
4104 GtkHTML
*html
= GTK_HTML (object
);
4108 gtk_html_set_editable (html
, g_value_get_boolean (value
));
4111 gtk_html_set_title (html
, g_value_get_string (value
));
4113 case PROP_DOCUMENT_BASE
:
4114 gtk_html_set_base (html
, g_value_get_string (value
));
4116 case PROP_TARGET_BASE
:
4117 /* This doesn't do anything yet */
4120 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
4126 gtk_html_get_property (GObject
*object
,
4131 GtkHTML
*html
= GTK_HTML (object
);
4135 g_value_set_boolean (value
, gtk_html_get_editable (html
));
4138 g_value_set_static_string (value
, gtk_html_get_title (html
));
4140 case PROP_DOCUMENT_BASE
:
4141 g_value_set_static_string (value
, gtk_html_get_base (html
));
4143 case PROP_TARGET_BASE
:
4144 g_value_set_static_string (value
, gtk_html_get_base (html
));
4147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
4154 gtk_html_set_editable (GtkHTML
*html
,
4157 g_return_if_fail (html
!= NULL
);
4158 g_return_if_fail (GTK_IS_HTML (html
));
4160 html_engine_set_editable (html
->engine
, editable
);
4163 gtk_html_update_styles (html
);
4167 gtk_html_get_editable (const GtkHTML
*html
)
4169 g_return_val_if_fail (html
!= NULL
, FALSE
);
4170 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4172 return html_engine_get_editable (html
->engine
);
4176 gtk_html_set_inline_spelling (GtkHTML
*html
,
4177 gboolean inline_spell
)
4179 g_return_if_fail (html
!= NULL
);
4180 g_return_if_fail (GTK_IS_HTML (html
));
4182 html
->priv
->inline_spelling
= inline_spell
;
4184 /* do not update content, when there is none set (yet) */
4185 if (!html
->engine
|| !html
->engine
->clue
)
4188 if (gtk_html_get_editable (html
) && html
->priv
->inline_spelling
)
4189 html_engine_spell_check (html
->engine
);
4191 html_engine_clear_spell_check (html
->engine
);
4195 gtk_html_get_inline_spelling (const GtkHTML
*html
)
4197 g_return_val_if_fail (html
!= NULL
, FALSE
);
4198 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4200 return html
->priv
->inline_spelling
;
4204 gtk_html_set_magic_links (GtkHTML
*html
,
4207 g_return_if_fail (html
!= NULL
);
4208 g_return_if_fail (GTK_IS_HTML (html
));
4210 html
->priv
->magic_links
= links
;
4214 gtk_html_get_magic_links (const GtkHTML
*html
)
4216 g_return_val_if_fail (html
!= NULL
, FALSE
);
4217 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4219 return html
->priv
->magic_links
;
4223 gtk_html_set_magic_smileys (GtkHTML
*html
,
4226 g_return_if_fail (html
!= NULL
);
4227 g_return_if_fail (GTK_IS_HTML (html
));
4229 html
->priv
->magic_smileys
= smile
;
4233 gtk_html_get_magic_smileys (const GtkHTML
*html
)
4235 g_return_val_if_fail (html
!= NULL
, FALSE
);
4236 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4238 return html
->priv
->magic_smileys
;
4242 frame_set_animate (HTMLObject
*o
,
4246 if (HTML_IS_FRAME (o
)) {
4247 html_image_factory_set_animate (GTK_HTML (HTML_FRAME (o
)->html
)->engine
->image_factory
,
4249 } else if (HTML_IS_IFRAME (o
)) {
4250 html_image_factory_set_animate (GTK_HTML (HTML_IFRAME (o
)->html
)->engine
->image_factory
,
4256 gtk_html_set_caret_mode (GtkHTML
*html
,
4257 gboolean caret_mode
)
4259 g_return_if_fail (GTK_IS_HTML (html
));
4260 g_return_if_fail (HTML_IS_ENGINE (html
->engine
));
4262 set_caret_mode (html
->engine
, caret_mode
);
4266 gtk_html_get_caret_mode (const GtkHTML
*html
)
4268 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4269 g_return_val_if_fail (HTML_IS_ENGINE (html
->engine
), FALSE
);
4271 return html
->engine
->caret_mode
;
4275 * gtk_html_set_caret_first_focus_anchor:
4276 * When setting focus to the GtkHTML first time and is in caret mode,
4277 * then looks for an anchor of name @param name and tries to set focus
4278 * just after it. If NULL, then behaves as before.
4280 * @param html GtkHTML instance.
4281 * @param name Name of the anchor to be set the first focus just after it,
4282 * or NULL to not look for the anchor.
4285 gtk_html_set_caret_first_focus_anchor (GtkHTML
*html
,
4288 g_return_if_fail (GTK_IS_HTML (html
));
4289 g_return_if_fail (html
->priv
!= NULL
);
4291 g_free (html
->priv
->caret_first_focus_anchor
);
4292 html
->priv
->caret_first_focus_anchor
= g_strdup (name
);
4296 gtk_html_set_animate (GtkHTML
*html
,
4299 g_return_if_fail (GTK_IS_HTML (html
));
4300 g_return_if_fail (HTML_IS_ENGINE (html
->engine
));
4302 html_image_factory_set_animate (html
->engine
->image_factory
, animate
);
4303 if (html
->engine
->clue
)
4304 html_object_forall (html
->engine
->clue
, html
->engine
, frame_set_animate
, &animate
);
4308 gtk_html_get_animate (const GtkHTML
*html
)
4310 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
4311 g_return_val_if_fail (HTML_IS_ENGINE (html
->engine
), FALSE
);
4313 return html_image_factory_get_animate (html
->engine
->image_factory
);
4317 gtk_html_load_empty (GtkHTML
*html
)
4319 g_return_if_fail (html
!= NULL
);
4320 g_return_if_fail (GTK_IS_HTML (html
));
4322 html_engine_load_empty (html
->engine
);
4326 gtk_html_load_from_string (GtkHTML
*html
,
4330 GtkHTMLStream
*stream
;
4332 stream
= gtk_html_begin_content (html
, "text/html; charset=utf-8");
4333 gtk_html_stream_write (stream
, str
, (len
== -1) ? strlen (str
) : len
);
4334 gtk_html_stream_close (stream
, GTK_HTML_STREAM_OK
);
4338 gtk_html_set_base (GtkHTML
*html
,
4341 g_return_if_fail (GTK_IS_HTML (html
));
4343 g_free (html
->priv
->base_url
);
4344 html
->priv
->base_url
= g_strdup (url
);
4348 gtk_html_get_base (GtkHTML
*html
)
4350 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
4352 return html
->priv
->base_url
;
4358 gtk_html_print_page (GtkHTML
*html
,
4359 GtkPrintContext
*context
)
4361 g_return_if_fail (html
!= NULL
);
4362 g_return_if_fail (GTK_IS_HTML (html
));
4364 html_engine_print (html
->engine
, context
, .0, .0, NULL
, NULL
, NULL
);
4368 gtk_html_print_page_with_header_footer (GtkHTML
*html
,
4369 GtkPrintContext
*context
,
4370 gdouble header_height
,
4371 gdouble footer_height
,
4372 GtkHTMLPrintCallback header_print
,
4373 GtkHTMLPrintCallback footer_print
,
4376 g_return_if_fail (html
!= NULL
);
4377 g_return_if_fail (GTK_IS_HTML (html
));
4380 html
->engine
, context
, header_height
, footer_height
,
4381 header_print
, footer_print
, user_data
);
4388 gtk_html_set_paragraph_style (GtkHTML
*html
,
4389 GtkHTMLParagraphStyle style
)
4391 HTMLClueFlowStyle current_style
;
4392 HTMLClueFlowStyle clueflow_style
;
4393 HTMLListType item_type
;
4394 HTMLListType cur_item_type
;
4396 g_return_if_fail (html
!= NULL
);
4397 g_return_if_fail (GTK_IS_HTML (html
));
4399 /* FIXME precondition: check if it's a valid style. */
4401 paragraph_style_to_clueflow_style (style
, &clueflow_style
, &item_type
);
4403 html_engine_get_current_clueflow_style (html
->engine
, ¤t_style
, &cur_item_type
);
4404 if (!html_engine_is_selection_active (html
->engine
) && current_style
== clueflow_style
4405 && (current_style
!= HTML_CLUEFLOW_STYLE_LIST_ITEM
|| item_type
== cur_item_type
))
4408 if (!html_engine_set_clueflow_style (html
->engine
, clueflow_style
, item_type
, 0, 0, NULL
,
4409 HTML_ENGINE_SET_CLUEFLOW_STYLE
, HTML_UNDO_UNDO
, TRUE
))
4412 html
->priv
->paragraph_style
= style
;
4414 g_signal_emit (html
, signals
[CURRENT_PARAGRAPH_STYLE_CHANGED
], 0, style
);
4418 GtkHTMLParagraphStyle
4419 gtk_html_get_paragraph_style (GtkHTML
*html
)
4421 HTMLClueFlowStyle style
;
4422 HTMLListType item_type
;
4424 html_engine_get_current_clueflow_style (html
->engine
, &style
, &item_type
);
4426 return clueflow_style_to_paragraph_style (style
, item_type
);
4430 gtk_html_get_paragraph_indentation (GtkHTML
*html
)
4432 return html_engine_get_current_clueflow_indentation (html
->engine
);
4436 gtk_html_set_indent (GtkHTML
*html
,
4439 g_return_if_fail (html
!= NULL
);
4440 g_return_if_fail (GTK_IS_HTML (html
));
4442 html_engine_set_clueflow_style (html
->engine
, 0, 0, 0,
4443 levels
? levels
->len
: 0,
4444 levels
? levels
->data
: NULL
,
4445 HTML_ENGINE_SET_CLUEFLOW_INDENTATION
, HTML_UNDO_UNDO
, TRUE
);
4447 gtk_html_update_styles (html
);
4451 gtk_html_modify_indent_by_delta (GtkHTML
*html
,
4455 g_return_if_fail (html
!= NULL
);
4456 g_return_if_fail (GTK_IS_HTML (html
));
4458 html_engine_set_clueflow_style (html
->engine
, 0, 0, 0, delta
, levels
,
4459 HTML_ENGINE_SET_CLUEFLOW_INDENTATION_DELTA
, HTML_UNDO_UNDO
, TRUE
);
4461 gtk_html_update_styles (html
);
4465 gtk_html_indent_push_level (GtkHTML
*html
,
4466 HTMLListType level_type
)
4468 guint8 type
= (guint8
) level_type
;
4469 gtk_html_modify_indent_by_delta (html
, +1, &type
);
4473 gtk_html_indent_pop_level (GtkHTML
*html
)
4475 gtk_html_modify_indent_by_delta (html
, -1, NULL
);
4479 gtk_html_set_font_style (GtkHTML
*html
,
4480 GtkHTMLFontStyle and_mask
,
4481 GtkHTMLFontStyle or_mask
)
4483 g_return_if_fail (html
!= NULL
);
4484 g_return_if_fail (GTK_IS_HTML (html
));
4486 if (html_engine_set_font_style (html
->engine
, and_mask
, or_mask
))
4487 g_signal_emit (html
, signals
[INSERTION_FONT_STYLE_CHANGED
], 0, html
->engine
->insertion_font_style
);
4491 gtk_html_set_color (GtkHTML
*html
,
4494 g_return_if_fail (html
!= NULL
);
4495 g_return_if_fail (GTK_IS_HTML (html
));
4497 if (html_engine_set_color (html
->engine
, color
))
4498 g_signal_emit (html
, signals
[INSERTION_COLOR_CHANGED
], 0, html
->engine
->insertion_color
);
4502 gtk_html_toggle_font_style (GtkHTML
*html
,
4503 GtkHTMLFontStyle style
)
4505 g_return_if_fail (html
!= NULL
);
4506 g_return_if_fail (GTK_IS_HTML (html
));
4508 if (HTML_IS_PLAIN_PAINTER (html
->engine
->painter
))
4511 if (html_engine_toggle_font_style (html
->engine
, style
))
4512 g_signal_emit (html
, signals
[INSERTION_FONT_STYLE_CHANGED
], 0, html
->engine
->insertion_font_style
);
4515 GtkHTMLParagraphAlignment
4516 gtk_html_get_paragraph_alignment (GtkHTML
*html
)
4518 /* This makes the function return a HTMLHalignType. Should the below
4519 * call really be html_alignment_to_paragraph()? */
4521 return paragraph_alignment_to_html (html_engine_get_current_clueflow_alignment (html
->engine
));
4525 gtk_html_set_paragraph_alignment (GtkHTML
*html
,
4526 GtkHTMLParagraphAlignment alignment
)
4528 HTMLHAlignType align
;
4530 g_return_if_fail (html
!= NULL
);
4531 g_return_if_fail (GTK_IS_HTML (html
));
4533 align
= paragraph_alignment_to_html (alignment
);
4535 if (html_engine_set_clueflow_style (html
->engine
, 0, 0, align
, 0, NULL
,
4536 HTML_ENGINE_SET_CLUEFLOW_ALIGNMENT
, HTML_UNDO_UNDO
, TRUE
)) {
4537 html
->priv
->paragraph_alignment
= alignment
;
4538 g_signal_emit (html
, signals
[CURRENT_PARAGRAPH_ALIGNMENT_CHANGED
], 0, alignment
);
4543 /* Clipboard operations. */
4546 free_contents (ClipboardContents
*contents
)
4548 if (contents
->html_text
)
4549 g_free (contents
->html_text
);
4550 if (contents
->plain_text
)
4551 g_free (contents
->plain_text
);
4553 contents
->html_text
= NULL
;
4554 contents
->plain_text
= NULL
;
4560 clipboard_get_contents_cb (GtkClipboard
*clipboard
,
4561 GtkSelectionData
*selection_data
,
4565 ClipboardContents
*contents
= (ClipboardContents
*) data
;
4567 if (info
== TARGET_HTML
&& contents
->html_text
) {
4568 gtk_selection_data_set (selection_data
,
4569 gdk_atom_intern ("text/html", FALSE
), 8,
4570 (const guchar
*) contents
->html_text
,
4571 (gint
) strlen (contents
->html_text
));
4572 } else if (contents
->plain_text
) {
4573 gtk_selection_data_set_text (selection_data
,
4574 contents
->plain_text
,
4575 (gint
) strlen (contents
->plain_text
));
4580 clipboard_clear_contents_cb (GtkClipboard
*clipboard
,
4583 ClipboardContents
*contents
= (ClipboardContents
*) data
;
4585 free_contents (contents
);
4589 clipboard_paste_received_cb (GtkClipboard
*clipboard
,
4590 GtkSelectionData
*selection_data
,
4594 GtkWidget
*widget
= GTK_WIDGET (user_data
);
4602 e
= GTK_HTML (widget
)->engine
;
4603 as_cite
= GTK_HTML (widget
)->priv
->selection_as_cite
;
4605 data
= gtk_selection_data_get_data (selection_data
);
4606 length
= gtk_selection_data_get_length (selection_data
);
4607 target
= gtk_selection_data_get_target (selection_data
);
4608 data_type
= gtk_selection_data_get_data_type (selection_data
);
4613 if (data_type
== gdk_atom_intern (selection_targets
[TARGET_HTML
].target
, FALSE
)) {
4615 !g_utf8_validate ((const gchar
*) data
, length
- 1, NULL
)) {
4616 utf8
= utf16_to_utf8_with_bom_check ((guchar
*) data
, length
);
4619 utf8
= utf8_filter_out_bom (g_strndup ((const gchar
*) data
, length
));
4622 if (as_cite
&& utf8
) {
4625 cite
= g_strdup_printf ("<br><blockquote type=\"cite\">%s</blockquote>", utf8
);
4631 gint leading_spaces
= 0;
4633 /* check for leading spaces */
4634 while (g_ascii_isspace (utf8
[leading_spaces
]) &&
4635 utf8
[leading_spaces
] != '\n' &&
4636 utf8
[leading_spaces
] != '\r')
4640 html_engine_paste_text (e
, utf8
, leading_spaces
);
4642 if (utf8
[leading_spaces
])
4643 gtk_html_insert_html (GTK_HTML (widget
), utf8
+ leading_spaces
);
4645 /* check for trailing spaces */
4646 length
= g_utf8_strlen (utf8
, -1);
4647 if (length
> leading_spaces
) {
4648 const gchar
*ptr
, *from
= NULL
;
4651 while (ptr
= g_utf8_next_char (ptr
), ptr
&& *ptr
) {
4652 if (g_ascii_isspace (*ptr
) && *ptr
!= '\n' && *ptr
!= '\r') {
4661 html_engine_paste_text (e
, from
, g_utf8_strlen (from
, -1));
4664 g_warning ("selection was empty");
4665 } else if ((utf8
= (gchar
*) gtk_selection_data_get_text (selection_data
))) {
4666 utf8
= utf8_filter_out_bom (utf8
);
4670 encoded
= html_encode_entities (utf8
, g_utf8_strlen (utf8
, -1), NULL
);
4672 utf8
= g_strdup_printf ("<br><pre><blockquote type=\"cite\">%s</blockquote></pre>",
4675 gtk_html_insert_html (GTK_HTML (widget
), utf8
);
4677 html_engine_paste_text (e
, utf8
, g_utf8_strlen (utf8
, -1));
4680 if (HTML_IS_TEXT (e
->cursor
->object
))
4681 html_text_magic_link (HTML_TEXT (e
->cursor
->object
), e
, 1);
4690 while (i
< n_selection_targets
- 1) {
4691 if (target
== gdk_atom_intern (selection_targets
[i
].target
, FALSE
))
4696 if (i
< n_selection_targets
- 1) {
4697 GTK_HTML (widget
)->priv
->selection_type
= i
+ 1;
4698 gtk_clipboard_request_contents (clipboard
,
4699 gdk_atom_intern (selection_targets
[i
+ 1].target
, FALSE
),
4700 clipboard_paste_received_cb
,
4705 static ClipboardContents
*
4706 create_clipboard_contents (GtkHTML
*html
)
4708 ClipboardContents
*contents
;
4709 gint html_len
, text_len
;
4711 contents
= g_new0 (ClipboardContents
, 1);
4714 contents
->html_text
= get_selection_string (html
, &html_len
, FALSE
, FALSE
, TRUE
);
4716 /* set plain text */
4717 contents
->plain_text
= get_selection_string (html
, &text_len
, FALSE
, FALSE
, FALSE
);
4723 gtk_html_cut (GtkHTML
*html
)
4725 GtkClipboard
*clipboard
;
4726 ClipboardContents
*contents
;
4728 g_return_if_fail (html
!= NULL
);
4729 g_return_if_fail (GTK_IS_HTML (html
));
4731 html_engine_cut (html
->engine
);
4733 contents
= create_clipboard_contents (html
);
4735 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (html
), GDK_SELECTION_CLIPBOARD
);
4737 if (!gtk_clipboard_set_with_data (clipboard
, selection_targets
, n_selection_targets
,
4738 clipboard_get_contents_cb
,
4739 clipboard_clear_contents_cb
,
4741 free_contents (contents
);
4743 gtk_clipboard_set_can_store (clipboard
,
4744 selection_targets
+ 1,
4745 n_selection_targets
- 1);
4750 gtk_html_copy (GtkHTML
*html
)
4752 GtkClipboard
*clipboard
;
4753 ClipboardContents
*contents
;
4755 g_return_if_fail (html
!= NULL
);
4756 g_return_if_fail (GTK_IS_HTML (html
));
4758 html_engine_copy (html
->engine
);
4760 contents
= create_clipboard_contents (html
);
4762 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (html
), GDK_SELECTION_CLIPBOARD
);
4764 if (!gtk_clipboard_set_with_data (clipboard
, selection_targets
, n_selection_targets
,
4765 clipboard_get_contents_cb
,
4766 clipboard_clear_contents_cb
,
4768 free_contents (contents
);
4770 gtk_clipboard_set_can_store (clipboard
,
4776 gtk_html_paste (GtkHTML
*html
,
4779 g_return_if_fail (html
!= NULL
);
4780 g_return_if_fail (GTK_IS_HTML (html
));
4782 g_object_ref (html
);
4783 html
->priv
->selection_as_cite
= as_cite
;
4784 html
->priv
->selection_type
= 0;
4786 gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (html
), GDK_SELECTION_CLIPBOARD
),
4787 gdk_atom_intern (selection_targets
[0].target
, FALSE
),
4788 clipboard_paste_received_cb
, html
);
4792 update_primary_selection (GtkHTML
*html
)
4794 GtkClipboard
*clipboard
;
4798 g_return_if_fail (html
!= NULL
);
4799 g_return_if_fail (GTK_IS_HTML (html
));
4801 if (!html
->allow_selection
)
4804 text
= get_selection_string (html
, &text_len
, FALSE
, TRUE
, FALSE
);
4808 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (html
), GDK_SELECTION_PRIMARY
);
4810 gtk_clipboard_set_text (clipboard
, text
, text_len
);
4819 gtk_html_undo (GtkHTML
*html
)
4821 g_return_if_fail (html
!= NULL
);
4822 g_return_if_fail (GTK_IS_HTML (html
));
4824 html_engine_undo (html
->engine
);
4825 gtk_html_update_styles (html
);
4829 gtk_html_redo (GtkHTML
*html
)
4831 g_return_if_fail (html
!= NULL
);
4832 g_return_if_fail (GTK_IS_HTML (html
));
4834 html_engine_redo (html
->engine
);
4835 gtk_html_update_styles (html
);
4839 /* if engine_type == false - default behaviour*/
4841 gtk_html_set_default_engine (GtkHTML
*html
,
4842 gboolean engine_type
)
4844 html_engine_set_engine_type (html
->engine
, engine_type
);
4848 gtk_html_get_default_engine (GtkHTML
*html
)
4850 return html_engine_get_engine_type (html
->engine
);
4854 gtk_html_set_default_content_type (GtkHTML
*html
,
4855 const gchar
*content_type
)
4857 html_engine_set_content_type (html
->engine
, content_type
);
4861 gtk_html_get_default_content_type (GtkHTML
*html
)
4863 return html_engine_get_content_type (html
->engine
);
4867 gtk_html_get_object_by_id (GtkHTML
*html
,
4870 g_return_val_if_fail (html
, NULL
);
4871 g_return_val_if_fail (id
, NULL
);
4872 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
4873 g_return_val_if_fail (html
->engine
, NULL
);
4875 return html_engine_get_object_by_id (html
->engine
, id
);
4878 /*******************************************
4885 get_line_height (GtkHTML
*html
)
4889 if (!html
->engine
|| !html
->engine
->painter
)
4892 html_painter_set_font_style (html
->engine
->painter
, GTK_HTML_FONT_STYLE_SIZE_3
);
4893 html_painter_set_font_face (html
->engine
->painter
, NULL
);
4894 html_painter_calc_text_size (html
->engine
->painter
, "a", 1, &w
, &a
, &d
);
4900 scroll (GtkHTML
*html
,
4901 GtkOrientation orientation
,
4902 GtkScrollType scroll_type
,
4905 GtkAdjustment
*adjustment
;
4912 gdouble page_increment
;
4913 gdouble step_increment
;
4915 /* we dont want scroll in editable (move cursor instead) */
4916 if (html_engine_get_editable (html
->engine
) || html
->engine
->caret_mode
)
4919 adjustment
= (orientation
== GTK_ORIENTATION_VERTICAL
) ?
4920 gtk_layout_get_vadjustment (GTK_LAYOUT (html
)) :
4921 gtk_layout_get_hadjustment (GTK_LAYOUT (html
));
4923 value
= gtk_adjustment_get_value (adjustment
);
4924 lower
= gtk_adjustment_get_lower (adjustment
);
4925 upper
= gtk_adjustment_get_upper (adjustment
);
4926 page_size
= gtk_adjustment_get_page_size (adjustment
);
4927 page_increment
= gtk_adjustment_get_page_increment (adjustment
);
4928 step_increment
= gtk_adjustment_get_step_increment (adjustment
);
4930 line_height
= (html
->engine
&& page_increment
> (3 * get_line_height (html
)))
4931 ? get_line_height (html
)
4934 switch (scroll_type
) {
4935 case GTK_SCROLL_STEP_FORWARD
:
4936 delta
= step_increment
;
4938 case GTK_SCROLL_STEP_BACKWARD
:
4939 delta
= -step_increment
;
4941 case GTK_SCROLL_PAGE_FORWARD
:
4942 delta
= page_increment
- line_height
;
4944 case GTK_SCROLL_PAGE_BACKWARD
:
4945 delta
= -page_increment
+ line_height
;
4948 g_warning ("invalid scroll parameters: %d %d %f\n", orientation
, scroll_type
, position
);
4952 if (position
== 1.0) {
4953 if (lower
> (value
+ delta
)) {
4954 if (lower
>= value
) {
4955 html
->binding_handled
= FALSE
;
4958 } else if (MAX (0.0, upper
- page_size
) < (value
+ delta
)) {
4960 if (MAX (0.0, upper
- page_size
) <= value
) {
4961 html
->binding_handled
= FALSE
;
4967 gtk_adjustment_set_value (adjustment
, CLAMP (value
+ delta
, lower
, MAX (0.0, upper
- page_size
)));
4969 html
->binding_handled
= TRUE
;
4973 scroll_command (GtkHTML
*html
,
4974 GtkScrollType scroll_type
)
4976 GtkAdjustment
*adjustment
;
4982 gdouble page_increment
;
4985 /* we dont want scroll in editable (move cursor instead) */
4986 if (html_engine_get_editable (html
->engine
))
4989 adjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
4990 value
= gtk_adjustment_get_value (adjustment
);
4991 lower
= gtk_adjustment_get_lower (adjustment
);
4992 upper
= gtk_adjustment_get_upper (adjustment
);
4993 page_increment
= gtk_adjustment_get_page_increment (adjustment
);
4994 page_size
= gtk_adjustment_get_page_size (adjustment
);
4996 line_height
= (html
->engine
&& page_increment
> (3 * get_line_height (html
)))
4997 ? get_line_height (html
)
5000 switch (scroll_type
) {
5001 case GTK_SCROLL_PAGE_FORWARD
:
5002 delta
= page_increment
- line_height
;
5004 case GTK_SCROLL_PAGE_BACKWARD
:
5005 delta
= -page_increment
+ line_height
;
5012 d_s (printf ("%f %f %f\n", value
+ delta
, lower
, MAX (0.0, upper
- page_size
));)
5014 if (lower
> (value
+ delta
)) {
5017 } else if (MAX (0.0, upper
- page_size
) < (value
+ delta
)) {
5019 if (MAX (0.0, upper
- page_size
) <= value
) {
5024 gtk_adjustment_set_value (adjustment
, CLAMP (value
+ delta
, lower
, MAX (0.0, upper
- page_size
)));
5030 scroll_by_amount (GtkHTML
*html
,
5033 GtkAdjustment
*adjustment
;
5039 adjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
5040 value
= gtk_adjustment_get_value (adjustment
);
5041 lower
= gtk_adjustment_get_lower (adjustment
);
5042 upper
= gtk_adjustment_get_upper (adjustment
);
5043 page_size
= gtk_adjustment_get_page_size (adjustment
);
5045 gtk_adjustment_set_value (
5046 adjustment
, CLAMP (value
+ (gfloat
) amount
,
5047 lower
, MAX (0.0, upper
- page_size
)));
5051 cursor_move (GtkHTML
*html
,
5052 GtkDirectionType dir_type
,
5053 GtkHTMLCursorSkipType skip
)
5057 if (!html
->engine
->caret_mode
&& !html_engine_get_editable (html
->engine
))
5060 html
->priv
->cursor_moved
= TRUE
;
5062 if (skip
== GTK_HTML_CURSOR_SKIP_NONE
) {
5063 update_primary_selection (html
);
5064 g_signal_emit (GTK_HTML (html
), signals
[CURSOR_CHANGED
], 0);
5068 if (html
->engine
->selection_mode
) {
5069 if (!html
->engine
->mark
)
5070 html_engine_set_mark (html
->engine
);
5071 } else if (html
->engine
->shift_selection
|| html
->engine
->mark
) {
5072 html_engine_disable_selection (html
->engine
);
5073 html_engine_edit_selection_updater_schedule (html
->engine
->selection_updater
);
5074 html
->engine
->shift_selection
= FALSE
;
5077 case GTK_HTML_CURSOR_SKIP_ONE
:
5080 html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_LEFT
, 1);
5083 html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_RIGHT
, 1);
5086 html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_UP
, 1);
5089 html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_DOWN
, 1);
5092 g_warning ("invalid cursor_move parameters\n");
5095 case GTK_HTML_CURSOR_SKIP_WORD
:
5099 html_engine_backward_word (html
->engine
);
5103 html_engine_forward_word (html
->engine
);
5106 g_warning ("invalid cursor_move parameters\n");
5109 case GTK_HTML_CURSOR_SKIP_PAGE
: {
5110 GtkAllocation allocation
;
5113 gtk_widget_get_allocation (GTK_WIDGET (html
), &allocation
);
5114 line_height
= allocation
.height
> (3 * get_line_height (html
))
5115 ? get_line_height (html
) : 0;
5120 if ((amount
= html_engine_scroll_up (html
->engine
,
5121 allocation
.height
- line_height
)) > 0)
5122 scroll_by_amount (html
, - amount
);
5126 if ((amount
= html_engine_scroll_down (html
->engine
,
5127 allocation
.height
- line_height
)) > 0)
5128 scroll_by_amount (html
, amount
);
5131 g_warning ("invalid cursor_move parameters\n");
5135 case GTK_HTML_CURSOR_SKIP_ALL
:
5138 html_engine_beginning_of_line (html
->engine
);
5141 html_engine_end_of_line (html
->engine
);
5144 html_engine_beginning_of_document (html
->engine
);
5147 html_engine_end_of_document (html
->engine
);
5150 g_warning ("invalid cursor_move parameters\n");
5154 g_warning ("invalid cursor_move parameters\n");
5157 html
->binding_handled
= TRUE
;
5158 html
->priv
->update_styles
= TRUE
;
5159 gtk_html_edit_make_cursor_visible (html
);
5160 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
5161 update_primary_selection (html
);
5162 g_signal_emit (GTK_HTML (html
), signals
[CURSOR_CHANGED
], 0);
5166 move_selection (GtkHTML
*html
,
5167 GtkHTMLCommandType com_type
)
5169 GtkAllocation allocation
;
5173 if (!html_engine_get_editable (html
->engine
) && !html
->engine
->caret_mode
)
5176 gtk_widget_get_allocation (GTK_WIDGET (html
), &allocation
);
5178 html
->priv
->cursor_moved
= TRUE
;
5179 html
->engine
->shift_selection
= TRUE
;
5180 if (!html
->engine
->mark
)
5181 html_engine_set_mark (html
->engine
);
5183 case GTK_HTML_COMMAND_MODIFY_SELECTION_UP
:
5184 rv
= html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_UP
, 1) > 0 ? TRUE
: FALSE
;
5186 case GTK_HTML_COMMAND_MODIFY_SELECTION_DOWN
:
5187 rv
= html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_DOWN
, 1) > 0 ? TRUE
: FALSE
;
5189 case GTK_HTML_COMMAND_MODIFY_SELECTION_LEFT
:
5190 rv
= html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_LEFT
, 1) > 0 ? TRUE
: FALSE
;
5192 case GTK_HTML_COMMAND_MODIFY_SELECTION_RIGHT
:
5193 rv
= html_engine_move_cursor (html
->engine
, HTML_ENGINE_CURSOR_RIGHT
, 1) > 0 ? TRUE
: FALSE
;
5195 case GTK_HTML_COMMAND_MODIFY_SELECTION_BOL
:
5196 rv
= html_engine_beginning_of_line (html
->engine
);
5198 case GTK_HTML_COMMAND_MODIFY_SELECTION_EOL
:
5199 rv
= html_engine_end_of_line (html
->engine
);
5201 case GTK_HTML_COMMAND_MODIFY_SELECTION_BOD
:
5202 html_engine_beginning_of_document (html
->engine
);
5205 case GTK_HTML_COMMAND_MODIFY_SELECTION_EOD
:
5206 html_engine_end_of_document (html
->engine
);
5209 case GTK_HTML_COMMAND_MODIFY_SELECTION_PREV_WORD
:
5210 rv
= html_engine_backward_word (html
->engine
);
5212 case GTK_HTML_COMMAND_MODIFY_SELECTION_NEXT_WORD
:
5213 rv
= html_engine_forward_word (html
->engine
);
5215 case GTK_HTML_COMMAND_MODIFY_SELECTION_PAGEUP
:
5216 if ((amount
= html_engine_scroll_up (html
->engine
, allocation
.height
)) > 0) {
5217 scroll_by_amount (html
, - amount
);
5222 case GTK_HTML_COMMAND_MODIFY_SELECTION_PAGEDOWN
:
5223 if ((amount
= html_engine_scroll_down (html
->engine
, allocation
.height
)) > 0) {
5224 scroll_by_amount (html
, amount
);
5230 g_warning ("invalid move_selection parameters\n");
5234 html
->binding_handled
= TRUE
;
5235 html
->priv
->update_styles
= TRUE
;
5237 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
5239 update_primary_selection (html
);
5245 delete_one (HTMLEngine
*e
,
5248 if (e
->cursor
->object
&& html_object_is_container (e
->cursor
->object
)
5249 && ((forward
&& !e
->cursor
->offset
) || (!forward
&& e
->cursor
->offset
)))
5250 html_engine_delete_container (e
);
5252 html_engine_delete_n (e
, 1, forward
);
5255 inline static gboolean
5256 insert_tab_or_next_cell (GtkHTML
*html
)
5258 HTMLEngine
*e
= html
->engine
;
5259 if (!html_engine_next_cell (e
, TRUE
)) {
5260 if (html_clueflow_tabs (HTML_CLUEFLOW (e
->cursor
->object
->parent
), e
->painter
))
5261 html_engine_paste_text (e
, "\t", 1);
5263 html_engine_paste_text (e
, "\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0", 4);
5271 indent_more_or_next_cell (GtkHTML
*html
)
5273 if (!html_engine_next_cell (html
->engine
, TRUE
))
5274 gtk_html_indent_push_level (html
, HTML_LIST_TYPE_BLOCKQUOTE
);
5278 command (GtkHTML
*html
,
5279 GtkHTMLCommandType com_type
)
5281 HTMLEngine
*e
= html
->engine
;
5284 /* printf ("command %d %s\n", com_type, get_value_nick (com_type)); */
5285 html
->binding_handled
= TRUE
;
5287 #define ensure_key_binding_not_editable() \
5288 if (html->priv->in_key_binding && html_engine_get_editable (e)) { \
5289 html->binding_handled = FALSE; \
5294 /* non-editable + editable commands */
5296 case GTK_HTML_COMMAND_ZOOM_IN
:
5297 ensure_key_binding_not_editable ();
5298 gtk_html_zoom_in (html
);
5300 case GTK_HTML_COMMAND_ZOOM_OUT
:
5301 ensure_key_binding_not_editable ();
5302 gtk_html_zoom_out (html
);
5304 case GTK_HTML_COMMAND_ZOOM_RESET
:
5305 ensure_key_binding_not_editable ();
5306 gtk_html_zoom_reset (html
);
5308 case GTK_HTML_COMMAND_SEARCH_INCREMENTAL_FORWARD
:
5309 gtk_html_isearch (html
, TRUE
);
5311 case GTK_HTML_COMMAND_SEARCH_INCREMENTAL_BACKWARD
:
5312 gtk_html_isearch (html
, FALSE
);
5314 case GTK_HTML_COMMAND_FOCUS_FORWARD
:
5315 if (!html_engine_get_editable (e
))
5316 html
->binding_handled
= gtk_widget_child_focus (GTK_WIDGET (html
), GTK_DIR_TAB_FORWARD
);
5318 case GTK_HTML_COMMAND_FOCUS_BACKWARD
:
5319 if (!html_engine_get_editable (e
))
5320 html
->binding_handled
= gtk_widget_child_focus (GTK_WIDGET (html
), GTK_DIR_TAB_BACKWARD
);
5322 case GTK_HTML_COMMAND_SCROLL_FORWARD
:
5323 rv
= scroll_command (html
, GTK_SCROLL_PAGE_FORWARD
);
5325 case GTK_HTML_COMMAND_SCROLL_BACKWARD
:
5326 rv
= scroll_command (html
, GTK_SCROLL_PAGE_BACKWARD
);
5328 case GTK_HTML_COMMAND_SCROLL_BOD
:
5329 if (!html_engine_get_editable (e
) && !e
->caret_mode
)
5330 gtk_adjustment_set_value (gtk_layout_get_vadjustment (GTK_LAYOUT (html
)), 0);
5332 case GTK_HTML_COMMAND_SCROLL_EOD
:
5333 if (!html_engine_get_editable (e
) && !e
->caret_mode
) {
5334 GtkAdjustment
*adjustment
;
5335 gdouble upper
, page_size
;
5337 adjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
5338 upper
= gtk_adjustment_get_upper (adjustment
);
5339 page_size
= gtk_adjustment_get_page_size (adjustment
);
5340 gtk_adjustment_set_value (adjustment
, upper
- page_size
);
5343 case GTK_HTML_COMMAND_COPY
:
5344 gtk_html_copy (html
);
5347 case GTK_HTML_COMMAND_MODIFY_SELECTION_UP
:
5348 case GTK_HTML_COMMAND_MODIFY_SELECTION_DOWN
:
5349 case GTK_HTML_COMMAND_MODIFY_SELECTION_LEFT
:
5350 case GTK_HTML_COMMAND_MODIFY_SELECTION_RIGHT
:
5351 case GTK_HTML_COMMAND_MODIFY_SELECTION_BOL
:
5352 case GTK_HTML_COMMAND_MODIFY_SELECTION_EOL
:
5353 case GTK_HTML_COMMAND_MODIFY_SELECTION_BOD
:
5354 case GTK_HTML_COMMAND_MODIFY_SELECTION_EOD
:
5355 case GTK_HTML_COMMAND_MODIFY_SELECTION_PAGEUP
:
5356 case GTK_HTML_COMMAND_MODIFY_SELECTION_PAGEDOWN
:
5357 case GTK_HTML_COMMAND_MODIFY_SELECTION_PREV_WORD
:
5358 case GTK_HTML_COMMAND_MODIFY_SELECTION_NEXT_WORD
:
5359 if (html
->engine
->caret_mode
|| html_engine_get_editable (e
)) {
5360 gtk_im_context_reset (html
->priv
->im_context
);
5361 rv
= move_selection (html
, com_type
);
5364 case GTK_HTML_COMMAND_SELECT_ALL
:
5365 gtk_html_select_all (html
);
5367 case GTK_HTML_COMMAND_EDITABLE_ON
:
5368 gtk_html_set_editable (html
, TRUE
);
5370 case GTK_HTML_COMMAND_EDITABLE_OFF
:
5371 gtk_html_set_editable (html
, FALSE
);
5373 case GTK_HTML_COMMAND_BLOCK_SELECTION
:
5374 html_engine_block_selection (html
->engine
);
5376 case GTK_HTML_COMMAND_UNBLOCK_SELECTION
:
5377 html_engine_unblock_selection (html
->engine
);
5379 case GTK_HTML_COMMAND_IS_SELECTION_ACTIVE
:
5380 rv
= html_engine_is_selection_active (html
->engine
);
5382 case GTK_HTML_COMMAND_UNSELECT_ALL
:
5383 gtk_html_unselect_all (html
);
5388 html
->binding_handled
= FALSE
;
5391 #undef ensure_key_binding_not_editable
5393 if (!html_engine_get_editable (e
) || html
->binding_handled
)
5396 html
->binding_handled
= TRUE
;
5397 html
->priv
->update_styles
= FALSE
;
5399 /* editable commands only */
5401 case GTK_HTML_COMMAND_UNDO
:
5402 gtk_html_undo (html
);
5404 case GTK_HTML_COMMAND_REDO
:
5405 gtk_html_redo (html
);
5407 case GTK_HTML_COMMAND_COPY_AND_DISABLE_SELECTION
:
5408 gtk_html_copy (html
);
5409 html_engine_disable_selection (e
);
5410 html_engine_edit_selection_updater_schedule (e
->selection_updater
);
5411 e
->selection_mode
= FALSE
;
5413 case GTK_HTML_COMMAND_CUT
:
5414 gtk_html_cut (html
);
5415 html
->priv
->update_styles
= TRUE
;
5417 case GTK_HTML_COMMAND_CUT_LINE
:
5418 html_engine_cut_line (e
);
5419 html
->priv
->update_styles
= TRUE
;
5421 case GTK_HTML_COMMAND_PASTE
:
5422 gtk_html_paste (html
, FALSE
);
5423 html
->priv
->update_styles
= TRUE
;
5425 case GTK_HTML_COMMAND_INSERT_RULE
:
5426 html_engine_insert_rule (e
, 0, 100, 2, TRUE
, HTML_HALIGN_LEFT
);
5428 case GTK_HTML_COMMAND_INSERT_PARAGRAPH
:
5429 html_engine_delete (e
);
5431 /* stop inserting links after newlines */
5432 html_engine_set_insertion_link (e
, NULL
, NULL
);
5434 html_engine_insert_empty_paragraph (e
);
5435 html
->priv
->update_styles
= TRUE
;
5437 case GTK_HTML_COMMAND_DELETE
:
5439 && e
->mark
->position
!= e
->cursor
->position
)
5440 html_engine_delete (e
);
5442 delete_one (e
, TRUE
);
5443 html
->priv
->update_styles
= TRUE
;
5445 case GTK_HTML_COMMAND_DELETE_BACK
:
5446 if (html_engine_is_selection_active (e
))
5447 html_engine_delete (e
);
5449 delete_one (e
, FALSE
);
5450 html
->priv
->update_styles
= TRUE
;
5452 case GTK_HTML_COMMAND_DELETE_BACK_OR_INDENT_DEC
:
5453 if (html_engine_is_selection_active (e
))
5454 html_engine_delete (e
);
5455 else if (html_engine_cursor_on_bop (e
) && html_engine_get_indent (e
) > 0
5456 && e
->cursor
->object
->parent
&& HTML_IS_CLUEFLOW (e
->cursor
->object
->parent
)
5457 && HTML_CLUEFLOW (e
->cursor
->object
->parent
)->style
!= HTML_CLUEFLOW_STYLE_LIST_ITEM
)
5458 gtk_html_indent_pop_level (html
);
5460 delete_one (e
, FALSE
);
5461 html
->priv
->update_styles
= TRUE
;
5463 case GTK_HTML_COMMAND_DELETE_TABLE
:
5464 html_engine_delete_table (e
);
5465 html
->priv
->update_styles
= TRUE
;
5467 case GTK_HTML_COMMAND_DELETE_TABLE_ROW
:
5468 html_engine_delete_table_row (e
);
5469 html
->priv
->update_styles
= TRUE
;
5471 case GTK_HTML_COMMAND_DELETE_TABLE_COLUMN
:
5472 html_engine_delete_table_column (e
);
5473 html
->priv
->update_styles
= TRUE
;
5475 case GTK_HTML_COMMAND_DELETE_TABLE_CELL_CONTENTS
:
5476 html_engine_delete_table_cell_contents (e
);
5477 html
->priv
->update_styles
= TRUE
;
5479 case GTK_HTML_COMMAND_SELECTION_MODE
:
5480 e
->selection_mode
= TRUE
;
5482 case GTK_HTML_COMMAND_DISABLE_SELECTION
:
5483 html_engine_disable_selection (e
);
5484 html_engine_edit_selection_updater_schedule (e
->selection_updater
);
5485 e
->selection_mode
= FALSE
;
5487 case GTK_HTML_COMMAND_BOLD_ON
:
5488 gtk_html_set_font_style (html
, GTK_HTML_FONT_STYLE_MAX
, GTK_HTML_FONT_STYLE_BOLD
);
5490 case GTK_HTML_COMMAND_BOLD_OFF
:
5491 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_BOLD
, 0);
5493 case GTK_HTML_COMMAND_BOLD_TOGGLE
:
5494 gtk_html_toggle_font_style (html
, GTK_HTML_FONT_STYLE_BOLD
);
5496 case GTK_HTML_COMMAND_ITALIC_ON
:
5497 gtk_html_set_font_style (html
, GTK_HTML_FONT_STYLE_MAX
, GTK_HTML_FONT_STYLE_ITALIC
);
5499 case GTK_HTML_COMMAND_ITALIC_OFF
:
5500 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_ITALIC
, 0);
5502 case GTK_HTML_COMMAND_ITALIC_TOGGLE
:
5503 gtk_html_toggle_font_style (html
, GTK_HTML_FONT_STYLE_ITALIC
);
5505 case GTK_HTML_COMMAND_STRIKEOUT_ON
:
5506 gtk_html_set_font_style (html
, GTK_HTML_FONT_STYLE_MAX
, GTK_HTML_FONT_STYLE_STRIKEOUT
);
5508 case GTK_HTML_COMMAND_STRIKEOUT_OFF
:
5509 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_STRIKEOUT
, 0);
5511 case GTK_HTML_COMMAND_STRIKEOUT_TOGGLE
:
5512 gtk_html_toggle_font_style (html
, GTK_HTML_FONT_STYLE_STRIKEOUT
);
5514 case GTK_HTML_COMMAND_UNDERLINE_ON
:
5515 gtk_html_set_font_style (html
, GTK_HTML_FONT_STYLE_MAX
, GTK_HTML_FONT_STYLE_UNDERLINE
);
5517 case GTK_HTML_COMMAND_UNDERLINE_OFF
:
5518 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_UNDERLINE
, 0);
5520 case GTK_HTML_COMMAND_UNDERLINE_TOGGLE
:
5521 gtk_html_toggle_font_style (html
, GTK_HTML_FONT_STYLE_UNDERLINE
);
5523 case GTK_HTML_COMMAND_SIZE_MINUS_2
:
5524 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_1
);
5526 case GTK_HTML_COMMAND_SIZE_MINUS_1
:
5527 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_2
);
5529 case GTK_HTML_COMMAND_SIZE_PLUS_0
:
5530 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_3
);
5532 case GTK_HTML_COMMAND_SIZE_PLUS_1
:
5533 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_4
);
5535 case GTK_HTML_COMMAND_SIZE_PLUS_2
:
5536 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_5
);
5538 case GTK_HTML_COMMAND_SIZE_PLUS_3
:
5539 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_6
);
5541 case GTK_HTML_COMMAND_SIZE_PLUS_4
:
5542 gtk_html_set_font_style (html
, ~GTK_HTML_FONT_STYLE_SIZE_MASK
, GTK_HTML_FONT_STYLE_SIZE_7
);
5544 case GTK_HTML_COMMAND_SIZE_INCREASE
:
5545 html_engine_font_size_inc_dec (e
, TRUE
);
5547 case GTK_HTML_COMMAND_SIZE_DECREASE
:
5548 html_engine_font_size_inc_dec (e
, FALSE
);
5550 case GTK_HTML_COMMAND_ALIGN_LEFT
:
5551 gtk_html_set_paragraph_alignment (html
, GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT
);
5553 case GTK_HTML_COMMAND_ALIGN_CENTER
:
5554 gtk_html_set_paragraph_alignment (html
, GTK_HTML_PARAGRAPH_ALIGNMENT_CENTER
);
5556 case GTK_HTML_COMMAND_ALIGN_RIGHT
:
5557 gtk_html_set_paragraph_alignment (html
, GTK_HTML_PARAGRAPH_ALIGNMENT_RIGHT
);
5559 case GTK_HTML_COMMAND_INDENT_ZERO
:
5560 gtk_html_set_indent (html
, NULL
);
5562 case GTK_HTML_COMMAND_INDENT_INC
:
5563 gtk_html_indent_push_level (html
, HTML_LIST_TYPE_BLOCKQUOTE
);
5565 case GTK_HTML_COMMAND_INDENT_INC_OR_NEXT_CELL
:
5566 indent_more_or_next_cell (html
);
5568 case GTK_HTML_COMMAND_INSERT_TAB
:
5569 if (!html_engine_is_selection_active (e
)
5570 && html_clueflow_tabs (HTML_CLUEFLOW (e
->cursor
->object
->parent
), e
->painter
))
5571 html_engine_insert_text (e
, "\t", 1);
5573 case GTK_HTML_COMMAND_INSERT_TAB_OR_INDENT_MORE
:
5574 if (!html_engine_is_selection_active (e
)
5575 && html_clueflow_tabs (HTML_CLUEFLOW (e
->cursor
->object
->parent
), e
->painter
))
5576 html_engine_insert_text (e
, "\t", 1);
5578 gtk_html_indent_push_level (html
, HTML_LIST_TYPE_BLOCKQUOTE
);
5580 case GTK_HTML_COMMAND_INSERT_TAB_OR_NEXT_CELL
:
5581 html
->binding_handled
= insert_tab_or_next_cell (html
);
5583 case GTK_HTML_COMMAND_INDENT_DEC
:
5584 gtk_html_indent_pop_level (html
);
5586 case GTK_HTML_COMMAND_PREV_CELL
:
5587 html
->binding_handled
= html_engine_prev_cell (html
->engine
);
5589 case GTK_HTML_COMMAND_INDENT_PARAGRAPH
:
5590 html_engine_indent_paragraph (e
);
5592 case GTK_HTML_COMMAND_BREAK_AND_FILL_LINE
:
5593 html_engine_break_and_fill_line (e
);
5595 case GTK_HTML_COMMAND_SPACE_AND_FILL_LINE
:
5596 html_engine_space_and_fill_line (e
);
5598 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_NORMAL
:
5599 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_NORMAL
);
5601 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H1
:
5602 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H1
);
5604 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H2
:
5605 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H2
);
5607 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H3
:
5608 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H3
);
5610 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H4
:
5611 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H4
);
5613 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H5
:
5614 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H5
);
5616 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_H6
:
5617 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_H6
);
5619 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_PRE
:
5620 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_PRE
);
5622 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_ADDRESS
:
5623 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_ADDRESS
);
5625 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_ITEMDOTTED
:
5626 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED
);
5628 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_ITEMROMAN
:
5629 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_ITEMROMAN
);
5631 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_ITEMDIGIT
:
5632 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_ITEMDIGIT
);
5634 case GTK_HTML_COMMAND_PARAGRAPH_STYLE_ITEMALPHA
:
5635 gtk_html_set_paragraph_style (html
, GTK_HTML_PARAGRAPH_STYLE_ITEMALPHA
);
5637 case GTK_HTML_COMMAND_SELECT_WORD
:
5638 gtk_html_select_word (html
);
5640 case GTK_HTML_COMMAND_SELECT_LINE
:
5641 gtk_html_select_line (html
);
5643 case GTK_HTML_COMMAND_SELECT_PARAGRAPH
:
5644 gtk_html_select_paragraph (html
);
5646 case GTK_HTML_COMMAND_SELECT_PARAGRAPH_EXTENDED
:
5647 gtk_html_select_paragraph_extended (html
);
5649 case GTK_HTML_COMMAND_CURSOR_POSITION_SAVE
:
5650 html_engine_edit_cursor_position_save (html
->engine
);
5652 case GTK_HTML_COMMAND_CURSOR_POSITION_RESTORE
:
5653 html_engine_edit_cursor_position_restore (html
->engine
);
5655 case GTK_HTML_COMMAND_CAPITALIZE_WORD
:
5656 html_engine_capitalize_word (e
);
5658 case GTK_HTML_COMMAND_UPCASE_WORD
:
5659 html_engine_upcase_downcase_word (e
, TRUE
);
5661 case GTK_HTML_COMMAND_DOWNCASE_WORD
:
5662 html_engine_upcase_downcase_word (e
, FALSE
);
5664 case GTK_HTML_COMMAND_SPELL_SUGGEST
:
5665 if (html
->editor_api
&& !html_engine_spell_word_is_valid (e
))
5666 (*html
->editor_api
->suggestion_request
) (html
, html
->editor_data
);
5668 case GTK_HTML_COMMAND_SPELL_PERSONAL_DICTIONARY_ADD
:
5669 case GTK_HTML_COMMAND_SPELL_SESSION_DICTIONARY_ADD
: {
5671 word
= html_engine_get_spell_word (e
);
5673 if (word
&& html
->editor_api
) {
5674 if (com_type
== GTK_HTML_COMMAND_SPELL_PERSONAL_DICTIONARY_ADD
)
5675 /* FIXME fire popup menu with more than 1 language enabled */
5676 (*html
->editor_api
->add_to_personal
) (html
, word
, html_engine_get_language (html
->engine
), html
->editor_data
);
5678 (*html
->editor_api
->add_to_session
) (html
, word
, html
->editor_data
);
5680 html_engine_spell_check (e
);
5681 gtk_widget_queue_draw (GTK_WIDGET (html
));
5685 case GTK_HTML_COMMAND_CURSOR_FORWARD
:
5686 rv
= html_cursor_forward (html
->engine
->cursor
, html
->engine
);
5688 case GTK_HTML_COMMAND_CURSOR_BACKWARD
:
5689 rv
= html_cursor_backward (html
->engine
->cursor
, html
->engine
);
5691 case GTK_HTML_COMMAND_INSERT_TABLE_1_1
:
5692 html_engine_insert_table_1_1 (e
);
5694 case GTK_HTML_COMMAND_TABLE_INSERT_COL_BEFORE
:
5695 html_engine_insert_table_column (e
, FALSE
);
5697 case GTK_HTML_COMMAND_TABLE_INSERT_COL_AFTER
:
5698 html_engine_insert_table_column (e
, TRUE
);
5700 case GTK_HTML_COMMAND_TABLE_DELETE_COL
:
5701 html_engine_delete_table_column (e
);
5703 case GTK_HTML_COMMAND_TABLE_INSERT_ROW_BEFORE
:
5704 html_engine_insert_table_row (e
, FALSE
);
5706 case GTK_HTML_COMMAND_TABLE_INSERT_ROW_AFTER
:
5707 html_engine_insert_table_row (e
, TRUE
);
5709 case GTK_HTML_COMMAND_TABLE_DELETE_ROW
:
5710 html_engine_delete_table_row (e
);
5712 case GTK_HTML_COMMAND_TABLE_BORDER_WIDTH_INC
:
5713 html_engine_table_set_border_width (e
, html_engine_get_table (e
), 1, TRUE
);
5715 case GTK_HTML_COMMAND_TABLE_BORDER_WIDTH_DEC
:
5716 html_engine_table_set_border_width (e
, html_engine_get_table (e
), -1, TRUE
);
5718 case GTK_HTML_COMMAND_TABLE_BORDER_WIDTH_ZERO
:
5719 html_engine_table_set_border_width (e
, html_engine_get_table (e
), 0, FALSE
);
5721 case GTK_HTML_COMMAND_TABLE_SPACING_INC
:
5722 html_engine_table_set_spacing (e
, html_engine_get_table (e
), 1, TRUE
);
5724 case GTK_HTML_COMMAND_TABLE_SPACING_DEC
:
5725 html_engine_table_set_spacing (e
, html_engine_get_table (e
), -1, TRUE
);
5727 case GTK_HTML_COMMAND_TABLE_SPACING_ZERO
:
5728 html_engine_table_set_spacing (e
, html_engine_get_table (e
), 0, FALSE
);
5730 case GTK_HTML_COMMAND_TABLE_PADDING_INC
:
5731 html_engine_table_set_padding (e
, html_engine_get_table (e
), 1, TRUE
);
5733 case GTK_HTML_COMMAND_TABLE_PADDING_DEC
:
5734 html_engine_table_set_padding (e
, html_engine_get_table (e
), -1, TRUE
);
5736 case GTK_HTML_COMMAND_TABLE_PADDING_ZERO
:
5737 html_engine_table_set_padding (e
, html_engine_get_table (e
), 0, FALSE
);
5739 case GTK_HTML_COMMAND_TEXT_SET_DEFAULT_COLOR
:
5740 html_engine_set_color (e
, NULL
);
5742 case GTK_HTML_COMMAND_CURSOR_BOD
:
5743 html_engine_beginning_of_document (e
);
5745 case GTK_HTML_COMMAND_CURSOR_EOD
:
5746 html_engine_end_of_document (e
);
5748 case GTK_HTML_COMMAND_BLOCK_REDRAW
:
5749 html_engine_block_redraw (e
);
5751 case GTK_HTML_COMMAND_UNBLOCK_REDRAW
:
5752 html_engine_unblock_redraw (e
);
5754 case GTK_HTML_COMMAND_GRAB_FOCUS
:
5755 gtk_widget_grab_focus (GTK_WIDGET (html
));
5757 case GTK_HTML_COMMAND_KILL_WORD
:
5758 case GTK_HTML_COMMAND_KILL_WORD_BACKWARD
:
5759 html_engine_block_selection (e
);
5760 html_engine_set_mark (e
);
5761 html_engine_update_selection_if_necessary (e
);
5762 html_engine_freeze (e
);
5763 rv
= com_type
== GTK_HTML_COMMAND_KILL_WORD
5764 ? html_engine_forward_word (e
)
5765 : html_engine_backward_word (e
);
5767 html_engine_delete (e
);
5768 html_engine_unblock_selection (e
);
5769 html_engine_thaw (e
);
5771 case GTK_HTML_COMMAND_SAVE_DATA_ON
:
5772 html
->engine
->save_data
= TRUE
;
5774 case GTK_HTML_COMMAND_SAVE_DATA_OFF
:
5775 html
->engine
->save_data
= FALSE
;
5777 case GTK_HTML_COMMAND_SAVED
:
5778 html_engine_saved (html
->engine
);
5780 case GTK_HTML_COMMAND_IS_SAVED
:
5781 rv
= html_engine_is_saved (html
->engine
);
5783 case GTK_HTML_COMMAND_CELL_CSPAN_INC
:
5784 rv
= html_engine_cspan_delta (html
->engine
, 1);
5786 case GTK_HTML_COMMAND_CELL_RSPAN_INC
:
5787 rv
= html_engine_rspan_delta (html
->engine
, 1);
5789 case GTK_HTML_COMMAND_CELL_CSPAN_DEC
:
5790 rv
= html_engine_cspan_delta (html
->engine
, -1);
5792 case GTK_HTML_COMMAND_CELL_RSPAN_DEC
:
5793 rv
= html_engine_rspan_delta (html
->engine
, -1);
5796 html
->binding_handled
= FALSE
;
5799 if (!html
->binding_handled
&& html
->editor_api
)
5800 html
->binding_handled
= (* html
->editor_api
->command
) (html
, com_type
, html
->editor_data
);
5806 add_bindings (GtkHTMLClass
*klass
)
5808 GtkBindingSet
*binding_set
;
5810 /* ensure enums are defined */
5811 gtk_html_cursor_skip_get_type ();
5812 gtk_html_command_get_type ();
5814 binding_set
= gtk_binding_set_by_class (klass
);
5816 /* layout scrolling */
5817 #define BSCROLL(m,key,orient,sc) \
5818 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ ## key, m, \
5820 GTK_TYPE_ORIENTATION, GTK_ORIENTATION_ ## orient, \
5821 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_ ## sc, \
5824 #define BSPACESCROLL(m,key,orient,sc) \
5825 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ ## key, m, \
5827 GTK_TYPE_ORIENTATION, GTK_ORIENTATION_ ## orient, \
5828 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_ ## sc, \
5831 BSCROLL (0, Up
, VERTICAL
, STEP_BACKWARD
);
5832 BSCROLL (0, KP_Up
, VERTICAL
, STEP_BACKWARD
);
5833 BSCROLL (0, Down
, VERTICAL
, STEP_FORWARD
);
5834 BSCROLL (0, KP_Down
, VERTICAL
, STEP_FORWARD
);
5836 BSCROLL (0, Left
, HORIZONTAL
, STEP_BACKWARD
);
5837 BSCROLL (0, KP_Left
, HORIZONTAL
, STEP_BACKWARD
);
5838 BSCROLL (0, Right
, HORIZONTAL
, STEP_FORWARD
);
5839 BSCROLL (0, KP_Right
, HORIZONTAL
, STEP_FORWARD
);
5841 BSCROLL (0, Page_Up
, VERTICAL
, PAGE_BACKWARD
);
5842 BSCROLL (0, KP_Page_Up
, VERTICAL
, PAGE_BACKWARD
);
5843 BSCROLL (0, Page_Down
, VERTICAL
, PAGE_FORWARD
);
5844 BSCROLL (0, KP_Page_Down
, VERTICAL
, PAGE_FORWARD
);
5845 BSPACESCROLL (0, BackSpace
, VERTICAL
, PAGE_BACKWARD
);
5846 BSPACESCROLL (0, space
, VERTICAL
, PAGE_FORWARD
);
5847 BSPACESCROLL (GDK_SHIFT_MASK
, space
, VERTICAL
, PAGE_BACKWARD
);
5849 BSCROLL (GDK_SHIFT_MASK
, Left
, HORIZONTAL
, PAGE_BACKWARD
);
5850 BSCROLL (GDK_SHIFT_MASK
, KP_Left
, HORIZONTAL
, PAGE_BACKWARD
);
5851 BSCROLL (GDK_SHIFT_MASK
, Right
, HORIZONTAL
, PAGE_FORWARD
);
5852 BSCROLL (GDK_SHIFT_MASK
, KP_Right
, HORIZONTAL
, PAGE_FORWARD
);
5856 #define BMOVE(m,key,dir,sk) \
5857 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ ## key, m, \
5859 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_ ## dir, \
5860 GTK_TYPE_HTML_CURSOR_SKIP, GTK_HTML_CURSOR_SKIP_ ## sk);
5862 BMOVE (0, Left
, LEFT
, ONE
);
5863 BMOVE (0, KP_Left
, LEFT
, ONE
);
5864 BMOVE (0, Right
, RIGHT
, ONE
);
5865 BMOVE (0, KP_Right
, RIGHT
, ONE
);
5866 BMOVE (0, Up
, UP
, ONE
);
5867 BMOVE (0, KP_Up
, UP
, ONE
);
5868 BMOVE (0, Down
, DOWN
, ONE
);
5869 BMOVE (0, KP_Down
, DOWN
, ONE
);
5871 BMOVE (GDK_CONTROL_MASK
, KP_Left
, LEFT
, WORD
);
5872 BMOVE (GDK_CONTROL_MASK
, Left
, LEFT
, WORD
);
5873 BMOVE (GDK_MOD1_MASK
, Left
, LEFT
, WORD
);
5874 BMOVE (GDK_SHIFT_MASK
, Left
, LEFT
, NONE
);
5875 BMOVE (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, Left
, LEFT
, NONE
);
5877 BMOVE (GDK_CONTROL_MASK
, KP_Right
, RIGHT
, WORD
);
5878 BMOVE (GDK_CONTROL_MASK
, Right
, RIGHT
, WORD
);
5879 BMOVE (GDK_MOD1_MASK
, Right
, RIGHT
, WORD
);
5880 BMOVE (GDK_SHIFT_MASK
, Right
, RIGHT
, NONE
);
5881 BMOVE (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, Right
, RIGHT
, NONE
);
5883 BMOVE (0, Page_Up
, UP
, PAGE
);
5884 BMOVE (0, KP_Page_Up
, UP
, PAGE
);
5885 BMOVE (0, Page_Down
, DOWN
, PAGE
);
5886 BMOVE (0, KP_Page_Down
, DOWN
, PAGE
);
5888 BMOVE (0, Home
, LEFT
, ALL
);
5889 BMOVE (0, KP_Home
, LEFT
, ALL
);
5890 BMOVE (0, End
, RIGHT
, ALL
);
5891 BMOVE (0, KP_End
, RIGHT
, ALL
);
5892 BMOVE (GDK_CONTROL_MASK
, Home
, UP
, ALL
);
5893 BMOVE (GDK_CONTROL_MASK
, KP_Home
, UP
, ALL
);
5894 BMOVE (GDK_CONTROL_MASK
, End
, DOWN
, ALL
);
5895 BMOVE (GDK_CONTROL_MASK
, KP_End
, DOWN
, ALL
);
5897 #define BCOM(m,key,com) \
5898 gtk_binding_entry_add_signal (binding_set, GDK_KEY_ ## key, m, \
5900 GTK_TYPE_HTML_COMMAND, GTK_HTML_COMMAND_ ## com);
5902 BCOM (0, Home
, SCROLL_BOD
);
5903 BCOM (0, KP_Home
, SCROLL_BOD
);
5904 BCOM (0, End
, SCROLL_EOD
);
5905 BCOM (0, KP_End
, SCROLL_EOD
);
5907 BCOM (GDK_CONTROL_MASK
, c
, COPY
);
5909 BCOM (0, Return
, INSERT_PARAGRAPH
);
5910 BCOM (GDK_SHIFT_MASK
, Return
, INSERT_PARAGRAPH
);
5911 BCOM (0, KP_Enter
, INSERT_PARAGRAPH
);
5912 BCOM (GDK_SHIFT_MASK
, KP_Enter
, INSERT_PARAGRAPH
);
5913 BCOM (0, BackSpace
, DELETE_BACK_OR_INDENT_DEC
);
5914 BCOM (GDK_SHIFT_MASK
, BackSpace
, DELETE_BACK_OR_INDENT_DEC
);
5915 BCOM (0, Delete
, DELETE
);
5916 BCOM (0, KP_Delete
, DELETE
);
5918 BCOM (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
, plus
, ZOOM_IN
);
5919 BCOM (GDK_CONTROL_MASK
, plus
, ZOOM_IN
);
5920 BCOM (GDK_CONTROL_MASK
, equal
, ZOOM_IN
);
5921 BCOM (GDK_CONTROL_MASK
, KP_Add
, ZOOM_IN
);
5922 BCOM (GDK_CONTROL_MASK
, minus
, ZOOM_OUT
);
5923 BCOM (GDK_CONTROL_MASK
, KP_Subtract
, ZOOM_OUT
);
5924 BCOM (GDK_CONTROL_MASK
, 8, ZOOM_IN
);
5925 BCOM (GDK_CONTROL_MASK
, 9, ZOOM_RESET
);
5926 BCOM (GDK_CONTROL_MASK
, 0, ZOOM_OUT
);
5927 BCOM (GDK_CONTROL_MASK
, KP_Multiply
, ZOOM_RESET
);
5930 BCOM (GDK_SHIFT_MASK
, Up
, MODIFY_SELECTION_UP
);
5931 BCOM (GDK_SHIFT_MASK
, Down
, MODIFY_SELECTION_DOWN
);
5932 BCOM (GDK_SHIFT_MASK
, Left
, MODIFY_SELECTION_LEFT
);
5933 BCOM (GDK_SHIFT_MASK
, Right
, MODIFY_SELECTION_RIGHT
);
5934 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, Left
, MODIFY_SELECTION_PREV_WORD
);
5935 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, Right
, MODIFY_SELECTION_NEXT_WORD
);
5936 BCOM (GDK_SHIFT_MASK
, Home
, MODIFY_SELECTION_BOL
);
5937 BCOM (GDK_SHIFT_MASK
, KP_Home
, MODIFY_SELECTION_BOL
);
5938 BCOM (GDK_SHIFT_MASK
, End
, MODIFY_SELECTION_EOL
);
5939 BCOM (GDK_SHIFT_MASK
, KP_End
, MODIFY_SELECTION_EOL
);
5940 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, Home
, MODIFY_SELECTION_BOD
);
5941 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, KP_Home
, MODIFY_SELECTION_BOD
);
5942 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, End
, MODIFY_SELECTION_EOD
);
5943 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, KP_End
, MODIFY_SELECTION_EOD
);
5944 BCOM (GDK_SHIFT_MASK
, Page_Up
, MODIFY_SELECTION_PAGEUP
);
5945 BCOM (GDK_SHIFT_MASK
, Page_Down
, MODIFY_SELECTION_PAGEDOWN
);
5946 BCOM (GDK_SHIFT_MASK
, KP_Page_Up
, MODIFY_SELECTION_PAGEUP
);
5947 BCOM (GDK_SHIFT_MASK
, KP_Page_Down
, MODIFY_SELECTION_PAGEDOWN
);
5948 BCOM (GDK_CONTROL_MASK
, a
, SELECT_ALL
);
5949 BCOM (GDK_CONTROL_MASK
, p
, SELECT_PARAGRAPH
);
5951 /* copy, cut, paste, delete */
5952 BCOM (GDK_CONTROL_MASK
, c
, COPY
);
5953 BCOM (GDK_CONTROL_MASK
, Insert
, COPY
);
5954 BCOM (GDK_CONTROL_MASK
, KP_Insert
, COPY
);
5955 BCOM (0, F16
, COPY
);
5956 BCOM (GDK_CONTROL_MASK
, x
, CUT
);
5957 BCOM (GDK_SHIFT_MASK
, Delete
, CUT
);
5958 BCOM (GDK_SHIFT_MASK
, KP_Delete
, CUT
);
5960 BCOM (GDK_CONTROL_MASK
, v
, PASTE
);
5961 BCOM (GDK_SHIFT_MASK
, Insert
, PASTE
);
5962 BCOM (GDK_SHIFT_MASK
, KP_Insert
, PASTE
);
5963 BCOM (0, F18
, PASTE
);
5964 BCOM (GDK_CONTROL_MASK
, Delete
, KILL_WORD
);
5965 BCOM (GDK_CONTROL_MASK
, BackSpace
, KILL_WORD_BACKWARD
);
5968 BCOM (GDK_CONTROL_MASK
, b
, BOLD_TOGGLE
);
5969 BCOM (GDK_CONTROL_MASK
, i
, ITALIC_TOGGLE
);
5970 BCOM (GDK_CONTROL_MASK
, u
, UNDERLINE_TOGGLE
);
5971 BCOM (GDK_CONTROL_MASK
, o
, TEXT_COLOR_APPLY
);
5972 BCOM (GDK_MOD1_MASK
, 1, SIZE_MINUS_2
);
5973 BCOM (GDK_MOD1_MASK
, 2, SIZE_MINUS_1
);
5974 BCOM (GDK_MOD1_MASK
, 3, SIZE_PLUS_0
);
5975 BCOM (GDK_MOD1_MASK
, 4, SIZE_PLUS_1
);
5976 BCOM (GDK_MOD1_MASK
, 5, SIZE_PLUS_2
);
5977 BCOM (GDK_MOD1_MASK
, 6, SIZE_PLUS_3
);
5978 BCOM (GDK_MOD1_MASK
, 7, SIZE_PLUS_4
);
5979 BCOM (GDK_MOD1_MASK
, 8, SIZE_INCREASE
);
5980 BCOM (GDK_MOD1_MASK
, 9, SIZE_DECREASE
);
5983 BCOM (GDK_CONTROL_MASK
, z
, UNDO
);
5984 BCOM (0, F14
, UNDO
);
5985 BCOM (GDK_CONTROL_MASK
, r
, REDO
);
5987 /* paragraph style */
5988 BCOM (GDK_CONTROL_MASK
| GDK_MOD1_MASK
, l
, ALIGN_LEFT
);
5989 BCOM (GDK_CONTROL_MASK
| GDK_MOD1_MASK
, r
, ALIGN_RIGHT
);
5990 BCOM (GDK_CONTROL_MASK
| GDK_MOD1_MASK
, c
, ALIGN_CENTER
);
5993 BCOM (0, Tab
, INSERT_TAB_OR_NEXT_CELL
);
5994 BCOM (GDK_SHIFT_MASK
, Tab
, PREV_CELL
);
5996 /* spell checking */
5997 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
| GDK_MOD1_MASK
, s
, SPELL_SUGGEST
);
5998 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
| GDK_MOD1_MASK
, p
, SPELL_PERSONAL_DICTIONARY_ADD
);
5999 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
| GDK_MOD1_MASK
, n
, SPELL_SESSION_DICTIONARY_ADD
);
6001 /* popup menu, properties dialog */
6002 BCOM (GDK_MOD1_MASK
, space
, POPUP_MENU
);
6003 BCOM (GDK_MOD1_MASK
, Return
, PROPERTIES_DIALOG
);
6004 BCOM (GDK_MOD1_MASK
, KP_Enter
, PROPERTIES_DIALOG
);
6007 BCOM (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
, t
, INSERT_TABLE_1_1
);
6008 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, l
, TABLE_INSERT_COL_AFTER
);
6009 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, r
, TABLE_INSERT_ROW_AFTER
);
6010 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, s
, TABLE_SPACING_INC
);
6011 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, p
, TABLE_PADDING_INC
);
6012 BCOM (GDK_SHIFT_MASK
| GDK_CONTROL_MASK
, o
, TABLE_BORDER_WIDTH_INC
);
6013 BCOM (GDK_MOD1_MASK
| GDK_CONTROL_MASK
, l
, TABLE_INSERT_COL_BEFORE
);
6014 BCOM (GDK_MOD1_MASK
| GDK_CONTROL_MASK
, r
, TABLE_INSERT_ROW_BEFORE
);
6015 BCOM (GDK_MOD1_MASK
| GDK_CONTROL_MASK
, s
, TABLE_SPACING_DEC
);
6016 BCOM (GDK_MOD1_MASK
| GDK_CONTROL_MASK
, p
, TABLE_PADDING_DEC
);
6017 BCOM (GDK_MOD1_MASK
| GDK_CONTROL_MASK
, o
, TABLE_BORDER_WIDTH_DEC
);
6018 BCOM (GDK_SHIFT_MASK
| GDK_MOD1_MASK
, l
, TABLE_DELETE_COL
);
6019 BCOM (GDK_SHIFT_MASK
| GDK_MOD1_MASK
, r
, TABLE_DELETE_ROW
);
6020 BCOM (GDK_SHIFT_MASK
| GDK_MOD1_MASK
, s
, TABLE_SPACING_ZERO
);
6021 BCOM (GDK_SHIFT_MASK
| GDK_MOD1_MASK
, p
, TABLE_PADDING_ZERO
);
6022 BCOM (GDK_SHIFT_MASK
| GDK_MOD1_MASK
, o
, TABLE_BORDER_WIDTH_ZERO
);
6026 gtk_html_set_iframe_parent (GtkHTML
*html
,
6030 GtkWidget
*top_level
;
6032 g_assert (GTK_IS_HTML (parent
));
6034 gtk_html_set_animate (html
, gtk_html_get_animate (GTK_HTML (parent
)));
6036 html
->iframe_parent
= parent
;
6037 html
->frame
= frame
;
6039 top_level
= GTK_WIDGET (gtk_html_get_top_html (html
));
6040 if (html
->engine
&& html
->engine
->painter
) {
6041 html_painter_set_widget (html
->engine
->painter
, top_level
);
6042 gtk_html_set_fonts (html
, html
->engine
->painter
);
6044 g_signal_emit (top_level
, signals
[IFRAME_CREATED
], 0, html
);
6046 while (html
->iframe_parent
) {
6048 html
= GTK_HTML (html
->iframe_parent
);
6055 gtk_html_select_word (GtkHTML
*html
)
6059 if (!html
->allow_selection
)
6063 if (html_engine_get_editable (e
))
6064 html_engine_select_word_editable (e
);
6066 html_engine_select_word (e
);
6068 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6069 update_primary_selection (html
);
6073 gtk_html_select_line (GtkHTML
*html
)
6077 if (!html
->allow_selection
)
6081 if (html_engine_get_editable (e
))
6082 html_engine_select_line_editable (e
);
6084 html_engine_select_line (e
);
6086 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6087 update_primary_selection (html
);
6091 gtk_html_select_paragraph (GtkHTML
*html
)
6095 if (!html
->allow_selection
)
6099 if (html_engine_get_editable (e
))
6100 html_engine_select_paragraph_editable (e
);
6101 /* FIXME: does anybody need this? if so bother me. rodo
6103 * html_engine_select_paragraph (e); */
6105 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6106 update_primary_selection (html
);
6110 gtk_html_select_paragraph_extended (GtkHTML
*html
)
6114 if (!html
->allow_selection
)
6118 if (html_engine_get_editable (e
))
6119 html_engine_select_paragraph_extended (e
);
6120 /* FIXME: does anybody need this? if so bother me. rodo
6122 * html_engine_select_paragraph (e); */
6124 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6125 update_primary_selection (html
);
6129 gtk_html_select_all (GtkHTML
*html
)
6133 if (!html
->allow_selection
)
6138 if (html_engine_get_editable (e
))
6139 html_engine_select_all_editable (e
);
6141 html_engine_select_all (e
);
6144 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6145 update_primary_selection (html
);
6149 gtk_html_unselect_all (GtkHTML
*html
)
6155 html_engine_unselect_all (e
);
6157 html_engine_update_selection_active_state (html
->engine
, html
->priv
->event_time
);
6158 update_primary_selection (html
);
6162 gtk_html_api_set_language (GtkHTML
*html
)
6164 g_return_if_fail (GTK_IS_HTML (html
));
6166 if (html
->editor_api
) {
6167 html
->editor_api
->set_language (html
, html_engine_get_language (html
->engine
), html
->editor_data
);
6168 html_engine_spell_check (html
->engine
);
6173 gtk_html_set_editor_api (GtkHTML
*html
,
6174 GtkHTMLEditorAPI
*api
,
6177 html
->editor_api
= api
;
6178 html
->editor_data
= data
;
6180 gtk_html_api_set_language (html
);
6183 static const gchar
*
6184 get_value_nick (GtkHTMLCommandType com_type
)
6187 GEnumClass
*enum_class
;
6189 enum_class
= g_type_class_ref (GTK_TYPE_HTML_COMMAND
);
6190 val
= g_enum_get_value (enum_class
, com_type
);
6191 g_type_class_unref (enum_class
);
6193 return val
->value_nick
;
6195 g_warning ("Invalid GTK_TYPE_HTML_COMMAND enum value %d\n", com_type
);
6201 gtk_html_editor_event_command (GtkHTML
*html
,
6202 GtkHTMLCommandType com_type
,
6207 memset (&arg
, 0, sizeof (GValue
));
6208 g_value_init (&arg
, G_TYPE_STRING
);
6209 g_value_set_string (&arg
, get_value_nick (com_type
));
6211 gtk_html_editor_event (html
, before
? GTK_HTML_EDITOR_EVENT_COMMAND_BEFORE
: GTK_HTML_EDITOR_EVENT_COMMAND_AFTER
,
6214 g_value_unset (&arg
);
6218 gtk_html_editor_event (GtkHTML
*html
,
6219 GtkHTMLEditorEventType event
,
6222 GValue
*retval
= NULL
;
6224 if (html
->editor_api
&& !html
->engine
->block_events
)
6225 retval
= (*html
->editor_api
->event
) (html
, event
, args
, html
->editor_data
);
6228 g_value_unset (retval
);
6234 gtk_html_command (GtkHTML
*html
,
6235 const gchar
*command_name
)
6240 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
6241 g_return_val_if_fail (command_name
!= NULL
, FALSE
);
6243 class = G_ENUM_CLASS (g_type_class_ref (GTK_TYPE_HTML_COMMAND
));
6244 val
= g_enum_get_value_by_nick (class, command_name
);
6245 g_type_class_unref (class);
6247 if (command (html
, val
->value
)) {
6248 if (html
->priv
->update_styles
)
6249 gtk_html_update_styles (html
);
6258 gtk_html_edit_make_cursor_visible (GtkHTML
*html
)
6260 GtkAdjustment
*hadjustment
;
6261 GtkAdjustment
*vadjustment
;
6262 gboolean rv
= FALSE
;
6264 g_return_val_if_fail (GTK_IS_HTML (html
), rv
);
6266 hadjustment
= gtk_layout_get_hadjustment (GTK_LAYOUT (html
));
6267 vadjustment
= gtk_layout_get_vadjustment (GTK_LAYOUT (html
));
6269 html_engine_hide_cursor (html
->engine
);
6270 if (html_engine_make_cursor_visible (html
->engine
)) {
6271 gtk_adjustment_set_value (hadjustment
, (gfloat
) html
->engine
->x_offset
);
6272 gtk_adjustment_set_value (vadjustment
, (gfloat
) html
->engine
->y_offset
);
6275 html_engine_show_cursor (html
->engine
);
6281 gtk_html_build_with_gconf (void)
6287 reparent_embedded (HTMLObject
*o
,
6291 if (html_object_is_embedded (o
)) {
6292 HTMLEmbedded
*eo
= HTML_EMBEDDED (o
);
6293 GtkWidget
*parent
= NULL
;
6295 if (eo
->widget
!= NULL
)
6296 parent
= gtk_widget_get_parent (eo
->widget
);
6298 if (parent
&& GTK_IS_HTML (parent
) &&
6299 GTK_HTML (parent
)->iframe_parent
== NULL
) {
6300 g_object_ref (eo
->widget
);
6301 gtk_container_remove (GTK_CONTAINER (parent
), eo
->widget
);
6302 g_object_force_floating (G_OBJECT (eo
->widget
));
6307 if (HTML_IS_IFRAME (o
) && GTK_HTML (HTML_IFRAME (o
)->html
)->iframe_parent
&&
6308 GTK_HTML (GTK_HTML (HTML_IFRAME (o
)->html
)->iframe_parent
)->iframe_parent
== NULL
)
6309 gtk_html_set_iframe_parent (GTK_HTML (HTML_IFRAME (o
)->html
), data
, o
);
6311 if (HTML_IS_FRAME (o
) && GTK_HTML (HTML_FRAME (o
)->html
)->iframe_parent
&&
6312 GTK_HTML (GTK_HTML (HTML_FRAME (o
)->html
)->iframe_parent
)->iframe_parent
== NULL
)
6313 gtk_html_set_iframe_parent (GTK_HTML (HTML_FRAME (o
)->html
), data
, o
);
6315 if (HTML_IS_FRAMESET (o
) && HTML_FRAMESET (o
)->parent
&&
6316 HTML_FRAMESET (o
)->parent
->iframe_parent
== NULL
) {
6317 HTML_FRAMESET (o
)->parent
= data
;
6322 gtk_html_insert_html_generic (GtkHTML
*html
,
6324 const gchar
*html_src
,
6327 GtkWidget
*window
, *sw
;
6330 html_engine_freeze (html
->engine
);
6331 html_engine_delete (html
->engine
);
6333 tmp
= GTK_HTML (gtk_html_new_from_string (html_src
, -1));
6334 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
6335 sw
= gtk_scrolled_window_new (NULL
, NULL
);
6336 gtk_container_add (GTK_CONTAINER (window
), GTK_WIDGET (sw
));
6337 gtk_container_add (GTK_CONTAINER (sw
), GTK_WIDGET (tmp
));
6338 gtk_widget_realize (GTK_WIDGET (tmp
));
6339 html_image_factory_move_images (html
->engine
->image_factory
, tmp
->engine
->image_factory
);
6341 /* copy the forms */
6342 g_list_foreach (tmp
->engine
->formList
, (GFunc
) html_form_set_engine
, html
->engine
);
6344 /* move top level iframes and embedded widgets from tmp to html */
6345 html_object_forall (tmp
->engine
->clue
, html
->engine
, reparent_embedded
, html
);
6347 if (tmp
->engine
->formList
&& html
->engine
->formList
) {
6350 form_last
= g_list_last (html
->engine
->formList
);
6351 tmp
->engine
->formList
->prev
= form_last
;
6352 form_last
->next
= tmp
->engine
->formList
;
6353 } else if (tmp
->engine
->formList
) {
6354 html
->engine
->formList
= tmp
->engine
->formList
;
6356 tmp
->engine
->formList
= NULL
;
6360 g_return_if_fail (tmp
->engine
->clue
&& HTML_CLUE (tmp
->engine
->clue
)->head
6361 && HTML_CLUE (HTML_CLUE (tmp
->engine
->clue
)->head
)->head
);
6363 html_undo_level_begin (html
->engine
->undo
, "Append HTML", "Remove appended HTML");
6364 o
= HTML_CLUE (tmp
->engine
->clue
)->head
;
6365 for (; o
; o
= next
) {
6367 html_object_remove_child (o
->parent
, o
);
6368 html_engine_append_flow (html
->engine
, o
, html_object_get_recursive_length (o
));
6370 html_undo_level_end (html
->engine
->undo
, html
->engine
);
6372 g_return_if_fail (tmp
->engine
->clue
);
6374 o
= tmp
->engine
->clue
;
6375 /* skip empty HTML */
6376 if (html_object_get_recursive_length (o
) > 0) {
6377 tmp
->engine
->clue
= NULL
;
6378 html_engine_insert_object (html
->engine
, o
,
6379 html_object_get_recursive_length (o
),
6380 html_engine_get_insert_level_for_object (html
->engine
, o
));
6383 gtk_widget_destroy (window
);
6384 html_engine_thaw (html
->engine
);
6388 gtk_html_insert_html (GtkHTML
*html
,
6389 const gchar
*html_src
)
6391 g_return_if_fail (GTK_IS_HTML (html
));
6393 gtk_html_insert_html_generic (html
, NULL
, html_src
, FALSE
);
6397 gtk_html_insert_gtk_html (GtkHTML
*html
,
6398 GtkHTML
*to_be_destroyed
)
6400 g_return_if_fail (GTK_IS_HTML (html
));
6402 gtk_html_insert_html_generic (html
, to_be_destroyed
, NULL
, FALSE
);
6406 gtk_html_append_html (GtkHTML
*html
,
6407 const gchar
*html_src
)
6409 g_return_if_fail (GTK_IS_HTML (html
));
6411 gtk_html_insert_html_generic (html
, NULL
, html_src
, TRUE
);
6415 set_magnification (HTMLObject
*o
,
6419 if (HTML_IS_FRAME (o
)) {
6420 html_font_manager_set_magnification (>K_HTML (HTML_FRAME (o
)->html
)->engine
->painter
->font_manager
,
6422 } else if (HTML_IS_IFRAME (o
)) {
6423 html_font_manager_set_magnification (>K_HTML (HTML_IFRAME (o
)->html
)->engine
->painter
->font_manager
,
6425 } else if (HTML_IS_TEXT (o
))
6426 html_text_calc_font_size (HTML_TEXT (o
), e
);
6430 gtk_html_set_magnification (GtkHTML
*html
,
6431 gdouble magnification
)
6433 g_return_if_fail (GTK_IS_HTML (html
));
6435 if (magnification
> 0.05 && magnification
< 20.0
6436 && magnification
* html
->engine
->painter
->font_manager
.var_size
>= 4 * PANGO_SCALE
6437 && magnification
* html
->engine
->painter
->font_manager
.fix_size
>= 4 * PANGO_SCALE
) {
6438 html_font_manager_set_magnification (&html
->engine
->painter
->font_manager
, magnification
);
6439 if (html
->engine
->clue
) {
6440 html_object_forall (html
->engine
->clue
, html
->engine
,
6441 set_magnification
, &magnification
);
6442 html_object_change_set_down (html
->engine
->clue
, HTML_CHANGE_ALL
);
6445 html_engine_schedule_update (html
->engine
);
6449 #define MAG_STEP 1.1
6452 gtk_html_zoom_in (GtkHTML
*html
)
6454 g_return_if_fail (GTK_IS_HTML (html
));
6456 gtk_html_set_magnification (html
, html
->engine
->painter
->font_manager
.magnification
* MAG_STEP
);
6460 gtk_html_zoom_out (GtkHTML
*html
)
6462 g_return_if_fail (GTK_IS_HTML (html
));
6463 g_return_if_fail (HTML_IS_ENGINE (html
->engine
));
6465 gtk_html_set_magnification (html
, html
->engine
->painter
->font_manager
.magnification
* (1.0 / MAG_STEP
));
6469 gtk_html_zoom_reset (GtkHTML
*html
)
6471 g_return_if_fail (GTK_IS_HTML (html
));
6473 gtk_html_set_magnification (html
, 1.0);
6477 gtk_html_set_allow_frameset (GtkHTML
*html
,
6480 g_return_if_fail (GTK_IS_HTML (html
));
6481 g_return_if_fail (HTML_IS_ENGINE (html
->engine
));
6483 html
->engine
->allow_frameset
= allow
;
6487 gtk_html_get_allow_frameset (GtkHTML
*html
)
6489 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
6490 g_return_val_if_fail (HTML_IS_ENGINE (html
->engine
), FALSE
);
6492 return html
->engine
->allow_frameset
;
6496 gtk_html_images_ref (GtkHTML
*html
)
6498 html_image_factory_ref_all_images (HTML_IMAGE_FACTORY (html
->engine
->image_factory
));
6502 gtk_html_images_unref (GtkHTML
*html
)
6504 html_image_factory_unref_all_images (HTML_IMAGE_FACTORY (html
->engine
->image_factory
));
6508 gtk_html_image_ref (GtkHTML
*html
,
6511 html_image_factory_ref_image_ptr (HTML_IMAGE_FACTORY (html
->engine
->image_factory
), url
);
6515 gtk_html_image_unref (GtkHTML
*html
,
6518 html_image_factory_unref_image_ptr (HTML_IMAGE_FACTORY (html
->engine
->image_factory
), url
);
6522 gtk_html_image_preload (GtkHTML
*html
,
6525 html_image_factory_register (HTML_IMAGE_FACTORY (html
->engine
->image_factory
), NULL
, url
, FALSE
);
6529 gtk_html_set_blocking (GtkHTML
*html
,
6532 html
->engine
->block
= block
;
6536 gtk_html_set_images_blocking (GtkHTML
*html
,
6539 html
->engine
->block_images
= block
;
6543 gtk_html_print_page_get_pages_num (GtkHTML
*html
,
6544 GtkPrintContext
*context
,
6545 gdouble header_height
,
6546 gdouble footer_height
)
6548 return html_engine_print_get_pages_num (
6549 html
->engine
, context
, header_height
, footer_height
);
6552 GtkPrintOperationResult
6553 gtk_html_print_operation_run (GtkHTML
*html
,
6554 GtkPrintOperation
*operation
,
6555 GtkPrintOperationAction action
,
6557 GtkHTMLPrintCalcHeight calc_header_height
,
6558 GtkHTMLPrintCalcHeight calc_footer_height
,
6559 GtkHTMLPrintDrawFunc draw_header
,
6560 GtkHTMLPrintDrawFunc draw_footer
,
6564 return html_engine_print_operation_run (
6565 html
->engine
, operation
, action
, parent
,
6566 calc_header_height
, calc_footer_height
,
6567 draw_header
, draw_footer
, user_data
, error
);
6571 gtk_html_has_undo (GtkHTML
*html
)
6573 return html_undo_has_undo_steps (html
->engine
->undo
);
6577 gtk_html_drop_undo (GtkHTML
*html
)
6579 html_undo_reset (html
->engine
->undo
);
6583 gtk_html_flush (GtkHTML
*html
)
6585 html_engine_flush (html
->engine
);
6589 gtk_html_get_object_id_at (GtkHTML
*html
,
6593 HTMLObject
*o
= html_engine_get_object_at (html
->engine
, x
, y
, NULL
, FALSE
);
6594 const gchar
*id
= NULL
;
6597 id
= html_object_get_id (o
);
6607 gtk_html_get_url_at (GtkHTML
*html
,
6614 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
6616 obj
= html_engine_get_object_at (html
->engine
, x
, y
, (guint
*) &offset
, FALSE
);
6619 return gtk_html_get_url_object_relative (html
, obj
, html_object_get_url (obj
, offset
));
6625 gtk_html_get_cursor_url (GtkHTML
*html
)
6630 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
6632 if (html
->engine
->caret_mode
) {
6633 obj
= html
->engine
->cursor
->object
;
6634 offset
= html
->engine
->cursor
->offset
;
6636 obj
= html_engine_get_focus_object (html
->engine
, &offset
);
6639 return gtk_html_get_url_object_relative (html
, obj
, html_object_get_url (obj
, offset
));
6645 gtk_html_get_image_src_at (GtkHTML
*html
,
6652 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
6654 obj
= html_engine_get_object_at (html
->engine
, x
, y
, (guint
*) &offset
, FALSE
);
6656 if (obj
&& HTML_IS_IMAGE (obj
)) {
6657 HTMLImage
*image
= (HTMLImage
*) obj
;
6659 if (!image
->image_ptr
)
6662 return g_strdup (image
->image_ptr
->url
);
6668 /* Unref when done with it */
6669 GdkPixbufAnimation
*
6670 gtk_html_get_image_at (GtkHTML
*html
,
6677 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
6679 obj
= html_engine_get_object_at (html
->engine
, x
, y
, (guint
*) &offset
, FALSE
);
6681 if (obj
&& HTML_IS_IMAGE (obj
)) {
6682 HTMLImage
*image
= (HTMLImage
*) obj
;
6684 if (!image
->image_ptr
|| !image
->image_ptr
->animation
)
6687 return g_object_ref (image
->image_ptr
->animation
);
6694 gtk_html_get_cursor_image_src (GtkHTML
*html
)
6699 g_return_val_if_fail (GTK_IS_HTML (html
), NULL
);
6701 if (html
->engine
->caret_mode
) {
6702 obj
= html
->engine
->cursor
->object
;
6703 offset
= html
->engine
->cursor
->offset
;
6705 obj
= html_engine_get_focus_object (html
->engine
, &offset
);
6707 if (obj
&& HTML_IS_IMAGE (obj
)) {
6708 HTMLImage
*image
= (HTMLImage
*) obj
;
6710 if (!image
->image_ptr
)
6713 return g_strdup (image
->image_ptr
->url
);
6720 gtk_html_set_tokenizer (GtkHTML
*html
,
6721 HTMLTokenizer
*tokenizer
)
6723 g_return_if_fail (GTK_IS_HTML (html
));
6725 html_engine_set_tokenizer (html
->engine
, tokenizer
);
6729 gtk_html_get_cursor_pos (GtkHTML
*html
,
6733 gboolean read
= FALSE
;
6735 g_return_val_if_fail (html
!= NULL
, FALSE
);
6736 g_return_val_if_fail (GTK_IS_HTML (html
), FALSE
);
6738 if (html
->engine
&& html
->engine
->cursor
) {
6742 *position
= html
->engine
->cursor
->position
;
6744 *offset
= html
->engine
->cursor
->offset
;
6751 gtk_html_filename_from_uri (const gchar
*uri
)
6753 const gchar
*relative_fpath
;
6754 gchar
*temp_uri
, *temp_filename
;
6760 if (g_ascii_strncasecmp (uri
, "file://", 7) == 0)
6761 return g_filename_from_uri (uri
, NULL
, NULL
);
6763 if (g_ascii_strncasecmp (uri
, "file:", 5) == 0) {
6764 /* Relative (file or other) URIs shouldn't contain the
6765 * scheme prefix at all. But accept such broken URIs
6766 * anyway. Whether they are URI-encoded or not is
6767 * anybody's guess, assume they are.
6769 relative_fpath
= uri
+ 5;
6771 /* A proper relative file URI. Just do the URI-decoding. */
6772 relative_fpath
= uri
;
6775 if (g_path_is_absolute (relative_fpath
)) {
6776 /* The totally broken case of "file:" followed
6777 * directly by an absolute pathname.
6779 /* file:/foo/bar.zap or file:c:/foo/bar.zap */
6781 if (g_ascii_isalpha (relative_fpath
[0]) && relative_fpath
[1] == ':')
6782 temp_uri
= g_strconcat ("file:///", relative_fpath
, NULL
);
6784 temp_uri
= g_strconcat ("file://", relative_fpath
, NULL
);
6786 temp_uri
= g_strconcat ("file://", relative_fpath
, NULL
);
6788 retval
= g_filename_from_uri (temp_uri
, NULL
, NULL
);
6794 /* Create a dummy absolute file: URI and call
6795 * g_filename_from_uri(), then strip off the dummy
6799 if (g_ascii_isalpha (relative_fpath
[0]) && relative_fpath
[1] == ':') {
6800 /* file:c:relative/path/foo.bar */
6801 gchar drive_letter
= relative_fpath
[0];
6803 temp_uri
= g_strconcat ("file:///dummy/", relative_fpath
+ 2, NULL
);
6804 temp_filename
= g_filename_from_uri (temp_uri
, NULL
, NULL
);
6807 if (temp_filename
== NULL
)
6810 g_assert (strncmp (temp_filename
, G_DIR_SEPARATOR_S
"dummy" G_DIR_SEPARATOR_S
, 7) == 0);
6812 retval
= g_strdup_printf ("%c:%s", drive_letter
, temp_filename
+ 7);
6813 g_free (temp_filename
);
6818 temp_uri
= g_strconcat ("file:///dummy/", relative_fpath
, NULL
);
6819 temp_filename
= g_filename_from_uri (temp_uri
, NULL
, NULL
);
6822 if (temp_filename
== NULL
)
6825 g_assert (strncmp (temp_filename
, G_DIR_SEPARATOR_S
"dummy" G_DIR_SEPARATOR_S
, 7) == 0);
6827 retval
= g_strdup (temp_filename
+ 7);
6828 g_free (temp_filename
);
6834 gtk_html_filename_to_uri (const gchar
*filename
)
6836 gchar
*fake_filename
, *fake_uri
, *retval
;
6837 const gchar dummy_prefix
[] = "file:///dummy/";
6838 const gint dummy_prefix_len
= sizeof (dummy_prefix
) - 1;
6840 gchar drive_letter
= 0;
6842 gchar
*first_end
, *colon
;
6845 if (!filename
|| !*filename
)
6848 if (g_path_is_absolute (filename
))
6849 return g_filename_to_uri (filename
, NULL
, NULL
);
6851 /* filename is a relative path, and the corresponding URI is
6852 * filename as such but URI-escaped. Instead of yet again
6853 * copy-pasteing the URI-escape code from gconvert.c (or
6854 * somewhere else), prefix a fake top-level directory to make
6855 * it into an absolute path, call g_filename_to_uri() to turn it
6856 * into a full file: URI, and then strip away the file:/// and
6857 * the fake top-level directory.
6861 if (g_ascii_isalpha (*filename
) && filename
[1] == ':') {
6862 /* A non-absolute path, but with a drive letter. Ugh. */
6863 drive_letter
= *filename
;
6867 fake_filename
= g_build_filename ("/dummy", filename
, NULL
);
6868 fake_uri
= g_filename_to_uri (fake_filename
, NULL
, NULL
);
6869 g_free (fake_filename
);
6871 if (fake_uri
== NULL
)
6874 g_assert (strncmp (fake_uri
, dummy_prefix
, dummy_prefix_len
) == 0);
6877 /* Re-insert the drive letter if we had one. Double ugh.
6878 * URI-encode the colon so the drive letter isn't taken for a
6882 retval
= g_strdup_printf ("%c%%3a%s",
6884 fake_uri
+ dummy_prefix_len
);
6886 retval
= g_strdup (fake_uri
+ dummy_prefix_len
);
6888 retval
= g_strdup (fake_uri
+ dummy_prefix_len
);
6893 /* Check if there are colons in the first component of the
6894 * pathname, and URI-encode them so that the part up to the
6895 * colon isn't taken for a URI scheme name! This isn't
6896 * necessary on Win32 as there can't be colons in a file name
6897 * in the first place.
6899 first_end
= strchr (retval
, '/');
6900 if (first_end
== NULL
)
6901 first_end
= retval
+ strlen (retval
);
6903 while ((colon
= strchr (retval
, ':')) != NULL
&& colon
< first_end
) {
6904 gchar
*new_retval
= g_malloc (strlen (retval
) + 3);
6906 strncpy (new_retval
, retval
, colon
- retval
);
6907 strcpy (new_retval
+ (colon
- retval
), "%3a");
6908 strcpy (new_retval
+ (colon
- retval
) + 3, colon
+ 1);
6911 retval
= new_retval
;
6918 #ifdef UNIT_TEST_URI_CONVERSIONS
6920 /* To test the uri<->filename code, cut&paste the above two functions
6921 * and this part into a separate file, insert #include <glib.h>, and
6922 * build with -DUNIT_TEST_URI_CONVERSIONS.
6925 static const gchar
*const tests
[][3] = {
6926 /* Each test case has three strings:
6928 * 0) a URI, the source for the uri->filename conversion test,
6929 * or NULL if this test is only for the filename->uri
6932 * 1) a filename or NULL, the expected result from
6933 * uri->filename conversion. If non-NULL also the source for
6934 * the filename->uri conversion test,
6936 * 2) a URI if the expected result from filename->uri is
6937 * different than string 0, or NULL if the result should be
6938 * equal to string 0.
6940 { "file:///top/s%20pace%20d/sub/file", "/top/s pace d/sub/file", NULL
},
6941 { "file:///top/sub/sub/", "/top/sub/sub/", NULL
},
6942 { "file:///top/sub/file#segment", NULL
, NULL
},
6943 { "file://tem", NULL
, NULL
},
6944 { "file:/tem", "/tem", "file:///tem" },
6945 { "file:sub/tem", "sub/tem", "sub/tem" },
6946 { "sub/tem", "sub/tem", NULL
},
6947 { "s%20pace%20d/tem", "s pace d/tem", NULL
},
6948 { "tem", "tem", NULL
},
6949 { "tem#segment", NULL
, NULL
},
6951 /* More or less same tests, but including a drive letter */
6952 { "file:///x:/top/s%20pace%20d/sub/file", "x:/top/s pace d/sub/file", NULL
},
6953 { "file:///x:top/sub/sub/", "x:top/sub/sub/", "x%3atop/sub/sub/" },
6954 { "file:///x:top/sub/file#segment", NULL
, NULL
},
6955 { "file://x:tem", NULL
, NULL
},
6956 { "file:x:/tem", "x:/tem", "file:///x:/tem" },
6957 { "file:x:tem", "x:tem", "x%3atem" },
6958 { "file:x:sub/tem", "x:sub/tem", "x%3asub/tem" },
6959 { "x%3as%20pace%20d/tem", "x:s pace d/tem", NULL
},
6960 { "x%3atem", "x:tem", NULL
},
6961 { "x%3atem#segment", NULL
, NULL
},
6964 /* Test filenames with a colon in them. That's not possible on Win32 */
6965 { "file:///top/silly:name/bar", "/top/silly:name/bar", NULL
},
6966 { "silly%3aname/bar", "silly:name/bar", NULL
},
6967 { "silly%3aname", "silly:name", NULL
},
6979 for (i
= 0; i
< G_N_ELEMENTS (tests
); i
++) {
6982 gchar
*expected_result
;
6985 const gchar
*expected_result
;
6987 if (tests
[i
][0] == NULL
)
6990 filename
= gtk_html_filename_from_uri (tests
[i
][0]);
6992 expected_result
= g_strdup (tests
[i
][1]);
6993 if (expected_result
)
6994 while ((slash
= strchr (expected_result
, '/')) != NULL
)
6997 expected_result
= tests
[i
][1];
7000 if (((filename
== NULL
) != (expected_result
== NULL
)) ||
7001 (filename
!= NULL
&& strcmp (filename
, expected_result
) != 0)) {
7002 g_print ("FAIL: %s -> %s, GOT: %s\n",
7004 expected_result
? expected_result
: "NULL",
7005 filename
? filename
: "NULL");
7008 g_print ("OK: %s -> %s\n",
7010 filename
? filename
: "NULL");
7014 for (i
= 0; i
< G_N_ELEMENTS (tests
); i
++) {
7016 const gchar
*expected_result
;
7018 if (tests
[i
][1] == NULL
)
7021 uri
= gtk_html_filename_to_uri (tests
[i
][1]);
7022 expected_result
= tests
[i
][2] ? tests
[i
][2] : tests
[i
][0];
7023 if (((uri
== NULL
) != (expected_result
== NULL
)) ||
7024 (uri
!= NULL
&& strcmp (uri
, expected_result
) != 0)) {
7025 g_printf ("FAIL: %s -> %s, GOT: %s\n",
7027 expected_result
? expected_result
: "NULL",
7028 uri
? uri
: "NULL");
7031 g_print ("OK: %s -> %s\n",
7033 uri
? uri
: "NULL");
7038 /* Test filename->uri also with backslashes */
7039 for (i
= 0; i
< G_N_ELEMENTS (tests
); i
++) {
7041 gchar
*filename
, *slash
;
7042 const gchar
*expected_result
;
7044 if (tests
[i
][1] == NULL
|| strchr (tests
[i
][1], '/') == NULL
)
7047 filename
= g_strdup (tests
[i
][1]);
7048 while ((slash
= strchr (filename
, '/')) != NULL
)
7050 uri
= gtk_html_filename_to_uri (tests
[i
][1]);
7051 expected_result
= tests
[i
][2] ? tests
[i
][2] : tests
[i
][0];
7052 if (((uri
== NULL
) != (expected_result
== NULL
)) ||
7053 (uri
!= NULL
&& strcmp (uri
, expected_result
) != 0)) {
7054 g_printf ("FAIL: %s -> %s, GOT: %s\n",
7056 expected_result
? expected_result
: "NULL",
7057 uri
? uri
: "NULL");
7060 g_print ("OK: %s -> %s\n",
7062 uri
? uri
: "NULL");
7067 return failures
!= 0;