dockapps/wmcliphist/gui.c

458 lines
10 KiB
C

#include "wmcliphist.h"
#include <gdk/gdkkeysyms.h>
/* color of locked item */
gchar locked_color_str[32] = DEF_LOCKED_COLOR;
GdkRGBA locked_color;
/* 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;
/* button */
GtkWidget *button;
/* pixmap */
GtkWidget *pixmap;
/* which clipboard to use */
gchar clipboard_str[32] = DEF_CLIPBOARD_STR;
GdkAtom clipboard;
/* ==========================================================================
* 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");
/* 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);
}
gtk_widget_override_color(
gtk_bin_get_child(GTK_BIN(data->menu_item)),
GTK_STATE_FLAG_NORMAL, &locked_color);
data->locked = 1;
locked_count++;
} else {
gtk_widget_override_color(
gtk_bin_get_child(GTK_BIN(data->menu_item)),
GTK_STATE_FLAG_NORMAL, NULL);
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);
}
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");
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);
gtk_container_remove(GTK_CONTAINER(hist_item->menu),
hist_item->menu_item);
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");
}
/* 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) {
gtk_widget_override_color(
gtk_bin_get_child(GTK_BIN(hist_item->menu_item)),
GTK_STATE_FLAG_NORMAL, &locked_color);
locked_count++;
}
/* add to menu */
gtk_menu_shell_insert(GTK_MENU_SHELL(hist_item->menu), hist_item->menu_item, 1);
/* connect actions to signals */
g_signal_connect(G_OBJECT(hist_item->menu_item),
"button-release-event",
G_CALLBACK(menu_item_button_released),
(gpointer)hist_item);
g_signal_connect(G_OBJECT(hist_item->menu_item),
"activate",
G_CALLBACK(menu_item_activated),
(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();
exit(0);
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
*/
static GMainLoop *loop;
static gint button_pressed;
static gboolean
dialog_button_press(GtkWidget *button, gpointer data)
{
begin_func("dialog_button_press");
button_pressed = GPOINTER_TO_INT(data);
g_main_quit(loop);
return_val(TRUE);
}
static gboolean
dialog_handle_key_press_event(GdkEventKey *event, gpointer data, guint key)
{
if(event->type != GDK_KEY_PRESS)
return_val(FALSE);
if(event->keyval != key)
return_val(FALSE);
button_pressed = GPOINTER_TO_INT(data);
g_main_quit(loop);
return_val(TRUE);
}
static gboolean
dialog_key_press_yes(GtkWidget *button, GdkEventKey *event, gpointer data)
{
begin_func("dialog_key_press_yes");
return dialog_handle_key_press_event(event, data, GDK_KEY_Return);
}
static gboolean
dialog_key_press_no(GtkWidget *button, GdkEventKey *event, gpointer data)
{
begin_func("dialog_key_press_no");
return dialog_handle_key_press_event(event, data, GDK_KEY_Escape);
}
/*
* open dialog with specified message andbuttons
* 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,
*button_0,
*button_1,
*button_2;
begin_func("show_message");
/* create the main widgets */
dialog = gtk_dialog_new();
label = gtk_label_new(message);
/* create buttons and set signals */
gtk_dialog_add_button(GTK_DIALOG(dialog), b0_text, 0);
button_0 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 0);
g_signal_connect(G_OBJECT(button_0), "clicked",
G_CALLBACK(dialog_button_press),
GINT_TO_POINTER(0));
if (!b2_text) {
g_signal_connect(G_OBJECT(dialog), "key-press-event",
G_CALLBACK(dialog_key_press_yes),
GINT_TO_POINTER(0));
}
if (b1_text != NULL) {
gtk_dialog_add_button(GTK_DIALOG(dialog), b1_text, 1);
button_1 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 1);
g_signal_connect(G_OBJECT(button_1), "clicked",
G_CALLBACK(dialog_button_press),
GINT_TO_POINTER(1));
if (!b2_text) {
g_signal_connect(G_OBJECT(dialog), "key-press-event",
G_CALLBACK(dialog_key_press_no),
GINT_TO_POINTER(1));
}
}
if (b2_text) {
gtk_dialog_add_button(GTK_DIALOG(dialog), b2_text, 2);
button_2 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 2);
g_signal_connect(G_OBJECT(button_2), "clicked",
G_CALLBACK(dialog_button_press),
GINT_TO_POINTER(2));
}
/* add the label, and show everything we've added to the dialog. */
gtk_misc_set_padding(&GTK_LABEL(label)->misc, 10, 10);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label);
gtk_widget_show_all(dialog);
/* set window title */
gtk_window_set_title(GTK_WINDOW(dialog), title);
loop = g_main_new(FALSE);
g_main_run(loop);
g_main_destroy(loop);
gtk_widget_destroy(dialog);
return_val(button_pressed);
}