Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/908db8a51d21163e8c7607538834693b4e2ae490
...commit
http://git.netsurf-browser.org/netsurf.git/commit/908db8a51d21163e8c7607538834693b4e2ae490
...tree
http://git.netsurf-browser.org/netsurf.git/tree/908db8a51d21163e8c7607538834693b4e2ae490
The branch, master has been updated
via 908db8a51d21163e8c7607538834693b4e2ae490 (commit)
via 378d975474315e98fe545a644f5499575d556f9d (commit)
via af191bbcc91512650ee5a2db5e1b25a20e410919 (commit)
via e0d531b824ce00b2b7c6f3c444f0855774c12f11 (commit)
via b939afe3fc70be446d9ffd6e6071a4af5cf98a8a (commit)
via 51725592c96b3cb94aa70761b10960c738815534 (commit)
via ca5b165c85e1e8cc7df286b6a0a9a061de99bcaa (commit)
via ea84f67035ea9899086223c540a79ffec328caef (commit)
via 0f5d7cfcd2daade443ea0695275171247e2cfc22 (commit)
via 8dbb61d2f57b32483d67434e9ac169b5f14e7460 (commit)
from 3303c005eedd67c5b973c64f2515b28f9a7f56d2 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=908db8a51d21163e8c7607538834693b4e2ae490
commit 908db8a51d21163e8c7607538834693b4e2ae490
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
Add url percent escape test with minimal test vectors
diff --git a/test/Makefile b/test/Makefile
index 9fdb3f2..ea16b0a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,7 +1,7 @@
#
# NetSurf unit tests
-TESTS := nsurl urldbtest nsoption bloom hashtable #llcache
+TESTS := nsurl urldbtest nsoption bloom hashtable urlescape #llcache
# nsurl sources
nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
@@ -34,6 +34,9 @@ bloom_SRCS := utils/bloom.c test/bloom.c
# hash table test sources
hashtable_SRCS := utils/hashtable.c test/log.c test/hashtable.c
+# url escape test sources
+urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
+
# Coverage builds need additional flags
ifeq ($(MAKECMDGOALS),coverage)
COV_CFLAGS ?= -fprofile-arcs -ftest-coverage -O0
diff --git a/test/urlescape.c b/test/urlescape.c
new file mode 100644
index 0000000..5d9d932
--- /dev/null
+++ b/test/urlescape.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Test url percent encoding operations.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+
+#include "utils/url.h"
+
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
+#define SLEN(x) (sizeof((x)) - 1)
+
+struct test_pairs {
+ const char* test;
+ const char* res;
+ const size_t res_len;
+};
+
+const char all_chars[] =
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+
+const char all_escaped[] =
+ "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F"
+ "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"
+ "%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F"
+ "0123456789%3A%3B%3C%3D%3E%3F"
+ "%40ABCDEFGHIJKLMNO"
+ "PQRSTUVWXYZ%5B%5C%5D%5E_"
+ "%60abcdefghijklmno"
+ "pqrstuvwxyz%7B%7C%7D%7E%7F"
+ "%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F"
+ "%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F"
+ "%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF"
+ "%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF"
+ "%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF"
+ "%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF"
+ "%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF"
+ "%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF";
+
+static const struct test_pairs url_escape_test_vec[] = {
+ { "", "" , 0 },
+ { "A.string.that.does.not.need.escaping",
+ "A.string.that.does.not.need.escaping" , 0 },
+ { " ", "%20" , 0 },
+ { &all_chars[0], &all_escaped[0], 0 },
+};
+
+
+START_TEST(url_escape_test)
+{
+ nserror err;
+ char *esc_str;
+ const struct test_pairs *tst = &url_escape_test_vec[_i];
+
+ err = url_escape(tst->test, false, "", &esc_str);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(esc_str, tst->res);
+}
+END_TEST
+
+static const struct test_pairs url_unescape_test_vec[] = {
+ { "", "" , 0 },
+ { "A.string.that.does.not.need.unescaping",
+ "A.string.that.does.not.need.unescaping",
+ SLEN("A.string.that.does.not.need.unescaping") },
+ { "%20", " " , 1 },
+ { &all_escaped[0], &all_chars[0], SLEN(all_chars) },
+};
+
+START_TEST(url_unescape_test)
+{
+ nserror err;
+ char *unesc_str;
+ size_t unesc_length;
+
+ const struct test_pairs *tst = &url_unescape_test_vec[_i];
+
+ err = url_unescape(tst->test, 0 , &unesc_length, &unesc_str);
+ ck_assert(err == NSERROR_OK);
+ /* ensure length */
+ ck_assert_uint_eq(unesc_length, tst->res_len);
+ /* ensure contents */
+ ck_assert_str_eq(unesc_str, tst->res);
+}
+END_TEST
+
+
+
+TCase *url_escape_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Escape");
+
+ tcase_add_loop_test(tc, url_escape_test,
+ 0, NELEMS(url_escape_test_vec));
+
+ return tc;
+}
+
+TCase *url_unescape_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Unescape");
+
+ tcase_add_loop_test(tc, url_unescape_test,
+ 0, NELEMS(url_unescape_test_vec));
+
+ return tc;
+}
+
+
+Suite *urlescape_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("Percent escaping");
+
+ suite_add_tcase(s, url_escape_case_create());
+ suite_add_tcase(s, url_unescape_case_create());
+
+ return s;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(urlescape_suite_create());
+ //srunner_add_suite(sr, bar_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=378d975474315e98fe545a644f5499575d556f9d
commit 378d975474315e98fe545a644f5499575d556f9d
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
add basic documentation on unit testing using check
diff --git a/Docs/unit-testing b/Docs/unit-testing
new file mode 100644
index 0000000..49d82ed
--- /dev/null
+++ b/Docs/unit-testing
@@ -0,0 +1,166 @@
+NetSurf Unit Testing
+====================
+
+Overview
+--------
+
+NetSurf has unit tests integrated in the test directory. These tests
+use the check unit test framework for C [1].
+
+The tests are in a logical hierachy of "suite", "case" and individual
+"test". Historicaly we have split suites of tests into separate test
+programs although the framework does not madate this and some test
+programs contain more than one suite.
+
+
+Execution
+---------
+
+The test programs are executed by using the standard "test" target
+from the top level make invocation. The "coverage" target additionally
+generates code coverage reports allowing visibility on how much of a
+code module is being exercised.
+
+The check library must be installed to run the tests and the CI system
+automatically executes all enabled tests and generates coverage
+reports for each commit.
+
+Adding tests
+------------
+
+The test/Makefile defines each indiviadual test program that should be
+built and executed in the TESTS variable.
+
+The test program source files are defined in a xxx_SRCS variable and
+the make rules will then ensure the target program is built and
+executed.
+
+Each individual test program requires a main function which creates
+one (or more) suites. The suites are added to a test runner and then
+executed and the results reported.
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(foo_suite_create());
+ //srunner_add_suite(sr, bar_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+Suite creation is done with a sub function to logically split suite
+code into sub modules. Each suite has test cases added to it.
+
+Suite *foo_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("foo");
+
+ suite_add_tcase(s, baz_case_create());
+ suite_add_tcase(s, qux_case_create());
+
+ return s;
+}
+
+Test cases include the actual tests to be performed within each case.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_test(tc, xxyz_test);
+ tcase_add_test(tc, zzyx_test);
+
+ return tc;
+}
+
+A test case may optionally have a fixture which is code that is
+executed before and after each test case. Unchecked fixtures are
+executed once before the test process forks for each test whereas
+checked fixtures are executed for each and every test.
+
+static void fixture_setup(void)
+{
+}
+
+static void fixture_teardown(void)
+{
+}
+
+TCase *qux_case_create(void)
+{
+ TCase *tc;
+
+ /* Matching entry tests */
+ tc = tcase_create("Match");
+
+ tcase_add_checked_fixture(tc,
+ fixture_setup,
+ fixture_teardown);
+
+ tcase_add_test(tc, zzz_test);
+
+ return tc;
+}
+
+Additionally test cases can contain tests executed in a loop. The test
+recives a single integer as a parameter named _i which iterates
+between values specified in the case setup.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_loop_test(tc, looping_test, 0, 5);
+
+ return tc;
+}
+
+It is also possible to create tests which will generate a signal. The
+most commonly used of these is to check asserts in API calls.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_test_raise_signal(tc, assert_test, 6);
+
+ return tc;
+}
+
+
+Actual test code is self contained in a function which uses the
+ck_assert macros to test results. The check framework requires each
+test to use the START_TEST and END_TEST macros when definig them.
+
+/**
+ * url access leaf test
+ */
+START_TEST(nsurl_access_leaf_test)
+{
+ nserror err;
+ nsurl *res_url;
+ const struct test_triplets *tst = &access_tests[_i];
+
+ /* not testing create, this should always succeed */
+ err = nsurl_create(tst->test1, &res_url);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(nsurl_access_leaf(res_url), tst->res);
+
+ nsurl_unref(res_url);
+}
+END_TEST
+
+
+[1] https://libcheck.github.io/check/
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=af191bbcc91512650ee5a2db5e1b25a20e410919
commit af191bbcc91512650ee5a2db5e1b25a20e410919
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
make gtk certificate viewing use gtk core window API
diff --git a/frontends/gtk/ssl_cert.c b/frontends/gtk/ssl_cert.c
index e3bc8a7..1cf0beb 100644
--- a/frontends/gtk/ssl_cert.c
+++ b/frontends/gtk/ssl_cert.c
@@ -16,122 +16,250 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * Implementation of gtk certificate viewing using gtk core windows.
+ */
+
+#include <stdint.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "utils/log.h"
-#include "utils/nsurl.h"
-#include "desktop/tree.h"
+#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
#include "desktop/sslcert_viewer.h"
+#include "desktop/treeview.h"
-#include "gtk/treeview.h"
+#include "gtk/plotters.h"
#include "gtk/scaffolding.h"
#include "gtk/resources.h"
#include "gtk/ssl_cert.h"
+#include "gtk/corewindow.h"
+
+
+/**
+ * GTK certificate viewing window context
+ */
+struct nsgtk_crtvrfy_window {
+ /** GTK core window context */
+ struct nsgtk_corewindow core;
+ /** GTK builder for window */
+ GtkBuilder *builder;
+ /** GTK dialog window being shown */
+ GtkDialog *dlg;
+ /** SSL certificate viewer context data */
+ struct sslcert_session_data *ssl_data;
+};
+/**
+ * destroy a previously created certificate view
+ */
+static nserror nsgtk_crtvrfy_destroy(struct nsgtk_crtvrfy_window *crtvrfy_win)
+{
+ nserror res;
-static void nsgtk_ssl_accept(GtkButton *w, gpointer data)
+ res = sslcert_viewer_fini(crtvrfy_win->ssl_data);
+ if (res == NSERROR_OK) {
+ res = nsgtk_corewindow_fini(&crtvrfy_win->core);
+ gtk_widget_destroy(GTK_WIDGET(crtvrfy_win->dlg));
+ g_object_unref(G_OBJECT(crtvrfy_win->builder));
+ free(crtvrfy_win);
+ }
+ return res;
+}
+
+static void
+nsgtk_crtvrfy_accept(GtkButton *w, gpointer data)
{
- void **session = data;
- GtkBuilder *x = session[0];
- struct nsgtk_treeview *wnd = session[1];
- struct sslcert_session_data *ssl_data = session[2];
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)data;
- sslcert_viewer_accept(ssl_data);
+ sslcert_viewer_accept(crtvrfy_win->ssl_data);
- nsgtk_treeview_destroy(wnd);
- g_object_unref(G_OBJECT(x));
- free(session);
+ nsgtk_crtvrfy_destroy(crtvrfy_win);
}
-static void nsgtk_ssl_reject(GtkWidget *w, gpointer data)
+static void
+nsgtk_crtvrfy_reject(GtkWidget *w, gpointer data)
{
- void **session = data;
- GtkBuilder *x = session[0];
- struct nsgtk_treeview *wnd = session[1];
- struct sslcert_session_data *ssl_data = session[2];
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)data;
- sslcert_viewer_reject(ssl_data);
+ sslcert_viewer_reject(crtvrfy_win->ssl_data);
- nsgtk_treeview_destroy(wnd);
- g_object_unref(G_OBJECT(x));
- free(session);
+ nsgtk_crtvrfy_destroy(crtvrfy_win);
}
-static gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event,
gpointer data)
+static gboolean
+nsgtk_crtvrfy_delete_event(GtkWidget *w, GdkEvent *event, gpointer data)
{
- nsgtk_ssl_reject(w, data);
+ nsgtk_crtvrfy_reject(w, data);
return FALSE;
}
-nserror gtk_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
- unsigned long num, nserror (*cb)(bool proceed, void *pw),
- void *cbpw)
+/**
+ * callback for mouse action for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_mouse(struct nsgtk_corewindow *nsgtk_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+/**
+ * callback for keypress for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
{
- static struct nsgtk_treeview *ssl_window;
- struct sslcert_session_data *data;
- GtkButton *accept, *reject;
- void **session;
- GtkDialog *dlg;
- GtkScrolledWindow *scrolled;
- GtkDrawingArea *drawing_area;
- GtkBuilder *builder;
- GtkWindow *gtk_parent;
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+/**
+ * callback on draw event for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in gtk/ssl_cert.h */
+nserror gtk_cert_verify(struct nsurl *url,
+ const struct ssl_cert_info *certs,
+ unsigned long num,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ struct nsgtk_crtvrfy_window *ncwin;
nserror res;
- /* state while dlg is open */
- session = calloc(sizeof(void *), 3);
- if (session == NULL) {
+ res = treeview_init(0);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ ncwin = malloc(sizeof(struct nsgtk_crtvrfy_window));
+ if (ncwin == NULL) {
return NSERROR_NOMEM;
}
- res = nsgtk_builder_new_from_resname("ssl", &builder);
+ res = nsgtk_builder_new_from_resname("ssl", &ncwin->builder);
if (res != NSERROR_OK) {
LOG("SSL UI builder init failed");
- free(session);
- return NSERROR_INIT_FAILED;
+ free(ncwin);
+ return res;
}
- gtk_builder_connect_signals(builder, NULL);
-
- sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, &data);
+ gtk_builder_connect_signals(ncwin->builder, NULL);
- dlg = GTK_DIALOG(gtk_builder_get_object(builder, "wndSSLProblem"));
+ ncwin->dlg = GTK_DIALOG(gtk_builder_get_object(ncwin->builder,
+ "wndSSLProblem"));
/* set parent for transient dialog */
- gtk_parent = nsgtk_scaffolding_window(nsgtk_current_scaffolding());
- gtk_window_set_transient_for(GTK_WINDOW(dlg), gtk_parent);
-
- scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(builder,
"SSLScrolled"));
- drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(builder,
"SSLDrawingArea"));
-
- ssl_window = nsgtk_treeview_create(TREE_SSLCERT,
- GTK_WINDOW(dlg),
- scrolled,
- drawing_area,
- data);
- if (ssl_window == NULL) {
- free(session);
- g_object_unref(G_OBJECT(dlg));
- return NSERROR_INIT_FAILED;
- }
+ gtk_window_set_transient_for(GTK_WINDOW(ncwin->dlg),
+ nsgtk_scaffolding_window(nsgtk_current_scaffolding()));
+
+ ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
+ gtk_builder_get_object(ncwin->builder, "SSLScrolled"));
+
+ ncwin->core.drawing_area = GTK_DRAWING_AREA(
+ gtk_builder_get_object(ncwin->builder, "SSLDrawingArea"));
+
+ /* make the delete event call our destructor */
+ g_signal_connect(G_OBJECT(ncwin->dlg),
+ "delete_event",
+ G_CALLBACK(nsgtk_crtvrfy_delete_event),
+ ncwin);
+
+ /* accept button */
+ g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder,
+ "sslaccept")),
+ "clicked",
+ G_CALLBACK(nsgtk_crtvrfy_accept),
+ ncwin);
- accept = GTK_BUTTON(gtk_builder_get_object(builder, "sslaccept"));
- reject = GTK_BUTTON(gtk_builder_get_object(builder, "sslreject"));
+ /* reject button */
+ g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder,
+ "sslreject")),
+ "clicked",
+ G_CALLBACK(nsgtk_crtvrfy_reject),
+ ncwin);
- session[0] = builder;
- session[1] = ssl_window;
- session[2] = data;
+ /* initialise GTK core window */
+ ncwin->core.draw = nsgtk_crtvrfy_draw;
+ ncwin->core.key = nsgtk_crtvrfy_key;
+ ncwin->core.mouse = nsgtk_crtvrfy_mouse;
-#define CONNECT(obj, sig, callback, ptr) \
- g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
+ res = nsgtk_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
- CONNECT(accept, "clicked", nsgtk_ssl_accept, session);
- CONNECT(reject, "clicked", nsgtk_ssl_reject, session);
- CONNECT(dlg, "delete_event", G_CALLBACK(nsgtk_ssl_delete_event),
- (gpointer)session);
+ /* initialise certificate viewing interface */
+ res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs,
+ &ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
+
+ res = sslcert_viewer_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
- gtk_widget_show(GTK_WIDGET(dlg));
+ gtk_widget_show(GTK_WIDGET(ncwin->dlg));
return NSERROR_OK;
}
diff --git a/frontends/gtk/ssl_cert.h b/frontends/gtk/ssl_cert.h
index 398f1cc..1712756 100644
--- a/frontends/gtk/ssl_cert.h
+++ b/frontends/gtk/ssl_cert.h
@@ -30,6 +30,7 @@ struct ssl_cert_info;
* \param num The number of certificates to be verified.
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK or error code if prompt creation failed.
*/
nserror gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=e0d531b824ce00b2b7c6f3c444f0855774c12f11
commit e0d531b824ce00b2b7c6f3c444f0855774c12f11
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
fix certificate viewer keypress consumption return
diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c
index f3eb169..93d6919 100644
--- a/desktop/sslcert_viewer.c
+++ b/desktop/sslcert_viewer.c
@@ -516,8 +516,7 @@ void sslcert_viewer_mouse_action(struct
sslcert_session_data *ssl_d,
/* Exported interface, documented in sslcert_viewer.h */
-void sslcert_viewer_keypress(struct sslcert_session_data *ssl_d,
- uint32_t key)
+bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key)
{
- treeview_keypress(ssl_d->tree, key);
+ return treeview_keypress(ssl_d->tree, key);
}
diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h
index f7c8f33..9b21cd1 100644
--- a/desktop/sslcert_viewer.h
+++ b/desktop/sslcert_viewer.h
@@ -119,7 +119,6 @@ void sslcert_viewer_mouse_action(struct
sslcert_session_data *ssl_d,
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
-void sslcert_viewer_keypress(struct sslcert_session_data *ssl_d,
- uint32_t key);
+bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key);
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=b939afe3fc70be446d9ffd6e6071a4af5cf98a8a
commit b939afe3fc70be446d9ffd6e6071a4af5cf98a8a
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
Allow certificate verification user prompt creation to return errors
diff --git a/content/llcache.c b/content/llcache.c
index 33a9b98..e338c1f 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -2214,6 +2214,11 @@ static nserror llcache_fetch_auth(llcache_object
*object, const char *realm)
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
+ if (error != NSERROR_OK) {
+ /* do not continue if error querying user */
+ error = llcache_query_handle_response(false,
+ object);
+ }
} else {
llcache_event event;
@@ -2269,6 +2274,10 @@ static nserror llcache_fetch_cert_error(llcache_object
*object,
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
+ if (error != NSERROR_OK) {
+ /* do not continue if error querying user */
+ error = llcache_query_handle_response(false, object);
+ }
} else {
llcache_event event;
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index cecbe6e..88bb9ba 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -685,13 +685,13 @@ static nserror gui_default_launch_url(struct nsurl *url)
}
-static void gui_default_cert_verify(nsurl *url,
+static nserror gui_default_cert_verify(nsurl *url,
const struct ssl_cert_info *certs,
unsigned long num,
nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
- cb(false, cbpw);
+ return NSERROR_NOT_IMPLEMENTED;
}
static void gui_default_401login_open(nsurl *url, const char *realm,
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index ffcec04..f1daeab 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -104,21 +104,25 @@ static void netsurf_lwc_iterator(lwc_string *str, void
*pw)
static nserror netsurf_llcache_query_handler(const llcache_query *query,
void *pw, llcache_query_response cb, void *cbpw)
{
+ nserror res = NSERROR_OK;
+
switch (query->type) {
case LLCACHE_QUERY_AUTH:
guit->misc->login(query->url, query->data.auth.realm, cb, cbpw);
break;
+
case LLCACHE_QUERY_REDIRECT:
/** \todo Need redirect query dialog */
/* For now, do nothing, as this query type isn't emitted yet */
break;
+
case LLCACHE_QUERY_SSL:
- guit->misc->cert_verify(query->url, query->data.ssl.certs,
+ res = guit->misc->cert_verify(query->url, query->data.ssl.certs,
query->data.ssl.num, cb, cbpw);
break;
}
- return NSERROR_OK;
+ return res;
}
/* exported interface documented in netsurf/netsurf.h */
diff --git a/frontends/amiga/sslcert.c b/frontends/amiga/sslcert.c
index ed72061..83798f2 100644
--- a/frontends/amiga/sslcert.c
+++ b/frontends/amiga/sslcert.c
@@ -27,7 +27,7 @@
#include "amiga/tree.h"
#include "amiga/sslcert.h"
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
@@ -39,9 +39,13 @@ void gui_cert_verify(nsurl *url,
ssl_current_session = data;
ssl_window = ami_tree_create(TREE_SSLCERT, data);
- if(!ssl_window) return;
+ if (!ssl_window) {
+ return NSERROR_INIT_FAILED;
+ }
ami_tree_open(ssl_window, AMI_TREE_SSLCERT);
+
+ return NSERROR_OK;
}
void ami_ssl_free(struct treeview_window *twin)
diff --git a/frontends/amiga/sslcert.h b/frontends/amiga/sslcert.h
index 953142e..86ce9c4 100644
--- a/frontends/amiga/sslcert.h
+++ b/frontends/amiga/sslcert.h
@@ -19,7 +19,7 @@
#ifndef AMIGA_SSLCERT_H
#define AMIGA_SSLCERT_H
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index 713db8b..eb15777 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -771,7 +771,7 @@ static void gui_401login_open(nsurl *url, const char *realm,
}
-static void
+static nserror
gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
@@ -795,7 +795,7 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info
*certs,
&data);
atari_sslcert_viewer_open(data);
}
-
+ return NSERROR_OK;
}
void gui_set_input_gui_window(struct gui_window *gw)
diff --git a/frontends/cocoa/gui.m b/frontends/cocoa/gui.m
index b1847eb..7e180fa 100644
--- a/frontends/cocoa/gui.m
+++ b/frontends/cocoa/gui.m
@@ -285,13 +285,13 @@ static nserror gui_launch_url(nsurl *url)
struct ssl_cert_info;
-static void
+static nserror
gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs,
unsigned long num,
nserror (*cb)(bool proceed,void *pw), void *cbpw)
{
- cb( false, cbpw );
+ return NSERROR_NOT_IMPLEMENTED;
}
diff --git a/frontends/gtk/ssl_cert.c b/frontends/gtk/ssl_cert.c
index 463f5cd..e3bc8a7 100644
--- a/frontends/gtk/ssl_cert.c
+++ b/frontends/gtk/ssl_cert.c
@@ -64,7 +64,7 @@ static gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent
*event, gpointer
return FALSE;
}
-void gtk_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
+nserror gtk_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
@@ -82,15 +82,14 @@ void gtk_cert_verify(nsurl *url, const struct ssl_cert_info
*certs,
/* state while dlg is open */
session = calloc(sizeof(void *), 3);
if (session == NULL) {
- return;
+ return NSERROR_NOMEM;
}
res = nsgtk_builder_new_from_resname("ssl", &builder);
if (res != NSERROR_OK) {
LOG("SSL UI builder init failed");
free(session);
- cb(false, cbpw);
- return;
+ return NSERROR_INIT_FAILED;
}
gtk_builder_connect_signals(builder, NULL);
@@ -114,7 +113,7 @@ void gtk_cert_verify(nsurl *url, const struct ssl_cert_info
*certs,
if (ssl_window == NULL) {
free(session);
g_object_unref(G_OBJECT(dlg));
- return;
+ return NSERROR_INIT_FAILED;
}
accept = GTK_BUTTON(gtk_builder_get_object(builder, "sslaccept"));
@@ -133,4 +132,6 @@ void gtk_cert_verify(nsurl *url, const struct ssl_cert_info
*certs,
(gpointer)session);
gtk_widget_show(GTK_WIDGET(dlg));
+
+ return NSERROR_OK;
}
diff --git a/frontends/gtk/ssl_cert.h b/frontends/gtk/ssl_cert.h
index 48937d4..398f1cc 100644
--- a/frontends/gtk/ssl_cert.h
+++ b/frontends/gtk/ssl_cert.h
@@ -31,6 +31,6 @@ struct ssl_cert_info;
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
*/
-void gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+nserror gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
#endif
diff --git a/frontends/monkey/cert.c b/frontends/monkey/cert.c
index ec1b1ce..710e710 100644
--- a/frontends/monkey/cert.c
+++ b/frontends/monkey/cert.c
@@ -35,15 +35,14 @@ typedef struct monkey_cert {
static monkey_cert_t *cert_ring = NULL;
static uint32_t cert_ctr = 0;
-void
+nserror
gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
monkey_cert_t *m4t = calloc(sizeof(*m4t), 1);
if (m4t == NULL) {
- cb(false, cbpw);
- return;
+ return NSERROR_NOMEM;
}
m4t->cb = cb;
m4t->pw = cbpw;
@@ -53,6 +52,8 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n",
m4t->num, nsurl_access(url));
+
+ return NSERROR_OK;
}
diff --git a/frontends/monkey/cert.h b/frontends/monkey/cert.h
index 283817f..4470e2e 100644
--- a/frontends/monkey/cert.h
+++ b/frontends/monkey/cert.h
@@ -21,7 +21,7 @@
struct ssl_cert_info;
-void gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
+nserror gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw);
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 624f9e2..505e8e7 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -212,7 +212,7 @@ extern int ro_plot_origin_y;
bool ro_gui_theme_install_apply(wimp_w w);
/* in sslcert.c */
-void gui_cert_verify(struct nsurl *url,
+nserror gui_cert_verify(struct nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
diff --git a/frontends/riscos/sslcert.c b/frontends/riscos/sslcert.c
index c7b8db4..8a8ddfb 100644
--- a/frontends/riscos/sslcert.c
+++ b/frontends/riscos/sslcert.c
@@ -101,7 +101,7 @@ void ro_gui_cert_postinitialise(void)
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
*/
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
@@ -117,7 +117,7 @@ void gui_cert_verify(nsurl *url,
sslcert_window = malloc(sizeof(struct ro_sslcert));
if (sslcert_window == NULL) {
LOG("Failed to allocate memory for SSL Cert Dialog");
- return;
+ return NSERROR_NOMEM;
}
/* Create the SSL window and its pane. */
@@ -127,7 +127,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
LOG("xwimp_create_window: 0x%x: %s", error->errnum,
error->errmess);
free(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
error = xwimp_create_window(ro_gui_cert_tree_template,
@@ -135,7 +135,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
LOG("xwimp_create_window: 0x%x: %s", error->errnum,
error->errmess);
free(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
/* Create the SSL data and build a tree from it. */
@@ -148,7 +148,7 @@ void gui_cert_verify(nsurl *url,
if (sslcert_window->tv == NULL) {
LOG("Failed to allocate treeview");
free(sslcert_window);
- return;
+ return NSERROR_NOMEM;
}
/* Set up the certificate window event handling.
@@ -182,7 +182,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_window_info: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
state.w = sslcert_window->window;
@@ -190,7 +190,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
istate.w = sslcert_window->window;
@@ -199,7 +199,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
state.w = sslcert_window->pane;
@@ -230,7 +230,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_set_extent: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
}
@@ -248,10 +248,12 @@ void gui_cert_verify(nsurl *url,
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum,
error->errmess);
ro_gui_cert_release_window(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
ro_treeview_set_origin(sslcert_window->tv, 0, 0);
+
+ return NSERROR_OK;
}
/**
diff --git a/include/netsurf/misc.h b/include/netsurf/misc.h
index 7b35495..2647b9a 100644
--- a/include/netsurf/misc.h
+++ b/include/netsurf/misc.h
@@ -89,8 +89,9 @@ struct gui_misc_table {
* \param num The number of certificates to be verified.
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK on sucess else error and cb never called
*/
- void (*cert_verify)(struct nsurl *url, const struct ssl_cert_info
*certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+ nserror (*cert_verify)(struct nsurl *url, const struct ssl_cert_info
*certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
/**
* Prompt user for login
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=51725592c96b3cb94aa70761b10960c738815534
commit 51725592c96b3cb94aa70761b10960c738815534
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
make gtk cookies manager use core window API
diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c
index f252e6b..d8f8b5d 100644
--- a/frontends/gtk/cookies.c
+++ b/frontends/gtk/cookies.c
@@ -16,28 +16,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Cookies (implementation).
+/**
+ * \file
+ * Implementation of GTK cookie manager.
*/
-#include <gtk/gtk.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
#include "utils/log.h"
#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
#include "desktop/cookie_manager.h"
-#include "desktop/plot_style.h"
-#include "desktop/tree.h"
+#include "desktop/treeview.h"
#include "gtk/cookies.h"
#include "gtk/plotters.h"
#include "gtk/scaffolding.h"
-#include "gtk/treeview.h"
#include "gtk/resources.h"
+#include "gtk/corewindow.h"
+
+struct nsgtk_cookie_window {
+ struct nsgtk_corewindow core;
+ GtkBuilder *builder;
+ GtkWindow *wnd;
+};
-static struct nsgtk_treeview *cookies_treeview;
-static GtkBuilder *cookie_builder;
-static GtkWindow *wndCookies = NULL;
+static struct nsgtk_cookie_window *cookie_window = NULL;
#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
GtkMenuItem *widget, gpointer g)
@@ -85,80 +91,6 @@ static struct menu_events menu_events[] = {
};
-
-/**
- * Connects menu events in the cookies window.
- */
-static void nsgtk_cookies_init_menu(void)
-{
- struct menu_events *event = menu_events;
- GtkWidget *w;
-
- while (event->widget != NULL) {
- w = GTK_WIDGET(gtk_builder_get_object(cookie_builder,
event->widget));
- if (w == NULL) {
- LOG("Unable to connect menu widget ""%s""",
event->widget); } else {
- g_signal_connect(G_OBJECT(w), "activate",
event->handler, cookies_treeview);
- }
- event++;
- }
-}
-
-/**
- * Creates the window for the cookies tree.
- *
- * \return NSERROR_OK on success else appropriate error code on faliure.
- */
-static nserror nsgtk_cookies_init(void)
-{
- GtkScrolledWindow *scrolled;
- GtkDrawingArea *drawing_area;
- nserror res;
-
- if (wndCookies != NULL) {
- return NSERROR_OK;
- }
-
- res = nsgtk_builder_new_from_resname("cookies", &cookie_builder);
- if (res != NSERROR_OK) {
- LOG("Cookie UI builder init failed");
- return res;
- }
-
- gtk_builder_connect_signals(cookie_builder, NULL);
-
- wndCookies = GTK_WINDOW(gtk_builder_get_object(cookie_builder,
- "wndCookies"));
-
- scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(cookie_builder,
- "cookiesScrolled"));
-
- drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(cookie_builder,
- "cookiesDrawingArea"));
-
- cookies_treeview = nsgtk_treeview_create(TREE_COOKIES,
- wndCookies,
- scrolled,
- drawing_area,
- NULL);
- if (cookies_treeview == NULL) {
- return NSERROR_INIT_FAILED;
- }
-
-#define CONNECT(obj, sig, callback, ptr) \
- g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
-
- CONNECT(wndCookies, "delete_event", gtk_widget_hide_on_delete, NULL);
- CONNECT(wndCookies, "hide", nsgtk_tree_window_hide, cookies_treeview);
-
- nsgtk_cookies_init_menu();
-
- return NSERROR_OK;
-}
-
-
-
-
/* edit menu */
MENUHANDLER(delete_selected)
{
@@ -222,6 +154,162 @@ MENUHANDLER(collapse_cookies)
return TRUE;
}
+/**
+ * Connects menu events in the cookies window.
+ */
+static void nsgtk_cookies_init_menu(struct nsgtk_cookie_window *ncwin)
+{
+ struct menu_events *event = menu_events;
+ GtkWidget *w;
+
+ while (event->widget != NULL) {
+ w = GTK_WIDGET(gtk_builder_get_object(ncwin->builder,
+ event->widget));
+ if (w == NULL) {
+ LOG("Unable to connect menu widget ""%s""",
+ event->widget);
+ } else {
+ g_signal_connect(G_OBJECT(w),
+ "activate",
+ event->handler,
+ ncwin);
+ }
+ event++;
+ }
+}
+
+/**
+ * callback for mouse action on cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_mouse(struct nsgtk_corewindow *nsgtk_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ cookie_manager_mouse_action(mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+/**
+ * callback for keypress on cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
+{
+ if (cookie_manager_keypress(nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+/**
+ * callback on draw event for cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+
+ cookie_manager_redraw(0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Creates the window for the cookies tree.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror nsgtk_cookies_init(void)
+{
+ struct nsgtk_cookie_window *ncwin;
+ nserror res;
+
+ if (cookie_window != NULL) {
+ return NSERROR_OK;
+ }
+
+ res = treeview_init(0);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ ncwin = malloc(sizeof(struct nsgtk_cookie_window));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_builder_new_from_resname("cookies", &ncwin->builder);
+ if (res != NSERROR_OK) {
+ LOG("Cookie UI builder init failed");
+ free(ncwin);
+ return res;
+ }
+
+ gtk_builder_connect_signals(ncwin->builder, NULL);
+
+ ncwin->wnd = GTK_WINDOW(gtk_builder_get_object(ncwin->builder,
+ "wndCookies"));
+
+ ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
+ gtk_builder_get_object(ncwin->builder, "cookiesScrolled"));
+
+ ncwin->core.drawing_area = GTK_DRAWING_AREA(
+ gtk_builder_get_object(ncwin->builder, "cookiesDrawingArea"));
+
+ /* make the delete event hide the window */
+ g_signal_connect(G_OBJECT(ncwin->wnd),
+ "delete_event",
+ G_CALLBACK(gtk_widget_hide_on_delete),
+ NULL);
+
+ nsgtk_cookies_init_menu(ncwin);
+
+ ncwin->core.draw = nsgtk_cookies_draw;
+ ncwin->core.key = nsgtk_cookies_key;
+ ncwin->core.mouse = nsgtk_cookies_mouse;
+
+ res = nsgtk_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = cookie_manager_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ cookie_window = ncwin;
+
+ return NSERROR_OK;
+}
+
+
/* exported function documented gtk/cookies.h */
nserror nsgtk_cookies_present(void)
{
@@ -229,16 +317,29 @@ nserror nsgtk_cookies_present(void)
res = nsgtk_cookies_init();
if (res == NSERROR_OK) {
- gtk_window_present(wndCookies);
+ gtk_window_present(cookie_window->wnd);
}
return res;
}
+
/* exported function documented gtk/cookies.h */
-void nsgtk_cookies_destroy(void)
+nserror nsgtk_cookies_destroy(void)
{
- /** \todo what about cookie_builder? */
- if (wndCookies != NULL) {
- nsgtk_treeview_destroy(cookies_treeview);
+ nserror res;
+
+ if (cookie_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = cookie_manager_fini();
+ if (res == NSERROR_OK) {
+ res = nsgtk_corewindow_fini(&cookie_window->core);
+ gtk_widget_destroy(GTK_WIDGET(cookie_window->wnd));
+ g_object_unref(G_OBJECT(cookie_window->builder));
+ free(cookie_window);
+ cookie_window = NULL;
}
+
+ return res;
}
diff --git a/frontends/gtk/cookies.h b/frontends/gtk/cookies.h
index 2af05e1..c1a68b7 100644
--- a/frontends/gtk/cookies.h
+++ b/frontends/gtk/cookies.h
@@ -35,7 +35,7 @@ nserror nsgtk_cookies_present(void);
*
* \return NSERROR_OK on success else appropriate error code on faliure.
*/
-void nsgtk_cookies_destroy(void);
+nserror nsgtk_cookies_destroy(void);
#endif /* __NSGTK_COOKIES_H__ */
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index d57ebdf..0ed32e9 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -434,13 +434,21 @@ static void nsgtk_main(void)
static void gui_quit(void)
{
+ nserror res;
+
LOG("Quitting GUI");
/* Ensure all scaffoldings are destroyed before we go into exit */
nsgtk_download_destroy();
urldb_save_cookies(nsoption_charp(cookie_jar));
urldb_save(nsoption_charp(url_file));
- nsgtk_cookies_destroy();
+
+ res = nsgtk_cookies_destroy();
+ if (res != NSERROR_OK) {
+ LOG("Error finalising cookie viewer: %s",
+ messages_get_errorcode(res));
+ }
+
nsgtk_history_destroy();
nsgtk_hotlist_destroy();
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ca5b165c85e1e8cc7df286b6a0a9a061de99bcaa
commit ca5b165c85e1e8cc7df286b6a0a9a061de99bcaa
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
add nsgtk support for core window API
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index aae1d44..f8f7d8c 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -163,7 +163,7 @@ S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c
plotters.c \
selection.c history.c window.c fetch.c download.c menu.c \
print.c search.c tabs.c toolbar.c gettext.c \
compat.c cookies.c hotlist.c viewdata.c viewsource.c \
- preferences.c about.c ssl_cert.c resources.c
+ preferences.c about.c ssl_cert.c resources.c corewindow.c
# This is the final source build list
# Note this is deliberately *not* expanded here as common and image
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
new file mode 100644
index 0000000..11dec83
--- /dev/null
+++ b/frontends/gtk/corewindow.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK generic core window interface.
+ *
+ * Provides interface for core renderers to the gtk toolkit drawable area.
+ * \todo should the interface really be called coredrawable?
+ *
+
+ * This module is an object that must be encapsulated. Client users
+ * should embed a struct nsgtk_corewindow at the beginning of their
+ * context for this display surface, fill in relevant data and then
+ * call nsgtk_corewindow_init()
+ *
+ * The nsgtk core window structure requires the drawing area and
+ * scrollable widgets are present and the callback for draw, key and
+ * mouse operations.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/messages.h"
+#include "utils/utf8.h"
+#include "netsurf/keypress.h"
+#include "netsurf/mouse.h"
+#include "desktop/plot_style.h"
+
+#include "gtk/compat.h"
+#include "gtk/gui.h" /* just for gtk_gui_gdkkey_to_nskey */
+#include "gtk/plotters.h"
+#include "gtk/corewindow.h"
+
+/**
+ * Convert GDK mouse event to netsurf mouse state
+ */
+static browser_mouse_state nsgtk_cw_gdkbutton_to_nsstate(GdkEventButton *event)
+{
+ browser_mouse_state ms;
+
+ if (event->type == GDK_2BUTTON_PRESS) {
+ ms = BROWSER_MOUSE_DOUBLE_CLICK;
+ } else {
+ ms = BROWSER_MOUSE_HOVER;
+ }
+
+ /* button state */
+ switch (event->button) {
+ case 1:
+ ms |= BROWSER_MOUSE_PRESS_1;
+ break;
+
+ case 2:
+ ms |= BROWSER_MOUSE_PRESS_2;
+ break;
+ }
+
+ /* Handle the modifiers too */
+ if (event->state & GDK_SHIFT_MASK) {
+ ms |= BROWSER_MOUSE_MOD_1;
+ }
+
+ if (event->state & GDK_CONTROL_MASK) {
+ ms |= BROWSER_MOUSE_MOD_2;
+ }
+
+ if (event->state & GDK_MOD1_MASK) {
+ ms |= BROWSER_MOUSE_MOD_3;
+ }
+
+ return ms;
+}
+
+/**
+ * gtk event on mouse button press.
+ *
+ * \param widget The gtk widget the event occoured for.
+ * \param event The event that occoured.
+ * \param g The context pointer passed when teh event was registered.
+ */
+static gboolean
+nsgtk_cw_button_press_event(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ gtk_im_context_reset(nsgtk_cw->input_method);
+ gtk_widget_grab_focus(GTK_WIDGET(nsgtk_cw->drawing_area));
+
+ /* record event information for potentially starting a drag. */
+ mouse->pressed_x = mouse->last_x = event->x;
+ mouse->pressed_y = mouse->last_y = event->y;
+ mouse->pressed = true;
+
+ mouse->state = nsgtk_cw_gdkbutton_to_nsstate(event);
+
+ nsgtk_cw->mouse(nsgtk_cw, mouse->state, event->x, event->y);
+
+ return TRUE;
+}
+
+static gboolean
+nsgtk_cw_button_release_event(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ /* only button 1 clicks are considered double clicks. If the
+ * mouse state is PRESS then we are waiting for a release to
+ * emit a click event, otherwise just reset the state to nothing.
+ */
+ if (mouse->state & BROWSER_MOUSE_DOUBLE_CLICK) {
+ if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ mouse->state ^= BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_CLICK_1;
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_CLICK_2 |
+ BROWSER_MOUSE_DOUBLE_CLICK);
+ }
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_CLICK_1);
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_CLICK_2);
+ } else if (mouse->state & BROWSER_MOUSE_HOLDING_1) {
+ mouse->state ^= (BROWSER_MOUSE_HOLDING_1 |
+ BROWSER_MOUSE_DRAG_ON);
+ } else if (mouse->state & BROWSER_MOUSE_HOLDING_2) {
+ mouse->state ^= (BROWSER_MOUSE_HOLDING_2 |
+ BROWSER_MOUSE_DRAG_ON);
+ }
+
+ /* Handle modifiers being removed */
+ if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
+ !(event->state & GDK_SHIFT_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_1;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
+ !(event->state & GDK_CONTROL_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_2;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
+ !(event->state & GDK_MOD1_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_3;
+ }
+
+ /* end drag with modifiers */
+ if (mouse->state & (BROWSER_MOUSE_MOD_1 |
+ BROWSER_MOUSE_MOD_2 |
+ BROWSER_MOUSE_MOD_3)) {
+ mouse->state = BROWSER_MOUSE_HOVER;
+ }
+
+ nsgtk_cw->mouse(nsgtk_cw, mouse->state, event->x, event->y);
+
+ mouse->pressed = false;
+
+ return TRUE;
+}
+
+static gboolean
+nsgtk_cw_motion_notify_event(GtkWidget *widget,
+ GdkEventMotion *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ if (mouse->pressed == false) {
+ return TRUE;
+ }
+
+ if ((fabs(event->x - mouse->last_x) < 5.0) &&
+ (fabs(event->y - mouse->last_y) < 5.0)) {
+ /* Mouse hasn't moved far enough from press coordinate
+ * for this to be considered a drag.
+ */
+ return FALSE;
+ }
+
+ /* This is a drag, ensure it's always treated as such, even if
+ * we drag back over the press location.
+ */
+ mouse->last_x = INT_MIN;
+ mouse->last_y = INT_MIN;
+
+
+ if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ /* Start button 1 drag */
+ nsgtk_cw->mouse(nsgtk_cw,
+ BROWSER_MOUSE_DRAG_1,
+ mouse->pressed_x,
+ mouse->pressed_y);
+
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_HOLDING_1);
+ mouse->state |= BROWSER_MOUSE_DRAG_ON;
+
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ /* Start button 2s drag */
+ nsgtk_cw->mouse(nsgtk_cw,
+ BROWSER_MOUSE_DRAG_2,
+ mouse->pressed_x,
+ mouse->pressed_y);
+
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_HOLDING_2);
+ mouse->state |= BROWSER_MOUSE_DRAG_ON;
+
+ } else {
+ /* continue drag */
+
+ /* Handle modifiers being removed */
+ if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
+ !(event->state & GDK_SHIFT_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_1;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
+ !(event->state & GDK_CONTROL_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_2;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
+ !(event->state & GDK_MOD1_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_3;
+ }
+
+ if (mouse->state &
+ (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2)) {
+ nsgtk_cw->mouse(nsgtk_cw,
+ mouse->state,
+ event->x, event->y);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Deal with keypress events not handled but input method or callback
+ *
+ * \param nsgtk_cw nsgtk core window key event happened in.
+ * \param nskey The netsurf keycode of the event.
+ * \return NSERROR_OK on sucess otherwise an error code.
+ */
+static nserror nsgtk_cw_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
+{
+ double value;
+ GtkAdjustment *vscroll;
+ GtkAdjustment *hscroll;
+ GtkAdjustment *scroll = NULL;
+ gdouble hpage, vpage;
+
+ vscroll = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+ hscroll = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled);
+ g_object_get(vscroll, "page-size", &vpage, NULL);
+ g_object_get(hscroll, "page-size", &hpage, NULL);
+
+ switch(nskey) {
+ case NS_KEY_TEXT_START:
+ scroll = vscroll;
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_TEXT_END:
+ scroll = vscroll;
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_LEFT:
+ scroll = hscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_RIGHT:
+ scroll = hscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value > nsgtk_adjustment_get_upper(scroll) - hpage)
+ value = nsgtk_adjustment_get_upper(scroll) - hpage;
+ break;
+ case NS_KEY_UP:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_DOWN:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ break;
+
+ case NS_KEY_PAGE_UP:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_page_increment(scroll);
+
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+
+ break;
+
+ case NS_KEY_PAGE_DOWN:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_page_increment(scroll);
+
+ if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ break;
+
+ }
+
+ if (scroll != NULL) {
+ gtk_adjustment_set_value(scroll, value);
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * gtk event on key press.
+ *
+ * \param widget The gtk widget the event occoured for.
+ * \param event The event that occoured.
+ * \param g The context pointer passed when teh event was registered.
+ */
+static gboolean
+nsgtk_cw_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ nserror res;
+ uint32_t nskey;
+
+ /* check to see if gtk input method swallowed the keypress */
+ if (gtk_im_context_filter_keypress(nsgtk_cw->input_method, event)) {
+ return TRUE;
+ }
+
+ /* convert gtk event to nskey */
+ nskey = gtk_gui_gdkkey_to_nskey(event);
+
+ /* attempt to handle keypress in caller */
+ res = nsgtk_cw->key(nsgtk_cw, nskey);
+ if (res == NSERROR_OK) {
+ return TRUE;
+ } else if (res != NSERROR_NOT_IMPLEMENTED) {
+ LOG("%s", messages_get_errorcode(res));
+ return FALSE;
+ }
+
+ /* deal with unprocessed keypress */
+ res = nsgtk_cw_key(nsgtk_cw, nskey);
+ if (res != NSERROR_OK) {
+ LOG("%s", messages_get_errorcode(res));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static gboolean
+nsgtk_cw_keyrelease_event(GtkWidget *widget, GdkEventKey *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+
+ return gtk_im_context_filter_keypress(nsgtk_cw->input_method, event);
+}
+
+
+static void
+nsgtk_cw_input_method_commit(GtkIMContext *ctx, const gchar *str, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ size_t len;
+ size_t offset = 0;
+ uint32_t nskey;
+
+ len = strlen(str);
+
+ while (offset < len) {
+ nskey = utf8_to_ucs4(str + offset, len - offset);
+
+ nsgtk_cw->key(nsgtk_cw, nskey);
+
+ offset = utf8_next(str, len, offset);
+ }
+}
+
+
+#if GTK_CHECK_VERSION(3,0,0)
+
+/* signal handler for core window redraw */
+static gboolean
+nsgtk_cw_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)data;
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+ struct rect clip;
+
+ current_widget = widget;
+ current_cr = cr;
+
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+
+ if (tv->tree_flags == TREE_SSLCERT) {
+ ssl_current_session = tv->ssl_data;
+ }
+
+ clip.x0 = x1;
+ clip.y0 = y1;
+ clip.x1 = x2;
+ clip.y1 = y2;
+
+ nsgtk_cw->draw(nsgtk_cw, &clip);
+
+ current_widget = NULL;
+
+ return FALSE;
+}
+
+#else
+
+/* signal handler for core window redraw */
+static gboolean
+nsgtk_cw_draw_event(GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct rect clip;
+
+ clip.x0 = event->area.x;
+ clip.y0 = event->area.y;
+ clip.x1 = event->area.x + event->area.width;
+ clip.y1 = event->area.y + event->area.height;
+
+ current_widget = widget;
+ current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget));
+
+ nsgtk_cw->draw(nsgtk_cw, &clip);
+
+ current_widget = NULL;
+ cairo_destroy(current_cr);
+
+ return FALSE;
+}
+
+#endif
+
+/**
+ * callback from core to request a redraw
+ */
+static void
+nsgtk_cw_redraw_request(struct core_window *cw, const struct rect *r)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(nsgtk_cw->drawing_area),
+ r->x0, r->y0,
+ r->x1 - r->x0, r->y1 - r->y0);
+}
+
+
+static void
+nsgtk_cw_update_size(struct core_window *cw, int width, int height)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+
+ gtk_widget_set_size_request(GTK_WIDGET(nsgtk_cw->drawing_area),
+ width, height);
+}
+
+
+static void
+nsgtk_cw_scroll_visible(struct core_window *cw, const struct rect *r)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ int y = 0, height = 0, y0, y1;
+ gdouble page;
+ GtkAdjustment *vadj;
+
+ vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+
+ assert(vadj);
+
+ g_object_get(vadj, "page-size", &page, NULL);
+
+ y0 = (int)(gtk_adjustment_get_value(vadj));
+ y1 = y0 + page;
+
+ if ((y >= y0) && (y + height <= y1))
+ return;
+ if (y + height > y1)
+ y0 = y0 + (y + height - y1);
+ if (y < y0)
+ y0 = y;
+ gtk_adjustment_set_value(vadj, y0);
+}
+
+
+static void
+nsgtk_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ GtkAdjustment *vadj;
+ GtkAdjustment *hadj;
+ gdouble page;
+
+ if (width != NULL) {
+ hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled);
+ g_object_get(hadj, "page-size", &page, NULL);
+ *width = page;
+ }
+
+ if (height != NULL) {
+ vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+ g_object_get(vadj, "page-size", &page, NULL);
+ *height = page;
+ }}
+
+
+static void
+nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ nsgtk_cw->drag_staus = ds;
+}
+
+
+struct core_window_callback_table nsgtk_cw_cb_table = {
+ .redraw_request = nsgtk_cw_redraw_request,
+ .update_size = nsgtk_cw_update_size,
+ .scroll_visible = nsgtk_cw_scroll_visible,
+ .get_window_dimensions = nsgtk_cw_get_window_dimensions,
+ .drag_status = nsgtk_cw_drag_status
+};
+
+/* exported function documented gtk/corewindow.h */
+nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw)
+{
+ nsgtk_cw->cb_table = &nsgtk_cw_cb_table;
+
+ /* input method setup */
+ nsgtk_cw->input_method = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(nsgtk_cw->input_method,
+
gtk_widget_get_parent_window(GTK_WIDGET(nsgtk_cw->drawing_area)));
+ gtk_im_context_set_use_preedit(nsgtk_cw->input_method, FALSE);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->input_method),
+ "commit",
+ G_CALLBACK(nsgtk_cw_input_method_commit),
+ nsgtk_cw);
+
+ nsgtk_connect_draw_event(GTK_WIDGET(nsgtk_cw->drawing_area),
+ G_CALLBACK(nsgtk_cw_draw_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "button-press-event",
+ G_CALLBACK(nsgtk_cw_button_press_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "button-release-event",
+ G_CALLBACK(nsgtk_cw_button_release_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "motion-notify-event",
+ G_CALLBACK(nsgtk_cw_motion_notify_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "key-press-event",
+ G_CALLBACK(nsgtk_cw_keypress_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "key-release-event",
+ G_CALLBACK(nsgtk_cw_keyrelease_event),
+ nsgtk_cw);
+
+ nsgtk_widget_override_background_color(
+ GTK_WIDGET(nsgtk_cw->drawing_area),
+ GTK_STATE_NORMAL,
+ 0, 0xffff, 0xffff, 0xffff);
+
+ return NSERROR_OK;
+}
+
+nserror nsgtk_corewindow_fini(struct nsgtk_corewindow *nsgtk_cw)
+{
+ g_object_unref(nsgtk_cw->input_method);
+
+ return NSERROR_OK;
+}
diff --git a/frontends/gtk/corewindow.h b/frontends/gtk/corewindow.h
new file mode 100644
index 0000000..d6f3011
--- /dev/null
+++ b/frontends/gtk/corewindow.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTK_COREWINDOW_H
+#define GTK_COREWINDOW_H
+
+#include "desktop/core_window.h"
+
+/**
+ * nsgtk core window mouse state
+ */
+struct nsgtk_corewindow_mouse {
+ browser_mouse_state state; /**< last event status */
+ bool pressed;
+ int pressed_x;
+ int pressed_y;
+ int last_x;
+ int last_y;
+};
+
+/**
+ * nsgtk core window state
+ */
+struct nsgtk_corewindow {
+ /* public variables */
+ /** GTK drawable widget */
+ GtkDrawingArea *drawing_area;
+ /** scrollable area drawing area is within */
+ GtkScrolledWindow *scrolled;
+
+ /* private variables */
+ /** Input method */
+ GtkIMContext *input_method;
+ /** table of callbacks for core window operations */
+ struct core_window_callback_table *cb_table;
+ /** mouse state */
+ struct nsgtk_corewindow_mouse mouse_state;
+ /** drag status set by core */
+ core_window_drag_status drag_staus;
+
+ /**
+ * callback to draw on drawable area of nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ nserror (*draw)(struct nsgtk_corewindow *nsgtk_cw, struct rect *r);
+
+ /**
+ * callback for keypress on nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code.
+ * \return NSERROR_OK if key processed,
+ * NSERROR_NOT_IMPLEMENTED if key not processed
+ * otherwise apropriate error code
+ */
+ nserror (*key)(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey);
+
+ /**
+ * callback for mouse event on nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state mouse state
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on sucess otherwise apropriate error code.
+ */
+ nserror (*mouse)(struct nsgtk_corewindow *nsgtk_cw, browser_mouse_state
mouse_state, int x, int y);
+};
+
+/**
+ * initialise elements of gtk core window.
+ *
+ * \param nsgtk_cw A gtk core window structure to initialise
+ * \return NSERROR_OK on successful initialisation otherwise error code.
+ */
+nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw);
+
+/**
+ * finalise elements of gtk core window.
+ *
+ * \param nsgtk_cw A gtk core window structure to initialise
+ * \return NSERROR_OK on successful finalisation otherwise error code.
+ */
+nserror nsgtk_corewindow_fini(struct nsgtk_corewindow *nsgtk_cw);
+
+#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=ea84f67035ea9899086223c540a79ffec328caef
commit ea84f67035ea9899086223c540a79ffec328caef
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
fix gdk to nskey mapping for home/end and missing keypad mappings
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index af24d40..d57ebdf 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -631,60 +631,93 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
return NS_KEY_DELETE_LINE_START;
else
return NS_KEY_DELETE_LEFT;
+
case GDK_KEY(Delete):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_END;
else
return NS_KEY_DELETE_RIGHT;
- case GDK_KEY(Linefeed): return 13;
- case GDK_KEY(Return): return 10;
- case GDK_KEY(Left): return NS_KEY_LEFT;
- case GDK_KEY(Right): return NS_KEY_RIGHT;
- case GDK_KEY(Up): return NS_KEY_UP;
- case GDK_KEY(Down): return NS_KEY_DOWN;
+
+ case GDK_KEY(Linefeed):
+ return 13;
+
+ case GDK_KEY(Return):
+ return 10;
+
+ case GDK_KEY(Left):
+ case GDK_KEY(KP_Left):
+ return NS_KEY_LEFT;
+
+ case GDK_KEY(Right):
+ case GDK_KEY(KP_Right):
+ return NS_KEY_RIGHT;
+
+ case GDK_KEY(Up):
+ case GDK_KEY(KP_Up):
+ return NS_KEY_UP;
+
+ case GDK_KEY(Down):
+ case GDK_KEY(KP_Down):
+ return NS_KEY_DOWN;
+
case GDK_KEY(Home):
+ case GDK_KEY(KP_Home):
if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_TEXT_START;
- else
return NS_KEY_LINE_START;
+ else
+ return NS_KEY_TEXT_START;
+
case GDK_KEY(End):
+ case GDK_KEY(KP_End):
if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_TEXT_END;
- else
return NS_KEY_LINE_END;
+ else
+ return NS_KEY_TEXT_END;
+
case GDK_KEY(Page_Up):
+ case GDK_KEY(KP_Page_Up):
return NS_KEY_PAGE_UP;
+
case GDK_KEY(Page_Down):
+ case GDK_KEY(KP_Page_Down):
return NS_KEY_PAGE_DOWN;
+
case 'a':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_SELECT_ALL;
return gdk_keyval_to_unicode(key->keyval);
+
case 'u':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_DELETE_LINE;
return gdk_keyval_to_unicode(key->keyval);
+
case 'c':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_COPY_SELECTION;
return gdk_keyval_to_unicode(key->keyval);
+
case 'v':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_PASTE;
return gdk_keyval_to_unicode(key->keyval);
+
case 'x':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_CUT_SELECTION;
return gdk_keyval_to_unicode(key->keyval);
+
case 'Z':
case 'y':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_REDO;
return gdk_keyval_to_unicode(key->keyval);
+
case 'z':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_UNDO;
return gdk_keyval_to_unicode(key->keyval);
+
case GDK_KEY(Escape):
return NS_KEY_ESCAPE;
@@ -705,9 +738,8 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(Hyper_R):
return 0;
- default:
- return gdk_keyval_to_unicode(key->keyval);
}
+ return gdk_keyval_to_unicode(key->keyval);
}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=0f5d7cfcd2daade443ea0695275171247e2cfc22
commit 0f5d7cfcd2daade443ea0695275171247e2cfc22
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
Fix cookie manager keypress consumption return
diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c
index 6731e8e..082a14a 100644
--- a/desktop/cookie_manager.c
+++ b/desktop/cookie_manager.c
@@ -844,9 +844,9 @@ void cookie_manager_mouse_action(enum browser_mouse_state
mouse, int x, int y)
/* Exported interface, documented in cookie_manager.h */
-void cookie_manager_keypress(uint32_t key)
+bool cookie_manager_keypress(uint32_t key)
{
- treeview_keypress(cm_ctx.tree, key);
+ return treeview_keypress(cm_ctx.tree, key);
}
diff --git a/desktop/cookie_manager.h b/desktop/cookie_manager.h
index 65690d6..4ae74a2 100644
--- a/desktop/cookie_manager.h
+++ b/desktop/cookie_manager.h
@@ -101,7 +101,7 @@ void cookie_manager_mouse_action(enum browser_mouse_state
mouse, int x, int y);
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
-void cookie_manager_keypress(uint32_t key);
+bool cookie_manager_keypress(uint32_t key);
/**
* Determine whether there is a selection
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=8dbb61d2f57b32483d67434e9ac169b5f14e7460
commit 8dbb61d2f57b32483d67434e9ac169b5f14e7460
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>
fix documentation of mouse state enumeration
diff --git a/include/netsurf/mouse.h b/include/netsurf/mouse.h
index 19cd3ea..1b16998 100644
--- a/include/netsurf/mouse.h
+++ b/include/netsurf/mouse.h
@@ -27,56 +27,59 @@
#ifndef _NETSURF_MOUSE_H_
#define _NETSURF_MOUSE_H_
-/* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS).
- * 2 is secondary mouse button (e.g. Adjust on RISC OS). */
+/**
+ * Mouse state. 1 is primary mouse button (e.g. Select on RISC OS).
+ * 2 is secondary mouse button (e.g. Adjust on RISC OS).
+ *
+ * \note click meaning is different for different front ends. On RISC
+ * OS, it is standard to act on press, so a click is fired at
+ * the same time as a mouse button is pressed. With GTK, it is
+ * standard to act on release, so a click is fired when the
+ * mouse button is released, if the operation wasn't a drag.
+ *
+ * \note double and triple clicks are fired alongside a
+ * BROWSER_MOUSE_CLICK_[1|2] to indicate which button is used.
+ */
typedef enum browser_mouse_state {
- BROWSER_MOUSE_HOVER = 0, /* No mouse buttons pressed,
- * May be used to indicate
- * hover or end of drag. */
-
- BROWSER_MOUSE_PRESS_1 = (1 << 0), /* button 1 pressed */
- BROWSER_MOUSE_PRESS_2 = (1 << 1), /* button 2 pressed */
-
- /* note: click meaning is different for
- * different front ends. On RISC OS, it
- * is standard to act on press, so a
- * click is fired at the same time as a
- * mouse button is pressed. With GTK, it
- * is standard to act on release, so a
- * click is fired when the mouse button
- * is released, if the operation wasn't
- * a drag. */
-
- BROWSER_MOUSE_CLICK_1 = (1 << 2), /* button 1 clicked. */
- BROWSER_MOUSE_CLICK_2 = (1 << 3), /* button 2 clicked. */
-
- BROWSER_MOUSE_DOUBLE_CLICK = (1 << 4), /* button double clicked */
- BROWSER_MOUSE_TRIPLE_CLICK = (1 << 5), /* button triple clicked */
-
- /* note: double and triple clicks are
- * fired alongside a
- * BROWSER_MOUSE_CLICK_[1|2]
- * to indicate which button
- * is used.
- */
-
- BROWSER_MOUSE_DRAG_1 = (1 << 6), /* start of button 1 drag */
- BROWSER_MOUSE_DRAG_2 = (1 << 7), /* start of button 2 drag */
-
- BROWSER_MOUSE_DRAG_ON = (1 << 8), /* a drag operation was started
- * and a mouse button is still
- * pressed */
-
- BROWSER_MOUSE_HOLDING_1 = (1 << 9), /* during button 1 drag */
- BROWSER_MOUSE_HOLDING_2 = (1 << 10), /* during button 2 drag */
-
-
- BROWSER_MOUSE_MOD_1 = (1 << 11), /* 1st modifier key pressed
- * (eg. Shift) */
- BROWSER_MOUSE_MOD_2 = (1 << 12), /* 2nd modifier key pressed
- * (eg. Ctrl) */
- BROWSER_MOUSE_MOD_3 = (1 << 13) /* 3rd modifier key pressed
- * (eg. Alt) */
+ /** No mouse buttons pressed, May be used to indicate hover or
+ * end of drag.
+ */
+ BROWSER_MOUSE_HOVER = 0,
+
+ /** button 1 pressed */
+ BROWSER_MOUSE_PRESS_1 = (1 << 0),
+ /** button 2 pressed */
+ BROWSER_MOUSE_PRESS_2 = (1 << 1),
+
+ /** button 1 clicked. */
+ BROWSER_MOUSE_CLICK_1 = (1 << 2),
+ /** button 2 clicked. */
+ BROWSER_MOUSE_CLICK_2 = (1 << 3),
+
+ /** button double clicked */
+ BROWSER_MOUSE_DOUBLE_CLICK = (1 << 4),
+ /** button triple clicked */
+ BROWSER_MOUSE_TRIPLE_CLICK = (1 << 5),
+
+ /** start of button 1 drag */
+ BROWSER_MOUSE_DRAG_1 = (1 << 6),
+ /** start of button 2 drag */
+ BROWSER_MOUSE_DRAG_2 = (1 << 7),
+
+ /** a drag operation was started and a mouse button is still pressed */
+ BROWSER_MOUSE_DRAG_ON = (1 << 8),
+
+ /** during button 1 drag */
+ BROWSER_MOUSE_HOLDING_1 = (1 << 9),
+ /** during button 2 drag */
+ BROWSER_MOUSE_HOLDING_2 = (1 << 10),
+
+ /** 1st modifier key pressed (eg. Shift) */
+ BROWSER_MOUSE_MOD_1 = (1 << 11),
+ /** 2nd modifier key pressed (eg. Ctrl) */
+ BROWSER_MOUSE_MOD_2 = (1 << 12),
+ /** 3rd modifier key pressed (eg. Alt) */
+ BROWSER_MOUSE_MOD_3 = (1 << 13)
} browser_mouse_state;
-----------------------------------------------------------------------
Summary of changes:
Docs/unit-testing | 166 ++++++++++++
content/llcache.c | 9 +
desktop/cookie_manager.c | 4 +-
desktop/cookie_manager.h | 2 +-
desktop/gui_factory.c | 4 +-
desktop/netsurf.c | 8 +-
desktop/sslcert_viewer.c | 5 +-
desktop/sslcert_viewer.h | 3 +-
frontends/amiga/sslcert.c | 8 +-
frontends/amiga/sslcert.h | 2 +-
frontends/atari/gui.c | 4 +-
frontends/cocoa/gui.m | 4 +-
frontends/gtk/Makefile | 2 +-
frontends/gtk/cookies.c | 277 +++++++++++++------
frontends/gtk/cookies.h | 2 +-
frontends/gtk/corewindow.c | 638 ++++++++++++++++++++++++++++++++++++++++++++
frontends/gtk/corewindow.h | 104 ++++++++
frontends/gtk/gui.c | 66 ++++-
frontends/gtk/ssl_cert.c | 279 +++++++++++++------
frontends/gtk/ssl_cert.h | 3 +-
frontends/monkey/cert.c | 7 +-
frontends/monkey/cert.h | 2 +-
frontends/riscos/gui.h | 2 +-
frontends/riscos/sslcert.c | 22 +-
include/netsurf/misc.h | 3 +-
include/netsurf/mouse.h | 101 +++----
test/Makefile | 5 +-
test/urlescape.c | 178 ++++++++++++
28 files changed, 1646 insertions(+), 264 deletions(-)
create mode 100644 Docs/unit-testing
create mode 100644 frontends/gtk/corewindow.c
create mode 100644 frontends/gtk/corewindow.h
create mode 100644 test/urlescape.c
diff --git a/Docs/unit-testing b/Docs/unit-testing
new file mode 100644
index 0000000..49d82ed
--- /dev/null
+++ b/Docs/unit-testing
@@ -0,0 +1,166 @@
+NetSurf Unit Testing
+====================
+
+Overview
+--------
+
+NetSurf has unit tests integrated in the test directory. These tests
+use the check unit test framework for C [1].
+
+The tests are in a logical hierachy of "suite", "case" and individual
+"test". Historicaly we have split suites of tests into separate test
+programs although the framework does not madate this and some test
+programs contain more than one suite.
+
+
+Execution
+---------
+
+The test programs are executed by using the standard "test" target
+from the top level make invocation. The "coverage" target additionally
+generates code coverage reports allowing visibility on how much of a
+code module is being exercised.
+
+The check library must be installed to run the tests and the CI system
+automatically executes all enabled tests and generates coverage
+reports for each commit.
+
+Adding tests
+------------
+
+The test/Makefile defines each indiviadual test program that should be
+built and executed in the TESTS variable.
+
+The test program source files are defined in a xxx_SRCS variable and
+the make rules will then ensure the target program is built and
+executed.
+
+Each individual test program requires a main function which creates
+one (or more) suites. The suites are added to a test runner and then
+executed and the results reported.
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(foo_suite_create());
+ //srunner_add_suite(sr, bar_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+Suite creation is done with a sub function to logically split suite
+code into sub modules. Each suite has test cases added to it.
+
+Suite *foo_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("foo");
+
+ suite_add_tcase(s, baz_case_create());
+ suite_add_tcase(s, qux_case_create());
+
+ return s;
+}
+
+Test cases include the actual tests to be performed within each case.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_test(tc, xxyz_test);
+ tcase_add_test(tc, zzyx_test);
+
+ return tc;
+}
+
+A test case may optionally have a fixture which is code that is
+executed before and after each test case. Unchecked fixtures are
+executed once before the test process forks for each test whereas
+checked fixtures are executed for each and every test.
+
+static void fixture_setup(void)
+{
+}
+
+static void fixture_teardown(void)
+{
+}
+
+TCase *qux_case_create(void)
+{
+ TCase *tc;
+
+ /* Matching entry tests */
+ tc = tcase_create("Match");
+
+ tcase_add_checked_fixture(tc,
+ fixture_setup,
+ fixture_teardown);
+
+ tcase_add_test(tc, zzz_test);
+
+ return tc;
+}
+
+Additionally test cases can contain tests executed in a loop. The test
+recives a single integer as a parameter named _i which iterates
+between values specified in the case setup.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_loop_test(tc, looping_test, 0, 5);
+
+ return tc;
+}
+
+It is also possible to create tests which will generate a signal. The
+most commonly used of these is to check asserts in API calls.
+
+TCase *baz_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Baz");
+
+ tcase_add_test_raise_signal(tc, assert_test, 6);
+
+ return tc;
+}
+
+
+Actual test code is self contained in a function which uses the
+ck_assert macros to test results. The check framework requires each
+test to use the START_TEST and END_TEST macros when definig them.
+
+/**
+ * url access leaf test
+ */
+START_TEST(nsurl_access_leaf_test)
+{
+ nserror err;
+ nsurl *res_url;
+ const struct test_triplets *tst = &access_tests[_i];
+
+ /* not testing create, this should always succeed */
+ err = nsurl_create(tst->test1, &res_url);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(nsurl_access_leaf(res_url), tst->res);
+
+ nsurl_unref(res_url);
+}
+END_TEST
+
+
+[1] https://libcheck.github.io/check/
diff --git a/content/llcache.c b/content/llcache.c
index 33a9b98..e338c1f 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -2214,6 +2214,11 @@ static nserror llcache_fetch_auth(llcache_object
*object, const char *realm)
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
+ if (error != NSERROR_OK) {
+ /* do not continue if error querying user */
+ error = llcache_query_handle_response(false,
+ object);
+ }
} else {
llcache_event event;
@@ -2269,6 +2274,10 @@ static nserror llcache_fetch_cert_error(llcache_object
*object,
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
+ if (error != NSERROR_OK) {
+ /* do not continue if error querying user */
+ error = llcache_query_handle_response(false, object);
+ }
} else {
llcache_event event;
diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c
index 6731e8e..082a14a 100644
--- a/desktop/cookie_manager.c
+++ b/desktop/cookie_manager.c
@@ -844,9 +844,9 @@ void cookie_manager_mouse_action(enum browser_mouse_state
mouse, int x, int y)
/* Exported interface, documented in cookie_manager.h */
-void cookie_manager_keypress(uint32_t key)
+bool cookie_manager_keypress(uint32_t key)
{
- treeview_keypress(cm_ctx.tree, key);
+ return treeview_keypress(cm_ctx.tree, key);
}
diff --git a/desktop/cookie_manager.h b/desktop/cookie_manager.h
index 65690d6..4ae74a2 100644
--- a/desktop/cookie_manager.h
+++ b/desktop/cookie_manager.h
@@ -101,7 +101,7 @@ void cookie_manager_mouse_action(enum browser_mouse_state
mouse, int x, int y);
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
-void cookie_manager_keypress(uint32_t key);
+bool cookie_manager_keypress(uint32_t key);
/**
* Determine whether there is a selection
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index cecbe6e..88bb9ba 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -685,13 +685,13 @@ static nserror gui_default_launch_url(struct nsurl *url)
}
-static void gui_default_cert_verify(nsurl *url,
+static nserror gui_default_cert_verify(nsurl *url,
const struct ssl_cert_info *certs,
unsigned long num,
nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
- cb(false, cbpw);
+ return NSERROR_NOT_IMPLEMENTED;
}
static void gui_default_401login_open(nsurl *url, const char *realm,
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index ffcec04..f1daeab 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -104,21 +104,25 @@ static void netsurf_lwc_iterator(lwc_string *str, void
*pw)
static nserror netsurf_llcache_query_handler(const llcache_query *query,
void *pw, llcache_query_response cb, void *cbpw)
{
+ nserror res = NSERROR_OK;
+
switch (query->type) {
case LLCACHE_QUERY_AUTH:
guit->misc->login(query->url, query->data.auth.realm, cb, cbpw);
break;
+
case LLCACHE_QUERY_REDIRECT:
/** \todo Need redirect query dialog */
/* For now, do nothing, as this query type isn't emitted yet */
break;
+
case LLCACHE_QUERY_SSL:
- guit->misc->cert_verify(query->url, query->data.ssl.certs,
+ res = guit->misc->cert_verify(query->url, query->data.ssl.certs,
query->data.ssl.num, cb, cbpw);
break;
}
- return NSERROR_OK;
+ return res;
}
/* exported interface documented in netsurf/netsurf.h */
diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c
index f3eb169..93d6919 100644
--- a/desktop/sslcert_viewer.c
+++ b/desktop/sslcert_viewer.c
@@ -516,8 +516,7 @@ void sslcert_viewer_mouse_action(struct
sslcert_session_data *ssl_d,
/* Exported interface, documented in sslcert_viewer.h */
-void sslcert_viewer_keypress(struct sslcert_session_data *ssl_d,
- uint32_t key)
+bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key)
{
- treeview_keypress(ssl_d->tree, key);
+ return treeview_keypress(ssl_d->tree, key);
}
diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h
index f7c8f33..9b21cd1 100644
--- a/desktop/sslcert_viewer.h
+++ b/desktop/sslcert_viewer.h
@@ -119,7 +119,6 @@ void sslcert_viewer_mouse_action(struct
sslcert_session_data *ssl_d,
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
-void sslcert_viewer_keypress(struct sslcert_session_data *ssl_d,
- uint32_t key);
+bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key);
#endif
diff --git a/frontends/amiga/sslcert.c b/frontends/amiga/sslcert.c
index ed72061..83798f2 100644
--- a/frontends/amiga/sslcert.c
+++ b/frontends/amiga/sslcert.c
@@ -27,7 +27,7 @@
#include "amiga/tree.h"
#include "amiga/sslcert.h"
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
@@ -39,9 +39,13 @@ void gui_cert_verify(nsurl *url,
ssl_current_session = data;
ssl_window = ami_tree_create(TREE_SSLCERT, data);
- if(!ssl_window) return;
+ if (!ssl_window) {
+ return NSERROR_INIT_FAILED;
+ }
ami_tree_open(ssl_window, AMI_TREE_SSLCERT);
+
+ return NSERROR_OK;
}
void ami_ssl_free(struct treeview_window *twin)
diff --git a/frontends/amiga/sslcert.h b/frontends/amiga/sslcert.h
index 953142e..86ce9c4 100644
--- a/frontends/amiga/sslcert.h
+++ b/frontends/amiga/sslcert.h
@@ -19,7 +19,7 @@
#ifndef AMIGA_SSLCERT_H
#define AMIGA_SSLCERT_H
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index 713db8b..eb15777 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -771,7 +771,7 @@ static void gui_401login_open(nsurl *url, const char *realm,
}
-static void
+static nserror
gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
@@ -795,7 +795,7 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info
*certs,
&data);
atari_sslcert_viewer_open(data);
}
-
+ return NSERROR_OK;
}
void gui_set_input_gui_window(struct gui_window *gw)
diff --git a/frontends/cocoa/gui.m b/frontends/cocoa/gui.m
index b1847eb..7e180fa 100644
--- a/frontends/cocoa/gui.m
+++ b/frontends/cocoa/gui.m
@@ -285,13 +285,13 @@ static nserror gui_launch_url(nsurl *url)
struct ssl_cert_info;
-static void
+static nserror
gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs,
unsigned long num,
nserror (*cb)(bool proceed,void *pw), void *cbpw)
{
- cb( false, cbpw );
+ return NSERROR_NOT_IMPLEMENTED;
}
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index aae1d44..f8f7d8c 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -163,7 +163,7 @@ S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c
plotters.c \
selection.c history.c window.c fetch.c download.c menu.c \
print.c search.c tabs.c toolbar.c gettext.c \
compat.c cookies.c hotlist.c viewdata.c viewsource.c \
- preferences.c about.c ssl_cert.c resources.c
+ preferences.c about.c ssl_cert.c resources.c corewindow.c
# This is the final source build list
# Note this is deliberately *not* expanded here as common and image
diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c
index f252e6b..d8f8b5d 100644
--- a/frontends/gtk/cookies.c
+++ b/frontends/gtk/cookies.c
@@ -16,28 +16,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Cookies (implementation).
+/**
+ * \file
+ * Implementation of GTK cookie manager.
*/
-#include <gtk/gtk.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
#include "utils/log.h"
#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
#include "desktop/cookie_manager.h"
-#include "desktop/plot_style.h"
-#include "desktop/tree.h"
+#include "desktop/treeview.h"
#include "gtk/cookies.h"
#include "gtk/plotters.h"
#include "gtk/scaffolding.h"
-#include "gtk/treeview.h"
#include "gtk/resources.h"
+#include "gtk/corewindow.h"
+
+struct nsgtk_cookie_window {
+ struct nsgtk_corewindow core;
+ GtkBuilder *builder;
+ GtkWindow *wnd;
+};
-static struct nsgtk_treeview *cookies_treeview;
-static GtkBuilder *cookie_builder;
-static GtkWindow *wndCookies = NULL;
+static struct nsgtk_cookie_window *cookie_window = NULL;
#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
GtkMenuItem *widget, gpointer g)
@@ -85,80 +91,6 @@ static struct menu_events menu_events[] = {
};
-
-/**
- * Connects menu events in the cookies window.
- */
-static void nsgtk_cookies_init_menu(void)
-{
- struct menu_events *event = menu_events;
- GtkWidget *w;
-
- while (event->widget != NULL) {
- w = GTK_WIDGET(gtk_builder_get_object(cookie_builder,
event->widget));
- if (w == NULL) {
- LOG("Unable to connect menu widget ""%s""",
event->widget); } else {
- g_signal_connect(G_OBJECT(w), "activate",
event->handler, cookies_treeview);
- }
- event++;
- }
-}
-
-/**
- * Creates the window for the cookies tree.
- *
- * \return NSERROR_OK on success else appropriate error code on faliure.
- */
-static nserror nsgtk_cookies_init(void)
-{
- GtkScrolledWindow *scrolled;
- GtkDrawingArea *drawing_area;
- nserror res;
-
- if (wndCookies != NULL) {
- return NSERROR_OK;
- }
-
- res = nsgtk_builder_new_from_resname("cookies", &cookie_builder);
- if (res != NSERROR_OK) {
- LOG("Cookie UI builder init failed");
- return res;
- }
-
- gtk_builder_connect_signals(cookie_builder, NULL);
-
- wndCookies = GTK_WINDOW(gtk_builder_get_object(cookie_builder,
- "wndCookies"));
-
- scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(cookie_builder,
- "cookiesScrolled"));
-
- drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(cookie_builder,
- "cookiesDrawingArea"));
-
- cookies_treeview = nsgtk_treeview_create(TREE_COOKIES,
- wndCookies,
- scrolled,
- drawing_area,
- NULL);
- if (cookies_treeview == NULL) {
- return NSERROR_INIT_FAILED;
- }
-
-#define CONNECT(obj, sig, callback, ptr) \
- g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
-
- CONNECT(wndCookies, "delete_event", gtk_widget_hide_on_delete, NULL);
- CONNECT(wndCookies, "hide", nsgtk_tree_window_hide, cookies_treeview);
-
- nsgtk_cookies_init_menu();
-
- return NSERROR_OK;
-}
-
-
-
-
/* edit menu */
MENUHANDLER(delete_selected)
{
@@ -222,6 +154,162 @@ MENUHANDLER(collapse_cookies)
return TRUE;
}
+/**
+ * Connects menu events in the cookies window.
+ */
+static void nsgtk_cookies_init_menu(struct nsgtk_cookie_window *ncwin)
+{
+ struct menu_events *event = menu_events;
+ GtkWidget *w;
+
+ while (event->widget != NULL) {
+ w = GTK_WIDGET(gtk_builder_get_object(ncwin->builder,
+ event->widget));
+ if (w == NULL) {
+ LOG("Unable to connect menu widget ""%s""",
+ event->widget);
+ } else {
+ g_signal_connect(G_OBJECT(w),
+ "activate",
+ event->handler,
+ ncwin);
+ }
+ event++;
+ }
+}
+
+/**
+ * callback for mouse action on cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_mouse(struct nsgtk_corewindow *nsgtk_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ cookie_manager_mouse_action(mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+/**
+ * callback for keypress on cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
+{
+ if (cookie_manager_keypress(nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+/**
+ * callback on draw event for cookie window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_cookies_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+
+ cookie_manager_redraw(0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Creates the window for the cookies tree.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+static nserror nsgtk_cookies_init(void)
+{
+ struct nsgtk_cookie_window *ncwin;
+ nserror res;
+
+ if (cookie_window != NULL) {
+ return NSERROR_OK;
+ }
+
+ res = treeview_init(0);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ ncwin = malloc(sizeof(struct nsgtk_cookie_window));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_builder_new_from_resname("cookies", &ncwin->builder);
+ if (res != NSERROR_OK) {
+ LOG("Cookie UI builder init failed");
+ free(ncwin);
+ return res;
+ }
+
+ gtk_builder_connect_signals(ncwin->builder, NULL);
+
+ ncwin->wnd = GTK_WINDOW(gtk_builder_get_object(ncwin->builder,
+ "wndCookies"));
+
+ ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
+ gtk_builder_get_object(ncwin->builder, "cookiesScrolled"));
+
+ ncwin->core.drawing_area = GTK_DRAWING_AREA(
+ gtk_builder_get_object(ncwin->builder, "cookiesDrawingArea"));
+
+ /* make the delete event hide the window */
+ g_signal_connect(G_OBJECT(ncwin->wnd),
+ "delete_event",
+ G_CALLBACK(gtk_widget_hide_on_delete),
+ NULL);
+
+ nsgtk_cookies_init_menu(ncwin);
+
+ ncwin->core.draw = nsgtk_cookies_draw;
+ ncwin->core.key = nsgtk_cookies_key;
+ ncwin->core.mouse = nsgtk_cookies_mouse;
+
+ res = nsgtk_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ res = cookie_manager_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin);
+ if (res != NSERROR_OK) {
+ free(ncwin);
+ return res;
+ }
+
+ /* memoise window so it can be represented when necessary
+ * instead of recreating every time.
+ */
+ cookie_window = ncwin;
+
+ return NSERROR_OK;
+}
+
+
/* exported function documented gtk/cookies.h */
nserror nsgtk_cookies_present(void)
{
@@ -229,16 +317,29 @@ nserror nsgtk_cookies_present(void)
res = nsgtk_cookies_init();
if (res == NSERROR_OK) {
- gtk_window_present(wndCookies);
+ gtk_window_present(cookie_window->wnd);
}
return res;
}
+
/* exported function documented gtk/cookies.h */
-void nsgtk_cookies_destroy(void)
+nserror nsgtk_cookies_destroy(void)
{
- /** \todo what about cookie_builder? */
- if (wndCookies != NULL) {
- nsgtk_treeview_destroy(cookies_treeview);
+ nserror res;
+
+ if (cookie_window == NULL) {
+ return NSERROR_OK;
+ }
+
+ res = cookie_manager_fini();
+ if (res == NSERROR_OK) {
+ res = nsgtk_corewindow_fini(&cookie_window->core);
+ gtk_widget_destroy(GTK_WIDGET(cookie_window->wnd));
+ g_object_unref(G_OBJECT(cookie_window->builder));
+ free(cookie_window);
+ cookie_window = NULL;
}
+
+ return res;
}
diff --git a/frontends/gtk/cookies.h b/frontends/gtk/cookies.h
index 2af05e1..c1a68b7 100644
--- a/frontends/gtk/cookies.h
+++ b/frontends/gtk/cookies.h
@@ -35,7 +35,7 @@ nserror nsgtk_cookies_present(void);
*
* \return NSERROR_OK on success else appropriate error code on faliure.
*/
-void nsgtk_cookies_destroy(void);
+nserror nsgtk_cookies_destroy(void);
#endif /* __NSGTK_COOKIES_H__ */
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
new file mode 100644
index 0000000..11dec83
--- /dev/null
+++ b/frontends/gtk/corewindow.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK generic core window interface.
+ *
+ * Provides interface for core renderers to the gtk toolkit drawable area.
+ * \todo should the interface really be called coredrawable?
+ *
+
+ * This module is an object that must be encapsulated. Client users
+ * should embed a struct nsgtk_corewindow at the beginning of their
+ * context for this display surface, fill in relevant data and then
+ * call nsgtk_corewindow_init()
+ *
+ * The nsgtk core window structure requires the drawing area and
+ * scrollable widgets are present and the callback for draw, key and
+ * mouse operations.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/messages.h"
+#include "utils/utf8.h"
+#include "netsurf/keypress.h"
+#include "netsurf/mouse.h"
+#include "desktop/plot_style.h"
+
+#include "gtk/compat.h"
+#include "gtk/gui.h" /* just for gtk_gui_gdkkey_to_nskey */
+#include "gtk/plotters.h"
+#include "gtk/corewindow.h"
+
+/**
+ * Convert GDK mouse event to netsurf mouse state
+ */
+static browser_mouse_state nsgtk_cw_gdkbutton_to_nsstate(GdkEventButton *event)
+{
+ browser_mouse_state ms;
+
+ if (event->type == GDK_2BUTTON_PRESS) {
+ ms = BROWSER_MOUSE_DOUBLE_CLICK;
+ } else {
+ ms = BROWSER_MOUSE_HOVER;
+ }
+
+ /* button state */
+ switch (event->button) {
+ case 1:
+ ms |= BROWSER_MOUSE_PRESS_1;
+ break;
+
+ case 2:
+ ms |= BROWSER_MOUSE_PRESS_2;
+ break;
+ }
+
+ /* Handle the modifiers too */
+ if (event->state & GDK_SHIFT_MASK) {
+ ms |= BROWSER_MOUSE_MOD_1;
+ }
+
+ if (event->state & GDK_CONTROL_MASK) {
+ ms |= BROWSER_MOUSE_MOD_2;
+ }
+
+ if (event->state & GDK_MOD1_MASK) {
+ ms |= BROWSER_MOUSE_MOD_3;
+ }
+
+ return ms;
+}
+
+/**
+ * gtk event on mouse button press.
+ *
+ * \param widget The gtk widget the event occoured for.
+ * \param event The event that occoured.
+ * \param g The context pointer passed when teh event was registered.
+ */
+static gboolean
+nsgtk_cw_button_press_event(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ gtk_im_context_reset(nsgtk_cw->input_method);
+ gtk_widget_grab_focus(GTK_WIDGET(nsgtk_cw->drawing_area));
+
+ /* record event information for potentially starting a drag. */
+ mouse->pressed_x = mouse->last_x = event->x;
+ mouse->pressed_y = mouse->last_y = event->y;
+ mouse->pressed = true;
+
+ mouse->state = nsgtk_cw_gdkbutton_to_nsstate(event);
+
+ nsgtk_cw->mouse(nsgtk_cw, mouse->state, event->x, event->y);
+
+ return TRUE;
+}
+
+static gboolean
+nsgtk_cw_button_release_event(GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ /* only button 1 clicks are considered double clicks. If the
+ * mouse state is PRESS then we are waiting for a release to
+ * emit a click event, otherwise just reset the state to nothing.
+ */
+ if (mouse->state & BROWSER_MOUSE_DOUBLE_CLICK) {
+ if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ mouse->state ^= BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_CLICK_1;
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_CLICK_2 |
+ BROWSER_MOUSE_DOUBLE_CLICK);
+ }
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_CLICK_1);
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_CLICK_2);
+ } else if (mouse->state & BROWSER_MOUSE_HOLDING_1) {
+ mouse->state ^= (BROWSER_MOUSE_HOLDING_1 |
+ BROWSER_MOUSE_DRAG_ON);
+ } else if (mouse->state & BROWSER_MOUSE_HOLDING_2) {
+ mouse->state ^= (BROWSER_MOUSE_HOLDING_2 |
+ BROWSER_MOUSE_DRAG_ON);
+ }
+
+ /* Handle modifiers being removed */
+ if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
+ !(event->state & GDK_SHIFT_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_1;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
+ !(event->state & GDK_CONTROL_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_2;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
+ !(event->state & GDK_MOD1_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_3;
+ }
+
+ /* end drag with modifiers */
+ if (mouse->state & (BROWSER_MOUSE_MOD_1 |
+ BROWSER_MOUSE_MOD_2 |
+ BROWSER_MOUSE_MOD_3)) {
+ mouse->state = BROWSER_MOUSE_HOVER;
+ }
+
+ nsgtk_cw->mouse(nsgtk_cw, mouse->state, event->x, event->y);
+
+ mouse->pressed = false;
+
+ return TRUE;
+}
+
+static gboolean
+nsgtk_cw_motion_notify_event(GtkWidget *widget,
+ GdkEventMotion *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state;
+
+ if (mouse->pressed == false) {
+ return TRUE;
+ }
+
+ if ((fabs(event->x - mouse->last_x) < 5.0) &&
+ (fabs(event->y - mouse->last_y) < 5.0)) {
+ /* Mouse hasn't moved far enough from press coordinate
+ * for this to be considered a drag.
+ */
+ return FALSE;
+ }
+
+ /* This is a drag, ensure it's always treated as such, even if
+ * we drag back over the press location.
+ */
+ mouse->last_x = INT_MIN;
+ mouse->last_y = INT_MIN;
+
+
+ if (mouse->state & BROWSER_MOUSE_PRESS_1) {
+ /* Start button 1 drag */
+ nsgtk_cw->mouse(nsgtk_cw,
+ BROWSER_MOUSE_DRAG_1,
+ mouse->pressed_x,
+ mouse->pressed_y);
+
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ mouse->state ^= (BROWSER_MOUSE_PRESS_1 |
+ BROWSER_MOUSE_HOLDING_1);
+ mouse->state |= BROWSER_MOUSE_DRAG_ON;
+
+ } else if (mouse->state & BROWSER_MOUSE_PRESS_2) {
+ /* Start button 2s drag */
+ nsgtk_cw->mouse(nsgtk_cw,
+ BROWSER_MOUSE_DRAG_2,
+ mouse->pressed_x,
+ mouse->pressed_y);
+
+ /* Replace PRESS with HOLDING and declare drag in progress */
+ mouse->state ^= (BROWSER_MOUSE_PRESS_2 |
+ BROWSER_MOUSE_HOLDING_2);
+ mouse->state |= BROWSER_MOUSE_DRAG_ON;
+
+ } else {
+ /* continue drag */
+
+ /* Handle modifiers being removed */
+ if ((mouse->state & BROWSER_MOUSE_MOD_1) &&
+ !(event->state & GDK_SHIFT_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_1;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_2) &&
+ !(event->state & GDK_CONTROL_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_2;
+ }
+ if ((mouse->state & BROWSER_MOUSE_MOD_3) &&
+ !(event->state & GDK_MOD1_MASK)) {
+ mouse->state ^= BROWSER_MOUSE_MOD_3;
+ }
+
+ if (mouse->state &
+ (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2)) {
+ nsgtk_cw->mouse(nsgtk_cw,
+ mouse->state,
+ event->x, event->y);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Deal with keypress events not handled but input method or callback
+ *
+ * \param nsgtk_cw nsgtk core window key event happened in.
+ * \param nskey The netsurf keycode of the event.
+ * \return NSERROR_OK on sucess otherwise an error code.
+ */
+static nserror nsgtk_cw_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
+{
+ double value;
+ GtkAdjustment *vscroll;
+ GtkAdjustment *hscroll;
+ GtkAdjustment *scroll = NULL;
+ gdouble hpage, vpage;
+
+ vscroll = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+ hscroll = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled);
+ g_object_get(vscroll, "page-size", &vpage, NULL);
+ g_object_get(hscroll, "page-size", &hpage, NULL);
+
+ switch(nskey) {
+ case NS_KEY_TEXT_START:
+ scroll = vscroll;
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_TEXT_END:
+ scroll = vscroll;
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_LEFT:
+ scroll = hscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_RIGHT:
+ scroll = hscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value > nsgtk_adjustment_get_upper(scroll) - hpage)
+ value = nsgtk_adjustment_get_upper(scroll) - hpage;
+ break;
+ case NS_KEY_UP:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+ break;
+
+ case NS_KEY_DOWN:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_step_increment(scroll);
+ if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ break;
+
+ case NS_KEY_PAGE_UP:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) -
+ nsgtk_adjustment_get_page_increment(scroll);
+
+ if (value < nsgtk_adjustment_get_lower(scroll))
+ value = nsgtk_adjustment_get_lower(scroll);
+
+ break;
+
+ case NS_KEY_PAGE_DOWN:
+ scroll = vscroll;
+ value = gtk_adjustment_get_value(scroll) +
+ nsgtk_adjustment_get_page_increment(scroll);
+
+ if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
+ value = nsgtk_adjustment_get_upper(scroll) - vpage;
+ break;
+
+ }
+
+ if (scroll != NULL) {
+ gtk_adjustment_set_value(scroll, value);
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * gtk event on key press.
+ *
+ * \param widget The gtk widget the event occoured for.
+ * \param event The event that occoured.
+ * \param g The context pointer passed when teh event was registered.
+ */
+static gboolean
+nsgtk_cw_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ nserror res;
+ uint32_t nskey;
+
+ /* check to see if gtk input method swallowed the keypress */
+ if (gtk_im_context_filter_keypress(nsgtk_cw->input_method, event)) {
+ return TRUE;
+ }
+
+ /* convert gtk event to nskey */
+ nskey = gtk_gui_gdkkey_to_nskey(event);
+
+ /* attempt to handle keypress in caller */
+ res = nsgtk_cw->key(nsgtk_cw, nskey);
+ if (res == NSERROR_OK) {
+ return TRUE;
+ } else if (res != NSERROR_NOT_IMPLEMENTED) {
+ LOG("%s", messages_get_errorcode(res));
+ return FALSE;
+ }
+
+ /* deal with unprocessed keypress */
+ res = nsgtk_cw_key(nsgtk_cw, nskey);
+ if (res != NSERROR_OK) {
+ LOG("%s", messages_get_errorcode(res));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static gboolean
+nsgtk_cw_keyrelease_event(GtkWidget *widget, GdkEventKey *event, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+
+ return gtk_im_context_filter_keypress(nsgtk_cw->input_method, event);
+}
+
+
+static void
+nsgtk_cw_input_method_commit(GtkIMContext *ctx, const gchar *str, gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ size_t len;
+ size_t offset = 0;
+ uint32_t nskey;
+
+ len = strlen(str);
+
+ while (offset < len) {
+ nskey = utf8_to_ucs4(str + offset, len - offset);
+
+ nsgtk_cw->key(nsgtk_cw, nskey);
+
+ offset = utf8_next(str, len, offset);
+ }
+}
+
+
+#if GTK_CHECK_VERSION(3,0,0)
+
+/* signal handler for core window redraw */
+static gboolean
+nsgtk_cw_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)data;
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+ struct rect clip;
+
+ current_widget = widget;
+ current_cr = cr;
+
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+
+ if (tv->tree_flags == TREE_SSLCERT) {
+ ssl_current_session = tv->ssl_data;
+ }
+
+ clip.x0 = x1;
+ clip.y0 = y1;
+ clip.x1 = x2;
+ clip.y1 = y2;
+
+ nsgtk_cw->draw(nsgtk_cw, &clip);
+
+ current_widget = NULL;
+
+ return FALSE;
+}
+
+#else
+
+/* signal handler for core window redraw */
+static gboolean
+nsgtk_cw_draw_event(GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer g)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)g;
+ struct rect clip;
+
+ clip.x0 = event->area.x;
+ clip.y0 = event->area.y;
+ clip.x1 = event->area.x + event->area.width;
+ clip.y1 = event->area.y + event->area.height;
+
+ current_widget = widget;
+ current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget));
+
+ nsgtk_cw->draw(nsgtk_cw, &clip);
+
+ current_widget = NULL;
+ cairo_destroy(current_cr);
+
+ return FALSE;
+}
+
+#endif
+
+/**
+ * callback from core to request a redraw
+ */
+static void
+nsgtk_cw_redraw_request(struct core_window *cw, const struct rect *r)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(nsgtk_cw->drawing_area),
+ r->x0, r->y0,
+ r->x1 - r->x0, r->y1 - r->y0);
+}
+
+
+static void
+nsgtk_cw_update_size(struct core_window *cw, int width, int height)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+
+ gtk_widget_set_size_request(GTK_WIDGET(nsgtk_cw->drawing_area),
+ width, height);
+}
+
+
+static void
+nsgtk_cw_scroll_visible(struct core_window *cw, const struct rect *r)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ int y = 0, height = 0, y0, y1;
+ gdouble page;
+ GtkAdjustment *vadj;
+
+ vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+
+ assert(vadj);
+
+ g_object_get(vadj, "page-size", &page, NULL);
+
+ y0 = (int)(gtk_adjustment_get_value(vadj));
+ y1 = y0 + page;
+
+ if ((y >= y0) && (y + height <= y1))
+ return;
+ if (y + height > y1)
+ y0 = y0 + (y + height - y1);
+ if (y < y0)
+ y0 = y;
+ gtk_adjustment_set_value(vadj, y0);
+}
+
+
+static void
+nsgtk_cw_get_window_dimensions(struct core_window *cw, int *width, int *height)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ GtkAdjustment *vadj;
+ GtkAdjustment *hadj;
+ gdouble page;
+
+ if (width != NULL) {
+ hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled);
+ g_object_get(hadj, "page-size", &page, NULL);
+ *width = page;
+ }
+
+ if (height != NULL) {
+ vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled);
+ g_object_get(vadj, "page-size", &page, NULL);
+ *height = page;
+ }}
+
+
+static void
+nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds)
+{
+ struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw;
+ nsgtk_cw->drag_staus = ds;
+}
+
+
+struct core_window_callback_table nsgtk_cw_cb_table = {
+ .redraw_request = nsgtk_cw_redraw_request,
+ .update_size = nsgtk_cw_update_size,
+ .scroll_visible = nsgtk_cw_scroll_visible,
+ .get_window_dimensions = nsgtk_cw_get_window_dimensions,
+ .drag_status = nsgtk_cw_drag_status
+};
+
+/* exported function documented gtk/corewindow.h */
+nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw)
+{
+ nsgtk_cw->cb_table = &nsgtk_cw_cb_table;
+
+ /* input method setup */
+ nsgtk_cw->input_method = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(nsgtk_cw->input_method,
+
gtk_widget_get_parent_window(GTK_WIDGET(nsgtk_cw->drawing_area)));
+ gtk_im_context_set_use_preedit(nsgtk_cw->input_method, FALSE);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->input_method),
+ "commit",
+ G_CALLBACK(nsgtk_cw_input_method_commit),
+ nsgtk_cw);
+
+ nsgtk_connect_draw_event(GTK_WIDGET(nsgtk_cw->drawing_area),
+ G_CALLBACK(nsgtk_cw_draw_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "button-press-event",
+ G_CALLBACK(nsgtk_cw_button_press_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "button-release-event",
+ G_CALLBACK(nsgtk_cw_button_release_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "motion-notify-event",
+ G_CALLBACK(nsgtk_cw_motion_notify_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "key-press-event",
+ G_CALLBACK(nsgtk_cw_keypress_event),
+ nsgtk_cw);
+
+ g_signal_connect(G_OBJECT(nsgtk_cw->drawing_area),
+ "key-release-event",
+ G_CALLBACK(nsgtk_cw_keyrelease_event),
+ nsgtk_cw);
+
+ nsgtk_widget_override_background_color(
+ GTK_WIDGET(nsgtk_cw->drawing_area),
+ GTK_STATE_NORMAL,
+ 0, 0xffff, 0xffff, 0xffff);
+
+ return NSERROR_OK;
+}
+
+nserror nsgtk_corewindow_fini(struct nsgtk_corewindow *nsgtk_cw)
+{
+ g_object_unref(nsgtk_cw->input_method);
+
+ return NSERROR_OK;
+}
diff --git a/frontends/gtk/corewindow.h b/frontends/gtk/corewindow.h
new file mode 100644
index 0000000..d6f3011
--- /dev/null
+++ b/frontends/gtk/corewindow.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTK_COREWINDOW_H
+#define GTK_COREWINDOW_H
+
+#include "desktop/core_window.h"
+
+/**
+ * nsgtk core window mouse state
+ */
+struct nsgtk_corewindow_mouse {
+ browser_mouse_state state; /**< last event status */
+ bool pressed;
+ int pressed_x;
+ int pressed_y;
+ int last_x;
+ int last_y;
+};
+
+/**
+ * nsgtk core window state
+ */
+struct nsgtk_corewindow {
+ /* public variables */
+ /** GTK drawable widget */
+ GtkDrawingArea *drawing_area;
+ /** scrollable area drawing area is within */
+ GtkScrolledWindow *scrolled;
+
+ /* private variables */
+ /** Input method */
+ GtkIMContext *input_method;
+ /** table of callbacks for core window operations */
+ struct core_window_callback_table *cb_table;
+ /** mouse state */
+ struct nsgtk_corewindow_mouse mouse_state;
+ /** drag status set by core */
+ core_window_drag_status drag_staus;
+
+ /**
+ * callback to draw on drawable area of nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+ nserror (*draw)(struct nsgtk_corewindow *nsgtk_cw, struct rect *r);
+
+ /**
+ * callback for keypress on nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code.
+ * \return NSERROR_OK if key processed,
+ * NSERROR_NOT_IMPLEMENTED if key not processed
+ * otherwise apropriate error code
+ */
+ nserror (*key)(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey);
+
+ /**
+ * callback for mouse event on nsgtk core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state mouse state
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on sucess otherwise apropriate error code.
+ */
+ nserror (*mouse)(struct nsgtk_corewindow *nsgtk_cw, browser_mouse_state
mouse_state, int x, int y);
+};
+
+/**
+ * initialise elements of gtk core window.
+ *
+ * \param nsgtk_cw A gtk core window structure to initialise
+ * \return NSERROR_OK on successful initialisation otherwise error code.
+ */
+nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw);
+
+/**
+ * finalise elements of gtk core window.
+ *
+ * \param nsgtk_cw A gtk core window structure to initialise
+ * \return NSERROR_OK on successful finalisation otherwise error code.
+ */
+nserror nsgtk_corewindow_fini(struct nsgtk_corewindow *nsgtk_cw);
+
+#endif
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index af24d40..0ed32e9 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -434,13 +434,21 @@ static void nsgtk_main(void)
static void gui_quit(void)
{
+ nserror res;
+
LOG("Quitting GUI");
/* Ensure all scaffoldings are destroyed before we go into exit */
nsgtk_download_destroy();
urldb_save_cookies(nsoption_charp(cookie_jar));
urldb_save(nsoption_charp(url_file));
- nsgtk_cookies_destroy();
+
+ res = nsgtk_cookies_destroy();
+ if (res != NSERROR_OK) {
+ LOG("Error finalising cookie viewer: %s",
+ messages_get_errorcode(res));
+ }
+
nsgtk_history_destroy();
nsgtk_hotlist_destroy();
@@ -631,60 +639,93 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
return NS_KEY_DELETE_LINE_START;
else
return NS_KEY_DELETE_LEFT;
+
case GDK_KEY(Delete):
if (key->state & GDK_SHIFT_MASK)
return NS_KEY_DELETE_LINE_END;
else
return NS_KEY_DELETE_RIGHT;
- case GDK_KEY(Linefeed): return 13;
- case GDK_KEY(Return): return 10;
- case GDK_KEY(Left): return NS_KEY_LEFT;
- case GDK_KEY(Right): return NS_KEY_RIGHT;
- case GDK_KEY(Up): return NS_KEY_UP;
- case GDK_KEY(Down): return NS_KEY_DOWN;
+
+ case GDK_KEY(Linefeed):
+ return 13;
+
+ case GDK_KEY(Return):
+ return 10;
+
+ case GDK_KEY(Left):
+ case GDK_KEY(KP_Left):
+ return NS_KEY_LEFT;
+
+ case GDK_KEY(Right):
+ case GDK_KEY(KP_Right):
+ return NS_KEY_RIGHT;
+
+ case GDK_KEY(Up):
+ case GDK_KEY(KP_Up):
+ return NS_KEY_UP;
+
+ case GDK_KEY(Down):
+ case GDK_KEY(KP_Down):
+ return NS_KEY_DOWN;
+
case GDK_KEY(Home):
+ case GDK_KEY(KP_Home):
if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_TEXT_START;
- else
return NS_KEY_LINE_START;
+ else
+ return NS_KEY_TEXT_START;
+
case GDK_KEY(End):
+ case GDK_KEY(KP_End):
if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_TEXT_END;
- else
return NS_KEY_LINE_END;
+ else
+ return NS_KEY_TEXT_END;
+
case GDK_KEY(Page_Up):
+ case GDK_KEY(KP_Page_Up):
return NS_KEY_PAGE_UP;
+
case GDK_KEY(Page_Down):
+ case GDK_KEY(KP_Page_Down):
return NS_KEY_PAGE_DOWN;
+
case 'a':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_SELECT_ALL;
return gdk_keyval_to_unicode(key->keyval);
+
case 'u':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_DELETE_LINE;
return gdk_keyval_to_unicode(key->keyval);
+
case 'c':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_COPY_SELECTION;
return gdk_keyval_to_unicode(key->keyval);
+
case 'v':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_PASTE;
return gdk_keyval_to_unicode(key->keyval);
+
case 'x':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_CUT_SELECTION;
return gdk_keyval_to_unicode(key->keyval);
+
case 'Z':
case 'y':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_REDO;
return gdk_keyval_to_unicode(key->keyval);
+
case 'z':
if (key->state & GDK_CONTROL_MASK)
return NS_KEY_UNDO;
return gdk_keyval_to_unicode(key->keyval);
+
case GDK_KEY(Escape):
return NS_KEY_ESCAPE;
@@ -705,9 +746,8 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
case GDK_KEY(Hyper_R):
return 0;
- default:
- return gdk_keyval_to_unicode(key->keyval);
}
+ return gdk_keyval_to_unicode(key->keyval);
}
diff --git a/frontends/gtk/ssl_cert.c b/frontends/gtk/ssl_cert.c
index 463f5cd..1cf0beb 100644
--- a/frontends/gtk/ssl_cert.c
+++ b/frontends/gtk/ssl_cert.c
@@ -16,121 +16,250 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * Implementation of gtk certificate viewing using gtk core windows.
+ */
+
+#include <stdint.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "utils/log.h"
-#include "utils/nsurl.h"
-#include "desktop/tree.h"
+#include "netsurf/keypress.h"
+#include "netsurf/plotters.h"
#include "desktop/sslcert_viewer.h"
+#include "desktop/treeview.h"
-#include "gtk/treeview.h"
+#include "gtk/plotters.h"
#include "gtk/scaffolding.h"
#include "gtk/resources.h"
#include "gtk/ssl_cert.h"
+#include "gtk/corewindow.h"
+
+
+/**
+ * GTK certificate viewing window context
+ */
+struct nsgtk_crtvrfy_window {
+ /** GTK core window context */
+ struct nsgtk_corewindow core;
+ /** GTK builder for window */
+ GtkBuilder *builder;
+ /** GTK dialog window being shown */
+ GtkDialog *dlg;
+ /** SSL certificate viewer context data */
+ struct sslcert_session_data *ssl_data;
+};
+/**
+ * destroy a previously created certificate view
+ */
+static nserror nsgtk_crtvrfy_destroy(struct nsgtk_crtvrfy_window *crtvrfy_win)
+{
+ nserror res;
-static void nsgtk_ssl_accept(GtkButton *w, gpointer data)
+ res = sslcert_viewer_fini(crtvrfy_win->ssl_data);
+ if (res == NSERROR_OK) {
+ res = nsgtk_corewindow_fini(&crtvrfy_win->core);
+ gtk_widget_destroy(GTK_WIDGET(crtvrfy_win->dlg));
+ g_object_unref(G_OBJECT(crtvrfy_win->builder));
+ free(crtvrfy_win);
+ }
+ return res;
+}
+
+static void
+nsgtk_crtvrfy_accept(GtkButton *w, gpointer data)
{
- void **session = data;
- GtkBuilder *x = session[0];
- struct nsgtk_treeview *wnd = session[1];
- struct sslcert_session_data *ssl_data = session[2];
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)data;
- sslcert_viewer_accept(ssl_data);
+ sslcert_viewer_accept(crtvrfy_win->ssl_data);
- nsgtk_treeview_destroy(wnd);
- g_object_unref(G_OBJECT(x));
- free(session);
+ nsgtk_crtvrfy_destroy(crtvrfy_win);
}
-static void nsgtk_ssl_reject(GtkWidget *w, gpointer data)
+static void
+nsgtk_crtvrfy_reject(GtkWidget *w, gpointer data)
{
- void **session = data;
- GtkBuilder *x = session[0];
- struct nsgtk_treeview *wnd = session[1];
- struct sslcert_session_data *ssl_data = session[2];
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)data;
- sslcert_viewer_reject(ssl_data);
+ sslcert_viewer_reject(crtvrfy_win->ssl_data);
- nsgtk_treeview_destroy(wnd);
- g_object_unref(G_OBJECT(x));
- free(session);
+ nsgtk_crtvrfy_destroy(crtvrfy_win);
}
-static gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event,
gpointer data)
+static gboolean
+nsgtk_crtvrfy_delete_event(GtkWidget *w, GdkEvent *event, gpointer data)
{
- nsgtk_ssl_reject(w, data);
+ nsgtk_crtvrfy_reject(w, data);
return FALSE;
}
-void gtk_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
- unsigned long num, nserror (*cb)(bool proceed, void *pw),
- void *cbpw)
+/**
+ * callback for mouse action for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param mouse_state netsurf mouse state on event
+ * \param x location of event
+ * \param y location of event
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_mouse(struct nsgtk_corewindow *nsgtk_cw,
+ browser_mouse_state mouse_state,
+ int x, int y)
+{
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y);
+
+ return NSERROR_OK;
+}
+
+/**
+ * callback for keypress for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param nskey The netsurf key code
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
{
- static struct nsgtk_treeview *ssl_window;
- struct sslcert_session_data *data;
- GtkButton *accept, *reject;
- void **session;
- GtkDialog *dlg;
- GtkScrolledWindow *scrolled;
- GtkDrawingArea *drawing_area;
- GtkBuilder *builder;
- GtkWindow *gtk_parent;
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) {
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_IMPLEMENTED;
+}
+
+/**
+ * callback on draw event for certificate verify on core window
+ *
+ * \param nsgtk_cw The nsgtk core window structure.
+ * \param r The rectangle of the window that needs updating.
+ * \return NSERROR_OK on success otherwise apropriate error code
+ */
+static nserror
+nsgtk_crtvrfy_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+ struct nsgtk_crtvrfy_window *crtvrfy_win;
+
+ /* technically degenerate container of */
+ crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw;
+
+ sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in gtk/ssl_cert.h */
+nserror gtk_cert_verify(struct nsurl *url,
+ const struct ssl_cert_info *certs,
+ unsigned long num,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ struct nsgtk_crtvrfy_window *ncwin;
nserror res;
- /* state while dlg is open */
- session = calloc(sizeof(void *), 3);
- if (session == NULL) {
- return;
+ res = treeview_init(0);
+ if (res != NSERROR_OK) {
+ return res;
}
- res = nsgtk_builder_new_from_resname("ssl", &builder);
+ ncwin = malloc(sizeof(struct nsgtk_crtvrfy_window));
+ if (ncwin == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_builder_new_from_resname("ssl", &ncwin->builder);
if (res != NSERROR_OK) {
LOG("SSL UI builder init failed");
- free(session);
- cb(false, cbpw);
- return;
+ free(ncwin);
+ return res;
}
- gtk_builder_connect_signals(builder, NULL);
-
- sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, &data);
+ gtk_builder_connect_signals(ncwin->builder, NULL);
- dlg = GTK_DIALOG(gtk_builder_get_object(builder, "wndSSLProblem"));
+ ncwin->dlg = GTK_DIALOG(gtk_builder_get_object(ncwin->builder,
+ "wndSSLProblem"));
/* set parent for transient dialog */
- gtk_parent = nsgtk_scaffolding_window(nsgtk_current_scaffolding());
- gtk_window_set_transient_for(GTK_WINDOW(dlg), gtk_parent);
-
- scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(builder,
"SSLScrolled"));
- drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(builder,
"SSLDrawingArea"));
-
- ssl_window = nsgtk_treeview_create(TREE_SSLCERT,
- GTK_WINDOW(dlg),
- scrolled,
- drawing_area,
- data);
- if (ssl_window == NULL) {
- free(session);
- g_object_unref(G_OBJECT(dlg));
- return;
- }
+ gtk_window_set_transient_for(GTK_WINDOW(ncwin->dlg),
+ nsgtk_scaffolding_window(nsgtk_current_scaffolding()));
+
+ ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
+ gtk_builder_get_object(ncwin->builder, "SSLScrolled"));
+
+ ncwin->core.drawing_area = GTK_DRAWING_AREA(
+ gtk_builder_get_object(ncwin->builder, "SSLDrawingArea"));
+
+ /* make the delete event call our destructor */
+ g_signal_connect(G_OBJECT(ncwin->dlg),
+ "delete_event",
+ G_CALLBACK(nsgtk_crtvrfy_delete_event),
+ ncwin);
- accept = GTK_BUTTON(gtk_builder_get_object(builder, "sslaccept"));
- reject = GTK_BUTTON(gtk_builder_get_object(builder, "sslreject"));
+ /* accept button */
+ g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder,
+ "sslaccept")),
+ "clicked",
+ G_CALLBACK(nsgtk_crtvrfy_accept),
+ ncwin);
- session[0] = builder;
- session[1] = ssl_window;
- session[2] = data;
+ /* reject button */
+ g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder,
+ "sslreject")),
+ "clicked",
+ G_CALLBACK(nsgtk_crtvrfy_reject),
+ ncwin);
-#define CONNECT(obj, sig, callback, ptr) \
- g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
+ /* initialise GTK core window */
+ ncwin->core.draw = nsgtk_crtvrfy_draw;
+ ncwin->core.key = nsgtk_crtvrfy_key;
+ ncwin->core.mouse = nsgtk_crtvrfy_mouse;
+
+ res = nsgtk_corewindow_init(&ncwin->core);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
+
+ /* initialise certificate viewing interface */
+ res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs,
+ &ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
+
+ res = sslcert_viewer_init(ncwin->core.cb_table,
+ (struct core_window *)ncwin,
+ ncwin->ssl_data);
+ if (res != NSERROR_OK) {
+ g_object_unref(G_OBJECT(ncwin->dlg));
+ free(ncwin);
+ return res;
+ }
- CONNECT(accept, "clicked", nsgtk_ssl_accept, session);
- CONNECT(reject, "clicked", nsgtk_ssl_reject, session);
- CONNECT(dlg, "delete_event", G_CALLBACK(nsgtk_ssl_delete_event),
- (gpointer)session);
+ gtk_widget_show(GTK_WIDGET(ncwin->dlg));
- gtk_widget_show(GTK_WIDGET(dlg));
+ return NSERROR_OK;
}
diff --git a/frontends/gtk/ssl_cert.h b/frontends/gtk/ssl_cert.h
index 48937d4..1712756 100644
--- a/frontends/gtk/ssl_cert.h
+++ b/frontends/gtk/ssl_cert.h
@@ -30,7 +30,8 @@ struct ssl_cert_info;
* \param num The number of certificates to be verified.
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK or error code if prompt creation failed.
*/
-void gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+nserror gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
#endif
diff --git a/frontends/monkey/cert.c b/frontends/monkey/cert.c
index ec1b1ce..710e710 100644
--- a/frontends/monkey/cert.c
+++ b/frontends/monkey/cert.c
@@ -35,15 +35,14 @@ typedef struct monkey_cert {
static monkey_cert_t *cert_ring = NULL;
static uint32_t cert_ctr = 0;
-void
+nserror
gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
monkey_cert_t *m4t = calloc(sizeof(*m4t), 1);
if (m4t == NULL) {
- cb(false, cbpw);
- return;
+ return NSERROR_NOMEM;
}
m4t->cb = cb;
m4t->pw = cbpw;
@@ -53,6 +52,8 @@ gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
fprintf(stdout, "SSLCERT VERIFY CERT %u URL %s\n",
m4t->num, nsurl_access(url));
+
+ return NSERROR_OK;
}
diff --git a/frontends/monkey/cert.h b/frontends/monkey/cert.h
index 283817f..4470e2e 100644
--- a/frontends/monkey/cert.h
+++ b/frontends/monkey/cert.h
@@ -21,7 +21,7 @@
struct ssl_cert_info;
-void gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
+nserror gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw);
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 624f9e2..505e8e7 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -212,7 +212,7 @@ extern int ro_plot_origin_y;
bool ro_gui_theme_install_apply(wimp_w w);
/* in sslcert.c */
-void gui_cert_verify(struct nsurl *url,
+nserror gui_cert_verify(struct nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
diff --git a/frontends/riscos/sslcert.c b/frontends/riscos/sslcert.c
index c7b8db4..8a8ddfb 100644
--- a/frontends/riscos/sslcert.c
+++ b/frontends/riscos/sslcert.c
@@ -101,7 +101,7 @@ void ro_gui_cert_postinitialise(void)
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
*/
-void gui_cert_verify(nsurl *url,
+nserror gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs, unsigned long num,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
@@ -117,7 +117,7 @@ void gui_cert_verify(nsurl *url,
sslcert_window = malloc(sizeof(struct ro_sslcert));
if (sslcert_window == NULL) {
LOG("Failed to allocate memory for SSL Cert Dialog");
- return;
+ return NSERROR_NOMEM;
}
/* Create the SSL window and its pane. */
@@ -127,7 +127,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
LOG("xwimp_create_window: 0x%x: %s", error->errnum,
error->errmess);
free(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
error = xwimp_create_window(ro_gui_cert_tree_template,
@@ -135,7 +135,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
LOG("xwimp_create_window: 0x%x: %s", error->errnum,
error->errmess);
free(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
/* Create the SSL data and build a tree from it. */
@@ -148,7 +148,7 @@ void gui_cert_verify(nsurl *url,
if (sslcert_window->tv == NULL) {
LOG("Failed to allocate treeview");
free(sslcert_window);
- return;
+ return NSERROR_NOMEM;
}
/* Set up the certificate window event handling.
@@ -182,7 +182,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_window_info: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
state.w = sslcert_window->window;
@@ -190,7 +190,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_window_state: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
istate.w = sslcert_window->window;
@@ -199,7 +199,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
state.w = sslcert_window->pane;
@@ -230,7 +230,7 @@ void gui_cert_verify(nsurl *url,
if (error) {
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_set_extent: 0x%x: %s", error->errnum,
error->errmess);
- return;
+ return NSERROR_INIT_FAILED;
}
}
@@ -248,10 +248,12 @@ void gui_cert_verify(nsurl *url,
ro_gui_cert_release_window(sslcert_window);
LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum,
error->errmess);
ro_gui_cert_release_window(sslcert_window);
- return;
+ return NSERROR_INIT_FAILED;
}
ro_treeview_set_origin(sslcert_window->tv, 0, 0);
+
+ return NSERROR_OK;
}
/**
diff --git a/include/netsurf/misc.h b/include/netsurf/misc.h
index 7b35495..2647b9a 100644
--- a/include/netsurf/misc.h
+++ b/include/netsurf/misc.h
@@ -89,8 +89,9 @@ struct gui_misc_table {
* \param num The number of certificates to be verified.
* \param cb Callback upon user decision.
* \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK on sucess else error and cb never called
*/
- void (*cert_verify)(struct nsurl *url, const struct ssl_cert_info
*certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+ nserror (*cert_verify)(struct nsurl *url, const struct ssl_cert_info
*certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
/**
* Prompt user for login
diff --git a/include/netsurf/mouse.h b/include/netsurf/mouse.h
index 19cd3ea..1b16998 100644
--- a/include/netsurf/mouse.h
+++ b/include/netsurf/mouse.h
@@ -27,56 +27,59 @@
#ifndef _NETSURF_MOUSE_H_
#define _NETSURF_MOUSE_H_
-/* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS).
- * 2 is secondary mouse button (e.g. Adjust on RISC OS). */
+/**
+ * Mouse state. 1 is primary mouse button (e.g. Select on RISC OS).
+ * 2 is secondary mouse button (e.g. Adjust on RISC OS).
+ *
+ * \note click meaning is different for different front ends. On RISC
+ * OS, it is standard to act on press, so a click is fired at
+ * the same time as a mouse button is pressed. With GTK, it is
+ * standard to act on release, so a click is fired when the
+ * mouse button is released, if the operation wasn't a drag.
+ *
+ * \note double and triple clicks are fired alongside a
+ * BROWSER_MOUSE_CLICK_[1|2] to indicate which button is used.
+ */
typedef enum browser_mouse_state {
- BROWSER_MOUSE_HOVER = 0, /* No mouse buttons pressed,
- * May be used to indicate
- * hover or end of drag. */
-
- BROWSER_MOUSE_PRESS_1 = (1 << 0), /* button 1 pressed */
- BROWSER_MOUSE_PRESS_2 = (1 << 1), /* button 2 pressed */
-
- /* note: click meaning is different for
- * different front ends. On RISC OS, it
- * is standard to act on press, so a
- * click is fired at the same time as a
- * mouse button is pressed. With GTK, it
- * is standard to act on release, so a
- * click is fired when the mouse button
- * is released, if the operation wasn't
- * a drag. */
-
- BROWSER_MOUSE_CLICK_1 = (1 << 2), /* button 1 clicked. */
- BROWSER_MOUSE_CLICK_2 = (1 << 3), /* button 2 clicked. */
-
- BROWSER_MOUSE_DOUBLE_CLICK = (1 << 4), /* button double clicked */
- BROWSER_MOUSE_TRIPLE_CLICK = (1 << 5), /* button triple clicked */
-
- /* note: double and triple clicks are
- * fired alongside a
- * BROWSER_MOUSE_CLICK_[1|2]
- * to indicate which button
- * is used.
- */
-
- BROWSER_MOUSE_DRAG_1 = (1 << 6), /* start of button 1 drag */
- BROWSER_MOUSE_DRAG_2 = (1 << 7), /* start of button 2 drag */
-
- BROWSER_MOUSE_DRAG_ON = (1 << 8), /* a drag operation was started
- * and a mouse button is still
- * pressed */
-
- BROWSER_MOUSE_HOLDING_1 = (1 << 9), /* during button 1 drag */
- BROWSER_MOUSE_HOLDING_2 = (1 << 10), /* during button 2 drag */
-
-
- BROWSER_MOUSE_MOD_1 = (1 << 11), /* 1st modifier key pressed
- * (eg. Shift) */
- BROWSER_MOUSE_MOD_2 = (1 << 12), /* 2nd modifier key pressed
- * (eg. Ctrl) */
- BROWSER_MOUSE_MOD_3 = (1 << 13) /* 3rd modifier key pressed
- * (eg. Alt) */
+ /** No mouse buttons pressed, May be used to indicate hover or
+ * end of drag.
+ */
+ BROWSER_MOUSE_HOVER = 0,
+
+ /** button 1 pressed */
+ BROWSER_MOUSE_PRESS_1 = (1 << 0),
+ /** button 2 pressed */
+ BROWSER_MOUSE_PRESS_2 = (1 << 1),
+
+ /** button 1 clicked. */
+ BROWSER_MOUSE_CLICK_1 = (1 << 2),
+ /** button 2 clicked. */
+ BROWSER_MOUSE_CLICK_2 = (1 << 3),
+
+ /** button double clicked */
+ BROWSER_MOUSE_DOUBLE_CLICK = (1 << 4),
+ /** button triple clicked */
+ BROWSER_MOUSE_TRIPLE_CLICK = (1 << 5),
+
+ /** start of button 1 drag */
+ BROWSER_MOUSE_DRAG_1 = (1 << 6),
+ /** start of button 2 drag */
+ BROWSER_MOUSE_DRAG_2 = (1 << 7),
+
+ /** a drag operation was started and a mouse button is still pressed */
+ BROWSER_MOUSE_DRAG_ON = (1 << 8),
+
+ /** during button 1 drag */
+ BROWSER_MOUSE_HOLDING_1 = (1 << 9),
+ /** during button 2 drag */
+ BROWSER_MOUSE_HOLDING_2 = (1 << 10),
+
+ /** 1st modifier key pressed (eg. Shift) */
+ BROWSER_MOUSE_MOD_1 = (1 << 11),
+ /** 2nd modifier key pressed (eg. Ctrl) */
+ BROWSER_MOUSE_MOD_2 = (1 << 12),
+ /** 3rd modifier key pressed (eg. Alt) */
+ BROWSER_MOUSE_MOD_3 = (1 << 13)
} browser_mouse_state;
diff --git a/test/Makefile b/test/Makefile
index 9fdb3f2..ea16b0a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,7 +1,7 @@
#
# NetSurf unit tests
-TESTS := nsurl urldbtest nsoption bloom hashtable #llcache
+TESTS := nsurl urldbtest nsoption bloom hashtable urlescape #llcache
# nsurl sources
nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
@@ -34,6 +34,9 @@ bloom_SRCS := utils/bloom.c test/bloom.c
# hash table test sources
hashtable_SRCS := utils/hashtable.c test/log.c test/hashtable.c
+# url escape test sources
+urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
+
# Coverage builds need additional flags
ifeq ($(MAKECMDGOALS),coverage)
COV_CFLAGS ?= -fprofile-arcs -ftest-coverage -O0
diff --git a/test/urlescape.c b/test/urlescape.c
new file mode 100644
index 0000000..5d9d932
--- /dev/null
+++ b/test/urlescape.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2016 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Test url percent encoding operations.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+
+#include "utils/url.h"
+
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
+#define SLEN(x) (sizeof((x)) - 1)
+
+struct test_pairs {
+ const char* test;
+ const char* res;
+ const size_t res_len;
+};
+
+const char all_chars[] =
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
+
+const char all_escaped[] =
+ "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F"
+ "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"
+ "%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F"
+ "0123456789%3A%3B%3C%3D%3E%3F"
+ "%40ABCDEFGHIJKLMNO"
+ "PQRSTUVWXYZ%5B%5C%5D%5E_"
+ "%60abcdefghijklmno"
+ "pqrstuvwxyz%7B%7C%7D%7E%7F"
+ "%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F"
+ "%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F"
+ "%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF"
+ "%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF"
+ "%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF"
+ "%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF"
+ "%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF"
+ "%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF";
+
+static const struct test_pairs url_escape_test_vec[] = {
+ { "", "" , 0 },
+ { "A.string.that.does.not.need.escaping",
+ "A.string.that.does.not.need.escaping" , 0 },
+ { " ", "%20" , 0 },
+ { &all_chars[0], &all_escaped[0], 0 },
+};
+
+
+START_TEST(url_escape_test)
+{
+ nserror err;
+ char *esc_str;
+ const struct test_pairs *tst = &url_escape_test_vec[_i];
+
+ err = url_escape(tst->test, false, "", &esc_str);
+ ck_assert(err == NSERROR_OK);
+
+ ck_assert_str_eq(esc_str, tst->res);
+}
+END_TEST
+
+static const struct test_pairs url_unescape_test_vec[] = {
+ { "", "" , 0 },
+ { "A.string.that.does.not.need.unescaping",
+ "A.string.that.does.not.need.unescaping",
+ SLEN("A.string.that.does.not.need.unescaping") },
+ { "%20", " " , 1 },
+ { &all_escaped[0], &all_chars[0], SLEN(all_chars) },
+};
+
+START_TEST(url_unescape_test)
+{
+ nserror err;
+ char *unesc_str;
+ size_t unesc_length;
+
+ const struct test_pairs *tst = &url_unescape_test_vec[_i];
+
+ err = url_unescape(tst->test, 0 , &unesc_length, &unesc_str);
+ ck_assert(err == NSERROR_OK);
+ /* ensure length */
+ ck_assert_uint_eq(unesc_length, tst->res_len);
+ /* ensure contents */
+ ck_assert_str_eq(unesc_str, tst->res);
+}
+END_TEST
+
+
+
+TCase *url_escape_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Escape");
+
+ tcase_add_loop_test(tc, url_escape_test,
+ 0, NELEMS(url_escape_test_vec));
+
+ return tc;
+}
+
+TCase *url_unescape_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Unescape");
+
+ tcase_add_loop_test(tc, url_unescape_test,
+ 0, NELEMS(url_unescape_test_vec));
+
+ return tc;
+}
+
+
+Suite *urlescape_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("Percent escaping");
+
+ suite_add_tcase(s, url_escape_case_create());
+ suite_add_tcase(s, url_unescape_case_create());
+
+ return s;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(urlescape_suite_create());
+ //srunner_add_suite(sr, bar_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org