~midori/midori/nativeGTK+ErrorPages

« back to all changes in this revision

Viewing changes to extensions/tabs2one.c

  • Committer: RabbitBot
  • Author(s): Paweł Forysiuk, Eder Sosa
  • Date: 2015-03-21 18:20:39 UTC
  • mfrom: (6181.7.13 tabs2one)
  • Revision ID: rabbitbot-20150321182039-e9vxy9m4ibpdch5f
Implement Tabs2One extension

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 Copyright (C) 2013 Eder Sosa <eder.sohe@gmail.com>
 
3
 
 
4
 This library is free software; you can redistribute it and/or
 
5
 modify it under the terms of the GNU Lesser General Public
 
6
 License as published by the Free Software Foundation; either
 
7
 version 2.1 of the License, or (at your option) any later version.
 
8
 
 
9
 See the file COPYING for the full license text.
 
10
*/
 
11
 
 
12
#include <midori/midori.h>
 
13
 
 
14
typedef struct
 
15
{
 
16
    gchar* folder;
 
17
    gchar* filename;
 
18
    gchar* uri;
 
19
} tabs2onePriv;
 
20
 
 
21
static tabs2onePriv* priv;
 
22
 
 
23
tabs2onePriv*
 
24
tabs2one_private_new ()
 
25
{
 
26
    tabs2onePriv* priv = g_slice_new (tabs2onePriv);
 
27
    priv->folder = NULL;
 
28
    priv->filename = NULL;
 
29
    priv->uri = NULL;
 
30
 
 
31
    return priv;
 
32
}
 
33
 
 
34
void tabs2one_private_destroy (tabs2onePriv* priv)
 
35
{
 
36
    katze_assign (priv->folder, NULL);
 
37
    katze_assign (priv->filename, NULL);
 
38
    katze_assign (priv->uri, NULL);
 
39
    g_slice_free (tabs2onePriv, priv);
 
40
}
 
41
 
 
42
static void
 
43
tabs2one_dom_click_restore_item_cb (WebKitDOMNode  *element,
 
44
                                    WebKitDOMEvent *dom_event,
 
45
                                    WebKitWebView  *webview);
 
46
 
 
47
static void
 
48
tabs2one_dom_click_remove_item_cb (WebKitDOMNode *element,
 
49
                                   WebKitDOMEvent *dom_event,
 
50
                                   WebKitWebView  *webview);
 
51
 
 
52
static gchar*
 
53
tabs2one_id_generator (void)
 
54
{
 
55
    GString* id = g_string_new("");
 
56
    GRand* generator = g_rand_new();
 
57
    gint32 id1 = g_rand_int_range (generator, 1000, 9999);
 
58
    gint32 id2 = g_rand_int_range (generator, 1000, 9999);
 
59
    g_rand_free(generator);
 
60
    g_string_printf(id, "%i-%i", id1, id2);
 
61
    return g_string_free(id, FALSE);
 
62
}
 
63
 
 
64
static void
 
65
tabs2one_dom_create_item (WebKitDOMDocument* doc,
 
66
                          const gchar* icon,
 
67
                          const gchar* uri,
 
68
                          const gchar* title)
 
69
{
 
70
    WebKitDOMElement* body = webkit_dom_document_query_selector(doc, "body", NULL);
 
71
    WebKitDOMElement* item = webkit_dom_document_create_element(doc, "div", NULL);
 
72
    WebKitDOMElement* favicon = webkit_dom_document_create_element(doc, "img", NULL);
 
73
    WebKitDOMElement* link = webkit_dom_document_create_element(doc, "a", NULL);
 
74
    WebKitDOMElement* close_link = webkit_dom_document_create_element(doc, "a", NULL);
 
75
    WebKitDOMElement* close_button = webkit_dom_document_create_element (doc, "img", NULL);
 
76
    WebKitDOMElement* br = webkit_dom_document_create_element(doc, "br", NULL);
 
77
    WebKitDOMText* content = webkit_dom_document_create_text_node(doc, title);
 
78
 
 
79
    webkit_dom_element_set_attribute(item, "id", tabs2one_id_generator(), NULL);
 
80
    webkit_dom_element_set_attribute(item, "class", "item", NULL);
 
81
    webkit_dom_element_set_attribute(item, "style", "padding: 5px;", NULL);
 
82
 
 
83
    webkit_dom_element_set_attribute(close_link, "class", "close-link", NULL);
 
84
    webkit_dom_element_set_attribute(close_link, "target", "_blank", NULL);
 
85
    webkit_dom_element_set_attribute(close_link, "href", "about:blank", NULL);
 
86
    webkit_dom_element_set_attribute(close_button, "src", "res://close.png", NULL);
 
87
    webkit_dom_element_set_attribute(close_button, "width", "16px", NULL);
 
88
    webkit_dom_element_set_attribute(close_button, "height", "16px", NULL);
 
89
 
 
90
    webkit_dom_element_set_attribute(favicon, "src", icon, NULL);
 
91
    webkit_dom_element_set_attribute(favicon, "width", "16px", NULL);
 
92
    webkit_dom_element_set_attribute(favicon, "height", "16px", NULL);
 
93
    webkit_dom_element_set_attribute(favicon, "style", "padding-left: 5px;", NULL);
 
94
 
 
95
    webkit_dom_element_set_attribute(link, "class", "restore-link",NULL);
 
96
    webkit_dom_element_set_attribute(link, "href", uri, NULL);
 
97
    webkit_dom_element_set_attribute(link, "style", "padding-left: 5px;", NULL);
 
98
    webkit_dom_element_set_attribute(link, "target", "_blank", NULL);
 
99
 
 
100
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(link), WEBKIT_DOM_NODE(content), NULL);
 
101
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(item), WEBKIT_DOM_NODE(close_link), NULL);
 
102
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(close_link), WEBKIT_DOM_NODE(close_button), NULL);
 
103
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(item), WEBKIT_DOM_NODE(favicon), NULL);
 
104
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(item), WEBKIT_DOM_NODE(link), NULL);
 
105
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(item), WEBKIT_DOM_NODE(br), NULL);
 
106
    webkit_dom_node_append_child(WEBKIT_DOM_NODE(body), WEBKIT_DOM_NODE(item), NULL);
 
107
}
 
108
 
 
109
static void
 
110
tabs2one_cache_create_dir (void)
 
111
{
 
112
    midori_paths_mkdir_with_parents (priv->folder, 0700);
 
113
}
 
114
 
 
115
static gchar*
 
116
tabs2one_cache_get_filename (void)
 
117
{
 
118
    return priv->filename;
 
119
}
 
120
 
 
121
static gchar*
 
122
tabs2one_cache_get_uri (void)
 
123
{
 
124
    return priv->uri;
 
125
}
 
126
 
 
127
static bool
 
128
tabs2one_cache_exist (void)
 
129
{
 
130
    return g_file_test (priv->filename, G_FILE_TEST_EXISTS);
 
131
}
 
132
 
 
133
static gboolean
 
134
tabs2one_is_uri_tabs2one_tab (const gchar* uri)
 
135
{
 
136
    return g_str_equal (uri, tabs2one_cache_get_uri ());
 
137
}
 
138
 
 
139
static void
 
140
tabs2one_dom_add_click_listeners (WebKitDOMDocument* doc,
 
141
                                  WebKitWebView* webview)
 
142
{
 
143
    WebKitDOMNodeList *elements = webkit_dom_document_query_selector_all(doc, ".restore-link", NULL);
 
144
 
 
145
    int i;
 
146
 
 
147
    for (i = 0; i < webkit_dom_node_list_get_length(elements); i++)
 
148
    {
 
149
        WebKitDOMNode *element = webkit_dom_node_list_item(elements, i);
 
150
        webkit_dom_event_target_add_event_listener(
 
151
            WEBKIT_DOM_EVENT_TARGET(element), "click",
 
152
            G_CALLBACK (tabs2one_dom_click_restore_item_cb), TRUE, webview);
 
153
    }
 
154
 
 
155
    elements = webkit_dom_document_query_selector_all(doc, ".close-link", NULL);
 
156
    for (i = 0; i < webkit_dom_node_list_get_length(elements); i++)
 
157
    {
 
158
        WebKitDOMNode *element = webkit_dom_node_list_item(elements, i);
 
159
        webkit_dom_event_target_add_event_listener(
 
160
            WEBKIT_DOM_EVENT_TARGET(element), "click",
 
161
            G_CALLBACK (tabs2one_dom_click_remove_item_cb), TRUE, webview);
 
162
    }
 
163
}
 
164
 
 
165
static bool
 
166
tabs2one_cache_write_file (WebKitWebView* webview)
 
167
{
 
168
    WebKitDOMDocument* doc = webkit_web_view_get_dom_document(webview);
 
169
    WebKitDOMHTMLDocument* dochtml = (WebKitDOMHTMLDocument*)doc;
 
170
    WebKitDOMHTMLElement* elementhtml = (WebKitDOMHTMLElement*)dochtml;
 
171
    const gchar* content = webkit_dom_html_element_get_inner_html(elementhtml);
 
172
    if (content == NULL)
 
173
        return FALSE;
 
174
 
 
175
    tabs2one_dom_add_click_listeners (doc, webview);
 
176
 
 
177
    return g_file_set_contents(tabs2one_cache_get_filename (), content, -1, NULL);
 
178
}
 
179
 
 
180
static void
 
181
tabs2one_onload_create_items_cb(WebKitWebView*  webview,
 
182
                                WebKitWebFrame* webframe,
 
183
                                MidoriBrowser*  browser)
 
184
{
 
185
    WebKitDOMDocument* doc = webkit_web_view_get_dom_document(webview);
 
186
 
 
187
    const gchar* icon;
 
188
    const gchar* title;
 
189
    const gchar* uri;
 
190
 
 
191
    GList* tabs = midori_browser_get_tabs (browser);
 
192
    for (; tabs; tabs = g_list_next (tabs))
 
193
    {
 
194
        icon = midori_view_get_icon_uri (tabs->data);
 
195
        if (icon == NULL) icon = "";
 
196
        title = midori_view_get_display_title (tabs->data);
 
197
        uri = midori_view_get_display_uri (tabs->data);
 
198
 
 
199
        if (!tabs2one_is_uri_tabs2one_tab (uri))
 
200
        {
 
201
            if (!midori_uri_is_blank (uri))
 
202
                tabs2one_dom_create_item(doc, icon, uri, title);
 
203
        }
 
204
    }
 
205
 
 
206
 
 
207
    if (tabs2one_cache_write_file (webview))
 
208
    {
 
209
        tabs = midori_browser_get_tabs (browser);
 
210
        while ((tabs = g_list_next (tabs)))
 
211
            midori_browser_close_tab (browser, tabs->data);
 
212
 
 
213
        tabs2one_dom_add_click_listeners (doc, webview);
 
214
        midori_browser_set_current_uri (browser, tabs2one_cache_get_uri ());
 
215
    }
 
216
 
 
217
    g_list_free(tabs);
 
218
}
 
219
 
 
220
static void
 
221
tabs2one_reload_connected_events_cb(WebKitWebView*  webview,
 
222
                                    WebKitWebFrame* frame,
 
223
                                    MidoriView*     view)
 
224
{
 
225
    const gchar* uri = midori_view_get_display_uri(view);
 
226
 
 
227
    if (tabs2one_is_uri_tabs2one_tab (uri))
 
228
    {
 
229
        WebKitDOMDocument* doc = webkit_web_view_get_dom_document(webview);
 
230
        tabs2one_dom_add_click_listeners (doc, webview);
 
231
    }
 
232
}
 
233
 
 
234
 
 
235
static void
 
236
tabs2one_add_tab_cb (MidoriBrowser*   browser,
 
237
                     MidoriView*      view,
 
238
                     MidoriExtension* extension)
 
239
{
 
240
    WebKitWebView* webview = WEBKIT_WEB_VIEW (midori_view_get_web_view(view));
 
241
    g_signal_connect (webview, "document-load-finished",
 
242
        G_CALLBACK (tabs2one_reload_connected_events_cb), view);
 
243
}
 
244
 
 
245
static void
 
246
tabs2one_dom_click_restore_item_cb (WebKitDOMNode  *element,
 
247
                                    WebKitDOMEvent *dom_event,
 
248
                                    WebKitWebView  *webview)
 
249
{
 
250
    webkit_dom_event_prevent_default (dom_event);
 
251
    MidoriView* view = midori_view_get_for_widget (GTK_WIDGET (webview));
 
252
    MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (webview));
 
253
    WebKitDOMNode* item = webkit_dom_node_get_parent_node (element);
 
254
    WebKitDOMNode* body = webkit_dom_node_get_parent_node (item);
 
255
    const gchar* uri = webkit_dom_element_get_attribute(WEBKIT_DOM_ELEMENT(element), "href");
 
256
    midori_browser_add_uri (browser, uri);
 
257
 
 
258
    WebKitDOMDocument* doc = webkit_web_view_get_dom_document (webview);
 
259
    webkit_dom_node_remove_child(body, item, NULL);
 
260
    tabs2one_cache_write_file (webview);
 
261
 
 
262
    WebKitDOMNodeList *elements = webkit_dom_document_query_selector_all(doc, ".restore-link", NULL);
 
263
    if (webkit_dom_node_list_get_length(elements) <= 0){
 
264
        midori_browser_close_tab(browser, GTK_WIDGET(view));
 
265
    }
 
266
}
 
267
 
 
268
static void
 
269
tabs2one_dom_click_remove_item_cb (WebKitDOMNode  *element,
 
270
                                   WebKitDOMEvent *dom_event,
 
271
                                   WebKitWebView  *webview)
 
272
{
 
273
    webkit_dom_event_prevent_default (dom_event);
 
274
    MidoriView* view = midori_view_get_for_widget (GTK_WIDGET (webview));
 
275
    MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (webview));
 
276
    WebKitDOMNode* item = webkit_dom_node_get_parent_node (element);
 
277
    WebKitDOMNode* body = webkit_dom_node_get_parent_node (item);
 
278
 
 
279
    WebKitDOMDocument* doc = webkit_web_view_get_dom_document (webview);
 
280
    webkit_dom_node_remove_child(body, item, NULL);
 
281
    tabs2one_cache_write_file (webview);
 
282
 
 
283
    WebKitDOMNodeList *elements = webkit_dom_document_query_selector_all(doc, ".close-link", NULL);
 
284
    if (webkit_dom_node_list_get_length(elements) <= 0){
 
285
        midori_browser_close_tab(browser, GTK_WIDGET(view));
 
286
    }
 
287
}
 
288
 
 
289
static void
 
290
tabs2one_apply_cb (GtkWidget*     menuitem,
 
291
                   MidoriBrowser* browser)
 
292
{
 
293
    GtkWidget* tab = NULL;
 
294
 
 
295
    if (!tabs2one_cache_exist ())
 
296
    {
 
297
        GString* tpl = g_string_new ("<html>\n<title>");
 
298
 
 
299
        g_string_append_printf (tpl, "%s", _("Tabs to One"));
 
300
        g_string_append (tpl, "</title>\n<head><meta charset=\"utf-8\"></head><body>\n");
 
301
        g_string_append_printf (tpl, "<h2>%s</h2>\n", _("Tabs you collected so far"));
 
302
        g_string_append_printf (tpl, "<div><span>%s</span></div>\n", _("Clicking an item restores a tab."));
 
303
        g_string_append (tpl, "</body>\n</html>\n");
 
304
 
 
305
        g_file_set_contents(tabs2one_cache_get_filename (), g_string_free (tpl, FALSE), -1, NULL);
 
306
    }
 
307
 
 
308
    tab = midori_browser_add_uri (browser, tabs2one_cache_get_uri ());
 
309
 
 
310
    WebKitWebView* webview = WEBKIT_WEB_VIEW (midori_view_get_web_view(MIDORI_VIEW (tab)));
 
311
    midori_browser_set_current_tab (browser, tab);
 
312
 
 
313
     g_signal_connect (webview, "document-load-finished",
 
314
        G_CALLBACK (tabs2one_onload_create_items_cb), browser);
 
315
}
 
316
 
 
317
static void
 
318
tabs2one_app_add_browser_cb (MidoriApp*       app,
 
319
                             MidoriBrowser*   browser,
 
320
                             MidoriExtension* extension);
 
321
 
 
322
static void
 
323
tabs2one_browser_populate_tool_menu_cb (MidoriBrowser*   browser,
 
324
                                        GtkWidget*       menu,
 
325
                                        MidoriExtension* extension)
 
326
{
 
327
    GtkWidget* menuitem = gtk_menu_item_new_with_mnemonic (_("Tabs to _One"));
 
328
 
 
329
    g_signal_connect (menuitem, "activate",
 
330
        G_CALLBACK (tabs2one_apply_cb), browser);
 
331
    gtk_widget_show (menuitem);
 
332
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
 
333
}
 
334
 
 
335
static void
 
336
tabs2one_deactivate_cb (MidoriExtension* extension,
 
337
                        MidoriBrowser*   browser)
 
338
{
 
339
    MidoriApp* app = midori_extension_get_app (extension);
 
340
 
 
341
    g_signal_handlers_disconnect_by_func (
 
342
        browser, tabs2one_browser_populate_tool_menu_cb, extension);
 
343
    g_signal_handlers_disconnect_by_func (
 
344
        extension, tabs2one_deactivate_cb, browser);
 
345
    g_signal_handlers_disconnect_by_func (
 
346
        app, tabs2one_app_add_browser_cb, extension);
 
347
    g_signal_handlers_disconnect_by_func (
 
348
        browser, tabs2one_add_tab_cb, extension);
 
349
 
 
350
    tabs2one_private_destroy (priv);
 
351
}
 
352
 
 
353
static void
 
354
tabs2one_app_add_browser_cb (MidoriApp*       app,
 
355
                             MidoriBrowser*   browser,
 
356
                             MidoriExtension* extension)
 
357
{
 
358
    g_signal_connect (browser, "populate-tool-menu",
 
359
        G_CALLBACK (tabs2one_browser_populate_tool_menu_cb), extension);
 
360
    g_signal_connect (extension, "deactivate",
 
361
        G_CALLBACK (tabs2one_deactivate_cb), browser);
 
362
    g_signal_connect_after (browser, "add-tab",
 
363
        G_CALLBACK (tabs2one_add_tab_cb), extension);
 
364
 
 
365
    tabs2one_cache_create_dir();
 
366
}
 
367
 
 
368
static void
 
369
tabs2one_activate_cb (MidoriExtension* extension,
 
370
                      MidoriApp*       app)
 
371
{
 
372
    const gchar* config_dir = midori_extension_get_config_dir (extension);
 
373
    priv = tabs2one_private_new ();
 
374
    KatzeArray* browsers;
 
375
    MidoriBrowser* browser;
 
376
    gchar* filename, *uri;
 
377
 
 
378
    filename = g_build_filename (config_dir, "tabs2one.html", NULL);
 
379
    uri = g_filename_to_uri (filename, NULL, NULL);
 
380
 
 
381
    priv->filename = g_strdup (filename);
 
382
    priv->uri = g_strdup (uri);
 
383
    priv->folder = g_strdup (config_dir);
 
384
 
 
385
    browsers = katze_object_get_object (app, "browsers");
 
386
    KATZE_ARRAY_FOREACH_ITEM (browser, browsers)
 
387
        tabs2one_app_add_browser_cb (app, browser, extension);
 
388
    g_object_unref (browsers);
 
389
    g_signal_connect (app, "add-browser",
 
390
        G_CALLBACK (tabs2one_app_add_browser_cb), extension);
 
391
 
 
392
    g_free (filename);
 
393
    g_free (uri);
 
394
}
 
395
 
 
396
MidoriExtension*
 
397
extension_init (void)
 
398
{
 
399
    MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
 
400
        "name", _("Tabs to One"),
 
401
        "description", _("Closes all open tabs and creates new tab with tabs links"),
 
402
        "version", "0.1" MIDORI_VERSION_SUFFIX,
 
403
        "authors", "Eder Sosa <eder.sohe@gmail.com>",
 
404
        NULL);
 
405
 
 
406
    g_signal_connect (extension, "activate",
 
407
        G_CALLBACK (tabs2one_activate_cb), NULL);
 
408
 
 
409
    return extension;
 
410
}