summaryrefslogtreecommitdiff
path: root/surf-webext-dom.c
blob: 9d2570436835d155ead7bb33b73df2f38769971c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//
// !!! THIS IS A BUGGY CONCEPT/PROTOTYPE. USE AT YOUR OWN RISK !!!
//
// The following simple Webkit2GTK+ extension was hacked together
// in the sleepless night between 09th and 10th March 2018 (and later 
// refined) by:
//
// Michal Idziorek <m.i@gmx.at>.
//
// It regjsters a document_loaded_callback, where the DOM is manipulated,
// i.e: a <span> with a number added to every link encountered.
//
// The urls are extracted from the DOM and shared with the browsers 
// process over a system V memory segment. 
//
// As an example, this can be used to enable keyboardless navigation 
// in surf by simply typing in the number of the link. 
//
// TODO: Support multiple clients! See source for more TODOS!
//       THE biggest limitation by now is the lazily hardcoded:
//       key_t my_ftok = ftok("~/surf-webext-dom-shared-mem",'a');
//
// Last Update: 14th March 2018
// 
// Last Tested: with surf commit 81f0452bc6c2a110239fa303ad1e72f11c33dc94
//              from htps://git.suckless.org/surf
// 

#include <webkit2/webkit-web-extension.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

bool str_prefix(const char *str, const char *pre);

static int call=0;
static char *shared_buf;
WebKitDOMHTMLDocument *my_doc;

void
document_loaded_callback (WebKitWebPage *web_page,
                          GPtrArray     *elements,
                          GVariant      *user_data)
{

    my_doc = webkit_web_page_get_dom_document(web_page);
//    if(!WEBKIT_DOM_IS_HTML_DOCUMENT(my_doc))return;

//    GThread *t1 = g_thread_new ("show hints", show_hints, doc);
 //   g_thread_join(t1);
}

GThreadFunc
show_hints(WebKitDOMHTMLDocument *doc)
{

    // TODO: g_free where appropriate !!
    // TODO: allow focus on input boxes/forms 
    // TODO: Put this somehwere else? (but I dislike #defines)
    // share this info with surf itself! maybe surf can supply this along
    // the ftok path via the user_data GVariant.
    int MAX_LINKS=1024;
    int MAX_LINK_LENGTH=1024;
    int DEBUG=9;

    // get url
    char *url = webkit_dom_document_get_url (doc); 
    if(DEBUG>1) g_print("document_loaded (callback): %s\n", url);

    // tokenize url
    char *url_proto=strtok(url,"/");
    char *url_host=strtok(NULL,"/");
    if(DEBUG>2) g_print("proto: %s\n", url_proto);
    if(DEBUG>2) g_print("host: %s\n", url_host);

    // get html body
    WebKitDOMHTMLElement *body  = webkit_dom_document_get_body(doc);

    // get links (alt)
    WebKitDOMNodeList *links = webkit_dom_document_query_selector_all(doc,"a",NULL);
    gulong links_count		   = webkit_dom_node_list_get_length (links);
    g_print("extracted %i links\n",links_count);

    // get links 
    /*
    WebKitDOMHTMLCollection *links = webkit_dom_document_get_links(doc);
    gulong links_count		   = webkit_dom_html_collection_get_length (links);
    if(DEBUG>1) g_print("extracted %i links\n",links_count);
    */

    // iterate over links
    for(gulong i=0;i<links_count;i++)
    {
	char buf[MAX_LINK_LENGTH]; // TODO: dynamic!

	WebKitDOMHTMLElement * node = webkit_dom_node_list_item (links,i);

	// add hint for keyboard navigation
	
        //g_print("node address: %p\n", node);
	
	char *txt = webkit_dom_html_element_get_inner_html (node); 

	// TODO: style via stylesheet
	snprintf(buf,MAX_LINK_LENGTH, 
		"<span style='padding-right:5px;border-bottom:1px solid black;'>\
		<span style='font-size:13px;font-weight:bold;font-face:Arial;\
		      border:1px solid black;display:inline;color:white;\
		      background-color:#77b;padding:0 5px;margin:0;\
		      margin-right:5px;'>%i</span>%s</span>", i,txt);
        if(DEBUG>10) g_print("extracted link : %s\n",txt);

	webkit_dom_html_element_set_inner_html (node,buf,NULL);
	
	//sleep(1);
	// alternatively add hints at the end of the body
	// webkit_dom_element_insert_adjacent_html (body,"beforeend",buf,NULL);

	// TODO: this does not work for some sad reason. 
	// sadly, likely due to my misunderstanding.
	// node seems not to be a LinkElement at all :(
	//txt = webkit_dom_html_link_element_get_href (node); 
	// so we have to use this:
	txt = webkit_dom_element_get_attribute (node,"href");
	if(txt==NULL)continue;
	if(str_prefix(txt,"//"))     snprintf(buf,MAX_LINK_LENGTH,"%s%s",url_proto,txt);
	else if(str_prefix(txt,"/")) snprintf(buf,MAX_LINK_LENGTH,"%s//%s%s",url_proto,url_host,txt);
	else                         snprintf(buf,MAX_LINK_LENGTH,"%s",txt);
	
	if(i<MAX_LINKS) snprintf(&(shared_buf[MAX_LINK_LENGTH*i]),MAX_LINK_LENGTH,"%s\0",buf);
        if(DEBUG>10) g_print("extracted link : %s\n",buf);
    }
}

static gboolean mycallback(GIOChannel *ch, GIOCondition c, gpointer p)
{
    g_print("callback called\n");
    gchar *line;
    g_io_channel_read_line(ch, &line, NULL, NULL, NULL);
    g_print("read: %s\n",line);
    g_free(line);
    show_hints(my_doc);
    return true;

}
static void
page_created_callback (WebKitWebExtension *extension,
                       WebKitWebPage      *web_page,
                       GVariant           *user_data)
{
    g_signal_connect (web_page, "document-loaded", 
                      G_CALLBACK (document_loaded_callback), 
                      user_data);

    GMainContext *ctx = g_main_context_default();
    GIOChannel *io = g_io_channel_new_file("/home/miguel/temp/mypipe", "r+", NULL);
    GSource *watch = g_io_create_watch(io, G_IO_IN);
    g_source_attach(watch,ctx);
    g_source_set_callback(watch,(GSourceFunc)mycallback,NULL,NULL);

}

G_MODULE_EXPORT void
webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
					        GVariant           *user_data)
{
    g_print("Initalizing Miguel's Surfin' Quick Links WebKit2GTK+ Extension\n");
    g_print("Extension  PID: %d\n",getpid());
    gchar *str=g_variant_get_string(user_data,NULL);
    g_print("UI Process Data: %s\n",str);
//    g_free(str);
    g_signal_connect (extension, "page-created", 
                      G_CALLBACK (page_created_callback),
                      user_data );
    
}

//https://stackoverflow.com/questions/4770985/how-to-check-if-a-string-starts-with-another-string-in-c
bool str_prefix(const char *str, const char *pre)
{
    size_t lenpre = strlen(pre),
           lenstr = strlen(str);
    return lenstr < lenpre ? false : strncmp(pre, str, lenpre) == 0;
}