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.
26 #include <pango/pango.h>
32 *-----------------------------------------------------------------------------
34 *-----------------------------------------------------------------------------
38 * @brief Add accelerator key to a window popup menu
43 * This is used only so that the user can see the applicable
44 * shortcut key displayed in the menu. The actual handling of
45 * the keystroke is done elsewhere in the code.
47 static void menu_item_add_accelerator(GtkWidget *menu, GtkAccelGroup *accel_group, hard_coded_window_keys *window_keys)
51 gchar **label_stripped;
54 label = g_strdup(gtk_menu_item_get_label(GTK_MENU_ITEM(menu)));
56 pango_parse_markup(label, -1, '_', nullptr, &label_text, nullptr, nullptr);
58 label_stripped = g_strsplit(label_text, "...", 2);
60 while (window_keys[i].text != nullptr)
62 if (g_strcmp0(window_keys[i].text, label_stripped[0]) == 0)
64 gtk_widget_add_accelerator(menu, "activate", accel_group, window_keys[i].key_value, window_keys[i].mask, GTK_ACCEL_VISIBLE);
73 g_strfreev(label_stripped);
77 * @brief Callback for the actions GList sort function
82 * Sort the action entries so that the non-shifted and non-control
83 * entries are at the start of the list. The user then sees the basic
84 * non-modified key shortcuts displayed in the menus.
86 static gint actions_sort_cb(gconstpointer a, gconstpointer b)
88 const gchar *accel_path_a;
90 const gchar *accel_path_b;
93 accel_path_a = gq_gtk_action_get_accel_path(GTK_ACTION(a));
94 accel_path_b = gq_gtk_action_get_accel_path(GTK_ACTION(b));
96 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))
98 if (key_a.accel_mods < key_b.accel_mods) return -1;
99 if (key_a.accel_mods > key_b.accel_mods) return 1;
106 * @brief Add accelerator key to main window popup menu
110 * This is used only so that the user can see the applicable
111 * shortcut key displayed in the menu. The actual handling of
112 * the keystroke is done elsewhere in the code.
114 static void menu_item_add_main_window_accelerator(GtkWidget *menu, GtkAccelGroup *accel_group)
117 gchar *menu_label_text;
119 gchar *action_label_text;
124 const gchar *accel_path;
127 menu_label = g_strdup(gtk_menu_item_get_label(GTK_MENU_ITEM(menu)));
129 pango_parse_markup(menu_label, -1, '_', nullptr, &menu_label_text, nullptr, nullptr);
131 lw = static_cast<LayoutWindow *>(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */
133 g_assert(lw && lw->ui_manager);
134 groups = gq_gtk_ui_manager_get_action_groups(lw->ui_manager);
138 actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
139 actions = g_list_sort(actions, actions_sort_cb);
143 action = GTK_ACTION(actions->data);
144 accel_path = gq_gtk_action_get_accel_path(action);
145 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
147 g_object_get(action, "label", &action_label, NULL);
149 pango_parse_markup(action_label, -1, '_', nullptr, &action_label_text, nullptr, nullptr);
151 if (g_strcmp0(action_label_text, menu_label_text) == 0)
153 if (key.accel_key != 0)
155 gtk_widget_add_accelerator(menu, "activate", accel_group, key.accel_key, key.accel_mods, GTK_ACCEL_VISIBLE);
160 g_free(action_label_text);
161 g_free(action_label);
163 actions = actions->next;
165 groups = groups->next;
169 g_free(menu_label_text);
172 static void menu_item_finish(GtkWidget *menu, GtkWidget *item, GCallback func, gpointer data)
174 if (func) g_signal_connect(G_OBJECT(item), "activate", func, data);
175 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
176 gtk_widget_show(item);
179 GtkWidget *menu_item_add(GtkWidget *menu, const gchar *label,
180 GCallback func, gpointer data)
183 GtkAccelGroup *accel_group;
184 hard_coded_window_keys *window_keys;
186 item = gtk_menu_item_new_with_mnemonic(label);
187 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
188 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
190 if (accel_group && window_keys)
192 menu_item_add_accelerator(item, accel_group, window_keys);
194 else if (accel_group)
196 menu_item_add_main_window_accelerator(item, accel_group);
199 menu_item_finish(menu, item, func, data);
204 GtkWidget *menu_item_add_stock(GtkWidget *menu, const gchar *label, const gchar *stock_id,
205 GCallback func, gpointer data)
209 GtkAccelGroup *accel_group;
210 hard_coded_window_keys *window_keys;
212 item = gtk_image_menu_item_new_with_mnemonic(label);
213 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
214 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
216 image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU);
217 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
219 if (accel_group && window_keys)
221 menu_item_add_accelerator(item, accel_group, window_keys);
223 else if (accel_group)
225 menu_item_add_main_window_accelerator(item, accel_group);
228 gtk_widget_show(image);
229 menu_item_finish(menu, item, func, data);
234 GtkWidget *menu_item_add_icon(GtkWidget *menu, const gchar *label, const gchar *icon_name,
235 GCallback func, gpointer data)
239 GtkAccelGroup *accel_group;
240 hard_coded_window_keys *window_keys;
242 item = gtk_image_menu_item_new_with_mnemonic(label);
243 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
244 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
246 image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_MENU);
247 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
249 if (accel_group && window_keys)
251 menu_item_add_accelerator(item, accel_group, window_keys);
253 else if (accel_group)
255 menu_item_add_main_window_accelerator(item, accel_group);
258 gtk_widget_show(image);
259 menu_item_finish(menu, item, func, data);
264 GtkWidget *menu_item_add_sensitive(GtkWidget *menu, const gchar *label, gboolean sensitive,
265 GCallback func, gpointer data)
268 GtkAccelGroup *accel_group;
269 hard_coded_window_keys *window_keys;
271 item = menu_item_add(menu, label, func, data);
272 gtk_widget_set_sensitive(item, sensitive);
273 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
274 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
275 if (accel_group && window_keys)
277 menu_item_add_accelerator(item, accel_group, window_keys);
279 else if (accel_group)
281 menu_item_add_main_window_accelerator(item, accel_group);
287 GtkWidget *menu_item_add_stock_sensitive(GtkWidget *menu, const gchar *label, const gchar *stock_id, gboolean sensitive,
288 GCallback func, gpointer data)
291 GtkAccelGroup *accel_group;
292 hard_coded_window_keys *window_keys;
294 item = menu_item_add_stock(menu, label, stock_id, func, data);
295 gtk_widget_set_sensitive(item, sensitive);
296 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
297 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
298 if (accel_group && window_keys)
300 menu_item_add_accelerator(item, accel_group, window_keys);
302 else if (accel_group)
304 menu_item_add_main_window_accelerator(item, accel_group);
310 GtkWidget *menu_item_add_icon_sensitive(GtkWidget *menu, const gchar *label, const gchar *icon_name, gboolean sensitive,
311 GCallback func, gpointer data)
314 GtkAccelGroup *accel_group;
315 hard_coded_window_keys *window_keys;
317 item = menu_item_add_icon(menu, label, icon_name, func, data);
318 gtk_widget_set_sensitive(item, sensitive);
319 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
320 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
321 if (accel_group && window_keys)
323 menu_item_add_accelerator(item, accel_group, window_keys);
325 else if (accel_group)
327 menu_item_add_main_window_accelerator(item, accel_group);
333 GtkWidget *menu_item_add_check(GtkWidget *menu, const gchar *label, gboolean active,
334 GCallback func, gpointer data)
337 GtkAccelGroup *accel_group;
338 hard_coded_window_keys *window_keys;
340 item = gtk_check_menu_item_new_with_mnemonic(label);
341 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
342 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
344 if (accel_group && window_keys)
346 menu_item_add_accelerator(item, accel_group, window_keys);
348 else if (accel_group)
350 menu_item_add_main_window_accelerator(item, accel_group);
353 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
354 menu_item_finish(menu, item, func, data);
359 GtkWidget *menu_item_add_radio(GtkWidget *menu, const gchar *label, gpointer item_data, gboolean active,
360 GCallback func, gpointer data)
362 GtkAccelGroup *accel_group;
363 hard_coded_window_keys *window_keys;
365 GtkWidget *item = menu_item_add_check(menu, label, active, func, data);
366 g_object_set_data(G_OBJECT(item), "menu_item_radio_data", item_data);
367 g_object_set(G_OBJECT(item), "draw-as-radio", TRUE, NULL);
369 window_keys = static_cast<hard_coded_window_keys *>(g_object_get_data(G_OBJECT(menu), "window_keys"));
370 accel_group = static_cast<GtkAccelGroup *>(g_object_get_data(G_OBJECT(menu), "accel_group"));
371 if (accel_group && window_keys)
373 menu_item_add_accelerator(item, accel_group, window_keys);
375 else if (accel_group)
377 menu_item_add_main_window_accelerator(item, accel_group);
383 void menu_item_add_divider(GtkWidget *menu)
385 GtkWidget *item = gtk_separator_menu_item_new();
386 gtk_widget_set_sensitive(item, FALSE);
387 gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
388 gtk_widget_show(item);
391 GtkWidget *menu_item_add_simple(GtkWidget *menu, const gchar *label,
392 GCallback func, gpointer data)
394 GtkWidget *item = gtk_menu_item_new_with_label(label);
395 menu_item_finish(menu, item, func, data);
401 *-----------------------------------------------------------------------------
403 *-----------------------------------------------------------------------------
406 static void popup_menu_short_lived_cb(GtkWidget *, gpointer data)
408 /* destroy the menu */
409 g_object_unref(G_OBJECT(data));
412 GtkWidget *popup_menu_short_lived()
416 menu = gtk_menu_new();
418 /* take ownership of menu */
419 g_object_ref_sink(G_OBJECT(menu));
421 g_signal_connect(G_OBJECT(menu), "selection_done",
422 G_CALLBACK(popup_menu_short_lived_cb), menu);
426 // @todo Used only in vd_menu_position_cb_unused(). Remove?
427 gboolean popup_menu_position_clamp(GtkMenu *menu, gint *x, gint *y, gint height)
429 gboolean adjusted = FALSE;
434 GtkRequisition requisition;
436 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
437 gtk_widget_get_requisition(GTK_WIDGET(menu), &requisition);
438 w = requisition.width;
439 h = requisition.height;
440 xw = gdk_screen_width();
441 xh = gdk_screen_height();
442 G_GNUC_END_IGNORE_DEPRECATIONS;
453 *y = MAX(0, *y - h - height);
475 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */