Update Romanian translation
[evolution.git] / src / web-extensions / e-web-extension.c
blob94757f5bcae63f7f7807f766566abe412b081d6b
1 /*
2 * e-web-extension.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
19 #include "evolution-config.h"
21 #include <string.h>
23 #include <gio/gio.h>
24 #include <glib/gstdio.h>
25 #include <gtk/gtk.h>
27 #include <camel/camel.h>
28 #include <libedataserver/libedataserver.h>
30 #include "e-web-extension.h"
31 #include "e-dom-utils.h"
32 #include "e-web-extension-names.h"
34 #include <webkitdom/webkitdom.h>
36 #define WEB_EXTENSION_PAGE_ID_KEY "web-extension-page-id"
38 #define E_WEB_EXTENSION_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE \
40 ((obj), E_TYPE_WEB_EXTENSION, EWebExtensionPrivate))
42 typedef struct _EWebPageData {
43 WebKitWebPage *web_page; /* not referenced */
44 gboolean need_input;
45 guint32 clipboard_flags;
46 } EWebPageData;
48 struct _EWebExtensionPrivate {
49 WebKitWebExtension *wk_extension;
51 GDBusConnection *dbus_connection;
52 guint registration_id;
54 gboolean initialized;
56 GHashTable *pages; /* guint64 *webpage_id ~> EWebPageData * */
59 static const char introspection_xml[] =
60 "<node>"
61 " <interface name='" E_WEB_EXTENSION_INTERFACE "'>"
62 " <method name='RegisterElementClicked'>"
63 " <arg type='t' name='page_id' direction='in'/>"
64 " <arg type='s' name='element_class' direction='in'/>"
65 " </method>"
66 " <signal name='ElementClicked'>"
67 " <arg type='t' name='page_id' direction='out'/>"
68 " <arg type='s' name='element_class' direction='out'/>"
69 " <arg type='s' name='element_value' direction='out'/>"
70 " <arg type='i' name='position_left' direction='out'/>"
71 " <arg type='i' name='position_top' direction='out'/>"
72 " <arg type='i' name='position_width' direction='out'/>"
73 " <arg type='i' name='position_height' direction='out'/>"
74 " </signal>"
75 " <method name='SetElementHidden'>"
76 " <arg type='t' name='page_id' direction='in'/>"
77 " <arg type='s' name='element_id' direction='in'/>"
78 " <arg type='b' name='hidden' direction='in'/>"
79 " </method>"
80 " <method name='SetElementStyleProperty'>"
81 " <arg type='t' name='page_id' direction='in'/>"
82 " <arg type='s' name='element_id' direction='in'/>"
83 " <arg type='s' name='property_name' direction='in'/>"
84 " <arg type='s' name='value' direction='in'/>"
85 " <arg type='s' name='priority' direction='in'/>"
86 " </method>"
87 " <method name='SetElementAttribute'>"
88 " <arg type='t' name='page_id' direction='in'/>"
89 " <arg type='s' name='element_id' direction='in'/>"
90 " <arg type='s' name='namespace_uri' direction='in'/>"
91 " <arg type='s' name='qualified_name' direction='in'/>"
92 " <arg type='s' name='value' direction='in'/>"
93 " </method>"
94 " <signal name='HeadersCollapsed'>"
95 " <arg type='b' name='expanded' direction='out'/>"
96 " </signal>"
97 " <method name='DocumentHasSelection'>"
98 " <arg type='t' name='page_id' direction='in'/>"
99 " <arg type='b' name='has_selection' direction='out'/>"
100 " </method>"
101 " <method name='GetDocumentContentHTML'>"
102 " <arg type='t' name='page_id' direction='in'/>"
103 " <arg type='s' name='html_content' direction='out'/>"
104 " </method>"
105 " <method name='GetSelectionContentHTML'>"
106 " <arg type='t' name='page_id' direction='in'/>"
107 " <arg type='s' name='html_content' direction='out'/>"
108 " </method>"
109 " <method name='GetSelectionContentText'>"
110 " <arg type='t' name='page_id' direction='in'/>"
111 " <arg type='s' name='text_content' direction='out'/>"
112 " </method>"
113 " <method name='GetSelectionContentMultipart'>"
114 " <arg type='t' name='page_id' direction='in'/>"
115 " <arg type='s' name='content' direction='out'/>"
116 " <arg type='b' name='is_html' direction='out'/>"
117 " </method>"
118 " <method name='CreateAndAddCSSStyleSheet'>"
119 " <arg type='t' name='page_id' direction='in'/>"
120 " <arg type='s' name='style_sheet_id' direction='in'/>"
121 " </method>"
122 " <method name='AddCSSRuleIntoStyleSheet'>"
123 " <arg type='t' name='page_id' direction='in'/>"
124 " <arg type='s' name='style_sheet_id' direction='in'/>"
125 " <arg type='s' name='selector' direction='in'/>"
126 " <arg type='s' name='style' direction='in'/>"
127 " </method>"
128 " <method name='EABContactFormatterBindDOM'>"
129 " <arg type='t' name='page_id' direction='in'/>"
130 " </method>"
131 " <method name='EMailDisplayBindDOM'>"
132 " <arg type='t' name='page_id' direction='in'/>"
133 " </method>"
134 " <method name='ElementExists'>"
135 " <arg type='t' name='page_id' direction='in'/>"
136 " <arg type='s' name='element_id' direction='in'/>"
137 " <arg type='b' name='element_exists' direction='out'/>"
138 " <arg type='t' name='page_id' direction='out'/>"
139 " </method>"
140 " <method name='GetActiveElementName'>"
141 " <arg type='t' name='page_id' direction='in'/>"
142 " <arg type='s' name='element_name' direction='out'/>"
143 " </method>"
144 " <method name='EMailPartHeadersBindDOMElement'>"
145 " <arg type='t' name='page_id' direction='in'/>"
146 " <arg type='s' name='element_id' direction='in'/>"
147 " </method>"
148 " <signal name='VCardInlineDisplayModeToggled'>"
149 " <arg type='s' name='button_id' direction='out'/>"
150 " </signal>"
151 " <signal name='VCardInlineSaveButtonPressed'>"
152 " <arg type='s' name='button_value' direction='out'/>"
153 " </signal>"
154 " <method name='VCardInlineBindDOM'>"
155 " <arg type='t' name='page_id' direction='in'/>"
156 " <arg type='s' name='element_id' direction='in'/>"
157 " </method>"
158 " <method name='VCardInlineUpdateButton'>"
159 " <arg type='t' name='page_id' direction='in'/>"
160 " <arg type='s' name='button_id' direction='in'/>"
161 " <arg type='s' name='html_label' direction='in'/>"
162 " <arg type='s' name='access_key' direction='in'/>"
163 " </method>"
164 " <method name='VCardInlineSetIFrameSrc'>"
165 " <arg type='t' name='page_id' direction='in'/>"
166 " <arg type='s' name='button_id' direction='in'/>"
167 " <arg type='s' name='src' direction='in'/>"
168 " </method>"
169 " <method name='GetDocumentURIFromPoint'>"
170 " <arg type='t' name='page_id' direction='in'/>"
171 " <arg type='i' name='x' direction='in'/>"
172 " <arg type='i' name='y' direction='in'/>"
173 " <arg type='s' name='document_uri' direction='out'/>"
174 " </method>"
175 " <method name='SetDocumentIFrameSrc'>"
176 " <arg type='t' name='page_id' direction='in'/>"
177 " <arg type='s' name='document_uri' direction='in'/>"
178 " <arg type='s' name='new_iframe_src' direction='in'/>"
179 " </method>"
180 " <method name='ProcessMagicSpacebar'>"
181 " <arg type='t' name='page_id' direction='in'/>"
182 " <arg type='b' name='towards_bottom' direction='in'/>"
183 " <arg type='b' name='processed' direction='out'/>"
184 " </method>"
185 " <method name='EWebViewEnsureBodyClass'>"
186 " <arg type='t' name='page_id' direction='in'/>"
187 " <arg type='s' name='body_class' direction='in'/>"
188 " </method>"
189 " <signal name='NeedInputChanged'>"
190 " <arg type='t' name='page_id' direction='out'/>"
191 " <arg type='b' name='need_input' direction='out'/>"
192 " </signal>"
193 " <signal name='ClipboardFlagsChanged'>"
194 " <arg type='t' name='page_id' direction='out'/>"
195 " <arg type='u' name='flags' direction='out'/>"
196 " </signal>"
197 " <signal name='MailPartAppeared'>"
198 " <arg type='t' name='page_id' direction='out'/>"
199 " <arg type='s' name='part_id' direction='out'/>"
200 " </signal>"
201 " </interface>"
202 "</node>";
204 G_DEFINE_TYPE (EWebExtension, e_web_extension, G_TYPE_OBJECT)
206 static WebKitWebPage *
207 get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
208 WebKitWebExtension *web_extension,
209 guint64 page_id)
211 WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
212 if (!web_page) {
213 g_dbus_method_invocation_return_error (
214 invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
215 "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
217 return web_page;
220 static void
221 element_clicked_cb (WebKitDOMElement *element,
222 WebKitDOMEvent *event,
223 gpointer user_data)
225 EWebExtension *extension = user_data;
226 WebKitDOMElement *offset_parent;
227 WebKitDOMDOMWindow *dom_window = NULL;
228 gchar *attr_class, *attr_value;
229 const guint64 *ppage_id;
230 gdouble with_parents_left, with_parents_top;
231 glong scroll_x = 0, scroll_y = 0;
232 GError *error = NULL;
234 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
235 g_return_if_fail (G_IS_OBJECT (element));
237 ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
238 g_return_if_fail (ppage_id != NULL);
240 with_parents_left = webkit_dom_element_get_offset_left (element);
241 with_parents_top = webkit_dom_element_get_offset_top (element);
243 offset_parent = element;
244 while (offset_parent = webkit_dom_element_get_offset_parent (offset_parent), offset_parent) {
245 with_parents_left += webkit_dom_element_get_offset_left (offset_parent);
246 with_parents_top += webkit_dom_element_get_offset_top (offset_parent);
249 dom_window = webkit_dom_document_get_default_view (webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)));
250 if (WEBKIT_DOM_IS_DOM_WINDOW (dom_window)) {
251 g_object_get (G_OBJECT (dom_window),
252 "scroll-x", &scroll_x,
253 "scroll-y", &scroll_y,
254 NULL);
256 g_clear_object (&dom_window);
258 attr_class = webkit_dom_element_get_class_name (element);
259 attr_value = webkit_dom_element_get_attribute (element, "value");
261 g_dbus_connection_emit_signal (
262 extension->priv->dbus_connection,
263 NULL,
264 E_WEB_EXTENSION_OBJECT_PATH,
265 E_WEB_EXTENSION_INTERFACE,
266 "ElementClicked",
267 g_variant_new ("(tssiiii)", *ppage_id, attr_class ? attr_class : "", attr_value ? attr_value : "",
268 (gint) (with_parents_left - scroll_x),
269 (gint) (with_parents_top - scroll_y),
270 (gint) webkit_dom_element_get_offset_width (element),
271 (gint) webkit_dom_element_get_offset_height (element)),
272 &error);
274 if (error) {
275 g_warning ("Error emitting signal ElementClicked: %s\n", error->message);
276 g_error_free (error);
279 g_free (attr_class);
280 g_free (attr_value);
283 static void
284 web_extension_register_element_clicked_in_document (EWebExtension *extension,
285 guint64 page_id,
286 WebKitDOMDocument *document,
287 const gchar *element_class)
289 WebKitDOMHTMLCollection *collection = NULL;
290 gulong ii, len;
292 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
293 g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
294 g_return_if_fail (element_class && *element_class);
296 collection = webkit_dom_document_get_elements_by_class_name_as_html_collection (document, element_class);
297 if (collection) {
298 len = webkit_dom_html_collection_get_length (collection);
299 for (ii = 0; ii < len; ii++) {
300 WebKitDOMNode *node;
302 node = webkit_dom_html_collection_item (collection, ii);
303 if (WEBKIT_DOM_IS_EVENT_TARGET (node)) {
304 guint64 *ppage_id;
306 ppage_id = g_new0 (guint64, 1);
307 *ppage_id = page_id;
309 g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
311 /* Remove first, in case there was a listener already (it's when
312 the page is dynamically filled and not all the elements are
313 available in time of the first call. */
314 webkit_dom_event_target_remove_event_listener (
315 WEBKIT_DOM_EVENT_TARGET (node), "click",
316 G_CALLBACK (element_clicked_cb), FALSE);
318 webkit_dom_event_target_add_event_listener (
319 WEBKIT_DOM_EVENT_TARGET (node), "click",
320 G_CALLBACK (element_clicked_cb), FALSE, extension);
324 g_clear_object (&collection);
326 /* Traverse also iframe-s */
327 collection = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
328 if (collection) {
329 len = webkit_dom_html_collection_get_length (collection);
330 for (ii = 0; ii < len; ii++) {
331 WebKitDOMNode *node;
333 node = webkit_dom_html_collection_item (collection, ii);
334 if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
335 WebKitDOMDocument *content;
337 content = webkit_dom_html_iframe_element_get_content_document (WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
338 if (content)
339 web_extension_register_element_clicked_in_document (extension, page_id, content, element_class);
343 g_clear_object (&collection);
346 static guint64
347 e_web_extension_find_page_id_from_document (WebKitDOMDocument *document)
349 guint64 *ppage_id;
351 g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), 0);
353 while (document) {
354 WebKitDOMDocument *prev_document = document;
356 ppage_id = g_object_get_data (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY);
357 if (ppage_id)
358 return *ppage_id;
360 document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (document));
361 if (prev_document == document)
362 break;
365 return 0;
368 static void
369 e_web_extension_set_need_input (EWebExtension *extension,
370 guint64 page_id,
371 gboolean need_input)
373 EWebPageData *page_data;
374 GError *error = NULL;
376 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
377 g_return_if_fail (page_id != 0);
379 page_data = g_hash_table_lookup (extension->priv->pages, &page_id);
381 if (!page_data || (!page_data->need_input) == (!need_input))
382 return;
384 page_data->need_input = need_input;
386 g_dbus_connection_emit_signal (
387 extension->priv->dbus_connection,
388 NULL,
389 E_WEB_EXTENSION_OBJECT_PATH,
390 E_WEB_EXTENSION_INTERFACE,
391 "NeedInputChanged",
392 g_variant_new ("(tb)", page_id, need_input),
393 &error);
395 if (error) {
396 g_warning ("Error emitting signal NeedInputChanged: %s\n", error->message);
397 g_error_free (error);
401 static void
402 element_focus_cb (WebKitDOMElement *element,
403 WebKitDOMEvent *event,
404 EWebExtension *extension)
406 guint64 *ppage_id;
408 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
410 ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
411 g_return_if_fail (ppage_id != NULL);
413 e_web_extension_set_need_input (extension, *ppage_id, TRUE);
416 static void
417 element_blur_cb (WebKitDOMElement *element,
418 WebKitDOMEvent *event,
419 EWebExtension *extension)
421 guint64 *ppage_id;
423 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
425 ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
426 g_return_if_fail (ppage_id != NULL);
428 e_web_extension_set_need_input (extension, *ppage_id, FALSE);
431 static void
432 e_web_extension_bind_focus_and_blur_recursively (EWebExtension *extension,
433 WebKitDOMDocument *document,
434 const gchar *selector,
435 guint64 page_id)
437 WebKitDOMNodeList *nodes = NULL;
438 WebKitDOMHTMLCollection *frames = NULL;
439 gulong ii, length;
441 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
443 nodes = webkit_dom_document_query_selector_all (document, selector, NULL);
445 length = webkit_dom_node_list_get_length (nodes);
446 for (ii = 0; ii < length; ii++) {
447 WebKitDOMNode *node;
448 guint64 *ppage_id;
450 node = webkit_dom_node_list_item (nodes, ii);
452 ppage_id = g_new (guint64, 1);
453 *ppage_id = page_id;
455 g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
457 webkit_dom_event_target_add_event_listener (
458 WEBKIT_DOM_EVENT_TARGET (node), "focus",
459 G_CALLBACK (element_focus_cb), FALSE, extension);
461 webkit_dom_event_target_add_event_listener (
462 WEBKIT_DOM_EVENT_TARGET (node), "blur",
463 G_CALLBACK (element_blur_cb), FALSE, extension);
465 g_clear_object (&nodes);
467 frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
468 length = webkit_dom_html_collection_get_length (frames);
470 /* Add rules to every sub document */
471 for (ii = 0; ii < length; ii++) {
472 WebKitDOMDocument *content_document = NULL;
473 WebKitDOMNode *node;
475 node = webkit_dom_html_collection_item (frames, ii);
476 content_document =
477 webkit_dom_html_iframe_element_get_content_document (
478 WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
480 if (!content_document)
481 continue;
483 e_web_extension_bind_focus_and_blur_recursively (
484 extension,
485 content_document,
486 selector,
487 page_id);
489 g_clear_object (&frames);
492 static void
493 e_web_extension_bind_focus_on_elements (EWebExtension *extension,
494 WebKitDOMDocument *document)
496 const gchar *elements = "input, textarea, select, button, label";
497 guint64 page_id;
499 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
500 g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
502 page_id = e_web_extension_find_page_id_from_document (document);
503 g_return_if_fail (page_id != 0);
505 e_web_extension_bind_focus_and_blur_recursively (
506 extension,
507 document,
508 elements,
509 page_id);
512 static void
513 handle_method_call (GDBusConnection *connection,
514 const char *sender,
515 const char *object_path,
516 const char *interface_name,
517 const char *method_name,
518 GVariant *parameters,
519 GDBusMethodInvocation *invocation,
520 gpointer user_data)
522 guint64 page_id;
523 EWebExtension *extension = E_WEB_EXTENSION (user_data);
524 WebKitDOMDocument *document;
525 WebKitWebExtension *web_extension = extension->priv->wk_extension;
526 WebKitWebPage *web_page;
528 if (g_strcmp0 (interface_name, E_WEB_EXTENSION_INTERFACE) != 0)
529 return;
531 if (camel_debug ("webkit:preview"))
532 printf ("EWebExtension - %s - %s\n", G_STRFUNC, method_name);
534 if (g_strcmp0 (method_name, "RegisterElementClicked") == 0) {
535 const gchar *element_class = NULL;
537 g_variant_get (parameters, "(t&s)", &page_id, &element_class);
539 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
540 if (!web_page)
541 return;
543 if (!element_class || !*element_class) {
544 g_warn_if_fail (element_class && *element_class);
545 } else {
546 document = webkit_web_page_get_dom_document (web_page);
547 web_extension_register_element_clicked_in_document (extension, page_id, document, element_class);
550 g_dbus_method_invocation_return_value (invocation, NULL);
551 } else if (g_strcmp0 (method_name, "SetElementHidden") == 0) {
552 const gchar *element_id = NULL;
553 gboolean hidden = FALSE;
555 g_variant_get (parameters, "(t&sb)", &page_id, &element_id, &hidden);
557 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
558 if (!web_page)
559 return;
561 if (!element_id || !*element_id) {
562 g_warn_if_fail (element_id && *element_id);
563 } else {
564 gboolean expand_inner_data = FALSE;
566 document = webkit_web_page_get_dom_document (web_page);
567 /* A secret short-cut, to not have two functions for basically the same thing ("hide attachment" and "hide element") */
568 if (!hidden && g_str_has_prefix (element_id, "attachment-wrapper-")) {
569 WebKitDOMElement *element;
571 element = e_dom_utils_find_element_by_id (document, element_id);
573 if (WEBKIT_DOM_IS_HTML_ELEMENT (element) &&
574 webkit_dom_element_get_child_element_count (element) == 0) {
575 gchar *inner_html_data;
577 expand_inner_data = TRUE;
579 inner_html_data = webkit_dom_element_get_attribute (element, "inner-html-data");
580 if (inner_html_data && *inner_html_data) {
581 gchar *related_part_id;
583 webkit_dom_element_set_inner_html (element, inner_html_data, NULL);
584 webkit_dom_element_remove_attribute (element, "inner-html-data");
586 related_part_id = webkit_dom_element_get_attribute (element, "related-part-id");
587 webkit_dom_element_remove_attribute (element, "related-part-id");
589 if (related_part_id && *related_part_id) {
590 GError *error = NULL;
592 g_dbus_connection_emit_signal (
593 extension->priv->dbus_connection,
594 NULL,
595 E_WEB_EXTENSION_OBJECT_PATH,
596 E_WEB_EXTENSION_INTERFACE,
597 "MailPartAppeared",
598 g_variant_new ("(ts)", page_id, related_part_id),
599 &error);
601 if (error) {
602 g_warning ("Error emitting signal MailPartAppeared: %s", error->message);
603 g_error_free (error);
607 g_free (related_part_id);
610 g_free (inner_html_data);
614 e_dom_utils_hide_element (document, element_id, hidden);
616 if (expand_inner_data)
617 e_dom_resize_document_content_to_preview_width (document);
620 g_dbus_method_invocation_return_value (invocation, NULL);
621 } else if (g_strcmp0 (method_name, "SetElementStyleProperty") == 0) {
622 const gchar *element_id = NULL, *property_name = NULL, *value = NULL, *priority = NULL;
624 g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &property_name, &value, &priority);
626 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
627 if (!web_page)
628 return;
630 if (!element_id || !*element_id || !property_name || !*property_name) {
631 g_warn_if_fail (element_id && *element_id);
632 g_warn_if_fail (property_name && *property_name);
633 } else {
634 WebKitDOMElement *element;
635 gboolean use_child = FALSE;
636 gchar *tmp = NULL;
638 /* element_id can be also of the form: "id::child", where the change will
639 be done on the first child of it */
640 use_child = g_str_has_suffix (element_id, "::child");
641 if (use_child) {
642 tmp = g_strdup (element_id);
643 tmp[strlen (tmp) - 7] = '\0';
645 element_id = tmp;
648 document = webkit_web_page_get_dom_document (web_page);
649 element = e_dom_utils_find_element_by_id (document, element_id);
651 if (use_child && element)
652 element = webkit_dom_element_get_first_element_child (element);
654 if (element) {
655 WebKitDOMCSSStyleDeclaration *css;
657 css = webkit_dom_element_get_style (element);
659 if (value && *value)
660 webkit_dom_css_style_declaration_set_property (css, property_name, value, priority, NULL);
661 else
662 g_free (webkit_dom_css_style_declaration_remove_property (css, property_name, NULL));
664 g_clear_object (&css);
667 g_free (tmp);
670 g_dbus_method_invocation_return_value (invocation, NULL);
671 } else if (g_strcmp0 (method_name, "SetElementAttribute") == 0) {
672 const gchar *element_id = NULL, *namespace_uri = NULL, *qualified_name = NULL, *value = NULL;
674 g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &namespace_uri, &qualified_name, &value);
676 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
677 if (!web_page)
678 return;
680 if (!element_id || !*element_id || !qualified_name || !*qualified_name) {
681 g_warn_if_fail (element_id && *element_id);
682 g_warn_if_fail (qualified_name && *qualified_name);
683 } else {
684 WebKitDOMElement *element;
685 gboolean use_child = FALSE;
686 gchar *tmp = NULL;
688 /* element_id can be also of the form: "id::child", where the change will
689 be done on the first child of it */
690 use_child = g_str_has_suffix (element_id, "::child");
691 if (use_child) {
692 tmp = g_strdup (element_id);
693 tmp[strlen (tmp) - 7] = '\0';
695 element_id = tmp;
698 if (namespace_uri && !*namespace_uri)
699 namespace_uri = NULL;
701 document = webkit_web_page_get_dom_document (web_page);
702 element = e_dom_utils_find_element_by_id (document, element_id);
704 if (use_child && element)
705 element = webkit_dom_element_get_first_element_child (element);
707 if (element) {
708 if (value && *value)
709 webkit_dom_element_set_attribute_ns (element, namespace_uri, qualified_name, value, NULL);
710 else
711 webkit_dom_element_remove_attribute_ns (element, namespace_uri, qualified_name);
714 g_free (tmp);
717 g_dbus_method_invocation_return_value (invocation, NULL);
718 } else if (g_strcmp0 (method_name, "DocumentHasSelection") == 0) {
719 gboolean has_selection;
721 g_variant_get (parameters, "(t)", &page_id);
722 web_page = get_webkit_web_page_or_return_dbus_error (
723 invocation, web_extension, page_id);
724 if (!web_page)
725 return;
727 document = webkit_web_page_get_dom_document (web_page);
728 has_selection = e_dom_utils_document_has_selection (document);
730 g_dbus_method_invocation_return_value (
731 invocation, g_variant_new ("(b)", has_selection));
732 } else if (g_strcmp0 (method_name, "GetDocumentContentHTML") == 0) {
733 gchar *html_content;
735 g_variant_get (parameters, "(t)", &page_id);
736 web_page = get_webkit_web_page_or_return_dbus_error (
737 invocation, web_extension, page_id);
738 if (!web_page)
739 return;
741 document = webkit_web_page_get_dom_document (web_page);
742 html_content = e_dom_utils_get_document_content_html (document);
744 g_dbus_method_invocation_return_value (
745 invocation,
746 g_variant_new (
747 "(@s)",
748 g_variant_new_take_string (
749 html_content ? html_content : g_strdup (""))));
750 } else if (g_strcmp0 (method_name, "GetSelectionContentHTML") == 0) {
751 gchar *html_content;
753 g_variant_get (parameters, "(t)", &page_id);
754 web_page = get_webkit_web_page_or_return_dbus_error (
755 invocation, web_extension, page_id);
756 if (!web_page)
757 return;
759 document = webkit_web_page_get_dom_document (web_page);
760 html_content = e_dom_utils_get_selection_content_html (document);
762 g_dbus_method_invocation_return_value (
763 invocation,
764 g_variant_new (
765 "(@s)",
766 g_variant_new_take_string (
767 html_content ? html_content : g_strdup (""))));
768 } else if (g_strcmp0 (method_name, "GetSelectionContentMultipart") == 0) {
769 gchar *text_content;
770 gboolean is_html = FALSE;
772 g_variant_get (parameters, "(t)", &page_id);
773 web_page = get_webkit_web_page_or_return_dbus_error (
774 invocation, web_extension, page_id);
775 if (!web_page)
776 return;
778 document = webkit_web_page_get_dom_document (web_page);
779 text_content = e_dom_utils_get_selection_content_multipart (document, &is_html);
781 g_dbus_method_invocation_return_value (
782 invocation,
783 g_variant_new (
784 "(@sb)",
785 g_variant_new_take_string (
786 text_content ? text_content : g_strdup ("")),
787 is_html));
788 } else if (g_strcmp0 (method_name, "GetSelectionContentText") == 0) {
789 gchar *text_content;
791 g_variant_get (parameters, "(t)", &page_id);
792 web_page = get_webkit_web_page_or_return_dbus_error (
793 invocation, web_extension, page_id);
794 if (!web_page)
795 return;
797 document = webkit_web_page_get_dom_document (web_page);
798 text_content = e_dom_utils_get_selection_content_text (document);
800 g_dbus_method_invocation_return_value (
801 invocation,
802 g_variant_new (
803 "(@s)",
804 g_variant_new_take_string (
805 text_content ? text_content : g_strdup (""))));
806 } else if (g_strcmp0 (method_name, "AddCSSRuleIntoStyleSheet") == 0) {
807 const gchar *style_sheet_id, *selector, *style;
809 g_variant_get (
810 parameters,
811 "(t&s&s&s)",
812 &page_id, &style_sheet_id, &selector, &style);
814 web_page = get_webkit_web_page_or_return_dbus_error (
815 invocation, web_extension, page_id);
816 if (!web_page)
817 return;
819 document = webkit_web_page_get_dom_document (web_page);
820 e_dom_utils_add_css_rule_into_style_sheet (document, style_sheet_id, selector, style);
822 g_dbus_method_invocation_return_value (invocation, NULL);
823 } else if (g_strcmp0 (method_name, "CreateAndAddCSSStyleSheet") == 0) {
824 const gchar *style_sheet_id;
826 g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_id);
827 web_page = get_webkit_web_page_or_return_dbus_error (
828 invocation, web_extension, page_id);
829 if (!web_page)
830 return;
832 document = webkit_web_page_get_dom_document (web_page);
833 e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
835 g_dbus_method_invocation_return_value (invocation, NULL);
836 } else if (g_strcmp0 (method_name, "EABContactFormatterBindDOM") == 0) {
837 g_variant_get (parameters, "(t)", &page_id);
838 web_page = get_webkit_web_page_or_return_dbus_error (
839 invocation, web_extension, page_id);
840 if (!web_page)
841 return;
843 document = webkit_web_page_get_dom_document (web_page);
844 e_dom_utils_eab_contact_formatter_bind_dom (document);
846 g_dbus_method_invocation_return_value (invocation, NULL);
847 } else if (g_strcmp0 (method_name, "EMailDisplayBindDOM") == 0) {
848 g_variant_get (parameters, "(t)", &page_id);
849 web_page = get_webkit_web_page_or_return_dbus_error (
850 invocation, web_extension, page_id);
851 if (!web_page)
852 return;
854 document = webkit_web_page_get_dom_document (web_page);
855 e_dom_utils_e_mail_display_unstyle_blockquotes (document);
856 e_dom_utils_e_mail_display_bind_dom (document, connection);
857 e_web_extension_bind_focus_on_elements (extension, document);
859 g_dbus_method_invocation_return_value (invocation, NULL);
860 } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
861 const gchar *element_id;
862 gboolean element_exists;
864 g_variant_get (parameters, "(t&s)", &page_id, &element_id);
865 web_page = get_webkit_web_page_or_return_dbus_error (
866 invocation, web_extension, page_id);
867 if (!web_page)
868 return;
870 document = webkit_web_page_get_dom_document (web_page);
871 element_exists = e_dom_utils_element_exists (document, element_id);
873 g_dbus_method_invocation_return_value (
874 invocation, g_variant_new ("(bt)", element_exists, page_id));
875 } else if (g_strcmp0 (method_name, "GetActiveElementName") == 0) {
876 gchar *element_name;
878 g_variant_get (parameters, "(t)", &page_id);
879 web_page = get_webkit_web_page_or_return_dbus_error (
880 invocation, web_extension, page_id);
881 if (!web_page)
882 return;
884 document = webkit_web_page_get_dom_document (web_page);
885 element_name = e_dom_utils_get_active_element_name (document);
887 g_dbus_method_invocation_return_value (
888 invocation,
889 g_variant_new (
890 "(@s)",
891 g_variant_new_take_string (
892 element_name ? element_name : g_strdup (""))));
893 } else if (g_strcmp0 (method_name, "EMailPartHeadersBindDOMElement") == 0) {
894 const gchar *element_id;
896 g_variant_get (parameters, "(t&s)", &page_id, &element_id);
897 web_page = get_webkit_web_page_or_return_dbus_error (
898 invocation, web_extension, page_id);
899 if (!web_page)
900 return;
902 document = webkit_web_page_get_dom_document (web_page);
903 e_dom_utils_e_mail_part_headers_bind_dom_element (document, element_id);
905 g_dbus_method_invocation_return_value (invocation, NULL);
906 } else if (g_strcmp0 (method_name, "VCardInlineBindDOM") == 0) {
907 const gchar *element_id;
909 g_variant_get (parameters, "(t&s)", &page_id, &element_id);
910 web_page = get_webkit_web_page_or_return_dbus_error (
911 invocation, web_extension, page_id);
912 if (!web_page)
913 return;
915 document = webkit_web_page_get_dom_document (web_page);
916 e_dom_utils_module_vcard_inline_bind_dom (
917 document, element_id, connection);
919 g_dbus_method_invocation_return_value (invocation, NULL);
920 } else if (g_strcmp0 (method_name, "VCardInlineUpdateButton") == 0) {
921 const gchar *button_id, *html_label, *access_key;
923 g_variant_get (
924 parameters,
925 "(t&s&s&s)",
926 &page_id, &button_id, &html_label, &access_key);
928 web_page = get_webkit_web_page_or_return_dbus_error (
929 invocation, web_extension, page_id);
930 if (!web_page)
931 return;
933 document = webkit_web_page_get_dom_document (web_page);
934 e_dom_utils_module_vcard_inline_update_button (
935 document, button_id, html_label, access_key);
937 g_dbus_method_invocation_return_value (invocation, NULL);
938 } else if (g_strcmp0 (method_name, "VCardInlineSetIFrameSrc") == 0) {
939 const gchar *src, *button_id;
941 g_variant_get (parameters, "(t&s&s)", &page_id, &button_id, &src);
942 web_page = get_webkit_web_page_or_return_dbus_error (
943 invocation, web_extension, page_id);
944 if (!web_page)
945 return;
947 document = webkit_web_page_get_dom_document (web_page);
948 e_dom_utils_module_vcard_inline_set_iframe_src (document, button_id, src);
950 g_dbus_method_invocation_return_value (invocation, NULL);
951 } else if (g_strcmp0 (method_name, "GetDocumentURIFromPoint") == 0) {
952 WebKitDOMDocument *document_at_point;
953 gchar *document_uri = NULL;
954 gint32 xx = 0, yy = 0;
956 g_variant_get (parameters, "(tii)", &page_id, &xx, &yy);
957 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
958 if (!web_page)
959 return;
961 document = webkit_web_page_get_dom_document (web_page);
962 document_at_point = e_dom_utils_get_document_from_point (document, xx, yy);
964 if (document_at_point)
965 document_uri = webkit_dom_document_get_document_uri (document_at_point);
967 g_dbus_method_invocation_return_value (
968 invocation,
969 g_variant_new ("(@s)", g_variant_new_take_string (document_uri ? document_uri : g_strdup (""))));
970 } else if (g_strcmp0 (method_name, "SetDocumentIFrameSrc") == 0) {
971 const gchar *document_uri = NULL, *new_iframe_src = NULL;
972 WebKitDOMDocument *iframe_document;
974 g_variant_get (parameters, "(t&s&s)", &page_id, &document_uri, &new_iframe_src);
975 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
976 if (!web_page)
977 return;
979 document = webkit_web_page_get_dom_document (web_page);
980 iframe_document = e_dom_utils_find_document_with_uri (document, document_uri);
982 if (iframe_document) {
983 WebKitDOMDOMWindow *dom_window;
984 WebKitDOMElement *frame_element;
986 /* Get frame's window and from the window the actual <iframe> element */
987 dom_window = webkit_dom_document_get_default_view (iframe_document);
988 frame_element = webkit_dom_dom_window_get_frame_element (dom_window);
989 webkit_dom_html_iframe_element_set_src (
990 WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), new_iframe_src);
991 g_clear_object (&dom_window);
994 g_dbus_method_invocation_return_value (invocation, NULL);
995 } else if (g_strcmp0 (method_name, "ProcessMagicSpacebar") == 0) {
996 gboolean towards_bottom = FALSE, processed = FALSE;
997 WebKitDOMDOMWindow *dom_window;
998 glong inner_height = -1, scroll_y_before = -1, scroll_y_after = -1;
1000 g_variant_get (parameters, "(tb)", &page_id, &towards_bottom);
1001 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
1002 if (!web_page)
1003 return;
1005 document = webkit_web_page_get_dom_document (web_page);
1006 dom_window = webkit_dom_document_get_default_view (document);
1008 g_object_get (G_OBJECT (dom_window),
1009 "inner-height", &inner_height,
1010 "scroll-y", &scroll_y_before,
1011 NULL);
1013 if (inner_height) {
1014 webkit_dom_dom_window_scroll_by (dom_window, 0, towards_bottom ? inner_height : -inner_height);
1016 g_object_get (G_OBJECT (dom_window),
1017 "scroll-y", &scroll_y_after,
1018 NULL);
1020 processed = scroll_y_before != scroll_y_after;
1023 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", processed));
1024 } else if (g_strcmp0 (method_name, "EWebViewEnsureBodyClass") == 0) {
1025 const gchar *body_class = NULL;
1026 WebKitDOMHTMLElement *body;
1028 g_variant_get (parameters, "(t&s)", &page_id, &body_class);
1029 web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
1030 if (!web_page)
1031 return;
1033 document = webkit_web_page_get_dom_document (web_page);
1035 body = webkit_dom_document_get_body (document);
1036 if (body && !webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (body), "class"))
1037 webkit_dom_element_set_class_name (WEBKIT_DOM_ELEMENT (body), body_class);
1039 g_dbus_method_invocation_return_value (invocation, NULL);
1043 static GVariant *
1044 handle_get_property (GDBusConnection *connection,
1045 const gchar *sender,
1046 const gchar *object_path,
1047 const gchar *interface_name,
1048 const gchar *property_name,
1049 GError **error,
1050 gpointer user_data)
1052 /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
1053 GVariant *variant = NULL;
1055 g_warn_if_reached ();
1057 return variant;
1060 static gboolean
1061 handle_set_property (GDBusConnection *connection,
1062 const gchar *sender,
1063 const gchar *object_path,
1064 const gchar *interface_name,
1065 const gchar *property_name,
1066 GVariant *variant,
1067 GError **error,
1068 gpointer user_data)
1070 /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
1072 g_warn_if_reached ();
1074 return TRUE;
1077 static const GDBusInterfaceVTable interface_vtable = {
1078 handle_method_call,
1079 handle_get_property,
1080 handle_set_property
1083 static void
1084 web_page_gone_cb (gpointer user_data,
1085 GObject *gone_web_page)
1087 EWebExtension *extension = user_data;
1088 GHashTableIter iter;
1089 gpointer key, value;
1091 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
1093 g_hash_table_iter_init (&iter, extension->priv->pages);
1094 while (g_hash_table_iter_next (&iter, &key, &value)) {
1095 EWebPageData *page_data = value;
1097 if (page_data->web_page == (gpointer) gone_web_page) {
1098 g_hash_table_remove (extension->priv->pages, key);
1099 break;
1104 static void
1105 e_web_extension_dispose (GObject *object)
1107 EWebExtension *extension = E_WEB_EXTENSION (object);
1109 if (extension->priv->dbus_connection) {
1110 g_dbus_connection_unregister_object (
1111 extension->priv->dbus_connection,
1112 extension->priv->registration_id);
1113 extension->priv->registration_id = 0;
1114 extension->priv->dbus_connection = NULL;
1117 g_hash_table_remove_all (extension->priv->pages);
1119 g_clear_object (&extension->priv->wk_extension);
1121 G_OBJECT_CLASS (e_web_extension_parent_class)->dispose (object);
1124 static void
1125 e_web_extension_finalize (GObject *object)
1127 EWebExtension *extension = E_WEB_EXTENSION (object);
1129 if (extension->priv->pages) {
1130 g_hash_table_destroy (extension->priv->pages);
1131 extension->priv->pages = NULL;
1134 G_OBJECT_CLASS (e_web_extension_parent_class)->finalize (object);
1137 static void
1138 e_web_extension_class_init (EWebExtensionClass *class)
1140 GObjectClass *object_class = G_OBJECT_CLASS (class);
1142 g_type_class_add_private (object_class, sizeof (EWebExtensionPrivate));
1144 object_class->dispose = e_web_extension_dispose;
1145 object_class->finalize = e_web_extension_finalize;
1148 static void
1149 e_web_extension_init (EWebExtension *extension)
1151 extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, E_TYPE_WEB_EXTENSION, EWebExtensionPrivate);
1153 extension->priv->initialized = FALSE;
1154 extension->priv->pages = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, g_free);
1157 static gpointer
1158 e_web_extension_create_instance(gpointer data)
1160 return g_object_new (E_TYPE_WEB_EXTENSION, NULL);
1163 EWebExtension *
1164 e_web_extension_get (void)
1166 static GOnce once_init = G_ONCE_INIT;
1167 return E_WEB_EXTENSION (g_once (&once_init, e_web_extension_create_instance, NULL));
1170 static gboolean
1171 web_page_send_request_cb (WebKitWebPage *web_page,
1172 WebKitURIRequest *request,
1173 WebKitURIResponse *redirected_response,
1174 EWebExtension *extension)
1176 const gchar *request_uri;
1177 const gchar *page_uri;
1179 request_uri = webkit_uri_request_get_uri (request);
1180 page_uri = webkit_web_page_get_uri (web_page);
1182 /* Always load the main resource. */
1183 if (g_strcmp0 (request_uri, page_uri) == 0 ||
1184 /* Do not influence real pages, like those with eds OAuth sign-in */
1185 g_str_has_prefix (page_uri, "http:") ||
1186 g_str_has_prefix (page_uri, "https:"))
1187 return FALSE;
1189 if (g_str_has_prefix (request_uri, "http:") ||
1190 g_str_has_prefix (request_uri, "https:")) {
1191 gchar *new_uri;
1193 new_uri = g_strconcat ("evo-", request_uri, NULL);
1195 webkit_uri_request_set_uri (request, new_uri);
1197 g_free (new_uri);
1200 return FALSE;
1203 static void
1204 e_web_extension_store_page_id_on_document (WebKitWebPage *web_page)
1206 WebKitDOMDocument *document;
1207 guint64 *ppage_id;
1209 g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
1211 ppage_id = g_new (guint64, 1);
1212 *ppage_id = webkit_web_page_get_id (web_page);
1214 document = webkit_web_page_get_dom_document (web_page);
1216 g_object_set_data_full (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
1219 static void
1220 web_page_document_loaded_cb (WebKitWebPage *web_page,
1221 gpointer user_data)
1223 WebKitDOMDocument *document;
1225 e_web_extension_store_page_id_on_document (web_page);
1227 document = webkit_web_page_get_dom_document (web_page);
1229 e_dom_utils_replace_local_image_links (document);
1231 if ((webkit_dom_document_query_selector (
1232 document, "[data-evo-signature-plain-text-mode]", NULL))) {
1234 WebKitDOMHTMLElement *body;
1236 body = webkit_dom_document_get_body (document);
1238 webkit_dom_element_set_attribute (
1239 WEBKIT_DOM_ELEMENT (body),
1240 "style",
1241 "font-family: Monospace;",
1242 NULL);
1246 static void
1247 e_web_extension_set_clipboard_flags (EWebExtension *extension,
1248 WebKitDOMDocument *document,
1249 guint32 clipboard_flags)
1251 EWebPageData *page_data;
1252 guint64 page_id;
1253 GError *error = NULL;
1255 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
1256 g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
1258 page_id = e_web_extension_find_page_id_from_document (document);
1259 g_return_if_fail (page_id != 0);
1261 page_data = g_hash_table_lookup (extension->priv->pages, &page_id);
1263 if (!page_data || page_data->clipboard_flags == clipboard_flags)
1264 return;
1266 page_data->clipboard_flags = clipboard_flags;
1268 g_dbus_connection_emit_signal (
1269 extension->priv->dbus_connection,
1270 NULL,
1271 E_WEB_EXTENSION_OBJECT_PATH,
1272 E_WEB_EXTENSION_INTERFACE,
1273 "ClipboardFlagsChanged",
1274 g_variant_new ("(tu)", page_id, clipboard_flags),
1275 &error);
1277 if (error) {
1278 g_warning ("Error emitting signal ClipboardFlagsChanged: %s\n", error->message);
1279 g_error_free (error);
1283 static void
1284 web_editor_selection_changed_cb (WebKitWebEditor *web_editor,
1285 EWebExtension *extension)
1287 WebKitWebPage *web_page;
1288 WebKitDOMDocument *document;
1289 guint32 clipboard_flags = 0;
1291 web_page = webkit_web_editor_get_page (web_editor);
1293 document = webkit_web_page_get_dom_document (web_page);
1295 if (e_dom_utils_document_has_selection (document))
1296 clipboard_flags |= E_CLIPBOARD_CAN_COPY;
1298 e_web_extension_set_clipboard_flags (extension, document, clipboard_flags);
1301 static void
1302 web_page_created_cb (WebKitWebExtension *wk_extension,
1303 WebKitWebPage *web_page,
1304 EWebExtension *extension)
1306 EWebPageData *page_data;
1307 guint64 *ppage_id;
1309 ppage_id = g_new (guint64, 1);
1310 *ppage_id = webkit_web_page_get_id (web_page);
1312 page_data = g_new0 (EWebPageData, 1);
1313 page_data->web_page = web_page;
1314 page_data->need_input = FALSE;
1315 page_data->clipboard_flags = 0;
1317 e_web_extension_store_page_id_on_document (web_page);
1319 g_hash_table_insert (extension->priv->pages, ppage_id, page_data);
1321 g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
1323 g_signal_connect_object (
1324 web_page, "send-request",
1325 G_CALLBACK (web_page_send_request_cb),
1326 extension, 0);
1328 g_signal_connect_object (
1329 web_page, "document-loaded",
1330 G_CALLBACK (web_page_document_loaded_cb),
1331 extension, 0);
1333 g_signal_connect_object (
1334 webkit_web_page_get_editor (web_page), "selection-changed",
1335 G_CALLBACK (web_editor_selection_changed_cb),
1336 extension, 0);
1339 void
1340 e_web_extension_initialize (EWebExtension *extension,
1341 WebKitWebExtension *wk_extension)
1343 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
1345 if (extension->priv->initialized)
1346 return;
1348 extension->priv->initialized = TRUE;
1350 extension->priv->wk_extension = g_object_ref (wk_extension);
1352 g_signal_connect (
1353 wk_extension, "page-created",
1354 G_CALLBACK (web_page_created_cb), extension);
1357 void
1358 e_web_extension_dbus_register (EWebExtension *extension,
1359 GDBusConnection *connection)
1361 GError *error = NULL;
1362 static GDBusNodeInfo *introspection_data = NULL;
1364 g_return_if_fail (E_IS_WEB_EXTENSION (extension));
1365 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1367 if (!introspection_data) {
1368 introspection_data =
1369 g_dbus_node_info_new_for_xml (introspection_xml, NULL);
1371 extension->priv->registration_id =
1372 g_dbus_connection_register_object (
1373 connection,
1374 E_WEB_EXTENSION_OBJECT_PATH,
1375 introspection_data->interfaces[0],
1376 &interface_vtable,
1377 extension,
1378 NULL,
1379 &error);
1381 if (!extension->priv->registration_id) {
1382 g_warning ("Failed to register object: %s\n", error->message);
1383 g_error_free (error);
1384 } else {
1385 extension->priv->dbus_connection = connection;
1386 g_object_add_weak_pointer (
1387 G_OBJECT (connection),
1388 (gpointer *)&extension->priv->dbus_connection);