2 * Copyright © 2002 Christophe Fergeau
3 * Copyright © 2003, 2004 Marco Pesenti Gritti
4 * Copyright © 2003, 2004, 2005 Christian Persch
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)
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.
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.
20 * $Id: ephy-notebook.c 6952 2007-03-11 19:42:02Z chpe $
25 #include "ephy-notebook.h"
26 #include "eel-gconf-extensions.h"
27 #include "ephy-prefs.h"
28 #include "ephy-marshal.h"
29 #include "ephy-file-helpers.h"
31 #include "ephy-embed.h"
32 #include "ephy-window.h"
33 #include "ephy-shell.h"
34 #include "ephy-spinner.h"
35 #include "ephy-link.h"
36 #include "ephy-debug.h"
38 #include <glib/gi18n.h>
39 #include <gtk/gtkeventbox.h>
40 #include <gtk/gtkhbox.h>
41 #include <gtk/gtklabel.h>
42 #include <gtk/gtkwidget.h>
43 #include <gtk/gtktooltips.h>
44 #include <gtk/gtkstock.h>
45 #include <gtk/gtkimage.h>
46 #include <gtk/gtkbutton.h>
47 #include <gtk/gtkaccelgroup.h>
48 #include <gtk/gtkiconfactory.h>
50 #define TAB_WIDTH_N_CHARS 15
52 #define AFTER_ALL_TABS -1
53 #define NOT_IN_APP_WINDOWS -2
55 #define INSANE_NUMBER_OF_URLS 20
58 #define TOOLTIP_MAX_LENGTH 256
60 /* Until https://bugzilla.mozilla.org/show_bug.cgi?id=296002 is fixed */
61 #define KEEP_TAB_IN_SAME_TOPLEVEL
63 #define EPHY_NOTEBOOK_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_NOTEBOOK, EphyNotebookPrivate))
65 struct _EphyNotebookPrivate
68 GtkTooltips
*title_tips
;
69 guint tabs_vis_notifier_id
;
72 guint dnd_enabled
: 1;
75 static void ephy_notebook_init (EphyNotebook
*notebook
);
76 static void ephy_notebook_class_init (EphyNotebookClass
*klass
);
77 static void ephy_notebook_finalize (GObject
*object
);
78 static int ephy_notebook_insert_page (GtkNotebook
*notebook
,
81 GtkWidget
*menu_label
,
83 static void ephy_notebook_remove (GtkContainer
*container
,
84 GtkWidget
*tab_widget
);
86 static const GtkTargetEntry url_drag_types
[] =
88 { EPHY_DND_URI_LIST_TYPE
, 0, 0 },
89 { EPHY_DND_URL_TYPE
, 0, 1 }
105 static guint signals
[LAST_SIGNAL
];
106 static GObjectClass
*parent_class
;
109 ephy_notebook_get_type (void)
111 static GType type
= 0;
113 if (G_UNLIKELY (type
== 0))
115 const GTypeInfo our_info
=
117 sizeof (EphyNotebookClass
),
118 NULL
, /* base_init */
119 NULL
, /* base_finalize */
120 (GClassInitFunc
) ephy_notebook_class_init
,
122 NULL
, /* class_data */
123 sizeof (EphyNotebook
),
125 (GInstanceInitFunc
) ephy_notebook_init
128 const GInterfaceInfo link_info
=
135 type
= g_type_register_static (GTK_TYPE_NOTEBOOK
,
138 g_type_add_interface_static (type
,
147 ephy_notebook_set_dnd_enabled (EphyNotebook
*notebook
,
150 EphyNotebookPrivate
*priv
= notebook
->priv
;
152 priv
->dnd_enabled
= enabled
;
153 /* FIXME abort any DNDs in progress */
155 g_object_notify (G_OBJECT (notebook
), "dnd-enabled");
159 ephy_notebook_get_property (GObject
*object
,
164 EphyNotebook
*notebook
= EPHY_NOTEBOOK (object
);
165 EphyNotebookPrivate
*priv
= notebook
->priv
;
169 case PROP_DND_ENABLED
:
170 g_value_set_boolean (value
, priv
->dnd_enabled
);
173 g_value_set_boolean (value
, priv
->show_tabs
);
179 ephy_notebook_set_property (GObject
*object
,
184 EphyNotebook
*notebook
= EPHY_NOTEBOOK (object
);
188 case PROP_DND_ENABLED
:
189 ephy_notebook_set_dnd_enabled (notebook
, g_value_get_boolean (value
));
192 ephy_notebook_set_show_tabs (notebook
, g_value_get_boolean (value
));
198 ephy_notebook_class_init (EphyNotebookClass
*klass
)
200 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
201 GtkContainerClass
*container_class
= GTK_CONTAINER_CLASS (klass
);
202 GtkNotebookClass
*notebook_class
= GTK_NOTEBOOK_CLASS (klass
);
204 parent_class
= g_type_class_peek_parent (klass
);
206 object_class
->finalize
= ephy_notebook_finalize
;
207 object_class
->get_property
= ephy_notebook_get_property
;
208 object_class
->set_property
= ephy_notebook_set_property
;
210 container_class
->remove
= ephy_notebook_remove
;
212 notebook_class
->insert_page
= ephy_notebook_insert_page
;
214 signals
[TAB_CLOSE_REQUEST
] =
215 g_signal_new ("tab-close-request",
216 G_OBJECT_CLASS_TYPE (object_class
),
218 G_STRUCT_OFFSET (EphyNotebookClass
, tab_close_req
),
220 g_cclosure_marshal_VOID__OBJECT
,
225 g_object_class_install_property (object_class
,
227 g_param_spec_boolean ("dnd-enabled",
229 "Whether the notebook allows tab reordering by DND",
231 G_PARAM_READWRITE
| G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
233 g_object_class_install_property (object_class
,
235 g_param_spec_boolean ("show-tabs",
237 "Whether the notebook shows the tabs bar",
239 G_PARAM_READWRITE
| G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
241 g_type_class_add_private (object_class
, sizeof (EphyNotebookPrivate
));
245 /* FIXME remove when gtknotebook's func for this becomes public, bug #.... */
246 static EphyNotebook
*
247 find_notebook_at_pointer (gint abs_x
, gint abs_y
)
249 GdkWindow
*win_at_pointer
, *toplevel_win
;
250 gpointer toplevel
= NULL
;
253 /* FIXME multi-head */
254 win_at_pointer
= gdk_window_at_pointer (&x
, &y
);
255 if (win_at_pointer
== NULL
)
257 /* We are outside all windows containing a notebook */
261 toplevel_win
= gdk_window_get_toplevel (win_at_pointer
);
263 /* get the GtkWidget which owns the toplevel GdkWindow */
264 gdk_window_get_user_data (toplevel_win
, &toplevel
);
266 /* toplevel should be an EphyWindow */
267 if (toplevel
!= NULL
&& EPHY_IS_WINDOW (toplevel
))
269 return EPHY_NOTEBOOK (ephy_window_get_notebook
270 (EPHY_WINDOW (toplevel
)));
277 is_in_notebook_window (EphyNotebook
*notebook
,
278 gint abs_x
, gint abs_y
)
280 EphyNotebook
*nb_at_pointer
;
282 nb_at_pointer
= find_notebook_at_pointer (abs_x
, abs_y
);
284 return nb_at_pointer
== notebook
;
288 find_tab_num_at_pos (EphyNotebook
*notebook
, gint abs_x
, gint abs_y
)
290 GtkPositionType tab_pos
;
292 GtkNotebook
*nb
= GTK_NOTEBOOK (notebook
);
295 tab_pos
= gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook
));
297 if (GTK_NOTEBOOK (notebook
)->first_tab
== NULL
)
299 return AFTER_ALL_TABS
;
302 /* For some reason unfullscreen + quick click can
303 cause a wrong click event to be reported to the tab */
304 if (!is_in_notebook_window(notebook
, abs_x
, abs_y
))
306 return NOT_IN_APP_WINDOWS
;
309 while ((page
= gtk_notebook_get_nth_page (nb
, page_num
)))
315 tab
= gtk_notebook_get_tab_label (nb
, page
);
316 g_return_val_if_fail (tab
!= NULL
, -1);
318 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (tab
)))
324 gdk_window_get_origin (GDK_WINDOW (tab
->window
),
327 max_x
= x_root
+ tab
->allocation
.x
+ tab
->allocation
.width
;
328 max_y
= y_root
+ tab
->allocation
.y
+ tab
->allocation
.height
;
330 if (((tab_pos
== GTK_POS_TOP
)
331 || (tab_pos
== GTK_POS_BOTTOM
))
336 else if (((tab_pos
== GTK_POS_LEFT
)
337 || (tab_pos
== GTK_POS_RIGHT
))
345 return AFTER_ALL_TABS
;
349 button_press_cb (EphyNotebook
*notebook
,
350 GdkEventButton
*event
,
355 tab_clicked
= find_tab_num_at_pos (notebook
, event
->x_root
, event
->y_root
);
357 if (event
->type
== GDK_BUTTON_PRESS
&&
358 event
->button
== 3 &&
359 (event
->state
& gtk_accelerator_get_default_mod_mask ()) == 0)
361 if (tab_clicked
== -1)
363 /* consume event, so that we don't pop up the context menu when
364 * the mouse if not over a tab label
369 /* switch to the page the mouse is over, but don't consume the event */
370 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook
), tab_clicked
);
377 ephy_notebook_switch_page_cb (GtkNotebook
*notebook
,
378 GtkNotebookPage
*page
,
382 EphyNotebook
*nb
= EPHY_NOTEBOOK (notebook
);
385 child
= gtk_notebook_get_nth_page (notebook
, page_num
);
387 /* Remove the old page, we dont want to grow unnecessarily
389 if (nb
->priv
->focused_pages
)
391 nb
->priv
->focused_pages
=
392 g_list_remove (nb
->priv
->focused_pages
, child
);
395 nb
->priv
->focused_pages
= g_list_append (nb
->priv
->focused_pages
,
400 notebook_drag_data_received_cb (GtkWidget
* widget
, GdkDragContext
*context
,
401 gint x
, gint y
, GtkSelectionData
*selection_data
,
402 guint info
, guint time
, EphyTab
*tab
)
407 g_signal_stop_emission_by_name (widget
, "drag_data_received");
409 if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_ARBITRARY_URL
)) return;
411 if (selection_data
->length
<= 0 || selection_data
->data
== NULL
) return;
413 window
= EPHY_WINDOW (gtk_widget_get_toplevel (widget
));
414 notebook
= ephy_window_get_notebook (window
);
416 if (selection_data
->target
== gdk_atom_intern (EPHY_DND_URL_TYPE
, FALSE
))
420 /* URL_TYPE has format: url \n title */
421 split
= g_strsplit ((const gchar
*)selection_data
->data
, "\n", 2);
422 if (split
!= NULL
&& split
[0] != NULL
&& split
[0][0] != '\0')
424 ephy_link_open (EPHY_LINK (notebook
), split
[0], tab
,
425 tab
? 0 : EPHY_LINK_NEW_TAB
);
429 else if (selection_data
->target
== gdk_atom_intern (EPHY_DND_URI_LIST_TYPE
, FALSE
))
434 uris
= gtk_selection_data_get_uris (selection_data
);
435 if (uris
== NULL
) return;
437 for (i
= 0; uris
[i
] != NULL
&& i
< INSANE_NUMBER_OF_URLS
; i
++)
439 tab
= ephy_link_open (EPHY_LINK (notebook
), uris
[i
],
440 tab
, i
== 0 ? 0 : EPHY_LINK_NEW_TAB
);
449 text
= (char *) gtk_selection_data_get_text (selection_data
);
451 ephy_link_open (EPHY_LINK (notebook
), text
, tab
,
452 tab
? 0 : EPHY_LINK_NEW_TAB
);
459 * update_tabs_visibility: Hide tabs if there is only one tab
460 * and the pref is not set.
463 update_tabs_visibility (EphyNotebook
*nb
, gboolean before_inserting
)
468 num
= gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb
));
470 if (before_inserting
) num
++;
472 show_tabs
= (eel_gconf_get_boolean (CONF_ALWAYS_SHOW_TABS_BAR
) || num
> 1) &&
473 nb
->priv
->show_tabs
== TRUE
;
475 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb
), show_tabs
);
479 tabs_visibility_notifier (GConfClient
*client
,
484 update_tabs_visibility (nb
, FALSE
);
488 ephy_notebook_init (EphyNotebook
*notebook
)
490 notebook
->priv
= EPHY_NOTEBOOK_GET_PRIVATE (notebook
);
492 gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook
), TRUE
);
493 gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook
), FALSE
);
494 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook
), FALSE
);
496 notebook
->priv
->title_tips
= gtk_tooltips_new ();
497 gtk_tooltips_force_window (notebook
->priv
->title_tips
);
498 gtk_label_set_max_width_chars (GTK_LABEL (notebook
->priv
->title_tips
->tip_label
), TOOLTIP_MAX_LENGTH
);
499 gtk_label_set_ellipsize (GTK_LABEL (notebook
->priv
->title_tips
->tip_label
), PANGO_ELLIPSIZE_END
);
500 g_object_ref_sink (notebook
->priv
->title_tips
);
502 notebook
->priv
->show_tabs
= TRUE
;
503 notebook
->priv
->dnd_enabled
= TRUE
;
505 g_signal_connect (notebook
, "button-press-event",
506 (GCallback
)button_press_cb
, NULL
);
507 g_signal_connect_after (notebook
, "switch-page",
508 G_CALLBACK (ephy_notebook_switch_page_cb
),
511 /* Set up drag-and-drop target */
512 g_signal_connect (notebook
, "drag-data-received",
513 G_CALLBACK (notebook_drag_data_received_cb
),
515 gtk_drag_dest_set (GTK_WIDGET (notebook
),
516 GTK_DEST_DEFAULT_MOTION
|
517 GTK_DEST_DEFAULT_DROP
,
518 url_drag_types
, G_N_ELEMENTS (url_drag_types
),
519 GDK_ACTION_MOVE
| GDK_ACTION_COPY
);
520 gtk_drag_dest_add_text_targets (GTK_WIDGET(notebook
));
522 notebook
->priv
->tabs_vis_notifier_id
= eel_gconf_notification_add
523 (CONF_ALWAYS_SHOW_TABS_BAR
,
524 (GConfClientNotifyFunc
)tabs_visibility_notifier
, notebook
);
528 ephy_notebook_finalize (GObject
*object
)
530 EphyNotebook
*notebook
= EPHY_NOTEBOOK (object
);
532 eel_gconf_notification_remove (notebook
->priv
->tabs_vis_notifier_id
);
534 if (notebook
->priv
->focused_pages
)
536 g_list_free (notebook
->priv
->focused_pages
);
538 g_object_unref (notebook
->priv
->title_tips
);
540 G_OBJECT_CLASS (parent_class
)->finalize (object
);
544 sync_load_status (EphyTab
*tab
, GParamSpec
*pspec
, GtkWidget
*proxy
)
546 GtkWidget
*spinner
, *icon
;
548 spinner
= GTK_WIDGET (g_object_get_data (G_OBJECT (proxy
), "spinner"));
549 icon
= GTK_WIDGET (g_object_get_data (G_OBJECT (proxy
), "icon"));
550 g_return_if_fail (spinner
!= NULL
&& icon
!= NULL
);
552 if (ephy_tab_get_load_status (tab
))
554 gtk_widget_hide (icon
);
555 gtk_widget_show (spinner
);
556 ephy_spinner_start (EPHY_SPINNER (spinner
));
560 ephy_spinner_stop (EPHY_SPINNER (spinner
));
561 gtk_widget_hide (spinner
);
562 gtk_widget_show (icon
);
567 sync_icon (EphyTab
*tab
,
573 icon
= GTK_IMAGE (g_object_get_data (G_OBJECT (proxy
), "icon"));
574 g_return_if_fail (icon
!= NULL
);
576 gtk_image_set_from_pixbuf (icon
, ephy_tab_get_icon (tab
));
580 sync_label (EphyTab
*tab
, GParamSpec
*pspec
, GtkWidget
*proxy
)
582 GtkWidget
*label
, *ebox
;
586 ebox
= GTK_WIDGET (g_object_get_data (G_OBJECT (proxy
), "label-ebox"));
587 tips
= GTK_TOOLTIPS (g_object_get_data (G_OBJECT (proxy
), "tooltips"));
588 label
= GTK_WIDGET (g_object_get_data (G_OBJECT (proxy
), "label"));
590 g_return_if_fail (ebox
!= NULL
&& tips
!= NULL
&& label
!= NULL
);
592 title
= ephy_tab_get_title (tab
);
596 gtk_label_set_text (GTK_LABEL (label
), title
);
597 gtk_tooltips_set_tip (tips
, ebox
, title
, NULL
);
602 close_button_clicked_cb (GtkWidget
*widget
, GtkWidget
*tab
)
606 notebook
= gtk_widget_get_parent (tab
);
607 g_signal_emit (notebook
, signals
[TAB_CLOSE_REQUEST
], 0, tab
);
611 tab_label_style_set_cb (GtkWidget
*hbox
,
612 GtkStyle
*previous_style
,
615 PangoFontMetrics
*metrics
;
616 PangoContext
*context
;
618 int char_width
, h
, w
;
620 context
= gtk_widget_get_pango_context (hbox
);
621 metrics
= pango_context_get_metrics (context
,
622 hbox
->style
->font_desc
,
623 pango_context_get_language (context
));
625 char_width
= pango_font_metrics_get_approximate_digit_width (metrics
);
626 pango_font_metrics_unref (metrics
);
628 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (hbox
),
629 GTK_ICON_SIZE_MENU
, &w
, &h
);
631 gtk_widget_set_size_request
632 (hbox
, TAB_WIDTH_N_CHARS
* PANGO_PIXELS(char_width
) + 2 * w
, -1);
634 button
= g_object_get_data (G_OBJECT (hbox
), "close-button");
635 gtk_widget_set_size_request (button
, w
+ 2, h
+ 2);
639 build_tab_label (EphyNotebook
*nb
, EphyTab
*tab
)
641 GtkWidget
*hbox
, *label_hbox
, *label_ebox
;
642 GtkWidget
*label
, *close_button
, *image
, *spinner
, *icon
;
645 /* set hbox spacing and label padding (see below) so that there's an
646 * equal amount of space around the label */
647 hbox
= gtk_hbox_new (FALSE
, 4);
649 label_ebox
= gtk_event_box_new ();
650 gtk_event_box_set_visible_window (GTK_EVENT_BOX (label_ebox
), FALSE
);
651 gtk_box_pack_start (GTK_BOX (hbox
), label_ebox
, TRUE
, TRUE
, 0);
653 label_hbox
= gtk_hbox_new (FALSE
, 4);
654 gtk_container_add (GTK_CONTAINER (label_ebox
), label_hbox
);
656 /* setup close button */
657 close_button
= gtk_button_new ();
658 gtk_button_set_relief (GTK_BUTTON (close_button
),
660 /* don't allow focus on the close button */
661 gtk_button_set_focus_on_click (GTK_BUTTON (close_button
), FALSE
);
663 rcstyle
= gtk_rc_style_new ();
664 rcstyle
->xthickness
= rcstyle
->ythickness
= 0;
665 gtk_widget_modify_style (close_button
, rcstyle
);
666 gtk_rc_style_unref (rcstyle
);
668 image
= gtk_image_new_from_stock (GTK_STOCK_CLOSE
, GTK_ICON_SIZE_MENU
);
669 gtk_container_add (GTK_CONTAINER (close_button
), image
);
670 gtk_box_pack_start (GTK_BOX (hbox
), close_button
, FALSE
, FALSE
, 0);
672 gtk_tooltips_set_tip (nb
->priv
->title_tips
, close_button
,
673 _("Close tab"), NULL
);
675 g_signal_connect (close_button
, "clicked",
676 G_CALLBACK (close_button_clicked_cb
), tab
);
678 /* setup load feedback */
679 spinner
= ephy_spinner_new ();
680 ephy_spinner_set_size (EPHY_SPINNER (spinner
), GTK_ICON_SIZE_MENU
);
681 gtk_box_pack_start (GTK_BOX (label_hbox
), spinner
, FALSE
, FALSE
, 0);
683 /* setup site icon, empty by default */
684 icon
= gtk_image_new ();
685 gtk_box_pack_start (GTK_BOX (label_hbox
), icon
, FALSE
, FALSE
, 0);
688 label
= gtk_label_new ("");
689 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
690 gtk_label_set_single_line_mode (GTK_LABEL (label
), TRUE
);
691 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
692 gtk_misc_set_padding (GTK_MISC (label
), 0, 0);
693 gtk_box_pack_start (GTK_BOX (label_hbox
), label
, TRUE
, TRUE
, 0);
695 /* Set minimal size */
696 g_signal_connect (hbox
, "style-set",
697 G_CALLBACK (tab_label_style_set_cb
), NULL
);
699 /* Set up drag-and-drop target */
700 g_signal_connect (hbox
, "drag_data_received",
701 G_CALLBACK (notebook_drag_data_received_cb
), tab
);
702 gtk_drag_dest_set (hbox
, GTK_DEST_DEFAULT_ALL
,
703 url_drag_types
, G_N_ELEMENTS (url_drag_types
),
704 GDK_ACTION_MOVE
| GDK_ACTION_COPY
);
705 gtk_drag_dest_add_text_targets (hbox
);
707 gtk_widget_show (hbox
);
708 gtk_widget_show (label_ebox
);
709 gtk_widget_show (label_hbox
);
710 gtk_widget_show (label
);
711 gtk_widget_show (image
);
712 gtk_widget_show (close_button
);
714 g_object_set_data (G_OBJECT (hbox
), "label", label
);
715 g_object_set_data (G_OBJECT (hbox
), "label-ebox", label_ebox
);
716 g_object_set_data (G_OBJECT (hbox
), "spinner", spinner
);
717 g_object_set_data (G_OBJECT (hbox
), "icon", icon
);
718 g_object_set_data (G_OBJECT (hbox
), "close-button", close_button
);
719 g_object_set_data (G_OBJECT (hbox
), "tooltips", nb
->priv
->title_tips
);
721 /* Hook the label up to the tab properties */
722 sync_icon (tab
, NULL
, hbox
);
723 sync_label (tab
, NULL
, hbox
);
724 sync_load_status (tab
, NULL
, hbox
);
726 g_signal_connect_object (tab
, "notify::icon",
727 G_CALLBACK (sync_icon
), hbox
, 0);
728 g_signal_connect_object (tab
, "notify::title",
729 G_CALLBACK (sync_label
), hbox
, 0);
730 g_signal_connect_object (tab
, "notify::load-status",
731 G_CALLBACK (sync_load_status
), hbox
, 0);
737 ephy_notebook_set_show_tabs (EphyNotebook
*nb
, gboolean show_tabs
)
739 nb
->priv
->show_tabs
= show_tabs
;
741 update_tabs_visibility (nb
, FALSE
);
745 ephy_notebook_get_focused_pages (EphyNotebook
*nb
)
747 g_return_val_if_fail (EPHY_IS_NOTEBOOK (nb
), NULL
);
749 return nb
->priv
->focused_pages
;
753 ephy_notebook_insert_page (GtkNotebook
*gnotebook
,
754 GtkWidget
*tab_widget
,
755 GtkWidget
*tab_label
,
756 GtkWidget
*menu_label
,
759 EphyNotebook
*notebook
= EPHY_NOTEBOOK (gnotebook
);
761 /* Destroy passed-in tab label */
762 if (tab_label
!= NULL
)
764 g_object_ref_sink (tab_label
);
765 g_object_unref (tab_label
);
768 g_assert (EPHY_IS_TAB (tab_widget
));
770 tab_label
= build_tab_label (notebook
, EPHY_TAB (tab_widget
));
772 update_tabs_visibility (notebook
, TRUE
);
774 position
= GTK_NOTEBOOK_CLASS (parent_class
)->insert_page (gnotebook
,
780 gtk_notebook_set_tab_reorderable (gnotebook
, tab_widget
, TRUE
);
786 ephy_notebook_add_tab (EphyNotebook
*notebook
,
791 GtkNotebook
*gnotebook
= GTK_NOTEBOOK (notebook
);
793 g_return_val_if_fail (EPHY_IS_NOTEBOOK (notebook
), -1);
795 position
= gtk_notebook_insert_page (GTK_NOTEBOOK (notebook
),
801 /* The signal handler may have reordered the tabs */
802 position
= gtk_notebook_page_num (gnotebook
, GTK_WIDGET (tab
));
806 gtk_notebook_set_current_page (gnotebook
, position
);
807 g_object_set_data (G_OBJECT (tab
), "jump_to",
808 GINT_TO_POINTER (jump_to
));
816 smart_tab_switching_on_closure (EphyNotebook
*notebook
,
819 EphyNotebookPrivate
*priv
= notebook
->priv
;
822 jump_to
= GPOINTER_TO_INT (g_object_get_data
823 (G_OBJECT (tab
), "jump_to"));
825 if (!jump_to
|| !priv
->focused_pages
)
827 gtk_notebook_next_page (GTK_NOTEBOOK (notebook
));
835 /* activate the last focused tab */
836 l
= g_list_last (priv
->focused_pages
);
837 child
= GTK_WIDGET (l
->data
);
838 page_num
= gtk_notebook_page_num (GTK_NOTEBOOK (notebook
),
840 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook
),
846 ephy_notebook_remove (GtkContainer
*container
,
847 GtkWidget
*tab_widget
)
849 GtkNotebook
*gnotebook
= GTK_NOTEBOOK (container
);
850 EphyNotebook
*notebook
= EPHY_NOTEBOOK (container
);
851 EphyNotebookPrivate
*priv
= notebook
->priv
;
852 GtkWidget
*tab_label
, *ebox
;
855 g_assert (EPHY_IS_TAB (tab_widget
));
857 /* Remove the page from the focused pages list */
858 priv
->focused_pages
= g_list_remove (priv
->focused_pages
, tab_widget
);
860 position
= gtk_notebook_page_num (gnotebook
, tab_widget
);
861 curr
= gtk_notebook_get_current_page (gnotebook
);
863 if (position
== curr
)
865 smart_tab_switching_on_closure (notebook
, tab_widget
);
868 /* Prepare tab label for destruction */
869 tab_label
= gtk_notebook_get_tab_label (gnotebook
, tab_widget
);
870 ebox
= GTK_WIDGET (g_object_get_data (G_OBJECT (tab_label
), "label-ebox"));
871 gtk_tooltips_set_tip (GTK_TOOLTIPS (priv
->title_tips
), ebox
, NULL
, NULL
);
873 g_signal_handlers_disconnect_by_func
874 (tab_widget
, G_CALLBACK (sync_icon
), tab_label
);
875 g_signal_handlers_disconnect_by_func
876 (tab_widget
, G_CALLBACK (sync_label
), tab_label
);
877 g_signal_handlers_disconnect_by_func
878 (tab_widget
, G_CALLBACK (sync_load_status
), tab_label
);
880 GTK_CONTAINER_CLASS (parent_class
)->remove (container
, tab_widget
);
882 update_tabs_visibility (notebook
, FALSE
);
884 /* if that was the last tab, destroy the window */
885 if (gtk_notebook_get_n_pages (gnotebook
) == 0)
887 gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (notebook
)));