1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
4 # Copyright (C) 2011-2012 Johan Dahlin <johan@gnome.org>
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 PyGTK compatibility layer.
24 This modules goes a little bit longer to maintain PyGTK compatibility than
25 the normal overrides system.
27 It is recommended to not depend on this layer, but only use it as an
28 intermediate step when porting your application to PyGI.
30 Compatibility might never be 100%, but the aim is to make it possible to run
31 a well behaved PyGTK application mostly unmodified on top of PyGI.
39 from gi
.repository
import GObject
40 from gi
import _compat
46 _enabled_registry
= {}
49 def _patch(obj
, name
, new_value
):
50 old_value
= getattr(obj
, name
, _unset
)
51 setattr(obj
, name
, new_value
)
52 _patches
.append((obj
, name
, old_value
))
55 def _patch_module(name
, new_value
):
56 old_value
= sys
.modules
.get(name
, _unset
)
57 sys
.modules
[name
] = new_value
58 _module_patches
.append((name
, old_value
))
61 def _install_enums(module
, dest
=None, strip
=''):
64 modname
= dest
.__name
__.rsplit('.', 1)[1].upper()
65 for attr
in dir(module
):
67 obj
= getattr(module
, attr
, None)
71 if issubclass(obj
, GObject
.GEnum
):
72 for value
, enum
in obj
.__enum
_values
__.items():
73 name
= enum
.value_name
74 name
= name
.replace(modname
+ '_', '')
75 if strip
and name
.startswith(strip
):
76 name
= name
[len(strip
):]
77 _patch(dest
, name
, enum
)
81 if issubclass(obj
, GObject
.GFlags
):
82 for value
, flag
in obj
.__flags
_values
__.items():
84 name
= flag
.value_names
[-1].replace(modname
+ '_', '')
86 # FIXME: this happens for some large flags which do not
87 # fit into a long on 32 bit systems
89 _patch(dest
, name
, flag
)
94 def _check_enabled(name
, version
=None):
95 """Returns True in case it is already enabled"""
97 if name
in _enabled_registry
:
98 enabled_version
= _enabled_registry
[name
]
99 if enabled_version
!= version
:
101 "%r already enabled with different version (%r)" % (
102 name
, enabled_version
))
105 _enabled_registry
[name
] = version
110 if _check_enabled(""):
114 from gi
.repository
import GLib
115 _patch_module('glib', GLib
)
118 from gi
.repository
import GObject
119 _patch_module('gobject', GObject
)
120 from gi
import _propertyhelper
121 _patch_module('gobject.propertyhelper', _propertyhelper
)
124 from gi
.repository
import Gio
125 _patch_module('gio', Gio
)
129 """Reverse all effects of the enable_xxx() calls except for
130 require_version() calls and imports.
133 _enabled_registry
.clear()
135 for obj
, name
, old_value
in reversed(_patches
):
136 if old_value
is _unset
:
139 # try if deleting is enough (for override proxies)
141 if getattr(obj
, name
, _unset
) is not old_value
:
142 setattr(obj
, name
, old_value
)
145 for name
, old_value
in reversed(_module_patches
):
146 if old_value
is _unset
:
147 del sys
.modules
[name
]
149 sys
.modules
[name
] = old_value
150 del _module_patches
[:]
154 sys
.setdefaultencoding('ascii')
157 def enable_gtk(version
='3.0'):
158 if _check_enabled("gtk", version
):
162 raise ValueError("version 4.0 not supported")
164 # set the default encoding like PyGTK
167 sys
.setdefaultencoding('utf-8')
170 gi
.require_version('Atk', '1.0')
171 from gi
.repository
import Atk
172 _patch_module('atk', Atk
)
176 gi
.require_version('Pango', '1.0')
177 from gi
.repository
import Pango
178 _patch_module('pango', Pango
)
179 _install_enums(Pango
)
182 gi
.require_version('PangoCairo', '1.0')
183 from gi
.repository
import PangoCairo
184 _patch_module('pangocairo', PangoCairo
)
187 gi
.require_version('Gdk', version
)
188 gi
.require_version('GdkPixbuf', '2.0')
189 from gi
.repository
import Gdk
190 from gi
.repository
import GdkPixbuf
191 _patch_module('gtk.gdk', Gdk
)
193 _install_enums(GdkPixbuf
, dest
=Gdk
)
194 _patch(Gdk
, "_2BUTTON_PRESS", 5)
195 _patch(Gdk
, "BUTTON_PRESS", 4)
197 _patch(Gdk
, "screen_get_default", Gdk
.Screen
.get_default
)
198 _patch(Gdk
, "Pixbuf", GdkPixbuf
.Pixbuf
)
199 _patch(Gdk
, "PixbufLoader", GdkPixbuf
.PixbufLoader
.new_with_type
)
200 _patch(Gdk
, "pixbuf_new_from_data", GdkPixbuf
.Pixbuf
.new_from_data
)
201 _patch(Gdk
, "pixbuf_new_from_file", GdkPixbuf
.Pixbuf
.new_from_file
)
203 _patch(Gdk
, "pixbuf_new_from_file_at_scale", GdkPixbuf
.Pixbuf
.new_from_file_at_scale
)
204 except AttributeError:
206 _patch(Gdk
, "pixbuf_new_from_file_at_size", GdkPixbuf
.Pixbuf
.new_from_file_at_size
)
207 _patch(Gdk
, "pixbuf_new_from_inline", GdkPixbuf
.Pixbuf
.new_from_inline
)
208 _patch(Gdk
, "pixbuf_new_from_stream", GdkPixbuf
.Pixbuf
.new_from_stream
)
209 _patch(Gdk
, "pixbuf_new_from_stream_at_scale", GdkPixbuf
.Pixbuf
.new_from_stream_at_scale
)
210 _patch(Gdk
, "pixbuf_new_from_xpm_data", GdkPixbuf
.Pixbuf
.new_from_xpm_data
)
211 _patch(Gdk
, "pixbuf_get_file_info", GdkPixbuf
.Pixbuf
.get_file_info
)
213 orig_get_formats
= GdkPixbuf
.Pixbuf
.get_formats
216 formats
= orig_get_formats()
219 def make_dict(format_
):
221 result
['description'] = format_
.get_description()
222 result
['name'] = format_
.get_name()
223 result
['mime_types'] = format_
.get_mime_types()
224 result
['extensions'] = format_
.get_extensions()
227 for format_
in formats
:
228 result
.append(make_dict(format_
))
231 _patch(Gdk
, "pixbuf_get_formats", get_formats
)
233 orig_get_frame_extents
= Gdk
.Window
.get_frame_extents
235 def get_frame_extents(window
):
238 rect
= Gdk
.Rectangle(0, 0, 0, 0)
240 rect
= Gdk
.Rectangle()
241 orig_get_frame_extents(window
, rect
)
243 rect
= orig_get_frame_extents(window
)
245 _patch(Gdk
.Window
, "get_frame_extents", get_frame_extents
)
247 orig_get_origin
= Gdk
.Window
.get_origin
249 def get_origin(self
):
250 return orig_get_origin(self
)[1:]
251 _patch(Gdk
.Window
, "get_origin", get_origin
)
253 _patch(Gdk
, "screen_width", Gdk
.Screen
.width
)
254 _patch(Gdk
, "screen_height", Gdk
.Screen
.height
)
256 orig_gdk_window_get_geometry
= Gdk
.Window
.get_geometry
258 def gdk_window_get_geometry(window
):
259 return orig_gdk_window_get_geometry(window
) + (window
.get_visual().get_best_depth(),)
260 _patch(Gdk
.Window
, "get_geometry", gdk_window_get_geometry
)
263 gi
.require_version('Gtk', version
)
264 from gi
.repository
import Gtk
265 _patch_module('gtk', Gtk
)
266 _patch(Gtk
, "gdk", Gdk
)
268 _patch(Gtk
, "pygtk_version", (2, 99, 0))
270 _patch(Gtk
, "gtk_version", (Gtk
.MAJOR_VERSION
,
277 def set_tool_item_type(menuaction
, gtype
):
278 warnings
.warn('set_tool_item_type() is not supported',
279 gi
.PyGIDeprecationWarning
, stacklevel
=2)
280 _patch(Gtk
.Action
, "set_tool_item_type", classmethod(set_tool_item_type
))
284 orig_Alignment
= Gtk
.Alignment
286 class Alignment(orig_Alignment
):
287 def __init__(self
, xalign
=0.0, yalign
=0.0, xscale
=0.0, yscale
=0.0):
288 orig_Alignment
.__init
__(self
)
289 self
.props
.xalign
= xalign
290 self
.props
.yalign
= yalign
291 self
.props
.xscale
= xscale
292 self
.props
.yscale
= yscale
294 _patch(Gtk
, "Alignment", Alignment
)
298 orig_pack_end
= Gtk
.Box
.pack_end
300 def pack_end(self
, child
, expand
=True, fill
=True, padding
=0):
301 orig_pack_end(self
, child
, expand
, fill
, padding
)
302 _patch(Gtk
.Box
, "pack_end", pack_end
)
304 orig_pack_start
= Gtk
.Box
.pack_start
306 def pack_start(self
, child
, expand
=True, fill
=True, padding
=0):
307 orig_pack_start(self
, child
, expand
, fill
, padding
)
308 _patch(Gtk
.Box
, "pack_start", pack_start
)
312 orig_tree_view_column_pack_end
= Gtk
.TreeViewColumn
.pack_end
314 def tree_view_column_pack_end(self
, cell
, expand
=True):
315 orig_tree_view_column_pack_end(self
, cell
, expand
)
316 _patch(Gtk
.TreeViewColumn
, "pack_end", tree_view_column_pack_end
)
318 orig_tree_view_column_pack_start
= Gtk
.TreeViewColumn
.pack_start
320 def tree_view_column_pack_start(self
, cell
, expand
=True):
321 orig_tree_view_column_pack_start(self
, cell
, expand
)
322 _patch(Gtk
.TreeViewColumn
, "pack_start", tree_view_column_pack_start
)
326 orig_cell_pack_end
= Gtk
.CellLayout
.pack_end
328 def cell_pack_end(self
, cell
, expand
=True):
329 orig_cell_pack_end(self
, cell
, expand
)
330 _patch(Gtk
.CellLayout
, "pack_end", cell_pack_end
)
332 orig_cell_pack_start
= Gtk
.CellLayout
.pack_start
334 def cell_pack_start(self
, cell
, expand
=True):
335 orig_cell_pack_start(self
, cell
, expand
)
336 _patch(Gtk
.CellLayout
, "pack_start", cell_pack_start
)
338 orig_set_cell_data_func
= Gtk
.CellLayout
.set_cell_data_func
340 def set_cell_data_func(self
, cell
, func
, user_data
=_unset
):
342 if args
[-1] == _unset
:
345 orig_set_cell_data_func(self
, cell
, callback
, user_data
)
346 _patch(Gtk
.CellLayout
, "set_cell_data_func", set_cell_data_func
)
350 class GenericCellRenderer(Gtk
.CellRenderer
):
352 _patch(Gtk
, "GenericCellRenderer", GenericCellRenderer
)
356 orig_combo_row_separator_func
= Gtk
.ComboBox
.set_row_separator_func
358 def combo_row_separator_func(self
, func
, user_data
=_unset
):
360 if args
[-1] == _unset
:
363 orig_combo_row_separator_func(self
, callback
, user_data
)
364 _patch(Gtk
.ComboBox
, "set_row_separator_func", combo_row_separator_func
)
368 class ComboBoxEntry(Gtk
.ComboBox
):
369 def __init__(self
, **kwds
):
370 Gtk
.ComboBox
.__init
__(self
, has_entry
=True, **kwds
)
372 def set_text_column(self
, text_column
):
373 self
.set_entry_text_column(text_column
)
375 def get_text_column(self
):
376 return self
.get_entry_text_column()
377 _patch(Gtk
, "ComboBoxEntry", ComboBoxEntry
)
379 def combo_box_entry_new():
380 return Gtk
.ComboBoxEntry()
381 _patch(Gtk
, "combo_box_entry_new", combo_box_entry_new
)
383 def combo_box_entry_new_with_model(model
):
384 return Gtk
.ComboBoxEntry(model
=model
)
385 _patch(Gtk
, "combo_box_entry_new_with_model", combo_box_entry_new_with_model
)
389 def install_child_property(container
, flag
, pspec
):
390 warnings
.warn('install_child_property() is not supported',
391 gi
.PyGIDeprecationWarning
, stacklevel
=2)
392 _patch(Gtk
.Container
, "install_child_property", classmethod(install_child_property
))
395 combo
= Gtk
.ComboBox()
396 model
= Gtk
.ListStore(str)
397 combo
.set_model(model
)
398 combo
.set_entry_text_column(0)
400 _patch(Gtk
, "combo_box_new_text", new_text
)
402 def append_text(self
, text
):
403 model
= self
.get_model()
405 _patch(Gtk
.ComboBox
, "append_text", append_text
)
406 _patch(Gtk
, "expander_new_with_mnemonic", Gtk
.Expander
.new_with_mnemonic
)
407 _patch(Gtk
, "icon_theme_get_default", Gtk
.IconTheme
.get_default
)
408 _patch(Gtk
, "image_new_from_pixbuf", Gtk
.Image
.new_from_pixbuf
)
409 _patch(Gtk
, "image_new_from_stock", Gtk
.Image
.new_from_stock
)
410 _patch(Gtk
, "image_new_from_animation", Gtk
.Image
.new_from_animation
)
411 _patch(Gtk
, "image_new_from_icon_set", Gtk
.Image
.new_from_icon_set
)
412 _patch(Gtk
, "image_new_from_file", Gtk
.Image
.new_from_file
)
413 _patch(Gtk
, "settings_get_default", Gtk
.Settings
.get_default
)
414 _patch(Gtk
, "window_set_default_icon", Gtk
.Window
.set_default_icon
)
416 _patch(Gtk
, "clipboard_get", Gtk
.Clipboard
.get
)
417 except AttributeError:
421 _patch(Gtk
.AccelGroup
, "connect_group", Gtk
.AccelGroup
.connect
)
424 _patch(Gtk
, "status_icon_position_menu", Gtk
.StatusIcon
.position_menu
)
425 _patch(Gtk
.StatusIcon
, "set_tooltip", Gtk
.StatusIcon
.set_tooltip_text
)
429 orig_HScale
= Gtk
.HScale
430 orig_VScale
= Gtk
.VScale
432 class HScale(orig_HScale
):
433 def __init__(self
, adjustment
=None):
434 orig_HScale
.__init
__(self
, adjustment
=adjustment
)
435 _patch(Gtk
, "HScale", HScale
)
437 class VScale(orig_VScale
):
438 def __init__(self
, adjustment
=None):
439 orig_VScale
.__init
__(self
, adjustment
=adjustment
)
440 _patch(Gtk
, "VScale", VScale
)
442 _patch(Gtk
, "stock_add", lambda items
: None)
446 _patch(Gtk
.Widget
, "window", property(fget
=Gtk
.Widget
.get_window
))
448 _patch(Gtk
, "widget_get_default_direction", Gtk
.Widget
.get_default_direction
)
449 orig_size_request
= Gtk
.Widget
.size_request
451 def size_request(widget
):
452 class SizeRequest(_compat
.UserList
):
453 def __init__(self
, req
):
454 self
.height
= req
.height
455 self
.width
= req
.width
456 _compat
.UserList
.__init
__(self
, [self
.width
, self
.height
])
457 return SizeRequest(orig_size_request(widget
))
458 _patch(Gtk
.Widget
, "size_request", size_request
)
459 _patch(Gtk
.Widget
, "hide_all", Gtk
.Widget
.hide
)
461 class BaseGetter(object):
462 def __init__(self
, context
):
463 self
.context
= context
465 def __getitem__(self
, state
):
466 color
= self
.context
.get_background_color(state
)
467 return Gdk
.Color(red
=int(color
.red
* 65535),
468 green
=int(color
.green
* 65535),
469 blue
=int(color
.blue
* 65535))
471 class Styles(object):
472 def __init__(self
, widget
):
473 context
= widget
.get_style_context()
474 self
.base
= BaseGetter(context
)
475 self
.black
= Gdk
.Color(red
=0, green
=0, blue
=0)
477 class StyleDescriptor(object):
478 def __get__(self
, instance
, class_
):
479 return Styles(instance
)
480 _patch(Gtk
.Widget
, "style", StyleDescriptor())
484 orig_text_view_scroll_to_mark
= Gtk
.TextView
.scroll_to_mark
486 def text_view_scroll_to_mark(self
, mark
, within_margin
,
487 use_align
=False, xalign
=0.5, yalign
=0.5):
488 return orig_text_view_scroll_to_mark(self
, mark
, within_margin
,
489 use_align
, xalign
, yalign
)
490 _patch(Gtk
.TextView
, "scroll_to_mark", text_view_scroll_to_mark
)
494 orig_set_geometry_hints
= Gtk
.Window
.set_geometry_hints
496 def set_geometry_hints(self
, geometry_widget
=None,
497 min_width
=-1, min_height
=-1, max_width
=-1, max_height
=-1,
498 base_width
=-1, base_height
=-1, width_inc
=-1, height_inc
=-1,
499 min_aspect
=-1.0, max_aspect
=-1.0):
501 geometry
= Gdk
.Geometry()
502 geom_mask
= Gdk
.WindowHints(0)
504 if min_width
>= 0 or min_height
>= 0:
505 geometry
.min_width
= max(min_width
, 0)
506 geometry
.min_height
= max(min_height
, 0)
507 geom_mask |
= Gdk
.WindowHints
.MIN_SIZE
509 if max_width
>= 0 or max_height
>= 0:
510 geometry
.max_width
= max(max_width
, 0)
511 geometry
.max_height
= max(max_height
, 0)
512 geom_mask |
= Gdk
.WindowHints
.MAX_SIZE
514 if base_width
>= 0 or base_height
>= 0:
515 geometry
.base_width
= max(base_width
, 0)
516 geometry
.base_height
= max(base_height
, 0)
517 geom_mask |
= Gdk
.WindowHints
.BASE_SIZE
519 if width_inc
>= 0 or height_inc
>= 0:
520 geometry
.width_inc
= max(width_inc
, 0)
521 geometry
.height_inc
= max(height_inc
, 0)
522 geom_mask |
= Gdk
.WindowHints
.RESIZE_INC
524 if min_aspect
>= 0.0 or max_aspect
>= 0.0:
525 if min_aspect
<= 0.0 or max_aspect
<= 0.0:
526 raise TypeError("aspect ratios must be positive")
528 geometry
.min_aspect
= min_aspect
529 geometry
.max_aspect
= max_aspect
530 geom_mask |
= Gdk
.WindowHints
.ASPECT
532 return orig_set_geometry_hints(self
, geometry_widget
, geometry
, geom_mask
)
534 _patch(Gtk
.Window
, "set_geometry_hints", set_geometry_hints
)
535 _patch(Gtk
, "window_list_toplevels", Gtk
.Window
.list_toplevels
)
536 _patch(Gtk
, "window_set_default_icon_name", Gtk
.Window
.set_default_icon_name
)
540 class UnixPrint(object):
542 unixprint
= UnixPrint()
543 _patch_module('gtkunixprint', unixprint
)
547 with warnings
.catch_warnings():
548 warnings
.simplefilter('ignore', category
=RuntimeWarning)
549 from gi
.overrides
import keysyms
551 _patch_module('gtk.keysyms', keysyms
)
552 _patch(Gtk
, "keysyms", keysyms
)
554 from . import generictreemodel
555 _patch(Gtk
, "GenericTreeModel", generictreemodel
.GenericTreeModel
)
559 if _check_enabled("vte"):
562 gi
.require_version('Vte', '0.0')
563 from gi
.repository
import Vte
564 _patch_module('vte', Vte
)
567 def enable_poppler():
568 if _check_enabled("poppler"):
571 gi
.require_version('Poppler', '0.18')
572 from gi
.repository
import Poppler
573 _patch_module('poppler', Poppler
)
575 _patch(Poppler
, "pypoppler_version", (1, 0, 0))
578 def enable_webkit(version
='1.0'):
579 if _check_enabled("webkit", version
):
582 gi
.require_version('WebKit', version
)
583 from gi
.repository
import WebKit
584 _patch_module('webkit', WebKit
)
586 _patch(WebKit
.WebView
, "get_web_inspector", WebKit
.WebView
.get_inspector
)
590 if _check_enabled("gudev"):
593 gi
.require_version('GUdev', '1.0')
594 from gi
.repository
import GUdev
595 _patch_module('gudev', GUdev
)
599 if _check_enabled("gst"):
602 gi
.require_version('Gst', '0.10')
603 from gi
.repository
import Gst
604 _patch_module('gst', Gst
)
607 _patch(Gst
, "registry_get_default", Gst
.Registry
.get_default
)
608 _patch(Gst
, "element_register", Gst
.Element
.register
)
609 _patch(Gst
, "element_factory_make", Gst
.ElementFactory
.make
)
610 _patch(Gst
, "caps_new_any", Gst
.Caps
.new_any
)
611 _patch(Gst
, "get_pygst_version", lambda: (0, 10, 19))
612 _patch(Gst
, "get_gst_version", lambda: (0, 10, 40))
614 from gi
.repository
import GstInterfaces
615 _patch_module('gst.interfaces', GstInterfaces
)
616 _install_enums(GstInterfaces
)
618 from gi
.repository
import GstAudio
619 _patch_module('gst.audio', GstAudio
)
620 _install_enums(GstAudio
)
622 from gi
.repository
import GstVideo
623 _patch_module('gst.video', GstVideo
)
624 _install_enums(GstVideo
)
626 from gi
.repository
import GstBase
627 _patch_module('gst.base', GstBase
)
628 _install_enums(GstBase
)
630 _patch(Gst
, "BaseTransform", GstBase
.BaseTransform
)
631 _patch(Gst
, "BaseSink", GstBase
.BaseSink
)
633 from gi
.repository
import GstController
634 _patch_module('gst.controller', GstController
)
635 _install_enums(GstController
, dest
=Gst
)
637 from gi
.repository
import GstPbutils
638 _patch_module('gst.pbutils', GstPbutils
)
639 _install_enums(GstPbutils
)
642 def enable_goocanvas():
643 if _check_enabled("goocanvas"):
646 gi
.require_version('GooCanvas', '2.0')
647 from gi
.repository
import GooCanvas
648 _patch_module('goocanvas', GooCanvas
)
649 _install_enums(GooCanvas
, strip
='GOO_CANVAS_')
651 _patch(GooCanvas
, "ItemSimple", GooCanvas
.CanvasItemSimple
)
652 _patch(GooCanvas
, "Item", GooCanvas
.CanvasItem
)
653 _patch(GooCanvas
, "Image", GooCanvas
.CanvasImage
)
654 _patch(GooCanvas
, "Group", GooCanvas
.CanvasGroup
)
655 _patch(GooCanvas
, "Rect", GooCanvas
.CanvasRect
)