2014-11-23 02:48:41 +00:00
|
|
|
#include "wmcliphist.h"
|
2014-11-23 02:48:37 +00:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* color of locked item */
|
|
|
|
gchar locked_color_str[32] = DEF_LOCKED_COLOR;
|
2014-11-23 02:48:47 +00:00
|
|
|
GdkRGBA locked_color;
|
2014-11-23 02:48:37 +00:00
|
|
|
|
|
|
|
/* Exec on middle click? */
|
|
|
|
int exec_middleclick = 1;
|
|
|
|
|
|
|
|
/* main window widget */
|
|
|
|
GtkWidget *main_window;
|
|
|
|
|
|
|
|
/* dock icon widget */
|
|
|
|
GtkWidget *dock_app;
|
|
|
|
|
|
|
|
/* clipboard history menu */
|
|
|
|
GtkWidget *menu_hist;
|
|
|
|
GtkWidget *menu_title;
|
|
|
|
gint submenu_count = 0;
|
|
|
|
|
|
|
|
/* application menu */
|
|
|
|
GtkWidget *menu_app;
|
|
|
|
GtkWidget *menu_app_clip_lock;
|
|
|
|
GtkWidget *menu_app_clip_ignore;
|
|
|
|
GtkWidget *menu_app_exit;
|
|
|
|
GtkWidget *menu_app_save;
|
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
/* event box */
|
|
|
|
GtkWidget *event;
|
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* button */
|
|
|
|
GtkWidget *button;
|
|
|
|
|
|
|
|
/* pixmap */
|
|
|
|
GtkWidget *pixmap;
|
|
|
|
|
2014-11-23 02:48:52 +00:00
|
|
|
/* which clipboard to use */
|
|
|
|
gchar clipboard_str[32] = DEF_CLIPBOARD_STR;
|
|
|
|
GdkAtom clipboard;
|
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* ==========================================================================
|
|
|
|
* clipboard history menu
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* history menu item button click function
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
menu_item_button_released(GtkWidget *widget,
|
|
|
|
GdkEvent *event,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *)event;
|
|
|
|
HISTORY_ITEM *data = user_data;
|
|
|
|
|
|
|
|
begin_func("menu_item_button_released");
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* button 2 or 3 - exec or (un)lock item respectively */
|
|
|
|
if (bevent->button == 2) {
|
|
|
|
if (exec_middleclick) {
|
|
|
|
gtk_menu_popdown(GTK_MENU(menu_hist));
|
|
|
|
exec_item(data->content, NULL);
|
|
|
|
}
|
|
|
|
return_val(TRUE);
|
|
|
|
} else if (bevent->button == 3) {
|
|
|
|
if (data->locked == 0) {
|
|
|
|
|
|
|
|
/* cannot lock all records */
|
|
|
|
if (locked_count == num_items_to_keep - 1) {
|
|
|
|
show_message("There must remain at least one "
|
|
|
|
"unlocked item\nwhen menu is full!",
|
|
|
|
"Warning", "OK", NULL, NULL);
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
|
2014-11-23 02:48:47 +00:00
|
|
|
gtk_widget_override_color(
|
|
|
|
gtk_bin_get_child(GTK_BIN(data->menu_item)),
|
|
|
|
GTK_STATE_FLAG_NORMAL, &locked_color);
|
2014-11-23 02:48:37 +00:00
|
|
|
data->locked = 1;
|
|
|
|
locked_count++;
|
|
|
|
|
|
|
|
} else {
|
2014-11-23 02:48:47 +00:00
|
|
|
gtk_widget_override_color(
|
|
|
|
gtk_bin_get_child(GTK_BIN(data->menu_item)),
|
|
|
|
GTK_STATE_FLAG_NORMAL, NULL);
|
2014-11-23 02:48:37 +00:00
|
|
|
data->locked = 0;
|
|
|
|
locked_count--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return_val(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* history menu item left click or keypress function
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
menu_item_activated(GtkWidget *widget, gpointer user_data)
|
|
|
|
{
|
|
|
|
move_item_to_begin((HISTORY_ITEM *) user_data);
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* checks, if there is already such item in menu,
|
|
|
|
* in which case it moves it to the begining
|
|
|
|
*/
|
|
|
|
HISTORY_ITEM *
|
|
|
|
menu_item_exists(gchar *content, GtkWidget *submenu)
|
|
|
|
{
|
|
|
|
HISTORY_ITEM *hist_item;
|
|
|
|
GList *list_node;
|
|
|
|
|
|
|
|
begin_func("menu_item_exists");
|
|
|
|
|
|
|
|
list_node = g_list_last(history_items);
|
|
|
|
while (list_node) {
|
|
|
|
hist_item = (HISTORY_ITEM *)list_node->data;
|
|
|
|
if (hist_item->menu == submenu
|
|
|
|
&& g_utf8_collate(hist_item->content, content)
|
|
|
|
== 0) {
|
|
|
|
gtk_menu_reorder_child(GTK_MENU(hist_item->menu),
|
|
|
|
hist_item->menu_item, 1);
|
|
|
|
history_items = g_list_remove_link(history_items,
|
|
|
|
list_node);
|
|
|
|
history_items = g_list_concat(list_node, history_items);
|
|
|
|
|
|
|
|
return_val(hist_item);
|
|
|
|
}
|
|
|
|
list_node = g_list_previous(list_node);
|
|
|
|
}
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
return_val(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add new item to menu
|
|
|
|
*/
|
|
|
|
HISTORY_ITEM *
|
|
|
|
menu_item_add(gchar *content, gint locked, GtkWidget *target_menu)
|
|
|
|
{
|
|
|
|
GList *list_node;
|
|
|
|
gint i;
|
|
|
|
gchar *menu_item_name;
|
|
|
|
gchar *fixed_menu_item_name;
|
|
|
|
gsize length;
|
|
|
|
HISTORY_ITEM *hist_item;
|
|
|
|
|
|
|
|
begin_func("menu_item_add");
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
hist_item = menu_item_exists(content, target_menu);
|
|
|
|
if (hist_item != NULL) {
|
|
|
|
dump_history_list("reorder");
|
|
|
|
return_val(hist_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_items == num_items_to_keep) {
|
|
|
|
/* max item limit reached, destroy oldest one */
|
|
|
|
list_node = g_list_last(history_items);
|
|
|
|
while (1) {
|
|
|
|
hist_item = (HISTORY_ITEM*)
|
|
|
|
list_node->data;
|
|
|
|
if (hist_item->locked == 0)
|
|
|
|
break;
|
|
|
|
list_node = g_list_previous(list_node);
|
|
|
|
g_assert((list_node != NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
history_items = g_list_remove_link(history_items, list_node);
|
2018-04-27 09:16:48 +00:00
|
|
|
/* gtk_container_remove(GTK_CONTAINER(hist_item->menu),
|
|
|
|
hist_item->menu_item); */
|
2014-11-23 02:48:37 +00:00
|
|
|
gtk_widget_destroy(hist_item->menu_item);
|
|
|
|
g_free(hist_item->content);
|
|
|
|
g_free(hist_item);
|
|
|
|
g_list_free_1(list_node);
|
|
|
|
num_items--;
|
|
|
|
dump_history_list("remove oldest");
|
|
|
|
}
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* prepare menu item name */
|
|
|
|
menu_item_name = g_new0(char, MAX_ITEM_LENGTH * 2 + 1);
|
|
|
|
memset(menu_item_name, 0, MAX_ITEM_LENGTH * 2 + 1);
|
|
|
|
length = g_utf8_strlen(content, -1);
|
|
|
|
if (length > (size_t) (MAX_ITEM_LENGTH)) {
|
|
|
|
g_utf8_strncpy(menu_item_name, content, MAX_ITEM_LENGTH - 4);
|
|
|
|
strcat(menu_item_name, "...");
|
|
|
|
} else {
|
|
|
|
strcpy(menu_item_name, content);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do some menu item name cleanups */
|
|
|
|
fixed_menu_item_name = g_new0(char, strlen(menu_item_name) + 1);
|
|
|
|
for (i = 0; i < g_utf8_strlen(menu_item_name, -1); i++) {
|
|
|
|
gchar *uchar_ptr = g_utf8_offset_to_pointer(menu_item_name, i);
|
|
|
|
gunichar uchar = g_utf8_get_char(uchar_ptr);
|
|
|
|
if (g_unichar_isprint(uchar)) {
|
|
|
|
gchar *decoded_char = g_ucs4_to_utf8(&uchar, 1, NULL,
|
|
|
|
NULL, NULL);
|
|
|
|
strcat(fixed_menu_item_name, decoded_char);
|
|
|
|
g_free(decoded_char);
|
|
|
|
} else {
|
|
|
|
strcat(fixed_menu_item_name, "_");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free(menu_item_name);
|
|
|
|
menu_item_name = fixed_menu_item_name;
|
|
|
|
|
|
|
|
/* create menu item */
|
|
|
|
hist_item = g_new0(HISTORY_ITEM, 1);
|
|
|
|
hist_item->menu_item = gtk_menu_item_new_with_label(menu_item_name);
|
|
|
|
hist_item->content = g_strdup(content);
|
|
|
|
hist_item->locked = locked;
|
|
|
|
hist_item->menu = target_menu;
|
|
|
|
|
|
|
|
if (locked == 1) {
|
2014-11-23 02:48:47 +00:00
|
|
|
gtk_widget_override_color(
|
|
|
|
gtk_bin_get_child(GTK_BIN(hist_item->menu_item)),
|
|
|
|
GTK_STATE_FLAG_NORMAL, &locked_color);
|
2014-11-23 02:48:37 +00:00
|
|
|
locked_count++;
|
|
|
|
}
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* add to menu */
|
2014-11-23 02:48:44 +00:00
|
|
|
gtk_menu_shell_insert(GTK_MENU_SHELL(hist_item->menu), hist_item->menu_item, 1);
|
2014-11-23 02:48:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* connect actions to signals */
|
2014-11-23 02:48:44 +00:00
|
|
|
g_signal_connect(G_OBJECT(hist_item->menu_item),
|
2014-11-23 02:48:37 +00:00
|
|
|
"button-release-event",
|
2014-11-23 02:48:44 +00:00
|
|
|
G_CALLBACK(menu_item_button_released),
|
2014-11-23 02:48:37 +00:00
|
|
|
(gpointer)hist_item);
|
|
|
|
|
2014-11-23 02:48:44 +00:00
|
|
|
g_signal_connect(G_OBJECT(hist_item->menu_item),
|
2014-11-23 02:48:37 +00:00
|
|
|
"activate",
|
2014-11-23 02:48:44 +00:00
|
|
|
G_CALLBACK(menu_item_activated),
|
2014-11-23 02:48:37 +00:00
|
|
|
(gpointer)hist_item);
|
|
|
|
|
|
|
|
gtk_widget_show(hist_item->menu_item);
|
|
|
|
|
|
|
|
history_items = g_list_insert(history_items, hist_item, 0);
|
|
|
|
|
|
|
|
num_items++;
|
|
|
|
|
|
|
|
return_val(hist_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==========================================================================
|
|
|
|
* application menu
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* application main menu handler
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
menu_app_item_click(GtkWidget *menuitem, gpointer data)
|
|
|
|
{
|
|
|
|
gint button;
|
|
|
|
|
|
|
|
begin_func("menu_app_item_click");
|
|
|
|
|
|
|
|
switch (GPOINTER_TO_INT(data)) {
|
|
|
|
/* save history menu */
|
|
|
|
case 0:
|
|
|
|
if (history_save() != 0) {
|
|
|
|
button = show_message("History was NOT saved.\n",
|
|
|
|
"Warning", "OK", NULL, NULL);
|
|
|
|
}
|
|
|
|
return_val(TRUE);
|
|
|
|
|
|
|
|
/* exit menu */
|
|
|
|
case 1:
|
|
|
|
if (history_save() != 0) {
|
|
|
|
button = show_message("History was NOT saved.\n"
|
|
|
|
"Do you really want to exit?",
|
|
|
|
"Error", "Yes", "No", NULL);
|
|
|
|
if (button != 0)
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
history_free();
|
|
|
|
rcconfig_free();
|
2018-04-27 09:16:48 +00:00
|
|
|
|
|
|
|
gtk_main_quit();
|
2014-11-23 02:48:44 +00:00
|
|
|
exit(0);
|
2014-11-23 02:48:37 +00:00
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
return_val(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ==========================================================================
|
|
|
|
* dock button press
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dock button click response
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
button_press(GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
{
|
|
|
|
begin_func("button_press");
|
|
|
|
|
|
|
|
if (event->type == GDK_BUTTON_PRESS) {
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *)event;
|
|
|
|
|
|
|
|
switch (bevent->button) {
|
|
|
|
case 1:
|
|
|
|
/* popup history menu */
|
|
|
|
gtk_menu_popup(GTK_MENU(menu_hist),
|
|
|
|
NULL, NULL,
|
|
|
|
NULL, NULL,
|
|
|
|
bevent->button,
|
|
|
|
bevent->time);
|
|
|
|
return_val(TRUE);
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* popup application menu */
|
|
|
|
gtk_menu_popup(GTK_MENU(menu_app),
|
|
|
|
NULL, NULL,
|
|
|
|
NULL, NULL,
|
|
|
|
bevent->button,
|
|
|
|
bevent->time);
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return_val(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ==========================================================================
|
|
|
|
* message dialogs
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2018-04-27 09:16:48 +00:00
|
|
|
* open dialog with specified message and buttons
|
2014-11-23 02:48:37 +00:00
|
|
|
* and return number of button pressed
|
|
|
|
*/
|
|
|
|
gint
|
|
|
|
show_message(gchar *message, char *title,
|
|
|
|
char *b0_text, char *b1_text, char *b2_text)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog,
|
|
|
|
*label,
|
2018-04-27 09:16:48 +00:00
|
|
|
*content_area;
|
|
|
|
gint result;
|
|
|
|
gint button_pressed = 1;
|
2014-11-23 02:48:37 +00:00
|
|
|
|
|
|
|
begin_func("show_message");
|
|
|
|
|
|
|
|
/* create the main widgets */
|
|
|
|
dialog = gtk_dialog_new();
|
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
2014-11-23 02:48:37 +00:00
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
/* Show the message */
|
|
|
|
label = gtk_label_new(message);
|
|
|
|
gtk_container_add(GTK_CONTAINER (content_area), label);
|
|
|
|
gtk_widget_show(label);
|
2014-11-23 02:48:37 +00:00
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
/* add the button */
|
|
|
|
gtk_dialog_add_button(GTK_DIALOG (dialog), b0_text, 0);
|
|
|
|
if(b1_text != NULL) gtk_dialog_add_button(GTK_DIALOG (dialog), b1_text, 1);
|
|
|
|
if(b2_text != NULL) gtk_dialog_add_button(GTK_DIALOG (dialog), b2_text, 2);
|
2014-11-23 02:48:37 +00:00
|
|
|
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
/* set the dialog title */
|
2014-11-23 02:48:37 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(dialog), title);
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2018-04-27 09:16:48 +00:00
|
|
|
/* set the dialog modal and transient */
|
|
|
|
/* gtk_window_set_modal(GTK_WINDOW (dialog), TRUE);*/
|
|
|
|
gtk_window_set_transient_for(GTK_WINDOW (dialog), GTK_WINDOW (dock_app));
|
|
|
|
|
|
|
|
/*wait for the user response */
|
|
|
|
result = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
switch (result)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
button_pressed = 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
button_pressed = 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
button_pressed = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*destroy the dialog box, when the user responds */
|
2014-11-23 02:48:37 +00:00
|
|
|
gtk_widget_destroy(dialog);
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
return_val(button_pressed);
|
|
|
|
}
|