Portapapeles

 Algunos tópicos sobre el portapeles en glib.
 Es para quien desee ahondar en el modelo o sistema de portapapeles
 en glib/gtk+.
 Esta es la primera parte y describe como trabaja el porta papeles.

Primera parte

  • Lamentablemente, en la red no se encuentra mucha información del portapapeles de glib.

 Este documento ha sido elaborado según la experiencia en el tema.
 Por lo tanto cualquier error u omisión es involuntario y se recomienda
 al lector hacérmelo saber.
 ¡¡¡ Gracias !!!  ;)

Porta papeles

  •    Es una forma de comunicación entre procesos.
       Se usa para guardar datos y luego recuperarlos,
       ya sea en el mismo proceso o en otro.
         En glib/gtk, el grupo de funciones u objeto que lo hace, se llama:
         gtkclipboard.
         Por defecto, el  gtkclipboard sólo guarda dos tipos
         de datos, que son:  texto e imágenes.
         En principio,cuando uno desea pasar otro tipo de objeto, el
         gtkclipboard no dá opciones.
         Mirando el código del «porta papeles»  se puede
         encontrar que probablemente se pueda hacer.

Funcionamiento

  • Primero vamos a entender como es el funcionamiento del gtkclipboard y luego nos ponemos manos a la obra.
  •     En principio si uno desea poner en el porta papeles un texto
        o una imagen sólo ha de llamar una de estas dos funciones:
        gtk_clipboard_set_text  
        ó
        gtk_clipboard_set_image 
        Para el primero, habrá que pasarle el clipboard del tipo GtkClipboard*,
        se le ha de pasar el texto y la longitud de éste.
        Para el segundo, sólo  habrá que pasarle el GtkClipboard* y la imagen; la imagen
        ha de ser del tipo GdkPixbuf*. Por cierto GdkPixbuf no es un objeto
        heredable, sólo es estático.
       El portapapeles hay que iniciarlo antes de usarlo, y una de las formas
       como se puede hacer es: 
       gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
       GDK_SELECTION_CLIPBOARD equivale a usar el porta papeles herado por defecto.
       Cuando se quiere pasar información al porta-papeles, la forma
       de hacerlo es:
       Para un texto:
       gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),texto,long_texto);
       Para una imagen:
       gtk_clipboard_set_image(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),imagen); 

gtk_clipboard_set_text

  • /**
    • gtk_clipboard_set_text:
    • @clipboard: a #GtkClipboard object

    • @text: a UTF-8 string.
    • @len: length of @text, in bytes, or -1, in which case
    • the length will be determined with <function>strlen()</function>.

    • Sets the contents of the clipboard to the given UTF-8 string. GTK+ will
    • make a copy of the text and take responsibility for responding
    • for requests for the text, and for converting the text into
    • the requested format.
    • */
    •       El nombre de la función con sus parámetros, nada raro hasta ahora.

      void gtk_clipboard_set_text (GtkClipboard* clipboard,const gchar *text,

      • gint len)
      {
      • GtkTargetList *list;

               Resulta que hace hace una variable de tipo
               GtkTargetList. Ésta es una estructura que depende
               de gtk-Selections. 
               gtk-Selections Son un conjunto de funciones
               encargadas de manejar la comunicación entre procesos. No 
               significa que sea la única manera, pero es la forma que usa el
               gtkclipgboard.
               GtkTargetList, guarda los tipos de datos
               que maneja gtk-Selections; que son del tipo GtkTargetEntry
               y que fuera de otra información, contiene identificadores de
               la estructura de datos y de su posible recuperación. 
        • GList *l; " un Glist ;)"
               El tipo de datos que usa gtk-selections

        GtkTargetEntry *targets;

               La cantidad de elementos que posee la lista de targets.
        gint n_targets, i; g_return_if_fail (clipboard != NULL); g_return_if_fail (text != NULL); list = gtk_target_list_new (NULL, 0); gtk_target_list_add_text_targets (list, 0);
              Esta función le agrega una cantidad determinada de targets a list.
              ¿Pero que són esos targets?
              Según lo que entiendo, los targets son «como apuntadores», 
              que se rerefrencian dentro de una tabla de cadenas manejada por el servidor
              X.
              Los targets son del tipo GdkAtom.Hay que tener en cuenta que no es un 
              apuntador a un tipo, 
              ¿Pero qué tiene qué ver la función con los GdkAtom...?"
              Pues gtk_target_list_add_text_targets (list, 0); es la encargada
              de sumarle a la lista, los targets que indican el tipo de dato
              que se le va a pasar al porta papeles.
              Lo realiza de la siguiente forma:
               Esta función está en gtkselection:
           
               void  gtk_target_list_add_text_targets (GtkTargetList *list,guint info)
               {
                g_return_if_fail (list != NULL); si no hay objeto para qué seguir.
                init_atoms ();
                {{{ 
                  init_atoms, encargada de inicializar los tipos de atoms
                  que por defecto trae gtkselections y la forma que lo hace es:
                  [
                  ...
                   utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
                   text_atom = gdk_atom_intern ("TEXT", FALSE);
                  ...
                  ]
                 Y si uds. se dan cuenta, entonces sólo hacen referencias al
                 tipo de información que se le está pasando al porta papeles.. 
           continuando dentro gtk_target_list_add_text_targets...
           
           Sólo se encarga de agregarle a GtkTargetList los
           atoms que «equivalen» a los tipos de datos que soportará
           el portapapeles para texto.
           utf8_atom, ctext_atom, etc, son los «atom» predefindos
           para tipos de texto plano que existen en gtk_clipboard,
           que para el caso son 7.
        /* Keep in sync with gtk_selection_data_targets_include_text()
         */
          gtk_target_list_add (list, utf8_atom, 0, info);  
          gtk_target_list_add (list, ctext_atom, 0, info);  
          gtk_target_list_add (list, text_atom, 0, info);  
          gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);  
          gtk_target_list_add (list, text_plain_utf8_atom, 0, info);  
          gtk_target_list_add (list, text_plain_locale_atom, 0, info);  
          gtk_target_list_add (list, text_plain_atom, 0, info);  
        }

continuando con gtk_clipboard_set_text:

  •    Entrega la cantidad de atoms o tipos de  texto
       que puede soportar, que para el caso son 7.

    n_targets = g_list_length (list->list); targets = g_new (GtkTargetEntry, n_targets);

    • for (l = list->list, i = 0; l; l = l->next, i++)

         Recupera la longitud del texto, esto es de vital importancia.

      if (len < 0)

      • len = strlen (text);
      gtk_clipboard_set_with_data (clipboard,
      • targets, n_targets, text_get_func, text_clear_func, g_strndup (text, len));
           La anterior función cumple su papel, pone el texto que se le pasa como parámetro
           al porta papeles. Los parámetros de la función son lo siguientes:
           clipboard: debe ser del tipo GtkClipboard*.
           targets: del tipo GtkTargetEntry *.
           n_targets: del tipo int.
           text_get_func: ha de ser un apuntador a una función 
           con el siguiente modelo
           (*GtkClipboardReceivedFunc) (GtkClipboard *clipboard,
            GtkSelectionData *selection_data, gpointer data);
           Aunque el nombre no importa ni su tipo, si importa la forma
           que ha de ser (*nombre)(GtkClipboard *clipboard,
             GtkSelectionData *selection_data, gpointer data);
           ""Y hay que tenerla en cuenta.""
      • g_strndup (text, len)
             sólo hace una copia del texto a memoria
             para no trabajar con el original.
             Las funciones text_get_func, text_clear_func se representan a continuación:
           
           static void  text_get_func (GtkClipboard     *clipboard,
                     GtkSelectionData *selection_data,
                     guint             info,
                     gpointer          data)
          {
           gtk_selection_data_set_text (selection_data, data, -1);
          } 
      
           gtk_selection_data_set_text está en gtk_selection,
           ¿qué hace?
           ¿Se acuerdan que hay unos atoms?
           Entonces dependiendo de la referencia del átom, así mismo
           se decide como convertir el tipo de texto a la forma
           que es aceptada por el porta papeles. 
           Cuando se realiza tal conversión terminan llamando a:
        
           gtk_selection_data_set (selection_data,
                                selection_data->target, 
                                8, result,longitud));
      
          en este momento uno no se dá cuenta de lo siguiente:
          Que el formato que trabaja el porta papeles es utf 8 o mejor
          char de 8.
          Bien, cuando se vea lo que hacen con pixbuf se llega a ésa conclusión.
    Volviendo a gtk_clipboard_set_text: gtk_clipboard_set_can_store (clipboard, NULL, 0);
    •      Esta función le dice al porta-papeles que la información
           debe ser guardada en cualquier lugar cuando la aplicación
           termine o cuando la función sea llamada.
           El valor es vuelto a su estado inicial cuando el porta -papeles 
           cambia de dueño.

      for (i = 0; i < n_targets; i++)

      • g_free (targets[i].target);
      g_free (targets); gtk_target_list_unref (list);

}

Como ven analizamos un poco la función gtk_clipboard_set_text. Ahora leeremos la que se encarga de poner la imagen en el portapeles..

gtk_clipboard_set_image.

/**

  • gtk_clipboard_set_image:
  • @clipboard: a #GtkClipboard object

  • @pixbuf: a #GdkPixbuf

  • Sets the contents of the clipboard to the given #GdkPixbuf.

  • GTK+ will take responsibility for responding for requests
  • for the image, and for converting the image into the
  • requested format.
  • Since: 2.6
  • */

   En un vuelo de pájaro, se encuentra  que tiene el 
   mismo formato que gtk_clipboard_set_text por lo tanto...

void gtk_clipboard_set_image (GtkClipboard *clipboard,

{

  •   Ya se sabe que es la lista de los GtkTargetEntry
    {{{¿adivinen? }}}
    • GList *l;
        los targets que son del tipo átom
    • GtkTargetEntry *targets; gint n_targets, i; g_return_if_fail (clipboard != NULL); g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); list = gtk_target_list_new (NULL, 0); gtk_target_list_add_image_targets (list, 0, TRUE);

          Resulta que la función tiene un comportamiento similar al presentado
          por gtk_target_list_add_text_targets.
          gtk_target_list_add_image_targets está en gtkselections.c,
          que a su vez llama a gdk_pixbuf_format_get_mime_types,
          que se encuentra en gdk-pixbuf-io.c y que a terminadas
          cuentas entrega los tipos de imágenes soportados.
          Después, gtk_target_list_add_image_targets hace cosas como 
          la siguiente:
                      gdk_atom_intern_static_string ("image/png"))
          Es resgistar un átom, con un nombre cualquiera, para el caso
          "image/png"
          Volviendo a gtk_clipboard_set_image:
          La cantidad de tipos para guardar en el porta papeles.. 

      n_targets = g_list_length (list->list); targets = g_new0 (GtkTargetEntry, n_targets); for (l = list->list, i = 0; l; l = l->next, i++)

           Y la encargada de guargar la info en el porta papeles..
      gtk_clipboard_set_with_data (clipboard,
      • targets, n_targets, pixbuf_get_func, pixbuf_clear_func, g_object_ref (pixbuf));
            ¿y adivinen qué...?  
            Vamos por : pixbuf_get_func para saber, qué es lo que hace...
           Bien entonces :
            La definición:
           static void pixbuf_get_func (GtkClipboard     *clipboard,
                       GtkSelectionData *selection_data,
                       guint             info,
                       gpointer          data)
          {
            gtk_selection_data_set_pixbuf (selection_data, data);
           }
         
          Metamos las narices en: gtk_selection_data_set_pixbuf
        /**
          * gtk_selection_data_set_pixbuf:
          * @selection_data: a #GtkSelectionData
          * @pixbuf: a #GdkPixbuf
          * 
          * Sets the contents of the selection from a #GdkPixbuf
          * The pixbuf is converted to the form determined by
          * @selection_data->target.
          * 
          * Return value: %TRUE if the selection was successfully set,
          *   otherwise %FALSE.
          *
          * Since: 2.6
        **/
          Una función normal que recibe algunos parámetros ;p
      
         gboolean gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data,
                                     GdkPixbuf        *pixbuf)
         {  
          GSList *formats, *f;
          gchar **mimes, **m;
          GdkAtom atom;
          gboolean result;
          gchar *str, *type;
          gsize len;
      
          formats = gdk_pixbuf_get_formats (); Los formatos y sus tipos...
      
          for (f = formats; f; f = f->next)
           {
            GdkPixbufFormat *fmt = f->data;
      
            mimes = gdk_pixbuf_format_get_mime_types (fmt);
            for (m = mimes; *m; m++)
              {
                atom = gdk_atom_intern (*m, FALSE);
                if (selection_data->target == atom)
                  {
                    str = NULL;
                    type = gdk_pixbuf_format_get_name (fmt); obtiene el tipo
                  
                    {{{  Se acuerdan de gdkatom... bien, aquí puede ser.
      • result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len,

        • type, NULL, NULL);
                        Resulta (jejeje) que,  de alguna forma mágica
                        se llama a esta función gdk_pixbuf_save_to_buffer
                        para cambiar de imagen a formato char ;)
                        de nuevo gdk_pixbuf_save_to_buffer está en gdk-pixbuf-io.c
                        y es un poco críptica para exponerla en unas lineas.
                        Ésa función entrega la convcersión en  la variable str
                        e igualmente sigue siendo importante su tamaño: len.
                       y ahora qué:...¿?  
        if (result)
        • gtk_selection_data_set (selection_data,
          • atom, 8, (guchar *)str, len);
                       ¿Si todo bien?
                        Entonces: Pone la imagen en el porta papeles ..
                        y cómo.. tranformada a un int 8 o guchar...
                       ¡¡¡ Es algo para tener en cuenta jajajajajajaja. !!!!
        g_free (type); g_free (str); g_strfreev (mimes); g_slist_free (formats); return result;
      • }
      • }
      • g_strfreev (mimes);
      • }
      • g_slist_free (formats); return FALSE;
      }
    }}}
        De nuevo en   Volviendo a gtk_clipboard_set_image:
    • gtk_clipboard_set_can_store (clipboard, NULL, 0);

      for (i = 0; i < n_targets; i++)

      • g_free (targets[i].target);
      g_free (targets); gtk_target_list_unref (list);
     De forma idéntica al texto.

}

Ya conocemos la forma aproximada, el como se comporta el porta papeles cuando se guardan datos. :)

  • Escrito por:
  • Made by: Exell Enrique Franklin Jiménez.



arawaco/portapapeles (last edited 2008-02-03 14:47:05 by anonymous)