Fix the drag-and-drop of terminals/text back to pre-port functionality - a real pain this one (gtk2->gtk3)

This commit is contained in:
Stephen Boddy 2015-07-12 22:06:36 +02:00
parent 8b566b9859
commit d56da596b3
2 changed files with 71 additions and 42 deletions

View File

@ -8,7 +8,7 @@ import sys
import os
import signal
import gi
from gi.repository import GLib, GObject, Pango, Gtk, Gdk
from gi.repository import GLib, GObject, Pango, Gtk, Gdk, cairo
gi.require_version('Vte', '2.91') # vte-0.38 (gnome-3.14)
from gi.repository import Vte
import subprocess
@ -128,7 +128,7 @@ class Terminal(Gtk.VBox):
self.pending_on_vte_size_allocate = False
self.vte = Vte.Terminal()
self.vte._expose_data = None
self.vte._draw_data = None
if not hasattr(self.vte, "set_opacity") or \
not hasattr(self.vte, "is_composited"):
self.composite_support = False
@ -363,18 +363,40 @@ class Terminal(Gtk.VBox):
dsttargets = [("vte", Gtk.TargetFlags.SAME_APP, self.TARGET_TYPE_VTE),
('text/x-moz-url', 0, 0),
('_NETSCAPE_URL', 0, 0)]
# dsttargets = Gtk.target_list_add_text_targets(dsttargets) # FIXME FOR GTK3
# dsttargets = Gtk.target_list_add_uri_targets(dsttargets)
'''
The following should work, but on my system it corrupts the returned
TargetEntry's in the newdstargets with binary crap, causing "Segmentation
fault (core dumped)" when the later drag_dest_set gets called.
dsttargetlist = Gtk.TargetList.new([])
dsttargetlist.add_text_targets(0)
dsttargetlist.add_uri_targets(0)
dsttargetlist.add_table(dsttargets)
newdsttargets = Gtk.target_table_new_from_list(dsttargetlist)
'''
# FIXME: Temporary workaround for the problems with the correct way of doing things
dsttargets.extend([('text/plain', 0, 0),
('text/plain;charset=utf-8', 0, 0),
('TEXT', 0, 0),
('STRING', 0, 0),
('UTF8_STRING', 0, 0),
('COMPOUND_TEXT', 0, 0),
('text/uri-list', 0, 0)])
# Convert to target entries
srcvtetargets = [Gtk.TargetEntry.new(*tgt) for tgt in srcvtetargets]
dsttargets = [Gtk.TargetEntry.new(*tgt) for tgt in dsttargets]
dbg('Finalised drag targets: %s' % dsttargets)
# for (widget, mask) in [
# (self.vte, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.BUTTON3_MASK),
# (self.titlebar, Gdk.ModifierType.BUTTON1_MASK)]:
# widget.drag_source_set(mask, srcvtetargets, Gdk.DragAction.MOVE) # FIXME FOR GTK3
#
# self.vte.drag_dest_set(Gtk.DestDefaults.MOTION |
# Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
# dsttargets, Gdk.DragAction.COPY | Gdk.DragAction.MOVE) # FIXME FOR GTK3
for (widget, mask) in [
(self.vte, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.BUTTON3_MASK),
(self.titlebar, Gdk.ModifierType.BUTTON1_MASK)]:
widget.drag_source_set(mask, srcvtetargets, Gdk.DragAction.MOVE)
self.vte.drag_dest_set(Gtk.DestDefaults.MOTION |
Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
dsttargets, Gdk.DragAction.COPY | Gdk.DragAction.MOVE)
for widget in [self.vte, self.titlebar]:
widget.connect('drag-begin', self.on_drag_begin, self)
@ -919,29 +941,28 @@ class Terminal(Gtk.VBox):
def on_drag_begin(self, widget, drag_context, _data):
"""Handle the start of a drag event"""
widget.drag_source_set_icon_pixbuf(util.widget_pixbuf(self, 512))
Gtk.drag_set_icon_pixbuf(drag_context, util.widget_pixbuf(self, 512), 0, 0)
def on_drag_data_get(self, _widget, _drag_context, selection_data, info,
_time, data):
"""I have no idea what this does, drag and drop is a mystery. sorry."""
selection_data.set('vte', info,
selection_data.set(Gdk.atom_intern('vte', False), info,
str(data.terminator.terminals.index(self)))
def on_drag_motion(self, widget, drag_context, x, y, _time, _data):
"""*shrug*"""
if not drag_context.targets == ['vte'] and \
(Gtk.targets_include_text(drag_context.targets) or \
Gtk.targets_include_uri(drag_context.targets)):
if not drag_context.list_targets() == [Gdk.atom_intern('vte', False)] and \
(Gtk.targets_include_text(drag_context.list_targets()) or \
Gtk.targets_include_uri(drag_context.list_targets())):
# copy text from another widget
return
srcwidget = drag_context.get_source_widget()
srcwidget = Gtk.drag_get_source_widget(drag_context)
if(isinstance(srcwidget, Gtk.EventBox) and
srcwidget == self.titlebar) or widget == srcwidget:
# on self
return
alloc = widget.get_allocation()
rect = (0, 0, alloc.width, alloc.height)
if self.config['use_theme_colors']:
color = self.vte.get_style_context().get_color(Gtk.StateType.NORMAL) # VERIFY FOR GTK3 as above
@ -970,24 +991,23 @@ class Terminal(Gtk.VBox):
coord = (bottomleft, bottomright, middleright , middleleft)
#here, we define some widget internal values
widget._expose_data = { 'color': color, 'coord' : coord }
widget._draw_data = { 'color': color, 'coord' : coord }
#redraw by forcing an event
connec = widget.connect_after('expose-event', self.on_expose_event)
widget.window.invalidate_rect(rect, True)
widget.window.process_updates(True)
connec = widget.connect_after('draw', self.on_draw)
widget.queue_draw_area(0, 0, alloc.width, alloc.height)
widget.get_window().process_updates(True)
#finaly reset the values
widget.disconnect(connec)
widget._expose_data = None
widget._draw_data = None
def on_expose_event(self, widget, _event):
def on_draw(self, widget, context):
"""Handle an expose event while dragging"""
if not widget._expose_data:
if not widget._draw_data:
return(False)
color = widget._expose_data['color']
coord = widget._expose_data['coord']
color = widget._draw_data['color']
coord = widget._draw_data['coord']
context = widget.window.cairo_create()
context.set_source_rgba(color.red, color.green, color.blue, 0.5)
if len(coord) > 0 :
context.move_to(coord[len(coord)-1][0], coord[len(coord)-1][1])
@ -1001,11 +1021,11 @@ class Terminal(Gtk.VBox):
_info, _time, data):
"""Something has been dragged into the terminal. Handle it as either a
URL or another terminal."""
dbg('drag data received of type: %s' % selection_data.type)
if Gtk.targets_include_text(drag_context.targets) or \
Gtk.targets_include_uri(drag_context.targets):
dbg('drag data received of type: %s' % (selection_data.get_data_type()))
if Gtk.targets_include_text(drag_context.list_targets()) or \
Gtk.targets_include_uri(drag_context.list_targets()):
# copy text to destination
txt = selection_data.data.strip(' ')
txt = selection_data.get_data().strip(' ')
if txt[0:7] == 'file://':
txt = "'%s'" % urllib.unquote(txt[7:])
else:
@ -1014,8 +1034,8 @@ class Terminal(Gtk.VBox):
term.feed(txt)
return
widgetsrc = data.terminator.terminals[int(selection_data.data)]
srcvte = drag_context.get_source_widget()
widgetsrc = data.terminator.terminals[int(selection_data.get_data())]
srcvte = Gtk.drag_get_source_widget(drag_context)
#check if computation requireds
if (isinstance(srcvte, Gtk.EventBox) and
srcvte == self.titlebar) or srcvte == widget:

View File

@ -24,7 +24,8 @@
"""
import sys
from gi.repository import Gtk
from gi.repository import Gtk, Gdk
import cairo
import os
import pwd
import inspect
@ -142,11 +143,9 @@ def shell_lookup():
def widget_pixbuf(widget, maxsize=None):
"""Generate a pixbuf of a widget"""
pixmap = widget.get_snapshot()
(width, height) = pixmap.get_size()
pixbuf = GdkPixbuf.Pixbuf(GdkPixbuf.Colorspace.RGB, False, 8, width, height)
pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width,
height)
# FIXME: Can this be changed from using "import cairo" to "from gi.repository import cairo"?
window = widget.get_window()
width, height = window.get_width(), window.get_height()
longest = max(width, height)
@ -156,7 +155,17 @@ def widget_pixbuf(widget, maxsize=None):
if not maxsize or (width * factor) > width or (height * factor) > height:
factor = 1
scaledpixbuf = pixbuf.scale_simple(int(width * factor), int(height * factor), GdkPixbuf.InterpType.BILINEAR)
preview_width, preview_height = int(width * factor), int(height * factor)
preview_surface = Gdk.Window.create_similar_surface(window,
cairo.CONTENT_COLOR, preview_width, preview_height)
cairo_context = cairo.Context(preview_surface)
cairo_context.scale(factor, factor)
Gdk.cairo_set_source_window(cairo_context, window, 0, 0)
cairo_context.paint()
scaledpixbuf = Gdk.pixbuf_get_from_surface(preview_surface, 0, 0, preview_width, preview_height);
return(scaledpixbuf)