Merge branch 'stable' into 'main'
[ladish.git] / gui / dynmenu.c
blobc96a7579a236f7f8858bf48917cca49947fae3c6
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains dynamic menu related code
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "dynmenu.h"
28 #include "gtk_builder.h"
29 #include "../common/catdup.h"
31 struct ladish_dynmenu
33 int count;
34 GtkWidget * menu_item;
35 GtkWidget * menu;
36 bool
37 (* fill_callback)(
38 void
39 (* callback)(
40 void * context,
41 const char * name,
42 void * data,
43 ladish_dynmenu_item_activate_callback item_activate_callback,
44 void (* data_free)()),
45 void * context);
46 ladish_dynmenu_item_activate_callback item_activate_callback;
47 bool add_sensitive;
48 gulong activate_signal_id;
49 char * description;
52 struct ladish_dynmenu_item_data
54 GtkWidget * item;
55 void * data;
56 void (* data_free)();
57 ladish_dynmenu_item_activate_callback item_activate_callback;
60 void on_activate_item(GtkMenuItem * UNUSED(item), struct ladish_dynmenu_item_data * data_ptr)
62 //log_info("on_activate_item('%s')", gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(data_ptr->item)))));
64 data_ptr->item_activate_callback(
65 gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(data_ptr->item)))),
66 data_ptr->data);
69 #define data_ptr ((struct ladish_dynmenu_item_data *)data)
71 void free_item_data(gpointer data, GClosure * UNUSED(closure))
73 //log_info("data_ptr %p deallocate", data_ptr);
75 if (data_ptr->data != NULL)
77 if (data_ptr->data_free != NULL)
79 data_ptr->data_free(data_ptr->data);
81 else
83 free(data_ptr->data);
87 free(data_ptr);
90 #undef data_ptr
91 #define dynmenu_ptr ((struct ladish_dynmenu *)context)
93 static
94 void
95 ladish_dynmenu_add_entry(
96 void * context,
97 const char * name,
98 void * data,
99 ladish_dynmenu_item_activate_callback item_activate_callback,
100 void (* data_free)())
102 struct ladish_dynmenu_item_data * data_ptr;
103 GtkWidget * item;
105 if (name == NULL)
107 /* add separator */
108 ASSERT(data == NULL);
109 ASSERT(item_activate_callback == NULL);
110 ASSERT(data_free == NULL);
111 item = gtk_separator_menu_item_new();
112 gtk_widget_show(item);
113 gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), item);
115 else
117 data_ptr = malloc(sizeof(struct ladish_dynmenu_item_data));
118 if (data_ptr == NULL)
120 log_error("Allocation of memory for dynmenu item data struct failed.");
121 return;
124 //log_info("data_ptr %p allocated", data_ptr);
125 data_ptr->data = data;
126 data_ptr->data_free = data_free;
127 data_ptr->item_activate_callback = item_activate_callback != NULL ? item_activate_callback : dynmenu_ptr->item_activate_callback;
129 data_ptr->item = gtk_menu_item_new_with_label(name);
130 //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label
131 gtk_widget_set_sensitive(data_ptr->item, dynmenu_ptr->add_sensitive);
132 gtk_widget_show(data_ptr->item);
133 gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item);
134 g_signal_connect_data(
135 G_OBJECT(data_ptr->item),
136 "activate",
137 G_CALLBACK(on_activate_item),
138 data_ptr,
139 free_item_data,
140 (GConnectFlags)0);
143 dynmenu_ptr->count++;
146 static void remove_dynmenu_menu_entry(GtkWidget * item, gpointer context)
148 GtkWidget * label;
150 label = gtk_bin_get_child(GTK_BIN(item));
152 //log_debug("removing dynmenu item \"%s\"", gtk_menu_item_get_label(GTK_MENU_ITEM(item));
153 // gtk_menu_item_get_label() requries gtk 2.16
154 log_debug("removing dynmenu item \"%s\"", gtk_label_get_text(GTK_LABEL(label)));
156 gtk_container_remove(GTK_CONTAINER(item), label); /* destroy the label and drop the item refcount by one */
157 //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count);
158 gtk_container_remove(GTK_CONTAINER(dynmenu_ptr->menu), item); /* drop the refcount of item by one and thus destroy it */
159 dynmenu_ptr->count--;
162 #undef dynmenu_ptr
164 static void menu_dynmenu_clear(struct ladish_dynmenu * dynmenu_ptr)
166 gtk_container_foreach(GTK_CONTAINER(dynmenu_ptr->menu), remove_dynmenu_menu_entry, dynmenu_ptr);
167 ASSERT(dynmenu_ptr->count == 0);
168 dynmenu_ptr->count = 0;
171 static void populate_dynmenu_menu(GtkMenuItem * menu_item, struct ladish_dynmenu * dynmenu_ptr)
173 const char * prefix;
174 char * text;
176 if (!gtk_widget_get_sensitive(GTK_WIDGET(menu_item)))
178 return;
181 menu_dynmenu_clear(dynmenu_ptr);
182 dynmenu_ptr->add_sensitive = true;
183 if (!dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr))
185 menu_dynmenu_clear(dynmenu_ptr);
186 prefix = _("Error filling ");
188 else if (dynmenu_ptr->count == 0)
190 prefix = _("Empty ");
192 else
194 return;
197 text = catdup(prefix, dynmenu_ptr->description);
199 dynmenu_ptr->add_sensitive = false;
200 ladish_dynmenu_add_entry(dynmenu_ptr, text != NULL ? text : prefix, NULL, NULL, NULL);
202 free(text); /* free(NULL) is safe */
205 bool
206 ladish_dynmenu_create(
207 const char * menu_item,
208 const char * menu,
209 bool
210 (* fill_callback)(
211 void
212 (* callback)(
213 void * context,
214 const char * name,
215 void * data,
216 ladish_dynmenu_item_activate_callback item_activate_callback,
217 void (* data_free)()),
218 void * context),
219 const char * description,
220 ladish_dynmenu_item_activate_callback item_activate_callback,
221 ladish_dynmenu_handle * dynmenu_handle_ptr)
223 struct ladish_dynmenu * dynmenu_ptr;
225 dynmenu_ptr = malloc(sizeof(struct ladish_dynmenu));
226 if (dynmenu_ptr == NULL)
228 log_error("Allocation of ladish_dynmenu struct failed");
229 return false;
232 dynmenu_ptr->description = strdup(description);
233 if (dynmenu_ptr->description == NULL)
235 log_error("strdup('%s') failed for dynmenu description string", description);
236 free(dynmenu_ptr);
237 return false;
240 dynmenu_ptr->count = 0;
241 dynmenu_ptr->menu_item = get_gtk_builder_widget(menu_item);
242 dynmenu_ptr->menu = get_gtk_builder_widget(menu);
243 dynmenu_ptr->fill_callback = fill_callback;
244 dynmenu_ptr->item_activate_callback = item_activate_callback;
245 gtk_menu_item_set_submenu(GTK_MENU_ITEM(dynmenu_ptr->menu_item), dynmenu_ptr->menu);
246 dynmenu_ptr->activate_signal_id = g_signal_connect(G_OBJECT(dynmenu_ptr->menu_item), "activate", G_CALLBACK(populate_dynmenu_menu), dynmenu_ptr);
248 *dynmenu_handle_ptr = (ladish_dynmenu_handle)dynmenu_ptr;
249 return true;
252 #define dynmenu_ptr ((struct ladish_dynmenu *)dynmenu_handle)
254 void
255 ladish_dynmenu_fill_external(
256 ladish_dynmenu_handle dynmenu_handle,
257 GtkMenu * menu)
259 GtkWidget * menu_backup;
260 int count_backup;
262 menu_backup = dynmenu_ptr->menu;
263 count_backup = dynmenu_ptr->count;
265 dynmenu_ptr->menu = GTK_WIDGET(menu);
266 dynmenu_ptr->add_sensitive = true;
268 dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr);
270 dynmenu_ptr->menu = menu_backup;
271 dynmenu_ptr->count = count_backup;
274 void
275 ladish_dynmenu_destroy(
276 ladish_dynmenu_handle dynmenu_handle)
278 if (g_signal_handler_is_connected(G_OBJECT(dynmenu_ptr->menu_item), dynmenu_ptr->activate_signal_id))
280 g_signal_handler_disconnect(G_OBJECT(dynmenu_ptr->menu_item), dynmenu_ptr->activate_signal_id);
283 free(dynmenu_ptr->description);
284 free(dynmenu_ptr);
287 #undef dynmenu_ptr