3 * Copyright (c) 2010 Marco Peereboom <marco@peereboom.us>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * inverse color browsing
23 * download files status
24 * multi letter commands
25 * pre and post counts for commands
28 * autocompletion on various inputs
29 * create privacy browsing
30 * - encrypted local data
41 #include <sys/queue.h>
42 #include <sys/types.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <webkit/webkit.h>
48 #include <libsoup/soup.h>
49 #include <JavaScriptCore/JavaScript.h>
51 #include "javascript.h"
54 javascript.h borrowed from vimprobable2 under the following license:
56 Copyright (c) 2009 Leon Winter
57 Copyright (c) 2009 Hannes Schueller
58 Copyright (c) 2009 Matto Fransen
60 Permission is hereby granted, free of charge, to any person obtaining a copy
61 of this software and associated documentation files (the "Software"), to deal
62 in the Software without restriction, including without limitation the rights
63 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64 copies of the Software, and to permit persons to whom the Software is
65 furnished to do so, subject to the following conditions:
67 The above copyright notice and this permission notice shall be included in
68 all copies or substantial portions of the Software.
70 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
79 static char *version
= "$xxxterm$";
82 /* #define XT_DEBUG */
84 #define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0)
85 #define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0)
86 #define XT_D_MOVE 0x0001
87 #define XT_D_KEY 0x0002
88 #define XT_D_TAB 0x0004
89 #define XT_D_URL 0x0008
90 #define XT_D_CMD 0x0010
91 #define XT_D_NAV 0x0020
92 #define XT_D_DOWNLOAD 0x0040
93 #define XT_D_CONFIG 0x0080
94 #define XT_D_JS 0x0100
95 u_int32_t swm_debug
= 0
107 #define DPRINTF(x...)
108 #define DNPRINTF(n,x...)
111 #define LENGTH(x) (sizeof x / sizeof x[0])
112 #define CLEAN(mask) (mask & ~(GDK_MOD2_MASK) & \
113 ~(GDK_BUTTON1_MASK) & \
114 ~(GDK_BUTTON2_MASK) & \
115 ~(GDK_BUTTON3_MASK) & \
116 ~(GDK_BUTTON4_MASK) & \
120 TAILQ_ENTRY(tab
) entry
;
124 GtkWidget
*uri_entry
;
125 GtkWidget
*search_entry
;
127 GtkWidget
*browser_win
;
129 GtkToolItem
*backward
;
130 GtkToolItem
*forward
;
135 /* adjustments for browser */
138 GtkAdjustment
*adjust_h
;
139 GtkAdjustment
*adjust_v
;
149 #define XT_HINT_NONE (0)
150 #define XT_HINT_NUMERICAL (1)
151 #define XT_HINT_ALPHANUM (2)
160 WebKitWebSettings
*settings
;
164 TAILQ_HEAD(tab_list
, tab
);
172 #define XT_NAME ("XXXTerm")
173 #define XT_DIR (".xxxterm")
174 #define XT_CONF_FILE ("xxxterm.conf")
175 #define XT_FAVS_FILE ("favorites")
176 #define XT_CB_HANDLED (TRUE)
177 #define XT_CB_PASSTHROUGH (FALSE)
180 #define XT_MOVE_INVALID (0)
181 #define XT_MOVE_DOWN (1)
182 #define XT_MOVE_UP (2)
183 #define XT_MOVE_BOTTOM (3)
184 #define XT_MOVE_TOP (4)
185 #define XT_MOVE_PAGEDOWN (5)
186 #define XT_MOVE_PAGEUP (6)
187 #define XT_MOVE_HALFDOWN (7)
188 #define XT_MOVE_HALFUP (8)
189 #define XT_MOVE_LEFT (9)
190 #define XT_MOVE_FARLEFT (10)
191 #define XT_MOVE_RIGHT (11)
192 #define XT_MOVE_FARRIGHT (12)
194 #define XT_TAB_LAST (-4)
195 #define XT_TAB_FIRST (-3)
196 #define XT_TAB_PREV (-2)
197 #define XT_TAB_NEXT (-1)
198 #define XT_TAB_INVALID (0)
199 #define XT_TAB_NEW (1)
200 #define XT_TAB_DELETE (2)
201 #define XT_TAB_DELQUIT (3)
202 #define XT_TAB_OPEN (4)
204 #define XT_NAV_INVALID (0)
205 #define XT_NAV_BACK (1)
206 #define XT_NAV_FORWARD (2)
207 #define XT_NAV_RELOAD (3)
209 #define XT_FOCUS_INVALID (0)
210 #define XT_FOCUS_URI (1)
211 #define XT_FOCUS_SEARCH (2)
213 #define XT_SEARCH_INVALID (0)
214 #define XT_SEARCH_NEXT (1)
215 #define XT_SEARCH_PREV (2)
217 #define XT_FONT_SET (0)
220 extern char *__progname
;
222 GtkWidget
*main_window
;
223 GtkNotebook
*notebook
;
224 struct tab_list tabs
;
231 TAILQ_ENTRY(mime_type
) entry
;
233 TAILQ_HEAD(mime_type_list
, mime_type
);
239 TAILQ_ENTRY(alias
) entry
;
241 TAILQ_HEAD(alias_list
, alias
);
244 int showtabs
= 1; /* show tabs on notebook */
245 int showurl
= 1; /* show url toolbar on notebook */
246 int tabless
= 0; /* allow only 1 tab */
247 int ctrl_click_focus
= 0; /* ctrl click gets focus */
248 int cookies_enabled
= 1; /* enable cookies */
249 int read_only_cookies
= 0; /* enable to not write cookies */
250 int enable_scripts
= 0;
251 int enable_plugins
= 0;
252 int default_font_size
= 12;
253 int fancy_bar
= 1; /* fancy toolbar */
255 char *home
= "http://www.peereboom.us";
256 char *search_string
= NULL
;
257 char *http_proxy
= NULL
;
258 SoupURI
*proxy_uri
= NULL
;
259 char work_dir
[PATH_MAX
];
260 char cookie_file
[PATH_MAX
];
261 char download_dir
[PATH_MAX
];
262 SoupSession
*session
;
263 SoupCookieJar
*cookiejar
;
265 struct mime_type_list mtl
;
266 struct alias_list aliases
;
269 void create_new_tab(char *, int);
270 void delete_tab(struct tab
*);
271 void adjustfont_webkit(struct tab
*, int);
272 int run_script(struct tab
*, char *);
274 struct valid_url_types
{
284 valid_url_type(char *url
)
288 for (i
= 0; i
< LENGTH(vut
); i
++)
289 if (!strncasecmp(vut
[i
].type
, url
, strlen(vut
[i
].type
)))
296 match_alias(char *url_in
)
300 char *url_out
= NULL
;
303 if (strsep(&arg
, " \t") == NULL
)
304 errx(1, "match_alias: NULL URL");
306 TAILQ_FOREACH(a
, &aliases
, entry
) {
307 if (!strcmp(url_in
, a
->a_name
))
312 DNPRINTF(XT_D_URL
, "match_alias: matched alias %s\n",
315 url_out
= g_strdup_printf(a
->a_uri
, arg
);
317 url_out
= g_strdup(a
->a_uri
);
324 guess_url_type(char *url_in
)
327 char *url_out
= NULL
;
329 url_out
= match_alias(url_in
);
333 /* XXX not sure about this heuristic */
334 if (stat(url_in
, &sb
) == 0)
335 url_out
= g_strdup_printf("file://%s", url_in
);
337 url_out
= g_strdup_printf("http://%s", url_in
); /* guess http */
339 DNPRINTF(XT_D_URL
, "guess_url_type: guessed %s\n", url_out
);
345 add_alias(char *line
)
351 errx(1, "add_alias");
354 a
= g_malloc(sizeof(*a
));
356 if ((alias
= strsep(&l
, " \t,")) == NULL
|| l
== NULL
)
357 errx(1, "add_alias: incomplete alias definition");
359 if (strlen(alias
) == 0 || strlen(l
) == 0)
360 errx(1, "add_alias: invalid alias definition");
362 a
->a_name
= g_strdup(alias
);
363 a
->a_uri
= g_strdup(l
);
365 DNPRINTF(XT_D_CONFIG
, "add_alias: %s for %s\n", a
->a_name
, a
->a_uri
);
367 TAILQ_INSERT_TAIL(&aliases
, a
, entry
);
371 add_mime_type(char *line
)
377 /* XXX this could be smarter */
380 errx(1, "add_mime_type");
383 m
= g_malloc(sizeof(*m
));
385 if ((mime_type
= strsep(&l
, " \t,")) == NULL
|| l
== NULL
)
386 errx(1, "add_mime_type: invalid mime_type");
388 if (mime_type
[strlen(mime_type
) - 1] == '*') {
389 mime_type
[strlen(mime_type
) - 1] = '\0';
394 if (strlen(mime_type
) == 0 || strlen(l
) == 0)
395 errx(1, "add_mime_type: invalid mime_type");
397 m
->mt_type
= g_strdup(mime_type
);
398 m
->mt_action
= g_strdup(l
);
400 DNPRINTF(XT_D_CONFIG
, "add_mime_type: type %s action %s default %d\n",
401 m
->mt_type
, m
->mt_action
, m
->mt_default
);
403 TAILQ_INSERT_TAIL(&mtl
, m
, entry
);
407 find_mime_type(char *mime_type
)
409 struct mime_type
*m
, *def
= NULL
, *rv
= NULL
;
411 TAILQ_FOREACH(m
, &mtl
, entry
) {
413 !strncmp(mime_type
, m
->mt_type
, strlen(m
->mt_type
)))
416 if (m
->mt_default
== 0 && !strcmp(mime_type
, m
->mt_type
)) {
430 config_parse(char *filename
)
433 char *line
, *cp
, *var
, *val
;
434 size_t len
, lineno
= 0;
436 DNPRINTF(XT_D_CONFIG
, "config_parse: filename %s\n", filename
);
439 TAILQ_INIT(&aliases
);
441 if (filename
== NULL
)
444 if ((config
= fopen(filename
, "r")) == NULL
) {
445 warn("config_parse: cannot open %s", filename
);
450 if ((line
= fparseln(config
, &len
, &lineno
, NULL
, 0)) == NULL
)
451 if (feof(config
) || ferror(config
))
455 cp
+= (long)strspn(cp
, WS
);
462 if ((var
= strsep(&cp
, WS
)) == NULL
|| cp
== NULL
)
465 cp
+= (long)strspn(cp
, WS
);
467 if ((val
= strsep(&cp
, "\0")) == NULL
)
470 DNPRINTF(XT_D_CONFIG
, "config_parse: %s=%s\n",var
,val
);
473 if (!strcmp(var
, "home"))
474 home
= g_strdup(val
);
475 else if (!strcmp(var
, "ctrl_click_focus"))
476 ctrl_click_focus
= atoi(val
);
477 else if (!strcmp(var
, "read_only_cookies"))
478 read_only_cookies
= atoi(val
);
479 else if (!strcmp(var
, "cookies_enabled"))
480 cookies_enabled
= atoi(val
);
481 else if (!strcmp(var
, "enable_scripts"))
482 enable_scripts
= atoi(val
);
483 else if (!strcmp(var
, "enable_plugins"))
484 enable_plugins
= atoi(val
);
485 else if (!strcmp(var
, "default_font_size"))
486 default_font_size
= atoi(val
);
487 else if (!strcmp(var
, "fancy_bar"))
488 fancy_bar
= atoi(val
);
489 else if (!strcmp(var
, "mime_type"))
491 else if (!strcmp(var
, "alias"))
493 else if (!strcmp(var
, "http_proxy")) {
496 http_proxy
= g_strdup(val
);
497 } else if (!strcmp(var
, "search_string")) {
499 g_free(search_string
);
500 search_string
= g_strdup(val
);
501 } else if (!strcmp(var
, "download_dir")) {
503 snprintf(download_dir
, sizeof download_dir
,
504 "%s/%s", pwd
->pw_dir
, &val
[1]);
506 strlcpy(download_dir
, val
, sizeof download_dir
);
508 errx(1, "invalid conf file entry: %s=%s", var
, val
);
517 js_ref_to_string(JSContextRef context
, JSValueRef ref
)
523 jsref
= JSValueToStringCopy(context
, ref
, NULL
);
527 l
= JSStringGetMaximumUTF8CStringSize(jsref
);
530 JSStringGetUTF8CString(jsref
, s
, l
);
531 JSStringRelease(jsref
);
537 disable_hints(struct tab
*t
)
539 bzero(t
->hint_buf
, sizeof t
->hint_buf
);
540 bzero(t
->hint_num
, sizeof t
->hint_num
);
541 run_script(t
, "vimprobable_clear()");
543 t
->hint_mode
= XT_HINT_NONE
;
547 enable_hints(struct tab
*t
)
549 bzero(t
->hint_buf
, sizeof t
->hint_buf
);
550 run_script(t
, "vimprobable_show_hints()");
552 t
->hint_mode
= XT_HINT_NONE
;
555 #define XT_JS_OPEN ("open;")
556 #define XT_JS_OPEN_LEN (strlen(XT_JS_OPEN))
557 #define XT_JS_FIRE ("fire;")
558 #define XT_JS_FIRE_LEN (strlen(XT_JS_FIRE))
559 #define XT_JS_FOUND ("found;")
560 #define XT_JS_FOUND_LEN (strlen(XT_JS_FOUND))
563 run_script(struct tab
*t
, char *s
)
565 JSGlobalContextRef ctx
;
566 WebKitWebFrame
*frame
;
568 JSValueRef val
, exception
;
571 DNPRINTF(XT_D_JS
, "run_script: tab %d %s\n",
572 t
->tab_id
, s
== (char *)JS_HINTING
? "JS_HINTING" : s
);
574 frame
= webkit_web_view_get_main_frame(t
->wv
);
575 ctx
= webkit_web_frame_get_global_context(frame
);
577 str
= JSStringCreateWithUTF8CString(s
);
578 val
= JSEvaluateScript(ctx
, str
, JSContextGetGlobalObject(ctx
),
579 NULL
, 0, &exception
);
580 JSStringRelease(str
);
582 DNPRINTF(XT_D_JS
, "run_script: val %p\n", val
);
584 es
= js_ref_to_string(ctx
, exception
);
585 DNPRINTF(XT_D_JS
, "run_script: exception %s\n", es
);
589 es
= js_ref_to_string(ctx
, val
);
590 DNPRINTF(XT_D_JS
, "run_script: val %s\n", es
);
592 /* handle return value right here */
593 if (!strncmp(es
, XT_JS_OPEN
, XT_JS_OPEN_LEN
)) {
595 webkit_web_view_load_uri(t
->wv
, &es
[XT_JS_OPEN_LEN
]);
598 if (!strncmp(es
, XT_JS_FIRE
, XT_JS_FIRE_LEN
)) {
599 snprintf(buf
, sizeof buf
, "vimprobable_fire(%s)",
600 &es
[XT_JS_FIRE_LEN
]);
605 if (!strncmp(es
, XT_JS_FOUND
, XT_JS_FOUND_LEN
)) {
606 if (atoi(&es
[XT_JS_FOUND_LEN
]) == 0)
617 hint(struct tab
*t
, struct karg
*args
)
620 DNPRINTF(XT_D_JS
, "hint: tab %d\n", t
->tab_id
);
622 if (t
->hints_on
== 0)
631 quit(struct tab
*t
, struct karg
*args
)
639 focus(struct tab
*t
, struct karg
*args
)
641 if (t
== NULL
|| args
== NULL
)
644 if (args
->i
== XT_FOCUS_URI
)
645 gtk_widget_grab_focus(GTK_WIDGET(t
->uri_entry
));
646 else if (args
->i
== XT_FOCUS_SEARCH
)
647 gtk_widget_grab_focus(GTK_WIDGET(t
->search_entry
));
653 help(struct tab
*t
, struct karg
*args
)
658 webkit_web_view_load_string(t
->wv
,
659 "<html><body><h1>XXXTerm</h1></body></html>",
668 favorites(struct tab
*t
, struct karg
*args
)
672 char *uri
= NULL
, *title
= NULL
;
673 size_t len
, lineno
= 0;
677 errx(1, "favorites");
679 /* XXX run a digest over the favorites file instead of always generating it */
682 snprintf(file
, sizeof file
, "%s/%s/%s",
683 pwd
->pw_dir
, XT_DIR
, XT_FAVS_FILE
);
684 if ((f
= fopen(file
, "r")) == NULL
) {
689 /* open favorites html */
690 snprintf(file
, sizeof file
, "%s/%s/%s.html",
691 pwd
->pw_dir
, XT_DIR
, XT_FAVS_FILE
);
692 if ((h
= fopen(file
, "w+")) == NULL
) {
693 warn("favorites.html");
697 fprintf(h
, "<html><body>Favorites:<p>\n<ol>\n");
700 if ((title
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
)
701 if (feof(f
) || ferror(f
))
709 if ((uri
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
)
710 if (feof(f
) || ferror(f
)) {
715 fprintf(h
, "<li><a href=\"%s\">%s</a><br>\n", uri
, title
);
729 fprintf(h
, "</ol></body></html>");
734 webkit_web_view_load_string(t
->wv
,
735 "<html><body>Invalid favorites file</body></html>",
740 snprintf(file
, sizeof file
, "file://%s/%s/%s.html",
741 pwd
->pw_dir
, XT_DIR
, XT_FAVS_FILE
);
742 webkit_web_view_load_uri(t
->wv
, file
);
749 favadd(struct tab
*t
, struct karg
*args
)
754 size_t urilen
, linelen
;
755 WebKitWebFrame
*frame
;
756 const gchar
*uri
, *title
;
761 snprintf(file
, sizeof file
, "%s/%s/%s",
762 pwd
->pw_dir
, XT_DIR
, XT_FAVS_FILE
);
763 if ((f
= fopen(file
, "r+")) == NULL
) {
768 title
= webkit_web_view_get_title(t
->wv
);
769 frame
= webkit_web_view_get_main_frame(t
->wv
);
770 uri
= webkit_web_frame_get_uri(frame
);
774 if (title
== NULL
|| uri
== NULL
) {
775 webkit_web_view_load_string(t
->wv
,
776 "<html><body>can't add page to favorites</body></html>",
783 urilen
= strlen(uri
);
786 line
= fparseln(f
, &linelen
, NULL
, NULL
, 0);
787 if (linelen
== urilen
&& !strcmp(line
, uri
))
793 fprintf(f
, "\n%s\n%s", title
, uri
);
803 navaction(struct tab
*t
, struct karg
*args
)
805 DNPRINTF(XT_D_NAV
, "navaction: tab %d opcode %d\n",
810 webkit_web_view_go_back(t
->wv
);
813 webkit_web_view_go_forward(t
->wv
);
816 webkit_web_view_reload(t
->wv
);
819 return (XT_CB_PASSTHROUGH
);
823 move(struct tab
*t
, struct karg
*args
)
825 GtkAdjustment
*adjust
;
826 double pi
, si
, pos
, ps
, upper
, lower
, max
;
833 case XT_MOVE_PAGEDOWN
:
835 case XT_MOVE_HALFDOWN
:
837 adjust
= t
->adjust_v
;
840 adjust
= t
->adjust_h
;
844 pos
= gtk_adjustment_get_value(adjust
);
845 ps
= gtk_adjustment_get_page_size(adjust
);
846 upper
= gtk_adjustment_get_upper(adjust
);
847 lower
= gtk_adjustment_get_lower(adjust
);
848 si
= gtk_adjustment_get_step_increment(adjust
);
849 pi
= gtk_adjustment_get_page_increment(adjust
);
852 DNPRINTF(XT_D_MOVE
, "move: opcode %d %s pos %f ps %f upper %f lower %f "
853 "max %f si %f pi %f\n",
854 args
->i
, adjust
== t
->adjust_h
? "horizontal" : "vertical",
855 pos
, ps
, upper
, lower
, max
, si
, pi
);
861 gtk_adjustment_set_value(adjust
, MIN(pos
, max
));
866 gtk_adjustment_set_value(adjust
, MAX(pos
, lower
));
869 case XT_MOVE_FARRIGHT
:
870 gtk_adjustment_set_value(adjust
, max
);
873 case XT_MOVE_FARLEFT
:
874 gtk_adjustment_set_value(adjust
, lower
);
876 case XT_MOVE_PAGEDOWN
:
878 gtk_adjustment_set_value(adjust
, MIN(pos
, max
));
882 gtk_adjustment_set_value(adjust
, MAX(pos
, lower
));
884 case XT_MOVE_HALFDOWN
:
886 gtk_adjustment_set_value(adjust
, MIN(pos
, max
));
890 gtk_adjustment_set_value(adjust
, MAX(pos
, lower
));
893 return (XT_CB_PASSTHROUGH
);
896 DNPRINTF(XT_D_MOVE
, "move: new pos %f %f\n", pos
, MIN(pos
, max
));
898 return (XT_CB_HANDLED
);
902 getparams(char *cmd
, char *cmp
)
907 if (!strncmp(cmd
, cmp
, strlen(cmp
))) {
908 rv
= cmd
+ strlen(cmp
);
920 tabaction(struct tab
*t
, struct karg
*args
)
922 int rv
= XT_CB_HANDLED
;
923 char *url
= NULL
, *newuri
= NULL
;
925 DNPRINTF(XT_D_TAB
, "tabaction: %p %d %d\n", t
, args
->i
, t
->focus_wv
);
928 return (XT_CB_PASSTHROUGH
);
932 if ((url
= getparams(args
->s
, "tabnew")))
933 create_new_tab(url
, 1);
935 create_new_tab(NULL
, 1);
941 if (gtk_notebook_get_n_pages(notebook
) > 1)
947 if ((url
= getparams(args
->s
, "open")) ||
948 ((url
= getparams(args
->s
, "op"))) ||
949 ((url
= getparams(args
->s
, "o"))))
952 rv
= XT_CB_PASSTHROUGH
;
956 if (valid_url_type(url
)) {
957 newuri
= guess_url_type(url
);
960 webkit_web_view_load_uri(t
->wv
, url
);
965 rv
= XT_CB_PASSTHROUGH
;
979 resizetab(struct tab
*t
, struct karg
*args
)
981 if (t
== NULL
|| args
== NULL
)
982 errx(1, "resizetab");
984 DNPRINTF(XT_D_TAB
, "resizetab: tab %d %d\n",
987 adjustfont_webkit(t
, args
->i
);
989 return (XT_CB_HANDLED
);
993 movetab(struct tab
*t
, struct karg
*args
)
998 if (t
== NULL
|| args
== NULL
)
1001 DNPRINTF(XT_D_TAB
, "movetab: tab %d opcode %d\n",
1002 t
->tab_id
, args
->i
);
1004 if (args
->i
== XT_TAB_INVALID
)
1005 return (XT_CB_PASSTHROUGH
);
1007 if (args
->i
< XT_TAB_INVALID
) {
1008 /* next or previous tab */
1009 if (TAILQ_EMPTY(&tabs
))
1010 return (XT_CB_PASSTHROUGH
);
1014 gtk_notebook_next_page(notebook
);
1017 gtk_notebook_prev_page(notebook
);
1020 gtk_notebook_set_current_page(notebook
, 0);
1023 gtk_notebook_set_current_page(notebook
, -1);
1026 return (XT_CB_PASSTHROUGH
);
1029 return (XT_CB_HANDLED
);
1034 if (t
->tab_id
== x
) {
1035 DNPRINTF(XT_D_TAB
, "movetab: do nothing\n");
1036 return (XT_CB_HANDLED
);
1039 TAILQ_FOREACH(tt
, &tabs
, entry
) {
1040 if (tt
->tab_id
== x
) {
1041 gtk_notebook_set_current_page(notebook
, x
);
1042 DNPRINTF(XT_D_TAB
, "movetab: going to %d\n", x
);
1044 gtk_widget_grab_focus(GTK_WIDGET(tt
->wv
));
1048 return (XT_CB_HANDLED
);
1052 command(struct tab
*t
, struct karg
*args
)
1057 if (t
== NULL
|| args
== NULL
)
1062 else if (args
->i
== '?')
1064 else if (args
->i
== ':')
1067 warnx("invalid command %c\n", args
->i
);
1068 return (XT_CB_PASSTHROUGH
);
1071 DNPRINTF(XT_D_CMD
, "command: type %s\n", s
);
1073 gtk_entry_set_text(GTK_ENTRY(t
->cmd
), s
);
1074 gdk_color_parse("white", &color
);
1075 gtk_widget_modify_base(t
->cmd
, GTK_STATE_NORMAL
, &color
);
1076 gtk_widget_show(t
->cmd
);
1077 gtk_widget_grab_focus(GTK_WIDGET(t
->cmd
));
1078 gtk_editable_set_position(GTK_EDITABLE(t
->cmd
), -1);
1080 return (XT_CB_HANDLED
);
1084 search(struct tab
*t
, struct karg
*args
)
1088 if (t
== NULL
|| args
== NULL
)
1090 if (t
->search_text
== NULL
)
1091 return (XT_CB_PASSTHROUGH
);
1093 DNPRINTF(XT_D_CMD
, "search: tab %d opc %d forw %d text %s\n",
1094 t
->tab_id
, args
->i
, t
->search_forward
, t
->search_text
);
1097 case XT_SEARCH_NEXT
:
1098 d
= t
->search_forward
;
1100 case XT_SEARCH_PREV
:
1101 d
= !t
->search_forward
;
1104 return (XT_CB_PASSTHROUGH
);
1107 webkit_web_view_search_text(t
->wv
, t
->search_text
, FALSE
, d
, TRUE
);
1109 return (XT_CB_HANDLED
);
1113 mnprintf(char **buf
, int *len
, char *fmt
, ...)
1121 x
= vsnprintf(*buf
, *len
, fmt
, ap
);
1125 errx(1, "mnprintf: buffer overflow");
1136 set(struct tab
*t
, struct karg
*args
)
1138 struct mime_type
*m
;
1139 char b
[16 * 1024], *s
, *pars
;
1142 if (t
== NULL
|| args
== NULL
)
1145 DNPRINTF(XT_D_CMD
, "set: tab %d\n",
1151 if ((pars
= getparams(args
->s
, "set")) == NULL
) {
1152 mnprintf(&s
, &l
, "<html><body><pre>");
1153 mnprintf(&s
, &l
, "ctrl_click_focus\t= %d<br>", ctrl_click_focus
);
1154 mnprintf(&s
, &l
, "cookies_enabled\t\t= %d<br>", cookies_enabled
);
1155 mnprintf(&s
, &l
, "default_font_size\t= %d<br>", default_font_size
);
1156 mnprintf(&s
, &l
, "enable_plugins\t\t= %d<br>", enable_plugins
);
1157 mnprintf(&s
, &l
, "enable_scripts\t\t= %d<br>", enable_scripts
);
1158 mnprintf(&s
, &l
, "fancy_bar\t\t= %d<br>", fancy_bar
);
1159 mnprintf(&s
, &l
, "home\t\t\t= %s<br>", home
);
1160 TAILQ_FOREACH(m
, &mtl
, entry
) {
1161 mnprintf(&s
, &l
, "mime_type\t\t= %s%s,%s<br>",
1162 m
->mt_type
, m
->mt_default
? "*" : "", m
->mt_action
);
1164 mnprintf(&s
, &l
, "proxy_uri\t\t= %s<br>", proxy_uri
);
1165 mnprintf(&s
, &l
, "read_only_cookies\t= %d<br>", read_only_cookies
);
1166 mnprintf(&s
, &l
, "search_string\t\t= %s<br>", search_string
);
1167 mnprintf(&s
, &l
, "showurl\t\t\t= %d<br>", showurl
);
1168 mnprintf(&s
, &l
, "showtabs\t\t= %d<br>", showtabs
);
1169 mnprintf(&s
, &l
, "tabless\t\t\t= %d<br>", tabless
);
1170 mnprintf(&s
, &l
, "download_dir\t\t= %s<br>", download_dir
);
1171 mnprintf(&s
, &l
, "</pre></body></html>");
1173 webkit_web_view_load_string(t
->wv
,
1181 /* XXX this sucks donkey balls and is a POC only */
1184 if (!strncmp(pars
, "enable_scripts ", strlen("enable_scripts"))) {
1185 s
= pars
+ strlen("enable_scripts");
1186 x
= strtol(s
, &e
, 10);
1187 if (s
[0] == '\0' || *e
!= '\0')
1188 webkit_web_view_load_string(t
->wv
,
1189 "<html><body>invalid value</body></html>",
1195 g_object_set((GObject
*)t
->settings
,
1196 "enable-scripts", enable_scripts
, (char *)NULL
);
1197 webkit_web_view_set_settings(t
->wv
, t
->settings
);
1206 return (XT_CB_PASSTHROUGH
);
1209 /* inherent to GTK not all keys will be caught at all times */
1214 int (*func
)(struct tab
*, struct karg
*);
1217 { 0, 0, GDK_slash
, command
, {.i
= '/'} },
1218 { GDK_SHIFT_MASK
, 0, GDK_question
, command
, {.i
= '?'} },
1219 { GDK_SHIFT_MASK
, 0, GDK_colon
, command
, {.i
= ':'} },
1220 { GDK_CONTROL_MASK
, 0, GDK_q
, quit
, {0} },
1223 { 0, 0, GDK_n
, search
, {.i
= XT_SEARCH_NEXT
} },
1224 { GDK_SHIFT_MASK
, 0, GDK_N
, search
, {.i
= XT_SEARCH_PREV
} },
1227 { 0, 0, GDK_F6
, focus
, {.i
= XT_FOCUS_URI
} },
1228 { 0, 0, GDK_F7
, focus
, {.i
= XT_FOCUS_SEARCH
} },
1231 { 0, 0, GDK_f
, hint
, {.i
= 0} },
1234 { 0, 0, GDK_BackSpace
, navaction
, {.i
= XT_NAV_BACK
} },
1235 { GDK_MOD1_MASK
, 0, GDK_Left
, navaction
, {.i
= XT_NAV_BACK
} },
1236 { GDK_SHIFT_MASK
, 0, GDK_BackSpace
, navaction
, {.i
= XT_NAV_FORWARD
} },
1237 { GDK_MOD1_MASK
, 0, GDK_Right
, navaction
, {.i
= XT_NAV_FORWARD
} },
1238 { 0, 0, GDK_F5
, navaction
, {.i
= XT_NAV_RELOAD
} },
1239 { GDK_CONTROL_MASK
, 0, GDK_r
, navaction
, {.i
= XT_NAV_RELOAD
} },
1240 { GDK_CONTROL_MASK
, 0, GDK_l
, navaction
, {.i
= XT_NAV_RELOAD
} },
1241 { GDK_SHIFT_MASK
, 0, GDK_F
, favorites
, {0} },
1243 /* vertical movement */
1244 { 0, 0, GDK_j
, move
, {.i
= XT_MOVE_DOWN
} },
1245 { 0, 0, GDK_Down
, move
, {.i
= XT_MOVE_DOWN
} },
1246 { 0, 0, GDK_Up
, move
, {.i
= XT_MOVE_UP
} },
1247 { 0, 0, GDK_k
, move
, {.i
= XT_MOVE_UP
} },
1248 { GDK_SHIFT_MASK
, 0, GDK_G
, move
, {.i
= XT_MOVE_BOTTOM
} },
1249 { 0, 0, GDK_End
, move
, {.i
= XT_MOVE_BOTTOM
} },
1250 { 0, 0, GDK_Home
, move
, {.i
= XT_MOVE_TOP
} },
1251 { 0, GDK_g
, GDK_g
, move
, {.i
= XT_MOVE_TOP
} }, /* XXX make this work */
1252 { 0, 0, GDK_space
, move
, {.i
= XT_MOVE_PAGEDOWN
} },
1253 { GDK_CONTROL_MASK
, 0, GDK_f
, move
, {.i
= XT_MOVE_PAGEDOWN
} },
1254 { GDK_CONTROL_MASK
, 0, GDK_d
, move
, {.i
= XT_MOVE_HALFDOWN
} },
1255 { 0, 0, GDK_Page_Down
, move
, {.i
= XT_MOVE_PAGEDOWN
} },
1256 { 0, 0, GDK_Page_Up
, move
, {.i
= XT_MOVE_PAGEUP
} },
1257 { GDK_CONTROL_MASK
, 0, GDK_b
, move
, {.i
= XT_MOVE_PAGEUP
} },
1258 { GDK_CONTROL_MASK
, 0, GDK_u
, move
, {.i
= XT_MOVE_HALFUP
} },
1259 /* horizontal movement */
1260 { 0, 0, GDK_l
, move
, {.i
= XT_MOVE_RIGHT
} },
1261 { 0, 0, GDK_Right
, move
, {.i
= XT_MOVE_RIGHT
} },
1262 { 0, 0, GDK_Left
, move
, {.i
= XT_MOVE_LEFT
} },
1263 { 0, 0, GDK_h
, move
, {.i
= XT_MOVE_LEFT
} },
1264 { GDK_SHIFT_MASK
, 0, GDK_dollar
, move
, {.i
= XT_MOVE_FARRIGHT
} },
1265 { 0, 0, GDK_0
, move
, {.i
= XT_MOVE_FARLEFT
} },
1268 { GDK_CONTROL_MASK
, 0, GDK_t
, tabaction
, {.i
= XT_TAB_NEW
} },
1269 { GDK_CONTROL_MASK
, 0, GDK_w
, tabaction
, {.i
= XT_TAB_DELETE
} },
1270 { GDK_CONTROL_MASK
, 0, GDK_1
, movetab
, {.i
= 1} },
1271 { GDK_CONTROL_MASK
, 0, GDK_2
, movetab
, {.i
= 2} },
1272 { GDK_CONTROL_MASK
, 0, GDK_3
, movetab
, {.i
= 3} },
1273 { GDK_CONTROL_MASK
, 0, GDK_4
, movetab
, {.i
= 4} },
1274 { GDK_CONTROL_MASK
, 0, GDK_5
, movetab
, {.i
= 5} },
1275 { GDK_CONTROL_MASK
, 0, GDK_6
, movetab
, {.i
= 6} },
1276 { GDK_CONTROL_MASK
, 0, GDK_7
, movetab
, {.i
= 7} },
1277 { GDK_CONTROL_MASK
, 0, GDK_8
, movetab
, {.i
= 8} },
1278 { GDK_CONTROL_MASK
, 0, GDK_9
, movetab
, {.i
= 9} },
1279 { GDK_CONTROL_MASK
, 0, GDK_0
, movetab
, {.i
= 10} },
1280 { GDK_CONTROL_MASK
|GDK_SHIFT_MASK
, 0, GDK_less
, movetab
, {.i
= XT_TAB_FIRST
} },
1281 { GDK_CONTROL_MASK
|GDK_SHIFT_MASK
, 0, GDK_greater
, movetab
, {.i
= XT_TAB_LAST
} },
1282 { GDK_CONTROL_MASK
, 0, GDK_minus
, resizetab
, {.i
= -1} },
1283 { GDK_CONTROL_MASK
|GDK_SHIFT_MASK
, 0, GDK_plus
, resizetab
, {.i
= 1} },
1284 { GDK_CONTROL_MASK
, 0, GDK_equal
, resizetab
, {.i
= 1} },
1290 int (*func
)(struct tab
*, struct karg
*);
1293 { "q!", 0, quit
, {0} },
1294 { "qa", 0, quit
, {0} },
1295 { "qa!", 0, quit
, {0} },
1296 { "help", 0, help
, {0} },
1299 { "fav", 0, favorites
, {0} },
1300 { "favadd", 0, favadd
, {0} },
1302 { "1", 0, move
, {.i
= XT_MOVE_TOP
} },
1305 { "o", 1, tabaction
, {.i
= XT_TAB_OPEN
} },
1306 { "op", 1, tabaction
, {.i
= XT_TAB_OPEN
} },
1307 { "open", 1, tabaction
, {.i
= XT_TAB_OPEN
} },
1308 { "tabnew", 1, tabaction
, {.i
= XT_TAB_NEW
} },
1309 { "tabedit", 1, tabaction
, {.i
= XT_TAB_NEW
} },
1310 { "tabe", 1, tabaction
, {.i
= XT_TAB_NEW
} },
1311 { "tabclose", 0, tabaction
, {.i
= XT_TAB_DELETE
} },
1312 { "tabc", 0, tabaction
, {.i
= XT_TAB_DELETE
} },
1313 { "quit", 0, tabaction
, {.i
= XT_TAB_DELQUIT
} },
1314 { "q", 0, tabaction
, {.i
= XT_TAB_DELQUIT
} },
1315 /* XXX add count to these commands */
1316 { "tabfirst", 0, movetab
, {.i
= XT_TAB_FIRST
} },
1317 { "tabfir", 0, movetab
, {.i
= XT_TAB_FIRST
} },
1318 { "tabrewind", 0, movetab
, {.i
= XT_TAB_FIRST
} },
1319 { "tabr", 0, movetab
, {.i
= XT_TAB_FIRST
} },
1320 { "tablast", 0, movetab
, {.i
= XT_TAB_LAST
} },
1321 { "tabl", 0, movetab
, {.i
= XT_TAB_LAST
} },
1322 { "tabprevious", 0, movetab
, {.i
= XT_TAB_PREV
} },
1323 { "tabp", 0, movetab
, {.i
= XT_TAB_PREV
} },
1324 { "tabnext", 0, movetab
, {.i
= XT_TAB_NEXT
} },
1325 { "tabn", 0, movetab
, {.i
= XT_TAB_NEXT
} },
1328 { "set", 1, set
, {0} },
1332 tab_close_cb(GtkWidget
*button
, struct tab
*t
)
1334 DNPRINTF(XT_D_TAB
, "tab_close_cb: tab %d\n", t
->tab_id
);
1342 focus_uri_entry_cb(GtkWidget
* w
, GtkDirectionType direction
, struct tab
*t
)
1344 DNPRINTF(XT_D_URL
, "focus_uri_entry_cb: tab %d focus_wv %d\n",
1345 t
->tab_id
, t
->focus_wv
);
1348 errx(1, "focus_uri_entry_cb");
1350 /* focus on wv instead */
1352 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1356 activate_uri_entry_cb(GtkWidget
* entry
, struct tab
*t
)
1358 const gchar
*uri
= gtk_entry_get_text(GTK_ENTRY(entry
));
1359 char *newuri
= NULL
;
1361 DNPRINTF(XT_D_URL
, "activate_uri_entry_cb: %s\n", uri
);
1364 errx(1, "activate_uri_entry_cb");
1369 uri
+= strspn(uri
, "\t ");
1371 if (valid_url_type((char *)uri
)) {
1372 newuri
= guess_url_type((char *)uri
);
1376 webkit_web_view_load_uri(t
->wv
, uri
);
1377 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1384 activate_search_entry_cb(GtkWidget
* entry
, struct tab
*t
)
1386 const gchar
*search
= gtk_entry_get_text(GTK_ENTRY(entry
));
1387 char *newuri
= NULL
;
1389 DNPRINTF(XT_D_URL
, "activate_search_entry_cb: %s\n", search
);
1392 errx(1, "activate_search_entry_cb");
1394 if (search_string
== NULL
) {
1395 warnx("no search_string");
1399 newuri
= g_strdup_printf(search_string
, search
);
1401 webkit_web_view_load_uri(t
->wv
, newuri
);
1402 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1409 notify_load_status_cb(WebKitWebView
* wview
, GParamSpec
* pspec
, struct tab
*t
)
1412 WebKitWebFrame
*frame
;
1416 errx(1, "notify_load_status_cb");
1418 switch (webkit_web_view_get_load_status(wview
)) {
1419 case WEBKIT_LOAD_PROVISIONAL
:
1420 gtk_widget_show(t
->spinner
);
1421 gtk_spinner_start(GTK_SPINNER(t
->spinner
));
1422 gtk_label_set_text(GTK_LABEL(t
->label
), "Loading");
1424 gtk_widget_set_sensitive(GTK_WIDGET(t
->stop
), TRUE
);
1427 /* take focus if we are visible */
1428 if (gtk_notebook_get_current_page(notebook
) == t
->tab_id
)
1429 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1433 case WEBKIT_LOAD_COMMITTED
:
1434 frame
= webkit_web_view_get_main_frame(wview
);
1435 uri
= webkit_web_frame_get_uri(frame
);
1437 gtk_entry_set_text(GTK_ENTRY(t
->uri_entry
), uri
);
1439 /* color uri_entry */
1440 if (uri
&& !strncmp(uri
, "https://", strlen("https://")))
1441 gdk_color_parse("green", &color
);
1443 gdk_color_parse("white", &color
);
1444 gtk_widget_modify_base(t
->uri_entry
, GTK_STATE_NORMAL
, &color
);
1448 case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT
:
1449 uri
= webkit_web_view_get_title(wview
);
1451 frame
= webkit_web_view_get_main_frame(wview
);
1452 uri
= webkit_web_frame_get_uri(frame
);
1454 gtk_label_set_text(GTK_LABEL(t
->label
), uri
);
1455 gtk_window_set_title(GTK_WINDOW(main_window
), uri
);
1458 case WEBKIT_LOAD_FINISHED
:
1459 #if WEBKIT_CHECK_VERSION(1, 1, 18)
1460 case WEBKIT_LOAD_FAILED
:
1462 gtk_spinner_stop(GTK_SPINNER(t
->spinner
));
1463 gtk_widget_hide(t
->spinner
);
1465 gtk_widget_set_sensitive(GTK_WIDGET(t
->stop
), FALSE
);
1469 gtk_widget_set_sensitive(GTK_WIDGET(t
->backward
),
1470 webkit_web_view_can_go_back(wview
));
1472 gtk_widget_set_sensitive(GTK_WIDGET(t
->forward
),
1473 webkit_web_view_can_go_forward(wview
));
1477 webview_load_finished_cb(WebKitWebView
*wv
, WebKitWebFrame
*wf
, struct tab
*t
)
1479 run_script(t
, JS_HINTING
);
1483 webview_progress_changed_cb(WebKitWebView
*wv
, int progress
, struct tab
*t
)
1485 gtk_entry_set_progress_fraction(GTK_ENTRY(t
->uri_entry
),
1486 progress
== 100 ? 0 : (double)progress
/ 100);
1490 webview_nw_cb(WebKitWebView
*wv
, WebKitWebFrame
*wf
,
1491 WebKitNetworkRequest
*request
, WebKitWebNavigationAction
*na
,
1492 WebKitWebPolicyDecision
*pd
, struct tab
*t
)
1497 errx(1, "webview_nw_cb");
1499 DNPRINTF(XT_D_NAV
, "webview_nw_cb: %s\n",
1500 webkit_network_request_get_uri(request
));
1502 /* open in current tab */
1503 uri
= (char *)webkit_network_request_get_uri(request
);
1504 webkit_web_view_load_uri(t
->wv
, uri
);
1505 webkit_web_policy_decision_ignore(pd
);
1507 return (TRUE
); /* we made the decission */
1511 webview_npd_cb(WebKitWebView
*wv
, WebKitWebFrame
*wf
,
1512 WebKitNetworkRequest
*request
, WebKitWebNavigationAction
*na
,
1513 WebKitWebPolicyDecision
*pd
, struct tab
*t
)
1518 errx(1, "webview_npd_cb");
1520 DNPRINTF(XT_D_NAV
, "webview_npd_cb: ctrl_click %d %s\n",
1522 webkit_network_request_get_uri(request
));
1524 uri
= (char *)webkit_network_request_get_uri(request
);
1525 if (t
->ctrl_click
) {
1527 create_new_tab(uri
, ctrl_click_focus
);
1528 webkit_web_policy_decision_ignore(pd
);
1529 return (TRUE
); /* we made the decission */
1532 webkit_web_policy_decision_use(pd
);
1533 return (TRUE
); /* we made the decission */
1537 webview_cwv_cb(WebKitWebView
*wv
, WebKitWebFrame
*wf
, struct tab
*t
)
1540 errx(1, "webview_cwv_cb");
1542 DNPRINTF(XT_D_NAV
, "webview_cwv_cb: %s\n",
1543 webkit_web_view_get_uri(wv
));
1549 webview_event_cb(GtkWidget
*w
, GdkEventButton
*e
, struct tab
*t
)
1551 /* we can not eat the event without throwing gtk off so defer it */
1553 /* catch middle click */
1554 if (e
->type
== GDK_BUTTON_RELEASE
&& e
->button
== 2) {
1559 /* catch ctrl click */
1560 if (e
->type
== GDK_BUTTON_RELEASE
&&
1561 CLEAN(e
->state
) == GDK_CONTROL_MASK
)
1566 return (XT_CB_PASSTHROUGH
);
1570 run_mimehandler(struct tab
*t
, char *mime_type
, WebKitNetworkRequest
*request
)
1572 struct mime_type
*m
;
1574 m
= find_mime_type(mime_type
);
1589 execlp(m
->mt_action
, m
->mt_action
,
1590 webkit_network_request_get_uri(request
), (void *)NULL
);
1599 webview_mimetype_cb(WebKitWebView
*wv
, WebKitWebFrame
*frame
,
1600 WebKitNetworkRequest
*request
, char *mime_type
,
1601 WebKitWebPolicyDecision
*decision
, struct tab
*t
)
1604 errx(1, "webview_mimetype_cb");
1606 DNPRINTF(XT_D_DOWNLOAD
, "webview_mimetype_cb: tab %d mime %s\n",
1607 t
->tab_id
, mime_type
);
1609 if (run_mimehandler(t
, mime_type
, request
) == 0) {
1610 webkit_web_policy_decision_ignore(decision
);
1611 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1615 if (webkit_web_view_can_show_mime_type(wv
, mime_type
) == FALSE
) {
1616 webkit_web_policy_decision_download(decision
);
1624 webview_download_cb(WebKitWebView
*wv
, WebKitDownload
*download
, struct tab
*t
)
1626 const gchar
*filename
;
1629 if (download
== NULL
|| t
== NULL
)
1630 errx(1, "webview_download_cb: invalid pointers");
1632 filename
= webkit_download_get_suggested_filename(download
);
1633 if (filename
== NULL
)
1634 return (FALSE
); /* abort download */
1636 uri
= g_strdup_printf("file://%s/%s", download_dir
, filename
);
1638 DNPRINTF(XT_D_DOWNLOAD
, "webview_download_cb: tab %d filename %s "
1640 t
->tab_id
, filename
, uri
);
1642 webkit_download_set_destination_uri(download
, uri
);
1643 webkit_download_start(download
);
1648 return (TRUE
); /* start download */
1651 /* XXX currently unused */
1653 webview_hover_cb(WebKitWebView
*wv
, gchar
*title
, gchar
*uri
, struct tab
*t
)
1655 DNPRINTF(XT_D_KEY
, "webview_hover_cb: %s %s\n", title
, uri
);
1658 errx(1, "webview_hover_cb");
1665 t
->hover
= g_strdup(uri
);
1666 } else if (t
->hover
) {
1673 webview_keypress_cb(GtkWidget
*w
, GdkEventKey
*e
, struct tab
*t
)
1676 char s
[2], buf
[128];
1677 const char *errstr
= NULL
;
1680 /* don't use w directly; use t->whatever instead */
1683 errx(1, "webview_keypress_cb");
1685 DNPRINTF(XT_D_KEY
, "webview_keypress_cb: keyval 0x%x mask 0x%x t %p\n",
1686 e
->keyval
, e
->state
, t
);
1690 if (CLEAN(e
->state
) == 0 && e
->keyval
== GDK_Escape
) {
1692 return (XT_CB_HANDLED
);
1696 if (CLEAN(e
->state
) == 0 && e
->keyval
== GDK_Return
) {
1697 link
= strtonum(t
->hint_num
, 1, 1000, &errstr
);
1699 /* we have a string */
1701 /* we have a number */
1702 snprintf(buf
, sizeof buf
, "vimprobable_fire(%s)",
1710 /* XXX unfuck this */
1711 if (CLEAN(e
->state
) == 0 && e
->keyval
== GDK_BackSpace
) {
1712 if (t
->hint_mode
== XT_HINT_NUMERICAL
) {
1713 /* last input was numerical */
1715 l
= strlen(t
->hint_num
);
1722 t
->hint_num
[l
] = '\0';
1726 } else if (t
->hint_mode
== XT_HINT_ALPHANUM
) {
1727 /* last input was alphanumerical */
1729 l
= strlen(t
->hint_buf
);
1736 t
->hint_buf
[l
] = '\0';
1746 /* numerical input */
1747 if (CLEAN(e
->state
) == 0 &&
1748 ((e
->keyval
>= GDK_0
&& e
->keyval
<= GDK_9
) || (e
->keyval
>= GDK_KP_0
&& e
->keyval
<= GDK_KP_9
))) {
1749 snprintf(s
, sizeof s
, "%c", e
->keyval
);
1750 strlcat(t
->hint_num
, s
, sizeof t
->hint_num
);
1751 DNPRINTF(XT_D_JS
, "webview_keypress_cb: numerical %s\n",
1754 link
= strtonum(t
->hint_num
, 1, 1000, &errstr
);
1756 DNPRINTF(XT_D_JS
, "webview_keypress_cb: invalid link number\n");
1759 snprintf(buf
, sizeof buf
, "vimprobable_update_hints(%s)",
1761 t
->hint_mode
= XT_HINT_NUMERICAL
;
1765 /* empty the counter buffer */
1766 bzero(t
->hint_buf
, sizeof t
->hint_buf
);
1767 return (XT_CB_HANDLED
);
1770 /* alphanumerical input */
1772 (CLEAN(e
->state
) == 0 && e
->keyval
>= GDK_a
&& e
->keyval
<= GDK_z
) ||
1773 (CLEAN(e
->state
) == GDK_SHIFT_MASK
&& e
->keyval
>= GDK_A
&& e
->keyval
<= GDK_Z
) ||
1774 (CLEAN(e
->state
) == 0 && ((e
->keyval
>= GDK_0
&& e
->keyval
<= GDK_9
) ||
1775 ((e
->keyval
>= GDK_KP_0
&& e
->keyval
<= GDK_KP_9
) && (t
->hint_mode
!= XT_HINT_NUMERICAL
))))) {
1776 snprintf(s
, sizeof s
, "%c", e
->keyval
);
1777 strlcat(t
->hint_buf
, s
, sizeof t
->hint_buf
);
1778 DNPRINTF(XT_D_JS
, "webview_keypress_cb: alphanumerical %s\n",
1781 snprintf(buf
, sizeof buf
, "vimprobable_cleanup()");
1784 snprintf(buf
, sizeof buf
, "vimprobable_show_hints('%s')",
1786 t
->hint_mode
= XT_HINT_ALPHANUM
;
1789 /* empty the counter buffer */
1790 bzero(t
->hint_num
, sizeof t
->hint_num
);
1791 return (XT_CB_HANDLED
);
1794 return (XT_CB_HANDLED
);
1797 for (i
= 0; i
< LENGTH(keys
); i
++)
1798 if (e
->keyval
== keys
[i
].key
&& CLEAN(e
->state
) ==
1800 keys
[i
].func(t
, &keys
[i
].arg
);
1801 return (XT_CB_HANDLED
);
1804 return (XT_CB_PASSTHROUGH
);
1808 cmd_keyrelease_cb(GtkEntry
*w
, GdkEventKey
*e
, struct tab
*t
)
1810 const gchar
*c
= gtk_entry_get_text(w
);
1814 DNPRINTF(XT_D_CMD
, "cmd_keyrelease_cb: keyval 0x%x mask 0x%x t %p\n",
1815 e
->keyval
, e
->state
, t
);
1818 errx(1, "cmd_keyrelease_cb");
1820 DNPRINTF(XT_D_CMD
, "cmd_keyrelease_cb: keyval 0x%x mask 0x%x t %p\n",
1821 e
->keyval
, e
->state
, t
);
1830 else if (c
[0] == '?')
1836 if (webkit_web_view_search_text(t
->wv
, &c
[1], FALSE
, forward
, TRUE
) ==
1838 /* not found, mark red */
1839 gdk_color_parse("red", &color
);
1840 gtk_widget_modify_base(t
->cmd
, GTK_STATE_NORMAL
, &color
);
1841 /* unmark and remove selection */
1842 webkit_web_view_unmark_text_matches(t
->wv
);
1843 /* my kingdom for a way to unselect text in webview */
1845 /* found, highlight all */
1846 webkit_web_view_unmark_text_matches(t
->wv
);
1847 webkit_web_view_mark_text_matches(t
->wv
, &c
[1], FALSE
, 0);
1848 webkit_web_view_set_highlight_text_matches(t
->wv
, TRUE
);
1849 gdk_color_parse("white", &color
);
1850 gtk_widget_modify_base(t
->cmd
, GTK_STATE_NORMAL
, &color
);
1853 return (XT_CB_PASSTHROUGH
);
1858 cmd_complete(struct tab
*t
, char *s
)
1861 GtkEntry
*w
= GTK_ENTRY(t
->cmd
);
1863 DNPRINTF(XT_D_CMD
, "cmd_keypress_cb: complete %s\n", s
);
1865 for (i
= 0; i
< LENGTH(cmds
); i
++) {
1866 if (!strncasecmp(cmds
[i
].cmd
, s
, strlen(s
))) {
1867 fprintf(stderr
, "match %s %d\n", cmds
[i
].cmd
, strcasecmp(cmds
[i
].cmd
, s
));
1869 gtk_entry_set_text(w
, ":");
1870 gtk_entry_append_text(w
, cmds
[i
].cmd
);
1871 gtk_editable_set_position(GTK_EDITABLE(w
), -1);
1881 cmd_keypress_cb(GtkEntry
*w
, GdkEventKey
*e
, struct tab
*t
)
1883 int rv
= XT_CB_HANDLED
;
1884 const gchar
*c
= gtk_entry_get_text(w
);
1887 errx(1, "cmd_keypress_cb");
1889 DNPRINTF(XT_D_CMD
, "cmd_keypress_cb: keyval 0x%x mask 0x%x t %p\n",
1890 e
->keyval
, e
->state
, t
);
1894 e
->keyval
= GDK_Escape
;
1895 else if (!(c
[0] == ':' || c
[0] == '/' || c
[0] == '?'))
1896 e
->keyval
= GDK_Escape
;
1898 switch (e
->keyval
) {
1904 if (strchr (c
, ' ')) {
1905 /* par completion */
1906 fprintf(stderr
, "completeme par\n");
1910 cmd_complete(t
, (char *)&c
[1]);
1915 if (!(!strcmp(c
, ":") || !strcmp(c
, "/") || !strcmp(c
, "?")))
1919 gtk_widget_hide(t
->cmd
);
1920 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1924 rv
= XT_CB_PASSTHROUGH
;
1930 cmd_focusout_cb(GtkWidget
*w
, GdkEventFocus
*e
, struct tab
*t
)
1933 errx(1, "cmd_focusout_cb");
1935 DNPRINTF(XT_D_CMD
, "cmd_focusout_cb: tab %d focus_wv %d\n",
1936 t
->tab_id
, t
->focus_wv
);
1938 /* abort command when losing focus */
1939 gtk_widget_hide(t
->cmd
);
1941 gtk_widget_grab_focus(GTK_WIDGET(t
->wv
));
1943 gtk_widget_grab_focus(GTK_WIDGET(t
->uri_entry
));
1945 return (XT_CB_PASSTHROUGH
);
1949 cmd_activate_cb(GtkEntry
*entry
, struct tab
*t
)
1953 const gchar
*c
= gtk_entry_get_text(entry
);
1956 errx(1, "cmd_activate_cb");
1958 DNPRINTF(XT_D_CMD
, "cmd_activate_cb: tab %d %s\n", t
->tab_id
, c
);
1963 else if (!(c
[0] == ':' || c
[0] == '/' || c
[0] == '?'))
1969 if (c
[0] == '/' || c
[0] == '?') {
1970 if (t
->search_text
) {
1971 g_free(t
->search_text
);
1972 t
->search_text
= NULL
;
1975 t
->search_text
= g_strdup(s
);
1976 t
->search_forward
= c
[0] == '/';
1981 for (i
= 0; i
< LENGTH(cmds
); i
++)
1982 if (cmds
[i
].params
) {
1983 if (!strncmp(s
, cmds
[i
].cmd
, strlen(cmds
[i
].cmd
))) {
1984 cmds
[i
].arg
.s
= g_strdup(s
);
1985 cmds
[i
].func(t
, &cmds
[i
].arg
);
1988 if (!strcmp(s
, cmds
[i
].cmd
))
1989 cmds
[i
].func(t
, &cmds
[i
].arg
);
1993 gtk_widget_hide(t
->cmd
);
1997 backward_cb(GtkWidget
*w
, struct tab
*t
)
2000 errx(1, "backward_cb");
2002 DNPRINTF(XT_D_NAV
, "backward_cb: tab %d\n", t
->tab_id
);
2004 webkit_web_view_go_back(t
->wv
);
2008 forward_cb(GtkWidget
*w
, struct tab
*t
)
2011 errx(1, "forward_cb");
2013 DNPRINTF(XT_D_NAV
, "forward_cb: tab %d\n", t
->tab_id
);
2015 webkit_web_view_go_forward(t
->wv
);
2019 stop_cb(GtkWidget
*w
, struct tab
*t
)
2021 WebKitWebFrame
*frame
;
2026 DNPRINTF(XT_D_NAV
, "stop_cb: tab %d\n", t
->tab_id
);
2028 frame
= webkit_web_view_get_main_frame(t
->wv
);
2029 if (frame
== NULL
) {
2030 warnx("stop_cb: no frame");
2034 webkit_web_frame_stop_loading(frame
);
2038 setup_webkit(struct tab
*t
)
2040 g_object_set((GObject
*)t
->settings
,
2041 "user-agent", t
->user_agent
, (char *)NULL
);
2042 g_object_set((GObject
*)t
->settings
,
2043 "enable-scripts", enable_scripts
, (char *)NULL
);
2044 g_object_set((GObject
*)t
->settings
,
2045 "enable-plugins", enable_plugins
, (char *)NULL
);
2046 adjustfont_webkit(t
, XT_FONT_SET
);
2048 webkit_web_view_set_settings(t
->wv
, t
->settings
);
2052 create_browser(struct tab
*t
)
2058 errx(1, "create_browser");
2060 t
->sb_h
= GTK_SCROLLBAR(gtk_hscrollbar_new(NULL
));
2061 t
->sb_v
= GTK_SCROLLBAR(gtk_vscrollbar_new(NULL
));
2062 t
->adjust_h
= gtk_range_get_adjustment(GTK_RANGE(t
->sb_h
));
2063 t
->adjust_v
= gtk_range_get_adjustment(GTK_RANGE(t
->sb_v
));
2065 w
= gtk_scrolled_window_new(t
->adjust_h
, t
->adjust_v
);
2066 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w
),
2067 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2069 t
->wv
= WEBKIT_WEB_VIEW(webkit_web_view_new());
2070 gtk_container_add(GTK_CONTAINER(w
), GTK_WIDGET(t
->wv
));
2073 t
->settings
= webkit_web_settings_new();
2075 g_object_get((GObject
*)t
->settings
, "user-agent", &strval
, (char *)NULL
);
2076 t
->user_agent
= g_strdup_printf("%s %s+", strval
, version
);
2089 w
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
2090 gtk_window_set_default_size(GTK_WINDOW(w
), 1024, 768);
2091 gtk_widget_set_name(w
, "xxxterm");
2092 gtk_window_set_wmclass(GTK_WINDOW(w
), "xxxterm", "XXXTerm");
2093 g_signal_connect(G_OBJECT(w
), "delete_event",
2094 G_CALLBACK (gtk_main_quit
), NULL
);
2100 create_toolbar(struct tab
*t
)
2102 GtkWidget
*toolbar
= gtk_toolbar_new();
2105 #if GTK_CHECK_VERSION(2,15,0)
2106 gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar
),
2107 GTK_ORIENTATION_HORIZONTAL
);
2109 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar
),
2110 GTK_ORIENTATION_HORIZONTAL
);
2112 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
2115 /* backward button */
2116 t
->backward
= gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK
);
2117 gtk_widget_set_sensitive(GTK_WIDGET(t
->backward
), FALSE
);
2118 g_signal_connect(G_OBJECT(t
->backward
), "clicked",
2119 G_CALLBACK(backward_cb
), t
);
2120 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), t
->backward
, -1);
2122 /* forward button */
2124 gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD
);
2125 gtk_widget_set_sensitive(GTK_WIDGET(t
->forward
), FALSE
);
2126 g_signal_connect(G_OBJECT(t
->forward
), "clicked",
2127 G_CALLBACK(forward_cb
), t
);
2128 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), t
->forward
, -1);
2131 t
->stop
= gtk_tool_button_new_from_stock(GTK_STOCK_STOP
);
2132 gtk_widget_set_sensitive(GTK_WIDGET(t
->stop
), FALSE
);
2133 g_signal_connect(G_OBJECT(t
->stop
), "clicked",
2134 G_CALLBACK(stop_cb
), t
);
2135 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), t
->stop
, -1);
2139 i
= gtk_tool_item_new();
2140 gtk_tool_item_set_expand(i
, TRUE
);
2141 t
->uri_entry
= gtk_entry_new();
2142 gtk_container_add(GTK_CONTAINER(i
), t
->uri_entry
);
2143 g_signal_connect(G_OBJECT(t
->uri_entry
), "activate",
2144 G_CALLBACK(activate_uri_entry_cb
), t
);
2145 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), i
, -1);
2148 if (fancy_bar
&& search_string
) {
2149 i
= gtk_tool_item_new();
2150 t
->search_entry
= gtk_entry_new();
2151 gtk_entry_set_width_chars(GTK_ENTRY(t
->search_entry
), 30);
2152 gtk_container_add(GTK_CONTAINER(i
), t
->search_entry
);
2153 g_signal_connect(G_OBJECT(t
->search_entry
), "activate",
2154 G_CALLBACK(activate_search_entry_cb
), t
);
2155 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), i
, -1);
2162 delete_tab(struct tab
*t
)
2164 DNPRINTF(XT_D_TAB
, "delete_tab: %p\n", t
);
2169 TAILQ_REMOVE(&tabs
, t
, entry
);
2170 if (TAILQ_EMPTY(&tabs
))
2171 create_new_tab(NULL
, 1);
2173 gtk_widget_destroy(t
->vbox
);
2175 g_free(t
->user_agent
);
2178 TAILQ_FOREACH(t
, &tabs
, entry
)
2179 t
->tab_id
= gtk_notebook_page_num(notebook
, t
->vbox
);
2183 adjustfont_webkit(struct tab
*t
, int adjust
)
2186 errx(1, "adjustfont_webkit");
2188 if (adjust
== XT_FONT_SET
)
2189 t
->font_size
= default_font_size
;
2191 t
->font_size
+= adjust
;
2192 g_object_set((GObject
*)t
->settings
, "default-font-size",
2193 t
->font_size
, (char *)NULL
);
2194 g_object_get((GObject
*)t
->settings
, "default-font-size",
2195 &t
->font_size
, (char *)NULL
);
2199 create_new_tab(char *title
, int focus
)
2203 char *newuri
= NULL
;
2204 GtkWidget
*image
, *b
, *button
;
2206 DNPRINTF(XT_D_TAB
, "create_new_tab: title %s focus %d\n", title
, focus
);
2208 if (tabless
&& !TAILQ_EMPTY(&tabs
)) {
2209 DNPRINTF(XT_D_TAB
, "create_new_tab: new tab rejected\n");
2213 t
= g_malloc0(sizeof *t
);
2214 TAILQ_INSERT_TAIL(&tabs
, t
, entry
);
2216 if (title
== NULL
) {
2217 title
= "(untitled)";
2220 if (valid_url_type(title
)) {
2221 newuri
= guess_url_type(title
);
2226 t
->vbox
= gtk_vbox_new(FALSE
, 0);
2228 /* label + button for tab */
2229 b
= gtk_hbox_new(FALSE
, 0);
2230 t
->spinner
= gtk_spinner_new ();
2231 t
->label
= gtk_label_new(title
);
2232 image
= gtk_image_new_from_stock(GTK_STOCK_CLOSE
, GTK_ICON_SIZE_MENU
);
2233 button
= gtk_button_new();
2234 gtk_button_set_image(GTK_BUTTON(button
), image
);
2235 gtk_button_set_relief(GTK_BUTTON(button
), GTK_RELIEF_NONE
);
2236 gtk_button_set_focus_on_click(GTK_BUTTON(button
), FALSE
);
2237 gtk_widget_set_size_request(t
->label
, 100, -1);
2238 gtk_box_pack_start(GTK_BOX(b
), t
->spinner
, FALSE
, FALSE
, 0);
2239 gtk_box_pack_start(GTK_BOX(b
), t
->label
, FALSE
, FALSE
, 0);
2240 gtk_box_pack_start(GTK_BOX(b
), button
, FALSE
, FALSE
, 0);
2243 t
->toolbar
= create_toolbar(t
);
2244 gtk_box_pack_start(GTK_BOX(t
->vbox
), t
->toolbar
, FALSE
, FALSE
, 0);
2247 t
->browser_win
= create_browser(t
);
2248 gtk_box_pack_start(GTK_BOX(t
->vbox
), t
->browser_win
, TRUE
, TRUE
, 0);
2251 t
->cmd
= gtk_entry_new();
2252 gtk_entry_set_inner_border(GTK_ENTRY(t
->cmd
), NULL
);
2253 gtk_entry_set_has_frame(GTK_ENTRY(t
->cmd
), FALSE
);
2254 gtk_box_pack_end(GTK_BOX(t
->vbox
), t
->cmd
, FALSE
, FALSE
, 0);
2256 /* and show it all */
2257 gtk_widget_show_all(b
);
2258 gtk_widget_show_all(t
->vbox
);
2259 t
->tab_id
= gtk_notebook_append_page(notebook
, t
->vbox
, b
);
2261 /* turn spinner off if we are a new tab without uri */
2263 gtk_spinner_stop(GTK_SPINNER(t
->spinner
));
2264 gtk_widget_hide(t
->spinner
);
2267 /* make notebook tabs reorderable */
2268 gtk_notebook_set_tab_reorderable(notebook
, t
->vbox
, TRUE
);
2270 g_object_connect((GObject
*)t
->cmd
,
2271 "signal::key-press-event", (GCallback
)cmd_keypress_cb
, t
,
2272 "signal::key-release-event", (GCallback
)cmd_keyrelease_cb
, t
,
2273 "signal::focus-out-event", (GCallback
)cmd_focusout_cb
, t
,
2274 "signal::activate", (GCallback
)cmd_activate_cb
, t
,
2277 g_object_connect((GObject
*)t
->wv
,
2278 "signal-after::key-press-event", (GCallback
)webview_keypress_cb
, t
,
2279 /* "signal::hovering-over-link", (GCallback)webview_hover_cb, t, */
2280 "signal::download-requested", (GCallback
)webview_download_cb
, t
,
2281 "signal::mime-type-policy-decision-requested", (GCallback
)webview_mimetype_cb
, t
,
2282 "signal::navigation-policy-decision-requested", (GCallback
)webview_npd_cb
, t
,
2283 "signal::new-window-policy-decision-requested", (GCallback
)webview_nw_cb
, t
,
2284 "signal::create-web-view", (GCallback
)webview_cwv_cb
, t
,
2285 "signal::event", (GCallback
)webview_event_cb
, t
,
2286 "signal::load-finished", (GCallback
)webview_load_finished_cb
, t
,
2287 "signal::load-progress-changed", (GCallback
)webview_progress_changed_cb
, t
,
2289 g_signal_connect(t
->wv
, "notify::load-status",
2290 G_CALLBACK(notify_load_status_cb
), t
);
2292 /* hijack the unused keys as if we were the browser */
2293 g_object_connect((GObject
*)t
->toolbar
,
2294 "signal-after::key-press-event", (GCallback
)webview_keypress_cb
, t
,
2297 g_signal_connect(G_OBJECT(t
->uri_entry
), "focus",
2298 G_CALLBACK(focus_uri_entry_cb
), t
);
2300 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(tab_close_cb
), t
);
2303 gtk_widget_hide(t
->cmd
);
2305 gtk_widget_hide(t
->toolbar
);
2308 gtk_notebook_set_current_page(notebook
, t
->tab_id
);
2309 DNPRINTF(XT_D_TAB
, "create_new_tab: going to tab: %d\n",
2314 webkit_web_view_load_uri(t
->wv
, title
);
2316 gtk_widget_grab_focus(GTK_WIDGET(t
->uri_entry
));
2323 notebook_switchpage_cb(GtkNotebook
*nb
, GtkNotebookPage
*nbp
, guint pn
,
2329 DNPRINTF(XT_D_TAB
, "notebook_switchpage_cb: tab: %d\n", pn
);
2331 TAILQ_FOREACH(t
, &tabs
, entry
) {
2332 if (t
->tab_id
== pn
) {
2333 DNPRINTF(XT_D_TAB
, "notebook_switchpage_cb: going to "
2336 uri
= webkit_web_view_get_title(t
->wv
);
2339 gtk_window_set_title(GTK_WINDOW(main_window
), uri
);
2341 gtk_widget_hide(t
->cmd
);
2351 vbox
= gtk_vbox_new(FALSE
, 0);
2352 notebook
= GTK_NOTEBOOK(gtk_notebook_new());
2354 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
2355 gtk_notebook_set_scrollable(notebook
, TRUE
);
2357 gtk_box_pack_start(GTK_BOX(vbox
), GTK_WIDGET(notebook
), TRUE
, TRUE
, 0);
2359 g_object_connect((GObject
*)notebook
,
2360 "signal::switch-page", (GCallback
)notebook_switchpage_cb
, NULL
,
2363 main_window
= create_window();
2364 gtk_container_add(GTK_CONTAINER(main_window
), vbox
);
2365 gtk_window_set_title(GTK_WINDOW(main_window
), XT_NAME
);
2366 gtk_widget_show_all(main_window
);
2370 setup_cookies(char *file
)
2373 soup_session_remove_feature(session
,
2374 (SoupSessionFeature
*)cookiejar
);
2375 g_object_unref(cookiejar
);
2379 if (cookies_enabled
== 0)
2382 cookiejar
= soup_cookie_jar_text_new(file
, read_only_cookies
);
2383 soup_session_add_feature(session
, (SoupSessionFeature
*)cookiejar
);
2387 setup_proxy(char *uri
)
2390 g_object_set(session
, "proxy_uri", NULL
, (char *)NULL
);
2391 soup_uri_free(proxy_uri
);
2395 if (http_proxy
!= uri
) {
2402 http_proxy
= g_strdup(uri
);
2403 DNPRINTF(XT_D_CONFIG
, "setup_proxy: %s\n", uri
);
2404 proxy_uri
= soup_uri_new(http_proxy
);
2405 g_object_set(session
, "proxy-uri", proxy_uri
, (char *)NULL
);
2413 "%s [-STVt][-f file] url ...\n", __progname
);
2418 main(int argc
, char *argv
[])
2422 char conf
[PATH_MAX
] = { '\0' };
2423 char file
[PATH_MAX
];
2424 char *env_proxy
= NULL
;
2427 while ((c
= getopt(argc
, argv
, "STVf:t")) != -1) {
2436 errx(0 , "Version: %s", version
);
2439 strlcpy(conf
, optarg
, sizeof(conf
));
2455 gtk_init(&argc
, &argv
);
2456 if (!g_thread_supported())
2457 g_thread_init(NULL
);
2459 pwd
= getpwuid(getuid());
2461 errx(1, "invalid user %d", getuid());
2463 /* set download dir */
2464 strlcpy(download_dir
, pwd
->pw_dir
, sizeof download_dir
);
2466 /* read config file */
2467 if (strlen(conf
) == 0)
2468 snprintf(conf
, sizeof conf
, "%s/.%s",
2469 pwd
->pw_dir
, XT_CONF_FILE
);
2473 if (!strcmp(download_dir
, pwd
->pw_dir
))
2474 strlcat(download_dir
, "/downloads", sizeof download_dir
);
2476 if (stat(download_dir
, &sb
)) {
2477 if (mkdir(download_dir
, S_IRWXU
) == -1)
2478 err(1, "mkdir download_dir");
2480 if (S_ISDIR(sb
.st_mode
) == 0)
2481 errx(1, "%s not a dir", download_dir
);
2482 if (((sb
.st_mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
))) != S_IRWXU
) {
2483 warnx("fixing invalid permissions on %s", download_dir
);
2484 if (chmod(download_dir
, S_IRWXU
) == -1)
2488 /* working directory */
2489 snprintf(work_dir
, sizeof work_dir
, "%s/%s", pwd
->pw_dir
, XT_DIR
);
2490 if (stat(work_dir
, &sb
)) {
2491 if (mkdir(work_dir
, S_IRWXU
) == -1)
2492 err(1, "mkdir work_dir");
2494 if (S_ISDIR(sb
.st_mode
) == 0)
2495 errx(1, "%s not a dir", work_dir
);
2496 if (((sb
.st_mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
))) != S_IRWXU
) {
2497 warnx("fixing invalid permissions on %s", work_dir
);
2498 if (chmod(work_dir
, S_IRWXU
) == -1)
2502 /* favorites file */
2503 snprintf(file
, sizeof file
, "%s/%s", work_dir
, XT_FAVS_FILE
);
2504 if (stat(file
, &sb
)) {
2505 warnx("favorites file doesn't exist, creating it");
2506 if ((f
= fopen(file
, "w")) == NULL
)
2507 err(1, "favorites");
2512 session
= webkit_get_default_session();
2513 snprintf(file
, sizeof file
, "%s/cookies.txt", work_dir
);
2514 setup_cookies(file
);
2517 env_proxy
= getenv("http_proxy");
2519 setup_proxy(env_proxy
);
2521 setup_proxy(http_proxy
);
2526 create_new_tab(argv
[0], focus
);
2533 create_new_tab(home
, 1);