1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2012 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (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
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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <gtk/gtkwidget.h>
27 #include <gtk/gtkmenu.h>
28 #include <gtk/gtkmenubar.h>
29 #include <gtk/gtkcheckmenuitem.h>
30 #include <gtk/gtkitemfactory.h>
31 #include <gtk/gtkbutton.h>
32 #include <gtk/gtkwindow.h>
33 
34 #include "menu.h"
35 #include "utils.h"
36 
37 static gchar *menu_translate(const gchar *path, gpointer data);
38 
menubar_create(GtkWidget * window,GtkItemFactoryEntry * entries,guint n_entries,const gchar * path,gpointer data)39 GtkWidget *menubar_create(GtkWidget *window, GtkItemFactoryEntry *entries,
40 			  guint n_entries, const gchar *path, gpointer data)
41 {
42 	GtkItemFactory *factory;
43 
44 	factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, path, NULL);
45 	gtk_item_factory_set_translate_func(factory, menu_translate,
46 					    NULL, NULL);
47 	gtk_item_factory_create_items(factory, n_entries, entries, data);
48 	gtk_window_add_accel_group(GTK_WINDOW(window), factory->accel_group);
49 
50 	return gtk_item_factory_get_widget(factory, path);
51 }
52 
menu_create_items(GtkItemFactoryEntry * entries,guint n_entries,const gchar * path,GtkItemFactory ** factory,gpointer data)53 GtkWidget *menu_create_items(GtkItemFactoryEntry *entries,
54 			     guint n_entries, const gchar *path,
55 			     GtkItemFactory **factory, gpointer data)
56 {
57 	*factory = gtk_item_factory_new(GTK_TYPE_MENU, path, NULL);
58 	gtk_item_factory_set_translate_func(*factory, menu_translate,
59 					    NULL, NULL);
60 	gtk_item_factory_create_items(*factory, n_entries, entries, data);
61 
62 	return gtk_item_factory_get_widget(*factory, path);
63 }
64 
menu_translate(const gchar * path,gpointer data)65 static gchar *menu_translate(const gchar *path, gpointer data)
66 {
67 	gchar *retval;
68 
69 	retval = gettext(path);
70 
71 	return retval;
72 }
73 
74 #if 0
75 static void factory_print_func(gpointer data, gchar *string)
76 {
77 	GString *out_str = data;
78 
79 	g_string_append(out_str, string);
80 	g_string_append_c(out_str, '\n');
81 }
82 
83 GString *menu_factory_get_rc(const gchar *path)
84 {
85 	GString *string;
86 	GtkPatternSpec *pspec;
87 	gchar pattern[256];
88 
89 	pspec = g_new(GtkPatternSpec, 1);
90 	g_snprintf(pattern, sizeof(pattern), "%s*", path);
91 	gtk_pattern_spec_init(pspec, pattern);
92 	string = g_string_new("");
93 	gtk_item_factory_dump_items(pspec, FALSE, factory_print_func,
94 				    string);
95 	gtk_pattern_spec_free_segs(pspec);
96 
97 	return string;
98 }
99 
100 void menu_factory_clear_rc(const gchar *rc_str)
101 {
102 	GString *string;
103 	gchar *p;
104 	gchar *start, *end;
105 	guint pos = 0;
106 
107 	string = g_string_new(rc_str);
108 	while ((p = strstr(string->str + pos, "(menu-path \"")) != NULL) {
109 		pos = p + 12 - string->str;
110 		p = strchr(p + 12, '"');
111 		if (!p) continue;
112 		start = strchr(p + 1, '"');
113 		if (!start) continue;
114 		end = strchr(start + 1, '"');
115 		if (!end) continue;
116 		pos = start + 1 - string->str;
117 		if (end > start + 1)
118 			g_string_erase(string, pos, end - (start + 1));
119 	}
120 
121 	gtk_item_factory_parse_rc_string(string->str);
122 	g_string_free(string, TRUE);
123 }
124 
125 void menu_factory_copy_rc(const gchar *src_path, const gchar *dest_path)
126 {
127 	GString *string;
128 	gint src_path_len;
129 	gint dest_path_len;
130 	gchar *p;
131 	guint pos = 0;
132 
133 	string = menu_factory_get_rc(src_path);
134 	src_path_len = strlen(src_path);
135 	dest_path_len = strlen(dest_path);
136 
137 	while ((p = strstr(string->str + pos, src_path)) != NULL) {
138 		pos = p - string->str;
139 		g_string_erase(string, pos, src_path_len);
140 		g_string_insert(string, pos, dest_path);
141 		pos += dest_path_len;
142 	}
143 
144 	pos = 0;
145 	while ((p = strchr(string->str + pos, ';')) != NULL) {
146 		pos = p - string->str;
147 		if (pos == 0 || *(p - 1) == '\n')
148 			g_string_erase(string, pos, 1);
149 	}
150 
151 	menu_factory_clear_rc(string->str);
152 	gtk_item_factory_parse_rc_string(string->str);
153 	g_string_free(string, TRUE);
154 }
155 #endif
156 
menu_set_sensitive(GtkItemFactory * ifactory,const gchar * path,gboolean sensitive)157 void menu_set_sensitive(GtkItemFactory *ifactory, const gchar *path,
158 			gboolean sensitive)
159 {
160 	GtkWidget *widget;
161 
162 	g_return_if_fail(ifactory != NULL);
163 
164 	widget = gtk_item_factory_get_item(ifactory, path);
165 	gtk_widget_set_sensitive(widget, sensitive);
166 }
167 
menu_set_sensitive_all(GtkMenuShell * menu_shell,gboolean sensitive)168 void menu_set_sensitive_all(GtkMenuShell *menu_shell, gboolean sensitive)
169 {
170 	GList *cur;
171 
172 	for (cur = menu_shell->children; cur != NULL; cur = cur->next)
173 		gtk_widget_set_sensitive(GTK_WIDGET(cur->data), sensitive);
174 }
175 
menu_set_active(GtkItemFactory * ifactory,const gchar * path,gboolean is_active)176 void menu_set_active(GtkItemFactory *ifactory, const gchar *path,
177 		     gboolean is_active)
178 {
179 	GtkWidget *widget;
180 
181 	g_return_if_fail(ifactory != NULL);
182 
183 	widget = gtk_item_factory_get_item(ifactory, path);
184 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), is_active);
185 }
186 
menu_button_position(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer user_data)187 void menu_button_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
188 			  gpointer user_data)
189 {
190 	GtkWidget *button;
191 	GtkRequisition requisition;
192 	gint button_xpos, button_ypos;
193 	gint xpos, ypos;
194 	gint width, height;
195 	gint scr_width, scr_height;
196 
197 	g_return_if_fail(x != NULL && y != NULL && push_in != NULL);
198 
199 	button = GTK_WIDGET(user_data);
200 
201 	gtk_widget_get_child_requisition(GTK_WIDGET(menu), &requisition);
202 	width = requisition.width;
203 	height = requisition.height;
204 	gdk_window_get_origin(button->window, &button_xpos, &button_ypos);
205 
206 	xpos = button_xpos + button->allocation.x;
207 	ypos = button_ypos + button->allocation.y + button->allocation.height;
208 
209 	scr_width = gdk_screen_width();
210 	scr_height = gdk_screen_height();
211 
212 	if (xpos + width > scr_width)
213 		xpos -= (xpos + width) - scr_width;
214 	if (ypos + height > scr_height)
215 		ypos -= button->allocation.height + height;
216 	if (xpos < 0)
217 		xpos = 0;
218 	if (ypos < 0)
219 		ypos = 0;
220 
221 	*x = xpos;
222 	*y = ypos;
223 	*push_in = FALSE;
224 }
225 
menu_widget_position(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer user_data)226 void menu_widget_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
227 			  gpointer user_data)
228 {
229 	GtkWidget *widget;
230 	GtkRequisition requisition;
231 	gint w_xpos, w_ypos;
232 	gint xpos, ypos;
233 	gint width, height;
234 	gint scr_width, scr_height;
235 
236 	g_return_if_fail(x != NULL && y != NULL && push_in != NULL);
237 
238 	widget = GTK_WIDGET(user_data);
239 
240 	gtk_widget_get_child_requisition(GTK_WIDGET(menu), &requisition);
241 	width = requisition.width;
242 	height = requisition.height;
243 	gdk_window_get_origin(widget->window, &w_xpos, &w_ypos);
244 
245 	xpos = w_xpos;
246 	ypos = w_ypos;
247 
248 	scr_width = gdk_screen_width();
249 	scr_height = gdk_screen_height();
250 
251 	if (xpos + width > scr_width)
252 		xpos -= (xpos + width) - scr_width;
253 	if (ypos + height > scr_height)
254 		ypos -= height;
255 	if (xpos < 0)
256 		xpos = 0;
257 	if (ypos < 0)
258 		ypos = 0;
259 
260 	*x = xpos;
261 	*y = ypos;
262 	*push_in = FALSE;
263 }
264 
menu_find_option_menu_index(GtkOptionMenu * optmenu,gpointer data,GCompareFunc func)265 gint menu_find_option_menu_index(GtkOptionMenu *optmenu, gpointer data,
266 				 GCompareFunc func)
267 {
268 	GtkWidget *menu;
269 	GtkWidget *menuitem;
270 	gpointer menu_data;
271 	GList *cur;
272 	gint n;
273 
274 	menu = gtk_option_menu_get_menu(optmenu);
275 
276 	for (cur = GTK_MENU_SHELL(menu)->children, n = 0;
277 	     cur != NULL; cur = cur->next, n++) {
278 		menuitem = GTK_WIDGET(cur->data);
279 		menu_data = g_object_get_data(G_OBJECT(menuitem), MENU_VAL_ID);
280 		if (func) {
281 			if (func(menu_data, data) == 0)
282 				return n;
283 		} else if (menu_data == data)
284 			return n;
285 	}
286 
287 	return -1;
288 }
289 
menu_get_option_menu_active_index(GtkOptionMenu * optmenu)290 gint menu_get_option_menu_active_index(GtkOptionMenu *optmenu)
291 {
292 	GtkWidget *menu;
293 	GtkWidget *menuitem;
294 
295 	menu = gtk_option_menu_get_menu(optmenu);
296 	menuitem = gtk_menu_get_active(GTK_MENU(menu));
297 
298 	return GPOINTER_TO_INT
299 		(g_object_get_data(G_OBJECT(menuitem), MENU_VAL_ID));
300 }
301