Fix compilation
[hclip.git] / hclip.c
diff --git a/hclip.c b/hclip.c
index 1f591b7..55f0494 100644 (file)
--- 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;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;
@@ -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;
@@ -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)<buflen && i < MaxItemName; i++)
+       for(i=0; *ptrbuffer && i < MaxItemName; i++)
        {
                int     charlen = g_utf8_offset_to_pointer(ptrbuffer, 1) - ptrbuffer; 
                gunichar         widechar;
@@ -416,12 +418,40 @@ addMenuItem( ClipboardDescr *descr, const gchar *buffer, size_t buflen )
        );
 }
 
+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
         */
@@ -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;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