1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2001-2008 Imendio AB
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21 /*
22 * Fullscreen mode code adapted from gedit
23 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
24 * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
25 * Copyright (C) 2002-2005 Paolo Maggi
26 */
27
28 #include "config.h"
29 #include <string.h>
30 #include <glib/gi18n-lib.h>
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtk.h>
33 #include <webkit/webkit.h>
34
35 #ifdef GDK_WINDOWING_QUARTZ
36 #include <ige-mac-integration.h>
37 #endif
38
39 #include "dh-book-tree.h"
40 #include "dh-book-manager.h"
41 #include "dh-book.h"
42 #include "dh-preferences.h"
43 #include "dh-search.h"
44 #include "dh-window.h"
45 #include "dh-util.h"
46 #include "dh-marshal.h"
47 #include "dh-enum-types.h"
48 #include "eggfindbar.h"
49 #include "ige-conf.h"
50
51 #define FULLSCREEN_ANIMATION_SPEED 4
52
53 struct _DhWindowPriv {
54 DhBase *base;
55
56 GtkWidget *main_box;
57 GtkWidget *menu_box;
58 GtkWidget *hpaned;
59 GtkWidget *control_notebook;
60 GtkWidget *book_tree;
61 GtkWidget *search;
62 GtkWidget *notebook;
63
64 GtkWidget *vbox;
65 GtkWidget *findbar;
66
67 GtkWidget *fullscreen_controls;
68 guint fullscreen_animation_timeout_id;
69 gboolean fullscreen_animation_enter;
70
71 GtkUIManager *manager;
72 GtkActionGroup *action_group;
73
74 DhLink *selected_search_link;
75 guint find_source_id;
76 };
77
78 enum {
79 OPEN_LINK,
80 LAST_SIGNAL
81 };
82
83 static gint signals[LAST_SIGNAL] = { 0 };
84
85 static guint tab_accel_keys[] = {
86 GDK_1, GDK_2, GDK_3, GDK_4, GDK_5,
87 GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
88 };
89
90 static const
91 struct
92 {
93 gchar *name;
94 int level;
95 }
96 zoom_levels[] =
97 {
98 { N_("50%"), 70 },
99 { N_("75%"), 84 },
100 { N_("100%"), 100 },
101 { N_("125%"), 119 },
102 { N_("150%"), 141 },
103 { N_("175%"), 168 },
104 { N_("200%"), 200 },
105 { N_("300%"), 283 },
106 { N_("400%"), 400 }
107 };
108
109 #define ZOOM_MINIMAL (zoom_levels[0].level)
110 #define ZOOM_MAXIMAL (zoom_levels[8].level)
111 #define ZOOM_DEFAULT (zoom_levels[2].level)
112
113 #if GTK_CHECK_VERSION (2,17,5)
114 #define ERRORS_IN_INFOBAR
115 #endif
116
117 static void dh_window_class_init (DhWindowClass *klass);
118 static void dh_window_init (DhWindow *window);
119 static void window_populate (DhWindow *window);
120 static void window_tree_link_selected_cb (GObject *ignored,
121 DhLink *link,
122 DhWindow *window);
123 static void window_search_link_selected_cb (GObject *ignored,
124 DhLink *link,
125 DhWindow *window);
126 static void window_check_history (DhWindow *window,
127 WebKitWebView *web_view);
128 static void window_web_view_tab_accel_cb (GtkAccelGroup *accel_group,
129 GObject *object,
130 guint key,
131 GdkModifierType mod,
132 DhWindow *window);
133 static void window_find_search_changed_cb (GObject *object,
134 GParamSpec *arg1,
135 DhWindow *window);
136 static void window_find_case_changed_cb (GObject *object,
137 GParamSpec *arg1,
138 DhWindow *window);
139 static void window_find_previous_cb (GtkEntry *entry,
140 DhWindow *window);
141 static void window_find_next_cb (GtkEntry *entry,
142 DhWindow *window);
143 static void window_findbar_close_cb (GtkWidget *widget,
144 DhWindow *window);
145 static GtkWidget * window_new_tab_label (DhWindow *window,
146 const gchar *label,
147 const GtkWidget *parent);
148 static int window_open_new_tab (DhWindow *window,
149 const gchar *location,
150 gboolean switch_focus);
151 static WebKitWebView *window_get_active_web_view (DhWindow *window);
152 #ifdef ERRORS_IN_INFOBAR
153 static GtkWidget * window_get_active_info_bar (DhWindow *window);
154 #endif
155 static void window_update_title (DhWindow *window,
156 WebKitWebView *web_view,
157 const gchar *title);
158 static void window_tab_set_title (DhWindow *window,
159 WebKitWebView *web_view,
160 const gchar *title);
161 static void window_close_tab (DhWindow *window,
162 gint page_num);
163
164 G_DEFINE_TYPE (DhWindow, dh_window, GTK_TYPE_WINDOW);
165
166 #define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
167 (instance, DH_TYPE_WINDOW, DhWindowPriv);
168
169 static void
window_activate_new_window(GtkAction * action,DhWindow * window)170 window_activate_new_window (GtkAction *action,
171 DhWindow *window)
172 {
173 DhWindowPriv *priv;
174 GtkWidget *new_window;
175
176 priv = window->priv;
177
178 new_window = dh_base_new_window (priv->base);
179 gtk_widget_show (new_window);
180 }
181
182 static void
window_activate_new_tab(GtkAction * action,DhWindow * window)183 window_activate_new_tab (GtkAction *action,
184 DhWindow *window)
185 {
186 window_open_new_tab (window, NULL, TRUE);
187 }
188
189 static void
window_activate_print(GtkAction * action,DhWindow * window)190 window_activate_print (GtkAction *action,
191 DhWindow *window)
192 {
193 WebKitWebView *web_view;
194
195 web_view = window_get_active_web_view (window);
196 webkit_web_view_execute_script (web_view, "print();");
197 }
198
199 static void
window_close_tab(DhWindow * window,gint page_num)200 window_close_tab (DhWindow *window,
201 gint page_num)
202 {
203 DhWindowPriv *priv;
204 gint pages;
205
206 priv = window->priv;
207
208 gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), page_num);
209
210 pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
211
212 if (pages == 0) {
213 gtk_widget_destroy (GTK_WIDGET (window));
214 }
215 else if (pages == 1) {
216 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
217 }
218 }
219
220 static void
window_activate_close(GtkAction * action,DhWindow * window)221 window_activate_close (GtkAction *action,
222 DhWindow *window)
223 {
224 gint page_num;
225
226 page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->priv->notebook));
227 window_close_tab (window, page_num);
228 }
229
230 static void
window_activate_quit(GtkAction * action,DhWindow * window)231 window_activate_quit (GtkAction *action,
232 DhWindow *window)
233 {
234 dh_base_quit (window->priv->base);
235 }
236
237 static void
window_activate_copy(GtkAction * action,DhWindow * window)238 window_activate_copy (GtkAction *action,
239 DhWindow *window)
240 {
241 GtkWidget *widget;
242 DhWindowPriv *priv;
243
244 priv = window->priv;
245
246 widget = gtk_window_get_focus (GTK_WINDOW (window));
247
248 if (GTK_IS_EDITABLE (widget)) {
249 gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
250 } else if (GTK_IS_TREE_VIEW (widget) &&
251 gtk_widget_is_ancestor (widget, priv->search) &&
252 priv->selected_search_link) {
253 GtkClipboard *clipboard;
254 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
255 gtk_clipboard_set_text (clipboard,
256 dh_link_get_name(priv->selected_search_link), -1);
257 } else {
258 WebKitWebView *web_view;
259
260 web_view = window_get_active_web_view (window);
261 webkit_web_view_copy_clipboard (web_view);
262 }
263 }
264
265 static void
window_activate_find(GtkAction * action,DhWindow * window)266 window_activate_find (GtkAction *action,
267 DhWindow *window)
268 {
269 DhWindowPriv *priv;
270 WebKitWebView *web_view;
271
272 priv = window->priv;
273 web_view = window_get_active_web_view (window);
274
275 gtk_widget_show (priv->findbar);
276 gtk_widget_grab_focus (priv->findbar);
277
278 webkit_web_view_set_highlight_text_matches (web_view, TRUE);
279 }
280
281 static int
window_get_current_zoom_level_index(DhWindow * window)282 window_get_current_zoom_level_index (DhWindow *window)
283 {
284 WebKitWebView *web_view;
285 float zoom_level;
286 int zoom_level_as_int = ZOOM_DEFAULT;
287 int i;
288
289 web_view = window_get_active_web_view (window);
290 if (web_view) {
291 g_object_get (web_view, "zoom-level", &zoom_level, NULL);
292 zoom_level_as_int = (int)(zoom_level*100);
293 }
294
295 for (i=0; zoom_levels[i].level != ZOOM_MAXIMAL; i++) {
296 if (zoom_levels[i].level == zoom_level_as_int)
297 return i;
298 }
299 return i;
300 }
301
302 static void
window_update_zoom_actions_sensitiveness(DhWindow * window)303 window_update_zoom_actions_sensitiveness (DhWindow *window)
304 {
305 DhWindowPriv *priv;
306 GtkAction *zoom_in, *zoom_out, *zoom_default;
307 int zoom_level_idx;
308
309 priv = window->priv;
310 zoom_in = gtk_action_group_get_action (priv->action_group, "ZoomIn");
311 zoom_out = gtk_action_group_get_action (priv->action_group, "ZoomOut");
312 zoom_default = gtk_action_group_get_action (priv->action_group, "ZoomDefault");
313
314 zoom_level_idx = window_get_current_zoom_level_index (window);
315
316 gtk_action_set_sensitive (zoom_in,
317 zoom_levels[zoom_level_idx].level < ZOOM_MAXIMAL);
318 gtk_action_set_sensitive (zoom_out,
319 zoom_levels[zoom_level_idx].level > ZOOM_MINIMAL);
320 gtk_action_set_sensitive (zoom_default,
321 zoom_levels[zoom_level_idx].level != ZOOM_DEFAULT);
322 }
323
324 static void
window_activate_zoom_in(GtkAction * action,DhWindow * window)325 window_activate_zoom_in (GtkAction *action,
326 DhWindow *window)
327 {
328 int zoom_level_idx;
329
330 zoom_level_idx = window_get_current_zoom_level_index (window);
331 if (zoom_levels[zoom_level_idx].level < ZOOM_MAXIMAL) {
332 WebKitWebView *web_view;
333
334 web_view = window_get_active_web_view (window);
335 g_object_set (web_view,
336 "zoom-level", (float)(zoom_levels[zoom_level_idx+1].level)/100,
337 NULL);
338 window_update_zoom_actions_sensitiveness (window);
339 }
340
341 }
342
343 static void
window_activate_zoom_out(GtkAction * action,DhWindow * window)344 window_activate_zoom_out (GtkAction *action,
345 DhWindow *window)
346 {
347 int zoom_level_idx;
348
349 zoom_level_idx = window_get_current_zoom_level_index (window);
350 if (zoom_levels[zoom_level_idx].level > ZOOM_MINIMAL) {
351 WebKitWebView *web_view;
352
353 web_view = window_get_active_web_view (window);
354 g_object_set (web_view,
355 "zoom-level", (float)(zoom_levels[zoom_level_idx-1].level)/100,
356 NULL);
357 window_update_zoom_actions_sensitiveness (window);
358 }
359 }
360
361 static void
window_activate_zoom_default(GtkAction * action,DhWindow * window)362 window_activate_zoom_default (GtkAction *action,
363 DhWindow *window)
364 {
365 WebKitWebView *web_view;
366
367 web_view = window_get_active_web_view (window);
368 g_object_set (web_view, "zoom-level", (float)(ZOOM_DEFAULT)/100, NULL);
369 window_update_zoom_actions_sensitiveness (window);
370 }
371
372 static gboolean
run_fullscreen_animation(gpointer data)373 run_fullscreen_animation (gpointer data)
374 {
375 DhWindow *window = DH_WINDOW (data);
376 GdkScreen *screen;
377 GdkRectangle fs_rect;
378 gint x, y;
379
380 screen = gtk_window_get_screen (GTK_WINDOW (window));
381 gdk_screen_get_monitor_geometry (screen,
382 gdk_screen_get_monitor_at_window (screen,
383 gtk_widget_get_window (GTK_WIDGET (window))),
384 &fs_rect);
385
386 gtk_window_get_position (GTK_WINDOW (window->priv->fullscreen_controls),
387 &x, &y);
388
389 if (window->priv->fullscreen_animation_enter)
390 {
391 if (y == fs_rect.y)
392 {
393 window->priv->fullscreen_animation_timeout_id = 0;
394 return FALSE;
395 }
396 else
397 {
398 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
399 x, y + 1);
400 return TRUE;
401 }
402 }
403 else
404 {
405 gint w, h;
406
407 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls),
408 &w, &h);
409
410 if (y == fs_rect.y - h + 1)
411 {
412 window->priv->fullscreen_animation_timeout_id = 0;
413 return FALSE;
414 }
415 else
416 {
417 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
418 x, y - 1);
419 return TRUE;
420 }
421 }
422 }
423
424 static void
show_hide_fullscreen_toolbar(DhWindow * window,gboolean show,gint height)425 show_hide_fullscreen_toolbar (DhWindow *window,
426 gboolean show,
427 gint height)
428 {
429 GtkSettings *settings;
430 gboolean enable_animations;
431
432 settings = gtk_widget_get_settings (GTK_WIDGET (window));
433 g_object_get (G_OBJECT (settings),
434 "gtk-enable-animations",
435 &enable_animations,
436 NULL);
437
438 if (enable_animations)
439 {
440 window->priv->fullscreen_animation_enter = show;
441
442 if (window->priv->fullscreen_animation_timeout_id == 0)
443 {
444 window->priv->fullscreen_animation_timeout_id =
445 g_timeout_add (FULLSCREEN_ANIMATION_SPEED,
446 (GSourceFunc) run_fullscreen_animation,
447 window);
448 }
449 }
450 else
451 {
452 GdkRectangle fs_rect;
453 GdkScreen *screen;
454
455 screen = gtk_window_get_screen (GTK_WINDOW (window));
456 gdk_screen_get_monitor_geometry (screen,
457 gdk_screen_get_monitor_at_window (screen,
458 gtk_widget_get_window (GTK_WIDGET (window))),
459 &fs_rect);
460
461 if (show)
462 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
463 fs_rect.x, fs_rect.y);
464 else
465 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
466 fs_rect.x, fs_rect.y - height + 1);
467 }
468
469 }
470
471
472 static gboolean
on_fullscreen_controls_enter_notify_event(GtkWidget * widget,GdkEventCrossing * event,DhWindow * window)473 on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
474 GdkEventCrossing *event,
475 DhWindow *window)
476 {
477 show_hide_fullscreen_toolbar (window, TRUE, 0);
478
479 return FALSE;
480 }
481
482 static gboolean
on_fullscreen_controls_leave_notify_event(GtkWidget * widget,GdkEventCrossing * event,DhWindow * window)483 on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
484 GdkEventCrossing *event,
485 DhWindow *window)
486 {
487 GdkDisplay *display;
488 GdkScreen *screen;
489 gint w, h;
490 gint x, y;
491
492 display = gdk_display_get_default ();
493 screen = gtk_window_get_screen (GTK_WINDOW (window));
494
495 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
496 gdk_display_get_pointer (display, &screen, &x, &y, NULL);
497
498 /* gtk seems to emit leave notify when clicking on tool items,
499 * work around it by checking the coordinates
500 */
501 if (y >= h)
502 {
503 show_hide_fullscreen_toolbar (window, FALSE, h);
504 }
505
506 return FALSE;
507 }
508
509 static gboolean
window_is_fullscreen(DhWindow * window)510 window_is_fullscreen (DhWindow *window)
511 {
512 GdkWindowState state;
513
514 g_return_val_if_fail (DH_IS_WINDOW (window), FALSE);
515
516 #if GTK_CHECK_VERSION (2,14,0)
517 state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
518 #else
519 state = gdk_window_get_state (GTK_WIDGET (window)->window);
520 #endif
521
522 return state & GDK_WINDOW_STATE_FULLSCREEN;
523 }
524
525 static void
window_fullscreen_controls_build(DhWindow * window)526 window_fullscreen_controls_build (DhWindow *window)
527 {
528 GtkWidget *toolbar;
529 GtkAction *action;
530 DhWindowPriv *priv;
531
532 priv = window->priv;
533 if (priv->fullscreen_controls != NULL)
534 return;
535
536 priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP);
537 gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls),
538 GTK_WINDOW (window));
539
540 toolbar = gtk_ui_manager_get_widget (priv->manager, "/FullscreenToolBar");
541 gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls),
542 toolbar);
543 action = gtk_action_group_get_action (priv->action_group,
544 "LeaveFullscreen");
545 g_object_set (action, "is-important", TRUE, NULL);
546
547 /* Set the toolbar style */
548 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
549 GTK_TOOLBAR_BOTH_HORIZ);
550
551 g_signal_connect (priv->fullscreen_controls, "enter-notify-event",
552 G_CALLBACK (on_fullscreen_controls_enter_notify_event),
553 window);
554 g_signal_connect (priv->fullscreen_controls, "leave-notify-event",
555 G_CALLBACK (on_fullscreen_controls_leave_notify_event),
556 window);
557 }
558
559 static void
window_fullscreen_controls_show(DhWindow * window)560 window_fullscreen_controls_show (DhWindow *window)
561 {
562 GdkScreen *screen;
563 GdkRectangle fs_rect;
564 gint w, h;
565
566 screen = gtk_window_get_screen (GTK_WINDOW (window));
567 gdk_screen_get_monitor_geometry (screen,
568 gdk_screen_get_monitor_at_window (
569 screen,
570 gtk_widget_get_window (GTK_WIDGET (window))),
571 &fs_rect);
572
573 gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
574
575 gtk_window_resize (GTK_WINDOW (window->priv->fullscreen_controls),
576 fs_rect.width, h);
577
578 gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
579 fs_rect.x, fs_rect.y - h + 1);
580
581 gtk_widget_show_all (window->priv->fullscreen_controls);
582 }
583
584 static void
window_fullscreen(DhWindow * window)585 window_fullscreen (DhWindow *window)
586 {
587 if (window_is_fullscreen (window))
588 return;
589
590 gtk_window_fullscreen (GTK_WINDOW (window));
591 gtk_widget_hide (gtk_ui_manager_get_widget (window->priv->manager, "/MenuBar"));
592 gtk_widget_hide (gtk_ui_manager_get_widget (window->priv->manager, "/Toolbar"));
593
594 window_fullscreen_controls_build (window);
595 window_fullscreen_controls_show (window);
596 }
597
598 static void
window_unfullscreen(DhWindow * window)599 window_unfullscreen (DhWindow *window)
600 {
601 if (! window_is_fullscreen (window))
602 return;
603
604 gtk_window_unfullscreen (GTK_WINDOW (window));
605 gtk_widget_show (gtk_ui_manager_get_widget (window->priv->manager, "/MenuBar"));
606 gtk_widget_show (gtk_ui_manager_get_widget (window->priv->manager, "/Toolbar"));
607
608 gtk_widget_hide (window->priv->fullscreen_controls);
609 }
610
611
612 static void
window_toggle_fullscreen_mode(GtkAction * action,DhWindow * window)613 window_toggle_fullscreen_mode (GtkAction *action,
614 DhWindow *window)
615 {
616 if (window_is_fullscreen (window)) {
617 window_unfullscreen (window);
618 } else {
619 window_fullscreen (window);
620 }
621 }
622
623 static void
window_leave_fullscreen_mode(GtkAction * action,DhWindow * window)624 window_leave_fullscreen_mode (GtkAction *action,
625 DhWindow *window)
626 {
627 GtkAction *view_action;
628
629 view_action = gtk_action_group_get_action (window->priv->action_group,
630 "ViewFullscreen");
631 g_signal_handlers_block_by_func (view_action,
632 G_CALLBACK (window_toggle_fullscreen_mode),
633 window);
634 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_action),
635 FALSE);
636 window_unfullscreen (window);
637 g_signal_handlers_unblock_by_func (view_action,
638 G_CALLBACK (window_toggle_fullscreen_mode),
639 window);
640 }
641
642 static void
window_activate_preferences(GtkAction * action,DhWindow * window)643 window_activate_preferences (GtkAction *action,
644 DhWindow *window)
645 {
646 dh_preferences_show_dialog (GTK_WINDOW (window));
647 }
648
649 static void
window_activate_back(GtkAction * action,DhWindow * window)650 window_activate_back (GtkAction *action,
651 DhWindow *window)
652 {
653 DhWindowPriv *priv;
654 WebKitWebView *web_view;
655 GtkWidget *frame;
656
657 priv = window->priv;
658
659 frame = gtk_notebook_get_nth_page (
660 GTK_NOTEBOOK (priv->notebook),
661 gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)));
662 web_view = g_object_get_data (G_OBJECT (frame), "web_view");
663
664 webkit_web_view_go_back (web_view);
665 }
666
667 static void
window_activate_forward(GtkAction * action,DhWindow * window)668 window_activate_forward (GtkAction *action,
669 DhWindow *window)
670 {
671 DhWindowPriv *priv;
672 WebKitWebView *web_view;
673 GtkWidget *frame;
674
675 priv = window->priv;
676
677 frame = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook),
678 gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook))
679 );
680 web_view = g_object_get_data (G_OBJECT (frame), "web_view");
681
682 webkit_web_view_go_forward (web_view);
683 }
684
685 static void
window_activate_show_contents(GtkAction * action,DhWindow * window)686 window_activate_show_contents (GtkAction *action,
687 DhWindow *window)
688 {
689 DhWindowPriv *priv;
690
691 priv = window->priv;
692
693 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 0);
694 gtk_widget_grab_focus (priv->book_tree);
695 }
696
697 static void
window_activate_show_search(GtkAction * action,DhWindow * window)698 window_activate_show_search (GtkAction *action,
699 DhWindow *window)
700 {
701 DhWindowPriv *priv;
702
703 priv = window->priv;
704
705 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
706 gtk_widget_grab_focus (priv->search);
707 }
708
709 static void
window_activate_about(GtkAction * action,DhWindow * window)710 window_activate_about (GtkAction *action,
711 DhWindow *window)
712 {
713 const gchar *authors[] = {
714 "Mikael Hallendal <micke@imendio.com>",
715 "Richard Hult <richard@imendio.com>",
716 "Johan Dahlin <johan@gnome.org>",
717 "Ross Burton <ross@burtonini.com>",
718 "Aleksander Morgado <aleksander@lanedo.com>",
719 NULL
720 };
721 const gchar **documenters = NULL;
722 const gchar *translator_credits = _("translator_credits");
723
724 /* i18n: Please don't translate "Devhelp" (it's marked as translatable
725 * for transliteration only) */
726 gtk_show_about_dialog (GTK_WINDOW (window),
727 "name", _("Devhelp"),
728 "version", PACKAGE_VERSION,
729 "comments", _("A developers' help browser for GNOME"),
730 "authors", authors,
731 "documenters", documenters,
732 "translator-credits",
733 strcmp (translator_credits, "translator_credits") != 0 ?
734 translator_credits : NULL,
735 "website", "http://live.gnome.org/devhelp",
736 "logo-icon-name", "devhelp",
737 NULL);
738 }
739
740 static void
window_open_link_cb(DhWindow * window,const char * location,DhOpenLinkFlags flags)741 window_open_link_cb (DhWindow *window,
742 const char *location,
743 DhOpenLinkFlags flags)
744 {
745 DhWindowPriv *priv;
746 priv = window->priv;
747
748 if (flags & DH_OPEN_LINK_NEW_TAB) {
749 window_open_new_tab (window, location, FALSE);
750 }
751 else if (flags & DH_OPEN_LINK_NEW_WINDOW) {
752 GtkWidget *new_window;
753 new_window = dh_base_new_window (priv->base);
754 gtk_widget_show (new_window);
755 }
756 }
757
758 static const GtkActionEntry actions[] = {
759 { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
760 { "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL },
761 { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
762 { "GoMenu", NULL, N_("_Go"), NULL, NULL, NULL },
763 { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
764
765 /* File menu */
766 { "NewWindow", GTK_STOCK_NEW, N_("_New Window"), "<control>N", NULL,
767 G_CALLBACK (window_activate_new_window) },
768 { "NewTab", GTK_STOCK_NEW, N_("New _Tab"), "<control>T", NULL,
769 G_CALLBACK (window_activate_new_tab) },
770 { "Print", GTK_STOCK_PRINT, N_("_Print…"), "<control>P", NULL,
771 G_CALLBACK (window_activate_print) },
772 { "Close", GTK_STOCK_CLOSE, NULL, NULL, NULL,
773 G_CALLBACK (window_activate_close) },
774 { "Quit", GTK_STOCK_QUIT, NULL, NULL, NULL,
775 G_CALLBACK (window_activate_quit) },
776
777 /* Edit menu */
778 { "Copy", GTK_STOCK_COPY, NULL, "<control>C", NULL,
779 G_CALLBACK (window_activate_copy) },
780 { "Find", GTK_STOCK_FIND, NULL, "<control>F", NULL,
781 G_CALLBACK (window_activate_find) },
782 { "Find Next", GTK_STOCK_GO_FORWARD, N_("Find Next"), "<control>G", NULL,
783 G_CALLBACK (window_find_next_cb) },
784 { "Find Previous", GTK_STOCK_GO_BACK, N_("Find Previous"), "<shift><control>G", NULL,
785 G_CALLBACK (window_find_previous_cb) },
786 { "Preferences", GTK_STOCK_PREFERENCES, NULL, NULL, NULL,
787 G_CALLBACK (window_activate_preferences) },
788
789 /* Go menu */
790 { "Back", GTK_STOCK_GO_BACK, NULL, "<alt>Left",
791 N_("Go to the previous page"),
792 G_CALLBACK (window_activate_back) },
793 { "Forward", GTK_STOCK_GO_FORWARD, NULL, "<alt>Right",
794 N_("Go to the next page"),
795 G_CALLBACK (window_activate_forward) },
796
797 { "ShowContentsTab", NULL, N_("_Contents Tab"), "<ctrl>B", NULL,
798 G_CALLBACK (window_activate_show_contents) },
799
800 { "ShowSearchTab", NULL, N_("_Search Tab"), "<ctrl>S", NULL,
801 G_CALLBACK (window_activate_show_search) },
802
803 /* View menu */
804 { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("_Larger Text"), "<ctrl>plus",
805 N_("Increase the text size"),
806 G_CALLBACK (window_activate_zoom_in) },
807 { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("S_maller Text"), "<ctrl>minus",
808 N_("Decrease the text size"),
809 G_CALLBACK (window_activate_zoom_out) },
810 { "ZoomDefault", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<ctrl>0",
811 N_("Use the normal text size"),
812 G_CALLBACK (window_activate_zoom_default) },
813
814 /* About menu */
815 { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL,
816 G_CALLBACK (window_activate_about) },
817
818 /* Fullscreen toolbar */
819 { "LeaveFullscreen", GTK_STOCK_LEAVE_FULLSCREEN, NULL,
820 NULL, N_("Leave fullscreen mode"),
821 G_CALLBACK (window_leave_fullscreen_mode) }
822 };
823
824 static const GtkToggleActionEntry always_sensitive_toggle_menu_entries[] =
825 {
826 { "ViewFullscreen", GTK_STOCK_FULLSCREEN, NULL, "F11",
827 N_("Display in full screen"),
828 G_CALLBACK (window_toggle_fullscreen_mode), FALSE },
829 };
830
831 static const gchar* important_actions[] = {
832 "Back",
833 "Forward"
834 };
835
836 static void
window_finalize(GObject * object)837 window_finalize (GObject *object)
838 {
839 DhWindowPriv *priv = GET_PRIVATE (object);
840
841 g_object_unref (priv->base);
842
843 G_OBJECT_CLASS (dh_window_parent_class)->finalize (object);
844 }
845
846 static void
dh_window_class_init(DhWindowClass * klass)847 dh_window_class_init (DhWindowClass *klass)
848 {
849 GObjectClass *object_class = G_OBJECT_CLASS (klass);
850
851 object_class->finalize = window_finalize;
852
853 signals[OPEN_LINK] =
854 g_signal_new ("open-link",
855 G_TYPE_FROM_CLASS (klass),
856 G_SIGNAL_RUN_LAST,
857 G_STRUCT_OFFSET (DhWindowClass, open_link),
858 NULL, NULL,
859 _dh_marshal_VOID__STRING_FLAGS,
860 G_TYPE_NONE,
861 2,
862 G_TYPE_STRING,
863 DH_TYPE_OPEN_LINK_FLAGS);
864
865 gtk_rc_parse_string ("style \"devhelp-tab-close-button-style\"\n"
866 "{\n"
867 "GtkWidget::focus-padding = 0\n"
868 "GtkWidget::focus-line-width = 0\n"
869 "xthickness = 0\n"
870 "ythickness = 0\n"
871 "}\n"
872 "widget \"*.devhelp-tab-close-button\" "
873 "style \"devhelp-tab-close-button-style\"");
874
875 g_type_class_add_private (klass, sizeof (DhWindowPriv));
876 }
877
878 static void
dh_window_init(DhWindow * window)879 dh_window_init (DhWindow *window)
880 {
881 DhWindowPriv *priv;
882 GtkAction *action;
883 GtkAccelGroup *accel_group;
884 GClosure *closure;
885 guint i;
886
887 priv = GET_PRIVATE (window);
888 window->priv = priv;
889
890 priv->selected_search_link = NULL;
891
892 priv->manager = gtk_ui_manager_new ();
893
894 accel_group = gtk_ui_manager_get_accel_group (priv->manager);
895 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
896
897 priv->main_box = gtk_vbox_new (FALSE, 0);
898 gtk_widget_show (priv->main_box);
899
900 priv->menu_box = gtk_vbox_new (FALSE, 0);
901 gtk_widget_show (priv->menu_box);
902 gtk_container_set_border_width (GTK_CONTAINER (priv->menu_box), 0);
903 gtk_box_pack_start (GTK_BOX (priv->main_box), priv->menu_box,
904 FALSE, TRUE, 0);
905
906 gtk_container_add (GTK_CONTAINER (window), priv->main_box);
907
908 g_signal_connect (window,
909 "open-link",
910 G_CALLBACK (window_open_link_cb),
911 window);
912
913 priv->action_group = gtk_action_group_new ("MainWindow");
914
915 gtk_action_group_set_translation_domain (priv->action_group,
916 GETTEXT_PACKAGE);
917
918 gtk_action_group_add_actions (priv->action_group,
919 actions,
920 G_N_ELEMENTS (actions),
921 window);
922 gtk_action_group_add_toggle_actions (priv->action_group,
923 always_sensitive_toggle_menu_entries,
924 G_N_ELEMENTS (always_sensitive_toggle_menu_entries),
925 window);
926
927 for (i = 0; i < G_N_ELEMENTS (important_actions); i++) {
928 action = gtk_action_group_get_action (priv->action_group,
929 important_actions[i]);
930 g_object_set (action, "is-important", TRUE, NULL);
931 }
932
933 gtk_ui_manager_insert_action_group (priv->manager,
934 priv->action_group,
935 0);
936
937 action = gtk_action_group_get_action (priv->action_group,
938 "Back");
939 g_object_set (action, "sensitive", FALSE, NULL);
940
941 action = gtk_action_group_get_action (priv->action_group,
942 "Forward");
943 g_object_set (action, "sensitive", FALSE, NULL);
944
945 action = gtk_action_group_get_action (priv->action_group, "ZoomIn");
946 /* Translators: This refers to text size */
947 g_object_set (action, "short_label", _("Larger"), NULL);
948 action = gtk_action_group_get_action (priv->action_group, "ZoomOut");
949 /* Translators: This refers to text size */
950 g_object_set (action, "short_label", _("Smaller"), NULL);
951
952 accel_group = gtk_accel_group_new ();
953 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
954
955 for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
956 closure = g_cclosure_new (G_CALLBACK (window_web_view_tab_accel_cb),
957 window,
958 NULL);
959 gtk_accel_group_connect (accel_group,
960 tab_accel_keys[i],
961 GDK_MOD1_MASK,
962 0,
963 closure);
964 }
965 }
966
967 /* The ugliest hack. When switching tabs, the selection and cursor is changed
968 * for the tree view so the web_view content is changed. Block the signal during
969 * switch.
970 */
971 static void
window_control_switch_page_cb(GtkWidget * notebook,gpointer page,guint page_num,DhWindow * window)972 window_control_switch_page_cb (GtkWidget *notebook,
973 gpointer page,
974 guint page_num,
975 DhWindow *window)
976 {
977 DhWindowPriv *priv;
978
979 priv = window->priv;
980
981 g_signal_handlers_block_by_func (priv->book_tree,
982 window_tree_link_selected_cb,
983 window);
984 }
985
986 static void
window_control_after_switch_page_cb(GtkWidget * notebook,gpointer page,guint page_num,DhWindow * window)987 window_control_after_switch_page_cb (GtkWidget *notebook,
988 gpointer page,
989 guint page_num,
990 DhWindow *window)
991 {
992 DhWindowPriv *priv;
993
994 priv = window->priv;
995
996 g_signal_handlers_unblock_by_func (priv->book_tree,
997 window_tree_link_selected_cb,
998 window);
999 }
1000
1001 static void
window_web_view_switch_page_cb(GtkNotebook * notebook,gpointer page,guint new_page_num,DhWindow * window)1002 window_web_view_switch_page_cb (GtkNotebook *notebook,
1003 gpointer page,
1004 guint new_page_num,
1005 DhWindow *window)
1006 {
1007 DhWindowPriv *priv;
1008 GtkWidget *new_page;
1009
1010 priv = window->priv;
1011
1012 new_page = gtk_notebook_get_nth_page (notebook, new_page_num);
1013 if (new_page) {
1014 WebKitWebView *new_web_view;
1015 WebKitWebFrame *web_frame;
1016 const gchar *location;
1017
1018 new_web_view = g_object_get_data (G_OBJECT (new_page), "web_view");
1019
1020 /* Sync the book tree. */
1021 web_frame = webkit_web_view_get_main_frame (new_web_view);
1022 location = webkit_web_frame_get_uri (web_frame);
1023
1024 if (location) {
1025 dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree),
1026 location);
1027 }
1028 window_check_history (window, new_web_view);
1029
1030 window_update_title (window, new_web_view, NULL);
1031 } else {
1032 /* i18n: Please don't translate "Devhelp" (it's marked as translatable
1033 * for transliteration only) */
1034 gtk_window_set_title (GTK_WINDOW (window), _("Devhelp"));
1035 window_check_history (window, NULL);
1036 }
1037 }
1038
1039 static void
window_web_view_switch_page_after_cb(GtkNotebook * notebook,gpointer page,guint new_page_num,DhWindow * window)1040 window_web_view_switch_page_after_cb (GtkNotebook *notebook,
1041 gpointer page,
1042 guint new_page_num,
1043 DhWindow *window)
1044 {
1045 window_update_zoom_actions_sensitiveness (window);
1046 }
1047
1048 static void
window_populate(DhWindow * window)1049 window_populate (DhWindow *window)
1050 {
1051 DhWindowPriv *priv;
1052 gchar *path;
1053 GtkWidget *book_tree_sw;
1054 DhBookManager *book_manager;
1055 GtkWidget *menubar;
1056 GtkWidget *toolbar;
1057
1058 priv = window->priv;
1059
1060 path = dh_util_build_data_filename ("devhelp", "ui", "window.ui", NULL);
1061 gtk_ui_manager_add_ui_from_file (priv->manager,
1062 path,
1063 NULL);
1064 g_free (path);
1065 gtk_ui_manager_ensure_update (priv->manager);
1066
1067 menubar = gtk_ui_manager_get_widget (priv->manager, "/MenuBar");
1068 gtk_box_pack_start (GTK_BOX (priv->menu_box), menubar,
1069 FALSE, FALSE, 0);
1070 toolbar = gtk_ui_manager_get_widget (priv->manager, "/Toolbar");
1071 gtk_box_pack_start (GTK_BOX (priv->menu_box), toolbar,
1072 FALSE, FALSE, 0);
1073
1074 #ifdef GDK_WINDOWING_QUARTZ
1075 {
1076 GtkWidget *widget;
1077 IgeMacMenuGroup *group;
1078
1079 /* Hide toolbar labels. */
1080 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
1081
1082 /* Setup menubar. */
1083 ige_mac_menu_set_menu_bar (GTK_MENU_SHELL (menubar));
1084 gtk_widget_hide (menubar);
1085
1086 widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/FileMenu/Quit");
1087 ige_mac_menu_set_quit_menu_item (GTK_MENU_ITEM (widget));
1088
1089 group = ige_mac_menu_add_app_menu_group ();
1090 widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/HelpMenu/About");
1091 ige_mac_menu_add_app_menu_item (group, GTK_MENU_ITEM (widget),
1092 /* i18n: please don't translate
1093 * "Devhelp", it's a name, not a
1094 * generic word. */
1095 _("About Devhelp"));
1096
1097 group = ige_mac_menu_add_app_menu_group ();
1098 widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/EditMenu/Preferences");
1099 ige_mac_menu_add_app_menu_item (group, GTK_MENU_ITEM (widget),
1100 _("Preferences…"));
1101
1102 ige_mac_menu_set_global_key_handler_enabled (TRUE);
1103 }
1104 #endif
1105
1106 priv->hpaned = gtk_hpaned_new ();
1107
1108 gtk_box_pack_start (GTK_BOX (priv->main_box), priv->hpaned, TRUE, TRUE, 0);
1109
1110 /* Search and contents notebook. */
1111 priv->control_notebook = gtk_notebook_new ();
1112
1113 gtk_paned_add1 (GTK_PANED (priv->hpaned), priv->control_notebook);
1114
1115 g_signal_connect (priv->control_notebook,
1116 "switch-page",
1117 G_CALLBACK (window_control_switch_page_cb),
1118 window);
1119
1120 g_signal_connect_after (priv->control_notebook,
1121 "switch-page",
1122 G_CALLBACK (window_control_after_switch_page_cb),
1123 window);
1124
1125 book_tree_sw = gtk_scrolled_window_new (NULL, NULL);
1126
1127 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (book_tree_sw),
1128 GTK_POLICY_NEVER,
1129 GTK_POLICY_AUTOMATIC);
1130 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (book_tree_sw),
1131 GTK_SHADOW_IN);
1132 gtk_container_set_border_width (GTK_CONTAINER (book_tree_sw), 2);
1133
1134 book_manager = dh_base_get_book_manager (priv->base);
1135
1136 priv->book_tree = dh_book_tree_new (book_manager);
1137 gtk_container_add (GTK_CONTAINER (book_tree_sw),
1138 priv->book_tree);
1139 dh_util_state_set_notebook_page_name (book_tree_sw, "content");
1140 gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
1141 book_tree_sw,
1142 gtk_label_new (_("Contents")));
1143 g_signal_connect (priv->book_tree,
1144 "link-selected",
1145 G_CALLBACK (window_tree_link_selected_cb),
1146 window);
1147
1148 priv->search = dh_search_new (book_manager);
1149 dh_util_state_set_notebook_page_name (priv->search, "search");
1150 gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
1151 priv->search,
1152 gtk_label_new (_("Search")));
1153 g_signal_connect (priv->search,
1154 "link-selected",
1155 G_CALLBACK (window_search_link_selected_cb),
1156 window);
1157
1158 priv->vbox = gtk_vbox_new (FALSE, 0);
1159 gtk_paned_add2 (GTK_PANED (priv->hpaned), priv->vbox);
1160
1161 /* HTML tabs notebook. */
1162 priv->notebook = gtk_notebook_new ();
1163 gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 0);
1164 gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
1165 gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
1166 gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0);
1167
1168 g_signal_connect (priv->notebook,
1169 "switch-page",
1170 G_CALLBACK (window_web_view_switch_page_cb),
1171 window);
1172 g_signal_connect_after (priv->notebook,
1173 "switch-page",
1174 G_CALLBACK (window_web_view_switch_page_after_cb),
1175 window);
1176
1177
1178 /* Create findbar. */
1179 priv->findbar = egg_find_bar_new ();
1180 gtk_widget_set_no_show_all (priv->findbar, TRUE);
1181 gtk_box_pack_start (GTK_BOX (priv->vbox), priv->findbar, FALSE, FALSE, 0);
1182
1183 g_signal_connect (priv->findbar,
1184 "notify::search-string",
1185 G_CALLBACK(window_find_search_changed_cb),
1186 window);
1187 g_signal_connect (priv->findbar,
1188 "notify::case-sensitive",
1189 G_CALLBACK (window_find_case_changed_cb),
1190 window);
1191 g_signal_connect (priv->findbar,
1192 "previous",
1193 G_CALLBACK (window_find_previous_cb),
1194 window);
1195 g_signal_connect (priv->findbar,
1196 "next",
1197 G_CALLBACK (window_find_next_cb),
1198 window);
1199 g_signal_connect (priv->findbar,
1200 "close",
1201 G_CALLBACK (window_findbar_close_cb),
1202 window);
1203
1204 gtk_widget_show_all (priv->hpaned);
1205
1206 window_update_zoom_actions_sensitiveness (window);
1207 window_open_new_tab (window, NULL, TRUE);
1208 }
1209
1210
1211 static gchar *
find_library_equivalent(DhWindow * window,const gchar * uri)1212 find_library_equivalent (DhWindow *window,
1213 const gchar *uri)
1214 {
1215 DhWindowPriv *priv;
1216 gchar **components;
1217 GList *iter;
1218 DhLink *link;
1219 DhBookManager *book_manager;
1220 gchar *book_id;
1221 gchar *filename;
1222 gchar *local_uri = NULL;
1223 GList *books;
1224
1225 components = g_strsplit (uri, "/", 0);
1226 book_id = components[4];
1227 filename = components[6];
1228
1229 priv = window->priv;
1230 book_manager = dh_base_get_book_manager (priv->base);
1231
1232 /* use list pointer to iterate */
1233 for (books = dh_book_manager_get_books (book_manager);
1234 !local_uri && books;
1235 books = g_list_next (books)) {
1236 DhBook *book = DH_BOOK (books->data);
1237
1238 for (iter = dh_book_get_keywords (book);
1239 iter;
1240 iter = g_list_next (iter)) {
1241 link = iter->data;
1242 if (g_strcmp0 (dh_link_get_book_id (link), book_id) != 0) {
1243 continue;
1244 }
1245 if (g_strcmp0 (dh_link_get_file_name (link), filename) != 0) {
1246 continue;
1247 }
1248 local_uri = dh_link_get_uri (link);
1249 break;
1250 }
1251 }
1252
1253 g_strfreev (components);
1254
1255 return local_uri;
1256 }
1257
1258
1259 static gboolean
window_web_view_navigation_policy_decision_requested(WebKitWebView * web_view,WebKitWebFrame * frame,WebKitNetworkRequest * request,WebKitWebNavigationAction * navigation_action,WebKitWebPolicyDecision * policy_decision,DhWindow * window)1260 window_web_view_navigation_policy_decision_requested (WebKitWebView *web_view,
1261 WebKitWebFrame *frame,
1262 WebKitNetworkRequest *request,
1263 WebKitWebNavigationAction *navigation_action,
1264 WebKitWebPolicyDecision *policy_decision,
1265 DhWindow *window)
1266 {
1267 DhWindowPriv *priv;
1268 const char *uri;
1269
1270 priv = window->priv;
1271
1272 uri = webkit_network_request_get_uri (request);
1273
1274 #ifdef ERRORS_IN_INFOBAR
1275 /* make sure to hide the info bar on page change */
1276 gtk_widget_hide (window_get_active_info_bar (window));
1277 #endif
1278
1279 if (webkit_web_navigation_action_get_button (navigation_action) == 2) { /* middle click */
1280 webkit_web_policy_decision_ignore (policy_decision);
1281 g_signal_emit (window, signals[OPEN_LINK], 0, uri, DH_OPEN_LINK_NEW_TAB);
1282 return TRUE;
1283 }
1284
1285 if (strcmp (uri, "about:blank") == 0) {
1286 return FALSE;
1287 }
1288
1289 if (strncmp (uri, "http://library.gnome.org/devel/", 31) == 0) {
1290 gchar *local_uri = find_library_equivalent (window, uri);
1291 if (local_uri) {
1292 webkit_web_policy_decision_ignore (policy_decision);
1293 _dh_window_display_uri (window, local_uri);
1294 g_free (local_uri);
1295 return TRUE;
1296 }
1297 }
1298
1299 if (strncmp (uri, "file://", 7) != 0) {
1300 webkit_web_policy_decision_ignore (policy_decision);
1301 gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL);
1302 return TRUE;
1303 }
1304
1305 if (web_view == window_get_active_web_view (window)) {
1306 dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
1307 window_check_history (window, web_view);
1308 }
1309
1310 return FALSE;
1311 }
1312
1313
1314 static gboolean
window_web_view_load_error_cb(WebKitWebView * web_view,WebKitWebFrame * frame,gchar * uri,gpointer * web_error,DhWindow * window)1315 window_web_view_load_error_cb (WebKitWebView *web_view,
1316 WebKitWebFrame *frame,
1317 gchar *uri,
1318 gpointer *web_error,
1319 DhWindow *window)
1320 {
1321 #ifdef ERRORS_IN_INFOBAR
1322 GtkWidget *info_bar;
1323 GtkWidget *content_area;
1324 GtkWidget *message_label;
1325 GList *children;
1326 gchar *markup;
1327
1328 info_bar = window_get_active_info_bar (window);
1329 markup = g_strdup_printf ("<b>%s</b>",
1330 _("Error opening the requested link."));
1331 message_label = gtk_label_new (markup);
1332 gtk_misc_set_alignment (GTK_MISC (message_label), 0, 0.5);
1333 gtk_label_set_use_markup (GTK_LABEL (message_label), TRUE);
1334 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
1335 children = gtk_container_get_children (GTK_CONTAINER (content_area));
1336 if (children) {
1337 gtk_container_remove (GTK_CONTAINER (content_area), children->data);
1338 g_list_free (children);
1339 }
1340 gtk_container_add (GTK_CONTAINER (content_area), message_label);
1341 gtk_widget_show (message_label);
1342
1343 gtk_widget_show (info_bar);
1344 g_free (markup);
1345
1346 return TRUE;
1347 #else
1348 return FALSE;
1349 #endif
1350 }
1351
1352 static void
window_tree_link_selected_cb(GObject * ignored,DhLink * link,DhWindow * window)1353 window_tree_link_selected_cb (GObject *ignored,
1354 DhLink *link,
1355 DhWindow *window)
1356 {
1357 WebKitWebView *view;
1358 gchar *uri;
1359
1360 view = window_get_active_web_view (window);
1361
1362 uri = dh_link_get_uri (link);
1363 webkit_web_view_load_uri (view, uri);
1364 g_free (uri);
1365
1366 window_check_history (window, view);
1367 }
1368
1369 static void
window_search_link_selected_cb(GObject * ignored,DhLink * link,DhWindow * window)1370 window_search_link_selected_cb (GObject *ignored,
1371 DhLink *link,
1372 DhWindow *window)
1373 {
1374 DhWindowPriv *priv;
1375 WebKitWebView *view;
1376 gchar *uri;
1377
1378 priv = window->priv;
1379
1380 priv->selected_search_link = link;
1381
1382 view = window_get_active_web_view (window);
1383
1384 uri = dh_link_get_uri (link);
1385 webkit_web_view_load_uri (view, uri);
1386 g_free (uri);
1387
1388 window_check_history (window, view);
1389 }
1390
1391 static void
window_check_history(DhWindow * window,WebKitWebView * web_view)1392 window_check_history (DhWindow *window,
1393 WebKitWebView *web_view)
1394 {
1395 DhWindowPriv *priv;
1396 GtkAction *action;
1397
1398 priv = window->priv;
1399
1400 action = gtk_action_group_get_action (priv->action_group, "Forward");
1401 g_object_set (action,
1402 "sensitive", web_view ? webkit_web_view_can_go_forward (web_view) : FALSE,
1403 NULL);
1404
1405 action = gtk_action_group_get_action (priv->action_group, "Back");
1406 g_object_set (action,
1407 "sensitive", web_view ? webkit_web_view_can_go_back (web_view) : FALSE,
1408 NULL);
1409 }
1410
1411 static void
window_web_view_title_changed_cb(WebKitWebView * web_view,WebKitWebFrame * web_frame,const gchar * title,DhWindow * window)1412 window_web_view_title_changed_cb (WebKitWebView *web_view,
1413 WebKitWebFrame *web_frame,
1414 const gchar *title,
1415 DhWindow *window)
1416 {
1417 if (web_view == window_get_active_web_view (window)) {
1418 window_update_title (window, web_view, title);
1419 }
1420
1421 window_tab_set_title (window, web_view, title);
1422 }
1423
1424 static gboolean
window_web_view_button_press_event_cb(WebKitWebView * web_view,GdkEventButton * event,DhWindow * window)1425 window_web_view_button_press_event_cb (WebKitWebView *web_view,
1426 GdkEventButton *event,
1427 DhWindow *window)
1428 {
1429 if (event->button == 3) {
1430 return TRUE;
1431 }
1432
1433 return FALSE;
1434 }
1435
1436 static gboolean
do_search(DhWindow * window)1437 do_search (DhWindow *window)
1438 {
1439 DhWindowPriv *priv = window->priv;
1440 WebKitWebView *web_view;
1441
1442 priv->find_source_id = 0;
1443
1444 web_view = window_get_active_web_view (window);
1445
1446 webkit_web_view_unmark_text_matches (web_view);
1447 webkit_web_view_mark_text_matches (
1448 web_view,
1449 egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar)),
1450 egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar)), 0);
1451 webkit_web_view_set_highlight_text_matches (web_view, TRUE);
1452
1453 webkit_web_view_search_text (
1454 web_view, egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar)),
1455 egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar)),
1456 TRUE, TRUE);
1457
1458 return FALSE;
1459 }
1460
1461 static void
window_find_search_changed_cb(GObject * object,GParamSpec * pspec,DhWindow * window)1462 window_find_search_changed_cb (GObject *object,
1463 GParamSpec *pspec,
1464 DhWindow *window)
1465 {
1466 DhWindowPriv *priv = window->priv;
1467
1468 if (priv->find_source_id != 0) {
1469 g_source_remove (priv->find_source_id);
1470 priv->find_source_id = 0;
1471 }
1472
1473 priv->find_source_id = g_timeout_add (300, (GSourceFunc)do_search, window);
1474 }
1475
1476 static void
window_find_case_changed_cb(GObject * object,GParamSpec * pspec,DhWindow * window)1477 window_find_case_changed_cb (GObject *object,
1478 GParamSpec *pspec,
1479 DhWindow *window)
1480 {
1481 DhWindowPriv *priv = window->priv;;
1482 WebKitWebView *view;
1483 const gchar *string;
1484 gboolean case_sensitive;
1485
1486 view = window_get_active_web_view (window);
1487
1488 string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
1489 case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
1490
1491 webkit_web_view_unmark_text_matches (view);
1492 webkit_web_view_mark_text_matches (view, string, case_sensitive, 0);
1493 webkit_web_view_set_highlight_text_matches (view, TRUE);
1494 }
1495
1496 static void
window_find_next_cb(GtkEntry * entry,DhWindow * window)1497 window_find_next_cb (GtkEntry *entry,
1498 DhWindow *window)
1499 {
1500 DhWindowPriv *priv = window->priv;
1501 WebKitWebView *view;
1502 const gchar *string;
1503 gboolean case_sensitive;
1504
1505 view = window_get_active_web_view (window);
1506
1507 gtk_widget_show (priv->findbar);
1508
1509 string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
1510 case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
1511
1512 webkit_web_view_search_text (view, string, case_sensitive, TRUE, TRUE);
1513 }
1514
1515 static void
window_find_previous_cb(GtkEntry * entry,DhWindow * window)1516 window_find_previous_cb (GtkEntry *entry,
1517 DhWindow *window)
1518 {
1519 DhWindowPriv *priv = window->priv;
1520 WebKitWebView *view;
1521 const gchar *string;
1522 gboolean case_sensitive;
1523
1524 view = window_get_active_web_view (window);
1525
1526 gtk_widget_show (priv->findbar);
1527
1528 string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
1529 case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
1530
1531 webkit_web_view_search_text (view, string, case_sensitive, FALSE, TRUE);
1532 }
1533
1534 static void
window_findbar_close_cb(GtkWidget * widget,DhWindow * window)1535 window_findbar_close_cb (GtkWidget *widget,
1536 DhWindow *window)
1537 {
1538 DhWindowPriv *priv = window->priv;
1539 WebKitWebView *view;
1540
1541 view = window_get_active_web_view (window);
1542
1543 gtk_widget_hide (priv->findbar);
1544
1545 webkit_web_view_set_highlight_text_matches (view, FALSE);
1546 }
1547
1548 #if 0
1549 static void
1550 window_web_view_open_new_tab_cb (WebKitWebView *web_view,
1551 const gchar *location,
1552 DhWindow *window)
1553 {
1554 window_open_new_tab (window, location);
1555 }
1556 #endif
1557
1558 static void
window_web_view_tab_accel_cb(GtkAccelGroup * accel_group,GObject * object,guint key,GdkModifierType mod,DhWindow * window)1559 window_web_view_tab_accel_cb (GtkAccelGroup *accel_group,
1560 GObject *object,
1561 guint key,
1562 GdkModifierType mod,
1563 DhWindow *window)
1564 {
1565 DhWindowPriv *priv;
1566 gint i, num;
1567
1568 priv = window->priv;
1569
1570 num = -1;
1571 for (i = 0; i < (gint) G_N_ELEMENTS (tab_accel_keys); i++) {
1572 if (tab_accel_keys[i] == key) {
1573 num = i;
1574 break;
1575 }
1576 }
1577
1578 if (num != -1) {
1579 gtk_notebook_set_current_page (
1580 GTK_NOTEBOOK (priv->notebook), num);
1581 }
1582 }
1583
1584 static int
window_open_new_tab(DhWindow * window,const gchar * location,gboolean switch_focus)1585 window_open_new_tab (DhWindow *window,
1586 const gchar *location,
1587 gboolean switch_focus)
1588 {
1589 DhWindowPriv *priv;
1590 GtkWidget *view;
1591 GtkWidget *vbox;
1592 GtkWidget *scrolled_window;
1593 GtkWidget *label;
1594 gint num;
1595 #ifdef ERRORS_IN_INFOBAR
1596 GtkWidget *info_bar;
1597 #endif
1598
1599 priv = window->priv;
1600
1601 /* Prepare the web view */
1602 view = webkit_web_view_new ();
1603 gtk_widget_show (view);
1604 dh_util_font_add_web_view (WEBKIT_WEB_VIEW (view));
1605
1606 #ifdef ERRORS_IN_INFOBAR
1607 /* Prepare the info bar */
1608 info_bar = gtk_info_bar_new ();
1609 gtk_widget_set_no_show_all (info_bar, TRUE);
1610 gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
1611 GTK_STOCK_CLOSE, GTK_RESPONSE_OK);
1612 gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
1613 GTK_MESSAGE_ERROR);
1614 g_signal_connect (info_bar, "response",
1615 G_CALLBACK (gtk_widget_hide), NULL);
1616 #endif
1617
1618 #if 0
1619 /* Leave this in for now to make it easier to experiment. */
1620 {
1621 WebKitWebSettings *settings;
1622 settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view));
1623
1624 g_object_set (settings,
1625 "user-stylesheet-uri", "file://" DATADIR "/devhelp/devhelp.css",
1626 NULL);
1627 }
1628 #endif
1629
1630 vbox = gtk_vbox_new (0, FALSE);
1631 gtk_widget_show (vbox);
1632
1633 /* XXX: Really it would be much better to use real structures */
1634 g_object_set_data (G_OBJECT (vbox), "web_view", view);
1635 #ifdef ERRORS_IN_INFOBAR
1636 g_object_set_data (G_OBJECT (vbox), "info_bar", info_bar);
1637
1638 gtk_box_pack_start (GTK_BOX(vbox), info_bar, FALSE, TRUE, 0);
1639 #endif
1640
1641 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1642 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1643 GTK_POLICY_AUTOMATIC,
1644 GTK_POLICY_AUTOMATIC);
1645 gtk_container_add (GTK_CONTAINER (scrolled_window), view);
1646 gtk_widget_show (scrolled_window);
1647 gtk_box_pack_start (GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
1648
1649 label = window_new_tab_label (window, _("Empty Page"), vbox);
1650 gtk_widget_show_all (label);
1651
1652 g_signal_connect (view, "title-changed",
1653 G_CALLBACK (window_web_view_title_changed_cb),
1654 window);
1655 g_signal_connect (view, "button-press-event",
1656 G_CALLBACK (window_web_view_button_press_event_cb),
1657 window);
1658 g_signal_connect (view, "navigation-policy-decision-requested",
1659 G_CALLBACK (window_web_view_navigation_policy_decision_requested),
1660 window);
1661 g_signal_connect (view, "load-error",
1662 G_CALLBACK (window_web_view_load_error_cb),
1663 window);
1664
1665 num = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
1666 vbox, NULL);
1667
1668 gtk_notebook_set_tab_label (GTK_NOTEBOOK (priv->notebook),
1669 vbox, label);
1670
1671 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) > 1) {
1672 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), TRUE);
1673 } else {
1674 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
1675 }
1676
1677 if (location) {
1678 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), location);
1679 } else {
1680 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), "about:blank");
1681 }
1682
1683 if (switch_focus) {
1684 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num);
1685 }
1686
1687 return num;
1688 }
1689
1690 #ifndef GDK_WINDOWING_QUARTZ
1691 static void
close_button_clicked_cb(GtkButton * button,DhWindow * window)1692 close_button_clicked_cb (GtkButton *button,
1693 DhWindow *window)
1694 {
1695 GtkWidget *parent_tab;
1696 gint pages;
1697 gint i;
1698
1699 parent_tab = g_object_get_data (G_OBJECT (button), "parent_tab");
1700 pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook));
1701 for (i=0; i<pages; i++) {
1702 if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->priv->notebook), i) == parent_tab) {
1703 window_close_tab (window, i);
1704 break;
1705 }
1706 }
1707 }
1708
1709 static void
tab_label_style_set_cb(GtkWidget * hbox,GtkStyle * previous_style,gpointer user_data)1710 tab_label_style_set_cb (GtkWidget *hbox,
1711 GtkStyle *previous_style,
1712 gpointer user_data)
1713 {
1714 PangoFontMetrics *metrics;
1715 PangoContext *context;
1716 GtkWidget *button;
1717 GtkStyle *style;
1718 gint char_width;
1719 gint h, w;
1720
1721 context = gtk_widget_get_pango_context (hbox);
1722 style = gtk_widget_get_style (hbox);
1723 metrics = pango_context_get_metrics (context,
1724 style->font_desc,
1725 pango_context_get_language (context));
1726
1727 char_width = pango_font_metrics_get_approximate_digit_width (metrics);
1728 pango_font_metrics_unref (metrics);
1729
1730 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (hbox),
1731 GTK_ICON_SIZE_MENU, &w, &h);
1732
1733 gtk_widget_set_size_request (hbox, 15 * PANGO_PIXELS (char_width) + 2 * w, -1);
1734
1735 button = g_object_get_data (G_OBJECT (hbox), "close-button");
1736 gtk_widget_set_size_request (button, w + 2, h + 2);
1737 }
1738 #endif
1739
1740 /* Don't create a close button on quartz, it looks very much out of
1741 * place.
1742 */
1743 static GtkWidget*
window_new_tab_label(DhWindow * window,const gchar * str,const GtkWidget * parent)1744 window_new_tab_label (DhWindow *window,
1745 const gchar *str,
1746 const GtkWidget *parent)
1747 {
1748 GtkWidget *label;
1749 #ifndef GDK_WINDOWING_QUARTZ
1750 GtkWidget *hbox;
1751 GtkWidget *close_button;
1752 GtkWidget *image;
1753
1754 hbox = gtk_hbox_new (FALSE, 4);
1755
1756 label = gtk_label_new (str);
1757 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
1758 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1759 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
1760
1761 close_button = gtk_button_new ();
1762 gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
1763 gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE);
1764 gtk_widget_set_name (close_button, "devhelp-tab-close-button");
1765 g_object_set_data (G_OBJECT (close_button), "parent_tab", (gpointer) parent);
1766
1767 image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
1768 g_signal_connect (close_button, "clicked",
1769 G_CALLBACK (close_button_clicked_cb),
1770 window);
1771 gtk_container_add (GTK_CONTAINER (close_button), image);
1772
1773 gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
1774
1775 /* Set minimal size */
1776 g_signal_connect (hbox, "style-set",
1777 G_CALLBACK (tab_label_style_set_cb),
1778 NULL);
1779
1780 g_object_set_data (G_OBJECT (hbox), "label", label);
1781 g_object_set_data (G_OBJECT (hbox), "close-button", close_button);
1782
1783 return hbox;
1784 #else
1785 label = gtk_label_new (str);
1786 g_object_set_data (G_OBJECT (label), "label", label);
1787
1788 return label;
1789 #endif
1790 }
1791
1792 static WebKitWebView *
window_get_active_web_view(DhWindow * window)1793 window_get_active_web_view (DhWindow *window)
1794 {
1795 DhWindowPriv *priv;
1796 gint page_num;
1797 GtkWidget *page;
1798
1799 priv = window->priv;
1800
1801 page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
1802 if (page_num == -1) {
1803 return NULL;
1804 }
1805
1806 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num);
1807
1808 return g_object_get_data (G_OBJECT (page), "web_view");
1809 }
1810
1811 #ifdef ERRORS_IN_INFOBAR
1812 static GtkWidget *
window_get_active_info_bar(DhWindow * window)1813 window_get_active_info_bar (DhWindow *window)
1814 {
1815 DhWindowPriv *priv;
1816 gint page_num;
1817 GtkWidget *page;
1818
1819 priv = window->priv;
1820
1821 page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
1822 if (page_num == -1) {
1823 return NULL;
1824 }
1825
1826 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num);
1827
1828 return g_object_get_data (G_OBJECT (page), "info_bar");
1829 }
1830 #endif
1831
1832 static void
window_update_title(DhWindow * window,WebKitWebView * web_view,const gchar * web_view_title)1833 window_update_title (DhWindow *window,
1834 WebKitWebView *web_view,
1835 const gchar *web_view_title)
1836 {
1837 DhWindowPriv *priv;
1838 const gchar *book_title;
1839
1840 priv = window->priv;
1841
1842 if (!web_view_title) {
1843 WebKitWebFrame *web_frame;
1844
1845 web_frame = webkit_web_view_get_main_frame (web_view);
1846 web_view_title = webkit_web_frame_get_title (web_frame);
1847 }
1848
1849 if (web_view_title && *web_view_title == '\0') {
1850 web_view_title = NULL;
1851 }
1852
1853 book_title = dh_book_tree_get_selected_book_title (DH_BOOK_TREE (priv->book_tree));
1854
1855 /* Don't use both titles if they are the same. */
1856 if (book_title && web_view_title && strcmp (book_title, web_view_title) == 0) {
1857 web_view_title = NULL;
1858 }
1859
1860 if (!book_title) {
1861 /* i18n: Please don't translate "Devhelp" (it's marked as translatable
1862 * for transliteration only) */
1863 book_title = _("Devhelp");
1864 }
1865
1866 if (web_view_title) {
1867 gchar *full_title;
1868 full_title = g_strdup_printf ("%s - %s", book_title, web_view_title);
1869 gtk_window_set_title (GTK_WINDOW (window), full_title);
1870 g_free (full_title);
1871 } else {
1872 gtk_window_set_title (GTK_WINDOW (window), book_title);
1873 }
1874 }
1875
1876 static void
window_tab_set_title(DhWindow * window,WebKitWebView * web_view,const gchar * title)1877 window_tab_set_title (DhWindow *window,
1878 WebKitWebView *web_view,
1879 const gchar *title)
1880 {
1881 DhWindowPriv *priv;
1882 gint num_pages, i;
1883 GtkWidget *page;
1884 GtkWidget *hbox;
1885 GtkWidget *label;
1886 GtkWidget *page_web_view;
1887
1888 priv = window->priv;
1889
1890 if (!title || title[0] == '\0') {
1891 title = _("Empty Page");
1892 }
1893
1894 num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
1895 for (i = 0; i < num_pages; i++) {
1896 page = gtk_notebook_get_nth_page (
1897 GTK_NOTEBOOK (priv->notebook), i);
1898 page_web_view = g_object_get_data (G_OBJECT (page), "web_view");
1899
1900 /* The web_view widget is inside a frame. */
1901 if (page_web_view == GTK_WIDGET (web_view)) {
1902 hbox = gtk_notebook_get_tab_label (
1903 GTK_NOTEBOOK (priv->notebook), page);
1904
1905 if (hbox) {
1906 label = g_object_get_data (G_OBJECT (hbox), "label");
1907 gtk_label_set_text (GTK_LABEL (label), title);
1908 }
1909 break;
1910 }
1911 }
1912 }
1913
1914 GtkWidget *
dh_window_new(DhBase * base)1915 dh_window_new (DhBase *base)
1916 {
1917 DhWindow *window;
1918 DhWindowPriv *priv;
1919
1920 window = g_object_new (DH_TYPE_WINDOW, NULL);
1921 priv = window->priv;
1922
1923 priv->base = g_object_ref (base);
1924
1925 window_populate (window);
1926
1927 gtk_window_set_icon_name (GTK_WINDOW (window), "devhelp");
1928
1929 dh_util_state_manage_window (GTK_WINDOW (window), "main/window");
1930 dh_util_state_manage_paned (GTK_PANED (priv->hpaned), "main/paned");
1931 dh_util_state_manage_notebook (GTK_NOTEBOOK (priv->control_notebook),
1932 "main/search_notebook",
1933 "content");
1934
1935 return GTK_WIDGET (window);
1936 }
1937
1938 void
dh_window_search(DhWindow * window,const gchar * str,const gchar * book_id)1939 dh_window_search (DhWindow *window,
1940 const gchar *str,
1941 const gchar *book_id)
1942 {
1943 DhWindowPriv *priv;
1944
1945 g_return_if_fail (DH_IS_WINDOW (window));
1946
1947 priv = window->priv;
1948
1949 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
1950 dh_search_set_search_string (DH_SEARCH (priv->search), str, book_id);
1951 }
1952
1953 void
dh_window_focus_search(DhWindow * window)1954 dh_window_focus_search (DhWindow *window)
1955 {
1956 DhWindowPriv *priv;
1957
1958 g_return_if_fail (DH_IS_WINDOW (window));
1959
1960 priv = window->priv;
1961
1962 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
1963 gtk_widget_grab_focus (priv->search);
1964 }
1965
1966 /* Only call this with a URI that is known to be in the docs. */
1967 void
_dh_window_display_uri(DhWindow * window,const gchar * uri)1968 _dh_window_display_uri (DhWindow *window,
1969 const gchar *uri)
1970 {
1971 DhWindowPriv *priv;
1972 WebKitWebView *web_view;
1973
1974 g_return_if_fail (DH_IS_WINDOW (window));
1975 g_return_if_fail (uri != NULL);
1976
1977 priv = window->priv;
1978
1979 web_view = window_get_active_web_view (window);
1980 webkit_web_view_load_uri (web_view, uri);
1981 dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
1982 }
1983