typedef struct ClipboardMenuItem {
GtkWidget *widget; /* pointer to GtkMenuItem */
gchar *buffer; /* value and it's length */
- size_t buflen;
gint flags;
} ClipboardMenuItem;
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 */
GtkStyle *style_locked; /* style for locked item */
} ClipboardDescr;
+
/*
* Assign menu's popup to hotkey
*/
* 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;i<descr->nitems;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;
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;
* 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];
/*
* 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;
}
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;
/*
ptrname = itemname;
ptrbuffer = (gchar*)buffer;
- for(i=0; *ptrbuffer && (ptrbuffer - buffer)<buflen && i < MaxItemName; i++)
+ for(i=0; *ptrbuffer && i < MaxItemName; i++)
{
int charlen = g_utf8_offset_to_pointer(ptrbuffer, 1) - ptrbuffer;
gunichar widechar;
);
}
+static gboolean
+appToggleActivate(GtkWidget *widget, gpointer user_data)
+{
+ ClipboardDescr *descr = (ClipboardDescr*)user_data;
+
+ if ( descr->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
*/
*/
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;
* 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;i<n_atoms;i++)
+ {
+ gchar *target_name = gdk_atom_name( atoms[i] );
+
+ if (!target_name)
+ continue;
+
+ ptr = ignore_targets;
+
+ while( ptr->target_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