wmweather+: Remove from repository.
[dockapps.git] / wmcliphist / gui.c
blob1ba4eae68e135753811f66e121ce8f0eb0369b78
1 #include "wmcliphist.h"
2 #include <gdk/gdkkeysyms.h>
5 /* color of locked item */
6 gchar locked_color_str[32] = DEF_LOCKED_COLOR;
7 GdkRGBA locked_color;
9 /* Exec on middle click? */
10 int exec_middleclick = 1;
12 /* main window widget */
13 GtkWidget *main_window;
15 /* dock icon widget */
16 GtkWidget *dock_app;
18 /* clipboard history menu */
19 GtkWidget *menu_hist;
20 GtkWidget *menu_title;
21 gint submenu_count = 0;
23 /* application menu */
24 GtkWidget *menu_app;
25 GtkWidget *menu_app_clip_lock;
26 GtkWidget *menu_app_clip_ignore;
27 GtkWidget *menu_app_exit;
28 GtkWidget *menu_app_save;
30 /* button */
31 GtkWidget *button;
33 /* pixmap */
34 GtkWidget *pixmap;
36 /* which clipboard to use */
37 gchar clipboard_str[32] = DEF_CLIPBOARD_STR;
38 GdkAtom clipboard;
40 /* ==========================================================================
41 * clipboard history menu
45 * history menu item button click function
47 static gboolean
48 menu_item_button_released(GtkWidget *widget,
49 GdkEvent *event,
50 gpointer user_data)
52 GdkEventButton *bevent = (GdkEventButton *)event;
53 HISTORY_ITEM *data = user_data;
55 begin_func("menu_item_button_released");
57 /* button 2 or 3 - exec or (un)lock item respectively */
58 if (bevent->button == 2) {
59 if (exec_middleclick) {
60 gtk_menu_popdown(GTK_MENU(menu_hist));
61 exec_item(data->content, NULL);
63 return_val(TRUE);
64 } else if (bevent->button == 3) {
65 if (data->locked == 0) {
67 /* cannot lock all records */
68 if (locked_count == num_items_to_keep - 1) {
69 show_message("There must remain at least one "
70 "unlocked item\nwhen menu is full!",
71 "Warning", "OK", NULL, NULL);
72 return_val(TRUE);
75 gtk_widget_override_color(
76 gtk_bin_get_child(GTK_BIN(data->menu_item)),
77 GTK_STATE_FLAG_NORMAL, &locked_color);
78 data->locked = 1;
79 locked_count++;
81 } else {
82 gtk_widget_override_color(
83 gtk_bin_get_child(GTK_BIN(data->menu_item)),
84 GTK_STATE_FLAG_NORMAL, NULL);
85 data->locked = 0;
86 locked_count--;
88 } else {
89 return_val(FALSE);
92 return_val(TRUE);
97 * history menu item left click or keypress function
99 static gboolean
100 menu_item_activated(GtkWidget *widget, gpointer user_data)
102 move_item_to_begin((HISTORY_ITEM *) user_data);
103 return_val(TRUE);
108 * checks, if there is already such item in menu,
109 * in which case it moves it to the begining
111 HISTORY_ITEM *
112 menu_item_exists(gchar *content, GtkWidget *submenu)
114 HISTORY_ITEM *hist_item;
115 GList *list_node;
117 begin_func("menu_item_exists");
119 list_node = g_list_last(history_items);
120 while (list_node) {
121 hist_item = (HISTORY_ITEM *)list_node->data;
122 if (hist_item->menu == submenu
123 && g_utf8_collate(hist_item->content, content)
124 == 0) {
125 gtk_menu_reorder_child(GTK_MENU(hist_item->menu),
126 hist_item->menu_item, 1);
127 history_items = g_list_remove_link(history_items,
128 list_node);
129 history_items = g_list_concat(list_node, history_items);
131 return_val(hist_item);
133 list_node = g_list_previous(list_node);
136 return_val(NULL);
141 * add new item to menu
143 HISTORY_ITEM *
144 menu_item_add(gchar *content, gint locked, GtkWidget *target_menu)
146 GList *list_node;
147 gint i;
148 gchar *menu_item_name;
149 gchar *fixed_menu_item_name;
150 gsize length;
151 HISTORY_ITEM *hist_item;
153 begin_func("menu_item_add");
155 hist_item = menu_item_exists(content, target_menu);
156 if (hist_item != NULL) {
157 dump_history_list("reorder");
158 return_val(hist_item);
161 if (num_items == num_items_to_keep) {
162 /* max item limit reached, destroy oldest one */
163 list_node = g_list_last(history_items);
164 while (1) {
165 hist_item = (HISTORY_ITEM*)
166 list_node->data;
167 if (hist_item->locked == 0)
168 break;
169 list_node = g_list_previous(list_node);
170 g_assert((list_node != NULL));
173 history_items = g_list_remove_link(history_items, list_node);
174 gtk_container_remove(GTK_CONTAINER(hist_item->menu),
175 hist_item->menu_item);
176 gtk_widget_destroy(hist_item->menu_item);
177 g_free(hist_item->content);
178 g_free(hist_item);
179 g_list_free_1(list_node);
180 num_items--;
181 dump_history_list("remove oldest");
184 /* prepare menu item name */
185 menu_item_name = g_new0(char, MAX_ITEM_LENGTH * 2 + 1);
186 memset(menu_item_name, 0, MAX_ITEM_LENGTH * 2 + 1);
187 length = g_utf8_strlen(content, -1);
188 if (length > (size_t) (MAX_ITEM_LENGTH)) {
189 g_utf8_strncpy(menu_item_name, content, MAX_ITEM_LENGTH - 4);
190 strcat(menu_item_name, "...");
191 } else {
192 strcpy(menu_item_name, content);
195 /* do some menu item name cleanups */
196 fixed_menu_item_name = g_new0(char, strlen(menu_item_name) + 1);
197 for (i = 0; i < g_utf8_strlen(menu_item_name, -1); i++) {
198 gchar *uchar_ptr = g_utf8_offset_to_pointer(menu_item_name, i);
199 gunichar uchar = g_utf8_get_char(uchar_ptr);
200 if (g_unichar_isprint(uchar)) {
201 gchar *decoded_char = g_ucs4_to_utf8(&uchar, 1, NULL,
202 NULL, NULL);
203 strcat(fixed_menu_item_name, decoded_char);
204 g_free(decoded_char);
205 } else {
206 strcat(fixed_menu_item_name, "_");
209 g_free(menu_item_name);
210 menu_item_name = fixed_menu_item_name;
212 /* create menu item */
213 hist_item = g_new0(HISTORY_ITEM, 1);
214 hist_item->menu_item = gtk_menu_item_new_with_label(menu_item_name);
215 hist_item->content = g_strdup(content);
216 hist_item->locked = locked;
217 hist_item->menu = target_menu;
219 if (locked == 1) {
220 gtk_widget_override_color(
221 gtk_bin_get_child(GTK_BIN(hist_item->menu_item)),
222 GTK_STATE_FLAG_NORMAL, &locked_color);
223 locked_count++;
226 /* add to menu */
227 gtk_menu_shell_insert(GTK_MENU_SHELL(hist_item->menu), hist_item->menu_item, 1);
230 /* connect actions to signals */
231 g_signal_connect(G_OBJECT(hist_item->menu_item),
232 "button-release-event",
233 G_CALLBACK(menu_item_button_released),
234 (gpointer)hist_item);
236 g_signal_connect(G_OBJECT(hist_item->menu_item),
237 "activate",
238 G_CALLBACK(menu_item_activated),
239 (gpointer)hist_item);
241 gtk_widget_show(hist_item->menu_item);
243 history_items = g_list_insert(history_items, hist_item, 0);
245 num_items++;
247 return_val(hist_item);
252 /* ==========================================================================
253 * application menu
257 * application main menu handler
259 gboolean
260 menu_app_item_click(GtkWidget *menuitem, gpointer data)
262 gint button;
264 begin_func("menu_app_item_click");
266 switch (GPOINTER_TO_INT(data)) {
267 /* save history menu */
268 case 0:
269 if (history_save() != 0) {
270 button = show_message("History was NOT saved.\n",
271 "Warning", "OK", NULL, NULL);
273 return_val(TRUE);
275 /* exit menu */
276 case 1:
277 if (history_save() != 0) {
278 button = show_message("History was NOT saved.\n"
279 "Do you really want to exit?",
280 "Error", "Yes", "No", NULL);
281 if (button != 0)
282 return_val(TRUE);
284 history_free();
285 rcconfig_free();
287 exit(0);
288 return_val(TRUE);
290 return_val(FALSE);
295 /* ==========================================================================
296 * dock button press
300 * dock button click response
302 gboolean
303 button_press(GtkWidget *widget, GdkEvent *event, gpointer data)
305 begin_func("button_press");
307 if (event->type == GDK_BUTTON_PRESS) {
308 GdkEventButton *bevent = (GdkEventButton *)event;
310 switch (bevent->button) {
311 case 1:
312 /* popup history menu */
313 gtk_menu_popup(GTK_MENU(menu_hist),
314 NULL, NULL,
315 NULL, NULL,
316 bevent->button,
317 bevent->time);
318 return_val(TRUE);
320 case 3:
321 /* popup application menu */
322 gtk_menu_popup(GTK_MENU(menu_app),
323 NULL, NULL,
324 NULL, NULL,
325 bevent->button,
326 bevent->time);
327 return_val(TRUE);
331 return_val(FALSE);
336 /* ==========================================================================
337 * message dialogs
340 static GMainLoop *loop;
341 static gint button_pressed;
344 static gboolean
345 dialog_button_press(GtkWidget *button, gpointer data)
347 begin_func("dialog_button_press");
349 button_pressed = GPOINTER_TO_INT(data);
350 g_main_quit(loop);
352 return_val(TRUE);
357 static gboolean
358 dialog_handle_key_press_event(GdkEventKey *event, gpointer data, guint key)
360 if(event->type != GDK_KEY_PRESS)
361 return_val(FALSE);
362 if(event->keyval != key)
363 return_val(FALSE);
364 button_pressed = GPOINTER_TO_INT(data);
365 g_main_quit(loop);
367 return_val(TRUE);
372 static gboolean
373 dialog_key_press_yes(GtkWidget *button, GdkEventKey *event, gpointer data)
375 begin_func("dialog_key_press_yes");
376 return dialog_handle_key_press_event(event, data, GDK_KEY_Return);
381 static gboolean
382 dialog_key_press_no(GtkWidget *button, GdkEventKey *event, gpointer data)
384 begin_func("dialog_key_press_no");
385 return dialog_handle_key_press_event(event, data, GDK_KEY_Escape);
391 * open dialog with specified message andbuttons
392 * and return number of button pressed
394 gint
395 show_message(gchar *message, char *title,
396 char *b0_text, char *b1_text, char *b2_text)
398 GtkWidget *dialog,
399 *label,
400 *button_0,
401 *button_1,
402 *button_2;
404 begin_func("show_message");
406 /* create the main widgets */
407 dialog = gtk_dialog_new();
408 label = gtk_label_new(message);
410 /* create buttons and set signals */
411 gtk_dialog_add_button(GTK_DIALOG(dialog), b0_text, 0);
412 button_0 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 0);
413 g_signal_connect(G_OBJECT(button_0), "clicked",
414 G_CALLBACK(dialog_button_press),
415 GINT_TO_POINTER(0));
416 if (!b2_text) {
417 g_signal_connect(G_OBJECT(dialog), "key-press-event",
418 G_CALLBACK(dialog_key_press_yes),
419 GINT_TO_POINTER(0));
422 if (b1_text != NULL) {
423 gtk_dialog_add_button(GTK_DIALOG(dialog), b1_text, 1);
424 button_1 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 1);
425 g_signal_connect(G_OBJECT(button_1), "clicked",
426 G_CALLBACK(dialog_button_press),
427 GINT_TO_POINTER(1));
428 if (!b2_text) {
429 g_signal_connect(G_OBJECT(dialog), "key-press-event",
430 G_CALLBACK(dialog_key_press_no),
431 GINT_TO_POINTER(1));
435 if (b2_text) {
436 gtk_dialog_add_button(GTK_DIALOG(dialog), b2_text, 2);
437 button_2 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 2);
438 g_signal_connect(G_OBJECT(button_2), "clicked",
439 G_CALLBACK(dialog_button_press),
440 GINT_TO_POINTER(2));
443 /* add the label, and show everything we've added to the dialog. */
444 gtk_misc_set_padding(&GTK_LABEL(label)->misc, 10, 10);
445 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label);
446 gtk_widget_show_all(dialog);
448 /* set window title */
449 gtk_window_set_title(GTK_WINDOW(dialog), title);
451 loop = g_main_new(FALSE);
452 g_main_run(loop);
453 g_main_destroy(loop);
454 gtk_widget_destroy(dialog);
456 return_val(button_pressed);