First pass for GTK 3 and Python 3.

Still some bugs to fix but we can diff files.
Need tests with non-utf8 files.
This commit is contained in:
Romain Failliot 2016-07-03 20:22:54 -04:00
parent 4d54a00041
commit 18328c98c3
1 changed files with 139 additions and 118 deletions

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2006-2014 Derrick Moser <derrick_moser@yahoo.com> # Copyright (C) 2006-2014 Derrick Moser <derrick_moser@yahoo.com>
@ -69,22 +69,15 @@ VERSION = '0.4.8'
COPYRIGHT = _('Copyright © 2006-2014 Derrick Moser') COPYRIGHT = _('Copyright © 2006-2014 Derrick Moser')
WEBSITE = 'http://diffuse.sourceforge.net/' WEBSITE = 'http://diffuse.sourceforge.net/'
# print a UTF-8 string using the host's native encoding
def printMessage(s):
try:
print(codecs.encode(unicode(s, 'utf_8'), sys.getfilesystemencoding()))
except UnicodeEncodeError:
pass
# process help options # process help options
if __name__ == '__main__': if __name__ == '__main__':
args = sys.argv args = sys.argv
argc = len(args) argc = len(args)
if argc == 2 and args[1] in [ '-v', '--version' ]: if argc == 2 and args[1] in [ '-v', '--version' ]:
printMessage('%s %s\n%s' % (APP_NAME, VERSION, COPYRIGHT)) print('%s %s\n%s' % (APP_NAME, VERSION, COPYRIGHT))
sys.exit(0) sys.exit(0)
if argc == 2 and args[1] in [ '-h', '-?', '--help' ]: if argc == 2 and args[1] in [ '-h', '-?', '--help' ]:
printMessage(_('''Usage: print(_('''Usage:
diffuse [ [OPTION...] [FILE...] ]... diffuse [ [OPTION...] [FILE...] ]...
diffuse ( -h | -? | --help | -v | --version ) diffuse ( -h | -? | --help | -v | --version )
@ -123,8 +116,15 @@ Display Options:
( -w | --ignore-all-space ) Ignore white space differences''')) ( -w | --ignore-all-space ) Ignore white space differences'''))
sys.exit(0) sys.exit(0)
import pygtk import gi
pygtk.require('2.0') from gi import pygtkcompat
pygtkcompat.enable()
pygtkcompat.enable_gtk(version='3.0')
from gi.repository import PangoCairo
gi.require_version('PangoCairo', '1.0')
import gtk import gtk
import difflib import difflib
@ -279,7 +279,7 @@ def readlines(fd):
return strip_eols(splitlines(fd.read())) return strip_eols(splitlines(fd.read()))
def readconfiglines(fd): def readconfiglines(fd):
return unicode(fd.read(), 'utf_8').replace(u'\r', u'').split(u'\n') return fd.read().replace(u'\r', u'').split(u'\n')
# This class to hold all customisable behaviour not exposed in the preferences # This class to hold all customisable behaviour not exposed in the preferences
# dialogue: hotkey assignment, colours, syntax highlighting, etc. # dialogue: hotkey assignment, colours, syntax highlighting, etc.
@ -464,7 +464,7 @@ class Resources:
# keyboard action processing # keyboard action processing
def setKeyBinding(self, ctx, s, v): def setKeyBinding(self, ctx, s, v):
action_tuple = (ctx, s) action_tuple = (ctx, s)
modifiers = 0 modifiers = gtk.gdk.ModifierType(0)
key = None key = None
for token in v.split('+'): for token in v.split('+'):
if token == 'Shift': if token == 'Shift':
@ -559,7 +559,7 @@ class Resources:
# syntax highlighting # syntax highlighting
def getSyntaxNames(self): def getSyntaxNames(self):
return self.syntaxes.keys() return list(self.syntaxes.keys())
def getSyntax(self, name): def getSyntax(self, name):
return self.syntaxes.get(name, None) return self.syntaxes.get(name, None)
@ -758,7 +758,7 @@ class FileEntry(gtk.HBox):
# action performed when the pick file button is pressed # action performed when the pick file button is pressed
def chooseFile(self, widget): def chooseFile(self, widget):
dialog = gtk.FileChooserDialog(self.title, self.toplevel, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog = gtk.FileChooserDialog(self.title, self.toplevel, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
dialog.set_current_folder(unicode(os.path.realpath(os.curdir), sys.getfilesystemencoding())) dialog.set_current_folder(os.path.realpath(os.curdir))
if dialog.run() == gtk.RESPONSE_OK: if dialog.run() == gtk.RESPONSE_OK:
self.entry.set_text(dialog.get_filename()) self.entry.set_text(dialog.get_filename())
dialog.destroy() dialog.destroy()
@ -1118,11 +1118,11 @@ class Preferences:
for encoding in self._getDefaultEncodings(): for encoding in self._getDefaultEncodings():
try: try:
for m in magic.get(encoding.lower().replace('-', '').replace('_', ''), [ '' ]): for m in magic.get(encoding.lower().replace('-', '').replace('_', ''), [ '' ]):
if s.startswith(m): if str(s).startswith(m):
break break
else: else:
continue continue
return unicode(s, encoding), encoding return str(s, encoding=encoding), encoding
except (UnicodeDecodeError, LookupError): except (UnicodeDecodeError, LookupError):
pass pass
return u''.join([ unichr(ord(c)) for c in s ]), None return u''.join([ unichr(ord(c)) for c in s ]), None
@ -1130,7 +1130,6 @@ class Preferences:
# cygwin and native applications can be used on windows, use this method # cygwin and native applications can be used on windows, use this method
# to convert a path to the usual form expected on sys.platform # to convert a path to the usual form expected on sys.platform
def convertToNativePath(self, s): def convertToNativePath(self, s):
s = unicode(s, sys.getfilesystemencoding())
if isWindows() and s.find('/') >= 0: if isWindows() and s.find('/') >= 0:
# treat as a cygwin path # treat as a cygwin path
s = s.replace(os.sep, '/') s = s.replace(os.sep, '/')
@ -1185,10 +1184,11 @@ def createMenu(specs, radio=None, accel_group=None):
item.set_sensitive(spec[5]) item.set_sensitive(spec[5])
if len(spec) > 6 and spec[6] is not None: if len(spec) > 6 and spec[6] is not None:
item.set_submenu(createMenu(spec[6], radio, accel_group)) item.set_submenu(createMenu(spec[6], radio, accel_group))
item.set_use_underline(True)
else: else:
item = gtk.SeparatorMenuItem() item = gtk.SeparatorMenuItem()
menu.append(item)
item.show() item.show()
menu.append(item)
return menu return menu
# convenience method for creating a menu bar according to a template # convenience method for creating a menu bar according to a template
@ -1197,8 +1197,9 @@ def createMenuBar(specs, radio, accel_group):
for label, spec in specs: for label, spec in specs:
menu = gtk.MenuItem(label) menu = gtk.MenuItem(label)
menu.set_submenu(createMenu(spec, radio, accel_group)) menu.set_submenu(createMenu(spec, radio, accel_group))
menu_bar.append(menu) menu.set_use_underline(True)
menu.show() menu.show()
menu_bar.append(menu)
return menu_bar return menu_bar
# convenience method to set a widget's tooltip # convenience method to set a widget's tooltip
@ -1218,7 +1219,7 @@ def appendButtons(box, size, specs):
if len(spec) > 0: if len(spec) > 0:
button = gtk.Button() button = gtk.Button()
button.set_relief(gtk.RELIEF_NONE) button.set_relief(gtk.RELIEF_NONE)
button.unset_flags(gtk.CAN_FOCUS) button.set_can_focus(False)
image = gtk.Image() image = gtk.Image()
image.set_from_stock(spec[0], size) image.set_from_stock(spec[0], size)
button.add(image) button.add(image)
@ -2675,8 +2676,8 @@ theVCSs = VCSs()
def step_adjustment(adj, delta): def step_adjustment(adj, delta):
v = adj.get_value() + delta v = adj.get_value() + delta
# clamp to the allowed range # clamp to the allowed range
v = max(v, int(adj.lower)) v = max(v, int(adj.get_lower()))
v = min(v, int(adj.upper - adj.page_size)) v = min(v, int(adj.get_upper() - adj.get_page_size()))
adj.set_value(v) adj.set_value(v)
# This is a replacement for gtk.ScrolledWindow as it forced expose events to be # This is a replacement for gtk.ScrolledWindow as it forced expose events to be
@ -2694,6 +2695,7 @@ class ScrolledWindow(gtk.Table):
self.hadj, self.vadj = hadj, vadj self.hadj, self.vadj = hadj, vadj
vport = gtk.Viewport() vport = gtk.Viewport()
darea = gtk.DrawingArea() darea = gtk.DrawingArea()
darea.add_events(gtk.gdk.SCROLL_MASK)
self.darea = darea self.darea = darea
# replace darea's queue_draw_area with our own so we can tell when # replace darea's queue_draw_area with our own so we can tell when
# to disable/enable our scrolling optimisation # to disable/enable our scrolling optimisation
@ -2717,17 +2719,17 @@ class ScrolledWindow(gtk.Table):
vadj.connect('value-changed', self.value_changed_cb) vadj.connect('value-changed', self.value_changed_cb)
darea.connect('configure-event', self.configure_cb) darea.connect('configure-event', self.configure_cb)
darea.connect('scroll-event', self.scroll_cb) darea.connect('scroll-event', self.scroll_cb)
darea.connect('expose-event', self.expose_cb) darea.connect('draw', self.draw_cb)
# updates the adjustments to match the new widget size # updates the adjustments to match the new widget size
def configure_cb(self, widget, event): def configure_cb(self, widget, event):
w, h = event.width, event.height w, h = event.width, event.height
for adj, d in (self.hadj, w), (self.vadj, h): for adj, d in (self.hadj, w), (self.vadj, h):
v = adj.get_value() v = adj.get_value()
if v + d > adj.upper: if v + d > adj.get_upper():
adj.set_value(max(0, adj.upper - d)) adj.set_value(max(0, adj.get_upper() - d))
adj.page_size = d adj.set_page_size(d)
adj.page_increment = d adj.set_page_increment(d)
# update the vertical adjustment when the mouse's scroll wheel is used # update the vertical adjustment when the mouse's scroll wheel is used
def scroll_cb(self, widget, event): def scroll_cb(self, widget, event):
@ -2760,7 +2762,7 @@ class ScrolledWindow(gtk.Table):
self.partial_redraw = False self.partial_redraw = False
self.darea.queue_draw() self.darea.queue_draw()
def expose_cb(self, widget, event): def draw_cb(self, widget, cr):
self.scroll_count = 0 self.scroll_count = 0
# replacement for darea.queue_draw_area that notifies us when a partial # replacement for darea.queue_draw_area that notifies us when a partial
@ -3222,7 +3224,7 @@ class FileDiffViewer(gtk.Table):
raise ValueError('Invalid number of panes') raise ValueError('Invalid number of panes')
gtk.Table.__init__(self, 3, n + 1) gtk.Table.__init__(self, 3, n + 1)
self.set_flags(gtk.CAN_FOCUS) self.set_can_focus(True)
self.prefs = prefs self.prefs = prefs
self.string_width_cache = {} self.string_width_cache = {}
self.options = {} self.options = {}
@ -3345,10 +3347,11 @@ class FileDiffViewer(gtk.Table):
# pane contents # pane contents
sw = ScrolledWindow(self.hadj, self.vadj) sw = ScrolledWindow(self.hadj, self.vadj)
darea = sw.darea darea = sw.darea
darea.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON1_MOTION_MASK) darea.add_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON1_MOTION_MASK)
darea.connect('button-press-event', self.darea_button_press_cb, i) darea.connect('button-press-event', self.darea_button_press_cb, i)
darea.connect('motion-notify-event', self.darea_motion_notify_cb, i) darea.connect('motion-notify-event', self.darea_motion_notify_cb, i)
darea.connect('expose-event', self.darea_expose_cb, i) darea.connect('draw', self.darea_draw_cb, i)
self.dareas.append(darea) self.dareas.append(darea)
self.attach(sw, i, i + 1, 1, 2) self.attach(sw, i, i + 1, 1, 2)
sw.show() sw.show()
@ -3358,11 +3361,13 @@ class FileDiffViewer(gtk.Table):
# add diff map # add diff map
self.map = map = gtk.DrawingArea() self.map = map = gtk.DrawingArea()
map.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON1_MOTION_MASK) map.add_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON1_MOTION_MASK |
gtk.gdk.SCROLL_MASK)
map.connect('button-press-event', self.map_button_press_cb) map.connect('button-press-event', self.map_button_press_cb)
map.connect('motion-notify-event', self.map_button_press_cb) map.connect('motion-notify-event', self.map_button_press_cb)
map.connect('scroll-event', self.map_scroll_cb) map.connect('scroll-event', self.map_scroll_cb)
map.connect('expose-event', self.map_expose_cb) map.connect('draw', self.map_draw_cb)
self.attach(map, n, n + 1, 1, 2, gtk.FILL, gtk.FILL) self.attach(map, n, n + 1, 1, 2, gtk.FILL, gtk.FILL)
map.show() map.show()
map.set_size_request(16 * n, 0) map.set_size_request(16 * n, 0)
@ -3386,6 +3391,12 @@ class FileDiffViewer(gtk.Table):
self.setFont(pango.FontDescription(prefs.getString('display_font'))) self.setFont(pango.FontDescription(prefs.getString('display_font')))
self.cursor_pos = (0, 0) self.cursor_pos = (0, 0)
# Contextual menu
self.ctxMenu = gtk.Menu()
menuItem = gtk.MenuItem("Test")
menuItem.show()
self.ctxMenu.append(menuItem)
# scroll to first difference when realised # scroll to first difference when realised
darea.connect_after('realize', self._realise_cb) darea.connect_after('realize', self._realise_cb)
@ -3693,9 +3704,9 @@ class FileDiffViewer(gtk.Table):
width = pixels(width) width = pixels(width)
height = self.font_height * num_lines height = self.font_height * num_lines
# update the adjustments # update the adjustments
self.hadj.upper = width self.hadj.set_upper(width)
self.hadj.step_increment = self.font_height self.hadj.step_increment = self.font_height
self.vadj.upper = height self.vadj.set_upper(height)
self.vadj.step_increment = self.font_height self.vadj.step_increment = self.font_height
# returns a line from the specified pane and offset # returns a line from the specified pane and offset
@ -4511,7 +4522,7 @@ class FileDiffViewer(gtk.Table):
upper = lower + h upper = lower + h
vadj = self.vadj vadj = self.vadj
v = vadj.get_value() v = vadj.get_value()
ps = vadj.page_size ps = vadj.get_page_size()
if lower < v: if lower < v:
vadj.set_value(lower) vadj.set_value(lower)
elif upper > v + ps: elif upper > v + ps:
@ -4574,7 +4585,13 @@ class FileDiffViewer(gtk.Table):
x, y = self.dareas[self.current_pane].translate_coordinates(self.get_toplevel(), x, y) x, y = self.dareas[self.current_pane].translate_coordinates(self.get_toplevel(), x, y)
# input methods support widgets are centred horizontally about the # input methods support widgets are centred horizontally about the
# cursor, a width of 50 seems to give a better widget positions # cursor, a width of 50 seems to give a better widget positions
self.im_context.set_cursor_location((x, y, 50, h)) rect = gtk.gdk.Rectangle()
rect.x = x
rect.y = y
rect.width = 50
rect.height = h
self.im_context.set_cursor_location(rect)
# get the position of the cursor in pango units # get the position of the cursor in pango units
def _get_cursor_x_offset(self): def _get_cursor_x_offset(self):
@ -4599,7 +4616,7 @@ class FileDiffViewer(gtk.Table):
# scroll horizontally # scroll horizontally
hadj = self.hadj hadj = self.hadj
v = hadj.get_value() v = hadj.get_value()
ps = hadj.page_size ps = hadj.get_page_size()
if lower < v: if lower < v:
hadj.set_value(lower) hadj.set_value(lower)
elif upper > v + ps: elif upper > v + ps:
@ -4736,7 +4753,7 @@ class FileDiffViewer(gtk.Table):
i = min(y // self.font_height, nlines) i = min(y // self.font_height, nlines)
if event.button == 1: if event.button == 1:
# left mouse button # left mouse button
if event.type == gtk.gdk._2BUTTON_PRESS: if event.type == gtk.gdk.EventType._2BUTTON_PRESS:
# double click # double click
if self.mode == ALIGN_MODE: if self.mode == ALIGN_MODE:
self.setLineMode() self.setLineMode()
@ -4763,7 +4780,7 @@ class FileDiffViewer(gtk.Table):
while j < n and getCharacterClass(text[j]) == c: while j < n and getCharacterClass(text[j]) == c:
j += 1 j += 1
self.setCurrentChar(i, j, i, k) self.setCurrentChar(i, j, i, k)
elif event.type == gtk.gdk._3BUTTON_PRESS: elif event.type == gtk.gdk.EventType._3BUTTON_PRESS:
# triple click, select a whole line # triple click, select a whole line
if self.mode == CHAR_MODE and self.current_pane == f: if self.mode == CHAR_MODE and self.current_pane == f:
i2 = min(i + 1, nlines) i2 = min(i + 1, nlines)
@ -4801,7 +4818,8 @@ class FileDiffViewer(gtk.Table):
[_('Clear Edits'), self.button_cb, 'clear_edits', gtk.STOCK_CLEAR, None, can_isolate], [_('Clear Edits'), self.button_cb, 'clear_edits', gtk.STOCK_CLEAR, None, can_isolate],
[], [],
[_('Swap with Selected Pane'), self.swap_panes_cb, f, None, None, can_swap] ]) [_('Swap with Selected Pane'), self.swap_panes_cb, f, None, None, can_swap] ])
menu.popup(None, None, None, event.button, event.time) menu.attach_to_widget(self)
menu.popup(None, None, None, None, event.button, event.time)
# callback used to notify us about click and drag motion # callback used to notify us about click and drag motion
def darea_motion_notify_cb(self, widget, event, f): def darea_motion_notify_cb(self, widget, event, f):
@ -4931,22 +4949,23 @@ class FileDiffViewer(gtk.Table):
return s return s
# draw the text viewport # draw the text viewport
def darea_expose_cb(self, widget, event, f): def darea_draw_cb(self, widget, cr, f):
pane = self.panes[f] pane = self.panes[f]
syntax = theResources.getSyntax(self.syntax) syntax = theResources.getSyntax(self.syntax)
offset_x, offset_y, width, height = event.area #offset_x, offset_y, width, height = widget.get_allocation()
x = offset_x + int(self.hadj.get_value()) rect = widget.get_allocation()
y = offset_y + int(self.vadj.get_value()) x = rect.x + int(self.hadj.get_value())
y = rect.y + int(self.vadj.get_value())
# draw to a pixmap to avoid screen flicker # draw to a pixmap to avoid screen flicker
pixmap = gtk.gdk.Pixmap(widget.window, width, height) #pixmap = gtk.gdk.Pixmap(widget.window, width, height)
cr = pixmap.cairo_create() #cr = pixmap.cairo_create()
cr.translate(-x, -y) cr.translate(-x, -y)
maxx = x + width maxx = x + rect.width
maxy = y + height maxy = y + rect.height
line_number_width = pixels(self.getLineNumberWidth()) line_number_width = pixels(self.getLineNumberWidth())
h = self.font_height h = self.font_height
@ -4976,7 +4995,8 @@ class FileDiffViewer(gtk.Table):
layout.set_font_description(self.font) layout.set_font_description(self.font)
w = pixels(layout.get_size()[0] + self.digit_width) w = pixels(layout.get_size()[0] + self.digit_width)
cr.move_to(line_number_width - w, y_start) cr.move_to(line_number_width - w, y_start)
cr.show_layout(layout) #cr.show_layout(layout)
PangoCairo.show_layout(cr, layout)
cr.restore() cr.restore()
x_start = line_number_width x_start = line_number_width
@ -5218,12 +5238,14 @@ class FileDiffViewer(gtk.Table):
layout = self.create_pango_layout(''.join(ss[starti:self.current_char])) layout = self.create_pango_layout(''.join(ss[starti:self.current_char]))
layout.set_font_description(self.font) layout.set_font_description(self.font)
cr.move_to(x_start + pixels(start), y_start) cr.move_to(x_start + pixels(start), y_start)
cr.show_layout(layout) #cr.show_layout(layout)
PangoCairo.show_layout(cr, layout)
start += layout.get_size()[0] + preeditwidth start += layout.get_size()[0] + preeditwidth
layout = self.create_pango_layout(''.join(ss[self.current_char:endi])) layout = self.create_pango_layout(''.join(ss[self.current_char:endi]))
layout.set_font_description(self.font) layout.set_font_description(self.font)
cr.move_to(x_start + pixels(start), y_start) cr.move_to(x_start + pixels(start), y_start)
cr.show_layout(layout) #cr.show_layout(layout)
PangoCairo.show_layout(cr, layout)
if self.current_pane == f and self.current_line == i: if self.current_pane == f and self.current_line == i:
# draw the cursor and preedit text # draw the cursor and preedit text
@ -5243,7 +5265,8 @@ class FileDiffViewer(gtk.Table):
colour = theResources.getColour('preedit') colour = theResources.getColour('preedit')
cr.set_source_rgb(colour.red, colour.green, colour.blue) cr.set_source_rgb(colour.red, colour.green, colour.blue)
cr.move_to(x_pos, y_start) cr.move_to(x_pos, y_start)
cr.show_layout(layout) #cr.show_layout(layout)
PangoCairo.show_layout(cr, layout)
# advance to the preedit's cursor position # advance to the preedit's cursor position
x_pos += pixels(self._preedit_layout(True).get_size()[0]) x_pos += pixels(self._preedit_layout(True).get_size()[0])
# draw the character editing cursor # draw the character editing cursor
@ -5269,8 +5292,8 @@ class FileDiffViewer(gtk.Table):
y_start += h y_start += h
# draw the pixmap to window # draw the pixmap to window
gc = pixmap.new_gc() #gc = pixmap.new_gc()
widget.window.draw_drawable(gc, pixmap, 0, 0, offset_x, offset_y, width, height) #widget.window.draw_drawable(gc, pixmap, 0, 0, offset_x, offset_y, width, height)
# callback used when panes are scrolled horizontally # callback used when panes are scrolled horizontally
def hadj_changed_cb(self, adj): def hadj_changed_cb(self, adj):
@ -5286,13 +5309,13 @@ class FileDiffViewer(gtk.Table):
vadj = self.vadj vadj = self.vadj
h = widget.get_allocation().height h = widget.get_allocation().height
hmax = max(int(vadj.upper), h) hmax = max(int(vadj.get_upper()), h)
# centre view about picked location # centre view about picked location
y = event.y * hmax // h y = event.y * hmax // h
v = y - int(vadj.page_size / 2) v = y - int(vadj.get_page_size() / 2)
v = max(v, int(vadj.lower)) v = max(v, int(vadj.get_lower()))
v = min(v, int(vadj.upper - vadj.page_size)) v = min(v, int(vadj.get_upper() - vadj.get_page_size()))
vadj.set_value(v) vadj.set_value(v)
# callback to handle mouse scrollwheel events # callback to handle mouse scrollwheel events
@ -5304,7 +5327,7 @@ class FileDiffViewer(gtk.Table):
step_adjustment(self.vadj, delta) step_adjustment(self.vadj, delta)
# redraws the overview map when a portion is exposed # redraws the overview map when a portion is exposed
def map_expose_cb(self, widget, event): def map_draw_cb(self, widget, cr):
n = len(self.panes) n = len(self.panes)
# compute map if it hasn't already been cached # compute map if it hasn't already been cached
@ -5352,10 +5375,10 @@ class FileDiffViewer(gtk.Table):
self.map_cache[f].append([start[f], nlines, flags[f]]) self.map_cache[f].append([start[f], nlines, flags[f]])
# draw to a pixmap to avoid screen flicker # draw to a pixmap to avoid screen flicker
x, y, width, height = event.area #x, y, width, height = event.area
pixmap = gtk.gdk.Pixmap(widget.window, width, height) #pixmap = gtk.gdk.Pixmap(widget.window, width, height)
cr = pixmap.cairo_create() #cr = pixmap.cairo_create()
cr.translate(-x, -y) #cr.translate(-rect.x, -rect.y)
# clear # clear
colour = theResources.getColour('map_background') colour = theResources.getColour('map_background')
@ -5364,14 +5387,14 @@ class FileDiffViewer(gtk.Table):
bg_colour = theResources.getColour('text_background') bg_colour = theResources.getColour('text_background')
edited_colour = theResources.getColour('edited') edited_colour = theResources.getColour('edited')
rect = widget.get_allocation()
# get scroll position and total size # get scroll position and total size
r = widget.get_allocation()
w, h = r.width, r.height
vadj = self.vadj vadj = self.vadj
hmax = max(vadj.upper, h) hmax = max(vadj.get_upper(), rect.height)
# draw diff blocks # draw diff blocks
wn = w / n wn = rect.width / n
pad = 1 pad = 1
for f in range(n): for f in range(n):
diffcolours = [ theResources.getDifferenceColour(f), theResources.getDifferenceColour(f + 1) ] diffcolours = [ theResources.getDifferenceColour(f), theResources.getDifferenceColour(f + 1) ]
@ -5393,12 +5416,13 @@ class FileDiffViewer(gtk.Table):
continue continue
# ensure the line is visible in the map # ensure the line is visible in the map
ymin = h * self.font_height * start // hmax ymin = rect.height * self.font_height * start // hmax
if ymin >= y + height: if ymin >= rect.y + rect.height:
break break
yh = max(h * self.font_height * end // hmax - ymin, 1) yh = max(rect.height * self.font_height * end // hmax - ymin, 1)
if ymin + yh <= y:
continue #if ymin + yh <= rect.y:
# continue
cr.set_source_rgb(colour.red, colour.green, colour.blue) cr.set_source_rgb(colour.red, colour.green, colour.blue)
cr.rectangle(wx + pad, ymin, wn - 2 * pad, yh) cr.rectangle(wx + pad, ymin, wn - 2 * pad, yh)
@ -5406,28 +5430,28 @@ class FileDiffViewer(gtk.Table):
# draw cursor # draw cursor
vmin = int(vadj.get_value()) vmin = int(vadj.get_value())
vmax = vmin + vadj.page_size vmax = vmin + vadj.get_page_size()
ymin = h * vmin // hmax ymin = rect.height * vmin // hmax
if ymin < y + height: if ymin < rect.y + rect.height:
yh = h * vmax // hmax - ymin yh = rect.height * vmax // hmax - ymin
if yh > 1: if yh > 1:
yh -= 1 yh -= 1
if ymin + yh > y: #if ymin + yh > rect.y:
colour = theResources.getColour('line_selection') colour = theResources.getColour('line_selection')
alpha = theResources.getFloat('line_selection_opacity') alpha = theResources.getFloat('line_selection_opacity')
cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha) cr.set_source_rgba(colour.red, colour.green, colour.blue, alpha)
cr.rectangle(0.5, ymin + 0.5, w - 1, yh - 1) cr.rectangle(0.5, ymin + 0.5, rect.width - 1, yh - 1)
cr.fill() cr.fill()
colour = theResources.getColour('cursor') colour = theResources.getColour('cursor')
cr.set_source_rgb(colour.red, colour.green, colour.blue) cr.set_source_rgb(colour.red, colour.green, colour.blue)
cr.set_line_width(1) cr.set_line_width(1)
cr.rectangle(0.5, ymin + 0.5, w - 1, yh - 1) cr.rectangle(0.5, ymin + 0.5, rect.width - 1, yh - 1)
cr.stroke() cr.stroke()
# draw the pixmap to the window # draw the pixmap to the window
gc = pixmap.new_gc() #gc = pixmap.new_gc()
widget.window.draw_drawable(gc, pixmap, 0, 0, x, y, width, height) #widget.window.draw_drawable(gc, pixmap, 0, 0, x, y, width, height)
# returns the maximum valid offset for a cursor position # returns the maximum valid offset for a cursor position
# cursors cannot be moved to the right of line ending characters # cursors cannot be moved to the right of line ending characters
@ -5499,7 +5523,7 @@ class FileDiffViewer(gtk.Table):
# 'page_up' keybinding action # 'page_up' keybinding action
def _line_mode_page_up(self, selection=None): def _line_mode_page_up(self, selection=None):
delta = int(self.vadj.page_size // self.font_height) delta = int(self.vadj.get_page_size() // self.font_height)
self.setCurrentLine(self.current_pane, self.current_line - delta, selection) self.setCurrentLine(self.current_pane, self.current_line - delta, selection)
# 'extend_page_up' keybinding action # 'extend_page_up' keybinding action
@ -5508,7 +5532,7 @@ class FileDiffViewer(gtk.Table):
# 'page_down' keybinding action # 'page_down' keybinding action
def _line_mode_page_down(self, selection=None): def _line_mode_page_down(self, selection=None):
delta = int(self.vadj.page_size // self.font_height) delta = int(self.vadj.get_page_size() // self.font_height)
self.setCurrentLine(self.current_pane, self.current_line + delta, selection) self.setCurrentLine(self.current_pane, self.current_line + delta, selection)
# 'extend_page_down' keybinding action # 'extend_page_down' keybinding action
@ -5550,7 +5574,7 @@ class FileDiffViewer(gtk.Table):
def im_commit_cb(self, im, s): def im_commit_cb(self, im, s):
if self.mode == CHAR_MODE: if self.mode == CHAR_MODE:
self.openUndoBlock() self.openUndoBlock()
self.replaceText(unicode(s, 'utf_8')) self.replaceText(s)
self.closeUndoBlock() self.closeUndoBlock()
# update the cached preedit text # update the cached preedit text
@ -5571,7 +5595,6 @@ class FileDiffViewer(gtk.Table):
s, a, c = self.im_context.get_preedit_string() s, a, c = self.im_context.get_preedit_string()
if len(s) > 0: if len(s) > 0:
# we have preedit text, draw that instead # we have preedit text, draw that instead
s = unicode(s, 'utf_8')
p = (s, a, c) p = (s, a, c)
else: else:
p = None p = None
@ -5646,7 +5669,7 @@ class FileDiffViewer(gtk.Table):
if event.keyval in [ gtk.keysyms.Up, gtk.keysyms.Down ]: if event.keyval in [ gtk.keysyms.Up, gtk.keysyms.Down ]:
delta = 1 delta = 1
else: else:
delta = int(self.vadj.page_size // self.font_height) delta = int(self.vadj.get_page_size() // self.font_height)
if event.keyval in [ gtk.keysyms.Up, gtk.keysyms.Page_Up ]: if event.keyval in [ gtk.keysyms.Up, gtk.keysyms.Page_Up ]:
delta = -delta delta = -delta
i += delta i += delta
@ -5776,7 +5799,7 @@ class FileDiffViewer(gtk.Table):
self.replaceText('') self.replaceText('')
# return key, add the platform specific end of line characters # return key, add the platform specific end of line characters
elif event.keyval in [ gtk.keysyms.Return, gtk.keysyms.KP_Enter ]: elif event.keyval in [ gtk.keysyms.Return, gtk.keysyms.KP_Enter ]:
s = unicode(os.linesep) s = os.linesep
if self.prefs.getBool('editor_auto_indent'): if self.prefs.getBool('editor_auto_indent'):
start_i, start_j = self.selection_line, self.selection_char start_i, start_j = self.selection_line, self.selection_char
end_i, end_j = self.current_line, self.current_char end_i, end_j = self.current_line, self.current_char
@ -5789,12 +5812,12 @@ class FileDiffViewer(gtk.Table):
w = self.stringWidth(text[:j]) w = self.stringWidth(text[:j])
if self.prefs.getBool('editor_expand_tabs'): if self.prefs.getBool('editor_expand_tabs'):
# convert to spaces # convert to spaces
s += u' ' * w s += ' ' * w
else: else:
tab_width = self.prefs.getInt('display_tab_width') tab_width = self.prefs.getInt('display_tab_width')
# replace with tab characters where possible # replace with tab characters where possible
s += u'\t' * (w // tab_width) s += '\t' * (w // tab_width)
s += u' ' * (w % tab_width) s += ' ' * (w % tab_width)
self.replaceText(s) self.replaceText(s)
# insert key # insert key
elif event.keyval in [ gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab ]: elif event.keyval in [ gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab ]:
@ -5896,7 +5919,7 @@ class FileDiffViewer(gtk.Table):
needs_block = (self.undoblock is None) needs_block = (self.undoblock is None)
if needs_block: if needs_block:
self.openUndoBlock() self.openUndoBlock()
self.replaceText(unicode(nullToEmpty(text), 'utf_8')) self.replaceText(nullToEmpty(text))
if needs_block: if needs_block:
self.closeUndoBlock() self.closeUndoBlock()
@ -6124,7 +6147,7 @@ class FileDiffViewer(gtk.Table):
# scroll the viewport so pixels at position 'y' are centred # scroll the viewport so pixels at position 'y' are centred
def centre_view_about_y(self, y): def centre_view_about_y(self, y):
vadj = self.vadj vadj = self.vadj
y = min(max(0, y - vadj.page_size / 2), vadj.upper - vadj.page_size) y = min(max(0, y - vadj.get_page_size() / 2), vadj.get_upper() - vadj.get_page_size())
vadj.set_value(y) vadj.set_value(y)
# move the cursor from line 'i' to the next difference in direction 'delta' # move the cursor from line 'i' to the next difference in direction 'delta'
@ -6734,7 +6757,7 @@ class FileChooserDialog(gtk.FileChooserDialog):
self.vbox.pack_start(hbox, False, False, 0) self.vbox.pack_start(hbox, False, False, 0)
hbox.show() hbox.show()
self.set_current_folder(unicode(self.last_chosen_folder, sys.getfilesystemencoding())) self.set_current_folder(self.last_chosen_folder)
self.connect('current-folder-changed', self.__current_folder_changed_cb) self.connect('current-folder-changed', self.__current_folder_changed_cb)
def set_encoding(self, encoding): def set_encoding(self, encoding):
@ -6748,9 +6771,7 @@ class FileChooserDialog(gtk.FileChooserDialog):
def get_filename(self): def get_filename(self):
# convert from UTF-8 string to unicode # convert from UTF-8 string to unicode
s = gtk.FileChooserDialog.get_filename(self) return gtk.FileChooserDialog.get_filename(self)
if s is not None:
return unicode(s, 'utf_8')
# dialogue used to search for text # dialogue used to search for text
class NumericDialog(gtk.Dialog): class NumericDialog(gtk.Dialog):
@ -6783,7 +6804,7 @@ class NumericDialog(gtk.Dialog):
def url_hook(dialog, link, userdata): def url_hook(dialog, link, userdata):
webbrowser.open(link) webbrowser.open(link)
gtk.about_dialog_set_url_hook(url_hook, None) #gtk.about_dialog_set_url_hook(url_hook, None)
# the about dialogue # the about dialogue
class AboutDialog(gtk.AboutDialog): class AboutDialog(gtk.AboutDialog):
@ -7028,7 +7049,7 @@ class Diffuse(gtk.Window):
self.connect('format-changed', self.format_changed_cb) self.connect('format-changed', self.format_changed_cb)
for i, darea in enumerate(self.dareas): for i, darea in enumerate(self.dareas):
darea.drag_dest_set(gtk.DEST_DEFAULT_ALL, [ ('text/uri-list', 0, 0) ], gtk.gdk.ACTION_COPY) darea.drag_dest_set(gtk.DEST_DEFAULT_ALL, [ gtk.TargetEntry.new('text/uri-list', 0, 0) ], gtk.gdk.ACTION_COPY)
darea.connect('drag-data-received', self.drag_data_received_cb, i) darea.connect('drag-data-received', self.drag_data_received_cb, i)
# initialise status # initialise status
self.updateStatus() self.updateStatus()
@ -7082,7 +7103,7 @@ class Diffuse(gtk.Window):
if i > start: if i > start:
p = url2path(s[start:i]) p = url2path(s[start:i])
if p is not None: if p is not None:
ss.append(unicode(p, 'utf_8')) ss.append(p)
# load the first valid file # load the first valid file
for s in ss: for s in ss:
if os.path.isfile(s): if os.path.isfile(s):
@ -7161,7 +7182,7 @@ class Diffuse(gtk.Window):
if encoding is None: if encoding is None:
s, encoding = self.prefs.convertToUnicode(s) s, encoding = self.prefs.convertToUnicode(s)
else: else:
s = unicode(s, encoding) s = str(s, encoding=encoding)
ss = splitlines(s) ss = splitlines(s)
except (IOError, OSError, UnicodeDecodeError, WindowsError, LookupError): except (IOError, OSError, UnicodeDecodeError, WindowsError, LookupError):
# FIXME: this can occur before the toplevel window is drawn # FIXME: this can occur before the toplevel window is drawn
@ -7456,7 +7477,7 @@ class Diffuse(gtk.Window):
s = 0.8 s = 0.8
sw, sh = int(s * w), int(s * h) sw, sh = int(s * w), int(s * h)
w1, h1 = w - sw, h - sh w1, h1 = w - sw, h - sh
p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h) p = gtk.gdk.Pixbuf.new(gtk.gdk.COLORSPACE_RGB, True, 8, w, h)
p.fill(0) p.fill(0)
p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255)
p0.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255)
@ -7467,7 +7488,7 @@ class Diffuse(gtk.Window):
sw, sh = int(s * w), int(s * h) sw, sh = int(s * w), int(s * h)
w1, h1 = (w - sw) / 2, (h - sh) / 2 w1, h1 = (w - sw) / 2, (h - sh) / 2
w2, h2 = w - sw, h - sh w2, h2 = w - sw, h - sh
p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h) p = gtk.gdk.Pixbuf.new(gtk.gdk.COLORSPACE_RGB, True, 8, w, h)
p.fill(0) p.fill(0)
p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255)
p0.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255)
@ -7482,14 +7503,14 @@ class Diffuse(gtk.Window):
w1, h1 = w - sw, h - sh w1, h1 = w - sw, h - sh
# create merge from left then right icon # create merge from left then right icon
p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h) p = gtk.gdk.Pixbuf.new(gtk.gdk.COLORSPACE_RGB, True, 8, w, h)
p.fill(0) p.fill(0)
p1.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255) p1.composite(p, w1, h1, sw, sh, w1, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255)
p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, 0, 0, sw, sh, 0, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255)
factory.add(DIFFUSE_STOCK_LEFT_RIGHT, gtk.IconSet(p)) factory.add(DIFFUSE_STOCK_LEFT_RIGHT, gtk.IconSet(p))
# create merge from right then left icon # create merge from right then left icon
p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h) p = gtk.gdk.Pixbuf.new(gtk.gdk.COLORSPACE_RGB, True, 8, w, h)
p.fill(0) p.fill(0)
p0.composite(p, 0, h1, sw, sh, 0, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255) p0.composite(p, 0, h1, sw, sh, 0, h1, s, s, gtk.gdk.INTERP_BILINEAR, 255)
p1.composite(p, w1, 0, sw, sh, w1, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255) p1.composite(p, w1, 0, sw, sh, w1, 0, s, s, gtk.gdk.INTERP_BILINEAR, 255)
@ -8423,7 +8444,7 @@ if __name__ == '__main__':
elif i + 1 < argc and arg in [ '-r', '--revision' ]: elif i + 1 < argc and arg in [ '-r', '--revision' ]:
# specified revision # specified revision
i += 1 i += 1
revs.append((unicode(args[i], sys.getfilesystemencoding()), encoding)) revs.append((args[i], encoding))
elif arg in [ '-s', '--separate' ]: elif arg in [ '-s', '--separate' ]:
funcs[mode](specs, labels, options) funcs[mode](specs, labels, options)
specs, labels, options = [], [], {} specs, labels, options = [], [], {}
@ -8436,7 +8457,7 @@ if __name__ == '__main__':
mode = 'single' mode = 'single'
elif i + 1 < argc and arg in [ '-V', '--vcs-order' ]: elif i + 1 < argc and arg in [ '-V', '--vcs-order' ]:
i += 1 i += 1
diff.prefs.setString('vcs_search_order', unicode(args[i], sys.getfilesystemencoding())) diff.prefs.setString('vcs_search_order', args[i])
diff.preferences_updated() diff.preferences_updated()
elif arg in [ '-b', '--ignore-space-change' ]: elif arg in [ '-b', '--ignore-space-change' ]:
diff.prefs.setBool('display_ignore_whitespace_changes', True) diff.prefs.setBool('display_ignore_whitespace_changes', True)
@ -8460,7 +8481,7 @@ if __name__ == '__main__':
diff.preferences_updated() diff.preferences_updated()
elif i + 1 < argc and arg == '-L': elif i + 1 < argc and arg == '-L':
i += 1 i += 1
labels.append(unicode(args[i], sys.getfilesystemencoding())) labels.append(args[i])
elif i + 1 < argc and arg == '--line': elif i + 1 < argc and arg == '--line':
i += 1 i += 1
try: try: