diff options
author | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2011-09-19 21:33:52 +0200 |
---|---|---|
committer | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2011-09-19 21:33:52 +0200 |
commit | abd446c2eebe1f96764b6d95f1c6c61ae9bc40b2 (patch) | |
tree | b313bbeebf50fd53369d303824edab57aa69d016 /src | |
parent | b0b0cddaff10b4cff371b8bb7aa21e045f8e3915 (diff) | |
parent | 0caf22a3f7c33578a073cee42c6cfa61f971bc42 (diff) |
merge
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/Url.h | 3 | ||||
-rw-r--r-- | src/IO/about.c | 83 | ||||
-rw-r--r-- | src/IO/http.c | 10 | ||||
-rw-r--r-- | src/IO/iowatch.cc | 12 | ||||
-rw-r--r-- | src/IO/iowatch.hh | 2 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/auth.c | 4 | ||||
-rw-r--r-- | src/bw.c | 25 | ||||
-rw-r--r-- | src/bw.h | 12 | ||||
-rw-r--r-- | src/cache.c | 34 | ||||
-rw-r--r-- | src/capi.c | 35 | ||||
-rw-r--r-- | src/chain.c | 5 | ||||
-rw-r--r-- | src/cookies.c | 21 | ||||
-rw-r--r-- | src/cookies.h | 5 | ||||
-rw-r--r-- | src/css.cc | 49 | ||||
-rw-r--r-- | src/css.hh | 6 | ||||
-rw-r--r-- | src/cssparser.cc | 22 | ||||
-rw-r--r-- | src/cssparser.hh | 5 | ||||
-rw-r--r-- | src/dialog.cc | 379 | ||||
-rw-r--r-- | src/dialog.hh | 2 | ||||
-rw-r--r-- | src/dillo.cc | 94 | ||||
-rw-r--r-- | src/dns.h | 2 | ||||
-rw-r--r-- | src/doctree.hh | 63 | ||||
-rw-r--r-- | src/findbar.cc | 164 | ||||
-rw-r--r-- | src/findbar.hh | 33 | ||||
-rw-r--r-- | src/form.cc | 10 | ||||
-rw-r--r-- | src/gif.c | 5 | ||||
-rw-r--r-- | src/html.cc | 110 | ||||
-rw-r--r-- | src/keys.cc | 192 | ||||
-rw-r--r-- | src/keys.hh | 3 | ||||
-rw-r--r-- | src/keysrc | 22 | ||||
-rw-r--r-- | src/menu.cc | 558 | ||||
-rw-r--r-- | src/menu.hh | 4 | ||||
-rw-r--r-- | src/misc.c | 34 | ||||
-rw-r--r-- | src/misc.h | 1 | ||||
-rw-r--r-- | src/nav.c | 45 | ||||
-rw-r--r-- | src/pixmaps.h | 32 | ||||
-rw-r--r-- | src/prefs.c | 18 | ||||
-rw-r--r-- | src/prefs.h | 8 | ||||
-rw-r--r-- | src/prefsparser.cc | 30 | ||||
-rw-r--r-- | src/styleengine.cc | 23 | ||||
-rw-r--r-- | src/styleengine.hh | 1 | ||||
-rw-r--r-- | src/table.cc | 9 | ||||
-rw-r--r-- | src/timeout.cc | 9 | ||||
-rw-r--r-- | src/ui.cc | 1010 | ||||
-rw-r--r-- | src/ui.hh | 192 | ||||
-rw-r--r-- | src/uicmd.cc | 894 | ||||
-rw-r--r-- | src/uicmd.hh | 12 | ||||
-rw-r--r-- | src/url.c | 19 | ||||
-rw-r--r-- | src/url.h | 24 | ||||
-rw-r--r-- | src/utf8.cc | 13 | ||||
-rw-r--r-- | src/utf8.hh | 1 | ||||
-rw-r--r-- | src/web.cc | 12 | ||||
-rw-r--r-- | src/web.hh | 3 | ||||
-rw-r--r-- | src/xembed.cc | 65 | ||||
-rw-r--r-- | src/xembed.hh | 8 |
56 files changed, 2391 insertions, 2049 deletions
diff --git a/src/IO/Url.h b/src/IO/Url.h index 95919f11..15934e13 100644 --- a/src/IO/Url.h +++ b/src/IO/Url.h @@ -18,7 +18,8 @@ int a_Http_proxy_auth(void); void a_Http_set_proxy_passwd(const char *str); char *a_Http_make_connect_str(const DilloUrl *url); const char *a_Http_get_proxy_urlstr(); -Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy); +Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, + bool_t use_proxy); void a_Http_ccc (int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2); diff --git a/src/IO/about.c b/src/IO/about.c index 508bfd11..77af318f 100644 --- a/src/IO/about.c +++ b/src/IO/about.c @@ -61,7 +61,7 @@ const char *const AboutSplash= " <table border='0' cellspacing='0' cellpadding='2'><tr>\n" " <td>\n" " <td>\n" -" <a href='http://www.dillo.org/dillo2-help.html'>\n" +" <a href='http://www.dillo.org/dillo3-help.html'>\n" " Help</a>\n" " <tr>\n" " <td> \n" @@ -153,12 +153,6 @@ const char *const AboutSplash= " <table border='0' cellspacing='0' cellpadding='5'><tr><td>\n" " <table border='0' cellpadding='2'><tr>\n" " <td> \n" -" <td><a href='http://www.google.com/'>Google</a>\n" -" <tr>\n" -" <td> \n" -" <td><a href='http://www.wikipedia.org/'>Wikipedia</a>\n" -" <tr>\n" -" <td> \n" " <td><a href='http://www.gutenberg.org/'>P. Gutenberg</a>\n" " <tr>\n" " <td> \n" @@ -240,20 +234,27 @@ const char *const AboutSplash= "<tr>\n" " <td bgcolor='#CCCCCC'>\n" " <h4>Release overview</h4>\n" -" February 11, 2010\n" +" September 06, 2011\n" "<tr>\n" " <td bgcolor='#FFFFFF'>\n" " <table border='0' cellspacing='0' cellpadding='5'>\n" " <tr>\n" " <td>\n" "<p>\n" -"This release features a major overhaul of the cookies subsystem,\n" -"a reimplementation of the DPI API, a configurable connection limit,\n" -"and various CSS improvements.\n" +"Dillo-3.0 is a port to FLTK-1.3, which is big news because FLTK-1.3.0 was\n" +"<a href='http://fltk.org/articles.php?L1086'>released</a>\n" +"in June, clearing the way for Dillo to return to those distributions\n" +"which had excluded Dillo2 due to FLTK2 never being officially released.\n" +"<p>\n" +"Dillo-3.0 also has plenty of improvements and bugfixes.\n" +"<p>\n" +"After this release, the core team will focus on implementing the CSS\n" +"feature of floating elements. This will <em>greatly</em> improve dillo's\n" +"web page rendering since many sites have adopted floats instead of tables.\n" +"<p>\n" +"The new dillo3 has shown excellent stability in our experience.\n" +"The core team welcomes developers willing to join our workforce.\n" "<p>\n" -"Remember that the dillo project uses a release model where every new\n" -"version shall be better than the last.\n" -"<EM>Keep up with the latest one!</EM>\n" " </table>\n" "</table>\n" "</table>\n" @@ -274,27 +275,39 @@ const char *const AboutSplash= " <tr>\n" " <td>\n" "<ul>\n" -"<li>Added keybindings for scrolling.\n" -"<li>Help button and local help file.\n" -"<li>Add support for multiple class names in CSS.\n" -"<li>Fix X11 coordinate overflows.\n" -"<li>Improve CSS font parsing.\n" -"<li>Enable font face setting via <font> element.\n" -"<li>Ignore XML comment markers in CSS.\n" -"<li>Fix user agent style for nested <ul>.\n" -"<li>Handle signed chars. Added dIsspace() and dIsalnum() to dlib.\n" -"<li>Changed the CCCs to build in one step (for both HTTP and DPI).\n" -"<li>Remove the empty cache entry lingering after connection abort.\n" -"<li>Fixed URL unescaping in the datauri DPI.\n" -"<li>Changed and reimplemented the DPI API.\n" -"<li>Allow linebreaks around Chinese/Japanese characters.\n" -"<li>Fix scrolling for text search.\n" -"<li>Tooltips.\n" -"<li>Enable popup menu below bottom of page content.\n" -"<li>Handle JPEGs with CMYK color space.\n" -"<li>General cookies overhaul.\n" -"<li>Fixed a bug in w3c_mode.\n" -"<li>Limit number of simultaneous connections.\n" +"<li>Ported Dillo to FLTK-1.3.\n" +"<li>Native build on OSX.\n" +"<li>Default binding for close-all changed from Alt-q to Ctrl-q.\n" +"<li>Default binding for close-tab changed from Ctrl-q to Ctrl-w.\n" +"<li>Default binding for left-tab changed to Shift-Ctrl-Tab.\n" +"<li>Rewrote the User Interface: much simpler design and event handling.\n" +"<li>Added on-the-fly panel resize (tiny/small/medium and normal/small icons).\n" +"<li>'hide-panels' key action now hides the findbar if present,\n" +" and toggles display of the control panels otherwise.\n" +"<li>Allow multiple search engines to be set in dillorc, with a menu\n" +" in the web search dialog to select between them.\n" +"<li>Added an optional label to dillorc's search_url.\n" +" Format: \"[<label> ]<url>\"\n" +"<li>Add right_click_closes_tab preference (default is middle click).\n" +"<li>Allow binding to non-ASCII keys and multimedia keys.\n" +"<li>Avoid a certificate dialog storm on some HTTPS sites (BUG#868).\n" +"<li>Enable line wrapping for <textarea>. (BUG#903)\n" +"<li>Avoid double render after going Back or Forward\n" +" (it takes half the time now!)\n" +"<li>Implemented a custom tabs handler (to allow fine control of it).\n" +"<li>Rewrote dw's crossing-events dispatcher (avoids redundant events).\n" +"<li>Fixed a years old bug: stamped tooltips when scrolling with keyboard.\n" +"<li>Fixed a border case in URL resolver: empty path + {query|fragment}\n" +" (BUG#948)\n" +"<li>Cancel the expected URL after offering a download (BUG#982)\n" +"<li>Eliminated a pack of 22 compiler warnings (gcc-4.6.1 amd64)\n" +"<li>Removed 'large' option of panel_size preference.\n" +"<li>Removed --enable-ansi configure option.\n" +"<li>Limit saved cookie size.\n" +"<li>Wrap image alt text.\n" +"<li>Added support for CSS adjacent sibling selectors.\n" +"<li>Fix redraw loops and reenabled limit_text_width dillorc option.\n" +"<li>Collapse parent's and first child's top margin.\n" "</ul>\n" " </table>\n" "</table>\n" diff --git a/src/IO/http.c b/src/IO/http.c index 77a1be43..41ee137a 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -174,7 +174,7 @@ static void Http_connect_queued_sockets(HostConnection_t *hc) MSG_BW(sd->web, 1, "ERROR: %s", dStrerror(sd->Err)); a_Chain_bfcb(OpAbort, sd->Info, NULL, "Both"); dFree(sd->Info); - Http_socket_free((int) sd->Info->LocalKey); + Http_socket_free(VOIDP2INT(sd->Info->LocalKey)); } else { sd->connected_to = hc->host; hc->active_connections++; @@ -271,7 +271,8 @@ static Dstr *Http_make_content_type(const DilloUrl *url) /* * Make the http query string */ -Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) +Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, + bool_t use_proxy) { const char *auth; char *ptr, *cookies, *referer; @@ -296,7 +297,7 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, bool_t use_proxy) (URL_PATH_(url) || URL_QUERY_(url)) ? "" : "/"); } - cookies = a_Cookies_get_query(url); + cookies = a_Cookies_get_query(url, requester); auth = a_Auth_get_auth_str(url); referer = Http_get_referer(url); if (URL_FLAGS(url) & URL_Post) { @@ -365,7 +366,8 @@ static void Http_send_query(ChainLink *Info, SocketData_t *S) DataBuf *dbuf; /* Create the query */ - query = a_Http_make_query_str(S->web->url, S->flags & HTTP_SOCKET_USE_PROXY); + query = a_Http_make_query_str(S->web->url, S->web->requester, + S->flags & HTTP_SOCKET_USE_PROXY); dbuf = a_Chain_dbuf_new(query->str, query->len, 0); /* actually this message is sent too early. diff --git a/src/IO/iowatch.cc b/src/IO/iowatch.cc index f67b711f..f5243934 100644 --- a/src/IO/iowatch.cc +++ b/src/IO/iowatch.cc @@ -11,19 +11,17 @@ // Simple ADT for watching file descriptor activity -#include <fltk/run.h> +#include <FL/Fl.H> #include "iowatch.hh" -using namespace fltk; - - // // Hook a Callback for a certain activities in a FD // -void a_IOwatch_add_fd(int fd, int when, FileHandler Callback, void *usr_data=0) +void a_IOwatch_add_fd(int fd, int when, Fl_FD_Handler Callback, + void *usr_data = 0) { if (fd >= 0) - add_fd(fd, when, Callback, usr_data); + Fl::add_fd(fd, when, Callback, usr_data); } // @@ -32,6 +30,6 @@ void a_IOwatch_add_fd(int fd, int when, FileHandler Callback, void *usr_data=0) void a_IOwatch_remove_fd(int fd, int when) { if (fd >= 0) - remove_fd(fd, when); + Fl::remove_fd(fd, when); } diff --git a/src/IO/iowatch.hh b/src/IO/iowatch.hh index 681d0080..e2d497f1 100644 --- a/src/IO/iowatch.hh +++ b/src/IO/iowatch.hh @@ -2,7 +2,7 @@ #define __IO_WATCH_H__ /* - * BUG: enum {READ = 1, WRITE = 4, EXCEPT = 8} borrowed from fltk/run.h + * BUG: enum {READ = 1, WRITE = 4, EXCEPT = 8} borrowed from FL/Enumerations.H */ #define DIO_READ 1 #define DIO_WRITE 4 diff --git a/src/Makefile.am b/src/Makefile.am index 0f09b716..9de7eed5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,8 @@ dillo_LDADD = \ $(top_builddir)/dw/libDw-fltk.a \ $(top_builddir)/dw/libDw-core.a \ $(top_builddir)/lout/liblout.a \ - @LIBJPEG_LIBS@ @LIBPNG_LIBS@ @LIBFLTK_LIBS@ @LIBZ_LIBS@ @LIBICONV_LIBS@ + @LIBJPEG_LIBS@ @LIBPNG_LIBS@ @LIBFLTK_LIBS@ @LIBZ_LIBS@ \ + @LIBICONV_LIBS@ @LIBPTHREAD_LIBS@ dillo_SOURCES = \ dillo.cc \ @@ -486,8 +486,8 @@ static int Auth_do_auth_dialog(const char *realm, const DilloUrl *url) AuthDialogData_t *data; _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", realm); - message = dStrconcat("Enter a user and password for \"", - realm, "\".", NULL); + message = dStrconcat("The server at ", URL_HOST(url), " requires a username" + " and password for \"", realm, "\".", NULL); data = dNew(AuthDialogData_t, 1); data->realm_name = dStrdup(realm); data->url = a_Url_dup(url); @@ -55,7 +55,6 @@ BrowserWindow *a_Bw_new() bw->nav_stack_ptr = -1; /* Init expect */ - bw->nav_expecting = FALSE; bw->nav_expect_url = NULL; bw->redirect_level = 0; @@ -313,3 +312,27 @@ BrowserWindow *a_Bw_get(int i) return NULL; } +/* expect API ------------------------------------------------------------- */ + +void a_Bw_expect(BrowserWindow *bw, const DilloUrl *url) +{ + a_Url_free(bw->nav_expect_url); + bw->nav_expect_url = a_Url_dup(url); +} + +void a_Bw_cancel_expect(BrowserWindow *bw) +{ + a_Url_free(bw->nav_expect_url); + bw->nav_expect_url = NULL; +} + +bool_t a_Bw_expecting(BrowserWindow *bw) +{ + return (bw->nav_expect_url != NULL); +} + +const DilloUrl *a_Bw_expected_url(BrowserWindow *bw) +{ + return bw->nav_expect_url; +} + @@ -46,12 +46,9 @@ struct _BrowserWindow /* 'nav_stack_ptr' refers to what's being displayed */ int nav_stack_ptr; /* [0 based; -1 = empty] */ /* When the user clicks a link, the URL isn't pushed directly to history; - * nav_expect_url holds it until the first answer-bytes are got. Only then - * it is sent to history and referenced at the top of nav_stack */ + * nav_expect_url holds it until a dw is assigned to it. Only then an entry + * is made in history and referenced at the top of nav_stack */ DilloUrl *nav_expect_url; - /* 'nav_expecting' is true while dillo waits for non-cached URL data, - * until a dw is assigned to it. */ - bool_t nav_expecting; /* Counter for the number of hops on a redirection. Used to stop * redirection loops (accounts for WEB_RootUrl only) */ @@ -88,6 +85,11 @@ void *a_Bw_get_url_doc(BrowserWindow *bw, const DilloUrl *Url); void a_Bw_remove_doc(BrowserWindow *bw, void *vdoc); void a_Bw_add_url(BrowserWindow *bw, const DilloUrl *Url); void a_Bw_cleanup(BrowserWindow *bw); +/* expect API */ +void a_Bw_expect(BrowserWindow *bw, const DilloUrl *Url); +void a_Bw_cancel_expect(BrowserWindow *bw); +bool_t a_Bw_expecting(BrowserWindow *bw); +const DilloUrl *a_Bw_expected_url(BrowserWindow *bw); typedef void (*BwCallback_t)(BrowserWindow *bw, const void *data); diff --git a/src/cache.c b/src/cache.c index d26ae610..6094a8d5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -742,13 +742,29 @@ static void Cache_parse_header(CacheEntry_t *entry) #ifndef DISABLE_COOKIES if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) { - char *server_date = Cache_parse_field(header, "Date"); + CacheClient_t *client; + + for (i = 0; (client = dList_nth_data(ClientQueue, i)); ++i) { + if (client->Url == entry->Url) { + DilloWeb *web = client->Web; + + if (!web->requester || + a_Url_same_organization(entry->Url, web->requester)) { + char *server_date = Cache_parse_field(header, "Date"); + + a_Cookies_set(Cookies, entry->Url, server_date); + dFree(server_date); + break; + } + } + } + if (i >= dList_length(ClientQueue)) { + MSG("Cache: cookies not accepted from '%s'\n", URL_STR(entry->Url)); + } - a_Cookies_set(Cookies, entry->Url, server_date); for (i = 0; (data = dList_nth_data(Cookies, i)); ++i) dFree(data); dList_free(Cookies); - dFree(server_date); } #endif /* !DISABLE_COOKIES */ @@ -893,6 +909,16 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, MSG("entry->ExpectedSize = %d, entry->TransferSize = %d\n", entry->ExpectedSize, entry->TransferSize); } + if (!entry->TransferSize && !(entry->Flags & CA_Redirect) && + (entry->Flags & WEB_RootUrl)) { + char *eol = strchr(entry->Header->str, '\n'); + if (eol) { + char *status_line = dStrndup(entry->Header->str, + eol - entry->Header->str); + MSG_HTTP("Body was empty. Server sent status: %s\n", status_line); + dFree(status_line); + } + } entry->Flags |= CA_GotData; entry->Flags &= ~CA_Stopped; /* it may catch up! */ if (entry->TransferDecoder) { @@ -1166,6 +1192,8 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry) } } if (AbortEntry) { + if (ClientWeb->flags & WEB_RootUrl) + a_Nav_cancel_expect_if_eq(Client_bw, Client->Url); a_Bw_remove_client(Client_bw, Client->Key); Cache_client_dequeue(Client, NULLKey); --i; /* Keep the index value in the next iteration */ @@ -300,17 +300,26 @@ static char *Capi_dpi_build_cmd(DilloWeb *web, char *server) if (strcmp(server, "proto.https") == 0) { /* Let's be kind and make the HTTP query string for the dpi */ char *proxy_connect = a_Http_make_connect_str(web->url); - Dstr *http_query = a_Http_make_query_str(web->url, FALSE); + Dstr *http_query = a_Http_make_query_str(web->url, web->requester,FALSE); /* BUG: embedded NULLs in query data will truncate message */ + + /* BUG: WORKAROUND: request to only check the root URL's certificate. + * This avoids the dialog bombing that stems from loading multiple + * https images/resources in a single page. A proper fix would take + * either to implement the https-dpi as a server (with state), + * or to move back https handling into dillo. */ if (proxy_connect) { const char *proxy_urlstr = a_Http_get_proxy_urlstr(); cmd = a_Dpip_build_cmd("cmd=%s proxy_url=%s proxy_connect=%s " - "url=%s query=%s", "open_url", proxy_urlstr, + "url=%s query=%s check_cert=%s", + "open_url", proxy_urlstr, proxy_connect, URL_STR(web->url), - http_query->str); + http_query->str, + (web->flags & WEB_RootUrl) ? "true" : "false"); } else { - cmd = a_Dpip_build_cmd("cmd=%s url=%s query=%s", - "open_url", URL_STR(web->url),http_query->str); + cmd = a_Dpip_build_cmd("cmd=%s url=%s query=%s check_cert=%s", + "open_url", URL_STR(web->url),http_query->str, + (web->flags & WEB_RootUrl) ? "true" : "false"); } dFree(proxy_connect); dStr_free(http_query, 1); @@ -376,9 +385,7 @@ static bool_t Capi_filters_test(const DilloUrl *wanted, case PREFS_FILTER_SAME_DOMAIN: { const char *req_host = URL_HOST(requester), - *want_host = URL_HOST(wanted), - *req_suffix, - *want_suffix; + *want_host = URL_HOST(wanted); if (want_host[0] == '\0') { ret = (req_host[0] == '\0' || !dStrcasecmp(URL_SCHEME(wanted), "data")) ? TRUE : FALSE; @@ -386,14 +393,12 @@ static bool_t Capi_filters_test(const DilloUrl *wanted, /* This will regard "www.dillo.org" and "www.dillo.org." as * different, but it doesn't seem worth caring about. */ - req_suffix = a_Url_host_find_public_suffix(req_host); - want_suffix = a_Url_host_find_public_suffix(want_host); - - ret = dStrcasecmp(req_suffix, want_suffix) == 0; + ret = a_Url_same_organization(wanted, requester); + } + if (ret == FALSE) { + MSG("Capi_filters_test: deny from '%s' to '%s'\n", req_host, + want_host); } - - MSG("Capi_filters_test: %s from '%s' to '%s'\n", - ret ? "ALLOW" : "DENY", req_host, want_host); break; } case PREFS_FILTER_ALLOW_ALL: diff --git a/src/chain.c b/src/chain.c index d4098a2d..a13b3120 100644 --- a/src/chain.c +++ b/src/chain.c @@ -22,7 +22,7 @@ */ #if VERBOSE static void Chain_debug_msg(char *FuncStr, int Op, int Branch, int Dir, - ChainLink *Info) + ChainLink *Info) { const char *StrOps[] = {"", "OpStart", "OpSend", "OpStop", "OpEnd", "OpAbort"}; @@ -31,7 +31,8 @@ static void Chain_debug_msg(char *FuncStr, int Op, int Branch, int Dir, Info, Info ? Info->Flags : -1); } #else -static void Chain_debug_msg() { } +static void Chain_debug_msg(char *FuncStr, int Op, int Branch, int Dir, + ChainLink *Info) { } #endif /* * Create and initialize a new chain-link diff --git a/src/cookies.c b/src/cookies.c index 7b9062e2..d1451dc1 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -179,7 +179,7 @@ void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url, /* * Return a string containing cookie data for an HTTP query. */ -char *a_Cookies_get_query(const DilloUrl *request_url) +char *a_Cookies_get_query(const DilloUrl *query_url, const DilloUrl *requester) { char *cmd, *dpip_tag, *query; const char *path; @@ -188,16 +188,25 @@ char *a_Cookies_get_query(const DilloUrl *request_url) if (disabled) return dStrdup(""); - action = Cookies_control_check(request_url); + action = Cookies_control_check(query_url); if (action == COOKIE_DENY) { - _MSG("Cookies: denied GET for %s\n", URL_HOST_(request_url)); + _MSG("Cookies: denied GET for %s\n", URL_HOST_(query_url)); return dStrdup(""); } - path = URL_PATH_(request_url); + + if (requester == NULL) { + /* request made by user */ + } else if (!a_Url_same_organization(query_url, requester)) { + MSG("Cookies: No cookies sent for third-party request by '%s' for " + "'%s'\n", URL_HOST(requester), URL_STR(query_url)); + return dStrdup(""); + } + + path = URL_PATH_(query_url); cmd = a_Dpip_build_cmd("cmd=%s scheme=%s host=%s path=%s", - "get_cookie", URL_SCHEME(request_url), - URL_HOST(request_url), path ? path : "/"); + "get_cookie", URL_SCHEME(query_url), + URL_HOST(query_url), path ? path : "/"); /* Get the answer from cookies.dpi */ _MSG("cookies.c: a_Dpi_send_blocking_cmd cmd = {%s}\n", cmd); diff --git a/src/cookies.h b/src/cookies.h index d6ee1ccd..1cdb82ac 100644 --- a/src/cookies.h +++ b/src/cookies.h @@ -7,12 +7,13 @@ extern "C" { #ifdef DISABLE_COOKIES -# define a_Cookies_get_query(url) dStrdup("") +# define a_Cookies_get_query(url, requester) dStrdup("") # define a_Cookies_set() ; # define a_Cookies_init() ; # define a_Cookies_freeall() ; #else - char *a_Cookies_get_query(const DilloUrl *request_url); + char *a_Cookies_get_query(const DilloUrl *query_url, + const DilloUrl *requester); void a_Cookies_set(Dlist *cookie_string, const DilloUrl *set_url, const char *server_date); void a_Cookies_init( void ); @@ -104,6 +104,7 @@ CssSelector::CssSelector () { cs = selectorList->getRef (selectorList->size () - 1); cs->notMatchingBefore = -1; + cs->combinator = CHILD; cs->selector = new CssSimpleSelector (); }; @@ -133,6 +134,7 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) { switch (comb) { case CHILD: + case ADJACENT_SIBLING: if (!sel->match (node)) return false; break; @@ -156,7 +158,11 @@ bool CssSelector::match (Doctree *docTree, const DoctreeNode *node) { } comb = cs->combinator; - node = docTree->parent (node); + + if (comb == ADJACENT_SIBLING) + node = docTree->sibling (node); + else + node = docTree->parent (node); } return true; @@ -200,6 +206,9 @@ void CssSelector::print () { case DESCENDANT: fprintf (stderr, "\" \" "); break; + case ADJACENT_SIBLING: + fprintf (stderr, "+ "); + break; default: fprintf (stderr, "? "); break; @@ -489,39 +498,21 @@ void CssStyleSheet::apply (CssPropertyList *props, } } -CssStyleSheet *CssContext::userAgentStyle; -CssStyleSheet *CssContext::userStyle; -CssStyleSheet *CssContext::userImportantStyle; - CssContext::CssContext () { pos = 0; - for (int o = CSS_PRIMARY_USER_AGENT; o < CSS_PRIMARY_LAST; o++) - sheet[o] = NULL; - - if (userAgentStyle == NULL) { - userAgentStyle = new CssStyleSheet (); - userStyle = new CssStyleSheet (); - userImportantStyle = new CssStyleSheet (); + memset (sheet, 0, sizeof(sheet)); + sheet[CSS_PRIMARY_USER_AGENT] = new CssStyleSheet (); + sheet[CSS_PRIMARY_USER] = new CssStyleSheet (); + sheet[CSS_PRIMARY_USER_IMPORTANT] = new CssStyleSheet (); - sheet[CSS_PRIMARY_USER_AGENT] = userAgentStyle; - sheet[CSS_PRIMARY_USER] = userStyle; - sheet[CSS_PRIMARY_USER_IMPORTANT] = userImportantStyle; - - buildUserAgentStyle (); - buildUserStyle (); - } - - sheet[CSS_PRIMARY_USER_AGENT] = userAgentStyle; - sheet[CSS_PRIMARY_USER] = userStyle; - sheet[CSS_PRIMARY_USER_IMPORTANT] = userImportantStyle; + buildUserAgentStyle (); + buildUserStyle (); } CssContext::~CssContext () { for (int o = CSS_PRIMARY_USER_AGENT; o < CSS_PRIMARY_LAST; o++) - if (sheet[o] != userAgentStyle && sheet[o] != userStyle && - sheet[o] != userImportantStyle) - delete sheet[o]; + delete sheet[o]; } /** @@ -535,7 +526,8 @@ CssContext::~CssContext () { */ void CssContext::apply (CssPropertyList *props, Doctree *docTree, DoctreeNode *node, - CssPropertyList *tagStyle, CssPropertyList *nonCssHints) { + CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant, + CssPropertyList *nonCssHints) { if (sheet[CSS_PRIMARY_USER_AGENT]) sheet[CSS_PRIMARY_USER_AGENT]->apply (props, docTree, node); @@ -554,6 +546,9 @@ void CssContext::apply (CssPropertyList *props, Doctree *docTree, if (sheet[CSS_PRIMARY_AUTHOR_IMPORTANT]) sheet[CSS_PRIMARY_AUTHOR_IMPORTANT]->apply (props, docTree, node); + if (tagStyleImportant) + tagStyleImportant->apply (props); + if (sheet[CSS_PRIMARY_USER_IMPORTANT]) sheet[CSS_PRIMARY_USER_IMPORTANT]->apply (props, docTree, node); } @@ -458,9 +458,6 @@ class CssStyleSheet { */ class CssContext { private: - static CssStyleSheet *userAgentStyle; - static CssStyleSheet *userStyle; - static CssStyleSheet *userImportantStyle; CssStyleSheet *sheet[CSS_PRIMARY_USER_IMPORTANT + 1]; int pos; @@ -475,7 +472,8 @@ class CssContext { CssPrimaryOrder order); void apply (CssPropertyList *props, Doctree *docTree, DoctreeNode *node, - CssPropertyList *tagStyle, CssPropertyList *nonCssHints); + CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant, + CssPropertyList *nonCssHints); }; #endif diff --git a/src/cssparser.cc b/src/cssparser.cc index 7b522c8c..f6e60731 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -1053,7 +1053,7 @@ void CssParser::parseDeclaration(CssPropertyList * props, CssPropertyList * importantProps) { CssPropertyInfo pi = {NULL, {CSS_TYPE_UNUSED}, NULL}, *pip; - CssShorthandInfo si, *sip; + CssShorthandInfo *sip; CssValueType type = CSS_TYPE_UNUSED; CssPropertyName prop; @@ -1091,7 +1091,6 @@ void CssParser::parseDeclaration(CssPropertyList * props, } } else { /* Try shorthands. */ - si.symbol = tval; sip = (CssShorthandInfo *) bsearch(&pi, Css_shorthand_info, CSS_SHORTHAND_NUM, @@ -1294,6 +1293,9 @@ CssSelector *CssParser::parseSelector() } else if (ttype == CSS_TK_CHAR && tval[0] == '>') { selector->addSimpleSelector (CssSelector::CHILD); nextToken(); + } else if (ttype == CSS_TK_CHAR && tval[0] == '+') { + selector->addSimpleSelector (CssSelector::ADJACENT_SIBLING); + nextToken(); } else if (ttype != CSS_TK_END && spaceSeparated) { selector->addSimpleSelector (CssSelector::DESCENDANT); } else { @@ -1526,7 +1528,7 @@ const char * CssParser::propertyNameString(CssPropertyName name) { return Css_property_info[name].symbol; } - + void CssParser::ignoreBlock() { int depth = 0; @@ -1594,22 +1596,16 @@ void CssParser::parse(DilloHtml *html, DilloUrl *url, CssContext * context, } } -CssPropertyList *CssParser::parseDeclarationBlock(const char *buf, int buflen) +void CssParser::parseDeclarationBlock(const char *buf, int buflen, + CssPropertyList *props, + CssPropertyList *propsImortant) { - CssPropertyList *props = new CssPropertyList (true); CssParser parser (NULL, CSS_ORIGIN_AUTHOR, buf, buflen); parser.withinBlock = true; do - parser.parseDeclaration(props, NULL); + parser.parseDeclaration(props, propsImortant); while (!(parser.ttype == CSS_TK_END || (parser.ttype == CSS_TK_CHAR && parser.tval[0] == '}'))); - - if (props->size () == 0) { - delete props; - props = NULL; - } - - return props; } diff --git a/src/cssparser.hh b/src/cssparser.hh index 1542405d..8609877b 100644 --- a/src/cssparser.hh +++ b/src/cssparser.hh @@ -47,8 +47,9 @@ class CssParser { void ignoreStatement(); public: - static CssPropertyList *parseDeclarationBlock(const char *buf, - int buflen); + static void parseDeclarationBlock(const char *buf, int buflen, + CssPropertyList *props, + CssPropertyList *propsImortant); static void parse(DilloHtml *html, DilloUrl *url, CssContext *context, const char *buf, int buflen, CssOrigin origin); static const char *propertyNameString(CssPropertyName name); diff --git a/src/dialog.cc b/src/dialog.cc index 47af9921..15e5d7a9 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -13,58 +13,192 @@ #include <math.h> // for rint() -#include <fltk/Window.h> -#include <fltk/ask.h> -#include <fltk/file_chooser.h> -#include <fltk/TextBuffer.h> -#include <fltk/ReturnButton.h> -#include <fltk/TextDisplay.h> -#include <fltk/HighlightButton.h> -#include <fltk/WordwrapOutput.h> -#include <fltk/Input.h> -#include <fltk/SecretInput.h> +#include <FL/Fl_Window.H> +#include <FL/Fl_File_Chooser.H> +#include <FL/Fl_Return_Button.H> +#include <FL/Fl_Text_Display.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Return_Button.H> +#include <FL/Fl_Output.H> +#include <FL/Fl_Input.H> +#include <FL/Fl_Secret_Input.H> +#include <FL/Fl_Choice.H> +#include <FL/Fl_Menu_Item.H> #include "msg.h" #include "dialog.hh" #include "misc.h" #include "prefs.h" -using namespace fltk; +/* + * Local Data + */ +static int input_answer; +static char *input_str = NULL; +static int choice5_answer; + + +/* + * Local sub classes + */ +//---------------------------------------------------------------------------- /* - * Close dialog window. + * Used to enable CTRL+{a,e,d,k} in search dialog (for start,end,del,cut) + * TODO: bind down arrow to a search engine selection list. */ -static void window_close_cb(Widget *, void *vwin) +class CustInput3 : public Fl_Input { +public: + CustInput3 (int x, int y, int w, int h, const char* l=0) : + Fl_Input(x,y,w,h,l) {}; + int handle(int e); +}; + +int CustInput3::handle(int e) { - delete (Window*)vwin; + int k = Fl::event_key(); + + _MSG("CustInput3::handle event=%d\n", e); + + // We're only interested in some flags + unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT); + + if (e == FL_KEYBOARD && modifier == FL_CTRL) { + if (k == 'a' || k == 'e') { + position(k == 'a' ? 0 : size()); + return 1; + } else if (k == 'k') { + cut(position(), size()); + return 1; + } else if (k == 'd') { + cut(position(), position()+1); + return 1; + } + } + return Fl_Input::handle(e); } /* + * Used to make the ENTER key activate the CustChoice + */ +class CustChoice : public Fl_Choice { +public: + CustChoice (int x, int y, int w, int h, const char* l=0) : + Fl_Choice(x,y,w,h,l) {}; + int handle(int e) { + if (e == FL_KEYBOARD && + (Fl::event_key() == FL_Enter || Fl::event_key() == FL_Down) && + (Fl::event_state() & (FL_SHIFT|FL_CTRL|FL_ALT|FL_META)) == 0) { + return Fl_Choice::handle(FL_PUSH); + } + return Fl_Choice::handle(e); + }; +}; + +//---------------------------------------------------------------------------- + + +/* * Display a message in a popup window. */ void a_Dialog_msg(const char *msg) { - message("%s", msg); + fl_message("%s", msg); } + /* - * Offer a three choice dialog. - * The option string that begins with "*" is the default. - * - * Return: 0, 1 or 2 (esc = 2, window close = 2) + * Callback for a_Dialog_input() */ -int a_Dialog_choice3(const char *msg, - const char *b0, const char *b1, const char *b2) +static void input_cb(Fl_Widget *button, void *number) { - return choice(msg, b0, b1, b2); + input_answer = VOIDP2INT(number); + button->window()->hide(); } /* * Dialog for one line of Input with a message. + * avoids the sound bell in fl_input(), and allows customization + * + * Return value: string on success, NULL upon Cancel or Close window */ const char *a_Dialog_input(const char *msg) { - return input("%s", "", msg); + static Fl_Menu_Item *pm = 0; + int ww = 450, wh = 130, gap = 10, ih = 60, bw = 80, bh = 30; + + input_answer = 0; + + Fl_Window *window = new Fl_Window(ww,wh,"Ask"); + window->set_modal(); + window->begin(); + Fl_Group* ib = new Fl_Group(0,0,window->w(),window->h()); + ib->begin(); + window->resizable(ib); + + /* '?' Icon */ + Fl_Box* o = new Fl_Box(gap, gap, ih, ih); + o->box(FL_THIN_UP_BOX); + o->labelfont(FL_TIMES_BOLD); + o->labelsize(34); + o->color(FL_WHITE); + o->labelcolor(FL_BLUE); + o->label("?"); + o->show(); + + Fl_Box *box = new Fl_Box(ih+2*gap,gap,ww-(ih+3*gap),ih/2, msg); + box->labelfont(FL_HELVETICA); + box->labelsize(14); + box->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP|FL_ALIGN_WRAP); + + CustInput3 *c_inp = new CustInput3(ih+2*gap,gap+ih/2+gap,ww-(ih+3*gap),24); + c_inp->labelsize(14); + c_inp->textsize(14); + + CustChoice *ch = new CustChoice(1*gap,ih+3*gap,180,24); + if (!pm) { + int n_it = dList_length(prefs.search_urls); + pm = new Fl_Menu_Item[n_it+1]; + memset(pm, '\0', sizeof(Fl_Menu_Item[n_it+1])); + for (int i = 0, j = 0; i < n_it; i++) { + char *label, *url, *source; + source = (char *)dList_nth_data(prefs.search_urls, i); + if (!source || a_Misc_parse_search_url(source, &label, &url) < 0) + continue; + pm[j++].label(FL_NORMAL_LABEL, strdup(label)); + } + } + ch->tooltip("Select search engine"); + ch->menu(pm); + ch->value(prefs.search_url_idx); + ch->textcolor(FL_DARK_BLUE); + + int xpos = ww-2*(gap+bw), ypos = ih+3*gap; + Fl_Return_Button *rb = new Fl_Return_Button(xpos, ypos, bw, bh, "OK"); + rb->align(FL_ALIGN_INSIDE|FL_ALIGN_CLIP); + rb->box(FL_UP_BOX); + rb->callback(input_cb, INT2VOIDP(1)); + + xpos = ww-(gap+bw); + Fl_Button *b = new Fl_Button(xpos, ypos, bw, bh, "Cancel"); + b->align(FL_ALIGN_INSIDE|FL_ALIGN_CLIP); + b->box(FL_UP_BOX); + b->callback(input_cb, INT2VOIDP(2)); + + window->end(); + + window->show(); + while (window->shown()) + Fl::wait(); + if (input_answer == 1) { + /* we have a string, save it */ + dFree(input_str); + input_str = dStrdup(c_inp->value()); + prefs.search_url_idx = ch->value(); + } + delete window; + + return (input_answer == 1) ? input_str : NULL; } /* @@ -72,7 +206,7 @@ const char *a_Dialog_input(const char *msg) */ const char *a_Dialog_passwd(const char *msg) { - return password("%s", "", msg); + return fl_password("%s", "", msg); } /* @@ -83,7 +217,7 @@ const char *a_Dialog_passwd(const char *msg) const char *a_Dialog_save_file(const char *msg, const char *pattern, const char *fname) { - return file_chooser(msg, pattern, fname); + return fl_file_chooser(msg, pattern, fname); } /* @@ -101,7 +235,6 @@ const char *a_Dialog_select_file(const char *msg, return a_Dialog_save_file(msg, pattern, fname); } -//#include <fltk/FileIcon.h> /* * Show the open file dialog. * @@ -111,69 +244,66 @@ char *a_Dialog_open_file(const char *msg, const char *pattern, const char *fname) { const char *fc_name; -/* - static int icons_loaded = 0; - if (!icons_loaded) - FileIcon::load_system_icons(); -*/ - fc_name = file_chooser(msg, pattern, fname); + + fc_name = fl_file_chooser(msg, pattern, fname); return (fc_name) ? a_Misc_escape_chars(fc_name, "% ") : NULL; } /* + * Close text window. + */ +static void text_window_close_cb(Fl_Widget *, void *vtd) +{ + Fl_Text_Display *td = (Fl_Text_Display *)vtd; + Fl_Text_Buffer *buf = td->buffer(); + + delete (Fl_Window*)td->window(); + delete buf; +} + +/* * Show a new window with the provided text */ void a_Dialog_text_window(const char *txt, const char *title) { - //int wh = 600, ww = 650, bh = 30; int wh = prefs.height, ww = prefs.width, bh = 30; - int lines, line_num_width; - Font *textfont = font(prefs.font_monospace, 0); - Window *window = new Window(ww, wh, title ? title : "Untitled"); - window->callback(window_close_cb, window); - window->begin(); - - TextDisplay *td = new TextDisplay(0,0,ww, wh-bh); - td->buffer()->text(txt); + Fl_Window *window = new Fl_Window(ww, wh, title ? title : "Dillo text"); + Fl_Group::current(0); - if (textfont) - td->textfont(textfont); - td->textsize((int) rint(13.0 * prefs.font_factor)); - fltk::setfont(td->textfont(), td->textsize()); - lines = td->total_lines(); - line_num_width = 2; - while (lines /= 10) - ++line_num_width; - line_num_width = (int)(line_num_width * fltk::getwidth("0")); - td->linenumber_width(line_num_width); + Fl_Text_Buffer *buf = new Fl_Text_Buffer(); + buf->text(txt); + Fl_Text_Display *td = new Fl_Text_Display(0,0,ww, wh-bh); + td->buffer(buf); + td->textsize((int) rint(14.0 * prefs.font_factor)); /* enable wrapping lines; text uses entire width of window */ td->wrap_mode(true, false); - /* WORKAROUND: FLTK may not display all the lines without this */ - td->resize(ww+1,wh-bh); + window->add(td); - ReturnButton *b = new ReturnButton (0, wh-bh, ww, bh, "Close"); - b->callback(window_close_cb, window); + Fl_Return_Button *b = new Fl_Return_Button (0, wh-bh, ww, bh, "Close"); + b->callback(text_window_close_cb, td); + window->add(b); + window->callback(text_window_close_cb, td); window->resizable(td); - window->end(); window->show(); } /*--------------------------------------------------------------------------*/ -static int choice5_answer; -static void choice5_cb(Widget *button, void *number) +static void choice5_cb(Fl_Widget *button, void *number) { choice5_answer = VOIDP2INT(number); _MSG("choice5_cb: %d\n", choice5_answer); - button->window()->make_exec_return(true); + button->window()->hide(); } /* - * Make a question-dialog with a question and some alternatives. + * Make a question-dialog with a question and up to five alternatives. + * (if less alternatives, non used parameters must be NULL). + * * Return value: 0 = dialog was cancelled, 1-5 = selected alternative. */ int a_Dialog_choice5(const char *QuestionTxt, @@ -182,56 +312,72 @@ int a_Dialog_choice5(const char *QuestionTxt, { choice5_answer = 0; - int ww = 440, wh = 150, bw = 50, bh = 45, nb = 0; + int ww = 440, wh = 120, bw = 50, bh = 45, ih = 50, nb = 0; const char *txt[7]; txt[0] = txt[6] = NULL; txt[1] = alt1; txt[2] = alt2; txt[3] = alt3; txt[4] = alt4; txt[5] = alt5; - for (int i=1; txt[i]; ++i, ++nb) ; + for (int i=1; txt[i]; ++i, ++nb) + ; + + if (!nb) { + MSG_ERR("a_Dialog_choice5: No choices.\n"); + return choice5_answer; + } + ww = 140 + nb*(bw+10); - Window *window = new Window(ww,wh,"Choice5"); + Fl_Window *window = new Fl_Window(ww,wh,"Choice5"); + window->set_modal(); window->begin(); - Group* ib = new Group(0,0,window->w(),window->h()); + Fl_Group* ib = new Fl_Group(0,0,window->w(),window->h()); ib->begin(); window->resizable(ib); - Widget *box = new Widget(0,0,ww,wh-bh, QuestionTxt); - box->box(DOWN_BOX); - box->labelfont(HELVETICA_BOLD_ITALIC); + /* '?' Icon */ + Fl_Box* o = new Fl_Box(10, (wh-bh-ih)/2, ih, ih); + o->box(FL_THIN_UP_BOX); + o->labelfont(FL_TIMES_BOLD); + o->labelsize(34); + o->color(FL_WHITE); + o->labelcolor(FL_BLUE); + o->label("?"); + o->show(); + + Fl_Box *box = new Fl_Box(60,0,ww-60,wh-bh, QuestionTxt); + box->labelfont(FL_HELVETICA); box->labelsize(14); + box->align(FL_ALIGN_WRAP); - HighlightButton *b; + Fl_Button *b; int xpos = 0, gap = 8; bw = (ww - gap)/nb - gap; xpos += gap; for (int i=1; i <= nb; ++i) { - b = new HighlightButton(xpos, wh-bh, bw, bh, txt[i]); - b->align(ALIGN_WRAP|ALIGN_CLIP); - b->box(UP_BOX); + b = new Fl_Button(xpos, wh-bh, bw, bh, txt[i]); + b->align(FL_ALIGN_WRAP|FL_ALIGN_CLIP); + b->box(FL_UP_BOX); b->callback(choice5_cb, INT2VOIDP(i)); xpos += bw + gap; + /* TODO: set focus to the *-prefixed alternative */ } window->end(); - //window->hotspot(box); - window->exec(); + window->show(); + while (window->shown()) + Fl::wait(); + _MSG("a_Dialog_choice5 answer = %d\n", choice5_answer); delete window; - _MSG("Choice5 answer = %d\n", choice5_answer); return choice5_answer; } /*--------------------------------------------------------------------------*/ -/* - * ret: 0 = Cancel, 1 = OK - */ -static void Dialog_user_password_cb(Widget *button, void *vIntPtr) +static void Dialog_user_password_cb(Fl_Widget *button, void *) { - int ret = VOIDP2INT(vIntPtr); - _MSG("Dialog_user_password_cb: %d\n", ret); - button->window()->make_exec_return(ret); + button->window()->user_data(button); + button->window()->hide(); } /* @@ -241,52 +387,70 @@ static void Dialog_user_password_cb(Widget *button, void *vIntPtr) */ int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp) { - int ok, - window_w = 300, window_h = 280, - input_x = 80, input_w = 200, input_h = 30, - button_y = 230, button_h = 30; + int ok = 0, window_h = 280, y, msg_w, msg_h; + const int window_w = 300, input_x = 80, input_w = 200, input_h = 30, + button_h = 30; - Window *window = - new Window(window_w,window_h,"User/Password"); - window->begin(); + /* window is resized below */ + Fl_Window *window = new Fl_Window(window_w,window_h,"Dillo User/Password"); + Fl_Group::current(0); + window->user_data(NULL); /* message */ - WordwrapOutput *message_output = - new WordwrapOutput(20,20,window_w-40,100); - message_output->box(DOWN_BOX); - message_output->text(message); - message_output->textfont(HELVETICA_BOLD_ITALIC); - message_output->textsize(14); + y = 20; + msg_w = window_w - 40; + Fl_Box *msg = new Fl_Box(20, y, msg_w, 100); /* resized below */ + msg->label(message); + msg->labelfont(FL_HELVETICA); + msg->labelsize(14); + msg->align(FL_ALIGN_INSIDE | FL_ALIGN_TOP_LEFT | FL_ALIGN_WRAP); + + fl_font(msg->labelfont(), msg->labelsize()); + msg_w -= 6; /* The label doesn't fill the entire box. */ + fl_measure(msg->label(), msg_w, msg_h, 0); /* fl_measure wraps at msg_w */ + msg->size(msg->w(), msg_h); + window->add(msg); /* inputs */ - Input *user_input = - new Input(input_x,140,input_w,input_h,"User"); + y += msg_h + 20; + Fl_Input *user_input = new Fl_Input(input_x, y, input_w, input_h, "User"); user_input->labelsize(14); user_input->textsize(14); - SecretInput *password_input = - new SecretInput(input_x,180,input_w,input_h,"Password"); + window->add(user_input); + y += input_h + 10; + Fl_Secret_Input *password_input = + new Fl_Secret_Input(input_x, y, input_w, input_h, "Password"); password_input->labelsize(14); password_input->textsize(14); + window->add(password_input); /* "OK" button */ - Button *ok_button = - new Button(200,button_y,50,button_h,"OK"); + y += input_h + 20; + Fl_Button *ok_button = new Fl_Button(200, y, 50, button_h, "OK"); ok_button->labelsize(14); ok_button->callback(Dialog_user_password_cb); - ok_button->user_data(INT2VOIDP(1)); + window->add(ok_button); /* "Cancel" button */ - Button *cancel_button = - new Button(50,button_y,100,button_h,"Cancel"); + Fl_Button *cancel_button = + new Fl_Button(50, y, 100, button_h, "Cancel"); cancel_button->labelsize(14); cancel_button->callback(Dialog_user_password_cb); - cancel_button->user_data(INT2VOIDP(0)); + window->add(cancel_button); - window->end(); - window->size_range(window_w,window_h,window_w,window_h); + y += button_h + 20; + window_h = y; + window->size(window_w, window_h); + window->size_range(window_w, window_h, window_w, window_h); window->resizable(window); - if ((ok = window->exec())) { + window->show(); + while (window->shown()) + Fl::wait(); + + ok = ((Fl_Widget *)window->user_data()) == ok_button ? 1 : 0; + + if (ok) { /* call the callback */ const char *user, *password; user = user_input->value(); @@ -294,7 +458,6 @@ int a_Dialog_user_password(const char *message, UserPasswordCB cb, void *vp) _MSG("a_Dialog_user_passwd: ok = %d\n", ok); (*cb)(user, password, vp); } - delete window; return ok; diff --git a/src/dialog.hh b/src/dialog.hh index 440e9bba..57b21849 100644 --- a/src/dialog.hh +++ b/src/dialog.hh @@ -9,8 +9,6 @@ typedef void (*UserPasswordCB)(const char *user, const char *password, void *vp); void a_Dialog_msg(const char *msg); -int a_Dialog_choice3(const char *msg, - const char *b0, const char *b1, const char *b2); int a_Dialog_choice5(const char *QuestionTxt, const char *alt1, const char *alt2, const char *alt3, const char *alt4, const char *alt5); diff --git a/src/dillo.cc b/src/dillo.cc index 3159674e..b05cb16a 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -24,10 +24,9 @@ #include <signal.h> #include <locale.h> -#include <fltk/Window.h> -#include <fltk/TabGroup.h> -#include <fltk/Font.h> -#include <fltk/run.h> +#include <FL/Fl.H> +#include <FL/Fl_Window.H> +#include <FL/fl_draw.H> #include "msg.h" #include "paths.hh" @@ -49,6 +48,8 @@ #include "cookies.h" #include "auth.h" +#include "dw/fltkcore.hh" + /* * Command line options structure */ @@ -171,11 +172,55 @@ static OptID getCmdOption(const CLI_options *options, int argc, char **argv, } /* + * Set FL_NORMAL_LABEL to interpret neither symbols (@) nor shortcuts (&), + * and FL_FREE_LABELTYPE to interpret shortcuts. + */ +static void custLabelDraw(const Fl_Label* o, int X, int Y, int W, int H, + Fl_Align align) +{ + const int interpret_symbols = 0; + + fl_draw_shortcut = 0; + fl_font(o->font, o->size); + fl_color((Fl_Color)o->color); + fl_draw(o->value, X, Y, W, H, align, o->image, interpret_symbols); +} + +static void custLabelMeasure(const Fl_Label* o, int& W, int& H) +{ + const int interpret_symbols = 0; + + fl_draw_shortcut = 0; + fl_font(o->font, o->size); + fl_measure(o->value, W, H, interpret_symbols); +} + +static void custMenuLabelDraw(const Fl_Label* o, int X, int Y, int W, int H, + Fl_Align align) +{ + const int interpret_symbols = 0; + + fl_draw_shortcut = 1; + fl_font(o->font, o->size); + fl_color((Fl_Color)o->color); + fl_draw(o->value, X, Y, W, H, align, o->image, interpret_symbols); +} + +static void custMenuLabelMeasure(const Fl_Label* o, int& W, int& H) +{ + const int interpret_symbols = 0; + + fl_draw_shortcut = 1; + fl_font(o->font, o->size); + fl_measure(o->value, W, H, interpret_symbols); +} + +/* * Tell the user if default/pref fonts can't be found. */ static void checkFont(const char *name, const char *type) { - if (::fltk::font(name) == NULL) + if (! dw::fltk::FltkFont::fontExists(name)) MSG_WARN("preferred %s font \"%s\" not found.\n", type, name); } @@ -318,22 +363,38 @@ int main(int argc, char **argv) } // Sets WM_CLASS hint on X11 - fltk::Window::xclass("dillo"); + Fl_Window::default_xclass("dillo"); + + Fl::scheme(prefs.theme); - // WORKAROUND: sometimes the default pager triggers redraw storms - fltk::TabGroup::default_pager(fltk::PAGER_SHRINK); + if (!prefs.show_tooltip) { + // turn off UI tooltips + Fl::option(Fl::OPTION_SHOW_TOOLTIPS, false); + } + + // Disable '@' and '&' interpretation in normal labels. + Fl::set_labeltype(FL_NORMAL_LABEL, custLabelDraw, custLabelMeasure); + + // Use to permit '&' interpretation. + Fl::set_labeltype(FL_FREE_LABELTYPE,custMenuLabelDraw,custMenuLabelMeasure); checkPreferredFonts(); + /* use preferred font for UI */ - fltk::Font *dfont = fltk::font(prefs.font_sans_serif, 0); - if (dfont) { - fltk::Widget::default_style->textfont(dfont); - fltk::Widget::default_style->labelfont(dfont); - } + Fl_Font defaultFont = dw::fltk::FltkFont::get (prefs.font_sans_serif, 0); + Fl::set_font(FL_HELVETICA, defaultFont); // this seems to be the + // only way to set the + // default font in fltk1.3 // Create a new UI/bw pair BrowserWindow *bw = a_UIcmd_browser_window_new(0, 0, xid, NULL); + /* We need this so that fl_text_extents() in dw/fltkplatform.cc can + * work when FLTK is configured without XFT and Dillo is opening + * immediately-available URLs from the cmdline (e.g. about:splash). + */ + ((Fl_Widget *)bw->ui)->window()->make_current(); + /* Proxy authentication */ if (prefs.http_proxyuser && !a_Http_proxy_auth()) { const char *passwd = a_UIcmd_get_passwd(prefs.http_proxyuser); @@ -349,7 +410,10 @@ int main(int argc, char **argv) if (idx == argc) { /* No URLs/files on cmdline. Send startup screen */ - a_UIcmd_open_url(bw, prefs.start_page); + if (strcmp(URL_STR(prefs.start_page), "about:blank") == 0) + a_UIcmd_open_url(bw, NULL); + else + a_UIcmd_open_url(bw, prefs.start_page); } else { for (int i = idx; i < argc; i++) { DilloUrl *start_url = makeStartUrl(argv[i], local); @@ -369,7 +433,7 @@ int main(int argc, char **argv) } } - fltk::run(); + Fl::run(); /* * Memory deallocating routines @@ -8,7 +8,7 @@ extern "C" { #endif /* __cplusplus */ -typedef void (*DnsCallback_t)(int Status, Dlist *addr_list, void *data); +typedef void (*DnsCallback_t)(int status, Dlist *addr_list, void *data); void a_Dns_init (void); void a_Dns_freeall(void); diff --git a/src/doctree.hh b/src/doctree.hh index ef7faa7c..85c1effd 100644 --- a/src/doctree.hh +++ b/src/doctree.hh @@ -6,6 +6,8 @@ class DoctreeNode { public: DoctreeNode *parent; + DoctreeNode *sibling; + DoctreeNode *lastChild; int num; // unique ascending id int element; lout::misc::SimpleVector<char*> *klass; @@ -14,11 +16,27 @@ class DoctreeNode { DoctreeNode () { parent = NULL; + sibling = NULL; + lastChild = NULL; klass = NULL; pseudo = NULL; id = NULL; element = 0; }; + + ~DoctreeNode () { + dFree ((void*) id); + while (lastChild) { + DoctreeNode *n = lastChild; + lastChild = lastChild->sibling; + delete n; + } + if (klass) { + for (int i = 0; i < klass->size (); i++) + dFree (klass->get(i)); + delete klass; + } + } }; /** @@ -26,46 +44,55 @@ class DoctreeNode { * * The Doctree class defines the interface to the parsed HTML document tree * as it is used for CSS selector matching. - * Currently the Doctree can be represented as stack, however to support - * CSS adjacent siblings or for future JavaScript support it may have to - * be extended to a real tree. */ class Doctree { private: DoctreeNode *topNode; + DoctreeNode *rootNode; int num; public: Doctree () { - topNode = NULL; + rootNode = new DoctreeNode; + topNode = rootNode; num = 0; }; - ~Doctree () { while (top ()) pop (); }; + + ~Doctree () { + delete rootNode; + }; + DoctreeNode *push () { DoctreeNode *dn = new DoctreeNode (); dn->parent = topNode; + dn->sibling = dn->parent->lastChild; + dn->parent->lastChild = dn; dn->num = num++; topNode = dn; return dn; }; + void pop () { - DoctreeNode *dn = topNode; - if (dn) { - dFree ((void*) dn->id); - if (dn->klass) { - for (int i = 0; i < dn->klass->size (); i++) - dFree (dn->klass->get(i)); - delete dn->klass; - } - topNode = dn->parent; - delete dn; - } + assert (topNode != rootNode); // never pop the root node + topNode = topNode->parent; }; + inline DoctreeNode *top () { - return topNode; + if (topNode != rootNode) + return topNode; + else + return NULL; }; + inline DoctreeNode *parent (const DoctreeNode *node) { - return node->parent; + if (node->parent != rootNode) + return node->parent; + else + return NULL; + }; + + inline DoctreeNode *sibling (const DoctreeNode *node) { + return node->sibling; }; }; diff --git a/src/findbar.cc b/src/findbar.cc index 8cca52ba..47363db0 100644 --- a/src/findbar.cc +++ b/src/findbar.cc @@ -9,8 +9,8 @@ * (at your option) any later version. */ -#include <fltk/events.h> -#include <fltk/Window.h> +#include <FL/Fl.H> +#include <FL/Fl_Window.H> #include "findbar.hh" #include "msg.h" @@ -18,49 +18,58 @@ #include "uicmd.hh" #include "bw.h" -using namespace fltk; - /* * Local sub class * (Used to handle escape in the findbar, may also avoid some shortcuts). */ -class MyInput : public Input { +class MyInput : public Fl_Input { public: MyInput (int x, int y, int w, int h, const char* l=0) : - Input(x,y,w,h,l) {}; + Fl_Input(x,y,w,h,l) {}; int handle(int e); }; int MyInput::handle(int e) { _MSG("findbar MyInput::handle()\n"); - int ret = 1, k = event_key(); - unsigned modifier = event_state() & (SHIFT | CTRL | ALT | META); - - if (e == KEY) { - if (k == LeftKey || k == RightKey) { - if (modifier == SHIFT) { - a_UIcmd_send_event_to_tabs_by_wid(e, this); + int ret = 1, k = Fl::event_key(); + unsigned modifier = Fl::event_state() & (FL_SHIFT| FL_CTRL| FL_ALT|FL_META); + + if (e == FL_KEYBOARD) { + if (modifier == FL_SHIFT) { + if (k == FL_Left || k == FL_Right) { + // Let these keys get to the UI + return 0; + } + } else if (modifier == FL_CTRL) { + if (k == 'a' || k == 'e') { + position(k == 'a' ? 0 : size()); + return 1; + } else if (k == 'k') { + cut(position(), size()); + return 1; + } else if (k == 'd') { + cut(position(), position()+1); return 1; } - } else if (k == EscapeKey && modifier == 0) { + } else if (k == FL_Escape && modifier == 0) { // Avoid clearing the text with Esc, just hide the findbar. return 0; } } if (ret) - ret = Input::handle(e); + ret = Fl_Input::handle(e); return ret; }; /* * Find next occurrence of input key */ -void Findbar::search_cb(Widget *, void *vfb) +void Findbar::search_cb(Fl_Widget *, void *vfb) { Findbar *fb = (Findbar *)vfb; - const char *key = fb->i->text(); + const char *key = fb->i->value(); bool case_sens = fb->check_btn->value(); if (key[0] != '\0') @@ -71,10 +80,10 @@ void Findbar::search_cb(Widget *, void *vfb) /* * Find previous occurrence of input key */ -void Findbar::searchBackwards_cb(Widget *, void *vfb) +void Findbar::searchBackwards_cb(Fl_Widget *, void *vfb) { Findbar *fb = (Findbar *)vfb; - const char *key = fb->i->text(); + const char *key = fb->i->value(); bool case_sens = fb->check_btn->value(); if (key[0] != '\0') { @@ -84,86 +93,74 @@ void Findbar::searchBackwards_cb(Widget *, void *vfb) } /* - * Find next occurrence of input key - */ -void Findbar::search_cb2(Widget *widget, void *vfb) -{ - /* - * Somehow fltk even regards the first loss of focus for the - * window as a WHEN_ENTER_KEY_ALWAYS event. - */ - if (event_key() == ReturnKey) - search_cb(widget, vfb); -} - -/* * Hide the search bar */ -void Findbar::hide_cb(Widget *, void *vfb) +void Findbar::hide_cb(Fl_Widget *, void *vfb) { - ((Findbar *)vfb)->hide(); + a_UIcmd_findbar_toggle(a_UIcmd_get_bw_by_widget(vfb), 0); } /* * Construct text search bar */ Findbar::Findbar(int width, int height) : - Group(0, 0, width, height) + Fl_Group(0, 0, width, height) { int button_width = 70; int gap = 2; int border = 2; int input_width = width - (2 * border + 4 * (button_width + gap)); - int x = border; + int x = 0; + + Fl_Group::current(0); + height -= 2 * border; - box(PLASTIC_UP_BOX); - Group::hide(); + box(FL_THIN_UP_BOX); - begin(); - hide_btn = new HighlightButton(x, border, 16, height, 0); - hideImg = new xpmImage(new_s_xpm); + hide_btn = new Fl_Button(x, border, 16, height, 0); + hideImg = new Fl_Pixmap(new_s_xpm); hide_btn->image(hideImg); x += 16 + gap; hide_btn->callback(hide_cb, this); - hide_btn->clear_tab_to_focus(); + hide_btn->clear_visible_focus(); + hide_btn->box(FL_THIN_UP_BOX); + hide_btn->tooltip("Hide"); + add(hide_btn); i = new MyInput(x, border, input_width, height); x += input_width + gap; resizable(i); i->color(206); - i->when(WHEN_ENTER_KEY_ALWAYS); - i->callback(search_cb2, this); - i->clear_tab_to_focus(); - i->set_click_to_focus(); + i->when(FL_WHEN_NEVER); + add(i); - next_btn = new HighlightButton(x, border, button_width, height, "Next"); + next_btn = new Fl_Button(x, border, button_width, height, "Next"); x += button_width + gap; - next_btn->add_shortcut(ReturnKey); - next_btn->add_shortcut(KeypadEnter); + next_btn->shortcut(FL_Enter); next_btn->callback(search_cb, this); - next_btn->clear_tab_to_focus(); + next_btn->clear_visible_focus(); + next_btn->box(FL_THIN_UP_BOX); + next_btn->tooltip("Find next occurrence of the search phrase\n" + "shortcut: Enter"); + add(next_btn); - prev_btn= new HighlightButton(x, border, button_width, height, "Previous"); - prev_btn->add_shortcut(SHIFT+ReturnKey); - prev_btn->callback(searchBackwards_cb, this); - prev_btn->clear_tab_to_focus(); + prev_btn= new Fl_Button(x, border, button_width, height, "Previous"); x += button_width + gap; + prev_btn->shortcut(FL_SHIFT+FL_Enter); + prev_btn->callback(searchBackwards_cb, this); + prev_btn->clear_visible_focus(); + prev_btn->box(FL_THIN_UP_BOX); + prev_btn->tooltip("Find previous occurrence of the search phrase\n" + "shortcut: Shift+Enter"); + add(prev_btn); - check_btn = new CheckButton(x, border, 2*button_width, height, + check_btn = new Fl_Check_Button(x, border, 2*button_width, height, "Case-sensitive"); - check_btn->clear_tab_to_focus(); x += 2 * button_width + gap; + check_btn->clear_visible_focus(); + add(check_btn); - end(); - - if (prefs.show_tooltip) { - hide_btn->tooltip("Hide"); - next_btn->tooltip("Find next occurrence of the search phrase\n" - "shortcut: Enter"); - prev_btn->tooltip("Find previous occurrence of the search phrase\n" - "shortcut: Shift+Enter"); - } } Findbar::~Findbar() @@ -172,23 +169,19 @@ Findbar::~Findbar() } /* - * Handle events. Used to catch EscapeKey events. + * Handle events. Used to catch FL_Escape events. */ int Findbar::handle(int event) { - int ret = 0; - int k = event_key(); - unsigned modifier = event_state() & (SHIFT | CTRL | ALT | META); + int k = Fl::event_key(); + unsigned modifier = Fl::event_state() & (FL_SHIFT| FL_CTRL| FL_ALT|FL_META); - if (event == KEY && modifier == 0 && k == EscapeKey) { - hide(); - ret = 1; + if (event == FL_KEYBOARD && modifier == 0 && k == FL_Escape) { + /* let the UI handle it */ + return 0; } - if (ret == 0) - ret = Group::handle(event); - - return ret; + return Fl_Group::handle(event); } /* @@ -196,21 +189,14 @@ int Findbar::handle(int event) */ void Findbar::show() { - Group::show(); + BrowserWindow *bw = a_UIcmd_get_bw_by_widget(this); + dReturn_if (bw == NULL); + + // It takes more than just calling show() to do the trick + Fl_Group::show(); + /* select text even if already focused */ i->take_focus(); i->position(i->size(), 0); } -/* - * Hide the findbar and reset the search state - */ -void Findbar::hide() -{ - BrowserWindow *bw; - - Group::hide(); - if ((bw = a_UIcmd_get_bw_by_widget(this))) - a_UIcmd_findtext_reset(bw); - a_UIcmd_focus_main_area(bw); -} diff --git a/src/findbar.hh b/src/findbar.hh index ba7ed8ed..72d24c44 100644 --- a/src/findbar.hh +++ b/src/findbar.hh @@ -1,35 +1,32 @@ #ifndef __FINDBAR_HH__ #define __FINDBAR_HH__ -#include <fltk/xpmImage.h> -#include <fltk/Widget.h> -#include <fltk/HighlightButton.h> -#include <fltk/Button.h> -#include <fltk/Input.h> -#include <fltk/Group.h> -#include <fltk/CheckButton.h> +#include <FL/Fl_Pixmap.H> +#include <FL/Fl_Widget.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Input.H> +#include <FL/Fl_Group.H> +#include <FL/Fl_Check_Button.H> /* * Searchbar to find text in page. */ -class Findbar : public fltk::Group { - fltk::Button *clrb; - fltk::HighlightButton *hide_btn, *next_btn, *prev_btn; - fltk::CheckButton *check_btn; - fltk::xpmImage *hideImg; - fltk::Input *i; +class Findbar : public Fl_Group { + Fl_Button *clrb; + Fl_Button *hide_btn, *next_btn, *prev_btn; + Fl_Check_Button *check_btn; + Fl_Pixmap *hideImg; + Fl_Input *i; - static void search_cb (fltk::Widget *, void *); - static void searchBackwards_cb (fltk::Widget *, void *); - static void search_cb2 (fltk::Widget *, void *); - static void hide_cb (fltk::Widget *, void *); + static void search_cb (Fl_Widget *, void *); + static void searchBackwards_cb (Fl_Widget *, void *); + static void hide_cb (Fl_Widget *, void *); public: Findbar(int width, int height); ~Findbar(); int handle(int event); void show(); - void hide(); }; #endif // __FINDBAR_HH__ diff --git a/src/form.cc b/src/form.cc index 18441fb8..f70bea8c 100644 --- a/src/form.cc +++ b/src/form.cc @@ -249,7 +249,9 @@ static void Html_add_input(DilloHtml *html, DilloHtmlInputType type, html->inputs_outside_form->increase(); html->inputs_outside_form->set(ni, input); - input->setEnabled(false); + if (html->bw->NumPendingStyleSheets > 0) { + input->setEnabled(false); + } } } @@ -609,7 +611,6 @@ void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize) /* * The textarea tag - * (TODO: It doesn't support wrapping). */ void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize) { @@ -850,7 +851,10 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize) Embed *embed; char *name, *value; - page = new Textblock (prefs.limit_text_width); + /* We used to have Textblock (prefs.limit_text_width) here, + * but it caused 100% CPU usage. + */ + page = new Textblock (false); page->setStyle (html->styleEngine->backgroundStyle ()); ResourceFactory *factory = HT2LT(html)->getResourceFactory(); @@ -677,7 +677,7 @@ static int Gif_decode(DilloGif *gif, const uchar_t *buf, size_t bsize) case 2: /* End code... consume remaining data chunks..? */ goto error; /* Could clean up better? */ default: - printf("dillo_gif_decode: error!\n"); + MSG("Gif_decode: error!\n"); goto error; } } @@ -810,8 +810,6 @@ static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, return 0; } - gif->linebuf = dMalloc(gif->Width); - a_Dicache_set_parms(gif->url, gif->version, gif->Image, gif->Width, gif->Height, DILLO_IMG_TYPE_INDEXED); @@ -842,6 +840,7 @@ static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, gif->y = 0; Gif_lwz_init(gif); gif->spill_line_index = 0; + gif->linebuf = dMalloc(gif->Width); gif->state = 3; /*Process the lzw data next */ if (gif->Image && gif->ColorMap_ofs) { a_Dicache_set_cmap(gif->url, gif->version, gif->Image, diff --git a/src/html.cc b/src/html.cc index bcefe14b..98fe7b8b 100644 --- a/src/html.cc +++ b/src/html.cc @@ -652,7 +652,7 @@ bool_t DilloHtml::unloadedImages() */ void DilloHtml::loadImages (const DilloUrl *pattern) { - dReturn_if_fail (bw->nav_expecting == FALSE); + dReturn_if (a_Bw_expecting(bw)); /* If the user asked for a specific URL, the user (NULL) is the requester, * but if the user just asked for all URLs, use the page URL as the @@ -693,12 +693,10 @@ bool DilloHtml::HtmlLinkReceiver::enter (Widget *widget, int link, int img, if (link == -1) { _MSG(" Link LEAVE notify...\n"); a_UIcmd_set_msg(bw, ""); - a_UIcmd_set_pointer_on_link(bw, FALSE); } else { _MSG(" Link ENTER notify...\n"); Html_set_link_coordinates(html, link, x, y); a_UIcmd_set_msg(bw, "%s", URL_STR(html->links->get(link))); - a_UIcmd_set_pointer_on_link(bw, TRUE); } return true; } @@ -1723,7 +1721,6 @@ static void Html_tag_close_style(DilloHtml *html, int TagIdx) static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) { const char *attrbuf; - Textblock *textblock; int32_t color; int tag_index_a = a_Html_tag_index ("a"); style::Color *bgColor; @@ -1741,8 +1738,6 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) BUG_MSG("unclosed HEAD element\n"); } - textblock = HT2TB(html); - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { color = a_Html_color_parse(html, attrbuf, -1); if (color != -1) @@ -2148,8 +2143,7 @@ static bool Html_load_image(BrowserWindow *bw, DilloUrl *url, DilloWeb *Web; int ClientKey; /* Fill a Web structure for the cache query */ - Web = a_Web_new(url, requester); - Web->bw = bw; + Web = a_Web_new(bw, url, requester); Web->Image = Image; a_Image_ref(Image); Web->flags |= WEB_Image; @@ -2170,7 +2164,6 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) { DilloImage *Image; DilloUrl *url, *usemap_url; - Textblock *textblock; const char *attrbuf; /* This avoids loading images. Useful for viewing suspicious HTML email. */ @@ -2181,8 +2174,6 @@ static void Html_tag_open_img(DilloHtml *html, const char *tag, int tagsize) !(url = a_Html_url_new(html, attrbuf, NULL, 0))) return; - textblock = HT2TB(html); - usemap_url = NULL; if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "usemap"))) /* TODO: usemap URLs outside of the document are not used. */ @@ -2259,12 +2250,11 @@ static void Html_tag_close_map(DilloHtml *html, int TagIdx) static misc::SimpleVector<int> *Html_read_coords(DilloHtml *html, const char *str) { - int i, coord; + int coord; const char *tail = str; char *newtail = NULL; misc::SimpleVector<int> *coords = new misc::SimpleVector<int> (4); - i = 0; while (1) { coord = strtol(tail, &newtail, 10); if (coord == 0 && newtail == tail) @@ -2461,12 +2451,14 @@ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize) html->InVisitedLink = true; html->styleEngine->setPseudoVisited (); if (html->non_css_visited_color != -1) - html->styleEngine->setNonCssHint(CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, + html->styleEngine->setNonCssHint(CSS_PROPERTY_COLOR, + CSS_TYPE_COLOR, html->non_css_visited_color); } else { html->styleEngine->setPseudoLink (); if (html->non_css_link_color != -1) - html->styleEngine->setNonCssHint(CSS_PROPERTY_COLOR, CSS_TYPE_COLOR, + html->styleEngine->setNonCssHint(CSS_PROPERTY_COLOR, + CSS_TYPE_COLOR, html->non_css_link_color); } @@ -2744,9 +2736,11 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_LEFT_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, size_top); html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, size_bottom); + CSS_TYPE_LENGTH_PERCENTAGE, + size_bottom); html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_RIGHT_WIDTH, - CSS_TYPE_LENGTH_PERCENTAGE, size_bottom); + CSS_TYPE_LENGTH_PERCENTAGE, + size_bottom); } HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); @@ -2850,6 +2844,7 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) const char *p, *equiv, *content, *new_content; char delay_str[64], *mr_url; + DilloUrl *new_url; int delay; /* only valid inside HEAD */ @@ -2871,44 +2866,45 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) } /* Skip to anything after "URL=" */ while (*content && *(content++) != '=') ; - if (*content) { - - /* Handle the case of a quoted URL */ - if (*content == '"' || *content == '\'') { - if ((p = strchr(content + 1, *content))) - mr_url = dStrndup(content + 1, p - content - 1); - else - mr_url = dStrdup(content + 1); - } else { - mr_url = dStrdup(content); - } - - if (delay == 0) { - /* zero-delay redirection */ - html->stop_parser = true; - DilloUrl *new_url = a_Url_new(mr_url, URL_STR(html->base_url)); - if (a_Capi_dpi_verify_request(html->bw, new_url)) - a_UIcmd_redirection0((void*)html->bw, new_url); - a_Url_free(new_url); - } else { - /* Send a custom HTML message. - * TODO: This is a hairy hack, - * It'd be much better to build a widget. */ - Dstr *ds_msg = dStr_sized_new(256); - dStr_sprintf(ds_msg, meta_template, mr_url, delay_str); - { - int o_InFlags = html->InFlags; - int o_TagSoup = html->TagSoup; - html->InFlags = IN_BODY; - html->TagSoup = false; - Html_write_raw(html, ds_msg->str, ds_msg->len, 0); - html->TagSoup = o_TagSoup; - html->InFlags = o_InFlags; - } - dStr_free(ds_msg, 1); + /* Handle the case of a quoted URL */ + if (*content == '"' || *content == '\'') { + if ((p = strchr(content + 1, *content))) + mr_url = dStrndup(content + 1, p - content - 1); + else + mr_url = dStrdup(content + 1); + } else { + mr_url = dStrdup(content); + } + new_url = a_Url_new(mr_url, URL_STR(html->base_url)); + + if (a_Url_cmp(html->base_url, new_url) == 0) { + /* redirection loop, or empty url string: ignore */ + BUG_MSG("META refresh: %s\n", + *mr_url ? "redirection loop" : "no target URL"); + } else if (delay == 0) { + /* zero-delay redirection */ + html->stop_parser = true; + if (a_Capi_dpi_verify_request(html->bw, new_url)) + a_UIcmd_redirection0((void*)html->bw, new_url); + } else { + /* Send a custom HTML message. + * TODO: This is a hairy hack, + * It'd be much better to build a widget. */ + Dstr *ds_msg = dStr_sized_new(256); + dStr_sprintf(ds_msg, meta_template, mr_url, delay_str); + { + int o_InFlags = html->InFlags; + int o_TagSoup = html->TagSoup; + html->InFlags = IN_BODY; + html->TagSoup = false; + Html_write_raw(html, ds_msg->str, ds_msg->len, 0); + html->TagSoup = o_TagSoup; + html->InFlags = o_InFlags; } - dFree(mr_url); + dStr_free(ds_msg, 1); } + a_Url_free(new_url); + dFree(mr_url); } else if (!dStrcasecmp(equiv, "content-type") && (content = a_Html_get_attr(html, tag, tagsize, "content"))) { @@ -2958,14 +2954,13 @@ void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url) if (endq && (endq - data <= 51)) { /* IANA limits charset names to 40 characters */ - const char *ignored; char *content_type; *endq = '\0'; content_type = dStrconcat("text/css; charset=", data+10, NULL); *endq = '"'; a_Capi_unref_buf(url); - ignored = a_Capi_set_content_type(url, content_type, "meta"); + a_Capi_set_content_type(url, content_type, "meta"); dFree(content_type); a_Capi_get_buf(url, &data, &len); } @@ -2976,8 +2971,7 @@ void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url) } else { /* Fill a Web structure for the cache query */ int ClientKey; - DilloWeb *Web = a_Web_new(url, html->page_url); - Web->bw = html->bw; + DilloWeb *Web = a_Web_new(html->bw, url, html->page_url); if ((ClientKey = a_Capi_open_url(Web, Html_css_load_callback, NULL))) { ++html->bw->NumPendingStyleSheets; a_Bw_add_client(html->bw, ClientKey, 0); @@ -3031,7 +3025,7 @@ static void Html_tag_open_link(DilloHtml *html, const char *tag, int tagsize) !(url = a_Html_url_new(html, attrbuf, NULL, 0))) return; - MSG(" Html_tag_open_link(): addCssUrl %s\n", URL_STR(url)); + _MSG(" Html_tag_open_link(): addCssUrl %s\n", URL_STR(url)); html->addCssUrl(url); a_Url_free(url); diff --git a/src/keys.cc b/src/keys.cc index 1a39f4c8..bd78fd5f 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -9,7 +9,7 @@ * (at your option) any later version. */ -#include <fltk/events.h> +#include <FL/Fl.H> #include <stdio.h> #include <stdlib.h> /* strtol */ #include <string.h> @@ -17,6 +17,7 @@ #include "dlib/dlib.h" #include "keys.hh" +#include "utf8.hh" #include "msg.h" /* @@ -38,80 +39,99 @@ typedef struct { * Local data */ static const Mapping_t keyNames[] = { - { "Backspace", fltk::BackSpaceKey }, - { "Delete", fltk::DeleteKey }, - { "Down", fltk::DownKey }, - { "End", fltk::EndKey }, - { "Esc", fltk::EscapeKey }, - { "F1", fltk::F1Key }, - { "F2", fltk::F2Key }, - { "F3", fltk::F3Key }, - { "F4", fltk::F4Key }, - { "F5", fltk::F5Key }, - { "F6", fltk::F6Key }, - { "F7", fltk::F7Key }, - { "F8", fltk::F8Key }, - { "F9", fltk::F9Key }, - { "F10", fltk::F10Key }, - { "F11", fltk::F11Key }, - { "F12", fltk::F12Key }, - { "Home", fltk::HomeKey }, - { "Insert", fltk::InsertKey }, - { "Left", fltk::LeftKey }, - { "PageDown", fltk::PageDownKey }, - { "PageUp", fltk::PageUpKey }, - { "Print", fltk::PrintKey }, - { "Return", fltk::ReturnKey }, - { "Right", fltk::RightKey }, - { "Space", fltk::SpaceKey }, - { "Tab", fltk::TabKey }, - { "Up", fltk::UpKey } + { "Backspace", FL_BackSpace }, + { "Delete", FL_Delete }, + { "Down", FL_Down }, + { "End", FL_End }, + { "Esc", FL_Escape }, + { "F1", FL_F + 1 }, + { "F2", FL_F + 2 }, + { "F3", FL_F + 3 }, + { "F4", FL_F + 4 }, + { "F5", FL_F + 5 }, + { "F6", FL_F + 6 }, + { "F7", FL_F + 7 }, + { "F8", FL_F + 8 }, + { "F9", FL_F + 9 }, + { "F10", FL_F + 10 }, + { "F11", FL_F + 11 }, + { "F12", FL_F + 12 }, + { "Home", FL_Home }, + { "Insert", FL_Insert }, + { "Left", FL_Left }, + { "PageDown", FL_Page_Down }, + { "PageUp", FL_Page_Up }, + { "Print", FL_Print }, + { "Return", FL_Enter }, + { "Right", FL_Right }, + { "Space", ' ' }, + { "Tab", FL_Tab }, + { "Up", FL_Up }, + /* multimedia keys */ + { "Back", FL_Back }, + { "Favorites", FL_Favorites }, + { "Forward", FL_Forward }, + { "HomePage", FL_Home_Page }, + { "Mail", FL_Mail }, + { "MediaNext", FL_Media_Next }, + { "MediaPlay", FL_Media_Play }, + { "MediaPrev", FL_Media_Prev }, + { "MediaStop", FL_Media_Stop }, + { "Refresh", FL_Refresh }, + { "Search", FL_Search }, + { "Sleep", FL_Sleep }, + { "Stop", FL_Stop }, + { "VolumeDown", FL_Volume_Down }, + { "VolumeMute", FL_Volume_Mute }, + { "VolumeUp", FL_Volume_Up }, }; static const Mapping_t modifierNames[] = { - { "Shift", fltk::SHIFT }, - { "Ctrl", fltk::CTRL }, - { "Alt", fltk::ALT }, - { "Meta", fltk::META }, - { "Button1", fltk::BUTTON1 }, - { "Button2", fltk::BUTTON2 }, - { "Button3", fltk::BUTTON3 } + { "Shift", FL_SHIFT }, + { "Ctrl", FL_CTRL }, + { "Alt", FL_ALT }, + { "Meta", FL_META }, + { "Button1", FL_BUTTON1 }, + { "Button2", FL_BUTTON2 }, + { "Button3", FL_BUTTON3 } }; static const KeyBinding_t default_keys[] = { - { "nop" , KEYS_NOP , 0 , 0 }, - { "open" , KEYS_OPEN , fltk::CTRL , 'o' }, - { "new-window" , KEYS_NEW_WINDOW , fltk::CTRL , 'n' }, - { "new-tab" , KEYS_NEW_TAB , fltk::CTRL , 't' }, - { "left-tab" , KEYS_LEFT_TAB , fltk::SHIFT , fltk::TabKey }, - { "right-tab" , KEYS_RIGHT_TAB , fltk::CTRL , fltk::TabKey }, - { "close-tab" , KEYS_CLOSE_TAB , fltk::CTRL , 'q' }, - { "find" , KEYS_FIND , fltk::CTRL , 'f' }, - { "websearch" , KEYS_WEBSEARCH , fltk::CTRL , 's' }, - { "bookmarks" , KEYS_BOOKMARKS , fltk::CTRL , 'b' }, - { "fullscreen" , KEYS_FULLSCREEN , fltk::CTRL , fltk::SpaceKey }, - { "reload" , KEYS_RELOAD , fltk::CTRL , 'r' }, - { "stop" , KEYS_STOP , 0 , 0 }, - { "save" , KEYS_SAVE , 0 , 0 }, - { "hide-panels" , KEYS_HIDE_PANELS , 0 , fltk::EscapeKey }, - { "file-menu" , KEYS_FILE_MENU , fltk::ALT , 'f' }, - { "close-all" , KEYS_CLOSE_ALL , fltk::ALT , 'q' }, - { "back" , KEYS_BACK , 0 , fltk::BackSpaceKey }, - { "back" , KEYS_BACK , 0 , ',' }, - { "forward" , KEYS_FORWARD , fltk::SHIFT , fltk::BackSpaceKey }, - { "forward" , KEYS_FORWARD , 0 , '.' }, - { "goto" , KEYS_GOTO , fltk::CTRL , 'l' }, - { "home" , KEYS_HOME , fltk::CTRL , 'h' }, - { "screen-up" , KEYS_SCREEN_UP , 0 , fltk::PageUpKey }, - { "screen-up" , KEYS_SCREEN_UP , 0 , 'b' }, - { "screen-down" , KEYS_SCREEN_DOWN , 0 , fltk::PageDownKey }, - { "screen-down" , KEYS_SCREEN_DOWN , 0 , fltk::SpaceKey }, - { "line-up" , KEYS_LINE_UP , 0 , fltk::UpKey }, - { "line-down" , KEYS_LINE_DOWN , 0 , fltk::DownKey }, - { "left" , KEYS_LEFT , 0 , fltk::LeftKey }, - { "right" , KEYS_RIGHT , 0 , fltk::RightKey }, - { "top" , KEYS_TOP , 0 , fltk::HomeKey }, - { "bottom" , KEYS_BOTTOM , 0 , fltk::EndKey }, + { "nop" , KEYS_NOP , 0 , 0 }, + { "open" , KEYS_OPEN , FL_CTRL , 'o' }, + { "new-window" , KEYS_NEW_WINDOW , FL_CTRL , 'n' }, + { "new-tab" , KEYS_NEW_TAB , FL_CTRL , 't' }, + { "left-tab" , KEYS_LEFT_TAB , FL_CTRL | + FL_SHIFT , FL_Tab }, + { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Tab }, + { "close-tab" , KEYS_CLOSE_TAB , FL_CTRL , 'w' }, + { "find" , KEYS_FIND , FL_CTRL , 'f' }, + { "websearch" , KEYS_WEBSEARCH , FL_CTRL , 's' }, + { "bookmarks" , KEYS_BOOKMARKS , FL_CTRL , 'b' }, + { "reload" , KEYS_RELOAD , FL_CTRL , 'r' }, + { "stop" , KEYS_STOP , 0 , 0 }, + { "save" , KEYS_SAVE , 0 , 0 }, + { "hide-panels" , KEYS_HIDE_PANELS , 0 , FL_Escape }, + { "file-menu" , KEYS_FILE_MENU , FL_ALT , 'f' }, + { "close-all" , KEYS_CLOSE_ALL , FL_CTRL , 'q' }, + { "back" , KEYS_BACK , 0 , FL_BackSpace }, + { "back" , KEYS_BACK , 0 , ',' }, + { "forward" , KEYS_FORWARD , FL_SHIFT , FL_BackSpace }, + { "forward" , KEYS_FORWARD , 0 , '.' }, + { "goto" , KEYS_GOTO , FL_CTRL , 'l' }, + { "home" , KEYS_HOME , FL_CTRL , 'h' }, + { "screen-up" , KEYS_SCREEN_UP , 0 , FL_Page_Up }, + { "screen-up" , KEYS_SCREEN_UP , 0 , 'b' }, + { "screen-down" , KEYS_SCREEN_DOWN , 0 , FL_Page_Down }, + { "screen-down" , KEYS_SCREEN_DOWN , 0 , ' ' }, + { "screen-left" , KEYS_SCREEN_LEFT , 0 , 0 }, + { "screen-right" , KEYS_SCREEN_RIGHT , 0 , 0 }, + { "line-up" , KEYS_LINE_UP , 0 , FL_Up }, + { "line-down" , KEYS_LINE_DOWN , 0 , FL_Down }, + { "left" , KEYS_LEFT , 0 , FL_Left }, + { "right" , KEYS_RIGHT , 0 , FL_Right }, + { "top" , KEYS_TOP , 0 , FL_Home }, + { "bottom" , KEYS_BOTTOM , 0 , FL_End }, }; static Dlist *bindings; @@ -172,20 +192,25 @@ KeysCommand_t Keys::getKeyCmd() { KeysCommand_t ret = KEYS_NOP; KeyBinding_t keyNode; - // We're only interested in some flags - keyNode.modifier = fltk::event_state() & - (fltk::SHIFT | fltk::CTRL | fltk::ALT | fltk::META); - - if (keyNode.modifier == fltk::SHIFT && - ispunct(fltk::event_text()[0])) { - // Get key code for a shifted character - keyNode.key = fltk::event_text()[0]; - keyNode.modifier = 0; + + keyNode.modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL |FL_ALT|FL_META); + if (iscntrl(Fl::event_text()[0])) { + keyNode.key = Fl::event_key(); } else { - keyNode.key = fltk::event_key(); + const char *beyond = Fl::event_text() + Fl::event_length(); + keyNode.key = a_Utf8_decode(Fl::event_text(), beyond, NULL); + + /* BUG: The idea is to drop the modifiers if their use results in a + * different character (e.g., if shift-8 gives '*', drop the shift, + * but if ctrl-6 gives '6', keep the ctrl), but we have to compare a + * keysym with a Unicode codepoint, which only works for characters + * below U+0100 (those known to latin-1). + */ + if (keyNode.key != Fl::event_key()) + keyNode.modifier = 0; } - - _MSG("getKeyCmd: key=%d, mod=%d\n", keyNode.key, keyNode.modifier); + _MSG("getKeyCmd: evkey=0x%x evtext=\'%s\' key=0x%x, mod=0x%x\n", + Fl::event_key(), Fl::event_text(), keyNode.key, keyNode.modifier); void *data = dList_find_sorted(bindings, &keyNode, nodeByKeyCmp); if (data) ret = ((KeyBinding_t*)data)->cmd; @@ -311,8 +336,11 @@ void Keys::parseKey(char *key, char *commandName) // Get key code if (!key[1]) { keycode = *key; + } else if (a_Utf8_char_count(keystr, strlen(keystr)) == 1) { + const char *beyond = keystr + strlen(keystr); + keycode = a_Utf8_decode(keystr, beyond, NULL); } else if (key[0] == '0' && key[1] == 'x') { - /* keysym. For details on values reported, see fltk's fltk/events.h */ + /* keysym */ keycode = strtol(key, NULL, 0x10); } else if ((st = getKeyCode(keystr)) == -1) { MSG("Keys::parseKey unknown keyname: %s\n", keystr); diff --git a/src/keys.hh b/src/keys.hh index d234838c..d3a5d586 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -27,7 +27,6 @@ typedef enum { KEYS_FIND, KEYS_WEBSEARCH, KEYS_BOOKMARKS, - KEYS_FULLSCREEN, KEYS_RELOAD, KEYS_STOP, KEYS_SAVE, @@ -40,6 +39,8 @@ typedef enum { KEYS_HOME, KEYS_SCREEN_UP, KEYS_SCREEN_DOWN, + KEYS_SCREEN_LEFT, + KEYS_SCREEN_RIGHT, KEYS_LINE_UP, KEYS_LINE_DOWN, KEYS_LEFT, @@ -6,10 +6,16 @@ # The commented-out bindings below show the defaults built into Dillo. # # Modifiers recognized: "Shift", "Ctrl", "Alt", "Meta". +# (OS X: Use "Meta" for Command) +# # Key names recognized: "Backspace", "Delete", "Down", "End", "Esc", # "F1" through "F12", "Home", "Insert", "Left", "PageDown", "PageUp", # "Print", "Return", "Right", "Space", "Tab", "Up". # +# Multimedia keys: "Back", "Favorites", "Forward", "HomePage", "Mail", +# "MediaNext", "MediaPlay", "MediaPrev", "MediaStop", "Refresh", "Search", +# "Sleep", "Stop", "VolumeDown", "VolumeMute", VolumeUp". +# # If Dillo is running under X11, keys whose names are not recognized can # be specified using their keysym value in hexadecimal. Use xev to get # the keysym. Example rule: "0x1008ff27 = forward". @@ -27,14 +33,13 @@ # "close-tab" closes the current tab. # Note that this closes the browser window if there is only one tab. -#<ctrl>q = close-tab +#<ctrl>w = close-tab # "close-all" closes all tabs/windows and exits. -#<alt>q = close-all +#<ctrl>q = close-all # "left-tab" and "right-tab" switch to the left/right of the current tab. -# *** NOT HOOKED UP YET *** -# <shift>tab = left-tab +# <ctrl><shift>tab = left-tab # <ctrl>tab = right-tab # "back" and "forward" move back/forward through the browser history. @@ -52,7 +57,7 @@ # "find" lets you search for a text string on the current page. #<ctrl>f = find -# "hide-panels" hides the findbar. +# "hide-panels" hides the findbar if present, control panels if not. #esc = hide-panels # "websearch" lets you send a text string to the search engine that you @@ -62,9 +67,6 @@ # go to your "bookmarks". #<ctrl>b = bookmarks -# "fullscreen" hides/shows the panels at the top and bottom of a dillo window. -#<ctrl>space = fullscreen - # "file-menu" pops up the file menu. #<alt>f = file-menu @@ -87,6 +89,10 @@ #pagedown = screen-down #space = screen-down +#(screen-left has no default binding) + +#(screen-right has no default binding) + #up = line-up #down = line-down diff --git a/src/menu.cc b/src/menu.cc index d802bddb..658b89bc 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -11,11 +11,8 @@ // Functions/Methods for menus -#include <fltk/events.h> -#include <fltk/PopupMenu.h> -#include <fltk/Item.h> -#include <fltk/ToggleItem.h> -#include <fltk/Divider.h> +#include <FL/Fl.H> +#include <FL/Fl_Menu_Item.H> #include "lout/misc.hh" /* SimpleVector */ #include "msg.h" @@ -27,8 +24,6 @@ #include "keys.hh" #include "timeout.hh" -using namespace fltk; - /* * Local data */ @@ -38,54 +33,27 @@ using namespace fltk; static DilloUrl *popup_url = NULL; // Weak reference to the popup's bw static BrowserWindow *popup_bw = NULL; -// Where to place the filemenu popup +static void *popup_form = NULL; +// Where to place the popup static int popup_x, popup_y; // History popup direction (-1 = back, 1 = forward). static int history_direction = -1; // History popup, list of URL-indexes. static int *history_list = NULL; -/* - * Local sub class. - * Used to add the hint for history popup menus, and to remember - * the mouse button pressed over a menu item. - */ -class CustItem : public Item { - int EventButton; -public: - CustItem (const char* label) : Item(label) { EventButton = 0; }; - int button () { return EventButton; }; - void draw(); - int handle(int e) { - EventButton = event_button(); - return Item::handle(e); - } -}; - -/* - * This adds a call to a_UIcmd_set_msg() to show the URL in the status bar - * TODO: erase the URL on popup close. - */ -void CustItem::draw() { - const DilloUrl *url; - if (flags() & SELECTED) { - url = a_History_get_url(history_list[(VOIDP2INT(user_data()))-1]); - a_UIcmd_set_msg(popup_bw, "%s", URL_STR(url)); - } - Item::draw(); +//-------------------------------------------------------------------------- +static void Menu_nop_cb(Fl_Widget*, void*) +{ } - -//-------------------------------------------------------------------------- /* * Static function for File menu callbacks. */ -static void filemenu_cb(Widget *wid, void *data) +static void filemenu_cb(Fl_Widget*, void *data) { if (strcmp((char*)data, "nw") == 0) { - UI *ui = (UI*)popup_bw->ui; - a_UIcmd_browser_window_new(ui->w(), ui->h(), 0, popup_bw); + a_UIcmd_open_url_nw(popup_bw, NULL); } else if (strcmp((char*)data, "nt") == 0) { a_UIcmd_open_url_nt(popup_bw, NULL, 1); } else if (strcmp((char*)data, "of") == 0) { @@ -100,13 +68,13 @@ static void filemenu_cb(Widget *wid, void *data) } -static void Menu_copy_urlstr_cb(Widget *) +static void Menu_copy_urlstr_cb(Fl_Widget*, void*) { if (popup_url) a_UIcmd_copy_urlstr(popup_bw, URL_STR(popup_url)); } -static void Menu_link_cb(Widget*, void *user_data) +static void Menu_link_cb(Fl_Widget*, void *user_data) { DilloUrl *url = (DilloUrl *) user_data ; _MSG("Menu_link_cb: click! :-)\n"); @@ -118,7 +86,7 @@ static void Menu_link_cb(Widget*, void *user_data) /* * Open URL */ -static void Menu_open_url_cb(Widget* ) +static void Menu_open_url_cb(Fl_Widget*, void*) { _MSG("Open URL cb: click! :-)\n"); a_UIcmd_open_url(popup_bw, popup_url); @@ -127,7 +95,7 @@ static void Menu_open_url_cb(Widget* ) /* * Open URL in new window */ -static void Menu_open_url_nw_cb(Widget* ) +static void Menu_open_url_nw_cb(Fl_Widget*, void*) { _MSG("Open URL in new window cb: click! :-)\n"); a_UIcmd_open_url_nw(popup_bw, popup_url); @@ -136,17 +104,17 @@ static void Menu_open_url_nw_cb(Widget* ) /* * Open URL in new Tab */ -static void Menu_open_url_nt_cb(Widget* ) +static void Menu_open_url_nt_cb(Fl_Widget*, void*) { int focus = prefs.focus_new_tab ? 1 : 0; - if (event_state(SHIFT)) focus = !focus; + if (Fl::event_state(FL_SHIFT)) focus = !focus; a_UIcmd_open_url_nt(popup_bw, popup_url, focus); } /* * Add bookmark */ -static void Menu_add_bookmark_cb(Widget* ) +static void Menu_add_bookmark_cb(Fl_Widget*, void*) { a_UIcmd_add_bookmark(popup_bw, popup_url); } @@ -154,15 +122,15 @@ static void Menu_add_bookmark_cb(Widget* ) /* * Find text */ -static void Menu_find_text_cb(Widget* ) +static void Menu_find_text_cb(Fl_Widget*, void*) { - ((UI *)popup_bw->ui)->set_findbar_visibility(1); + ((UI *)popup_bw->ui)->findbar_toggle(1); } /* * Save link */ -static void Menu_save_link_cb(Widget* ) +static void Menu_save_link_cb(Fl_Widget*, void*) { a_UIcmd_save_link(popup_bw, popup_url); } @@ -170,7 +138,7 @@ static void Menu_save_link_cb(Widget* ) /* * Save current page */ -static void Menu_save_page_cb(Widget* ) +static void Menu_save_page_cb(Fl_Widget*, void*) { a_UIcmd_save(popup_bw); } @@ -178,7 +146,7 @@ static void Menu_save_page_cb(Widget* ) /* * View current page source */ -static void Menu_view_page_source_cb(Widget* ) +static void Menu_view_page_source_cb(Fl_Widget*, void*) { a_UIcmd_view_page_source(popup_bw, popup_url); } @@ -186,7 +154,7 @@ static void Menu_view_page_source_cb(Widget* ) /* * View current page's bugs */ -static void Menu_view_page_bugs_cb(Widget* ) +static void Menu_view_page_bugs_cb(Fl_Widget*, void*) { a_UIcmd_view_page_bugs(popup_bw); } @@ -194,7 +162,7 @@ static void Menu_view_page_bugs_cb(Widget* ) /* * Load images on current page that match URL pattern */ -static void Menu_load_images_cb(Widget*, void *user_data) +static void Menu_load_images_cb(Fl_Widget*, void *user_data) { DilloUrl *page_url = (DilloUrl *) user_data; void *doc = a_Bw_get_url_doc(popup_bw, page_url); @@ -206,39 +174,38 @@ static void Menu_load_images_cb(Widget*, void *user_data) /* * Submit form */ -static void Menu_form_submit_cb(Widget*, void *v_form) +static void Menu_form_submit_cb(Fl_Widget*, void*) { void *doc = a_Bw_get_url_doc(popup_bw, popup_url); if (doc) - a_Html_form_submit(doc, v_form); + a_Html_form_submit(doc, popup_form); } /* * Reset form */ -static void Menu_form_reset_cb(Widget*, void *v_form) +static void Menu_form_reset_cb(Fl_Widget*, void*) { void *doc = a_Bw_get_url_doc(popup_bw, popup_url); if (doc) - a_Html_form_reset(doc, v_form); + a_Html_form_reset(doc, popup_form); } /* * Toggle display of 'hidden' form controls. */ -static void Menu_form_hiddens_cb(Widget *w, void *user_data) +static void Menu_form_hiddens_cb(Fl_Widget*, void *user_data) { - void *v_form = w->parent()->user_data(); bool visible = *((bool *) user_data); void *doc = a_Bw_get_url_doc(popup_bw, popup_url); if (doc) - a_Html_form_display_hiddens(doc, v_form, !visible); + a_Html_form_display_hiddens(doc, popup_form, !visible); } -static void Menu_stylesheet_cb(Widget *w, void *vUrl) +static void Menu_stylesheet_cb(Fl_Widget*, void *vUrl) { const DilloUrl *url = (const DilloUrl *) vUrl; a_UIcmd_open_url(popup_bw, url); @@ -247,7 +214,7 @@ static void Menu_stylesheet_cb(Widget *w, void *vUrl) /* * Validate URL with the W3C */ -static void Menu_bugmeter_validate_w3c_cb(Widget* ) +static void Menu_bugmeter_validate_w3c_cb(Fl_Widget*, void*) { Dstr *dstr = dStr_sized_new(128); @@ -260,7 +227,7 @@ static void Menu_bugmeter_validate_w3c_cb(Widget* ) /* * Validate URL with the WDG */ -static void Menu_bugmeter_validate_wdg_cb(Widget* ) +static void Menu_bugmeter_validate_wdg_cb(Fl_Widget*, void*) { Dstr *dstr = dStr_sized_new(128); @@ -274,7 +241,7 @@ static void Menu_bugmeter_validate_wdg_cb(Widget* ) /* * Show info page for the bug meter */ -static void Menu_bugmeter_about_cb(Widget* ) +static void Menu_bugmeter_about_cb(Fl_Widget*, void*) { a_UIcmd_open_urlstr(popup_bw, "http://www.dillo.org/help/bug_meter.html"); } @@ -283,23 +250,23 @@ static void Menu_bugmeter_about_cb(Widget* ) * Navigation History callback. * Go to selected URL. */ -static void Menu_history_cb(Widget *wid, void *data) +static void Menu_history_cb(Fl_Widget*, void *data) { - int mb = ((CustItem*)wid)->button(); + int mb = Fl::event_button(); int offset = history_direction * VOIDP2INT(data); const DilloUrl *url = a_History_get_url(history_list[VOIDP2INT(data)-1]); - if (mb == 2) { + if (mb == 1) { + a_UIcmd_nav_jump(popup_bw, offset, 0); + } else if (mb == 2) { // Middle button, open in a new window/tab if (prefs.middle_click_opens_new_tab) { int focus = prefs.focus_new_tab ? 1 : 0; - if (event_state(SHIFT)) focus = !focus; + if (Fl::event_state(FL_SHIFT)) focus = !focus; a_UIcmd_open_url_nt(popup_bw, url, focus); } else { a_UIcmd_open_url_nw(popup_bw, url); } - } else { - a_UIcmd_nav_jump(popup_bw, offset, 0); } } @@ -311,18 +278,10 @@ static void Menu_history_cb(Widget *wid, void *data) */ static void Menu_popup_cb(void *data) { - ((PopupMenu *)data)->popup(); - a_Timeout_remove(); -} + const Fl_Menu_Item *m = ((Fl_Menu_Item *)data)->popup(popup_x, popup_y); -/* - * Same as above but with coordinates. - */ -static void Menu_popup_cb2(void *data) -{ - Menu *m = (Menu *)data; - m->value(-1); - m->popup(Rectangle(popup_x,popup_y,m->w(),m->h()), m->label()); + if (m && m->callback()) + m->do_callback((Fl_Widget *)data); a_Timeout_remove(); } @@ -334,65 +293,49 @@ void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url, { lout::misc::SimpleVector <DilloUrl*> *cssUrls = (lout::misc::SimpleVector <DilloUrl*> *) v_cssUrls; - Item *i; - int j; - // One menu for every browser window - static PopupMenu *pm = 0; - // Active/inactive control. - static Item *view_page_bugs_item = 0, *view_source_item = 0; - static ItemGroup *stylesheets = 0; - + int j = 0; + + static Fl_Menu_Item *stylesheets = NULL; + static Fl_Menu_Item pm[] = { + {"View page source", 0, Menu_view_page_source_cb,0,0,0,0,0,0}, + {"View page bugs", 0, Menu_view_page_bugs_cb,0,0,0,0,0,0}, + {"View stylesheets", 0, Menu_nop_cb,0,FL_SUBMENU_POINTER|FL_MENU_DIVIDER, + 0,0,0,0}, + {"Bookmark this page", 0,Menu_add_bookmark_cb,0,FL_MENU_DIVIDER,0,0,0,0}, + {"Find text", 0, Menu_find_text_cb,0,0,0,0,0,0}, + {"Save page as...", 0, Menu_save_page_cb,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; + + popup_x = Fl::event_x(); + popup_y = Fl::event_y(); popup_bw = bw; a_Url_free(popup_url); popup_url = a_Url_dup(url); - if (!pm) { - pm = new PopupMenu(0,0,0,0,"&PAGE OPTIONS"); - pm->begin(); - i = view_source_item = new Item("View page Source"); - i->callback(Menu_view_page_source_cb); - i = view_page_bugs_item = new Item("View page Bugs"); - i->callback(Menu_view_page_bugs_cb); - stylesheets = new ItemGroup("View Stylesheets"); - new Divider(); - i = new Item("Bookmark this page"); - i->callback(Menu_add_bookmark_cb); - new Divider(); - i = new Item("Find Text"); - i->callback(Menu_find_text_cb); - //i->shortcut(CTRL+'f'); - i = new Item("Jump to..."); - i->deactivate(); - new Divider(); - i = new Item("Save page As..."); - i->callback(Menu_save_page_cb); - - pm->type(PopupMenu::POPUP123); - pm->end(); - } - - if (has_bugs == TRUE) - view_page_bugs_item->activate(); - else - view_page_bugs_item->deactivate(); + has_bugs == TRUE ? pm[1].activate() : pm[1].deactivate(); if (strncmp(URL_STR(url), "dpi:/vsource/", 13) == 0) - view_source_item->deactivate(); + pm[0].deactivate(); else - view_source_item->activate(); - - int n = stylesheets->children(); - for (j = 0; j < n; j++) { - /* get rid of the old ones */ - Widget *child = stylesheets->child(0); - dFree((char *)child->label()); - a_Url_free((DilloUrl *)child->user_data()); - delete child; + pm[0].activate(); + + if (stylesheets) { + while (stylesheets[j].text) { + dFree((char *) stylesheets[j].label()); + a_Url_free((DilloUrl *) stylesheets[j].user_data()); + j++; + } + delete [] stylesheets; + stylesheets = NULL; } if (cssUrls && cssUrls->size () > 0) { - stylesheets->activate(); + stylesheets = new Fl_Menu_Item[cssUrls->size() + 1]; + memset(stylesheets, '\0', sizeof(Fl_Menu_Item[cssUrls->size() + 1])); + for (j = 0; j < cssUrls->size(); j++) { + /* may want ability to Load individual unloaded stylesheets as well */ const char *action = "View "; DilloUrl *url = cssUrls->get(j); @@ -411,17 +354,17 @@ void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url, label = dStrconcat(action, url_str, NULL); } - i = new Item(label); - i->set_flag(RAW_LABEL); - i->user_data(a_Url_dup(url)); - i->callback(Menu_stylesheet_cb); - stylesheets->add(i); + stylesheets[j].label(FL_NORMAL_LABEL, label); + stylesheets[j].callback(Menu_stylesheet_cb, a_Url_dup(url)); } + + pm[2].user_data(stylesheets); + pm[2].activate(); } else { - stylesheets->deactivate(); + pm[2].deactivate(); } - a_Timeout_add(0.0, Menu_popup_cb, (void *)pm); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -429,35 +372,23 @@ void a_Menu_page_popup(BrowserWindow *bw, const DilloUrl *url, */ void a_Menu_link_popup(BrowserWindow *bw, const DilloUrl *url) { - // One menu for every browser window - static PopupMenu *pm = 0; - + static Fl_Menu_Item pm[] = { + {"Open link in new tab", 0, Menu_open_url_nt_cb,0,0,0,0,0,0}, + {"Open link in new window", 0, Menu_open_url_nw_cb,0,FL_MENU_DIVIDER,0,0, + 0,0}, + {"Bookmark this link", 0, Menu_add_bookmark_cb,0,0,0,0,0,0}, + {"Copy link location", 0, Menu_copy_urlstr_cb,0,FL_MENU_DIVIDER,0,0,0,0}, + {"Save link as...", 0, Menu_save_link_cb,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; + + popup_x = Fl::event_x(); + popup_y = Fl::event_y(); popup_bw = bw; a_Url_free(popup_url); popup_url = a_Url_dup(url); - if (!pm) { - Item *i; - pm = new PopupMenu(0,0,0,0,"&LINK OPTIONS"); - //pm->callback(Menu_link_cb, url); - pm->begin(); - i = new Item("Open Link in New Window"); - i->callback(Menu_open_url_nw_cb); - i = new Item("Open Link in New Tab"); - i->callback(Menu_open_url_nt_cb); - new Divider(); - i = new Item("Bookmark this Link"); - i->callback(Menu_add_bookmark_cb); - i = new Item("Copy Link location"); - i->callback(Menu_copy_urlstr_cb); - new Divider(); - i = new Item("Save Link As..."); - i->callback(Menu_save_link_cb); - - pm->type(PopupMenu::POPUP123); - pm->end(); - } - a_Timeout_add(0.0, Menu_popup_cb, (void *)pm); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -467,14 +398,23 @@ void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url, bool_t loaded_img, DilloUrl *page_url, DilloUrl *link_url) { - // One menu for every browser window - static PopupMenu *pm = 0; - // Active/inactive control. - static Item *link_menuitem = 0; - static Item *load_img_menuitem = 0; static DilloUrl *popup_page_url = NULL; static DilloUrl *popup_link_url = NULL; - + static Fl_Menu_Item pm[] = { + {"Isolate image", 0, Menu_open_url_cb,0,0,0,0,0,0}, + {"Open image in new tab", 0, Menu_open_url_nt_cb,0,0,0,0,0,0}, + {"Open image in new window", 0, Menu_open_url_nw_cb, 0, FL_MENU_DIVIDER, + 0,0,0,0}, + {"Load image", 0, Menu_load_images_cb,0,0,0,0,0,0}, + {"Bookmark this image", 0, Menu_add_bookmark_cb,0,0,0,0,0,0}, + {"Copy image location", 0,Menu_copy_urlstr_cb,0,FL_MENU_DIVIDER,0,0,0,0}, + {"Save image as...", 0, Menu_save_link_cb, 0, FL_MENU_DIVIDER,0,0,0,0}, + {"Link menu", 0, Menu_link_cb,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; + + popup_x = Fl::event_x(); + popup_y = Fl::event_y(); popup_bw = bw; a_Url_free(popup_url); popup_url = a_Url_dup(url); @@ -483,49 +423,22 @@ void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url, a_Url_free(popup_link_url); popup_link_url = a_Url_dup(link_url); - if (!pm) { - Item *i; - pm = new PopupMenu(0,0,0,0,"&IMAGE OPTIONS"); - pm->begin(); - i = new Item("Isolate Image"); - i->callback(Menu_open_url_cb); - i = new Item("Open Image in New Window"); - i->callback(Menu_open_url_nw_cb); - i = new Item("Open Image in New Tab"); - i->callback(Menu_open_url_nt_cb); - new Divider(); - i = load_img_menuitem = new Item("Load image"); - i->callback(Menu_load_images_cb); - i = new Item("Bookmark this Image"); - i->callback(Menu_add_bookmark_cb); - i = new Item("Copy Image location"); - i->callback(Menu_copy_urlstr_cb); - new Divider(); - i = new Item("Save Image As..."); - i->callback(Menu_save_link_cb); - new Divider(); - i = link_menuitem = new Item("Link menu"); - i->callback(Menu_link_cb); - - pm->type(PopupMenu::POPUP123); - pm->end(); - } if (loaded_img) { - load_img_menuitem->deactivate(); + pm[3].deactivate(); } else { - load_img_menuitem->activate(); - load_img_menuitem->user_data(popup_page_url); + pm[3].activate(); + pm[3].user_data(popup_page_url); } if (link_url) { - link_menuitem->user_data(popup_link_url); - link_menuitem->activate(); + pm[7].activate(); + pm[7].user_data(popup_link_url); } else { - link_menuitem->deactivate(); + pm[7].deactivate(); } - a_Timeout_add(0.0, Menu_popup_cb, (void *)pm); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -534,31 +447,25 @@ void a_Menu_image_popup(BrowserWindow *bw, const DilloUrl *url, void a_Menu_form_popup(BrowserWindow *bw, const DilloUrl *page_url, void *formptr, bool_t hidvis) { - static PopupMenu *pm = 0; - static Item *hiddens_item = 0; static bool hiddens_visible; - + static Fl_Menu_Item pm[] = { + {"Submit form", 0, Menu_form_submit_cb,0,0,0,0,0,0}, + {"Reset form", 0, Menu_form_reset_cb,0,0,0,0,0,0}, + {0, 0, Menu_form_hiddens_cb, &hiddens_visible, 0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; + + popup_x = Fl::event_x(); + popup_y = Fl::event_y(); popup_bw = bw; a_Url_free(popup_url); popup_url = a_Url_dup(page_url); - if (!pm) { - Item *i; - pm = new PopupMenu(0,0,0,0,"FORM OPTIONS"); - pm->add(i = new Item("Submit form")); - i->callback(Menu_form_submit_cb); - pm->add(i = new Item("Reset form")); - i->callback(Menu_form_reset_cb); - pm->add(hiddens_item = new Item("")); - hiddens_item->callback(Menu_form_hiddens_cb); - hiddens_item->user_data(&hiddens_visible); - pm->type(PopupMenu::POPUP123); - } - pm->user_data(formptr); + popup_form = formptr; hiddens_visible = hidvis; - hiddens_item->label(hiddens_visible ? "Hide hiddens": "Show hiddens"); + pm[2].label(hiddens_visible ? "Hide hiddens": "Show hiddens"); - a_Timeout_add(0.0, Menu_popup_cb, (void *)pm); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -566,44 +473,32 @@ void a_Menu_form_popup(BrowserWindow *bw, const DilloUrl *page_url, */ void a_Menu_file_popup(BrowserWindow *bw, void *v_wid) { - UI *ui = (UI *)bw->ui; - Widget *wid = (Widget*)v_wid; - // One menu for every browser window - static PopupMenu *pm = 0; + Fl_Widget *wid = (Fl_Widget*)v_wid; + + static Fl_Menu_Item pm[] = { + {"New tab", Keys::getShortcut(KEYS_NEW_TAB), filemenu_cb, + (void*)"nt",0,0,0,0,0}, + {"New window", Keys::getShortcut(KEYS_NEW_WINDOW), filemenu_cb, + (void*)"nw", FL_MENU_DIVIDER,0,0,0,0}, + {"Open file...", Keys::getShortcut(KEYS_OPEN), filemenu_cb, + (void*)"of",0,0,0,0,0}, + {"Open URL...", Keys::getShortcut(KEYS_GOTO), filemenu_cb, + (void*)"ou",0,0,0,0,0}, + {"Close", Keys::getShortcut(KEYS_CLOSE_TAB), filemenu_cb, + (void*)"cw", FL_MENU_DIVIDER,0,0,0,0}, + {"Exit Dillo", Keys::getShortcut(KEYS_CLOSE_ALL), filemenu_cb, + (void*)"ed",0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; popup_bw = bw; popup_x = wid->x(); - popup_y = wid->y() + wid->h() + - // WORKAROUND: ?? wid->y() doesn't count tabs ?? - (((Group*)ui->tabs())->children() > 1 ? 20 : 0); + popup_y = wid->y() + wid->h(); a_Url_free(popup_url); popup_url = NULL; - if (!pm) { - int shortcut; - Item *i; - pm = new PopupMenu(0,0,0,0,"File"); - pm->begin(); - shortcut = Keys::getShortcut(KEYS_NEW_WINDOW); - i = new Item("New Window", shortcut, filemenu_cb, (void*)"nw"); - shortcut = Keys::getShortcut(KEYS_NEW_TAB); - i = new Item("New Tab", shortcut, filemenu_cb, (void*)"nt"); - new Divider(); - shortcut = Keys::getShortcut(KEYS_OPEN); - i = new Item("Open File...", shortcut, filemenu_cb, (void*)"of"); - shortcut = Keys::getShortcut(KEYS_GOTO); - i = new Item("Open URL...", shortcut, filemenu_cb, (void*)"ou"); - shortcut = Keys::getShortcut(KEYS_CLOSE_TAB); - i = new Item("Close", shortcut, filemenu_cb, (void*)"cw"); - new Divider(); - shortcut = Keys::getShortcut(KEYS_CLOSE_ALL); - i = new Item("Exit Dillo", shortcut, filemenu_cb, (void*)"ed"); - pm->type(PopupMenu::POPUP123); - pm->end(); - } - - pm->label(wid->visible() ? NULL : "File"); - a_Timeout_add(0.0, Menu_popup_cb2, (void *)pm); + //pm->label(wid->visible() ? NULL : "File"); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -611,28 +506,21 @@ void a_Menu_file_popup(BrowserWindow *bw, void *v_wid) */ void a_Menu_bugmeter_popup(BrowserWindow *bw, const DilloUrl *url) { - // One menu for every browser window - static PopupMenu *pm = 0; + static Fl_Menu_Item pm[] = { + {"Validate URL with W3C", 0, Menu_bugmeter_validate_w3c_cb,0,0,0,0,0,0}, + {"Validate URL with WDG", 0, Menu_bugmeter_validate_wdg_cb, 0, + FL_MENU_DIVIDER,0,0,0,0}, + {"About bug meter", 0, Menu_bugmeter_about_cb,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; + popup_x = Fl::event_x(); + popup_y = Fl::event_y(); popup_bw = bw; a_Url_free(popup_url); popup_url = a_Url_dup(url); - if (!pm) { - Item *i; - pm = new PopupMenu(0,0,0,0,"&BUG METER OPTIONS"); - pm->begin(); - i = new Item("Validate URL with W3C"); - i->callback(Menu_bugmeter_validate_w3c_cb); - i = new Item("Validate URL with WDG"); - i->callback(Menu_bugmeter_validate_wdg_cb); - new Divider(); - i = new Item("About Bug Meter..."); - i->callback(Menu_bugmeter_about_cb); - pm->type(PopupMenu::POPUP123); - pm->end(); - } - pm->popup(); + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* @@ -640,67 +528,82 @@ void a_Menu_bugmeter_popup(BrowserWindow *bw, const DilloUrl *url) * * direction: {backward = -1, forward = 1} */ -void a_Menu_history_popup(BrowserWindow *bw, int direction) +void a_Menu_history_popup(BrowserWindow *bw, int x, int y, int direction) { - static PopupMenu *pm = 0; - Item *it; - int i; + static Fl_Menu_Item *pm = 0; + int i, n; popup_bw = bw; + popup_x = x; + popup_y = y; history_direction = direction; // TODO: hook popdown event with delete or similar. if (pm) - delete(pm); + delete [] pm; if (history_list) dFree(history_list); - if (direction == -1) { - pm = new PopupMenu(0,0,0,0, "&PREVIOUS PAGES"); - } else { - pm = new PopupMenu(0,0,0,0, "&FOLLOWING PAGES"); - } - // Get a list of URLs for this popup history_list = a_UIcmd_get_history(bw, direction); - pm->begin(); - for (i = 0; history_list[i] != -1; i += 1) { - // TODO: restrict title size - it = new CustItem(a_History_get_title(history_list[i], 1)); - it->callback(Menu_history_cb, INT2VOIDP(i+1)); - } - pm->type(PopupMenu::POPUP123); - pm->end(); + for (n = 0; history_list[n] != -1; n++) + ; - pm->popup(); + pm = new Fl_Menu_Item[n + 1]; + memset(pm, '\0', sizeof(Fl_Menu_Item[n + 1])); + + for (i = 0; i < n; i++) { + pm[i].label(FL_NORMAL_LABEL, a_History_get_title(history_list[i], 1)); + pm[i].callback(Menu_history_cb, INT2VOIDP(i+1)); + } + a_Timeout_add(0.0, Menu_popup_cb, (void*)pm); } /* * Toggle use of remote stylesheets */ -static void Menu_remote_css_cb(Widget *wid) +static void Menu_remote_css_cb(Fl_Widget *wid, void*) { - _MSG("Menu_remote_css_cb\n"); - prefs.load_stylesheets = wid->state() ? 1 : 0; + Fl_Menu_Item *item = (Fl_Menu_Item*) wid; + + item->flags ^= FL_MENU_VALUE; + prefs.load_stylesheets = item->flags & FL_MENU_VALUE ? 1 : 0; a_UIcmd_repush(popup_bw); } /* * Toggle use of embedded CSS style */ -static void Menu_embedded_css_cb(Widget *wid) +static void Menu_embedded_css_cb(Fl_Widget *wid, void*) { - prefs.parse_embedded_css = wid->state() ? 1 : 0; + Fl_Menu_Item *item = (Fl_Menu_Item*) wid; + + item->flags ^= FL_MENU_VALUE; + prefs.parse_embedded_css = item->flags & FL_MENU_VALUE ? 1 : 0; a_UIcmd_repush(popup_bw); } +static void Menu_panel_change_cb(Fl_Widget*, void *user_data) +{ + UI *ui = (UI*)popup_bw->ui; + + if (VOIDP2INT(user_data) == 10) /* small icons */ + ui->change_panel(ui->get_panelsize(), !ui->get_smallicons()); + else + ui->change_panel(VOIDP2INT(user_data), ui->get_smallicons()); +} + /* * Toggle loading of images -- and load them if enabling. */ -static void Menu_imgload_toggle_cb(Widget *wid) +static void Menu_imgload_toggle_cb(Fl_Widget *wid, void*) { - if ((prefs.load_images = wid->state() ? 1 : 0)) { + Fl_Menu_Item *item = (Fl_Menu_Item*) wid; + + item->flags ^= FL_MENU_VALUE; + + if ((prefs.load_images = item->flags & FL_MENU_VALUE ? 1 : 0)) { void *doc = a_Bw_get_current_doc(popup_bw); if (doc) { @@ -713,33 +616,44 @@ static void Menu_imgload_toggle_cb(Widget *wid) /* * Tools popup menu (construction & popup) */ -void a_Menu_tools_popup(BrowserWindow *bw, void *v_wid) -{ - // One menu shared by every browser window - static PopupMenu *pm = NULL; - Widget *wid = (Widget*)v_wid; - Item *it; +void a_Menu_tools_popup(BrowserWindow *bw, int x, int y) +{ + const Fl_Menu_Item *item; + UI *ui = (UI*)bw->ui; + + static Fl_Menu_Item pm[] = { + {"Use remote CSS", 0, Menu_remote_css_cb, 0, FL_MENU_TOGGLE,0,0,0,0}, + {"Use embedded CSS", 0, Menu_embedded_css_cb, 0, + FL_MENU_TOGGLE|FL_MENU_DIVIDER,0,0,0,0}, + {"Load images", 0, Menu_imgload_toggle_cb, 0, + FL_MENU_TOGGLE|FL_MENU_DIVIDER,0,0,0,0}, + {"Panel size", 0, Menu_nop_cb, (void*)"Submenu1", FL_SUBMENU,0,0,0,0}, + {"tiny", 0,Menu_panel_change_cb,(void*)0,FL_MENU_RADIO,0,0,0,0}, + {"small", 0,Menu_panel_change_cb,(void*)1,FL_MENU_RADIO,0,0,0,0}, + {"medium",0,Menu_panel_change_cb,(void*)2, + FL_MENU_RADIO|FL_MENU_DIVIDER,0,0,0,0}, + {"small icons", 0,Menu_panel_change_cb,(void*)10, + FL_MENU_TOGGLE,0,0,0,0}, + {0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0} + }; popup_bw = bw; - - if (!pm) { - pm = new PopupMenu(0,0,0,0, "TOOLS"); - pm->begin(); - it = new ToggleItem("Use remote CSS"); - it->callback(Menu_remote_css_cb); - it->state(prefs.load_stylesheets); - it = new ToggleItem("Use embedded CSS"); - it->callback(Menu_embedded_css_cb); - it->state(prefs.parse_embedded_css); - new Divider(); - it = new ToggleItem("Load images"); - it->callback(Menu_imgload_toggle_cb); - it->state(prefs.load_images); - pm->type(PopupMenu::POPUP13); - pm->end(); + int cur_panelsize = ui->get_panelsize(); + int cur_smallicons = ui->get_smallicons(); + + if (prefs.load_stylesheets) + pm[0].set(); + if (prefs.parse_embedded_css) + pm[1].set(); + if (prefs.load_images) + pm[2].set(); + pm[4+cur_panelsize].setonly(); + cur_smallicons ? pm[7].set() : pm[7].clear(); + + item = pm->popup(x, y); + if (item) { + ((Fl_Widget *)item)->do_callback(); } - //pm->popup(); - pm->value(-1); - ((Menu*)pm)->popup(Rectangle(0,wid->h(),pm->w(),pm->h())); } diff --git a/src/menu.hh b/src/menu.hh index 668de001..a8170e89 100644 --- a/src/menu.hh +++ b/src/menu.hh @@ -17,8 +17,8 @@ void a_Menu_form_popup(BrowserWindow *bw, const DilloUrl *page_url, void *vform, bool_t showing_hiddens); void a_Menu_file_popup(BrowserWindow *bw, void *v_wid); void a_Menu_bugmeter_popup(BrowserWindow *bw, const DilloUrl *url); -void a_Menu_history_popup(BrowserWindow *bw, int direction); -void a_Menu_tools_popup(BrowserWindow *bw, void *v_wid); +void a_Menu_history_popup(BrowserWindow *bw, int x, int y, int direction); +void a_Menu_tools_popup(BrowserWindow *bw, int x, int y); #ifdef __cplusplus @@ -383,6 +383,40 @@ int a_Misc_parse_geometry(char *str, int *x, int *y, int *w, int *h) } /* + * Parse dillorc's search_url string ("[<label> ]<url>") + * Return value: -1 on error, 0 on success (and label and urlstr pointers) + */ +int a_Misc_parse_search_url(char *source, char **label, char **urlstr) +{ + static char buf[32]; + char *p, *q; + int ret = -1; + + if ((p = strrchr(source, ' '))) { + /* label and url pair */ + strncpy(buf,source,MIN(p-source,31)); + buf[MIN(p-source,31)] = 0; + source = p+1; + if ((p = strchr(source, '/')) && p[1] && (q = strchr(p+2,'/'))) { + *urlstr = source; + ret = 0; + } + } else { + /* url only, make a custom label */ + if ((p = strchr(source, '/')) && p[1] && (q = strchr(p+2,'/'))) { + strncpy(buf,p+2,MIN(q-p-2,31)); + buf[MIN(q-p-2,31)] = 0; + *urlstr = source; + ret = 0; + } + } + *label = buf; + if (ret == -1) + MSG("Invalid search_url: \"%s\"\n", source); + return ret; +} + +/* * Encodes string using base64 encoding. * Return value: new string or NULL if input string is empty. */ @@ -17,6 +17,7 @@ void a_Misc_parse_content_type(const char *str, char **major, char **minor, char **charset); int a_Misc_content_type_cmp(const char* ct1, const char *ct2); int a_Misc_parse_geometry(char *geom, int *x, int *y, int *w, int *h); +int a_Misc_parse_search_url(char *source, char **label, char **urlstr); char *a_Misc_encode_base64(const char *in); Dstr *a_Misc_file2dstr(const char *filename); @@ -195,13 +195,12 @@ static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, const DilloUrl *requester, int offset) { const DilloUrl *old_url; - bool_t MustLoad, ForceReload, Repush, IgnoreScroll; + bool_t MustLoad, ForceReload, IgnoreScroll; int x, y, idx, ClientKey; DilloWeb *Web; MSG("Nav_open_url: new url='%s'\n", URL_STR_(url)); - Repush = (URL_FLAGS(url) & URL_ReloadFromCache) != 0; ForceReload = (URL_FLAGS(url) & (URL_E2EQuery + URL_ReloadFromCache)) != 0; IgnoreScroll = (URL_FLAGS(url) & URL_IgnoreScroll) != 0; @@ -233,8 +232,7 @@ static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, // a_Menu_pagemarks_new(bw); - Web = a_Web_new(url, requester); - Web->bw = bw; + Web = a_Web_new(bw, url, requester); Web->flags |= WEB_RootUrl; if ((ClientKey = a_Capi_open_url(Web, NULL, NULL)) != 0) { a_Bw_add_client(bw, ClientKey, 1); @@ -249,10 +247,9 @@ static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, */ void a_Nav_cancel_expect(BrowserWindow *bw) { - if (bw->nav_expecting) { - a_Url_free(bw->nav_expect_url); - bw->nav_expect_url = NULL; - bw->nav_expecting = FALSE; + if (a_Bw_expecting(bw)) { + a_Bw_cancel_expect(bw); + a_UIcmd_set_buttons_sens(bw); } if (bw->meta_refresh_status > 0) --bw->meta_refresh_status; @@ -263,7 +260,7 @@ void a_Nav_cancel_expect(BrowserWindow *bw) */ void a_Nav_cancel_expect_if_eq(BrowserWindow *bw, const DilloUrl *url) { - if (bw->nav_expecting && a_Url_cmp(url, bw->nav_expect_url) == 0) + if (a_Url_cmp(url, a_Bw_expected_url(bw)) == 0) a_Nav_cancel_expect(bw); } @@ -281,8 +278,8 @@ void a_Nav_expect_done(BrowserWindow *bw) dReturn_if_fail(bw != NULL); - if (bw->nav_expecting) { - url = bw->nav_expect_url; + if (a_Bw_expecting(bw)) { + url = a_Url_dup(a_Bw_expected_url(bw)); reload = (URL_FLAGS(url) & URL_ReloadPage); repush = (URL_FLAGS(url) & URL_ReloadFromCache); e2equery = (URL_FLAGS(url) & URL_E2EQuery); @@ -293,6 +290,7 @@ void a_Nav_expect_done(BrowserWindow *bw) m = URL_E2EQuery|URL_ReloadPage|URL_ReloadFromCache|URL_IgnoreScroll; a_Url_set_flags(url, URL_FLAGS(url) & ~m); url_idx = a_History_add_url(url); + a_Url_free(url); if (repush) { MSG("a_Nav_expect_done: repush!\n"); @@ -345,16 +343,17 @@ void a_Nav_expect_done(BrowserWindow *bw) void a_Nav_push(BrowserWindow *bw, const DilloUrl *url, const DilloUrl *requester) { + const DilloUrl *e_url; dReturn_if_fail (bw != NULL); - if (bw->nav_expecting && !a_Url_cmp(bw->nav_expect_url, url) && - !strcmp(URL_FRAGMENT(bw->nav_expect_url),URL_FRAGMENT(url))) { + e_url = a_Bw_expected_url(bw); + if (e_url && !a_Url_cmp(e_url, url) && + !strcmp(URL_FRAGMENT(e_url),URL_FRAGMENT(url))) { /* we're already expecting that url (most probably a double-click) */ return; } a_Nav_cancel_expect(bw); - bw->nav_expect_url = a_Url_dup(url); - bw->nav_expecting = TRUE; + a_Bw_expect(bw, url); Nav_open_url(bw, url, requester, 0); } @@ -370,8 +369,7 @@ static void Nav_repush(BrowserWindow *bw) url = a_Url_dup(a_History_get_url(NAV_TOP_UIDX(bw))); /* Let's make reload be from Cache */ a_Url_set_flags(url, URL_FLAGS(url) | URL_ReloadFromCache); - bw->nav_expect_url = a_Url_dup(url); - bw->nav_expecting = TRUE; + a_Bw_expect(bw, url); Nav_open_url(bw, url, NULL, 0); a_Url_free(url); } @@ -488,9 +486,9 @@ static void Nav_reload_callback(void *data) confirmed = 0; } else if (URL_FLAGS(h_url) & URL_Post) { /* Attempt to repost data, let's confirm... */ - choice = a_Dialog_choice3("Repost form data?", - "Yes", "*No", "Cancel"); - confirmed = (choice == 0); /* "Yes" */ + choice = a_Dialog_choice5("Repost form data?", + "No", "Yes", "Cancel", NULL, NULL); + confirmed = (choice == 2); /* "Yes" */ } if (confirmed) { @@ -501,9 +499,9 @@ static void Nav_reload_callback(void *data) a_Url_set_flags(r_url, URL_FLAGS(r_url) | URL_E2EQuery); /* This is an explicit reload, so clear the SpamSafe flag */ a_Url_set_flags(r_url, URL_FLAGS(r_url) & ~URL_SpamSafe); - bw->nav_expect_url = r_url; - bw->nav_expecting = TRUE; + a_Bw_expect(bw, r_url); Nav_open_url(bw, r_url, NULL, 0); + a_Url_free(r_url); } } } @@ -567,8 +565,7 @@ static void Nav_save_cb(int Op, CacheClient_t *Client) void a_Nav_save_url(BrowserWindow *bw, const DilloUrl *url, const char *filename) { - DilloWeb *Web = a_Web_new(url, NULL); - Web->bw = bw; + DilloWeb *Web = a_Web_new(bw, url, NULL); Web->filename = dStrdup(filename); Web->flags |= WEB_Download; /* TODO: keep track of this client */ diff --git a/src/pixmaps.h b/src/pixmaps.h index 83235dd2..9d3c4f28 100644 --- a/src/pixmaps.h +++ b/src/pixmaps.h @@ -819,11 +819,11 @@ static const char *const tools_xpm[] = { " ", " ", " .XXo. ", -" oO $$+. ", +" oO$$$+. ", " oo@$$$@# ", " #o@$$$O# ", " #X$$$$%X ", -" &#% #X$$$@o ", +" &# #X$$$@o ", " #*o =-@$$$# ", " oO*o #$@$$$$# ", " oOOOX oO@;$$$$X ", @@ -1426,11 +1426,11 @@ static const char *const tools_s_xpm[] = { " p*45<Xg ", " h.>885oa ", " p.3883Xg ", -" i$O s$488;s ", +" $O s$488;s ", " O>1p e;588;a ", " O331sr;7778:s ", " O343,**3678;a ", -" f,643;#%368:s ", +" O,643;#%368:s ", " t<64>= &374f ", " t244>= &379ih", " d@:;=& &475u", @@ -1539,22 +1539,22 @@ static const char *const help_xpm[] = { "D c #000000", "E c #000000", "F c #000000", -" 5555555 ", -" 544433355 ", -" 54555438455 ", -" 44555542835 ", -" 44445548245 ", -" 4444554274 ", -" 544554274 ", -" 55474 ", -" 5474 ", -" 544 ", +" ", +" 444333 ", +" 4 4384 ", +" 44 4283 ", +" 4444 4824 ", +" 4444 4274 ", +" 44 4274 ", +" 474 ", +" 474 ", +" 44 ", " 44 ", " ", -" 5445 ", +" 44 ", " 4764 ", " 4674 ", -" 5445 "}; +" 44 "}; /* XPM */ static const char *const full_screen_on_xpm[] = { diff --git a/src/prefs.c b/src/prefs.c index f968710a..f243205a 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -18,11 +18,12 @@ #define PREFS_FONT_CURSIVE "URW Chancery L" #define PREFS_FONT_FANTASY "DejaVu Sans" /* TODO: find good default */ #define PREFS_FONT_MONOSPACE "DejaVu Sans Mono" -#define PREFS_SEARCH_URL "http://www.google.com/search?ie=UTF-8&oe=UTF-8&q=%s" +#define PREFS_SEARCH_URL "http://duckduckgo.com/lite/?kp=-1&q=%s" #define PREFS_NO_PROXY "localhost 127.0.0.1" #define PREFS_SAVE_DIR "/tmp/" #define PREFS_HTTP_REFERER "host" #define PREFS_HTTP_USER_AGENT "Dillo/" VERSION +#define PREFS_THEME "none" /*----------------------------------------------------------------------------- * Global Data @@ -70,11 +71,15 @@ void a_Prefs_init(void) prefs.load_stylesheets=TRUE; prefs.middle_click_drags_page = TRUE; prefs.middle_click_opens_new_tab = TRUE; + prefs.right_click_closes_tab = FALSE; prefs.no_proxy = dStrdup(PREFS_NO_PROXY); prefs.panel_size = P_medium; prefs.parse_embedded_css=TRUE; prefs.save_dir = dStrdup(PREFS_SAVE_DIR); - prefs.search_url = dStrdup(PREFS_SEARCH_URL); + prefs.search_urls = dList_new(16); + dList_append(prefs.search_urls, dStrdup(PREFS_SEARCH_URL)); + dList_append(prefs.search_urls, NULL); /* flags a default search URL */ + prefs.search_url_idx = 0; prefs.show_back = TRUE; prefs.show_bookmarks = TRUE; prefs.show_clear_url = TRUE; @@ -85,6 +90,7 @@ void a_Prefs_init(void) prefs.show_home = TRUE; prefs.show_msg = TRUE; prefs.show_progress_box = TRUE; + prefs.show_quit_dialog = TRUE; prefs.show_reload = TRUE; prefs.show_save = TRUE; prefs.show_search = TRUE; @@ -94,6 +100,7 @@ void a_Prefs_init(void) prefs.show_url = TRUE; prefs.small_icons = FALSE; prefs.start_page = a_Url_new(PREFS_START_PAGE, NULL); + prefs.theme = dStrdup(PREFS_THEME); prefs.w3c_plus_heuristics = TRUE; } @@ -103,6 +110,8 @@ void a_Prefs_init(void) */ void a_Prefs_freeall(void) { + int i; + dFree(prefs.font_cursive); dFree(prefs.font_fantasy); dFree(prefs.font_monospace); @@ -116,6 +125,9 @@ void a_Prefs_freeall(void) dFree(prefs.http_user_agent); dFree(prefs.no_proxy); dFree(prefs.save_dir); - dFree(prefs.search_url); + for (i = 0; i < dList_length(prefs.search_urls); ++i) + dFree(dList_nth_data(prefs.search_urls, i)); + dList_free(prefs.search_urls); a_Url_free(prefs.start_page); + dFree(prefs.theme); } diff --git a/src/prefs.h b/src/prefs.h index 4009925c..f1a3d538 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -24,7 +24,7 @@ extern "C" { #define PREFS_GEOMETRY_DEFAULT_YPOS -9999 /* Panel sizes */ -enum { P_tiny = 0, P_small, P_medium, P_large }; +enum { P_tiny = 0, P_small, P_medium }; enum {PREFS_FILTER_ALLOW_ALL, PREFS_FILTER_SAME_DOMAIN}; @@ -49,6 +49,7 @@ struct _DilloPrefs { int32_t bg_color; bool_t contrast_visited_color; bool_t show_tooltip; + char *theme; int panel_size; bool_t small_icons; bool_t limit_text_width; @@ -71,6 +72,7 @@ struct _DilloPrefs { bool_t show_search; bool_t show_help; bool_t show_progress_box; + bool_t show_quit_dialog; bool_t fullwindow_start; bool_t load_images; bool_t load_stylesheets; @@ -84,7 +86,9 @@ struct _DilloPrefs { char *font_monospace; bool_t enterpress_forces_submit; bool_t middle_click_opens_new_tab; - char *search_url; + bool_t right_click_closes_tab; + bool_t search_url_idx; + Dlist *search_urls; char *save_dir; bool_t show_msg; bool_t show_extra_warnings; diff --git a/src/prefsparser.cc b/src/prefsparser.cc index 95f98c16..efe64a0e 100644 --- a/src/prefsparser.cc +++ b/src/prefsparser.cc @@ -24,6 +24,7 @@ typedef enum { PREFS_BOOL, PREFS_COLOR, PREFS_STRING, + PREFS_STRINGS, PREFS_URL, PREFS_INT32, PREFS_DOUBLE, @@ -81,11 +82,12 @@ int PrefsParser::parseOption(char *name, char *value) PREFS_BOOL }, { "middle_click_opens_new_tab", &prefs.middle_click_opens_new_tab, PREFS_BOOL }, + { "right_click_closes_tab", &prefs.right_click_closes_tab, PREFS_BOOL }, { "no_proxy", &prefs.no_proxy, PREFS_STRING }, { "panel_size", &prefs.panel_size, PREFS_PANEL_SIZE }, { "parse_embedded_css", &prefs.parse_embedded_css, PREFS_BOOL }, { "save_dir", &prefs.save_dir, PREFS_STRING }, - { "search_url", &prefs.search_url, PREFS_STRING }, + { "search_url", &prefs.search_urls, PREFS_STRINGS }, { "show_back", &prefs.show_back, PREFS_BOOL }, { "show_bookmarks", &prefs.show_bookmarks, PREFS_BOOL }, { "show_clear_url", &prefs.show_clear_url, PREFS_BOOL }, @@ -96,6 +98,7 @@ int PrefsParser::parseOption(char *name, char *value) { "show_home", &prefs.show_home, PREFS_BOOL }, { "show_msg", &prefs.show_msg, PREFS_BOOL }, { "show_progress_box", &prefs.show_progress_box, PREFS_BOOL }, + { "show_quit_dialog", &prefs.show_quit_dialog, PREFS_BOOL }, { "show_reload", &prefs.show_reload, PREFS_BOOL }, { "show_save", &prefs.show_save, PREFS_BOOL }, { "show_search", &prefs.show_search, PREFS_BOOL }, @@ -105,6 +108,7 @@ int PrefsParser::parseOption(char *name, char *value) { "show_url", &prefs.show_url, PREFS_BOOL }, { "small_icons", &prefs.small_icons, PREFS_BOOL }, { "start_page", &prefs.start_page, PREFS_URL }, + { "theme", &prefs.theme, PREFS_STRING }, { "w3c_plus_heuristics", &prefs.w3c_plus_heuristics, PREFS_BOOL } }; @@ -128,11 +132,26 @@ int PrefsParser::parseOption(char *name, char *value) break; case PREFS_COLOR: *(int32_t *)node->pref = a_Color_parse(value, *(int32_t*)node->pref,&st); + if (st) + MSG("prefs: Color '%s' not recognized.\n", value); break; case PREFS_STRING: dFree(*(char **)node->pref); *(char **)node->pref = dStrdup(value); break; + case PREFS_STRINGS: + { + Dlist *lp = *(Dlist **)node->pref; + if (dList_length(lp) == 2 && !dList_nth_data(lp, 1)) { + /* override the default */ + void *data = dList_nth_data(lp, 0); + dList_remove(lp, data); + dList_remove(lp, NULL); + dFree(data); + } + dList_append(lp, dStrdup(value)); + break; + } case PREFS_URL: a_Url_free(*(DilloUrl **)node->pref); *(DilloUrl **)node->pref = a_Url_new(value, NULL); @@ -161,8 +180,6 @@ int PrefsParser::parseOption(char *name, char *value) prefs.panel_size = P_tiny; else if (!dStrcasecmp(value, "small")) prefs.panel_size = P_small; - else if (!dStrcasecmp(value, "large")) - prefs.panel_size = P_large; else /* default to "medium" */ prefs.panel_size = P_medium; break; @@ -170,13 +187,6 @@ int PrefsParser::parseOption(char *name, char *value) MSG_WARN("prefs: {%s} IS recognized but not handled!\n", name); break; /* Not reached */ } - - if (prefs.limit_text_width) { - /* BUG: causes 100% CPU usage with <button> or <input type="image"> */ - MSG_WARN("Disabling limit_text_width preference (currently broken).\n"); - prefs.limit_text_width = FALSE; - } - return 0; } diff --git a/src/styleengine.cc b/src/styleengine.cc index 776c1694..a4c31ccb 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -52,6 +52,7 @@ StyleEngine::StyleEngine (dw::core::Layout *layout) { n->wordStyle = NULL; n->backgroundStyle = NULL; n->styleAttrProperties = NULL; + n->styleAttrPropertiesImportant = NULL; n->nonCssProperties = NULL; n->inheritBackgroundColor = false; } @@ -82,6 +83,7 @@ void StyleEngine::startElement (int element) { stack->increase (); Node *n = stack->getRef (stack->size () - 1); n->styleAttrProperties = NULL; + n->styleAttrPropertiesImportant = NULL; n->nonCssProperties = NULL; n->style = NULL; n->wordStyle = NULL; @@ -138,10 +140,14 @@ void StyleEngine::setStyle (const char *styleAttr) { Node *n = stack->getRef (stack->size () - 1); assert (n->styleAttrProperties == NULL); // parse style information from style="" attribute, if it exists - if (styleAttr && prefs.parse_embedded_css) - n->styleAttrProperties = - CssParser::parseDeclarationBlock (styleAttr, - strlen (styleAttr)); + if (styleAttr && prefs.parse_embedded_css) { + n->styleAttrProperties = new CssPropertyList (true); + n->styleAttrPropertiesImportant = new CssPropertyList (true); + + CssParser::parseDeclarationBlock (styleAttr, strlen (styleAttr), + n->styleAttrProperties, + n->styleAttrPropertiesImportant); + } }; /** @@ -213,6 +219,8 @@ void StyleEngine::endElement (int element) { if (n->styleAttrProperties) delete n->styleAttrProperties; + if (n->styleAttrPropertiesImportant) + delete n->styleAttrPropertiesImportant; if (n->nonCssProperties) delete n->nonCssProperties; if (n->style) @@ -709,7 +717,8 @@ Style * StyleEngine::backgroundStyle () { * This method is private. Call style() to get a current style object. */ Style * StyleEngine::style0 (int i) { - CssPropertyList props, *styleAttrProperties, *nonCssProperties; + CssPropertyList props, *styleAttrProperties, *styleAttrPropertiesImportant; + CssPropertyList *nonCssProperties; // get previous style from the stack StyleAttrs attrs = *stack->getRef (i - 1)->style; @@ -726,11 +735,13 @@ Style * StyleEngine::style0 (int i) { preprocessAttrs (&attrs); styleAttrProperties = stack->getRef (i)->styleAttrProperties; + styleAttrPropertiesImportant = stack->getRef(i)->styleAttrPropertiesImportant; nonCssProperties = stack->getRef (i)->nonCssProperties; // merge style information cssContext->apply (&props, doctree, stack->getRef(i)->doctreeNode, - styleAttrProperties, nonCssProperties); + styleAttrProperties, styleAttrPropertiesImportant, + nonCssProperties); // apply style apply (i, &attrs, &props); diff --git a/src/styleengine.hh b/src/styleengine.hh index e37aeed1..b73a8b5f 100644 --- a/src/styleengine.hh +++ b/src/styleengine.hh @@ -21,6 +21,7 @@ class StyleEngine { private: struct Node { CssPropertyList *styleAttrProperties; + CssPropertyList *styleAttrPropertiesImportant; CssPropertyList *nonCssProperties; dw::core::style::Style *style; dw::core::style::Style *wordStyle; diff --git a/src/table.cc b/src/table.cc index 58cdf22e..d48a0c45 100644 --- a/src/table.cc +++ b/src/table.cc @@ -151,7 +151,6 @@ void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize) { const char *attrbuf; int32_t bgcolor = -1; - bool new_style = false; html->styleEngine->inheritNonCssHints (); @@ -183,10 +182,8 @@ void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize) if (bgcolor != -1) { html->styleEngine->setNonCssHint(CSS_PROPERTY_BACKGROUND_COLOR, CSS_TYPE_COLOR, bgcolor); - new_style = true; } - if (a_Html_tag_set_valign_attr (html, tag, tagsize)) - new_style = true; + a_Html_tag_set_valign_attr (html, tag, tagsize); break; default: break; @@ -318,7 +315,6 @@ static void Html_tag_open_table_cell(DilloHtml *html, int colspan = 1, rowspan = 1; const char *attrbuf; int32_t bgcolor; - bool_t new_style; html->styleEngine->inheritNonCssHints (); @@ -363,8 +359,7 @@ static void Html_tag_open_table_cell(DilloHtml *html, a_Html_parse_length (html, attrbuf)); } - if (a_Html_tag_set_valign_attr (html, tag, tagsize)) - new_style = TRUE; + a_Html_tag_set_valign_attr (html, tag, tagsize); if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { bgcolor = a_Html_color_parse(html, attrbuf, -1); diff --git a/src/timeout.cc b/src/timeout.cc index 80eb6425..1ddcd5e1 100644 --- a/src/timeout.cc +++ b/src/timeout.cc @@ -11,12 +11,9 @@ // Simple ADT for timeout functions -#include <fltk/run.h> +#include <FL/Fl.H> #include "timeout.hh" -using namespace fltk; - - // C++ functions with C linkage ---------------------------------------------- /* @@ -25,7 +22,7 @@ using namespace fltk; */ void a_Timeout_add(float t, TimeoutCb_t cb, void *cbdata) { - add_timeout(t, cb, cbdata); + Fl::add_timeout(t, cb, cbdata); } /* @@ -33,7 +30,7 @@ void a_Timeout_add(float t, TimeoutCb_t cb, void *cbdata) */ void a_Timeout_repeat(float t, TimeoutCb_t cb, void *cbdata) { - add_timeout(t, cb, cbdata); + Fl::add_timeout(t, cb, cbdata); } /* @@ -14,73 +14,64 @@ #include <unistd.h> #include <stdio.h> -#include <fltk/HighlightButton.h> -#include <fltk/run.h> -#include <fltk/damage.h> -#include <fltk/xpmImage.h> -#include <fltk/events.h> // for mouse buttons and keys -#include <fltk/Font.h> // UI label font for tabs -#include <fltk/InvisibleBox.h> -#include <fltk/PopupMenu.h> -#include <fltk/Item.h> -#include <fltk/Divider.h> - #include "keys.hh" #include "ui.hh" #include "msg.h" #include "timeout.hh" #include "utf8.hh" -using namespace fltk; - +#include <FL/Fl.H> +#include <FL/Fl_Pixmap.H> +#include <FL/Fl_Box.H> +#include <FL/names.h> // Include image data #include "pixmaps.h" #include "uicmd.hh" struct iconset { - Image *ImgMeterOK, *ImgMeterBug, - *ImgHome, *ImgReload, *ImgSave, *ImgBook, *ImgTools, - *ImgClear,*ImgSearch, *ImgHelp; - MultiImage *ImgLeftMulti, *ImgRightMulti, *ImgStopMulti; + Fl_Image *ImgMeterOK, *ImgMeterBug, + *ImgHome, *ImgReload, *ImgSave, *ImgBook, *ImgTools, + *ImgClear,*ImgSearch, *ImgHelp, *ImgLeft, *ImgLeftIn, + *ImgRight, *ImgRightIn, *ImgStop, *ImgStopIn; }; static struct iconset standard_icons = { - new xpmImage(mini_ok_xpm), - new xpmImage(mini_bug_xpm), - new xpmImage(home_xpm), - new xpmImage(reload_xpm), - new xpmImage(save_xpm), - new xpmImage(bm_xpm), - new xpmImage(tools_xpm), - new xpmImage(new_s_xpm), - new xpmImage(search_xpm), - new xpmImage(help_xpm), - new MultiImage(*new xpmImage(left_xpm), INACTIVE_R, - *new xpmImage(left_i_xpm)), - new MultiImage(*new xpmImage(right_xpm), INACTIVE_R, - *new xpmImage(right_i_xpm)), - new MultiImage(*new xpmImage(stop_xpm), INACTIVE_R, - *new xpmImage(stop_i_xpm)), + new Fl_Pixmap(mini_ok_xpm), + new Fl_Pixmap(mini_bug_xpm), + new Fl_Pixmap(home_xpm), + new Fl_Pixmap(reload_xpm), + new Fl_Pixmap(save_xpm), + new Fl_Pixmap(bm_xpm), + new Fl_Pixmap(tools_xpm), + new Fl_Pixmap(new_s_xpm), + new Fl_Pixmap(search_xpm), + new Fl_Pixmap(help_xpm), + new Fl_Pixmap(left_xpm), + new Fl_Pixmap(left_i_xpm), + new Fl_Pixmap(right_xpm), + new Fl_Pixmap(right_i_xpm), + new Fl_Pixmap(stop_xpm), + new Fl_Pixmap(stop_i_xpm), }; static struct iconset small_icons = { standard_icons.ImgMeterOK, standard_icons.ImgMeterBug, - new xpmImage(home_s_xpm), - new xpmImage(reload_s_xpm), - new xpmImage(save_s_xpm), - new xpmImage(bm_s_xpm), - new xpmImage(tools_s_xpm), - new xpmImage(new_s_xpm), + new Fl_Pixmap(home_s_xpm), + new Fl_Pixmap(reload_s_xpm), + new Fl_Pixmap(save_s_xpm), + new Fl_Pixmap(bm_s_xpm), + new Fl_Pixmap(tools_s_xpm), + new Fl_Pixmap(new_s_xpm), standard_icons.ImgSearch, standard_icons.ImgHelp, - new MultiImage(*new xpmImage(left_s_xpm), INACTIVE_R, - *new xpmImage(left_si_xpm)), - new MultiImage(*new xpmImage(right_s_xpm), INACTIVE_R, - *new xpmImage(right_si_xpm)), - new MultiImage(*new xpmImage(stop_s_xpm), INACTIVE_R, - *new xpmImage(stop_si_xpm)), + new Fl_Pixmap(left_s_xpm), + new Fl_Pixmap(left_si_xpm), + new Fl_Pixmap(right_s_xpm), + new Fl_Pixmap(right_si_xpm), + new Fl_Pixmap(stop_s_xpm), + new Fl_Pixmap(stop_si_xpm), }; @@ -95,49 +86,69 @@ static struct iconset *icons = &standard_icons; /* * (Used to avoid certain shortcuts in the location bar) */ -class CustInput : public Input { +class CustInput : public Fl_Input { public: CustInput (int x, int y, int w, int h, const char* l=0) : - Input(x,y,w,h,l) {}; + Fl_Input(x,y,w,h,l) {}; int handle(int e); }; /* - * Disable: UpKey, DownKey, PageUpKey, PageDownKey and - * CTRL+{o,r,HomeKey,EndKey} + * Disable keys: Up, Down, Page_Up, Page_Down, Tab and + * CTRL+{o,r,Home,End} SHIFT+{Left,Right}. */ int CustInput::handle(int e) { - int k = event_key(); + int k = Fl::event_key(); _MSG("CustInput::handle event=%d\n", e); // We're only interested in some flags - unsigned modifier = event_state() & (SHIFT | CTRL | ALT); + unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT); // Don't focus with arrow keys - if (e == FOCUS && - (k == UpKey || k == DownKey || k == LeftKey || k == RightKey)) { + if (e == FL_FOCUS && + (k == FL_Up || k == FL_Down || k == FL_Left || k == FL_Right)) { return 0; - } else if (e == KEY) { - if (modifier == CTRL) { - if (k == 'l') { + } else if (e == FL_KEYBOARD) { + if (k == FL_Escape && modifier == 0) { + // Let the parent group handle this Esc key + return 0; + } else if (modifier == FL_SHIFT) { + if (k == FL_Left || k == FL_Right) { + // Let these keys get to the UI + return 0; + } + } else if (modifier == FL_CTRL) { + if (k == 'a' || k == 'e') { + position(k == 'a' ? 0 : size()); + return 1; + } else if (k == 'k') { + cut(position(), size()); + return 1; + } else if (k == 'd') { + cut(position(), position()+1); + return 1; + } else if (k == 'l') { // Make text selected when already focused. position(size(), 0); return 1; - } else if (k == 'o' || k == 'r' || k == HomeKey || k == EndKey) + } else if (k == 'h' || k == 'o' || k == 'r' || + k == FL_Home || k == FL_End) { + // Let these keys get to the UI + return 0; + } + } else if (modifier == 0) { + if (k == FL_Down || k == FL_Up || + k == FL_Page_Down || k == FL_Page_Up || k == FL_Tab) { + // Give up focus and honor the key + a_UIcmd_focus_main_area(a_UIcmd_get_bw_by_widget(this)); return 0; - } else if (modifier == SHIFT) { - if (k == LeftKey || k == RightKey) { - _MSG(" CustInput::handle > SHIFT+RightKey\n"); - a_UIcmd_send_event_to_tabs_by_wid(e, this); - return 1; } } } - _MSG("\n"); - return Input::handle(e); + return Fl_Input::handle(e); } //---------------------------------------------------------------------------- @@ -145,24 +156,24 @@ int CustInput::handle(int e) /* * Used to handle "paste" within the toolbar's Clear button. */ -class CustHighlightButton : public HighlightButton { +class CustPasteButton : public CustLightButton { public: - CustHighlightButton(int x, int y, int w, int h, const char *l=0) : - HighlightButton(x,y,w,h,l) {}; + CustPasteButton(int x, int y, int w, int h, const char *l=0) : + CustLightButton(x,y,w,h,l) {}; int handle(int e); }; -int CustHighlightButton::handle(int e) +int CustPasteButton::handle(int e) { - if (e == PASTE) { - const char* t = event_text(); + if (e == FL_PASTE) { + const char* t = Fl::event_text(); if (t && *t) { a_UIcmd_set_location_text(a_UIcmd_get_bw_by_widget(this), t); a_UIcmd_open_urlstr(a_UIcmd_get_bw_by_widget(this), t); return 1; } } - return HighlightButton::handle(e); + return CustLightButton::handle(e); } //---------------------------------------------------------------------------- @@ -170,22 +181,19 @@ int CustHighlightButton::handle(int e) /* * Used to resize the progress boxes automatically. */ -class CustProgressBox : public InvisibleBox { +class CustProgressBox : public Fl_Box { int padding; public: CustProgressBox(int x, int y, int w, int h, const char *l=0) : - InvisibleBox(x,y,w,h,l) { padding = 0; }; + Fl_Box(x,y,w,h,l) { padding = 0; }; void update_label(const char *lbl) { - int w,h; + int w = 0, h = 0; if (!padding) { copy_label("W"); measure_label(w, h); padding = w > 2 ? w/2 : 1; } copy_label(lbl); - measure_label(w,h); - resize(w+padding,h); - redraw_label(); } }; @@ -205,23 +213,23 @@ public: /* * Callback for the search button. */ -static void search_cb(Widget *wid, void *data) +static void search_cb(Fl_Widget *wid, void *data) { - int k = event_key(); + int b = Fl::event_button(); - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_search_dialog(a_UIcmd_get_bw_by_widget(wid)); - } else if (k == 2) { + } else if (b == FL_MIDDLE_MOUSE) { ((UI*)data)->color_change_cb_i(); - } else if (k == 3) { - ((UI*)data)->panel_cb_i(); + } else if (b == FL_RIGHT_MOUSE) { + // nothing ATM } } /* * Callback for the help button. */ -static void help_cb(Widget *w, void *) +static void help_cb(Fl_Widget *w, void *) { char *path = dStrconcat(DILLO_DOCDIR, "user_help.html", NULL); BrowserWindow *bw = a_UIcmd_get_bw_by_widget(w); @@ -233,7 +241,7 @@ static void help_cb(Widget *w, void *) } else { MSG("Can't read local help file at \"%s\"." " Getting remote help...\n", path); - a_UIcmd_open_urlstr(bw, "http://www.dillo.org/dillo2-help.html"); + a_UIcmd_open_urlstr(bw, "http://www.dillo.org/dillo3-help.html"); } dFree(path); } @@ -241,10 +249,10 @@ static void help_cb(Widget *w, void *) /* * Callback for the File menu button. */ -static void filemenu_cb(Widget *wid, void *) +static void filemenu_cb(Fl_Widget *wid, void *) { - int k = event_key(); - if (k == 1 || k == 3) { + int b = Fl::event_button(); + if (b == FL_LEFT_MOUSE || b == FL_RIGHT_MOUSE) { a_UIcmd_file_popup(a_UIcmd_get_bw_by_widget(wid), wid); } } @@ -252,105 +260,92 @@ static void filemenu_cb(Widget *wid, void *) /* * Callback for the location's clear-button. */ -static void clear_cb(Widget *w, void *data) +static void clear_cb(Fl_Widget *w, void *data) { UI *ui = (UI*)data; - int k = event_key(); - if (k == 1) { + int b = Fl::event_button(); + if (b == FL_LEFT_MOUSE) { ui->set_location(""); ui->focus_location(); - } if (k == 2) { + } if (b == FL_MIDDLE_MOUSE) { ui->paste_url(); } } /* - * Change the color of the location bar. - * -static void color_change_cb(Widget *wid, void *data) -{ - ((UI*)data)->color_change_cb_i(); -} - */ - - -/* * Send the browser to the new URL in the location. */ -static void location_cb(Widget *wid, void *data) +static void location_cb(Fl_Widget *wid, void *data) { - Input *i = (Input*)wid; + Fl_Input *i = (Fl_Input*)wid; UI *ui = (UI*)data; _MSG("location_cb()\n"); - /* This test is necessary because WHEN_ENTER_KEY also includes - * other events we're not interested in. For instance pressing - * The Back or Forward, buttons, or the first click on a rendered - * page. BUG: this must be investigated and reported to FLTK2 team */ - if (event_key() == ReturnKey) { - a_UIcmd_open_urlstr(a_UIcmd_get_bw_by_widget(i), i->value()); - } - if (ui->get_panelmode() == UI_TEMPORARILY_SHOW_PANELS) { - ui->set_panelmode(UI_HIDDEN); - } + a_UIcmd_open_urlstr(a_UIcmd_get_bw_by_widget(i), i->value()); + + if (ui->temporaryPanels()) + ui->panels_toggle(); } /* * Callback handler for button press on the panel */ -static void b1_cb(Widget *wid, void *cb_data) +static void b1_cb(Fl_Widget *wid, void *cb_data) { int bn = VOIDP2INT(cb_data); - int k = event_key(); - if (k && k <= 7) { - _MSG("[%s], mouse button %d was pressed\n", button_names[bn], k); - _MSG("mouse button %d was pressed\n", k); + int b = Fl::event_button(); + if (b >= FL_LEFT_MOUSE && b <= FL_RIGHT_MOUSE) { + _MSG("[%s], mouse button %d was pressed\n", button_names[bn], b); + _MSG("mouse button %d was pressed\n", b); } switch (bn) { case UI_BACK: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_back(a_UIcmd_get_bw_by_widget(wid)); - } else if (k == 3) { - a_UIcmd_back_popup(a_UIcmd_get_bw_by_widget(wid)); + } else if (b == FL_RIGHT_MOUSE) { + a_UIcmd_back_popup(a_UIcmd_get_bw_by_widget(wid), wid->x(), + wid->y() + wid->h()); } break; case UI_FORW: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_forw(a_UIcmd_get_bw_by_widget(wid)); - } else if (k == 3) { - a_UIcmd_forw_popup(a_UIcmd_get_bw_by_widget(wid)); + } else if (b == FL_RIGHT_MOUSE) { + a_UIcmd_forw_popup(a_UIcmd_get_bw_by_widget(wid), wid->x(), + wid->y() + wid->h()); } break; case UI_HOME: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_home(a_UIcmd_get_bw_by_widget(wid)); } break; case UI_RELOAD: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_reload(a_UIcmd_get_bw_by_widget(wid)); } break; case UI_SAVE: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_save(a_UIcmd_get_bw_by_widget(wid)); } break; case UI_STOP: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_stop(a_UIcmd_get_bw_by_widget(wid)); } break; case UI_BOOK: - if (k == 1) { + if (b == FL_LEFT_MOUSE) { a_UIcmd_book(a_UIcmd_get_bw_by_widget(wid)); } break; case UI_TOOLS: - if (k == 1 || k == 3) { - a_UIcmd_tools(a_UIcmd_get_bw_by_widget(wid), wid); + if (b == FL_LEFT_MOUSE || b == FL_RIGHT_MOUSE) { + a_UIcmd_tools(a_UIcmd_get_bw_by_widget(wid), wid->x(), + wid->y() + wid->h()); } break; default: @@ -359,24 +354,14 @@ static void b1_cb(Widget *wid, void *cb_data) } /* - * Callback handler for fullscreen button press - */ -//static void fullscreen_cb(Widget *wid, void *data) -//{ -// /* TODO: do we want to toggle fullscreen or panelmode? -// maybe we need to add another button?*/ -// ((UI*)data)->panelmode_cb_i(); -//} - -/* * Callback for the bug meter button. */ -static void bugmeter_cb(Widget *wid, void *data) +static void bugmeter_cb(Fl_Widget *wid, void *data) { - int k = event_key(); - if (k == 1) { + int b = Fl::event_button(); + if (b == FL_LEFT_MOUSE) { a_UIcmd_view_page_bugs(a_UIcmd_get_bw_by_widget(wid)); - } else if (k == 3) { + } else if (b == FL_RIGHT_MOUSE) { a_UIcmd_bugmeter_popup(a_UIcmd_get_bw_by_widget(wid)); } } @@ -390,159 +375,136 @@ static void bugmeter_cb(Widget *wid, void *data) //---------------------------- /* + * Make a generic navigation button + */ +Fl_Button *UI::make_button(const char *label, Fl_Image *img, Fl_Image *deimg, + int b_n, int start) +{ + if (start) + p_xpos = 0; + + Fl_Button *b = new CustLightButton(p_xpos, 0, bw, bh, (lbl) ? label : NULL); + if (img) + b->image(img); + if (deimg) + b->deimage(deimg); + b->callback(b1_cb, INT2VOIDP(b_n)); + b->clear_visible_focus(); + b->labelsize(12); + b->box(FL_FLAT_BOX); + b->down_box(FL_THIN_DOWN_FRAME); + p_xpos += bw; + return b; +} + +/* * Create the archetipic browser buttons */ -PackedGroup *UI::make_toolbar(int tw, int th) +void UI::make_toolbar(int tw, int th) { - HighlightButton *b; - PackedGroup *p1=new PackedGroup(0,0,tw,th); - p1->begin(); - Back = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Back" : 0); - b->image(icons->ImgLeftMulti); - b->callback(b1_cb, (void *)UI_BACK); - b->clear_tab_to_focus(); - HighlightButton::default_style->highlight_color(CuteColor); - - Forw = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Forw" : 0); - b->image(icons->ImgRightMulti); - b->callback(b1_cb, (void *)UI_FORW); - b->clear_tab_to_focus(); - - Home = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Home" : 0); - b->image(icons->ImgHome); - b->callback(b1_cb, (void *)UI_HOME); - b->clear_tab_to_focus(); - - Reload = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Reload" : 0); - b->image(icons->ImgReload); - b->callback(b1_cb, (void *)UI_RELOAD); - b->clear_tab_to_focus(); - - Save = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Save" : 0); - b->image(icons->ImgSave); - b->callback(b1_cb, (void *)UI_SAVE); - b->clear_tab_to_focus(); - - Stop = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Stop" : 0); - b->image(icons->ImgStopMulti); - b->callback(b1_cb, (void *)UI_STOP); - b->clear_tab_to_focus(); - - Bookmarks = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Book" : 0); - b->image(icons->ImgBook); - b->callback(b1_cb, (void *)UI_BOOK); - b->clear_tab_to_focus(); - - Tools = b = new HighlightButton(xpos, 0, bw, bh, (lbl) ? "Tools" : 0); - b->image(icons->ImgTools); - b->callback(b1_cb, (void *)UI_TOOLS); - b->clear_tab_to_focus(); - - p1->type(PackedGroup::ALL_CHILDREN_VERTICAL); - p1->end(); - - if (prefs.show_tooltip) { - Back->tooltip("Previous page"); - Forw->tooltip("Next page"); - Home->tooltip("Go to the Home page"); - Reload->tooltip("Reload"); - Save->tooltip("Save this page"); - Stop->tooltip("Stop loading"); - Bookmarks->tooltip("View bookmarks"); - Tools->tooltip("Settings"); - } - return p1; + Back = make_button("Back", icons->ImgLeft, icons->ImgLeftIn, UI_BACK, 1); + Forw = make_button("Forw", icons->ImgRight, icons->ImgRightIn, UI_FORW); + Home = make_button("Home", icons->ImgHome, NULL, UI_HOME); + Reload = make_button("Reload", icons->ImgReload, NULL, UI_RELOAD); + Save = make_button("Save", icons->ImgSave, NULL, UI_SAVE); + Stop = make_button("Stop", icons->ImgStop, icons->ImgStopIn, UI_STOP); + Bookmarks = make_button("Book", icons->ImgBook, NULL, UI_BOOK); + Tools = make_button("Tools", icons->ImgTools, NULL, UI_TOOLS); + + Back->tooltip("Previous page"); + Forw->tooltip("Next page"); + Home->tooltip("Go to the Home page"); + Reload->tooltip("Reload"); + Save->tooltip("Save this page"); + Stop->tooltip("Stop loading"); + Bookmarks->tooltip("View bookmarks"); + Tools->tooltip("Settings"); } /* * Create the location box (Clear/Input/Search) */ -PackedGroup *UI::make_location() +void UI::make_location(int ww) { - Button *b; - PackedGroup *pg = new PackedGroup(0,0,0,0); - pg->begin(); - Clear = b = new CustHighlightButton(2,2,16,22,0); + Fl_Button *b; + + Clear = b = new CustPasteButton(p_xpos,0,16,lh,0); b->image(icons->ImgClear); b->callback(clear_cb, this); - b->clear_tab_to_focus(); + b->clear_visible_focus(); + b->box(FL_THIN_UP_BOX); + b->tooltip("Clear the URL box.\nMiddle-click to paste a URL."); + p_xpos += b->w(); - Input *i = Location = new CustInput(0,0,0,0,0); + Fl_Input *i = Location = new CustInput(p_xpos,0,ww-p_xpos-32,lh,0); i->color(CuteColor); - i->when(WHEN_ENTER_KEY); + i->when(FL_WHEN_ENTER_KEY); i->callback(location_cb, this); - i->set_click_to_focus(); + i->tooltip("Location"); + p_xpos += i->w(); - Search = b = new HighlightButton(0,0,16,22,0); + Search = b = new CustLightButton(p_xpos,0,16,lh,0); b->image(icons->ImgSearch); b->callback(search_cb, this); - b->clear_tab_to_focus(); + b->clear_visible_focus(); + b->box(FL_THIN_UP_BOX); + b->tooltip("Search the Web"); + p_xpos += b->w(); - Help = b = new HighlightButton(0,0,16,22,0); + Help = b = new CustLightButton(p_xpos,0,16,lh,0); b->image(icons->ImgHelp); b->callback(help_cb, this); - b->clear_tab_to_focus(); + b->clear_visible_focus(); + b->box(FL_THIN_UP_BOX); + b->tooltip("Help"); + p_xpos += b->w(); - pg->type(PackedGroup::ALL_CHILDREN_VERTICAL); - pg->resizable(i); - pg->end(); - - if (prefs.show_tooltip) { - Clear->tooltip("Clear the URL box.\nMiddle-click to paste a URL."); - Location->tooltip("Location"); - Search->tooltip("Search the Web"); - Help->tooltip("Help"); - } - return pg; } /* * Create the progress bars */ -PackedGroup *UI::make_progress_bars(int wide, int thin_up) +void UI::make_progress_bars(int wide, int thin_up) { - ProgBox = new PackedGroup(0,0,0,0); - ProgBox->begin(); // Images - IProg = new CustProgressBox(0,0,0,0); - IProg->box(thin_up ? THIN_UP_BOX : EMBOSSED_BOX); - IProg->labelcolor(GRAY10); + IProg = new CustProgressBox(p_xpos,p_ypos,pw,bh); + IProg->labelsize(12); + IProg->box(thin_up ? FL_THIN_UP_BOX : FL_EMBOSSED_BOX); + IProg->labelcolor(FL_GRAY_RAMP + 2); IProg->update_label(wide ? "Images\n0 of 0" : "0 of 0"); + p_xpos += pw; // Page - PProg = new CustProgressBox(0,0,0,0); - PProg->box(thin_up ? THIN_UP_BOX : EMBOSSED_BOX); - PProg->labelcolor(GRAY10); + PProg = new CustProgressBox(p_xpos,p_ypos,pw,bh); + PProg->labelsize(12); + PProg->box(thin_up ? FL_THIN_UP_BOX : FL_EMBOSSED_BOX); + PProg->labelcolor(FL_GRAY_RAMP + 2); PProg->update_label(wide ? "Page\n0.0KB" : "0.0KB"); - ProgBox->type(PackedGroup::ALL_CHILDREN_VERTICAL); - ProgBox->end(); - - return ProgBox; } /* * Create the "File" menu * Static function for File menu callbacks. */ -Widget *UI::make_filemenu_button() +Fl_Widget *UI::make_filemenu_button() { - HighlightButton *btn; - int w,h, padding; + Fl_Button *btn; + int w = 0, h = 0, padding; - FileButton = btn = new HighlightButton(0,0,0,0,"W"); + FileButton = btn = new Fl_Button(p_xpos,0,bw,bh,"W"); + btn->labeltype(FL_FREE_LABELTYPE); btn->measure_label(w, h); padding = w; btn->copy_label(PanelSize == P_tiny ? "&F" : "&File"); btn->measure_label(w,h); - if (PanelSize == P_large) - h = fh; - btn->resize(w+padding,h); + h = (PanelSize == P_tiny) ? bh : lh; + btn->size(w+padding, h); + p_xpos += btn->w(); _MSG("UI::make_filemenu_button w=%d h=%d padding=%d\n", w, h, padding); - btn->box(PanelSize == P_large ? FLAT_BOX : THIN_UP_BOX); + btn->box(FL_THIN_UP_BOX); btn->callback(filemenu_cb, this); - if (prefs.show_tooltip) - btn->tooltip("File menu"); - btn->clear_tab_to_focus(); - if (!prefs.show_filemenu && PanelSize != P_large) + btn->tooltip("File menu"); + btn->clear_visible_focus(); + if (!prefs.show_filemenu) btn->hide(); return btn; } @@ -551,216 +513,173 @@ Widget *UI::make_filemenu_button() /* * Create the control panel */ -Group *UI::make_panel(int ww) +void UI::make_panel(int ww) { - Widget *w; - Group *g1, *g2, *g3; - PackedGroup *pg; - - if (PanelSize > P_large) { - PanelSize = P_tiny; - Small_Icons = !Small_Icons; - } + Fl_Widget *w; if (Small_Icons) icons = &small_icons; else icons = &standard_icons; + pw = 70; + p_xpos = p_ypos = 0; if (PanelSize == P_tiny) { if (Small_Icons) - xpos = 0, bw = 22, bh = 22, fh = 0, lh = 22, lbl = 0; + bw = 22, bh = 22, mh = 0, lh = 22, lbl = 0; else - xpos = 0, bw = 28, bh = 28, fh = 0, lh = 28, lbl = 0; + bw = 28, bh = 28, mh = 0, lh = 28, lbl = 0; } else if (PanelSize == P_small) { if (Small_Icons) - xpos = 0, bw = 20, bh = 20, fh = 0, lh = 20, lbl = 0; + bw = 20, bh = 20, mh = 0, lh = 20, lbl = 0; else - xpos = 0, bw = 28, bh = 28, fh = 0, lh = 28, lbl = 0; + bw = 28, bh = 28, mh = 0, lh = 28, lbl = 0; } else if (PanelSize == P_medium) { if (Small_Icons) - xpos = 0, bw = 42, bh = 36, fh = 0, lh = 22, lbl = 1; - else - xpos = 0, bw = 45, bh = 45, fh = 0, lh = 28, lbl = 1; - } else { // P_large - if (Small_Icons) - xpos = 0, bw = 42, bh = 36, fh = 22, lh = 22, lbl = 1; + bw = 42, bh = 36, mh = 0, lh = 22, lbl = 1; else - xpos = 0, bw = 45, bh = 45, fh = 24, lh = 28, lbl = 1; + bw = 45, bh = 45, mh = 0, lh = 28, lbl = 1; } + nh = bh, fh = 28; sh = 20; + current(0); if (PanelSize == P_tiny) { - g1 = new Group(0,0,ww,bh); - // Toolbar - pg = make_toolbar(ww,bh); - pg->box(EMBOSSED_BOX); - g1->add(pg); - w = make_filemenu_button(); - pg->add(w); - w = make_location(); - pg->add(w); - pg->resizable(w); - w = make_progress_bars(0,1); - pg->add(w); - - g1->resizable(pg); - + NavBar = new CustGroupHorizontal(0,0,ww,nh); + NavBar->box(FL_NO_BOX); + NavBar->begin(); + make_toolbar(ww,bh); + make_filemenu_button(); + make_location(ww); + NavBar->resizable(Location); + make_progress_bars(0,1); + NavBar->box(FL_THIN_UP_FRAME); + NavBar->end(); + NavBar->rearrange(); + TopGroup->insert(*NavBar,0); } else { - g1 = new Group(0,0,ww,fh+lh+bh); - g1->begin(); - // File menu - if (PanelSize == P_large) { - g3 = new Group(0,0,ww,lh); - g3->box(FLAT_BOX); - Widget *bn = make_filemenu_button(); - g3->add(bn); - g3->add_resizable(*new InvisibleBox(bn->w(),0,ww - bn->w(),lh)); - - g2 = new Group(0,fh,ww,lh); - g2->begin(); - pg = make_location(); - pg->resize(ww,lh); - } else { - g2 = new PackedGroup(0,fh,ww,lh); - g2->type(PackedGroup::ALL_CHILDREN_VERTICAL); - g2->begin(); - make_filemenu_button(); - pg = make_location(); - } - - g2->resizable(pg); - g2->end(); + // Location + LocBar = new CustGroupHorizontal(0,0,ww,lh); + LocBar->box(FL_NO_BOX); + LocBar->begin(); + p_xpos = 0; + make_filemenu_button(); + make_location(ww); + LocBar->resizable(Location); + LocBar->end(); + LocBar->rearrange(); + TopGroup->insert(*LocBar,0); // Toolbar - g3 = new Group(0,fh+lh,ww,bh); - g3->begin(); - pg = make_toolbar(ww,bh); - //w = new InvisibleBox(0,0,0,0,"i n v i s i b l e"); - w = new InvisibleBox(0,0,0,0,0); - pg->add(w); - pg->resizable(w); - + p_ypos = 0; + NavBar = new CustGroupHorizontal(0,0,ww,bh); + NavBar->box(FL_NO_BOX); + NavBar->begin(); + make_toolbar(ww,bh); + w = new Fl_Box(p_xpos,0,ww-p_xpos-2*pw,bh); + w->box(FL_FLAT_BOX); + NavBar->resizable(w); + p_xpos = ww - 2*pw; if (PanelSize == P_small) { - w = make_progress_bars(0,0); + make_progress_bars(0,0); } else { - w = make_progress_bars(1,0); + make_progress_bars(1,0); } - pg->add(w); - - g3->resizable(pg); // Better than 'w3' and it also works - pg->box(BORDER_FRAME); - //g3->box(EMBOSSED_BOX); - g3->end(); - - g1->resizable(g3); - g1->end(); + NavBar->end(); + NavBar->rearrange(); + TopGroup->insert(*NavBar,1); } - - return g1; } /* * Create the status panel */ -Group *UI::make_status_panel(int ww) +void UI::make_status_bar(int ww, int wh) { - const int s_h = 20, bm_w = 16; - Group *g = new Group(0, 0, ww, s_h, 0); - - // Status box - Status = new Output(0, 0, ww-bm_w, s_h, 0); - Status->value(""); - Status->box(THIN_DOWN_BOX); - Status->clear_click_to_focus(); - Status->clear_tab_to_focus(); - Status->color(GRAY80); - g->add(Status); - //Status->throw_focus(); - - // Bug Meter - BugMeter = new HighlightButton(ww-bm_w,0,bm_w,s_h,0); - BugMeter->image(icons->ImgMeterOK); - BugMeter->box(THIN_DOWN_BOX); - BugMeter->align(ALIGN_INSIDE|ALIGN_CLIP|ALIGN_LEFT); - if (prefs.show_tooltip) - BugMeter->tooltip("Show HTML bugs\n(right-click for menu)"); - BugMeter->callback(bugmeter_cb, this); - BugMeter->clear_tab_to_focus(); - g->add(BugMeter); - - g->resizable(Status); - return g; + const int bm_w = 20; + StatusBar = new CustGroupHorizontal(0, wh-sh, ww, sh); + StatusBar->box(FL_NO_BOX); + + // Status box + StatusOutput = new Fl_Output(0, wh-sh, ww-bm_w, sh); + StatusOutput->value("http://www.dillo.org"); + StatusOutput->labelsize(8); + StatusOutput->box(FL_THIN_DOWN_BOX); + StatusOutput->clear_visible_focus(); + StatusOutput->color(FL_GRAY_RAMP + 18); + + // Bug Meter + BugMeter = new CustLightButton(ww-bm_w,wh-sh,bm_w,sh); + BugMeter->image(icons->ImgMeterOK); + BugMeter->box(FL_THIN_DOWN_BOX); + BugMeter->align(FL_ALIGN_INSIDE | FL_ALIGN_TEXT_NEXT_TO_IMAGE); + BugMeter->tooltip("Show HTML bugs\n(right-click for menu)"); + BugMeter->callback(bugmeter_cb, this); + BugMeter->clear_visible_focus(); + + StatusBar->end(); + StatusBar->resizable(StatusOutput); + StatusBar->rearrange(); } /* * User Interface constructor */ -UI::UI(int x, int y, int ww, int wh, const char* label, const UI *cur_ui) : - Group(x, y, ww, wh, label) +UI::UI(int x, int y, int ui_w, int ui_h, const char* label, const UI *cur_ui) : + CustGroupVertical(x, y, ui_w, ui_h, label) { - PointerOnLink = FALSE; + LocBar = NavBar = StatusBar = NULL; Tabs = NULL; TabTooltip = NULL; - TopGroup = new PackedGroup(0, 0, ww, wh); - add(TopGroup); - resizable(TopGroup); - set_flag(RAW_LABEL); + TopGroup = this; + TopGroup->box(FL_NO_BOX); + clear_flag(SHORTCUT_LABEL); + PanelTemporary = false; if (cur_ui) { PanelSize = cur_ui->PanelSize; CuteColor = cur_ui->CuteColor; Small_Icons = cur_ui->Small_Icons; - if (cur_ui->Panelmode == UI_HIDDEN || - cur_ui->Panelmode == UI_TEMPORARILY_SHOW_PANELS) - Panelmode = UI_HIDDEN; - else - Panelmode = UI_NORMAL; + Panelmode = cur_ui->Panelmode; } else { // Set some default values - //PanelSize = P_tiny, CuteColor = 26, Small_Icons = 0; PanelSize = prefs.panel_size; Small_Icons = prefs.small_icons; CuteColor = 206; - Panelmode = (UIPanelmode) prefs.fullwindow_start; + Panelmode = (prefs.fullwindow_start) ? UI_HIDDEN : UI_NORMAL; } // Control panel - Panel = make_panel(ww); - TopGroup->add(Panel); - - // Render area - Main = new Widget(0,0,1,1,"Welcome..."); - Main->box(FLAT_BOX); - Main->color(GRAY15); - Main->labelfont(HELVETICA_BOLD_ITALIC); - Main->labelsize(36); - Main->labeltype(SHADOW_LABEL); - Main->labelcolor(WHITE); - TopGroup->add(Main); - TopGroup->resizable(Main); - MainIdx = TopGroup->find(Main); - - // Find text bar - findbar = new Findbar(ww, 28); - TopGroup->add(findbar); - - // Status Panel - StatusPanel = make_status_panel(ww); - TopGroup->add(StatusPanel); - - // Make the full screen button (to be attached to the viewport later) - // TODO: attach to the viewport - //FullScreen = new HighlightButton(0,0,15,15); - //FullScreen->image(ImgFullScreenOn); - //FullScreen->tooltip("Hide Controls"); - //FullScreen->callback(fullscreen_cb, this); + TopGroup->begin(); + make_panel(ui_w); + + // Render area + Main = new Fl_Group(0,0,0,0,"Welcome..."); // size is set by rearrange() + Main->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); + Main->box(FL_FLAT_BOX); + Main->color(FL_GRAY_RAMP + 3); + Main->labelfont(FL_HELVETICA_BOLD_ITALIC); + Main->labelsize(36); + Main->labeltype(FL_SHADOW_LABEL); + Main->labelcolor(FL_WHITE); + TopGroup->add(Main); + TopGroup->resizable(Main); + MainIdx = TopGroup->find(Main); + + // Find text bar + FindBar = new Findbar(ui_w, fh); + TopGroup->add(FindBar); + + // Status Panel + make_status_bar(ui_w, ui_h); + TopGroup->add(StatusBar); + TopGroup->end(); + TopGroup->rearrange(); customize(0); - if (Panelmode) { - Panel->hide(); - StatusPanel->hide(); + if (Panelmode == UI_HIDDEN) { + panels_toggle(); } } @@ -778,18 +697,27 @@ UI::~UI() */ int UI::handle(int event) { - _MSG("UI::handle event=%d (%d,%d)\n", event, event_x(), event_y()); - _MSG("Panel->h()=%d Main->h()=%d\n", Panel->h() , Main->h()); + _MSG("UI::handle event=%s\n", fl_eventnames[event]); int ret = 0; + if (event == FL_KEYBOARD) { + /* WORKAROUND: remove the Panel's fltk-tooltip. + * Although the expose event is delivered, it has an offset. This + * extra call avoids the lingering tooltip. */ + if (!Fl::event_inside(Main) && + (Fl::event_inside((Fl_Widget*)tabs()) || + Fl::event_inside(NavBar) || + (LocBar && Fl::event_inside(LocBar)) || + (StatusBar && Fl::event_inside(StatusBar)))) + window()->damage(FL_DAMAGE_EXPOSE,0,0,1,1); - if (event == KEY) { return 0; // Receive as shortcut - } else if (event == SHORTCUT) { + } else if (event == FL_SHORTCUT) { KeysCommand_t cmd = Keys::getKeyCmd(); if (cmd == KEYS_NOP) { // Do nothing } else if (cmd == KEYS_SCREEN_UP || cmd == KEYS_SCREEN_DOWN || + cmd == KEYS_SCREEN_LEFT || cmd == KEYS_SCREEN_RIGHT || cmd == KEYS_LINE_UP || cmd == KEYS_LINE_DOWN || cmd == KEYS_LEFT || cmd == KEYS_RIGHT || cmd == KEYS_TOP || cmd == KEYS_BOTTOM) { @@ -805,26 +733,22 @@ int UI::handle(int event) a_UIcmd_book(a_UIcmd_get_bw_by_widget(this)); ret = 1; } else if (cmd == KEYS_FIND) { - set_findbar_visibility(1); + findbar_toggle(1); ret = 1; } else if (cmd == KEYS_WEBSEARCH) { a_UIcmd_search_dialog(a_UIcmd_get_bw_by_widget(this)); ret = 1; } else if (cmd == KEYS_GOTO) { + if (Panelmode == UI_HIDDEN) { + panels_toggle(); + temporaryPanels(true); + } focus_location(); ret = 1; - } else if (cmd == KEYS_NEW_TAB) { - a_UIcmd_open_url_nt(a_UIcmd_get_bw_by_widget(this), NULL, 1); - ret = 1; - } else if (cmd == KEYS_CLOSE_TAB) { - a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (cmd == KEYS_HIDE_PANELS && - get_panelmode() == UI_TEMPORARILY_SHOW_PANELS) { - set_panelmode(UI_HIDDEN); - ret = 1; - } else if (cmd == KEYS_NEW_WINDOW) { - a_UIcmd_browser_window_new(w(),h(),0,a_UIcmd_get_bw_by_widget(this)); + } else if (cmd == KEYS_HIDE_PANELS) { + /* Hide findbar if present, hide panels if not */ + (FindBar->visible()) ? findbar_toggle(0) : panels_toggle(); + temporaryPanels(false); ret = 1; } else if (cmd == KEYS_OPEN) { a_UIcmd_open_file(a_UIcmd_get_bw_by_widget(this)); @@ -841,40 +765,26 @@ int UI::handle(int event) } else if (cmd == KEYS_SAVE) { a_UIcmd_save(a_UIcmd_get_bw_by_widget(this)); ret = 1; - } else if (cmd == KEYS_FULLSCREEN) { - panelmode_cb_i(); - ret = 1; } else if (cmd == KEYS_FILE_MENU) { a_UIcmd_file_popup(a_UIcmd_get_bw_by_widget(this), FileButton); ret = 1; - } else if (cmd == KEYS_CLOSE_ALL) { - a_Timeout_add(0.0, a_UIcmd_close_all_bw, NULL); - ret = 1; } - } else if (event == PUSH) { - if (prefs.middle_click_drags_page == 0 && - event_button() == MiddleButton && - !a_UIcmd_pointer_on_link(a_UIcmd_get_bw_by_widget(this))) { - if (Main->Rectangle::contains (event_x (), event_y ())) { - /* Offer the event to Main's children (form widgets) */ - int save_x = e_x, save_y = e_y; - - e_x -= Main->x(); - e_y -= Main->y(); - ret = ((Group *)Main)->Group::handle(event); - e_x = save_x; - e_y = save_y; - } - if (!ret) { - /* middle click was not on a link or a form widget */ - paste_url(); - ret = 1; - } + } else if (event == FL_RELEASE) { + if (Fl::event_button() == FL_MIDDLE_MOUSE && + prefs.middle_click_drags_page == 0) { + /* nobody claimed the event; try paste */ + paste_url(); + ret = 1; } } if (!ret) { - ret = Group::handle(event); + ret = Fl_Group::handle(event); + } + if (!ret && event == FL_PUSH && !prefs.middle_click_drags_page) { + /* nobody claimed FL_PUSH: ask for FL_RELEASE, + * which is necessary for middle-click paste URL) */ + ret = 1; } return ret; @@ -899,9 +809,7 @@ const char *UI::get_location() void UI::set_location(const char *str) { if (!str) str = ""; - // This text() call clears fl_pending_callback, avoiding - // an extra location_cb() call. - Location->text(str); + Location->value(str); Location->position(strlen(str)); } @@ -911,9 +819,6 @@ void UI::set_location(const char *str) */ void UI::focus_location() { - if (get_panelmode() == UI_HIDDEN) { - set_panelmode(UI_TEMPORARILY_SHOW_PANELS); - } Location->take_focus(); // Make text selected when already focused. Location->position(Location->size(), 0); @@ -932,7 +837,7 @@ void UI::focus_main() */ void UI::set_status(const char *str) { - Status->value(str); + StatusOutput->value(str); } /* @@ -985,7 +890,7 @@ void UI::set_img_prog(int n_img, int t_img, int cmd) void UI::set_bug_prog(int n_bug) { char str[32]; - int new_w = 16; + int new_w = 20; if (n_bug == 0) { BugMeter->image(icons->ImgMeterOK); @@ -995,12 +900,10 @@ void UI::set_bug_prog(int n_bug) BugMeter->image(icons->ImgMeterBug); snprintf(str, 32, "%d", n_bug); BugMeter->copy_label(str); - BugMeter->redraw_label(); - new_w = strlen(str)*8 + 20; + new_w = strlen(str)*9 + 20; } - Status->resize(0,0,StatusPanel->w()-new_w,Status->h()); - BugMeter->resize(StatusPanel->w()-new_w, 0, new_w, BugMeter->h()); - StatusPanel->init_sizes(); + BugMeter->size(new_w, BugMeter->h()); + StatusBar->rearrange(); } /* @@ -1034,25 +937,40 @@ void UI::customize(int flags) Search->hide(); if ( !prefs.show_help ) Help->hide(); - if ( !prefs.show_progress_box ) - ProgBox->hide(); + if ( !prefs.show_progress_box ) { + IProg->hide(); + PProg->hide(); + } + + if (NavBar) + NavBar->rearrange(); + if (LocBar) + LocBar->rearrange(); } /* * On-the-fly panel style change */ -void UI::panel_cb_i() +void UI::change_panel(int new_size, int small_icons) { - Group *NewPanel; - - // Create a new Panel - ++PanelSize; - NewPanel = make_panel(TopGroup->w()); - TopGroup->replace(*Panel, *NewPanel); - delete(Panel); - Panel = NewPanel; + // Remove current panel's bars + init_sizes(); + TopGroup->remove(LocBar); + Fl::delete_widget(LocBar); + TopGroup->remove(NavBar); + Fl::delete_widget(NavBar); + LocBar = NavBar = NULL; + + // Set internal vars for panel size + PanelSize = new_size; + Small_Icons = small_icons; + + // make a new panel + make_panel(TopGroup->w()); customize(0); + a_UIcmd_set_buttons_sens(a_UIcmd_get_bw_by_widget(this)); + TopGroup->rearrange(); Location->take_focus(); } @@ -1069,88 +987,21 @@ void UI::color_change_cb_i() MSG("Location color %d\n", CuteColor); Location->color(CuteColor); Location->redraw(); - HighlightButton::default_style->highlight_color(CuteColor); -} - -/* - * Set or remove the Panelmode flag and update the UI accordingly - */ -void UI::set_panelmode(UIPanelmode mode) -{ - if (mode == UI_HIDDEN) { - Panel->hide(); - StatusPanel->hide(); - } else { - /* UI_NORMAL or UI_TEMPORARILY_SHOW_PANELS */ - Panel->show(); - StatusPanel->show(); - } - Panelmode = mode; -} - -/* - * Get the value of the panelmode flag - */ -UIPanelmode UI::get_panelmode() -{ - return Panelmode; -} - -/* - * Toggle the Control Panel out of the way - */ -void UI::panelmode_cb_i() -{ - set_panelmode((UIPanelmode) !Panelmode); } /* * Set 'nw' as the main render area widget */ -void UI::set_render_layout(Widget &nw) +void UI::set_render_layout(Fl_Group *nw) { - // BUG: replace() is not working as it should. - // In our case, replacing the rendering area leaves the vertical - // scrollbar without events. - // - // We'll use a workaround in a_UIcmd_browser_window_new() instead. - TopGroup->replace(MainIdx, nw); - delete(Main); - Main = &nw; - //TopGroup->box(DOWN_BOX); - //TopGroup->box(BORDER_FRAME); - TopGroup->resizable(TopGroup->child(MainIdx)); -} + // Resize layout widget to current height + nw->resize(0,Main->y(),Main->w(),Main->h()); -/* - * Set the tab title - */ -void UI::set_tab_title(const char *label) -{ - char title[128]; - - dReturn_if_fail(label != NULL); - - if (*label) { - // Make a label for this tab - size_t tab_chars = 18, label_len = strlen(label); - - if (label_len > tab_chars) - tab_chars = a_Utf8_end_of_char(label, tab_chars - 1) + 1; - snprintf(title, tab_chars + 1, "%s", label); - if (label_len > tab_chars) - snprintf(title + tab_chars, 4, "..."); - // Avoid unnecessary redraws - if (strcmp(this->label(), title)) { - this->copy_label(title); - this->redraw_label(); - } - - // Disabled because of a bug in fltk::Tabgroup - //dFree(TabTooltip); - //TabTooltip = dStrdup(label); - //this->tooltip(TabTooltip); - } + TopGroup->insert(*nw, Main); + remove(Main); + delete(Main); + Main = nw; + TopGroup->resizable(Main); } /* @@ -1161,15 +1012,12 @@ void UI::button_set_sens(UIButton btn, int sens) switch (btn) { case UI_BACK: (sens) ? Back->activate() : Back->deactivate(); - Back->redraw(DAMAGE_HIGHLIGHT); break; case UI_FORW: (sens) ? Forw->activate() : Forw->deactivate(); - Forw->redraw(DAMAGE_HIGHLIGHT); break; case UI_STOP: (sens) ? Stop->activate() : Stop->deactivate(); - Stop->redraw(DAMAGE_HIGHLIGHT); break; default: break; @@ -1181,17 +1029,63 @@ void UI::button_set_sens(UIButton btn, int sens) */ void UI::paste_url() { - paste(*Clear, false); + Fl::paste(*Clear, false); } /* - * Shows or hides the findbar of this window + * Adjust space for the findbar (if necessary) and show or remove it */ -void UI::set_findbar_visibility(bool visible) +void UI::findbar_toggle(bool add) { - if (visible) { - findbar->show(); + /* WORKAROUND: + * This is tricky: As fltk-1.3 resizes hidden widgets (which it + * doesn't resize when visible!). We need to set the size to (0,0) to + * get the desired behaviour. + * (STR#2639 in FLTK bug tracker). + */ + + if (add) { + if (!FindBar->visible()) + FindBar->size(w(), fh); + FindBar->show(); } else { - findbar->hide(); + // hide + FindBar->size(0,0); + FindBar->hide(); + // reset state + a_UIcmd_findtext_reset(a_UIcmd_get_bw_by_widget(this)); + // focus main area + focus_main(); + } + TopGroup->rearrange(); +} + +/* + * Make panels disappear growing the render area. + * WORKAROUND: here we avoid hidden widgets resize by setting their + * size to (0,0) while hidden. + * (Already reported to FLTK team) + */ +void UI::panels_toggle() +{ + int hide = StatusBar->visible(); + + // hide/show panels + init_sizes(); + if (LocBar) { + hide ? LocBar->size(0,0) : LocBar->size(w(),lh); + hide ? LocBar->hide() : LocBar->show(); } + if (NavBar) { + hide ? NavBar->size(0,0) : NavBar->size(w(),nh); + hide ? NavBar->hide() : NavBar->show(); + } + if (StatusBar) { + hide ? StatusBar->size(0,0) : StatusBar->size(w(),sh);; + hide ? StatusBar->hide() : StatusBar->show();; + StatusBar->rearrange(); + } + + TopGroup->rearrange(); + Panelmode = (hide) ? UI_HIDDEN : UI_NORMAL; } @@ -3,16 +3,13 @@ // UI for dillo -------------------------------------------------------------- -#include <fltk/Window.h> -#include <fltk/Widget.h> -#include <fltk/Button.h> -#include <fltk/Input.h> -#include <fltk/PackedGroup.h> -#include <fltk/Output.h> -#include <fltk/Image.h> -#include <fltk/MultiImage.h> -#include <fltk/MenuBuild.h> -#include <fltk/TabGroup.h> +#include <FL/Fl_Window.H> +#include <FL/Fl_Widget.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Input.H> +#include <FL/Fl_Output.H> +#include <FL/Fl_Image.H> +#include <FL/Fl_Tabs.H> #include "findbar.hh" @@ -31,47 +28,153 @@ typedef enum { typedef enum { UI_NORMAL = 0, /* make sure it's compatible with bool */ - UI_HIDDEN = 1, - UI_TEMPORARILY_SHOW_PANELS + UI_HIDDEN = 1 } UIPanelmode; + +// Min size to fit the full UI +#define UI_MIN_W 600 +#define UI_MIN_H 200 + // Private classes class CustProgressBox; -class CustTabGroup; +class CustTabs; + + +// Class definitions --------------------------------------------------------- +/* + * Used to reposition group's widgets when some of them are hidden. + * All children get the height of the group but retain their original width. + * The resizable child get's the remaining space. + */ +class CustGroupHorizontal : public Fl_Group { + Fl_Widget *rsz; +public: + CustGroupHorizontal(int x,int y,int w ,int h,const char *l = 0) : + Fl_Group(x,y,w,h,l) { }; + + void rearrange() { + Fl_Widget*const* a = array(); + int sum = 0, _x = x(); + int children_ = children(); + + if (resizable()) + rsz = resizable(); + + for (int i=0; i < children_; i++) + if (a[i] != resizable() && a[i]->visible()) + sum += a[i]->w(); + + for (int i=0; i < children_; i++) { + if (a[i] == rsz) { + if (w() > sum) { + a[i]->resize(_x, y(), w()-sum, h()); + if (!resizable()) + resizable(rsz); + } else { + /* widgets overflow width */ + a[i]->resize(_x, y(), 0, h()); + resizable(NULL); + } + } else { + a[i]->resize(_x, y(), a[i]->w(), h()); + } + if (a[i]->visible()) + _x += a[i]->w(); + } + init_sizes(); + redraw(); + } +}; + +class CustGroupVertical : public Fl_Group { +public: + CustGroupVertical(int x,int y,int w ,int h,const char *l = 0) : + Fl_Group(x,y,w,h,l) { }; + + void rearrange() { + Fl_Widget*const* a = array(); + int sum = 0, _y = y(); + int children_ = children(); + + for (int i=0; i < children_; i++) + if (a[i] != resizable() && a[i]->visible()) + sum += a[i]->h(); + + for (int i=0; i < children_; i++) { + if (a[i] == resizable()) { + a[i]->resize(x(), _y, w(), h() - sum); + } else { + a[i]->resize(x(), _y, w(), a[i]->h()); + } + if (a[i]->visible()) + _y += a[i]->h(); + } + init_sizes(); + redraw(); + } +}; + +/* + * A button that highlights on mouse over + */ +class CustLightButton : public Fl_Button { + Fl_Color norm_color, light_color; +public: + CustLightButton(int x, int y, int w, int h, const char *l=0) : + Fl_Button(x,y,w,h,l) { norm_color = color(); light_color = 51; }; + virtual int handle(int e) + { + if (active()) { + if (e == FL_ENTER) { + color(light_color); // {17,26,51} + redraw(); + } else if (e == FL_LEAVE || e == FL_RELEASE || e == FL_HIDE) { + color(norm_color); + redraw(); + } + } else if (e == FL_DEACTIVATE && color() != norm_color) { + color(norm_color); + redraw(); + } + return Fl_Button::handle(e); + } + void hl_color(Fl_Color col) { light_color = col; }; +}; // // UI class definition ------------------------------------------------------- // -class UI : public fltk::Group { - CustTabGroup *Tabs; +class UI : public CustGroupVertical { + CustTabs *Tabs; char *TabTooltip; - fltk::Group *TopGroup; - fltk::Button *Back, *Forw, *Home, *Reload, *Save, *Stop, *Bookmarks, *Tools, - *Clear, *Search, *Help, *FullScreen, *BugMeter, *FileButton; - fltk::Input *Location; - fltk::PackedGroup *ProgBox; + CustGroupVertical *TopGroup; + Fl_Button *Back, *Forw, *Home, *Reload, *Save, *Stop, *Bookmarks, *Tools, + *Clear, *Search, *Help, *BugMeter, *FileButton; + CustGroupHorizontal *LocBar, *NavBar, *StatusBar; + Fl_Input *Location; CustProgressBox *PProg, *IProg; - fltk::Group *Panel, *StatusPanel; - fltk::Widget *Main; - fltk::Output *Status; + Fl_Group *Panel, *Main; + Fl_Output *StatusOutput; + Findbar *FindBar; int MainIdx; // Panel customization variables int PanelSize, CuteColor, Small_Icons; - int xpos, bw, bh, fh, lh, lbl; + int p_xpos, p_ypos, bw, bh, mh, lh, nh, fh, sh, pw, lbl; + bool PanelTemporary; UIPanelmode Panelmode; - Findbar *findbar; - int PointerOnLink; - - fltk::PackedGroup *make_toolbar(int tw, int th); - fltk::PackedGroup *make_location(); - fltk::PackedGroup *make_progress_bars(int wide, int thin_up); + Fl_Button *make_button(const char *label, Fl_Image *img, + Fl_Image*deimg, int b_n, int start = 0); + void make_toolbar(int tw, int th); + void make_location(int ww); + void make_progress_bars(int wide, int thin_up); void make_menubar(int x, int y, int w, int h); - fltk::Widget *make_filemenu_button(); - fltk::Group *make_panel(int ww); - fltk::Group *make_status_panel(int ww); + Fl_Widget *make_filemenu_button(); + void make_panel(int ww); + void make_status_bar(int ww, int wh); public: @@ -89,27 +192,24 @@ public: void set_page_prog(size_t nbytes, int cmd); void set_img_prog(int n_img, int t_img, int cmd); void set_bug_prog(int n_bug); - void set_render_layout(Widget &nw); - void set_tab_title(const char *label); + void set_render_layout(Fl_Group *nw); void customize(int flags); void button_set_sens(UIButton btn, int sens); void paste_url(); - void set_panelmode(UIPanelmode mode); - UIPanelmode get_panelmode(); - void set_findbar_visibility(bool visible); - Widget *fullscreen_button() { return FullScreen; } - void fullscreen_toggle() { FullScreen->do_callback(); } + int get_panelsize() { return PanelSize; } + int get_smallicons() { return Small_Icons; } + void change_panel(int new_size, int small_icons); + void findbar_toggle(bool add); + void panels_toggle(); - CustTabGroup *tabs() { return Tabs; } - void tabs(CustTabGroup *tabs) { Tabs = tabs; } - int pointerOnLink() { return PointerOnLink; } - void pointerOnLink(int flag) { PointerOnLink = flag; } + CustTabs *tabs() { return Tabs; } + void tabs(CustTabs *tabs) { Tabs = tabs; } + bool temporaryPanels() { return PanelTemporary; } + void temporaryPanels(bool val) { PanelTemporary = val; } // Hooks to method callbacks - void panel_cb_i(); void color_change_cb_i(); void toggle_cb_i(); - void panelmode_cb_i(); }; #endif // __UI_HH__ diff --git a/src/uicmd.cc b/src/uicmd.cc index 5573db11..38225047 100644 --- a/src/uicmd.cc +++ b/src/uicmd.cc @@ -1,7 +1,7 @@ /* * File: uicmd.cc * - * Copyright (C) 2005-2007 Jorge Arellano Cid <jcid@dillo.org> + * Copyright (C) 2005-2011 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,11 +16,14 @@ #include <stdarg.h> #include <math.h> /* for rint */ -#include <fltk/draw.h> -#include <fltk/damage.h> -#include <fltk/Widget.h> -#include <fltk/TabGroup.h> -#include <fltk/Tooltip.h> +#include <FL/Fl.H> +#include <FL/Fl_Widget.H> +#include <FL/Fl_Double_Window.H> +#include <FL/Fl_Wizard.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Pack.H> +#include <FL/Fl_Scroll.H> +#include <FL/names.h> #include "paths.hh" #include "keys.hh" @@ -35,12 +38,14 @@ #include "history.h" #include "msg.h" #include "prefs.h" +#include "misc.h" #include "dw/fltkviewport.hh" #include "nav.h" -#define DEFAULT_TAB_LABEL "Dillo" +//#define DEFAULT_TAB_LABEL "-.untitled.-" +#define DEFAULT_TAB_LABEL "-.new.-" // Handy macro #define BW2UI(bw) ((UI*)((bw)->ui)) @@ -56,316 +61,384 @@ using namespace dw::fltk; */ static char *save_dir = NULL; -using namespace fltk; - +/* + * Forward declarations + */ +static BrowserWindow *UIcmd_tab_new(CustTabs *tabs, UI *old_ui, int focus); +static void close_tab_btn_cb (Fl_Widget *w, void *cb_data); //---------------------------------------------------------------------------- -#define BTN_W 25 -#define BTN_H 20 -static int btn_x; +/* + * CustTabs --------------------------------------------------------------- + */ /* - * Adds a tab-close button at the rightmost part + * stores the respective UI pointer */ -class CustShrinkTabPager : public TabGroupPager { - bool btn_hl; - TabGroup *tg; +class CustTabButton : public Fl_Button { + UI *ui_; public: - int update_positions( - TabGroup *g, int numchildren, int &selected, - int &cumulated_width, int &available_width, - int *tab_pos, int *tab_width); - virtual int which(TabGroup* g, int m_x,int m_y); - virtual TabGroupPager* clone() const; - virtual const char * mode_name() const {return "Shrink";} - virtual int id() const {return PAGER_SHRINK;} - virtual int available_width(TabGroup *g) const; - virtual bool draw_tabs(TabGroup* g, int selected, int* tab_pos, - int* tab_width) { - if (!tg) tg = g; - if (g->children() > 1) { - fltk::Rectangle r(btn_x,0,BTN_W,BTN_H); - setcolor(btn_hl ? 206 : GRAY75); - fillrect(r); - if (btn_hl) { - setcolor(WHITE); - strokerect(r); - } - setcolor(GRAY10); - //fltk::setfont(fltk::getfont()->bold(), fltk::getsize()); - r.h(r.h()-2); - drawtext("X", r, ALIGN_CENTER); - return false; - } else { - // WORKAROUND: for http://fltk.org/str.php?L2062 - // By returning true we avoid a call to TabGroup::draw_tab() - // in TabGroup::draw() in case we don't show the tabs. - return true; - } - } + CustTabButton (int x,int y,int w,int h, const char* label = 0) : + Fl_Button (x,y,w,h,label) { ui_ = NULL; }; + void ui(UI *pui) { ui_ = pui; } + UI *ui(void) { return ui_; } +}; - void btn_highlight(bool flag) { - if (btn_hl != flag) { - btn_hl = flag; - if (tg) - tg->redraw(DAMAGE_VALUE); - } - }; - bool btn_highlight() { return btn_hl; }; +/* + * Allows fine control of the tabbed interface + */ +class CustTabs : public Fl_Group { + int tab_w, tab_h, ctab_h, btn_w, ctl_w; + Fl_Wizard *Wizard; + Fl_Scroll *Scroll; + Fl_Pack *Pack; + Fl_Group *Control; + CustLightButton *CloseBtn; + int tabcolor_inactive, tabcolor_active; - CustShrinkTabPager() : TabGroupPager() { - noclip(true); - btn_hl = false; - tg = NULL; - } + void update_pack_offset(void); + void resize(int x, int y, int w, int h) + { Fl_Group::resize(x,y,w,h); update_pack_offset(); } + int get_btn_idx(UI *ui); + +public: + CustTabs (int ww, int wh, int th, const char *lbl=0) : + Fl_Group(0,0,ww,th,lbl) { + Pack = NULL; + tab_w = 50, tab_h = th, ctab_h = 1, btn_w = 20, ctl_w = 1*btn_w+2; + tabcolor_active = 0x87aca700; tabcolor_inactive = 0xb7beb700; + resize(0,0,ww,ctab_h); + /* tab buttons go inside a pack within a scroll */ + Scroll = new Fl_Scroll(0,0,ww-ctl_w,ctab_h); + Scroll->type(0); /* no scrollbars */ + Scroll->box(FL_NO_BOX); + Pack = new Fl_Pack(0,0,ww-ctl_w,tab_h); + Pack->type(Fl_Pack::HORIZONTAL); + Pack->box(FL_NO_BOX); //FL_THIN_DOWN_FRAME + Pack->end(); + Scroll->end(); + resizable(Scroll); + + /* control buttons go inside a group */ + Control = new Fl_Group(ww-ctl_w,0,ctl_w,ctab_h); + CloseBtn = new CustLightButton(ww-ctl_w+2,0,btn_w,ctab_h, "X"); + CloseBtn->box(FL_THIN_UP_BOX); + CloseBtn->labelcolor(0x00641000); + CloseBtn->hl_color(FL_WHITE); + CloseBtn->clear_visible_focus(); + CloseBtn->tooltip(prefs.right_click_closes_tab ? + "Close current tab.\nor Right-click tab label to close." : + "Close current tab.\nor Middle-click tab label to close."); + CloseBtn->callback(close_tab_btn_cb, this); + CloseBtn->hide(); + Control->end(); + + box(FL_FLAT_BOX); + end(); + + Wizard = new Fl_Wizard(0,ctab_h,ww,wh-ctab_h); + Wizard->box(FL_NO_BOX); + Wizard->end(); + }; + int handle(int e); + UI *add_new_tab(UI *old_ui, int focus); + void remove_tab(UI *ui); + Fl_Wizard *wizard(void) { return Wizard; } + int num_tabs() { return (Pack ? Pack->children() : 0); } + void switch_tab(CustTabButton *cbtn); + void prev_tab(void); + void next_tab(void); + void set_tab_label(UI *ui, const char *title); }; -int CustShrinkTabPager::available_width(TabGroup *g) const +/* + * Callback for mouse click + */ +static void tab_btn_cb (Fl_Widget *w, void *cb_data) { - _MSG("CustShrinkTabPager::available_width\n"); - int w = MAX (g->w() - this->slope()-1 - BTN_W, 0); - btn_x = w + 6; - return w; + CustTabButton *btn = (CustTabButton*) w; + CustTabs *tabs = (CustTabs*) cb_data; + int b = Fl::event_button(); + + if (b == FL_LEFT_MOUSE) { + tabs->switch_tab(btn); + } else if ((b == FL_RIGHT_MOUSE && prefs.right_click_closes_tab) || + (b == FL_MIDDLE_MOUSE && !prefs.right_click_closes_tab)) { + // TODO: just an example, not necessarily final + a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(btn->ui())); + } } -int CustShrinkTabPager::which(TabGroup* g, int event_x,int event_y) +/* + * Callback for the close-tab button + */ +static void close_tab_btn_cb (Fl_Widget *, void *cb_data) { - int H = g->tab_height(); - if (!H) return -1; - if (H < 0) { - if (event_y > g->h() || event_y < g->h()+H) return -1; - } else { - if (event_y > H || event_y < 0) return -1; + CustTabs *tabs = (CustTabs*) cb_data; + int b = Fl::event_button(); + + if (b == FL_LEFT_MOUSE) { + a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(tabs->wizard()->value())); } - if (event_x < 0) return -1; - int p[128], w[128]; - int selected = g->tab_positions(p, w); - int d = (event_y-(H>=0?0:g->h()))*slope()/H; - for (int i=0; i<g->children(); i++) { - if (event_x < p[i+1]+(i<selected ? slope() - d : d)) return i; +} + +int CustTabs::handle(int e) +{ + int ret = 0; + + _MSG("CustTabs::handle e=%s\n", fl_eventnames[e]); + if (e == FL_KEYBOARD) { + return 0; // Receive as shortcut + } else if (e == FL_SHORTCUT) { + UI *ui = (UI*)wizard()->value(); + BrowserWindow *bw = a_UIcmd_get_bw_by_widget(ui); + KeysCommand_t cmd = Keys::getKeyCmd(); + if (cmd == KEYS_NOP) { + // Do nothing + _MSG("CustTabs::handle KEYS_NOP\n"); + } else if (cmd == KEYS_NEW_TAB) { + a_UIcmd_open_url_nt(bw, NULL, 1); + ret = 1; + } else if (cmd == KEYS_CLOSE_TAB) { + a_UIcmd_close_bw(bw); + ret = 1; + } else if (cmd == KEYS_LEFT_TAB) { + prev_tab(); + ret = 1; + } else if (cmd == KEYS_RIGHT_TAB) { + next_tab(); + ret = 1; + } else if (cmd == KEYS_NEW_WINDOW) { + a_UIcmd_open_url_nw(bw, NULL); + ret = 1; + } else if (cmd == KEYS_CLOSE_ALL) { + a_Timeout_add(0.0, a_UIcmd_close_all_bw, NULL); + ret = 1; + } } - return -1; + + return (ret) ? ret : Fl_Group::handle(e); } /* - * Prevents tabs from going over the close-tab button. - * Modified from fltk-2.0.x-r6525. + * Create a new tab with its own UI */ -int CustShrinkTabPager::update_positions( - TabGroup *g, int numchildren, int &selected, - int &cumulated_width, int &available_width, - int *tab_pos, int *tab_width) +UI *CustTabs::add_new_tab(UI *old_ui, int focus) { - available_width-=BTN_W; - - // uh oh, they are too big, we must move them: - // special case when the selected tab itself is too big, make it fill - // cumulated_width: - int i; + if (num_tabs() == 1) { + // Show tabbar + ctab_h = tab_h; + Wizard->resize(0,ctab_h,Wizard->w(),window()->h()-ctab_h); + resize(0,0,window()->w(),ctab_h); // tabbar + CloseBtn->show(); + {int w = 0, h; Pack->child(0)->measure_label(w, h); + Pack->child(0)->size(w+14,ctab_h);} + Pack->child(0)->show(); // first tab button + window()->init_sizes(); + } - if (tab_width[selected] >= available_width) { - tab_width[selected] = available_width; - for (i = 0; i <= selected; i++) - tab_pos[i] = 0; - for (i = selected + 1; i <= numchildren; i++) - tab_pos[i] = available_width; - return selected; + /* The UI is constructed in a comfortable fitting size, and then resized + * so FLTK doesn't get confused later with even smaller dimensions! */ + current(0); + UI *new_ui = new UI(0,0,UI_MIN_W,UI_MIN_H,"Dillo:",old_ui); + new_ui->resize(0,ctab_h,Wizard->w(),Wizard->h()); + new_ui->tabs(this); + Wizard->add(new_ui); + new_ui->show(); + + CustTabButton *btn = new CustTabButton(num_tabs()*tab_w,0,tab_w,ctab_h); + btn->align(FL_ALIGN_INSIDE); + btn->labelsize(btn->labelsize()-2); + btn->copy_label(DEFAULT_TAB_LABEL); + btn->clear_visible_focus(); + btn->box(FL_GTK_THIN_UP_BOX); + btn->color(focus ? tabcolor_active : tabcolor_inactive); + btn->ui(new_ui); + btn->callback(tab_btn_cb, this); + Pack->add(btn); // append + + if (focus) { + switch_tab(btn); + } else if (num_tabs() == 2) { + // no focus and tabbar added: redraw current page + Wizard->redraw(); } + if (num_tabs() == 1) + btn->hide(); + update_pack_offset(); - int w2[128]; + return new_ui; +} - for (i = 0; i < numchildren; i++) - w2[i] = tab_width[i]; - i = numchildren - 1; - int j = 0; +/* + * Remove tab by UI + */ +void CustTabs::remove_tab(UI *ui) +{ + CustTabButton *btn; - int minsize = 5; + // get active tab idx + int act_idx = get_btn_idx((UI*)Wizard->value()); + // get to-be-removed tab idx + int rm_idx = get_btn_idx(ui); + btn = (CustTabButton*)Pack->child(rm_idx); - bool right = true; + if (act_idx == rm_idx) { + // Active tab is being closed, switch to another one + rm_idx > 0 ? prev_tab() : next_tab(); + } + Pack->remove(rm_idx); + update_pack_offset(); + delete btn; - while (cumulated_width > available_width) { - int n; // which one to shrink + Wizard->remove(ui); + delete(ui); - if (j < selected && (!right || i <= selected)) { // shrink a left one - n = j++; - right = true; - } else if (i > selected) { // shrink a right one - n = i--; - right = false; - } else { // no more space, start making them zero - minsize = 0; - i = numchildren - 1; - j = 0; - right = true; - continue; - } - cumulated_width -= w2[n] - minsize; - w2[n] = minsize; - if (cumulated_width < available_width) { - w2[n] = available_width - cumulated_width + minsize; - cumulated_width = available_width; - break; - } + if (num_tabs() == 1) { + // hide tabbar + ctab_h = 1; + CloseBtn->hide(); + Pack->child(0)->size(0,0); + Pack->child(0)->hide(); // first tab button + resize(0,0,window()->w(),ctab_h); // tabbar + Wizard->resize(0,ctab_h,Wizard->w(),window()->h()-ctab_h); + window()->init_sizes(); + window()->redraw(); } - // re-sum the positions: - cumulated_width = 0; - for (i = 0; i < numchildren; i++) { - cumulated_width += w2[i]; - tab_pos[i+1] = cumulated_width; - } - return selected; } -TabGroupPager* CustShrinkTabPager::clone() const { - return new CustShrinkTabPager(*this); +int CustTabs::get_btn_idx(UI *ui) +{ + for (int i = 0; i < num_tabs(); ++i) { + CustTabButton *btn = (CustTabButton*)Pack->child(i); + if (btn->ui() == ui) + return i; + } + return -1; } -//---------------------------------------------------------------------------- +/* + * Keep active tab visible + * (Pack children have unusable x() coordinate) + */ +void CustTabs::update_pack_offset() +{ + dReturn_if (num_tabs() == 0); + + // get active tab button + int act_idx = get_btn_idx((UI*)Wizard->value()); + CustTabButton *cbtn = (CustTabButton*)Pack->child(act_idx); + + // calculate tab button's x() coordinates + int x_i = 0, x_f; + for (int j=0; j < act_idx; ++j) + x_i += Pack->child(j)->w(); + x_f = x_i + cbtn->w(); + + int scr_x = Scroll->xposition(), scr_y = Scroll->yposition(); + int px_i = x_i - scr_x; + int px_f = px_i + cbtn->w(); + int pw = Scroll->window()->w() - ctl_w; + _MSG(" scr_x=%d btn_x=%d px_i=%d btn_w=%d px_f=%d pw=%d", + Scroll->xposition(),cbtn->x(),px_i,cbtn->w(),px_f,pw); + if (px_i < 0) { + Scroll->scroll_to(x_i, scr_y); + } else if (px_i > pw || (px_i > 0 && px_f > pw)) { + Scroll->scroll_to(MIN(x_i, x_f-pw), scr_y); + } + Scroll->redraw(); + _MSG(" >>scr_x=%d btn0_x=%d\n", scr_x, Pack->child(0)->x()); +} /* - * For custom handling of keyboard + * Make cbtn's tab the active one */ -class CustTabGroup : public fltk::TabGroup { - Tooltip *toolTip; - bool tooltipEnabled; - bool buttonPushed; -public: - CustTabGroup (int x, int y, int ww, int wh, const char *lbl=0) : - TabGroup(x,y,ww,wh,lbl) { - // The parameter pager is cloned, so free it. - CustShrinkTabPager *cp = new CustShrinkTabPager(); - this->pager(cp); - delete cp; - toolTip = new Tooltip; - tooltipEnabled = false; - buttonPushed = false; - }; - ~CustTabGroup() { delete toolTip; } - int handle(int e) { - // Don't focus with arrow keys - _MSG("CustTabGroup::handle %d\n", e); - fltk::Rectangle r(btn_x,0,BTN_W,BTN_H); - if (e == KEY) { - int k = event_key(); - // We're only interested in some flags - unsigned modifier = event_state() & (SHIFT | CTRL | ALT); - if (k == UpKey || k == DownKey || k == TabKey) { - return 0; - } else if (k == LeftKey || k == RightKey) { - if (modifier == SHIFT) { - int i = value(); - if (k == LeftKey) {i = i ? i-1 : children()-1;} - else {i++; if (i >= children()) i = 0;} - selected_child(child(i)); - return 1; - } - // Avoid focus change. - return 0; - } - } else if (e == FOCUS_CHANGE) { - // Update the window title - BrowserWindow *bw = a_UIcmd_get_bw_by_widget(selected_child()); - const char *title = a_History_get_title(NAV_TOP_UIDX(bw), 1); - a_UIcmd_set_page_title(bw, title ? title : ""); - } else if (e == MOVE) { - CustShrinkTabPager *cstp = (CustShrinkTabPager *) pager(); - if (event_inside(r) && children() > 1) { - /* We're inside the button area */ - cstp->btn_highlight(true); - if (prefs.show_tooltip) { - /* Prepare the tooltip for pop-up */ - tooltipEnabled = true; - /* We use parent() if available because we are returning 0. - * Returning without having TabGroup processing makes the - * popup event never reach 'this', but it reaches parent() */ - toolTip->enter(parent() ?parent():this, r, "Close current Tab"); - } - return 0; // Change focus - } else { - cstp->btn_highlight(false); - - if (prefs.show_tooltip) { - /* Hide the tooltip or enable it again.*/ - if (tooltipEnabled) { - tooltipEnabled = false; - toolTip->exit(); - } else { - toolTip->enable(); - } - } - } - } else if (e == PUSH && event_inside(r) && - event_button() == 1 && children() > 1) { - buttonPushed = true; - return 1; /* non-zero */ - } else if (e == RELEASE) { - if (event_inside(r) && event_button() == 1 && - children() > 1 && buttonPushed) { - a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(selected_child())); - } else { - CustShrinkTabPager *cstp = (CustShrinkTabPager *) pager(); - cstp->btn_highlight(false); - } - buttonPushed = false; - } else if (e == DRAG) { - /* Ignore this event */ - return 1; +void CustTabs::switch_tab(CustTabButton *cbtn) +{ + int idx; + CustTabButton *btn; + BrowserWindow *bw; + UI *old_ui = (UI*)Wizard->value(); + + if (cbtn->ui() != old_ui) { + // Set old tab label to normal color + if ((idx = get_btn_idx(old_ui)) != -1) { + btn = (CustTabButton*)Pack->child(idx); + btn->color(tabcolor_inactive); + btn->redraw(); } - int ret = TabGroup::handle(e); - - if (e == PUSH) { - /* WORKAROUND: FLTK raises the window on unhandled clicks, - * which we do not want. - */ - ret = 1; + Wizard->value(cbtn->ui()); + cbtn->color(tabcolor_active); + cbtn->redraw(); + update_pack_offset(); + + // Update window title + if ((bw = a_UIcmd_get_bw_by_widget(cbtn->ui()))) { + const char *title = (cbtn->ui())->label(); + cbtn->window()->copy_label(title ? title : ""); } - return ret; } +} - void remove (Widget *w) { - TabGroup::remove (w); - /* fixup resizable in case we just removed it */ - if (resizable () == w) { - if (children () > 0) - resizable (child (children () - 1)); - else - resizable (NULL); - } +void CustTabs::prev_tab() +{ + int idx; - if (children () < 2) - hideLabels (); - } + if ((idx = get_btn_idx((UI*)Wizard->value())) != -1) + switch_tab((CustTabButton*)Pack->child(idx>0 ? idx-1 : num_tabs()-1)); +} - void add (Widget *w) { - TabGroup::add (w); - if (children () > 1) - showLabels (); - } +void CustTabs::next_tab() +{ + int idx; - void hideLabels() { - for (int i = children () - 1; i >= 0; i--) - child(i)->resize(x(), y(), w(), h()); - } + if ((idx = get_btn_idx((UI*)Wizard->value())) != -1) + switch_tab((CustTabButton*)Pack->child((idx+1<num_tabs()) ? idx+1 : 0)); +} + +/* + * Set this UI's tab button label + */ +void CustTabs::set_tab_label(UI *ui, const char *label) +{ + char title[128]; + int idx = get_btn_idx(ui); + + if (idx != -1) { + // Make a label for this tab + size_t tab_chars = 15, label_len = strlen(label); - void showLabels() { - for (int i = children () - 1; i >= 0; i--) - child(i)->resize(x(), y() + 20, w(), h() - 20); + if (label_len > tab_chars) + tab_chars = a_Utf8_end_of_char(label, tab_chars - 1) + 1; + snprintf(title, tab_chars + 1, "%s", label); + if (label_len > tab_chars) + snprintf(title + tab_chars, 4, "..."); + + // Avoid unnecessary redraws + if (strcmp(Pack->child(idx)->label(), title)) { + int w = 0, h; + Pack->child(idx)->copy_label(title); + Pack->child(idx)->measure_label(w, h); + Pack->child(idx)->size(w+14,ctab_h); + update_pack_offset(); + } } -}; +} + //---------------------------------------------------------------------------- -static void win_cb (fltk::Widget *w, void *cb_data) { - int choice = 0; - CustTabGroup *tabs = (CustTabGroup*) cb_data; +static void win_cb (Fl_Widget *w, void *cb_data) { + CustTabs *tabs = (CustTabs*) cb_data; + int choice = 1, ntabs = tabs->num_tabs(); - if (tabs->children () > 1) - choice = a_Dialog_choice3 ("Window contains more than one tab.", - "Close all tabs", "Cancel", NULL); - if (choice == 0) - while (tabs->children()) - a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(tabs->child(0))); + if (prefs.show_quit_dialog && ntabs > 1) + choice = a_Dialog_choice5("Window contains more than one tab.", + "Close", "Cancel", NULL, NULL, NULL); + if (choice == 1) + while (ntabs-- > 0) + a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(tabs->wizard()->value())); } /* @@ -376,27 +449,14 @@ BrowserWindow *a_UIcmd_get_bw_by_widget(void *v_wid) BrowserWindow *bw; for (int i = 0; i < a_Bw_num(); ++i) { bw = a_Bw_get(i); - if (((fltk::Widget*)bw->ui)->contains((fltk::Widget*)v_wid)) + if (((UI*)bw->ui)->contains((Fl_Widget*)v_wid)) { return bw; + } } return NULL; } /* - * FLTK regards SHIFT + {LeftKey, Right} as navigation keys. - * Special handling is required to override it. Here we route - * these events directly to the recipient. - * TODO: focus is not remembered correctly. - */ -void a_UIcmd_send_event_to_tabs_by_wid(int e, void *v_wid) -{ - BrowserWindow *bw = a_UIcmd_get_bw_by_widget(v_wid); - UI *ui = (UI*)bw->ui; - if (ui->tabs()) - ui->tabs()->handle(e); -} - -/* * Create a new UI and its associated BrowserWindow data structure. * Use style from v_ui. If non-NULL it must be of type UI*. */ @@ -405,7 +465,8 @@ BrowserWindow *a_UIcmd_browser_window_new(int ww, int wh, { BrowserWindow *old_bw = (BrowserWindow*)vbw; BrowserWindow *new_bw = NULL; - Window *win; + UI *old_ui = old_bw ? BW2UI(old_bw) : NULL; + Fl_Window *win; if (ww <= 0 || wh <= 0) { // Set default geometry from dillorc. @@ -415,96 +476,40 @@ BrowserWindow *a_UIcmd_browser_window_new(int ww, int wh, if (xid) win = new Xembed(xid, ww, wh); + else if (prefs.buffered_drawing != 2) + win = new Fl_Window(ww, wh); else - win = new Window(ww, wh); + win = new Fl_Double_Window(ww, wh); - win->shortcut(0); // Ignore Escape - if (prefs.buffered_drawing != 2) - win->clear_double_buffer(); - win->set_flag(RAW_LABEL); - CustTabGroup *DilloTabs = new CustTabGroup(0, 0, ww, wh); - DilloTabs->clear_tab_to_focus(); - DilloTabs->selection_color(156); - win->add(DilloTabs); + win->box(FL_NO_BOX); + CustTabs *DilloTabs = new CustTabs(ww, wh, 16); + win->end(); - // Create and set the UI - UI *new_ui = new UI(0, 0, ww, wh, DEFAULT_TAB_LABEL, - old_bw ? BW2UI(old_bw) : NULL); - new_ui->set_status("http://www.dillo.org/"); - new_ui->tabs(DilloTabs); - - DilloTabs->add(new_ui); - DilloTabs->resizable(new_ui); - DilloTabs->window()->resizable(new_ui); - DilloTabs->window()->show(); + int focus = 1; + new_bw = UIcmd_tab_new(DilloTabs, old_ui, focus); + win->resizable(DilloTabs->wizard()); + win->show(); if (old_bw == NULL && prefs.xpos >= 0 && prefs.ypos >= 0) { // position the first window according to preferences - fltk::Rectangle r; - new_ui->window()->borders(&r); - // borders() gives x and y border sizes as negative values - new_ui->window()->position(prefs.xpos - r.x(), prefs.ypos - r.y()); + DilloTabs->window()->position(prefs.xpos, prefs.ypos); } - // Now create the Dw render layout and viewport - FltkPlatform *platform = new FltkPlatform (); - Layout *layout = new Layout (platform); - style::Color *bgColor = style::Color::create (layout, prefs.bg_color); - layout->setBgColor (bgColor); - - FltkViewport *viewport = new FltkViewport (0, 0, 1, 1); - if (prefs.buffered_drawing == 1) - viewport->setBufferedDrawing (true); - else - viewport->setBufferedDrawing (false); - - layout->attachView (viewport); - new_ui->set_render_layout(*viewport); - - viewport->setScrollStep((int) rint(14.0 * prefs.font_factor)); - - // Now, create a new browser window structure - new_bw = a_Bw_new(); - - // Reference the UI from the bw - new_bw->ui = (void *)new_ui; - // Copy the layout pointer into the bw data - new_bw->render_layout = (void*)layout; - win->callback(win_cb, DilloTabs); - new_ui->focus_location(); - return new_bw; } /* - * Create a new Tab. - * i.e the new UI and its associated BrowserWindow data structure. + * Create a new Tab button, UI and its associated BrowserWindow data + * structure. */ -static BrowserWindow *UIcmd_tab_new(const void *vbw) +static BrowserWindow *UIcmd_tab_new(CustTabs *tabs, UI *old_ui, int focus) { - _MSG(" UIcmd_tab_new vbw=%p\n", vbw); - - dReturn_val_if_fail (vbw != NULL, NULL); - - BrowserWindow *new_bw = NULL; - BrowserWindow *old_bw = (BrowserWindow*)vbw; - UI *ui = BW2UI(old_bw); - - // WORKAROUND: limit the number of tabs because of a fltk bug - if (ui->tabs()->children() >= 127) - return a_UIcmd_browser_window_new(ui->window()->w(), ui->window()->h(), - 0, vbw); + _MSG(" UIcmd_tab_new\n"); // Create and set the UI - UI *new_ui = new UI(0, 0, ui->w(), ui->h(), DEFAULT_TAB_LABEL, ui); - new_ui->tabs(ui->tabs()); - - new_ui->tabs()->add(new_ui); - new_ui->tabs()->resizable(new_ui); - new_ui->tabs()->window()->resizable(new_ui); - new_ui->tabs()->window()->show(); + UI *new_ui = tabs->add_new_tab(old_ui, focus); // Now create the Dw render layout and viewport FltkPlatform *platform = new FltkPlatform (); @@ -512,21 +517,30 @@ static BrowserWindow *UIcmd_tab_new(const void *vbw) style::Color *bgColor = style::Color::create (layout, prefs.bg_color); layout->setBgColor (bgColor); - FltkViewport *viewport = new FltkViewport (0, 0, 1, 1); - + // set_render_layout() sets the proper viewport size + FltkViewport *viewport = new FltkViewport (0, 0, 0, 1); + viewport->box(FL_NO_BOX); + viewport->setBufferedDrawing (prefs.buffered_drawing ? true : false); + viewport->setDragScroll (prefs.middle_click_drags_page ? true : false); layout->attachView (viewport); - new_ui->set_render_layout(*viewport); - - viewport->setScrollStep((int) rint(14.0 * prefs.font_factor)); + new_ui->set_render_layout(viewport); + viewport->setScrollStep((int) rint(28.0 * prefs.font_factor)); // Now, create a new browser window structure - new_bw = a_Bw_new(); + BrowserWindow *new_bw = a_Bw_new(); // Reference the UI from the bw new_bw->ui = (void *)new_ui; // Copy the layout pointer into the bw data new_bw->render_layout = (void*)layout; + // Clear the window title + if (focus) + new_ui->window()->copy_label(new_ui->label()); + + // WORKAROUND: see findbar_toggle() + new_ui->findbar_toggle(0); + return new_bw; } @@ -537,21 +551,17 @@ void a_UIcmd_close_bw(void *vbw) { BrowserWindow *bw = (BrowserWindow *)vbw; UI *ui = BW2UI(bw); + CustTabs *tabs = ui->tabs(); Layout *layout = (Layout*)bw->render_layout; - MSG("a_UIcmd_close_bw\n"); + _MSG("a_UIcmd_close_bw\n"); a_Bw_stop_clients(bw, BW_Root + BW_Img + BW_Force); delete(layout); - if (ui->tabs()) { - ui->tabs()->remove(ui); - ui->tabs()->value(ui->tabs()->children() - 1); - if (ui->tabs()->value() != -1) - ui->tabs()->selected_child()->take_focus(); - else - ui->tabs()->window()->hide(); + if (tabs) { + tabs->remove_tab(ui); + if (tabs->num_tabs() == 0) + delete tabs->window(); } - delete(ui); - a_Bw_free(bw); } @@ -561,12 +571,12 @@ void a_UIcmd_close_bw(void *vbw) void a_UIcmd_close_all_bw(void *) { BrowserWindow *bw; - int choice = 0; + int choice = 1; - if (a_Bw_num() > 1) - choice = a_Dialog_choice3 ("More than one open tab or Window.", - "Close all tabs and windows", "Cancel", NULL); - if (choice == 0) + if (prefs.show_quit_dialog && a_Bw_num() > 1) + choice = a_Dialog_choice5("More than one open tab or window.", + "Quit", "Cancel", NULL, NULL, NULL); + if (choice == 1) while ((bw = a_Bw_get(0))) a_UIcmd_close_bw((void*)bw); } @@ -616,10 +626,14 @@ void a_UIcmd_open_urlstr(void *vbw, const char *urlstr) */ void a_UIcmd_open_url(BrowserWindow *bw, const DilloUrl *url) { - a_Nav_push(bw, url, NULL); - if (BW2UI(bw)->get_panelmode() == UI_TEMPORARILY_SHOW_PANELS) - BW2UI(bw)->set_panelmode(UI_HIDDEN); - a_UIcmd_focus_main_area(bw); + if (url) { + a_Nav_push(bw, url, NULL); + BW2UI(bw)->focus_main(); + } else { + // Used to start a bw with a blank screen + BW2UI(bw)->focus_location(); + a_UIcmd_set_buttons_sens(bw); + } } static void UIcmd_open_url_nbw(BrowserWindow *new_bw, const DilloUrl *url) @@ -632,6 +646,7 @@ static void UIcmd_open_url_nbw(BrowserWindow *new_bw, const DilloUrl *url) BW2UI(new_bw)->focus_main(); } else { BW2UI(new_bw)->focus_location(); + a_UIcmd_set_buttons_sens(new_bw); } } @@ -654,11 +669,9 @@ void a_UIcmd_open_url_nw(BrowserWindow *bw, const DilloUrl *url) */ void a_UIcmd_open_url_nt(void *vbw, const DilloUrl *url, int focus) { - BrowserWindow *new_bw = UIcmd_tab_new(vbw); - - if (focus) - BW2UI(new_bw)->tabs()->selected_child(BW2UI(new_bw)); - + BrowserWindow *bw = (BrowserWindow *)vbw; + BrowserWindow *new_bw = UIcmd_tab_new(BW2UI(bw)->tabs(), + bw ? BW2UI(bw) : NULL, focus); UIcmd_open_url_nbw(new_bw, url); } @@ -673,9 +686,9 @@ void a_UIcmd_back(void *vbw) /* * Popup the navigation menu of the Back button */ -void a_UIcmd_back_popup(void *vbw) +void a_UIcmd_back_popup(void *vbw, int x, int y) { - a_Menu_history_popup((BrowserWindow*)vbw, -1); + a_Menu_history_popup((BrowserWindow*)vbw, x, y, -1); } /* @@ -689,9 +702,9 @@ void a_UIcmd_forw(void *vbw) /* * Popup the navigation menu of the Forward button */ -void a_UIcmd_forw_popup(void *vbw) +void a_UIcmd_forw_popup(void *vbw, int x, int y) { - a_Menu_history_popup((BrowserWindow*)vbw, 1); + a_Menu_history_popup((BrowserWindow*)vbw, x, y, 1); } /* @@ -825,9 +838,9 @@ void a_UIcmd_stop(void *vbw) /* * Popup the tools menu */ -void a_UIcmd_tools(void *vbw, void *v_wid) +void a_UIcmd_tools(void *vbw, int x, int y) { - a_Menu_tools_popup((BrowserWindow*)vbw, v_wid); + a_Menu_tools_popup((BrowserWindow*)vbw, x, y); } /* @@ -850,29 +863,33 @@ void a_UIcmd_open_file(void *vbw) /* * Returns a newly allocated string holding a search url generated from - * a string of keywords (separarated by blanks) and prefs.search_url. + * a string of keywords (separated by blanks) and the current search_url. * The search string is urlencoded. */ static char *UIcmd_make_search_str(const char *str) { - char *keys = a_Url_encode_hex_str(str), *c = prefs.search_url; + char *search_url, *l, *u, *c; + char *keys = a_Url_encode_hex_str(str), + *src = (char*)dList_nth_data(prefs.search_urls, prefs.search_url_idx); Dstr *ds = dStr_sized_new(128); - char *search_url; - - for (; *c; c++) { - if (*c == '%') - switch(*++c) { - case 's': - dStr_append(ds, keys); break;; - case '%': - dStr_append_c(ds, '%'); break;; - case 0: - MSG_WARN("search_url ends with '%%'\n"); c--; break;; - default: - MSG_WARN("illegal specifier '%%%c' in search_url\n", *c); - } - else - dStr_append_c(ds, *c); + + /* parse search_url into label and url */ + if (a_Misc_parse_search_url(src, &l, &u) == 0) { + for (c = u; *c; c++) { + if (*c == '%') + switch(*++c) { + case 's': + dStr_append(ds, keys); break;; + case '%': + dStr_append_c(ds, '%'); break;; + case 0: + MSG_WARN("search_url ends with '%%'\n"); c--; break;; + default: + MSG_WARN("illegal specifier '%%%c' in search_url\n", *c); + } + else + dStr_append_c(ds, *c); + } } dFree(keys); @@ -918,13 +935,11 @@ void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url) a_UIcmd_set_save_dir(prefs.save_dir); SuggestedName = UIcmd_make_save_filename(URL_STR(url)); - name = a_Dialog_save_file("Save Link as File", NULL, SuggestedName); - MSG("a_UIcmd_save_link: %s\n", name); - dFree(SuggestedName); - - if (name) { + if ((name = a_Dialog_save_file("Save Link as File", NULL, SuggestedName))) { + MSG("a_UIcmd_save_link: %s\n", name); a_Nav_save_url(bw, url, name); } + dFree(SuggestedName); } /* @@ -1030,7 +1045,7 @@ void a_UIcmd_view_page_source(BrowserWindow *bw, const DilloUrl *url) } /* - * Show a text window with the URL's source + * Show the browser window's HTML errors in a text window */ void a_UIcmd_view_page_bugs(void *vbw) { @@ -1151,6 +1166,8 @@ void a_UIcmd_scroll(BrowserWindow *bw, int icmd) const mapping_t map[] = { {KEYS_SCREEN_UP, SCREEN_UP_CMD}, {KEYS_SCREEN_DOWN, SCREEN_DOWN_CMD}, + {KEYS_SCREEN_LEFT, SCREEN_LEFT_CMD}, + {KEYS_SCREEN_RIGHT, SCREEN_RIGHT_CMD}, {KEYS_LINE_UP, LINE_UP_CMD}, {KEYS_LINE_DOWN, LINE_DOWN_CMD}, {KEYS_LEFT, LEFT_CMD}, @@ -1217,7 +1234,7 @@ void a_UIcmd_set_bug_prog(BrowserWindow *bw, int n_bug) } /* - * Set the page title in the window titlebar and tab label. + * Set the page title in the tab label and window titlebar. * (Update window titlebar for the current tab only) */ void a_UIcmd_set_page_title(BrowserWindow *bw, const char *label) @@ -1225,16 +1242,17 @@ void a_UIcmd_set_page_title(BrowserWindow *bw, const char *label) const int size = 128; char title[size]; - if (a_UIcmd_get_bw_by_widget(BW2UI(bw)->tabs()->selected_child()) == bw) { + if (snprintf(title, size, "Dillo: %s", label ? label : "") >= size) { + uint_t i = MIN(size - 4, 1 + a_Utf8_end_of_char(title, size - 8)); + snprintf(title + i, 4, "..."); + } + BW2UI(bw)->copy_label(title); + BW2UI(bw)->tabs()->set_tab_label(BW2UI(bw), label ? label : ""); + + if (a_UIcmd_get_bw_by_widget(BW2UI(bw)->tabs()->wizard()->value()) == bw) { // This is the focused bw, set window title - if (snprintf(title, size, "Dillo: %s", label) >= size) { - uint_t i = MIN(size - 4, 1 + a_Utf8_end_of_char(title, size - 8)); - snprintf(title + i, 4, "..."); - } BW2UI(bw)->window()->copy_label(title); - BW2UI(bw)->window()->redraw_label(); } - BW2UI(bw)->set_tab_title(label); } /* @@ -1268,32 +1286,16 @@ void a_UIcmd_set_buttons_sens(BrowserWindow *bw) BW2UI(bw)->button_set_sens(UI_BACK, sens); // Forward sens = (a_Nav_stack_ptr(bw) < a_Nav_stack_size(bw) - 1 && - !bw->nav_expecting); + !a_Bw_expecting(bw)); BW2UI(bw)->button_set_sens(UI_FORW, sens); } /* - * Keep track of mouse pointer over a link. - */ -void a_UIcmd_set_pointer_on_link(BrowserWindow *bw, int flag) -{ - BW2UI(bw)->pointerOnLink(flag); -} - -/* - * Is the mouse pointer over a link? + * Toggle control panel */ -int a_UIcmd_pointer_on_link(BrowserWindow *bw) +void a_UIcmd_panels_toggle(BrowserWindow *bw) { - return BW2UI(bw)->pointerOnLink(); -} - -/* - * Toggle control panel (aka. fullscreen) - */ -void a_UIcmd_fullscreen_toggle(BrowserWindow *bw) -{ - BW2UI(bw)->fullscreen_toggle(); + BW2UI(bw)->panels_toggle(); } /* @@ -1330,6 +1332,14 @@ void a_UIcmd_findtext_reset(BrowserWindow *bw) } /* + * Tell the UI to hide/show the findbar + */ +void a_UIcmd_findbar_toggle(BrowserWindow *bw, int on) +{ + BW2UI(bw)->findbar_toggle(on); +} + +/* * Focus the rendered area. */ void a_UIcmd_focus_main_area(BrowserWindow *bw) diff --git a/src/uicmd.hh b/src/uicmd.hh index c8fea9e7..c859ba9c 100644 --- a/src/uicmd.hh +++ b/src/uicmd.hh @@ -17,16 +17,16 @@ void a_UIcmd_open_url(BrowserWindow *bw, const DilloUrl *url); void a_UIcmd_open_url_nw(BrowserWindow *bw, const DilloUrl *url); void a_UIcmd_open_url_nt(void *vbw, const DilloUrl *url, int focus); void a_UIcmd_back(void *vbw); -void a_UIcmd_back_popup(void *vbw); +void a_UIcmd_back_popup(void *vbw, int x, int y); void a_UIcmd_forw(void *vbw); -void a_UIcmd_forw_popup(void *vbw); +void a_UIcmd_forw_popup(void *vbw, int x, int y); void a_UIcmd_home(void *vbw); void a_UIcmd_reload(void *vbw); void a_UIcmd_repush(void *vbw); void a_UIcmd_redirection0(void *vbw, const DilloUrl *url); void a_UIcmd_save(void *vbw); void a_UIcmd_stop(void *vbw); -void a_UIcmd_tools(void *vbw, void *v_wid); +void a_UIcmd_tools(void *vbw, int x, int y); void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url); void a_UIcmd_open_file(void *vbw); const char *a_UIcmd_select_file(); @@ -34,11 +34,12 @@ void a_UIcmd_search_dialog(void *vbw); const char *a_UIcmd_get_passwd(const char *user); void a_UIcmd_book(void *vbw); void a_UIcmd_add_bookmark(BrowserWindow *bw, const DilloUrl *url); -void a_UIcmd_fullscreen_toggle(BrowserWindow *bw); +void a_UIcmd_panels_toggle(BrowserWindow *bw); void a_UIcmd_findtext_dialog(BrowserWindow *bw); void a_UIcmd_findtext_search(BrowserWindow *bw,const char *key,int case_sens, int backwards); void a_UIcmd_findtext_reset(BrowserWindow *bw); +void a_UIcmd_findbar_toggle(BrowserWindow *bw, int on); void a_UIcmd_focus_main_area(BrowserWindow *bw); void a_UIcmd_focus_location(void *vbw); void a_UIcmd_page_popup(void *vbw, bool_t has_bugs, void *v_cssUrls); @@ -77,9 +78,6 @@ void a_UIcmd_set_bug_prog(BrowserWindow *bw, int n_bug); void a_UIcmd_set_page_title(BrowserWindow *bw, const char *label); void a_UIcmd_set_msg(BrowserWindow *bw, const char *format, ...); void a_UIcmd_set_buttons_sens(BrowserWindow *bw); -void a_UIcmd_fullscreen_toggle(BrowserWindow *bw); -void a_UIcmd_set_pointer_on_link(BrowserWindow *bw, int flag); -int a_UIcmd_pointer_on_link(BrowserWindow *bw); #ifdef __cplusplus } @@ -233,6 +233,8 @@ static Dstr *Url_resolve_relative(const char *RelStr, dStr_append(SolvedUrl, BaseStr); if ((p = strchr(SolvedUrl->str, '#'))) dStr_truncate(SolvedUrl, p - SolvedUrl->str); + if (!BaseUrl->path) + dStr_append_c(SolvedUrl, '/'); if (RelUrl->query) { /* query */ if (BaseUrl->query) @@ -687,11 +689,11 @@ static uint_t Url_host_public_internal_dots(const char *host) if (tld_len > 0) { /* These TLDs were chosen by examining the current publicsuffix list - * in January 2010 and picking out those where it was simplest for + * in September 2011 and picking out those where it was simplest for * them to describe the situation by beginning with a "*.[tld]" rule. */ - const char *const tlds[] = {"ar","au","bd","bn","bt","ck","cy","do", - "eg","er","et","fj","fk","gt","gu","id", + const char *const tlds[] = {"ar","au","bd","bn","bt","ck","cy", + "er","et","fj","fk","gt","gu","id", "il","jm","ke","kh","kw","ml","mm","mt", "mz","ni","np","nz","om","pg","py","qa", "sv","tr","uk","uy","ve","ye","yu","za", @@ -716,7 +718,7 @@ static uint_t Url_host_public_internal_dots(const char *host) * domain that is in a registry outside the organization. * For 'www.dillo.org', that would be 'dillo.org'. */ -const char *a_Url_host_find_public_suffix(const char *host) +static const char *Url_host_find_public_suffix(const char *host) { const char *s; uint_t dots; @@ -751,3 +753,12 @@ const char *a_Url_host_find_public_suffix(const char *host) _MSG("public suffix of %s is %s\n", host, s); return s; } + +bool_t a_Url_same_organization(const DilloUrl *u1, const DilloUrl *u2) +{ + if (!u1 || !u2) + return FALSE; + + return dStrcasecmp(Url_host_find_public_suffix(URL_HOST(u1)), + Url_host_find_public_suffix(URL_HOST(u2))) ? FALSE :TRUE; +} @@ -47,21 +47,21 @@ * (non '_'-ended macros MUST use these for initialization sake) */ /* these MAY return NULL: */ -#define URL_SCHEME_(u) u->scheme -#define URL_AUTHORITY_(u) u->authority -#define URL_PATH_(u) u->path -#define URL_QUERY_(u) u->query -#define URL_FRAGMENT_(u) u->fragment +#define URL_SCHEME_(u) (u)->scheme +#define URL_AUTHORITY_(u) (u)->authority +#define URL_PATH_(u) (u)->path +#define URL_QUERY_(u) (u)->query +#define URL_FRAGMENT_(u) (u)->fragment #define URL_HOST_(u) a_Url_hostname(u) -#define URL_ALT_(u) u->alt +#define URL_ALT_(u) (u)->alt #define URL_STR_(u) a_Url_str(u) /* this returns a Dstr* */ -#define URL_DATA_(u) u->data +#define URL_DATA_(u) (u)->data /* these return an integer */ -#define URL_PORT_(u) (URL_HOST(u), u->port) -#define URL_FLAGS_(u) u->flags -#define URL_ILLEGAL_CHARS_(u) url->illegal_chars -#define URL_ILLEGAL_CHARS_SPC_(u) url->illegal_chars_spc +#define URL_PORT_(u) (URL_HOST(u), (u)->port) +#define URL_FLAGS_(u) (u)->flags +#define URL_ILLEGAL_CHARS_(u) (u)->illegal_chars +#define URL_ILLEGAL_CHARS_SPC_(u) (u)->illegal_chars_spc /* * Access methods that never return NULL. @@ -122,7 +122,7 @@ void a_Url_set_ismap_coords(DilloUrl *u, char *coord_str); char *a_Url_decode_hex_str(const char *str); char *a_Url_encode_hex_str(const char *str); char *a_Url_string_strip_delimiters(const char *str); -const char *a_Url_host_find_public_suffix(const char *host); +bool_t a_Url_same_organization(const DilloUrl *u1, const DilloUrl *u2); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/utf8.cc b/src/utf8.cc index 0138c616..3d25f4f5 100644 --- a/src/utf8.cc +++ b/src/utf8.cc @@ -9,7 +9,7 @@ * (at your option) any later version. */ -#include <fltk/utf.h> +#include <FL/fl_utf8.h> #include "../dlib/dlib.h" /* TRUE/FALSE */ #include "utf8.hh" @@ -45,7 +45,7 @@ uint_t a_Utf8_end_of_char(const char *str, uint_t i) */ uint_t a_Utf8_decode(const char* str, const char* end, int* len) { - return utf8decode(str, end, len); + return fl_utf8decode(str, end, len); } /* @@ -53,7 +53,7 @@ uint_t a_Utf8_decode(const char* str, const char* end, int* len) */ int a_Utf8_encode(unsigned int ucs, char *buf) { - return utf8encode(ucs, buf); + return fl_utf8encode(ucs, buf); } /* @@ -63,7 +63,7 @@ int a_Utf8_encode(unsigned int ucs, char *buf) */ int a_Utf8_test(const char* src, unsigned int srclen) { - return utf8test(src, srclen); + return fl_utf8test(src, srclen); } /* @@ -100,3 +100,8 @@ bool_t a_Utf8_combining_char(int unicode) (unicode >= 0x20d0 && unicode <= 0x20ff) || (unicode >= 0xfe20 && unicode <= 0xfe2f)); } + +int a_Utf8_char_count(const char *str, int len) +{ + return fl_utf_nb_char((const uchar_t*)str, len); +} diff --git a/src/utf8.hh b/src/utf8.hh index 4ded50b8..ce575118 100644 --- a/src/utf8.hh +++ b/src/utf8.hh @@ -24,6 +24,7 @@ int a_Utf8_encode(unsigned int ucs, char *buf); int a_Utf8_test(const char* src, unsigned int srclen); bool_t a_Utf8_ideographic(const char *s, const char *end, int *len); bool_t a_Utf8_combining_char(int unicode); +int a_Utf8_char_count(const char *str, int len); #ifdef __cplusplus } @@ -78,8 +78,11 @@ int a_Web_dispatch_by_type (const char *Type, DilloWeb *Web, /* This method frees the old dw if any */ layout->setWidget(dw); - /* Clear the title bar for pages without a <TITLE> tag */ - a_UIcmd_set_page_title(Web->bw, ""); + /* Set the page title with the bare filename (e.g. for images), + * HTML pages with a <TITLE> tag will overwrite it later */ + const char *p = strrchr(URL_STR(Web->url), '/'); + a_UIcmd_set_page_title(Web->bw, p ? p+1 : ""); + a_UIcmd_set_location_text(Web->bw, URL_STR(Web->url)); /* Reset both progress bars */ a_UIcmd_set_page_prog(Web->bw, 0, 2); @@ -106,14 +109,15 @@ int a_Web_dispatch_by_type (const char *Type, DilloWeb *Web, /* * Allocate and set safe values for a DilloWeb structure */ -DilloWeb* a_Web_new(const DilloUrl *url, const DilloUrl *requester) +DilloWeb* a_Web_new(BrowserWindow *bw, const DilloUrl *url, + const DilloUrl *requester) { DilloWeb *web= dNew(DilloWeb, 1); _MSG(" a_Web_new: ValidWebs ==> %d\n", dList_length(ValidWebs)); web->url = a_Url_dup(url); web->requester = a_Url_dup(requester); - web->bw = NULL; + web->bw = bw; web->flags = 0; web->Image = NULL; web->filename = NULL; @@ -36,7 +36,8 @@ struct _DilloWeb { }; void a_Web_init(void); -DilloWeb* a_Web_new (const DilloUrl* url, const DilloUrl *requester); +DilloWeb* a_Web_new (BrowserWindow *bw, const DilloUrl* url, + const DilloUrl *requester); int a_Web_valid(DilloWeb *web); void a_Web_free (DilloWeb*); int a_Web_dispatch_by_type (const char *Type, DilloWeb *web, diff --git a/src/xembed.cc b/src/xembed.cc index 04a4362a..f180d81d 100644 --- a/src/xembed.cc +++ b/src/xembed.cc @@ -12,14 +12,14 @@ #include <string.h> #include <ctype.h> -#include <fltk/Window.h> -#include <fltk/run.h> -#include <fltk/events.h> -#include <fltk/x.h> +#define FL_INTERNALS +#include <FL/Fl_Window.H> +#include <FL/Fl.H> +#include <FL/x.H> #include "xembed.hh" -#if USE_X11 +#ifdef X_PROTOCOL typedef enum { XEMBED_EMBEDDED_NOTIFY = 0, @@ -41,12 +41,12 @@ Xembed::setXembedInfo(unsigned long flags) { unsigned long buffer[2]; - Atom xembed_info_atom = XInternAtom (fltk::xdisplay, "_XEMBED_INFO", false); + Atom xembed_info_atom = XInternAtom (fl_display, "_XEMBED_INFO", false); buffer[0] = 1; buffer[1] = flags; - XChangeProperty (fltk::xdisplay, + XChangeProperty (fl_display, xid, xembed_info_atom, xembed_info_atom, 32, PropModeReplace, @@ -60,35 +60,36 @@ Xembed::sendXembedEvent(uint32_t message) { memset (&xclient, 0, sizeof (xclient)); xclient.window = xid; xclient.type = ClientMessage; - xclient.message_type = XInternAtom (fltk::xdisplay, "_XEMBED", false); + xclient.message_type = XInternAtom (fl_display, "_XEMBED", false); xclient.format = 32; - xclient.data.l[0] = fltk::event_time; + xclient.data.l[0] = fl_event_time; xclient.data.l[1] = message; - XSendEvent(fltk::xdisplay, xid, False, NoEventMask, (XEvent *)&xclient); - XSync(fltk::xdisplay, False); + XSendEvent(fl_display, xid, False, NoEventMask, (XEvent *)&xclient); + XSync(fl_display, False); } int Xembed::handle(int e) { - if (e == fltk::PUSH) + if (e == FL_PUSH) sendXembedEvent(XEMBED_REQUEST_FOCUS); - return Window::handle(e); + return Fl_Window::handle(e); } -static int event_handler(int e, fltk::Window *w) { - Atom xembed_atom = XInternAtom (fltk::xdisplay, "_XEMBED", false); +static int event_handler(int e, Fl_Window *w) { + Atom xembed_atom = XInternAtom (fl_display, "_XEMBED", false); - if (fltk::xevent.type == ClientMessage) { - if (fltk::xevent.xclient.message_type == xembed_atom) { - long message = fltk::xevent.xclient.data.l[1]; + if (fl_xevent->type == ClientMessage) { + if (fl_xevent->xclient.message_type == xembed_atom) { + long message = fl_xevent->xclient.data.l[1]; switch (message) { case XEMBED_WINDOW_ACTIVATE: // Force a ConfigureNotify message so fltk can get the new // coordinates after a move of the embedder window. - w->resize(0, 0, w->w(), w->h()); + if (w) + w->resize(0,0, w->w(), w->h()); break; case XEMBED_WINDOW_DEACTIVATE: break; @@ -98,20 +99,20 @@ static int event_handler(int e, fltk::Window *w) { } } - return 0; + return Fl::handle_(e, w); } // TODO: Implement more XEMBED support; -void Xembed::create() { +void Xembed::show() { createInternal(xid); setXembedInfo(1); - fltk::add_event_handler(event_handler); + Fl::event_dispatch(event_handler); } void Xembed::createInternal(uint32_t parent) { - fltk::Window *window = this; - Colormap colormap = fltk::xcolormap; + Fl_Window *window = this; + Colormap colormap = fl_colormap; XSetWindowAttributes attr; attr.border_pixel = 0; @@ -133,18 +134,18 @@ void Xembed::createInternal(uint32_t parent) { | EnterWindowMask | LeaveWindowMask | PointerMotionMask; - fltk::CreatedWindow::set_xid(window, - XCreateWindow(fltk::xdisplay, + Fl_X::set_xid(window, + XCreateWindow(fl_display, parent, X, Y, W, H, 0, // borderwidth - fltk::xvisual->depth, + fl_visual->depth, InputOutput, - fltk::xvisual->visual, + fl_visual->visual, mask, &attr)); } -#else // USE_X11 +#else // X_PROTOCOL void Xembed::setXembedInfo(unsigned long flags) {}; @@ -154,12 +155,12 @@ Xembed::sendXembedEvent(uint32_t message) {}; int Xembed::handle(int e) { - return Window::handle(e); + return Fl_Window::handle(e); } void -Xembed::create() { - Window::create(); +Xembed::show() { + Fl_Window::show(); } #endif diff --git a/src/xembed.hh b/src/xembed.hh index 70d79c5f..d7663c8e 100644 --- a/src/xembed.hh +++ b/src/xembed.hh @@ -1,11 +1,11 @@ #ifndef __XEMBED_HH__ #define __XEMBED_HH__ -#include <fltk/Window.h> +#include <FL/Fl_Window.H> #include "d_size.h" -class Xembed : public fltk::Window { +class Xembed : public Fl_Window { private: uint32_t xid; void createInternal(uint32_t parent); @@ -13,10 +13,10 @@ class Xembed : public fltk::Window { void sendXembedEvent(uint32_t message); public: - Xembed(uint32_t xid, int _w, int _h) : fltk::Window(_w, _h) { + Xembed(uint32_t xid, int _w, int _h) : Fl_Window(_w, _h) { this->xid = xid; }; - void create(); + void show(); int handle(int event); }; |