~ubuntu-branches/ubuntu/utopic/yelp/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/git_signal_handler.patch/libyelp/yelp-view.c

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2014-03-09 08:19:09 UTC
  • mfrom: (1.6.1)
  • Revision ID: package-import@ubuntu.com-20140309081909-iu2d7n88h312j78l
Tags: 3.10.2-0ubuntu1
* New upstream release.
  - Drop git_signal_handler.patch, fixed upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
 
/*
3
 
 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
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
 
 * Author: Shaun McCance <shaunm@gnome.org>
21
 
 */
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#include <config.h>
25
 
#endif
26
 
 
27
 
#include <glib/gi18n.h>
28
 
#include <glib-object.h>
29
 
#include <gio/gio.h>
30
 
#include <gtk/gtk.h>
31
 
#include <gdk/gdkx.h>
32
 
#include <webkit/webkit.h>
33
 
 
34
 
#include "yelp-debug.h"
35
 
#include "yelp-docbook-document.h"
36
 
#include "yelp-error.h"
37
 
#include "yelp-marshal.h"
38
 
#include "yelp-settings.h"
39
 
#include "yelp-types.h"
40
 
#include "yelp-view.h"
41
 
 
42
 
#define BOGUS_URI "file:///bogus/"
43
 
#define BOGUS_URI_LEN 14
44
 
 
45
 
static void        yelp_view_init                 (YelpView           *view);
46
 
static void        yelp_view_class_init           (YelpViewClass      *klass);
47
 
static void        yelp_view_dispose              (GObject            *object);
48
 
static void        yelp_view_finalize             (GObject            *object);
49
 
static void        yelp_view_get_property         (GObject            *object,
50
 
                                                   guint               prop_id,
51
 
                                                   GValue             *value,
52
 
                                                   GParamSpec         *pspec);
53
 
static void        yelp_view_set_property         (GObject            *object,
54
 
                                                   guint               prop_id,
55
 
                                                   const GValue       *value,
56
 
                                                   GParamSpec         *pspec);
57
 
 
58
 
static gboolean    view_external_uri              (YelpView           *view,
59
 
                                                   YelpUri            *uri);
60
 
static void        view_install_uri               (YelpView           *view,
61
 
                                                   const gchar        *uri);
62
 
static void        view_scrolled                  (GtkAdjustment      *adjustment,
63
 
                                                   YelpView           *view);
64
 
static void        view_set_hadjustment           (YelpView           *view,
65
 
                                                   GParamSpec         *pspec,
66
 
                                                   gpointer            data);
67
 
static void        view_set_vadjustment           (YelpView           *view,
68
 
                                                   GParamSpec         *pspec,
69
 
                                                   gpointer            data);
70
 
static void        popup_open_link                (GtkMenuItem        *item,
71
 
                                                   YelpView           *view);
72
 
static void        popup_open_link_new            (GtkMenuItem        *item,
73
 
                                                   YelpView           *view);
74
 
static void        popup_copy_link                (GtkMenuItem        *item,
75
 
                                                   YelpView           *view);
76
 
static void        popup_save_image               (GtkMenuItem        *item,
77
 
                                                   YelpView           *view);
78
 
static void        popup_send_image               (GtkMenuItem        *item,
79
 
                                                   YelpView           *view);
80
 
static void        popup_copy_code                (GtkMenuItem        *item,
81
 
                                                   YelpView           *view);
82
 
static void        popup_save_code                (GtkMenuItem        *item,
83
 
                                                   YelpView           *view);
84
 
static void        view_populate_popup            (YelpView           *view,
85
 
                                                   GtkMenu            *menu,
86
 
                                                   gpointer            data);
87
 
static void        view_script_alert              (YelpView           *view,
88
 
                                                   WebKitWebFrame     *frame,
89
 
                                                   gchar              *message,
90
 
                                                   gpointer            data);
91
 
static gboolean    view_navigation_requested      (WebKitWebView             *view,
92
 
                                                   WebKitWebFrame            *frame,
93
 
                                                   WebKitNetworkRequest      *request,
94
 
                                                   WebKitWebNavigationAction *action,
95
 
                                                   WebKitWebPolicyDecision   *decision,
96
 
                                                   gpointer                   user_data);
97
 
static void        view_resource_request          (WebKitWebView             *view,
98
 
                                                   WebKitWebFrame            *frame,
99
 
                                                   WebKitWebResource         *resource,
100
 
                                                   WebKitNetworkRequest      *request,
101
 
                                                   WebKitNetworkResponse     *response,
102
 
                                                   gpointer                   user_data);
103
 
static void        view_document_loaded           (WebKitWebView             *view,
104
 
                                                   WebKitWebFrame            *frame,
105
 
                                                   gpointer                   user_data);
106
 
 
107
 
static void        view_print                     (GtkAction          *action,
108
 
                                                   YelpView           *view);
109
 
static void        view_history_action            (GtkAction          *action,
110
 
                                                   YelpView           *view);
111
 
static void        view_navigation_action         (GtkAction          *action,
112
 
                                                   YelpView           *view);
113
 
 
114
 
static void        view_clear_load                (YelpView           *view);
115
 
static void        view_load_page                 (YelpView           *view);
116
 
static void        view_show_error_page           (YelpView           *view,
117
 
                                                   GError             *error);
118
 
 
119
 
static void        settings_set_fonts             (YelpSettings       *settings);
120
 
static void        settings_show_text_cursor      (YelpSettings       *settings);
121
 
 
122
 
static void        uri_resolved                   (YelpUri            *uri,
123
 
                                                   YelpView           *view);
124
 
static void        document_callback              (YelpDocument       *document,
125
 
                                                   YelpDocumentSignal  signal,
126
 
                                                   YelpView           *view,
127
 
                                                   GError             *error);
128
 
 
129
 
static const GtkActionEntry entries[] = {
130
 
    {"YelpViewPrint", GTK_STOCK_PRINT,
131
 
     N_("_Print..."),
132
 
     "<Control>P",
133
 
     NULL,
134
 
     G_CALLBACK (view_print) },
135
 
    {"YelpViewGoBack", GTK_STOCK_GO_BACK,
136
 
     N_("_Back"),
137
 
     "<Alt>Left",
138
 
     NULL,
139
 
     G_CALLBACK (view_history_action) },
140
 
    {"YelpViewGoForward", GTK_STOCK_GO_FORWARD,
141
 
     N_("_Forward"),
142
 
     "<Alt>Right",
143
 
     NULL,
144
 
     G_CALLBACK (view_history_action) },
145
 
    {"YelpViewGoPrevious", NULL,
146
 
     N_("_Previous Page"),
147
 
     "<Control>Page_Up",
148
 
     NULL,
149
 
     G_CALLBACK (view_navigation_action) },
150
 
    {"YelpViewGoNext", NULL,
151
 
     N_("_Next Page"),
152
 
     "<Control>Page_Down",
153
 
     NULL,
154
 
     G_CALLBACK (view_navigation_action) }
155
 
};
156
 
 
157
 
static gchar *nautilus_sendto = NULL;
158
 
 
159
 
enum {
160
 
    PROP_0,
161
 
    PROP_URI,
162
 
    PROP_STATE,
163
 
    PROP_PAGE_ID,
164
 
    PROP_ROOT_TITLE,
165
 
    PROP_PAGE_TITLE,
166
 
    PROP_PAGE_DESC,
167
 
    PROP_PAGE_ICON
168
 
};
169
 
 
170
 
enum {
171
 
    NEW_VIEW_REQUESTED,
172
 
    EXTERNAL_URI,
173
 
    LOADED,
174
 
    LAST_SIGNAL
175
 
};
176
 
static gint signals[LAST_SIGNAL] = { 0 };
177
 
 
178
 
G_DEFINE_TYPE (YelpView, yelp_view, WEBKIT_TYPE_WEB_VIEW);
179
 
#define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_VIEW, YelpViewPrivate))
180
 
 
181
 
static WebKitWebSettings *websettings;
182
 
 
183
 
typedef struct _YelpActionEntry YelpActionEntry;
184
 
struct _YelpActionEntry {
185
 
    GtkAction               *action;
186
 
    YelpViewActionValidFunc  func;
187
 
    gpointer                 data;
188
 
};
189
 
static void
190
 
action_entry_free (YelpActionEntry *entry)
191
 
{
192
 
    if (entry == NULL)
193
 
        return;
194
 
    g_object_unref (entry->action);
195
 
    g_free (entry);
196
 
}
197
 
 
198
 
typedef struct _YelpBackEntry YelpBackEntry;
199
 
struct _YelpBackEntry {
200
 
    YelpUri *uri;
201
 
    gchar   *title;
202
 
    gchar   *desc;
203
 
    gdouble  hadj;
204
 
    gdouble  vadj;
205
 
};
206
 
static void
207
 
back_entry_free (YelpBackEntry *back)
208
 
{
209
 
    if (back == NULL)
210
 
        return;
211
 
    g_object_unref (back->uri);
212
 
    g_free (back->title);
213
 
    g_free (back->desc);
214
 
    g_free (back);
215
 
}
216
 
 
217
 
typedef struct _YelpViewPrivate YelpViewPrivate;
218
 
struct _YelpViewPrivate {
219
 
    YelpUri       *uri;
220
 
    YelpUri       *resolve_uri;
221
 
    gulong         uri_resolved;
222
 
    gchar         *bogus_uri;
223
 
    YelpDocument  *document;
224
 
    GCancellable  *cancellable;
225
 
    GtkAdjustment *vadjustment;
226
 
    GtkAdjustment *hadjustment;
227
 
    gdouble        vadjust;
228
 
    gdouble        hadjust;
229
 
    gulong         vadjuster;
230
 
    gulong         hadjuster;
231
 
 
232
 
    gchar         *popup_link_uri;
233
 
    gchar         *popup_link_text;
234
 
    gchar         *popup_image_uri;
235
 
    WebKitDOMNode *popup_code_node;
236
 
    WebKitDOMNode *popup_code_title;
237
 
    gchar         *popup_code_text;
238
 
 
239
 
    YelpViewState  state;
240
 
    YelpViewState  prevstate;
241
 
 
242
 
    gchar         *page_id;
243
 
    gchar         *root_title;
244
 
    gchar         *page_title;
245
 
    gchar         *page_desc;
246
 
    gchar         *page_icon;
247
 
 
248
 
    GList          *back_list;
249
 
    GList          *back_cur;
250
 
    gboolean        back_load;
251
 
 
252
 
    GtkActionGroup *action_group;
253
 
 
254
 
    GSList         *link_actions;
255
 
 
256
 
    gint            navigation_requested;
257
 
};
258
 
 
259
 
#define TARGET_TYPE_URI_LIST     "text/uri-list"
260
 
enum {
261
 
    TARGET_URI_LIST
262
 
};
263
 
 
264
 
static void
265
 
yelp_view_init (YelpView *view)
266
 
{
267
 
    GtkAction *action;
268
 
    YelpViewPrivate *priv = GET_PRIV (view);
269
 
 
270
 
    g_object_set (view, "settings", websettings, NULL);
271
 
 
272
 
    priv->cancellable = NULL;
273
 
 
274
 
    priv->prevstate = priv->state = YELP_VIEW_STATE_BLANK;
275
 
 
276
 
    priv->navigation_requested =
277
 
        g_signal_connect (view, "navigation-policy-decision-requested",
278
 
                          G_CALLBACK (view_navigation_requested), NULL);
279
 
    g_signal_connect (view, "resource-request-starting",
280
 
                      G_CALLBACK (view_resource_request), NULL);
281
 
    g_signal_connect (view, "document-load-finished",
282
 
                      G_CALLBACK (view_document_loaded), NULL);
283
 
    g_signal_connect (view, "notify::hadjustment",
284
 
                      G_CALLBACK (view_set_hadjustment), NULL);
285
 
    g_signal_connect (view, "notify::vadjustment",
286
 
                      G_CALLBACK (view_set_vadjustment), NULL);
287
 
    g_signal_connect (view, "populate-popup",
288
 
                      G_CALLBACK (view_populate_popup), NULL);
289
 
    g_signal_connect (view, "script-alert",
290
 
                      G_CALLBACK (view_script_alert), NULL);
291
 
 
292
 
    priv->action_group = gtk_action_group_new ("YelpView");
293
 
    gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
294
 
    gtk_action_group_add_actions (priv->action_group,
295
 
                                  entries, G_N_ELEMENTS (entries),
296
 
                                  view);
297
 
    action = gtk_action_group_get_action (priv->action_group, "YelpViewGoBack");
298
 
    gtk_action_set_sensitive (action, FALSE);
299
 
    action = gtk_action_group_get_action (priv->action_group, "YelpViewGoForward");
300
 
    gtk_action_set_sensitive (action, FALSE);
301
 
}
302
 
 
303
 
static void
304
 
yelp_view_dispose (GObject *object)
305
 
{
306
 
    YelpViewPrivate *priv = GET_PRIV (object);
307
 
 
308
 
    view_clear_load (YELP_VIEW (object));
309
 
 
310
 
    if (priv->vadjuster > 0) {
311
 
        g_source_remove (priv->vadjuster);
312
 
        priv->vadjuster = 0;
313
 
    }
314
 
 
315
 
    if (priv->hadjuster > 0) {
316
 
        g_source_remove (priv->hadjuster);
317
 
        priv->hadjuster = 0;
318
 
    }
319
 
 
320
 
    if (priv->action_group) {
321
 
        g_object_unref (priv->action_group);
322
 
        priv->action_group = NULL;
323
 
    }
324
 
 
325
 
    if (priv->document) {
326
 
        g_object_unref (priv->document);
327
 
        priv->document = NULL;
328
 
    }
329
 
 
330
 
    while (priv->link_actions) {
331
 
        action_entry_free (priv->link_actions->data);
332
 
        priv->link_actions = g_slist_delete_link (priv->link_actions, priv->link_actions);
333
 
    }
334
 
 
335
 
    priv->back_cur = NULL;
336
 
    while (priv->back_list) {
337
 
        back_entry_free ((YelpBackEntry *) priv->back_list->data);
338
 
        priv->back_list = g_list_delete_link (priv->back_list, priv->back_list);
339
 
    }
340
 
 
341
 
    G_OBJECT_CLASS (yelp_view_parent_class)->dispose (object);
342
 
}
343
 
 
344
 
static void
345
 
yelp_view_finalize (GObject *object)
346
 
{
347
 
    YelpViewPrivate *priv = GET_PRIV (object);
348
 
 
349
 
    g_free (priv->popup_link_uri);
350
 
    g_free (priv->popup_link_text);
351
 
    g_free (priv->popup_image_uri);
352
 
    g_free (priv->popup_code_text);
353
 
 
354
 
    g_free (priv->page_id);
355
 
    g_free (priv->root_title);
356
 
    g_free (priv->page_title);
357
 
    g_free (priv->page_desc);
358
 
    g_free (priv->page_icon);
359
 
 
360
 
    g_free (priv->bogus_uri);
361
 
 
362
 
    G_OBJECT_CLASS (yelp_view_parent_class)->finalize (object);
363
 
}
364
 
 
365
 
static void
366
 
yelp_view_class_init (YelpViewClass *klass)
367
 
{
368
 
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
369
 
    YelpSettings *settings = yelp_settings_get_default ();
370
 
 
371
 
    nautilus_sendto = g_find_program_in_path ("nautilus-sendto");
372
 
 
373
 
    websettings = webkit_web_settings_new ();
374
 
    g_object_set (websettings, "enable-universal-access-from-file-uris", TRUE, NULL);
375
 
    g_signal_connect (settings,
376
 
                      "fonts-changed",
377
 
                      G_CALLBACK (settings_set_fonts),
378
 
                      NULL);
379
 
    settings_set_fonts (settings);
380
 
    g_signal_connect (settings,
381
 
                      "notify::show-text-cursor",
382
 
                      G_CALLBACK (settings_show_text_cursor),
383
 
                      NULL);
384
 
    settings_show_text_cursor (settings);
385
 
 
386
 
    klass->external_uri = view_external_uri;
387
 
 
388
 
    object_class->dispose = yelp_view_dispose;
389
 
    object_class->finalize = yelp_view_finalize;
390
 
    object_class->get_property = yelp_view_get_property;
391
 
    object_class->set_property = yelp_view_set_property;
392
 
 
393
 
    signals[NEW_VIEW_REQUESTED] =
394
 
        g_signal_new ("new-view-requested",
395
 
                      G_TYPE_FROM_CLASS (klass),
396
 
                      G_SIGNAL_RUN_LAST,
397
 
                      0, NULL, NULL,
398
 
                      g_cclosure_marshal_VOID__OBJECT,
399
 
                      G_TYPE_NONE, 1, YELP_TYPE_URI);
400
 
 
401
 
    signals[EXTERNAL_URI] =
402
 
        g_signal_new ("external-uri",
403
 
                      G_TYPE_FROM_CLASS (klass),
404
 
                      G_SIGNAL_RUN_LAST,
405
 
                      G_STRUCT_OFFSET (YelpViewClass, external_uri),
406
 
                      g_signal_accumulator_true_handled, NULL,
407
 
                      yelp_marshal_BOOLEAN__OBJECT,
408
 
                      G_TYPE_BOOLEAN, 1, YELP_TYPE_URI);
409
 
 
410
 
    signals[LOADED] =
411
 
        g_signal_new ("loaded",
412
 
                      G_TYPE_FROM_CLASS (klass),
413
 
                      G_SIGNAL_RUN_LAST,
414
 
                      0, NULL, NULL,
415
 
                      g_cclosure_marshal_VOID__VOID,
416
 
                      G_TYPE_NONE, 0);
417
 
 
418
 
    g_type_class_add_private (klass, sizeof (YelpViewPrivate));
419
 
 
420
 
    g_object_class_install_property (object_class,
421
 
                                     PROP_URI,
422
 
                                     g_param_spec_object ("yelp-uri",
423
 
                                                          _("Yelp URI"),
424
 
                                                          _("A YelpUri with the current location"),
425
 
                                                          YELP_TYPE_URI,
426
 
                                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
427
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
428
 
 
429
 
    g_object_class_install_property (object_class,
430
 
                                     PROP_STATE,
431
 
                                     g_param_spec_enum ("state",
432
 
                                                        N_("Loading State"),
433
 
                                                        N_("The loading state of the view"),
434
 
                                                        YELP_TYPE_VIEW_STATE,
435
 
                                                        YELP_VIEW_STATE_BLANK,
436
 
                                                        G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
437
 
                                                        G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
438
 
 
439
 
    g_object_class_install_property (object_class,
440
 
                                     PROP_PAGE_ID,
441
 
                                     g_param_spec_string ("page-id",
442
 
                                                          N_("Page ID"),
443
 
                                                          N_("The ID of the root page of the page being viewed"),
444
 
                                                          NULL,
445
 
                                                          G_PARAM_READABLE |
446
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
447
 
 
448
 
    g_object_class_install_property (object_class,
449
 
                                     PROP_ROOT_TITLE,
450
 
                                     g_param_spec_string ("root-title",
451
 
                                                          N_("Root Title"),
452
 
                                                          N_("The title of the root page of the page being viewed"),
453
 
                                                          NULL,
454
 
                                                          G_PARAM_READABLE |
455
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
456
 
 
457
 
    g_object_class_install_property (object_class,
458
 
                                     PROP_PAGE_TITLE,
459
 
                                     g_param_spec_string ("page-title",
460
 
                                                          N_("Page Title"),
461
 
                                                          N_("The title of the page being viewed"),
462
 
                                                          NULL,
463
 
                                                          G_PARAM_READABLE |
464
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
465
 
 
466
 
    g_object_class_install_property (object_class,
467
 
                                     PROP_PAGE_DESC,
468
 
                                     g_param_spec_string ("page-desc",
469
 
                                                          N_("Page Description"),
470
 
                                                          N_("The description of the page being viewed"),
471
 
                                                          NULL,
472
 
                                                          G_PARAM_READABLE |
473
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
474
 
 
475
 
    g_object_class_install_property (object_class,
476
 
                                     PROP_PAGE_ICON,
477
 
                                     g_param_spec_string ("page-icon",
478
 
                                                          N_("Page Icon"),
479
 
                                                          N_("The icon of the page being viewed"),
480
 
                                                          NULL,
481
 
                                                          G_PARAM_READABLE |
482
 
                                                          G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
483
 
}
484
 
 
485
 
static void
486
 
yelp_view_get_property (GObject    *object,
487
 
                        guint       prop_id,
488
 
                        GValue     *value,
489
 
                        GParamSpec *pspec)
490
 
{
491
 
    YelpViewPrivate *priv = GET_PRIV (object);
492
 
 
493
 
    switch (prop_id)
494
 
        {
495
 
        case PROP_URI:
496
 
            g_value_set_object (value, priv->uri);
497
 
            break;
498
 
        case PROP_PAGE_ID:
499
 
            g_value_set_string (value, priv->page_id);
500
 
            break;
501
 
        case PROP_ROOT_TITLE:
502
 
            g_value_set_string (value, priv->root_title);
503
 
            break;
504
 
        case PROP_PAGE_TITLE:
505
 
            g_value_set_string (value, priv->page_title);
506
 
            break;
507
 
        case PROP_PAGE_DESC:
508
 
            g_value_set_string (value, priv->page_desc);
509
 
            break;
510
 
        case PROP_PAGE_ICON:
511
 
            if (priv->page_icon)
512
 
                g_value_set_string (value, priv->page_icon);
513
 
            else
514
 
                g_value_set_string (value, "yelp-page-symbolic");
515
 
            break;
516
 
        case PROP_STATE:
517
 
            g_value_set_enum (value, priv->state);
518
 
            break;
519
 
        default:
520
 
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
521
 
            break;
522
 
    }
523
 
}
524
 
 
525
 
static void
526
 
yelp_view_set_property (GObject      *object,
527
 
                        guint         prop_id,
528
 
                        const GValue *value,
529
 
                        GParamSpec   *pspec)
530
 
{
531
 
    YelpUri *uri;
532
 
    YelpViewPrivate *priv = GET_PRIV (object);
533
 
 
534
 
    switch (prop_id)
535
 
        {
536
 
        case PROP_URI:
537
 
            uri = g_value_get_object (value);
538
 
            yelp_view_load_uri (YELP_VIEW (object), uri);
539
 
            g_object_unref (uri);
540
 
            break;
541
 
        case PROP_STATE:
542
 
            priv->prevstate = priv->state;
543
 
            priv->state = g_value_get_enum (value);
544
 
            break;
545
 
        default:
546
 
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
547
 
            break;
548
 
    }
549
 
}
550
 
 
551
 
/******************************************************************************/
552
 
 
553
 
GtkWidget *
554
 
yelp_view_new (void)
555
 
{
556
 
    return (GtkWidget *) g_object_new (YELP_TYPE_VIEW, NULL);
557
 
}
558
 
 
559
 
void
560
 
yelp_view_load (YelpView    *view,
561
 
                const gchar *uri)
562
 
{
563
 
    YelpUri *yuri = yelp_uri_new (uri);
564
 
    yelp_view_load_uri (view, yuri);
565
 
    g_object_unref (yuri);
566
 
}
567
 
 
568
 
void
569
 
yelp_view_load_uri (YelpView *view,
570
 
                    YelpUri  *uri)
571
 
{
572
 
    YelpViewPrivate *priv = GET_PRIV (view);
573
 
 
574
 
    g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
575
 
 
576
 
    gtk_action_set_sensitive (gtk_action_group_get_action (priv->action_group,
577
 
                                                           "YelpViewGoPrevious"),
578
 
                              FALSE);
579
 
    gtk_action_set_sensitive (gtk_action_group_get_action (priv->action_group,
580
 
                                                           "YelpViewGoNext"),
581
 
                              FALSE);
582
 
 
583
 
    if (!yelp_uri_is_resolved (uri)) {
584
 
        if (priv->resolve_uri != NULL) {
585
 
            if (priv->uri_resolved != 0) {
586
 
                g_signal_handler_disconnect (priv->resolve_uri, priv->uri_resolved);
587
 
                priv->uri_resolved = 0;
588
 
            }
589
 
            g_object_unref (priv->resolve_uri);
590
 
        }
591
 
        priv->resolve_uri = g_object_ref (uri);
592
 
        priv->uri_resolved = g_signal_connect (uri, "resolved",
593
 
                                               G_CALLBACK (uri_resolved),
594
 
                                               view);
595
 
        yelp_uri_resolve (uri);
596
 
    }
597
 
    else {
598
 
        uri_resolved (uri, view);
599
 
    }
600
 
}
601
 
 
602
 
void
603
 
yelp_view_load_document (YelpView     *view,
604
 
                         YelpUri      *uri,
605
 
                         YelpDocument *document)
606
 
{
607
 
    GParamSpec *spec;
608
 
    YelpViewPrivate *priv = GET_PRIV (view);
609
 
 
610
 
    g_return_if_fail (yelp_uri_is_resolved (uri));
611
 
 
612
 
    g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
613
 
 
614
 
    g_object_ref (uri);
615
 
    view_clear_load (view);
616
 
    priv->uri = uri;
617
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
618
 
                                         "yelp-uri");
619
 
    g_signal_emit_by_name (view, "notify::yelp-uri", spec);
620
 
    g_object_ref (document);
621
 
    if (priv->document)
622
 
        g_object_unref (document);
623
 
    priv->document = document;
624
 
 
625
 
    view_load_page (view);
626
 
}
627
 
 
628
 
YelpDocument *
629
 
yelp_view_get_document (YelpView *view)
630
 
{
631
 
    YelpViewPrivate *priv = GET_PRIV (view);
632
 
    return priv->document;
633
 
}
634
 
 
635
 
GtkActionGroup *
636
 
yelp_view_get_action_group (YelpView *view)
637
 
{
638
 
    YelpViewPrivate *priv = GET_PRIV (view);
639
 
    return priv->action_group;
640
 
}
641
 
 
642
 
/******************************************************************************/
643
 
 
644
 
void
645
 
yelp_view_add_link_action (YelpView                *view,
646
 
                           GtkAction               *action,
647
 
                           YelpViewActionValidFunc  func,
648
 
                           gpointer                 data)
649
 
{
650
 
    YelpActionEntry *entry;
651
 
    YelpViewPrivate *priv = GET_PRIV (view);
652
 
 
653
 
    entry = g_new0 (YelpActionEntry, 1);
654
 
    entry->action = g_object_ref (action);
655
 
    entry->func = func;
656
 
    entry->data = data;
657
 
 
658
 
    priv->link_actions = g_slist_append (priv->link_actions, entry);
659
 
}
660
 
 
661
 
YelpUri *
662
 
yelp_view_get_active_link_uri (YelpView *view)
663
 
{
664
 
    YelpViewPrivate *priv = GET_PRIV (view);
665
 
    YelpUri *uri;
666
 
 
667
 
    if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
668
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
669
 
    else
670
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
671
 
 
672
 
    return uri;
673
 
}
674
 
 
675
 
gchar *
676
 
yelp_view_get_active_link_text (YelpView *view)
677
 
{
678
 
    YelpViewPrivate *priv = GET_PRIV (view);
679
 
    return g_strdup (priv->popup_link_text);
680
 
}
681
 
 
682
 
/******************************************************************************/
683
 
 
684
 
static gboolean
685
 
view_external_uri (YelpView *view,
686
 
                   YelpUri  *uri)
687
 
{
688
 
    gchar *struri = yelp_uri_get_canonical_uri (uri);
689
 
    g_app_info_launch_default_for_uri (struri, NULL, NULL);
690
 
    g_free (struri);
691
 
    return TRUE;
692
 
}
693
 
 
694
 
typedef struct _YelpInstallInfo YelpInstallInfo;
695
 
struct _YelpInstallInfo {
696
 
    YelpView *view;
697
 
    gchar *uri;
698
 
};
699
 
 
700
 
static void
701
 
yelp_install_info_free (YelpInstallInfo *info)
702
 
{
703
 
    g_object_unref (info->view);
704
 
    if (info->uri)
705
 
        g_free (info->uri);
706
 
    g_free (info);
707
 
}
708
 
 
709
 
static void
710
 
view_install_installed (GDBusConnection *connection,
711
 
                        GAsyncResult    *res,
712
 
                        YelpInstallInfo *info)
713
 
{
714
 
    GError *error = NULL;
715
 
    g_dbus_connection_call_finish (connection, res, &error);
716
 
    if (error) {
717
 
        const gchar *err = NULL;
718
 
        if (error->domain == G_DBUS_ERROR) {
719
 
            if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
720
 
                err = _("You do not have PackageKit. Package install links require PackageKit.");
721
 
            else
722
 
                err = error->message;
723
 
        }
724
 
        if (err != NULL) {
725
 
            GtkWidget *dialog = gtk_message_dialog_new (NULL, 0,
726
 
                                                        GTK_MESSAGE_ERROR,
727
 
                                                        GTK_BUTTONS_CLOSE,
728
 
                                                        "%s", err);
729
 
            gtk_dialog_run ((GtkDialog *) dialog);
730
 
            gtk_widget_destroy (dialog);
731
 
        }
732
 
        g_error_free (error);
733
 
    }
734
 
    else if (info->uri) {
735
 
        gchar *struri, *docuri;
736
 
        YelpViewPrivate *priv = GET_PRIV (info->view);
737
 
        docuri = yelp_uri_get_document_uri (priv->uri);
738
 
        if (g_str_equal (docuri, info->uri)) {
739
 
            struri = yelp_uri_get_canonical_uri (priv->uri);
740
 
            yelp_view_load (info->view, struri);
741
 
            g_free (struri);
742
 
        }
743
 
        g_free (docuri);
744
 
    }
745
 
 
746
 
    yelp_install_info_free (info);
747
 
}
748
 
 
749
 
static void
750
 
view_install_uri (YelpView    *view,
751
 
                  const gchar *uri)
752
 
{
753
 
    GDBusConnection *connection;
754
 
    GError *error;
755
 
    gboolean help = FALSE, ghelp = FALSE;
756
 
    GVariantBuilder *strv;
757
 
    YelpInstallInfo *info;
758
 
    guint32 xid = 0;
759
 
    YelpViewPrivate *priv = GET_PRIV (view);
760
 
    GtkWidget *gtkwin;
761
 
    GdkWindow *gdkwin;
762
 
    /* do not free */
763
 
    gchar *pkg, *confirm_search;
764
 
 
765
 
    if (g_str_has_prefix (uri, "install-help:")) {
766
 
        help = TRUE;
767
 
        pkg = (gchar *) uri + 13;
768
 
    }
769
 
    else if (g_str_has_prefix (uri, "install-ghelp:")) {
770
 
        ghelp = TRUE;
771
 
        pkg = (gchar *) uri + 14;
772
 
    }
773
 
    else if (g_str_has_prefix (uri, "install:")) {
774
 
        pkg = (gchar *) uri + 8;
775
 
    }
776
 
 
777
 
    connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
778
 
    if (connection == NULL) {
779
 
        g_warning ("Unable to connect to dbus: %s", error->message);
780
 
        g_error_free (error);
781
 
        return;
782
 
    }
783
 
 
784
 
    info = g_new0 (YelpInstallInfo, 1);
785
 
    info->view = g_object_ref (view);
786
 
 
787
 
    gtkwin = gtk_widget_get_toplevel (GTK_WIDGET (view));
788
 
    if (gtkwin != NULL && gtk_widget_is_toplevel (gtkwin)) {
789
 
        gdkwin = gtk_widget_get_window (gtkwin);
790
 
        if (gdkwin != NULL)
791
 
            xid = gdk_x11_window_get_xid (gdkwin);
792
 
    }
793
 
 
794
 
    if (priv->state == YELP_VIEW_STATE_ERROR)
795
 
        confirm_search = "hide-confirm-search";
796
 
    else
797
 
        confirm_search = "";
798
 
 
799
 
    if (help || ghelp) {
800
 
        const gchar * const *datadirs = g_get_system_data_dirs ();
801
 
        gint datadirs_i;
802
 
        gchar *docbook, *fname;
803
 
        docbook = g_strconcat (pkg, ".xml", NULL);
804
 
        strv = g_variant_builder_new (G_VARIANT_TYPE ("as"));
805
 
        for (datadirs_i = 0; datadirs[datadirs_i] != NULL; datadirs_i++) {
806
 
            if (ghelp) {
807
 
                fname = g_build_filename (datadirs[datadirs_i], "gnome", "help",
808
 
                                          pkg, "C", "index.page", NULL);
809
 
                g_variant_builder_add (strv, "s", fname);
810
 
                g_free (fname);
811
 
                fname = g_build_filename (datadirs[datadirs_i], "gnome", "help",
812
 
                                          pkg, "C", docbook, NULL);
813
 
                g_variant_builder_add (strv, "s", fname);
814
 
                g_free (fname);
815
 
            }
816
 
            else {
817
 
                fname = g_build_filename (datadirs[datadirs_i], "help", "C",
818
 
                                          pkg, "index.page", NULL);
819
 
                g_variant_builder_add (strv, "s", fname);
820
 
                g_free (fname);
821
 
                fname = g_build_filename (datadirs[datadirs_i], "help", "C",
822
 
                                          pkg, "index.docbook", NULL);
823
 
                g_variant_builder_add (strv, "s", fname);
824
 
                g_free (fname);
825
 
            }
826
 
        }
827
 
        g_free (docbook);
828
 
        info->uri = g_strconcat (ghelp ? "ghelp:" : "help:", pkg, NULL);
829
 
        g_dbus_connection_call (connection,
830
 
                                "org.freedesktop.PackageKit",
831
 
                                "/org/freedesktop/PackageKit",
832
 
                                "org.freedesktop.PackageKit.Modify",
833
 
                                "InstallProvideFiles",
834
 
                                g_variant_new ("(uass)", xid, strv, confirm_search),
835
 
                                NULL,
836
 
                                G_DBUS_CALL_FLAGS_NONE,
837
 
                                G_MAXINT, NULL,
838
 
                                (GAsyncReadyCallback) view_install_installed,
839
 
                                info);
840
 
        g_variant_builder_unref (strv);
841
 
    }
842
 
    else {
843
 
        gchar **pkgs;
844
 
        gint i;
845
 
        strv = g_variant_builder_new (G_VARIANT_TYPE ("as"));
846
 
        pkgs = g_strsplit (pkg, ",", 0);
847
 
        for (i = 0; pkgs[i]; i++)
848
 
            g_variant_builder_add (strv, "s", pkgs[i]);
849
 
        g_strfreev (pkgs);
850
 
        g_dbus_connection_call (connection,
851
 
                                "org.freedesktop.PackageKit",
852
 
                                "/org/freedesktop/PackageKit",
853
 
                                "org.freedesktop.PackageKit.Modify",
854
 
                                "InstallPackageNames",
855
 
                                g_variant_new ("(uass)", xid, strv, confirm_search),
856
 
                                NULL,
857
 
                                G_DBUS_CALL_FLAGS_NONE,
858
 
                                G_MAXINT, NULL,
859
 
                                (GAsyncReadyCallback) view_install_installed,
860
 
                                info);
861
 
        g_variant_builder_unref (strv);
862
 
    }
863
 
 
864
 
    g_object_unref (connection);
865
 
}
866
 
 
867
 
static void
868
 
view_scrolled (GtkAdjustment *adjustment,
869
 
               YelpView      *view)
870
 
{
871
 
    YelpViewPrivate *priv = GET_PRIV (view);
872
 
    if (priv->back_cur == NULL || priv->back_cur->data == NULL)
873
 
        return;
874
 
    if (adjustment == priv->vadjustment)
875
 
        ((YelpBackEntry *) priv->back_cur->data)->vadj = gtk_adjustment_get_value (adjustment);
876
 
    else if (adjustment = priv->hadjustment)
877
 
        ((YelpBackEntry *) priv->back_cur->data)->hadj = gtk_adjustment_get_value (adjustment);
878
 
}
879
 
 
880
 
static void
881
 
view_set_hadjustment (YelpView      *view,
882
 
                      GParamSpec    *pspec,
883
 
                      gpointer       data)
884
 
{
885
 
    YelpViewPrivate *priv = GET_PRIV (view);
886
 
    priv->hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (view));
887
 
    if (priv->hadjuster > 0)
888
 
        g_source_remove (priv->hadjuster);
889
 
    priv->hadjuster = 0;
890
 
    if (priv->hadjustment)
891
 
        priv->hadjuster = g_signal_connect (priv->hadjustment, "value-changed",
892
 
                                            G_CALLBACK (view_scrolled), view);
893
 
}
894
 
 
895
 
static void
896
 
view_set_vadjustment (YelpView      *view,
897
 
                      GParamSpec    *pspec,
898
 
                      gpointer       data)
899
 
{
900
 
    YelpViewPrivate *priv = GET_PRIV (view);
901
 
    priv->vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view));
902
 
    if (priv->vadjuster > 0)
903
 
        g_source_remove (priv->vadjuster);
904
 
    priv->vadjuster = 0;
905
 
    if (priv->vadjustment)
906
 
        priv->vadjuster = g_signal_connect (priv->vadjustment, "value-changed",
907
 
                                            G_CALLBACK (view_scrolled), view);
908
 
}
909
 
 
910
 
static void
911
 
popup_open_link (GtkMenuItem *item,
912
 
                 YelpView    *view)
913
 
{
914
 
    YelpViewPrivate *priv = GET_PRIV (view);
915
 
    YelpUri *uri;
916
 
 
917
 
    if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
918
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
919
 
    else
920
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
921
 
 
922
 
    yelp_view_load_uri (view, uri);
923
 
    g_object_unref (uri);
924
 
 
925
 
    g_free (priv->popup_link_uri);
926
 
    priv->popup_link_uri = NULL;
927
 
 
928
 
    g_free (priv->popup_link_text);
929
 
    priv->popup_link_text = NULL;
930
 
}
931
 
 
932
 
static void
933
 
popup_open_link_new (GtkMenuItem *item,
934
 
                     YelpView    *view)
935
 
{
936
 
    YelpViewPrivate *priv = GET_PRIV (view);
937
 
    YelpUri *uri;
938
 
 
939
 
    if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
940
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
941
 
    else
942
 
        uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
943
 
 
944
 
    g_free (priv->popup_link_uri);
945
 
    priv->popup_link_uri = NULL;
946
 
 
947
 
    g_free (priv->popup_link_text);
948
 
    priv->popup_link_text = NULL;
949
 
 
950
 
    g_signal_emit (view, signals[NEW_VIEW_REQUESTED], 0, uri);
951
 
    g_object_unref (uri);
952
 
}
953
 
 
954
 
static void
955
 
popup_copy_link (GtkMenuItem *item,
956
 
                 YelpView    *view)
957
 
{
958
 
    YelpViewPrivate *priv = GET_PRIV (view);
959
 
    gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD),
960
 
                            priv->popup_link_uri,
961
 
                            -1);
962
 
}
963
 
 
964
 
typedef struct _YelpSaveData YelpSaveData;
965
 
struct _YelpSaveData {
966
 
    GFile     *orig;
967
 
    GFile     *dest;
968
 
    YelpView  *view;
969
 
    GtkWindow *window;
970
 
};
971
 
 
972
 
static void
973
 
file_copied (GFile        *file,
974
 
             GAsyncResult *res,
975
 
             YelpSaveData *data)
976
 
{
977
 
    GError *error = NULL;
978
 
    if (!g_file_copy_finish (file, res, &error)) {
979
 
        GtkWidget *dialog = gtk_message_dialog_new (gtk_widget_get_visible (GTK_WIDGET (data->window)) ? data->window : NULL,
980
 
                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
981
 
                                                    GTK_MESSAGE_ERROR,
982
 
                                                    GTK_BUTTONS_OK,
983
 
                                                    "%s", error->message);
984
 
        gtk_dialog_run (GTK_DIALOG (dialog));
985
 
        gtk_widget_destroy (dialog);
986
 
    }
987
 
    g_object_unref (data->orig);
988
 
    g_object_unref (data->dest);
989
 
    g_object_unref (data->view);
990
 
    g_object_unref (data->window);
991
 
}
992
 
 
993
 
static void
994
 
popup_save_image (GtkMenuItem *item,
995
 
                  YelpView    *view)
996
 
{
997
 
    YelpSaveData *data;
998
 
    GtkWidget *dialog, *window;
999
 
    gchar *basename;
1000
 
    gint res;
1001
 
    YelpViewPrivate *priv = GET_PRIV (view);
1002
 
 
1003
 
    for (window = gtk_widget_get_parent (GTK_WIDGET (view));
1004
 
         window && !GTK_IS_WINDOW (window);
1005
 
         window = gtk_widget_get_parent (window));
1006
 
 
1007
 
    data = g_new0 (YelpSaveData, 1);
1008
 
    data->orig = g_file_new_for_uri (priv->popup_image_uri);
1009
 
    data->view = g_object_ref (view);
1010
 
    data->window = g_object_ref (window);
1011
 
    g_free (priv->popup_image_uri);
1012
 
    priv->popup_image_uri = NULL;
1013
 
 
1014
 
    dialog = gtk_file_chooser_dialog_new (_("Save Image"),
1015
 
                                          GTK_WINDOW (window),
1016
 
                                          GTK_FILE_CHOOSER_ACTION_SAVE,
1017
 
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1018
 
                                          GTK_STOCK_SAVE, GTK_RESPONSE_OK,
1019
 
                                          NULL);
1020
 
    gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
1021
 
    basename = g_file_get_basename (data->orig);
1022
 
    gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), basename);
1023
 
    g_free (basename);
1024
 
    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1025
 
                                         g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP));
1026
 
 
1027
 
    res = gtk_dialog_run (GTK_DIALOG (dialog));
1028
 
 
1029
 
    if (res == GTK_RESPONSE_OK) {
1030
 
        data->dest = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
1031
 
        g_file_copy_async (data->orig, data->dest,
1032
 
                           G_FILE_COPY_OVERWRITE,
1033
 
                           G_PRIORITY_DEFAULT,
1034
 
                           NULL, NULL, NULL,
1035
 
                           (GAsyncReadyCallback) file_copied,
1036
 
                           data);
1037
 
    }
1038
 
    else {
1039
 
        g_object_unref (data->orig);
1040
 
        g_object_unref (data->view);
1041
 
        g_object_unref (data->window);
1042
 
        g_free (data);
1043
 
    }
1044
 
 
1045
 
    gtk_widget_destroy (dialog);
1046
 
}
1047
 
 
1048
 
static void
1049
 
popup_send_image (GtkMenuItem *item,
1050
 
                  YelpView    *view)
1051
 
{
1052
 
    gchar *command;
1053
 
    GAppInfo *app;
1054
 
    GAppLaunchContext *context;
1055
 
    GError *error = NULL;
1056
 
    YelpViewPrivate *priv = GET_PRIV (view);
1057
 
 
1058
 
    command = g_strdup_printf ("%s %s", nautilus_sendto, priv->popup_image_uri);
1059
 
    context = (GAppLaunchContext *) gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (item)));
1060
 
 
1061
 
    app = g_app_info_create_from_commandline (command, NULL, 0, &error);
1062
 
    if (app) {
1063
 
        g_app_info_launch (app, NULL, context, &error);
1064
 
        g_object_unref (app);
1065
 
    }
1066
 
 
1067
 
    if (error) {
1068
 
        g_debug ("Could not launch nautilus-sendto: %s", error->message);
1069
 
        g_error_free (error);
1070
 
    }
1071
 
 
1072
 
    g_object_unref (context);
1073
 
    g_free (command);
1074
 
    g_free (priv->popup_image_uri);
1075
 
    priv->popup_image_uri = NULL;
1076
 
}
1077
 
 
1078
 
static void
1079
 
popup_copy_code (GtkMenuItem *item,
1080
 
                 YelpView    *view)
1081
 
{
1082
 
    YelpViewPrivate *priv = GET_PRIV (view);
1083
 
    GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1084
 
    gchar *content = webkit_dom_node_get_text_content (priv->popup_code_node);
1085
 
    gtk_clipboard_set_text (clipboard, content, -1);
1086
 
    g_free (content);
1087
 
}
1088
 
 
1089
 
static void
1090
 
popup_save_code (GtkMenuItem *item,
1091
 
                 YelpView    *view)
1092
 
{
1093
 
    YelpViewPrivate *priv = GET_PRIV (view);
1094
 
    GtkWidget *dialog, *window;
1095
 
    gint res;
1096
 
 
1097
 
    g_free (priv->popup_code_text);
1098
 
    priv->popup_code_text = webkit_dom_node_get_text_content (priv->popup_code_node);
1099
 
    if (!g_str_has_suffix (priv->popup_code_text, "\n")) {
1100
 
        gchar *tmp = g_strconcat (priv->popup_code_text, "\n", NULL);
1101
 
        g_free (priv->popup_code_text);
1102
 
        priv->popup_code_text = tmp;
1103
 
    }
1104
 
 
1105
 
    for (window = gtk_widget_get_parent (GTK_WIDGET (view));
1106
 
         window && !GTK_IS_WINDOW (window);
1107
 
         window = gtk_widget_get_parent (window));
1108
 
 
1109
 
    dialog = gtk_file_chooser_dialog_new (_("Save Code"),
1110
 
                                          GTK_WINDOW (window),
1111
 
                                          GTK_FILE_CHOOSER_ACTION_SAVE,
1112
 
                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1113
 
                                          GTK_STOCK_SAVE, GTK_RESPONSE_OK,
1114
 
                                          NULL);
1115
 
    gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
1116
 
    if (priv->popup_code_title) {
1117
 
        gchar *filename = webkit_dom_node_get_text_content (priv->popup_code_title);
1118
 
        gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename);
1119
 
        g_free (filename);
1120
 
    }
1121
 
    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1122
 
                                         g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
1123
 
 
1124
 
    res = gtk_dialog_run (GTK_DIALOG (dialog));
1125
 
 
1126
 
    if (res == GTK_RESPONSE_OK) {
1127
 
        GError *error = NULL;
1128
 
        GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
1129
 
        GFileOutputStream *stream = g_file_replace (file, NULL, FALSE,
1130
 
                                                    G_FILE_CREATE_NONE,
1131
 
                                                    NULL,
1132
 
                                                    &error);
1133
 
        if (stream == NULL) {
1134
 
            GtkWidget *dialog = gtk_message_dialog_new (gtk_widget_get_visible (window) ? GTK_WINDOW (window) : NULL,
1135
 
                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
1136
 
                                                        GTK_MESSAGE_ERROR,
1137
 
                                                        GTK_BUTTONS_OK,
1138
 
                                                        "%s", error->message);
1139
 
            gtk_dialog_run (GTK_DIALOG (dialog));
1140
 
            gtk_widget_destroy (dialog);
1141
 
            g_error_free (error);
1142
 
        }
1143
 
        else {
1144
 
            /* FIXME: we should do this async */
1145
 
            GDataOutputStream *datastream = g_data_output_stream_new (G_OUTPUT_STREAM (stream));
1146
 
            if (!g_data_output_stream_put_string (datastream, priv->popup_code_text, NULL, &error)) {
1147
 
                GtkWidget *dialog = gtk_message_dialog_new (gtk_widget_get_visible (window) ? GTK_WINDOW (window) : NULL,
1148
 
                                                            GTK_DIALOG_DESTROY_WITH_PARENT,
1149
 
                                                            GTK_MESSAGE_ERROR,
1150
 
                                                            GTK_BUTTONS_OK,
1151
 
                                                            "%s", error->message);
1152
 
                gtk_dialog_run (GTK_DIALOG (dialog));
1153
 
                gtk_widget_destroy (dialog);
1154
 
                g_error_free (error);
1155
 
            }
1156
 
            g_object_unref (datastream);
1157
 
        }
1158
 
        g_object_unref (file);
1159
 
    }
1160
 
 
1161
 
    priv->popup_code_node = NULL;
1162
 
    priv->popup_code_title = NULL;
1163
 
    g_free (priv->popup_code_text);
1164
 
    priv->popup_code_text = NULL;
1165
 
 
1166
 
    gtk_widget_destroy (dialog);
1167
 
}
1168
 
 
1169
 
static void
1170
 
view_populate_popup (YelpView *view,
1171
 
                     GtkMenu  *menu,
1172
 
                     gpointer  data)
1173
 
{
1174
 
    WebKitHitTestResult *result;
1175
 
    WebKitHitTestResultContext context;
1176
 
    GdkEvent *event;
1177
 
    YelpViewPrivate *priv = GET_PRIV (view);
1178
 
    GList *children;
1179
 
    GtkWidget *item;
1180
 
    WebKitDOMNode *node, *cur, *link_node = NULL, *code_node = NULL, *code_title_node = NULL;
1181
 
 
1182
 
    children = gtk_container_get_children (GTK_CONTAINER (menu));
1183
 
    while (children) {
1184
 
        gtk_container_remove (GTK_CONTAINER (menu),
1185
 
                              GTK_WIDGET (children->data));
1186
 
        children = children->next;
1187
 
    }
1188
 
    g_list_free (children);
1189
 
 
1190
 
    event = gtk_get_current_event ();
1191
 
 
1192
 
    result = webkit_web_view_get_hit_test_result (WEBKIT_WEB_VIEW (view), (GdkEventButton *) event);
1193
 
    g_object_get (result,
1194
 
                  "context", &context,
1195
 
                  "inner-node", &node,
1196
 
                  NULL);
1197
 
    for (cur = node; cur != NULL; cur = webkit_dom_node_get_parent_node (cur)) {
1198
 
        if (WEBKIT_DOM_IS_ELEMENT (cur) &&
1199
 
            webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) cur,
1200
 
                                                        "a", NULL))
1201
 
            link_node = cur;
1202
 
 
1203
 
        if (WEBKIT_DOM_IS_ELEMENT (cur) &&
1204
 
            webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) cur,
1205
 
                                                        "div.code", NULL)) {
1206
 
            WebKitDOMNode *title;
1207
 
            code_node = (WebKitDOMNode *)
1208
 
                webkit_dom_element_query_selector ((WebKitDOMElement *) cur,
1209
 
                                                   "pre.contents", NULL);
1210
 
            title = webkit_dom_node_get_parent_node (cur);
1211
 
            if (title != NULL && WEBKIT_DOM_IS_ELEMENT (title) &&
1212
 
                webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) title,
1213
 
                                                            "div.contents", NULL)) {
1214
 
                title = webkit_dom_node_get_previous_sibling (title);
1215
 
                if (title != NULL && WEBKIT_DOM_IS_ELEMENT (title) &&
1216
 
                    webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) title,
1217
 
                                                                "div.title", NULL)) {
1218
 
                    code_title_node = title;
1219
 
                }
1220
 
            }
1221
 
        }
1222
 
    }
1223
 
 
1224
 
    if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
1225
 
        gchar *uri;
1226
 
        g_object_get (result, "link-uri", &uri, NULL);
1227
 
        g_free (priv->popup_link_uri);
1228
 
        priv->popup_link_uri = uri;
1229
 
 
1230
 
        g_free (priv->popup_link_text);
1231
 
        priv->popup_link_text = NULL;
1232
 
        if (link_node != NULL) {
1233
 
            WebKitDOMNode *child;
1234
 
            gchar *tmp;
1235
 
            gint i, tmpi;
1236
 
            gboolean ws;
1237
 
 
1238
 
            child = (WebKitDOMNode *)
1239
 
                webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (link_node),
1240
 
                                                   "span.title", NULL);
1241
 
            if (child != NULL)
1242
 
                priv->popup_link_text = webkit_dom_node_get_text_content (child);
1243
 
 
1244
 
            if (priv->popup_link_text == NULL)
1245
 
                priv->popup_link_text = webkit_dom_node_get_text_content (link_node);
1246
 
 
1247
 
            tmp = g_new0 (gchar, strlen(priv->popup_link_text) + 1);
1248
 
            ws = FALSE;
1249
 
            for (i = 0, tmpi = 0; priv->popup_link_text[i] != '\0'; i++) {
1250
 
                if (priv->popup_link_text[i] == ' ' || priv->popup_link_text[i] == '\n') {
1251
 
                    if (!ws) {
1252
 
                        tmp[tmpi] = ' ';
1253
 
                        tmpi++;
1254
 
                        ws = TRUE;
1255
 
                    }
1256
 
                }
1257
 
                else {
1258
 
                    tmp[tmpi] = priv->popup_link_text[i];
1259
 
                    tmpi++;
1260
 
                    ws = FALSE;
1261
 
                }
1262
 
            }
1263
 
            tmp[tmpi] = '\0';
1264
 
            g_free (priv->popup_link_text);
1265
 
            priv->popup_link_text = tmp;
1266
 
        }
1267
 
        else {
1268
 
            priv->popup_link_text = g_strdup (uri);
1269
 
        }
1270
 
 
1271
 
        if (g_str_has_prefix (priv->popup_link_uri, "mailto:")) {
1272
 
            gchar *label = g_strdup_printf (_("Send email to %s"),
1273
 
                                            priv->popup_link_uri + 7);
1274
 
            /* Not using a mnemonic because underscores are common in email
1275
 
             * addresses, and we'd have to escape them. There doesn't seem
1276
 
             * to be a quick GTK+ function for this. In practice, there will
1277
 
             * probably only be one menu item for mailto link popups anyway,
1278
 
             * so the mnemonic's not that big of a deal.
1279
 
             */
1280
 
            item = gtk_menu_item_new_with_label (label);
1281
 
            g_signal_connect (item, "activate",
1282
 
                              G_CALLBACK (popup_open_link), view);
1283
 
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1284
 
            g_free (label);
1285
 
        }
1286
 
        else if (g_str_has_prefix (priv->popup_link_uri, "install:")) {
1287
 
            item = gtk_menu_item_new_with_mnemonic (_("_Install Packages"));
1288
 
            g_signal_connect (item, "activate",
1289
 
                              G_CALLBACK (popup_open_link), view);
1290
 
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1291
 
        }
1292
 
        else {
1293
 
            GSList *cur;
1294
 
 
1295
 
            item = gtk_menu_item_new_with_mnemonic (_("_Open Link"));
1296
 
            g_signal_connect (item, "activate",
1297
 
                              G_CALLBACK (popup_open_link), view);
1298
 
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1299
 
 
1300
 
            if (g_str_has_prefix (priv->popup_link_uri, "http://") ||
1301
 
                g_str_has_prefix (priv->popup_link_uri, "https://")) {
1302
 
                item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Location"));
1303
 
                g_signal_connect (item, "activate",
1304
 
                                  G_CALLBACK (popup_copy_link), view);
1305
 
                gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1306
 
            }
1307
 
            else {
1308
 
                item = gtk_menu_item_new_with_mnemonic (_("Open Link in New _Window"));
1309
 
                g_signal_connect (item, "activate",
1310
 
                                  G_CALLBACK (popup_open_link_new), view);
1311
 
                gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1312
 
            }
1313
 
 
1314
 
            for (cur = priv->link_actions; cur != NULL; cur = cur->next) {
1315
 
                gboolean add;
1316
 
                YelpActionEntry *entry = (YelpActionEntry *) cur->data;
1317
 
                if (entry->func == NULL)
1318
 
                    add = TRUE;
1319
 
                else
1320
 
                    add = (* entry->func) (view, entry->action,
1321
 
                                           priv->popup_link_uri,
1322
 
                                           entry->data);
1323
 
                if (add) {
1324
 
                    item = gtk_action_create_menu_item (entry->action);
1325
 
                    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1326
 
                }
1327
 
            }
1328
 
        }
1329
 
    }
1330
 
    else {
1331
 
        item = gtk_action_create_menu_item (gtk_action_group_get_action (priv->action_group,
1332
 
                                                                         "YelpViewGoBack"));
1333
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1334
 
        item = gtk_action_create_menu_item (gtk_action_group_get_action (priv->action_group,
1335
 
                                                                         "YelpViewGoForward"));
1336
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1337
 
    }
1338
 
 
1339
 
    if ((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) ||
1340
 
        (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)) {
1341
 
        /* This doesn't currently work for video with automatic controls,
1342
 
         * because WebKit puts the hit test on the div with the controls.
1343
 
         */
1344
 
        gboolean image = context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE;
1345
 
        gchar *uri;
1346
 
        g_object_get (result, image ? "image-uri" : "media-uri", &uri, NULL);
1347
 
        g_free (priv->popup_image_uri);
1348
 
        if (g_str_has_prefix (uri, BOGUS_URI)) {
1349
 
            priv->popup_image_uri = yelp_uri_locate_file_uri (priv->uri, uri + BOGUS_URI_LEN);
1350
 
            g_free (uri);
1351
 
        }
1352
 
        else {
1353
 
            priv->popup_image_uri = uri;
1354
 
        }
1355
 
 
1356
 
        item = gtk_separator_menu_item_new ();
1357
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1358
 
 
1359
 
        if (image)
1360
 
            item = gtk_menu_item_new_with_mnemonic (_("_Save Image As..."));
1361
 
        else
1362
 
            item = gtk_menu_item_new_with_mnemonic (_("_Save Video As..."));
1363
 
        g_signal_connect (item, "activate",
1364
 
                          G_CALLBACK (popup_save_image), view);
1365
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1366
 
 
1367
 
        if (nautilus_sendto) {
1368
 
            if (image)
1369
 
                item = gtk_menu_item_new_with_mnemonic (_("S_end Image To..."));
1370
 
            else
1371
 
                item = gtk_menu_item_new_with_mnemonic (_("S_end Video To..."));
1372
 
            g_signal_connect (item, "activate",
1373
 
                              G_CALLBACK (popup_send_image), view);
1374
 
            gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1375
 
        }
1376
 
    }
1377
 
 
1378
 
    if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) {
1379
 
        item = gtk_separator_menu_item_new ();
1380
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1381
 
 
1382
 
        item = gtk_menu_item_new_with_mnemonic (_("_Copy Text"));
1383
 
        g_signal_connect_swapped (item, "activate",
1384
 
                                  G_CALLBACK (webkit_web_view_copy_clipboard), view);
1385
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1386
 
    }
1387
 
 
1388
 
    if (code_node != NULL) {
1389
 
        item = gtk_separator_menu_item_new ();
1390
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1391
 
 
1392
 
        priv->popup_code_node = code_node;
1393
 
        priv->popup_code_title = code_title_node;
1394
 
 
1395
 
        item = gtk_menu_item_new_with_mnemonic (_("C_opy Code Block"));
1396
 
        g_signal_connect (item, "activate",
1397
 
                          G_CALLBACK (popup_copy_code), view);
1398
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1399
 
 
1400
 
        item = gtk_menu_item_new_with_mnemonic (_("Save Code _Block As..."));
1401
 
        g_signal_connect (item, "activate",
1402
 
                          G_CALLBACK (popup_save_code), view);
1403
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1404
 
    }
1405
 
 
1406
 
    g_object_unref (result);
1407
 
    gdk_event_free (event);
1408
 
    gtk_widget_show_all (GTK_WIDGET (menu));
1409
 
}
1410
 
 
1411
 
static void
1412
 
view_script_alert (YelpView        *view,
1413
 
                   WebKitWebFrame  *frame,
1414
 
                   gchar           *message,
1415
 
                   gpointer         data)
1416
 
{
1417
 
    printf ("\n\n===ALERT===\n%s\n\n", message);
1418
 
}
1419
 
 
1420
 
static gboolean
1421
 
view_navigation_requested (WebKitWebView             *view,
1422
 
                           WebKitWebFrame            *frame,
1423
 
                           WebKitNetworkRequest      *request,
1424
 
                           WebKitWebNavigationAction *action,
1425
 
                           WebKitWebPolicyDecision   *decision,
1426
 
                           gpointer                   user_data)
1427
 
{
1428
 
    const gchar *requri = webkit_network_request_get_uri (request);
1429
 
    YelpViewPrivate *priv = GET_PRIV (view);
1430
 
    YelpUri *uri;
1431
 
 
1432
 
    if (priv->bogus_uri &&
1433
 
        g_str_has_prefix (requri, priv->bogus_uri) &&
1434
 
        requri[strlen(priv->bogus_uri)] == '#') {
1435
 
        gchar *tmp = g_strconcat("xref:", requri + strlen(priv->bogus_uri), NULL);
1436
 
        uri = yelp_uri_new_relative (priv->uri, tmp);
1437
 
        g_free (tmp);
1438
 
    }
1439
 
    else if (g_str_has_prefix (requri, BOGUS_URI)) {
1440
 
        uri = yelp_uri_new_relative (priv->uri, requri + BOGUS_URI_LEN);
1441
 
    }
1442
 
    else
1443
 
        uri = yelp_uri_new_relative (priv->uri, requri);
1444
 
 
1445
 
    webkit_web_policy_decision_ignore (decision);
1446
 
 
1447
 
    yelp_view_load_uri ((YelpView *) view, uri);
1448
 
    g_object_unref (uri);
1449
 
 
1450
 
    return TRUE;
1451
 
}
1452
 
 
1453
 
static void
1454
 
view_resource_request (WebKitWebView         *view,
1455
 
                       WebKitWebFrame        *frame,
1456
 
                       WebKitWebResource     *resource,
1457
 
                       WebKitNetworkRequest  *request,
1458
 
                       WebKitNetworkResponse *response,
1459
 
                       gpointer               user_data)
1460
 
{
1461
 
    YelpViewPrivate *priv = GET_PRIV (view);
1462
 
    const gchar *requri = webkit_network_request_get_uri (request);
1463
 
    gchar last;
1464
 
    gchar *newpath;
1465
 
 
1466
 
    if (!g_str_has_prefix (requri, BOGUS_URI))
1467
 
        return;
1468
 
 
1469
 
    /* We get this signal for the page itself.  Ignore. */
1470
 
    if (g_str_equal (requri, priv->bogus_uri))
1471
 
        return;
1472
 
 
1473
 
    newpath = yelp_uri_locate_file_uri (priv->uri, requri + BOGUS_URI_LEN);
1474
 
    if (newpath != NULL) {
1475
 
        webkit_network_request_set_uri (request, newpath);
1476
 
        g_free (newpath);
1477
 
    }
1478
 
    else {
1479
 
        webkit_network_request_set_uri (request, "about:blank");
1480
 
    }
1481
 
}
1482
 
 
1483
 
static void
1484
 
view_document_loaded (WebKitWebView   *view,
1485
 
                      WebKitWebFrame  *frame,
1486
 
                      gpointer         user_data)
1487
 
{
1488
 
    YelpViewPrivate *priv = GET_PRIV (view);
1489
 
    gchar *search_terms;
1490
 
 
1491
 
    search_terms = yelp_uri_get_query (priv->uri, "terms");
1492
 
 
1493
 
    if (search_terms) {
1494
 
        WebKitDOMDocument *doc;
1495
 
        WebKitDOMElement *body, *link;
1496
 
        doc = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
1497
 
        body = webkit_dom_document_query_selector (doc, "div.body", NULL);
1498
 
        if (body) {
1499
 
            gchar *tmp, *uri, *txt;
1500
 
            link = webkit_dom_document_create_element (doc, "a", NULL);
1501
 
            webkit_dom_element_set_attribute (link, "class", "fullsearch", NULL);
1502
 
            tmp = g_uri_escape_string (search_terms, NULL, FALSE);
1503
 
            uri = g_strconcat ("xref:search=", tmp, NULL);
1504
 
            webkit_dom_element_set_attribute (link, "href", uri, NULL);
1505
 
            g_free (tmp);
1506
 
            g_free (uri);
1507
 
            txt = g_strdup_printf (_("See all search results for “%s”"),
1508
 
                                   search_terms);
1509
 
            webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (link), txt, NULL);
1510
 
            g_free (txt);
1511
 
            webkit_dom_node_insert_before (WEBKIT_DOM_NODE (body),
1512
 
                                           WEBKIT_DOM_NODE (link),
1513
 
                                           webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
1514
 
                                           NULL);
1515
 
        }
1516
 
        g_free (search_terms);
1517
 
    }
1518
 
}
1519
 
 
1520
 
static void
1521
 
view_print (GtkAction *action, YelpView  *view)
1522
 
{
1523
 
    webkit_web_frame_print (webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view)));
1524
 
}
1525
 
 
1526
 
static void
1527
 
view_history_action (GtkAction *action,
1528
 
                     YelpView  *view)
1529
 
{
1530
 
    GList *newcur;
1531
 
    YelpViewPrivate *priv = GET_PRIV (view);
1532
 
 
1533
 
    if (priv->back_cur == NULL)
1534
 
        return;
1535
 
 
1536
 
    if (g_str_equal (gtk_action_get_name (action), "YelpViewGoBack"))
1537
 
        newcur = priv->back_cur->next;
1538
 
    else
1539
 
        newcur = priv->back_cur->prev;
1540
 
 
1541
 
    if (newcur == NULL)
1542
 
        return;
1543
 
 
1544
 
    priv->back_cur = newcur;
1545
 
 
1546
 
    if (priv->back_cur->data == NULL)
1547
 
        return;
1548
 
 
1549
 
    priv->back_load = TRUE;
1550
 
    yelp_view_load_uri (view, ((YelpBackEntry *) priv->back_cur->data)->uri);
1551
 
    priv->vadjust = ((YelpBackEntry *) priv->back_cur->data)->vadj;
1552
 
    priv->hadjust = ((YelpBackEntry *) priv->back_cur->data)->hadj;
1553
 
}
1554
 
 
1555
 
static void
1556
 
view_navigation_action (GtkAction *action,
1557
 
                        YelpView  *view)
1558
 
{
1559
 
    YelpViewPrivate *priv = GET_PRIV (view);
1560
 
    gchar *page_id, *new_id, *xref;
1561
 
    YelpUri *new_uri;
1562
 
 
1563
 
    page_id = yelp_uri_get_page_id (priv->uri);
1564
 
 
1565
 
    if (g_str_equal (gtk_action_get_name (action), "YelpViewGoPrevious"))
1566
 
        new_id = yelp_document_get_prev_id (priv->document, page_id);
1567
 
    else
1568
 
        new_id = yelp_document_get_next_id (priv->document, page_id);
1569
 
 
1570
 
    /* Just in case we screwed up somewhere */
1571
 
    if (new_id == NULL) {
1572
 
        gtk_action_set_sensitive (action, FALSE);
1573
 
        return;
1574
 
    }
1575
 
 
1576
 
    xref = g_strconcat ("xref:", new_id, NULL);
1577
 
    new_uri = yelp_uri_new_relative (priv->uri, xref);
1578
 
    yelp_view_load_uri (view, new_uri);
1579
 
 
1580
 
    g_free (xref);
1581
 
    g_free (new_id);
1582
 
    g_object_unref (new_uri);
1583
 
}
1584
 
 
1585
 
static void
1586
 
view_clear_load (YelpView *view)
1587
 
{
1588
 
    YelpViewPrivate *priv = GET_PRIV (view);
1589
 
 
1590
 
    if (priv->resolve_uri != NULL) {
1591
 
        if (priv->uri_resolved != 0) {
1592
 
            g_signal_handler_disconnect (priv->resolve_uri, priv->uri_resolved);
1593
 
            priv->uri_resolved = 0;
1594
 
        }
1595
 
        g_object_unref (priv->resolve_uri);
1596
 
    }
1597
 
    priv->resolve_uri = NULL;
1598
 
 
1599
 
    if (priv->uri) {
1600
 
        g_object_unref (priv->uri);
1601
 
        priv->uri = NULL;
1602
 
    }
1603
 
 
1604
 
    if (priv->cancellable) {
1605
 
        g_cancellable_cancel (priv->cancellable);
1606
 
        priv->cancellable = NULL;
1607
 
    }
1608
 
}
1609
 
 
1610
 
static void
1611
 
view_load_page (YelpView *view)
1612
 
{
1613
 
    YelpViewPrivate *priv = GET_PRIV (view);
1614
 
    gchar *page_id;
1615
 
 
1616
 
    debug_print (DB_FUNCTION, "entering\n");
1617
 
 
1618
 
    g_return_if_fail (priv->cancellable == NULL);
1619
 
 
1620
 
    if (priv->document == NULL) {
1621
 
        GError *error;
1622
 
        gchar *docuri;
1623
 
        /* FIXME: and if priv->uri is NULL? */
1624
 
        docuri = yelp_uri_get_document_uri (priv->uri);
1625
 
        /* FIXME: CANT_READ isn't right */
1626
 
        if (docuri) {
1627
 
            error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
1628
 
                                 _("Could not load a document for ‘%s’"),
1629
 
                                 docuri);
1630
 
            g_free (docuri);
1631
 
        }
1632
 
        else {
1633
 
            error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
1634
 
                                 _("Could not load a document"));
1635
 
        }
1636
 
        view_show_error_page (view, error);
1637
 
        g_error_free (error);
1638
 
        return;
1639
 
    }
1640
 
 
1641
 
    page_id = yelp_uri_get_page_id (priv->uri);
1642
 
    priv->cancellable = g_cancellable_new ();
1643
 
    yelp_document_request_page (priv->document,
1644
 
                                page_id,
1645
 
                                priv->cancellable,
1646
 
                                (YelpDocumentCallback) document_callback,
1647
 
                                view);
1648
 
    g_free (page_id);
1649
 
}
1650
 
 
1651
 
static void
1652
 
view_show_error_page (YelpView *view,
1653
 
                      GError   *error)
1654
 
{
1655
 
    YelpViewPrivate *priv = GET_PRIV (view);
1656
 
    static const gchar *errorpage =
1657
 
        "<html><head>"
1658
 
        "<style type='text/css'>"
1659
 
        "body {"
1660
 
        " margin: 1em;"
1661
 
        " color: %s;"
1662
 
        " background-color: %s;"
1663
 
        " }\n"
1664
 
        "p { margin: 1em 0 0 0; }\n"
1665
 
        "div.note {"
1666
 
        " padding: 6px;"
1667
 
        " border-color: %s;"
1668
 
        " border-top: solid 1px;"
1669
 
        " border-bottom: solid 1px;"
1670
 
        " background-color: %s;"
1671
 
        " }\n"
1672
 
        "div.note div.inner {"
1673
 
        " margin: 0; padding: 0;"
1674
 
        " background-image: url(%s);"
1675
 
        " background-position: %s top;"
1676
 
        " background-repeat: no-repeat;"
1677
 
        " min-height: %ipx;"
1678
 
        " }\n"
1679
 
        "div.note div.contents {"
1680
 
        " margin-%s: %ipx;"
1681
 
        " }\n"
1682
 
        "div.note div.title {"
1683
 
        " margin-%s: %ipx;"
1684
 
        " margin-bottom: 0.2em;"
1685
 
        " font-weight: bold;"
1686
 
        " color: %s;"
1687
 
        " }\n"
1688
 
        "a { color: %s; text-decoration: none; }\n"
1689
 
        "</style>"
1690
 
        "</head><body>"
1691
 
        "<div class='note'><div class='inner'>"
1692
 
        "%s<div class='contents'>%s%s</div>"
1693
 
        "</div></div>"
1694
 
        "</body></html>";
1695
 
    YelpSettings *settings = yelp_settings_get_default ();
1696
 
    gchar *page, *title = NULL, *link = NULL, *title_m, *content_beg, *content_end;
1697
 
    gchar *textcolor, *bgcolor, *noteborder, *notebg, *titlecolor, *noteicon, *linkcolor;
1698
 
    gint iconsize;
1699
 
    GParamSpec *spec;
1700
 
    gboolean doc404 = FALSE;
1701
 
    const gchar *left = (gtk_widget_get_direction((GtkWidget *) view) == GTK_TEXT_DIR_RTL) ? "right" : "left";
1702
 
 
1703
 
    if (priv->uri && yelp_uri_get_document_type (priv->uri) == YELP_URI_DOCUMENT_TYPE_NOT_FOUND)
1704
 
        doc404 = TRUE;
1705
 
    if (error->domain == YELP_ERROR)
1706
 
        switch (error->code) {
1707
 
        case YELP_ERROR_NOT_FOUND:
1708
 
            if (doc404)
1709
 
                title = _("Document Not Found");
1710
 
            else
1711
 
                title = _("Page Not Found");
1712
 
            break;
1713
 
        case YELP_ERROR_CANT_READ:
1714
 
            title = _("Cannot Read");
1715
 
            break;
1716
 
        default:
1717
 
            break;
1718
 
        }
1719
 
    if (title == NULL)
1720
 
        title = _("Unknown Error");
1721
 
    title_m = g_markup_printf_escaped ("<div class='title'>%s</div>", title);
1722
 
 
1723
 
    content_beg = g_markup_printf_escaped ("<p>%s</p>", error->message);
1724
 
    content_end = NULL;
1725
 
    if (doc404) {
1726
 
        gchar *struri = yelp_uri_get_document_uri (priv->uri);
1727
 
        /* do not free */
1728
 
        gchar *pkg = NULL, *scheme = NULL;
1729
 
        if (g_str_has_prefix (struri, "help:")) {
1730
 
            scheme = "help";
1731
 
            pkg = struri + 5;
1732
 
        }
1733
 
        else if (g_str_has_prefix (struri, "ghelp:")) {
1734
 
            scheme = "ghelp";
1735
 
            pkg = struri + 6;
1736
 
        }
1737
 
        g_free (struri);
1738
 
    }
1739
 
 
1740
 
    textcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_TEXT);
1741
 
    bgcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_BASE);
1742
 
    noteborder = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_RED_BORDER);
1743
 
    notebg = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_YELLOW_BASE);
1744
 
    titlecolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_TEXT_LIGHT);
1745
 
    linkcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_LINK);
1746
 
    noteicon = yelp_settings_get_icon (settings, YELP_SETTINGS_ICON_WARNING);
1747
 
    iconsize = yelp_settings_get_icon_size (settings) + 6;
1748
 
 
1749
 
    page = g_strdup_printf (errorpage,
1750
 
                            textcolor, bgcolor, noteborder, notebg, noteicon,
1751
 
                            left, iconsize, left, iconsize, left, iconsize,
1752
 
                            titlecolor, linkcolor, title_m, content_beg,
1753
 
                            (content_end != NULL) ? content_end : "");
1754
 
 
1755
 
    g_object_set (view, "state", YELP_VIEW_STATE_ERROR, NULL);
1756
 
 
1757
 
    if (doc404) {
1758
 
        g_free (priv->root_title);
1759
 
        priv->root_title = g_strdup (title);
1760
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1761
 
                                             "root-title");
1762
 
        g_signal_emit_by_name (view, "notify::root-title", spec);
1763
 
        g_free (priv->page_id);
1764
 
        priv->page_id = g_strdup ("index");
1765
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1766
 
                                             "page-id");
1767
 
        g_signal_emit_by_name (view, "notify::page-id", spec);
1768
 
    }
1769
 
 
1770
 
    g_free (priv->page_title);
1771
 
    priv->page_title = g_strdup (title);
1772
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1773
 
                                         "page-title");
1774
 
    g_signal_emit_by_name (view, "notify::page-title", spec);
1775
 
 
1776
 
    g_free (priv->page_desc);
1777
 
    priv->page_desc = NULL;
1778
 
    if (priv->uri)
1779
 
        priv->page_desc = yelp_uri_get_canonical_uri (priv->uri);
1780
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1781
 
                                         "page-desc");
1782
 
    g_signal_emit_by_name (view, "notify::page-desc", spec);
1783
 
 
1784
 
    g_free (priv->page_icon);
1785
 
    priv->page_icon = g_strdup ("dialog-warning");
1786
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1787
 
                                         "page-icon");
1788
 
    g_signal_emit_by_name (view, "notify::page-icon", spec);
1789
 
 
1790
 
    g_signal_emit (view, signals[LOADED], 0);
1791
 
    g_signal_handler_block (view, priv->navigation_requested);
1792
 
    webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
1793
 
                                 page,
1794
 
                                 "text/html",
1795
 
                                 "UTF-8",
1796
 
                                 "file:///error/");
1797
 
    g_signal_handler_unblock (view, priv->navigation_requested);
1798
 
    g_free (title_m);
1799
 
    g_free (content_beg);
1800
 
    if (content_end != NULL)
1801
 
        g_free (content_end);
1802
 
    g_free (page);
1803
 
}
1804
 
 
1805
 
 
1806
 
static void
1807
 
settings_set_fonts (YelpSettings *settings)
1808
 
{
1809
 
    gchar *family;
1810
 
    gint size;
1811
 
 
1812
 
    g_object_set (websettings,
1813
 
                  "default-encoding", "utf-8",
1814
 
                  "enable-private-browsing", TRUE,
1815
 
                  NULL);
1816
 
 
1817
 
    family = yelp_settings_get_font_family (settings,
1818
 
                                            YELP_SETTINGS_FONT_VARIABLE);
1819
 
    size = yelp_settings_get_font_size (settings,
1820
 
                                        YELP_SETTINGS_FONT_VARIABLE);
1821
 
    g_object_set (websettings,
1822
 
                  "default-font-family", family,
1823
 
                  "sans-serif-font-family", family,
1824
 
                  "default-font-size", size,
1825
 
                  NULL);
1826
 
    g_free (family);
1827
 
 
1828
 
    family = yelp_settings_get_font_family (settings,
1829
 
                                            YELP_SETTINGS_FONT_FIXED);
1830
 
    size = yelp_settings_get_font_size (settings,
1831
 
                                        YELP_SETTINGS_FONT_FIXED);
1832
 
    g_object_set (websettings,
1833
 
                  "monospace-font-family", family,
1834
 
                  "default-monospace-font-size", size,
1835
 
                  NULL);
1836
 
    g_free (family);
1837
 
}
1838
 
 
1839
 
static void
1840
 
settings_show_text_cursor (YelpSettings *settings)
1841
 
{
1842
 
    g_object_set (websettings,
1843
 
                  "enable-caret-browsing",
1844
 
                  yelp_settings_get_show_text_cursor (settings),
1845
 
                  NULL);
1846
 
}
1847
 
 
1848
 
/******************************************************************************/
1849
 
 
1850
 
static void
1851
 
uri_resolved (YelpUri  *uri,
1852
 
              YelpView *view)
1853
 
{
1854
 
    YelpViewPrivate *priv = GET_PRIV (view);
1855
 
    YelpDocument *document;
1856
 
    YelpBackEntry *back;
1857
 
    GtkAction *action;
1858
 
    GSList *proxies, *cur;
1859
 
    GError *error = NULL;
1860
 
    gchar *struri;
1861
 
    GParamSpec *spec;
1862
 
 
1863
 
    if (yelp_uri_get_document_type (uri) != YELP_URI_DOCUMENT_TYPE_EXTERNAL) {
1864
 
        g_object_ref (uri);
1865
 
        view_clear_load (view);
1866
 
        priv->uri = uri;
1867
 
    }
1868
 
 
1869
 
    switch (yelp_uri_get_document_type (uri)) {
1870
 
    case YELP_URI_DOCUMENT_TYPE_EXTERNAL:
1871
 
        g_object_set (view, "state", priv->prevstate, NULL);
1872
 
        struri = yelp_uri_get_canonical_uri (uri);
1873
 
        if (g_str_has_prefix (struri, "install:") ||
1874
 
            g_str_has_prefix (struri, "install-ghelp:") ||
1875
 
            g_str_has_prefix (struri, "install-help:")) {
1876
 
            view_install_uri (view, struri);
1877
 
        }
1878
 
        else {
1879
 
            gboolean result;
1880
 
            g_signal_emit (view, signals[EXTERNAL_URI], 0, uri, &result);
1881
 
        }
1882
 
        g_free (struri);
1883
 
        return;
1884
 
    case YELP_URI_DOCUMENT_TYPE_NOT_FOUND:
1885
 
        struri = yelp_uri_get_canonical_uri (uri);
1886
 
        if (struri != NULL) {
1887
 
            error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
1888
 
                                 _("The URI ‘%s’ does not point to a valid page."),
1889
 
                                 struri);
1890
 
            g_free (struri);
1891
 
        }
1892
 
        else {
1893
 
            error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
1894
 
                                 _("The URI does not point to a valid page."));
1895
 
        }
1896
 
        break;
1897
 
    case YELP_URI_DOCUMENT_TYPE_ERROR:
1898
 
        struri = yelp_uri_get_canonical_uri (uri);
1899
 
        error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
1900
 
                             _("The URI ‘%s’ could not be parsed."),
1901
 
                             struri);
1902
 
        g_free (struri);
1903
 
        break;
1904
 
    default:
1905
 
        break;
1906
 
    }
1907
 
 
1908
 
    if (error == NULL) {
1909
 
        document  = yelp_document_get_for_uri (uri);
1910
 
        if (priv->document)
1911
 
            g_object_unref (priv->document);
1912
 
        priv->document = document;
1913
 
    }
1914
 
    else {
1915
 
        if (priv->document != NULL) {
1916
 
            g_object_unref (priv->document);
1917
 
            priv->document = NULL;
1918
 
        }
1919
 
    }
1920
 
 
1921
 
    if (!priv->back_load) {
1922
 
        back = g_new0 (YelpBackEntry, 1);
1923
 
        back->uri = g_object_ref (uri);
1924
 
        while (priv->back_list != priv->back_cur) {
1925
 
            back_entry_free ((YelpBackEntry *) priv->back_list->data);
1926
 
            priv->back_list = g_list_delete_link (priv->back_list, priv->back_list);
1927
 
        }
1928
 
        priv->back_list = g_list_prepend (priv->back_list, back);
1929
 
        priv->back_cur = priv->back_list;
1930
 
    }
1931
 
    priv->back_load = FALSE;
1932
 
 
1933
 
    action = gtk_action_group_get_action (priv->action_group, "YelpViewGoBack");
1934
 
    gtk_action_set_sensitive (action, FALSE);
1935
 
    proxies = gtk_action_get_proxies (action);
1936
 
    if (priv->back_cur->next && priv->back_cur->next->data) {
1937
 
        gchar *tooltip = "";
1938
 
        back = priv->back_cur->next->data;
1939
 
 
1940
 
        gtk_action_set_sensitive (action, TRUE);
1941
 
        if (back->title && back->desc) {
1942
 
            gchar *color;
1943
 
            color = yelp_settings_get_color (yelp_settings_get_default (),
1944
 
                                             YELP_SETTINGS_COLOR_TEXT_LIGHT);
1945
 
            tooltip = g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1946
 
                                               back->title, color, back->desc);
1947
 
            g_free (color);
1948
 
        }
1949
 
        else if (back->title)
1950
 
            tooltip = g_markup_printf_escaped ("<span size='larger'>%s</span>",
1951
 
                                               back->title);
1952
 
        /* Can't seem to use markup on GtkAction tooltip */
1953
 
        for (cur = proxies; cur != NULL; cur = cur->next)
1954
 
            gtk_widget_set_tooltip_markup (GTK_WIDGET (cur->data), tooltip);
1955
 
    }
1956
 
    else {
1957
 
        for (cur = proxies; cur != NULL; cur = cur->next)
1958
 
            gtk_widget_set_tooltip_text (GTK_WIDGET (cur->data), "");
1959
 
    }
1960
 
 
1961
 
    action = gtk_action_group_get_action (priv->action_group, "YelpViewGoForward");
1962
 
    gtk_action_set_sensitive (action, FALSE);
1963
 
    proxies = gtk_action_get_proxies (action);
1964
 
    if (priv->back_cur->prev && priv->back_cur->prev->data) {
1965
 
        gchar *tooltip = "";
1966
 
        back = priv->back_cur->prev->data;
1967
 
 
1968
 
        gtk_action_set_sensitive (action, TRUE);
1969
 
        if (back->title && back->desc) {
1970
 
            gchar *color;
1971
 
            color = yelp_settings_get_color (yelp_settings_get_default (),
1972
 
                                             YELP_SETTINGS_COLOR_TEXT_LIGHT);
1973
 
            tooltip = g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1974
 
                                               back->title, color, back->desc);
1975
 
            g_free (color);
1976
 
        }
1977
 
        else if (back->title)
1978
 
            tooltip = g_markup_printf_escaped ("<span size='larger'>%s</span>",
1979
 
                                               back->title);
1980
 
        /* Can't seem to use markup on GtkAction tooltip */
1981
 
        for (cur = proxies; cur != NULL; cur = cur->next)
1982
 
            gtk_widget_set_tooltip_markup (GTK_WIDGET (cur->data), tooltip);
1983
 
    }
1984
 
    else {
1985
 
        for (cur = proxies; cur != NULL; cur = cur->next)
1986
 
            gtk_widget_set_tooltip_text (GTK_WIDGET (cur->data), "");
1987
 
    }
1988
 
 
1989
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1990
 
                                         "yelp-uri");
1991
 
    g_signal_emit_by_name (view, "notify::yelp-uri", spec);
1992
 
 
1993
 
    g_free (priv->page_id);
1994
 
    priv->page_id = NULL;
1995
 
    if (priv->uri != NULL)
1996
 
        priv->page_id = yelp_uri_get_page_id (priv->uri);
1997
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1998
 
                                         "page-id");
1999
 
    g_signal_emit_by_name (view, "notify::page-id", spec);
2000
 
 
2001
 
    g_free (priv->root_title);
2002
 
    g_free (priv->page_title);
2003
 
    g_free (priv->page_desc);
2004
 
    g_free (priv->page_icon);
2005
 
    priv->root_title = NULL;
2006
 
    priv->page_title = NULL;
2007
 
    priv->page_desc = NULL;
2008
 
    priv->page_icon = NULL;
2009
 
 
2010
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2011
 
                                         "root-title");
2012
 
    g_signal_emit_by_name (view, "notify::root-title", spec);
2013
 
 
2014
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2015
 
                                         "page-title");
2016
 
    g_signal_emit_by_name (view, "notify::page-title", spec);
2017
 
 
2018
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2019
 
                                         "page-desc");
2020
 
    g_signal_emit_by_name (view, "notify::page-desc", spec);
2021
 
 
2022
 
    spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2023
 
                                         "page-icon");
2024
 
    g_signal_emit_by_name (view, "notify::page-icon", spec);
2025
 
 
2026
 
    if (error == NULL)
2027
 
        view_load_page (view);
2028
 
    else {
2029
 
        view_show_error_page (view, error);
2030
 
        g_error_free (error);
2031
 
    }
2032
 
}
2033
 
 
2034
 
static void
2035
 
document_callback (YelpDocument       *document,
2036
 
                   YelpDocumentSignal  signal,
2037
 
                   YelpView           *view,
2038
 
                   GError             *error)
2039
 
{
2040
 
    YelpViewPrivate *priv = GET_PRIV (view);
2041
 
 
2042
 
    debug_print (DB_FUNCTION, "entering\n");
2043
 
 
2044
 
    if (signal == YELP_DOCUMENT_SIGNAL_INFO) {
2045
 
        gchar *prev_id, *next_id, *real_id;
2046
 
        GtkAction *action;
2047
 
        YelpBackEntry *back = NULL;
2048
 
        GParamSpec *spec;
2049
 
 
2050
 
        real_id = yelp_document_get_page_id (document, priv->page_id);
2051
 
        if (priv->page_id && real_id && g_str_equal (real_id, priv->page_id)) {
2052
 
            g_free (real_id);
2053
 
        }
2054
 
        else {
2055
 
            GParamSpec *spec;
2056
 
            g_free (priv->page_id);
2057
 
            priv->page_id = real_id;
2058
 
            spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2059
 
                                                 "page-id");
2060
 
            g_signal_emit_by_name (view, "notify::page-id", spec);
2061
 
        }
2062
 
 
2063
 
        g_free (priv->root_title);
2064
 
        g_free (priv->page_title);
2065
 
        g_free (priv->page_desc);
2066
 
        g_free (priv->page_icon);
2067
 
 
2068
 
        priv->root_title = yelp_document_get_root_title (document, priv->page_id);
2069
 
        priv->page_title = yelp_document_get_page_title (document, priv->page_id);
2070
 
        priv->page_desc = yelp_document_get_page_desc (document, priv->page_id);
2071
 
        priv->page_icon = yelp_document_get_page_icon (document, priv->page_id);
2072
 
 
2073
 
        if (priv->back_cur)
2074
 
            back = priv->back_cur->data;
2075
 
        if (back) {
2076
 
            g_free (back->title);
2077
 
            back->title = g_strdup (priv->page_title);
2078
 
            g_free (back->desc);
2079
 
            back->desc = g_strdup (priv->page_desc);
2080
 
        }
2081
 
 
2082
 
        prev_id = yelp_document_get_prev_id (document, priv->page_id);
2083
 
        action = gtk_action_group_get_action (priv->action_group, "YelpViewGoPrevious");
2084
 
        gtk_action_set_sensitive (action, prev_id != NULL);
2085
 
        g_free (prev_id);
2086
 
 
2087
 
        next_id = yelp_document_get_next_id (document, priv->page_id);
2088
 
        action = gtk_action_group_get_action (priv->action_group, "YelpViewGoNext");
2089
 
        gtk_action_set_sensitive (action, next_id != NULL);
2090
 
        g_free (next_id);
2091
 
 
2092
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2093
 
                                             "root-title");
2094
 
        g_signal_emit_by_name (view, "notify::root-title", spec);
2095
 
 
2096
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2097
 
                                             "page-title");
2098
 
        g_signal_emit_by_name (view, "notify::page-title", spec);
2099
 
 
2100
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2101
 
                                             "page-desc");
2102
 
        g_signal_emit_by_name (view, "notify::page-desc", spec);
2103
 
 
2104
 
        spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2105
 
                                             "page-icon");
2106
 
        g_signal_emit_by_name (view, "notify::page-icon", spec);
2107
 
    }
2108
 
    else if (signal == YELP_DOCUMENT_SIGNAL_CONTENTS) {
2109
 
        YelpUriDocumentType doctype;
2110
 
        const gchar *contents;
2111
 
        gchar *mime_type, *page_id, *frag_id, *full_uri;
2112
 
        page_id = yelp_uri_get_page_id (priv->uri);
2113
 
        debug_print (DB_ARG, "    document.uri.page_id=\"%s\"\n", page_id);
2114
 
        mime_type = yelp_document_get_mime_type (document, page_id);
2115
 
        contents = yelp_document_read_contents (document, page_id);
2116
 
        frag_id = yelp_uri_get_frag_id (priv->uri);
2117
 
        g_free (priv->bogus_uri);
2118
 
        /* We don't have actual page and frag IDs for DocBook. We just map IDs
2119
 
           of block elements.  The result is that we get xref:someid#someid.
2120
 
           If someid is really the page ID, we just drop the frag reference.
2121
 
           Otherwise, normal page views scroll past the link trail.
2122
 
         */
2123
 
        if (frag_id != NULL) {
2124
 
            if (YELP_IS_DOCBOOK_DOCUMENT (document)) {
2125
 
                gchar *real_id = yelp_document_get_page_id (document, page_id);
2126
 
                if (g_str_equal (real_id, frag_id)) {
2127
 
                    g_free (frag_id);
2128
 
                    frag_id = NULL;
2129
 
                }
2130
 
                g_free (real_id);
2131
 
            }
2132
 
        }
2133
 
        /* We have to give WebKit a URI in a scheme it understands, otherwise we
2134
 
           won't get the resource-request-starting signal.  So we can't use the
2135
 
           canonical URI, because it might be something like ghelp.  We also have
2136
 
           to give it something unique, because WebKit ignores our load_string
2137
 
           call if the URI isn't different.  We could try to construct something
2138
 
           based on actual file locations, but in fact it doesn't matter.  So
2139
 
           we just make a bogus URI that's easy to process later.
2140
 
         */
2141
 
        doctype = yelp_uri_get_document_type (priv->uri);
2142
 
        full_uri = yelp_uri_get_canonical_uri (priv->uri);
2143
 
        if (g_str_has_prefix (full_uri, "file:/") &&
2144
 
            (doctype == YELP_URI_DOCUMENT_TYPE_TEXT ||
2145
 
             doctype == YELP_URI_DOCUMENT_TYPE_HTML ||
2146
 
             doctype == YELP_URI_DOCUMENT_TYPE_XHTML )) {
2147
 
            priv->bogus_uri = full_uri;
2148
 
        }
2149
 
        else {
2150
 
            g_free (full_uri);
2151
 
            if (frag_id != NULL)
2152
 
                priv->bogus_uri = g_strdup_printf ("%s%p#%s", BOGUS_URI, priv->uri, frag_id);
2153
 
            else
2154
 
                priv->bogus_uri = g_strdup_printf ("%s%p", BOGUS_URI, priv->uri);
2155
 
        }
2156
 
        g_signal_handler_block (view, priv->navigation_requested);
2157
 
        webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
2158
 
                                     contents,
2159
 
                                     mime_type,
2160
 
                                     "UTF-8",
2161
 
                                     priv->bogus_uri);
2162
 
        g_signal_handler_unblock (view, priv->navigation_requested);
2163
 
        g_object_set (view, "state", YELP_VIEW_STATE_LOADED, NULL);
2164
 
 
2165
 
        /* If we need to set the GtkAdjustment or trigger the page title
2166
 
         * from what WebKit thinks it is (see comment below), we need to
2167
 
         * let the main loop run through.
2168
 
         */
2169
 
        if (priv->vadjust > 0 || priv->hadjust > 0 ||  priv->page_title == NULL)
2170
 
            while (g_main_context_pending (NULL)) {
2171
 
                WebKitLoadStatus status;
2172
 
                status = webkit_web_view_get_load_status (WEBKIT_WEB_VIEW (view));
2173
 
                g_main_context_iteration (NULL, FALSE);
2174
 
                /* Sometimes some runaway JavaScript causes there to always
2175
 
                 * be pending sources. Break out if the document is loaded.
2176
 
                 */
2177
 
                if (status == WEBKIT_LOAD_FINISHED ||
2178
 
                    status == WEBKIT_LOAD_FAILED)
2179
 
                    break;
2180
 
            }
2181
 
 
2182
 
        /* Setting adjustments only work after the page is loaded. These
2183
 
         * are set by view_history_action, and they're reset to 0 after
2184
 
         * each load here.
2185
 
         */
2186
 
        if (priv->vadjust > 0) {
2187
 
            if (priv->vadjustment)
2188
 
                gtk_adjustment_set_value (priv->vadjustment, priv->vadjust);
2189
 
            priv->vadjust = 0;
2190
 
        }
2191
 
        if (priv->hadjust > 0) {
2192
 
            if (priv->hadjustment)
2193
 
                gtk_adjustment_set_value (priv->hadjustment, priv->hadjust);
2194
 
            priv->hadjust = 0;
2195
 
        }
2196
 
 
2197
 
        /* If the document didn't give us a page title, get it from WebKit.
2198
 
         * We let the main loop run through so that WebKit gets the title
2199
 
         * set so that we can send notify::page-title before loaded. It
2200
 
         * simplifies things if YelpView consumers can assume the title
2201
 
         * is set before loaded is triggered.
2202
 
         */
2203
 
        if (priv->page_title == NULL) {
2204
 
            GParamSpec *spec;
2205
 
            priv->page_title = g_strdup (webkit_web_view_get_title (WEBKIT_WEB_VIEW (view)));
2206
 
            spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2207
 
                                                 "page-title");
2208
 
            g_signal_emit_by_name (view, "notify::page-title", spec);
2209
 
        }
2210
 
 
2211
 
        g_free (frag_id);
2212
 
        g_free (page_id);
2213
 
        g_free (mime_type);
2214
 
        yelp_document_finish_read (document, contents);
2215
 
        g_signal_emit (view, signals[LOADED], 0);
2216
 
    }
2217
 
    else if (signal == YELP_DOCUMENT_SIGNAL_ERROR) {
2218
 
        view_show_error_page (view, error);
2219
 
    }
2220
 
}