1 /*
2  * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <stdlib.h>
20 #include <stdbool.h>
21 
22 #include <gdk/gdkkeysyms.h>
23 #include <gtk/gtk.h>
24 
25 #include "utils/messages.h"
26 
27 #include "gtk/compat.h"
28 #include "gtk/menu.h"
29 #include "gtk/warn.h"
30 #include "gtk/accelerator.h"
31 
32 /**
33  * Adds image menu item to a menu.
34  *
35  * \param menu the menu to add the item to
36  * \param item_out a pointer to the item's location in the menu struct
37  * \param message the menu item I18n lookup value
38  * \param group the 'global' in a gtk sense accelerator group
39  * \return true if sucessful and \a item_out updated else false.
40  */
41 
42 static bool
nsgtk_menu_add_image_item(GtkMenu * menu,GtkWidget ** item_out,const char * message,GtkAccelGroup * group)43 nsgtk_menu_add_image_item(GtkMenu *menu,
44 			  GtkWidget **item_out,
45 			  const char *message,
46 			  GtkAccelGroup *group)
47 {
48 	unsigned int key;
49 	GdkModifierType mod;
50 	GtkWidget *item;
51 	const char *accelerator_desc; /* accelerator key description */
52 
53 	item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message));
54 	if (item == NULL) {
55 		return false;
56 	}
57 
58 	accelerator_desc = nsgtk_accelerator_get_desc(message);
59 	if (accelerator_desc != NULL) {
60 		gtk_accelerator_parse(accelerator_desc, &key, &mod);
61 		if (key > 0) {
62 			gtk_widget_add_accelerator(item,
63 						   "activate",
64 						   group,
65 						   key,
66 						   mod,
67 						   GTK_ACCEL_VISIBLE);
68 		}
69 	}
70 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
71 	gtk_widget_show(item);
72 
73 	*item_out = item;
74 
75 	return true;
76 }
77 
78 #define NEW_MENU(n, m)				\
79 	n = malloc(sizeof(*n));			\
80 	if (n == NULL) {			\
81 		return NULL;			\
82 	}					\
83 	n->m##_menu = GTK_MENU(gtk_menu_new())
84 
85 #define IMAGE_ITEM(p, q, r, s, t)\
86 	nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r, t)
87 
88 #define CHECK_ITEM(p, q, r, s)					\
89 	do {							\
90 		s->q##_menuitem = GTK_CHECK_MENU_ITEM(		\
91 			gtk_check_menu_item_new_with_mnemonic(\
92 			messages_get(#r)));\
93 		if ((s->q##_menuitem != NULL) && (s->p##_menu != NULL)) { \
94 			gtk_menu_shell_append(GTK_MENU_SHELL(s->p##_menu), \
95 					      GTK_WIDGET(s->q##_menuitem)); \
96 			gtk_widget_show(GTK_WIDGET(s->q##_menuitem));	\
97 		}							\
98 	} while(0)
99 
100 #define SET_SUBMENU(q, r)					\
101 	do {							\
102 		r->q##_submenu = nsgtk_menu_##q##_submenu(group);	\
103 		if ((r->q##_submenu != NULL) &&				\
104 		    (r->q##_submenu->q##_menu != NULL) &&		\
105 		    (r->q##_menuitem != NULL)) {			\
106 			gtk_menu_item_set_submenu(GTK_MENU_ITEM(r->q##_menuitem), \
107 						  GTK_WIDGET(r->q##_submenu->q##_menu)); \
108 		}							\
109 	} while(0)
110 
111 #define ADD_NAMED_SEP(q, r, s)						\
112 	do {								\
113 		s->r##_separator = gtk_separator_menu_item_new();	\
114 		if ((s->r##_separator != NULL) && (s->q##_menu != NULL)) { \
115 			gtk_menu_shell_append(GTK_MENU_SHELL(s->q##_menu), s->r##_separator); \
116 			gtk_widget_show(s->r##_separator);		\
117 		}							\
118 	} while(0)
119 
120 #define ADD_SEP(q, r)							\
121 	do {								\
122 		GtkWidget *w = gtk_separator_menu_item_new();		\
123 		if ((w != NULL) && (r->q##_menu != NULL)) {		\
124 			gtk_menu_shell_append(GTK_MENU_SHELL(r->q##_menu), w); \
125 			gtk_widget_show(w);				\
126 		}							\
127 	} while(0)
128 
129 #define ATTACH_PARENT(parent, msgname, menuv, group)			\
130 	do {								\
131 		/* create top level menu entry and attach to parent */	\
132 		menuv = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(messages_get(#msgname))); \
133 		gtk_menu_shell_append(parent, GTK_WIDGET(menuv));	\
134 		gtk_widget_show(GTK_WIDGET(menuv));			\
135 		/* attach submenu to parent */				\
136 		gtk_menu_item_set_submenu(menuv, GTK_WIDGET(menuv##_menu)); \
137 		gtk_menu_set_accel_group(menuv##_menu, group);		\
138 	} while(0)
139 
140 /**
141 * creates an export submenu
142 * \param group the 'global' in a gtk sense accelerator reference
143 */
144 static struct nsgtk_export_submenu *
nsgtk_menu_export_submenu(GtkAccelGroup * group)145 nsgtk_menu_export_submenu(GtkAccelGroup *group)
146 {
147 	struct nsgtk_export_submenu *ret;
148 	ret = malloc(sizeof(struct nsgtk_export_submenu));
149 
150 	if (ret == NULL) {
151 		nsgtk_warning(messages_get("NoMemory"), 0);
152 		return NULL;
153 	}
154 
155 	ret->export_menu = GTK_MENU(gtk_menu_new());
156 	if (ret->export_menu == NULL) {
157 		nsgtk_warning(messages_get("NoMemory"), 0);
158 		free(ret);
159 		return NULL;
160 	}
161 
162 	IMAGE_ITEM(export, savepage, gtkSavePage, ret, group);
163 	IMAGE_ITEM(export, plaintext, gtkPlainText, ret, group);
164 	IMAGE_ITEM(export, pdf, gtkPDF, ret, group);
165 	return ret;
166 }
167 
168 /**
169 * creates a scaleview submenu
170 * \param group the 'global' in a gtk sense accelerator reference
171 */
172 
173 static struct nsgtk_scaleview_submenu *
nsgtk_menu_scaleview_submenu(GtkAccelGroup * group)174 nsgtk_menu_scaleview_submenu(GtkAccelGroup *group)
175 {
176 	struct nsgtk_scaleview_submenu *ret =
177 			malloc(sizeof(struct nsgtk_scaleview_submenu));
178 	if (ret == NULL) {
179 		nsgtk_warning(messages_get("NoMemory"), 0);
180 		return NULL;
181 	}
182 	ret->scaleview_menu = GTK_MENU(gtk_menu_new());
183 	if (ret->scaleview_menu == NULL) {
184 		nsgtk_warning(messages_get("NoMemory"), 0);
185 		free(ret);
186 		return NULL;
187 	}
188 	IMAGE_ITEM(scaleview, zoomplus, gtkZoomPlus, ret, group);
189 	IMAGE_ITEM(scaleview, zoomnormal, gtkZoomNormal, ret, group);
190 	IMAGE_ITEM(scaleview, zoomminus, gtkZoomMinus, ret, group);
191 	return ret;
192 }
193 
194 /**
195 * creates a tab navigation submenu
196 * \param group the 'global' in a gtk sense accelerator reference
197 */
198 
nsgtk_menu_tabs_submenu(GtkAccelGroup * group)199 static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group)
200 {
201 	struct nsgtk_tabs_submenu *ret;
202 	ret = malloc(sizeof(struct nsgtk_tabs_submenu));
203 	if (ret == NULL) {
204 		nsgtk_warning(messages_get("NoMemory"), 0);
205 		return NULL;
206 	}
207 	ret->tabs_menu = GTK_MENU(gtk_menu_new());
208 	if (ret->tabs_menu == NULL) {
209 		nsgtk_warning(messages_get("NoMemory"), 0);
210 		free(ret);
211 		return NULL;
212 	}
213 	IMAGE_ITEM(tabs, nexttab, gtkNextTab, ret, group);
214 	IMAGE_ITEM(tabs, prevtab, gtkPrevTab, ret, group);
215 	IMAGE_ITEM(tabs, closetab, gtkCloseTab, ret, group);
216 
217 	return ret;
218 }
219 
220 
221 /**
222  * creates a toolbars submenu
223  *
224  * \param group the 'global' in a gtk sense accelerator reference
225  */
226 static struct nsgtk_toolbars_submenu *
nsgtk_menu_toolbars_submenu(GtkAccelGroup * group)227 nsgtk_menu_toolbars_submenu(GtkAccelGroup *group)
228 {
229 	struct nsgtk_toolbars_submenu *tmenu;
230 
231 	tmenu = malloc(sizeof(struct nsgtk_toolbars_submenu));
232 	if (tmenu == NULL) {
233 		nsgtk_warning(messages_get("NoMemory"), 0);
234 		return NULL;
235 	}
236 
237 	tmenu->toolbars_menu = GTK_MENU(gtk_menu_new());
238 	if (tmenu->toolbars_menu == NULL) {
239 		nsgtk_warning(messages_get("NoMemory"), 0);
240 		free(tmenu);
241 		return NULL;
242 	}
243 
244 	CHECK_ITEM(toolbars, menubar, gtkMenuBar, tmenu);
245 	if (tmenu->menubar_menuitem != NULL) {
246 		gtk_check_menu_item_set_active(tmenu->menubar_menuitem, TRUE);
247 	}
248 
249 	CHECK_ITEM(toolbars, toolbar, gtkToolBar, tmenu);
250 	if (tmenu->toolbar_menuitem != NULL) {
251 		gtk_check_menu_item_set_active(tmenu->toolbar_menuitem, TRUE);
252 	}
253 
254 	ADD_SEP(toolbars, tmenu);
255 
256 	IMAGE_ITEM(toolbars, customize, gtkCustomize, tmenu, group);
257 
258 	return tmenu;
259 }
260 
261 /**
262 * creates a debugging submenu
263 * \param group the 'global' in a gtk sense accelerator reference
264 */
265 
266 static struct nsgtk_developer_submenu *
nsgtk_menu_developer_submenu(GtkAccelGroup * group)267 nsgtk_menu_developer_submenu(GtkAccelGroup *group)
268 {
269 	struct nsgtk_developer_submenu *dmenu =
270 			malloc(sizeof(struct nsgtk_developer_submenu));
271 	if (dmenu == NULL) {
272 		nsgtk_warning(messages_get("NoMemory"), 0);
273 		return NULL;
274 	}
275 	dmenu->developer_menu = GTK_MENU(gtk_menu_new());
276 	if (dmenu->developer_menu == NULL) {
277 		nsgtk_warning(messages_get("NoMemory"), 0);
278 		free(dmenu);
279 		return NULL;
280 	}
281 
282 	IMAGE_ITEM(developer, viewsource, gtkPageSource, dmenu, group);
283 	IMAGE_ITEM(developer, toggledebugging, gtkToggleDebugging, dmenu, group);
284 	IMAGE_ITEM(developer, debugboxtree, gtkDebugBoxTree, dmenu, group);
285 	IMAGE_ITEM(developer, debugdomtree, gtkDebugDomTree, dmenu, group);
286 
287 	return dmenu;
288 }
289 
290 /**
291  * creates the file menu
292  *
293  * \param group The gtk 'global' accelerator reference
294  * \return The new file menu or NULL on error
295  */
nsgtk_menu_file_submenu(GtkAccelGroup * group)296 static struct nsgtk_file_menu *nsgtk_menu_file_submenu(GtkAccelGroup *group)
297 {
298 	struct nsgtk_file_menu *fmenu;
299 
300 	fmenu = malloc(sizeof(struct nsgtk_file_menu));
301 	if (fmenu == NULL) {
302 		nsgtk_warning(messages_get("NoMemory"), 0);
303 		return NULL;
304 	}
305 
306 	fmenu->file_menu = GTK_MENU(gtk_menu_new());
307 	if (fmenu->file_menu == NULL) {
308 		nsgtk_warning(messages_get("NoMemory"), 0);
309 		free(fmenu);
310 		return NULL;
311 	}
312 
313 	IMAGE_ITEM(file, newwindow, gtkNewWindow, fmenu, group);
314 	IMAGE_ITEM(file, newtab, gtkNewTab, fmenu, group);
315 	IMAGE_ITEM(file, openfile, gtkOpenFile, fmenu, group);
316 	IMAGE_ITEM(file, closewindow, gtkCloseWindow, fmenu, group);
317 	ADD_SEP(file, fmenu);
318 	IMAGE_ITEM(file, export, gtkExport, fmenu, group);
319 	ADD_SEP(file, fmenu);
320 	IMAGE_ITEM(file, printpreview, gtkPrintPreview, fmenu, group);
321 	IMAGE_ITEM(file, print, gtkPrint, fmenu, group);
322 	ADD_SEP(file, fmenu);
323 	IMAGE_ITEM(file, quit, gtkQuitMenu, fmenu, group);
324 	SET_SUBMENU(export, fmenu);
325 
326 	return fmenu;
327 }
328 
329 /**
330 * creates an edit menu
331 * \param group the 'global' in a gtk sense accelerator reference
332 */
333 
nsgtk_menu_edit_submenu(GtkAccelGroup * group)334 static struct nsgtk_edit_menu *nsgtk_menu_edit_submenu(GtkAccelGroup *group)
335 {
336 	struct nsgtk_edit_menu *ret = malloc(sizeof(struct nsgtk_edit_menu));
337 	if (ret == NULL) {
338 		nsgtk_warning(messages_get("NoMemory"), 0);
339 		return NULL;
340 	}
341 	ret->edit_menu = GTK_MENU(gtk_menu_new());
342 	if (ret->edit_menu == NULL) {
343 		nsgtk_warning(messages_get("NoMemory"), 0);
344 		free(ret);
345 		return NULL;
346 	}
347 	IMAGE_ITEM(edit, cut, gtkCut, ret, group);
348 	IMAGE_ITEM(edit, copy, gtkCopy, ret, group);
349 	IMAGE_ITEM(edit, paste, gtkPaste, ret, group);
350 	IMAGE_ITEM(edit, delete, gtkDelete, ret, group);
351 	ADD_SEP(edit, ret);
352 	IMAGE_ITEM(edit, selectall, gtkSelectAll, ret, group);
353 	ADD_SEP(edit, ret);
354 	IMAGE_ITEM(edit, find, gtkFind, ret, group);
355 	ADD_SEP(edit, ret);
356 	IMAGE_ITEM(edit, preferences, gtkPreferences, ret, group);
357 
358 	return ret;
359 }
360 
361 /**
362 * creates a view menu
363 * \param group the 'global' in a gtk sense accelerator reference
364 */
365 
nsgtk_menu_view_submenu(GtkAccelGroup * group)366 static struct nsgtk_view_menu *nsgtk_menu_view_submenu(GtkAccelGroup *group)
367 {
368 	struct nsgtk_view_menu *ret = malloc(sizeof(struct nsgtk_view_menu));
369 	if (ret == NULL) {
370 		nsgtk_warning(messages_get("NoMemory"), 0);
371 		return NULL;
372 	}
373 	ret->view_menu = GTK_MENU(gtk_menu_new());
374 	if (ret->view_menu == NULL) {
375 		nsgtk_warning(messages_get("NoMemory"), 0);
376 		free(ret);
377 		return NULL;
378 	}
379 	IMAGE_ITEM(view, scaleview, gtkScaleView, ret, group);
380 	SET_SUBMENU(scaleview, ret);
381 	IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group);
382 	ADD_SEP(view, ret);
383 	IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group);
384 	SET_SUBMENU(toolbars, ret);
385 	IMAGE_ITEM(view, tabs, gtkTabs, ret, group);
386 	SET_SUBMENU(tabs, ret);
387 	ADD_SEP(view, ret);
388 	IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group);
389 
390 	return ret;
391 }
392 
393 /**
394 * creates a nav menu
395 * \param group the 'global' in a gtk sense accelerator reference
396 */
397 
nsgtk_menu_nav_submenu(GtkAccelGroup * group)398 static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group)
399 {
400 	struct nsgtk_nav_menu *ret = malloc(sizeof(struct nsgtk_nav_menu));
401 	if (ret == NULL) {
402 		nsgtk_warning(messages_get("NoMemory"), 0);
403 		return NULL;
404 	}
405 	ret->nav_menu = GTK_MENU(gtk_menu_new());
406 	if (ret->nav_menu == NULL) {
407 		nsgtk_warning(messages_get("NoMemory"), 0);
408 		free(ret);
409 		return NULL;
410 	}
411 
412 	IMAGE_ITEM(nav, back, gtkBack, ret, group);
413 	IMAGE_ITEM(nav, forward, gtkForward, ret, group);
414 	IMAGE_ITEM(nav, stop, gtkStop, ret, group);
415 	IMAGE_ITEM(nav, reload, gtkReload, ret, group);
416 	IMAGE_ITEM(nav, home, gtkHome, ret, group);
417 	ADD_SEP(nav, ret);
418 	IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group);
419 	IMAGE_ITEM(nav, globalhistory, gtkGlobalHistory, ret, group);
420 	ADD_SEP(nav, ret);
421 	IMAGE_ITEM(nav, addbookmarks, gtkAddBookMarks, ret, group);
422 	IMAGE_ITEM(nav, showbookmarks, gtkShowBookMarks, ret, group);
423 	ADD_SEP(nav, ret);
424 	IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group);
425 
426 	return ret;
427 }
428 
429 /**
430  * creates the tools menu
431  * \param group the 'global' in a gtk sense accelerator reference
432  */
nsgtk_menu_tools_submenu(GtkAccelGroup * group)433 static struct nsgtk_tools_menu *nsgtk_menu_tools_submenu(GtkAccelGroup *group)
434 {
435 	struct nsgtk_tools_menu *ret = malloc(sizeof(struct nsgtk_tools_menu));
436 	if (ret == NULL) {
437 		nsgtk_warning(messages_get("NoMemory"), 0);
438 		return NULL;
439 	}
440 	ret->tools_menu = GTK_MENU(gtk_menu_new());
441 	if (ret->tools_menu == NULL) {
442 		nsgtk_warning(messages_get("NoMemory"), 0);
443 		free(ret);
444 		return NULL;
445 	}
446 
447 	IMAGE_ITEM(tools, downloads, gtkDownloads, ret, group);
448 	IMAGE_ITEM(tools, showcookies, gtkShowCookies, ret, group);
449 	IMAGE_ITEM(tools, developer, gtkDeveloper, ret, group);
450 	SET_SUBMENU(developer, ret);
451 
452 	return ret;
453 }
454 
455 /**
456  * creates a help menu
457  * \param group the 'global' in a gtk sense accelerator reference
458  */
nsgtk_menu_help_submenu(GtkAccelGroup * group)459 static struct nsgtk_help_menu *nsgtk_menu_help_submenu(GtkAccelGroup *group)
460 {
461 	struct nsgtk_help_menu *ret = malloc(sizeof(struct nsgtk_help_menu));
462 	if (ret == NULL) {
463 		nsgtk_warning(messages_get("NoMemory"), 0);
464 		return NULL;
465 	}
466 	ret->help_menu = GTK_MENU(gtk_menu_new());
467 	if (ret->help_menu == NULL) {
468 		nsgtk_warning(messages_get("NoMemory"), 0);
469 		free(ret);
470 		return NULL;
471 	}
472 	IMAGE_ITEM(help, contents, gtkContents, ret, group);
473 	IMAGE_ITEM(help, guide, gtkGuide, ret, group);
474 	IMAGE_ITEM(help, info, gtkUserInformation, ret, group);
475 	ADD_SEP(help, ret);
476 	IMAGE_ITEM(help, about, gtkAbout, ret, group);
477 
478 	return ret;
479 }
480 
481 
482 /**
483  * Generate menubar menus.
484  *
485  * Generate the main menu structure and attach it to a menubar widget.
486  */
487 struct nsgtk_bar_submenu *
nsgtk_menu_bar_create(GtkMenuShell * menubar,GtkAccelGroup * group)488 nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkAccelGroup *group)
489 {
490 	struct nsgtk_bar_submenu *nmenu;
491 
492 	nmenu = calloc(1, sizeof(struct nsgtk_bar_submenu));
493 	if (nmenu == NULL) {
494 		return NULL;
495 	}
496 
497 	/* create sub menus */
498 	nmenu->file_submenu = nsgtk_menu_file_submenu(group);
499 	nmenu->edit_submenu = nsgtk_menu_edit_submenu(group);
500 	nmenu->view_submenu = nsgtk_menu_view_submenu(group);
501 	nmenu->nav_submenu = nsgtk_menu_nav_submenu(group);
502 	nmenu->tools_submenu = nsgtk_menu_tools_submenu(group);
503 	nmenu->help_submenu = nsgtk_menu_help_submenu(group);
504 
505 	if (menubar != NULL) {
506 		nmenu->bar_menu = GTK_MENU_BAR(menubar);
507 
508 		/* attach menus to menubar */
509 		ATTACH_PARENT(menubar, gtkFile, nmenu->file_submenu->file, group);
510 		ATTACH_PARENT(menubar, gtkEdit, nmenu->edit_submenu->edit, group);
511 		ATTACH_PARENT(menubar, gtkView, nmenu->view_submenu->view, group);
512 		ATTACH_PARENT(menubar, gtkNavigate, nmenu->nav_submenu->nav, group);
513 		ATTACH_PARENT(menubar, gtkTools, nmenu->tools_submenu->tools, group);
514 		ATTACH_PARENT(menubar, gtkHelp, nmenu->help_submenu->help, group);
515 	}
516 
517 	return nmenu;
518 }
519 
520 
521 /* exported function documented in gtk/menu.h */
nsgtk_burger_menu_create(GtkAccelGroup * group)522 struct nsgtk_burger_menu *nsgtk_burger_menu_create(GtkAccelGroup *group)
523 {
524 	struct nsgtk_burger_menu *nmenu;
525 
526 	NEW_MENU(nmenu, burger);
527 
528 	IMAGE_ITEM(burger, file, gtkFile, nmenu, group);
529 	SET_SUBMENU(file, nmenu);
530 
531 	IMAGE_ITEM(burger, edit, gtkEdit, nmenu, group);
532 	SET_SUBMENU(edit, nmenu);
533 
534 	IMAGE_ITEM(burger, view, gtkView, nmenu, group);
535 	SET_SUBMENU(view, nmenu);
536 
537 	IMAGE_ITEM(burger, nav, gtkNavigate, nmenu, group);
538 	SET_SUBMENU(nav, nmenu);
539 
540 	IMAGE_ITEM(burger, tools, gtkTools, nmenu, group);
541 	SET_SUBMENU(tools, nmenu);
542 
543 	IMAGE_ITEM(burger, help, gtkHelp, nmenu, group);
544 	SET_SUBMENU(help, nmenu);
545 
546 	return nmenu;
547 }
548 
549 
550 /* exported function documented in gtk/menu.h */
nsgtk_popup_menu_create(GtkAccelGroup * group)551 struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group)
552 {
553 	struct nsgtk_popup_menu *nmenu;
554 
555 	NEW_MENU(nmenu, popup);
556 
557 	IMAGE_ITEM(popup, back, gtkBack, nmenu, group);
558 	IMAGE_ITEM(popup, forward, gtkForward, nmenu, group);
559 	IMAGE_ITEM(popup, stop, gtkStop, nmenu, group);
560 	IMAGE_ITEM(popup, reload, gtkReload, nmenu, group);
561 
562 	ADD_NAMED_SEP(popup, first, nmenu);
563 
564 	IMAGE_ITEM(popup, cut, gtkCut, nmenu, group);
565 	IMAGE_ITEM(popup, copy, gtkCopy, nmenu, group);
566 	IMAGE_ITEM(popup, paste, gtkPaste, nmenu, group);
567 
568 	ADD_NAMED_SEP(popup, second, nmenu);
569 
570 	IMAGE_ITEM(popup, toolbars, gtkToolbars, nmenu, group);
571 	SET_SUBMENU(toolbars, nmenu);
572 
573 	IMAGE_ITEM(popup, tools, gtkTools, nmenu, group);
574 	SET_SUBMENU(tools, nmenu);
575 
576 	return nmenu;
577 }
578 
579 
580 /* exported function documented in gtk/menu.h */
581 struct nsgtk_link_menu *
nsgtk_link_menu_create(GtkAccelGroup * group)582 nsgtk_link_menu_create(GtkAccelGroup *group)
583 {
584 	struct nsgtk_link_menu *nmenu;
585 
586 	NEW_MENU(nmenu, link);
587 
588 	IMAGE_ITEM(link, opentab, gtkOpentab, nmenu, group);
589 	IMAGE_ITEM(link, openwin, gtkOpenwin, nmenu, group);
590 
591 	ADD_SEP(link, nmenu);
592 
593 	IMAGE_ITEM(link, save, gtkSavelink, nmenu, group);
594 	IMAGE_ITEM(link, bookmark, gtkBookmarklink, nmenu, group);
595 	IMAGE_ITEM(link, copy, gtkCopylink, nmenu, group);
596 
597 	return nmenu;
598 }
599 
600 
601 /* exported function documented in gtk/menu.h */
nsgtk_menu_bar_destroy(struct nsgtk_bar_submenu * menu)602 nserror nsgtk_menu_bar_destroy(struct nsgtk_bar_submenu *menu)
603 {
604 	gtk_widget_destroy(GTK_WIDGET(menu->bar_menu));
605 
606 	free(menu->file_submenu->export_submenu);
607 	free(menu->file_submenu);
608 	free(menu->edit_submenu);
609 	free(menu->view_submenu->tabs_submenu);
610 	free(menu->view_submenu->toolbars_submenu);
611 	free(menu->view_submenu->scaleview_submenu);
612 	free(menu->view_submenu);
613 	free(menu->nav_submenu);
614 	free(menu->tools_submenu->developer_submenu);
615 	free(menu->tools_submenu);
616 	free(menu->help_submenu);
617 	free(menu);
618 
619 	return NSERROR_OK;
620 }
621 
622 /* exported function documented in gtk/menu.h */
nsgtk_burger_menu_destroy(struct nsgtk_burger_menu * menu)623 nserror nsgtk_burger_menu_destroy(struct nsgtk_burger_menu *menu)
624 {
625 	gtk_widget_destroy(GTK_WIDGET(menu->burger_menu));
626 
627 	free(menu->file_submenu->export_submenu);
628 	free(menu->file_submenu);
629 	free(menu->edit_submenu);
630 	free(menu->view_submenu->tabs_submenu);
631 	free(menu->view_submenu->toolbars_submenu);
632 	free(menu->view_submenu->scaleview_submenu);
633 	free(menu->view_submenu);
634 	free(menu->nav_submenu);
635 	free(menu->tools_submenu->developer_submenu);
636 	free(menu->tools_submenu);
637 	free(menu->help_submenu);
638 	free(menu);
639 
640 	return NSERROR_OK;
641 }
642 
643 
644 /* exported function documented in gtk/menu.h */
nsgtk_popup_menu_destroy(struct nsgtk_popup_menu * menu)645 nserror nsgtk_popup_menu_destroy(struct nsgtk_popup_menu *menu)
646 {
647 	gtk_widget_destroy(GTK_WIDGET(menu->popup_menu));
648 
649 	free(menu->toolbars_submenu);
650 	free(menu->tools_submenu->developer_submenu);
651 	free(menu->tools_submenu);
652 	free(menu);
653 
654 	return NSERROR_OK;
655 }
656 
657 
658 /* exported function documented in gtk/menu.h */
nsgtk_link_menu_destroy(struct nsgtk_link_menu * menu)659 nserror nsgtk_link_menu_destroy(struct nsgtk_link_menu *menu)
660 {
661 	gtk_widget_destroy(GTK_WIDGET(menu->link_menu));
662 
663 	free(menu);
664 
665 	return NSERROR_OK;
666 }
667