BrowserWindow.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /*
  2. * Copyright (C) 2006, 2007 Apple Inc.
  3. * Copyright (C) 2007 Alp Toker <alp@atoker.com>
  4. * Copyright (C) 2011 Igalia S.L.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  17. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  18. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  19. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  25. * THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include "BrowserWindow.h"
  28. #include "BrowserDownloadsBar.h"
  29. #include "BrowserSettingsDialog.h"
  30. #include <string.h>
  31. enum {
  32. PROP_0,
  33. PROP_VIEW
  34. };
  35. struct _BrowserWindow {
  36. GtkWindow parent;
  37. GtkWidget *mainBox;
  38. GtkWidget *toolbar;
  39. GtkWidget *uriEntry;
  40. GtkWidget *backItem;
  41. GtkWidget *forwardItem;
  42. GtkWidget *zoomInItem;
  43. GtkWidget *zoomOutItem;
  44. GtkWidget *statusLabel;
  45. GtkWidget *settingsDialog;
  46. WebKitWebView *webView;
  47. GtkWidget *downloadsBar;
  48. GdkPixbuf *favicon;
  49. GtkWidget *fullScreenMessageLabel;
  50. guint fullScreenMessageLabelId;
  51. };
  52. struct _BrowserWindowClass {
  53. GtkWindowClass parent;
  54. };
  55. static const char *defaultWindowTitle = "WebKitGTK+ MiniBrowser";
  56. static const char *miniBrowserAboutScheme = "minibrowser-about";
  57. static const gdouble minimumZoomLevel = 0.5;
  58. static const gdouble maximumZoomLevel = 3;
  59. static const gdouble zoomStep = 1.2;
  60. static gint windowCount = 0;
  61. G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
  62. static char *getInternalURI(const char *uri)
  63. {
  64. // Internally we use minibrowser-about: as about: prefix is ignored by WebKit.
  65. if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
  66. return g_strconcat(miniBrowserAboutScheme, uri + strlen ("about"), NULL);
  67. return g_strdup(uri);
  68. }
  69. static char *getExternalURI(const char *uri)
  70. {
  71. // From the user point of view we support about: prefix.
  72. if (g_str_has_prefix(uri, miniBrowserAboutScheme))
  73. return g_strconcat("about", uri + strlen(miniBrowserAboutScheme), NULL);
  74. return g_strdup(uri);
  75. }
  76. static void browserWindowSetStatusText(BrowserWindow *window, const char *text)
  77. {
  78. gtk_label_set_text(GTK_LABEL(window->statusLabel), text);
  79. gtk_widget_set_visible(window->statusLabel, !!text);
  80. }
  81. static void resetStatusText(GtkWidget *widget, BrowserWindow *window)
  82. {
  83. browserWindowSetStatusText(window, NULL);
  84. }
  85. static void activateUriEntryCallback(BrowserWindow *window)
  86. {
  87. browser_window_load_uri(window, gtk_entry_get_text(GTK_ENTRY(window->uriEntry)));
  88. }
  89. static void reloadCallback(BrowserWindow *window)
  90. {
  91. webkit_web_view_reload(window->webView);
  92. }
  93. static void goBackCallback(BrowserWindow *window)
  94. {
  95. webkit_web_view_go_back(window->webView);
  96. }
  97. static void goForwardCallback(BrowserWindow *window)
  98. {
  99. webkit_web_view_go_forward(window->webView);
  100. }
  101. static void settingsCallback(BrowserWindow *window)
  102. {
  103. if (window->settingsDialog) {
  104. gtk_window_present(GTK_WINDOW(window->settingsDialog));
  105. return;
  106. }
  107. window->settingsDialog = browser_settings_dialog_new(webkit_web_view_get_settings(window->webView));
  108. gtk_window_set_transient_for(GTK_WINDOW(window->settingsDialog), GTK_WINDOW(window));
  109. g_object_add_weak_pointer(G_OBJECT(window->settingsDialog), (gpointer *)&window->settingsDialog);
  110. gtk_widget_show(window->settingsDialog);
  111. }
  112. static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
  113. {
  114. char *externalURI = getExternalURI(webkit_web_view_get_uri(webView));
  115. gtk_entry_set_text(GTK_ENTRY(window->uriEntry), externalURI);
  116. g_free(externalURI);
  117. }
  118. static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
  119. {
  120. const char *title = webkit_web_view_get_title(webView);
  121. gtk_window_set_title(GTK_WINDOW(window), title ? title : defaultWindowTitle);
  122. }
  123. static gboolean resetEntryProgress(GtkEntry *entry)
  124. {
  125. gtk_entry_set_progress_fraction(entry, 0);
  126. return FALSE;
  127. }
  128. static void webViewLoadProgressChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
  129. {
  130. gdouble progress = webkit_web_view_get_estimated_load_progress(webView);
  131. gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), progress);
  132. if (progress == 1.0)
  133. g_timeout_add(500, (GSourceFunc)resetEntryProgress, window->uriEntry);
  134. }
  135. static void downloadStarted(WebKitWebContext *webContext, WebKitDownload *download, BrowserWindow *window)
  136. {
  137. if (!window->downloadsBar) {
  138. window->downloadsBar = browser_downloads_bar_new();
  139. gtk_box_pack_start(GTK_BOX(window->mainBox), window->downloadsBar, FALSE, FALSE, 0);
  140. gtk_box_reorder_child(GTK_BOX(window->mainBox), window->downloadsBar, 0);
  141. g_object_add_weak_pointer(G_OBJECT(window->downloadsBar), (gpointer *)&(window->downloadsBar));
  142. gtk_widget_show(window->downloadsBar);
  143. }
  144. browser_downloads_bar_add_download(BROWSER_DOWNLOADS_BAR(window->downloadsBar), download);
  145. }
  146. static void browserWindowHistoryItemSelected(BrowserWindow *window, GtkMenuItem *item)
  147. {
  148. GtkAction *action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(item));
  149. browserWindowSetStatusText(window, action ? gtk_action_get_name(action) : NULL);
  150. }
  151. static void browserWindowHistoryItemActivated(BrowserWindow *window, GtkAction *action)
  152. {
  153. WebKitBackForwardListItem *item = g_object_get_data(G_OBJECT(action), "back-forward-list-item");
  154. if (!item)
  155. return;
  156. webkit_web_view_go_to_back_forward_list_item(window->webView, item);
  157. }
  158. static GtkWidget *browserWindowCreateBackForwardMenu(BrowserWindow *window, GList *list)
  159. {
  160. if (!list)
  161. return NULL;
  162. GtkWidget *menu = gtk_menu_new();
  163. GList *listItem;
  164. for (listItem = list; listItem; listItem = g_list_next(listItem)) {
  165. WebKitBackForwardListItem *item = (WebKitBackForwardListItem *)listItem->data;
  166. const char *uri = webkit_back_forward_list_item_get_uri(item);
  167. const char *title = webkit_back_forward_list_item_get_title(item);
  168. GtkAction *action = gtk_action_new(uri, title, NULL, NULL);
  169. g_object_set_data_full(G_OBJECT(action), "back-forward-list-item", g_object_ref(item), g_object_unref);
  170. g_signal_connect_swapped(action, "activate", G_CALLBACK(browserWindowHistoryItemActivated), window);
  171. GtkWidget *menuItem = gtk_action_create_menu_item(action);
  172. g_signal_connect_swapped(menuItem, "select", G_CALLBACK(browserWindowHistoryItemSelected), window);
  173. g_object_unref(action);
  174. gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuItem);
  175. gtk_widget_show(menuItem);
  176. }
  177. g_signal_connect(menu, "hide", G_CALLBACK(resetStatusText), window);
  178. return menu;
  179. }
  180. static void browserWindowUpdateNavigationActions(BrowserWindow *window, WebKitBackForwardList *backForwadlist)
  181. {
  182. gtk_widget_set_sensitive(window->backItem, webkit_web_view_can_go_back(window->webView));
  183. gtk_widget_set_sensitive(window->forwardItem, webkit_web_view_can_go_forward(window->webView));
  184. GList *list = webkit_back_forward_list_get_back_list_with_limit(backForwadlist, 10);
  185. gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->backItem),
  186. browserWindowCreateBackForwardMenu(window, list));
  187. g_list_free(list);
  188. list = webkit_back_forward_list_get_forward_list_with_limit(backForwadlist, 10);
  189. gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(window->forwardItem),
  190. browserWindowCreateBackForwardMenu(window, list));
  191. g_list_free(list);
  192. }
  193. static void backForwadlistChanged(WebKitBackForwardList *backForwadlist, WebKitBackForwardListItem *itemAdded, GList *itemsRemoved, BrowserWindow *window)
  194. {
  195. browserWindowUpdateNavigationActions(window, backForwadlist);
  196. }
  197. static void geolocationRequestDialogCallback(GtkDialog *dialog, gint response, WebKitPermissionRequest *request)
  198. {
  199. switch (response) {
  200. case GTK_RESPONSE_YES:
  201. webkit_permission_request_allow(request);
  202. break;
  203. default:
  204. webkit_permission_request_deny(request);
  205. break;
  206. }
  207. gtk_widget_destroy(GTK_WIDGET(dialog));
  208. g_object_unref(request);
  209. }
  210. static void webViewClose(WebKitWebView *webView, BrowserWindow *window)
  211. {
  212. gtk_widget_destroy(GTK_WIDGET(window));
  213. }
  214. static void webViewRunAsModal(WebKitWebView *webView, BrowserWindow *window)
  215. {
  216. gtk_window_set_modal(GTK_WINDOW(window), TRUE);
  217. }
  218. static void webViewReadyToShow(WebKitWebView *webView, BrowserWindow *window)
  219. {
  220. WebKitWindowProperties *windowProperties = webkit_web_view_get_window_properties(webView);
  221. GdkRectangle geometry;
  222. webkit_window_properties_get_geometry(windowProperties, &geometry);
  223. if (geometry.x >= 0 && geometry.y >= 0)
  224. gtk_window_move(GTK_WINDOW(window), geometry.x, geometry.y);
  225. if (geometry.width > 0 && geometry.height > 0)
  226. gtk_window_resize(GTK_WINDOW(window), geometry.width, geometry.height);
  227. if (!webkit_window_properties_get_toolbar_visible(windowProperties))
  228. gtk_widget_hide(window->toolbar);
  229. else if (!webkit_window_properties_get_locationbar_visible(windowProperties))
  230. gtk_widget_hide(window->uriEntry);
  231. if (!webkit_window_properties_get_resizable(windowProperties))
  232. gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
  233. gtk_widget_show(GTK_WIDGET(window));
  234. }
  235. static gboolean fullScreenMessageTimeoutCallback(BrowserWindow *window)
  236. {
  237. gtk_widget_hide(window->fullScreenMessageLabel);
  238. window->fullScreenMessageLabelId = 0;
  239. return FALSE;
  240. }
  241. static gboolean webViewEnterFullScreen(WebKitWebView *webView, BrowserWindow *window)
  242. {
  243. gchar *titleOrURI = g_strdup(webkit_web_view_get_title(window->webView));
  244. if (!titleOrURI)
  245. titleOrURI = getExternalURI(webkit_web_view_get_uri(window->webView));
  246. gchar *message = g_strdup_printf("%s is now full screen. Press ESC or f to exit.", titleOrURI);
  247. gtk_label_set_text(GTK_LABEL(window->fullScreenMessageLabel), message);
  248. g_free(titleOrURI);
  249. g_free(message);
  250. gtk_widget_show(window->fullScreenMessageLabel);
  251. window->fullScreenMessageLabelId = g_timeout_add_seconds(2, (GSourceFunc)fullScreenMessageTimeoutCallback, window);
  252. gtk_widget_hide(window->toolbar);
  253. return FALSE;
  254. }
  255. static gboolean webViewLeaveFullScreen(WebKitWebView *webView, BrowserWindow *window)
  256. {
  257. if (window->fullScreenMessageLabelId) {
  258. g_source_remove(window->fullScreenMessageLabelId);
  259. window->fullScreenMessageLabelId = 0;
  260. }
  261. gtk_widget_hide(window->fullScreenMessageLabel);
  262. gtk_widget_show(window->toolbar);
  263. return FALSE;
  264. }
  265. static GtkWidget *webViewCreate(WebKitWebView *webView, BrowserWindow *window)
  266. {
  267. WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
  268. webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView));
  269. GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
  270. g_signal_connect(newWebView, "ready-to-show", G_CALLBACK(webViewReadyToShow), newWindow);
  271. g_signal_connect(newWebView, "run-as-modal", G_CALLBACK(webViewRunAsModal), newWindow);
  272. g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), newWindow);
  273. return GTK_WIDGET(newWebView);
  274. }
  275. static gboolean webViewLoadFailed(WebKitWebView *webView, WebKitLoadEvent loadEvent, const char *failingURI, GError *error, BrowserWindow *window)
  276. {
  277. gtk_entry_set_progress_fraction(GTK_ENTRY(window->uriEntry), 0.);
  278. return FALSE;
  279. }
  280. static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserWindow *window)
  281. {
  282. switch (decisionType) {
  283. case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
  284. WebKitNavigationPolicyDecision *navigationDecision = WEBKIT_NAVIGATION_POLICY_DECISION(decision);
  285. if (webkit_navigation_policy_decision_get_navigation_type(navigationDecision) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
  286. || webkit_navigation_policy_decision_get_mouse_button(navigationDecision) != GDK_BUTTON_MIDDLE)
  287. return FALSE;
  288. // Opening a new window if link clicked with the middle button.
  289. WebKitWebView *newWebView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(webkit_web_view_get_context(webView)));
  290. GtkWidget *newWindow = browser_window_new(newWebView, GTK_WINDOW(window));
  291. webkit_web_view_load_request(newWebView, webkit_navigation_policy_decision_get_request(navigationDecision));
  292. gtk_widget_show(newWindow);
  293. webkit_policy_decision_ignore(decision);
  294. return TRUE;
  295. }
  296. case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
  297. WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
  298. WebKitURIResponse *response = webkit_response_policy_decision_get_response(responseDecision);
  299. const char *mimeType = webkit_uri_response_get_mime_type(response);
  300. if (webkit_web_view_can_show_mime_type(webView, mimeType))
  301. return FALSE;
  302. WebKitWebResource *mainResource = webkit_web_view_get_main_resource(webView);
  303. WebKitURIRequest *request = webkit_response_policy_decision_get_request(responseDecision);
  304. const char *requestURI = webkit_uri_request_get_uri(request);
  305. if (g_strcmp0(webkit_web_resource_get_uri(mainResource), requestURI))
  306. return FALSE;
  307. webkit_policy_decision_download(decision);
  308. return TRUE;
  309. }
  310. case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
  311. default:
  312. return FALSE;
  313. }
  314. }
  315. static gboolean webViewDecidePermissionRequest(WebKitWebView *webView, WebKitPermissionRequest *request, BrowserWindow *window)
  316. {
  317. if (!WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(request))
  318. return FALSE;
  319. GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window),
  320. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  321. GTK_MESSAGE_QUESTION,
  322. GTK_BUTTONS_YES_NO,
  323. "Geolocation request");
  324. gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "Allow geolocation request?");
  325. g_signal_connect(dialog, "response", G_CALLBACK(geolocationRequestDialogCallback), g_object_ref(request));
  326. gtk_widget_show(dialog);
  327. return TRUE;
  328. }
  329. static void webViewMouseTargetChanged(WebKitWebView *webView, WebKitHitTestResult *hitTestResult, guint mouseModifiers, BrowserWindow *window)
  330. {
  331. if (!webkit_hit_test_result_context_is_link(hitTestResult)) {
  332. browserWindowSetStatusText(window, NULL);
  333. return;
  334. }
  335. browserWindowSetStatusText(window, webkit_hit_test_result_get_link_uri(hitTestResult));
  336. }
  337. static gboolean browserWindowCanZoomIn(BrowserWindow *window)
  338. {
  339. gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
  340. return zoomLevel < maximumZoomLevel;
  341. }
  342. static gboolean browserWindowCanZoomOut(BrowserWindow *window)
  343. {
  344. gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
  345. return zoomLevel > minimumZoomLevel;
  346. }
  347. static void browserWindowUpdateZoomActions(BrowserWindow *window)
  348. {
  349. gtk_widget_set_sensitive(window->zoomInItem, browserWindowCanZoomIn(window));
  350. gtk_widget_set_sensitive(window->zoomOutItem, browserWindowCanZoomOut(window));
  351. }
  352. static void webViewZoomLevelChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
  353. {
  354. browserWindowUpdateZoomActions(window);
  355. }
  356. static void updateUriEntryIcon(BrowserWindow *window)
  357. {
  358. GtkEntry *entry = GTK_ENTRY(window->uriEntry);
  359. if (window->favicon)
  360. gtk_entry_set_icon_from_pixbuf(entry, GTK_ENTRY_ICON_PRIMARY, window->favicon);
  361. else
  362. gtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_NEW);
  363. }
  364. static void faviconChanged(GObject *object, GParamSpec *paramSpec, BrowserWindow *window)
  365. {
  366. GdkPixbuf *favicon = NULL;
  367. cairo_surface_t *surface = webkit_web_view_get_favicon(window->webView);
  368. if (surface) {
  369. int width = cairo_image_surface_get_width(surface);
  370. int height = cairo_image_surface_get_height(surface);
  371. favicon = gdk_pixbuf_get_from_surface(surface, 0, 0, width, height);
  372. }
  373. if (window->favicon)
  374. g_object_unref(window->favicon);
  375. window->favicon = favicon;
  376. updateUriEntryIcon(window);
  377. }
  378. static void zoomInCallback(BrowserWindow *window)
  379. {
  380. gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) * zoomStep;
  381. webkit_web_view_set_zoom_level(window->webView, zoomLevel);
  382. }
  383. static void zoomOutCallback(BrowserWindow *window)
  384. {
  385. gdouble zoomLevel = webkit_web_view_get_zoom_level(window->webView) / zoomStep;
  386. webkit_web_view_set_zoom_level(window->webView, zoomLevel);
  387. }
  388. static void browserWindowFinalize(GObject *gObject)
  389. {
  390. BrowserWindow *window = BROWSER_WINDOW(gObject);
  391. if (window->favicon) {
  392. g_object_unref(window->favicon);
  393. window->favicon = NULL;
  394. }
  395. if (window->fullScreenMessageLabelId)
  396. g_source_remove(window->fullScreenMessageLabelId);
  397. G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
  398. if (g_atomic_int_dec_and_test(&windowCount))
  399. gtk_main_quit();
  400. }
  401. static void browserWindowGetProperty(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
  402. {
  403. BrowserWindow *window = BROWSER_WINDOW(object);
  404. switch (propId) {
  405. case PROP_VIEW:
  406. g_value_set_object(value, browser_window_get_view(window));
  407. break;
  408. default:
  409. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
  410. }
  411. }
  412. static void browserWindowSetProperty(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
  413. {
  414. BrowserWindow* window = BROWSER_WINDOW(object);
  415. switch (propId) {
  416. case PROP_VIEW:
  417. window->webView = g_value_get_object(value);
  418. break;
  419. default:
  420. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
  421. }
  422. }
  423. static void browser_window_init(BrowserWindow *window)
  424. {
  425. g_atomic_int_inc(&windowCount);
  426. gtk_window_set_title(GTK_WINDOW(window), defaultWindowTitle);
  427. gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
  428. window->uriEntry = gtk_entry_new();
  429. g_signal_connect_swapped(window->uriEntry, "activate", G_CALLBACK(activateUriEntryCallback), (gpointer)window);
  430. gtk_entry_set_icon_activatable(GTK_ENTRY(window->uriEntry), GTK_ENTRY_ICON_PRIMARY, FALSE);
  431. updateUriEntryIcon(window);
  432. GtkWidget *toolbar = gtk_toolbar_new();
  433. window->toolbar = toolbar;
  434. gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
  435. gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
  436. GtkToolItem *item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
  437. window->backItem = GTK_WIDGET(item);
  438. gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
  439. g_signal_connect_swapped(item, "clicked", G_CALLBACK(goBackCallback), (gpointer)window);
  440. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  441. gtk_widget_show(GTK_WIDGET(item));
  442. item = gtk_menu_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
  443. window->forwardItem = GTK_WIDGET(item);
  444. gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(item), 0);
  445. g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCallback), (gpointer)window);
  446. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  447. gtk_widget_show(GTK_WIDGET(item));
  448. item = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES);
  449. g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(settingsCallback), window);
  450. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  451. gtk_widget_show(GTK_WIDGET(item));
  452. item = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_OUT);
  453. window->zoomOutItem = GTK_WIDGET(item);
  454. g_signal_connect_swapped(item, "clicked", G_CALLBACK(zoomOutCallback), window);
  455. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  456. gtk_widget_show(GTK_WIDGET(item));
  457. item = gtk_tool_button_new_from_stock(GTK_STOCK_ZOOM_IN);
  458. window->zoomInItem = GTK_WIDGET(item);
  459. g_signal_connect_swapped(item, "clicked", G_CALLBACK(zoomInCallback), window);
  460. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  461. gtk_widget_show(GTK_WIDGET(item));
  462. item = gtk_tool_item_new();
  463. gtk_tool_item_set_expand(item, TRUE);
  464. gtk_container_add(GTK_CONTAINER(item), window->uriEntry);
  465. gtk_widget_show(window->uriEntry);
  466. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  467. gtk_widget_show(GTK_WIDGET(item));
  468. item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
  469. g_signal_connect_swapped(item, "clicked", G_CALLBACK(reloadCallback), window);
  470. gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
  471. gtk_widget_show(GTK_WIDGET(item));
  472. GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  473. window->mainBox = vbox;
  474. gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
  475. gtk_widget_show(toolbar);
  476. gtk_container_add(GTK_CONTAINER(window), vbox);
  477. gtk_widget_show(vbox);
  478. }
  479. static void browserWindowConstructed(GObject *gObject)
  480. {
  481. BrowserWindow *window = BROWSER_WINDOW(gObject);
  482. browserWindowUpdateZoomActions(window);
  483. g_signal_connect(window->webView, "notify::uri", G_CALLBACK(webViewURIChanged), window);
  484. g_signal_connect(window->webView, "notify::estimated-load-progress", G_CALLBACK(webViewLoadProgressChanged), window);
  485. g_signal_connect(window->webView, "notify::title", G_CALLBACK(webViewTitleChanged), window);
  486. g_signal_connect(window->webView, "create", G_CALLBACK(webViewCreate), window);
  487. g_signal_connect(window->webView, "load-failed", G_CALLBACK(webViewLoadFailed), window);
  488. g_signal_connect(window->webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), window);
  489. g_signal_connect(window->webView, "permission-request", G_CALLBACK(webViewDecidePermissionRequest), window);
  490. g_signal_connect(window->webView, "mouse-target-changed", G_CALLBACK(webViewMouseTargetChanged), window);
  491. g_signal_connect(window->webView, "notify::zoom-level", G_CALLBACK(webViewZoomLevelChanged), window);
  492. g_signal_connect(window->webView, "notify::favicon", G_CALLBACK(faviconChanged), window);
  493. g_signal_connect(window->webView, "enter-fullscreen", G_CALLBACK(webViewEnterFullScreen), window);
  494. g_signal_connect(window->webView, "leave-fullscreen", G_CALLBACK(webViewLeaveFullScreen), window);
  495. g_signal_connect(webkit_web_view_get_context(window->webView), "download-started", G_CALLBACK(downloadStarted), window);
  496. WebKitBackForwardList *backForwadlist = webkit_web_view_get_back_forward_list(window->webView);
  497. g_signal_connect(backForwadlist, "changed", G_CALLBACK(backForwadlistChanged), window);
  498. GtkWidget *overlay = gtk_overlay_new();
  499. gtk_box_pack_start(GTK_BOX(window->mainBox), overlay, TRUE, TRUE, 0);
  500. gtk_widget_show(overlay);
  501. window->statusLabel = gtk_label_new(NULL);
  502. gtk_widget_set_halign(window->statusLabel, GTK_ALIGN_START);
  503. gtk_widget_set_valign(window->statusLabel, GTK_ALIGN_END);
  504. gtk_widget_set_margin_left(window->statusLabel, 1);
  505. gtk_widget_set_margin_right(window->statusLabel, 1);
  506. gtk_widget_set_margin_top(window->statusLabel, 1);
  507. gtk_widget_set_margin_bottom(window->statusLabel, 1);
  508. gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->statusLabel);
  509. gtk_container_add(GTK_CONTAINER(overlay), GTK_WIDGET(window->webView));
  510. window->fullScreenMessageLabel = gtk_label_new(NULL);
  511. gtk_widget_set_halign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
  512. gtk_widget_set_valign(window->fullScreenMessageLabel, GTK_ALIGN_CENTER);
  513. gtk_widget_set_no_show_all(window->fullScreenMessageLabel, TRUE);
  514. gtk_overlay_add_overlay(GTK_OVERLAY(overlay), window->fullScreenMessageLabel);
  515. gtk_widget_show(GTK_WIDGET(window->webView));
  516. }
  517. static void browser_window_class_init(BrowserWindowClass *klass)
  518. {
  519. GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
  520. gobjectClass->constructed = browserWindowConstructed;
  521. gobjectClass->get_property = browserWindowGetProperty;
  522. gobjectClass->set_property = browserWindowSetProperty;
  523. gobjectClass->finalize = browserWindowFinalize;
  524. g_object_class_install_property(gobjectClass,
  525. PROP_VIEW,
  526. g_param_spec_object("view",
  527. "View",
  528. "The web view of this window",
  529. WEBKIT_TYPE_WEB_VIEW,
  530. G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
  531. }
  532. // Public API.
  533. GtkWidget *browser_window_new(WebKitWebView *view, GtkWindow *parent)
  534. {
  535. g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(view), 0);
  536. return GTK_WIDGET(g_object_new(BROWSER_TYPE_WINDOW,
  537. "transient-for", parent,
  538. "type", GTK_WINDOW_TOPLEVEL,
  539. "view", view, NULL));
  540. }
  541. WebKitWebView *browser_window_get_view(BrowserWindow *window)
  542. {
  543. g_return_val_if_fail(BROWSER_IS_WINDOW(window), 0);
  544. return window->webView;
  545. }
  546. void browser_window_load_uri(BrowserWindow *window, const char *uri)
  547. {
  548. g_return_if_fail(BROWSER_IS_WINDOW(window));
  549. g_return_if_fail(uri);
  550. if (!g_str_has_prefix(uri, "javascript:")) {
  551. char *internalURI = getInternalURI(uri);
  552. webkit_web_view_load_uri(window->webView, internalURI);
  553. g_free(internalURI);
  554. return;
  555. }
  556. webkit_web_view_run_javascript(window->webView, strstr(uri, "javascript:"), NULL, NULL, NULL);
  557. }