20.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 GtkSelectionData is the same as above, but this time, we're responsible for filling in the fields type, format, data, and length. (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(SELECTION_TYPE_INTEGER, 32, data)

When prompted by the user, you claim ownership of the selection by calling:
 
result = widget.selection_owner_set(selection, time)

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. 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 20.2 illustrates the program display when the program has taken the primary selection ownership:

Figure 20.2 Set Selection Example

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