2 * Copyright (C) 2004 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program 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; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 *-----------------------------------------------------------------------------
39 *-----------------------------------------------------------------------------
43 * @brief Add accelerator key to a window popup menu
48 * This is used only so that the user can see the applicable
49 * shortcut key displayed in the menu. The actual handling of
50 * the keystroke is done elsewhere in the code.
52 static void menu_item_add_accelerator(GtkWidget *menu, GtkAccelGroup *accel_group, hard_coded_window_keys *window_keys)
56 gchar **label_stripped;
59 label = g_strdup(gtk_menu_item_get_label(GTK_MENU_ITEM(menu)));
61 pango_parse_markup(label, -1, '_', NULL, &label_text, NULL, NULL);
63 label_stripped = g_strsplit(label_text, "...", 2);
65 while (window_keys[i].text != NULL)
67 if (g_strcmp0(window_keys[i].text, label_stripped[0]) == 0)
69 gtk_widget_add_accelerator(menu, "activate", accel_group, window_keys[i].key_value, (GdkModifierType)window_keys[i].mask, GTK_ACCEL_VISIBLE);
78 g_strfreev(label_stripped);
82 * @brief Callback for the actions GList sort function
87 * Sort the action entries so that the non-shifted and non-control
88 * entries are at the start of the list. The user then sees the basic
89 * non-modified key shortcuts displayed in the menus.
91 static gint actions_sort_cb(gconstpointer a, gconstpointer b)
93 const gchar *accel_path_a;
95 const gchar *accel_path_b;
98 accel_path_a = gtk_action_get_accel_path(GTK_ACTION(a));
99 accel_path_b = gtk_action_get_accel_path(GTK_ACTION(b));
101 if (accel_path_a && gtk_accel_map_lookup_entry(accel_path_a, &key_a) && accel_path_b && gtk_accel_map_lookup_entry(accel_path_b, &key_b))
103 if (key_a.accel_mods < key_b.accel_mods) return -1;
104 if (key_a.accel_mods > key_b.accel_mods) return 1;
111 * @brief Add accelerator key to main window popup menu
115 * This is used only so that the user can see the applicable
116 * shortcut key displayed in the menu. The actual handling of
117 * the keystroke is done elsewhere in the code.
119 static void menu_item_add_main_window_accelerator(GtkWidget *menu, GtkAccelGroup *accel_group)
122 gchar *menu_label_text;
124 gchar *action_label_text;
129 const gchar *accel_path;
132 menu_label = g_strdup(gtk_menu_item_get_label(GTK_MENU_ITEM(menu)));
134 pango_parse_markup(menu_label, -1, '_', NULL, &menu_label_text, NULL, NULL);
136 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
138 g_assert(lw && lw->ui_manager);
139 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
143 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
144 actions = g_list_sort(actions, actions_sort_cb);
148 action = GTK_ACTION(actions->data);
149 accel_path = gtk_action_get_accel_path(action);
150 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
152 g_object_get(action, "label", &action_label, NULL);
154 pango_parse_markup(action_label, -1, '_', NULL, &action_label_text, NULL, NULL);
156 if (g_strcmp0(action_label_text, menu_label_text) == 0)
158 if (key.accel_key != 0)
160 gtk_widget_add_accelerator(menu, "activate", accel_group, key.accel_key, key.accel_mods, GTK_ACCEL_VISIBLE);
165 g_free(action_label_text);
166 g_free(action_label);
168 actions = actions->next;
170 groups = groups->next;
174 g_free(menu_label_text);
177 static void menu_item_finish(GtkWidget *menu, GtkWidget *item, GCallback func, gpointer data)
179 if (func) g_signal_connect(G_OBJECT(item), "activate", func, data);
180 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
181 gtk_widget_show(item);
184 GtkWidget *menu_item_add(GtkWidget *menu, const gchar *label,
185 GCallback func, gpointer data)
188 GtkAccelGroup *accel_group;
189 hard_coded_window_keys *window_keys;
191 item = gtk_menu_item_new_with_mnemonic(label);
192 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
193 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
195 if (accel_group && window_keys)
197 menu_item_add_accelerator(item, accel_group, window_keys);
199 else if (accel_group)
201 menu_item_add_main_window_accelerator(item, accel_group);
204 menu_item_finish(menu, item, func, data);
209 GtkWidget *menu_item_add_stock(GtkWidget *menu, const gchar *label, const gchar *stock_id,
210 GCallback func, gpointer data)
214 GtkAccelGroup *accel_group;
215 hard_coded_window_keys *window_keys;
217 item = gtk_image_menu_item_new_with_mnemonic(label);
218 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
219 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
221 image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU);
222 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
224 if (accel_group && window_keys)
226 menu_item_add_accelerator(item, accel_group, window_keys);
228 else if (accel_group)
230 menu_item_add_main_window_accelerator(item, accel_group);
233 gtk_widget_show(image);
234 menu_item_finish(menu, item, func, data);
239 GtkWidget *menu_item_add_sensitive(GtkWidget *menu, const gchar *label, gboolean sensitive,
240 GCallback func, gpointer data)
243 GtkAccelGroup *accel_group;
244 hard_coded_window_keys *window_keys;
246 item = menu_item_add(menu, label, func, data);
247 gtk_widget_set_sensitive(item, sensitive);
248 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
249 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
250 if (accel_group && window_keys)
252 menu_item_add_accelerator(item, accel_group, window_keys);
254 else if (accel_group)
256 menu_item_add_main_window_accelerator(item, accel_group);
262 GtkWidget *menu_item_add_stock_sensitive(GtkWidget *menu, const gchar *label, const gchar *stock_id, gboolean sensitive,
263 GCallback func, gpointer data)
266 GtkAccelGroup *accel_group;
267 hard_coded_window_keys *window_keys;
269 item = menu_item_add_stock(menu, label, stock_id, func, data);
270 gtk_widget_set_sensitive(item, sensitive);
271 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
272 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
273 if (accel_group && window_keys)
275 menu_item_add_accelerator(item, accel_group, window_keys);
277 else if (accel_group)
279 menu_item_add_main_window_accelerator(item, accel_group);
285 GtkWidget *menu_item_add_check(GtkWidget *menu, const gchar *label, gboolean active,
286 GCallback func, gpointer data)
289 GtkAccelGroup *accel_group;
290 hard_coded_window_keys *window_keys;
292 item = gtk_check_menu_item_new_with_mnemonic(label);
293 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
294 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
296 if (accel_group && window_keys)
298 menu_item_add_accelerator(item, accel_group, window_keys);
300 else if (accel_group)
302 menu_item_add_main_window_accelerator(item, accel_group);
305 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
306 menu_item_finish(menu, item, func, data);
311 GtkWidget *menu_item_add_radio(GtkWidget *menu, const gchar *label, gpointer item_data, gboolean active,
312 GCallback func, gpointer data)
314 GtkAccelGroup *accel_group;
315 hard_coded_window_keys *window_keys;
317 GtkWidget *item = menu_item_add_check(menu, label, active, func, data);
318 g_object_set_data(G_OBJECT(item), "menu_item_radio_data", item_data);
319 g_object_set(G_OBJECT(item), "draw-as-radio", TRUE, NULL);
321 window_keys = g_object_get_data(G_OBJECT(menu), "window_keys");
322 accel_group = g_object_get_data(G_OBJECT(menu), "accel_group");
323 if (accel_group && window_keys)
325 menu_item_add_accelerator(item, accel_group, window_keys);
327 else if (accel_group)
329 menu_item_add_main_window_accelerator(item, accel_group);
335 void menu_item_add_divider(GtkWidget *menu)
337 GtkWidget *item = gtk_separator_menu_item_new();
338 gtk_widget_set_sensitive(item, FALSE);
339 gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
340 gtk_widget_show(item);
343 GtkWidget *menu_item_add_simple(GtkWidget *menu, const gchar *label,
344 GCallback func, gpointer data)
346 GtkWidget *item = gtk_menu_item_new_with_label(label);
347 menu_item_finish(menu, item, func, data);
353 *-----------------------------------------------------------------------------
355 *-----------------------------------------------------------------------------
358 static void popup_menu_short_lived_cb(GtkWidget *UNUSED(widget), gpointer data)
360 /* destroy the menu */
361 g_object_unref(G_OBJECT(data));
364 GtkWidget *popup_menu_short_lived(void)
368 menu = gtk_menu_new();
370 /* take ownership of menu */
371 #ifdef GTK_OBJECT_FLOATING
373 g_object_ref(G_OBJECT(menu));
374 gtk_object_sink(GTK_OBJECT(menu));
377 g_object_ref_sink(G_OBJECT(menu));
380 g_signal_connect(G_OBJECT(menu), "selection_done",
381 G_CALLBACK(popup_menu_short_lived_cb), menu);
385 gboolean popup_menu_position_clamp(GtkMenu *menu, gint *x, gint *y, gint height)
387 gboolean adjusted = FALSE;
390 GtkRequisition requisition;
392 gtk_widget_get_requisition(GTK_WIDGET(menu), &requisition);
393 w = requisition.width;
394 h = requisition.height;
395 xw = gdk_screen_width();
396 xh = gdk_screen_height();
407 *y = MAX(0, *y - h - height);
429 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */