/* Copyright (C) 2013 Stephan Haller This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See the file COPYING for the full license text. */ #include "nojs-view.h" #include "nojs-preferences.h" /* Define this class in GObject system */ G_DEFINE_TYPE(NoJSView, nojs_view, G_TYPE_OBJECT) /* Properties */ enum { PROP_0, PROP_MANAGER, PROP_BROWSER, PROP_VIEW, PROP_MENU_ICON_STATE, PROP_LAST }; static GParamSpec* NoJSViewProperties[PROP_LAST]={ 0, }; /* Private structure - access only by public API if needed */ #define NOJS_VIEW_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_NOJS_VIEW, NoJSViewPrivate)) struct _NoJSViewPrivate { /* Extension related */ NoJS *manager; MidoriBrowser *browser; MidoriView *view; GtkWidget *menu; gboolean menuPolicyWasChanged; NoJSMenuIconState menuIconState; GSList *resourceURIs; }; /* IMPLEMENTATION: Private variables and methods */ /* Preferences of this extension should be opened */ static void _nojs_view_on_preferences_response(GtkWidget* inDialog, gint inResponse, gpointer *inUserData) { gtk_widget_destroy(inDialog); } static void _nojs_view_on_open_preferences(NoJSView *self, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); NoJSViewPrivate *priv=self->priv; /* Show preferences window */ GtkWidget* dialog; dialog=nojs_preferences_new(priv->manager); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); g_signal_connect(dialog, "response", G_CALLBACK (_nojs_view_on_preferences_response), self); gtk_widget_show_all(dialog); } /* Selection was done in menu */ static void _nojs_view_on_menu_selection_done(NoJSView *self, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); NoJSViewPrivate *priv=self->priv; /* Check if any policy was changed and reload page */ if(priv->menuPolicyWasChanged!=FALSE) { /* Reset flag that any policy was changed */ priv->menuPolicyWasChanged=FALSE; /* Reload page */ midori_view_reload(priv->view, FALSE); g_message("%s: Reloading page %s as policy has changed", __func__, midori_view_get_display_uri(priv->view)); } } /* Destroy menu */ static void _nojs_view_destroy_menu(NoJSView *self) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(self->priv->menu!=NULL); NoJSViewPrivate *priv=self->priv; /* Empty menu and list of domains added to menu */ gtk_widget_destroy(priv->menu); priv->menu=NULL; /* Reset menu icon to default state */ priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); } /* Create empty menu */ static void _nojs_view_create_empty_menu(NoJSView *self) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(self->priv->menu==NULL); NoJSViewPrivate *priv=self->priv; GtkWidget *item; /* Create new menu and set up default items */ priv->menu=gtk_menu_new(); item=gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL); g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_open_preferences), self); gtk_menu_shell_prepend(GTK_MENU_SHELL(priv->menu), item); gtk_widget_show_all(item); /* Reset flag that any policy was changed */ priv->menuPolicyWasChanged=FALSE; /* Reset menu icon to default state */ priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); /* Connect signal to menu */ g_signal_connect_swapped(priv->menu, "selection-done", G_CALLBACK(_nojs_view_on_menu_selection_done), self); } /* Change visibility state of menu item for a domain depending on policy */ static gboolean _nojs_view_menu_item_change_policy(NoJSView *self, const gchar *inDomain, NoJSPolicy inPolicy) { g_return_val_if_fail(NOJS_IS_VIEW(self), FALSE); g_return_val_if_fail(inDomain, FALSE); NoJSViewPrivate *priv=self->priv; GList *items, *iter; gboolean updated; /* Handle accept-for-session like accept when showing or hiding menu items */ if(inPolicy==NOJS_POLICY_ACCEPT_TEMPORARILY) inPolicy=NOJS_POLICY_ACCEPT; /* Update menu items */ updated=FALSE; items=gtk_container_get_children(GTK_CONTAINER(priv->menu)); for(iter=items; iter; iter=iter->next) { /* Only check and update menu items (not separators and so on) */ if(GTK_IS_MENU_ITEM(iter->data)) { GtkMenuItem *item=GTK_MENU_ITEM(iter->data); const gchar *itemDomain; NoJSPolicy itemPolicy; itemDomain=(const gchar*)g_object_get_data(G_OBJECT(item), "domain"); itemPolicy=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "policy")); /* Handle accept-for-session like accept when showing or hiding menu items */ if(itemPolicy==NOJS_POLICY_ACCEPT_TEMPORARILY) itemPolicy=NOJS_POLICY_ACCEPT; /* If menu item has "domain"-data update its visibility state * depending on matching policy */ if(g_strcmp0(itemDomain, inDomain)==0) { if(itemPolicy==inPolicy) gtk_widget_hide(GTK_WIDGET(item)); else gtk_widget_show_all(GTK_WIDGET(item)); /* Set flag that at least one menu item was updated */ updated=TRUE; } } } g_list_free(items); /* Return flag indicating if at least one menu item was updated */ return(updated); } /* A menu item was selected */ static void _nojs_view_on_menu_item_activate(NoJSView *self, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(GTK_IS_MENU_ITEM(inUserData)); NoJSViewPrivate *priv=self->priv; GtkMenuItem *item=GTK_MENU_ITEM(inUserData); const gchar *domain; NoJSPolicy policy; /* Get domain and policy to set */ domain=(const gchar*)g_object_get_data(G_OBJECT(item), "domain"); policy=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "policy")); g_return_if_fail(domain); g_return_if_fail(policy>=NOJS_POLICY_ACCEPT && policy<=NOJS_POLICY_BLOCK); /* Set policy for domain and update menu items */ _nojs_view_menu_item_change_policy(self, domain, policy); nojs_set_policy(priv->manager, domain, policy); /* Set flag that a policy was changed */ priv->menuPolicyWasChanged=TRUE; } /* Add site to menu */ static void _nojs_view_add_site_to_menu(NoJSView *self, const gchar *inDomain, NoJSPolicy inPolicy) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(inDomain); NoJSViewPrivate *priv=self->priv; GtkWidget *item; gchar *itemLabel; GtkWidget *itemImage; static gint INSERT_POSITION=1; NoJSMenuIconState newMenuIconState; /* Create menu object if not available */ if(!priv->menu) _nojs_view_create_empty_menu(self); /* Check if domain was already added to menu. If it exists just update it. */ if(_nojs_view_menu_item_change_policy(self, inDomain, inPolicy)==TRUE) return; /* Add menu item(s) for domain */ itemLabel=g_strdup_printf(_("Deny %s"), inDomain); item=gtk_image_menu_item_new_with_label(itemLabel); itemImage=gtk_image_new_from_stock (GTK_STOCK_NO, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); if(inPolicy!=NOJS_POLICY_BLOCK) gtk_widget_show_all(item); g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_BLOCK)); g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); g_free(itemLabel); itemLabel=g_strdup_printf(_("Allow %s"), inDomain); item=gtk_image_menu_item_new_with_label(itemLabel); itemImage=gtk_image_new_from_stock (GTK_STOCK_YES, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); if(inPolicy!=NOJS_POLICY_ACCEPT && inPolicy!=NOJS_POLICY_ACCEPT_TEMPORARILY) gtk_widget_show_all(item); g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_ACCEPT)); g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); g_free(itemLabel); itemLabel=g_strdup_printf(_("Allow %s this session"), inDomain); item=gtk_image_menu_item_new_with_label(itemLabel); itemImage=gtk_image_new_from_stock (GTK_STOCK_OK, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); if(inPolicy!=NOJS_POLICY_ACCEPT && inPolicy!=NOJS_POLICY_ACCEPT_TEMPORARILY) gtk_widget_show_all(item); g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_ACCEPT_TEMPORARILY)); g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); g_free(itemLabel); /* Add seperator to seperate actions for this domain from the other domains */ item=gtk_separator_menu_item_new(); gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); gtk_widget_show_all(item); /* Determine state of status icon */ if(priv->menuIconState!=NOJS_MENU_ICON_STATE_MIXED) { switch(inPolicy) { case NOJS_POLICY_ACCEPT: case NOJS_POLICY_ACCEPT_TEMPORARILY: newMenuIconState=NOJS_MENU_ICON_STATE_ALLOWED; break; case NOJS_POLICY_BLOCK: newMenuIconState=NOJS_MENU_ICON_STATE_DENIED; break; default: newMenuIconState=NOJS_MENU_ICON_STATE_MIXED; break; } if(priv->menuIconState==NOJS_MENU_ICON_STATE_UNDETERMINED || priv->menuIconState!=newMenuIconState) { priv->menuIconState=newMenuIconState; g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); } } } /* Status of loading a site has changed */ static void _nojs_view_on_load_status_changed(NoJSView *self, GParamSpec *inSpec, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(WEBKIT_IS_WEB_VIEW(inUserData)); NoJSViewPrivate *priv=self->priv; WebKitWebView *webkitView=WEBKIT_WEB_VIEW(inUserData); WebKitWebSettings *settings=webkit_web_view_get_settings(webkitView); WebKitLoadStatus status; SoupURI *uri; /* Get URI of document loading/loaded */ uri=soup_uri_new(webkit_web_view_get_uri(webkitView)); /* Check load status */ status=webkit_web_view_get_load_status(webkitView); /* Check if a view was emptied, e.g. for a new document going to be loaded soon */ if(status==WEBKIT_LOAD_PROVISIONAL) { /* Create a new empty menu */ _nojs_view_destroy_menu(self); _nojs_view_create_empty_menu(self); /* Free list of resource URIs, that's the list of URIs for all resources * of a page */ if(priv->resourceURIs) { g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); priv->resourceURIs=NULL; } } /* Check if document loading is going to start. Do not check special pages. */ if(status==WEBKIT_LOAD_COMMITTED && uri && uri->scheme && g_strcmp0(uri->scheme, "about")!=0) { /* Check if domain is black-listed or white-listed and enable or * disable javascript accordingly. But if settings match already * the state it should get do not set it again to avoid reloads of page. */ gchar *domain; NoJSPolicy policy; gboolean currentScriptsEnabled; gboolean newScriptsEnabled; domain=nojs_get_domain(priv->manager, uri); policy=nojs_get_policy(priv->manager, uri); if(policy==NOJS_POLICY_UNDETERMINED) { policy=nojs_get_policy_for_unknown_domain(priv->manager); // TODO: Show nick_name of policy (enum) to use in warning g_warning("Got invalid policy. Using default policy for unknown domains."); } newScriptsEnabled=(policy==NOJS_POLICY_BLOCK ? FALSE : TRUE); g_object_get(G_OBJECT(settings), "enable-scripts", ¤tScriptsEnabled, NULL); if(newScriptsEnabled!=currentScriptsEnabled) { g_object_set(G_OBJECT(settings), "enable-scripts", newScriptsEnabled, NULL); // TODO: Set uri also to ensure this uri is going to be reloaded } if(domain) { _nojs_view_add_site_to_menu(self, domain, policy); g_free(domain); } } /* Free allocated resources */ if(uri) soup_uri_free(uri); } /* A request is going to sent */ static void _nojs_view_on_resource_request_starting(NoJSView *self, WebKitWebFrame *inFrame, WebKitWebResource *inResource, WebKitNetworkRequest *inRequest, WebKitNetworkResponse *inResponse, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); NoJSViewPrivate *priv=self->priv; SoupMessage *message; SoupURI *uri; gchar *uriText; /* Remember resource URIs requesting */ message=(inRequest ? webkit_network_request_get_message(inRequest) : NULL); if(message) { uri=soup_message_get_uri(message); if(uri) { uriText=soup_uri_to_string(uri, FALSE); priv->resourceURIs=g_slist_prepend(priv->resourceURIs, uriText); } } message=(inResponse ? webkit_network_response_get_message(inResponse) : NULL); if(message) { uri=soup_message_get_uri(message); if(uri) { uriText=soup_uri_to_string(uri, FALSE); priv->resourceURIs=g_slist_prepend(priv->resourceURIs, uriText); } } } /* A policy has changed */ static void _nojs_view_on_policy_changed(NoJSView *self, gchar *inDomain, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(inDomain); NoJSViewPrivate *priv=self->priv; GList *items, *iter; gboolean reloaded; /* Check if the policy of a domain has changed this view has referenced resources to */ reloaded=FALSE; items=gtk_container_get_children(GTK_CONTAINER(priv->menu)); for(iter=items; reloaded==FALSE && iter; iter=iter->next) { if(GTK_IS_MENU_ITEM(iter->data)) { const gchar *itemDomain; /* Check if domain matches menu item */ itemDomain=(const gchar*)g_object_get_data(G_OBJECT(iter->data), "domain"); if(g_strcmp0(itemDomain, inDomain)==0) { /* Found domain in our menu so reload page */ midori_view_reload(priv->view, FALSE); reloaded=TRUE; } } } g_list_free(items); } /* A javascript URI is going to loaded or blocked */ static void _nojs_view_on_uri_load_policy_status(NoJSView *self, gchar *inURI, NoJSPolicy inPolicy, gpointer inUserData) { g_return_if_fail(NOJS_IS_VIEW(self)); NoJSViewPrivate *priv=self->priv; GSList *iter; gchar *checkURI; /* Check if uri (accepted or blocked) might be one of ours */ for(iter=priv->resourceURIs; iter; iter=iter->next) { checkURI=(gchar*)iter->data; if(g_strcmp0(checkURI, inURI)==0) { SoupURI *uri; gchar *domain; uri=soup_uri_new(inURI); domain=nojs_get_domain(priv->manager, uri); if(domain) { _nojs_view_add_site_to_menu(self, domain, inPolicy); g_free(domain); } soup_uri_free(uri); break; } } } /* Property "view" has changed */ static void _nojs_view_on_view_changed(NoJSView *self, MidoriView *inView) { NoJSViewPrivate *priv=self->priv; WebKitWebView *webkitView; /* Disconnect signal on old view */ if(priv->view) { webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(priv->view)); g_signal_handlers_disconnect_by_data(webkitView, self); g_object_set_data(G_OBJECT(priv->view), "nojs-view-instance", NULL); g_object_unref(priv->view); priv->view=NULL; } /* Set new view if valid pointer */ if(!inView) return; priv->view=g_object_ref(inView); g_object_set_data(G_OBJECT(priv->view), "nojs-view-instance", self); /* Listen to changes of load-status in view */ webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(priv->view)); g_signal_connect_swapped(webkitView, "notify::load-status", G_CALLBACK(_nojs_view_on_load_status_changed), self); g_signal_connect_swapped(webkitView, "resource-request-starting", G_CALLBACK(_nojs_view_on_resource_request_starting), self); /* Create empty menu */ _nojs_view_destroy_menu(self); _nojs_view_create_empty_menu(self); /* Release list of resource URIs */ if(priv->resourceURIs) { g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); priv->resourceURIs=NULL; } } /* This extension is going to be deactivated */ static void _nojs_view_on_extension_deactivated(NoJSView *self, MidoriExtension *inExtension) { g_return_if_fail(NOJS_IS_VIEW(self)); /* Dispose allocated resources by unreferencing ourselve */ g_object_unref(self); } /* Property "manager" has changed */ static void _nojs_view_on_manager_changed(NoJSView *self, NoJS *inNoJS) { g_return_if_fail(NOJS_IS_VIEW(self)); g_return_if_fail(!inNoJS || IS_NOJS(inNoJS)); NoJSViewPrivate *priv=self->priv; MidoriExtension *extension; /* Release reference to old manager and clean up */ if(priv->manager) { g_object_get(priv->manager, "extension", &extension, NULL); g_signal_handlers_disconnect_by_data(extension, self); g_object_unref(extension); g_signal_handlers_disconnect_by_data(priv->manager, self); g_object_unref(priv->manager); priv->manager=NULL; } /* Set new view if valid pointer */ if(!inNoJS) return; priv->manager=g_object_ref(inNoJS); /* Connect signals to manager */ g_signal_connect_swapped(priv->manager, "uri-load-policy-status", G_CALLBACK(_nojs_view_on_uri_load_policy_status), self); g_signal_connect_swapped(priv->manager, "policy-changed", G_CALLBACK(_nojs_view_on_policy_changed), self); /* Connect signal to get noticed when extension is going to be deactivated * to release all references to GObjects */ g_object_get(priv->manager, "extension", &extension, NULL); g_signal_connect_swapped(extension, "deactivate", G_CALLBACK(_nojs_view_on_extension_deactivated), self); g_object_unref(extension); } /* IMPLEMENTATION: GObject */ /* Finalize this object */ static void nojs_view_finalize(GObject *inObject) { NoJSView *self=NOJS_VIEW(inObject); NoJSViewPrivate *priv=self->priv; /* Dispose allocated resources */ if(priv->manager) { MidoriExtension *extension; g_object_get(priv->manager, "extension", &extension, NULL); g_signal_handlers_disconnect_by_data(extension, self); g_object_unref(extension); g_signal_handlers_disconnect_by_data(priv->manager, self); g_object_unref(priv->manager); priv->manager=NULL; } if(priv->browser) { g_object_unref(priv->browser); priv->browser=NULL; } if(priv->view) { _nojs_view_on_view_changed(self, NULL); } if(priv->menu) { gtk_widget_destroy(priv->menu); priv->menu=NULL; } if(priv->resourceURIs) { g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); priv->resourceURIs=NULL; } /* Call parent's class finalize method */ G_OBJECT_CLASS(nojs_view_parent_class)->finalize(inObject); } /* Set/get properties */ static void nojs_view_set_property(GObject *inObject, guint inPropID, const GValue *inValue, GParamSpec *inSpec) { NoJSView *self=NOJS_VIEW(inObject); switch(inPropID) { /* Construct-only properties */ case PROP_MANAGER: _nojs_view_on_manager_changed(self, NOJS(g_value_get_object(inValue))); break; case PROP_BROWSER: if(self->priv->browser) g_object_unref(self->priv->browser); self->priv->browser=g_object_ref(g_value_get_object(inValue)); break; case PROP_VIEW: _nojs_view_on_view_changed(self, MIDORI_VIEW(g_value_get_object(inValue))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); break; } } static void nojs_view_get_property(GObject *inObject, guint inPropID, GValue *outValue, GParamSpec *inSpec) { NoJSView *self=NOJS_VIEW(inObject); switch(inPropID) { case PROP_MANAGER: g_value_set_object(outValue, self->priv->manager); break; case PROP_BROWSER: g_value_set_object(outValue, self->priv->browser); break; case PROP_VIEW: g_value_set_object(outValue, self->priv->view); break; case PROP_MENU_ICON_STATE: g_value_set_enum(outValue, self->priv->menuIconState); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); break; } } /* Class initialization * Override functions in parent classes and define properties and signals */ static void nojs_view_class_init(NoJSViewClass *klass) { GObjectClass *gobjectClass=G_OBJECT_CLASS(klass); /* Override functions */ gobjectClass->finalize=nojs_view_finalize; gobjectClass->set_property=nojs_view_set_property; gobjectClass->get_property=nojs_view_get_property; /* Set up private structure */ g_type_class_add_private(klass, sizeof(NoJSViewPrivate)); /* Define properties */ NoJSViewProperties[PROP_MANAGER]= g_param_spec_object("manager", _("Manager instance"), _("Instance to global NoJS manager"), TYPE_NOJS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); NoJSViewProperties[PROP_BROWSER]= g_param_spec_object("browser", _("Browser window"), _("The Midori browser instance this view belongs to"), MIDORI_TYPE_BROWSER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); NoJSViewProperties[PROP_VIEW]= g_param_spec_object("view", _("View"), _("The Midori view instance this view belongs to"), MIDORI_TYPE_VIEW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); NoJSViewProperties[PROP_MENU_ICON_STATE]= g_param_spec_enum("menu-icon-state", _("Menu icon state"), _("State of menu icon to show in status bar"), NOJS_TYPE_MENU_ICON_STATE, NOJS_MENU_ICON_STATE_UNDETERMINED, G_PARAM_READABLE); g_object_class_install_properties(gobjectClass, PROP_LAST, NoJSViewProperties); } /* Object initialization * Create private structure and set up default values */ static void nojs_view_init(NoJSView *self) { NoJSViewPrivate *priv; priv=self->priv=NOJS_VIEW_GET_PRIVATE(self); /* Set up default values */ priv->manager=NULL; priv->browser=NULL; priv->view=NULL; priv->menu=NULL; priv->menuPolicyWasChanged=FALSE; priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; priv->resourceURIs=NULL; /* Create empty menu */ _nojs_view_create_empty_menu(self); } /* Implementation: Public API */ /* Create new object */ NoJSView* nojs_view_new(NoJS *inNoJS, MidoriBrowser *inBrowser, MidoriView *inView) { return(g_object_new(TYPE_NOJS_VIEW, "manager", inNoJS, "browser", inBrowser, "view", inView, NULL)); } /* Get menu widget for this view */ GtkMenu* nojs_view_get_menu(NoJSView *self) { g_return_val_if_fail(NOJS_IS_VIEW(self), NULL); return(GTK_MENU(self->priv->menu)); } /* Get image used for menu icon in status bar */ NoJSMenuIconState nojs_view_get_menu_icon_state(NoJSView *self) { g_return_val_if_fail(NOJS_IS_VIEW(self), NOJS_MENU_ICON_STATE_UNDETERMINED); return(self->priv->menuIconState); } /************************************************************************************/ /* Implementation: Enumeration */ GType nojs_menu_icon_state_get_type(void) { static volatile gsize g_define_type_id__volatile=0; if(g_once_init_enter(&g_define_type_id__volatile)) { static const GEnumValue values[]= { { NOJS_MENU_ICON_STATE_UNDETERMINED, "NOJS_MENU_ICON_STATE_UNDETERMINED", N_("Undetermined") }, { NOJS_MENU_ICON_STATE_ALLOWED, "NOJS_MENU_ICON_STATE_ALLOWED", N_("Allowed") }, { NOJS_MENU_ICON_STATE_MIXED, "NOJS_MENU_ICON_STATE_MIXED", N_("Mixed") }, { NOJS_MENU_ICON_STATE_DENIED, "NOJS_MENU_ICON_STATE_DENIED", N_("Denied") }, { 0, NULL, NULL } }; GType g_define_type_id=g_enum_register_static(g_intern_static_string("NoJSMenuIconState"), values); g_once_init_leave(&g_define_type_id__volatile, g_define_type_id); } return(g_define_type_id__volatile); }