/* * Copyright (c) 2010-2013 Stefan Bolte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "dwb.h" #include "util.h" #include "view.h" #include "dom.h" #define ALLOWED(g) (VIEW(g)->status->allowed_plugins) Plugins * plugins_new() { Plugins *p = dwb_malloc(sizeof(Plugins)); p->created = 0; p->clicks = NULL; p->status = 0; p->elements = NULL; p->max = 0; return p; } static void plugins_free_elements(Plugins *p) { if (p->elements != NULL) { for (GSList *l = p->elements; l; l=l->next) g_object_unref(l->data); g_slist_free(p->elements); p->elements = NULL; } } void plugins_free(Plugins *p) { if (p == NULL) return; if (p->clicks != NULL) { for (GSList *l = p->clicks; l; l=l->next) g_object_unref(l->data); g_slist_free(p->clicks); } plugins_free_elements(p); FREE0(p); } static void plugins_onclick_cb(WebKitDOMElement *element, WebKitDOMEvent *event, GList *gl) { WebKitDOMElement *e = g_object_get_data((gpointer)element, "dwb-plugin-element"); ALLOWED(gl) = g_slist_append(ALLOWED(gl), e); WebKitDOMNode *parent = webkit_dom_node_get_parent_node(WEBKIT_DOM_NODE(element)); WebKitDOMNode *child = webkit_dom_node_get_first_child(WEBKIT_DOM_NODE(element)); webkit_dom_node_remove_child(WEBKIT_DOM_NODE(parent), child, NULL); webkit_dom_node_remove_child(parent, WEBKIT_DOM_NODE(element), NULL); webkit_dom_node_append_child(parent, WEBKIT_DOM_NODE(e), NULL); g_object_unref(parent); } void plugins_create_click_element(WebKitDOMElement *element, GList *gl) { WebKitDOMNode *parent = webkit_dom_node_get_parent_node(WEBKIT_DOM_NODE(element)); View *v = VIEW(gl); WebKitDOMElement *div; if (parent == NULL) return; WebKitDOMDocument *doc = webkit_dom_node_get_owner_document(WEBKIT_DOM_NODE(element)); WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc); WebKitDOMCSSStyleDeclaration *style = webkit_dom_dom_window_get_computed_style(win, element, ""); char *width = webkit_dom_css_style_declaration_get_property_value(style, "width"); char *height = webkit_dom_css_style_declaration_get_property_value(style, "height"); char *top = webkit_dom_css_style_declaration_get_property_value(style, "top"); char *left = webkit_dom_css_style_declaration_get_property_value(style, "left"); char *position = webkit_dom_css_style_declaration_get_property_value(style, "position"); int w, h; if (*width == '\0' || (sscanf(width, "%dpx", &w) == 1 && w<72)) w = 72; if (*height == '\0' || (sscanf(height, "%dpx", &h) == 1 && h<24)) h = 24; if (v->plugins->max <= v->plugins->created) { div = webkit_dom_document_create_element(doc, "div", NULL); v->plugins->clicks = g_slist_prepend(v->plugins->clicks, div); v->plugins->max++; } else div = g_slist_nth_data(v->plugins->clicks, v->plugins->created); webkit_dom_html_element_set_inner_html(WEBKIT_DOM_HTML_ELEMENT(div), "
click to enable flash
", NULL); char *new_style = g_strdup_printf("position:%s;width:%dpx;height:%dpx;top:%s;left:%s;display:table;z-index:37000;", position, w, h, top, left); webkit_dom_element_set_attribute(div, "style", new_style, NULL); g_free(new_style); webkit_dom_element_set_attribute(div, "onclick", "return", NULL); g_object_set_data((gpointer)div, "dwb-plugin-element", element); webkit_dom_node_remove_child(parent, WEBKIT_DOM_NODE(element), NULL); webkit_dom_node_append_child(parent, WEBKIT_DOM_NODE(div), NULL); v->plugins->elements = g_slist_prepend(v->plugins->elements, element); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(div), "click", G_CALLBACK(plugins_onclick_cb), true, gl); g_object_unref(style); g_object_unref(parent); v->plugins->created++; } static gboolean plugins_before_load_cb(WebKitDOMDOMWindow *win, WebKitDOMEvent *event, GList *gl) { WebKitDOMElement *element = (void*)webkit_dom_event_get_src_element(event); char *tagname = webkit_dom_element_get_tag_name(element); char *type = webkit_dom_element_get_attribute(element, "type"); if ( (!g_strcmp0(type, "application/x-shockwave-flash") && (! g_ascii_strcasecmp(tagname, "object") || ! g_ascii_strcasecmp(tagname, "embed")) ) && ! g_slist_find(ALLOWED(gl), element) ) { VIEW(gl)->plugins->status |= PLUGIN_STATUS_HAS_PLUGIN; webkit_dom_event_prevent_default(event); webkit_dom_event_stop_propagation(event); plugins_create_click_element(element, gl); } g_object_unref(element); g_free(tagname); g_free(type); return true; } static void plugins_remove_all(GList *gl) { if (ALLOWED(gl) != NULL) { ALLOWED(gl) = g_slist_remove_all(ALLOWED(gl), ALLOWED(gl)->data); ALLOWED(gl) = NULL; } View *v = VIEW(gl); v->plugins->created = 0; } static gboolean plugins_before_unload_cb(WebKitDOMDOMWindow *win, WebKitDOMEvent *event, GList *gl) { plugins_remove_all(gl); plugins_free_elements(VIEW(gl)->plugins); return true; } void plugins_load_status_cb(WebKitWebView *wv, GParamSpec *p, GList *gl) { WebKitLoadStatus status = webkit_web_view_get_load_status(wv); if (status == WEBKIT_LOAD_COMMITTED) { WebKitDOMDocument *doc = webkit_web_view_get_dom_document(wv); WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "beforeload", G_CALLBACK(plugins_before_load_cb), true, gl); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "beforeunload", G_CALLBACK(plugins_before_unload_cb), true, gl); } } void plugins_frame_load_cb(WebKitWebFrame *frame, GParamSpec *p, GList *gl) { dom_add_frame_listener(frame, "beforeload", G_CALLBACK(plugins_before_load_cb), true, gl); } void plugins_frame_created_cb(WebKitWebView *wv, WebKitWebFrame *frame, GList *gl) { g_signal_connect(frame, "notify::load-status", G_CALLBACK(plugins_frame_load_cb), gl); } void plugins_connect(GList *gl) { View *v = VIEW(gl); if (v->plugins->status & PLUGIN_STATUS_CONNECTED) return; v->status->signals[SIG_PLUGINS_LOAD] = g_signal_connect(WEBVIEW(gl), "notify::load-status", G_CALLBACK(plugins_load_status_cb), gl); v->status->signals[SIG_PLUGINS_FRAME_CREATED] = g_signal_connect(WEBVIEW(gl), "frame-created", G_CALLBACK(plugins_frame_created_cb), gl); v->plugins->status ^= (v->plugins->status & PLUGIN_STATUS_DISCONNECTED) | PLUGIN_STATUS_CONNECTED; } void plugins_disconnect(GList *gl) { View *v = VIEW(gl); if (v->plugins->status & PLUGIN_STATUS_DISCONNECTED) return; for (int i=SIG_PLUGINS_FIRST+1; istatus->signals[i] > 0) { g_signal_handler_disconnect(WEBVIEW(gl), VIEW(gl)->status->signals[i]); v->status->signals[i] = 0; } } plugins_remove_all(gl); v->plugins->status ^= (v->plugins->status & PLUGIN_STATUS_CONNECTED) | PLUGIN_STATUS_DISCONNECTED; }