diff --git a/help/reference/shell/evince-docs.xml b/help/reference/shell/evince-docs.xml index 052ab206..7c1036f3 100644 --- a/help/reference/shell/evince-docs.xml +++ b/help/reference/shell/evince-docs.xml @@ -93,11 +93,9 @@ - - diff --git a/help/reference/shell/evince-sections.txt b/help/reference/shell/evince-sections.txt index a775f7e2..1bf89a5d 100644 --- a/help/reference/shell/evince-sections.txt +++ b/help/reference/shell/evince-sections.txt @@ -365,23 +365,6 @@ EV_IS_MEDIA_PLAYER_KEYS_CLASS EV_MEDIA_PLAYER_KEYS_GET_CLASS -
-ev-navigation-action -EvNavigationAction -EvNavigationAction -EvNavigationActionPrivate -EvNavigationActionClass -ev_navigation_action_set_history - -EV_NAVIGATION_ACTION -EV_IS_NAVIGATION_ACTION -EV_TYPE_NAVIGATION_ACTION -ev_navigation_action_get_type -EV_NAVIGATION_ACTION_CLASS -EV_IS_NAVIGATION_ACTION_CLASS -EV_NAVIGATION_ACTION_GET_CLASS -
-
ev-file-monitor EvFileMonitor @@ -429,17 +412,6 @@ ev_window_title_set_uri ev_window_title_free
-
-ev-navigation-action-widget -EvNavigationActionWidget -EV_TYPE_NAVIGATION_ACTION_WIDGET -EV_NAVIGATION_ACTION_WIDGET -EvNavigationActionWidget -EvNavigationActionWidgetClass -ev_navigation_action_widget_get_type -ev_navigation_action_widget_set_menu -
-
ev-keyring ev_keyring_is_available diff --git a/help/reference/shell/evince.types b/help/reference/shell/evince.types index dea7db50..1df224b7 100644 --- a/help/reference/shell/evince.types +++ b/help/reference/shell/evince.types @@ -5,8 +5,6 @@ ev_history_get_type ev_media_player_keys_get_type ev_message_area_get_type ev_metadata_get_type -ev_navigation_action_get_type -ev_navigation_action_widget_get_type ev_open_recent_action_get_type ev_page_action_get_type ev_page_action_widget_get_type diff --git a/po/POTFILES.in b/po/POTFILES.in index e09f2faf..5455485f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -36,10 +36,9 @@ shell/eggfindbar.c shell/ev-annotation-properties-dialog.c shell/ev-application.c shell/ev-history.c +shell/ev-history-action-widget.c shell/ev-keyring.c shell/ev-loading-message.c -shell/ev-navigation-action.c -shell/ev-navigation-action-widget.c shell/ev-open-recent-action.c shell/ev-password-view.c shell/ev-properties-dialog.c diff --git a/shell/Makefile.am b/shell/Makefile.am index 38952b66..1ec8ddeb 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -39,6 +39,10 @@ evince_SOURCES= \ ev-file-monitor.c \ ev-history.c \ ev-history.h \ + ev-history-action.c \ + ev-history-action.h \ + ev-history-action-widget.c \ + ev-history-action-widget.h \ ev-keyring.h \ ev-keyring.c \ ev-loading-message.c \ @@ -47,10 +51,6 @@ evince_SOURCES= \ ev-message-area.h \ ev-metadata.c \ ev-metadata.h \ - ev-navigation-action.c \ - ev-navigation-action.h \ - ev-navigation-action-widget.c \ - ev-navigation-action-widget.h \ ev-password-view.h \ ev-password-view.c \ ev-progress-message-area.h \ diff --git a/shell/ev-history-action-widget.c b/shell/ev-history-action-widget.c new file mode 100644 index 00000000..fc3a707b --- /dev/null +++ b/shell/ev-history-action-widget.c @@ -0,0 +1,331 @@ +/* ev-history-action-widget.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2013 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ev-history-action-widget.h" + +#include +#include + + +enum { + PROP_0, + + PROP_POPUP_SHOWN +}; + +struct _EvHistoryActionWidgetPrivate { + GtkWidget *back_button; + GtkWidget *forward_button; + + EvHistory *history; + gboolean popup_shown; +}; + +typedef enum { + EV_HISTORY_ACTION_BUTTON_BACK, + EV_HISTORY_ACTION_BUTTON_FORWARD +} EvHistoryActionButton; + +G_DEFINE_TYPE (EvHistoryActionWidget, ev_history_action_widget, GTK_TYPE_TOOL_ITEM) + +static void +ev_history_action_widget_finalize (GObject *object) +{ + EvHistoryActionWidget *control = EV_HISTORY_ACTION_WIDGET (object); + + ev_history_action_widget_set_history (control, NULL); + + G_OBJECT_CLASS (ev_history_action_widget_parent_class)->finalize (object); +} + +static void +ev_history_action_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvHistoryActionWidget *history_widget = EV_HISTORY_ACTION_WIDGET (object); + + switch (prop_id) { + case PROP_POPUP_SHOWN: + g_value_set_boolean (value, history_widget->priv->popup_shown); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ev_history_action_widget_set_popup_shown (EvHistoryActionWidget *history_widget, + gboolean popup_shown) +{ + if (history_widget->priv->popup_shown == popup_shown) + return; + + history_widget->priv->popup_shown = popup_shown; + g_object_notify (G_OBJECT (history_widget), "popup-shown"); +} + +static void +history_menu_link_activated (GtkMenuItem *item, + EvHistoryActionWidget *history_widget) +{ + EvLink *link; + + link = EV_LINK (g_object_get_data (G_OBJECT (item), "ev-history-menu-item-link")); + if (!link) + return; + + ev_history_go_to_link (history_widget->priv->history, link); +} + +static void +popup_menu_hide_cb (GtkMenu *menu, + EvHistoryActionWidget *history_widget) +{ + ev_history_action_widget_set_popup_shown (history_widget, FALSE); +} + +static void +ev_history_action_widget_show_popup (EvHistoryActionWidget *history_widget, + EvHistoryActionButton action_button, + guint button, + guint32 event_time) +{ + GtkWidget *menu; + GList *list = NULL; + GList *l; + + switch (action_button) { + case EV_HISTORY_ACTION_BUTTON_BACK: + list = ev_history_get_back_list (history_widget->priv->history); + break; + case EV_HISTORY_ACTION_BUTTON_FORWARD: + list = ev_history_get_forward_list (history_widget->priv->history); + break; + } + + if (!list) + return; + + menu = gtk_menu_new (); + + for (l = list; l; l = g_list_next (l)) { + EvLink *link = EV_LINK (l->data); + GtkWidget *item; + + item = gtk_menu_item_new_with_label (ev_link_get_title (link)); + g_object_set_data_full (G_OBJECT (item), "ev-history-menu-item-link", + g_object_ref (link), (GDestroyNotify)g_object_unref); + g_signal_connect_object (item, "activate", + G_CALLBACK (history_menu_link_activated), + history_widget, 0); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + } + + ev_history_action_widget_set_popup_shown (history_widget, TRUE); + g_signal_connect (menu, "hide", + G_CALLBACK (popup_menu_hide_cb), + history_widget); + gtk_menu_popup (GTK_MENU (menu), + NULL, NULL, NULL, NULL, + button, event_time); +} + +static void +button_clicked (GtkWidget *button, + EvHistoryActionWidget *history_widget) +{ + EvHistoryActionWidgetPrivate *priv = history_widget->priv; + + if (button == priv->back_button) + ev_history_go_back (priv->history); + else if (button == priv->forward_button) + ev_history_go_forward (priv->history); +} + +static gboolean +button_pressed (GtkWidget *button, + GdkEventButton *event, + EvHistoryActionWidget *history_widget) +{ + EvHistoryActionWidgetPrivate *priv = history_widget->priv; + + /* TODO: Show the popup menu after a long press too */ + switch (event->button) { + case GDK_BUTTON_SECONDARY: + ev_history_action_widget_show_popup (history_widget, + button == priv->back_button ? + EV_HISTORY_ACTION_BUTTON_BACK : + EV_HISTORY_ACTION_BUTTON_FORWARD, + event->button, event->time); + return GDK_EVENT_STOP; + default: + break; + } + + return GDK_EVENT_PROPAGATE; +} + +static gint +get_icon_margin (EvHistoryActionWidget *history_widget) +{ + gint toolbar_size_px, menu_size_px; + GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (history_widget)); + + gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &menu_size_px, NULL); + gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_LARGE_TOOLBAR, &toolbar_size_px, NULL); + + return (gint)floor ((toolbar_size_px - menu_size_px) / 2.0); +} + +static GtkWidget * +ev_history_action_widget_create_button (EvHistoryActionWidget *history_widget, + EvHistoryActionButton action_button) +{ + GtkWidget *button; + GtkWidget *image; + const gchar *icon_name = NULL; + const gchar *tooltip_text = NULL; + + button = gtk_button_new (); + g_signal_connect (button, "clicked", + G_CALLBACK (button_clicked), + history_widget); + g_signal_connect (button, "button-press-event", + G_CALLBACK (button_pressed), + history_widget); + + switch (action_button) { + case EV_HISTORY_ACTION_BUTTON_BACK: + icon_name = "go-previous-symbolic"; + tooltip_text = _("Go to previous history item"); + break; + case EV_HISTORY_ACTION_BUTTON_FORWARD: + icon_name = "go-next-symbolic"; + tooltip_text = _("Go to next history item"); + break; + } + + image = gtk_image_new (); + g_object_set (image, "margin", get_icon_margin (history_widget), NULL); + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_MENU); + gtk_widget_set_tooltip_text (button, tooltip_text); + gtk_widget_set_can_focus (button, FALSE); + + return button; +} + +static void +ev_history_action_widget_init (EvHistoryActionWidget *history_widget) +{ + EvHistoryActionWidgetPrivate *priv; + GtkWidget *box; + GtkStyleContext *style_context; + + history_widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (history_widget, EV_TYPE_HISTORY_ACTION_WIDGET, EvHistoryActionWidgetPrivate); + priv = history_widget->priv; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + style_context = gtk_widget_get_style_context (box); + gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_RAISED); + gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_LINKED); + + priv->back_button = ev_history_action_widget_create_button (history_widget, + EV_HISTORY_ACTION_BUTTON_BACK); + gtk_container_add (GTK_CONTAINER (box), priv->back_button); + gtk_widget_show (priv->back_button); + + priv->forward_button = ev_history_action_widget_create_button (history_widget, + EV_HISTORY_ACTION_BUTTON_FORWARD); + gtk_container_add (GTK_CONTAINER (box), priv->forward_button); + gtk_widget_show (priv->forward_button); + + gtk_container_add (GTK_CONTAINER (history_widget), box); + gtk_widget_show (box); + + gtk_widget_set_sensitive (priv->back_button, FALSE); + gtk_widget_set_sensitive (priv->forward_button, FALSE); +} + +static void +ev_history_action_widget_class_init (EvHistoryActionWidgetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = ev_history_action_widget_get_property; + object_class->finalize = ev_history_action_widget_finalize; + + g_object_class_install_property (object_class, + PROP_POPUP_SHOWN, + g_param_spec_boolean ("popup-shown", + "Popup shown", + "Whether the history's dropdown is shown", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private (object_class, sizeof (EvHistoryActionWidgetPrivate)); +} + +static void +history_changed_cb (EvHistory *history, + EvHistoryActionWidget *history_widget) +{ + EvHistoryActionWidgetPrivate *priv = history_widget->priv; + + gtk_widget_set_sensitive (priv->back_button, ev_history_can_go_back (history)); + gtk_widget_set_sensitive (priv->forward_button, ev_history_can_go_forward (history)); +} + +void +ev_history_action_widget_set_history (EvHistoryActionWidget *history_widget, + EvHistory *history) +{ + g_return_if_fail (EV_IS_HISTORY_ACTION_WIDGET (history_widget)); + + if (history_widget->priv->history == history) + return; + + if (history_widget->priv->history) { + g_object_remove_weak_pointer (G_OBJECT (history_widget->priv->history), + (gpointer)&history_widget->priv->history); + g_signal_handlers_disconnect_by_func (history_widget->priv->history, + G_CALLBACK (history_changed_cb), + history_widget); + } + + history_widget->priv->history = history; + if (!history) + return; + + g_object_add_weak_pointer (G_OBJECT (history), + (gpointer)&history_widget->priv->history); + + g_signal_connect (history, "changed", + G_CALLBACK (history_changed_cb), + history_widget); +} + diff --git a/shell/ev-history-action-widget.h b/shell/ev-history-action-widget.h new file mode 100644 index 00000000..befa24b2 --- /dev/null +++ b/shell/ev-history-action-widget.h @@ -0,0 +1,58 @@ +/* ev-history-action-widget.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2013 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EV_HISTORY_ACTION_WIDGET_H +#define EV_HISTORY_ACTION_WIDGET_H + +#include + +#include "ev-history.h" + +G_BEGIN_DECLS + +#define EV_TYPE_HISTORY_ACTION_WIDGET (ev_history_action_widget_get_type()) +#define EV_HISTORY_ACTION_WIDGET(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_HISTORY_ACTION_WIDGET, EvHistoryActionWidget)) +#define EV_IS_HISTORY_ACTION_WIDGET(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_HISTORY_ACTION_WIDGET)) +#define EV_HISTORY_ACTION_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_HISTORY_ACTION_WIDGET, EvHistoryActionWidgetClass)) +#define EV_IS_HISTORY_ACTION_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_HISTORY_ACTION_WIDGET)) +#define EV_HISTORY_ACTION_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_HISTORY_ACTION_WIDGET, EvHistoryActionWidgetClass)) + +typedef struct _EvHistoryActionWidget EvHistoryActionWidget; +typedef struct _EvHistoryActionWidgetClass EvHistoryActionWidgetClass; +typedef struct _EvHistoryActionWidgetPrivate EvHistoryActionWidgetPrivate; + +struct _EvHistoryActionWidget { + GtkToolItem parent_object; + + EvHistoryActionWidgetPrivate *priv; +}; + +struct _EvHistoryActionWidgetClass { + GtkToolItemClass parent_class; +}; + +GType ev_history_action_widget_get_type (void); + +void ev_history_action_widget_set_history (EvHistoryActionWidget *history_widget, + EvHistory *history); + +G_END_DECLS + +#endif diff --git a/shell/ev-history-action.c b/shell/ev-history-action.c new file mode 100644 index 00000000..cda9fc1f --- /dev/null +++ b/shell/ev-history-action.c @@ -0,0 +1,119 @@ +/* ev-history-action.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2013 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ev-history-action.h" +#include "ev-history-action-widget.h" + +enum { + ACTIVATED, + LAST_SIGNAL +}; + + +struct _EvHistoryActionPrivate { + EvHistory *history; + gboolean popup_shown; +}; + +G_DEFINE_TYPE (EvHistoryAction, ev_history_action, GTK_TYPE_ACTION) + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +popup_shown_cb (GObject *history_widget, + GParamSpec *pspec, + EvHistoryAction *history_action) +{ + g_object_get (history_widget, "popup-shown", &history_action->priv->popup_shown, NULL); +} + +static void +connect_proxy (GtkAction *action, + GtkWidget *proxy) +{ + if (EV_IS_HISTORY_ACTION_WIDGET (proxy)) { + EvHistoryAction *history_action = EV_HISTORY_ACTION (action); + EvHistoryActionWidget *history_widget = EV_HISTORY_ACTION_WIDGET (proxy); + + ev_history_action_widget_set_history (history_widget, history_action->priv->history); + g_signal_connect (history_widget, "notify::popup-shown", + G_CALLBACK (popup_shown_cb), + action); + } + + GTK_ACTION_CLASS (ev_history_action_parent_class)->connect_proxy (action, proxy); +} + +static void +ev_history_action_class_init (EvHistoryActionClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkActionClass *action_class = GTK_ACTION_CLASS (class); + + action_class->toolbar_item_type = EV_TYPE_HISTORY_ACTION_WIDGET; + action_class->connect_proxy = connect_proxy; + + signals[ACTIVATED] = + g_signal_new ("activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (object_class, sizeof (EvHistoryActionPrivate)); +} + +static void +ev_history_action_init (EvHistoryAction *action) +{ + action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action, EV_TYPE_HISTORY_ACTION, EvHistoryActionPrivate); +} + +void +ev_history_action_set_history (EvHistoryAction *action, + EvHistory *history) +{ + GSList *proxies, *l; + + g_return_if_fail (EV_IS_HISTORY_ACTION (action)); + g_return_if_fail (EV_IS_HISTORY (history)); + + if (action->priv->history == history) + return; + + action->priv->history = history; + proxies = gtk_action_get_proxies (GTK_ACTION (action)); + for (l = proxies; l && l->data; l = g_slist_next (l)) { + if (EV_IS_HISTORY_ACTION_WIDGET (l->data)) + ev_history_action_widget_set_history (EV_HISTORY_ACTION_WIDGET (l->data), history); + } +} + +gboolean +ev_history_action_get_popup_shown (EvHistoryAction *action) +{ + g_return_val_if_fail (EV_IS_HISTORY_ACTION (action), FALSE); + + return action->priv->popup_shown; +} + diff --git a/shell/ev-history-action.h b/shell/ev-history-action.h new file mode 100644 index 00000000..48b3160a --- /dev/null +++ b/shell/ev-history-action.h @@ -0,0 +1,59 @@ +/* ev-history-action.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2013 Carlos Garcia Campos + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EV_HISTORY_ACTION_H +#define EV_HISTORY_ACTION_H + +#include + +#include "ev-history.h" + +G_BEGIN_DECLS + +#define EV_TYPE_HISTORY_ACTION (ev_history_action_get_type ()) +#define EV_HISTORY_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_HISTORY_ACTION, EvHistoryAction)) +#define EV_IS_HISTORY_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_HISTORY_ACTION)) +#define EV_HISTORY_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_HISTORY_ACTION, EvHistoryActionClass)) +#define EV_IS_HISTORY_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_HISTORY_ACTION)) +#define EV_HISTORY_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_HISTORY_ACTION, EvHistoryActionClass)) + +typedef struct _EvHistoryAction EvHistoryAction; +typedef struct _EvHistoryActionClass EvHistoryActionClass; +typedef struct _EvHistoryActionPrivate EvHistoryActionPrivate; + +struct _EvHistoryAction { + GtkAction parent; + + EvHistoryActionPrivate *priv; +}; + +struct _EvHistoryActionClass { + GtkActionClass parent_class; +}; + +GType ev_history_action_get_type (void); + +void ev_history_action_set_history (EvHistoryAction *action, + EvHistory *history); +gboolean ev_history_action_get_popup_shown (EvHistoryAction *action); + +G_END_DECLS + +#endif diff --git a/shell/ev-history.c b/shell/ev-history.c index 9b59014c..0f3ee2d1 100644 --- a/shell/ev-history.c +++ b/shell/ev-history.c @@ -24,40 +24,40 @@ #include "ev-history.h" +enum { + CHANGED, + ACTIVATE_LINK, -enum -{ - HISTORY_CHANGED, N_SIGNALS }; static guint signals[N_SIGNALS] = {0, }; -struct _EvHistoryPrivate -{ - GList *links; -}; +struct _EvHistoryPrivate { + EvLink *current; + GList *back_list; + GList *forward_list; -static void ev_history_init (EvHistory *history); -static void ev_history_class_init (EvHistoryClass *class); + EvDocumentModel *model; + gulong page_changed_handler_id; + gboolean activating_current_link; +}; G_DEFINE_TYPE (EvHistory, ev_history, G_TYPE_OBJECT) -#define EV_HISTORY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_HISTORY, EvHistoryPrivate)) +static void ev_history_set_model (EvHistory *history, + EvDocumentModel *model); static void -ev_history_init (EvHistory *history) +ev_history_clear (EvHistory *history) { - history->priv = EV_HISTORY_GET_PRIVATE (history); + g_clear_object (&history->priv->current); - history->priv->links = NULL; -} + g_list_free_full (history->priv->back_list, (GDestroyNotify)g_object_unref); + history->priv->back_list = NULL; -static void -free_links_list (GList *l) -{ - g_list_foreach (l, (GFunc)g_object_unref, NULL); - g_list_free (l); + g_list_free_full (history->priv->forward_list, (GDestroyNotify)g_object_unref); + history->priv->forward_list = NULL; } static void @@ -65,7 +65,8 @@ ev_history_finalize (GObject *object) { EvHistory *history = EV_HISTORY (object); - free_links_list (history->priv->links); + ev_history_clear (history); + ev_history_set_model (history, NULL); G_OBJECT_CLASS (ev_history_parent_class)->finalize (object); } @@ -77,72 +78,347 @@ ev_history_class_init (EvHistoryClass *class) object_class->finalize = ev_history_finalize; - signals[HISTORY_CHANGED] = - g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EvHistoryClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvHistoryClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[ACTIVATE_LINK] = + g_signal_new ("activate-link", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvHistoryClass, activate_link), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); g_type_class_add_private (object_class, sizeof (EvHistoryPrivate)); } -#define HISTORY_LENGTH 7 +static void +ev_history_init (EvHistory *history) +{ + history->priv = G_TYPE_INSTANCE_GET_PRIVATE (history, EV_TYPE_HISTORY, EvHistoryPrivate); +} void -ev_history_add_link (EvHistory *history, EvLink *link) +ev_history_add_link (EvHistory *history, + EvLink *link) { - GList *l; - g_return_if_fail (EV_IS_HISTORY (history)); g_return_if_fail (EV_IS_LINK (link)); - for (l = history->priv->links; l; l = l->next) { - if (!strcmp (ev_link_get_title (EV_LINK (l->data)), ev_link_get_title (link))) { - g_object_unref (G_OBJECT (l->data)); - history->priv->links = g_list_delete_link (history->priv->links, l); - break; - } - } + if (history->priv->activating_current_link) + return; + + if (ev_history_go_to_link (history, link)) + return; + + if (history->priv->current) { + history->priv->back_list = g_list_prepend (history->priv->back_list, + history->priv->current); + } + + history->priv->current = g_object_ref (link); + + g_list_free_full (history->priv->forward_list, (GDestroyNotify)g_object_unref); + history->priv->forward_list = NULL; + + /* TODO: Decide a history limit and delete old links when the limit is reached */ + + g_signal_emit (history, signals[CHANGED], 0); +} + +static void +ev_history_activate_current_link (EvHistory *history) +{ + history->priv->activating_current_link = TRUE; + g_signal_handler_block (history->priv->model, history->priv->page_changed_handler_id); + g_signal_emit (history, signals[ACTIVATE_LINK], 0, history->priv->current); + g_signal_handler_unblock (history->priv->model, history->priv->page_changed_handler_id); + history->priv->activating_current_link = FALSE; + + g_signal_emit (history, signals[CHANGED], 0); +} + +gboolean +ev_history_can_go_back (EvHistory *history) +{ + g_return_val_if_fail (EV_IS_HISTORY (history), FALSE); - g_object_ref (link); - history->priv->links = g_list_append (history->priv->links, - link); - - if (g_list_length (history->priv->links) > HISTORY_LENGTH) { - g_object_unref (G_OBJECT (history->priv->links->data)); - history->priv->links = g_list_delete_link (history->priv->links, - history->priv->links); - } - - g_signal_emit (history, signals[HISTORY_CHANGED], 0); + return history->priv->back_list != NULL; } -EvLink * -ev_history_get_link_nth (EvHistory *history, int index) +void +ev_history_go_back (EvHistory *history) { - GList *l; + g_return_if_fail (EV_IS_HISTORY (history)); - g_return_val_if_fail (EV_IS_HISTORY (history), NULL); + if (!history->priv->current || !history->priv->back_list) + return; - l = g_list_nth (history->priv->links, index); + history->priv->forward_list = g_list_prepend (history->priv->forward_list, + history->priv->current); + history->priv->current = EV_LINK (history->priv->back_list->data); + history->priv->back_list = g_list_delete_link (history->priv->back_list, + history->priv->back_list); - return EV_LINK (l->data); + ev_history_activate_current_link (history); } -int -ev_history_get_n_links (EvHistory *history) +gboolean +ev_history_can_go_forward (EvHistory *history) { - g_return_val_if_fail (EV_IS_HISTORY (history), -1); + g_return_val_if_fail (EV_IS_HISTORY (history), FALSE); - return g_list_length (history->priv->links); + return history->priv->forward_list != NULL; } -EvHistory * -ev_history_new (void) +void +ev_history_go_forward (EvHistory *history) +{ + g_return_if_fail (EV_IS_HISTORY (history)); + + if (!history->priv->current || !history->priv->forward_list) + return; + + history->priv->back_list = g_list_prepend (history->priv->back_list, + history->priv->current); + history->priv->current = EV_LINK (history->priv->forward_list->data); + history->priv->forward_list = g_list_delete_link (history->priv->forward_list, + history->priv->forward_list); + + ev_history_activate_current_link (history); +} + +static gint +compare_link (EvLink *a, + EvLink *b) +{ + if (a == b) + return 0; + + return ev_link_action_equal (ev_link_get_action (a), ev_link_get_action (b)) ? 0 : 1; +} + +gboolean +ev_history_go_to_link (EvHistory *history, + EvLink *link) { - return EV_HISTORY (g_object_new (EV_TYPE_HISTORY, NULL)); + GList *l; + + g_return_val_if_fail (EV_IS_HISTORY (history), FALSE); + g_return_val_if_fail (EV_IS_LINK (link), FALSE); + + if (!history->priv->current || (!history->priv->back_list && !history->priv->forward_list)) + return FALSE; + + l = g_list_find_custom (history->priv->back_list, link, (GCompareFunc)compare_link); + if (l) { + if (l->next) + l->next->prev = NULL; + if (l->prev) + l->prev->next = NULL; + + history->priv->forward_list = g_list_prepend (history->priv->forward_list, + history->priv->current); + history->priv->forward_list = g_list_concat (g_list_reverse (history->priv->back_list), + history->priv->forward_list); + history->priv->back_list = l->next; + history->priv->current = EV_LINK (l->data); + g_list_free_1 (l); + + ev_history_activate_current_link (history); + + return TRUE; + } + + l = g_list_find_custom (history->priv->forward_list, link, (GCompareFunc)compare_link); + if (l) { + if (l->next) + l->next->prev = NULL; + if (l->prev) + l->prev->next = NULL; + + history->priv->back_list = g_list_prepend (history->priv->back_list, + history->priv->current); + history->priv->back_list = g_list_concat (g_list_reverse (history->priv->forward_list), + history->priv->back_list); + history->priv->forward_list = l->next; + history->priv->current = EV_LINK (l->data); + g_list_free_1 (l); + + ev_history_activate_current_link (history); + + return TRUE; + } + + return FALSE; } +GList * +ev_history_get_back_list (EvHistory *history) +{ + g_return_val_if_fail (EV_IS_HISTORY (history), NULL); + + return history->priv->back_list; +} + +GList * +ev_history_get_forward_list (EvHistory *history) +{ + g_return_val_if_fail (EV_IS_HISTORY (history), NULL); + + return history->priv->forward_list; +} + +static gint +ev_history_get_current_page (EvHistory *history) +{ + EvDocument *document; + EvLinkDest *dest; + EvLinkAction *action; + + if (!history->priv->current) + return -1; + + action = ev_link_get_action (history->priv->current); + if (!action) + return -1; + + dest = ev_link_action_get_dest (action); + if (!dest) + return -1; + + switch (ev_link_dest_get_dest_type (dest)) { + case EV_LINK_DEST_TYPE_NAMED: + document = ev_document_model_get_document (history->priv->model); + if (!EV_IS_DOCUMENT_LINKS (document)) + return -1; + + return ev_document_links_find_link_page (EV_DOCUMENT_LINKS (document), + ev_link_dest_get_named_dest (dest)); + case EV_LINK_DEST_TYPE_PAGE_LABEL: { + gint page = -1; + + document = ev_document_model_get_document (history->priv->model); + ev_document_find_page_by_label (document, + ev_link_dest_get_page_label (dest), + &page); + + return page; + } + default: + return ev_link_dest_get_page (dest); + } + + return -1; +} + +static void +ev_history_add_link_for_page (EvHistory *history, + gint page) +{ + EvDocument *document; + EvLinkDest *dest; + EvLinkAction *action; + EvLink *link; + gchar *page_label; + gchar *title; + + if (ev_history_get_current_page (history) == page) + return; + + document = ev_document_model_get_document (history->priv->model); + if (!document) + return; + + page_label = ev_document_get_page_label (document, page); + if (!page_label) + return; + + title = g_strdup_printf (_("Page %s"), page_label); + g_free (page_label); + + dest = ev_link_dest_new_page (page); + action = ev_link_action_new_dest (dest); + g_object_unref (dest); + + link = ev_link_new (title, action); + g_object_unref (action); + g_free (title); + + ev_history_add_link (history, link); + g_object_unref (link); +} + +static void +page_changed_cb (EvDocumentModel *model, + gint old_page, + gint new_page, + EvHistory *history) +{ + if (ABS (new_page - old_page) > 1) + ev_history_add_link_for_page (history, new_page); +} + +static void +document_changed_cb (EvDocumentModel *model, + GParamSpec *pspec, + EvHistory *history) +{ + ev_history_clear (history); + ev_history_add_link_for_page (history, ev_document_model_get_page (model)); +} + +static void +ev_history_set_model (EvHistory *history, + EvDocumentModel *model) +{ + if (history->priv->model == model) + return; + + if (history->priv->model) { + g_object_remove_weak_pointer (G_OBJECT (history->priv->model), + (gpointer)&history->priv->model); + + if (history->priv->page_changed_handler_id) { + g_signal_handler_disconnect (history->priv->model, + history->priv->page_changed_handler_id); + history->priv->page_changed_handler_id = 0; + } + } + + history->priv->model = model; + if (!model) + return; + + g_object_add_weak_pointer (G_OBJECT (model), + (gpointer)&history->priv->model); + + g_signal_connect (history->priv->model, "notify::document", + G_CALLBACK (document_changed_cb), + history); + history->priv->page_changed_handler_id = + g_signal_connect (history->priv->model, "page-changed", + G_CALLBACK (page_changed_cb), + history); +} + +EvHistory * +ev_history_new (EvDocumentModel *model) +{ + EvHistory *history; + + g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), NULL); + + history = EV_HISTORY (g_object_new (EV_TYPE_HISTORY, NULL)); + ev_history_set_model (history, model); + + return history; +} diff --git a/shell/ev-history.h b/shell/ev-history.h index d8bb53f5..02604c79 100644 --- a/shell/ev-history.h +++ b/shell/ev-history.h @@ -21,8 +21,8 @@ #define EV_HISTORY_H #include - -#include "ev-link.h" +#include +#include G_BEGIN_DECLS @@ -40,7 +40,7 @@ typedef struct _EvHistoryClass EvHistoryClass; struct _EvHistory { GObject parent; - + /*< private >*/ EvHistoryPrivate *priv; }; @@ -48,17 +48,24 @@ struct _EvHistory struct _EvHistoryClass { GObjectClass parent_class; - - void (*changed) (EvHistory *history); + + void (* changed) (EvHistory *history); + void (* activate_link) (EvHistory *history, + EvLink *link); }; -GType ev_history_get_type (void); -EvHistory *ev_history_new (void); -void ev_history_add_link (EvHistory *history, - EvLink *linkk); -EvLink *ev_history_get_link_nth (EvHistory *history, - int index); -int ev_history_get_n_links (EvHistory *history); +GType ev_history_get_type (void); +EvHistory *ev_history_new (EvDocumentModel *model); +void ev_history_add_link (EvHistory *history, + EvLink *link); +gboolean ev_history_can_go_back (EvHistory *history); +void ev_history_go_back (EvHistory *history); +gboolean ev_history_can_go_forward (EvHistory *history); +void ev_history_go_forward (EvHistory *history); +gboolean ev_history_go_to_link (EvHistory *history, + EvLink *link); +GList *ev_history_get_back_list (EvHistory *history); +GList *ev_history_get_forward_list (EvHistory *history); G_END_DECLS diff --git a/shell/ev-navigation-action-widget.c b/shell/ev-navigation-action-widget.c deleted file mode 100644 index c3de6958..00000000 --- a/shell/ev-navigation-action-widget.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2003, 2004 Marco Pesenti Gritti - * Copyright (C) 2003, 2004 Christian Persch - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "ev-navigation-action-widget.h" - -#include -#include - -static void ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget); -static void ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *action_widget); -static void ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle); -static gboolean ev_navigation_action_widget_button_press_event (GtkWidget *widget, - GdkEventButton *event, - gpointer data); - -G_DEFINE_TYPE (EvNavigationActionWidget, ev_navigation_action_widget, GTK_TYPE_TOGGLE_TOOL_BUTTON) - -enum -{ - SHOW_MENU, - LAST_SIGNAL -}; - -static gint signals[LAST_SIGNAL]; - -static void -ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget) -{ - GtkWidget *toggle_button; - - /* It's rather dirty hack but we need a child to connect to - * button press event - */ - - toggle_button = gtk_bin_get_child (GTK_BIN (action_widget)); - - g_signal_connect (toggle_button, "button-press-event", - G_CALLBACK (ev_navigation_action_widget_button_press_event), - action_widget); - return; -} - -static void -ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *klass) -{ - GtkToggleToolButtonClass *toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (klass); - - toggle_tool_button_class->toggled = ev_navigation_action_widget_toggled; - - signals[SHOW_MENU] = - g_signal_new ("show-menu", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EvNavigationActionWidgetClass, show_menu), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static int -menu_deactivate_cb (GtkMenuShell *menu_shell, - EvNavigationActionWidget *widget) -{ - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (widget), FALSE); - return TRUE; -} - -static void -menu_detacher (GtkWidget *widget, - GtkMenu *menu) -{ - EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (widget); - g_return_if_fail (button->menu == menu); - button->menu = NULL; -} - -void -ev_navigation_action_widget_set_menu(EvNavigationActionWidget *button, GtkWidget *menu) -{ - - if (button->menu == GTK_MENU (menu)) - return; - - if (button->menu && gtk_widget_get_visible (GTK_WIDGET (button->menu))) - gtk_menu_shell_deactivate (GTK_MENU_SHELL (button->menu)); - - if (button->menu) { - g_signal_handlers_disconnect_by_func (button->menu, - menu_deactivate_cb, - button); - gtk_menu_detach (button->menu); - } - - button->menu = GTK_MENU (menu); - - if (button->menu) { - gtk_menu_attach_to_widget (button->menu, GTK_WIDGET (button), - menu_detacher); - g_signal_connect (button->menu, "deactivate", - G_CALLBACK (menu_deactivate_cb), button); - } -} - -static void -menu_position_func (GtkMenu *menu, - int *x, - int *y, - gboolean *push_in, - EvNavigationActionWidget *button) -{ - GtkWidget *widget = GTK_WIDGET (button); - GtkRequisition menu_req; - GtkAllocation allocation; - GtkTextDirection direction; - GdkWindow *gdk_window; - GdkRectangle monitor; - gint monitor_num; - GdkScreen *screen; - - gtk_widget_get_preferred_size (GTK_WIDGET (button->menu), &menu_req, NULL); - direction = gtk_widget_get_direction (widget); - screen = gtk_widget_get_screen (GTK_WIDGET (menu)); - - gdk_window = gtk_widget_get_window (widget); - monitor_num = gdk_screen_get_monitor_at_window (screen, gdk_window); - if (monitor_num < 0) - monitor_num = 0; - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); - - gdk_window_get_origin (gdk_window, x, y); - gtk_widget_get_allocation (widget, &allocation); - *x += allocation.x; - *y += allocation.y; - - if (direction == GTK_TEXT_DIR_LTR) - *x += MAX (allocation.width - menu_req.width, 0); - else if (menu_req.width > allocation.width) - *x -= menu_req.width - allocation.width; - - if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height) - *y += allocation.height; - else if ((*y - menu_req.height) >= monitor.y) - *y -= menu_req.height; - else if (monitor.y + monitor.height - (*y + allocation.height) > *y) - *y += allocation.height; - else - *y -= menu_req.height; - - *push_in = FALSE; -} - -static void -popup_menu_under_arrow (EvNavigationActionWidget *button, - GdkEventButton *event) -{ - g_signal_emit (button, signals[SHOW_MENU], 0); - - if (!button->menu) - return; - - gtk_menu_popup (button->menu, NULL, NULL, - (GtkMenuPositionFunc) menu_position_func, - button, - event ? event->button : 0, - event ? event->time : gtk_get_current_event_time ()); -} - -static void -ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle) -{ - EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (toggle); - if (!button->menu) - return; - - if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)) && - !gtk_widget_get_visible (GTK_WIDGET (button->menu))) { - /* we get here only when the menu is activated by a key - * press, so that we can select the first menu item */ - popup_menu_under_arrow (button, NULL); - gtk_menu_shell_select_first (GTK_MENU_SHELL (button->menu), FALSE); - } -} - -static gboolean -ev_navigation_action_widget_button_press_event (GtkWidget *widget, - GdkEventButton *event, - gpointer data) -{ - EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (data); - - if (event->button == 1) { - popup_menu_under_arrow (button, event); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button), TRUE); - return TRUE; - } - return FALSE; -} diff --git a/shell/ev-navigation-action-widget.h b/shell/ev-navigation-action-widget.h deleted file mode 100644 index 4241cd31..00000000 --- a/shell/ev-navigation-action-widget.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2003, 2004 Marco Pesenti Gritti - * Copyright (C) 2003, 2004 Christian Persch - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include - -#define EV_TYPE_NAVIGATION_ACTION_WIDGET (ev_navigation_action_widget_get_type ()) -#define EV_NAVIGATION_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_NAVIGATION_ACTION_WIDGET, EvNavigationActionWidget)) - -typedef struct _EvNavigationActionWidget EvNavigationActionWidget; -typedef struct _EvNavigationActionWidgetClass EvNavigationActionWidgetClass; - -struct _EvNavigationActionWidget -{ - GtkToggleToolButton parent; - - GtkMenu *menu; -}; - -struct _EvNavigationActionWidgetClass -{ - GtkToggleToolButtonClass parent_class; - - void (*show_menu) (EvNavigationActionWidget *widget); -}; - -GType ev_navigation_action_widget_get_type (void); - -void -ev_navigation_action_widget_set_menu(EvNavigationActionWidget *widget, GtkWidget *menu); diff --git a/shell/ev-navigation-action.c b/shell/ev-navigation-action.c deleted file mode 100644 index b34c3789..00000000 --- a/shell/ev-navigation-action.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2003, 2004 Marco Pesenti Gritti - * Copyright (C) 2003, 2004 Christian Persch - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" - -#include -#include - -#include "ev-navigation-action.h" -#include "ev-navigation-action-widget.h" - - -enum -{ - WIDGET_ACTIVATE_LINK, - WIDGET_N_SIGNALS -}; - -static guint widget_signals[WIDGET_N_SIGNALS] = {0, }; - -struct _EvNavigationActionPrivate -{ - EvHistory *history; -}; - -static void ev_navigation_action_init (EvNavigationAction *action); -static void ev_navigation_action_class_init (EvNavigationActionClass *class); - -G_DEFINE_TYPE (EvNavigationAction, ev_navigation_action, GTK_TYPE_ACTION) - -#define MAX_LABEL_LENGTH 48 - -#define EV_NAVIGATION_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionPrivate)) - -static void -ev_navigation_action_history_changed (EvHistory *history, - gpointer data) -{ - EvNavigationAction *action = EV_NAVIGATION_ACTION (data); - - gtk_action_set_sensitive (GTK_ACTION (action), - ev_history_get_n_links (history) > 0); -} - -void -ev_navigation_action_set_history (EvNavigationAction *action, - EvHistory *history) -{ - action->priv->history = history; - - g_object_add_weak_pointer (G_OBJECT (action->priv->history), - (gpointer) &action->priv->history); - - g_signal_connect_object (history, "changed", - G_CALLBACK (ev_navigation_action_history_changed), - action, 0); -} - -static void -activate_menu_item_cb (GtkWidget *widget, EvNavigationAction *action) -{ - int index; - - g_return_if_fail (EV_IS_HISTORY (action->priv->history)); - - index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "index")); - - if (action->priv->history) { - EvLink *link; - - link = ev_history_get_link_nth (action->priv->history, index); - - g_signal_emit (action, widget_signals[WIDGET_ACTIVATE_LINK], 0, link); - } -} - -static GtkWidget * -new_history_menu_item (EvNavigationAction *action, - EvLink *link, - int index) -{ - GtkLabel *label; - GtkWidget *item; - const char *title; - - title = ev_link_get_title (link); - item = gtk_image_menu_item_new_with_label (title); - label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (item))); - gtk_label_set_use_markup (label, TRUE); - g_object_set_data (G_OBJECT (item), "index", - GINT_TO_POINTER (index)); - - gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END); - gtk_label_set_max_width_chars (label, MAX_LABEL_LENGTH); - - g_signal_connect (item, "activate", - G_CALLBACK (activate_menu_item_cb), - action); - - gtk_widget_show (item); - - return item; -} - -static GtkWidget * -build_menu (EvNavigationAction *action) -{ - GtkMenuShell *menu; - GtkWidget *item; - EvLink *link; - EvHistory *history = action->priv->history; - int start, end, i; - - if (history == NULL || ev_history_get_n_links (history) <= 0) { - return NULL; - } - - menu = GTK_MENU_SHELL (gtk_menu_new ()); - - start = 0; - end = ev_history_get_n_links (history); - - for (i = start; i < end; i++) { - link = ev_history_get_link_nth (history, i); - item = new_history_menu_item (action, link, i); - gtk_menu_shell_prepend (menu, item); - } - - return GTK_WIDGET (menu); -} - -static void -menu_activated_cb (EvNavigationActionWidget *button, - EvNavigationAction *action) -{ - GtkWidget *menu; - - menu = build_menu (action); - ev_navigation_action_widget_set_menu (button, menu); -} - -static void -connect_proxy (GtkAction *action, GtkWidget *proxy) -{ - GtkWidget *menu; - - if (GTK_IS_TOOL_ITEM (proxy)) { - /* set dummy menu so the arrow gets sensitive */ - menu = gtk_menu_new (); - ev_navigation_action_widget_set_menu (EV_NAVIGATION_ACTION_WIDGET (proxy), menu); - - g_signal_connect (proxy, "show-menu", - G_CALLBACK (menu_activated_cb), action); - } - - GTK_ACTION_CLASS (ev_navigation_action_parent_class)->connect_proxy (action, proxy); -} - -static GtkWidget * -create_tool_item (GtkAction *action) -{ - EvNavigationActionWidget *proxy; - - proxy = g_object_new (EV_TYPE_NAVIGATION_ACTION_WIDGET, NULL); - gtk_widget_show (GTK_WIDGET (proxy)); - - return GTK_WIDGET (proxy); -} - -static GtkWidget * -create_menu_item (GtkAction *action) -{ - GtkWidget *menu; - GtkWidget *menu_item; - - menu = build_menu (EV_NAVIGATION_ACTION (action)); - - menu_item = GTK_ACTION_CLASS (ev_navigation_action_parent_class)->create_menu_item (action); - - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); - - gtk_widget_show (menu_item); - - return menu_item; -} - -static void -ev_navigation_action_init (EvNavigationAction *action) -{ - action->priv = EV_NAVIGATION_ACTION_GET_PRIVATE (action); -} - -static void -ev_navigation_action_finalize (GObject *object) -{ - EvNavigationAction *action = EV_NAVIGATION_ACTION (object); - - if (action->priv->history) { - g_object_remove_weak_pointer (G_OBJECT (action->priv->history), - (gpointer) &action->priv->history); - action->priv->history = NULL; - } - - G_OBJECT_CLASS (ev_navigation_action_parent_class)->finalize (object); -} - -static void -ev_navigation_action_class_init (EvNavigationActionClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - GtkActionClass *action_class = GTK_ACTION_CLASS (class); - - object_class->finalize = ev_navigation_action_finalize; - - action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM; - action_class->create_tool_item = create_tool_item; - action_class->connect_proxy = connect_proxy; - action_class->create_menu_item = create_menu_item; - - widget_signals[WIDGET_ACTIVATE_LINK] = g_signal_new ("activate_link", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EvNavigationActionClass, activate_link), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); - - g_type_class_add_private (object_class, sizeof (EvNavigationActionPrivate)); -} diff --git a/shell/ev-navigation-action.h b/shell/ev-navigation-action.h deleted file mode 100644 index 8089e4f4..00000000 --- a/shell/ev-navigation-action.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2003, 2004 Marco Pesenti Gritti - * Copyright (C) 2003, 2004 Christian Persch - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef EV_NAVIGATION_ACTION_H -#define EV_NAVIGATION_ACTION_H - -#include - -#include "ev-history.h" -#include "ev-link.h" - -G_BEGIN_DECLS - -#define EV_TYPE_NAVIGATION_ACTION (ev_navigation_action_get_type ()) -#define EV_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_NAVIGATION_ACTION, EvNavigationAction)) -#define EV_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionClass)) -#define EV_IS_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_NAVIGATION_ACTION)) -#define EV_IS_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_NAVIGATION_ACTION)) -#define EV_NAVIGATION_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_NAVIGATION_ACTION, EvNavigationActionClass)) - -typedef struct _EvNavigationAction EvNavigationAction; -typedef struct _EvNavigationActionPrivate EvNavigationActionPrivate; -typedef struct _EvNavigationActionClass EvNavigationActionClass; - -struct _EvNavigationAction -{ - GtkAction parent; - - /*< private >*/ - EvNavigationActionPrivate *priv; -}; - -struct _EvNavigationActionClass -{ - GtkActionClass parent_class; - - void (* activate_link) (EvNavigationAction *action, - EvLink *link); -}; - -GType ev_navigation_action_get_type (void); -void ev_navigation_action_set_history (EvNavigationAction *action, - EvHistory *history); - -G_END_DECLS - -#endif diff --git a/shell/ev-toolbar.c b/shell/ev-toolbar.c index 20d3acaa..a408769b 100644 --- a/shell/ev-toolbar.c +++ b/shell/ev-toolbar.c @@ -26,6 +26,7 @@ #include "ev-stock-icons.h" #include "ev-zoom-action.h" +#include "ev-history-action.h" #include enum @@ -203,6 +204,13 @@ ev_toolbar_constructed (GObject *object) gtk_container_add (GTK_CONTAINER (ev_toolbar), tool_item); gtk_widget_show (tool_item); + /* History */ + action = gtk_action_group_get_action (action_group, "History"); + tool_item = gtk_action_create_tool_item (action); + gtk_widget_set_margin_right (tool_item, 12); + gtk_container_add (GTK_CONTAINER (ev_toolbar), tool_item); + gtk_widget_show (tool_item); + /* Zoom selector */ action = gtk_action_group_get_action (action_group, "ViewZoom"); tool_item = gtk_action_create_tool_item (action); @@ -314,6 +322,10 @@ ev_toolbar_has_visible_popups (EvToolbar *ev_toolbar) if (ev_zoom_action_get_popup_shown (EV_ZOOM_ACTION (action))) return TRUE; + action = gtk_action_group_get_action (action_group, "History"); + if (ev_history_action_get_popup_shown (EV_HISTORY_ACTION (action))) + return TRUE; + return FALSE; } diff --git a/shell/ev-window.c b/shell/ev-window.c index 009a67e0..2a3e67df 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -62,9 +62,9 @@ #include "ev-loading-message.h" #include "ev-message-area.h" #include "ev-metadata.h" -#include "ev-navigation-action.h" #include "ev-open-recent-action.h" #include "ev-page-action.h" +#include "ev-history-action.h" #include "ev-password-view.h" #include "ev-properties-dialog.h" #include "ev-sidebar-annotations.h" @@ -237,7 +237,7 @@ struct _EvWindowPrivate { #define PAGE_SELECTOR_ACTION "PageSelector" #define ZOOM_CONTROL_ACTION "ViewZoom" -#define NAVIGATION_ACTION "Navigation" +#define HISTORY_ACTION "History" #define GS_LOCKDOWN_SCHEMA_NAME "org.gnome.desktop.lockdown" #define GS_LOCKDOWN_SAVE "disable-save-to-disk" @@ -481,7 +481,6 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) /* Toolbar-specific actions: */ ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages); ev_window_set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION, has_pages); - ev_window_set_action_sensitive (ev_window, NAVIGATION_ACTION, FALSE); ev_window_update_actions_sensitivity (ev_window); } @@ -801,122 +800,98 @@ ev_window_hide_loading_message (EvWindow *window) gtk_widget_hide (window->priv->loading_message); } -typedef struct _PageTitleData { - const gchar *page_label; - gchar *page_title; -} PageTitleData; +typedef struct _LinkTitleData { + EvLink *link; + const gchar *link_title; +} LinkTitleData; static gboolean -ev_window_find_page_title (GtkTreeModel *tree_model, - GtkTreePath *path, - GtkTreeIter *iter, - PageTitleData *data) +find_link_cb (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + LinkTitleData *data) { - gchar *page_string; - + EvLink *link; + gboolean retval = FALSE; + gtk_tree_model_get (tree_model, iter, - EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, &page_string, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - - if (!page_string) - return FALSE; - - if (!strcmp (page_string, data->page_label)) { - gtk_tree_model_get (tree_model, iter, - EV_DOCUMENT_LINKS_COLUMN_MARKUP, &data->page_title, - -1); - g_free (page_string); - return TRUE; + if (!link) + return retval; + + if (ev_link_action_equal (ev_link_get_action (data->link), ev_link_get_action (link))) { + data->link_title = ev_link_get_title (link); + retval = TRUE; } - - g_free (page_string); - return FALSE; + + g_object_unref (link); + + return retval; } -static gchar * -ev_window_get_page_title (EvWindow *window, - const gchar *page_label) +static const gchar * +ev_window_find_title_for_link (EvWindow *window, + EvLink *link) { if (EV_IS_DOCUMENT_LINKS (window->priv->document) && ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) { - PageTitleData data; + LinkTitleData data; GtkTreeModel *model; - data.page_label = page_label; - data.page_title = NULL; + data.link = link; + data.link_title = NULL; g_object_get (G_OBJECT (window->priv->sidebar_links), "model", &model, NULL); if (model) { gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc)ev_window_find_page_title, + (GtkTreeModelForeachFunc)find_link_cb, &data); g_object_unref (model); } - return data.page_title; + return data.link_title; } return NULL; } static void -ev_window_add_history (EvWindow *window, gint page, EvLink *link) +view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window) { - gchar *page_label = NULL; - gchar *page_title; - gchar *link_title; - EvLink *real_link; - EvLinkAction *action; - EvLinkDest *dest; - - if (window->priv->history == NULL) - return; + EvLink *new_link = NULL; - if (!EV_IS_DOCUMENT_LINKS (window->priv->document)) - return; - - if (link) { - action = g_object_ref (ev_link_get_action (link)); - dest = ev_link_action_get_dest (action); - page_label = ev_document_links_get_dest_page_label (EV_DOCUMENT_LINKS (window->priv->document), dest); - } else { - dest = ev_link_dest_new_page (page); - action = ev_link_action_new_dest (dest); - g_object_unref (dest); - page_label = ev_document_get_page_label (window->priv->document, page); - } + if (!ev_link_get_title (link)) { + const gchar *link_title; - if (!page_label) - return; - - page_title = ev_window_get_page_title (window, page_label); - if (page_title) { - link_title = g_strdup_printf (_("Page %s — %s"), page_label, page_title); - g_free (page_title); - } else { - link_title = g_strdup_printf (_("Page %s"), page_label); - } + link_title = ev_window_find_title_for_link (window, link); + if (link_title) { + new_link = ev_link_new (link_title, ev_link_get_action (link)); + } else { + EvLinkAction *action; + EvLinkDest *dest; + gchar *page_label; + gchar *title; - real_link = ev_link_new (link_title, action); - g_object_unref (action); + action = ev_link_get_action (link); + dest = ev_link_action_get_dest (action); + page_label = ev_document_links_get_dest_page_label (EV_DOCUMENT_LINKS (window->priv->document), dest); + if (!page_label) + return; - ev_history_add_link (window->priv->history, real_link); + title = g_strdup_printf (_("Page %s"), page_label); + g_free (page_label); - g_free (link_title); - g_free (page_label); - g_object_unref (real_link); -} - -static void -view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window) -{ - int current_page = ev_document_model_get_page (window->priv->model); - - ev_window_add_history (window, 0, link); - ev_window_add_history (window, current_page, NULL); + new_link = ev_link_new (title, action); + g_free (title); + } + } + ev_history_add_link (window->priv->history, new_link ? new_link : link); + if (new_link) + g_object_unref (new_link); } static void @@ -955,11 +930,6 @@ ev_window_page_changed_cb (EvWindow *ev_window, ev_window_update_find_status_message (ev_window); - if (abs (new_page - old_page) > 1) { - ev_window_add_history (ev_window, new_page, NULL); - ev_window_add_history (ev_window, old_page, NULL); - } - if (ev_window->priv->metadata && !ev_window_is_empty (ev_window)) ev_metadata_set_int (ev_window->priv->metadata, "page", new_page); } @@ -1437,7 +1407,6 @@ ev_window_setup_document (EvWindow *ev_window) { const EvDocumentInfo *info; EvDocument *document = ev_window->priv->document; - GtkAction *action; ev_window->priv->setup_document_idle = 0; @@ -1461,12 +1430,6 @@ ev_window_setup_document (EvWindow *ev_window) ev_window_setup_action_sensitivity (ev_window); - if (ev_window->priv->history) - g_object_unref (ev_window->priv->history); - ev_window->priv->history = ev_history_new (); - action = gtk_action_group_get_action (ev_window->priv->action_group, NAVIGATION_ACTION); - ev_navigation_action_set_history (EV_NAVIGATION_ACTION (action), ev_window->priv->history); - if (ev_window->priv->properties) { ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties), ev_window->priv->uri, @@ -6072,17 +6035,12 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group) gtk_action_group_add_action (group, action); g_object_unref (action); - action = g_object_new (EV_TYPE_NAVIGATION_ACTION, - "name", NAVIGATION_ACTION, - "label", _("Navigation"), - "is_important", TRUE, - "short_label", _("Back"), - "stock_id", GTK_STOCK_GO_BACK, - /*translators: this is the history action*/ - "tooltip", _("Move across visited pages"), + action = g_object_new (EV_TYPE_HISTORY_ACTION, + "name", HISTORY_ACTION, + "label", _("History"), NULL); - g_signal_connect (action, "activate_link", - G_CALLBACK (navigation_action_activate_link_cb), window); + ev_history_action_set_history (EV_HISTORY_ACTION (action), + window->priv->history); gtk_action_group_add_action (group, action); g_object_unref (action); @@ -7082,6 +7040,11 @@ ev_window_init (EvWindow *ev_window) ev_window->priv->presentation_mode_inhibit_id = 0; ev_window->priv->title = ev_window_title_new (ev_window); + ev_window->priv->history = ev_history_new (ev_window->priv->model); + g_signal_connect (ev_window->priv->history, "activate-link", + G_CALLBACK (activate_link_cb), + ev_window); + ev_window->priv->main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (ev_window), ev_window->priv->main_box); gtk_widget_show (ev_window->priv->main_box);