Skip to content

Instantly share code, notes, and snippets.

@ilikenwf
Last active January 28, 2018 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ilikenwf/f661cb781da598660a88bbaffd4c6f5d to your computer and use it in GitHub Desktop.
Save ilikenwf/f661cb781da598660a88bbaffd4c6f5d to your computer and use it in GitHub Desktop.
AUR is a pain in the rear
diff --git a/mcomix/about_dialog.py b/mcomix/about_dialog.py
index b31cbf4..4b2b6f3 100644
--- a/mcomix/about_dialog.py
+++ b/mcomix/about_dialog.py
@@ -1,18 +1,18 @@
# -*- coding: utf-8 -*-
"""about_dialog.py - About dialog."""
-import webbrowser
-import gtk
+from gi.repository import Gtk
import pkg_resources
+import webbrowser
from mcomix import constants
from mcomix import strings
from mcomix import image_tools
-class _AboutDialog(gtk.AboutDialog):
+class _AboutDialog(Gtk.AboutDialog):
def __init__(self, window):
- super(_AboutDialog, self).__init__()
+ super(_AboutDialog, self).__init__(parent=window)
self.set_name(constants.APPNAME)
self.set_program_name(constants.APPNAME)
@@ -20,7 +20,7 @@ class _AboutDialog(gtk.AboutDialog):
self.set_website('https://sourceforge.net/p/mcomix/wiki/')
self.set_copyright('Copyright © 2005-2016')
- icon_data = pkg_resources.resource_string('mcomix.images', 'mcomix.png')
+ icon_data = pkg_resources.resource_string('mcomix', 'images/mcomix.png')
pixbuf = image_tools.load_pixbuf_data(icon_data)
self.set_logo(pixbuf)
@@ -47,11 +47,12 @@ class _AboutDialog(gtk.AboutDialog):
artists = [ u'%s: %s' % (name, description) for name, description in strings.ARTISTS ]
self.set_artists(artists)
- self.show_all()
+ self.connect('activate-link', self._on_activate_link)
-def open_url(dialog, url, *args):
- webbrowser.open(url)
+ self.show_all()
-gtk.about_dialog_set_url_hook(open_url, None)
+ def _on_activate_link(self, about_dialog, uri):
+ webbrowser.open(uri)
+ return True
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/archive/__init__.py b/mcomix/archive/__init__.py
index 809ef76..e2c8bf4 100644
--- a/mcomix/archive/__init__.py
+++ b/mcomix/archive/__init__.py
@@ -1,32 +1,32 @@
# -*- coding: utf-8 -*-
-import gtk
+from gi.repository import Gtk
from mcomix import message_dialog
def ask_for_password(archive):
""" Openes an input dialog to ask for a password. Returns either
an Unicode string (the password), or None."""
- dialog = message_dialog.MessageDialog(None, gtk.DIALOG_MODAL,
- gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL)
+ dialog = message_dialog.MessageDialog(None, Gtk.DialogFlags.MODAL,
+ Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL)
dialog.set_text(
_("The archive is password-protected:"),
archive + '\n\n' +
("Please enter the password to continue:"))
- dialog.set_default_response(gtk.RESPONSE_OK)
+ dialog.set_default_response(Gtk.ResponseType.OK)
dialog.set_auto_destroy(False)
- password_box = gtk.Entry()
+ password_box = Gtk.Entry()
password_box.set_visibility(False)
password_box.set_activates_default(True)
- dialog.get_content_area().pack_end(password_box)
+ dialog.get_content_area().pack_end(password_box, True, True, 0)
dialog.set_focus(password_box)
result = dialog.run()
password = password_box.get_text()
dialog.destroy()
- if result == gtk.RESPONSE_OK and password:
+ if result == Gtk.ResponseType.OK and password:
return password.decode('utf-8')
else:
return None
diff --git a/mcomix/bookmark_backend.py b/mcomix/bookmark_backend.py
index 2f28b67..582ec9e 100644
--- a/mcomix/bookmark_backend.py
+++ b/mcomix/bookmark_backend.py
@@ -2,7 +2,7 @@
import os
import cPickle
-import gtk
+from gi.repository import Gtk
import operator
import datetime
import time
@@ -90,11 +90,11 @@ class __BookmarksStore(object):
response = self.show_replace_bookmark_dialog(same_file_bookmarks, page)
# Delete old bookmarks
- if response == gtk.RESPONSE_YES:
+ if response == Gtk.ResponseType.YES:
for bookmark in same_file_bookmarks:
self.remove_bookmark(bookmark)
# Perform no action
- elif response not in (gtk.RESPONSE_YES, gtk.RESPONSE_NO):
+ elif response not in (Gtk.ResponseType.YES, Gtk.ResponseType.NO):
return
self.add_bookmark_by_values(name, path, page, numpages,
@@ -195,13 +195,13 @@ class __BookmarksStore(object):
@return RESPONSE_YES to create replace bookmarks,
RESPONSE_NO to create a new bookmark, RESPONSE_CANCEL to abort creating
a new bookmark. """
- dialog = message_dialog.MessageDialog(self._window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO)
- dialog.add_buttons(gtk.STOCK_YES, gtk.RESPONSE_YES,
- gtk.STOCK_NO, gtk.RESPONSE_NO,
- gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
- dialog.set_default_response(gtk.RESPONSE_YES)
+ dialog = message_dialog.MessageDialog(self._window, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO)
+ dialog.add_buttons(Gtk.STOCK_YES, Gtk.ResponseType.YES,
+ Gtk.STOCK_NO, Gtk.ResponseType.NO,
+ Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
+ dialog.set_default_response(Gtk.ResponseType.YES)
dialog.set_should_remember_choice('replace-existing-bookmark',
- (gtk.RESPONSE_YES, gtk.RESPONSE_NO))
+ (Gtk.ResponseType.YES, Gtk.ResponseType.NO))
pages = map(str, sorted(map(operator.attrgetter('_page'), old_bookmarks)))
dialog.set_text(
diff --git a/mcomix/bookmark_dialog.py b/mcomix/bookmark_dialog.py
index 9f33b4b..3fa9adb 100644
--- a/mcomix/bookmark_dialog.py
+++ b/mcomix/bookmark_dialog.py
@@ -1,39 +1,38 @@
"""bookmark_dialog.py - Bookmarks dialog handler."""
-import gtk
-import gobject
+from gi.repository import Gdk, GdkPixbuf, Gtk, GObject
from mcomix import constants
from mcomix import bookmark_menu_item
-class _BookmarksDialog(gtk.Dialog):
+class _BookmarksDialog(Gtk.Dialog):
"""_BookmarksDialog lets the user remove or rearrange bookmarks."""
_SORT_TYPE, _SORT_NAME, _SORT_PAGE, _SORT_ADDED = 100, 101, 102, 103
def __init__(self, window, bookmarks_store):
- super(_BookmarksDialog, self).__init__(_('Edit Bookmarks'), window, gtk.DIALOG_DESTROY_WITH_PARENT,
- (gtk.STOCK_REMOVE, constants.RESPONSE_REMOVE,
- gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ super(_BookmarksDialog, self).__init__(_('Edit Bookmarks'), window, Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ (Gtk.STOCK_REMOVE, constants.RESPONSE_REMOVE,
+ Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
self._bookmarks_store = bookmarks_store
self.set_resizable(True)
- self.set_default_response(gtk.RESPONSE_CLOSE)
+ self.set_default_response(Gtk.ResponseType.CLOSE)
# scroll area fill to the edge (TODO window should not really be a dialog)
self.set_border_width(0)
- scrolled = gtk.ScrolledWindow()
+ scrolled = Gtk.ScrolledWindow()
scrolled.set_border_width(0)
- scrolled.set_shadow_type(gtk.SHADOW_IN)
- scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.vbox.pack_start(scrolled)
+ scrolled.set_shadow_type(Gtk.ShadowType.IN)
+ scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ self.vbox.pack_start(scrolled, True, True, 0)
- self._liststore = gtk.ListStore(gtk.gdk.Pixbuf, gobject.TYPE_STRING,
- gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, bookmark_menu_item._Bookmark)
+ self._liststore = Gtk.ListStore(GdkPixbuf.Pixbuf, GObject.TYPE_STRING,
+ GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, bookmark_menu_item._Bookmark)
- self._treeview = gtk.TreeView(self._liststore)
+ self._treeview = Gtk.TreeView(self._liststore)
self._treeview.set_rules_hint(True)
self._treeview.set_reorderable(True)
# search by typing first few letters of name
@@ -44,15 +43,15 @@ class _BookmarksDialog(gtk.Dialog):
scrolled.add(self._treeview)
- cellrenderer_text = gtk.CellRendererText()
- cellrenderer_pbuf = gtk.CellRendererPixbuf()
+ cellrenderer_text = Gtk.CellRendererText()
+ cellrenderer_pbuf = Gtk.CellRendererPixbuf()
- self._icon_col = gtk.TreeViewColumn(_('Type'), cellrenderer_pbuf)
- self._name_col = gtk.TreeViewColumn(_('Name'), cellrenderer_text)
- self._page_col = gtk.TreeViewColumn(_('Page'), cellrenderer_text)
- self._path_col = gtk.TreeViewColumn(_('Location'), cellrenderer_text)
+ self._icon_col = Gtk.TreeViewColumn(_('Type'), cellrenderer_pbuf)
+ self._name_col = Gtk.TreeViewColumn(_('Name'), cellrenderer_text)
+ self._page_col = Gtk.TreeViewColumn(_('Page'), cellrenderer_text)
+ self._path_col = Gtk.TreeViewColumn(_('Location'), cellrenderer_text)
# TRANSLATORS: "Added" as in "Date Added"
- self._date_add_col = gtk.TreeViewColumn(_('Added'), cellrenderer_text)
+ self._date_add_col = Gtk.TreeViewColumn(_('Added'), cellrenderer_text)
self._treeview.append_column(self._icon_col)
self._treeview.append_column(self._name_col)
@@ -82,11 +81,11 @@ class _BookmarksDialog(gtk.Dialog):
self._path_col.set_sort_column_id(3)
self._date_add_col.set_sort_column_id(_BookmarksDialog._SORT_ADDED)
- self._icon_col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
- self._name_col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
- self._page_col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
- self._path_col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
- self._date_add_col.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
+ self._icon_col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+ self._name_col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+ self._page_col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+ self._path_col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
+ self._date_add_col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
# FIXME Hide extra columns. Needs UI controls to enable these.
self._path_col.set_visible(False)
@@ -154,7 +153,7 @@ class _BookmarksDialog(gtk.Dialog):
def _response(self, dialog, response):
- if response == gtk.RESPONSE_CLOSE:
+ if response == Gtk.ResponseType.CLOSE:
self._close()
elif response == constants.RESPONSE_REMOVE:
@@ -165,7 +164,7 @@ class _BookmarksDialog(gtk.Dialog):
def _key_press_event(self, dialog, event, *args):
- if event.keyval == gtk.keysyms.Delete:
+ if event.keyval == Gdk.KEY_Delete:
self._remove_selected()
def _close(self, *args):
@@ -173,7 +172,7 @@ class _BookmarksDialog(gtk.Dialog):
ordering."""
ordering = []
- treeiter = self._liststore.get_iter_root()
+ treeiter = self._liststore.get_iter_first()
while treeiter is not None:
bookmark = self._liststore.get_value(treeiter, 5)
diff --git a/mcomix/bookmark_menu.py b/mcomix/bookmark_menu.py
index d2f02ef..e04b9cb 100644
--- a/mcomix/bookmark_menu.py
+++ b/mcomix/bookmark_menu.py
@@ -1,13 +1,13 @@
"""bookmark_menu.py - Bookmarks menu."""
-import gtk
+from gi.repository import Gtk
from mcomix import bookmark_backend
from mcomix import bookmark_dialog
-class BookmarksMenu(gtk.Menu):
+class BookmarksMenu(Gtk.Menu):
- """BookmarksMenu extends gtk.Menu with convenience methods relating to
+ """BookmarksMenu extends Gtk.Menu with convenience methods relating to
bookmarks. It contains fixed items for adding bookmarks etc. as well
as dynamic items corresponding to the current bookmarks.
"""
@@ -19,7 +19,7 @@ class BookmarksMenu(gtk.Menu):
self._bookmarks_store = bookmark_backend.BookmarksStore
self._bookmarks_store.initialize(window)
- self._actiongroup = gtk.ActionGroup('mcomix-bookmarks')
+ self._actiongroup = Gtk.ActionGroup('mcomix-bookmarks')
self._actiongroup.add_actions([
('add_bookmark', 'mcomix-add-bookmark', _('Add _Bookmark'),
'<Control>D', None, self._add_current_to_bookmarks),
@@ -53,7 +53,7 @@ class BookmarksMenu(gtk.Menu):
# Add separator
if bookmarks:
- separator = gtk.SeparatorMenuItem()
+ separator = Gtk.SeparatorMenuItem()
separator.show()
self.append(separator)
diff --git a/mcomix/bookmark_menu_item.py b/mcomix/bookmark_menu_item.py
index 454426e..d1d428e 100644
--- a/mcomix/bookmark_menu_item.py
+++ b/mcomix/bookmark_menu_item.py
@@ -1,10 +1,10 @@
"""bookmark_menu_item.py - A signle bookmark item."""
-import gtk
+from gi.repository import Gtk
-class _Bookmark(gtk.ImageMenuItem):
+class _Bookmark(Gtk.ImageMenuItem):
- """_Bookmark represents one bookmark. It extends the gtk.ImageMenuItem
+ """_Bookmark represents one bookmark. It extends the Gtk.ImageMenuItem
and is thus put directly in the bookmarks menu.
"""
@@ -22,10 +22,10 @@ class _Bookmark(gtk.ImageMenuItem):
super(_Bookmark, self).__init__(str(self), False)
if self._archive_type is not None:
- im = gtk.image_new_from_stock('mcomix-archive', gtk.ICON_SIZE_MENU)
+ im = Gtk.Image.new_from_stock('mcomix-archive', Gtk.IconSize.MENU)
else:
- im = gtk.image_new_from_stock('mcomix-image', gtk.ICON_SIZE_MENU)
+ im = Gtk.Image.new_from_stock('mcomix-image', Gtk.IconSize.MENU)
self.set_image(im)
self.connect('activate', self._load)
diff --git a/mcomix/callback.py b/mcomix/callback.py
index 09ecebc..915978b 100644
--- a/mcomix/callback.py
+++ b/mcomix/callback.py
@@ -3,7 +3,7 @@
import traceback
import weakref
import threading
-import gobject
+from gi.repository import GObject
from mcomix import log
@@ -33,7 +33,7 @@ class CallbackList(object):
return result
else:
# Call this method again in the main thread.
- gobject.idle_add(self.__mainthread_call, (args, kwargs))
+ GObject.idle_add(self.__mainthread_call, (args, kwargs))
def __iadd__(self, function):
""" Support for 'method += callback_function' syntax. """
@@ -55,7 +55,7 @@ class CallbackList(object):
def __mainthread_call(self, params):
""" Helper function to execute code in the main thread.
- This will be called by gobject.idle_add, with <params> being a tuple
+ This will be called by GObject.idle_add, with <params> being a tuple
of (args, kwargs). """
result = self(*params[0], **params[1])
diff --git a/mcomix/clipboard.py b/mcomix/clipboard.py
index c197946..a31d58e 100644
--- a/mcomix/clipboard.py
+++ b/mcomix/clipboard.py
@@ -1,30 +1,23 @@
"""clipboard.py - Clipboard handler"""
-import gtk
-import ctypes
-import cStringIO
-import sys
+from gi.repository import Gdk, Gtk
-from mcomix import log
from mcomix import image_tools
-class Clipboard(gtk.Clipboard):
+class Clipboard(object):
"""The Clipboard takes care of all necessary copy-paste functionality
"""
def __init__(self, window):
- super(Clipboard, self).__init__(display=gtk.gdk.display_get_default(),
- selection="CLIPBOARD")
+ self._clipboard = Gtk.Clipboard.get(Gdk.Atom.intern("CLIPBOARD", False))
self._window = window
def copy(self, text, pixbuf):
""" Copies C{text} and C{pixbuf} to clipboard. """
- if sys.platform == 'win32':
- self._copy_windows(pixbuf, text)
- else:
- self._copy_linux(pixbuf, text.encode('utf-8'))
+ self._clipboard.set_text(text, len(text))
+ self._clipboard.set_image(pixbuf)
def copy_page(self, *args):
""" Copies the currently opened page and pixbuf to clipboard. """
@@ -42,87 +35,7 @@ class Clipboard(gtk.Clipboard):
current_page_pixbufs[ 1 ],
self._window.is_manga_mode )
- # Get path for current page
path = self._window.imagehandler.get_path_to_page()
self.copy(path, pixbuf)
- def _copy_windows(self, pixbuf, path):
- """ Copies pixbuf and path to the clipboard.
- Uses native Win32 API, as GTK+ doesn't seem to work. """
-
- windll = ctypes.windll
- OpenClipboard = windll.user32.OpenClipboard
- EmptyClipboard = windll.user32.EmptyClipboard
- SetClipboardData = windll.user32.SetClipboardData
- CloseClipboard = windll.user32.CloseClipboard
- GlobalAlloc = windll.kernel32.GlobalAlloc
- GlobalLock = windll.kernel32.GlobalLock
- GlobalLock.restype = ctypes.c_void_p
- GlobalUnlock = windll.kernel32.GlobalUnlock
-
- def buffer_to_handle(buffer, buffer_size):
- """ Creates a memory handle for the passed data.
- This handle doesn't need to be freed by the application. """
- global_mem = GlobalAlloc(
- 0x0042, # GMEM_MOVEABLE | GMEM_ZEROINIT
- buffer_size)
- lock = GlobalLock(global_mem)
- ctypes.memmove(lock, ctypes.addressof(buffer), buffer_size)
- GlobalUnlock(global_mem)
-
- return global_mem
-
- # Paste the text as Unicode string
- text_buffer = ctypes.create_unicode_buffer(path)
- text_handle = buffer_to_handle(text_buffer,
- ctypes.sizeof(text_buffer))
- # Paste the image as Win32 DIB structure
- pil = image_tools.pixbuf_to_pil(pixbuf)
- output = cStringIO.StringIO()
- pil.convert("RGB").save(output, "BMP")
- dibdata = output.getvalue()[14:]
- output.close()
-
- image_buffer = ctypes.create_string_buffer(dibdata)
- image_handle = buffer_to_handle(image_buffer,
- ctypes.sizeof(image_buffer))
-
- # Actually copy data to clipboard
- if OpenClipboard(self._window.window.handle):
- EmptyClipboard()
- SetClipboardData(13, # CF_UNICODETEXT
- text_handle)
- SetClipboardData(8, # CF_DIB
- image_handle)
- CloseClipboard()
- else:
- log.warning('Could not open clipboard.')
-
- def _copy_linux(self, pixbuf, path):
- # Register various clipboard formats for either the
- # text or the pixbuf.
- clipboard_targets = ("image/bmp",
- "text/plain", "STRING", "UTF8_STRING")
- self.set_with_data(
- [ (target, 0, 0) for target in clipboard_targets ],
- self._get_clipboard_content,
- self._clear_clipboard_content,
- (pixbuf, path))
-
- def _get_clipboard_content(self, clipboard, selectiondata, info, data):
- """ Called whenever an application requests the content of the
- clipboard. selectiondata.target will contain one of the targets
- that have previously been registered. Currently, only "image/bmp"
- provides pixbuf data, while all other types point to the currently
- opened file as UTF-8 string. """
-
- if selectiondata.target == "image/bmp":
- selectiondata.set_pixbuf(data[0])
- else:
- selectiondata.set_text(data[1])
-
- def _clear_clipboard_content(self, clipboard, data):
- """ Called when clipboard ownership changes. """
- pass
-
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/comment_dialog.py b/mcomix/comment_dialog.py
index 21e4663..13e0996 100644
--- a/mcomix/comment_dialog.py
+++ b/mcomix/comment_dialog.py
@@ -1,29 +1,29 @@
"""comment.py - Comments dialog."""
import os
-import gtk
+from gi.repository import Gtk
from mcomix import i18n
-class _CommentsDialog(gtk.Dialog):
+class _CommentsDialog(Gtk.Dialog):
def __init__(self, window):
super(_CommentsDialog, self).__init__(_('Comments'), window, 0,
- (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ (Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
self.set_resizable(True)
- self.set_default_response(gtk.RESPONSE_CLOSE)
+ self.set_default_response(Gtk.ResponseType.CLOSE)
self.set_default_size(600, 550)
self.set_border_width(4)
- tag = gtk.TextTag()
+ tag = Gtk.TextTag()
tag.set_property('editable', False)
tag.set_property('editable-set', True)
tag.set_property('family', 'Monospace')
tag.set_property('family-set', True)
tag.set_property('scale', 0.9)
tag.set_property('scale-set', True)
- tag_table = gtk.TextTagTable()
+ tag_table = Gtk.TextTagTable()
tag_table.add(tag)
self._tag = tag
@@ -50,10 +50,10 @@ class _CommentsDialog(gtk.Dialog):
self._notebook.destroy()
self._notebook = None
- notebook = gtk.Notebook()
+ notebook = Gtk.Notebook()
notebook.set_scrollable(True)
notebook.set_border_width(6)
- self.vbox.pack_start(notebook)
+ self.vbox.pack_start(notebook, True, True, 0)
self._notebook = notebook
self._comments = {}
@@ -73,17 +73,17 @@ class _CommentsDialog(gtk.Dialog):
name = os.path.basename(path)
- page = gtk.VBox(False)
+ page = Gtk.VBox(False)
page.set_border_width(8)
- scrolled = gtk.ScrolledWindow()
- scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- page.pack_start(scrolled)
+ scrolled = Gtk.ScrolledWindow()
+ scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ page.pack_start(scrolled, True, True, 0)
- outbox = gtk.EventBox()
+ outbox = Gtk.EventBox()
scrolled.add_with_viewport(outbox)
- inbox = gtk.EventBox()
+ inbox = Gtk.EventBox()
inbox.set_border_width(6)
outbox.add(inbox)
@@ -91,16 +91,16 @@ class _CommentsDialog(gtk.Dialog):
if text is None:
text = _('Could not read %s') % name
- text_buffer = gtk.TextBuffer(self._tag_table)
+ text_buffer = Gtk.TextBuffer(tag_table=self._tag_table)
text_buffer.set_text(i18n.to_unicode(text))
text_buffer.apply_tag(self._tag, *text_buffer.get_bounds())
- text_view = gtk.TextView(text_buffer)
+ text_view = Gtk.TextView(buffer=text_buffer)
inbox.add(text_view)
- bg_color = text_view.get_default_attributes().bg_color
- outbox.modify_bg(gtk.STATE_NORMAL, bg_color)
- tab_label = gtk.Label(i18n.to_unicode(name))
- self._notebook.insert_page(page, tab_label)
+ bg_color = text_view.get_default_attributes().pg_bg_color
+ outbox.modify_bg(Gtk.StateType.NORMAL, bg_color)
+ tab_label = Gtk.Label(label=i18n.to_unicode(name))
+ self._notebook.insert_page(page, tab_label, -1)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/constants.py b/mcomix/constants.py
index 5be2040..ae9798e 100644
--- a/mcomix/constants.py
+++ b/mcomix/constants.py
@@ -8,7 +8,7 @@ import operator
from mcomix import tools
APPNAME = 'MComix'
-VERSION = '1.3.dev0'
+VERSION = '1.3.dev0-gtk3'
HOME_DIR = tools.get_home_directory()
CONFIG_DIR = tools.get_config_directory()
diff --git a/mcomix/cursor_handler.py b/mcomix/cursor_handler.py
index 9ddad5b..1e370b1 100644
--- a/mcomix/cursor_handler.py
+++ b/mcomix/cursor_handler.py
@@ -1,7 +1,6 @@
"""cursor_handler.py - Cursor handler."""
-import gobject
-import gtk
+from gi.repository import Gdk, GObject
from mcomix import constants
@@ -16,14 +15,14 @@ class CursorHandler(object):
def set_cursor_type(self, cursor):
"""Set the cursor to type <cursor>. Supported cursor types are
available as constants in this module. If <cursor> is not one of the
- cursor constants above, it must be a gtk.gdk.Cursor.
+ cursor constants above, it must be a Gdk.Cursor.
"""
if cursor == constants.NORMAL_CURSOR:
mode = None
elif cursor == constants.GRAB_CURSOR:
- mode = gtk.gdk.Cursor(gtk.gdk.FLEUR)
+ mode = Gdk.Cursor.new(Gdk.CursorType.FLEUR)
elif cursor == constants.WAIT_CURSOR:
- mode = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ mode = Gdk.Cursor.new(Gdk.CursorType.WATCH)
elif cursor == constants.NO_CURSOR:
mode = self._get_hidden_cursor()
else:
@@ -72,17 +71,15 @@ class CursorHandler(object):
def _set_hide_timer(self):
self._kill_timer()
- self._timer_id = gobject.timeout_add(2000, self._on_timeout)
+ self._timer_id = GObject.timeout_add(2000, self._on_timeout)
def _kill_timer(self):
if self._timer_id is not None:
- gobject.source_remove(self._timer_id)
+ GObject.source_remove(self._timer_id)
self._timer_id = None
def _get_hidden_cursor(self):
- pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
- color = gtk.gdk.Color()
- return gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
+ return Gdk.Cursor.new(Gdk.CursorType.BLANK_CURSOR)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/dialog_handler.py b/mcomix/dialog_handler.py
index d08f3c7..297b1cd 100644
--- a/mcomix/dialog_handler.py
+++ b/mcomix/dialog_handler.py
@@ -12,9 +12,11 @@ dialog_windows[ 'about-dialog' ] = [None, about_dialog._AboutDialog]
dialog_windows[ 'comments-dialog' ] = [None, comment_dialog._CommentsDialog]
dialog_windows[ 'properties-dialog' ] = [None, properties_dialog._PropertiesDialog]
-def open_dialog(action, window, name_of_dialog):
+def open_dialog(action, data):
"""Create and display the given dialog."""
+ window, name_of_dialog = data
+
_dialog = dialog_windows[ name_of_dialog ]
# if the dialog window is not created then create the window
diff --git a/mcomix/edit_comment_area.py b/mcomix/edit_comment_area.py
index 048beb8..e6b1ba1 100644
--- a/mcomix/edit_comment_area.py
+++ b/mcomix/edit_comment_area.py
@@ -1,11 +1,10 @@
"""edit_comment_area.py - The area in the editing window that displays comments."""
import os
-import gtk
-
+from gi.repository import Gdk, Gtk
from mcomix import tools
-class _CommentArea(gtk.VBox):
+class _CommentArea(Gtk.VBox):
"""The area used for displaying and handling non-image files."""
@@ -13,32 +12,32 @@ class _CommentArea(gtk.VBox):
super(_CommentArea, self).__init__()
self._edit_dialog = edit_dialog
- scrolled = gtk.ScrolledWindow()
- scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.pack_start(scrolled)
+ scrolled = Gtk.ScrolledWindow()
+ scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ self.pack_start(scrolled, True, True, 0)
- info = gtk.Label(_('Please note that the only files that are automatically added to this list are those files in archives that MComix recognizes as comments.'))
+ info = Gtk.Label(label=_('Please note that the only files that are automatically added to this list are those files in archives that MComix recognizes as comments.'))
info.set_alignment(0.5, 0.5)
info.set_line_wrap(True)
self.pack_start(info, False, False, 10)
# The ListStore layout is (basename, size, full path).
- self._liststore = gtk.ListStore(str, str, str)
- self._treeview = gtk.TreeView(self._liststore)
+ self._liststore = Gtk.ListStore(str, str, str)
+ self._treeview = Gtk.TreeView(self._liststore)
self._treeview.set_rules_hint(True)
self._treeview.connect('button_press_event', self._button_press)
self._treeview.connect('key_press_event', self._key_press)
- cellrenderer = gtk.CellRendererText()
- column = gtk.TreeViewColumn(_('Name'), cellrenderer, text=0)
+ cellrenderer = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn(_('Name'), cellrenderer, text=0)
column.set_expand(True)
self._treeview.append_column(column)
- column = gtk.TreeViewColumn(_('Size'), cellrenderer, text=1)
+ column = Gtk.TreeViewColumn(_('Size'), cellrenderer, text=1)
self._treeview.append_column(column)
scrolled.add(self._treeview)
- self._ui_manager = gtk.UIManager()
+ self._ui_manager = Gtk.UIManager()
ui_description = """
<ui>
@@ -49,9 +48,9 @@ class _CommentArea(gtk.VBox):
"""
self._ui_manager.add_ui_from_string(ui_description)
- actiongroup = gtk.ActionGroup('mcomix-edit-archive-comment-area')
+ actiongroup = Gtk.ActionGroup('mcomix-edit-archive-comment-area')
actiongroup.add_actions([
- ('remove', gtk.STOCK_REMOVE, _('Remove from archive'), None, None,
+ ('remove', Gtk.STOCK_REMOVE, _('Remove from archive'), None, None,
self._remove_file)])
self._ui_manager.insert_action_group(actiongroup, 0)
@@ -96,12 +95,12 @@ class _CommentArea(gtk.VBox):
path = path[0]
if event.button == 3:
- self._ui_manager.get_widget('/Popup').popup(None, None, None,
- event.button, event.time)
+ self._ui_manager.get_widget('/Popup').popup(None, None, None, None,
+ event.button, event.time)
def _key_press(self, iconview, event):
"""Handle key presses on the area."""
- if event.keyval == gtk.keysyms.Delete:
+ if event.keyval == Gdk.KEY_Delete:
self._remove_file()
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/edit_dialog.py b/mcomix/edit_dialog.py
index 0d443c9..b33f988 100644
--- a/mcomix/edit_dialog.py
+++ b/mcomix/edit_dialog.py
@@ -2,8 +2,7 @@
import os
import tempfile
-import gobject
-import gtk
+from gi.repository import Gdk, Gtk, GObject
import re
from mcomix.preferences import prefs
@@ -17,7 +16,7 @@ from mcomix import message_dialog
_dialog = None
-class _EditArchiveDialog(gtk.Dialog):
+class _EditArchiveDialog(Gtk.Dialog):
"""The _EditArchiveDialog lets users edit archives (or directories) by
reordering images and removing and adding images or comment files. The
@@ -25,40 +24,40 @@ class _EditArchiveDialog(gtk.Dialog):
"""
def __init__(self, window):
- super(_EditArchiveDialog, self).__init__(_('Edit archive'), window, gtk.DIALOG_MODAL,
- (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+ super(_EditArchiveDialog, self).__init__(_('Edit archive'), window, Gtk.DialogFlags.MODAL,
+ (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
- self._accept_changes_button = self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
+ self._accept_changes_button = self.add_button(Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY)
self.kill = False # Dialog is killed.
self.file_handler = window.filehandler
self._window = window
self._imported_files = []
- self._save_button = self.add_button(gtk.STOCK_SAVE_AS, constants.RESPONSE_SAVE_AS)
+ self._save_button = self.add_button(Gtk.STOCK_SAVE_AS, constants.RESPONSE_SAVE_AS)
self._import_button = self.add_button(_('_Import'), constants.RESPONSE_IMPORT)
- self._import_button.set_image(gtk.image_new_from_stock(gtk.STOCK_ADD,
- gtk.ICON_SIZE_BUTTON))
+ self._import_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_ADD,
+ Gtk.IconSize.BUTTON))
self.set_border_width(4)
- self.resize(min(gtk.gdk.screen_get_default().get_width() - 50, 750),
- min(gtk.gdk.screen_get_default().get_height() - 50, 600))
+ self.resize(min(Gdk.Screen.get_default().get_width() - 50, 750),
+ min(Gdk.Screen.get_default().get_height() - 50, 600))
self.connect('response', self._response)
self._image_area = edit_image_area._ImageArea(self, window)
self._comment_area = edit_comment_area._CommentArea(self)
- notebook = gtk.Notebook()
+ notebook = Gtk.Notebook()
notebook.set_border_width(6)
- notebook.append_page(self._image_area, gtk.Label(_('Images')))
- notebook.append_page(self._comment_area, gtk.Label(_('Comment files')))
- self.vbox.pack_start(notebook)
+ notebook.append_page(self._image_area, Gtk.Label(label=_('Images')))
+ notebook.append_page(self._comment_area, Gtk.Label(label=_('Comment files')))
+ self.vbox.pack_start(notebook, True, True, 0)
self.show_all()
- gobject.idle_add(self._load_original_files)
+ GObject.idle_add(self._load_original_files)
def _load_original_files(self):
"""Load the original files from the archive or directory into
@@ -66,7 +65,7 @@ class _EditArchiveDialog(gtk.Dialog):
"""
self._save_button.set_sensitive(False)
self._import_button.set_sensitive(False)
- self._window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ self._window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
self._image_area.fetch_images()
if self.kill: # fetch_images() allows pending events to be handled.
@@ -82,10 +81,10 @@ class _EditArchiveDialog(gtk.Dialog):
def _pack_archive(self, archive_path):
"""Create a new archive with the chosen files."""
self.set_sensitive(False)
- self._window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ self._window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
- while gtk.events_pending():
- gtk.main_iteration_do(False)
+ while Gtk.events_pending():
+ Gtk.main_iteration_do(False)
image_files = self._image_area.get_file_listing()
comment_files = self._comment_area.get_file_listing()
@@ -128,8 +127,8 @@ class _EditArchiveDialog(gtk.Dialog):
self._window.set_cursor(None)
if fail:
- dialog = message_dialog.MessageDialog(self._window, 0, gtk.MESSAGE_ERROR,
- gtk.BUTTONS_CLOSE)
+ dialog = message_dialog.MessageDialog(self._window, 0, Gtk.MessageType.ERROR,
+ Gtk.ButtonsType.CLOSE)
dialog.set_text(
_("The new archive could not be saved!"),
_("The original files have not been removed."))
@@ -142,14 +141,14 @@ class _EditArchiveDialog(gtk.Dialog):
if response == constants.RESPONSE_SAVE_AS:
dialog = file_chooser_simple_dialog.SimpleFileChooserDialog(
- gtk.FILE_CHOOSER_ACTION_SAVE)
+ Gtk.FileChooserAction.SAVE)
src_path = self.file_handler.get_path_to_base()
dialog.set_current_directory(os.path.dirname(src_path))
dialog.set_save_name('%s.cbz' % os.path.splitext(
os.path.basename(src_path))[0])
- dialog.filechooser.set_extra_widget(gtk.Label(
+ dialog.filechooser.set_extra_widget(Gtk.Label(label=
_('Archives are stored as ZIP files.')))
dialog.add_archive_filters()
dialog.run()
@@ -183,11 +182,11 @@ class _EditArchiveDialog(gtk.Dialog):
self._imported_files.append( path )
self._comment_area.add_extra_file(path)
- elif response == gtk.RESPONSE_APPLY:
+ elif response == Gtk.ResponseType.APPLY:
old_image_array = self._window.imagehandler._image_files
- treeiter = self._image_area._liststore.get_iter_root()
+ treeiter = self._image_area._liststore.get_iter_first()
new_image_array = []
@@ -223,7 +222,7 @@ class _EditArchiveDialog(gtk.Dialog):
def destroy(self):
self._image_area.cleanup()
- gtk.Dialog.destroy(self)
+ Gtk.Dialog.destroy(self)
def open_dialog(action, window):
global _dialog
diff --git a/mcomix/edit_image_area.py b/mcomix/edit_image_area.py
index d83a65e..5d548a2 100644
--- a/mcomix/edit_image_area.py
+++ b/mcomix/edit_image_area.py
@@ -1,7 +1,7 @@
"""edit_image_area.py - The area of the editing archive window that displays images."""
import os
-import gtk
+from gi.repository import Gdk, GdkPixbuf, Gtk
from mcomix import image_tools
from mcomix import i18n
@@ -9,7 +9,7 @@ from mcomix import thumbnail_tools
from mcomix import thumbnail_view
from mcomix.preferences import prefs
-class _ImageArea(gtk.ScrolledWindow):
+class _ImageArea(Gtk.ScrolledWindow):
"""The area used for displaying and handling image files."""
@@ -18,11 +18,11 @@ class _ImageArea(gtk.ScrolledWindow):
self._window = window
self._edit_dialog = edit_dialog
- self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
# The ListStore layout is (thumbnail, basename, full path, thumbnail status).
# Basename is used as image tooltip.
- self._liststore = gtk.ListStore(gtk.gdk.Pixbuf, str, str, bool)
+ self._liststore = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str, bool)
self._iconview = thumbnail_view.ThumbnailIconView(
self._liststore,
2, # UID
@@ -32,7 +32,7 @@ class _ImageArea(gtk.ScrolledWindow):
self._iconview.generate_thumbnail = self._generate_thumbnail
self._iconview.set_tooltip_column(1)
self._iconview.set_reorderable(True)
- self._iconview.set_selection_mode(gtk.SELECTION_MULTIPLE)
+ self._iconview.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
self._iconview.connect('button_press_event', self._button_press)
self._iconview.connect('key_press_event', self._key_press)
self._iconview.connect_after('drag_begin', self._drag_begin)
@@ -43,16 +43,16 @@ class _ImageArea(gtk.ScrolledWindow):
size=(self._thumbnail_size,
self._thumbnail_size))
- self._filler = gtk.gdk.Pixbuf(colorspace=gtk.gdk.COLORSPACE_RGB,
- has_alpha=True, bits_per_sample=8,
- width=self._thumbnail_size,
- height=self._thumbnail_size)
+ self._filler = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=True, bits_per_sample=8,
+ width=self._thumbnail_size,
+ height=self._thumbnail_size)
# Make the pixbuf transparent.
self._filler.fill(0)
self._window.imagehandler.page_available += self._on_page_available
- self._ui_manager = gtk.UIManager()
+ self._ui_manager = Gtk.UIManager()
ui_description = """
<ui>
<popup name="Popup">
@@ -63,9 +63,9 @@ class _ImageArea(gtk.ScrolledWindow):
self._ui_manager.add_ui_from_string(ui_description)
- actiongroup = gtk.ActionGroup('mcomix-edit-archive-image-area')
+ actiongroup = Gtk.ActionGroup('mcomix-edit-archive-image-area')
actiongroup.add_actions([
- ('remove', gtk.STOCK_REMOVE, _('Remove from archive'), None, None,
+ ('remove', Gtk.STOCK_REMOVE, _('Remove from archive'), None, None,
self._remove_pages)])
self._ui_manager.insert_action_group(actiongroup, 0)
@@ -120,12 +120,12 @@ class _ImageArea(gtk.ScrolledWindow):
iconview.unselect_all()
iconview.select_path(path)
- self._ui_manager.get_widget('/Popup').popup(None, None, None,
- event.button, event.time)
+ self._ui_manager.get_widget('/Popup').popup(None, None, None, None,
+ event.button, event.time)
def _key_press(self, iconview, event):
"""Handle key presses on the thumbnail area."""
- if event.keyval == gtk.keysyms.Delete:
+ if event.keyval == Gdk.KEY_Delete:
self._remove_pages()
def _drag_begin(self, iconview, context):
@@ -134,16 +134,10 @@ class _ImageArea(gtk.ScrolledWindow):
might actually see where we are dropping!).
"""
path = iconview.get_cursor()[0]
- pixmap = iconview.create_drag_icon(path)
-
- # context.set_icon_pixmap() seems to cause crashes, so we do a
- # quick and dirty conversion to pixbuf.
- pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- *pixmap.get_size())
- pointer = pointer.get_from_drawable(pixmap, iconview.get_colormap(),
- 0, 0, 0, 0, *pixmap.get_size())
-
- context.set_icon_pixbuf(pointer, -5, -5)
+ surface = treeview.create_row_drag_icon(path)
+ width, height = surface.get_width(), surface.get_height()
+ pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, width, height)
+ Gtk.drag_set_icon_pixbuf(context, pixbuf, -5, -5)
def cleanup(self):
self._iconview.stop_update()
diff --git a/mcomix/enhance_dialog.py b/mcomix/enhance_dialog.py
index 5bbd5f8..87e985f 100644
--- a/mcomix/enhance_dialog.py
+++ b/mcomix/enhance_dialog.py
@@ -1,6 +1,6 @@
"""enhance_dialog.py - Image enhancement dialog."""
-import gtk
+from gi.repository import Gtk
import histogram
from mcomix.preferences import prefs
@@ -8,9 +8,9 @@ from mcomix import image_tools
_dialog = None
-class _EnhanceImageDialog(gtk.Dialog):
+class _EnhanceImageDialog(Gtk.Dialog):
- """A gtk.Dialog which allows modification of the values belonging to
+ """A Gtk.Dialog which allows modification of the values belonging to
an ImageEnhancer.
"""
@@ -19,49 +19,50 @@ class _EnhanceImageDialog(gtk.Dialog):
self._window = window
- reset = gtk.Button(None, gtk.STOCK_REVERT_TO_SAVED)
+ reset = Gtk.Button(stock=Gtk.STOCK_REVERT_TO_SAVED)
reset.set_tooltip_text(_('Reset to defaults.'))
- self.add_action_widget(reset, gtk.RESPONSE_REJECT)
- save = gtk.Button(None, gtk.STOCK_SAVE)
+ self.add_action_widget(reset, Gtk.ResponseType.REJECT)
+ save = Gtk.Button(stock=Gtk.STOCK_SAVE)
save.set_tooltip_text(_('Save the selected values as default for future files.'))
- self.add_action_widget(save, gtk.RESPONSE_APPLY)
- self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+ self.add_action_widget(save, Gtk.ResponseType.APPLY)
+ self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
self.set_resizable(False)
self.connect('response', self._response)
- self.set_default_response(gtk.RESPONSE_OK)
+ self.set_default_response(Gtk.ResponseType.OK)
self._enhancer = window.enhancer
self._block = False
- vbox = gtk.VBox(False, 10)
+ vbox = Gtk.VBox(False, 10)
self.set_border_width(4)
vbox.set_border_width(6)
self.vbox.add(vbox)
- self._hist_image = gtk.Image()
+ self._hist_image = Gtk.Image()
self._hist_image.set_size_request(262, 170)
- vbox.pack_start(self._hist_image)
- vbox.pack_start(gtk.HSeparator())
+ vbox.pack_start(self._hist_image, True, True, 0)
+ vbox.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), True, True, 0)
- hbox = gtk.HBox(False, 4)
+ hbox = Gtk.HBox(False, 4)
vbox.pack_start(hbox, False, False, 2)
- vbox_left = gtk.VBox(False, 4)
- vbox_right = gtk.VBox(False, 4)
+ vbox_left = Gtk.VBox(False, 4)
+ vbox_right = Gtk.VBox(False, 4)
hbox.pack_start(vbox_left, False, False, 2)
hbox.pack_start(vbox_right, True, True, 2)
def _create_scale(label_text):
- label = gtk.Label(label_text)
+ label = Gtk.Label(label=label_text)
label.set_alignment(1, 0.5)
label.set_use_underline(True)
vbox_left.pack_start(label, True, False, 2)
- adj = gtk.Adjustment(0.0, -1.0, 1.0, 0.01, 0.1)
- scale = gtk.HScale(adj)
+ adj = Gtk.Adjustment(0.0, -1.0, 1.0, 0.01, 0.1)
+ scale = Gtk.HScale.new(adj)
scale.set_digits(2)
- scale.set_value_pos(gtk.POS_RIGHT)
+ scale.set_value_pos(Gtk.PositionType.RIGHT)
scale.connect('value-changed', self._change_values)
- scale.set_update_policy(gtk.UPDATE_DELAYED)
+ # FIXME
+ # scale.set_update_policy(Gtk.UPDATE_DELAYED)
label.set_mnemonic_widget(scale)
vbox_right.pack_start(scale, True, False, 2)
return scale
@@ -71,10 +72,10 @@ class _EnhanceImageDialog(gtk.Dialog):
self._saturation_scale = _create_scale(_('S_aturation:'))
self._sharpness_scale = _create_scale(_('S_harpness:'))
- vbox.pack_start(gtk.HSeparator())
+ vbox.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), True, True, 0)
self._autocontrast_button = \
- gtk.CheckButton(_('_Automatically adjust contrast'))
+ Gtk.CheckButton.new_with_mnemonic(_('_Automatically adjust contrast'))
self._autocontrast_button.set_tooltip_text(
_('Automatically adjust contrast (both lightness and darkness), separately for each colour band.'))
vbox.pack_start(self._autocontrast_button, False, False, 2)
@@ -138,10 +139,10 @@ class _EnhanceImageDialog(gtk.Dialog):
def _response(self, dialog, response):
- if response in [gtk.RESPONSE_OK, gtk.RESPONSE_DELETE_EVENT]:
+ if response in [Gtk.ResponseType.OK, Gtk.ResponseType.DELETE_EVENT]:
_close_dialog()
- elif response == gtk.RESPONSE_APPLY:
+ elif response == Gtk.ResponseType.APPLY:
self._change_values(self)
prefs['brightness'] = self._enhancer.brightness
prefs['contrast'] = self._enhancer.contrast
@@ -149,7 +150,7 @@ class _EnhanceImageDialog(gtk.Dialog):
prefs['sharpness'] = self._enhancer.sharpness
prefs['auto contrast'] = self._enhancer.autocontrast
- elif response == gtk.RESPONSE_REJECT:
+ elif response == Gtk.ResponseType.REJECT:
self._block = True
self._brightness_scale.set_value(prefs['brightness'] - 1.0)
self._contrast_scale.set_value(prefs['contrast'] - 1.0)
diff --git a/mcomix/event.py b/mcomix/event.py
index b465192..9f1333e 100644
--- a/mcomix/event.py
+++ b/mcomix/event.py
@@ -2,7 +2,7 @@
"""
import urllib
-import gtk
+from gi.repository import Gdk, Gtk
from mcomix.preferences import prefs
from mcomix import constants
@@ -398,45 +398,45 @@ class EventHandler(object):
manager = keybindings.keybinding_manager(self._window)
# Some keys can only be pressed with certain modifiers that
# are irrelevant to the actual hotkey. Find out and ignore them.
- ALL_ACCELS_MASK = (gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK |
- gtk.gdk.MOD1_MASK)
+ ALL_ACCELS_MASK = (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK |
+ Gdk.ModifierType.MOD1_MASK)
- keymap = gtk.gdk.keymap_get_default()
+ keymap = Gdk.Keymap.get_default()
code = keymap.translate_keyboard_state(
- event.hardware_keycode, event.state, event.group)
+ event.hardware_keycode, event.get_state(), event.group)
- if code is not None:
- keyval, egroup, level, consumed = code
+ if code[0]:
+ keyval = code[1]
+ consumed = code[4]
# If the resulting key is upper case (i.e. SHIFT + key),
# convert it to lower case and remove SHIFT from the consumed flags
# to match how keys are registered (<Shift> + lowercase)
- if (gtk.gdk.keyval_is_upper(keyval) and
- not gtk.gdk.keyval_is_lower(keyval) and
- event.state & gtk.gdk.SHIFT_MASK):
- keyval = gtk.gdk.keyval_to_lower(keyval)
- consumed &= ~gtk.gdk.SHIFT_MASK
+ if (event.get_state() & Gdk.ModifierType.SHIFT_MASK and
+ keyval != Gdk.keyval_to_lower(keyval)):
+ keyval = Gdk.keyval_to_lower(keyval)
+ consumed &= ~Gdk.ModifierType.SHIFT_MASK
# 'consumed' is the modifier that was necessary to type the key
- manager.execute((keyval, event.state & ~consumed & ALL_ACCELS_MASK))
+ manager.execute((keyval, event.get_state() & ~consumed & ALL_ACCELS_MASK))
# ---------------------------------------------------------------
# Register CTRL for scrolling only one page instead of two
# pages in double page mode. This is mainly for mouse scrolling.
# ---------------------------------------------------------------
- if event.keyval in (gtk.keysyms.Control_L, gtk.keysyms.Control_R):
+ if event.keyval in (Gdk.KEY_Control_L, Gdk.KEY_Control_R):
self._window.imagehandler.force_single_step = True
# ----------------------------------------------------------------
# We kill the signals here for the Up, Down, Space and Enter keys,
# or they will start fiddling with the thumbnail selector (bad).
# ----------------------------------------------------------------
- if (event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down,
- gtk.keysyms.space, gtk.keysyms.KP_Enter, gtk.keysyms.KP_Up,
- gtk.keysyms.KP_Down, gtk.keysyms.KP_Home, gtk.keysyms.KP_End,
- gtk.keysyms.KP_Page_Up, gtk.keysyms.KP_Page_Down) or
- (event.keyval == gtk.keysyms.Return and not
- 'GDK_MOD1_MASK' in event.state.value_names)):
+ if (event.keyval in (Gdk.KEY_Up, Gdk.KEY_Down,
+ Gdk.KEY_space, Gdk.KEY_KP_Enter, Gdk.KEY_KP_Up,
+ Gdk.KEY_KP_Down, Gdk.KEY_KP_Home, Gdk.KEY_KP_End,
+ Gdk.KEY_KP_Page_Up, Gdk.KEY_KP_Page_Down) or
+ (event.keyval == Gdk.KEY_Return and not
+ 'GDK_MOD1_MASK' in event.get_state().value_names)):
self._window.emit_stop_by_name('key_press_event')
return True
@@ -447,7 +447,7 @@ class EventHandler(object):
# ---------------------------------------------------------------
# Unregister CTRL for scrolling only one page in double page mode
# ---------------------------------------------------------------
- if event.keyval in (gtk.keysyms.Control_L, gtk.keysyms.Control_R):
+ if event.keyval in (Gdk.KEY_Control_L, Gdk.KEY_Control_R):
self._window.imagehandler.force_single_step = False
def escape_event(self):
@@ -462,34 +462,48 @@ class EventHandler(object):
wheel flips pages in best fit mode and scrolls the scrollbars
otherwise.
"""
- if 'GDK_BUTTON2_MASK' in event.state.value_names:
+ if event.get_state() & Gdk.ModifierType.BUTTON2_MASK:
return
+ has_direction, direction = event.get_scroll_direction()
+ if not has_direction:
+ direction = None
+ has_delta, delta_x, delta_y = event.get_scroll_deltas()
+ if has_delta:
+ if delta_y < 0:
+ direction = Gdk.ScrollDirection.UP
+ elif delta_y > 0:
+ direction = Gdk.ScrollDirection.DOWN
+ elif delta_x < 0:
+ direction = Gdk.ScrollDirection.LEFT
+ elif delta_x > 0:
+ direction = Gdk.ScrollDirection.RIGHT
+
self._scroll_protection = True
- if event.direction == gtk.gdk.SCROLL_UP:
- if event.state & gtk.gdk.CONTROL_MASK:
+ if direction == Gdk.ScrollDirection.UP:
+ if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
self._window.manual_zoom_in()
elif prefs['smart scroll']:
self._smart_scroll_up(prefs['number of pixels to scroll per mouse wheel event'])
else:
self._scroll_with_flipping(0, -prefs['number of pixels to scroll per mouse wheel event'])
- elif event.direction == gtk.gdk.SCROLL_DOWN:
- if event.state & gtk.gdk.CONTROL_MASK:
+ elif direction == Gdk.ScrollDirection.DOWN:
+ if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
self._window.manual_zoom_out()
elif prefs['smart scroll']:
self._smart_scroll_down(prefs['number of pixels to scroll per mouse wheel event'])
else:
self._scroll_with_flipping(0, prefs['number of pixels to scroll per mouse wheel event'])
- elif event.direction == gtk.gdk.SCROLL_RIGHT:
+ elif direction == Gdk.ScrollDirection.RIGHT:
if not self._window.is_manga_mode:
self._window.flip_page(+1)
else:
self._previous_page_with_protection()
- elif event.direction == gtk.gdk.SCROLL_LEFT:
+ elif direction == Gdk.ScrollDirection.LEFT:
if not self._window.is_manga_mode:
self._previous_page_with_protection()
else:
@@ -511,11 +525,11 @@ class EventHandler(object):
self._window.actiongroup.get_action('lens').set_active(True)
elif (event.button == 3 and
- not event.state & gtk.gdk.MOD1_MASK and
- not event.state & gtk.gdk.SHIFT_MASK):
+ not event.get_state() & Gdk.ModifierType.MOD1_MASK and
+ not event.get_state() & Gdk.ModifierType.SHIFT_MASK):
self._window.cursor_handler.set_cursor_type(constants.NORMAL_CURSOR)
- self._window.popup.popup(None, None, None, event.button,
- event.time)
+ self._window.popup.popup(None, None, None, None,
+ event.button, event.time)
elif event.button == 4:
self._window.show_info_panel()
@@ -531,7 +545,7 @@ class EventHandler(object):
event.y_root == self._pressed_pointer_pos_y and \
not self._window.was_out_of_focus:
- if event.state & gtk.gdk.SHIFT_MASK:
+ if event.get_state() & Gdk.ModifierType.SHIFT_MASK:
self._flip_page(10)
else:
self._flip_page(1)
@@ -543,9 +557,9 @@ class EventHandler(object):
self._window.actiongroup.get_action('lens').set_active(False)
elif event.button == 3:
- if event.state & gtk.gdk.MOD1_MASK:
+ if event.get_state() & Gdk.ModifierType.MOD1_MASK:
self._flip_page(-1)
- elif event.state & gtk.gdk.SHIFT_MASK:
+ elif event.get_state() & Gdk.ModifierType.SHIFT_MASK:
self._flip_page(-10)
def mouse_move_event(self, widget, event):
@@ -553,7 +567,7 @@ class EventHandler(object):
event = _get_latest_event_of_same_type(event)
- if 'GDK_BUTTON1_MASK' in event.state.value_names:
+ if 'GDK_BUTTON1_MASK' in event.get_state().value_names:
self._window.cursor_handler.set_cursor_type(constants.GRAB_CURSOR)
scrolled = self._window.scroll(self._last_pointer_pos_x - event.x_root,
self._last_pointer_pos_y - event.y_root)
@@ -588,7 +602,7 @@ class EventHandler(object):
"""Handle drag-n-drop events on the main layout area."""
# The drag source is inside MComix itself, so we ignore.
- if (context.get_source_widget() is not None):
+ if (Gtk.drag_get_source_widget(context) is not None):
return
uris = selection.get_uris()
@@ -753,10 +767,11 @@ def _get_latest_event_of_same_type(event):
as <event>, or <event> itself if no such events are in the queue. All
events of that type will be removed from the event queue.
"""
+ return event
events = []
- while gtk.gdk.events_pending():
- queued_event = gtk.gdk.event_get()
+ while Gdk.events_pending():
+ queued_event = Gdk.event_get()
if queued_event is not None:
diff --git a/mcomix/file_chooser_base_dialog.py b/mcomix/file_chooser_base_dialog.py
index e4fbf91..a6e9d81 100644
--- a/mcomix/file_chooser_base_dialog.py
+++ b/mcomix/file_chooser_base_dialog.py
@@ -3,8 +3,7 @@
import os
import mimetypes
import fnmatch
-import gtk
-import pango
+from gi.repository import Gtk, Pango
from mcomix.preferences import prefs
from mcomix import image_tools
@@ -19,12 +18,12 @@ from mcomix import tools
mimetypes.init()
-class _BaseFileChooserDialog(gtk.Dialog):
+class _BaseFileChooserDialog(Gtk.Dialog):
"""We roll our own FileChooserDialog because the one in GTK seems
buggy with the preview widget. The <action> argument dictates what type
- of filechooser dialog we want (i.e. it is gtk.FILE_CHOOSER_ACTION_OPEN
- or gtk.FILE_CHOOSER_ACTION_SAVE).
+ of filechooser dialog we want (i.e. it is Gtk.FileChooserAction.OPEN
+ or Gtk.FileChooserAction.SAVE).
This is a base class for the _MainFileChooserDialog, the
_LibraryFileChooserDialog and the SimpleFileChooserDialog.
@@ -36,49 +35,49 @@ class _BaseFileChooserDialog(gtk.Dialog):
_last_activated_file = None
- def __init__(self, action=gtk.FILE_CHOOSER_ACTION_OPEN):
+ def __init__(self, action=Gtk.FileChooserAction.OPEN):
self._action = action
self._destroyed = False
- if action == gtk.FILE_CHOOSER_ACTION_OPEN:
+ if action == Gtk.FileChooserAction.OPEN:
title = _('Open')
- buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OPEN, gtk.RESPONSE_OK)
+ buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+ Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
else:
title = _('Save')
- buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_SAVE, gtk.RESPONSE_OK)
+ buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+ Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
super(_BaseFileChooserDialog, self).__init__(title, None, 0, buttons)
- self.set_default_response(gtk.RESPONSE_OK)
+ self.set_default_response(Gtk.ResponseType.OK)
- self.filechooser = gtk.FileChooserWidget(action=action)
+ self.filechooser = Gtk.FileChooserWidget(action=action)
self.filechooser.set_size_request(680, 420)
- self.vbox.pack_start(self.filechooser)
+ self.vbox.pack_start(self.filechooser, True, True, 0)
self.set_border_width(4)
self.filechooser.set_border_width(6)
self.connect('response', self._response)
self.filechooser.connect('file_activated', self._response,
- gtk.RESPONSE_OK)
+ Gtk.ResponseType.OK)
- preview_box = gtk.VBox(False, 10)
+ preview_box = Gtk.VBox(False, 10)
preview_box.set_size_request(130, 0)
- self._preview_image = gtk.Image()
+ self._preview_image = Gtk.Image()
self._preview_image.set_size_request(130, 130)
- preview_box.pack_start(self._preview_image, False, False)
+ preview_box.pack_start(self._preview_image, False, False, 0)
self.filechooser.set_preview_widget(preview_box)
pango_scale_small = (1 / 1.2)
- self._namelabel = labels.FormattedLabel(weight=pango.WEIGHT_BOLD,
+ self._namelabel = labels.FormattedLabel(weight=Pango.Weight.BOLD,
scale=pango_scale_small)
- self._namelabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
- preview_box.pack_start(self._namelabel, False, False)
+ self._namelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
+ preview_box.pack_start(self._namelabel, False, False, 0)
self._sizelabel = labels.FormattedLabel(scale=pango_scale_small)
- self._sizelabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
- preview_box.pack_start(self._sizelabel, False, False)
+ self._sizelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
+ preview_box.pack_start(self._sizelabel, False, False, 0)
self.filechooser.set_use_preview_label(False)
preview_box.show_all()
self.filechooser.connect('update-preview', self._update_preview)
@@ -113,9 +112,9 @@ class _BaseFileChooserDialog(gtk.Dialog):
"""Add a filter, called <name>, for each mime type in <mimes> and
each pattern in <patterns> to the filechooser.
"""
- ffilter = gtk.FileFilter()
+ ffilter = Gtk.FileFilter()
ffilter.add_custom(
- gtk.FILE_FILTER_FILENAME|gtk.FILE_FILTER_MIME_TYPE,
+ Gtk.FileFilterFlags.FILENAME | Gtk.FileFilterFlags.MIME_TYPE,
self._filter, (patterns, mimes))
ffilter.set_name(name)
@@ -125,7 +124,7 @@ class _BaseFileChooserDialog(gtk.Dialog):
def add_archive_filters(self):
"""Add archive filters to the filechooser.
"""
- ffilter = gtk.FileFilter()
+ ffilter = Gtk.FileFilter()
ffilter.set_name(_('All archives'))
self.filechooser.add_filter(ffilter)
supported_formats = archive_tools.get_supported_formats()
@@ -141,7 +140,7 @@ class _BaseFileChooserDialog(gtk.Dialog):
def add_image_filters(self):
"""Add images filters to the filechooser.
"""
- ffilter = gtk.FileFilter()
+ ffilter = Gtk.FileFilter()
ffilter.set_name(_('All images'))
self.filechooser.add_filter(ffilter)
supported_formats = image_tools.get_supported_formats()
@@ -160,31 +159,31 @@ class _BaseFileChooserDialog(gtk.Dialog):
(patterns, mimes) that should pass the test. Returns True
if the file passed in C{filter_info} should be displayed. """
- path, uri, display, mime = filter_info
match_patterns, match_mimes = data
matches_mime = bool(filter(
- lambda match_mime: match_mime == mime,
+ lambda match_mime: match_mime == filter_info.mime_type,
match_mimes))
matches_pattern = bool(filter(
- lambda match_pattern: fnmatch.fnmatch(path, match_pattern),
+ lambda match_pattern: fnmatch.fnmatch(filter_info.filename, match_pattern),
match_patterns))
return matches_mime or matches_pattern
def collect_files_from_subdir(self, path, filter, recursive=False):
""" Finds archives within C{path} that match the
- L{gtk.FileFilter} passed in C{filter}. """
+ L{Gtk.FileFilter} passed in C{filter}. """
for root, dirs, files in os.walk(path):
for file in files:
full_path = os.path.join(root, file)
mimetype = mimetypes.guess_type(full_path)[0] or 'application/octet-stream'
+ filter_info = Gtk.FileFilterInfo()
+ filter_info.contains = Gtk.FileFilterFlags.FILENAME | Gtk.FileFilterFlags.MIME_TYPE
+ filter_info.filename = full_path.encode('utf-8')
+ filter_info.mime_type = mimetype
- if (filter == self._all_files_filter or
- filter.filter((full_path.encode('utf-8'),
- None, None, mimetype))):
-
+ if (filter == self._all_files_filter or filter.filter(filter_info)):
yield full_path
if not recursive:
@@ -203,7 +202,7 @@ class _BaseFileChooserDialog(gtk.Dialog):
"""Return a list of the paths of the chosen files, or None if the
event only changed the current directory.
"""
- if response == gtk.RESPONSE_OK:
+ if response == Gtk.ResponseType.OK:
if not self.filechooser.get_filenames():
return
@@ -224,19 +223,19 @@ class _BaseFileChooserDialog(gtk.Dialog):
# FileChooser.set_do_overwrite_confirmation() doesn't seem to
# work on our custom dialog, so we use a simple alternative.
first_path = self.filechooser.get_filenames()[0].decode('utf-8')
- if (self._action == gtk.FILE_CHOOSER_ACTION_SAVE and
+ if (self._action == Gtk.FileChooserAction.SAVE and
not os.path.isdir(first_path) and
os.path.exists(first_path)):
overwrite_dialog = message_dialog.MessageDialog(None, 0,
- gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL)
+ Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL)
overwrite_dialog.set_text(
_("A file named '%s' already exists. Do you want to replace it?") %
os.path.basename(first_path),
_('Replacing it will overwrite its contents.'))
response = overwrite_dialog.run()
- if response != gtk.RESPONSE_OK:
+ if response != Gtk.ResponseType.OK:
self.emit_stop_by_name('response')
return
diff --git a/mcomix/file_chooser_library_dialog.py b/mcomix/file_chooser_library_dialog.py
index c325863..c2f22f2 100644
--- a/mcomix/file_chooser_library_dialog.py
+++ b/mcomix/file_chooser_library_dialog.py
@@ -1,6 +1,6 @@
"""file_chooser_library_dialog.py - Custom FileChooserDialog implementations."""
-import gtk
+from gi.repository import Gtk
from mcomix.preferences import prefs
from mcomix import file_chooser_base_dialog
@@ -43,9 +43,9 @@ class _LibraryFileChooserDialog(file_chooser_base_dialog._BaseFileChooserDialog)
for widget in self.get_action_area().get_children():
self.get_action_area().remove(widget)
- self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
- self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
- self.set_default_response(gtk.RESPONSE_OK)
+ self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
+ self.add_button(Gtk.STOCK_ADD, Gtk.ResponseType.OK)
+ self.set_default_response(Gtk.ResponseType.OK)
def should_open_recursive(self):
return True
diff --git a/mcomix/file_chooser_main_dialog.py b/mcomix/file_chooser_main_dialog.py
index e5ca2c3..17d7afc 100644
--- a/mcomix/file_chooser_main_dialog.py
+++ b/mcomix/file_chooser_main_dialog.py
@@ -1,6 +1,6 @@
"""file_chooser_main_dialog.py - Custom FileChooserDialog implementations."""
-import gtk
+from gi.repository import Gtk
from mcomix.preferences import prefs
from mcomix import file_chooser_base_dialog
diff --git a/mcomix/file_chooser_simple_dialog.py b/mcomix/file_chooser_simple_dialog.py
index 8ff6f3f..8edf210 100644
--- a/mcomix/file_chooser_simple_dialog.py
+++ b/mcomix/file_chooser_simple_dialog.py
@@ -1,20 +1,20 @@
"""file_chooser_simple_dialog.py - Custom FileChooserDialog implementations."""
-import gtk
+from gi.repository import Gtk
from mcomix import file_chooser_base_dialog
class SimpleFileChooserDialog(file_chooser_base_dialog._BaseFileChooserDialog):
"""A simple filechooser dialog that is designed to be used with the
- gtk.Dialog.run() method. The <action> dictates what type of filechooser
+ Gtk.Dialog.run() method. The <action> dictates what type of filechooser
dialog we want (i.e. save or open). If the type is an open-dialog, we
use multiple selection by default.
"""
- def __init__(self, action=gtk.FILE_CHOOSER_ACTION_OPEN):
+ def __init__(self, action=Gtk.FileChooserAction.OPEN):
super(SimpleFileChooserDialog, self).__init__(action)
- if action == gtk.FILE_CHOOSER_ACTION_OPEN:
+ if action == Gtk.FileChooserAction.OPEN:
self.filechooser.set_select_multiple(True)
self._paths = None
diff --git a/mcomix/file_handler.py b/mcomix/file_handler.py
index e2eaeea..affc5c7 100644
--- a/mcomix/file_handler.py
+++ b/mcomix/file_handler.py
@@ -7,7 +7,7 @@ import tempfile
import threading
import re
import cPickle
-import gtk
+from gi.repository import Gtk
from mcomix.preferences import prefs
from mcomix import archive_extractor
@@ -217,8 +217,8 @@ class FileHandler(object):
self._name_table.clear()
self.file_closed()
# Catch up on UI events, so we don't leave idle callbacks.
- while gtk.events_pending():
- gtk.main_iteration_do(False)
+ while Gtk.events_pending():
+ Gtk.main_iteration_do(False)
tools.garbage_collect()
if self._tmp_dir is not None:
self.thread_delete(self._tmp_dir)
@@ -356,11 +356,11 @@ class FileHandler(object):
read_date = self.last_read_page.get_date(path)
- dialog = message_dialog.MessageDialog(self._window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
- gtk.BUTTONS_YES_NO)
- dialog.set_default_response(gtk.RESPONSE_YES)
+ dialog = message_dialog.MessageDialog(self._window, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO,
+ Gtk.ButtonsType.YES_NO)
+ dialog.set_default_response(Gtk.ResponseType.YES)
dialog.set_should_remember_choice('resume-from-last-read-page',
- (gtk.RESPONSE_YES, gtk.RESPONSE_NO))
+ (Gtk.ResponseType.YES, Gtk.ResponseType.NO))
dialog.set_text(
(_('Continue reading from page %d?') % last_read_page),
_('You stopped reading here on %(date)s, %(time)s. '
@@ -369,7 +369,7 @@ class FileHandler(object):
'time': read_date.time().strftime("%X"), 'page': last_read_page})
result = dialog.run()
- return result == gtk.RESPONSE_YES
+ return result == Gtk.ResponseType.YES
def _open_image_files(self, filelist, image_path):
""" Opens all files passed in C{filelist}.
diff --git a/mcomix/i18n.py b/mcomix/i18n.py
index c78486e..fa3e2ab 100644
--- a/mcomix/i18n.py
+++ b/mcomix/i18n.py
@@ -82,15 +82,19 @@ def install_gettext():
os.environ['LANGUAGE'] = lang
domain = constants.APPNAME.lower()
- translation = gettext.NullTranslations()
# Search for .mo files manually, since gettext doesn't support setuptools/pkg_resources.
for lang in lang_identifiers:
- resource = os.path.join(lang, 'LC_MESSAGES', '%s.mo' % domain)
- if pkg_resources.resource_exists('mcomix.messages', resource):
- translation = gettext.GNUTranslations(
- pkg_resources.resource_stream('mcomix.messages', resource))
+ resource = os.path.join('messages', lang, 'LC_MESSAGES', '%s.mo' % domain)
+ try:
+ fp = pkg_resources.resource_stream('mcomix', resource)
+ except IOError:
+ pass
+ else:
+ translation = gettext.GNUTranslations(fp)
break
+ else:
+ translation = gettext.NullTranslations()
translation.install(unicode=True)
diff --git a/mcomix/icons.py b/mcomix/icons.py
index 8eeeab9..b511ef7 100644
--- a/mcomix/icons.py
+++ b/mcomix/icons.py
@@ -1,6 +1,6 @@
"""icons.py - Load MComix specific icons."""
-import gtk
+from gi.repository import Gtk
from pkg_resources import resource_string
from mcomix import image_tools
@@ -13,7 +13,7 @@ def mcomix_icons():
sizes = ('16x16', '32x32', '48x48')
pixbufs = [
image_tools.load_pixbuf_data(
- resource_string('mcomix.images', size + '/mcomix.png')
+ resource_string('mcomix', 'images/%s/mcomix.png' % size)
) for size in sizes
]
@@ -45,14 +45,14 @@ def load_icons():
# Load window title icons.
pixbufs = mcomix_icons()
- gtk.window_set_default_icon_list(*pixbufs)
+ Gtk.Window.set_default_icon_list(pixbufs)
# Load application icons.
- factory = gtk.IconFactory()
+ factory = Gtk.IconFactory()
for filename, stockid in _icons:
try:
- icon_data = resource_string('mcomix.images', filename)
+ icon_data = resource_string('mcomix', 'images/%s' % filename)
pixbuf = image_tools.load_pixbuf_data(icon_data)
- iconset = gtk.IconSet(pixbuf)
+ iconset = Gtk.IconSet(pixbuf)
factory.add(stockid, iconset)
except Exception:
log.warning(_('! Could not load icon "%s"'), filename)
diff --git a/mcomix/image_tools.py b/mcomix/image_tools.py
index c89b700..77abd95 100644
--- a/mcomix/image_tools.py
+++ b/mcomix/image_tools.py
@@ -5,7 +5,7 @@ import binascii
import re
import sys
import operator
-import gtk
+from gi.repository import GLib, GdkPixbuf, Gdk, Gtk
from PIL import Image
from PIL import ImageEnhance
from PIL import ImageOps
@@ -34,22 +34,20 @@ else:
log.info('Using %s for loading images (versions: %s [%s], GDK [%s])',
'PIL' if USE_PIL else 'GDK',
PIL_VERSION[0], PIL_VERSION[1],
- # Unfortunately gdk_pixbuf_version is not exported,
- # so show the GTK+ version instead.
- 'GTK+ ' + '.'.join(map(str, gtk.gtk_version)))
+ GdkPixbuf.PIXBUF_VERSION)
# Fallback pixbuf for missing images.
MISSING_IMAGE_ICON = None
-_missing_icon_dialog = gtk.Dialog()
+_missing_icon_dialog = Gtk.Dialog()
_missing_icon_pixbuf = _missing_icon_dialog.render_icon(
- gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_LARGE_TOOLBAR)
+ Gtk.STOCK_MISSING_IMAGE, Gtk.IconSize.LARGE_TOOLBAR)
MISSING_IMAGE_ICON = _missing_icon_pixbuf
assert MISSING_IMAGE_ICON
-GTK_GDK_COLOR_BLACK = gtk.gdk.color_parse('black')
-GTK_GDK_COLOR_WHITE = gtk.gdk.color_parse('white')
+GTK_GDK_COLOR_BLACK = Gdk.color_parse('black')
+GTK_GDK_COLOR_WHITE = Gdk.color_parse('white')
def rotate_pixbuf(src, rotation):
@@ -57,11 +55,11 @@ def rotate_pixbuf(src, rotation):
if 0 == rotation:
return src
if 90 == rotation:
- return src.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
+ return src.rotate_simple(GdkPixbuf.PixbufRotation.CLOCKWISE)
if 180 == rotation:
- return src.rotate_simple(gtk.gdk.PIXBUF_ROTATE_UPSIDEDOWN)
+ return src.rotate_simple(GdkPixbuf.PixbufRotation.UPSIDEDOWN)
if 270 == rotation:
- return src.rotate_simple(gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
+ return src.rotate_simple(GdkPixbuf.PixbufRotation.COUNTERCLOCKWISE)
raise ValueError("unsupported rotation: %s" % rotation)
def get_fitting_size(source_size, target_size,
@@ -143,9 +141,9 @@ def fit_in_rectangle(src, width, height, keep_ratio=True, scale_up=False, rotati
else:
check_size, color1, color2 = 1024, 0xFFFFFF, 0xFFFFFF
if width == src_width and height == src_height:
- # Using anything other than INTERP_NEAREST will result in a
- # modified image even if it's opaque and no resizing takes place.
- scaling_quality = gtk.gdk.INTERP_NEAREST
+ # Using anything other than nearest interpolation will result in a
+ # modified image if no resizing takes place (even if it's opaque).
+ scaling_quality = GdkPixbuf.InterpType.NEAREST
src = src.composite_color_simple(width, height, scaling_quality,
255, check_size, color1, color2)
elif width != src_width or height != src_height:
@@ -160,7 +158,7 @@ def add_border(pixbuf, thickness, colour=0x000000FF):
"""Return a pixbuf from <pixbuf> with a <thickness> px border of
<colour> added.
"""
- canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
+ canvas = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8,
pixbuf.get_width() + thickness * 2,
pixbuf.get_height() + thickness * 2)
canvas.fill(colour)
@@ -245,7 +243,7 @@ def get_most_common_edge_colour(pixbufs, edge=2):
height = pixbuf.get_height()
edge = min(edge, width, height)
- subpix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
+ subpix = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB,
pixbuf.get_has_alpha(), 8, edge, height)
if side == 'left':
pixbuf.copy_area(0, 0, edge, height, subpix, 0, 0)
@@ -293,8 +291,8 @@ def pil_to_pixbuf(im, keep_orientation=False):
target_mode = 'RGBA' if has_alpha else 'RGB'
if im.mode != target_mode:
im = im.convert(target_mode)
- pixbuf = gtk.gdk.pixbuf_new_from_data(
- im.tobytes(), gtk.gdk.COLORSPACE_RGB,
+ pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(
+ GLib.Bytes.new(im.tobytes()), GdkPixbuf.Colorspace.RGB,
has_alpha, 8,
im.size[0], im.size[1],
(4 if has_alpha else 3) * im.size[0]
@@ -323,7 +321,8 @@ def pixbuf_to_pil(pixbuf):
return im
def is_animation(pixbuf):
- return isinstance(pixbuf, gtk.gdk.PixbufAnimation)
+ return isinstance(pixbuf, GdkPixbuf.PixbufAnimation)
+ #return isinstance(pixbuf, Gtk.gdk.PixbufAnimation)
def static_image(pixbuf):
""" Returns a non-animated version of the specified pixbuf. """
@@ -333,24 +332,24 @@ def static_image(pixbuf):
def unwrap_image(image):
""" Returns an object that contains the image data based on
- gtk.Image.get_storage_type or None if image is None or image.get_storage_type
- returns gtk.IMAGE_EMPTY. """
+ Gtk.Image.get_storage_type or None if image is None or image.get_storage_type
+ returns Gtk.IMAGE_EMPTY. """
if image is None:
return None
t = image.get_storage_type()
- if t == gtk.IMAGE_EMPTY:
+ if t == Gtk.IMAGE_EMPTY:
return None
- if t == gtk.IMAGE_PIXBUF:
+ if t == Gtk.IMAGE_PIXBUF:
return image.get_pixbuf()
- if t == gtk.IMAGE_ANIMATION:
+ if t == Gtk.IMAGE_ANIMATION:
return image.get_animation()
- if t == gtk.IMAGE_PIXMAP:
+ if t == Gtk.IMAGE_PIXMAP:
return image.get_pixmap()
- if t == gtk.IMAGE_IMAGE:
+ if t == Gtk.IMAGE_IMAGE:
return image.get_image()
- if t == gtk.IMAGE_STOCK:
+ if t == Gtk.IMAGE_STOCK:
return image.get_stock()
- if t == gtk.IMAGE_ICON_SET:
+ if t == Gtk.IMAGE_ICON_SET:
return image.get_icon_set()
raise ValueError()
@@ -364,7 +363,7 @@ def load_pixbuf(path):
""" Loads a pixbuf from a given image file. """
if prefs['animation mode'] != constants.ANIMATION_DISABLED:
# Note that this branch ignores USE_PIL
- pixbuf = gtk.gdk.PixbufAnimation(path)
+ pixbuf = Gtk.gdk.PixbufAnimation(path)
if pixbuf.is_static_image():
pixbuf = pixbuf.get_static_image()
return pixbuf
@@ -372,7 +371,7 @@ def load_pixbuf(path):
im = Image.open(path)
pixbuf = pil_to_pixbuf(im, keep_orientation=True)
else:
- pixbuf = gtk.gdk.pixbuf_new_from_file(path)
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
return pixbuf
def load_pixbuf_size(path, width, height):
@@ -387,24 +386,24 @@ def load_pixbuf_size(path, width, height):
# If we could not get the image info, still try to load
# the image to let GdkPixbuf raise the appropriate exception.
if (0, 0) == (image_width, image_height):
- pixbuf = gtk.gdk.pixbuf_new_from_file(path)
+ pixbuf = Gtk.gdk.pixbuf_new_from_file(path)
# Work around GdkPixbuf bug: https://bugzilla.gnome.org/show_bug.cgi?id=735422
elif 'GIF' == image_format:
- pixbuf = gtk.gdk.pixbuf_new_from_file(path)
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
else:
# Don't upscale if smaller than target dimensions!
if image_width <= width and image_height <= height:
width, height = image_width, image_height
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(path, width, height)
- return fit_in_rectangle(pixbuf, width, height, scaling_quality=gtk.gdk.INTERP_BILINEAR)
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, width, height)
+ return fit_in_rectangle(pixbuf, width, height, scaling_quality=GdkPixbuf.InterpType.BILINEAR)
def load_pixbuf_data(imgdata):
""" Loads a pixbuf from the data passed in <imgdata>. """
if USE_PIL:
pixbuf = pil_to_pixbuf(Image.open(StringIO(imgdata)), keep_orientation=True)
else:
- loader = gtk.gdk.PixbufLoader()
- loader.write(imgdata, len(imgdata))
+ loader = GdkPixbuf.PixbufLoader()
+ loader.write(imgdata)
loader.close()
pixbuf = loader.get_pixbuf()
return pixbuf
@@ -435,7 +434,7 @@ def _get_png_implied_rotation(pixbuf_or_image):
Lookup for Exif data in the tEXt chunk.
"""
- if isinstance(pixbuf_or_image, gtk.gdk.Pixbuf):
+ if isinstance(pixbuf_or_image, GdkPixbuf.Pixbuf):
exif = pixbuf_or_image.get_option('tEXt::Raw profile type exif')
elif isinstance(pixbuf_or_image, Image.Image):
exif = pixbuf_or_image.info.get('Raw profile type exif')
@@ -512,8 +511,10 @@ def combine_pixbufs( pixbuf1, pixbuf2, are_in_manga_mode ):
new_height = max( l_source_pixbuf_height, r_source_pixbuf_height )
- new_pix_buf = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, has_alpha,
- bits_per_sample, new_width, new_height )
+ new_pix_buf = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=has_alpha,
+ bits_per_sample=bits_per_sample,
+ width=new_width, height=new_height)
l_source_pixbuf.copy_area( 0, 0, l_source_pixbuf_width,
l_source_pixbuf_height,
@@ -540,6 +541,9 @@ def text_color_for_background_color(bgcolor):
return GTK_GDK_COLOR_BLACK if rgb_to_y_601(bgcolor) >= \
65535.0 / 2.0 else GTK_GDK_COLOR_WHITE
+def color_to_floats_rgba(color, alpha=1.0):
+ return [c / 65535.0 for c in color] + [alpha]
+
def get_image_info(path):
"""Return image informations:
(format, width, height)
@@ -554,9 +558,11 @@ def get_image_info(path):
# cannot be opened and identified.
im = None
else:
- info = gtk.gdk.pixbuf_get_file_info(path)
- if info is not None:
- info = info[0]['name'].upper(), info[1], info[2]
+ info = GdkPixbuf.Pixbuf.get_file_info(path)
+ if info[0] is None:
+ info = None
+ else:
+ info = info[0].get_name().upper(), info[1], info[2]
if info is None:
info = (_('Unknown filetype'), 0, 0)
return info
@@ -595,12 +601,12 @@ def get_supported_formats():
del supported_formats[name]
else:
supported_formats = {}
- for format in gtk.gdk.pixbuf_get_formats():
- name = format['name'].upper()
+ for format in GdkPixbuf.Pixbuf.get_formats():
+ name = format.get_name().upper()
assert name not in supported_formats
supported_formats[name] = (
- format['mime_types'],
- format['extensions'],
+ format.get_mime_types(),
+ format.get_extensions(),
)
return supported_formats
diff --git a/mcomix/images/__init__.py b/mcomix/images/__init__.py
deleted file mode 100644
index 7fc7b50..0000000
--- a/mcomix/images/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-""" This file is required for setuptools packaging. """
diff --git a/mcomix/keybindings.py b/mcomix/keybindings.py
index b7dac0d..883ee2b 100644
--- a/mcomix/keybindings.py
+++ b/mcomix/keybindings.py
@@ -26,7 +26,7 @@ Each action_name can have multiple keybindings.
import os
import shutil
-import gtk
+from gi.repository import Gtk
import json
from collections import defaultdict
@@ -163,7 +163,7 @@ class _KeybindingManager(object):
""" Registers an action for a predefined keybinding name.
@param name: Action name, defined in L{BINDING_INFO}.
@param bindings: List of keybinding strings, as understood
- by L{gtk.accelerator_parse}. Only used if no
+ by L{Gtk.accelerator_parse}. Only used if no
bindings were loaded for this action.
@param callback: Function callback
@param args: List of arguments to pass to the callback
@@ -174,7 +174,7 @@ class _KeybindingManager(object):
# Load stored keybindings, or fall back to passed arguments
keycodes = self._action_to_bindings[name]
if keycodes == []:
- keycodes = [gtk.accelerator_parse(binding) for binding in bindings ]
+ keycodes = [Gtk.accelerator_parse(binding) for binding in bindings ]
for keycode in keycodes:
if keycode in self._binding_to_action.keys():
@@ -189,7 +189,7 @@ class _KeybindingManager(object):
# Add gtk accelerator for labels in menu
if len(self._action_to_bindings[name]) > 0:
key, mod = self._action_to_bindings[name][0]
- gtk.accel_map_change_entry('<Actions>/mcomix-main/%s' % name, key, mod, True)
+ Gtk.AccelMap.change_entry('<Actions>/mcomix-main/%s' % name, key, mod, True)
self._action_to_callback[name] = (callback, args, kwargs)
@@ -205,7 +205,7 @@ class _KeybindingManager(object):
"""
assert name in BINDING_INFO, "'%s' isn't a valid keyboard action." % name
- nb = gtk.accelerator_parse(new_binding)
+ nb = Gtk.accelerator_parse(new_binding)
old_action_with_nb = self._binding_to_action.get(nb)
if old_action_with_nb is not None:
# The new key is already bound to an action, erase the action
@@ -214,7 +214,7 @@ class _KeybindingManager(object):
if old_binding and name != old_action_with_nb:
# The action already had a key that is now being replaced
- ob = gtk.accelerator_parse(old_binding)
+ ob = Gtk.accelerator_parse(old_binding)
self._binding_to_action[nb] = name
# Remove action bound to the key.
@@ -236,7 +236,7 @@ class _KeybindingManager(object):
""" Remove binding for an action """
assert name in BINDING_INFO, "'%s' isn't a valid keyboard action." % name
- ob = gtk.accelerator_parse(binding)
+ ob = Gtk.accelerator_parse(binding)
self._action_to_bindings[name].remove(ob)
self._binding_to_action.pop(ob)
@@ -277,7 +277,7 @@ class _KeybindingManager(object):
for action, bindings in self._action_to_bindings.iteritems():
if bindings is not None:
action_to_keys[action] = [
- gtk.accelerator_name(keyval, modifiers) for
+ Gtk.accelerator_name(keyval, modifiers) for
(keyval, modifiers) in bindings
]
fp = open(constants.KEYBINDINGS_CONF_PATH, "w")
@@ -297,7 +297,7 @@ class _KeybindingManager(object):
for action in BINDING_INFO.iterkeys():
if action in stored_action_bindings:
bindings = [
- gtk.accelerator_parse(keyname)
+ Gtk.accelerator_parse(keyname)
for keyname in stored_action_bindings[action] ]
self._action_to_bindings[action] = bindings
for binding in bindings:
@@ -313,7 +313,7 @@ class _KeybindingManager(object):
""" This method deals with upgrading from MComix 1.0 and older to
MComix 1.01, which integrated all UI hotkeys into this class. Simply
remove old files and start from default values. """
- gtkrc = os.path.join(constants.CONFIG_DIR, 'keybindings-gtk.rc')
+ gtkrc = os.path.join(constants.CONFIG_DIR, 'keybindings-Gtk.rc')
if os.path.isfile(gtkrc):
# In case the user has made modifications to his files,
# keep the old ones around for reference.
diff --git a/mcomix/keybindings_editor.py b/mcomix/keybindings_editor.py
index 72fe9d3..b74d203 100644
--- a/mcomix/keybindings_editor.py
+++ b/mcomix/keybindings_editor.py
@@ -2,18 +2,18 @@
""" Configuration tree view for the preferences dialog to edit keybindings. """
-import gtk
+from gi.repository import Gtk
from mcomix import keybindings
-class KeybindingEditorWindow(gtk.ScrolledWindow):
+class KeybindingEditorWindow(Gtk.ScrolledWindow):
def __init__(self, keymanager):
""" @param keymanager: KeybindingManager instance. """
super(KeybindingEditorWindow, self).__init__()
self.set_border_width(5)
- self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
+ self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
self.keymanager = keymanager
@@ -27,21 +27,21 @@ class KeybindingEditorWindow(gtk.ScrolledWindow):
model = [str, str, 'gboolean']
model.extend( [str, ] * accel_column_num)
- treestore = self.treestore = gtk.TreeStore(*model)
+ treestore = self.treestore = Gtk.TreeStore(*model)
self.refresh_model()
- treeview = gtk.TreeView(treestore)
+ treeview = Gtk.TreeView(treestore)
- tvcol1 = gtk.TreeViewColumn(_("Name"))
+ tvcol1 = Gtk.TreeViewColumn(_("Name"))
treeview.append_column(tvcol1)
- cell1 = gtk.CellRendererText()
+ cell1 = Gtk.CellRendererText()
tvcol1.pack_start(cell1, True)
tvcol1.set_attributes(cell1, text=0, editable=2)
for idx in range(0, self.accel_column_num):
- tvc = gtk.TreeViewColumn(_("Key %d") % (idx +1))
+ tvc = Gtk.TreeViewColumn(_("Key %d") % (idx +1))
treeview.append_column(tvc)
- accel_cell = gtk.CellRendererAccel()
+ accel_cell = Gtk.CellRendererAccel()
accel_cell.connect("accel-edited", self.get_on_accel_edited(idx))
accel_cell.connect("accel-cleared", self.get_on_accel_cleared(idx))
tvc.pack_start(accel_cell, True)
@@ -79,7 +79,7 @@ class KeybindingEditorWindow(gtk.ScrolledWindow):
acc_list = ["", ] * self.accel_column_num
for idx in range(0, self.accel_column_num):
if len(old_bindings) > idx:
- acc_list[idx] = gtk.accelerator_name(*old_bindings[idx])
+ acc_list[idx] = Gtk.accelerator_name(*old_bindings[idx])
row = [title, action_name, True]
row.extend(acc_list)
@@ -94,7 +94,7 @@ class KeybindingEditorWindow(gtk.ScrolledWindow):
iter = self.treestore.get_iter(path)
col = column + 3 # accel cells start from 3 position
old_accel = self.treestore.get(iter, col)[0]
- new_accel = gtk.accelerator_name(accel_key, accel_mods)
+ new_accel = Gtk.accelerator_name(accel_key, accel_mods)
self.treestore.set_value(iter, col, new_accel)
action_name = self.treestore.get_value(iter, 1)
affected_action = self.keymanager.edit_accel(action_name, new_accel, old_accel)
@@ -112,7 +112,7 @@ class KeybindingEditorWindow(gtk.ScrolledWindow):
# updating gtk accelerator for label in menu
if self.keymanager.get_bindings_for_action(action_name)[0] == (accel_key, accel_mods):
- gtk.accel_map_change_entry('<Actions>/mcomix-main/%s' % action_name,
+ Gtk.AccelMap.change_entry('<Actions>/mcomix-main/%s' % action_name,
accel_key, accel_mods, True)
return on_accel_edited
@@ -128,10 +128,10 @@ class KeybindingEditorWindow(gtk.ScrolledWindow):
# updating gtk accelerator for label in menu
if len(self.keymanager.get_bindings_for_action(action_name)) == 0:
- gtk.accel_map_change_entry('<Actions>/mcomix-main/%s' % action_name, 0, 0, True)
+ Gtk.AccelMap.change_entry('<Actions>/mcomix-main/%s' % action_name, 0, 0, True)
else:
key, mods = self.keymanager.get_bindings_for_action(action_name)[0]
- gtk.accel_map_change_entry('<Actions>/mcomix-main/%s' % action_name, key, mods, True)
+ Gtk.AccelMap.change_entry('<Actions>/mcomix-main/%s' % action_name, key, mods, True)
self.treestore.set_value(iter, col, "")
return on_accel_cleared
diff --git a/mcomix/labels.py b/mcomix/labels.py
index 7b1f491..1f814e9 100644
--- a/mcomix/labels.py
+++ b/mcomix/labels.py
@@ -1,47 +1,49 @@
-"""labels.py - gtk.Label convenience classes."""
+"""labels.py - Gtk.Label convenience classes."""
-import gtk
-import pango
+from gi.repository import GLib, Gtk, Pango
-class FormattedLabel(gtk.Label):
+class FormattedLabel(Gtk.Label):
"""FormattedLabel keeps a label always formatted with some pango weight,
style and scale, even when new text is set using set_text().
"""
- def __init__(self, text='', weight=pango.WEIGHT_NORMAL,
- style=pango.STYLE_NORMAL, scale=1.0):
- super(FormattedLabel, self).__init__(text)
+ _STYLES = {
+ Pango.Style.NORMAL : 'normal',
+ Pango.Style.OBLIQUE: 'oblique',
+ Pango.Style.ITALIC : 'italic',
+ }
+
+ def __init__(self, text='', weight=Pango.Weight.NORMAL,
+ style=Pango.Style.NORMAL, scale=1.0):
+ super(FormattedLabel, self).__init__()
self._weight = weight
self._style = style
self._scale = scale
- self._format()
+ self.set_text(text)
def set_text(self, text):
- gtk.Label.set_text(self, text)
- self._format()
-
- def _format(self):
- text_len = len(self.get_text())
- attrlist = pango.AttrList()
- attrlist.insert(pango.AttrWeight(self._weight, 0, text_len))
- attrlist.insert(pango.AttrStyle(self._style, 0, text_len))
- attrlist.insert(pango.AttrScale(self._scale, 0, text_len))
- self.set_attributes(attrlist)
+ markup = '<span font_size="%u" font_weight="%u" font_style="%s">%s</span>' % (
+ int(self._scale * 10 * 1024),
+ self._weight,
+ self._STYLES[self._style],
+ GLib.markup_escape_text(text)
+ )
+ self.set_markup(markup)
class BoldLabel(FormattedLabel):
"""A FormattedLabel that is always bold and otherwise normal."""
def __init__(self, text=''):
- super(BoldLabel, self).__init__(text=text, weight=pango.WEIGHT_BOLD)
+ super(BoldLabel, self).__init__(text=text, weight=Pango.Weight.BOLD)
class ItalicLabel(FormattedLabel):
"""A FormattedLabel that is always italic and otherwise normal."""
def __init__(self, text=''):
- super(ItalicLabel, self).__init__(text=text, style=pango.STYLE_ITALIC)
+ super(ItalicLabel, self).__init__(text=text, style=Pango.Style.ITALIC)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/lens.py b/mcomix/lens.py
index 80ac9b2..4f41114 100644
--- a/mcomix/lens.py
+++ b/mcomix/lens.py
@@ -1,7 +1,8 @@
"""lens.py - Magnifying lens."""
import math
-import gtk
+
+from gi.repository import Gdk, GdkPixbuf, Gtk
from mcomix.preferences import prefs
from mcomix import image_tools
@@ -58,24 +59,29 @@ class MagnifyingLens(object):
main window layout area.
"""
if self._window.images[0].get_storage_type() not in (gtk.IMAGE_PIXBUF,
- gtk.IMAGE_ANIMATION):
+ Gtk.IMAGE_ANIMATION):
return
rectangle = self._calculate_lens_rect(x, y, prefs['lens size'], prefs['lens size'])
pixbuf = self._get_lens_pixbuf(x, y)
- # Region used to draw the pixbuf
- lens_region = gtk.gdk.region_rectangle(rectangle)
- # Combined regions (area that will be drawn to in this operation
- full_region = lens_region.copy()
+ draw_region = Gdk.Rectangle()
+ draw_region.x, draw_region.y, draw_region.width, draw_region.height = rectangle
if self._last_lens_rect:
- last_region = gtk.gdk.region_rectangle(self._last_lens_rect)
- full_region.union(last_region)
+ last_region = Gdk.Rectangle()
+ last_region.x, last_region.y, last_region.width, last_region.height = self._last_lens_rect
+ draw_region = Gdk.rectangle_union(draw_region, last_region)
+
+ window = self._window._main_layout.get_bin_window()
+ window.begin_paint_rect(draw_region)
+
+ self._clear_lens()
+
+ cr = window.cairo_create()
+ surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, window)
+ cr.set_source_surface(surface, rectangle[0], rectangle[1])
+ cr.paint()
- window = self._area.get_bin_window()
- window.begin_paint_region(full_region)
- self._clear_lens(lens_region)
- window.draw_pixbuf(None, pixbuf, 0, 0, *rectangle)
window.end_paint()
self._last_lens_rect = rectangle
@@ -98,17 +104,17 @@ class MagnifyingLens(object):
return lens_x, lens_y, width + 2, height + 2
def _clear_lens(self, current_lens_region=None):
- """ Invalidates the area that was damaged by the last call to draw_lens.
- If <current_lens_region> is not None, this region will not be invalidated. """
+ """ Invalidates the area that was damaged by the last call to draw_lens. """
if not self._last_lens_rect:
return
- last_region = gtk.gdk.region_rectangle(self._last_lens_rect)
- if current_lens_region:
- last_region.subtract(current_lens_region)
-
- self._area.get_bin_window().invalidate_region(last_region, True)
+ window = self._window._main_layout.get_bin_window()
+ crect = Gdk.Rectangle()
+ crect.x, crect.y, crect.width, crect.height = self._last_lens_rect
+ window.invalidate_rect(crect, True)
+ window.process_updates(True)
+ self._last_lens_rect = None
def toggle(self, action):
"""Toggle on or off the lens depending on the state of <action>."""
@@ -124,8 +130,10 @@ class MagnifyingLens(object):
"""Get a pixbuf containing the appropiate image data for the lens
where <x> and <y> are the positions of the cursor.
"""
- canvas = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- prefs['lens size'], prefs['lens size'])
+ canvas = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=True, bits_per_sample=8,
+ width=prefs['lens size'],
+ height=prefs['lens size'])
canvas.fill(image_tools.convert_rgb16list_to_rgba8int(self._window.get_bg_colour()))
cb = self._window.layout.get_content_boxes()
source_pixbufs = self._window.imagehandler.get_pixbufs(len(cb))
@@ -207,7 +215,7 @@ class MagnifyingLens(object):
if width < 1 or height < 1:
return
- subpixbuf = source_pixbuf.subpixbuf(int(src_x), int(src_y),
+ subpixbuf = source_pixbuf.new_subpixbuf(int(src_x), int(src_y),
int(width), int(height))
subpixbuf = subpixbuf.scale_simple(
int(math.ceil(source_mag * subpixbuf.get_width())),
@@ -216,13 +224,13 @@ class MagnifyingLens(object):
if rotation == 90:
subpixbuf = subpixbuf.rotate_simple(
- gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
+ Gdk.PIXBUF_ROTATE_CLOCKWISE)
elif rotation == 180:
subpixbuf = subpixbuf.rotate_simple(
- gtk.gdk.PIXBUF_ROTATE_UPSIDEDOWN)
+ Gdk.PIXBUF_ROTATE_UPSIDEDOWN)
elif rotation == 270:
subpixbuf = subpixbuf.rotate_simple(
- gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
+ Gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
if prefs['horizontal flip']:
subpixbuf = subpixbuf.flip(horizontal=True)
if prefs['vertical flip']:
@@ -241,7 +249,7 @@ class MagnifyingLens(object):
if subpixbuf.get_has_alpha() and prefs['checkered bg for transparent images']:
subpixbuf = subpixbuf.composite_color_simple(subpixbuf.get_width(), subpixbuf.get_height(),
- gtk.gdk.INTERP_NEAREST, 255, 8, 0x777777, 0x999999)
+ GdkPixbuf.InterpType.NEAREST, 255, 8, 0x777777, 0x999999)
subpixbuf.copy_area(0, 0, subpixbuf.get_width(),
subpixbuf.get_height(), canvas, dest_x, dest_y)
diff --git a/mcomix/library/add_progress_dialog.py b/mcomix/library/add_progress_dialog.py
index 7d77708..243b2f1 100644
--- a/mcomix/library/add_progress_dialog.py
+++ b/mcomix/library/add_progress_dialog.py
@@ -1,7 +1,7 @@
"""library_add_progress_dialog.py - Progress bar for the library."""
-import gtk
-import pango
+from gi.repository import Gtk
+from gi.repository import Pango
from mcomix import labels
@@ -10,7 +10,7 @@ _dialog = None
# but is represented by this ID in the library's TreeModels.
_COLLECTION_ALL = -1
-class _AddLibraryProgressDialog(gtk.Dialog):
+class _AddLibraryProgressDialog(Gtk.Dialog):
"""Dialog with a ProgressBar that adds books to the library."""
@@ -19,7 +19,7 @@ class _AddLibraryProgressDialog(gtk.Dialog):
<collection>, unless it is None.
"""
super(_AddLibraryProgressDialog, self).__init__(_('Adding books'), library,
- gtk.DIALOG_MODAL, (gtk.STOCK_STOP, gtk.RESPONSE_CLOSE))
+ Gtk.DialogFlags.MODAL, (Gtk.STOCK_STOP, Gtk.ResponseType.CLOSE))
self._window = window
self._destroy = False
@@ -27,32 +27,34 @@ class _AddLibraryProgressDialog(gtk.Dialog):
self.set_resizable(False)
self.set_border_width(4)
self.connect('response', self._response)
- self.set_default_response(gtk.RESPONSE_CLOSE)
+ self.set_default_response(Gtk.ResponseType.CLOSE)
- main_box = gtk.VBox(False, 5)
+ main_box = Gtk.VBox(False, 5)
main_box.set_border_width(6)
- self.vbox.pack_start(main_box, False, False)
- hbox = gtk.HBox(False, 10)
+ self.vbox.pack_start(main_box, False, False, 0)
+ hbox = Gtk.HBox(False, 10)
main_box.pack_start(hbox, False, False, 5)
- left_box = gtk.VBox(True, 5)
- right_box = gtk.VBox(True, 5)
- hbox.pack_start(left_box, False, False)
- hbox.pack_start(right_box, False, False)
+ left_box = Gtk.VBox(True, 5)
+ right_box = Gtk.VBox(True, 5)
+ hbox.pack_start(left_box, False, False, 0)
+ hbox.pack_start(right_box, False, False, 0)
label = labels.BoldLabel(_('Added books:'))
label.set_alignment(1.0, 1.0)
- left_box.pack_start(label, True, True)
- number_label = gtk.Label('0')
+ left_box.pack_start(label, True, True, 0)
+ number_label = Gtk.Label(label='0')
number_label.set_alignment(0, 1.0)
- right_box.pack_start(number_label, True, True)
+ right_box.pack_start(number_label, True, True, 0)
- bar = gtk.ProgressBar()
- main_box.pack_start(bar, False, False)
+ bar = Gtk.ProgressBar()
+ main_box.pack_start(bar, False, False, 0)
added_label = labels.ItalicLabel()
added_label.set_alignment(0, 0.5)
- added_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
- main_box.pack_start(added_label, False, False)
+ added_label.set_width_chars(64)
+ added_label.set_max_width_chars(64)
+ added_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
+ main_box.pack_start(added_label, False, False, 0)
self.show_all()
total_paths_int = len(paths)
@@ -69,8 +71,8 @@ class _AddLibraryProgressDialog(gtk.Dialog):
added_label.set_text(_("Adding '%s'...") % path)
bar.set_fraction(total_added / total_paths_float)
- while gtk.events_pending():
- gtk.main_iteration_do(False)
+ while Gtk.events_pending():
+ Gtk.main_iteration_do(False)
if self._destroy:
return
diff --git a/mcomix/library/book_area.py b/mcomix/library/book_area.py
index ea6d46d..7b7cd91 100644
--- a/mcomix/library/book_area.py
+++ b/mcomix/library/book_area.py
@@ -2,8 +2,7 @@
import os
import urllib
-import gtk
-import gobject
+from gi.repository import Gdk, GdkPixbuf, Gtk, GObject
import PIL.Image as Image
import PIL.ImageDraw as ImageDraw
@@ -27,7 +26,7 @@ _dialog = None
_COLLECTION_ALL = -1
-class _BookArea(gtk.ScrolledWindow):
+class _BookArea(Gtk.ScrolledWindow):
"""The _BookArea is the central area in the library where the book
covers are displayed.
@@ -44,16 +43,16 @@ class _BookArea(gtk.ScrolledWindow):
self._library.backend.book_added_to_collection += self._new_book_added
- self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
# Store Cover, book ID, book path, book size, date added to library,
# is thumbnail loaded?
# The SORT_ constants must correspond to the correct column here,
# i.e. SORT_SIZE must be 3, since 3 is the size column in the ListStore.
- self._liststore = gtk.ListStore(gtk.gdk.Pixbuf,
- gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_INT64,
- gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
+ self._liststore = Gtk.ListStore(GdkPixbuf.Pixbuf,
+ GObject.TYPE_INT, GObject.TYPE_STRING, GObject.TYPE_INT64,
+ GObject.TYPE_STRING, GObject.TYPE_BOOLEAN)
self._liststore.set_sort_func(constants.SORT_NAME, self._sort_by_name, None)
self._liststore.set_sort_func(constants.SORT_PATH, self._sort_by_path, None)
self.set_sort_order()
@@ -73,21 +72,25 @@ class _BookArea(gtk.ScrolledWindow):
self._iconview.connect('button_press_event', self._button_press)
self._iconview.connect('key_press_event', self._key_press)
self._iconview.connect('popup_menu', self._popup_menu)
- self._iconview.modify_base(gtk.STATE_NORMAL, gtk.gdk.Color()) # Black.
- self._iconview.enable_model_drag_source(0,
- [('book', gtk.TARGET_SAME_APP, constants.LIBRARY_DRAG_EXTERNAL_ID)],
- gtk.gdk.ACTION_MOVE)
- self._iconview.drag_dest_set(gtk.DEST_DEFAULT_ALL,
- [('text/uri-list', 0, constants.LIBRARY_DRAG_EXTERNAL_ID)],
- gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
- self._iconview.set_selection_mode(gtk.SELECTION_MULTIPLE)
+ self._iconview.modify_base(Gtk.StateType.NORMAL, image_tools.GTK_GDK_COLOR_BLACK)
+ self._iconview.enable_model_drag_source(
+ Gdk.ModifierType.BUTTON1_MASK,
+ [Gtk.TargetEntry.new('book', Gtk.TargetFlags.SAME_APP,
+ constants.LIBRARY_DRAG_EXTERNAL_ID)],
+ Gdk.DragAction.MOVE)
+ self._iconview.drag_dest_set(
+ Gtk.DestDefaults.ALL,
+ [Gtk.TargetEntry.new('text/uri-list', 0,
+ constants.LIBRARY_DRAG_EXTERNAL_ID)],
+ Gdk.DragAction.COPY | Gdk.DragAction.MOVE)
+ self._iconview.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
self.add(self._iconview)
self._iconview.set_margin(0)
self._iconview.set_row_spacing(0)
self._iconview.set_column_spacing(0)
- self._ui_manager = gtk.UIManager()
+ self._ui_manager = Gtk.UIManager()
self._tooltipstatus = status.TooltipStatusHelper(self._ui_manager,
self._library.get_status_bar())
@@ -130,34 +133,34 @@ class _BookArea(gtk.ScrolledWindow):
"""
self._ui_manager.add_ui_from_string(ui_description)
- actiongroup = gtk.ActionGroup('mcomix-library-book-area')
+ actiongroup = Gtk.ActionGroup('mcomix-library-book-area')
# General book actions
actiongroup.add_actions([
('_title', None, _('Library books'), None, None,
None),
- ('open', gtk.STOCK_OPEN, _('_Open'), None,
+ ('open', Gtk.STOCK_OPEN, _('_Open'), None,
_('Opens the selected books for viewing.'),
self.open_selected_book),
- ('open keep library', gtk.STOCK_OPEN,
+ ('open keep library', Gtk.STOCK_OPEN,
_('Open _without closing library'), None,
_('Opens the selected books, but keeps the library window open.'),
self.open_selected_book_noclose),
- ('add', gtk.STOCK_ADD, _('_Add...'), '<Ctrl><Shift>a',
+ ('add', Gtk.STOCK_ADD, _('_Add...'), '<Ctrl><Shift>a',
_('Add more books to the library.'),
lambda *args: file_chooser_library_dialog.open_library_filechooser_dialog(self._library)),
- ('remove from collection', gtk.STOCK_REMOVE,
+ ('remove from collection', Gtk.STOCK_REMOVE,
_('Remove from this _collection'), None,
_('Removes the selected books from the current collection.'),
self._remove_books_from_collection),
- ('remove from library', gtk.STOCK_REMOVE,
+ ('remove from library', Gtk.STOCK_REMOVE,
_('Remove from the _library'), None,
_('Completely removes the selected books from the library.'),
self._remove_books_from_library),
- ('completely remove', gtk.STOCK_DELETE,
+ ('completely remove', Gtk.STOCK_DELETE,
_('_Remove and delete from disk'), None,
_('Deletes the selected books from disk.'),
self._completely_remove_book),
- ('copy to clipboard', gtk.STOCK_COPY,
+ ('copy to clipboard', Gtk.STOCK_COPY,
_('_Copy'), None,
_('Copies the selected book\'s path to clipboard.'),
self._copy_selected),
@@ -174,9 +177,9 @@ class _BookArea(gtk.ScrolledWindow):
('by date added', None, _('Date added'), None, None, constants.SORT_LAST_MODIFIED)],
prefs['lib sort key'], self._sort_changed)
actiongroup.add_radio_actions([
- ('ascending', gtk.STOCK_SORT_ASCENDING, _('Ascending'), None, None,
+ ('ascending', Gtk.STOCK_SORT_ASCENDING, _('Ascending'), None, None,
constants.SORT_ASCENDING),
- ('descending', gtk.STOCK_SORT_DESCENDING, _('Descending'), None, None,
+ ('descending', Gtk.STOCK_SORT_DESCENDING, _('Descending'), None, None,
constants.SORT_DESCENDING)],
prefs['lib sort order'], self._sort_changed)
@@ -318,9 +321,9 @@ class _BookArea(gtk.ScrolledWindow):
Should be one of the C{SORT_} constants from L{constants}.
"""
if prefs['lib sort order'] == constants.SORT_ASCENDING:
- sortorder = gtk.SORT_ASCENDING
+ sortorder = Gtk.SortType.ASCENDING
else:
- sortorder = gtk.SORT_DESCENDING
+ sortorder = Gtk.SortType.DESCENDING
self._liststore.set_sort_column_id(prefs['lib sort key'], sortorder)
@@ -389,36 +392,36 @@ class _BookArea(gtk.ScrolledWindow):
elif name == 'tiny':
prefs['library cover size'] = constants.SIZE_TINY
elif name == 'custom':
- dialog = message_dialog.MessageDialog(self._library, gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK)
+ dialog = message_dialog.MessageDialog(self._library, Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK)
dialog.set_auto_destroy(False)
dialog.set_text(_('Set library cover size'))
# Add adjustment scale
- adjustment = gtk.Adjustment(prefs['library cover size'], 20,
+ adjustment = Gtk.Adjustment(prefs['library cover size'], 20,
constants.MAX_LIBRARY_COVER_SIZE, 10, 25, 0)
- cover_size_scale = gtk.HScale(adjustment)
+ cover_size_scale = Gtk.HScale(adjustment)
cover_size_scale.set_size_request(200, -1)
cover_size_scale.set_digits(0)
cover_size_scale.set_draw_value(True)
- cover_size_scale.set_value_pos(gtk.POS_LEFT)
+ cover_size_scale.set_value_pos(Gtk.PositionType.LEFT)
for mark in (constants.SIZE_HUGE, constants.SIZE_LARGE,
constants.SIZE_NORMAL, constants.SIZE_SMALL,
constants.SIZE_TINY):
- cover_size_scale.add_mark(mark, gtk.POS_TOP, None)
+ cover_size_scale.add_mark(mark, Gtk.PositionType.TOP, None)
- dialog.get_message_area().pack_end(cover_size_scale)
+ dialog.get_message_area().pack_end(cover_size_scale, True, True, 0)
response = dialog.run()
size = int(adjustment.get_value())
dialog.destroy()
- if response == gtk.RESPONSE_OK:
+ if response == Gtk.ResponseType.OK:
prefs['library cover size'] = size
if prefs['library cover size'] != old_size:
self._cache.invalidate_all()
collection = self._library.collection_area.get_current_collection()
- gobject.idle_add(self.display_covers, collection)
+ GObject.idle_add(self.display_covers, collection)
def _pixbuf_size(self, border_size=_BORDER_SIZE):
# Don't forget the extra pixels for the border!
@@ -451,23 +454,23 @@ class _BookArea(gtk.ScrolledWindow):
return pixbuf
# Composite icon on the lower right corner of the book cover pixbuf.
- book_pixbuf = self.render_icon(gtk.STOCK_APPLY, gtk.ICON_SIZE_LARGE_TOOLBAR)
+ book_pixbuf = self.render_icon(Gtk.STOCK_APPLY, Gtk.IconSize.LARGE_TOOLBAR)
translation_x = pixbuf.get_width() - book_pixbuf.get_width() - 1
translation_y = pixbuf.get_height() - book_pixbuf.get_height() - 1
book_pixbuf.composite(pixbuf, translation_x, translation_y,
book_pixbuf.get_width(), book_pixbuf.get_height(),
translation_x, translation_y,
- 1.0, 1.0, gtk.gdk.INTERP_NEAREST, 0xFF)
+ 1.0, 1.0, GdkPixbuf.InterpType.NEAREST, 0xFF)
return pixbuf
def _get_empty_thumbnail(self):
""" Create an empty filler pixmap. """
width, height = self._pixbuf_size()
- pixbuf = gtk.gdk.Pixbuf(colorspace=gtk.gdk.COLORSPACE_RGB,
- has_alpha=True,
- bits_per_sample=8,
- width=width, height=height)
+ pixbuf = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=True,
+ bits_per_sample=8,
+ width=width, height=height)
# Make the pixbuf transparent.
pixbuf.fill(0)
@@ -545,10 +548,10 @@ class _BookArea(gtk.ScrolledWindow):
if request_response:
choice_dialog = message_dialog.MessageDialog(self._library, 0,
- gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO)
- choice_dialog.set_default_response(gtk.RESPONSE_YES)
+ Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO)
+ choice_dialog.set_default_response(Gtk.ResponseType.YES)
choice_dialog.set_should_remember_choice('library-remove-book-from-disk',
- (gtk.RESPONSE_YES,))
+ (Gtk.ResponseType.YES,))
choice_dialog.set_text(
_('Remove books from the library?'),
_('The selected books will be removed from the library and '
@@ -557,7 +560,7 @@ class _BookArea(gtk.ScrolledWindow):
response = choice_dialog.run()
# if no request is needed or the user has told us they definitely want to delete the book
- if not request_response or (request_response and response == gtk.RESPONSE_YES):
+ if not request_response or (request_response and response == Gtk.ResponseType.YES):
# get the array of currently selected books in the book window
selected_books = self._iconview.get_selected_items()
@@ -616,7 +619,7 @@ class _BookArea(gtk.ScrolledWindow):
self._set_sensitive('copy to clipboard', len(selected) == 1)
menu = self._ui_manager.get_widget('/library books')
- menu.popup(None, None, None, 3, gtk.get_current_event_time())
+ menu.popup(None, None, None, None, 3, Gtk.get_current_event_time())
def _set_sensitive(self, action, sensitive):
""" Enables the popup menu action <action> based on <sensitive>. """
@@ -626,7 +629,7 @@ class _BookArea(gtk.ScrolledWindow):
def _key_press(self, iconview, event):
"""Handle key presses on the _BookArea."""
- if event.keyval == gtk.keysyms.Delete:
+ if event.keyval == Gdk.KEY_Delete:
self._remove_books_from_collection()
def _popup_menu(self, iconview):
@@ -646,7 +649,7 @@ class _BookArea(gtk.ScrolledWindow):
automatically created when using enable_model_drag_source(), so in
essence it's a hack, but at least it works.
"""
- icon_path = iconview.get_cursor()[0]
+ icon_path = iconview.get_cursor()[1]
num_books = len(iconview.get_selected_items())
book = self.get_book_at_path(icon_path)
@@ -662,8 +665,10 @@ class _BookArea(gtk.ScrolledWindow):
if num_books > 1:
cover_width = cover.get_width()
cover_height = cover.get_height()
- pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- max(30, cover_width + 15), max(30, cover_height + 10))
+ pointer = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=True, bits_per_sample=8,
+ width=max(30, cover_width + 15),
+ height=max(30, cover_height + 10))
pointer.fill(0x00000000)
cover.composite(pointer, 0, 0, cover_width, cover_height, 0, 0,
1, 1, prefs['scaling quality'], 255)
@@ -685,7 +690,7 @@ class _BookArea(gtk.ScrolledWindow):
else:
pointer = cover
- context.set_icon_pixbuf(pointer, -5, -5)
+ Gtk.drag_set_icon_pixbuf(context, pointer, -5, -5)
def _drag_data_get(self, iconview, context, selection, *args):
"""Fill the SelectionData with (iconview) paths for the dragged books
diff --git a/mcomix/library/collection_area.py b/mcomix/library/collection_area.py
index 8036e14..89f75d3 100644
--- a/mcomix/library/collection_area.py
+++ b/mcomix/library/collection_area.py
@@ -1,8 +1,7 @@
"""library_collection_area.py - Comic book library window that displays the collections."""
from xml.sax.saxutils import escape as xmlescape
-import gtk
-import gobject
+from gi.repository import Gdk, GdkPixbuf, Gtk, GObject
from mcomix.preferences import prefs
from mcomix import constants
@@ -17,7 +16,7 @@ _dialog = None
_COLLECTION_ALL = -1
_COLLECTION_RECENT = -2
-class _CollectionArea(gtk.ScrolledWindow):
+class _CollectionArea(Gtk.ScrolledWindow):
"""The _CollectionArea is the sidebar area in the library where
different collections are displayed in a tree.
@@ -26,10 +25,10 @@ class _CollectionArea(gtk.ScrolledWindow):
def __init__(self, library):
super(_CollectionArea, self).__init__()
self._library = library
- self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
- self._treestore = gtk.TreeStore(str, int) # (Name, ID) of collections.
- self._treeview = gtk.TreeView(self._treestore)
+ self._treestore = Gtk.TreeStore(str, int) # (Name, ID) of collections.
+ self._treeview = Gtk.TreeView(self._treestore)
self._treeview.connect('cursor_changed', self._collection_selected)
self._treeview.connect('drag_data_received', self._drag_data_received)
self._treeview.connect('drag_motion', self._drag_motion)
@@ -41,16 +40,16 @@ class _CollectionArea(gtk.ScrolledWindow):
self._treeview.set_headers_visible(False)
self._treeview.set_rules_hint(True)
self._set_acceptable_drop(True)
- self._treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
- [('collection', gtk.TARGET_SAME_WIDGET, constants.LIBRARY_DRAG_COLLECTION_ID)],
- gtk.gdk.ACTION_MOVE)
+ self._treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
+ [('collection', Gtk.TargetFlags.SAME_WIDGET, constants.LIBRARY_DRAG_COLLECTION_ID)],
+ Gdk.DragAction.MOVE)
- cellrenderer = gtk.CellRendererText()
- column = gtk.TreeViewColumn(None, cellrenderer, markup=0)
+ cellrenderer = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn(None, cellrenderer, markup=0)
self._treeview.append_column(column)
self.add(self._treeview)
- self._ui_manager = gtk.UIManager()
+ self._ui_manager = Gtk.UIManager()
self._tooltipstatus = status.TooltipStatusHelper(self._ui_manager,
self._library.get_status_bar())
ui_description = """
@@ -70,26 +69,26 @@ class _CollectionArea(gtk.ScrolledWindow):
</ui>
"""
self._ui_manager.add_ui_from_string(ui_description)
- actiongroup = gtk.ActionGroup('mcomix-library-collection-area')
+ actiongroup = Gtk.ActionGroup('mcomix-library-collection-area')
actiongroup.add_actions([
('_title', None, _("Library collections"), None, None,
lambda *args: False),
- ('add', gtk.STOCK_ADD, _('_Add...'), None,
+ ('add', Gtk.STOCK_ADD, _('_Add...'), None,
_('Add more books to the library.'),
lambda *args: file_chooser_library_dialog.open_library_filechooser_dialog(self._library)),
- ('new', gtk.STOCK_NEW, _('New'), None,
+ ('new', Gtk.STOCK_NEW, _('New'), None,
_('Add a new empty collection.'),
self.add_collection),
- ('rename', gtk.STOCK_EDIT, _('Re_name'), None,
+ ('rename', Gtk.STOCK_EDIT, _('Re_name'), None,
_('Renames the selected collection.'),
self._rename_collection),
- ('duplicate', gtk.STOCK_COPY, _('_Duplicate'), None,
+ ('duplicate', Gtk.STOCK_COPY, _('_Duplicate'), None,
_('Creates a duplicate of the selected collection.'),
self._duplicate_collection),
- ('cleanup', gtk.STOCK_CLEAR, _('_Clean up'), None,
+ ('cleanup', Gtk.STOCK_CLEAR, _('_Clean up'), None,
_('Removes no longer existant books from the collection.'),
self._clean_collection),
- ('remove', gtk.STOCK_REMOVE, _('_Remove'), None,
+ ('remove', Gtk.STOCK_REMOVE, _('_Remove'), None,
_('Deletes the selected collection.'),
self._remove_collection)])
self._ui_manager.insert_action_group(actiongroup, 0)
@@ -146,18 +145,18 @@ class _CollectionArea(gtk.ScrolledWindow):
def add_collection(self, *args):
"""Add a new collection to the library, through a dialog."""
- add_dialog = message_dialog.MessageDialog(self._library, 0, gtk.MESSAGE_INFO,
- gtk.BUTTONS_OK_CANCEL)
+ add_dialog = message_dialog.MessageDialog(self._library, 0, Gtk.MessageType.INFO,
+ Gtk.ButtonsType.OK_CANCEL)
add_dialog.set_auto_destroy(False)
- add_dialog.set_default_response(gtk.RESPONSE_OK)
+ add_dialog.set_default_response(Gtk.ResponseType.OK)
add_dialog.set_text(
_('Add new collection?'),
_('Please enter a name for the new collection.')
)
- box = gtk.HBox() # To get nice line-ups with the padding.
- add_dialog.vbox.pack_start(box)
- entry = gtk.Entry()
+ box = Gtk.HBox() # To get nice line-ups with the padding.
+ add_dialog.vbox.pack_start(box, True, True, 0)
+ entry = Gtk.Entry()
entry.set_activates_default(True)
box.pack_start(entry, True, True, 6)
box.show_all()
@@ -165,7 +164,7 @@ class _CollectionArea(gtk.ScrolledWindow):
response = add_dialog.run()
name = entry.get_text().decode('utf-8')
add_dialog.destroy()
- if response == gtk.RESPONSE_OK and name:
+ if response == Gtk.ResponseType.OK and name:
if self._library.backend.add_collection(name):
collection = self._library.backend.get_collection_by_name(name)
prefs['last library collection'] = collection.id
@@ -194,7 +193,7 @@ class _CollectionArea(gtk.ScrolledWindow):
if removed > 0:
collection = self._library.collection_area.get_current_collection()
- gobject.idle_add(self._library.book_area.display_covers, collection)
+ GObject.idle_add(self._library.book_area.display_covers, collection)
def _get_collection_at_path(self, path):
"""Return the collection ID of the collection at the (TreeView)
@@ -212,7 +211,7 @@ class _CollectionArea(gtk.ScrolledWindow):
collection == prefs['last library collection']):
return
prefs['last library collection'] = collection
- gobject.idle_add(self._library.book_area.display_covers, collection)
+ GObject.idle_add(self._library.book_area.display_covers, collection)
def _clean_collection(self, *args):
""" Menu item hook to clean a collection. """
@@ -242,17 +241,17 @@ class _CollectionArea(gtk.ScrolledWindow):
except Exception:
return
rename_dialog = message_dialog.MessageDialog(self._library, 0,
- gtk.MESSAGE_INFO, gtk.BUTTONS_OK_CANCEL)
+ Gtk.MessageType.INFO, Gtk.ButtonsType.OK_CANCEL)
rename_dialog.set_auto_destroy(False)
rename_dialog.set_text(
_('Rename collection?'),
_('Please enter a new name for the selected collection.')
)
- rename_dialog.set_default_response(gtk.RESPONSE_OK)
+ rename_dialog.set_default_response(Gtk.ResponseType.OK)
- box = gtk.HBox() # To get nice line-ups with the padding.
- rename_dialog.vbox.pack_start(box)
- entry = gtk.Entry()
+ box = Gtk.HBox() # To get nice line-ups with the padding.
+ rename_dialog.vbox.pack_start(box, True, True, 0)
+ entry = Gtk.Entry()
entry.set_text(old_name)
entry.set_activates_default(True)
box.pack_start(entry, True, True, 6)
@@ -261,7 +260,7 @@ class _CollectionArea(gtk.ScrolledWindow):
response = rename_dialog.run()
new_name = entry.get_text()
rename_dialog.destroy()
- if response == gtk.RESPONSE_OK and new_name:
+ if response == Gtk.ResponseType.OK and new_name:
if self._library.backend.rename_collection(collection, new_name):
self.display_collections()
else:
@@ -325,11 +324,11 @@ class _CollectionArea(gtk.ScrolledWindow):
self._ui_manager.get_action('/library collections/_title').set_sensitive(False)
menu = self._ui_manager.get_widget('/library collections')
- menu.popup(None, None, None, 3, gtk.get_current_event_time())
+ menu.popup(None, None, None, None, 3, Gtk.get_current_event_time())
def _key_press(self, treeview, event):
"""Handle key presses on the _CollectionArea."""
- if event.keyval == gtk.keysyms.Delete:
+ if event.keyval == Gdk.KEY_Delete:
self._remove_collection()
def _expand_or_collapse_row(self, treeview, path, column):
@@ -348,13 +347,13 @@ class _CollectionArea(gtk.ScrolledWindow):
drop_row = treeview.get_dest_row_at_pos(x, y)
if drop_row is None: # Drop "after" the last row.
dest_path, pos = ((len(self._treestore) - 1,),
- gtk.TREE_VIEW_DROP_AFTER)
+ Gtk.TreeViewDropPosition.AFTER)
else:
dest_path, pos = drop_row
src_collection = self.get_current_collection()
dest_collection = self._get_collection_at_path(dest_path)
if drag_id == constants.LIBRARY_DRAG_COLLECTION_ID:
- if pos in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_AFTER):
+ if pos in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.AFTER):
dest_collection = self._library.backend.get_supercollection(
dest_collection)
self._library.backend.add_collection_to_collection(
@@ -382,10 +381,10 @@ class _CollectionArea(gtk.ScrolledWindow):
drop_row = treeview.get_dest_row_at_pos(x, y)
src_collection = self.get_current_collection()
# Why isn't the drag ID passed along with drag-motion events?
- if context.get_source_widget() is self._treeview: # Moving collection.
+ if Gtk.drag_get_source_widget(context) is self._treeview: # Moving collection.
model, src_iter = treeview.get_selection().get_selected()
if drop_row is None: # Drop "after" the last row.
- dest_path, pos = (len(model) - 1,), gtk.TREE_VIEW_DROP_AFTER
+ dest_path, pos = (len(model) - 1,), Gtk.TreeViewDropPosition.AFTER
else:
dest_path, pos = drop_row
dest_iter = model.get_iter(dest_path)
@@ -394,7 +393,7 @@ class _CollectionArea(gtk.ScrolledWindow):
self._library.set_status_message('')
return
dest_collection = self._get_collection_at_path(dest_path)
- if pos in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_AFTER):
+ if pos in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.AFTER):
dest_collection = self._library.backend.get_supercollection(
dest_collection)
if (_COLLECTION_ALL in (src_collection, dest_collection) or
@@ -418,7 +417,7 @@ class _CollectionArea(gtk.ScrolledWindow):
self._library.set_status_message('')
return
dest_path, pos = drop_row
- if pos in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_AFTER):
+ if pos in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.AFTER):
self._set_acceptable_drop(False)
self._library.set_status_message('')
return
@@ -445,11 +444,11 @@ class _CollectionArea(gtk.ScrolledWindow):
"""Set the TreeView to accept drops if <acceptable> is True."""
if acceptable:
self._treeview.enable_model_drag_dest(
- [('book', gtk.TARGET_SAME_APP, constants.LIBRARY_DRAG_BOOK_ID),
- ('collection', gtk.TARGET_SAME_WIDGET, constants.LIBRARY_DRAG_COLLECTION_ID)],
- gtk.gdk.ACTION_MOVE)
+ [('book', Gtk.TargetFlags.SAME_APP, constants.LIBRARY_DRAG_BOOK_ID),
+ ('collection', Gtk.TargetFlags.SAME_WIDGET, constants.LIBRARY_DRAG_COLLECTION_ID)],
+ Gdk.DragAction.MOVE)
else:
- self._treeview.enable_model_drag_dest([], gtk.gdk.ACTION_MOVE)
+ self._treeview.enable_model_drag_dest([], Gdk.DragAction.MOVE)
def _drag_begin(self, treeview, context):
"""Create a cursor image for drag-n-drop of collections. We use the
@@ -458,13 +457,9 @@ class _CollectionArea(gtk.ScrolledWindow):
which unfortunately isn't the default case.
"""
path = treeview.get_cursor()[0]
- pixmap = treeview.create_row_drag_icon(path)
- # context.set_icon_pixmap() seems to cause crashes, so we do a
- # quick and dirty conversion to pixbuf.
- pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- *pixmap.get_size())
- pointer = pointer.get_from_drawable(pixmap, treeview.get_colormap(),
- 0, 0, 0, 0, *pixmap.get_size())
- context.set_icon_pixbuf(pointer, -5, -5)
+ surface = treeview.create_row_drag_icon(path)
+ width, height = surface.get_width(), surface.get_height()
+ pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, width, height)
+ Gtk.drag_set_icon_pixbuf(context, pixbuf, -5, -5)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/library/control_area.py b/mcomix/library/control_area.py
index 57e64a9..f6cbbe8 100644
--- a/mcomix/library/control_area.py
+++ b/mcomix/library/control_area.py
@@ -2,9 +2,9 @@
and displays info."""
import os
-import gtk
-import gobject
-import pango
+from gi.repository import Gtk
+from gi.repository import GObject
+from gi.repository import Pango
from mcomix import i18n
from mcomix import labels
@@ -15,7 +15,7 @@ from mcomix.library.watchlist import WatchListDialog
_COLLECTION_ALL = -1
-class _ControlArea(gtk.HBox):
+class _ControlArea(Gtk.HBox):
"""The _ControlArea is the bottom area of the library window where
information is displayed and controls such as buttons reside.
@@ -27,49 +27,49 @@ class _ControlArea(gtk.HBox):
self._library = library
self.set_border_width(10)
- borderbox = gtk.Frame()
- borderbox.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ borderbox = Gtk.Frame()
+ borderbox.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
borderbox.set_size_request(350, -1)
- insidebox = gtk.EventBox()
+ insidebox = Gtk.EventBox()
insidebox.set_border_width(1)
- insidebox.set_state(gtk.STATE_ACTIVE)
+ insidebox.set_state(Gtk.StateType.ACTIVE)
- infobox = gtk.VBox(False, 5)
+ infobox = Gtk.VBox(False, 5)
infobox.set_border_width(10)
- self.pack_start(borderbox)
+ self.pack_start(borderbox, True, True, 0)
borderbox.add(insidebox)
insidebox.add(infobox)
self._namelabel = labels.BoldLabel()
self._namelabel.set_alignment(0, 0.5)
self._namelabel.set_selectable(True)
- self._namelabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
- infobox.pack_start(self._namelabel, False, False)
+ self._namelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
+ infobox.pack_start(self._namelabel, False, False, 0)
- self._filelabel = gtk.Label()
- self._filelabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ self._filelabel = Gtk.Label()
+ self._filelabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
self._filelabel.set_alignment(0, 0.5)
- infobox.pack_start(self._filelabel, False, False)
+ infobox.pack_start(self._filelabel, False, False, 0)
- self._dirlabel = gtk.Label()
- self._dirlabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ self._dirlabel = Gtk.Label()
+ self._dirlabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
self._dirlabel.set_alignment(0, 0.5)
self._dirlabel.set_selectable(True)
- infobox.pack_start(self._dirlabel, False, False)
+ infobox.pack_start(self._dirlabel, False, False, 0)
- vbox = gtk.VBox(False, 10)
+ vbox = Gtk.VBox(False, 10)
vbox.set_size_request(350, -1)
- self.pack_start(vbox, False)
+ self.pack_start(vbox, False, False, 0)
# First line of controls, containing the search box
- hbox = gtk.HBox(False)
- vbox.pack_start(hbox)
+ hbox = Gtk.HBox(False)
+ vbox.pack_start(hbox, True, True, 0)
- label = gtk.Label(_('_Search:'))
+ label = Gtk.Label(label=_('_Search:'))
label.set_use_underline(True)
- hbox.pack_start(label, False, False)
- search_entry = gtk.Entry()
+ hbox.pack_start(label, False, False, 0)
+ search_entry = Gtk.Entry()
search_entry.connect('activate', self._filter_books)
search_entry.set_tooltip_text(
_('Display only those books that have the specified text string '
@@ -78,24 +78,28 @@ class _ControlArea(gtk.HBox):
label.set_mnemonic_widget(search_entry)
# Last line of controls, containing buttons like 'Open'
- hbox = gtk.HBox(False, 10)
- vbox.pack_end(hbox)
+ hbox = Gtk.HBox(False, 10)
+ vbox.pack_end(hbox, True, True, 0)
- watchlist_button = gtk.Button(_("_Watch list"))
- watchlist_button.set_image(
- gtk.image_new_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_BUTTON))
+ watchlist_button = Gtk.Button(label=_("_Watch list"), use_underline=True)
+ watchlist_button.set_always_show_image(True)
+ watchlist_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.BUTTON))
+ watchlist_button.set_image_position(Gtk.PositionType.LEFT)
watchlist_button.connect('clicked',
lambda *args: WatchListDialog(self._library))
watchlist_button.set_tooltip_text(
_('Open the watchlist management dialog.'))
- hbox.pack_start(watchlist_button)
+ hbox.pack_start(watchlist_button, True, True, 0)
- self._open_button = gtk.Button(None, gtk.STOCK_OPEN)
+ self._open_button = Gtk.Button(label=_("_Open list"), use_underline=True)
+ self._open_button.set_always_show_image(True)
+ self._open_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.BUTTON))
+ self._open_button.set_image_position(Gtk.PositionType.LEFT)
self._open_button.connect('clicked',
self._library.book_area.open_selected_book)
self._open_button.set_tooltip_text(_('Open the selected book.'))
self._open_button.set_sensitive(False)
- hbox.pack_end(self._open_button)
+ hbox.pack_end(self._open_button, True, True, 0)
def update_info(self, selected):
"""Update the info box using the currently <selected> books from
@@ -155,13 +159,13 @@ class _ControlArea(gtk.HBox):
def _filter_books(self, entry, *args):
"""Display only the books in the current collection whose paths
- contain the string in the gtk.Entry. The string is not
+ contain the string in the Gtk.Entry. The string is not
case-sensitive.
"""
self._library.filter_string = entry.get_text().decode('utf-8')
if not self._library.filter_string:
self._library.filter_string = None
collection = self._library.collection_area.get_current_collection()
- gobject.idle_add(self._library.book_area.display_covers, collection)
+ GObject.idle_add(self._library.book_area.display_covers, collection)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/library/main_dialog.py b/mcomix/library/main_dialog.py
index 5e34c25..816d390 100644
--- a/mcomix/library/main_dialog.py
+++ b/mcomix/library/main_dialog.py
@@ -1,7 +1,7 @@
"""library_main_dialog.py - The library dialog window."""
import os
-import gtk
+from gi.repository import Gdk, Gtk
from mcomix.preferences import prefs
from mcomix import i18n
@@ -20,14 +20,14 @@ _dialog = None
# but is represented by this ID in the library's TreeModels.
_COLLECTION_ALL = -1
-class _LibraryDialog(gtk.Window):
+class _LibraryDialog(Gtk.Window):
"""The library window. Automatically creates and uses a new
library_backend.LibraryBackend when opened.
"""
def __init__(self, window, file_handler):
- super(_LibraryDialog, self).__init__(gtk.WINDOW_TOPLEVEL)
+ super(_LibraryDialog, self).__init__(Gtk.WindowType.TOPLEVEL)
self._window = window
@@ -38,8 +38,7 @@ class _LibraryDialog(gtk.Window):
self.filter_string = None
self._file_handler = file_handler
- self._statusbar = gtk.Statusbar()
- self._statusbar.set_has_resize_grip(True)
+ self._statusbar = Gtk.Statusbar()
self.backend = library_backend.LibraryBackend()
self.book_area = library_book_area._BookArea(self)
self.control_area = library_control_area._ControlArea(self)
@@ -47,16 +46,16 @@ class _LibraryDialog(gtk.Window):
self.backend.watchlist.new_files_found += self._new_files_found
- table = gtk.Table(2, 2, False)
- table.attach(self.collection_area, 0, 1, 0, 1, gtk.FILL,
- gtk.EXPAND|gtk.FILL)
- table.attach(self.book_area, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL,
- gtk.EXPAND|gtk.FILL)
- table.attach(self.control_area, 0, 2, 1, 2, gtk.EXPAND|gtk.FILL,
- gtk.FILL)
+ table = Gtk.Table(2, 2, False)
+ table.attach(self.collection_area, 0, 1, 0, 1, Gtk.AttachOptions.FILL,
+ Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL)
+ table.attach(self.book_area, 1, 2, 0, 1, Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL,
+ Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL)
+ table.attach(self.control_area, 0, 2, 1, 2, Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL,
+ Gtk.AttachOptions.FILL)
if prefs['show statusbar']:
- table.attach(self._statusbar, 0, 2, 2, 3, gtk.FILL, gtk.FILL)
+ table.attach(self._statusbar, 0, 2, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL)
self.add(table)
self.show_all()
@@ -154,7 +153,7 @@ class _LibraryDialog(gtk.Window):
def _key_press_event(self, widget, event, *args):
""" Handle key press events for closing the library on Escape press. """
- if event.keyval == gtk.keysyms.Escape:
+ if event.keyval == Gdk.KEY_Escape:
self.hide()
diff --git a/mcomix/library/watchlist.py b/mcomix/library/watchlist.py
index 9f44094..582ea0c 100644
--- a/mcomix/library/watchlist.py
+++ b/mcomix/library/watchlist.py
@@ -1,8 +1,8 @@
""" Library watch list dialog and backend classes. """
import os
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import GObject
from mcomix.library import backend_types
from mcomix.preferences import prefs
@@ -13,7 +13,7 @@ COL_COLLECTION = 0
COL_COLLECTION_ID = 1
COL_RECURSIVE = 2
-class WatchListDialog(gtk.Dialog):
+class WatchListDialog(Gtk.Dialog):
""" Dialog for managing watched directories. """
RESPONSE_SCANNOW = 1000
@@ -23,68 +23,68 @@ class WatchListDialog(gtk.Dialog):
@param library: Dialog parent window, should be library window.
"""
super(WatchListDialog, self).__init__(_("Library watch list"),
- library, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
+ library, Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
(_('_Scan now').encode('utf-8'), WatchListDialog.RESPONSE_SCANNOW,
- gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
#: Stores a reference to the library
self.library = library
#: True if changes were made to the watchlist. Not 100% accurate.
self._changed = False
- self.set_default_response(gtk.RESPONSE_CLOSE)
+ self.set_default_response(Gtk.ResponseType.CLOSE)
# Initialize treeview control showing existing watch directories
- self._treeview = gtk.TreeView(self._create_model())
+ self._treeview = Gtk.TreeView(self._create_model())
self._treeview.set_headers_visible(True)
self._treeview.get_selection().connect('changed', self._item_selected_cb)
- dir_renderer = gtk.CellRendererText()
- dir_column = gtk.TreeViewColumn(_("Directory"), dir_renderer)
+ dir_renderer = Gtk.CellRendererText()
+ dir_column = Gtk.TreeViewColumn(_("Directory"), dir_renderer)
dir_column.set_attributes(dir_renderer, text=COL_DIRECTORY)
dir_column.set_expand(True)
self._treeview.append_column(dir_column)
collection_model = self._create_collection_model()
- collection_renderer = gtk.CellRendererCombo()
+ collection_renderer = Gtk.CellRendererCombo()
collection_renderer.set_property('model', collection_model)
collection_renderer.set_property('text-column', COL_COLLECTION)
- collection_renderer.set_property('editable', gtk.TRUE)
- collection_renderer.set_property('has-entry', gtk.FALSE)
+ collection_renderer.set_property('editable', True)
+ collection_renderer.set_property('has-entry', False)
collection_renderer.connect('changed', self._collection_changed_cb, collection_model)
- collection_column = gtk.TreeViewColumn(_("Collection"), collection_renderer)
+ collection_column = Gtk.TreeViewColumn(_("Collection"), collection_renderer)
collection_column.set_cell_data_func(collection_renderer,
self._treeview_collection_id_to_name)
self._treeview.append_column(collection_column)
- recursive_renderer = gtk.CellRendererToggle()
+ recursive_renderer = Gtk.CellRendererToggle()
recursive_renderer.set_activatable(True)
recursive_renderer.connect('toggled', self._recursive_changed_cb)
- recursive_column = gtk.TreeViewColumn(_("With subdirectories"),
+ recursive_column = Gtk.TreeViewColumn(_("With subdirectories"),
recursive_renderer)
recursive_column.add_attribute(recursive_renderer, 'active', COL_RECURSIVE)
self._treeview.append_column(recursive_column)
- add_button = gtk.Button(_("_Add"), gtk.STOCK_ADD)
+ add_button = Gtk.Button(_("_Add"), Gtk.STOCK_ADD, use_underline=True)
add_button.connect('clicked', self._add_cb)
- self._remove_button = remove_button = gtk.Button(_("_Remove"), gtk.STOCK_REMOVE)
+ self._remove_button = remove_button = Gtk.Button(_("_Remove"), Gtk.STOCK_REMOVE, use_underline=True)
remove_button.set_sensitive(False)
remove_button.connect('clicked', self._remove_cb)
- button_box = gtk.VBox()
- button_box.pack_start(add_button, expand=False)
- button_box.pack_start(remove_button, expand=False, padding=2)
+ button_box = Gtk.VBox()
+ button_box.pack_start(add_button, False, True, 0)
+ button_box.pack_start(remove_button, False, True, 2)
- main_box = gtk.HBox()
- scroll_window = gtk.ScrolledWindow()
- scroll_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ main_box = Gtk.HBox()
+ scroll_window = Gtk.ScrolledWindow()
+ scroll_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
scroll_window.add(self._treeview)
- main_box.pack_start(scroll_window, padding=2)
- main_box.pack_end(button_box, expand=False)
- self.vbox.pack_start(main_box)
+ main_box.pack_start(scroll_window, True, True, 2)
+ main_box.pack_end(button_box, False, True, 0)
+ self.vbox.pack_start(main_box, True, True, 0)
- auto_checkbox = gtk.CheckButton(
- _('Automatically scan for new books when library is _opened'), True)
+ auto_checkbox = Gtk.CheckButton(
+ _('Automatically scan for new books when library is _opened'), use_underline=True)
auto_checkbox.set_active(prefs['scan for new books on library startup'])
auto_checkbox.connect('toggled', self._auto_scan_toggled_cb)
self.vbox.pack_end(auto_checkbox, False, False, 5)
@@ -115,7 +115,7 @@ class WatchListDialog(gtk.Dialog):
def _create_model(self):
""" Creates a model containing all watched directories. """
# Watched directory, associated library collection ID
- model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_BOOLEAN)
+ model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT, GObject.TYPE_BOOLEAN)
self._fill_model(model)
return model
@@ -133,7 +133,7 @@ class WatchListDialog(gtk.Dialog):
def _create_collection_model(self):
""" Creates a model containing all available collections. """
# Collection ID, collection name
- model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
+ model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
ids = self.library.backend.get_all_collections()
model.append((backend_types.DefaultCollection.name, -1))
@@ -157,7 +157,7 @@ class WatchListDialog(gtk.Dialog):
iter = model.get_iter(path)
# Editing the model in the CellRendererCombo callback stops the editing
# operation, causing GTK warnings. Delay until callback is finished.
- gobject.idle_add(model.set_value, iter, COL_COLLECTION_ID, new_id)
+ GObject.idle_add(model.set_value, iter, COL_COLLECTION_ID, new_id)
self._changed = True
@@ -175,10 +175,10 @@ class WatchListDialog(gtk.Dialog):
def _add_cb(self, button, *args):
""" Called when a new watch list entry should be added. """
- filechooser = gtk.FileChooserDialog(parent=self,
- action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
- gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ filechooser = Gtk.FileChooserDialog(parent=self,
+ action=Gtk.FileChooserAction.SELECT_FOLDER,
+ buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
+ Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT))
result = filechooser.run()
if filechooser.get_filename() is not None:
directory = filechooser.get_filename().decode('utf-8')
@@ -186,7 +186,7 @@ class WatchListDialog(gtk.Dialog):
directory = u""
filechooser.destroy()
- if result == gtk.RESPONSE_ACCEPT \
+ if result == Gtk.ResponseType.ACCEPT \
and os.path.isdir(directory):
self.library.backend.watchlist.add_directory(directory)
@@ -227,7 +227,7 @@ class WatchListDialog(gtk.Dialog):
def _close_cb(self, dialog, response, *args):
""" Trigger scan for new files after watch dialog closes. """
self.destroy()
- if response == gtk.RESPONSE_CLOSE and self._changed:
+ if response == Gtk.ResponseType.CLOSE and self._changed:
self.library.scan_for_new_files()
elif response == WatchListDialog.RESPONSE_SCANNOW:
self.library.scan_for_new_files()
diff --git a/mcomix/main.py b/mcomix/main.py
index 8d0d0bf..2e618fa 100644
--- a/mcomix/main.py
+++ b/mcomix/main.py
@@ -1,10 +1,12 @@
"""main.py - Main window."""
+import math
+import operator
import os
import shutil
import threading
-import gtk
-import gobject
+
+from gi.repository import GObject, Gdk, Gtk
from mcomix import constants
from mcomix import cursor_handler
@@ -34,11 +36,9 @@ from mcomix.library import backend, main_dialog
from mcomix import tools
from mcomix import layout
from mcomix import log
-import math
-import operator
-class MainWindow(gtk.Window):
+class MainWindow(Gtk.Window):
"""The main window, is created at start and terminates the
program when closed.
@@ -47,7 +47,7 @@ class MainWindow(gtk.Window):
def __init__(self, fullscreen=False, is_slideshow=slideshow,
show_library=False, manga_mode=False, double_page=False,
zoom_mode=None, open_path=None, open_page=1):
- super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL)
+ super(MainWindow, self).__init__(Gtk.WindowType.TOPLEVEL)
# ----------------------------------------------------------------
# Attributes
@@ -66,13 +66,19 @@ class MainWindow(gtk.Window):
self._spacing = 2
self._waiting_for_redraw = False
- self._image_box = gtk.HBox(False, 2) # XXX transitional(kept for osd.py)
- self._main_layout = gtk.Layout()
+ self._image_box = Gtk.HBox(False, 2) # XXX transitional(kept for osd.py)
+ self._main_layout = Gtk.Layout()
+ # Wrap main layout into an event box so
+ # we can change its background color.
+ self._event_box = Gtk.EventBox()
+ self._event_box.add(self._main_layout)
self._event_handler = event.EventHandler(self)
self._vadjust = self._main_layout.get_vadjustment()
self._hadjust = self._main_layout.get_hadjustment()
- self._scroll = (gtk.HScrollbar(self._hadjust),
- gtk.VScrollbar(self._vadjust))
+ self._scroll = (
+ Gtk.Scrollbar.new(Gtk.Orientation.HORIZONTAL, self._hadjust),
+ Gtk.Scrollbar.new(Gtk.Orientation.VERTICAL, self._vadjust),
+ )
self.filehandler = file_handler.FileHandler(self)
self.filehandler.file_closed += self._on_file_closed
@@ -95,7 +101,7 @@ class MainWindow(gtk.Window):
self.popup = self.uimanager.get_widget('/Popup')
self.actiongroup = self.uimanager.get_action_groups()[0]
- self.images = [gtk.Image(), gtk.Image()] # XXX limited to at most 2 pages
+ self.images = [Gtk.Image(), Gtk.Image()] # XXX limited to at most 2 pages
# ----------------------------------------------------------------
# Setup
@@ -111,8 +117,8 @@ class MainWindow(gtk.Window):
# we don't activate it with space or some other key (alternative?)
self.toolbar.set_focus_child(
self.uimanager.get_widget('/Tool/expander'))
- self.toolbar.set_style(gtk.TOOLBAR_ICONS)
- self.toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR)
+ self.toolbar.set_style(Gtk.ToolbarStyle.ICONS)
+ self.toolbar.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR)
for img in self.images:
self._main_layout.put(img, 0, 0)
@@ -123,22 +129,22 @@ class MainWindow(gtk.Window):
self._hadjust.step_increment = 15
self._hadjust.page_increment = 1
- table = gtk.Table(2, 2, False)
- table.attach(self.thumbnailsidebar, 0, 1, 2, 5, gtk.FILL,
- gtk.FILL|gtk.EXPAND, 0, 0)
-
- table.attach(self._main_layout, 1, 2, 2, 3, gtk.FILL|gtk.EXPAND,
- gtk.FILL|gtk.EXPAND, 0, 0)
- table.attach(self._scroll[constants.HEIGHT_AXIS], 2, 3, 2, 3, gtk.FILL|gtk.SHRINK,
- gtk.FILL|gtk.SHRINK, 0, 0)
- table.attach(self._scroll[constants.WIDTH_AXIS], 1, 2, 4, 5, gtk.FILL|gtk.SHRINK,
- gtk.FILL, 0, 0)
- table.attach(self.menubar, 0, 3, 0, 1, gtk.FILL|gtk.SHRINK,
- gtk.FILL, 0, 0)
- table.attach(self.toolbar, 0, 3, 1, 2, gtk.FILL|gtk.SHRINK,
- gtk.FILL, 0, 0)
- table.attach(self.statusbar, 0, 3, 5, 6, gtk.FILL|gtk.SHRINK,
- gtk.FILL, 0, 0)
+ table = Gtk.Table(2, 2, False)
+ table.attach(self.thumbnailsidebar, 0, 1, 2, 5, Gtk.AttachOptions.FILL,
+ Gtk.AttachOptions.FILL|Gtk.AttachOptions.EXPAND, 0, 0)
+
+ table.attach(self._event_box, 1, 2, 2, 3, Gtk.AttachOptions.FILL|Gtk.AttachOptions.EXPAND,
+ Gtk.AttachOptions.FILL|Gtk.AttachOptions.EXPAND, 0, 0)
+ table.attach(self._scroll[constants.HEIGHT_AXIS], 2, 3, 2, 3, Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK,
+ Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK, 0, 0)
+ table.attach(self._scroll[constants.WIDTH_AXIS], 1, 2, 4, 5, Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK,
+ Gtk.AttachOptions.FILL, 0, 0)
+ table.attach(self.menubar, 0, 3, 0, 1, Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK,
+ Gtk.AttachOptions.FILL, 0, 0)
+ table.attach(self.toolbar, 0, 3, 1, 2, Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK,
+ Gtk.AttachOptions.FILL, 0, 0)
+ table.attach(self.statusbar, 0, 3, 5, 6, Gtk.AttachOptions.FILL|Gtk.AttachOptions.SHRINK,
+ Gtk.AttachOptions.FILL, 0, 0)
if prefs['default double page'] or double_page:
self.actiongroup.get_action('double_page').activate()
@@ -220,18 +226,18 @@ class MainWindow(gtk.Window):
self.add(table)
table.show()
- self._main_layout.show()
+ self._event_box.show_all()
- self._main_layout.set_events(gtk.gdk.BUTTON1_MOTION_MASK |
- gtk.gdk.BUTTON2_MOTION_MASK |
- gtk.gdk.BUTTON_PRESS_MASK |
- gtk.gdk.BUTTON_RELEASE_MASK |
- gtk.gdk.POINTER_MOTION_MASK)
+ self._main_layout.set_events(Gdk.EventMask.BUTTON1_MOTION_MASK |
+ Gdk.EventMask.BUTTON2_MOTION_MASK |
+ Gdk.EventMask.BUTTON_PRESS_MASK |
+ Gdk.EventMask.BUTTON_RELEASE_MASK |
+ Gdk.EventMask.POINTER_MOTION_MASK)
- self._main_layout.drag_dest_set(gtk.DEST_DEFAULT_ALL,
- [('text/uri-list', 0, 0)],
- gtk.gdk.ACTION_COPY |
- gtk.gdk.ACTION_MOVE)
+ self._main_layout.drag_dest_set(Gtk.DestDefaults.ALL,
+ [Gtk.TargetEntry.new('text/uri-list', 0, 0)],
+ Gdk.DragAction.COPY |
+ Gdk.DragAction.MOVE)
self.connect('focus-in-event', self.gained_focus)
self.connect('focus-out-event', self.lost_focus)
@@ -282,10 +288,10 @@ class MainWindow(gtk.Window):
# Make sure we receive *all* mouse motion events,
# even if a modal dialog is being shown.
def _on_event(event):
- if gtk.gdk.MOTION_NOTIFY == event.type:
+ if Gdk.EventType.MOTION_NOTIFY == event.type:
self.cursor_handler.refresh()
- gtk.main_do_event(event)
- gtk.gdk.event_handler_set(_on_event)
+ Gtk.main_do_event(event)
+ Gdk.event_handler_set(_on_event)
def gained_focus(self, *args):
self.was_out_of_focus = False
@@ -304,8 +310,8 @@ class MainWindow(gtk.Window):
# FIXME: what if scroll_to is different?
if not self._waiting_for_redraw: # Don't stack up redraws.
self._waiting_for_redraw = True
- gobject.idle_add(self._draw_image, scroll_to,
- priority=gobject.PRIORITY_HIGH_IDLE)
+ GObject.idle_add(self._draw_image, scroll_to,
+ priority=GObject.PRIORITY_HIGH_IDLE)
def _update_toggle_preference(self, preference, toggleaction):
''' Update "toggle" widget corresponding <preference>.
@@ -353,6 +359,8 @@ class MainWindow(gtk.Window):
self._update_toggles_visibility()
+ self.osd.clear()
+
if not self.filehandler.file_loaded:
self._clear_main_area()
self._waiting_for_redraw = False
@@ -476,7 +484,7 @@ class MainWindow(gtk.Window):
if smartthumbbg:
self.thumbnailsidebar.change_thumbnail_background_color(bg_colour)
- self._main_layout.window.freeze_updates()
+ self._main_layout.get_bin_window().freeze_updates()
self._main_layout.set_size(*union_scaled_size)
content_boxes = self.layout.get_content_boxes()
@@ -505,7 +513,7 @@ class MainWindow(gtk.Window):
index = None
self.scroll_to_predefined(destination, index)
- self._main_layout.window.thaw_updates()
+ self._main_layout.get_bin_window().thaw_updates()
else:
# Save scroll destination for when the page becomes available.
self._last_scroll_destination = scroll_to
@@ -601,7 +609,7 @@ class MainWindow(gtk.Window):
self.thumbnailsidebar.hide()
self.thumbnailsidebar.clear()
self.uimanager.set_sensitivities()
- self.set_icon_list(*icons.mcomix_icons())
+ self.set_icon_list(icons.mcomix_icons())
def new_page(self, at_bottom=False):
"""Draw a *new* page correctly (as opposed to redrawing the same
@@ -750,8 +758,8 @@ class MainWindow(gtk.Window):
@property
def is_fullscreen(self):
- window_state = self.window.get_state()
- return 0 != (window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN)
+ window_state = self.get_window().get_state()
+ return 0 != (window_state & Gdk.WindowState.FULLSCREEN)
def change_fullscreen(self, toggleaction):
# Disable action until transition if complete.
@@ -855,8 +863,8 @@ class MainWindow(gtk.Window):
visible_width, visible_height = self.get_visible_area_size()
- hadjust_upper = max(0, self._hadjust.upper - visible_width)
- vadjust_upper = max(0, self._vadjust.upper - visible_height)
+ hadjust_upper = max(0, self._hadjust.get_upper() - visible_width)
+ vadjust_upper = max(0, self._vadjust.get_upper() - visible_height)
hadjust_lower = 0
if bound is not None and self.is_manga_mode:
@@ -864,10 +872,10 @@ class MainWindow(gtk.Window):
if bound == 'first':
hadjust_upper = max(0, hadjust_upper -
- self.images[1].size_request()[0] - 2) # XXX transitional(double page limitation)
+ self.images[1].size_request().width - 2) # XXX transitional(double page limitation)
elif bound == 'second':
- hadjust_lower = self.images[0].size_request()[0] + 2 # XXX transitional(double page limitation)
+ hadjust_lower = self.images[0].size_request().width + 2 # XXX transitional(double page limitation)
new_hadjust = old_hadjust + x
new_vadjust = old_vadjust + y
@@ -880,6 +888,8 @@ class MainWindow(gtk.Window):
self._vadjust.set_value(new_vadjust)
self._hadjust.set_value(new_hadjust)
+ self._scroll[0].queue_resize_no_redraw()
+ self._scroll[1].queue_resize_no_redraw()
return old_vadjust != new_vadjust or old_hadjust != new_hadjust
@@ -891,10 +901,12 @@ class MainWindow(gtk.Window):
viewport_position = self.layout.get_viewport_box().get_position()
self._hadjust.set_value(viewport_position[0]) # 2D only
self._vadjust.set_value(viewport_position[1]) # 2D only
+ self._scroll[0].queue_resize_no_redraw()
+ self._scroll[1].queue_resize_no_redraw()
def update_layout_position(self):
self.layout.set_viewport_position(
- (int(round(self._hadjust.value)), int(round(self._vadjust.value))))
+ (int(round(self._hadjust.get_value())), int(round(self._vadjust.get_value()))))
def clear(self):
"""Clear the currently displayed data (i.e. "close" the file)."""
@@ -929,7 +941,12 @@ class MainWindow(gtk.Window):
for widget in widget_list:
if widget.get_visible():
axis = self._toggle_axis[widget]
- dimensions[axis] -= widget.size_request()[axis]
+ requisition = widget.size_request()
+ if constants.WIDTH_AXIS == axis:
+ size = requisition.width
+ elif constants.HEIGHT_AXIS == axis:
+ size = requisition.height
+ dimensions[axis] -= size
return tuple(dimensions)
@@ -948,7 +965,7 @@ class MainWindow(gtk.Window):
probably use the cursor_handler instead of using this method
directly.
"""
- self._main_layout.window.set_cursor(mode)
+ self._main_layout.get_bin_window().set_cursor(mode)
def update_title(self):
"""Set the title acording to current state."""
@@ -972,11 +989,7 @@ class MainWindow(gtk.Window):
"""Set the background colour to <colour>. Colour is a sequence in the
format (r, g, b). Values are 16-bit.
"""
- self._main_layout.modify_bg(gtk.STATE_NORMAL,
- gtk.gdk.Color(colour[0],
- colour[1],
- colour[2]))
-
+ self._event_box.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(*colour))
if prefs['thumbnail bg uses main colour']:
self.thumbnailsidebar.change_thumbnail_background_color(prefs['bg colour'])
self._bg_colour = colour
@@ -995,13 +1008,12 @@ class MainWindow(gtk.Window):
else:
suggested_name = os.path.split(self.imagehandler.get_path_to_page())[-1]
- save_dialog = gtk.FileChooserDialog(_('Save page as'), self,
- gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
- gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
- save_dialog.set_do_overwrite_confirmation(True)
+ save_dialog = Gtk.FileChooserDialog(_('Save page as'), self,
+ Gtk.FileChooserAction.SAVE, (Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT,
+ Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT))
save_dialog.set_current_name(suggested_name.encode('utf-8'))
- if save_dialog.run() == gtk.RESPONSE_ACCEPT and save_dialog.get_filename():
+ if save_dialog.run() == Gtk.ResponseType.ACCEPT and save_dialog.get_filename():
shutil.copy(self.imagehandler.get_path_to_page(),
save_dialog.get_filename().decode('utf-8'))
@@ -1012,18 +1024,18 @@ class MainWindow(gtk.Window):
a confirmation dialog. """
current_file = self.imagehandler.get_real_path()
- dialog = message_dialog.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION,
- gtk.BUTTONS_NONE)
- dialog.set_should_remember_choice('delete-opend-file', (gtk.RESPONSE_OK,))
+ dialog = message_dialog.MessageDialog(self, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION,
+ Gtk.ButtonsType.NONE)
+ dialog.set_should_remember_choice('delete-opend-file', (Gtk.ResponseType.OK,))
dialog.set_text(
_('Delete "%s"?') % os.path.basename(current_file),
_('The file will be deleted from your harddisk.'))
- dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
- dialog.add_button(gtk.STOCK_DELETE, gtk.RESPONSE_OK)
- dialog.set_default_response(gtk.RESPONSE_OK)
+ dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
+ dialog.add_button(Gtk.STOCK_DELETE, Gtk.ResponseType.OK)
+ dialog.set_default_response(Gtk.ResponseType.OK)
result = dialog.run()
- if result == gtk.RESPONSE_OK:
+ if result == Gtk.ResponseType.OK:
# Go to next page/archive, and delete current file
if self.filehandler.archive_type is not None:
self.filehandler.last_read_page.clear_page(current_file)
@@ -1125,8 +1137,8 @@ class MainWindow(gtk.Window):
self.hide()
- if gtk.main_level() > 0:
- gtk.main_quit()
+ if Gtk.main_level() > 0:
+ Gtk.main_quit()
if prefs['auto load last file'] and self.filehandler.file_loaded:
prefs['path to last file'] = self.imagehandler.get_real_path()
diff --git a/mcomix/message_dialog.py b/mcomix/message_dialog.py
index 1c90f4a..dc56c93 100644
--- a/mcomix/message_dialog.py
+++ b/mcomix/message_dialog.py
@@ -1,13 +1,13 @@
-""" Simple extension of gtk.MessageDialog for consistent formating. Also
+""" Simple extension of Gtk.MessageDialog for consistent formating. Also
supports remembering the dialog result.
"""
-import gtk
+from gi.repository import Gtk
from mcomix.preferences import prefs
-class MessageDialog(gtk.MessageDialog):
+class MessageDialog(Gtk.MessageDialog):
def __init__(self, parent=None, flags=0, type=0, buttons=0):
""" Creates a dialog window.
@@ -29,10 +29,10 @@ class MessageDialog(gtk.MessageDialog):
#: Automatically destroy dialog after run?
self.auto_destroy = True
- self.remember_checkbox = gtk.CheckButton(_('Do not ask again.'))
+ self.remember_checkbox = Gtk.CheckButton(_('Do not ask again.'))
self.remember_checkbox.set_no_show_all(True)
self.remember_checkbox.set_can_focus(False)
- self.get_message_area().pack_end(self.remember_checkbox, padding=6)
+ self.get_message_area().pack_end(self.remember_checkbox, True, True, 6)
def set_text(self, primary, secondary=None):
""" Formats the dialog's text fields.
diff --git a/mcomix/messages/__init__.py b/mcomix/messages/__init__.py
deleted file mode 100644
index 7fc7b50..0000000
--- a/mcomix/messages/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-""" This file is required for setuptools packaging. """
diff --git a/mcomix/openwith.py b/mcomix/openwith.py
index 8732f52..2f0dc94 100644
--- a/mcomix/openwith.py
+++ b/mcomix/openwith.py
@@ -2,8 +2,8 @@
import sys
import os
import re
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import GObject
from mcomix.preferences import prefs
from mcomix import message_dialog
@@ -266,7 +266,7 @@ class OpenWithCommand(object):
return context
-class OpenWithEditor(gtk.Dialog):
+class OpenWithEditor(Gtk.Dialog):
""" The editor for changing and creating external commands. This window
keeps its own internal model once initialized, and will overwrite
the external model (i.e. preferences) only when properly closed. """
@@ -278,31 +278,31 @@ class OpenWithEditor(gtk.Dialog):
self._openwith = openwithmanager
self._changed = False
- self._command_tree = gtk.TreeView()
+ self._command_tree = Gtk.TreeView()
self._command_tree.get_selection().connect('changed', self._item_selected)
- self._add_button = gtk.Button(stock=gtk.STOCK_ADD)
+ self._add_button = Gtk.Button(stock=Gtk.STOCK_ADD)
self._add_button.connect('clicked', self._add_command)
- self._add_sep_button = gtk.Button(_('Add _separator'))
+ self._add_sep_button = Gtk.Button.new_with_mnemonic(_('Add _separator'))
self._add_sep_button.connect('clicked', self._add_sep_command)
- self._remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
+ self._remove_button = Gtk.Button(stock=Gtk.STOCK_REMOVE)
self._remove_button.connect('clicked', self._remove_command)
self._remove_button.set_sensitive(False)
- self._up_button = gtk.Button(stock=gtk.STOCK_GO_UP)
+ self._up_button = Gtk.Button(stock=Gtk.STOCK_GO_UP)
self._up_button.connect('clicked', self._up_command)
self._up_button.set_sensitive(False)
- self._down_button = gtk.Button(stock=gtk.STOCK_GO_DOWN)
+ self._down_button = Gtk.Button(stock=Gtk.STOCK_GO_DOWN)
self._down_button.connect('clicked', self._down_command)
self._down_button.set_sensitive(False)
- self._run_button = gtk.Button(_('Run _command'))
+ self._run_button = Gtk.Button.new_with_mnemonic(_('Run _command'))
self._run_button.connect('clicked', self._run_command)
self._run_button.set_sensitive(False)
- self._test_field = gtk.Entry()
- self._test_field.set_property('editable', gtk.FALSE)
- self._exec_label = gtk.Label()
+ self._test_field = Gtk.Entry()
+ self._test_field.set_property('editable', False)
+ self._exec_label = Gtk.Label()
self._exec_label.set_alignment(0, 0)
self._set_exec_text('')
- self._save_button = self.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)
- self.set_default_response(gtk.RESPONSE_ACCEPT)
+ self._save_button = self.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)
+ self.set_default_response(Gtk.ResponseType.ACCEPT)
self._layout()
self._setup_table()
@@ -379,7 +379,7 @@ class OpenWithEditor(gtk.Dialog):
def _add_command(self, button):
""" Add a new empty label-command line to the list. """
- row = (_('Command label'), '', '', gtk.FALSE, gtk.TRUE)
+ row = (_('Command label'), '', '', False, True)
selection = self._command_tree.get_selection()
if selection and selection.get_selected()[1]:
model, iter = selection.get_selected()
@@ -390,7 +390,7 @@ class OpenWithEditor(gtk.Dialog):
def _add_sep_command(self, button):
""" Adds a new separator line. """
- row = ('-', '', '', gtk.FALSE, gtk.FALSE)
+ row = ('-', '', '', False, False)
selection = self._command_tree.get_selection()
if selection and selection.get_selected()[1]:
model, iter = selection.get_selected()
@@ -452,64 +452,64 @@ class OpenWithEditor(gtk.Dialog):
""" Create and lay out UI components. """
# All these boxes basically are just for adding a 4px border
vbox = self.get_content_area()
- hbox = gtk.HBox()
- vbox.pack_start(hbox, padding=4)
- content = gtk.VBox()
+ hbox = Gtk.HBox()
+ vbox.pack_start(hbox, True, True, 4)
+ content = Gtk.VBox()
content.set_spacing(6)
- hbox.pack_start(content, padding=4)
+ hbox.pack_start(content, True, True, 4)
- scroll_window = gtk.ScrolledWindow()
- scroll_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scroll_window = Gtk.ScrolledWindow()
+ scroll_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
scroll_window.add(self._command_tree)
- content.pack_start(scroll_window)
+ content.pack_start(scroll_window, True, True, 0)
- buttonbox = gtk.HBox()
- buttonbox.pack_start(self._add_button, False)
- buttonbox.pack_start(self._add_sep_button, False)
- buttonbox.pack_start(self._remove_button, False)
- buttonbox.pack_start(self._up_button, False)
- buttonbox.pack_start(self._down_button, False)
- content.pack_start(buttonbox, False)
+ buttonbox = Gtk.HBox()
+ buttonbox.pack_start(self._add_button, False, False, 0)
+ buttonbox.pack_start(self._add_sep_button, False, False, 0)
+ buttonbox.pack_start(self._remove_button, False, False, 0)
+ buttonbox.pack_start(self._up_button, False, False, 0)
+ buttonbox.pack_start(self._down_button, False, False, 0)
+ content.pack_start(buttonbox, False, False, 0)
- preview_box = gtk.HBox()
- preview_box.pack_start(gtk.Label(_('Preview:')), False)
- preview_box.pack_start(self._test_field, padding=4)
- preview_box.pack_start(self._run_button, False)
- content.pack_start(preview_box, False)
+ preview_box = Gtk.HBox()
+ preview_box.pack_start(Gtk.Label(_('Preview:')), False, False, 0)
+ preview_box.pack_start(self._test_field, True, True, 4)
+ preview_box.pack_start(self._run_button, False, False, 0)
+ content.pack_start(preview_box, False, False, 0)
- content.pack_start(self._exec_label, False)
+ content.pack_start(self._exec_label, False, False, 0)
- linklabel = gtk.Label()
+ linklabel = Gtk.Label()
linklabel.set_markup(_('Please refer to the <a href="%s">external command documentation</a> '
'for a list of usable variables and other hints.') % \
'https://sourceforge.net/p/mcomix/wiki/External_Commands')
linklabel.set_alignment(0, 0)
- content.pack_start(linklabel, False, padding=4)
+ content.pack_start(linklabel, False, False, 4)
def _setup_table(self):
""" Initializes the TreeView with settings and data. """
for i, label in enumerate((_('Label'), _('Command'), _('Working directory'))):
- renderer = gtk.CellRendererText()
+ renderer = Gtk.CellRendererText()
renderer.connect('edited', self._text_changed, i)
- column = gtk.TreeViewColumn(label, renderer)
- column.set_property('resizable', gtk.TRUE)
+ column = Gtk.TreeViewColumn(label, renderer)
+ column.set_property('resizable', True)
column.set_attributes(renderer, text=i, editable=4)
if (i == 1):
column.set_expand(True) # Command column should scale automatically
self._command_tree.append_column(column)
# The 'Disabled in archives' field is shown as toggle button
- renderer = gtk.CellRendererToggle()
+ renderer = Gtk.CellRendererToggle()
renderer.connect('toggled', self._value_changed,
len(self._command_tree.get_columns()))
- column = gtk.TreeViewColumn(_('Disabled in archives'), renderer)
+ column = Gtk.TreeViewColumn(_('Disabled in archives'), renderer)
column.set_attributes(renderer, active=len(self._command_tree.get_columns()),
activatable=4)
self._command_tree.append_column(column)
# Label, command, working dir, disabled for archives, line is editable
- model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING,
- gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN)
+ model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING,
+ GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN)
for command in self._openwith.get_commands():
model.append((command.get_label(), command.get_command(), command.get_cwd(),
command.is_disabled_for_archives(), not command.is_separator()))
@@ -533,7 +533,7 @@ class OpenWithEditor(gtk.Dialog):
model.set_value(iter, column, new_text)
self._changed = old_value != new_text
self.test_command()
- gobject.idle_add(delayed_set_value)
+ GObject.idle_add(delayed_set_value)
def _value_changed(self, renderer, path, column):
""" Called when a toggle field is changed """
@@ -546,24 +546,24 @@ class OpenWithEditor(gtk.Dialog):
model.set_value(iter, column, value)
self._changed = True
- gobject.idle_add(delayed_set_value)
+ GObject.idle_add(delayed_set_value)
def _response(self, dialog, response):
- if response == gtk.RESPONSE_ACCEPT:
+ if response == Gtk.ResponseType.ACCEPT:
# The Save button is only enabled if all commands are valid
self.save()
- self.hide_all()
+ self.hide()
else:
if self._changed:
- confirm_diag = message_dialog.MessageDialog(self, gtk.DIALOG_MODAL,
- gtk.MESSAGE_INFO, gtk.BUTTONS_YES_NO)
+ confirm_diag = message_dialog.MessageDialog(self, Gtk.DialogFlags.MODAL,
+ Gtk.MessageType.INFO, Gtk.ButtonsType.YES_NO)
confirm_diag.set_text(_('Save changes to commands?'),
_('You have made changes to the list of external commands that '
'have not been saved yet. Press "Yes" to save all changes, '
'or "No" to discard them.'))
response = confirm_diag.run()
- if response == gtk.RESPONSE_YES:
+ if response == Gtk.ResponseType.YES:
self.save()
def _quote_if_necessary(self, arg):
diff --git a/mcomix/openwith_menu.py b/mcomix/openwith_menu.py
index cf6c907..a2943e6 100644
--- a/mcomix/openwith_menu.py
+++ b/mcomix/openwith_menu.py
@@ -1,6 +1,6 @@
""" openwith_menu.py - Menu shell for the Open with... menu. """
-import gtk
+from gi.repository import Gtk
from mcomix import openwith
@@ -9,7 +9,7 @@ _openwith_manager = openwith.OpenWithManager()
# Reference to the edit dialog (to keep only one instance)
_openwith_edit_diag = None
-class OpenWithMenu(gtk.Menu):
+class OpenWithMenu(Gtk.Menu):
def __init__(self, ui, window):
""" Constructor. """
super(OpenWithMenu, self).__init__()
@@ -17,9 +17,9 @@ class OpenWithMenu(gtk.Menu):
self._window = window
self._openwith_manager = _openwith_manager
- actiongroup = gtk.ActionGroup('mcomix-openwith')
+ actiongroup = Gtk.ActionGroup('mcomix-openwith')
actiongroup.add_actions([
- ('edit_commands', gtk.STOCK_EDIT, _('_Edit commands'),
+ ('edit_commands', Gtk.STOCK_EDIT, _('_Edit commands'),
None, None, self._edit_commands)])
action = actiongroup.get_action('edit_commands')
@@ -44,18 +44,18 @@ class OpenWithMenu(gtk.Menu):
commandlist = self._openwith_manager.get_commands()
if len(commandlist) > 0:
- separator = gtk.SeparatorMenuItem()
+ separator = Gtk.SeparatorMenuItem()
separator.show()
self.prepend(separator)
for command in reversed(commandlist):
if not command.is_separator():
- menuitem = gtk.MenuItem(command.get_label())
+ menuitem = Gtk.MenuItem(command.get_label())
menuitem.connect('activate', self._commandmenu_clicked,
command.get_command(), command.get_label(),
command.get_cwd(), command.is_disabled_for_archives())
else:
- menuitem = gtk.SeparatorMenuItem()
+ menuitem = Gtk.SeparatorMenuItem()
menuitem.show()
self.prepend(menuitem)
diff --git a/mcomix/osd.py b/mcomix/osd.py
index f7358f0..1582360 100644
--- a/mcomix/osd.py
+++ b/mcomix/osd.py
@@ -1,13 +1,14 @@
""" osd.py - Onscreen display showing currently opened file. """
# -*- coding: utf-8 -*-
-import gtk
-import gobject
-import pango
import textwrap
+from gi.repository import Gdk, Gtk, GObject
+from gi.repository import Pango, PangoCairo
+
from mcomix import image_tools
+
class OnScreenDisplay(object):
""" The OSD shows information such as currently opened file, archive and
@@ -35,8 +36,8 @@ class OnScreenDisplay(object):
# Set up font information
font = layout.get_context().get_font_description()
- font.set_weight(pango.WEIGHT_BOLD)
- layout.set_alignment(pango.ALIGN_CENTER)
+ font.set_weight(Pango.Weight.BOLD)
+ layout.set_alignment(Pango.Alignment.CENTER)
# Scale font to fit within the screen size
max_width, max_height = self._window.get_visible_area_size()
@@ -56,13 +57,13 @@ class OnScreenDisplay(object):
self._last_osd_rect = rect
if self._timeout_event:
- gobject.source_remove(self._timeout_event)
- self._timeout_event = gobject.timeout_add_seconds(OnScreenDisplay.TIMEOUT, self.clear)
+ GObject.source_remove(self._timeout_event)
+ self._timeout_event = GObject.timeout_add_seconds(OnScreenDisplay.TIMEOUT, self.clear)
def clear(self):
""" Removes the OSD. """
if self._timeout_event:
- gobject.source_remove(self._timeout_event)
+ GObject.source_remove(self._timeout_event)
self._timeout_event = None
self._clear_osd()
return 0 # To unregister gobject timer event
@@ -80,18 +81,17 @@ class OnScreenDisplay(object):
return "\n".join(result)
- def _clear_osd(self, exclude_region=None):
- """ Invalidates the OSD region. C{exclude_region} will not be invalidated, even
- if it was part of a previous drawing operation. """
+ def _clear_osd(self):
+ """ Clear the last OSD region. """
if not self._last_osd_rect:
return
- last_region = gtk.gdk.region_rectangle(self._last_osd_rect)
- if exclude_region:
- last_region.subtract(exclude_region)
- self._window._main_layout.get_bin_window().invalidate_region(last_region, True)
-
+ window = self._window._main_layout.get_bin_window()
+ gdk_rect = Gdk.Rectangle()
+ gdk_rect.x, gdk_rect.y, gdk_rect.width, gdk_rect.height = self._last_osd_rect
+ window.invalidate_rect(gdk_rect, True)
+ window.process_updates(True)
self._last_osd_rect = None
def _scale_font(self, font, layout, max_width, max_height):
@@ -100,7 +100,7 @@ class OnScreenDisplay(object):
SIZE_MIN, SIZE_MAX = 10, 60
for font_size in range(SIZE_MIN, SIZE_MAX, 5):
old_size = font.get_size()
- font.set_size(font_size * pango.SCALE)
+ font.set_size(font_size * Pango.SCALE)
layout.set_font_description(font)
if layout.get_pixel_size()[0] > max_width:
@@ -111,21 +111,34 @@ class OnScreenDisplay(object):
def _draw_osd(self, layout, rect):
""" Draws the text specified in C{layout} into a box at C{rect}. """
- osd_region = gtk.gdk.region_rectangle(rect)
- draw_region = osd_region.copy()
+ draw_region = Gdk.Rectangle()
+ draw_region.x, draw_region.y, draw_region.width, draw_region.height = rect
if self._last_osd_rect:
- draw_region.union(gtk.gdk.region_rectangle(self._last_osd_rect))
-
+ last_region = Gdk.Rectangle()
+ last_region.x, last_region.y, last_region.width, last_region.height = self._last_osd_rect
+ draw_region = Gdk.rectangle_union(draw_region, last_region)
+
+ gdk_rect = Gdk.Rectangle()
+ gdk_rect.x = draw_region.x
+ gdk_rect.y = draw_region.y
+ gdk_rect.width = draw_region.width
+ gdk_rect.height = draw_region.height
window = self._window._main_layout.get_bin_window()
- window.begin_paint_region(draw_region)
- self._clear_osd(osd_region)
+ window.begin_paint_rect(gdk_rect)
+
+ self._clear_osd()
- # Set up drawing context
- gc = window.new_gc(foreground=image_tools.GTK_GDK_COLOR_BLACK,
- background=image_tools.GTK_GDK_COLOR_BLACK)
+ cr = window.cairo_create()
+ cr.set_source_rgb(*image_tools.GTK_GDK_COLOR_BLACK.to_floats())
+ cr.rectangle(*rect)
+ cr.fill()
+ extents = layout.get_extents()[0]
+ cr.set_source_rgb(*image_tools.GTK_GDK_COLOR_WHITE.to_floats())
+ cr.translate(rect[0] + extents.x / Pango.SCALE,
+ rect[1] + extents.y / Pango.SCALE)
+ PangoCairo.update_layout(cr, layout)
+ PangoCairo.show_layout(cr, layout)
- window.draw_rectangle(gc, True, *rect)
- window.draw_layout(gc, rect[0] + 10, rect[1] + 10, layout, foreground=image_tools.GTK_GDK_COLOR_WHITE)
window.end_paint()
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/pageselect.py b/mcomix/pageselect.py
index 7230e49..e58516e 100644
--- a/mcomix/pageselect.py
+++ b/mcomix/pageselect.py
@@ -1,13 +1,13 @@
"""pageselect.py - The dialog window for the page selector."""
-import gtk
+from gi.repository import Gtk
from mcomix.preferences import prefs
from mcomix.worker_thread import WorkerThread
from mcomix import callback
-class Pageselector(gtk.Dialog):
+class Pageselector(Gtk.Dialog):
"""The Pageselector takes care of the popup page selector
"""
@@ -15,33 +15,31 @@ class Pageselector(gtk.Dialog):
def __init__(self, window):
self._window = window
super(Pageselector, self).__init__("Go to page...", window,
- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
- self.add_buttons(_('_Go'), gtk.RESPONSE_OK,
- _('_Cancel'), gtk.RESPONSE_CANCEL,)
- self.set_default_response(gtk.RESPONSE_OK)
+ Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT)
+ self.add_buttons(_('_Go'), Gtk.ResponseType.OK,
+ _('_Cancel'), Gtk.ResponseType.CANCEL,)
+ self.set_default_response(Gtk.ResponseType.OK)
self.connect('response', self._response)
self.set_resizable(True)
self._number_of_pages = self._window.imagehandler.get_number_of_pages()
- self._selector_adjustment = gtk.Adjustment(value=self._window.imagehandler.get_current_page(),
+ self._selector_adjustment = Gtk.Adjustment(value=self._window.imagehandler.get_current_page(),
lower=1,upper=self._number_of_pages,
step_incr=1, page_incr=1 )
- self._selector_adjustment.connect( 'value-changed', self._cb_value_changed )
-
- self._page_selector = gtk.VScale(self._selector_adjustment)
+ self._page_selector = Gtk.VScale.new(self._selector_adjustment)
self._page_selector.set_draw_value(False)
self._page_selector.set_digits( 0 )
- self._page_spinner = gtk.SpinButton(self._selector_adjustment)
+ self._page_spinner = Gtk.SpinButton.new(self._selector_adjustment, 0.0, 0)
self._page_spinner.connect( 'changed', self._page_text_changed )
self._page_spinner.set_activates_default(True)
self._page_spinner.set_numeric(True)
- self._pages_label = gtk.Label(_(' of %s') % self._number_of_pages)
+ self._pages_label = Gtk.Label(label=_(' of %s') % self._number_of_pages)
self._pages_label.set_alignment(0, 0.5)
- self._image_preview = gtk.Image()
+ self._image_preview = Gtk.Image()
self._image_preview.set_size_request(
prefs['thumbnail size'], prefs['thumbnail size'])
@@ -50,21 +48,23 @@ class Pageselector(gtk.Dialog):
prefs['pageselector height'])
# Group preview image and page selector next to each other
- preview_box = gtk.HBox()
+ preview_box = Gtk.HBox()
preview_box.set_border_width(5)
preview_box.set_spacing(5)
- preview_box.pack_start(self._image_preview, True)
- preview_box.pack_end(self._page_selector, False)
+ preview_box.pack_start(self._image_preview, True, True, 0)
+ preview_box.pack_end(self._page_selector, False, True, 0)
# Below them, group selection spinner and current page label
- selection_box = gtk.HBox()
+ selection_box = Gtk.HBox()
selection_box.set_border_width(5)
- selection_box.pack_start(self._page_spinner, True)
- selection_box.pack_end(self._pages_label, False)
+ selection_box.pack_start(self._page_spinner, True, True, 0)
+ selection_box.pack_end(self._pages_label, False, True, 0)
- self.get_content_area().pack_start(preview_box, True)
- self.get_content_area().pack_end(selection_box, False)
+ self.get_content_area().pack_start(preview_box, True, True, 0)
+ self.get_content_area().pack_end(selection_box, False, True, 0)
self.show_all()
+ self._selector_adjustment.connect('value-changed', self._cb_value_changed)
+
# Set focus on the input box.
self._page_spinner.select_region(0, -1)
self._page_spinner.grab_focus()
@@ -72,12 +72,12 @@ class Pageselector(gtk.Dialog):
# Currently displayed thumbnail page.
self._thumbnail_page = 0
self._thread = WorkerThread(self._generate_thumbnail, name='preview')
- self._update_thumbnail(int(self._selector_adjustment.value))
+ self._update_thumbnail(int(self._selector_adjustment.props.value))
self._window.imagehandler.page_available += self._page_available
def _cb_value_changed(self, *args):
""" Called whenever the spinbox value changes. Updates the preview thumbnail. """
- page = int(self._selector_adjustment.value)
+ page = int(self._selector_adjustment.props.value)
if page != self._thumbnail_page:
self._update_thumbnail(page)
@@ -88,7 +88,7 @@ class Pageselector(gtk.Dialog):
prefs['pageselector width'] = self.get_allocation().width
prefs['pageselector height'] = self.get_allocation().height
- self._update_thumbnail(int(self._selector_adjustment.value))
+ self._update_thumbnail(int(self._selector_adjustment.props.value))
def _page_text_changed(self, control, *args):
""" Called when the page selector has been changed. Used to instantly update
@@ -99,8 +99,8 @@ class Pageselector(gtk.Dialog):
control.set_value(page)
def _response(self, widget, event, *args):
- if event == gtk.RESPONSE_OK:
- self._window.set_page(int(self._selector_adjustment.value))
+ if event == Gtk.ResponseType.OK:
+ self._window.set_page(int(self._selector_adjustment.props.value))
self._window.imagehandler.page_available -= self._page_available
self._thread.stop()
@@ -130,7 +130,7 @@ class Pageselector(gtk.Dialog):
self._image_preview.set_from_pixbuf(pixbuf)
def _page_available(self, page):
- if page == int(self._selector_adjustment.value):
+ if page == int(self._selector_adjustment.props.value):
self._update_thumbnail(page)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/preferences.py b/mcomix/preferences.py
index 047893f..653e44c 100644
--- a/mcomix/preferences.py
+++ b/mcomix/preferences.py
@@ -94,7 +94,7 @@ prefs = {
'max threads': 3,
'max extract threads': 1,
'wrap mouse scroll': False,
- 'scaling quality': 2, # gtk.gdk.INTERP_BILINEAR
+ 'scaling quality': 2, # GdkPixbuf.InterpType.BILINEAR
'escape quits': False,
'fit to size mode': constants.ZOOM_MODE_HEIGHT,
'fit to size px': 1800,
diff --git a/mcomix/preferences_dialog.py b/mcomix/preferences_dialog.py
index d0933d7..a84978f 100644
--- a/mcomix/preferences_dialog.py
+++ b/mcomix/preferences_dialog.py
@@ -3,8 +3,7 @@
"""preferences_dialog.py - Preferences dialog."""
import operator
-import gtk
-import gobject
+from gi.repository import Gdk, GdkPixbuf, Gtk, GObject
from mcomix.preferences import prefs
from mcomix import preferences_page
@@ -16,7 +15,7 @@ from mcomix import keybindings_editor
_dialog = None
-class _PreferencesDialog(gtk.Dialog):
+class _PreferencesDialog(Gtk.Dialog):
"""The preferences dialog where most (but not all) settings that are
saved between sessions are presented to the user.
@@ -27,29 +26,29 @@ class _PreferencesDialog(gtk.Dialog):
# Button text is set later depending on active tab
self.reset_button = self.add_button('', constants.RESPONSE_REVERT_TO_DEFAULT)
- self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
+ self.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
self._window = window
self.set_resizable(True)
- self.set_default_response(gtk.RESPONSE_CLOSE)
+ self.set_default_response(Gtk.ResponseType.CLOSE)
self.connect('response', self._response)
- notebook = self.notebook = gtk.Notebook()
- self.vbox.pack_start(notebook)
+ notebook = self.notebook = Gtk.Notebook()
+ self.vbox.pack_start(notebook, True, True, 0)
self.set_border_width(4)
notebook.set_border_width(6)
appearance = self._init_appearance_tab()
- notebook.append_page(appearance, gtk.Label(_('Appearance')))
+ notebook.append_page(appearance, Gtk.Label(label=_('Appearance')))
behaviour = self._init_behaviour_tab()
- notebook.append_page(behaviour, gtk.Label(_('Behaviour')))
+ notebook.append_page(behaviour, Gtk.Label(label=_('Behaviour')))
display = self._init_display_tab()
- notebook.append_page(display, gtk.Label(_('Display')))
+ notebook.append_page(display, Gtk.Label(label=_('Display')))
advanced = self._init_advanced_tab()
- notebook.append_page(advanced, gtk.Label(_('Advanced')))
+ notebook.append_page(advanced, Gtk.Label(label=_('Advanced')))
shortcuts = self.shortcuts = self._init_shortcuts_tab()
- notebook.append_page(shortcuts, gtk.Label(_('Shortcuts')))
+ notebook.append_page(shortcuts, Gtk.Label(label=_('Shortcuts')))
notebook.connect('switch-page', self._tab_page_changed)
# Update the Reset button's tooltip
@@ -65,7 +64,7 @@ class _PreferencesDialog(gtk.Dialog):
page.new_section(_('User interface'))
- page.add_row(gtk.Label(_('Language (needs restart):')),
+ page.add_row(Gtk.Label(label=_('Language (needs restart):')),
self._create_language_control())
page.add_row(self._create_pref_check_button(
@@ -106,7 +105,7 @@ class _PreferencesDialog(gtk.Dialog):
'archive thumbnail as icon',
_('By enabling this setting, the first page of a book will be used as application icon instead of the standard icon.')))
- page.add_row(gtk.Label(_('Thumbnail size (in pixels):')),
+ page.add_row(Gtk.Label(label=_('Thumbnail size (in pixels):')),
self._create_pref_spinner('thumbnail size',
1, 20, 500, 1, 10, 0, None))
@@ -149,24 +148,24 @@ class _PreferencesDialog(gtk.Dialog):
'auto open next directory',
_('Automatically open the first file in the next sibling directory when flipping past the last page of the last file in a directory, or the previous directory when flipping past the first page of the first file.')))
- page.add_row(gtk.Label(_('Number of pixels to scroll per arrow key press:')),
+ page.add_row(Gtk.Label(label=_('Number of pixels to scroll per arrow key press:')),
self._create_pref_spinner('number of pixels to scroll per key event',
1, 1, 500, 1, 3, 0,
_('Set the number of pixels to scroll on a page when using the arrow keys.')))
- page.add_row(gtk.Label(_('Number of pixels to scroll per mouse wheel turn:')),
+ page.add_row(Gtk.Label(label=_('Number of pixels to scroll per mouse wheel turn:')),
self._create_pref_spinner('number of pixels to scroll per mouse wheel event',
1, 1, 500, 1, 3, 0,
_('Set the number of pixels to scroll on a page when using a mouse wheel.')))
- page.add_row(gtk.Label(_('Fraction of page to scroll '
+ page.add_row(Gtk.Label(label=_('Fraction of page to scroll '
'per space key press (in percent):')),
self._create_pref_spinner('smart scroll percentage',
0.01, 1, 100, 1, 5, 0,
_('Sets the percentage by which the page '
'will be scrolled down or up when the space key is pressed.')))
- page.add_row(gtk.Label(_('Number of "steps" to take before flipping the page:')),
+ page.add_row(Gtk.Label(label=_('Number of "steps" to take before flipping the page:')),
self._create_pref_spinner('number of key presses before page turn',
1, 1, 100, 1, 3, 0,
_('Set the number of "steps" needed to flip to the next or previous page. Less steps will allow for very fast page turning but you might find yourself accidentally turning pages.')))
@@ -178,7 +177,7 @@ class _PreferencesDialog(gtk.Dialog):
'double step in double page mode',
_('Flip two pages, instead of one, each time we flip pages in double page mode.')))
- page.add_row(gtk.Label(_('Show only one page where appropriate:')),
+ page.add_row(Gtk.Label(label=_('Show only one page where appropriate:')),
self._create_doublepage_as_one_control())
page.new_section(_('Files'))
@@ -188,7 +187,7 @@ class _PreferencesDialog(gtk.Dialog):
'auto load last file',
_('Automatically open, on startup, the file that was open when MComix was last closed.')))
- page.add_row(gtk.Label(_('Store information about recently opened files:')),
+ page.add_row(Gtk.Label(label=_('Store information about recently opened files:')),
self._create_store_recent_combobox())
return page
@@ -211,20 +210,20 @@ class _PreferencesDialog(gtk.Dialog):
page.new_section(_('Fit to size mode'))
- page.add_row(gtk.Label(_('Fit to width or height:')),
+ page.add_row(Gtk.Label(label=_('Fit to width or height:')),
self._create_fitmode_control())
- page.add_row(gtk.Label(_('Fixed size for this mode:')),
+ page.add_row(Gtk.Label(label=_('Fixed size for this mode:')),
self._create_pref_spinner('fit to size px',
1, 10, 10000, 10, 50, 0, None))
page.new_section(_('Slideshow'))
- page.add_row(gtk.Label(_('Slideshow delay (in seconds):')),
+ page.add_row(Gtk.Label(label=_('Slideshow delay (in seconds):')),
self._create_pref_spinner('slideshow delay',
1000.0, 0.01, 3600.0, 0.1, 1, 2, None))
- page.add_row(gtk.Label(_('Slideshow step (in pixels):')),
+ page.add_row(Gtk.Label(label=_('Slideshow step (in pixels):')),
self._create_pref_spinner('number of pixels to scroll per slideshow event',
1, -500, 500, 1, 1, 0,
_('Specify the number of pixels to scroll while in slideshow mode. A positive value will scroll forward, a negative value will scroll backwards, and a value of 0 will cause the slideshow to always flip to a new page.')))
@@ -243,7 +242,7 @@ class _PreferencesDialog(gtk.Dialog):
page.new_section(_('Image quality'))
- page.add_row(gtk.Label(_('Scaling mode')),
+ page.add_row(Gtk.Label(label=_('Scaling mode')),
self._create_scaling_quality_combobox())
return page
@@ -257,15 +256,15 @@ class _PreferencesDialog(gtk.Dialog):
page.new_section(_('File order'))
- page.add_row(gtk.Label(_('Sort files and directories by:')),
+ page.add_row(Gtk.Label(label=_('Sort files and directories by:')),
self._create_sort_by_control())
- page.add_row(gtk.Label(_('Sort archives by:')),
+ page.add_row(Gtk.Label(label=_('Sort archives by:')),
self._create_archive_sort_by_control())
page.new_section(_('Extraction and cache'))
- page.add_row(gtk.Label(_('Maximum number of concurrent extraction threads:')),
+ page.add_row(Gtk.Label(label=_('Maximum number of concurrent extraction threads:')),
self._create_pref_spinner('max extract threads',
1, 1, 16, 1, 4, 0,
_('Set the maximum number of concurrent threads for formats that support it.')))
@@ -275,31 +274,31 @@ class _PreferencesDialog(gtk.Dialog):
'create thumbnails',
_('Store thumbnails for opened files according to the freedesktop.org specification. These thumbnails are shared by many other applications, such as most file managers.')))
- page.add_row(gtk.Label(_('Maximum number of pages to store in the cache:')),
+ page.add_row(Gtk.Label(label=_('Maximum number of pages to store in the cache:')),
self._create_pref_spinner('max pages to cache',
1, -1, 500, 1, 3, 0,
_('Set the max number of pages to cache. A value of -1 will cache the entire archive.')))
page.new_section(_('Magnifying Lens'))
- page.add_row(gtk.Label(_('Magnifying lens size (in pixels):')),
+ page.add_row(Gtk.Label(label=_('Magnifying lens size (in pixels):')),
self._create_pref_spinner('lens size',
1, 50, 400, 1, 10, 0,
_('Set the size of the magnifying lens. It is a square with a side of this many pixels.')))
- page.add_row(gtk.Label(_('Magnification factor:')),
+ page.add_row(Gtk.Label(label=_('Magnification factor:')),
self._create_pref_spinner('lens magnification',
1, 1.1, 10.0, 0.1, 1.0, 1,
_('Set the magnification factor of the magnifying lens.')))
page.new_section(_('Comments'))
- page.add_row(gtk.Label(_('Comment extensions:')),
+ page.add_row(Gtk.Label(label=_('Comment extensions:')),
self._create_extensions_entry())
page.new_section(_('Animated images'))
- page.add_row(gtk.Label(_('Animation mode:')),
+ page.add_row(Gtk.Label(_('Animation mode:')),
self._create_animation_mode_combobox())
return page
@@ -328,7 +327,7 @@ class _PreferencesDialog(gtk.Dialog):
self.reset_button.set_sensitive(len(prefs['stored dialog choices']) > 0)
def _response(self, dialog, response):
- if response == gtk.RESPONSE_CLOSE:
+ if response == Gtk.ResponseType.CLOSE:
_close_dialog()
elif response == constants.RESPONSE_REVERT_TO_DEFAULT:
@@ -353,30 +352,30 @@ class _PreferencesDialog(gtk.Dialog):
# Source: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
languages = [
(_('Auto-detect (Default)'), 'auto'),
- ('Català', 'ca'), # Catalan
- ('čeština', 'cs'), # Czech
- ('Deutsch', 'de'), # German
- ('ελληνικά', 'el'), # Greek
- ('English', 'en'), # English
- ('Español', 'es'), # Spanish
- ('فارسی', 'fa'), # Persian
- ('Français', 'fr'), # French
- ('Galego', 'gl'), # Galician
- ('עברית', 'he'), # Hebrew
- ('Hrvatski jezik', 'hr'), # Croatian
- ('Magyar', 'hu'), # Hungarian
- ('Bahasa Indonesia', 'id'), # Indonesian
- ('Italiano', 'it'), # Italian
- ('日本語', 'ja'), # Japanese
- ('한국어', 'ko'), # Korean
- ('Nederlands', 'nl'), # Dutch
- ('Język polski', 'pl'), # Polish
- ('Português', 'pt_BR'), # Portuguese
- ('pусский язык', 'ru'), # Russian
- ('Svenska', 'sv'), # Swedish
- ('українська мова', 'uk'), # Ukrainian
- ('簡體中文', 'zh_CN'), # Chinese (simplified)
- ('正體中文', 'zh_TW')] # Chinese (traditional)
+ (u'Català', 'ca'), # Catalan
+ (u'čeština', 'cs'), # Czech
+ (u'Deutsch', 'de'), # German
+ (u'ελληνικά', 'el'), # Greek
+ (u'English', 'en'), # English
+ (u'Español', 'es'), # Spanish
+ (u'فارسی', 'fa'), # Persian
+ (u'Français', 'fr'), # French
+ (u'Galego', 'gl'), # Galician
+ (u'עברית', 'he'), # Hebrew
+ (u'Hrvatski jezik', 'hr'), # Croatian
+ (u'Magyar', 'hu'), # Hungarian
+ (u'Bahasa Indonesia', 'id'), # Indonesian
+ (u'Italiano', 'it'), # Italian
+ (u'日本語', 'ja'), # Japanese
+ (u'한국어', 'ko'), # Korean
+ (u'Nederlands', 'nl'), # Dutch
+ (u'Język polski', 'pl'), # Polish
+ (u'Português', 'pt_BR'), # Portuguese
+ (u'pусский язык', 'ru'), # Russian
+ (u'Svenska', 'sv'), # Swedish
+ (u'українська мова', 'uk'), # Ukrainian
+ (u'簡體中文', 'zh_CN'), # Chinese (simplified)
+ (u'正體中文', 'zh_TW')] # Chinese (traditional)
languages.sort(key=operator.itemgetter(0))
box = self._create_combobox(languages, prefs['language'],
@@ -459,9 +458,9 @@ class _PreferencesDialog(gtk.Dialog):
prefs['sort order'],
self._sort_order_changed_cb)
- box = gtk.HBox()
- box.pack_start(sortkey_box)
- box.pack_start(sortorder_box)
+ box = Gtk.HBox()
+ box.pack_start(sortkey_box, True, True, 0)
+ box.pack_start(sortorder_box, True, True, 0)
label = _("Files will be opened and displayed according to the sort order "
"specified here. This option does not affect ordering within archives.")
@@ -506,9 +505,9 @@ class _PreferencesDialog(gtk.Dialog):
prefs['sort archive order'],
self._sort_archive_order_changed_cb)
- box = gtk.HBox()
- box.pack_start(sortkey_box)
- box.pack_start(sortorder_box)
+ box = Gtk.HBox()
+ box.pack_start(sortkey_box, True, True, 0)
+ box.pack_start(sortorder_box, True, True, 0)
label = _("Files within archives will be sorted according to the order specified here. "
"Natural order will sort numbered files based on their natural order, "
@@ -572,25 +571,25 @@ class _PreferencesDialog(gtk.Dialog):
and (self._window.uimanager.recent.count() > 0
or self._window.filehandler.last_read_page.count() > 0)):
- dialog = message_dialog.MessageDialog(self, gtk.DIALOG_MODAL,
- gtk.MESSAGE_INFO, gtk.BUTTONS_YES_NO)
- dialog.set_default_response(gtk.RESPONSE_YES)
+ dialog = message_dialog.MessageDialog(self, Gtk.DialogFlags.MODAL,
+ Gtk.MessageType.INFO, Gtk.ButtonsType.YES_NO)
+ dialog.set_default_response(Gtk.ResponseType.YES)
dialog.set_text(
_('Delete information about recently opened files?'),
_('This will remove all entries from the "Recent" menu,'
' and clear information about last read pages.'))
response = dialog.run()
- if response == gtk.RESPONSE_YES:
+ if response == Gtk.ResponseType.YES:
self._window.uimanager.recent.remove_all()
self._window.filehandler.last_read_page.clear_all()
def _create_scaling_quality_combobox(self):
""" Creates combo box for image scaling quality """
items = (
- (_('Normal (fast)'), int(gtk.gdk.INTERP_TILES)),
- (_('Bilinear'), int(gtk.gdk.INTERP_BILINEAR)),
- (_('Hyperbolic (slow)'), int(gtk.gdk.INTERP_HYPER)))
+ (_('Normal (fast)'), int(GdkPixbuf.InterpType.TILES)),
+ (_('Bilinear'), int(GdkPixbuf.InterpType.BILINEAR)),
+ (_('Hyperbolic (slow)'), int(GdkPixbuf.InterpType.HYPER)))
selection = prefs['scaling quality']
@@ -645,18 +644,18 @@ class _PreferencesDialog(gtk.Dialog):
be pre-selected when the control is created.
@param change_callback: Function that will be called when the 'changed'
event is triggered.
- @returns gtk.ComboBox
+ @returns Gtk.ComboBox
"""
assert options and len(options[0]) == 2, "Invalid format for options."
# Use the first list item to determine typing of model fields.
# First field is textual description, second field is value.
- model = gtk.ListStore(gobject.TYPE_STRING, type(options[0][1]))
+ model = Gtk.ListStore(GObject.TYPE_STRING, type(options[0][1]))
for text, value in options:
model.append((text, value))
- box = gtk.ComboBox(model)
- renderer = gtk.CellRendererText()
+ box = Gtk.ComboBox(model=model)
+ renderer = Gtk.CellRendererText()
box.pack_start(renderer, True)
box.add_attribute(renderer, "text", 0)
@@ -676,7 +675,7 @@ class _PreferencesDialog(gtk.Dialog):
def _create_extensions_entry(self):
- entry = gtk.Entry()
+ entry = Gtk.Entry()
entry.set_size_request(200, -1)
entry.set_text(', '.join(prefs['comment extensions']))
entry.connect('activate', self._entry_cb)
@@ -687,7 +686,7 @@ class _PreferencesDialog(gtk.Dialog):
def _create_pref_check_button(self, label, prefkey, tooltip_text):
- button = gtk.CheckButton(label)
+ button = Gtk.CheckButton(label)
button.set_active(prefs[prefkey])
button.connect('toggled', self._check_button_cb, prefkey)
if tooltip_text:
@@ -697,11 +696,11 @@ class _PreferencesDialog(gtk.Dialog):
def _create_binary_pref_radio_buttons(self, label1, prefkey1, tooltip_text1,
label2, prefkey2, tooltip_text2):
- button1 = gtk.RadioButton(None, label1)
+ button1 = Gtk.RadioButton(label=label1)
button1.connect('toggled', self._check_button_cb, prefkey1)
if tooltip_text1:
button1.set_tooltip_text(tooltip_text1)
- button2 = gtk.RadioButton(button1, label2)
+ button2 = Gtk.RadioButton(group=button1, label=label2)
button2.connect('toggled', self._check_button_cb, prefkey2)
if tooltip_text2:
button2.set_tooltip_text(tooltip_text2)
@@ -710,7 +709,8 @@ class _PreferencesDialog(gtk.Dialog):
def _create_color_button(self, prefkey):
- button = gtk.ColorButton(gtk.gdk.Color(*prefs[prefkey]))
+ rgba = image_tools.color_to_floats_rgba(prefs[prefkey])
+ button = Gtk.ColorButton.new_with_rgba(Gdk.RGBA(*rgba))
button.connect('color_set', self._color_button_cb, prefkey)
return button
@@ -791,8 +791,8 @@ class _PreferencesDialog(gtk.Dialog):
def _create_pref_spinner(self, prefkey, scale, lower, upper, step_incr,
page_incr, digits, tooltip_text):
value = prefs[prefkey] / scale
- adjustment = gtk.Adjustment(value, lower, upper, step_incr, page_incr)
- spinner = gtk.SpinButton(adjustment, digits=digits)
+ adjustment = Gtk.Adjustment(value, lower, upper, step_incr, page_incr)
+ spinner = Gtk.SpinButton.new(adjustment, 0.0, digits)
spinner.set_size_request(80, -1)
spinner.connect('value_changed', self._spinner_cb, prefkey)
if tooltip_text:
diff --git a/mcomix/preferences_page.py b/mcomix/preferences_page.py
index 95bdc84..c2e3d00 100644
--- a/mcomix/preferences_page.py
+++ b/mcomix/preferences_page.py
@@ -1,10 +1,10 @@
"""preferences_page.py - MComix preference page."""
-import gtk
+from gi.repository import Gtk
from mcomix import preferences_section
-class _PreferencePage(gtk.VBox):
+class _PreferencePage(Gtk.VBox):
"""The _PreferencePage is a conveniece class for making one "page"
in a preferences-style dialog that contains one or more
@@ -25,21 +25,21 @@ class _PreferencePage(gtk.VBox):
<header>.
"""
self._section = preferences_section._PreferenceSection(header, self._right_column_width)
- self.pack_start(self._section, False, False)
+ self.pack_start(self._section, False, False, 0)
def add_row(self, left_item, right_item=None):
"""Add a row to the page (in the latest section), containing one
or two items. If the left item is a label it is automatically
aligned properly.
"""
- if isinstance(left_item, gtk.Label):
+ if isinstance(left_item, Gtk.Label):
left_item.set_alignment(0, 0.5)
if right_item is None:
- self._section.contentbox.pack_start(left_item)
+ self._section.contentbox.pack_start(left_item, True, True, 0)
else:
left_box, right_box = self._section.new_split_vboxes()
- left_box.pack_start(left_item)
- right_box.pack_start(right_item)
+ left_box.pack_start(left_item, True, True, 0)
+ right_box.pack_start(right_item, True, True, 0)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/preferences_section.py b/mcomix/preferences_section.py
index 6360323..f12cb04 100644
--- a/mcomix/preferences_section.py
+++ b/mcomix/preferences_section.py
@@ -1,10 +1,10 @@
"""preferences_section.py - Preference dialog section."""
-import gtk
+from gi.repository import Gtk
from mcomix import labels
-class _PreferenceSection(gtk.VBox):
+class _PreferenceSection(Gtk.VBox):
"""The _PreferenceSection is a convenience class for making one
"section" of a preference-style dialog, e.g. it has a bold header
@@ -18,13 +18,13 @@ class _PreferenceSection(gtk.VBox):
"""
super(_PreferenceSection, self).__init__(False, 0)
self._right_column_width = right_column_width
- self.contentbox = gtk.VBox(False, 6)
+ self.contentbox = Gtk.VBox(False, 6)
label = labels.BoldLabel(header)
label.set_alignment(0, 0.5)
- hbox = gtk.HBox(False, 0)
- hbox.pack_start(gtk.HBox(), False, False, 6)
- hbox.pack_start(self.contentbox)
- self.pack_start(label, False, False)
+ hbox = Gtk.HBox(False, 0)
+ hbox.pack_start(Gtk.HBox(True, True, 0), False, False, 6)
+ hbox.pack_start(self.contentbox, True, True, 0)
+ self.pack_start(label, False, False, 0)
self.pack_start(hbox, False, False, 6)
def new_split_vboxes(self):
@@ -34,16 +34,16 @@ class _PreferenceSection(gtk.VBox):
in order to make it easy for all "right column items" in a page to
line up nicely.
"""
- left_box = gtk.VBox(False, 6)
- right_box = gtk.VBox(False, 6)
+ left_box = Gtk.VBox(False, 6)
+ right_box = Gtk.VBox(False, 6)
if self._right_column_width != None:
right_box.set_size_request(self._right_column_width, -1)
- hbox = gtk.HBox(False, 12)
- hbox.pack_start(left_box)
- hbox.pack_start(right_box, False, False)
- self.contentbox.pack_start(hbox)
+ hbox = Gtk.HBox(False, 12)
+ hbox.pack_start(left_box, True, True, 0)
+ hbox.pack_start(right_box, False, False, 0)
+ self.contentbox.pack_start(hbox, True, True, 0)
return left_box, right_box
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/properties_dialog.py b/mcomix/properties_dialog.py
index 316d1df..c4d86ee 100644
--- a/mcomix/properties_dialog.py
+++ b/mcomix/properties_dialog.py
@@ -1,6 +1,6 @@
"""properties_dialog.py - Properties dialog that displays information about the archive/file."""
-import gtk
+from gi.repository import Gtk
import os
import time
import stat
@@ -16,26 +16,26 @@ from mcomix import strings
from mcomix import properties_page
from mcomix import tools
-class _PropertiesDialog(gtk.Dialog):
+class _PropertiesDialog(Gtk.Dialog):
def __init__(self, window):
super(_PropertiesDialog, self).__init__(_('Properties'), window, 0,
- (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+ (Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
self._window = window
- self.resize(400, 400)
+ self.resize(500, 430)
self.set_resizable(True)
- self.set_default_response(gtk.RESPONSE_CLOSE)
- notebook = gtk.Notebook()
+ self.set_default_response(Gtk.ResponseType.CLOSE)
+ notebook = Gtk.Notebook()
self.set_border_width(4)
notebook.set_border_width(6)
- self.vbox.pack_start(notebook)
+ self.vbox.pack_start(notebook, True, True, 0)
self._archive_page = properties_page._Page()
- notebook.append_page(self._archive_page, gtk.Label(_('Archive')))
+ notebook.append_page(self._archive_page, Gtk.Label(label=_('Archive')))
self._image_page = properties_page._Page()
- notebook.append_page(self._image_page, gtk.Label(_('Image')))
+ notebook.append_page(self._image_page, Gtk.Label(label=_('Image')))
self._update_archive_page()
self._window.page_changed += self._on_page_change
self._window.filehandler.file_opened += self._on_book_change
diff --git a/mcomix/properties_page.py b/mcomix/properties_page.py
index 001ffee..73a75d6 100644
--- a/mcomix/properties_page.py
+++ b/mcomix/properties_page.py
@@ -1,36 +1,36 @@
"""properties_page.py - A page to put in the properties dialog window."""
-import gtk
+from gi.repository import Gtk
from mcomix import i18n
from mcomix import image_tools
from mcomix import labels
-class _Page(gtk.ScrolledWindow):
+class _Page(Gtk.ScrolledWindow):
- """A page to put in the gtk.Notebook. Contains info about a file (an
+ """A page to put in the Gtk.Notebook. Contains info about a file (an
image or an archive.)
"""
def __init__(self):
super(_Page, self).__init__()
- self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self._vbox = gtk.VBox(False, 12)
+ self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ self._vbox = Gtk.VBox(False, 12)
self.add_with_viewport(self._vbox)
self.set_border_width(12)
- topbox = gtk.HBox(False, 12)
- self._vbox.pack_start(topbox)
- self._thumb = gtk.Image()
+ topbox = Gtk.HBox(False, 12)
+ self._vbox.pack_start(topbox, True, True, 0)
+ self._thumb = Gtk.Image()
self._thumb.set_size_request(128, 128)
- topbox.pack_start(self._thumb, False, False)
- borderbox = gtk.Frame()
- borderbox.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ topbox.pack_start(self._thumb, False, False, 0)
+ borderbox = Gtk.Frame()
+ borderbox.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
borderbox.set_size_request(-1, 130)
- topbox.pack_start(borderbox)
- insidebox = gtk.EventBox()
+ topbox.pack_start(borderbox, True, True, 0)
+ insidebox = Gtk.EventBox()
insidebox.set_border_width(1)
- insidebox.set_state(gtk.STATE_ACTIVE)
+ insidebox.set_state(Gtk.StateType.ACTIVE)
borderbox.add(insidebox)
self._insidebox = insidebox
self._mainbox = None
@@ -41,13 +41,13 @@ class _Page(gtk.ScrolledWindow):
self._thumb.clear()
if self._mainbox is not None:
self._mainbox.destroy()
- self._mainbox = gtk.VBox(False, 5)
+ self._mainbox = Gtk.VBox(False, 5)
self._mainbox.set_border_width(10)
self._insidebox.add(self._mainbox)
if self._extrabox is not None:
self._extrabox.destroy()
- self._extrabox = gtk.HBox(False, 10)
- self._vbox.pack_start(self._extrabox, False, False)
+ self._extrabox = Gtk.HBox(False, 10)
+ self._vbox.pack_start(self._extrabox, False, False, 0)
def set_thumbnail(self, pixbuf):
pixbuf = image_tools.add_border(pixbuf, 1)
@@ -60,34 +60,34 @@ class _Page(gtk.ScrolledWindow):
label = labels.BoldLabel(i18n.to_unicode(filename))
label.set_alignment(0, 0.5)
label.set_selectable(True)
- self._mainbox.pack_start(label, False, False)
- self._mainbox.pack_start(gtk.VBox()) # Just to add space (better way?)
+ self._mainbox.pack_start(label, False, False, 0)
+ self._mainbox.pack_start(Gtk.VBox(True, True, 0), True, True, 0) # Just to add space (better way?)
def set_main_info(self, info):
"""Set the information in the main info box (below the filename) to
the values in the sequence <info>.
"""
for text in info:
- label = gtk.Label(text)
+ label = Gtk.Label(label=text)
label.set_alignment(0, 0.5)
label.set_selectable(True)
- self._mainbox.pack_start(label, False, False)
+ self._mainbox.pack_start(label, False, False, 0)
def set_secondary_info(self, info):
"""Set the information below the main info box to the values in the
sequence <info>. Each entry in info should be a tuple (desc, value).
"""
- left_box = gtk.VBox(True, 8)
- right_box = gtk.VBox(True, 8)
- self._extrabox.pack_start(left_box, False, False)
- self._extrabox.pack_start(right_box, False, False)
+ left_box = Gtk.VBox(True, 8)
+ right_box = Gtk.VBox(True, 8)
+ self._extrabox.pack_start(left_box, False, False, 0)
+ self._extrabox.pack_start(right_box, False, False, 0)
for desc, value in info:
desc_label = labels.BoldLabel('%s:' % desc)
desc_label.set_alignment(1.0, 1.0)
- left_box.pack_start(desc_label, True, True)
- value_label = gtk.Label(value)
+ left_box.pack_start(desc_label, True, True, 0)
+ value_label = Gtk.Label(label=value)
value_label.set_alignment(0, 1.0)
value_label.set_selectable(True)
- right_box.pack_start(value_label, True, True)
+ right_box.pack_start(value_label, True, True, 0)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/recent.py b/mcomix/recent.py
index 2677ac5..1244aa1 100644
--- a/mcomix/recent.py
+++ b/mcomix/recent.py
@@ -2,9 +2,10 @@
import urllib
import itertools
-import gtk
+from gi.repository import Gtk
+from gi.repository import Gtk
import glib
-import gobject
+from gi.repository import GObject
import sys
from mcomix import preferences
@@ -14,21 +15,21 @@ from mcomix import archive_tools
from mcomix import image_tools
from mcomix import log
-class RecentFilesMenu(gtk.RecentChooserMenu):
+class RecentFilesMenu(Gtk.RecentChooserMenu):
def __init__(self, ui, window):
+ super(RecentFilesMenu, self).__init__()
self._window = window
- self._manager = gtk.recent_manager_get_default()
- super(RecentFilesMenu, self).__init__(self._manager)
+ self._manager = Gtk.RecentManager.get_default()
- self.set_sort_type(gtk.RECENT_SORT_MRU)
+ self.set_sort_type(Gtk.RecentSortType.MRU)
self.set_show_tips(True)
# Missing icons crash GTK on Win32
if sys.platform == 'win32':
self.set_show_icons(False)
self.set_show_numbers(True)
- rfilter = gtk.RecentFilter()
+ rfilter = Gtk.RecentFilter()
supported_formats = {}
supported_formats.update(image_tools.get_supported_formats())
supported_formats.update(archive_tools.get_supported_formats())
@@ -75,7 +76,7 @@ class RecentFilesMenu(gtk.RecentChooserMenu):
""" Removes all entries to recently opened files. """
try:
self._manager.purge_items()
- except gobject.GError, error:
+ except GObject.GError, error:
log.debug(error)
diff --git a/mcomix/run.py b/mcomix/run.py
index c0cec69..761c890 100644
--- a/mcomix/run.py
+++ b/mcomix/run.py
@@ -175,29 +175,22 @@ def run():
# Check for PyGTK and PIL dependencies.
try:
- import pygtk
- pygtk.require('2.0')
+ from gi import require_version
- import gtk
- assert gtk.gtk_version >= (2, 12, 0)
- assert gtk.pygtk_version >= (2, 12, 0)
+ require_version('PangoCairo', '1.0')
+ require_version('Gtk', '3.0')
+ require_version('Gdk', '3.0')
- import gobject
- gobject.threads_init()
+ from gi.repository import Gdk, Gtk, GObject
+
+ GObject.threads_init()
except AssertionError:
- log.error( _("You do not have the required versions of GTK+ and PyGTK installed.") )
- log.error( _('Installed GTK+ version is: %s') % \
- '.'.join([str(n) for n in gtk.gtk_version]) )
- log.error( _('Required GTK+ version is: 2.12.0 or higher') )
- log.error( _('Installed PyGTK version is: %s') % \
- '.'.join([str(n) for n in gtk.pygtk_version]) )
- log.error( _('Required PyGTK version is: 2.12.0 or higher') )
+ log.error( _("You do not have the required versions of GTK+ 3.0 and PyGObject installed.") )
wait_and_exit()
except ImportError:
- log.error( _('Required PyGTK version is: 2.12.0 or higher') )
- log.error( _('No version of PyGTK was found on your system.') )
+ log.error( _('No version of GObject was found on your system.') )
log.error( _('This error might be caused by missing GTK+ libraries.') )
wait_and_exit()
@@ -241,9 +234,13 @@ def run():
# Some languages require a RTL layout
if preferences.prefs['language'] in ('he', 'fa'):
- gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL)
+ Gtk.widget_set_default_direction(Gtk.TextDirection.RTL)
+
+ Gdk.set_program_class(constants.APPNAME)
- gtk.gdk.set_program_class(constants.APPNAME)
+ settings = Gtk.Settings.get_default()
+ # Enable icons for menu items.
+ settings.props.gtk_menu_images = True
from mcomix import main
window = main.MainWindow(fullscreen = opts.fullscreen, is_slideshow = opts.slideshow,
@@ -261,9 +258,10 @@ def run():
pass
signal.signal(signal.SIGCHLD, on_sigchld)
- signal.signal(signal.SIGTERM, lambda: gobject.idle_add(window.terminate_program))
+ for sig in (signal.SIGINT, signal.SIGTERM):
+ signal.signal(sig, lambda signum, stack: GObject.idle_add(window.terminate_program))
try:
- gtk.main()
+ Gtk.main()
except KeyboardInterrupt: # Will not always work because of threading.
window.terminate_program()
diff --git a/mcomix/slideshow.py b/mcomix/slideshow.py
index a501a06..62df301 100644
--- a/mcomix/slideshow.py
+++ b/mcomix/slideshow.py
@@ -1,7 +1,7 @@
"""slideshow.py - Slideshow handler."""
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import GObject
from mcomix.preferences import prefs
@@ -16,13 +16,13 @@ class Slideshow(object):
def _start(self):
if not self._running:
- self._id = gobject.timeout_add(prefs['slideshow delay'], self._next)
+ self._id = GObject.timeout_add(prefs['slideshow delay'], self._next)
self._running = True
self._window.update_title()
def _stop(self):
if self._running:
- gobject.source_remove(self._id)
+ GObject.source_remove(self._id)
self._running = False
self._window.update_title()
@@ -39,11 +39,11 @@ class Slideshow(object):
"""Toggle a slideshow on or off."""
if action.get_active():
self._start()
- self._window.uimanager.get_widget('/Tool/slideshow').set_stock_id( gtk.STOCK_MEDIA_STOP )
+ self._window.uimanager.get_widget('/Tool/slideshow').set_stock_id( Gtk.STOCK_MEDIA_STOP )
self._window.uimanager.get_widget('/Tool/slideshow').set_tooltip_text( _('Stop slideshow') )
else:
self._stop()
- self._window.uimanager.get_widget('/Tool/slideshow').set_stock_id( gtk.STOCK_MEDIA_PLAY )
+ self._window.uimanager.get_widget('/Tool/slideshow').set_stock_id( Gtk.STOCK_MEDIA_PLAY )
self._window.uimanager.get_widget('/Tool/slideshow').set_tooltip_text( _('Start slideshow') )
def is_running(self):
diff --git a/mcomix/status.py b/mcomix/status.py
index 4d9fb18..3d5a137 100644
--- a/mcomix/status.py
+++ b/mcomix/status.py
@@ -1,12 +1,12 @@
"""status.py - Statusbar for main window."""
-import gtk
+from gi.repository import Gdk, Gtk
from mcomix import i18n
from mcomix import constants
from mcomix.preferences import prefs
-class Statusbar(gtk.EventBox):
+class Statusbar(Gtk.EventBox):
SPACING = 5
@@ -15,12 +15,12 @@ class Statusbar(gtk.EventBox):
self._loading = True
- # Status text, page number, file number, resolution, path, filename, filesize
- self.status = gtk.Statusbar()
+ # Status text, page number, file number, resolution, path, filename
+ self.status = Gtk.Statusbar()
self.add(self.status)
# Create popup menu for enabling/disabling status boxes.
- self.ui_manager = gtk.UIManager()
+ self.ui_manager = Gtk.UIManager()
self.tooltipstatus = TooltipStatusHelper(self.ui_manager, self.status)
ui_description = """
<ui>
@@ -36,7 +36,7 @@ class Statusbar(gtk.EventBox):
"""
self.ui_manager.add_ui_from_string(ui_description)
- actiongroup = gtk.ActionGroup('mcomix-statusbar')
+ actiongroup = Gtk.ActionGroup('mcomix-statusbar')
actiongroup.add_toggle_actions([
('pagenumber', None, _('Show page numbers'), None, None,
self.toggle_status_visibility),
@@ -54,7 +54,7 @@ class Statusbar(gtk.EventBox):
# Hook mouse release event
self.connect('button-release-event', self._button_released)
- self.set_events(gtk.gdk.BUTTON_PRESS_MASK|gtk.gdk.BUTTON_RELEASE_MASK)
+ self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK|Gdk.EventMask.BUTTON_RELEASE_MASK)
# Default status information
self._page_info = ''
@@ -138,12 +138,12 @@ class Statusbar(gtk.EventBox):
self.status.push(0, space + text)
def push(self, context_id, message):
- """ Compatibility with gtk.Statusbar. """
+ """ Compatibility with Gtk.Statusbar. """
assert context_id >= 0
self.status.push(context_id + 1, message)
def pop(self, context_id):
- """ Compatibility with gtk.Statusbar. """
+ """ Compatibility with Gtk.Statusbar. """
assert context_id >= 0
self.status.pop(context_id + 1)
@@ -199,8 +199,8 @@ class Statusbar(gtk.EventBox):
""" Triggered when a mouse button is released to open the context
menu. """
if event.button == 3:
- self.ui_manager.get_widget('/Statusbar').popup(None, None, None,
- event.button, event.time)
+ self.ui_manager.get_widget('/Statusbar').popup(None, None, None, None,
+ event.button, event.time)
def _update_sensitivity(self):
""" Updates the action menu's sensitivity based on user preferences. """
@@ -223,7 +223,7 @@ class Statusbar(gtk.EventBox):
class TooltipStatusHelper(object):
- """ Attaches to a L{gtk.UIManager} to provide statusbar tooltips when
+ """ Attaches to a L{Gtk.UIManager} to provide statusbar tooltips when
selecting menu items. """
def __init__(self, uimanager, statusbar):
@@ -236,7 +236,7 @@ class TooltipStatusHelper(object):
""" Connects the widget's selection handlers to the status bar update.
"""
tooltip = action.get_property('tooltip')
- if isinstance(widget, gtk.MenuItem) and tooltip:
+ if isinstance(widget, Gtk.MenuItem) and tooltip:
cid = widget.connect('select', self._on_item_select, tooltip)
cid2 = widget.connect('deselect', self._on_item_deselect)
setattr(widget, 'app::connect-ids', (cid, cid2))
diff --git a/mcomix/thumbbar.py b/mcomix/thumbbar.py
index 5b97b40..cbd5896 100644
--- a/mcomix/thumbbar.py
+++ b/mcomix/thumbbar.py
@@ -1,8 +1,8 @@
"""thumbbar.py - Thumbnail sidebar for main window."""
import urllib
-import gtk
-import gobject
+from gi.repository import GObject, Gdk, GdkPixbuf, Gtk
+import cairo
from mcomix.preferences import prefs
from mcomix import image_tools
@@ -11,7 +11,7 @@ from mcomix import constants
from mcomix import thumbnail_view
-class ThumbnailSidebar(gtk.ScrolledWindow):
+class ThumbnailSidebar(Gtk.ScrolledWindow):
"""A thumbnail sidebar including scrollbar for the main window."""
@@ -27,12 +27,15 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
#: Selected row in treeview
self._currently_selected_row = 0
- self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
self.get_vadjustment().step_increment = 15
self.get_vadjustment().page_increment = 1
+ # Disable stupid overlay scrollbars...
+ if hasattr(self.props, 'overlay_scrolling'):
+ self.props.overlay_scrolling = False
# models - contains data
- self._thumbnail_liststore = gtk.ListStore(int, gtk.gdk.Pixbuf, bool)
+ self._thumbnail_liststore = Gtk.ListStore(int, GdkPixbuf.Pixbuf, bool)
# view - responsible for laying out the columns
self._treeview = thumbnail_view.ThumbnailTreeView(
@@ -41,38 +44,37 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
1, # pixbuf
2, # status
)
- # Whether or not unset_flags(gtk.DOUBLE_BUFFERED) reduces flickering on
- # update seems to depend on various circumstances, including the OS this
- # code is running on, and probably scheduling/threading issues.
- #self._treeview.unset_flags(gtk.DOUBLE_BUFFERED)
self._treeview.set_headers_visible(False)
self._treeview.generate_thumbnail = self._generate_thumbnail
+ self._treeview.set_activate_on_single_click(True)
self._treeview.connect_after('drag_begin', self._drag_begin)
self._treeview.connect('drag_data_get', self._drag_data_get)
- self._treeview.connect('cursor-changed', self._cursor_changed_event)
+ self._treeview.connect('row-activated', self._row_activated_event)
+ self._treeview.connect('button_press_event', self._mouse_press_event)
+
# enable drag and dropping of images from thumbnail bar to some file
# manager
- self._treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
- [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY)
+ self._treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
+ [('text/uri-list', 0, 0)], Gdk.DragAction.COPY)
# Page column
- self._thumbnail_page_treeviewcolumn = gtk.TreeViewColumn(None)
+ self._thumbnail_page_treeviewcolumn = Gtk.TreeViewColumn(None)
self._treeview.append_column(self._thumbnail_page_treeviewcolumn)
- self._text_cellrenderer = gtk.CellRendererText()
+ self._text_cellrenderer = Gtk.CellRendererText()
# Right align page numbers.
self._text_cellrenderer.set_property('xalign', 1.0)
- self._thumbnail_page_treeviewcolumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ self._thumbnail_page_treeviewcolumn.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
self._thumbnail_page_treeviewcolumn.pack_start(self._text_cellrenderer, False)
self._thumbnail_page_treeviewcolumn.add_attribute(self._text_cellrenderer, 'text', 0)
self._thumbnail_page_treeviewcolumn.set_visible(False)
# Pixbuf column
- self._thumbnail_image_treeviewcolumn = gtk.TreeViewColumn(None)
+ self._thumbnail_image_treeviewcolumn = Gtk.TreeViewColumn(None)
self._treeview.append_column(self._thumbnail_image_treeviewcolumn)
- self._pixbuf_cellrenderer = gtk.CellRendererPixbuf()
- self._thumbnail_image_treeviewcolumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ self._pixbuf_cellrenderer = Gtk.CellRendererPixbuf()
+ self._thumbnail_image_treeviewcolumn.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
self._thumbnail_image_treeviewcolumn.set_fixed_width(self._pixbuf_size)
self._thumbnail_image_treeviewcolumn.pack_start(self._pixbuf_cellrenderer, True)
self._thumbnail_image_treeviewcolumn.add_attribute(self._pixbuf_cellrenderer, 'pixbuf', 1)
@@ -95,13 +97,13 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
number_of_pages = self._window.imagehandler.get_number_of_pages()
number_of_digits = tools.number_of_digits(number_of_pages)
self._text_cellrenderer.set_property('width-chars', number_of_digits + 1)
- x, y, w, h = self._text_cellrenderer.get_size(self._treeview, None)
+ w = self._text_cellrenderer.get_preferred_size(self._treeview)[1].width
self._thumbnail_page_treeviewcolumn.set_fixed_width(w)
self._thumbnail_page_treeviewcolumn.set_visible(visible)
def get_width(self):
"""Return the width in pixels of the ThumbnailSidebar."""
- return self.size_request()[0]
+ return self.size_request().width
def show(self, *args):
"""Show the ThumbnailSidebar."""
@@ -134,17 +136,16 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
self.set_thumbnail_background(colour)
# Force a redraw of the widget.
- self.queue_draw()
+ self._treeview.queue_draw()
- def set_thumbnail_background(self, colour):
+ def set_thumbnail_background(self, color):
- color = gtk.gdk.Color(colour[0], colour[1], colour[2])
- self._pixbuf_cellrenderer.set_property('cell-background-gdk',
- color)
- self._text_cellrenderer.set_property('background-gdk',
- color)
- self._text_cellrenderer.set_property('foreground-gdk',
- image_tools.text_color_for_background_color(colour))
+ rgba = Gdk.RGBA(*image_tools.color_to_floats_rgba(color))
+ self._pixbuf_cellrenderer.set_property('cell-background-rgba', rgba)
+ self._text_cellrenderer.set_property('background-rgba', rgba)
+ fg_color = image_tools.text_color_for_background_color(color)
+ fg_rgba = Gdk.RGBA(*(fg_color.to_floats() + (1.0,)))
+ self._text_cellrenderer.set_property('foreground-rgba', fg_rgba)
@property
def _pixbuf_size(self):
@@ -207,23 +208,20 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
except IndexError:
return 0
- def _cursor_changed_event(self, treeview, *args):
+ def _row_activated_event(self, treeview, path, column):
"""Handle events due to changed thumbnail selection."""
+ selected_row = self._get_selected_row()
+ self._set_selected_row(selected_row, scroll=False)
+ self._window.set_page(selected_row + 1)
- if not self._loaded or not self._treeview.get_realized():
- # Skip event processing before widget is actually ready
- return
-
- if not self._window.was_out_of_focus:
- selected_row = self._get_selected_row()
- self._set_selected_row(selected_row, scroll=False)
- self._window.set_page(selected_row + 1)
- else:
+ def _mouse_press_event(self, widget, event):
+ if self._window.was_out_of_focus:
# if the window was out of focus and the user clicks on
# the thumbbar then do not select that page because they
# more than likely have many pages open and are simply trying
# to give mcomix focus again
- self._set_selected_row(self._currently_selected_row, scroll=False)
+ return True
+ return False
def _drag_data_get(self, treeview, context, selection, *args):
"""Put the URI of the selected file into the SelectionData, so that
@@ -241,19 +239,18 @@ class ThumbnailSidebar(gtk.ScrolledWindow):
might actually see where we are dropping!).
"""
path = treeview.get_cursor()[0]
- pixmap = treeview.create_row_drag_icon(path)
-
- # context.set_icon_pixmap() seems to cause crashes, so we do a
- # quick and dirty conversion to pixbuf.
- pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- *pixmap.get_size())
- pointer = pointer.get_from_drawable(pixmap, treeview.get_colormap(),
- 0, 0, 0, 0, *pixmap.get_size())
- context.set_icon_pixbuf(pointer, -5, -5)
+ surface = treeview.create_row_drag_icon(path)
+ # Because of course a cairo.Win32Surface does not have
+ # get_width/get_height, that would be to easy...
+ cr = cairo.Context(surface)
+ x1, y1, x2, y2 = cr.clip_extents()
+ width, height = x2 - x1, y2 - y1
+ pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, width, height)
+ Gtk.drag_set_icon_pixbuf(context, pixbuf, -5, -5)
def _get_empty_thumbnail(self):
""" Create an empty filler pixmap. """
- pixbuf = gtk.gdk.Pixbuf(colorspace=gtk.gdk.COLORSPACE_RGB,
+ pixbuf = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
has_alpha=True,
bits_per_sample=8,
width=self._pixbuf_size,
diff --git a/mcomix/thumbnail_tools.py b/mcomix/thumbnail_tools.py
index 71700d7..e157a5d 100644
--- a/mcomix/thumbnail_tools.py
+++ b/mcomix/thumbnail_tools.py
@@ -214,7 +214,12 @@ class Thumbnailer(object):
if os.path.isfile(thumbpath):
os.remove(thumbpath)
- pixbuf.save(thumbpath, 'png', tEXt_data)
+ option_keys = []
+ option_values = []
+ for key, value in tEXt_data.items():
+ option_keys.append(key)
+ option_values.append(value)
+ pixbuf.savev(thumbpath, 'png', option_keys, option_values)
os.chmod(thumbpath, 0600)
except Exception, ex:
diff --git a/mcomix/thumbnail_view.py b/mcomix/thumbnail_view.py
index 899e0bb..c7c5b08 100644
--- a/mcomix/thumbnail_view.py
+++ b/mcomix/thumbnail_view.py
@@ -1,16 +1,16 @@
-""" gtk.IconView subclass for dynamically generated thumbnails. """
+""" Gtk.IconView subclass for dynamically generated thumbnails. """
import Queue
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import GObject
from mcomix.preferences import prefs
from mcomix.worker_thread import WorkerThread
class ThumbnailViewBase(object):
- """ This class provides shared functionality for gtk.TreeView and
- gtk.IconView. Instantiating this class directly is *impossible*,
+ """ This class provides shared functionality for Gtk.TreeView and
+ Gtk.IconView. Instantiating this class directly is *impossible*,
as it depends on methods provided by the view classes. """
def __init__(self, uid_column, pixbuf_column, status_column):
@@ -39,7 +39,7 @@ class ThumbnailViewBase(object):
raise NotImplementedError()
def get_visible_range(self):
- """ See L{gtk.IconView.get_visible_range}. """
+ """ See L{Gtk.IconView.get_visible_range}. """
raise NotImplementedError()
def stop_update(self):
@@ -88,7 +88,7 @@ class ThumbnailViewBase(object):
uid, iter = order
pixbuf = self.generate_thumbnail(uid)
if pixbuf is not None:
- gobject.idle_add(self._pixbuf_finished, iter, pixbuf)
+ GObject.idle_add(self._pixbuf_finished, iter, pixbuf)
def _pixbuf_finished(self, iter, pixbuf):
""" Executed when a pixbuf was created, to actually insert the pixbuf
@@ -104,29 +104,29 @@ class ThumbnailViewBase(object):
# Remove this idle handler.
return 0
-class ThumbnailIconView(gtk.IconView, ThumbnailViewBase):
+class ThumbnailIconView(Gtk.IconView, ThumbnailViewBase):
def __init__(self, model, uid_column, pixbuf_column, status_column):
- assert gtk.TREE_MODEL_ITERS_PERSIST == (model.get_flags() & gtk.TREE_MODEL_ITERS_PERSIST)
+ assert 0 != (model.get_flags() & Gtk.TreeModelFlags.ITERS_PERSIST)
super(ThumbnailIconView, self).__init__(model)
ThumbnailViewBase.__init__(self, uid_column, pixbuf_column, status_column)
self.set_pixbuf_column(pixbuf_column)
# Connect events
- self.connect('expose-event', self.draw_thumbnails_on_screen)
+ self.connect('draw', self.draw_thumbnails_on_screen)
def get_visible_range(self):
- return gtk.IconView.get_visible_range(self)
+ return Gtk.IconView.get_visible_range(self)
-class ThumbnailTreeView(gtk.TreeView, ThumbnailViewBase):
+class ThumbnailTreeView(Gtk.TreeView, ThumbnailViewBase):
def __init__(self, model, uid_column, pixbuf_column, status_column):
- assert gtk.TREE_MODEL_ITERS_PERSIST == (model.get_flags() & gtk.TREE_MODEL_ITERS_PERSIST)
+ assert 0 != (model.get_flags() & Gtk.TreeModelFlags.ITERS_PERSIST)
super(ThumbnailTreeView, self).__init__(model)
ThumbnailViewBase.__init__(self, uid_column, pixbuf_column, status_column)
# Connect events
- self.connect('expose-event', self.draw_thumbnails_on_screen)
+ self.connect('draw', self.draw_thumbnails_on_screen)
def get_visible_range(self):
- return gtk.TreeView.get_visible_range(self)
+ return Gtk.TreeView.get_visible_range(self)
# vim: expandtab:sw=4:ts=4
diff --git a/mcomix/ui.py b/mcomix/ui.py
index 0e61411..e4d483f 100644
--- a/mcomix/ui.py
+++ b/mcomix/ui.py
@@ -1,7 +1,7 @@
"""ui.py - UI definitions for main window.
"""
-import gtk
+from gi.repository import Gtk
from mcomix import bookmark_menu
from mcomix import openwith_menu
@@ -16,7 +16,7 @@ from mcomix import file_chooser_main_dialog
from mcomix.preferences import prefs
from mcomix.library import main_dialog as library_main_dialog
-class MainUI(gtk.UIManager):
+class MainUI(Gtk.UIManager):
def __init__(self, window):
super(MainUI, self).__init__()
@@ -30,48 +30,48 @@ class MainUI(gtk.UIManager):
# ----------------------------------------------------------------
# Create actions for the menus.
# ----------------------------------------------------------------
- self._actiongroup = gtk.ActionGroup('mcomix-main')
+ self._actiongroup = Gtk.ActionGroup('mcomix-main')
self._actiongroup.add_actions([
- ('copy_page', gtk.STOCK_COPY, _('_Copy'),
+ ('copy_page', Gtk.STOCK_COPY, _('_Copy'),
None, _('Copies the current page to clipboard.'),
window.clipboard.copy_page),
- ('delete', gtk.STOCK_DELETE, _('_Delete'),
+ ('delete', Gtk.STOCK_DELETE, _('_Delete'),
None, _('Deletes the current file or archive from disk.'),
window.delete),
- ('next_page', gtk.STOCK_GO_FORWARD, _('_Next page'),
+ ('next_page', Gtk.STOCK_GO_FORWARD, _('_Next page'),
None, _('Next page'), _action_lambda(window.flip_page, +1)),
- ('previous_page', gtk.STOCK_GO_BACK, _('_Previous page'),
+ ('previous_page', Gtk.STOCK_GO_BACK, _('_Previous page'),
None, _('Previous page'), _action_lambda(window.flip_page, -1)),
- ('first_page', gtk.STOCK_GOTO_FIRST, _('_First page'),
+ ('first_page', Gtk.STOCK_GOTO_FIRST, _('_First page'),
None, _('First page'), _action_lambda(window.first_page)),
- ('last_page', gtk.STOCK_GOTO_LAST, _('_Last page'),
+ ('last_page', Gtk.STOCK_GOTO_LAST, _('_Last page'),
None, _('Last page'), _action_lambda(window.last_page)),
- ('go_to', gtk.STOCK_JUMP_TO, _('_Go to page...'),
+ ('go_to', Gtk.STOCK_JUMP_TO, _('_Go to page...'),
None, _('Go to page...'), window.page_select),
- ('refresh_archive', gtk.STOCK_REFRESH, _('Re_fresh'),
+ ('refresh_archive', Gtk.STOCK_REFRESH, _('Re_fresh'),
None, _('Reloads the currently opened files or archive.'),
window.filehandler.refresh_file),
- ('next_archive', gtk.STOCK_MEDIA_NEXT, _('Next _archive'),
+ ('next_archive', Gtk.STOCK_MEDIA_NEXT, _('Next _archive'),
None, _('Next archive'), window.filehandler._open_next_archive),
- ('previous_archive', gtk.STOCK_MEDIA_PREVIOUS, _('Previous a_rchive'),
+ ('previous_archive', Gtk.STOCK_MEDIA_PREVIOUS, _('Previous a_rchive'),
None, _('Previous archive'), window.filehandler._open_previous_archive),
- ('next_directory', gtk.STOCK_REDO, _('Next directory'),
+ ('next_directory', Gtk.STOCK_REDO, _('Next directory'),
None, _('Next directory'), window.filehandler.open_next_directory),
- ('previous_directory', gtk.STOCK_UNDO, _('Previous directory'),
+ ('previous_directory', Gtk.STOCK_UNDO, _('Previous directory'),
None, _('Previous directory'), window.filehandler.open_previous_directory),
- ('zoom_in', gtk.STOCK_ZOOM_IN, _('Zoom _In'),
+ ('zoom_in', Gtk.STOCK_ZOOM_IN, _('Zoom _In'),
None, None, window.manual_zoom_in),
- ('zoom_out', gtk.STOCK_ZOOM_OUT, _('Zoom _Out'),
+ ('zoom_out', Gtk.STOCK_ZOOM_OUT, _('Zoom _Out'),
None, None, window.manual_zoom_out),
- ('zoom_original', gtk.STOCK_ZOOM_100, _('_Normal Size'),
+ ('zoom_original', Gtk.STOCK_ZOOM_100, _('_Normal Size'),
None, None, window.manual_zoom_original),
- ('minimize', gtk.STOCK_LEAVE_FULLSCREEN, _('Mi_nimize'),
+ ('minimize', Gtk.STOCK_LEAVE_FULLSCREEN, _('Mi_nimize'),
None, None, window.minimize),
- ('close', gtk.STOCK_CLOSE, _('_Close'),
+ ('close', Gtk.STOCK_CLOSE, _('_Close'),
None, _('Closes all opened files.'), _action_lambda(window.filehandler.close_file)),
- ('quit', gtk.STOCK_QUIT, _('_Quit'),
+ ('quit', Gtk.STOCK_QUIT, _('_Quit'),
None, None, window.close_program),
- ('save_and_quit', gtk.STOCK_QUIT, _('_Save and quit'),
+ ('save_and_quit', Gtk.STOCK_QUIT, _('_Save and quit'),
None, _('Quits and restores the currently opened file next time the program starts.'),
window.save_and_terminate_program),
('rotate_90', 'mcomix-rotate-90', _('_Rotate 90 degrees CW'),
@@ -84,21 +84,21 @@ class MainUI(gtk.UIManager):
None, None, window.flip_horizontally),
('flip_vert', 'mcomix-flip-vertical', _('Flip _vertically'),
None, None, window.flip_vertically),
- ('extract_page', gtk.STOCK_SAVE_AS, _('Save _As'),
+ ('extract_page', Gtk.STOCK_SAVE_AS, _('Save _As'),
None, None, window.extract_page),
('menu_zoom', 'mcomix-zoom', _('_Zoom')),
- ('menu_recent', gtk.STOCK_DND_MULTIPLE, _('_Recent')),
+ ('menu_recent', Gtk.STOCK_FILE, _('_Recent')),
('menu_bookmarks_popup', 'comix-add-bookmark', _('_Bookmarks')),
('menu_bookmarks', None, _('_Bookmarks')),
('menu_toolbars', None, _('T_oolbars')),
('menu_edit', None, _('_Edit')),
- ('menu_open_with', gtk.STOCK_OPEN, _('Open _with'), ''),
- ('menu_open_with_popup', gtk.STOCK_OPEN, _('Open _with'), ''),
+ ('menu_open_with', Gtk.STOCK_OPEN, _('Open _with'), ''),
+ ('menu_open_with_popup', Gtk.STOCK_OPEN, _('Open _with'), ''),
('menu_file', None, _('_File')),
('menu_view', None, _('_View')),
('menu_view_popup', 'comix-image', _('_View')),
('menu_go', None, _('_Go')),
- ('menu_go_popup', gtk.STOCK_GO_FORWARD, _('_Go')),
+ ('menu_go_popup', Gtk.STOCK_GO_FORWARD, _('_Go')),
('menu_tools', None, _('_Tools')),
('menu_help', None, _('_Help')),
('menu_transform', 'mcomix-transform', _('_Transform image')),
@@ -108,7 +108,7 @@ class MainUI(gtk.UIManager):
('expander', None, None, None, None, None)])
self._actiongroup.add_toggle_actions([
- ('fullscreen', gtk.STOCK_FULLSCREEN, _('_Fullscreen'),
+ ('fullscreen', Gtk.STOCK_FULLSCREEN, _('_Fullscreen'),
None, _('Fullscreen mode'), window.change_fullscreen),
('double_page', 'mcomix-double-page', _('_Double page mode'),
None, _('Double page mode'), window.change_double_page),
@@ -126,12 +126,12 @@ class MainUI(gtk.UIManager):
None, None, window.change_hide_all),
('manga_mode', 'mcomix-manga', _('_Manga mode'),
None, _('Manga mode'), window.change_manga_mode),
- ('invert_scroll', gtk.STOCK_UNDO, _('Invert smart scroll'),
+ ('invert_scroll', Gtk.STOCK_UNDO, _('Invert smart scroll'),
None, _('Invert smart scrolling direction.'), window.change_invert_scroll),
('keep_transformation', None, _('_Keep transformation'),
None, _('Keeps the currently selected transformation for the next pages.'),
window.change_keep_transformation),
- ('slideshow', gtk.STOCK_MEDIA_PLAY, _('Start _slideshow'),
+ ('slideshow', Gtk.STOCK_MEDIA_PLAY, _('Start _slideshow'),
None, _('Start slideshow'), window.slideshow.toggle),
('lens', 'mcomix-lens', _('Magnifying _lens'),
None, _('Magnifying lens'), window.lens.toggle),
@@ -169,7 +169,7 @@ class MainUI(gtk.UIManager):
prefs['auto rotate depending on size'], window.change_autorotation)
self._actiongroup.add_actions([
- ('about', gtk.STOCK_ABOUT, _('_About'),
+ ('about', Gtk.STOCK_ABOUT, _('_About'),
None, None, dialog_handler.open_dialog)], (window, 'about-dialog'))
self._actiongroup.add_actions([
@@ -177,19 +177,19 @@ class MainUI(gtk.UIManager):
None, None, dialog_handler.open_dialog)], (window, 'comments-dialog'))
self._actiongroup.add_actions([
- ('properties', gtk.STOCK_PROPERTIES, _('Proper_ties'),
+ ('properties', Gtk.STOCK_PROPERTIES, _('Proper_ties'),
None, None, dialog_handler.open_dialog)], (window,'properties-dialog'))
self._actiongroup.add_actions([
- ('preferences', gtk.STOCK_PREFERENCES, _('Pr_eferences'),
- None, None, preferences_dialog.open_dialog)], (window))
+ ('preferences', Gtk.STOCK_PREFERENCES, _('Pr_eferences'),
+ None, None, preferences_dialog.open_dialog)], window)
# Some actions added separately since they need extra arguments.
self._actiongroup.add_actions([
- ('edit_archive', gtk.STOCK_EDIT, _('_Edit archive...'),
+ ('edit_archive', Gtk.STOCK_EDIT, _('_Edit archive...'),
None, _('Opens the archive editor.'),
edit_dialog.open_dialog),
- ('open', gtk.STOCK_OPEN, _('_Open...'),
+ ('open', Gtk.STOCK_OPEN, _('_Open...'),
None, None, file_chooser_main_dialog.open_main_filechooser_dialog),
('enhance_image', 'mcomix-enhance-image', _('En_hance image...'),
None, None, enhance_dialog.open_dialog)], window)
@@ -199,7 +199,7 @@ class MainUI(gtk.UIManager):
None, None, library_main_dialog.open_dialog)], window)
# fix some gtk magic: removing unreqired accelerators
- gtk.accel_map_change_entry('<Actions>/mcomix-main/%s' % 'close', 0, 0, True)
+ Gtk.AccelMap.change_entry('<Actions>/mcomix-main/%s' % 'close', 0, 0, True)
ui_description = """
<ui>
diff --git a/setup.py b/setup.py
index 01ffe93..ea87667 100755
--- a/setup.py
+++ b/setup.py
@@ -17,6 +17,7 @@ import setuptools
from mcomix import constants
+
def get_data_patterns(directory, *patterns):
""" Build a list of patterns for all subdirectories of <directory>
to be passed into package_data. """
@@ -44,11 +45,10 @@ images.extend([ os.path.basename(img)
setuptools.setup(
name = constants.APPNAME.lower(),
version = constants.VERSION,
- packages = ['mcomix', 'mcomix.archive', 'mcomix.library',
- 'mcomix.messages', 'mcomix.images', 'mcomix.win32'],
+ packages = ['mcomix', 'mcomix.archive', 'mcomix.library', 'mcomix.win32'],
package_data = {
- 'mcomix.messages' : get_data_patterns('mcomix/messages', '*.mo'),
- 'mcomix.images' : images },
+ 'mcomix' : get_data_patterns('mcomix/messages', '*.mo') + images,
+ },
entry_points = {
'console_scripts' : [ 'mcomix = mcomix.run:run' ],
'setuptools.installation': [ 'eggsecutable=mcomix.run:run' ],
diff --git a/test/test_image_tools.py b/test/test_image_tools.py
index a1f6c16..7558545 100644
--- a/test/test_image_tools.py
+++ b/test/test_image_tools.py
@@ -5,7 +5,7 @@ import os
import sys
import tempfile
-import gtk, gobject
+from gi.repository import GdkPixbuf, GObject
from collections import namedtuple
from PIL import Image, ImageDraw
@@ -81,8 +81,9 @@ def get_image_path(basename):
return get_testfile_path('images', basename)
def new_pixbuf(size, with_alpha, fill_colour):
- pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,
- with_alpha, 8, size[0], size[1])
+ pixbuf = GdkPixbuf.Pixbuf.new(colorspace=GdkPixbuf.Colorspace.RGB,
+ has_alpha=with_alpha, bits_per_sample=8,
+ width=size[0], height=size[1])
pixbuf.fill(fill_colour)
return pixbuf
@@ -128,9 +129,9 @@ def hexdump(data, group_size=4):
return [line for line in xhexdump(data, group_size=group_size)]
def composite_image(im1, im2):
- if isinstance(im1, gtk.gdk.Pixbuf):
+ if isinstance(im1, GdkPixbuf.Pixbuf):
im1 = image_tools.pixbuf_to_pil(im1)
- if isinstance(im2, gtk.gdk.Pixbuf):
+ if isinstance(im2, GdkPixbuf.Pixbuf):
im2 = image_tools.pixbuf_to_pil(im2)
im = Image.new('RGBA',
(im1.size[0] + im2.size[0],
@@ -167,7 +168,7 @@ class ImageToolsTest(object):
'diff': diff_fmt % args,
})
def info(im):
- if isinstance(im, gtk.gdk.Pixbuf):
+ if isinstance(im, GdkPixbuf.Pixbuf):
width, stride = im.get_width(), im.get_rowstride()
line_size = width * im.get_n_channels()
if stride == line_size:
@@ -182,6 +183,8 @@ class ImageToolsTest(object):
break
pixels += line
leftover = io.read(stride - line_size)
+ if not leftover:
+ break
assert len(leftover) == (stride - line_size)
mode = 'RGBA' if im.get_has_alpha() else 'RGB'
return mode, (im.get_width(), im.get_height()), pixels
@@ -250,7 +253,7 @@ class ImageToolsTest(object):
if self.use_pil:
exception = IOError
else:
- exception = gobject.GError
+ exception = GObject.GError
self.assertRaises(exception, image_tools.load_pixbuf, os.devnull)
def test_load_pixbuf_size_basic(self):
@@ -324,7 +327,7 @@ class ImageToolsTest(object):
if self.use_pil:
exception = IOError
else:
- exception = gobject.GError
+ exception = GObject.GError
self.assertRaises(exception, image_tools.load_pixbuf_size, os.devnull, 50, 50)
# Expose a rounding error bug in load_pixbuf_size.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment