1#!/usr/bin/env python 2'''Drag and Drop 3 4This is a test of the drag and drop capabilities of gtk. It is a 5fairly straight forward port of the example distributed with gtk. 6''' 7 8import pygtk 9pygtk.require('2.0') 10import gtk 11import gobject 12 13from dndpixmap import drag_icon_xpm, trashcan_open_xpm, trashcan_closed_xpm 14 15TARGET_STRING = 0 16TARGET_ROOTWIN = 1 17 18target = [ 19 ('STRING', 0, TARGET_STRING), 20 ('text/plain', 0, TARGET_STRING), 21 ('application/x-rootwin-drop', 0, TARGET_ROOTWIN) 22] 23 24def create_pixmap(widget, xpm_data): 25 return \ 26 gtk.gdk.pixmap_colormap_create_from_xpm_d( 27 None, widget.get_colormap(), None, xpm_data) 28 29class DragAndDropDemo(gtk.Window): 30 trashcan_open = None 31 trashcan_open_mask = None 32 trashcan_closed = None 33 trashcan_closed_mask = None 34 drag_icon = None 35 drag_mask = None 36 have_drag = False 37 popped_up = False 38 in_popup = False 39 popup_timer = 0 40 popdown_timer = 0 41 popup_win = None 42 43 def __init__(self, parent=None): 44 gtk.Window.__init__(self) 45 try: 46 self.set_screen(parent.get_screen()) 47 except AttributeError: 48 self.connect('destroy', lambda *w: gtk.main_quit()) 49 self.set_title(self.__class__.__name__) 50 51 table = gtk.Table(2,2) 52 self.add(table) 53 54 self.drag_icon, self.drag_mask = \ 55 create_pixmap(self, drag_icon_xpm) 56 self.trashcan_open, self.trashcan_open_mask = \ 57 create_pixmap(self, trashcan_open_xpm) 58 self.trashcan_closed, self.trashcan_closed_mask = \ 59 create_pixmap(self, trashcan_closed_xpm) 60 61 label = gtk.Label('Drop to Trashcan!\n') 62 label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], 63 gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) 64 label.connect('drag_data_received', self.label_drag_data_received) 65 table.attach(label, 0, 1, 0, 1) 66 67 label = gtk.Label('Popup\n') 68 label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], 69 gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) 70 table.attach(label, 1, 2, 1, 2) 71 label.connect('drag_motion', self.popsite_motion) 72 label.connect('drag_leave', self.popsite_leave) 73 74 image = gtk.Image() 75 image.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) 76 image.drag_dest_set(0, [], 0) 77 table.attach(image, 1, 2, 0, 1) 78 image.connect('drag_leave', self.target_drag_leave) 79 image.connect('drag_motion', self.target_drag_motion) 80 image.connect('drag_drop', self.target_drag_drop) 81 image.connect('drag_data_received', self.target_drag_data_received) 82 83 b = gtk.Button('Drag from Here\n') 84 b.drag_source_set(gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, 85 target, gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) 86 b.drag_source_set_icon(self.get_colormap(), self.drag_icon, self.drag_mask) 87 table.attach(b, 0, 1, 1, 2) 88 b.connect('drag_data_get', self.source_drag_data_get) 89 b.connect('drag_data_delete', self.source_drag_data_delete) 90 self.show_all() 91 92 def label_drag_data_received(self, w, context, x, y, data, info, time): 93 if data and data.format == 8: 94 print 'Received "%s" in label' % data.data 95 context.finish(True, False, time) 96 else: 97 context.finish(False, False, time) 98 99 def popsite_motion(self, w, context, x, y, time): 100 if not self.popup_timer: 101 self.popup_timer = gobject.timeout_add(500, self.popup_cb) 102 return True 103 104 def popsite_leave(self, w, context, time): 105 if self.popup_timer: 106 gobject.source_remove(self.popup_timer) 107 self.popup_timer = 0 108 109 def popup_motion(self, w, context, x, y, time): 110 print 'popup_motion' 111 if not self.in_popup: 112 self.in_popup = True 113 if self.popdown_timer: 114 print 'removed popdown' 115 gobject.source_remove(self.popdown_timer) 116 self.popdown_timer = 0 117 return True 118 119 def popup_leave(self, w, context, time): 120 print 'popup_leave' 121 if self.in_popup: 122 self.in_popup = False 123 if not self.popdown_timer: 124 print 'added popdown' 125 self.popdown_timer = gobject.timeout_add(500, self.popdown_cb) 126 127 def popup_cb(self): 128 if not self.popped_up: 129 if self.popup_win is None: 130 self.popup_win = gtk.Window(gtk.WINDOW_POPUP) 131 self.popup_win.set_position(gtk.WIN_POS_MOUSE) 132 table = gtk.Table(3, 3) 133 for k in range(9): 134 i, j = divmod(k, 3) 135 b = gtk.Button("%d,%d" % (i,j)) 136 b.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], 137 gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) 138 b.connect('drag_motion', self.popup_motion) 139 b.connect('drag_leave', self.popup_leave) 140 table.attach(b, i, i+1, j, j+1) 141 table.show_all() 142 self.popup_win.add(table) 143 self.popup_win.present() 144 self.popped_up = True 145 self.popdown_timer = gobject.timeout_add(500, self.popdown_cb) 146 print 'added popdown' 147 self.popup_timer = 0 148 return False 149 150 def popdown_cb(self): 151 print 'popdown' 152 #if self.in_popup: 153 # return True 154 self.popdown_timer = 0 155 self.popup_win.hide() 156 self.popped_up = False 157 return False 158 159 def target_drag_leave(self, img, context, time): 160 print 'leave' 161 self.have_drag = False 162 img.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) 163 164 def target_drag_motion(self, img, context, x, y, time): 165 if self.have_drag is False: 166 self.have_drag = True 167 img.set_from_pixmap(self.trashcan_open, self.trashcan_open_mask) 168 source_widget = context.get_source_widget() 169 print 'motion, source ', 170 if source_widget: 171 print source_widget.__class__.__name__ 172 else: 173 print 'unknown' 174 context.drag_status(context.suggested_action, time) 175 return True 176 177 def target_drag_drop(self, img, context, x, y, time): 178 print 'drop' 179 self.have_drag = False 180 img.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) 181 if context.targets: 182 img.drag_get_data(context, context.targets[0], time) 183 return True 184 return False 185 186 def target_drag_data_received(self, img, context, x, y, data, info, time): 187 if data.format == 8: 188 print 'Received "%s" in trashcan' % data.data 189 context.finish(True, False, time) 190 else: 191 context.finish(False, False, time) 192 193 def source_drag_data_get(self, btn, context, selection_data, info, time): 194 if info == TARGET_ROOTWIN: 195 print 'I was dropped on the rootwin' 196 else: 197 selection_data.set(selection_data.target, 8, "I'm Data!") 198 199 def source_drag_data_delete(self, btn, context, data): 200 print 'Delete the data!' 201 202def main(): 203 DragAndDropDemo() 204 gtk.main() 205 206if __name__ == '__main__': 207 main() 208