From e189704eb525febad919eb533b64b3a67ed86a36 Mon Sep 17 00:00:00 2001 From: fenze Date: Tue, 10 May 2022 17:35:37 +0200 Subject: [PATCH] fix double keypress events --- makefile | 8 ++- rose.c | 134 ++++------------------------------------------- webview.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ webview.h | 26 ++++++++++ window.c | 103 ++++++++++++++++++++++++++++++++++++ window.h | 21 ++++++++ 6 files changed, 320 insertions(+), 125 deletions(-) create mode 100644 webview.c create mode 100644 webview.h create mode 100644 window.c create mode 100644 window.h diff --git a/makefile b/makefile index b87a8a0..4104156 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,13 @@ CFLAGS = `pkg-config --cflags gtk4 webkit2gtk-5.0` LIBS = `pkg-config --libs gtk4 webkit2gtk-5.0` all: - ${CC} -fPIC -g -O3 -o rose *.c $(CFLAGS) $(LIBS) && ./rose + ${CC} -fPIC -g -O3 -o rose *.c $(CFLAGS) $(LIBS) + strip ./rose + +install: all + cp -uf ./rose /usr/local/bin/rose + mkdir -p /usr/local/share/rose + cp -uf ./youtube.js /usr/local/share/rose/youtube.js clean: rm -f rose compile_flags.txt diff --git a/rose.c b/rose.c index cf2494c..8fbba49 100644 --- a/rose.c +++ b/rose.c @@ -1,138 +1,24 @@ #include "rose.h" #include "config.h" +#include "webview.h" +#include "window.h" #include #include -typedef struct Client { - GtkWidget *window; - WebKitWebView *webview; -} Client; - -WebKitWebView* new_webview() -{ - char cookiefile[64]; - WebKitWebView *webview; - WebKitCookieManager *cookiemanager; - WebKitUserContentManager *contentmanager; - - WebKitSettings *settings = webkit_settings_new_with_settings( - "auto-load-images", true, - "enable-back-forward-navigation-gestures", true, - "enable-developer-extras", true, - "enable-media-stream", true, - "hardware-acceleration-policy", WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS, - "javascript-can-access-clipboard", true, NULL); - - WebKitWebContext *context = webkit_web_context_new_with_website_data_manager( - webkit_website_data_manager_new( - "base-cache-directory", cachedir, - "base-data-directory", cachedir, - NULL)); - - webkit_settings_set_user_agent_with_application_details( - settings, "Mini", "0.1"); - - webkit_web_context_set_process_model(context, WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES); - webkit_web_context_set_cache_model(context, WEBKIT_CACHE_MODEL_WEB_BROWSER); - contentmanager = webkit_user_content_manager_new(); - cookiemanager = webkit_web_context_get_cookie_manager(context); - - strcpy(cookiefile, cachedir); - strcat(cookiefile, "cookies"); - - webkit_cookie_manager_set_persistent_storage(cookiemanager, - cookiefile, WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE); - - webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS); - - return g_object_new( - WEBKIT_TYPE_WEB_VIEW, - "settings", settings, - "user-content-manager", contentmanager, - "web-context", context, NULL); -} - -static gboolean winevent(Client* c, - guint keyval, - guint keycode, - GdkModifierType state) -{ - if (state == GDK_CONTROL_MASK) { - switch (keycode) { - case 43: { - if (webkit_web_view_can_go_back(c->webview)) - webkit_web_view_go_back(c->webview); - } break; - case 46: { - if (webkit_web_view_can_go_forward(c->webview)) - webkit_web_view_go_forward(c->webview); - } break; - case 26: { - webkit_web_view_load_uri(c->webview, homepage); - } break; - } - } - - return GDK_EVENT_PROPAGATE; -} - -static void _history_append(const char *url, - const char* title) -{ - char filename[] = "history"; - char *path = calloc(1, sizeof(char) * (strlen(cachedir) + strlen(filename)) + 1); - strcpy(path, cachedir); - strcat(path, filename); - - FILE *f; - - if (!(f = fopen(path, "r"))) { - f = fopen(path, "w"); - fclose(f); - } - - f = fopen(path, "a"); - - fprintf(f, "'%s' - %s", title, url); - fclose(f); -} - -static void history_append(WebKitWebView *webview, - WebKitLoadEvent event, - gpointer userdata) -{ - if (event == WEBKIT_LOAD_FINISHED) { - const char *uri = webkit_web_view_get_uri(webview); - const char *title = webkit_web_view_get_title(webview); - _history_append(uri, title); - } -} - static void run(GtkApplication *app) { - if (dark_mode) + RoseWindow *window = rose_window_new(app); + GtkWidget *webview = rose_webview_new(); + + if (dark_mode) { g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", true, NULL); + } - Client *c = calloc(1, sizeof(Client)); - - c->window = gtk_window_new(); - c->webview = new_webview(); - - gtk_application_add_window(app, GTK_WINDOW(c->window)); + rose_window_set_webview(window, webview); + rose_window_show(window); if (homepage) - webkit_web_view_load_uri(c->webview, homepage); - - gtk_window_set_child(GTK_WINDOW(c->window), GTK_WIDGET(c->webview)); - - GtkEventController *controller = gtk_event_controller_key_new(); - gtk_widget_add_controller(GTK_WIDGET(c->window), controller); - gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE); - g_signal_connect_swapped(controller, "key-pressed", G_CALLBACK (winevent), c); - - g_signal_connect(c->webview, "load-changed", G_CALLBACK(history_append), NULL); - - gtk_widget_show(GTK_WIDGET(c->window)); + rose_webview_load_url(WEBKIT_WEB_VIEW(webview), homepage); } int main(int argc, char **argv) diff --git a/webview.c b/webview.c new file mode 100644 index 0000000..129f4f0 --- /dev/null +++ b/webview.c @@ -0,0 +1,153 @@ +#include "webview.h" +#include "config.h" + +struct _RoseWebView { + WebKitWebView parent_instance; + + GCancellable *cancellable; + RoseWebViewNavigationFlags navigation; + + char *address; +}; + +enum { + LAST_PROP, + PROP_NAVIGATION, + PROP_ADDRESS +}; + +static GParamSpec *obj_properties[LAST_PROP]; + +G_DEFINE_TYPE(RoseWebView, rose_webview, WEBKIT_TYPE_WEB_VIEW) + +static void update_navigation_flags(RoseWebView *webview) +{ + guint flags = 0; + if (webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(webview))) + flags |= ROSE_WEBVIEW_NAV_BACK; + + if (webkit_web_view_can_go_forward(WEBKIT_WEB_VIEW(webview))) + flags |= ROSE_WEBVIEW_FORWARD; + + if (webview->navigation != (RoseWebViewNavigationFlags) flags) { + webview->navigation = (RoseWebViewNavigationFlags) flags; + g_object_notify_by_pspec(G_OBJECT(webview), obj_properties[PROP_NAVIGATION]); + } +} + +static void rose_webview_constructed(GObject *object) +{ + RoseWebView *webview = ROSE_WEBVIEW(object); + g_auto(GStrv) cors_allowlist = NULL; + GtkStyleContext *context; + GdkRGBA color; + + G_OBJECT_CLASS(rose_webview_parent_class)->constructed (object); + + g_signal_connect_swapped(webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(webview)), + "changed", G_CALLBACK(update_navigation_flags), webview); + + context = gtk_widget_get_style_context(GTK_WIDGET(webview)); + + if (gtk_style_context_lookup_color(context, "theme_base_color", &color)) + webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(webview), &color); + + cors_allowlist = g_new(char*, 2); + cors_allowlist[0] = g_strdup("rose-resource://*/*"); + cors_allowlist[1] = NULL; + + webkit_web_view_set_cors_allowlist(WEBKIT_WEB_VIEW(webview), (const char* const *) cors_allowlist); +} + +static void rose_webview_dispose(GObject *object) +{ + RoseWebView *webview = ROSE_WEBVIEW(object); + WebKitUserContentManager *ucm = webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview)); + + if (webview->cancellable) { + g_cancellable_cancel(webview->cancellable); + g_clear_object(&webview->cancellable); + } + + G_OBJECT_CLASS(rose_webview_parent_class)->dispose (object); +} + +static void rose_webview_finalize(GObject *object) +{ + RoseWebView *view = ROSE_WEBVIEW(object); + + g_free(view->address); + + G_OBJECT_CLASS(rose_webview_parent_class)->finalize (object); +} + +static void rose_webview_class_init(RoseWebViewClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(class); + WebKitWebViewClass *webkit_webview_class = WEBKIT_WEB_VIEW_CLASS(class); + + object_class->dispose = rose_webview_dispose; + object_class->finalize = rose_webview_finalize; + object_class->constructed = rose_webview_constructed; + + obj_properties[PROP_ADDRESS] = + g_param_spec_string ("address", + "Address", + "address", + "", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); +} + +static void rose_webview_init(RoseWebView *webview) +{ + gtk_widget_set_overflow(GTK_WIDGET(webview), GTK_OVERFLOW_HIDDEN); +} + +void rose_webview_load_url(WebKitWebView *webview, const char *url) +{ + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url); +} + +GtkWidget* rose_webview_new() +{ + char cookiefile[64]; + WebKitWebView *webview; + WebKitCookieManager *cookiemanager; + WebKitUserContentManager *contentmanager; + + WebKitSettings *settings = webkit_settings_new_with_settings( + "auto-load-images", true, + "enable-back-forward-navigation-gestures", true, + "enable-developer-extras", true, + "enable-media-stream", true, + "hardware-acceleration-policy", WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS, + "javascript-can-access-clipboard", true, NULL); + + WebKitWebContext *context = webkit_web_context_new_with_website_data_manager( + webkit_website_data_manager_new( + "base-cache-directory", cachedir, + "base-data-directory", cachedir, + NULL)); + + webkit_settings_set_user_agent_with_application_details( + settings, "Mini", "0.1"); + + webkit_web_context_set_process_model(context, WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES); + webkit_web_context_set_cache_model(context, WEBKIT_CACHE_MODEL_WEB_BROWSER); + contentmanager = webkit_user_content_manager_new(); + cookiemanager = webkit_web_context_get_cookie_manager(context); + + strcpy(cookiefile, cachedir); + strcat(cookiefile, "cookies"); + + webkit_cookie_manager_set_persistent_storage(cookiemanager, + cookiefile, WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE); + + webkit_cookie_manager_set_accept_policy(cookiemanager, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS); + + return g_object_new( + WEBKIT_TYPE_WEB_VIEW, + "settings", settings, + "user-content-manager", contentmanager, + "web-context", context, NULL); +} diff --git a/webview.h b/webview.h new file mode 100644 index 0000000..697ea19 --- /dev/null +++ b/webview.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define ROSE_TYPE_WEBVIEW rose_webview_get_type() + +G_DECLARE_FINAL_TYPE(RoseWebView, rose_webview, ROSE, WEBVIEW, WebKitWebView) + +typedef enum +{ + ROSE_WEBVIEW_NAV_BACK = 1 << 0, + ROSE_WEBVIEW_FORWARD = 1 << 1 +} RoseWebViewNavigationFlags; + +GtkWidget* rose_webview_new(); +void rose_webview_load_url(WebKitWebView *webview, const char *url); + +RoseWebViewNavigationFlags rose_webview_get_navigation_flags(RoseWebView *webview); + +void rose_webview_go_back(RoseWebView *window); +void rose_webview_go_forward(RoseWebView *window); + +const char* rose_webview_get_address(RoseWebView *webview); diff --git a/window.c b/window.c new file mode 100644 index 0000000..b0ccfa9 --- /dev/null +++ b/window.c @@ -0,0 +1,103 @@ +#include "window.h" +/* #include "gestures.h" */ +#include "config.h" +#include "webview.h" + +struct _RoseWindow { + GtkApplicationWindow parent_instance; + + GtkWindow *window; + WebKitWebView *webview; + GHashTable *action_groups; + GHashTable *action_labels; + /* RoseGestureController *mouse_gesture_controller; */ +}; + +enum { + PROP_ACTIVE_CHILD +}; + +G_DEFINE_TYPE(RoseWindow, rose_window, GTK_TYPE_APPLICATION_WINDOW) + +static gboolean key_press_callback(WebKitWebView *webview, + guint keyval, + guint keycode, + GdkModifierType state) +{ + + if (state & GDK_CONTROL_MASK) { + switch (keycode) { + case 43: { + webkit_web_view_go_back(webview); + } break; + case 46: { + webkit_web_view_go_forward(webview); + } break; + case 26: { + rose_webview_load_url(webview, homepage); + } break; + } + } + + return GDK_EVENT_PROPAGATE; +} + +static void rose_window_constructed(GObject *object) +{ + RoseWindow *window; + GAction *action; + GActionGroup *action_group; + GSimpleActionGroup *simple_action_group; + guint i; + GApplication *app; + GtkEventController *controller; + + G_OBJECT_CLASS(rose_window_parent_class)->constructed(object); + + window = ROSE_WINDOW(window); +} + +static void rose_window_init(RoseWindow *window) +{ + window->window = GTK_WINDOW(gtk_window_new()); +} + +void rose_window_show(RoseWindow *window) +{ + GtkWidget *w = gtk_window_new(); + gtk_window_set_child(GTK_WINDOW(w), GTK_WIDGET(window->webview)); + + /* Keyboard shortcuts */ + GtkEventController *controller; + controller = gtk_event_controller_key_new(); + g_signal_connect_swapped(controller, "key-pressed", G_CALLBACK(key_press_callback), window->webview); + gtk_widget_add_controller(GTK_WIDGET(w), controller); + + gtk_widget_show(w); +} + +void rose_window_set_webview(RoseWindow *window, GtkWidget *webview) +{ + window->webview = WEBKIT_WEB_VIEW(webview); +} + +static void rose_window_class_init(RoseWindowClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(class); + GtkApplicationWindowClass *window_class = GTK_APPLICATION_WINDOW_CLASS(class); + + object_class->constructed = rose_window_constructed; + + /* g_object_class_override_property(object_class, */ + /* PROP_ACTIVE_CHILD, */ + /* "active-child"); */ +} + +RoseWindow* rose_window_new(GtkApplication *app) +{ + return g_object_new( + GTK_TYPE_APPLICATION_WINDOW, + "application", GTK_APPLICATION(app), + NULL + ); +} diff --git a/window.h b/window.h new file mode 100644 index 0000000..7e42018 --- /dev/null +++ b/window.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "webview.h" + +G_BEGIN_DECLS + +#define ROSE_TYPE_WINDOW rose_window_get_type() + +G_DECLARE_FINAL_TYPE(RoseWindow, rose_window, ROSE, WINDOW, GtkApplicationWindow) + +RoseWindow* rose_window_new(); +void rose_window_show(RoseWindow *window); +gboolean rose_window_close(RoseWindow *window); + +void rose_window_set_webview(RoseWindow *window, GtkWidget *webview); + +GActionGroup* rose_window_get_action_group(RoseWindow *window, + const char *prefix); + +G_END_DECLS