21.3. Supplying the Selection

Supplying the selection is a bit more complicated. You must register handlers that will be called when your selection is requested. For each selection-target pair you will handle, you make a call to:

  widget.selection_add_target(selection, target, info)

widget, selection, and target identify the requests this handler will manage. When a request for a selection is received, the "selection_get" signal will be called. info is an integer that can be used as an enumerator to identify the specific target within the callback.

The callback has the signature:

  def selection_get(widget, selection_data, info, time):

The gtk.SelectionData is the same as above, but this time, we're responsible for filling in the fields type, format and data. (The format field is actually important here - the X server uses it to figure out whether the data needs to be byte-swapped or not. Usually it will be 8 - i.e. a character - or 32 - i.e. a integer.) This is done by calling the method:

  selection_data.set(type, format, data)

This PyGTK method can only handle string data so the data must be loaded into a Python string but format will be whatever the appropriate size is (e.g. 32 for atoms and integers, 8 for strings). The Python struct or StringIO modules can be used to convert non-string data to string data. For example, you can convert a list of integers to a string and set the selection_data by:

  ilist = [1, 2, 3, 4, 5]

  data = apply(struct.pack, ['%di'%len(ilist)] + ilist)

  selection_data.set("INTEGER", 32, data)

The following method sets the selection data from the given string:

  selection_data.set_text(str, len)

When prompted by the user, you claim ownership of the selection by calling:

  result = widget.selection_owner_set(selection, time=0L)

result will be TRUE if program successfully claimed the selection. If another application claims ownership of the selection, you will receive a "selection_clear_event".

As an example of supplying the selection, the setselection.py program adds selection functionality to a toggle button enclosed in a gtk.EventBox. (The gtk.Eventbox is needed because the selection must be associated with a gtk.gdk.Window and a gtk.Button is a "windowless" object in GTK+ 2.0.) When the toggle button is depressed, the program claims the primary selection. The only target supported (aside from certain targets like "TARGETS" supplied by GTK+ itself), is the "STRING" target. When this target is requested, a string representation of the time is returned. Figure 21.2, “Set Selection Example” illustrates the program display when the program has taken the primary selection ownership:

Figure 21.2. Set Selection Example

Set Selection Example

The setselection.py source code is:

    1	#!/usr/bin/env python
    2	
    3	# example setselection.py
    4	
    5	import pygtk
    6	pygtk.require('2.0')
    7	import gtk
    8	import time
    9	
   10	class SetSelectionExample:
   11	    # Callback when the user toggles the selection
   12	    def selection_toggled(self, widget, window):
   13	        if widget.get_active():
   14	            self.have_selection = window.selection_owner_set("PRIMARY")
   15	            # if claiming the selection failed, we return the button to
   16	            # the out state
   17	            if not self.have_selection:
   18	                widget.set_active(False)
   19	        else:
   20	            if self.have_selection:
   21	                # Not possible to release the selection in PyGTK
   22	                # just mark that we don't have it
   23	                self.have_selection = False
   24	        return
   25	
   26	    # Called when another application claims the selection
   27	    def selection_clear(self, widget, event):
   28	        self.have_selection = False
   29	        widget.set_active(False)
   30	        return True
   31	
   32	    # Supplies the current time as the selection.
   33	    def selection_handle(self, widget, selection_data, info, time_stamp):
   34	        current_time = time.time()
   35	        timestr = time.asctime(time.localtime(current_time))
   36	
   37	        # When we return a single string, it should not be null terminated.
   38	        # That will be done for us
   39	        selection_data.set_text(timestr, len(timestr))
   40	        return
   41	
   42	    def __init__(self):
   43	        self.have_selection = False
   44	        # Create the toplevel window
   45	        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   46	        window.set_title("Set Selection")
   47	        window.set_border_width(10)
   48	        window.connect("destroy", lambda w: gtk.main_quit())
   49	        self.window = window
   50	        # Create an eventbox to hold the button since it no longer has
   51	        # a GdkWindow
   52	        eventbox = gtk.EventBox()
   53	        eventbox.show()
   54	        window.add(eventbox)
   55	        
   56	        # Create a toggle button to act as the selection
   57	        selection_button = gtk.ToggleButton("Claim Selection")
   58	        eventbox.add(selection_button)
   59	
   60	        selection_button.connect("toggled", self.selection_toggled, eventbox)
   61	        eventbox.connect_object("selection_clear_event", self.selection_clear,
   62	                                selection_button)
   63	
   64	        eventbox.selection_add_target("PRIMARY", "STRING", 1)
   65	        eventbox.selection_add_target("PRIMARY", "COMPOUND_TEXT", 1)
   66	        eventbox.connect("selection_get", self.selection_handle)
   67	        selection_button.show()
   68	        window.show()
   69	
   70	def main():
   71	    gtk.main()
   72	    return 0
   73	
   74	if __name__ == "__main__":
   75	    SetSelectionExample()
   76	    main()