NetSurf
hotlist.c
Go to the documentation of this file.
1/*
2 * Copyright 2010 John Mark Bell <jmb@netsurf-browser.org>
3 * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * \file
22 * Implementation of GTK bookmark (hotlist) manager.
23 */
24
25#include <stdint.h>
26#include <stdlib.h>
27#include <gtk/gtk.h>
28
29#include "utils/log.h"
30#include "utils/nsoption.h"
31#include "netsurf/keypress.h"
32#include "netsurf/plotters.h"
33#include "desktop/hotlist.h"
34
35#include "gtk/compat.h"
36#include "gtk/plotters.h"
37#include "gtk/resources.h"
38#include "gtk/corewindow.h"
39#include "gtk/hotlist.h"
40
41/**
42 * hotlist window container for gtk.
43 */
46 GtkBuilder *builder;
47 GtkWindow *wnd;
48};
49
51
52#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
53 GtkMenuItem *widget, gpointer g)
54#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) }
55#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \
56 gpointer g)
57
58struct menu_events {
59 const char *widget;
60 GCallback handler;
61};
62
63
64/* file menu*/
65MENUPROTO(export);
66MENUPROTO(new_folder);
67MENUPROTO(new_entry);
68
69/* edit menu */
70MENUPROTO(edit_selected);
71MENUPROTO(delete_selected);
72MENUPROTO(select_all);
73MENUPROTO(clear_selection);
74
75/* view menu*/
76MENUPROTO(expand_all);
77MENUPROTO(expand_directories);
78MENUPROTO(expand_addresses);
79MENUPROTO(collapse_all);
80MENUPROTO(collapse_directories);
81MENUPROTO(collapse_addresses);
82
83MENUPROTO(launch);
84
85static struct menu_events menu_events[] = {
86
87 /* file menu*/
88 MENUEVENT(export),
89 MENUEVENT(new_folder),
90 MENUEVENT(new_entry),
91
92 /* edit menu */
93 MENUEVENT(edit_selected),
94 MENUEVENT(delete_selected),
95 MENUEVENT(select_all),
96 MENUEVENT(clear_selection),
97
98 /* view menu*/
99 MENUEVENT(expand_all),
100 MENUEVENT(expand_directories),
101 MENUEVENT(expand_addresses),
102 MENUEVENT(collapse_all),
103 MENUEVENT(collapse_directories),
104 MENUEVENT(collapse_addresses),
105
106 MENUEVENT(launch),
107
108 {NULL, NULL}
109};
110
111
112/* file menu*/
114{
115 struct nsgtk_hotlist_window *hlwin;
116 GtkWidget *save_dialog;
117
118 hlwin = (struct nsgtk_hotlist_window *)g;
119
120 save_dialog = gtk_file_chooser_dialog_new("Save File",
121 hlwin->wnd,
122 GTK_FILE_CHOOSER_ACTION_SAVE,
123 NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
124 NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
125 NULL);
126
127 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog),
128 getenv("HOME") ? getenv("HOME") : "/");
129
130 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
131 "hotlist.html");
132
133 if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) {
134 gchar *filename = gtk_file_chooser_get_filename(
135 GTK_FILE_CHOOSER(save_dialog));
136
137 hotlist_export(filename, NULL);
138 g_free(filename);
139 }
140
141 gtk_widget_destroy(save_dialog);
142
143 return TRUE;
144}
145
146MENUHANDLER(new_folder)
147{
148 hotlist_add_folder(NULL, false, 0);
149 return TRUE;
150}
151
152MENUHANDLER(new_entry)
153{
154 hotlist_add_entry(NULL, NULL, false, 0);
155 return TRUE;
156}
157
158/* edit menu */
159MENUHANDLER(edit_selected)
160{
162 return TRUE;
163}
164
165MENUHANDLER(delete_selected)
166{
168 return TRUE;
169}
170
171MENUHANDLER(select_all)
172{
176 return TRUE;
177}
178
179MENUHANDLER(clear_selection)
180{
182 return TRUE;
183}
184
185/* view menu*/
186MENUHANDLER(expand_all)
187{
188 hotlist_expand(false);
189 return TRUE;
190}
191
192MENUHANDLER(expand_directories)
193{
194 hotlist_expand(true);
195 return TRUE;
196}
197
198MENUHANDLER(expand_addresses)
199{
200 hotlist_expand(false);
201 return TRUE;
202}
203
204MENUHANDLER(collapse_all)
205{
206 hotlist_contract(true);
207 return TRUE;
208}
209
210MENUHANDLER(collapse_directories)
211{
212 hotlist_contract(true);
213 return TRUE;
214}
215
216MENUHANDLER(collapse_addresses)
217{
218 hotlist_contract(false);
219 return TRUE;
220}
221
223{
225 return TRUE;
226}
227
228
229/**
230 * Connects menu events in the hotlist window.
231 */
233{
234 struct menu_events *event = menu_events;
235 GtkWidget *w;
236
237 while (event->widget != NULL) {
238 w = GTK_WIDGET(gtk_builder_get_object(hlwin->builder,
239 event->widget));
240 if (w == NULL) {
241 NSLOG(netsurf, INFO,
242 "Unable to connect menu widget ""%s""",
243 event->widget);
244 } else {
245 g_signal_connect(G_OBJECT(w),
246 "activate",
247 event->handler,
248 hlwin);
249 }
250 event++;
251 }
252}
253
254
255/**
256 * callback for mouse action on hotlist window
257 *
258 * \param nsgtk_cw The nsgtk core window structure.
259 * \param mouse_state netsurf mouse state on event
260 * \param x location of event
261 * \param y location of event
262 * \return NSERROR_OK on success otherwise apropriate error code
263 */
264static nserror
266 browser_mouse_state mouse_state,
267 int x, int y)
268{
269 hotlist_mouse_action(mouse_state, x, y);
270
271 return NSERROR_OK;
272}
273
274/**
275 * callback for keypress on hotlist window
276 *
277 * \param nsgtk_cw The nsgtk core window structure.
278 * \param nskey The netsurf key code
279 * \return NSERROR_OK on success otherwise apropriate error code
280 */
281static nserror
282nsgtk_hotlist_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
283{
284 if (hotlist_keypress(nskey)) {
285 return NSERROR_OK;
286 }
288}
289
290/**
291 * callback on draw event for hotlist window
292 *
293 * \param nsgtk_cw The nsgtk core window structure.
294 * \param r The rectangle of the window that needs updating.
295 * \return NSERROR_OK on success otherwise apropriate error code
296 */
297static nserror
298nsgtk_hotlist_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
299{
300 struct redraw_context ctx = {
301 .interactive = true,
302 .background_images = true,
303 .plot = &nsgtk_plotters
304 };
305
306 hotlist_redraw(0, 0, r, &ctx);
307
308 return NSERROR_OK;
309}
310
311/**
312 * Creates the window for the hotlist tree.
313 *
314 * \return NSERROR_OK on success else appropriate error code on faliure.
315 */
317{
318 struct nsgtk_hotlist_window *ncwin;
319 nserror res;
320
321 if (hotlist_window != NULL) {
322 return NSERROR_OK;
323 }
324
325 ncwin = calloc(1, sizeof(*ncwin));
326 if (ncwin == NULL) {
327 return NSERROR_NOMEM;
328 }
329
330 res = nsgtk_builder_new_from_resname("hotlist", &ncwin->builder);
331 if (res != NSERROR_OK) {
332 NSLOG(netsurf, INFO, "Hotlist UI builder init failed");
333 free(ncwin);
334 return res;
335 }
336
337 gtk_builder_connect_signals(ncwin->builder, NULL);
338
339 ncwin->wnd = GTK_WINDOW(gtk_builder_get_object(ncwin->builder,
340 "wndHotlist"));
341
342 ncwin->core.scrolled = GTK_SCROLLED_WINDOW(
343 gtk_builder_get_object(ncwin->builder, "hotlistScrolled"));
344
345 ncwin->core.drawing_area = GTK_DRAWING_AREA(
346 gtk_builder_get_object(ncwin->builder, "hotlistDrawingArea"));
347
348 /* make the delete event hide the window */
349 g_signal_connect(G_OBJECT(ncwin->wnd),
350 "delete_event",
351 G_CALLBACK(gtk_widget_hide_on_delete),
352 NULL);
353
355
357 ncwin->core.key = nsgtk_hotlist_key;
359
360 res = nsgtk_corewindow_init(&ncwin->core);
361 if (res != NSERROR_OK) {
362 free(ncwin);
363 return res;
364 }
365
367 (struct core_window *)ncwin);
368 if (res != NSERROR_OK) {
369 free(ncwin);
370 return res;
371 }
372
373 /* memoise window so it can be represented when necessary
374 * instead of recreating every time.
375 */
376 hotlist_window = ncwin;
377
378 return NSERROR_OK;
379}
380
381
382/* exported function documented gtk/hotlist.h */
384{
385 nserror res;
386
387 res = nsgtk_hotlist_init();
388 if (res == NSERROR_OK) {
389 gtk_window_present(hotlist_window->wnd);
390 }
391 return res;
392}
393
394
395/* exported function documented gtk/hotlist.h */
397{
398 nserror res;
399
400 if (hotlist_window == NULL) {
401 return NSERROR_OK;
402 }
403
404 res = hotlist_manager_fini();
405 if (res == NSERROR_OK) {
407 gtk_widget_destroy(GTK_WIDGET(hotlist_window->wnd));
408 g_object_unref(G_OBJECT(hotlist_window->builder));
409 free(hotlist_window);
410 hotlist_window = NULL;
411 }
412
413 return res;
414}
Compatibility functions for older GTK versions (interface)
#define NSGTK_STOCK_SAVE
Definition: compat.h:61
#define NSGTK_STOCK_CANCEL
Definition: compat.h:55
bool hotlist_keypress(uint32_t key)
Key press handling.
Definition: hotlist.c:1698
nserror hotlist_add_entry(nsurl *url, const char *title, bool at_y, int y)
Add an entry to the hotlist for given Title/URL.
Definition: hotlist.c:1624
void hotlist_mouse_action(browser_mouse_state mouse, int x, int y)
Handles all kinds of mouse action.
Definition: hotlist.c:1691
nserror hotlist_manager_fini(void)
Finalise the hotlist manager.
Definition: hotlist.c:1373
void hotlist_redraw(int x, int y, struct rect *clip, const struct redraw_context *ctx)
Redraw the hotlist.
Definition: hotlist.c:1683
nserror hotlist_manager_init(struct core_window_callback_table *cw_t, void *core_window_handle)
Initialise the hotlist manager.
Definition: hotlist.c:1354
nserror hotlist_add_folder(const char *title, bool at_y, int y)
Add a folder to the hotlist.
Definition: hotlist.c:1661
nserror hotlist_export(const char *path, const char *title)
Save hotlist to file.
Definition: hotlist.c:1086
nserror hotlist_expand(bool only_folders)
Expand the treeview's nodes.
Definition: hotlist.c:1741
void hotlist_edit_selection(void)
Edit the first selected node.
Definition: hotlist.c:1734
nserror hotlist_contract(bool all)
Contract the treeview's nodes.
Definition: hotlist.c:1748
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_IMPLEMENTED
Functionality is not implemented.
Definition: errors.h:61
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
static void nsgtk_hotlist_init_menu(struct nsgtk_hotlist_window *hlwin)
Connects menu events in the hotlist window.
Definition: hotlist.c:232
#define MENUHANDLER(x)
Definition: hotlist.c:55
static nserror nsgtk_hotlist_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
callback for keypress on hotlist window
Definition: hotlist.c:282
static struct nsgtk_hotlist_window * hotlist_window
Definition: hotlist.c:50
#define MENUEVENT(x)
Definition: hotlist.c:54
static nserror nsgtk_hotlist_mouse(struct nsgtk_corewindow *nsgtk_cw, browser_mouse_state mouse_state, int x, int y)
callback for mouse action on hotlist window
Definition: hotlist.c:265
static struct menu_events menu_events[]
Definition: hotlist.c:85
static nserror nsgtk_hotlist_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
callback on draw event for hotlist window
Definition: hotlist.c:298
nserror nsgtk_hotlist_destroy(void)
Free any resources allocated for the hotlist window.
Definition: hotlist.c:396
#define MENUPROTO(x)
Definition: hotlist.c:52
static nserror nsgtk_hotlist_init(void)
Creates the window for the hotlist tree.
Definition: hotlist.c:316
nserror nsgtk_hotlist_present(void)
make the hotlist window visible.
Definition: hotlist.c:383
Interface to GTK bookmarks (hotlist).
Target independent plotting GTK+ interface.
nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw)
initialise elements of gtk core window.
Definition: corewindow.c:732
nserror nsgtk_corewindow_fini(struct nsgtk_corewindow *nsgtk_cw)
finalise elements of gtk core window.
Definition: corewindow.c:786
const struct plotter_table nsgtk_plotters
GTK plotter table.
Definition: plotters.c:647
browser_mouse_state
Mouse state.
Definition: mouse.h:43
Target independent plotting interface.
Interface to key press operations.
@ NS_KEY_CR
Definition: keypress.h:40
@ NS_KEY_SELECT_ALL
Definition: keypress.h:32
@ NS_KEY_CLEAR_SELECTION
Definition: keypress.h:45
@ NS_KEY_DELETE_LEFT
Definition: keypress.h:35
@ NS_KEY_ESCAPE
Definition: keypress.h:47
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
nserror nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
Create gtk builder object for the named ui resource.
Definition: resources.c:526
Interface to gtk builtin resource handling.
GCallback handler
Definition: cookies.c:54
const char * widget
nsgtk core window state
Definition: corewindow.h:39
nserror(* key)(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey)
callback for keypress on nsgtk core window
Definition: corewindow.h:74
nserror(* draw)(struct nsgtk_corewindow *nsgtk_cw, struct rect *r)
callback to draw on drawable area of nsgtk core window
Definition: corewindow.h:63
struct core_window_callback_table * cb_table
table of callbacks for core window operations
Definition: corewindow.h:50
GtkScrolledWindow * scrolled
scrollable area drawing area is within
Definition: corewindow.h:44
nserror(* mouse)(struct nsgtk_corewindow *nsgtk_cw, browser_mouse_state mouse_state, int x, int y)
callback for mouse event on nsgtk core window
Definition: corewindow.h:85
GtkDrawingArea * drawing_area
GTK drawable widget.
Definition: corewindow.h:42
hotlist window container for gtk.
Definition: hotlist.c:44
GtkBuilder * builder
Definition: hotlist.c:46
struct nsgtk_corewindow core
Definition: hotlist.c:45
GtkWindow * wnd
Definition: hotlist.c:47
Rectangle coordinates.
Definition: types.h:40
Redraw context.
Definition: plotters.h:51
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
Option reading and saving interface.