Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / src / .svn / text-base / ephy-window.c.svn-base
blobd7f7ac9fc0252701a1e1ed67865d32ec9d98590d
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Copyright © 2000, 2001, 2002, 2003, 2004 Marco Pesenti Gritti
4  *  Copyright © 2003, 2004 Christian Persch
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  *  $Id$
21  */
23 #include "config.h"
25 #include "ephy-window.h"
26 #include "ephy-type-builtins.h"
27 #include "ephy-embed-type-builtins.h"
28 #include "ephy-command-manager.h"
29 #include "ephy-state.h"
30 #include "ppview-toolbar.h"
31 #include "window-commands.h"
32 #include "ephy-embed-shell.h"
33 #include "ephy-embed-single.h"
34 #include "ephy-shell.h"
35 #include "eel-gconf-extensions.h"
36 #include "ephy-prefs.h"
37 #include "ephy-embed-prefs.h"
38 #include "ephy-zoom.h"
39 #include "ephy-debug.h"
40 #include "ephy-file-helpers.h"
41 #include "ephy-statusbar.h"
42 #include "egg-editable-toolbar.h"
43 #include "ephy-toolbar.h"
44 #include "popup-commands.h"
45 #include "ephy-encoding-menu.h"
46 #include "ephy-tabs-menu.h"
47 #include "ephy-stock-icons.h"
48 #include "ephy-extension.h"
49 #include "ephy-bookmarks-ui.h"
50 #include "ephy-link.h"
51 #include "ephy-gui.h"
52 #include "ephy-notebook.h"
53 #include "ephy-fullscreen-popup.h"
54 #include "ephy-action-helper.h"
55 #include "ephy-find-toolbar.h"
57 #include <string.h>
58 #include <glib/gi18n.h>
59 #include <libgnomevfs/gnome-vfs-uri.h>
60 #include <libgnomeui/gnome-stock-icons.h>
61 #include <gtk/gtk.h>
62 #include <gdk/gdkkeysyms.h>
63 #include <gtk/gtkactiongroup.h>
64 #include <gtk/gtktoggleaction.h>
65 #include <gtk/gtkuimanager.h>
66 #include <gtk/gtktoggleaction.h>
67 #include <gtk/gtkdialog.h>
68 #include <gtk/gtkmessagedialog.h>
70 #ifdef HAVE_X11_XF86KEYSYM_H
71 #include <X11/XF86keysym.h>
72 #endif
74 #ifdef ENABLE_PYTHON
75 #include "ephy-python.h"
76 #endif
78 static void ephy_window_class_init              (EphyWindowClass *klass);
79 static void ephy_window_link_iface_init         (EphyLinkIface *iface);
80 static void ephy_window_init                    (EphyWindow *gs);
81 static GObject *ephy_window_constructor         (GType type,
82                                                  guint n_construct_properties,
83                                                  GObjectConstructParam *construct_params);
84 static void ephy_window_finalize                (GObject *object);
85 static void ephy_window_show                    (GtkWidget *widget);
86 static EphyTab *ephy_window_open_link           (EphyLink *link,
87                                                  const char *address,
88                                                  EphyTab *tab,
89                                                  EphyLinkFlags flags);
90 static void notebook_switch_page_cb             (GtkNotebook *notebook,
91                                                  GtkNotebookPage *page,
92                                                  guint page_num,
93                                                  EphyWindow *window);
94 static void ephy_window_view_statusbar_cb       (GtkAction *action,
95                                                  EphyWindow *window);
96 static void ephy_window_view_toolbar_cb         (GtkAction *action,
97                                                  EphyWindow *window);
98 static void ephy_window_view_popup_windows_cb   (GtkAction *action,
99                                                  EphyWindow *window);
100 static void sync_tab_load_status                (EphyTab *tab,
101                                                  GParamSpec *pspec,
102                                                  EphyWindow *window);
103 static void sync_tab_security                   (EphyTab *tab,
104                                                  GParamSpec *pspec,
105                                                  EphyWindow *window);
106 static void sync_tab_zoom                       (EphyTab *tab,
107                                                  GParamSpec *pspec,
108                                                  EphyWindow *window);
111 static const GtkActionEntry ephy_menu_entries [] = {
113         /* Toplevel */
115         { "File", NULL, N_("_File") },
116         { "Edit", NULL, N_("_Edit") },
117         { "View", NULL, N_("_View") },
118         { "Bookmarks", NULL, N_("_Bookmarks") },
119         { "Go", NULL, N_("_Go") },
120         { "Tools", NULL, N_("T_ools") },
121         { "Tabs", NULL, N_("_Tabs") },
122         { "Help", NULL, N_("_Help") },
123         { "Toolbar", NULL, N_("_Toolbars") },
124         { "PopupAction", NULL, "" },
125         { "NotebookPopupAction", NULL, "" },
127         /* File menu */
129         { "FileOpen", GTK_STOCK_OPEN, N_("_Open…"), "<control>O",
130           N_("Open a file"),
131           G_CALLBACK (window_cmd_file_open) },
132         { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _As…"), "<shift><control>S",
133           N_("Save the current page"),
134           G_CALLBACK (window_cmd_file_save_as) },
135         { "FilePrintSetup", STOCK_PRINT_SETUP, N_("Print Set_up…"), NULL,
136           N_("Setup the page settings for printing"),
137           G_CALLBACK (window_cmd_file_print_setup) },
138         { "FilePrintPreview", GTK_STOCK_PRINT_PREVIEW, N_("Print Pre_view"),"<control><shift>P",
139           N_("Print preview"),
140           G_CALLBACK (window_cmd_file_print_preview) },
141         { "FilePrint", GTK_STOCK_PRINT, N_("_Print…"), "<control>P",
142           N_("Print the current page"),
143           G_CALLBACK (window_cmd_file_print) },
144         { "FileSendTo", STOCK_SEND_MAIL, N_("S_end Link by Email…"), NULL,
145           N_("Send a link of the current page"),
146           G_CALLBACK (window_cmd_file_send_to) },
147         { "FileCloseTab", GTK_STOCK_CLOSE, N_("_Close"), "<control>W",
148           N_("Close this tab"),
149           G_CALLBACK (window_cmd_file_close_window) },
151         /* Edit menu */
153         { "EditUndo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z",
154           N_("Undo the last action"),
155           G_CALLBACK (window_cmd_edit_undo) },
156         { "EditRedo", GTK_STOCK_REDO, N_("Re_do"), "<shift><control>Z",
157           N_("Redo the last undone action"),
158           G_CALLBACK (window_cmd_edit_redo) },
159         { "EditCut", GTK_STOCK_CUT, N_("Cu_t"), "<control>X",
160           N_("Cut the selection"),
161           G_CALLBACK (window_cmd_edit_cut) },
162         { "EditCopy", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
163           N_("Copy the selection"),
164           G_CALLBACK (window_cmd_edit_copy) },
165         { "EditPaste", GTK_STOCK_PASTE, N_("_Paste"), "<control>V",
166           N_("Paste clipboard"),
167           G_CALLBACK (window_cmd_edit_paste) },
168         { "EditDelete", GTK_STOCK_DELETE, NULL, NULL,
169           N_("Delete text"),
170           G_CALLBACK (window_cmd_edit_delete) },
171         { "EditSelectAll", GTK_STOCK_SELECT_ALL, N_("Select _All"), "<control>A",
172           N_("Select the entire page"),
173           G_CALLBACK (window_cmd_edit_select_all) },
174         { "EditFind", GTK_STOCK_FIND, N_("_Find…"), "<control>F",
175           N_("Find a word or phrase in the page"),
176           G_CALLBACK (window_cmd_edit_find) },
177         { "EditFindNext", NULL, N_("Find Ne_xt"), "<control>G",
178           N_("Find next occurrence of the word or phrase"),
179           G_CALLBACK (window_cmd_edit_find_next) },
180         { "EditFindPrev", NULL, N_("Find Pre_vious"), "<shift><control>G",
181           N_("Find previous occurrence of the word or phrase"),
182           G_CALLBACK (window_cmd_edit_find_prev) },
183         { "EditPersonalData", NULL, N_("P_ersonal Data"), NULL,
184           N_("View and remove cookies and passwords"),
185           G_CALLBACK (window_cmd_edit_personal_data) },
186 #ifdef ENABLE_CERTIFICATE_MANAGER
187         { "EditCertificates", NULL, N_("Certificate_s"), NULL,
188           N_("Manage Certificates"),
189           G_CALLBACK (window_cmd_edit_certificates) },
190 #endif
191         { "EditPrefs", GTK_STOCK_PREFERENCES, N_("P_references"), NULL,
192           N_("Configure the web browser"),
193           G_CALLBACK (window_cmd_edit_prefs) },
195         /* View menu */
197         { "ViewToolbarEditor", NULL, N_("_Customize Toolbars…"), NULL,
198           N_("Customize toolbars"),
199           G_CALLBACK (window_cmd_edit_toolbar) },
200         { "ViewStop", GTK_STOCK_STOP, N_("_Stop"), "Escape",
201           N_("Stop current data transfer"),
202           G_CALLBACK (window_cmd_view_stop) },
203         { "ViewAlwaysStop", GTK_STOCK_STOP, N_("_Stop"), "Escape",
204           NULL, G_CALLBACK (window_cmd_view_stop) },
205         { "ViewReload", GTK_STOCK_REFRESH, N_("_Reload"), "<control>R",
206           N_("Display the latest content of the current page"),
207           G_CALLBACK (window_cmd_view_reload) },
208         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, N_("_Larger Text"), "<control>plus",
209           N_("Increase the text size"),
210           G_CALLBACK (window_cmd_view_zoom_in) },
211         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, N_("S_maller Text"), "<control>minus",
212           N_("Decrease the text size"),
213           G_CALLBACK (window_cmd_view_zoom_out) },
214         { "ViewZoomNormal", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<control>0",
215           N_("Use the normal text size"),
216           G_CALLBACK (window_cmd_view_zoom_normal) },
217         { "ViewEncoding", NULL, N_("Text _Encoding"), NULL,
218           N_("Change the text encoding"),
219           NULL },
220         { "ViewPageSource", NULL, N_("_Page Source"), "<control>U",
221           N_("View the source code of the page"),
222           G_CALLBACK (window_cmd_view_page_source) },
223         { "ViewPageSecurityInfo", NULL, N_("Page _Security Information…"), NULL,
224           N_("Display security information for the web page"),
225           G_CALLBACK (window_cmd_view_page_security_info) },
227         /* Bookmarks menu */
229         { "FileBookmarkPage", STOCK_ADD_BOOKMARK, N_("_Add Bookmark…"), "<control>D",
230           N_("Add a bookmark for the current page"),
231           G_CALLBACK (window_cmd_file_bookmark_page) },
232         { "GoBookmarks", EPHY_STOCK_BOOKMARKS, N_("_Edit Bookmarks"), "<control>B",
233           N_("Open the bookmarks window"),
234           G_CALLBACK (window_cmd_go_bookmarks) },
236         /* Go menu */
238         { "GoLocation", NULL, N_("_Location…"), "<control>L",
239           N_("Go to a specified location"),
240           G_CALLBACK (window_cmd_go_location) },
241         { "GoHistory", EPHY_STOCK_HISTORY, N_("Hi_story"), "<control>H",
242           N_("Open the history window"),
243           G_CALLBACK (window_cmd_go_history) },
245         /* Tabs menu */
247         { "TabsPrevious", NULL, N_("_Previous Tab"), "<control>Page_Up",
248           N_("Activate previous tab"),
249           G_CALLBACK (window_cmd_tabs_previous) },
250         { "TabsNext", NULL, N_("_Next Tab"), "<control>Page_Down",
251           N_("Activate next tab"),
252           G_CALLBACK (window_cmd_tabs_next) },
253         { "TabsMoveLeft", NULL, N_("Move Tab _Left"), "<shift><control>Page_Up",
254           N_("Move current tab to left"),
255           G_CALLBACK (window_cmd_tabs_move_left) },
256         { "TabsMoveRight", NULL, N_("Move Tab _Right"), "<shift><control>Page_Down",
257           N_("Move current tab to right"),
258           G_CALLBACK (window_cmd_tabs_move_right) },
260         /* Help menu */
262         {"HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1",
263          N_("Display web browser help"),
264          G_CALLBACK (window_cmd_help_contents) },
265         { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
266           N_("Display credits for the web browser creators"),
267           G_CALLBACK (window_cmd_help_about) },
270 static const GtkToggleActionEntry ephy_menu_toggle_entries [] =
272         /* File Menu */
274         { "FileWorkOffline", NULL, N_("_Work Offline"), NULL,
275           N_("Switch to offline mode"),
276           G_CALLBACK (window_cmd_file_work_offline), FALSE },
278         /* View Menu */
280         { "ViewToolbar", NULL, N_("_Hide Toolbars"), NULL,
281           N_("Show or hide toolbar"),
282           G_CALLBACK (ephy_window_view_toolbar_cb), FALSE },
283         { "ViewStatusbar", NULL, N_("St_atusbar"), NULL,
284           N_("Show or hide statusbar"),
285           G_CALLBACK (ephy_window_view_statusbar_cb), TRUE },
286         { "ViewFullscreen", GTK_STOCK_FULLSCREEN, N_("_Fullscreen"), "F11",
287           N_("Browse at full screen"),
288           G_CALLBACK (window_cmd_view_fullscreen), FALSE },
289         { "ViewPopupWindows", EPHY_STOCK_POPUPS, N_("Popup _Windows"), NULL,
290           N_("Show or hide unrequested popup windows from this site"),
291           G_CALLBACK (ephy_window_view_popup_windows_cb), FALSE },
292         { "BrowseWithCaret", NULL, N_("Selection Caret"), "F7",
293           "",
294           G_CALLBACK (window_cmd_browse_with_caret), FALSE }
297 static const GtkActionEntry ephy_popups_entries [] = {
298         /* Document */
300         { "ContextBookmarkPage", STOCK_ADD_BOOKMARK, N_("Add Boo_kmark…"), "<control>D",
301           N_("Add a bookmark for the current page"),
302           G_CALLBACK (window_cmd_file_bookmark_page) },
304         /* Framed document */
306         { "OpenFrame", NULL, N_("Show Only _This Frame"), NULL,
307           N_("Show only this frame in this window"),
308           G_CALLBACK (popup_cmd_open_frame) },
310         /* Links */
312         { "OpenLink", GTK_STOCK_OPEN, N_("_Open Link"), NULL,
313           N_("Open link in this window"),
314           G_CALLBACK (popup_cmd_open_link) },
315         { "OpenLinkInNewWindow", NULL, N_("Open Link in New _Window"), NULL,
316           N_("Open link in a new window"),
317           G_CALLBACK (popup_cmd_link_in_new_window) },
318         { "OpenLinkInNewTab", NULL, N_("Open Link in New _Tab"), NULL,
319           N_("Open link in a new tab"),
320           G_CALLBACK (popup_cmd_link_in_new_tab) },
321         { "DownloadLink", STOCK_DOWNLOAD, N_("_Download Link"), NULL,
322           NULL, G_CALLBACK (popup_cmd_download_link) },
323         { "DownloadLinkAs", GTK_STOCK_SAVE_AS, N_("_Save Link As…"), NULL,
324           N_("Save link with a different name"),
325           G_CALLBACK (popup_cmd_download_link_as) },
326         { "BookmarkLink", STOCK_ADD_BOOKMARK, N_("_Bookmark Link…"),
327           NULL, NULL, G_CALLBACK (popup_cmd_bookmark_link) },
328         { "CopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
329           NULL, G_CALLBACK (popup_cmd_copy_link_address) },
331         /* Email links */
333         /* This is on the context menu on a mailto: link and opens the mail program */
334         { "SendEmail", GTK_STOCK_OPEN, N_("_Send Email…"),
335           NULL, NULL, G_CALLBACK (popup_cmd_open_link) },
336         { "CopyEmailAddress", NULL, N_("_Copy Email Address"), NULL,
337           NULL, G_CALLBACK (popup_cmd_copy_link_address) },
339         /* Images */
341         { "OpenImage", GTK_STOCK_OPEN, N_("Open _Image"), NULL,
342           NULL, G_CALLBACK (popup_cmd_open_image) },
343         { "SaveImageAs", GTK_STOCK_SAVE_AS, N_("_Save Image As…"), NULL,
344           NULL, G_CALLBACK (popup_cmd_save_image_as) },
345         { "SetImageAsBackground", NULL, N_("_Use Image As Background"), NULL,
346           NULL, G_CALLBACK (popup_cmd_set_image_as_background) },
347         { "CopyImageLocation", NULL, N_("Copy I_mage Address"), NULL,
348           NULL, G_CALLBACK (popup_cmd_copy_image_location) },
349         { "StartImageAnimation", NULL, N_("St_art Animation"), NULL,
350           NULL, NULL },
351         { "StopImageAnimation", NULL, N_("St_op Animation"), NULL,
352           NULL, NULL },
355 static const struct
357         guint keyval;
358         GdkModifierType modifier;
359         const gchar *action;
360         gboolean fromToolbar;
361 } extra_keybindings [] = {
362         { GDK_s,                GDK_CONTROL_MASK,       "FileSaveAs",           FALSE },
363         { GDK_R,                GDK_CONTROL_MASK |
364                                 GDK_SHIFT_MASK,         "ViewReload",           FALSE },
365         /* Support all the MSIE tricks as well ;) */
366         { GDK_F5,               0,                      "ViewReload",           FALSE },
367         { GDK_F5,               GDK_CONTROL_MASK,       "ViewReload",           FALSE },
368         { GDK_F5,               GDK_SHIFT_MASK,         "ViewReload",           FALSE },
369         { GDK_F5,               GDK_CONTROL_MASK |
370                                 GDK_SHIFT_MASK,         "ViewReload",           FALSE },
371         { GDK_KP_Add,           GDK_CONTROL_MASK,       "ViewZoomIn",           FALSE },
372         { GDK_KP_Subtract,      GDK_CONTROL_MASK,       "ViewZoomOut",          FALSE },
373         { GDK_equal,            GDK_CONTROL_MASK,       "ViewZoomIn",           FALSE },
374         /* These keys are a bit strange: when pressed with no modifiers, they emit
375          * KP_PageUp/Down Control; when pressed with Control+Shift they are KP_9/3,
376          * when NumLock is on they are KP_9/3 and with NumLock and Control+Shift
377          * They're KP_PageUp/Down again!
378          */
379         { GDK_KP_Left,          GDK_MOD1_MASK /*Alt*/,  "NavigationBack",       TRUE },
380         { GDK_KP_4,             GDK_MOD1_MASK /*Alt*/,  "NavigationBack",       TRUE },
381         { GDK_KP_Right,         GDK_MOD1_MASK /*Alt*/,  "NavigationForward",    TRUE },
382         { GDK_KP_6,             GDK_MOD1_MASK /*Alt*/,  "NavigationForward",    TRUE },
383         { GDK_KP_Up,            GDK_MOD1_MASK /*Alt*/,  "NavigationUp",         TRUE },
384         { GDK_KP_8,             GDK_MOD1_MASK /*Alt*/,  "NavigationUp",         TRUE },
385         { GDK_KP_Page_Up,       GDK_CONTROL_MASK,       "TabsPrevious",         FALSE },
386         { GDK_KP_9,             GDK_CONTROL_MASK,       "TabsPrevious",         FALSE },
387         { GDK_KP_Page_Down,     GDK_CONTROL_MASK,       "TabsNext",             FALSE },
388         { GDK_KP_3,             GDK_CONTROL_MASK,       "TabsNext",             FALSE },
389         { GDK_KP_Page_Up,       GDK_SHIFT_MASK | GDK_CONTROL_MASK,      "TabsMoveLeft",         FALSE },
390         { GDK_KP_9,             GDK_SHIFT_MASK | GDK_CONTROL_MASK,      "TabsMoveLeft",         FALSE },
391         { GDK_KP_Page_Down,     GDK_SHIFT_MASK | GDK_CONTROL_MASK,      "TabsMoveRight",        FALSE },
392         { GDK_KP_3,             GDK_SHIFT_MASK | GDK_CONTROL_MASK,      "TabsMoveRight",        FALSE },
393 #ifdef HAVE_X11_XF86KEYSYM_H
394         { XF86XK_Back,          0,                      "NavigationBack",       TRUE  },
395         { XF86XK_Favorites,     0,                      "GoBookmarks",          FALSE },
396         { XF86XK_Forward,       0,                      "NavigationForward",    TRUE  },
397         { XF86XK_Go,            0,                      "GoLocation",           FALSE },
398         { XF86XK_History,       0,                      "GoHistory",            FALSE },
399         { XF86XK_HomePage,      0,                      "GoHome",               TRUE  },
400         { XF86XK_OpenURL,       0,                      "GoLocation",           FALSE },
401         { XF86XK_AddFavorite,   0,                      "FileBookmarkPage",     FALSE },
402         { XF86XK_Refresh,       0,                      "ViewReload",           FALSE },
403         { XF86XK_Reload,        0,                      "ViewReload",           FALSE },
404         { XF86XK_Search,        0,                      "EditFind",             FALSE },
405         { XF86XK_Send,          0,                      "FileSendTo",           FALSE },
406         { XF86XK_Start,         0,                      "GoHome",               TRUE  },
407         { XF86XK_Stop,          0,                      "ViewStop",             FALSE },
408         { XF86XK_ZoomIn,        0,                      "ViewZoomIn",           FALSE },
409         { XF86XK_ZoomOut,       0,                      "ViewZoomOut",          FALSE }
410         /* FIXME: what about ScrollUp, ScrollDown, Menu*, Option, LogOff, Save,.. any others? */
411 #endif /* HAVE_X11_XF86KEYSYM_H */
414 #define CONF_LOCKDOWN_HIDE_MENUBAR "/apps/epiphany/lockdown/hide_menubar"
416 #define BOOKMARKS_MENU_PATH "/menubar/BookmarksMenu"
418 #define SETTINGS_CONNECTION_DATA_KEY    "EphyWindowSettings"
420 /* Until https://bugzilla.mozilla.org/show_bug.cgi?id=296002 is fixed */
422 #define EPHY_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_WINDOW, EphyWindowPrivate))
424 struct _EphyWindowPrivate
426         GtkWidget *main_vbox;
427         GtkWidget *menu_dock;
428         GtkWidget *fullscreen_popup;
429         EphyToolbar *toolbar;
430         GtkWidget *statusbar;
431         GtkUIManager *manager;
432         GtkActionGroup *action_group;
433         GtkActionGroup *popups_action_group;
434         EphyEncodingMenu *enc_menu;
435         EphyTabsMenu *tabs_menu;
436         PPViewToolbar *ppview_toolbar;
437         GtkNotebook *notebook;
438         EphyTab *active_tab;
439         EphyFindToolbar *find_toolbar;
440         guint num_tabs;
441         guint tab_message_cid;
442         guint help_message_cid;
443         EphyEmbedChrome chrome;
444         guint idle_resize_handler;
445         GHashTable *tabs_to_remove;
446         EphyEmbedEvent *context_event;
447         guint idle_worker;
449         guint browse_with_caret_notifier_id;
450         guint allow_popups_notifier_id;
452         guint menubar_accel_keyval;
453         guint menubar_accel_modifier;
455         guint closing : 1;
456         guint has_size : 1;
457         guint fullscreen_mode : 1;
458         guint ppv_mode : 1;
459         guint should_save_chrome : 1;
460         guint is_popup : 1;
462         guint key_theme_is_emacs : 1;
465 enum
467         PROP_0,
468         PROP_ACTIVE_TAB,
469         PROP_CHROME,
470         PROP_PPV_MODE,
471         PROP_SINGLE_TAB_MODE
474 /* Make sure not to overlap with those in ephy-lockdown.c */
475 enum
477         SENS_FLAG_CHROME        = 1 << 0,
478         SENS_FLAG_CONTEXT       = 1 << 1,
479         SENS_FLAG_DOCUMENT      = 1 << 2,
480         SENS_FLAG_LOADING       = 1 << 3,
481         SENS_FLAG_NAVIGATION    = 1 << 4
484 static GObjectClass *parent_class = NULL;
486 GType
487 ephy_window_get_type (void)
489         static GType type = 0;
491         if (G_UNLIKELY (type == 0))
492         {
493                 const GTypeInfo our_info =
494                 {
495                         sizeof (EphyWindowClass),
496                         NULL, /* base_init */
497                         NULL, /* base_finalize */
498                         (GClassInitFunc) ephy_window_class_init,
499                         NULL,
500                         NULL, /* class_data */
501                         sizeof (EphyWindow),
502                         0, /* n_preallocs */
503                         (GInstanceInitFunc) ephy_window_init
504                 };
505                 const GInterfaceInfo link_info = 
506                 {
507                         (GInterfaceInitFunc) ephy_window_link_iface_init,
508                         NULL,
509                         NULL
510                 };
512                 type = g_type_register_static (GTK_TYPE_WINDOW,
513                                                "EphyWindow",
514                                                &our_info, 0);
516                 g_type_add_interface_static (type,
517                                              EPHY_TYPE_LINK,
518                                              &link_info);
519         }
521         return type;
524 static void
525 settings_change_notify (GtkSettings *settings,
526                         EphyWindow  *window)
528         EphyWindowPrivate *priv = window->priv;
529         char *key_theme_name, *menubar_accel_accel;
531         g_object_get (settings,
532                       "gtk-key-theme-name", &key_theme_name,
533                       "gtk-menu-bar-accel", &menubar_accel_accel,
534                       NULL);
536         g_return_if_fail (menubar_accel_accel != NULL);
538         if (menubar_accel_accel != NULL && menubar_accel_accel[0] != '\0')
539         {
540                 gtk_accelerator_parse (menubar_accel_accel,
541                                        &priv->menubar_accel_keyval,
542                                        &priv->menubar_accel_modifier);
543                 if (priv->menubar_accel_keyval == 0)
544                 {
545                         g_warning ("Failed to parse menu bar accelerator '%s'\n",
546                                    menubar_accel_accel);
547                 }
548         }
549         else
550         {
551                 priv->menubar_accel_keyval = 0;
552                 priv->menubar_accel_modifier = 0;
553         }
555         priv->key_theme_is_emacs =
556                 key_theme_name &&
557                 g_ascii_strcasecmp (key_theme_name, "Emacs") == 0;
559         g_free (key_theme_name);
560         g_free (menubar_accel_accel);
563 static void
564 settings_changed_cb (GtkSettings *settings)
566         GList *list, *l;
568         /* FIXME: multi-head */
569         list = gtk_window_list_toplevels ();
571         for (l = list; l != NULL; l = l->next)
572         {
573                 if (EPHY_IS_WINDOW (l->data))
574                 {
575                         settings_change_notify (settings, l->data);
576                 }
577         }
579         g_list_free (list);
582 static void
583 destroy_fullscreen_popup (EphyWindow *window)
585         if (window->priv->fullscreen_popup != NULL)
586         {
587                 gtk_widget_destroy (window->priv->fullscreen_popup);
588                 window->priv->fullscreen_popup = NULL;
589         }
592 static void
593 add_widget (GtkUIManager *manager,
594             GtkWidget *widget,
595             EphyWindow *window)
597         gtk_box_pack_start (GTK_BOX (window->priv->menu_dock),
598                             widget, FALSE, FALSE, 0);
601 static void
602 exit_fullscreen_clicked_cb (EphyWindow *window)
604         GtkAction *action;
606         action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
607         g_return_if_fail (action != NULL);
609         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
612 static gboolean
613 get_toolbar_visibility (EphyWindow *window)
615         return ((window->priv->chrome & EPHY_EMBED_CHROME_TOOLBAR) != 0) &&
616                !window->priv->ppv_mode;
617 }                       
619 static void
620 get_chromes_visibility (EphyWindow *window,
621                         gboolean *show_menubar,
622                         gboolean *show_statusbar,
623                         gboolean *show_toolbar,
624                         gboolean *show_tabsbar)
626         EphyWindowPrivate *priv = window->priv;
627         EphyEmbedChrome flags = priv->chrome;
629         if (window->priv->ppv_mode)
630         {
631                 *show_menubar = *show_statusbar
632                               = *show_toolbar
633                               = *show_tabsbar
634                               = FALSE;
635         }
636         else if (window->priv->fullscreen_mode)
637         {
638                 *show_toolbar = (flags & EPHY_EMBED_CHROME_TOOLBAR) != 0;
639                 *show_menubar = *show_statusbar = FALSE;
640                 *show_tabsbar = !priv->is_popup;
641         }
642         else
643         {
644                 *show_menubar = (flags & EPHY_EMBED_CHROME_MENUBAR) != 0;
645                 *show_statusbar = (flags & EPHY_EMBED_CHROME_STATUSBAR) != 0;
646                 *show_toolbar = (flags & EPHY_EMBED_CHROME_TOOLBAR) != 0;
647                 *show_tabsbar = !priv->is_popup;
648         }
651 static void
652 sync_chromes_visibility (EphyWindow *window)
654         EphyWindowPrivate *priv = window->priv;
655         GtkWidget *menubar;
656         gboolean show_statusbar, show_menubar, show_toolbar, show_tabsbar;
658         if (priv->closing) return;
660         get_chromes_visibility (window, &show_menubar,
661                                 &show_statusbar, &show_toolbar,
662                                 &show_tabsbar);
664         menubar = gtk_ui_manager_get_widget (window->priv->manager, "/menubar");
665         g_assert (menubar != NULL);
667         g_object_set (menubar, "visible", show_menubar, NULL);
668         g_object_set (priv->toolbar, "visible", show_toolbar, NULL);
669         g_object_set (priv->statusbar, "visible", show_statusbar, NULL);
671         ephy_notebook_set_show_tabs (EPHY_NOTEBOOK (priv->notebook), show_tabsbar);
673         if (priv->fullscreen_popup != NULL)
674         {
675                 g_object_set (priv->fullscreen_popup, "visible", !show_toolbar, NULL);
676         }
679 static void
680 ephy_window_fullscreen (EphyWindow *window)
682         EphyWindowPrivate *priv = window->priv;
683         GtkWidget *popup;
684         EphyTab *tab;
685         GtkAction *action;
686         gboolean lockdown_fs;
688         priv->fullscreen_mode = TRUE;
690         lockdown_fs = eel_gconf_get_boolean (CONF_LOCKDOWN_FULLSCREEN);
692         popup = ephy_fullscreen_popup_new (window);
693         ephy_fullscreen_popup_set_show_leave
694                 (EPHY_FULLSCREEN_POPUP (popup), !lockdown_fs);
695         priv->fullscreen_popup = popup;
696         g_signal_connect_swapped (popup, "exit-clicked",
697                                   G_CALLBACK (exit_fullscreen_clicked_cb), window);
699         action = gtk_action_group_get_action (priv->action_group, "ViewPageSecurityInfo");
700         g_signal_connect_swapped (popup, "lock-clicked",
701                                   G_CALLBACK (gtk_action_activate), action);
703         /* sync status */
704         tab = ephy_window_get_active_tab (window);
705         sync_tab_load_status (tab, NULL, window);
706         sync_tab_security (tab, NULL, window);
708         egg_editable_toolbar_set_model
709                 (EGG_EDITABLE_TOOLBAR (priv->toolbar),
710                  EGG_TOOLBARS_MODEL (
711                         ephy_shell_get_toolbars_model (ephy_shell, TRUE)));
713         ephy_toolbar_set_show_leave_fullscreen (priv->toolbar,
714                                                 !lockdown_fs);
715         
716         sync_chromes_visibility (window);
719 static void
720 ephy_window_unfullscreen (EphyWindow *window)
722         window->priv->fullscreen_mode = FALSE;
724         destroy_fullscreen_popup (window);
726         ephy_toolbar_set_show_leave_fullscreen (window->priv->toolbar, FALSE);
728         egg_editable_toolbar_set_model
729                 (EGG_EDITABLE_TOOLBAR (window->priv->toolbar),
730                  EGG_TOOLBARS_MODEL (
731                         ephy_shell_get_toolbars_model (ephy_shell, FALSE)));
733         sync_chromes_visibility (window);
736 static GtkWidget *
737 construct_confirm_close_dialog (EphyWindow *window)
739         GtkWidget *dialog;
741         dialog = gtk_message_dialog_new
742                 (GTK_WINDOW (window),
743                  GTK_DIALOG_MODAL,
744                  GTK_MESSAGE_WARNING,
745                  GTK_BUTTONS_CANCEL,
746                  _("There are unsubmitted changes to form elements"));
748         gtk_message_dialog_format_secondary_text
749                 (GTK_MESSAGE_DIALOG (dialog),
750                  _("If you close the document anyway, "
751                    "you will lose that information."));
752         
753         gtk_dialog_add_button (GTK_DIALOG (dialog),
754                                _("Close _Document"), GTK_RESPONSE_ACCEPT);
756         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
758         /* FIXME gtk_window_set_title (GTK_WINDOW (dialog), _("Close Document?")); */
759         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
761         gtk_window_group_add_window (GTK_WINDOW (window)->group, GTK_WINDOW (dialog));
763         return dialog;
766 static gboolean
767 confirm_close_with_modified_forms (EphyWindow *window)
769         GtkWidget *dialog;
770         int response;
772         dialog = construct_confirm_close_dialog (window);
773         response = gtk_dialog_run (GTK_DIALOG (dialog));
775         gtk_widget_destroy (dialog);
777         return response == GTK_RESPONSE_ACCEPT;
780 static void
781 menubar_deactivate_cb (GtkWidget *menubar,
782                        EphyWindow *window)
784         g_signal_handlers_disconnect_by_func
785                 (menubar, G_CALLBACK (menubar_deactivate_cb), window);
787         gtk_menu_shell_deselect (GTK_MENU_SHELL (menubar));
789         sync_chromes_visibility (window);
792 static gboolean 
793 ephy_window_key_press_event (GtkWidget *widget,
794                              GdkEventKey *event)
796         EphyWindow *window = EPHY_WINDOW (widget);
797         EphyWindowPrivate *priv = window->priv;
798         GtkWidget *menubar, *focus_widget;
799         gboolean shortcircuit = FALSE, force_chain = FALSE, handled = FALSE;
800         guint modifier = event->state & gtk_accelerator_get_default_mod_mask ();
801         guint i;
803         /* In an attempt to get the mozembed playing nice with things like emacs keybindings
804          * we are passing important events to the focused child widget before letting the window's
805          * base handler see them. This is *completely against* stated gtk2 policy but the 
806          * 'correct' behaviour is exceptionally useless. We need to keep an eye out for 
807          * unexpected consequences of this decision. IME's should be a high concern, but 
808          * considering that the IME folks complained about the upside-down event propagation
809          * rules, we might be doing them a favour.
810          *
811          * We achieve this by first evaluating the event to see if it's important, and if
812          * so, we get the focus widget and attempt to get the widget to handle that event.
813          * If the widget does handle it, we're done (unless force_chain is true, in which
814          * case the event is handled as normal in addition to being sent to the focus
815          * widget), otherwise the event follows the normal handling path.
816          */
818         if (event->keyval == GDK_Escape && modifier == 0)
819         {
820                 /* Always pass Escape to both the widget, and the parent */
821                 shortcircuit = TRUE;
822                 force_chain = TRUE;
823         }
824         else if (priv->key_theme_is_emacs && 
825                  (modifier == GDK_CONTROL_MASK) &&
826                  event->length > 0 &&
827                  /* But don't pass Ctrl+Enter twice */
828                  event->keyval != GDK_Return &&
829                  event->keyval != GDK_KP_Enter &&
830                  event->keyval != GDK_ISO_Enter)
831         {
832                 /* Pass CTRL+letter characters to the widget */
833                 shortcircuit = TRUE;
834         }
836         if (shortcircuit)
837         {
838                 focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
840                 if (GTK_IS_WIDGET (focus_widget))
841                 {
842                         handled = gtk_widget_event (focus_widget,
843                                                     (GdkEvent*) event);
844                 }
846                 if (handled && !force_chain)
847                 {
848                         return handled;
849                 }
850         }
852         /* Handle accelerators that we want bound, but aren't associated with
853          * an action */
854         for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++)
855         {
856                 if (event->keyval == extra_keybindings[i].keyval &&
857                     modifier == extra_keybindings[i].modifier)
858                 {
859                         GtkAction * action = gtk_action_group_get_action
860                                 (extra_keybindings[i].fromToolbar ? 
861                                         ephy_toolbar_get_action_group (priv->toolbar) :
862                                         priv->action_group,
863                                 extra_keybindings[i].action);
864                         if (gtk_action_is_sensitive (action))
865                         {
866                                 gtk_action_activate (action);
867                                 return TRUE;
868                         }
869                         break;
870                 }
871         }
873         /* Don't activate menubar in ppv mode, or in lockdown mode */
874         if (priv->ppv_mode || eel_gconf_get_boolean (CONF_LOCKDOWN_HIDE_MENUBAR))
875         {
876                 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
877         }
879         /* Show and activate the menubar, if it isn't visible */
880         if (priv->menubar_accel_keyval != 0 &&
881             event->keyval == priv->menubar_accel_keyval &&
882             modifier == priv->menubar_accel_modifier)
883         {
884                 menubar = gtk_ui_manager_get_widget (window->priv->manager, "/menubar");
885                 g_return_val_if_fail (menubar != NULL , FALSE);
887                 if (!GTK_WIDGET_VISIBLE (menubar))
888                 {
889                         g_signal_connect (menubar, "deactivate",
890                                           G_CALLBACK (menubar_deactivate_cb), window);
892                         gtk_widget_show (menubar);
893                         gtk_menu_shell_select_first (GTK_MENU_SHELL (menubar), FALSE);
895                         return TRUE;
896                 }
897         }
899         return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
902 static gboolean
903 ephy_window_delete_event (GtkWidget *widget,
904                           GdkEventAny *event)
906         EphyWindow *window = EPHY_WINDOW (widget);
907         EphyWindowPrivate *priv = window->priv;
908         EphyTab *modified_tab = NULL;
909         GList *tabs, *l;
910         gboolean modified = FALSE;
912         /* We ignore the delete_event if the disable_quit lockdown has been set
913          */
914         if (eel_gconf_get_boolean("/apps/epiphany/lockdown/disable_quit")) return TRUE;
916         /* Workaround a crash when closing a window while in print preview mode. See
917          * mozilla bug #241809. /
918          * Go back to normal mode instead of closing, see bug #326136.
919          */
920         if (priv->ppv_mode)
921         {
922                 EphyEmbed *embed;
924                 embed = ephy_window_get_active_embed (window);
925                 ephy_embed_set_print_preview_mode (embed, FALSE);
927                 ephy_window_set_print_preview (window, FALSE);
929                 return TRUE;
930         }
932         tabs = ephy_window_get_tabs (window);
933         for (l = tabs; l != NULL; l = l->next)
934         {
935                 EphyTab *tab = (EphyTab *) l->data;
936                 EphyEmbed *embed;
938                 g_return_val_if_fail (EPHY_IS_TAB (tab), FALSE);
940                 embed = ephy_tab_get_embed (tab);
941                 g_return_val_if_fail (EPHY_IS_EMBED (embed), FALSE);
943                 if (ephy_embed_has_modified_forms (embed))
944                 {
945                         modified = TRUE;
946                         modified_tab = tab;
947                         break;
948                 }
949         }
950         g_list_free (tabs);
952         if (modified)
953         {
954                 /* jump to the first tab with modified forms */
955                 ephy_window_jump_to_tab (window, modified_tab);
957                 if (confirm_close_with_modified_forms (window) == FALSE)
958                 {
959                         /* stop window close */
960                         return TRUE;
961                 }
962         }
963         
964         /* See bug #114689 */
965         gtk_widget_hide (widget);
967         /* proceed with window close */
968         if (GTK_WIDGET_CLASS (parent_class)->delete_event)
969         {
970                 return GTK_WIDGET_CLASS (parent_class)->delete_event (widget, event);
971         }
973         return FALSE;
976 static void
977 update_popup_actions_visibility (EphyWindow *window,
978                                  gboolean is_image,
979                                  gboolean is_frame)
981         GtkAction *action;
982         GtkActionGroup *action_group;
984         action_group = window->priv->popups_action_group;
986         action = gtk_action_group_get_action (action_group, "OpenImage");
987         gtk_action_set_visible (action, is_image);
988         action = gtk_action_group_get_action (action_group, "SaveImageAs");
989         gtk_action_set_visible (action, is_image);
990         action = gtk_action_group_get_action (action_group, "SetImageAsBackground");
991         gtk_action_set_visible (action, is_image);
992         action = gtk_action_group_get_action (action_group, "CopyImageLocation");
993         gtk_action_set_visible (action, is_image);
995         action = gtk_action_group_get_action (action_group, "OpenFrame");
996         gtk_action_set_visible (action, is_frame);
999 static void
1000 update_edit_actions_sensitivity (EphyWindow *window, gboolean hide)
1002         GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
1003         GtkActionGroup *action_group;
1004         GtkAction *action;
1005         gboolean can_copy, can_cut, can_undo, can_redo, can_paste;
1007         if (GTK_IS_EDITABLE (widget))
1008         {
1009                 gboolean has_selection;
1011                 has_selection = gtk_editable_get_selection_bounds
1012                         (GTK_EDITABLE (widget), NULL, NULL);
1014                 can_copy = has_selection;
1015                 can_cut = has_selection;
1016                 can_paste = TRUE;
1017                 can_undo = FALSE;
1018                 can_redo = FALSE;
1019         }
1020         else
1021         {
1022                 EphyEmbed *embed;
1024                 embed = ephy_window_get_active_embed (window);
1025                 g_return_if_fail (embed != NULL);
1027                 can_copy = ephy_command_manager_can_do_command
1028                                 (EPHY_COMMAND_MANAGER (embed), "cmd_copy");
1029                 can_cut = ephy_command_manager_can_do_command
1030                                 (EPHY_COMMAND_MANAGER (embed), "cmd_cut");
1031                 can_paste = ephy_command_manager_can_do_command
1032                                 (EPHY_COMMAND_MANAGER (embed), "cmd_paste");
1033                 can_undo = ephy_command_manager_can_do_command
1034                                 (EPHY_COMMAND_MANAGER (embed), "cmd_undo");
1035                 can_redo = ephy_command_manager_can_do_command
1036                                 (EPHY_COMMAND_MANAGER (embed), "cmd_redo");
1037         }
1039         action_group = window->priv->action_group;
1041         action = gtk_action_group_get_action (action_group, "EditCopy");
1042         gtk_action_set_sensitive (action, can_copy);
1043         gtk_action_set_visible (action, !hide || can_copy);
1044         action = gtk_action_group_get_action (action_group, "EditCut");
1045         gtk_action_set_sensitive (action, can_cut);
1046         gtk_action_set_visible (action, !hide || can_cut);
1047         action = gtk_action_group_get_action (action_group, "EditPaste");
1048         gtk_action_set_sensitive (action, can_paste);
1049         gtk_action_set_visible (action,  !hide || can_paste);
1050         action = gtk_action_group_get_action (action_group, "EditUndo");
1051         gtk_action_set_sensitive (action, can_undo);
1052         gtk_action_set_visible (action,  !hide || can_undo);
1053         action = gtk_action_group_get_action (action_group, "EditRedo");
1054         gtk_action_set_sensitive (action, can_redo);
1055         gtk_action_set_visible (action, !hide || can_redo);
1058 static void
1059 enable_edit_actions_sensitivity (EphyWindow *window)
1061         GtkActionGroup *action_group;
1062         GtkAction *action;
1064         action_group = window->priv->action_group;
1066         action = gtk_action_group_get_action (action_group, "EditCopy");
1067         gtk_action_set_sensitive (action, TRUE);
1068         gtk_action_set_visible (action, TRUE);
1069         action = gtk_action_group_get_action (action_group, "EditCut");
1070         gtk_action_set_sensitive (action, TRUE);
1071         gtk_action_set_visible (action, TRUE);
1072         action = gtk_action_group_get_action (action_group, "EditPaste");
1073         gtk_action_set_sensitive (action, TRUE);
1074         gtk_action_set_visible (action, TRUE);
1075         action = gtk_action_group_get_action (action_group, "EditUndo");
1076         gtk_action_set_sensitive (action, TRUE);
1077         gtk_action_set_visible (action, TRUE);
1078         action = gtk_action_group_get_action (action_group, "EditRedo");
1079         gtk_action_set_sensitive (action, TRUE);
1080         gtk_action_set_visible (action, TRUE);
1083 static void
1084 edit_menu_show_cb (GtkWidget *menu,
1085                    EphyWindow *window)
1087         update_edit_actions_sensitivity (window, FALSE);
1090 static void
1091 edit_menu_hide_cb (GtkWidget *menu,
1092                    EphyWindow *window)
1094         enable_edit_actions_sensitivity (window);
1097 static void
1098 init_menu_updaters (EphyWindow *window)
1100         GtkWidget *edit_menu_item, *edit_menu;
1102         edit_menu_item = gtk_ui_manager_get_widget
1103                 (window->priv->manager, "/menubar/EditMenu");
1104         edit_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (edit_menu_item));
1106         g_signal_connect (edit_menu, "show",
1107                           G_CALLBACK (edit_menu_show_cb), window);
1108         g_signal_connect (edit_menu, "hide",
1109                           G_CALLBACK (edit_menu_hide_cb), window);
1112 static void
1113 menu_item_select_cb (GtkMenuItem *proxy,
1114                      EphyWindow *window)
1116         GtkAction *action;
1117         char *message;
1119         action = g_object_get_data (G_OBJECT (proxy),  "gtk-action");
1120         g_return_if_fail (action != NULL);
1121         
1122         g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
1123         if (message)
1124         {
1125                 gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
1126                                     window->priv->help_message_cid, message);
1127                 g_free (message);
1128         }
1131 static void
1132 menu_item_deselect_cb (GtkMenuItem *proxy,
1133                        EphyWindow *window)
1135         gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
1136                            window->priv->help_message_cid);
1139 static gboolean
1140 tool_item_enter_cb (GtkWidget *proxy,
1141                     GdkEventCrossing *event,
1142                     EphyWindow *window)
1144         if (event->mode == GDK_CROSSING_NORMAL)
1145         {
1146                 GtkToolItem *item;
1147                 GtkAction *action;
1148                 char *message;
1149     
1150                 item = GTK_TOOL_ITEM (gtk_widget_get_ancestor (proxy, GTK_TYPE_TOOL_ITEM));
1151                 
1152                 action = g_object_get_data (G_OBJECT (item),  "gtk-action");
1153                 g_return_val_if_fail (action != NULL, FALSE);
1154                 
1155                 g_object_get (G_OBJECT (action), "tooltip", &message, NULL);
1156                 if (message)
1157                 {
1158                         gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
1159                                             window->priv->help_message_cid, message);
1160                         g_free (message);
1161                 }
1162         }
1163         
1164         return FALSE;
1167 static gboolean
1168 tool_item_leave_cb (GtkWidget *proxy,
1169                     GdkEventCrossing *event,
1170                     EphyWindow *window)
1172         if (event->mode == GDK_CROSSING_NORMAL)
1173         {
1174                 gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
1175                                    window->priv->help_message_cid);
1176         }
1177         
1178         return FALSE;
1181 static void
1182 tool_item_drag_begin_cb (GtkWidget          *widget,
1183                          GdkDragContext     *context,
1184                          EphyWindow         *window)
1186         gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
1187                            window->priv->help_message_cid);
1191 static void
1192 connect_tool_item (GtkWidget *proxy, EphyWindow *window)
1194         if (GTK_IS_CONTAINER (proxy))
1195         {
1196                 gtk_container_foreach (GTK_CONTAINER (proxy),
1197                                        (GtkCallback) connect_tool_item,
1198                                        (gpointer) window);
1199         }
1201         g_signal_connect (proxy, "drag_begin",
1202                           G_CALLBACK (tool_item_drag_begin_cb), window);
1203          g_signal_connect (proxy, "enter-notify-event",
1204                           G_CALLBACK (tool_item_enter_cb), window);
1205         g_signal_connect (proxy, "leave-notify-event",
1206                           G_CALLBACK (tool_item_leave_cb), window);
1209 static void
1210 disconnect_tool_item (GtkWidget *proxy, EphyWindow *window)
1212         if (GTK_IS_CONTAINER (proxy))
1213         {
1214                 gtk_container_foreach (GTK_CONTAINER (proxy),
1215                                        (GtkCallback) disconnect_tool_item,
1216                                        (gpointer) window);
1217         }
1219         g_signal_handlers_disconnect_by_func
1220           (proxy, G_CALLBACK (tool_item_enter_cb), window);
1221         g_signal_handlers_disconnect_by_func
1222           (proxy, G_CALLBACK (tool_item_leave_cb), window);
1225 static void
1226 disconnect_proxy_cb (GtkUIManager *manager,
1227                      GtkAction *action,
1228                      GtkWidget *proxy,
1229                      EphyWindow *window)
1231         if (GTK_IS_MENU_ITEM (proxy))
1232         {
1233                 g_signal_handlers_disconnect_by_func
1234                         (proxy, G_CALLBACK (menu_item_select_cb), window);
1235                 g_signal_handlers_disconnect_by_func
1236                         (proxy, G_CALLBACK (menu_item_deselect_cb), window);
1237         }
1238         else if (GTK_IS_TOOL_ITEM (proxy))
1239         {
1240                 disconnect_tool_item (proxy, window);
1241         }
1244 static void
1245 connect_proxy_cb (GtkUIManager *manager,
1246                   GtkAction *action,
1247                   GtkWidget *proxy,
1248                   EphyWindow *window)
1250         if (GTK_IS_MENU_ITEM (proxy))
1251         {
1252                 g_signal_connect (proxy, "select",
1253                                   G_CALLBACK (menu_item_select_cb), window);
1254                 g_signal_connect (proxy, "deselect",
1255                                   G_CALLBACK (menu_item_deselect_cb), window);
1256         }
1257         else if (GTK_IS_TOOL_ITEM (proxy))
1258         {
1259                 connect_tool_item (proxy, window);
1260         }
1263 static void
1264 update_chromes_actions (EphyWindow *window)
1266         GtkActionGroup *action_group = window->priv->action_group;
1267         GtkAction *action;
1268         gboolean show_statusbar, show_menubar, show_toolbar, show_tabsbar;
1270         get_chromes_visibility (window, &show_menubar,
1271                                 &show_statusbar, &show_toolbar,
1272                                 &show_tabsbar);
1274         action = gtk_action_group_get_action (action_group, "ViewToolbar");
1275         g_signal_handlers_block_by_func (G_OBJECT (action),
1276                                          G_CALLBACK (ephy_window_view_toolbar_cb),
1277                                          window);
1278         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !show_toolbar);
1279         g_signal_handlers_unblock_by_func (G_OBJECT (action),
1280                                            G_CALLBACK (ephy_window_view_toolbar_cb),
1281                                            window);
1283         action = gtk_action_group_get_action (action_group, "ViewStatusbar");
1284         g_signal_handlers_block_by_func (G_OBJECT (action),
1285                                          G_CALLBACK (ephy_window_view_statusbar_cb),
1286                                          window);
1287         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), show_statusbar);
1288         g_signal_handlers_unblock_by_func (G_OBJECT (action),
1289                                            G_CALLBACK (ephy_window_view_statusbar_cb),
1290                                            window);
1293 static void
1294 setup_ui_manager (EphyWindow *window)
1296         GtkActionGroup *action_group;
1297         GtkAction *action;
1298         GtkUIManager *manager;
1300         window->priv->main_vbox = gtk_vbox_new (FALSE, 0);
1301         gtk_widget_show (window->priv->main_vbox);
1302         gtk_container_add (GTK_CONTAINER (window),
1303                            window->priv->main_vbox);
1305         window->priv->menu_dock = gtk_vbox_new (FALSE, 0);
1306         gtk_widget_show (window->priv->menu_dock);
1307         gtk_box_pack_start (GTK_BOX (window->priv->main_vbox),
1308                             GTK_WIDGET (window->priv->menu_dock),
1309                             FALSE, TRUE, 0);
1311         manager = gtk_ui_manager_new ();
1313         g_signal_connect (manager, "connect_proxy",
1314                           G_CALLBACK (connect_proxy_cb), window);
1315         g_signal_connect (manager, "disconnect_proxy",
1316                           G_CALLBACK (disconnect_proxy_cb), window);
1318         action_group = gtk_action_group_new ("WindowActions");
1319         gtk_action_group_set_translation_domain (action_group, NULL);
1320         gtk_action_group_add_actions (action_group, ephy_menu_entries,
1321                                       G_N_ELEMENTS (ephy_menu_entries), window);
1322         gtk_action_group_add_toggle_actions (action_group,
1323                                              ephy_menu_toggle_entries,
1324                                              G_N_ELEMENTS (ephy_menu_toggle_entries),
1325                                              window);
1326         gtk_ui_manager_insert_action_group (manager, action_group, 0);
1327         window->priv->action_group = action_group;
1328         g_object_unref (action_group);
1330         action = gtk_action_group_get_action (action_group, "FileOpen");
1331         g_object_set (action, "short_label", _("Open"), NULL);
1332         action = gtk_action_group_get_action (action_group, "FileSaveAs");
1333         g_object_set (action, "short_label", _("Save As"), NULL);
1334         action = gtk_action_group_get_action (action_group, "FilePrint");
1335         g_object_set (action, "short_label", _("Print"), NULL);
1336         action = gtk_action_group_get_action (action_group, "FileBookmarkPage");
1337         g_object_set (action, "short_label", _("Bookmark"), NULL);
1338         action = gtk_action_group_get_action (action_group, "EditFind");
1339         g_object_set (action, "short_label", _("Find"), NULL);
1340         action = gtk_action_group_get_action (action_group, "GoBookmarks");
1341         g_object_set (action, "short_label", _("Bookmarks"), NULL);
1343         action = gtk_action_group_get_action (action_group, "EditFind");
1344         g_object_set (action, "is_important", TRUE, NULL);
1345         action = gtk_action_group_get_action (action_group, "GoBookmarks");
1346         g_object_set (action, "is_important", TRUE, NULL);
1348         action = gtk_action_group_get_action (action_group, "ViewEncoding");
1349         g_object_set (action, "hide_if_empty", FALSE, NULL);
1350         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
1351         /* Translators: This refers to text size */
1352         g_object_set (action, "short-label", _("Larger"), NULL);
1353         action = gtk_action_group_get_action (action_group, "ViewZoomOut");
1354         /* Translators: This refers to text size */
1355         g_object_set (action, "short-label", _("Smaller"), NULL);
1357         action_group = gtk_action_group_new ("PopupsActions");
1358         gtk_action_group_set_translation_domain (action_group, NULL);
1359         gtk_action_group_add_actions (action_group, ephy_popups_entries,
1360                                       G_N_ELEMENTS (ephy_popups_entries), window);
1361         gtk_ui_manager_insert_action_group (manager, action_group, 0);
1362         window->priv->popups_action_group = action_group;
1363         g_object_unref (action_group);
1365         window->priv->manager = manager;
1366         g_signal_connect (manager, "add_widget", G_CALLBACK (add_widget), window);
1367         gtk_window_add_accel_group (GTK_WINDOW (window),
1368                                     gtk_ui_manager_get_accel_group (manager));
1371 static void
1372 sync_tab_address (EphyTab *tab,
1373                   GParamSpec *pspec,
1374                   EphyWindow *window)
1376         EphyWindowPrivate *priv = window->priv;
1378         if (priv->closing) return;
1380         ephy_toolbar_set_location (priv->toolbar,
1381                                    ephy_tab_get_address (tab),
1382                                    ephy_tab_get_typed_address (tab));
1383         ephy_find_toolbar_request_close (priv->find_toolbar);
1386 static void
1387 sync_tab_document_type (EphyTab *tab,
1388                         GParamSpec *pspec,
1389                         EphyWindow *window)
1391         EphyWindowPrivate *priv = window->priv;
1392         GtkActionGroup *action_group = priv->action_group;
1393         GtkAction *action;
1394         EphyEmbedDocumentType type;
1395         gboolean can_find, disable, is_image;
1397         if (priv->closing) return;
1399         /* update zoom actions */
1400         sync_tab_zoom (tab, NULL, window);
1401         
1402         type = ephy_tab_get_document_type (tab);
1403         can_find = (type != EPHY_EMBED_DOCUMENT_IMAGE);
1404         is_image = type == EPHY_EMBED_DOCUMENT_IMAGE;
1405         disable = (type != EPHY_EMBED_DOCUMENT_HTML);
1407         action = gtk_action_group_get_action (action_group, "ViewEncoding");
1408         ephy_action_change_sensitivity_flags (action, SENS_FLAG_DOCUMENT, disable);
1409         action = gtk_action_group_get_action (action_group, "ViewPageSource");
1410         ephy_action_change_sensitivity_flags (action, SENS_FLAG_DOCUMENT, is_image);
1411         action = gtk_action_group_get_action (action_group, "EditFind");
1412         ephy_action_change_sensitivity_flags (action, SENS_FLAG_DOCUMENT, !can_find);
1413         action = gtk_action_group_get_action (action_group, "EditFindNext");
1414         ephy_action_change_sensitivity_flags (action, SENS_FLAG_DOCUMENT, !can_find);
1415         action = gtk_action_group_get_action (action_group, "EditFindPrev");
1416         ephy_action_change_sensitivity_flags (action, SENS_FLAG_DOCUMENT, !can_find);
1418         if (!can_find)
1419         {
1420                 ephy_find_toolbar_request_close (priv->find_toolbar);
1421         }
1424 static void
1425 sync_tab_icon (EphyTab *tab,
1426                GParamSpec *pspec,
1427                EphyWindow *window)
1429         EphyWindowPrivate *priv = window->priv;
1430         GdkPixbuf *icon;
1432         if (priv->closing) return;
1434         icon = ephy_tab_get_icon (tab);
1436         ephy_toolbar_set_favicon (priv->toolbar, icon);
1439 static void
1440 sync_tab_load_progress (EphyTab *tab, GParamSpec *pspec, EphyWindow *window)
1442         if (window->priv->closing) return;
1444         ephy_statusbar_set_progress (EPHY_STATUSBAR (window->priv->statusbar),
1445                                      ephy_tab_get_load_percent (tab));
1448 static void
1449 sync_tab_message (EphyTab *tab, GParamSpec *pspec, EphyWindow *window)
1451         GtkStatusbar *s = GTK_STATUSBAR (window->priv->statusbar);
1452         const char *message;
1454         if (window->priv->closing) return;
1456         message = ephy_tab_get_status_message (tab);
1458         gtk_statusbar_pop (s, window->priv->tab_message_cid);
1460         if (message)
1461         {
1462                 gtk_statusbar_push (s, window->priv->tab_message_cid, message);
1463         }
1466 static void
1467 sync_tab_navigation (EphyTab *tab,
1468                      GParamSpec *pspec,
1469                      EphyWindow *window)
1471         EphyTabNavigationFlags flags;
1472         gboolean up = FALSE, back = FALSE, forward = FALSE;
1474         if (window->priv->closing) return;
1476         flags = ephy_tab_get_navigation_flags (tab);
1478         if (flags & EPHY_TAB_NAV_UP)
1479         {
1480                 up = TRUE;
1481         }
1482         if (flags & EPHY_TAB_NAV_BACK)
1483         {
1484                 back = TRUE;
1485         }
1486         if (flags & EPHY_TAB_NAV_FORWARD)
1487         {
1488                 forward = TRUE;
1489         }
1491         ephy_toolbar_set_navigation_actions (window->priv->toolbar,
1492                                              back, forward, up);
1495 static void
1496 sync_tab_security (EphyTab *tab,
1497                    GParamSpec *pspec,
1498                    EphyWindow *window)
1500         EphyWindowPrivate *priv = window->priv;
1501         EphyEmbed *embed;
1502         EphyEmbedSecurityLevel level;
1503         char *description = NULL;
1504         char *state = NULL;
1505         char *tooltip;
1506         const char *stock_id = STOCK_LOCK_INSECURE;
1507         gboolean show_lock = FALSE, is_secure = FALSE;
1508         GtkAction *action;
1510         if (priv->closing) return;
1512         embed = ephy_tab_get_embed (tab);
1514         ephy_embed_get_security_level (embed, &level, &description);
1516         switch (level)
1517         {
1518                 case EPHY_EMBED_STATE_IS_UNKNOWN:
1519                         state = _("Unknown");
1520                         break;
1521                 case EPHY_EMBED_STATE_IS_INSECURE:
1522                         state = _("Insecure");
1523                         g_free (description);
1524                         description = NULL;
1525                         break;
1526                 case EPHY_EMBED_STATE_IS_BROKEN:
1527                         state = _("Broken");
1528                         stock_id = STOCK_LOCK_BROKEN;
1529                         show_lock = TRUE;
1531 #ifndef HAVE_GECKO_1_8_1
1532                         /* In Gecko 1.8.1/1.9, we get a useful tooltip here */
1533                         g_free (description);
1534                         description = NULL;
1535 #endif
1536                         break;
1537                 case EPHY_EMBED_STATE_IS_SECURE_LOW:
1538                 case EPHY_EMBED_STATE_IS_SECURE_MED:
1539                         state = _("Low");
1540                         /* We deliberately don't show the 'secure' icon
1541                          * for low & medium secure sites; see bug #151709.
1542                          */
1543                         stock_id = STOCK_LOCK_INSECURE;
1544                         break;
1545                 case EPHY_EMBED_STATE_IS_SECURE_HIGH:
1546                         state = _("High");
1547                         stock_id = STOCK_LOCK_SECURE;
1548                         show_lock = TRUE;
1549                         is_secure = TRUE;
1550                         break;
1551                 default:
1552                         g_assert_not_reached ();
1553                         break;
1554         }
1556         tooltip = g_strdup_printf (_("Security level: %s"), state);
1557         if (description != NULL)
1558         {
1559                 char *tmp = tooltip;
1561                 tooltip = g_strconcat (tmp, "\n", description, NULL);
1562                 g_free (description);
1563                 g_free (tmp);
1564         }
1566         ephy_statusbar_set_security_state (EPHY_STATUSBAR (priv->statusbar),
1567                                            stock_id, tooltip);
1569         ephy_toolbar_set_security_state (priv->toolbar, is_secure,
1570                                          show_lock, stock_id, tooltip);
1572         if (priv->fullscreen_popup != NULL)
1573         {
1574                 ephy_fullscreen_popup_set_security_state
1575                         (EPHY_FULLSCREEN_POPUP (priv->fullscreen_popup),
1576                          show_lock, stock_id, tooltip);
1577         }
1579         action = gtk_action_group_get_action (priv->action_group, "ViewPageSecurityInfo");
1580         gtk_action_set_sensitive (action, is_secure);
1582         g_free (tooltip);
1585 static void
1586 sync_tab_popup_windows (EphyTab *tab,
1587                         GParamSpec *pspec,
1588                         EphyWindow *window)
1590         guint num_popups = 0;
1591         char *tooltip = NULL;
1593         g_object_get (G_OBJECT (tab),
1594                       "hidden-popup-count", &num_popups,
1595                       NULL);
1597         if (num_popups > 0)
1598         {
1599                 tooltip = g_strdup_printf (ngettext ("%d hidden popup window",
1600                                                      "%d hidden popup windows",
1601                                                      num_popups),
1602                                            num_popups);
1603         }
1605         ephy_statusbar_set_popups_state
1606                 (EPHY_STATUSBAR (window->priv->statusbar),
1607                  tooltip == NULL,
1608                  tooltip);
1610         g_free (tooltip);
1613 static void
1614 sync_tab_popups_allowed (EphyTab *tab,
1615                          GParamSpec *pspec,
1616                          EphyWindow *window)
1618         GtkAction *action;
1619         gboolean allow;
1621         g_return_if_fail (EPHY_IS_TAB (tab));
1622         g_return_if_fail (EPHY_IS_WINDOW (window));
1624         action = gtk_action_group_get_action (window->priv->action_group,
1625                                               "ViewPopupWindows");
1626         g_return_if_fail (GTK_IS_ACTION (action));
1628         g_object_get (G_OBJECT (tab), "popups-allowed", &allow, NULL);
1630         g_signal_handlers_block_by_func
1631                 (G_OBJECT (action),
1632                  G_CALLBACK (ephy_window_view_popup_windows_cb),
1633                  window);
1635         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), allow);
1637         g_signal_handlers_unblock_by_func
1638                 (G_OBJECT (action),
1639                  G_CALLBACK (ephy_window_view_popup_windows_cb),
1640                  window);
1643 static void
1644 sync_tab_load_status (EphyTab *tab,
1645                       GParamSpec *pspec,
1646                       EphyWindow *window)
1648         EphyWindowPrivate *priv = window->priv;
1649         GtkActionGroup *action_group = priv->action_group;
1650         GtkAction *action;
1651         gboolean loading;
1653         if (window->priv->closing) return;
1655         loading = ephy_tab_get_load_status (tab);
1657         action = gtk_action_group_get_action (action_group, "ViewStop");
1658         gtk_action_set_sensitive (action, loading);
1660         /* disable print while loading, see bug #116344 */
1661         action = gtk_action_group_get_action (action_group, "FilePrintPreview");
1662         ephy_action_change_sensitivity_flags (action, SENS_FLAG_LOADING, loading);
1663         action = gtk_action_group_get_action (action_group, "FilePrint");
1664         ephy_action_change_sensitivity_flags (action, SENS_FLAG_LOADING, loading);
1666         ephy_toolbar_set_spinning (priv->toolbar, loading);
1668         if (priv->fullscreen_popup)
1669         {
1670                 ephy_fullscreen_popup_set_spinning
1671                          (EPHY_FULLSCREEN_POPUP (priv->fullscreen_popup),
1672                           loading);
1673         }
1676 static void
1677 sync_tab_title (EphyTab *tab,
1678                 GParamSpec *pspec,
1679                 EphyWindow *window)
1681         EphyWindowPrivate *priv = window->priv;
1683         if (priv->closing) return;
1685         gtk_window_set_title (GTK_WINDOW(window),
1686                               ephy_tab_get_title_composite (tab));
1689 static void
1690 sync_tab_visibility (EphyTab *tab,
1691                      GParamSpec *pspec,
1692                      EphyWindow *window)
1694         EphyWindowPrivate *priv = window->priv;
1695         GList *l, *tabs;
1696         gboolean visible = FALSE;
1698         if (priv->closing) return;
1700         tabs = ephy_window_get_tabs (window);
1701         for (l = tabs; l != NULL; l = l->next)
1702         {
1703                 EphyTab *tab = EPHY_TAB(l->data);
1704                 g_return_if_fail (EPHY_IS_TAB(tab));
1706                 if (ephy_tab_get_visibility (tab))
1707                 {
1708                         visible = TRUE;
1709                         break;
1710                 }
1711         }
1712         g_list_free (tabs);
1714         g_object_set (window, "visible", visible, NULL);
1717 static void
1718 sync_tab_zoom (EphyTab *tab, GParamSpec *pspec, EphyWindow *window)
1720         GtkActionGroup *action_group;
1721         GtkAction *action;
1722         EphyEmbedDocumentType type;
1723         gboolean can_zoom_in = TRUE, can_zoom_out = TRUE, can_zoom_normal = FALSE, can_zoom;
1724         float zoom;
1726         if (window->priv->closing) return;
1728         zoom = ephy_tab_get_zoom (tab);
1729         type = ephy_tab_get_document_type (tab);
1730         can_zoom = (type != EPHY_EMBED_DOCUMENT_IMAGE);
1732         if (zoom >= ZOOM_MAXIMAL)
1733         {
1734                 can_zoom_in = FALSE;
1735         }
1736         if (zoom <= ZOOM_MINIMAL)
1737         {
1738                 can_zoom_out = FALSE;
1739         }
1740         if (zoom != 1.0)
1741         {
1742                 can_zoom_normal = TRUE;
1743         }
1745         ephy_toolbar_set_zoom (window->priv->toolbar, can_zoom, zoom);
1747         action_group = window->priv->action_group;
1748         action = gtk_action_group_get_action (action_group, "ViewZoomIn");
1749         gtk_action_set_sensitive (action, can_zoom_in && can_zoom);
1750         action = gtk_action_group_get_action (action_group, "ViewZoomOut");
1751         gtk_action_set_sensitive (action, can_zoom_out && can_zoom);
1752         action = gtk_action_group_get_action (action_group, "ViewZoomNormal");
1753         gtk_action_set_sensitive (action, can_zoom_normal && can_zoom);
1756 static void
1757 sync_network_status (EphyEmbedSingle *single,
1758                      GParamSpec *pspec,
1759                      EphyWindow *window)
1761         EphyWindowPrivate *priv = window->priv;
1762         GtkAction *action;
1763         gboolean is_online;
1765         is_online = ephy_embed_single_get_network_status (single);
1767         action = gtk_action_group_get_action (priv->action_group,
1768                                               "FileWorkOffline");
1769         g_signal_handlers_block_by_func
1770                 (action, G_CALLBACK (window_cmd_file_work_offline), window);
1771         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !is_online);
1772         g_signal_handlers_unblock_by_func
1773                 (action, G_CALLBACK (window_cmd_file_work_offline), window);    
1776 static void
1777 popup_menu_at_coords (GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
1778                       gpointer user_data)
1780         EphyWindow *window = EPHY_WINDOW (user_data);
1781         EphyWindowPrivate *priv = window->priv;
1782         guint ux, uy;
1784         g_return_if_fail (priv->context_event != NULL);
1786         ephy_embed_event_get_coords (priv->context_event, &ux, &uy);
1787         *x = ux; *y = uy;
1789         /* FIXME: better position the popup within the window bounds? */
1790         ephy_gui_sanitise_popup_position (menu, GTK_WIDGET (window), x, y);
1792         *push_in = TRUE;
1795 static gboolean
1796 idle_unref_context_event (EphyWindow *window)
1798         EphyWindowPrivate *priv = window->priv;
1800         LOG ("Idle unreffing context event %p", priv->context_event);
1802         if (priv->context_event != NULL)
1803         {
1804                 g_object_unref (priv->context_event);
1805                 priv->context_event = NULL;
1806         }
1808         priv->idle_worker = 0;
1809         return FALSE;
1812 void
1813 _ephy_window_set_context_event (EphyWindow *window,
1814                                 EphyEmbedEvent *event)
1816         EphyWindowPrivate *priv = window->priv;
1818         if (priv->idle_worker != 0)
1819         {
1820                 g_source_remove (priv->idle_worker);
1821                 priv->idle_worker = 0;
1822         }
1824         if (priv->context_event != NULL)
1825         {
1826                 g_object_unref (priv->context_event);
1827         }
1829         priv->context_event = event != NULL ? g_object_ref (event) : NULL;
1832 void
1833 _ephy_window_unset_context_event (EphyWindow *window)
1835         EphyWindowPrivate *priv = window->priv;
1837         /* Unref the event from idle since we still need it
1838          * from the action callbacks which will run before idle.
1839          */
1840         if (priv->idle_worker == 0 && priv->context_event != NULL)
1841         {
1842                 priv->idle_worker =
1843                         g_idle_add ((GSourceFunc) idle_unref_context_event, window);
1844         }
1847 static void
1848 embed_popup_deactivate_cb (GtkWidget *popup,
1849                            EphyWindow *window)
1851         LOG ("Deactivating popup menu");
1853         enable_edit_actions_sensitivity (window);
1855         g_signal_handlers_disconnect_by_func
1856                 (popup, G_CALLBACK (embed_popup_deactivate_cb), window);
1858         _ephy_window_unset_context_event (window);
1861 static char *
1862 get_name_from_address_value (const GValue *value)
1864         GnomeVFSURI *uri;
1865         char *name = NULL;
1867         uri = gnome_vfs_uri_new (g_value_get_string (value));
1868         if (uri)
1869         {
1870                 name = gnome_vfs_uri_extract_short_name (uri);
1871                 gnome_vfs_uri_unref (uri);
1872         }
1874         return name != NULL ? name : g_strdup ("");
1877 static void
1878 update_popups_tooltips (EphyWindow *window, EphyEmbedEvent *event)
1880         EphyEmbedEventContext context;
1881         GtkActionGroup *group = window->priv->popups_action_group;
1882         const GValue *value;
1883         GtkAction *action;
1884         char *tooltip, *name;
1886         context = ephy_embed_event_get_context (event);
1888         if (context & EPHY_EMBED_CONTEXT_IMAGE)
1889         {
1890                 value = ephy_embed_event_get_property (event, "image");
1891                 name = get_name_from_address_value (value);
1893                 action = gtk_action_group_get_action (group, "OpenImage");
1894                 tooltip = g_strdup_printf (_("Open image “%s”"), name);
1895                 g_object_set (action, "tooltip", tooltip, NULL);
1896                 g_free (tooltip);
1898                 action = gtk_action_group_get_action (group, "SetImageAsBackground");
1899                 tooltip = g_strdup_printf (_("Use as desktop background “%s”"), name);
1900                 g_object_set (action, "tooltip", tooltip, NULL);
1901                 g_free (tooltip);
1903                 action = gtk_action_group_get_action (group, "SaveImageAs");
1904                 tooltip = g_strdup_printf (_("Save image “%s”"), name);
1905                 g_object_set (action, "tooltip", tooltip, NULL);
1906                 g_free (tooltip);
1908                 action = gtk_action_group_get_action (group, "CopyImageLocation");
1909                 tooltip = g_strdup_printf (_("Copy image address “%s”"),
1910                                            g_value_get_string (value));
1911                 g_object_set (action, "tooltip", tooltip, NULL);
1912                 g_free (tooltip);               
1914                 g_free (name);
1915         }
1917         if (context & EPHY_EMBED_CONTEXT_EMAIL_LINK)
1918         {
1919                 value = ephy_embed_event_get_property (event, "link");
1921                 action = gtk_action_group_get_action (group, "SendEmail");
1922                 tooltip = g_strdup_printf (_("Send email to address “%s”"),
1923                                            g_value_get_string (value));
1924                 g_object_set (action, "tooltip", tooltip, NULL);
1925                 g_free (tooltip);
1927                 action = gtk_action_group_get_action (group, "CopyEmailAddress");
1928                 tooltip = g_strdup_printf (_("Copy email address “%s”"),
1929                                            g_value_get_string (value));
1930                 g_object_set (action, "tooltip", tooltip, NULL);
1931                 g_free (tooltip);
1932         }
1934         if (context & EPHY_EMBED_CONTEXT_LINK)
1935         {
1936                 value = ephy_embed_event_get_property (event, "link");
1938                 action = gtk_action_group_get_action (group, "DownloadLink");
1939                 name = get_name_from_address_value (value);
1940                 tooltip = g_strdup_printf (_("Save link “%s”"), name);
1941                 g_object_set (action, "tooltip", tooltip, NULL);
1942                 g_free (name);
1943                 g_free (tooltip);
1945                 action = gtk_action_group_get_action (group, "BookmarkLink");
1946                 tooltip = g_strdup_printf (_("Bookmark link “%s”"),
1947                                            g_value_get_string (value));
1948                 g_object_set (action, "tooltip", tooltip, NULL);
1949                 g_free (tooltip);
1951                 action = gtk_action_group_get_action (group, "CopyLinkAddress");
1952                 tooltip = g_strdup_printf (_("Copy link's address “%s”"),
1953                                            g_value_get_string (value));
1954                 g_object_set (action, "tooltip", tooltip, NULL);
1955                 g_free (tooltip);
1956         }
1959 static void
1960 show_embed_popup (EphyWindow *window,
1961                   EphyTab *tab,
1962                   EphyEmbedEvent *event)
1964         EphyWindowPrivate *priv = window->priv;
1965         GtkActionGroup *action_group;
1966         GtkAction *action;
1967         EphyEmbedEventContext context;
1968         const char *popup;
1969         const GValue *value;
1970         gboolean framed, can_open_in_new;
1971         GtkWidget *widget;
1972         guint button;
1974         /* Do not show the menu in print preview mode */
1975         if (priv->ppv_mode)
1976         {
1977                 return;
1978         }
1980         value = ephy_embed_event_get_property (event, "framed_page");
1981         framed = g_value_get_int (value);
1983         can_open_in_new = ephy_embed_event_has_property (event, "link-has-web-scheme");
1985         context = ephy_embed_event_get_context (event);
1987         LOG ("show_embed_popup context %x", context);
1989         if (context & EPHY_EMBED_CONTEXT_EMAIL_LINK)
1990         {
1991                 popup = "/EphyEmailLinkPopup";
1992                 update_edit_actions_sensitivity (window, TRUE);
1993         }
1994         else if (context & EPHY_EMBED_CONTEXT_LINK)
1995         {
1996                 popup = "/EphyLinkPopup";
1997                 update_edit_actions_sensitivity (window, TRUE);
1998         }
1999         else if (context & EPHY_EMBED_CONTEXT_INPUT)
2000         {
2001                 popup = "/EphyInputPopup";
2002                 update_edit_actions_sensitivity (window, FALSE);
2003         }
2004         else
2005         {
2006                 popup = "/EphyDocumentPopup";
2007                 update_edit_actions_sensitivity (window, TRUE);
2008         }
2010         update_popups_tooltips (window, event);
2012         widget = gtk_ui_manager_get_widget (priv->manager, popup);
2013         g_return_if_fail (widget != NULL);
2015         action_group = window->priv->popups_action_group;
2017         action = gtk_action_group_get_action (action_group, "OpenLinkInNewWindow");
2018         gtk_action_set_sensitive (action, can_open_in_new);
2020         action = gtk_action_group_get_action (action_group, "OpenLinkInNewTab");
2021         ephy_action_change_sensitivity_flags (action, SENS_FLAG_CONTEXT, !can_open_in_new);
2023         
2024         update_popup_actions_visibility (window,
2025                                          context & EPHY_EMBED_CONTEXT_IMAGE,
2026                                          framed);
2028         _ephy_window_set_context_event (window, event);
2030         g_signal_connect (widget, "deactivate",
2031                           G_CALLBACK (embed_popup_deactivate_cb), window);
2033         button = ephy_embed_event_get_button (event);
2035         if (button == 0)
2036         {
2037                 gtk_menu_popup (GTK_MENU (widget), NULL, NULL,
2038                                 popup_menu_at_coords, window, 0,
2039                                 gtk_get_current_event_time ());
2040                 gtk_menu_shell_select_first (GTK_MENU_SHELL (widget), FALSE);
2041         }
2042         else
2043         {
2044                 gtk_menu_popup (GTK_MENU (widget), NULL, NULL,
2045                                 NULL, NULL, button,
2046                                 gtk_get_current_event_time ());
2047         }
2050 static gboolean
2051 tab_context_menu_cb (EphyEmbed *embed,
2052                      EphyEmbedEvent *event,
2053                      EphyWindow *window)
2055         EphyTab *tab;
2057         tab = ephy_tab_for_embed (embed);
2058         g_return_val_if_fail (EPHY_IS_TAB (tab), FALSE);
2059         g_return_val_if_fail (window->priv->active_tab == tab, FALSE);
2061         show_embed_popup (window, tab, event);
2063         return TRUE;
2066 static gboolean
2067 let_me_resize_hack (EphyWindow *window)
2069         EphyWindowPrivate *priv = window->priv;
2071         gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
2073         priv->idle_resize_handler = 0;
2074         return FALSE;
2077 static void
2078 tab_size_to_cb (EphyEmbed *embed,
2079                 int width,
2080                 int height,
2081                 EphyWindow *window)
2083         EphyWindowPrivate *priv = window->priv;
2084         GtkWidget *widget = GTK_WIDGET (window);
2085         GtkWidget *embed_widget = GTK_WIDGET (embed);
2086         GdkScreen *screen;
2087         EphyTab *tab;
2088         GdkRectangle rect;
2089         int monitor;
2090         int ww, wh, ew, eh, dw, dh;
2092         LOG ("tab_size_to_cb window %p embed %p width %d height %d", window, embed, width, height);
2094         tab = ephy_tab_for_embed (embed);
2095         g_return_if_fail (tab != NULL);
2097         /* FIXME: allow sizing also for non-popup single-tab windows? */
2098         if (tab != ephy_window_get_active_tab (window) || !priv->is_popup) return;
2100         /* contrain size so that the window will be fully contained within the screen */
2101         screen = gtk_widget_get_screen (widget);
2102         monitor = gdk_screen_get_monitor_at_window (screen, widget->window);
2103         gdk_screen_get_monitor_geometry (screen, monitor, &rect);
2104         /* FIXME: get and subtract the panel size */
2106         gtk_window_get_size (GTK_WINDOW (window), &ww, &wh);
2108         ew = embed_widget->allocation.width;
2109         eh = embed_widget->allocation.height;
2111         /* This should approximate the chrome extent */
2112         dw = ww - ew; dw = MAX (dw, 0); dw = MIN (dw, rect.width - 1);
2113         dh = wh - eh; dh = MAX (dh, 0); dh = MIN (dh, rect.height - 1);
2115         width = MIN (rect.width - dw, width);
2116         height = MIN (rect.height - dh, height);
2118         /* FIXME: move window if this will place it partially outside the screen rect? */
2120         gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
2121         ephy_tab_set_size (tab, width, height);
2123         if (priv->idle_resize_handler == 0)
2124         {
2125                 priv->idle_resize_handler =
2126                         g_idle_add ((GSourceFunc) let_me_resize_hack, window);
2127         }
2130 static void
2131 ephy_window_set_active_tab (EphyWindow *window, EphyTab *new_tab)
2133         EphyTab *old_tab;
2134         EphyEmbed *embed;
2136         g_return_if_fail (EPHY_IS_WINDOW (window));
2137         g_return_if_fail (gtk_widget_get_toplevel (GTK_WIDGET (new_tab)) == GTK_WIDGET (window));
2139         old_tab = window->priv->active_tab;
2141         if (old_tab == new_tab) return;
2143         if (old_tab != NULL)
2144         {
2145                 g_signal_handlers_disconnect_by_func (old_tab,
2146                                                       G_CALLBACK (sync_tab_address),
2147                                                       window);
2148                 g_signal_handlers_disconnect_by_func (old_tab,
2149                                                       G_CALLBACK (sync_tab_document_type),
2150                                                       window);
2151                 g_signal_handlers_disconnect_by_func (old_tab,
2152                                                       G_CALLBACK (sync_tab_icon),
2153                                                       window);
2154                 g_signal_handlers_disconnect_by_func (old_tab,
2155                                                       G_CALLBACK (sync_tab_load_progress),
2156                                                       window);
2157                 g_signal_handlers_disconnect_by_func (old_tab,
2158                                                       G_CALLBACK (sync_tab_load_status),
2159                                                       window);
2160                 g_signal_handlers_disconnect_by_func (old_tab,
2161                                                       G_CALLBACK (sync_tab_message),
2162                                                       window);
2163                 g_signal_handlers_disconnect_by_func (old_tab,
2164                                                       G_CALLBACK (sync_tab_navigation),
2165                                                       window);
2166                 g_signal_handlers_disconnect_by_func (old_tab,
2167                                                       G_CALLBACK (sync_tab_security),
2168                                                       window);
2169                 g_signal_handlers_disconnect_by_func (old_tab,
2170                                                       G_CALLBACK (sync_tab_popup_windows),
2171                                                       window);
2172                 g_signal_handlers_disconnect_by_func (old_tab,
2173                                                       G_CALLBACK (sync_tab_popups_allowed),
2174                                                       window);
2175                 g_signal_handlers_disconnect_by_func (old_tab,
2176                                                       G_CALLBACK (sync_tab_title),
2177                                                       window);
2178                 g_signal_handlers_disconnect_by_func (old_tab,
2179                                                       G_CALLBACK (sync_tab_zoom),
2180                                                       window);
2182                 embed = ephy_tab_get_embed (old_tab);
2183                 g_signal_handlers_disconnect_by_func
2184                         (embed, G_CALLBACK (tab_context_menu_cb), window);
2185                 g_signal_handlers_disconnect_by_func
2186                         (embed, G_CALLBACK (tab_size_to_cb), window);
2188         }
2190         window->priv->active_tab = new_tab;
2192         if (new_tab != NULL)
2193         {
2194                 sync_tab_address        (new_tab, NULL, window);
2195                 sync_tab_document_type  (new_tab, NULL, window);
2196                 sync_tab_icon           (new_tab, NULL, window);
2197                 sync_tab_load_progress  (new_tab, NULL, window);
2198                 sync_tab_load_status    (new_tab, NULL, window);
2199                 sync_tab_message        (new_tab, NULL, window);
2200                 sync_tab_navigation     (new_tab, NULL, window);
2201                 sync_tab_security       (new_tab, NULL, window);
2202                 sync_tab_popup_windows  (new_tab, NULL, window);
2203                 sync_tab_popups_allowed (new_tab, NULL, window);
2204                 sync_tab_title          (new_tab, NULL, window);
2205                 sync_tab_zoom           (new_tab, NULL, window);
2207                 g_signal_connect_object (new_tab, "notify::address",
2208                                          G_CALLBACK (sync_tab_address),
2209                                          window, 0);
2210                 g_signal_connect_object (new_tab, "notify::document-type",
2211                                          G_CALLBACK (sync_tab_document_type),
2212                                          window, 0);
2213                 g_signal_connect_object (new_tab, "notify::icon",
2214                                          G_CALLBACK (sync_tab_icon),
2215                                          window, 0);
2216                 g_signal_connect_object (new_tab, "notify::load-progress",
2217                                          G_CALLBACK (sync_tab_load_progress),
2218                                          window, 0);
2219                 g_signal_connect_object (new_tab, "notify::load-status",
2220                                          G_CALLBACK (sync_tab_load_status),
2221                                          window, 0);
2222                 g_signal_connect_object (new_tab, "notify::message",
2223                                          G_CALLBACK (sync_tab_message),
2224                                          window, 0);
2225                 g_signal_connect_object (new_tab, "notify::navigation",
2226                                          G_CALLBACK (sync_tab_navigation),
2227                                          window, 0);
2228                 g_signal_connect_object (new_tab, "notify::security-level",
2229                                          G_CALLBACK (sync_tab_security),
2230                                          window, 0);
2231                 g_signal_connect_object (new_tab, "notify::hidden-popup-count",
2232                                          G_CALLBACK (sync_tab_popup_windows),
2233                                          window, 0);
2234                 g_signal_connect_object (new_tab, "notify::popups-allowed",
2235                                          G_CALLBACK (sync_tab_popups_allowed),
2236                                          window, 0);
2237                 g_signal_connect_object (new_tab, "notify::title",
2238                                          G_CALLBACK (sync_tab_title),
2239                                          window, 0);
2240                 g_signal_connect_object (new_tab, "notify::zoom",
2241                                          G_CALLBACK (sync_tab_zoom),
2242                                          window, 0);
2244                 embed = ephy_tab_get_embed (new_tab);
2245                 g_signal_connect_object (embed, "ge-context-menu",
2246                                          G_CALLBACK (tab_context_menu_cb),
2247                                          window, G_CONNECT_AFTER);
2248                 g_signal_connect_object (embed, "size-to",
2249                                          G_CALLBACK (tab_size_to_cb),
2250                                          window, 0);
2252                 g_object_notify (G_OBJECT (window), "active-tab");
2253         }
2256 static void
2257 update_tabs_menu_sensitivity (EphyWindow *window)
2259         EphyWindowPrivate *priv = window->priv;
2260         GtkActionGroup *action_group;
2261         GtkAction *action;
2262         GtkNotebook *notebook;
2263         int page, n_pages;
2264         gboolean not_first, not_last;
2266         notebook = GTK_NOTEBOOK (priv->notebook);
2267         page = gtk_notebook_get_current_page (notebook);
2268         n_pages = gtk_notebook_get_n_pages (notebook);
2269         not_first = page > 0;
2270         not_last = page + 1 < n_pages;
2272         action_group = priv->action_group;
2273         action = gtk_action_group_get_action (action_group, "TabsPrevious");
2274         gtk_action_set_sensitive (action, not_first);
2275         action = gtk_action_group_get_action (action_group, "TabsNext");
2276         gtk_action_set_sensitive (action, not_last);
2277         action = gtk_action_group_get_action (action_group, "TabsMoveLeft");
2278         gtk_action_set_sensitive (action, not_first);
2279         action = gtk_action_group_get_action (action_group, "TabsMoveRight");
2280         gtk_action_set_sensitive (action, not_last);
2283 static gboolean
2284 embed_modal_alert_cb (EphyEmbed *embed,
2285                       EphyWindow *window)
2287         EphyWindowPrivate *priv = window->priv;
2288         EphyTab *tab;
2289         const char *address;
2291         tab = ephy_tab_for_embed (embed);
2292         g_return_val_if_fail (tab != NULL, FALSE);
2294         /* if we're in ppv mode, we cannot switch tabs, so inhibit the alert */
2295         if (priv->ppv_mode) return TRUE;
2297         /* switch the window to the tab, and bring the window to the foreground
2298          * (since the alert is modal, the user won't be able to do anything
2299          * with his current window anyway :|)
2300          */
2301         ephy_window_jump_to_tab (window, tab);
2302         gtk_window_present (GTK_WINDOW (window));
2304         /* make sure the location entry shows the real URL of the tab's page */
2305         address = ephy_tab_get_address (tab);
2306         ephy_toolbar_set_location (priv->toolbar, address, NULL);
2308         /* don't suppress alert */
2309         return FALSE;
2312 static gboolean
2313 idle_tab_remove_cb (GtkWidget *tab)
2315         GtkWidget *toplevel;
2316         EphyWindow *window;
2317         EphyWindowPrivate *priv;
2318         GtkNotebook *notebook;
2319         int position;
2321         toplevel = gtk_widget_get_toplevel (tab);
2322         if (!EPHY_IS_WINDOW (toplevel)) return FALSE; /* FIXME should this ever occur? */
2324         window = EPHY_WINDOW (toplevel);
2325         priv = window->priv;
2327         if (priv->closing) return FALSE;
2329         g_hash_table_remove (priv->tabs_to_remove, tab);
2331         notebook = GTK_NOTEBOOK (ephy_window_get_notebook (window));
2333         position = gtk_notebook_page_num (notebook, tab);
2334         gtk_notebook_remove_page (notebook, position);
2336         /* don't run again */
2337         return FALSE;
2340 static void
2341 schedule_tab_close (EphyWindow *window,
2342                     EphyEmbed *embed)
2344         EphyWindowPrivate *priv = window->priv;
2345         EphyTab *tab;
2346         guint id;
2348         LOG ("scheduling close of embed %p in window %p", embed, window);
2350         if (priv->closing) return;
2352         tab = ephy_tab_for_embed (embed);
2353         g_return_if_fail (tab != NULL);
2355         if (g_hash_table_lookup (priv->tabs_to_remove, tab) != NULL) return;
2357         /* do this on idle, because otherwise we'll crash in certain circumstances
2358         * (see galeon bug #116256)
2359         */
2360         id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2361                               (GSourceFunc) idle_tab_remove_cb,
2362                               tab, NULL);
2364         g_hash_table_insert (priv->tabs_to_remove, tab, GUINT_TO_POINTER (id));
2366         /* don't wait until idle to hide the window */
2367         if (g_hash_table_size (priv->tabs_to_remove) == priv->num_tabs)
2368         {
2369                 gtk_widget_hide (GTK_WIDGET (window));
2370         }
2373 static gboolean
2374 embed_close_request_cb (EphyEmbed *embed,
2375                         EphyWindow *window)
2377         LOG ("embed_close_request_cb embed %p window %p", embed, window);
2379         schedule_tab_close (window, embed);
2381         /* handled */
2382         return TRUE;
2385 static void
2386 embed_destroy_browser_cb (EphyEmbed *embed,
2387                           EphyWindow *window)
2389         g_return_if_reached ();
2392 static gboolean
2393 show_notebook_popup_menu (GtkNotebook *notebook,
2394                           EphyWindow *window,
2395                           GdkEventButton *event)
2397         GtkWidget *menu, *tab, *tab_label;
2398         GtkAction *action;
2400         menu = gtk_ui_manager_get_widget (window->priv->manager, "/EphyNotebookPopup");
2401         g_return_val_if_fail (menu != NULL, FALSE);
2403         /* allow extensions to sync when showing the popup */
2404         action = gtk_action_group_get_action (window->priv->action_group,
2405                                               "NotebookPopupAction");
2406         g_return_val_if_fail (action != NULL, FALSE);
2407         gtk_action_activate (action);
2409         if (event != NULL)
2410         {
2411                 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
2412                                 NULL, NULL,
2413                                 event->button, event->time);
2414         }
2415         else
2416         {
2417                 tab = GTK_WIDGET (ephy_window_get_active_tab (window));
2418                 tab_label = gtk_notebook_get_tab_label (notebook, tab);
2420                 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
2421                                 ephy_gui_menu_position_under_widget, tab_label,
2422                                 0, gtk_get_current_event_time ());
2423                 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
2424         }
2426         return TRUE;
2429 static gboolean
2430 notebook_button_press_cb (GtkNotebook *notebook,
2431                           GdkEventButton *event,
2432                           EphyWindow *window)
2434         if (GDK_BUTTON_PRESS == event->type && 3 == event->button)
2435         {
2436                 return show_notebook_popup_menu (notebook, window, event);
2437         }
2439         return FALSE;
2442 static gboolean
2443 notebook_popup_menu_cb (GtkNotebook *notebook,
2444                         EphyWindow *window)
2446         /* Only respond if the notebook is the actual focus */
2447         if (EPHY_IS_NOTEBOOK (gtk_window_get_focus (GTK_WINDOW (window))))
2448         {
2449                 return show_notebook_popup_menu (notebook, window, NULL);
2450         }
2452         return FALSE;
2455 static void
2456 notebook_page_added_cb (EphyNotebook *notebook,
2457                         EphyTab *tab,
2458                         guint position,
2459                         EphyWindow *window)
2461         EphyWindowPrivate *priv = window->priv;
2462         EphyExtension *manager;
2463         EphyEmbed *embed;
2465         LOG ("page-added   notebook %p tab %p position %u\n", notebook, tab, position);
2467         g_return_if_fail (EPHY_IS_TAB (tab));
2469         priv->num_tabs++;
2471         update_tabs_menu_sensitivity (window);
2473         g_signal_connect_object (tab, "notify::visibility",
2474                                  G_CALLBACK (sync_tab_visibility), window, 0);
2475         g_signal_connect_object (tab, "open-link",
2476                                  G_CALLBACK (ephy_link_open), window,
2477                                  G_CONNECT_SWAPPED);
2479         embed = ephy_tab_get_embed (tab);
2480         g_return_if_fail (embed != NULL);
2482         g_signal_connect_object (embed, "close-request",
2483                                  G_CALLBACK (embed_close_request_cb),
2484                                  window, 0);
2485         g_signal_connect_object (embed, "destroy-browser",
2486                                  G_CALLBACK (embed_destroy_browser_cb),
2487                                  window, 0);
2488         g_signal_connect_object (embed, "ge-modal-alert",
2489                                  G_CALLBACK (embed_modal_alert_cb), window, G_CONNECT_AFTER);
2491         /* Let the extensions attach themselves to the tab */
2492         manager = EPHY_EXTENSION (ephy_shell_get_extensions_manager (ephy_shell));
2493         ephy_extension_attach_tab (manager, window, tab);
2496 static void
2497 notebook_page_removed_cb (EphyNotebook *notebook,
2498                           EphyTab *tab,
2499                           guint position,
2500                           EphyWindow *window)
2502         EphyWindowPrivate *priv = window->priv;
2503         EphyExtension *manager;
2504         EphyEmbed *embed;
2506         LOG ("page-removed notebook %p tab %p position %u\n", notebook, tab, position);
2508         if (priv->closing) return;
2510         g_return_if_fail (EPHY_IS_TAB (tab));
2512         /* Let the extensions remove themselves from the tab */
2513         manager = EPHY_EXTENSION (ephy_shell_get_extensions_manager (ephy_shell));
2514         ephy_extension_detach_tab (manager, window, tab);
2516         g_signal_handlers_disconnect_by_func (G_OBJECT (tab),
2517                                               G_CALLBACK (sync_tab_visibility),
2518                                               window);
2519         g_signal_handlers_disconnect_by_func (G_OBJECT (tab),
2520                                               G_CALLBACK (ephy_link_open),
2521                                               window);  
2523         priv->num_tabs--;
2525         if (priv->num_tabs > 0)
2526         {
2527                 update_tabs_menu_sensitivity (window);
2528         }
2530         embed = ephy_tab_get_embed (tab);
2531         g_return_if_fail (embed != NULL);
2533         g_signal_handlers_disconnect_by_func
2534                 (embed, G_CALLBACK (embed_modal_alert_cb), window);
2535         g_signal_handlers_disconnect_by_func
2536                 (embed, G_CALLBACK (embed_close_request_cb), window);
2537         g_signal_handlers_disconnect_by_func
2538                 (embed, G_CALLBACK (embed_destroy_browser_cb), window);
2541 static void
2542 notebook_page_reordered_cb (EphyNotebook *notebook,
2543                             EphyTab *tab,
2544                             guint position,
2545                             EphyWindow *window)
2547         update_tabs_menu_sensitivity (window);
2550 static void
2551 notebook_page_close_request_cb (EphyNotebook *notebook,
2552                                 EphyTab *tab,
2553                                 EphyWindow *window)
2555         EphyWindowPrivate *priv = window->priv;
2556         EphyEmbed *embed;
2558         if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_QUIT) &&
2559             gtk_notebook_get_n_pages (priv->notebook) == 1)
2560         {
2561                 return;
2562         }
2564         embed = ephy_tab_get_embed (tab);
2565         g_return_if_fail (embed != NULL);
2567         if (!ephy_embed_has_modified_forms (embed) ||
2568             confirm_close_with_modified_forms (window))
2569         {
2570                 ephy_embed_close (embed);
2571         }
2574 static GtkNotebook *
2575 setup_notebook (EphyWindow *window)
2577         GtkNotebook *notebook;
2579         notebook = GTK_NOTEBOOK (g_object_new (EPHY_TYPE_NOTEBOOK, NULL));
2581         g_signal_connect_after (notebook, "switch-page",
2582                                 G_CALLBACK (notebook_switch_page_cb),
2583                                 window);
2585         g_signal_connect (notebook, "popup-menu",
2586                           G_CALLBACK (notebook_popup_menu_cb), window);
2587         g_signal_connect (notebook, "button-press-event",
2588                           G_CALLBACK (notebook_button_press_cb), window);
2590         g_signal_connect (notebook, "page-added",
2591                           G_CALLBACK (notebook_page_added_cb), window);
2592         g_signal_connect (notebook, "page-removed",
2593                           G_CALLBACK (notebook_page_removed_cb), window);
2594         g_signal_connect (notebook, "page-reordered",
2595                           G_CALLBACK (notebook_page_reordered_cb), window);
2596         g_signal_connect (notebook, "tab-close-request",
2597                           G_CALLBACK (notebook_page_close_request_cb), window);
2599         return notebook;
2602 static void
2603 ephy_window_set_chrome (EphyWindow *window, EphyEmbedChrome mask)
2605         EphyEmbedChrome chrome_mask = mask;
2607         if (mask == EPHY_EMBED_CHROME_ALL)
2608         {
2609                 window->priv->should_save_chrome = TRUE;
2610         }
2612         if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS))
2613         {
2614                 chrome_mask &= ~EPHY_EMBED_CHROME_TOOLBAR;
2615         }
2617         if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR))
2618         {
2619                 chrome_mask &= ~EPHY_EMBED_CHROME_STATUSBAR;
2620         }
2622         if (eel_gconf_get_boolean (CONF_LOCKDOWN_HIDE_MENUBAR))
2623         {
2624                 chrome_mask &= ~EPHY_EMBED_CHROME_MENUBAR;
2625         }
2627         window->priv->chrome = chrome_mask;
2630 static void
2631 ephy_window_set_is_popup (EphyWindow *window,
2632                           gboolean is_popup)
2634         EphyWindowPrivate *priv = window->priv;
2636         priv->is_popup = is_popup;
2638         g_object_notify (G_OBJECT (window), "is-popup");
2641 static gboolean
2642 remove_true (void)
2644         return TRUE;
2647 static void
2648 ephy_window_dispose (GObject *object)
2650         EphyWindow *window = EPHY_WINDOW (object);
2651         EphyWindowPrivate *priv = window->priv;
2652         GObject *single;
2653         GSList *popups;
2655         LOG ("EphyWindow dispose %p", window);
2657         /* Only do these once */
2658         if (window->priv->closing == FALSE)
2659         {
2660                 EphyExtension *manager;
2662                 window->priv->closing = TRUE;
2664                 /* Let the extensions detach themselves from the window */
2665                 manager = EPHY_EXTENSION (ephy_shell_get_extensions_manager (ephy_shell));
2666                 ephy_extension_detach_window (manager, window);
2667                 ephy_bookmarks_ui_detach_window (window);
2669                 /* Deactivate menus */
2670                 popups = gtk_ui_manager_get_toplevels (window->priv->manager, GTK_UI_MANAGER_POPUP);
2671                 g_slist_foreach (popups, (GFunc) gtk_menu_shell_deactivate, NULL);
2672                 g_slist_free (popups);
2673         
2674                 single = ephy_embed_shell_get_embed_single (embed_shell);
2675                 g_signal_handlers_disconnect_by_func
2676                         (single, G_CALLBACK (sync_network_status), window);
2677         
2678                 eel_gconf_notification_remove (priv->browse_with_caret_notifier_id);
2679                 eel_gconf_notification_remove (priv->allow_popups_notifier_id);
2680                 priv->browse_with_caret_notifier_id = 0;
2681                 priv->allow_popups_notifier_id = 0;
2683                 if (priv->idle_resize_handler != 0)
2684                 {
2685                         g_source_remove (priv->idle_resize_handler);
2686                         priv->idle_resize_handler = 0;
2687                 }
2689                 g_hash_table_foreach_remove (priv->tabs_to_remove, (GHRFunc) remove_true, NULL);
2691                 g_object_unref (priv->enc_menu);
2692                 priv->enc_menu = NULL;
2694                 g_object_unref (priv->tabs_menu);
2695                 priv->tabs_menu = NULL;
2697                 if (priv->ppview_toolbar)
2698                 {
2699                         g_object_unref (priv->ppview_toolbar);
2700                         priv->ppview_toolbar = NULL;
2701                 }
2703                 priv->action_group = NULL;
2704                 priv->popups_action_group = NULL;
2706                 g_object_unref (priv->manager);
2707                 priv->manager = NULL;
2709                 _ephy_window_set_context_event (window, NULL);
2710         }
2712         destroy_fullscreen_popup (window);
2714         G_OBJECT_CLASS (parent_class)->dispose (object);
2717 static void
2718 ephy_window_set_property (GObject *object,
2719                           guint prop_id,
2720                           const GValue *value,
2721                           GParamSpec *pspec)
2723         EphyWindow *window = EPHY_WINDOW (object);
2725         switch (prop_id)
2726         {
2727                 case PROP_ACTIVE_TAB:
2728                         ephy_window_set_active_tab (window, g_value_get_object (value));
2729                         break;
2730                 case PROP_CHROME:
2731                         ephy_window_set_chrome (window, g_value_get_flags (value));
2732                         break;
2733                 case PROP_PPV_MODE:
2734                         ephy_window_set_print_preview (window, g_value_get_boolean (value));
2735                         break;
2736                 case PROP_SINGLE_TAB_MODE:
2737                         ephy_window_set_is_popup (window, g_value_get_boolean (value));
2738                         break;
2739         }
2742 static void
2743 ephy_window_get_property (GObject *object,
2744                           guint prop_id,
2745                           GValue *value,
2746                           GParamSpec *pspec)
2748         EphyWindow *window = EPHY_WINDOW (object);
2750         switch (prop_id)
2751         {
2752                 case PROP_ACTIVE_TAB:
2753                         g_value_set_object (value, window->priv->active_tab);
2754                         break;
2755                 case PROP_CHROME:
2756                         g_value_set_flags (value, window->priv->chrome);
2757                         break;
2758                 case PROP_PPV_MODE:
2759                         g_value_set_boolean (value, window->priv->ppv_mode);
2760                         break;
2761                 case PROP_SINGLE_TAB_MODE:
2762                         g_value_set_boolean (value, window->priv->is_popup);
2763                         break;
2764         }
2767 static gboolean
2768 ephy_window_focus_in_event (GtkWidget *widget,
2769                             GdkEventFocus *event)
2771         EphyWindow *window = EPHY_WINDOW (widget);
2772         EphyWindowPrivate *priv = window->priv;
2774         if (priv->fullscreen_popup && !get_toolbar_visibility (window))
2775         {
2776                 gtk_widget_show (priv->fullscreen_popup);
2777         }
2779         return GTK_WIDGET_CLASS (parent_class)->focus_in_event (widget, event);
2782 static gboolean
2783 ephy_window_focus_out_event (GtkWidget *widget,
2784                              GdkEventFocus *event)
2786         EphyWindow *window = EPHY_WINDOW (widget);
2787         EphyWindowPrivate *priv = window->priv;
2789         if (priv->fullscreen_popup)
2790         {
2791                 gtk_widget_hide (priv->fullscreen_popup);
2792         }
2794         return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
2797 static gboolean
2798 ephy_window_state_event (GtkWidget *widget,
2799                          GdkEventWindowState *event)
2801         EphyWindow *window = EPHY_WINDOW (widget);
2802         EphyWindowPrivate *priv = window->priv;
2803         gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *);
2805         window_state_event = GTK_WIDGET_CLASS (parent_class)->window_state_event;
2806         if (window_state_event)
2807         {
2808                 window_state_event (widget, event);
2809         }
2811         if (event->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED))
2812         {
2813                 gboolean show;
2815                 show = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) == 0;
2817                 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (priv->statusbar), show);
2818         }
2820         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
2821         {
2822                 GtkActionGroup *action_group;
2823                 GtkAction *action;
2824                 gboolean fullscreen;
2826                 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
2828                 if (fullscreen)
2829                 {
2830                         ephy_window_fullscreen (window);
2831                 }
2832                 else
2833                 {
2834                         ephy_window_unfullscreen (window);
2835                 }
2837                 action_group = priv->action_group;
2839                 action = gtk_action_group_get_action (action_group, "ViewFullscreen");
2840                 g_signal_handlers_block_by_func
2841                         (action, G_CALLBACK (window_cmd_view_fullscreen), window);
2842                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
2843                 g_signal_handlers_unblock_by_func
2844                         (action, G_CALLBACK (window_cmd_view_fullscreen), window);
2846                 action = gtk_action_group_get_action (action_group, "ViewToolbarEditor");
2847                 ephy_action_change_sensitivity_flags (action, SENS_FLAG_CHROME, fullscreen);
2848         }
2850         return FALSE;
2853 static void
2854 ephy_window_link_iface_init (EphyLinkIface *iface)
2856         iface->open_link = ephy_window_open_link;
2859 static void
2860 ephy_window_class_init (EphyWindowClass *klass)
2862         GObjectClass *object_class = G_OBJECT_CLASS (klass);
2863         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
2865         parent_class = g_type_class_peek_parent (klass);
2867         object_class->constructor = ephy_window_constructor;
2868         object_class->dispose = ephy_window_dispose;
2869         object_class->finalize = ephy_window_finalize;
2870         object_class->get_property = ephy_window_get_property;
2871         object_class->set_property = ephy_window_set_property;
2873         widget_class->show = ephy_window_show;
2874         widget_class->key_press_event = ephy_window_key_press_event;
2875         widget_class->focus_in_event = ephy_window_focus_in_event;
2876         widget_class->focus_out_event = ephy_window_focus_out_event;
2877         widget_class->window_state_event = ephy_window_state_event;
2878         widget_class->delete_event = ephy_window_delete_event;
2880         g_object_class_install_property (object_class,
2881                                          PROP_ACTIVE_TAB,
2882                                          g_param_spec_object ("active-tab",
2883                                                               "active-tab",
2884                                                               "Active tab",
2885                                                               EPHY_TYPE_TAB,
2886                                                               G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
2888         g_object_class_install_property (object_class,
2889                                          PROP_CHROME,
2890                                          g_param_spec_flags ("chrome",
2891                                                              "chrome",
2892                                                              "Window chrome",
2893                                                              EPHY_TYPE_EMBED_CHROME,
2894                                                              EPHY_EMBED_CHROME_ALL,
2895                                                              G_PARAM_CONSTRUCT_ONLY |
2896                                                              G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
2898         g_object_class_install_property (object_class,
2899                                          PROP_PPV_MODE,
2900                                          g_param_spec_boolean ("print-preview-mode",
2901                                                                "Print preview mode",
2902                                                                "Whether the window is in print preview mode",
2903                                                                FALSE,
2904                                                                G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
2906         g_object_class_install_property (object_class,
2907                                          PROP_SINGLE_TAB_MODE,
2908                                          g_param_spec_boolean ("is-popup",
2909                                                                "Is Popup",
2910                                                                "Whether the window is a popup",
2911                                                                FALSE,
2912                                                                G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
2913                                                                G_PARAM_CONSTRUCT_ONLY));
2915         g_type_class_add_private (object_class, sizeof (EphyWindowPrivate));
2918 static void
2919 browse_with_caret_notifier (GConfClient *client,
2920                             guint cnxn_id,
2921                             GConfEntry *entry,
2922                             EphyWindow *window)
2924         EphyWindowPrivate *priv = window->priv;
2925         GtkAction *action;
2926         gboolean enabled;
2928         enabled = eel_gconf_get_boolean (CONF_BROWSE_WITH_CARET);
2929         action = gtk_action_group_get_action (window->priv->action_group,
2930                                               "BrowseWithCaret");
2931         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), enabled);
2933         ephy_statusbar_set_caret_mode (EPHY_STATUSBAR (priv->statusbar), enabled);
2936 static void
2937 allow_popups_notifier (GConfClient *client,
2938                        guint cnxn_id,
2939                        GConfEntry *entry,
2940                        EphyWindow *window)
2942         GList *tabs;
2943         EphyTab *tab;
2945         g_return_if_fail (EPHY_IS_WINDOW (window));
2947         tabs = ephy_window_get_tabs (window);
2949         for (; tabs; tabs = g_list_next (tabs))
2950         {
2951                 tab = EPHY_TAB (tabs->data);
2952                 g_return_if_fail (EPHY_IS_TAB (tab));
2954                 g_object_notify (G_OBJECT (tab), "popups-allowed");
2955         }
2958 static EphyTab *
2959 ephy_window_open_link (EphyLink *link,
2960                        const char *address,
2961                        EphyTab *tab,
2962                        EphyLinkFlags flags)
2964         EphyWindow *window = EPHY_WINDOW (link);
2965         EphyWindowPrivate *priv = window->priv;
2966         EphyTab *new_tab;
2968         g_return_val_if_fail (address != NULL, NULL);
2970         /* don't do anything in ppv mode */
2971         if (window->priv->ppv_mode) return NULL;
2973         if (tab == NULL)
2974         {
2975                 tab = ephy_window_get_active_tab (window);
2976         }
2978         if (flags  & (EPHY_LINK_JUMP_TO | 
2979                       EPHY_LINK_NEW_TAB | 
2980                       EPHY_LINK_NEW_WINDOW))
2981         {
2982                 EphyNewTabFlags ntflags = EPHY_NEW_TAB_OPEN_PAGE;
2984                 if (flags & EPHY_LINK_JUMP_TO)
2985                 {
2986                         ntflags |= EPHY_NEW_TAB_JUMP;
2987                 }
2988                 if (flags & EPHY_LINK_NEW_WINDOW ||
2989                     (flags & EPHY_LINK_NEW_TAB && priv->is_popup))
2990                 {
2991                         ntflags |= EPHY_NEW_TAB_IN_NEW_WINDOW;
2992                 }
2993                 else
2994                 {
2995                         ntflags |= EPHY_NEW_TAB_IN_EXISTING_WINDOW;
2996                 }
2997                 if (flags & EPHY_LINK_ALLOW_FIXUP)
2998                 {
2999                         ntflags |= EPHY_NEW_TAB_ALLOW_FIXUP;
3000                 }
3002                 new_tab = ephy_shell_new_tab
3003                                 (ephy_shell,
3004                                  EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))),
3005                                  tab, address, ntflags);
3006         }
3007         else
3008         {
3009                 EphyEmbed *embed;
3010                 
3011                 embed = ephy_tab_get_embed (tab);
3013                 if (flags & EPHY_LINK_ALLOW_FIXUP)
3014                 {
3015                         ephy_embed_load (embed, 
3016                                          address, 
3017                                          EPHY_EMBED_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP,
3018                                          NULL);
3019                 }
3020                 else
3021                 {
3022                         ephy_embed_load_url (embed, address);
3023                 }
3025                 if (address == NULL || address[0] == '\0' || strcmp (address, "about:blank") == 0)
3026                 {
3027                         ephy_toolbar_activate_location (priv->toolbar);
3028                 }
3029                 else
3030                 {
3031                         gtk_widget_grab_focus (GTK_WIDGET (embed));
3032                 }
3034                 new_tab = tab;
3035         }
3037         return new_tab;
3040 static void
3041 find_toolbar_close_cb (EphyFindToolbar *toolbar,
3042                        EphyWindow *window)
3044         EphyWindowPrivate *priv = window->priv;
3045         EphyTab *tab;
3047         if (priv->closing) return;
3049         ephy_find_toolbar_close (priv->find_toolbar);
3051         tab = ephy_window_get_active_tab (window);
3052         if (tab == NULL) return;
3054         gtk_widget_grab_focus (GTK_WIDGET (tab));
3057 static void
3058 cancel_handler (gpointer idptr)
3060         guint id = GPOINTER_TO_UINT (idptr);
3062         g_source_remove (id);
3065 static void
3066 ephy_window_init (EphyWindow *window)
3068         LOG ("EphyWindow initialising %p", window);
3070         g_object_ref (ephy_shell);
3072         window->priv = EPHY_WINDOW_GET_PRIVATE (window);
3075 static GObject *
3076 ephy_window_constructor (GType type,
3077                          guint n_construct_properties,
3078                          GObjectConstructParam *construct_params)
3080         GObject *object;
3081         EphyWindow *window;
3082         EphyWindowPrivate *priv;
3083         EphyExtension *manager;
3084         EphyEmbedSingle *single;
3085         EggToolbarsModel *model;
3086         GtkSettings *settings;
3087         GtkAction *action;
3088         GtkActionGroup *toolbar_action_group;
3089         GError *error = NULL;
3090         guint settings_connection;
3092         object = parent_class->constructor (type, n_construct_properties,
3093                                             construct_params);
3095         window = EPHY_WINDOW (object);
3097         priv = window->priv;
3099         priv->tabs_to_remove = g_hash_table_new_full (g_direct_hash, g_direct_equal,
3100                                                               NULL, cancel_handler);
3102         ephy_gui_ensure_window_group (GTK_WINDOW (window));
3104         /* initialize the listener for the key theme
3105          * FIXME: Need to handle multi-head and migration.
3106          */
3107         settings = gtk_settings_get_default ();
3108         settings_connection = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings),
3109                                                                    SETTINGS_CONNECTION_DATA_KEY));
3110         if (settings_connection == 0)
3111         {
3112                 settings_connection =
3113                         g_signal_connect (settings, "notify::gtk-key-theme-name",
3114                                           G_CALLBACK (settings_changed_cb), NULL);
3115                 g_object_set_data (G_OBJECT (settings), SETTINGS_CONNECTION_DATA_KEY,
3116                                    GUINT_TO_POINTER (settings_connection));
3118         }
3120         settings_change_notify (settings, window);
3122         /* Setup the UI manager and connect verbs */
3123         setup_ui_manager (window);
3125         priv->notebook = setup_notebook (window);
3126         g_signal_connect_swapped (priv->notebook, "open-link",
3127                                   G_CALLBACK (ephy_link_open), window);
3128         gtk_box_pack_start (GTK_BOX (priv->main_vbox),
3129                             GTK_WIDGET (priv->notebook),
3130                             TRUE, TRUE, 0);
3131         gtk_widget_show (GTK_WIDGET (priv->notebook));
3132         ephy_notebook_set_dnd_enabled (EPHY_NOTEBOOK (priv->notebook), !priv->is_popup);
3134         priv->find_toolbar = ephy_find_toolbar_new (window);
3135         g_signal_connect (priv->find_toolbar, "close",
3136                           G_CALLBACK (find_toolbar_close_cb), window);
3137         gtk_box_pack_start (GTK_BOX (priv->main_vbox),
3138                             GTK_WIDGET (priv->find_toolbar), FALSE, FALSE, 0);
3139         /* don't show the find toolbar here! */
3140         
3141         priv->statusbar = ephy_statusbar_new ();
3142         gtk_box_pack_end (GTK_BOX (priv->main_vbox),
3143                           GTK_WIDGET (priv->statusbar),
3144                           FALSE, TRUE, 0);
3145         priv->tab_message_cid = gtk_statusbar_get_context_id
3146                 (GTK_STATUSBAR (priv->statusbar), "tab_message");
3147         priv->help_message_cid = gtk_statusbar_get_context_id
3148                 (GTK_STATUSBAR (priv->statusbar), "help_message");
3150         /* get the toolbars model *before* getting the bookmarksbar model
3151          * (via ephy_bookmarsbar_new()), so that the toolbars model is
3152          * instantiated *before* the bookmarksbarmodel, to make forwarding
3153          * works. See bug #151267.
3154          */
3155         model= EGG_TOOLBARS_MODEL (ephy_shell_get_toolbars_model (ephy_shell, FALSE));
3157         /* create the toolbars */
3158         priv->toolbar = ephy_toolbar_new (window);
3159         g_signal_connect_swapped (priv->toolbar, "open-link",
3160                                   G_CALLBACK (ephy_link_open), window);
3161         g_signal_connect_swapped (priv->toolbar, "exit-clicked",
3162                                   G_CALLBACK (exit_fullscreen_clicked_cb), window);
3163         g_signal_connect_swapped (priv->toolbar, "activation-finished",
3164                                   G_CALLBACK (sync_chromes_visibility), window);
3166         /* now load the UI definition */
3167         gtk_ui_manager_add_ui_from_file
3168                 (priv->manager, ephy_file ("epiphany-ui.xml"), &error);
3169         if (error != NULL)
3170         {
3171                 g_warning ("Could not merge epiphany-ui.xml: %s", error->message);
3172                 g_error_free (error);
3173         }
3174 #if ENABLE_CERTIFICATE_MANAGER
3176         guint ui_id;
3177         ui_id = gtk_ui_manager_new_merge_id (priv->manager);
3178         gtk_ui_manager_add_ui (priv->manager, ui_id,
3179                                "/menubar/EditMenu/EditPersonalDataMenu",
3180                                "EditCertificates", "EditCertificates",
3181                                GTK_UI_MANAGER_MENUITEM, FALSE);
3183 #endif
3185         /* Initialize the menus */
3186         priv->tabs_menu = ephy_tabs_menu_new (window);
3187         priv->enc_menu = ephy_encoding_menu_new (window);
3189         /* Add the toolbars to the window */
3190         gtk_box_pack_end (GTK_BOX (priv->menu_dock),
3191                           GTK_WIDGET (priv->toolbar),
3192                           FALSE, FALSE, 0);
3194         /* Once the window is sufficiently created let the extensions attach to it */
3195         manager = EPHY_EXTENSION (ephy_shell_get_extensions_manager (ephy_shell));
3196         ephy_extension_attach_window (manager, window);
3197         ephy_bookmarks_ui_attach_window (window);
3199         /* We only set the model now after attaching the extensions, so that
3200          * extensions already have created their actions which may be on
3201          * the toolbar
3202          */
3203         egg_editable_toolbar_set_model
3204                 (EGG_EDITABLE_TOOLBAR (priv->toolbar), model);
3206         /* other notifiers */
3207         browse_with_caret_notifier (NULL, 0, NULL, window);
3208         priv->browse_with_caret_notifier_id = eel_gconf_notification_add
3209                 (CONF_BROWSE_WITH_CARET,
3210                  (GConfClientNotifyFunc)browse_with_caret_notifier, window);
3212         priv->allow_popups_notifier_id = eel_gconf_notification_add
3213                 (CONF_SECURITY_ALLOW_POPUPS,
3214                  (GConfClientNotifyFunc)allow_popups_notifier, window);
3216         /* network status */
3217         single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
3218         sync_network_status (single, NULL, window);
3219         g_signal_connect (single, "notify::network-status",
3220                           G_CALLBACK (sync_network_status), window);
3222         /* Popup part */
3223         toolbar_action_group = ephy_toolbar_get_action_group (priv->toolbar);
3224         action = gtk_action_group_get_action (toolbar_action_group, "FileNewTab");
3225         ephy_action_change_sensitivity_flags (action, SENS_FLAG_CHROME, priv->is_popup);
3227         action = gtk_action_group_get_action (priv->popups_action_group, "OpenLinkInNewTab");
3228         ephy_action_change_sensitivity_flags (action, SENS_FLAG_CHROME, priv->is_popup);
3230         /* Connect lock clicks */
3231         action = gtk_action_group_get_action (priv->action_group, "ViewPageSecurityInfo");
3232         g_signal_connect_swapped (priv->statusbar, "lock-clicked",
3233                                   G_CALLBACK (gtk_action_activate), action);
3234         g_signal_connect_swapped (priv->toolbar, "lock-clicked",
3235                                   G_CALLBACK (gtk_action_activate), action);
3237         /* ensure the UI is updated */
3238         gtk_ui_manager_ensure_update (priv->manager);
3240         init_menu_updaters (window);
3242         update_chromes_actions (window);
3244         sync_chromes_visibility (window);
3246         return object;
3249 static void
3250 ephy_window_finalize (GObject *object)
3252         EphyWindow *window = EPHY_WINDOW (object);
3253         EphyWindowPrivate *priv = window->priv;
3255         g_hash_table_destroy (priv->tabs_to_remove);
3257         G_OBJECT_CLASS (parent_class)->finalize (object);
3259         LOG ("EphyWindow finalised %p", object);
3261 #ifdef ENABLE_PYTHON
3262         ephy_python_schedule_gc ();
3263 #endif
3265         g_object_unref (ephy_shell);
3269  * ephy_window_new:
3271  * Equivalent to g_object_new() but returns an #EphyWindow so you don't have
3272  * to cast it.
3274  * Return value: a new #EphyWindow
3275  **/
3276 EphyWindow *
3277 ephy_window_new (void)
3279         return EPHY_WINDOW (g_object_new (EPHY_TYPE_WINDOW, NULL));
3283  * ephy_window_new_with_chrome:
3284  * @chrome: an #EphyEmbedChrome
3285  * @is_popup: whether the new window is a popup window
3287  * Identical to ephy_window_new(), but allows you to specify a chrome.
3289  * Return value: a new #EphyWindow
3290  **/
3291 EphyWindow *
3292 ephy_window_new_with_chrome (EphyEmbedChrome chrome,
3293                              gboolean is_popup)
3295         return EPHY_WINDOW (g_object_new (EPHY_TYPE_WINDOW,
3296                                           "chrome", chrome,
3297                                           "is-popup", is_popup,
3298                                           NULL));
3302  * ephy_window_set_print_preview:
3303  * @window: an #EphyWindow
3304  * @enabled: %TRUE to enable print preview mode
3306  * Sets whether the window is in print preview mode.
3307  **/
3308 void
3309 ephy_window_set_print_preview (EphyWindow *window,
3310                                gboolean enabled)
3312         EphyWindowPrivate *priv = window->priv;
3313         GtkAccelGroup *accel_group;
3315         accel_group = gtk_ui_manager_get_accel_group (window->priv->manager);
3317         if (priv->ppv_mode == enabled) return;
3319         priv->ppv_mode = enabled;
3321         sync_chromes_visibility (window);
3323         if (enabled)
3324         {
3325                 g_return_if_fail (priv->ppview_toolbar == NULL);
3327                 ephy_find_toolbar_request_close (priv->find_toolbar);
3329                 priv->ppview_toolbar = ppview_toolbar_new (window);
3330                 gtk_window_remove_accel_group (GTK_WINDOW (window), accel_group);
3331         }
3332         else
3333         {
3334                 g_return_if_fail (priv->ppview_toolbar != NULL);
3336                 g_object_unref (priv->ppview_toolbar);
3337                 priv->ppview_toolbar = NULL;
3338                 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3339         }
3341         g_object_notify (G_OBJECT (window), "print-preview-mode");
3345  * ephy_window_get_ui_manager:
3346  * @window: an #EphyWindow
3348  * Returns this window's UI manager.
3350  * Return value: an #GtkUIManager
3351  **/
3352 GObject *
3353 ephy_window_get_ui_manager (EphyWindow *window)
3355         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3357         return G_OBJECT (window->priv->manager);
3361  * ephy_window_get_toolbar:
3362  * @window: an #EphyWindow
3364  * Returns this window's toolbar as an #EggEditableToolbar.
3366  * Return value: an #EggEditableToolbar
3367  **/
3368 GtkWidget *
3369 ephy_window_get_toolbar (EphyWindow *window)
3371         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3373         return GTK_WIDGET (window->priv->toolbar);
3377  * ephy_window_get_notebook:
3378  * @window: an #EphyWindow
3380  * Returns the #GtkNotebook used by this window.
3382  * Return value: the @window's #GtkNotebook
3383  **/
3384 GtkWidget *
3385 ephy_window_get_notebook (EphyWindow *window)
3387         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3389         return GTK_WIDGET (window->priv->notebook);
3393  * ephy_window_get_find_toolbar:
3394  * @window: an #EphyWindow
3396  * Returns the #EphyFindToolbar used by this window.
3398  * Return value: the @window's #EphyFindToolbar
3399  **/
3400 GtkWidget *
3401 ephy_window_get_find_toolbar (EphyWindow *window)
3403        g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3405        return GTK_WIDGET (window->priv->find_toolbar);
3409  * ephy_window_get_statusbar:
3410  * @window: an #EphyWindow
3412  * Returns this window's statusbar as an #EphyStatusbar.
3414  * Return value: This window's statusbar
3415  **/
3416 GtkWidget *
3417 ephy_window_get_statusbar (EphyWindow *window)
3419         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3421         return GTK_WIDGET (window->priv->statusbar);
3425  * ephy_window_add_tab:
3426  * @window: an #EphyWindow
3427  * @tab: an #EphyTab
3428  * @position: the position in @window's #GtkNotebook
3429  * @jump_to: %TRUE to switch to @tab's new notebook page after insertion
3431  * Inserts @tab into @window.
3432  **/
3433 void
3434 ephy_window_add_tab (EphyWindow *window,
3435                      EphyTab *tab,
3436                      gint position,
3437                      gboolean jump_to)
3439         GtkWidget *widget;
3441         g_return_if_fail (EPHY_IS_WINDOW (window));
3442         g_return_if_fail (EPHY_IS_TAB (tab));
3443         g_return_if_fail (!window->priv->is_popup ||
3444                           gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook)) < 1);
3446         widget = GTK_WIDGET(ephy_tab_get_embed (tab));
3448         ephy_notebook_add_tab (EPHY_NOTEBOOK (window->priv->notebook),
3449                                tab, position, jump_to);
3453  * ephy_window_jump_to_tab:
3454  * @window: an #EphyWindow
3455  * @tab: an #EphyTab inside @window
3457  * Switches @window's #GtkNotebook to open @tab as its current page.
3458  **/
3459 void
3460 ephy_window_jump_to_tab (EphyWindow *window,
3461                          EphyTab *tab)
3463         int page;
3465         page = gtk_notebook_page_num
3466                 (window->priv->notebook, GTK_WIDGET (tab));
3467         gtk_notebook_set_current_page
3468                 (window->priv->notebook, page);
3471 static EphyTab *
3472 real_get_active_tab (EphyWindow *window, int page_num)
3474         GtkWidget *tab;
3476         if (page_num == -1)
3477         {
3478                 page_num = gtk_notebook_get_current_page (window->priv->notebook);
3479         }
3480         tab = gtk_notebook_get_nth_page (window->priv->notebook, page_num);
3482         g_return_val_if_fail (EPHY_IS_TAB (tab), NULL);
3484         return EPHY_TAB (tab);
3488  * ephy_window_remove_tab:
3489  * @window: an #EphyWindow
3490  * @tab: an #EphyTab
3492  * Removes @tab from @window.
3493  **/
3494 void
3495 ephy_window_remove_tab (EphyWindow *window,
3496                         EphyTab *tab)
3498         EphyWindowPrivate *priv = window->priv;
3499         EphyEmbed *embed;
3500         GtkNotebook *notebook;
3501         gboolean modified;
3502         int position;
3504         g_return_if_fail (EPHY_IS_WINDOW (window));
3505         g_return_if_fail (EPHY_IS_TAB (tab));
3507         embed = ephy_tab_get_embed (tab);
3508         g_return_if_fail (EPHY_IS_EMBED (embed));
3510         modified = ephy_embed_has_modified_forms (embed);
3511         if (ephy_embed_has_modified_forms (embed)
3512             && confirm_close_with_modified_forms (window) == FALSE)
3513         {
3514                 /* don't close the tab */
3515                 return;
3516         }
3518         notebook = GTK_NOTEBOOK (priv->notebook);
3519         position = gtk_notebook_page_num (notebook, GTK_WIDGET (tab));
3520         gtk_notebook_remove_page (notebook, position);
3524  * ephy_window_load_url:
3525  * @window: a #EphyWindow
3526  * @url: the url to load
3528  * Loads a new url in the active tab of @window.
3529  * Unlike ephy_embed_load_url(), this function activates
3530  * the embed.
3532  **/
3533 void
3534 ephy_window_load_url (EphyWindow *window,
3535                       const char *url)
3537         g_return_if_fail (url != NULL);
3539         ephy_link_open (EPHY_LINK (window), url, NULL, 0);
3543  * ephy_window_activate_location:
3544  * @window: an #EphyWindow
3546  * Activates the location entry on @window's toolbar.
3547  **/
3548 void
3549 ephy_window_activate_location (EphyWindow *window)
3551         if (window->priv->fullscreen_popup)
3552         {
3553                 gtk_widget_hide (window->priv->fullscreen_popup);
3554         }
3556         ephy_toolbar_activate_location (window->priv->toolbar);
3559 static void
3560 ephy_window_show (GtkWidget *widget)
3562         EphyWindow *window = EPHY_WINDOW(widget);
3563         EphyWindowPrivate *priv = window->priv;
3565         if (!priv->has_size)
3566         {
3567                 EphyTab *tab;
3568                 int width, height;
3570                 tab = ephy_window_get_active_tab (EPHY_WINDOW (window));
3571                 g_return_if_fail (tab != NULL);
3573                 ephy_tab_get_size (tab, &width, &height);
3574                 if (width == -1 && height == -1)
3575                 {
3576                         ephy_state_add_window (widget, "main_window", 600, 500,
3577                                                TRUE, EPHY_STATE_WINDOW_SAVE_SIZE);
3578                 }
3580                 priv->has_size = TRUE;
3581         }
3583         GTK_WIDGET_CLASS (parent_class)->show (widget);
3587  * ephy_window_get_active_tab:
3588  * @window: an #EphyWindow
3590  * Returns @window's active #EphyTab.
3592  * Return value: @window's active tab
3593  **/
3594 EphyTab *
3595 ephy_window_get_active_tab (EphyWindow *window)
3597         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3599         return window->priv->active_tab;
3603  * ephy_window_get_active_embed:
3604  * @window: an #EphyWindow
3606  * Return @window's active #EphyEmbed. This is identical to calling
3607  * ephy_window_get_active_tab() followed by ephy_tab_get_embed().
3609  * Return value: @window's active embed
3610  **/
3611 EphyEmbed *
3612 ephy_window_get_active_embed (EphyWindow *window)
3614         EphyTab *tab;
3616         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3618         tab = ephy_window_get_active_tab (window);
3619         if (tab == NULL) return NULL;
3621         return ephy_tab_get_embed (tab);
3625  * ephy_window_get_tabs:
3626  * @window: a #EphyWindow
3628  * Returns the list of #EphyTab:s in the window.
3630  * Return value: a newly-allocated list of #EphyTab:s
3631  */
3632 GList *
3633 ephy_window_get_tabs (EphyWindow *window)
3635         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3637         return gtk_container_get_children (GTK_CONTAINER (window->priv->notebook));
3640 static void
3641 notebook_switch_page_cb (GtkNotebook *notebook,
3642                          GtkNotebookPage *page,
3643                          guint page_num,
3644                          EphyWindow *window)
3646         EphyWindowPrivate *priv = window->priv;
3647         EphyTab *tab;
3648         EphyEmbed *embed;
3650         LOG ("switch-page notebook %p position %u\n", notebook, page_num);
3652         if (priv->closing) return;
3654         /* get the new tab */
3655         tab = real_get_active_tab (window, page_num);
3656         embed = ephy_tab_get_embed (tab);
3658         /* update new tab */
3659         ephy_window_set_active_tab (window, tab);
3661         ephy_find_toolbar_set_embed (priv->find_toolbar, embed);
3663         /* update window controls */
3664         update_tabs_menu_sensitivity (window);
3668  * ephy_window_set_zoom:
3669  * @window: an #EphyWindow
3670  * @zoom: the desired zoom level
3672  * Sets the zoom on @window's active #EphyEmbed. A @zoom of 1.0 corresponds to
3673  * 100% zoom (normal size).
3674  **/
3675 void
3676 ephy_window_set_zoom (EphyWindow *window,
3677                       float zoom)
3679         EphyEmbed *embed;
3680         float current_zoom = 1.0;
3682         g_return_if_fail (EPHY_IS_WINDOW (window));
3684         embed = ephy_window_get_active_embed (window);
3685         g_return_if_fail (embed != NULL);
3687         current_zoom = ephy_embed_get_zoom (embed);
3689         if (zoom == ZOOM_IN)
3690         {
3691                 zoom = ephy_zoom_get_changed_zoom_level (current_zoom, 1);
3692         }
3693         else if (zoom == ZOOM_OUT)
3694         {
3695                 zoom = ephy_zoom_get_changed_zoom_level (current_zoom, -1);
3696         }
3698         if (zoom != current_zoom)
3699         {
3700                 ephy_embed_set_zoom (embed, zoom);
3701         }
3704 static void
3705 sync_prefs_with_chrome (EphyWindow *window)
3707         EphyEmbedChrome flags = window->priv->chrome;
3709         if (window->priv->should_save_chrome)
3710         {
3711                 eel_gconf_set_boolean (CONF_WINDOWS_SHOW_TOOLBARS,
3712                                        flags & EPHY_EMBED_CHROME_TOOLBAR);
3713                 eel_gconf_set_boolean (CONF_WINDOWS_SHOW_STATUSBAR,
3714                                        flags & EPHY_EMBED_CHROME_STATUSBAR);
3715         }
3718 static void
3719 sync_chrome_with_view_toggle (GtkAction *action,
3720                               EphyWindow *window,
3721                               EphyEmbedChrome chrome_flag,
3722                               gboolean invert)
3724         gboolean active;
3726         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
3727         window->priv->chrome = (active != invert) ?
3728                                         window->priv->chrome | chrome_flag :
3729                                         window->priv->chrome & (~chrome_flag);
3731         sync_chromes_visibility (window);
3732         sync_prefs_with_chrome (window);
3735 static void
3736 ephy_window_view_statusbar_cb (GtkAction *action,
3737                                EphyWindow *window)
3739         sync_chrome_with_view_toggle (action, window,
3740                                       EPHY_EMBED_CHROME_STATUSBAR, FALSE);
3743 static void
3744 ephy_window_view_toolbar_cb (GtkAction *action,
3745                              EphyWindow *window)
3747         sync_chrome_with_view_toggle (action, window,
3748                                       EPHY_EMBED_CHROME_TOOLBAR, TRUE);
3751 static void
3752 ephy_window_view_popup_windows_cb (GtkAction *action,
3753                                    EphyWindow *window)
3755         EphyTab *tab;
3756         gboolean allow;
3758         g_return_if_fail (EPHY_IS_WINDOW (window));
3760         tab = ephy_window_get_active_tab (window);
3761         g_return_if_fail (EPHY_IS_TAB (tab));
3763         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
3764         {
3765                 allow = TRUE;
3766         }
3767         else
3768         {
3769                 allow = FALSE;
3770         }
3772         g_object_set (G_OBJECT (tab), "popups-allowed", allow, NULL);
3776  * ephy_window_get_is_popup:
3777  * @window: an #EphyWindow
3779  * Returns whether this window is a popup window.
3781  * Return value: %TRUE if it is a popup window
3782  **/
3783 gboolean
3784 ephy_window_get_is_popup (EphyWindow *window)
3786         g_return_val_if_fail (EPHY_IS_WINDOW (window), FALSE);
3788         return window->priv->is_popup;
3792  * ephy_window_get_is_print_preview:
3793  * @window: an #EphyWindow
3795  * Returns whether this window is in print preview mode.
3797  * Return value: %TRUE if it is in print preview mode
3798  **/
3799 gboolean
3800 ephy_window_get_is_print_preview (EphyWindow *window)
3802         g_return_val_if_fail (EPHY_IS_WINDOW (window), FALSE);
3804         return window->priv->ppv_mode;
3808  * ephy_window_get_context_event:
3809  * @window: an #EphyWindow
3811  * Returns the #EphyEmbedEvent for the current context menu.
3812  * Use this to get the event from the action callback.
3814  * Return value: an #EphyEmbedEvent, or %NULL
3815  **/
3816 EphyEmbedEvent *
3817 ephy_window_get_context_event (EphyWindow *window)
3819         g_return_val_if_fail (EPHY_IS_WINDOW (window), NULL);
3821         return window->priv->context_event;