]> www.fi.muni.cz Git - evince.git/blob - shell/ev-sidebar-bookmarks.c
bypass GDKSplashOutputDev and just use a normal SplashOutputDev. Speeds
[evince.git] / shell / ev-sidebar-bookmarks.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2004 Red Hat, Inc.
4  *
5  *  Author:
6  *    Jonathan Blandford <jrb@alum.mit.edu>
7  *
8  * Evince is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Evince is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28 #include <gtk/gtk.h>
29
30 #include "ev-sidebar-bookmarks.h"
31 #include "ev-document-bookmarks.h"
32
33 /* Amount of time we devote to each iteration of the idle, in microseconds */
34 #define IDLE_WORK_LENGTH 5000
35
36 typedef struct {
37         EvDocumentBookmarksIter *bookmarks_iter;
38         GtkTreeIter *tree_iter;
39 } IdleStackData;
40
41 struct _EvSidebarBookmarksPrivate {
42         GtkWidget *tree_view;
43         GtkTreeModel *model;
44         EvDocument *current_document;
45         GList *idle_stack;
46         guint idle_id;
47 };
48
49 enum {
50         BOOKMARKS_COLUMN_MARKUP,
51         BOOKMARKS_COLUMN_PAGE_NUM,
52         BOOKMARKS_COLUMN_PAGE_VALID,
53         BOOKMARKS_COLUMN_NUM_COLUMNS
54 };
55
56 static void bookmarks_page_num_func (GtkTreeViewColumn *tree_column,
57                                      GtkCellRenderer   *cell,
58                                      GtkTreeModel      *tree_model,
59                                      GtkTreeIter       *iter,
60                                      gpointer           data);
61
62 G_DEFINE_TYPE (EvSidebarBookmarks, ev_sidebar_bookmarks, GTK_TYPE_VBOX)
63
64 #define EV_SIDEBAR_BOOKMARKS_GET_PRIVATE(object) \
65         (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_BOOKMARKS, EvSidebarBookmarksPrivate))
66
67
68 static void
69 ev_sidebar_bookmarks_destroy (GtkObject *object)
70 {
71         EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *) object;
72
73         g_print ("ev_sidebar_bookmarks_destroy!\n");
74         ev_sidebar_bookmarks_clear_document (ev_sidebar_bookmarks);
75 }
76
77 static void
78 ev_sidebar_bookmarks_class_init (EvSidebarBookmarksClass *ev_sidebar_bookmarks_class)
79 {
80         GObjectClass *g_object_class;
81         GtkObjectClass *gtk_object_class;
82
83         g_object_class = G_OBJECT_CLASS (ev_sidebar_bookmarks_class);
84         gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_bookmarks_class);
85
86         gtk_object_class->destroy = ev_sidebar_bookmarks_destroy;
87
88         g_type_class_add_private (g_object_class, sizeof (EvSidebarBookmarksPrivate));
89 }
90
91
92 static void
93 ev_sidebar_bookmarks_construct (EvSidebarBookmarks *ev_sidebar_bookmarks)
94 {
95         EvSidebarBookmarksPrivate *priv;
96         GtkWidget *swindow;
97         GtkTreeViewColumn *column;
98         GtkCellRenderer *renderer;
99
100         priv = ev_sidebar_bookmarks->priv;
101         priv->model = (GtkTreeModel *) gtk_tree_store_new (BOOKMARKS_COLUMN_NUM_COLUMNS,
102                                                            G_TYPE_STRING,
103                                                            G_TYPE_INT,
104                                                            G_TYPE_BOOLEAN);
105
106         swindow = gtk_scrolled_window_new (NULL, NULL);
107
108         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
109                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
110         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
111                                              GTK_SHADOW_IN);
112
113         /* Create tree view */
114         priv->tree_view = gtk_tree_view_new_with_model (priv->model);
115         g_object_unref (priv->model);
116         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
117         gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view);
118         gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree_view), TRUE);
119
120         gtk_box_pack_start (GTK_BOX (ev_sidebar_bookmarks), swindow, TRUE, TRUE, 0);
121         gtk_widget_show_all (GTK_WIDGET (ev_sidebar_bookmarks));
122
123         column = gtk_tree_view_column_new ();
124         gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
125         gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), column);
126
127         renderer = (GtkCellRenderer*)
128                 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
129                               "ellipsize", PANGO_ELLIPSIZE_END,
130                               NULL);
131         gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE);
132         gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
133                                              "markup", BOOKMARKS_COLUMN_MARKUP,
134                                              NULL);
135
136         renderer = gtk_cell_renderer_text_new ();
137         gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
138         gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer,
139                                                  (GtkTreeCellDataFunc) bookmarks_page_num_func,
140                                                  NULL, NULL);
141
142 }
143
144 static void
145 ev_sidebar_bookmarks_init (EvSidebarBookmarks *ev_sidebar_bookmarks)
146 {
147         ev_sidebar_bookmarks->priv = EV_SIDEBAR_BOOKMARKS_GET_PRIVATE (ev_sidebar_bookmarks);
148
149         ev_sidebar_bookmarks_construct (ev_sidebar_bookmarks);
150 }
151
152 static void
153 bookmarks_page_num_func (GtkTreeViewColumn *tree_column,
154                          GtkCellRenderer   *cell,
155                          GtkTreeModel      *tree_model,
156                          GtkTreeIter       *iter,
157                          gpointer           data)
158 {
159         int page_num;
160         gboolean page_valid;
161
162         gtk_tree_model_get (tree_model, iter,
163                             BOOKMARKS_COLUMN_PAGE_NUM, &page_num,
164                             BOOKMARKS_COLUMN_PAGE_VALID, &page_valid,
165                             -1);
166
167         if (page_valid) {
168                 gchar *markup = g_strdup_printf ("<i>%d</i>", page_num);
169                 g_object_set (cell,
170                               "markup", markup,
171                               "visible", TRUE,
172                               NULL);
173                 g_free (markup);
174         } else {
175                 g_object_set (cell,
176                               "visible", FALSE,
177                               NULL);
178         }
179 }
180
181 /* Public Functions */
182
183 GtkWidget *
184 ev_sidebar_bookmarks_new (void)
185 {
186         GtkWidget *ev_sidebar_bookmarks;
187
188         ev_sidebar_bookmarks = g_object_new (EV_TYPE_SIDEBAR_BOOKMARKS, NULL);
189
190         return ev_sidebar_bookmarks;
191 }
192
193 static void
194 stack_data_free (IdleStackData       *stack_data,
195                  EvDocumentBookmarks *document_bookmarks)
196 {
197         g_assert (stack_data);
198
199         if (stack_data->tree_iter)
200                 gtk_tree_iter_free (stack_data->tree_iter);
201         if (stack_data->bookmarks_iter)
202                 ev_document_bookmarks_free_iter (document_bookmarks, stack_data->bookmarks_iter);
203         g_free (stack_data);
204 }
205
206 #if 0
207 static gboolean
208 do_one_iteration (EvSidebarBookmarks *ev_sidebar_bookmarks)
209 {
210         EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv;
211         IdleStackData *stack_data;
212         GtkTreeIter tree_iter;
213         gchar *title = NULL;
214         EvDocumentBookmarksType type;
215         EvDocumentBookmarksIter *child_iter;
216         gint page = -1;
217
218         g_assert (priv->idle_stack);
219
220         stack_data = (IdleStackData *) priv->idle_stack->data;
221
222         if (! ev_document_bookmarks_get_values (EV_DOCUMENT_BOOKMARKS (priv->current_document),
223                                                 stack_data->bookmarks_iter,
224                                                 &title,
225                                                 &type,
226                                                 &page)) {
227                 g_warning ("mismatch in model.  No values available at current level.\n");
228                 return FALSE;
229         }
230
231         gtk_tree_store_append (GTK_TREE_STORE (priv->model), &tree_iter, stack_data->tree_iter);
232         gtk_tree_store_set (GTK_TREE_STORE (priv->model), &tree_iter,
233                             BOOKMARKS_COLUMN_MARKUP, title,
234                             BOOKMARKS_COLUMN_PAGE_NUM, page,
235                             /* FIXME: Handle links for real. */
236                             BOOKMARKS_COLUMN_PAGE_VALID, (page >= 0),
237                             -1);
238         g_free (title);
239         
240         child_iter = ev_document_bookmarks_get_child (EV_DOCUMENT_BOOKMARKS (priv->current_document),
241                                                       stack_data->bookmarks_iter);
242         if (child_iter) {
243                 IdleStackData *child_stack_data;
244
245                 child_stack_data = g_new0 (IdleStackData, 1);
246                 child_stack_data->tree_iter = gtk_tree_iter_copy (&tree_iter);
247                 child_stack_data->bookmarks_iter = child_iter;
248                 priv->idle_stack = g_list_prepend (priv->idle_stack, child_stack_data);
249
250                 return TRUE;
251         }
252
253         /* We don't have children, so we need to walk to the next node */
254         while (TRUE) {
255                 if (ev_document_bookmarks_next (EV_DOCUMENT_BOOKMARKS (priv->current_document),
256                                                 stack_data->bookmarks_iter))
257                         return TRUE;
258
259                 /* We're done with this level.  Pop it off the idle stack and go
260                  * to the next level */
261                 stack_data_free (stack_data, EV_DOCUMENT_BOOKMARKS (priv->current_document));
262                 priv->idle_stack = g_list_delete_link (priv->idle_stack, priv->idle_stack);
263                 if (priv->idle_stack == NULL)
264                         return FALSE;
265                 stack_data = priv->idle_stack->data;
266         }
267 }
268
269 static gboolean
270 populate_bookmarks_idle (gpointer data)
271 {
272         GTimer *timer;
273         gint i;
274         gulong microseconds = 0;
275
276         EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *)data;
277         EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv;
278
279         if (priv->idle_stack == NULL) {
280                 priv->idle_id = 0;
281                 return FALSE;
282         }
283
284         /* The amount of time that reading the next bookmark takes is wildly
285          * inconsistent, so we constrain it to IDLE_WORK_LENGTH microseconds per
286          * idle iteration. */
287         timer = g_timer_new ();
288         i = 0;
289         g_timer_start (timer);
290         while (do_one_iteration (ev_sidebar_bookmarks)) {
291                 i++;
292                 g_timer_elapsed (timer, &microseconds);
293                 if (microseconds > IDLE_WORK_LENGTH)
294                         break;
295         }
296         g_timer_destroy (timer);
297 #if 0
298         g_print ("%d rows done this idle in %d\n", i, (int)microseconds);
299 #endif
300         return TRUE;
301 }
302 #endif
303 void
304 ev_sidebar_bookmarks_clear_document (EvSidebarBookmarks *sidebar_bookmarks)
305 {
306         EvSidebarBookmarksPrivate *priv;
307
308         g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks));
309
310         priv = sidebar_bookmarks->priv;
311         if (priv->current_document) {
312                 g_object_unref (priv->current_document);
313                 priv->current_document = NULL;
314         }
315         gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
316
317         /* Clear the idle */
318         if (priv->idle_id != 0) {
319                 g_source_remove (priv->idle_id);
320                 priv->idle_id = 0;
321         }
322         g_list_foreach (priv->idle_stack, (GFunc) stack_data_free, priv->current_document);
323         g_list_free (priv->idle_stack);
324         priv->idle_stack = NULL;
325
326 }
327
328 void
329 ev_sidebar_bookmarks_set_document (EvSidebarBookmarks *sidebar_bookmarks,
330                                    EvDocument         *document)
331 {
332         EvSidebarBookmarksPrivate *priv;
333         EvDocumentBookmarksIter *bookmarks_iter;
334
335         g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks));
336         g_return_if_fail (EV_IS_DOCUMENT (document));
337
338         priv = sidebar_bookmarks->priv;
339
340         g_object_ref (document);
341         ev_sidebar_bookmarks_clear_document (sidebar_bookmarks);
342
343         priv->current_document = document;
344         bookmarks_iter = ev_document_bookmarks_begin_read (EV_DOCUMENT_BOOKMARKS (document));
345         if (bookmarks_iter) {
346                 IdleStackData *stack_data;
347
348                 stack_data = g_new0 (IdleStackData, 1);
349                 stack_data->bookmarks_iter = bookmarks_iter;
350                 stack_data->tree_iter = NULL;
351
352                 priv->idle_stack = g_list_prepend (priv->idle_stack, stack_data);
353                 //priv->idle_id = g_idle_add (populate_bookmarks_idle, sidebar_bookmarks);
354         }
355 }
356