X-Git-Url: http://sigaev.ru/git/gitweb.cgi?p=hclip.git;a=blobdiff_plain;f=hclip.c;h=55f0494eb30b762a6a7cfb9a5a3d6acbc62740e5;hp=c4cdaaac33c24265e6f09d8db69c6df75a2f7e69;hb=HEAD;hpb=0f33952e3a5f99f5dc516805b7d15cf66412234d diff --git a/hclip.c b/hclip.c index c4cdaaa..55f0494 100644 --- a/hclip.c +++ b/hclip.c @@ -66,7 +66,6 @@ typedef struct ClipboardMenuItem { GtkWidget *widget; /* pointer to GtkMenuItem */ gchar *buffer; /* value and it's length */ - size_t buflen; gint flags; } ClipboardMenuItem; @@ -82,6 +81,9 @@ typedef struct ClipboardDescr { GtkWidget *widget; /* GtkMenu */ + GtkWidget *activator; /* GtkMenuItem for manage active state */ + gboolean is_active; + ClipboardMenuItem *items[NHistItem]; /* histories item's */ gint nitems; /* number of items */ gint nlocked; /* number of locked items */ @@ -90,6 +92,7 @@ typedef struct ClipboardDescr { GtkStyle *style_locked; /* style for locked item */ } ClipboardDescr; + /* * Assign menu's popup to hotkey */ @@ -142,12 +145,12 @@ catchKey(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) * buffer and -1 if it isn't found */ static gint -existMenuItem(ClipboardDescr *descr, const gchar *buffer, size_t buflen) +existMenuItem(ClipboardDescr *descr, const gchar *buffer) { gint i; for(i=0;initems;i++) - if ( descr->items[i]->buflen == buflen && strcmp( descr->items[i]->buffer, buffer ) == 0 ) + if ( strcmp( descr->items[i]->buffer, buffer ) == 0 ) return i; return -1; @@ -207,8 +210,7 @@ itemActivate(GtkWidget *widget, gpointer user_data) moveMenuItemFirst( descr, n ); gtk_clipboard_set_text( gtk_clipboard_get(GDK_SELECTION_PRIMARY), - descr->items[0]->buffer, - descr->items[0]->buflen); + descr->items[0]->buffer, -1 ); } return TRUE; @@ -299,12 +301,12 @@ newClipboardMenuItem(ClipboardDescr *descr) g_signal_connect(item->widget, "activate", - (GCallback)itemActivate, + G_CALLBACK(itemActivate), (gpointer)descr); g_signal_connect(item->widget, "button-release-event", - (GCallback)itemToggleLock, + G_CALLBACK(itemToggleLock), (gpointer)descr); gtk_menu_shell_prepend(GTK_MENU_SHELL(descr->widget), item->widget); @@ -318,7 +320,7 @@ newClipboardMenuItem(ClipboardDescr *descr) * existing */ static void -addMenuItem( ClipboardDescr *descr, const gchar *buffer, size_t buflen ) +addMenuItem( ClipboardDescr *descr, gchar *buffer ) { gint i; static gchar itemname[5*MaxItemName + 1]; @@ -327,9 +329,10 @@ addMenuItem( ClipboardDescr *descr, const gchar *buffer, size_t buflen ) /* * if such value already exists just move to to head */ - if ( (i=existMenuItem(descr, buffer, buflen)) >= 0 ) + if ( (i=existMenuItem(descr, buffer)) >= 0 ) { moveMenuItemFirst( descr, i ); + g_free( buffer ); /* free buffer if is not needed */ return; } @@ -365,8 +368,7 @@ addMenuItem( ClipboardDescr *descr, const gchar *buffer, size_t buflen ) if ( descr->items[0]->buffer ) g_free( descr->items[0]->buffer ); - descr->items[0]->buffer = g_memdup(buffer, buflen+1); - descr->items[0]->buflen = buflen; + descr->items[0]->buffer = buffer; descr->items[0]->flags = 0; /* @@ -377,7 +379,7 @@ addMenuItem( ClipboardDescr *descr, const gchar *buffer, size_t buflen ) ptrname = itemname; ptrbuffer = (gchar*)buffer; - for(i=0; *ptrbuffer && (ptrbuffer - buffer)is_active == TRUE ) + { + gtk_widget_set_style( GTK_BIN(descr->activator)->child, descr->style_locked); + gtk_label_set_text( + GTK_LABEL( gtk_bin_get_child(GTK_BIN(descr->activator)) ), + "Activate" + ); + descr->is_active = FALSE; + } + else + { + gtk_widget_set_style( GTK_BIN(descr->activator)->child, descr->style_normal); + gtk_label_set_text( + GTK_LABEL( gtk_bin_get_child(GTK_BIN(descr->activator)) ), + "Deactivate" + ); + descr->is_active = TRUE; + } + + return TRUE; +} + /* * Initialize main struct */ static void initHistMenu( ClipboardDescr *descr ) { + GtkWidget *separator; /* * set up hotkey to call menu */ @@ -435,6 +465,23 @@ initHistMenu( ClipboardDescr *descr ) */ descr->widget = gtk_menu_new(); gtk_menu_set_title(GTK_MENU(descr->widget), "Clipboard history"); + + separator = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(descr->widget), separator); + + descr->activator = gtk_menu_item_new_with_label("Deactivate"); + gtk_label_set_max_width_chars( + GTK_LABEL( gtk_bin_get_child(GTK_BIN(descr->activator)) ), + MaxItemName + ); + g_signal_connect(descr->activator, + "activate", + G_CALLBACK(appToggleActivate), + (gpointer)descr); + gtk_menu_shell_append(GTK_MENU_SHELL(descr->widget), descr->activator); + + gtk_widget_show(descr->activator); + gtk_widget_show(separator); gtk_widget_show(descr->widget); descr->nitems = 0; @@ -453,28 +500,112 @@ initHistMenu( ClipboardDescr *descr ) * Create first item and mark it as INIT due to * void menu is showed very bad */ - addMenuItem( descr, StartupItem, strlen(StartupItem) ); + addMenuItem( descr, g_strdup(StartupItem) ); descr->items[0]->flags = CMI_INIT; + + descr->is_active = TRUE; } /* - * Retrieves content of clipoard in a text form + * Receive text content of buffer + * + * Some applications ( OpenOffice at least ) sets owner at + * begining of selection instead of after finishing selection. And + * gtk_clipboard_wait_for_text() will fix state of X-Selection. So, + * GTK clipboard will see only small part of real selection. For preventing + * from this misbehaviour we will not try to get contents of selection - + * just skip it as image etc. However, it's possible to delay + * request of contents - but I don't know way to count correct + * timeout or to get finalizing event (may be yet :) ) */ static void -receiveText(GtkClipboard *cpb, const gchar *text, gpointer data) +receiveTarget(GtkClipboard *clipboard, GdkAtom *atoms, gint n_atoms, gpointer data) { - if ( text != NULL ) - addMenuItem( (ClipboardDescr*)data, text, strlen(text) ); + gint i; + gchar *text; + static struct /* just an unnamed struct */ + { + gchar *target_prefix; + gint target_prefix_len; + } ignore_targets[] = { + { "application/x-openoffice", -1 }, + { NULL, 0 } /* mark end */ + }, + *ptr ; + + + /* + * If there is not text in targets then return + */ + if ( gtk_targets_include_text( atoms, n_atoms ) == FALSE ) + return; + + /* + * init ignore target if it's needed + */ + if ( ignore_targets->target_prefix_len < 0 ) + { + ptr = ignore_targets; + + while( ptr->target_prefix ) + { + ptr->target_prefix_len = strlen( ptr->target_prefix ); + ptr++; + } + } + + /* + * checks all avaliable targets for presence of ignorable + * targets ( which come from "wrong" applications ) + */ + for(i=0;itarget_prefix ) + { + if ( strncmp( target_name, ptr->target_prefix, ptr->target_prefix_len ) == 0 ) + { + /* + * It's found a ignorable targets - we will not accept text to + * prevent unexpected and surprised behaviour of X-selection + */ + g_free(target_name); + return; + } + + g_free(target_name); + ptr++; + } + } + + /* + * Ok - selection has text, selection is not owned to strange application - + * request contents + */ + text = gtk_clipboard_wait_for_text(clipboard); + /* be carefull - world has a lot of unexpected events :) */ + if (text) + addMenuItem( (ClipboardDescr*)data, text ); } /* - * Clipboard change signal handler. It requests new content of - * clipboard in a text form + * Clipboard change signal handler. It requests avaliable + * targets to make checks about contents of selection */ static void ClipboardChange(GtkClipboard *clipboard, GdkEvent *event, gpointer data) { - gtk_clipboard_request_text( clipboard, receiveText, data ); + /* + * Do real work if and only if application is active + */ + if ( ((ClipboardDescr*)data)->is_active ) + gtk_clipboard_request_targets( clipboard, receiveTarget, data ); } int @@ -492,7 +623,7 @@ main( int argc, char *argv[] ) { */ g_signal_connect(gtk_clipboard_get(GDK_SELECTION_PRIMARY), "owner-change", - (GCallback)ClipboardChange, + G_CALLBACK(ClipboardChange), (gpointer)&descr); gtk_main ();