1# -*- Mode: Python; py-indent-offset: 4 -*- 2# vim: tabstop=4 shiftwidth=4 expandtab 3# 4# Copyright (C) 2009 Johan Dahlin <johan@gnome.org> 5# 2010 Simon van der Linden <svdlinden@src.gnome.org> 6# 7# This library is free software; you can redistribute it and/or 8# modify it under the terms of the GNU Lesser General Public 9# License as published by the Free Software Foundation; either 10# version 2.1 of the License, or (at your option) any later version. 11# 12# This library is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15# Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public 18# License along with this library; if not, write to the Free Software 19# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 20# USA 21 22import sys 23import warnings 24from collections import abc 25 26from gi.repository import GObject 27from .._ossighelper import wakeup_on_signal, register_sigint_fallback 28from .._gtktemplate import Template 29from ..overrides import override, strip_boolean_result, deprecated_init 30from ..module import get_introspection_module 31from gi import PyGIDeprecationWarning 32 33 34Gtk = get_introspection_module('Gtk') 35 36__all__ = [] 37 38 39Template = Template 40__all__.append('Template') 41 42if Gtk._version == '2.0': 43 warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \ 44was not designed for use with introspection some of the \ 45interfaces and API will fail. As such this is not supported \ 46by the pygobject development team and we encourage you to \ 47port your app to Gtk 3 or greater. PyGTK is the recomended \ 48python module to use with Gtk 2.0" 49 50 warnings.warn(warn_msg, RuntimeWarning) 51 52 53class PyGTKDeprecationWarning(PyGIDeprecationWarning): 54 pass 55 56 57__all__.append('PyGTKDeprecationWarning') 58 59 60def _construct_target_list(targets): 61 """Create a list of TargetEntry items from a list of tuples in the form (target, flags, info) 62 63 The list can also contain existing TargetEntry items in which case the existing entry 64 is re-used in the return list. 65 """ 66 target_entries = [] 67 for entry in targets: 68 if not isinstance(entry, Gtk.TargetEntry): 69 entry = Gtk.TargetEntry.new(*entry) 70 target_entries.append(entry) 71 return target_entries 72 73 74__all__.append('_construct_target_list') 75 76 77def _extract_handler_and_args(obj_or_map, handler_name): 78 handler = None 79 if isinstance(obj_or_map, abc.Mapping): 80 handler = obj_or_map.get(handler_name, None) 81 else: 82 handler = getattr(obj_or_map, handler_name, None) 83 84 if handler is None: 85 raise AttributeError('Handler %s not found' % handler_name) 86 87 args = () 88 if isinstance(handler, abc.Sequence): 89 if len(handler) == 0: 90 raise TypeError("Handler %s tuple can not be empty" % handler) 91 args = handler[1:] 92 handler = handler[0] 93 94 elif not callable(handler): 95 raise TypeError('Handler %s is not a method, function or tuple' % handler) 96 97 return handler, args 98 99 100# Exposed for unit-testing. 101__all__.append('_extract_handler_and_args') 102 103 104def _builder_connect_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map): 105 handler, args = _extract_handler_and_args(obj_or_map, handler_name) 106 107 after = flags & GObject.ConnectFlags.AFTER 108 if connect_obj is not None: 109 if after: 110 gobj.connect_object_after(signal_name, handler, connect_obj, *args) 111 else: 112 gobj.connect_object(signal_name, handler, connect_obj, *args) 113 else: 114 if after: 115 gobj.connect_after(signal_name, handler, *args) 116 else: 117 gobj.connect(signal_name, handler, *args) 118 119 120class _FreezeNotifyManager(object): 121 def __init__(self, obj): 122 self.obj = obj 123 124 def __enter__(self): 125 pass 126 127 def __exit__(self, exc_type, exc_value, traceback): 128 self.obj.thaw_child_notify() 129 130 131class Widget(Gtk.Widget): 132 133 translate_coordinates = strip_boolean_result(Gtk.Widget.translate_coordinates) 134 135 if Gtk._version != "4.0": 136 def freeze_child_notify(self): 137 super(Widget, self).freeze_child_notify() 138 return _FreezeNotifyManager(self) 139 140 if Gtk._version != "4.0": 141 def drag_dest_set_target_list(self, target_list): 142 if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)): 143 target_list = Gtk.TargetList.new(_construct_target_list(target_list)) 144 super(Widget, self).drag_dest_set_target_list(target_list) 145 146 if Gtk._version != "4.0": 147 def drag_source_set_target_list(self, target_list): 148 if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)): 149 target_list = Gtk.TargetList.new(_construct_target_list(target_list)) 150 super(Widget, self).drag_source_set_target_list(target_list) 151 152 def style_get_property(self, property_name, value=None): 153 if value is None: 154 prop = self.find_style_property(property_name) 155 if prop is None: 156 raise ValueError('Class "%s" does not contain style property "%s"' % 157 (self, property_name)) 158 value = GObject.Value(prop.value_type) 159 160 Gtk.Widget.style_get_property(self, property_name, value) 161 return value.get_value() 162 163 164Widget = override(Widget) 165__all__.append('Widget') 166 167 168class Container(Gtk.Container, Widget): 169 170 def __len__(self): 171 return len(self.get_children()) 172 173 def __contains__(self, child): 174 return child in self.get_children() 175 176 def __iter__(self): 177 return iter(self.get_children()) 178 179 def __bool__(self): 180 return True 181 182 # alias for Python 2.x object protocol 183 __nonzero__ = __bool__ 184 185 if Gtk._version in ("2.0", "3.0"): 186 187 def child_get_property(self, child, property_name, value=None): 188 if value is None: 189 prop = self.find_child_property(property_name) 190 if prop is None: 191 raise ValueError('Class "%s" does not contain child property "%s"' % 192 (self, property_name)) 193 value = GObject.Value(prop.value_type) 194 195 Gtk.Container.child_get_property(self, child, property_name, value) 196 return value.get_value() 197 198 def child_get(self, child, *prop_names): 199 """Returns a list of child property values for the given names.""" 200 return [self.child_get_property(child, name) for name in prop_names] 201 202 def child_set(self, child, **kwargs): 203 """Set a child properties on the given child to key/value pairs.""" 204 for name, value in kwargs.items(): 205 name = name.replace('_', '-') 206 self.child_set_property(child, name, value) 207 208 get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain) 209 210 211Container = override(Container) 212__all__.append('Container') 213 214 215class Editable(Gtk.Editable): 216 217 def insert_text(self, text, position): 218 return super(Editable, self).insert_text(text, -1, position) 219 220 get_selection_bounds = strip_boolean_result(Gtk.Editable.get_selection_bounds, fail_ret=()) 221 222 223Editable = override(Editable) 224__all__.append("Editable") 225 226 227if Gtk._version in ("2.0", "3.0"): 228 class Action(Gtk.Action): 229 __init__ = deprecated_init(Gtk.Action.__init__, 230 arg_names=('name', 'label', 'tooltip', 'stock_id'), 231 category=PyGTKDeprecationWarning) 232 233 Action = override(Action) 234 __all__.append("Action") 235 236 class RadioAction(Gtk.RadioAction): 237 __init__ = deprecated_init(Gtk.RadioAction.__init__, 238 arg_names=('name', 'label', 'tooltip', 'stock_id', 'value'), 239 category=PyGTKDeprecationWarning) 240 241 RadioAction = override(RadioAction) 242 __all__.append("RadioAction") 243 244 class ActionGroup(Gtk.ActionGroup): 245 __init__ = deprecated_init(Gtk.ActionGroup.__init__, 246 arg_names=('name',), 247 category=PyGTKDeprecationWarning) 248 249 def add_actions(self, entries, user_data=None): 250 """ 251 The add_actions() method is a convenience method that creates a number 252 of gtk.Action objects based on the information in the list of action 253 entry tuples contained in entries and adds them to the action group. 254 The entry tuples can vary in size from one to six items with the 255 following information: 256 257 * The name of the action. Must be specified. 258 * The stock id for the action. Optional with a default value of None 259 if a label is specified. 260 * The label for the action. This field should typically be marked 261 for translation, see the set_translation_domain() method. Optional 262 with a default value of None if a stock id is specified. 263 * The accelerator for the action, in the format understood by the 264 gtk.accelerator_parse() function. Optional with a default value of 265 None. 266 * The tooltip for the action. This field should typically be marked 267 for translation, see the set_translation_domain() method. Optional 268 with a default value of None. 269 * The callback function invoked when the action is activated. 270 Optional with a default value of None. 271 272 The "activate" signals of the actions are connected to the callbacks and 273 their accel paths are set to <Actions>/group-name/action-name. 274 """ 275 try: 276 iter(entries) 277 except (TypeError): 278 raise TypeError('entries must be iterable') 279 280 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None): 281 action = Action(name=name, label=label, tooltip=tooltip, stock_id=stock_id) 282 if callback is not None: 283 if user_data is None: 284 action.connect('activate', callback) 285 else: 286 action.connect('activate', callback, user_data) 287 288 self.add_action_with_accel(action, accelerator) 289 290 for e in entries: 291 # using inner function above since entries can leave out optional arguments 292 _process_action(*e) 293 294 def add_toggle_actions(self, entries, user_data=None): 295 """ 296 The add_toggle_actions() method is a convenience method that creates a 297 number of gtk.ToggleAction objects based on the information in the list 298 of action entry tuples contained in entries and adds them to the action 299 group. The toggle action entry tuples can vary in size from one to seven 300 items with the following information: 301 302 * The name of the action. Must be specified. 303 * The stock id for the action. Optional with a default value of None 304 if a label is specified. 305 * The label for the action. This field should typically be marked 306 for translation, see the set_translation_domain() method. Optional 307 with a default value of None if a stock id is specified. 308 * The accelerator for the action, in the format understood by the 309 gtk.accelerator_parse() function. Optional with a default value of 310 None. 311 * The tooltip for the action. This field should typically be marked 312 for translation, see the set_translation_domain() method. Optional 313 with a default value of None. 314 * The callback function invoked when the action is activated. 315 Optional with a default value of None. 316 * A flag indicating whether the toggle action is active. Optional 317 with a default value of False. 318 319 The "activate" signals of the actions are connected to the callbacks and 320 their accel paths are set to <Actions>/group-name/action-name. 321 """ 322 323 try: 324 iter(entries) 325 except (TypeError): 326 raise TypeError('entries must be iterable') 327 328 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False): 329 action = Gtk.ToggleAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id) 330 action.set_active(is_active) 331 if callback is not None: 332 if user_data is None: 333 action.connect('activate', callback) 334 else: 335 action.connect('activate', callback, user_data) 336 337 self.add_action_with_accel(action, accelerator) 338 339 for e in entries: 340 # using inner function above since entries can leave out optional arguments 341 _process_action(*e) 342 343 def add_radio_actions(self, entries, value=None, on_change=None, user_data=None): 344 """ 345 The add_radio_actions() method is a convenience method that creates a 346 number of gtk.RadioAction objects based on the information in the list 347 of action entry tuples contained in entries and adds them to the action 348 group. The entry tuples can vary in size from one to six items with the 349 following information: 350 351 * The name of the action. Must be specified. 352 * The stock id for the action. Optional with a default value of None 353 if a label is specified. 354 * The label for the action. This field should typically be marked 355 for translation, see the set_translation_domain() method. Optional 356 with a default value of None if a stock id is specified. 357 * The accelerator for the action, in the format understood by the 358 gtk.accelerator_parse() function. Optional with a default value of 359 None. 360 * The tooltip for the action. This field should typically be marked 361 for translation, see the set_translation_domain() method. Optional 362 with a default value of None. 363 * The value to set on the radio action. Optional with a default 364 value of 0. Should be specified in applications. 365 366 The value parameter specifies the radio action that should be set 367 active. The "changed" signal of the first radio action is connected to 368 the on_change callback (if specified and not None) and the accel paths 369 of the actions are set to <Actions>/group-name/action-name. 370 """ 371 try: 372 iter(entries) 373 except (TypeError): 374 raise TypeError('entries must be iterable') 375 376 first_action = None 377 378 def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0): 379 action = RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value) 380 381 if Gtk._version == '3.0': 382 action.join_group(group_source) 383 384 if value == entry_value: 385 action.set_active(True) 386 387 self.add_action_with_accel(action, accelerator) 388 return action 389 390 for e in entries: 391 # using inner function above since entries can leave out optional arguments 392 action = _process_action(first_action, *e) 393 if first_action is None: 394 first_action = action 395 396 if first_action is not None and on_change is not None: 397 if user_data is None: 398 first_action.connect('changed', on_change) 399 else: 400 first_action.connect('changed', on_change, user_data) 401 402 ActionGroup = override(ActionGroup) 403 __all__.append('ActionGroup') 404 405 class UIManager(Gtk.UIManager): 406 def add_ui_from_string(self, buffer): 407 if not isinstance(buffer, str): 408 raise TypeError('buffer must be a string') 409 410 length = _get_utf8_length(buffer) 411 412 return Gtk.UIManager.add_ui_from_string(self, buffer, length) 413 414 def insert_action_group(self, buffer, length=-1): 415 return Gtk.UIManager.insert_action_group(self, buffer, length) 416 417 UIManager = override(UIManager) 418 __all__.append('UIManager') 419 420 421class ComboBox(Gtk.ComboBox, Container): 422 get_active_iter = strip_boolean_result(Gtk.ComboBox.get_active_iter) 423 424 425ComboBox = override(ComboBox) 426__all__.append('ComboBox') 427 428 429class Box(Gtk.Box): 430 __init__ = deprecated_init(Gtk.Box.__init__, 431 arg_names=('homogeneous', 'spacing'), 432 category=PyGTKDeprecationWarning) 433 434 435Box = override(Box) 436__all__.append('Box') 437 438 439class SizeGroup(Gtk.SizeGroup): 440 __init__ = deprecated_init(Gtk.SizeGroup.__init__, 441 arg_names=('mode',), 442 deprecated_defaults={'mode': Gtk.SizeGroupMode.VERTICAL}, 443 category=PyGTKDeprecationWarning) 444 445 446SizeGroup = override(SizeGroup) 447__all__.append('SizeGroup') 448 449 450if Gtk._version in ("2.0", "3.0"): 451 class MenuItem(Gtk.MenuItem): 452 __init__ = deprecated_init(Gtk.MenuItem.__init__, 453 arg_names=('label',), 454 category=PyGTKDeprecationWarning) 455 456 MenuItem = override(MenuItem) 457 __all__.append('MenuItem') 458 459 460def _get_utf8_length(string): 461 assert isinstance(string, str) 462 if not isinstance(string, bytes): 463 string = string.encode("utf-8") 464 return len(string) 465 466 467class Builder(Gtk.Builder): 468 def connect_signals(self, obj_or_map): 469 """Connect signals specified by this builder to a name, handler mapping. 470 471 Connect signal, name, and handler sets specified in the builder with 472 the given mapping "obj_or_map". The handler/value aspect of the mapping 473 can also contain a tuple in the form of (handler [,arg1 [,argN]]) 474 allowing for extra arguments to be passed to the handler. For example: 475 476 .. code-block:: python 477 478 builder.connect_signals({'on_clicked': (on_clicked, arg1, arg2)}) 479 """ 480 self.connect_signals_full(_builder_connect_callback, obj_or_map) 481 482 def add_from_string(self, buffer): 483 if not isinstance(buffer, str): 484 raise TypeError('buffer must be a string') 485 486 length = _get_utf8_length(buffer) 487 488 return Gtk.Builder.add_from_string(self, buffer, length) 489 490 def add_objects_from_string(self, buffer, object_ids): 491 if not isinstance(buffer, str): 492 raise TypeError('buffer must be a string') 493 494 length = _get_utf8_length(buffer) 495 496 return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids) 497 498 499Builder = override(Builder) 500__all__.append('Builder') 501 502 503# NOTE: This must come before any other Window/Dialog subclassing, to ensure 504# that we have a correct inheritance hierarchy. 505 506_window_init = deprecated_init(Gtk.Window.__init__, 507 arg_names=('type',), 508 category=PyGTKDeprecationWarning, 509 stacklevel=3) 510 511 512class Window(Gtk.Window): 513 def __init__(self, *args, **kwargs): 514 if not initialized: 515 raise RuntimeError( 516 "Gtk couldn't be initialized. " 517 "Use Gtk.init_check() if you want to handle this case.") 518 _window_init(self, *args, **kwargs) 519 520 521Window = override(Window) 522__all__.append('Window') 523 524 525class Dialog(Gtk.Dialog, Container): 526 _old_arg_names = ('title', 'parent', 'flags', 'buttons', '_buttons_property') 527 _init = deprecated_init(Gtk.Dialog.__init__, 528 arg_names=('title', 'transient_for', 'flags', 529 'add_buttons', 'buttons'), 530 ignore=('flags', 'add_buttons'), 531 deprecated_aliases={'transient_for': 'parent', 532 'buttons': '_buttons_property'}, 533 category=PyGTKDeprecationWarning) 534 535 def __init__(self, *args, **kwargs): 536 537 new_kwargs = kwargs.copy() 538 old_kwargs = dict(zip(self._old_arg_names, args)) 539 old_kwargs.update(kwargs) 540 541 # Increment the warning stacklevel for sub-classes which implement their own __init__. 542 stacklevel = 2 543 if self.__class__ != Dialog and self.__class__.__init__ != Dialog.__init__: 544 stacklevel += 1 545 546 # buttons was overloaded by PyGtk but is needed for Gtk.MessageDialog 547 # as a pass through, so type check the argument and give a deprecation 548 # when it is not of type Gtk.ButtonsType 549 add_buttons = old_kwargs.get('buttons', None) 550 if add_buttons is not None and not isinstance(add_buttons, Gtk.ButtonsType): 551 warnings.warn('The "buttons" argument must be a Gtk.ButtonsType enum value. ' 552 'Please use the "add_buttons" method for adding buttons. ' 553 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', 554 PyGTKDeprecationWarning, stacklevel=stacklevel) 555 new_kwargs.pop('buttons', None) 556 else: 557 add_buttons = None 558 559 flags = old_kwargs.get('flags', 0) 560 if flags: 561 warnings.warn('The "flags" argument for dialog construction is deprecated. ' 562 'Please use initializer keywords: modal=True and/or destroy_with_parent=True. ' 563 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', 564 PyGTKDeprecationWarning, stacklevel=stacklevel) 565 566 if flags & Gtk.DialogFlags.MODAL: 567 new_kwargs['modal'] = True 568 569 if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT: 570 new_kwargs['destroy_with_parent'] = True 571 572 self._init(*args, **new_kwargs) 573 574 if add_buttons: 575 self.add_buttons(*add_buttons) 576 577 def run(self, *args, **kwargs): 578 with register_sigint_fallback(self.destroy): 579 with wakeup_on_signal(): 580 return Gtk.Dialog.run(self, *args, **kwargs) 581 582 action_area = property(lambda dialog: dialog.get_action_area()) 583 vbox = property(lambda dialog: dialog.get_content_area()) 584 585 def add_buttons(self, *args): 586 """ 587 The add_buttons() method adds several buttons to the Gtk.Dialog using 588 the button data passed as arguments to the method. This method is the 589 same as calling the Gtk.Dialog.add_button() repeatedly. The button data 590 pairs - button text (or stock ID) and a response ID integer are passed 591 individually. For example: 592 593 .. code-block:: python 594 595 dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE) 596 597 will add "Open" and "Close" buttons to dialog. 598 """ 599 def _button(b): 600 while b: 601 try: 602 t, r = b[0:2] 603 except ValueError: 604 raise ValueError('Must pass an even number of arguments') 605 b = b[2:] 606 yield t, r 607 608 for text, response in _button(args): 609 self.add_button(text, response) 610 611 612Dialog = override(Dialog) 613__all__.append('Dialog') 614 615 616class MessageDialog(Gtk.MessageDialog, Dialog): 617 __init__ = deprecated_init(Gtk.MessageDialog.__init__, 618 arg_names=('parent', 'flags', 'message_type', 619 'buttons', 'message_format'), 620 deprecated_aliases={'text': 'message_format', 621 'message_type': 'type'}, 622 category=PyGTKDeprecationWarning) 623 624 def format_secondary_text(self, message_format): 625 self.set_property('secondary-use-markup', False) 626 self.set_property('secondary-text', message_format) 627 628 def format_secondary_markup(self, message_format): 629 self.set_property('secondary-use-markup', True) 630 self.set_property('secondary-text', message_format) 631 632 633MessageDialog = override(MessageDialog) 634__all__.append('MessageDialog') 635 636 637if Gtk._version in ("2.0", "3.0"): 638 class ColorSelectionDialog(Gtk.ColorSelectionDialog): 639 __init__ = deprecated_init(Gtk.ColorSelectionDialog.__init__, 640 arg_names=('title',), 641 category=PyGTKDeprecationWarning) 642 643 ColorSelectionDialog = override(ColorSelectionDialog) 644 __all__.append('ColorSelectionDialog') 645 646 647class FileChooserDialog(Gtk.FileChooserDialog): 648 __init__ = deprecated_init(Gtk.FileChooserDialog.__init__, 649 arg_names=('title', 'parent', 'action', 'buttons'), 650 category=PyGTKDeprecationWarning) 651 652 653FileChooserDialog = override(FileChooserDialog) 654__all__.append('FileChooserDialog') 655 656 657if Gtk._version in ("2.0", "3.0"): 658 class FontSelectionDialog(Gtk.FontSelectionDialog): 659 __init__ = deprecated_init(Gtk.FontSelectionDialog.__init__, 660 arg_names=('title',), 661 category=PyGTKDeprecationWarning) 662 663 FontSelectionDialog = override(FontSelectionDialog) 664 __all__.append('FontSelectionDialog') 665 666 667if Gtk._version in ("2.0", "3.0"): 668 class RecentChooserDialog(Gtk.RecentChooserDialog): 669 # Note, the "manager" keyword must work across the entire 3.x series because 670 # "recent_manager" is not backwards compatible with PyGObject versions prior to 3.10. 671 __init__ = deprecated_init(Gtk.RecentChooserDialog.__init__, 672 arg_names=('title', 'parent', 'recent_manager', 'buttons'), 673 deprecated_aliases={'recent_manager': 'manager'}, 674 category=PyGTKDeprecationWarning) 675 676 RecentChooserDialog = override(RecentChooserDialog) 677 __all__.append('RecentChooserDialog') 678 679 680class IconView(Gtk.IconView): 681 __init__ = deprecated_init(Gtk.IconView.__init__, 682 arg_names=('model',), 683 category=PyGTKDeprecationWarning) 684 685 get_item_at_pos = strip_boolean_result(Gtk.IconView.get_item_at_pos) 686 get_visible_range = strip_boolean_result(Gtk.IconView.get_visible_range) 687 get_dest_item_at_pos = strip_boolean_result(Gtk.IconView.get_dest_item_at_pos) 688 689 690IconView = override(IconView) 691__all__.append('IconView') 692 693 694if Gtk._version in ("2.0", "3.0"): 695 class ToolButton(Gtk.ToolButton): 696 __init__ = deprecated_init(Gtk.ToolButton.__init__, 697 arg_names=('stock_id',), 698 category=PyGTKDeprecationWarning) 699 700 ToolButton = override(ToolButton) 701 __all__.append('ToolButton') 702 703 704class IMContext(Gtk.IMContext): 705 get_surrounding = strip_boolean_result(Gtk.IMContext.get_surrounding) 706 707 708IMContext = override(IMContext) 709__all__.append('IMContext') 710 711 712class RecentInfo(Gtk.RecentInfo): 713 get_application_info = strip_boolean_result(Gtk.RecentInfo.get_application_info) 714 715 716RecentInfo = override(RecentInfo) 717__all__.append('RecentInfo') 718 719 720class TextBuffer(Gtk.TextBuffer): 721 722 def create_tag(self, tag_name=None, **properties): 723 """Creates a tag and adds it to the tag table of the TextBuffer. 724 725 :param str tag_name: 726 Name of the new tag, or None 727 :param **properties: 728 Keyword list of properties and their values 729 730 This is equivalent to creating a Gtk.TextTag and then adding the 731 tag to the buffer's tag table. The returned tag is owned by 732 the buffer's tag table. 733 734 If ``tag_name`` is None, the tag is anonymous. 735 736 If ``tag_name`` is not None, a tag called ``tag_name`` must not already 737 exist in the tag table for this buffer. 738 739 Properties are passed as a keyword list of names and values (e.g. 740 foreground='DodgerBlue', weight=Pango.Weight.BOLD) 741 742 :returns: 743 A new tag. 744 """ 745 746 tag = Gtk.TextTag(name=tag_name, **properties) 747 self.get_tag_table().add(tag) 748 return tag 749 750 def create_mark(self, mark_name, where, left_gravity=False): 751 return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity) 752 753 def set_text(self, text, length=-1): 754 Gtk.TextBuffer.set_text(self, text, length) 755 756 def insert(self, iter, text, length=-1): 757 if not isinstance(text, str): 758 raise TypeError('text must be a string, not %s' % type(text)) 759 760 Gtk.TextBuffer.insert(self, iter, text, length) 761 762 def insert_with_tags(self, iter, text, *tags): 763 start_offset = iter.get_offset() 764 self.insert(iter, text) 765 766 if not tags: 767 return 768 769 start = self.get_iter_at_offset(start_offset) 770 771 for tag in tags: 772 self.apply_tag(tag, start, iter) 773 774 def insert_with_tags_by_name(self, iter, text, *tags): 775 tag_objs = [] 776 777 for tag in tags: 778 tag_obj = self.get_tag_table().lookup(tag) 779 if not tag_obj: 780 raise ValueError('unknown text tag: %s' % tag) 781 tag_objs.append(tag_obj) 782 783 self.insert_with_tags(iter, text, *tag_objs) 784 785 def insert_at_cursor(self, text, length=-1): 786 if not isinstance(text, str): 787 raise TypeError('text must be a string, not %s' % type(text)) 788 789 Gtk.TextBuffer.insert_at_cursor(self, text, length) 790 791 get_selection_bounds = strip_boolean_result(Gtk.TextBuffer.get_selection_bounds, fail_ret=()) 792 793 794TextBuffer = override(TextBuffer) 795__all__.append('TextBuffer') 796 797 798class TextIter(Gtk.TextIter): 799 forward_search = strip_boolean_result(Gtk.TextIter.forward_search) 800 backward_search = strip_boolean_result(Gtk.TextIter.backward_search) 801 802 803TextIter = override(TextIter) 804__all__.append('TextIter') 805 806 807class TreeModel(Gtk.TreeModel): 808 def __len__(self): 809 return self.iter_n_children(None) 810 811 def __bool__(self): 812 return True 813 814 # alias for Python 2.x object protocol 815 __nonzero__ = __bool__ 816 817 def _getiter(self, key): 818 if isinstance(key, Gtk.TreeIter): 819 return key 820 elif isinstance(key, int) and key < 0: 821 index = len(self) + key 822 if index < 0: 823 raise IndexError("row index is out of bounds: %d" % key) 824 return self.get_iter(index) 825 else: 826 try: 827 aiter = self.get_iter(key) 828 except ValueError: 829 raise IndexError("could not find tree path '%s'" % key) 830 return aiter 831 832 def sort_new_with_model(self): 833 super_object = super(TreeModel, self) 834 if hasattr(super_object, "sort_new_with_model"): 835 return super_object.sort_new_with_model() 836 else: 837 return TreeModelSort.new_with_model(self) 838 839 def _coerce_path(self, path): 840 if isinstance(path, Gtk.TreePath): 841 return path 842 else: 843 return TreePath(path) 844 845 def __getitem__(self, key): 846 aiter = self._getiter(key) 847 return TreeModelRow(self, aiter) 848 849 def __setitem__(self, key, value): 850 row = self[key] 851 self.set_row(row.iter, value) 852 853 def __delitem__(self, key): 854 aiter = self._getiter(key) 855 self.remove(aiter) 856 857 def __iter__(self): 858 return TreeModelRowIter(self, self.get_iter_first()) 859 860 get_iter_first = strip_boolean_result(Gtk.TreeModel.get_iter_first) 861 iter_children = strip_boolean_result(Gtk.TreeModel.iter_children) 862 iter_nth_child = strip_boolean_result(Gtk.TreeModel.iter_nth_child) 863 iter_parent = strip_boolean_result(Gtk.TreeModel.iter_parent) 864 get_iter_from_string = strip_boolean_result(Gtk.TreeModel.get_iter_from_string, 865 ValueError, 'invalid tree path') 866 867 def get_iter(self, path): 868 path = self._coerce_path(path) 869 success, aiter = super(TreeModel, self).get_iter(path) 870 if not success: 871 raise ValueError("invalid tree path '%s'" % path) 872 return aiter 873 874 def iter_next(self, aiter): 875 next_iter = aiter.copy() 876 success = super(TreeModel, self).iter_next(next_iter) 877 if success: 878 return next_iter 879 880 def iter_previous(self, aiter): 881 prev_iter = aiter.copy() 882 success = super(TreeModel, self).iter_previous(prev_iter) 883 if success: 884 return prev_iter 885 886 def _convert_row(self, row): 887 # TODO: Accept a dictionary for row 888 # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name}) 889 if isinstance(row, str): 890 raise TypeError('Expected a list or tuple, but got str') 891 892 n_columns = self.get_n_columns() 893 if len(row) != n_columns: 894 raise ValueError('row sequence has the incorrect number of elements') 895 896 result = [] 897 columns = [] 898 for cur_col, value in enumerate(row): 899 # do not try to set None values, they are causing warnings 900 if value is None: 901 continue 902 result.append(self._convert_value(cur_col, value)) 903 columns.append(cur_col) 904 return (result, columns) 905 906 def set_row(self, treeiter, row): 907 converted_row, columns = self._convert_row(row) 908 for column in columns: 909 self.set_value(treeiter, column, row[column]) 910 911 def _convert_value(self, column, value): 912 '''Convert value to a GObject.Value of the expected type''' 913 914 if isinstance(value, GObject.Value): 915 return value 916 return GObject.Value(self.get_column_type(column), value) 917 918 def get(self, treeiter, *columns): 919 n_columns = self.get_n_columns() 920 921 values = [] 922 for col in columns: 923 if not isinstance(col, int): 924 raise TypeError("column numbers must be ints") 925 926 if col < 0 or col >= n_columns: 927 raise ValueError("column number is out of range") 928 929 values.append(self.get_value(treeiter, col)) 930 931 return tuple(values) 932 933 # 934 # Signals supporting python iterables as tree paths 935 # 936 def row_changed(self, path, iter): 937 return super(TreeModel, self).row_changed(self._coerce_path(path), iter) 938 939 def row_inserted(self, path, iter): 940 return super(TreeModel, self).row_inserted(self._coerce_path(path), iter) 941 942 def row_has_child_toggled(self, path, iter): 943 return super(TreeModel, self).row_has_child_toggled(self._coerce_path(path), 944 iter) 945 946 def row_deleted(self, path): 947 return super(TreeModel, self).row_deleted(self._coerce_path(path)) 948 949 def rows_reordered(self, path, iter, new_order): 950 return super(TreeModel, self).rows_reordered(self._coerce_path(path), 951 iter, new_order) 952 953 954TreeModel = override(TreeModel) 955__all__.append('TreeModel') 956 957 958class TreeSortable(Gtk.TreeSortable, ): 959 960 get_sort_column_id = strip_boolean_result(Gtk.TreeSortable.get_sort_column_id, fail_ret=(None, None)) 961 962 def set_sort_func(self, sort_column_id, sort_func, user_data=None): 963 super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data) 964 965 def set_default_sort_func(self, sort_func, user_data=None): 966 super(TreeSortable, self).set_default_sort_func(sort_func, user_data) 967 968 969TreeSortable = override(TreeSortable) 970__all__.append('TreeSortable') 971 972 973class TreeModelSort(Gtk.TreeModelSort): 974 __init__ = deprecated_init(Gtk.TreeModelSort.__init__, 975 arg_names=('model',), 976 category=PyGTKDeprecationWarning) 977 978 if not hasattr(Gtk.TreeModelSort, "new_with_model"): 979 @classmethod 980 def new_with_model(self, child_model): 981 return TreeModel.sort_new_with_model(child_model) 982 983 984TreeModelSort = override(TreeModelSort) 985__all__.append('TreeModelSort') 986 987 988class ListStore(Gtk.ListStore, TreeModel, TreeSortable): 989 def __init__(self, *column_types): 990 Gtk.ListStore.__init__(self) 991 self.set_column_types(column_types) 992 993 def _do_insert(self, position, row): 994 if row is not None: 995 row, columns = self._convert_row(row) 996 treeiter = self.insert_with_valuesv(position, columns, row) 997 else: 998 treeiter = Gtk.ListStore.insert(self, position) 999 1000 return treeiter 1001 1002 def append(self, row=None): 1003 if row: 1004 return self._do_insert(-1, row) 1005 # gtk_list_store_insert() does not know about the "position == -1" 1006 # case, so use append() here 1007 else: 1008 return Gtk.ListStore.append(self) 1009 1010 def prepend(self, row=None): 1011 return self._do_insert(0, row) 1012 1013 def insert(self, position, row=None): 1014 return self._do_insert(position, row) 1015 1016 def insert_before(self, sibling, row=None): 1017 if row is not None: 1018 if sibling is None: 1019 position = -1 1020 else: 1021 position = self.get_path(sibling).get_indices()[-1] 1022 return self._do_insert(position, row) 1023 1024 return Gtk.ListStore.insert_before(self, sibling) 1025 1026 def insert_after(self, sibling, row=None): 1027 if row is not None: 1028 if sibling is None: 1029 position = 0 1030 else: 1031 position = self.get_path(sibling).get_indices()[-1] + 1 1032 return self._do_insert(position, row) 1033 1034 return Gtk.ListStore.insert_after(self, sibling) 1035 1036 def set_value(self, treeiter, column, value): 1037 value = self._convert_value(column, value) 1038 Gtk.ListStore.set_value(self, treeiter, column, value) 1039 1040 def set(self, treeiter, *args): 1041 def _set_lists(cols, vals): 1042 if len(cols) != len(vals): 1043 raise TypeError('The number of columns do not match the number of values') 1044 1045 columns = [] 1046 values = [] 1047 for col_num, value in zip(cols, vals): 1048 if not isinstance(col_num, int): 1049 raise TypeError('TypeError: Expected integer argument for column.') 1050 1051 columns.append(col_num) 1052 values.append(self._convert_value(col_num, value)) 1053 1054 Gtk.ListStore.set(self, treeiter, columns, values) 1055 1056 if args: 1057 if isinstance(args[0], int): 1058 _set_lists(args[::2], args[1::2]) 1059 elif isinstance(args[0], (tuple, list)): 1060 if len(args) != 2: 1061 raise TypeError('Too many arguments') 1062 _set_lists(args[0], args[1]) 1063 elif isinstance(args[0], dict): 1064 _set_lists(list(args[0]), args[0].values()) 1065 else: 1066 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.') 1067 1068 1069ListStore = override(ListStore) 1070__all__.append('ListStore') 1071 1072 1073class TreeModelRow(object): 1074 1075 def __init__(self, model, iter_or_path): 1076 if not isinstance(model, Gtk.TreeModel): 1077 raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__) 1078 self.model = model 1079 if isinstance(iter_or_path, Gtk.TreePath): 1080 self.iter = model.get_iter(iter_or_path) 1081 elif isinstance(iter_or_path, Gtk.TreeIter): 1082 self.iter = iter_or_path 1083 else: 1084 raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, " 1085 "%s found" % type(iter_or_path).__name__) 1086 1087 @property 1088 def path(self): 1089 return self.model.get_path(self.iter) 1090 1091 @property 1092 def next(self): 1093 return self.get_next() 1094 1095 @property 1096 def previous(self): 1097 return self.get_previous() 1098 1099 @property 1100 def parent(self): 1101 return self.get_parent() 1102 1103 def get_next(self): 1104 next_iter = self.model.iter_next(self.iter) 1105 if next_iter: 1106 return TreeModelRow(self.model, next_iter) 1107 1108 def get_previous(self): 1109 prev_iter = self.model.iter_previous(self.iter) 1110 if prev_iter: 1111 return TreeModelRow(self.model, prev_iter) 1112 1113 def get_parent(self): 1114 parent_iter = self.model.iter_parent(self.iter) 1115 if parent_iter: 1116 return TreeModelRow(self.model, parent_iter) 1117 1118 def __getitem__(self, key): 1119 if isinstance(key, int): 1120 if key >= self.model.get_n_columns(): 1121 raise IndexError("column index is out of bounds: %d" % key) 1122 elif key < 0: 1123 key = self._convert_negative_index(key) 1124 return self.model.get_value(self.iter, key) 1125 elif isinstance(key, slice): 1126 start, stop, step = key.indices(self.model.get_n_columns()) 1127 alist = [] 1128 for i in range(start, stop, step): 1129 alist.append(self.model.get_value(self.iter, i)) 1130 return alist 1131 elif isinstance(key, tuple): 1132 return [self[k] for k in key] 1133 else: 1134 raise TypeError("indices must be integers, slice or tuple, not %s" 1135 % type(key).__name__) 1136 1137 def __setitem__(self, key, value): 1138 if isinstance(key, int): 1139 if key >= self.model.get_n_columns(): 1140 raise IndexError("column index is out of bounds: %d" % key) 1141 elif key < 0: 1142 key = self._convert_negative_index(key) 1143 self.model.set_value(self.iter, key, value) 1144 elif isinstance(key, slice): 1145 start, stop, step = key.indices(self.model.get_n_columns()) 1146 indexList = range(start, stop, step) 1147 if len(indexList) != len(value): 1148 raise ValueError( 1149 "attempt to assign sequence of size %d to slice of size %d" 1150 % (len(value), len(indexList))) 1151 1152 for i, v in enumerate(indexList): 1153 self.model.set_value(self.iter, v, value[i]) 1154 elif isinstance(key, tuple): 1155 if len(key) != len(value): 1156 raise ValueError( 1157 "attempt to assign sequence of size %d to sequence of size %d" 1158 % (len(value), len(key))) 1159 for k, v in zip(key, value): 1160 self[k] = v 1161 else: 1162 raise TypeError("indices must be an integer, slice or tuple, not %s" 1163 % type(key).__name__) 1164 1165 def _convert_negative_index(self, index): 1166 new_index = self.model.get_n_columns() + index 1167 if new_index < 0: 1168 raise IndexError("column index is out of bounds: %d" % index) 1169 return new_index 1170 1171 def iterchildren(self): 1172 child_iter = self.model.iter_children(self.iter) 1173 return TreeModelRowIter(self.model, child_iter) 1174 1175 1176__all__.append('TreeModelRow') 1177 1178 1179class TreeModelRowIter(object): 1180 1181 def __init__(self, model, aiter): 1182 self.model = model 1183 self.iter = aiter 1184 1185 def __next__(self): 1186 if not self.iter: 1187 raise StopIteration 1188 row = TreeModelRow(self.model, self.iter) 1189 self.iter = self.model.iter_next(self.iter) 1190 return row 1191 1192 # alias for Python 2.x object protocol 1193 next = __next__ 1194 1195 def __iter__(self): 1196 return self 1197 1198 1199__all__.append('TreeModelRowIter') 1200 1201 1202class TreePath(Gtk.TreePath): 1203 1204 def __new__(cls, path=0): 1205 if isinstance(path, int): 1206 path = str(path) 1207 elif not isinstance(path, str): 1208 path = ":".join(str(val) for val in path) 1209 1210 if len(path) == 0: 1211 raise TypeError("could not parse subscript '%s' as a tree path" % path) 1212 try: 1213 return TreePath.new_from_string(path) 1214 except TypeError: 1215 raise TypeError("could not parse subscript '%s' as a tree path" % path) 1216 1217 def __init__(self, *args, **kwargs): 1218 super(TreePath, self).__init__() 1219 1220 def __str__(self): 1221 return self.to_string() or "" 1222 1223 def __lt__(self, other): 1224 return other is not None and self.compare(other) < 0 1225 1226 def __le__(self, other): 1227 return other is not None and self.compare(other) <= 0 1228 1229 def __eq__(self, other): 1230 return other is not None and self.compare(other) == 0 1231 1232 def __ne__(self, other): 1233 return other is None or self.compare(other) != 0 1234 1235 def __gt__(self, other): 1236 return other is None or self.compare(other) > 0 1237 1238 def __ge__(self, other): 1239 return other is None or self.compare(other) >= 0 1240 1241 def __iter__(self): 1242 return iter(self.get_indices()) 1243 1244 def __len__(self): 1245 return self.get_depth() 1246 1247 def __getitem__(self, index): 1248 return self.get_indices()[index] 1249 1250 1251TreePath = override(TreePath) 1252__all__.append('TreePath') 1253 1254 1255class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable): 1256 def __init__(self, *column_types): 1257 Gtk.TreeStore.__init__(self) 1258 self.set_column_types(column_types) 1259 1260 def _do_insert(self, parent, position, row): 1261 if row is not None: 1262 row, columns = self._convert_row(row) 1263 treeiter = self.insert_with_values(parent, position, columns, row) 1264 else: 1265 treeiter = Gtk.TreeStore.insert(self, parent, position) 1266 1267 return treeiter 1268 1269 def append(self, parent, row=None): 1270 return self._do_insert(parent, -1, row) 1271 1272 def prepend(self, parent, row=None): 1273 return self._do_insert(parent, 0, row) 1274 1275 def insert(self, parent, position, row=None): 1276 return self._do_insert(parent, position, row) 1277 1278 def insert_before(self, parent, sibling, row=None): 1279 if row is not None: 1280 if sibling is None: 1281 position = -1 1282 else: 1283 if parent is None: 1284 parent = self.iter_parent(sibling) 1285 position = self.get_path(sibling).get_indices()[-1] 1286 return self._do_insert(parent, position, row) 1287 1288 return Gtk.TreeStore.insert_before(self, parent, sibling) 1289 1290 def insert_after(self, parent, sibling, row=None): 1291 if row is not None: 1292 if sibling is None: 1293 position = 0 1294 else: 1295 if parent is None: 1296 parent = self.iter_parent(sibling) 1297 position = self.get_path(sibling).get_indices()[-1] + 1 1298 return self._do_insert(parent, position, row) 1299 1300 return Gtk.TreeStore.insert_after(self, parent, sibling) 1301 1302 def set_value(self, treeiter, column, value): 1303 value = self._convert_value(column, value) 1304 Gtk.TreeStore.set_value(self, treeiter, column, value) 1305 1306 def set(self, treeiter, *args): 1307 def _set_lists(cols, vals): 1308 if len(cols) != len(vals): 1309 raise TypeError('The number of columns do not match the number of values') 1310 1311 columns = [] 1312 values = [] 1313 for col_num, value in zip(cols, vals): 1314 if not isinstance(col_num, int): 1315 raise TypeError('TypeError: Expected integer argument for column.') 1316 1317 columns.append(col_num) 1318 values.append(self._convert_value(col_num, value)) 1319 1320 Gtk.TreeStore.set(self, treeiter, columns, values) 1321 1322 if args: 1323 if isinstance(args[0], int): 1324 _set_lists(args[::2], args[1::2]) 1325 elif isinstance(args[0], (tuple, list)): 1326 if len(args) != 2: 1327 raise TypeError('Too many arguments') 1328 _set_lists(args[0], args[1]) 1329 elif isinstance(args[0], dict): 1330 _set_lists(args[0].keys(), args[0].values()) 1331 else: 1332 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.') 1333 1334 1335TreeStore = override(TreeStore) 1336__all__.append('TreeStore') 1337 1338 1339class TreeView(Gtk.TreeView, Container): 1340 __init__ = deprecated_init(Gtk.TreeView.__init__, 1341 arg_names=('model',), 1342 category=PyGTKDeprecationWarning) 1343 1344 get_path_at_pos = strip_boolean_result(Gtk.TreeView.get_path_at_pos) 1345 get_visible_range = strip_boolean_result(Gtk.TreeView.get_visible_range) 1346 get_dest_row_at_pos = strip_boolean_result(Gtk.TreeView.get_dest_row_at_pos) 1347 1348 def enable_model_drag_source(self, start_button_mask, targets, actions): 1349 target_entries = _construct_target_list(targets) 1350 super(TreeView, self).enable_model_drag_source(start_button_mask, 1351 target_entries, 1352 actions) 1353 1354 def enable_model_drag_dest(self, targets, actions): 1355 target_entries = _construct_target_list(targets) 1356 super(TreeView, self).enable_model_drag_dest(target_entries, 1357 actions) 1358 1359 def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0): 1360 if not isinstance(path, Gtk.TreePath): 1361 path = TreePath(path) 1362 super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align) 1363 1364 def set_cursor(self, path, column=None, start_editing=False): 1365 if not isinstance(path, Gtk.TreePath): 1366 path = TreePath(path) 1367 super(TreeView, self).set_cursor(path, column, start_editing) 1368 1369 def get_cell_area(self, path, column=None): 1370 if not isinstance(path, Gtk.TreePath): 1371 path = TreePath(path) 1372 return super(TreeView, self).get_cell_area(path, column) 1373 1374 def insert_column_with_attributes(self, position, title, cell, **kwargs): 1375 column = TreeViewColumn() 1376 column.set_title(title) 1377 column.pack_start(cell, False) 1378 self.insert_column(column, position) 1379 column.set_attributes(cell, **kwargs) 1380 1381 1382TreeView = override(TreeView) 1383__all__.append('TreeView') 1384 1385 1386class TreeViewColumn(Gtk.TreeViewColumn): 1387 def __init__(self, title='', 1388 cell_renderer=None, 1389 **attributes): 1390 Gtk.TreeViewColumn.__init__(self, title=title) 1391 if cell_renderer: 1392 self.pack_start(cell_renderer, True) 1393 1394 for (name, value) in attributes.items(): 1395 self.add_attribute(cell_renderer, name, value) 1396 1397 cell_get_position = strip_boolean_result(Gtk.TreeViewColumn.cell_get_position) 1398 1399 def set_cell_data_func(self, cell_renderer, func, func_data=None): 1400 super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data) 1401 1402 def set_attributes(self, cell_renderer, **attributes): 1403 Gtk.CellLayout.clear_attributes(self, cell_renderer) 1404 1405 for (name, value) in attributes.items(): 1406 Gtk.CellLayout.add_attribute(self, cell_renderer, name, value) 1407 1408 1409TreeViewColumn = override(TreeViewColumn) 1410__all__.append('TreeViewColumn') 1411 1412 1413class TreeSelection(Gtk.TreeSelection): 1414 1415 def select_path(self, path): 1416 if not isinstance(path, Gtk.TreePath): 1417 path = TreePath(path) 1418 super(TreeSelection, self).select_path(path) 1419 1420 def get_selected(self): 1421 success, model, aiter = super(TreeSelection, self).get_selected() 1422 if success: 1423 return (model, aiter) 1424 else: 1425 return (model, None) 1426 1427 # for compatibility with PyGtk 1428 1429 def get_selected_rows(self): 1430 rows, model = super(TreeSelection, self).get_selected_rows() 1431 return (model, rows) 1432 1433 1434TreeSelection = override(TreeSelection) 1435__all__.append('TreeSelection') 1436 1437 1438class Button(Gtk.Button, Container): 1439 _init = deprecated_init(Gtk.Button.__init__, 1440 arg_names=('label', 'stock', 'use_stock', 'use_underline'), 1441 ignore=('stock',), 1442 category=PyGTKDeprecationWarning, 1443 stacklevel=3) 1444 1445 def __init__(self, *args, **kwargs): 1446 # Doubly deprecated initializer, the stock keyword is non-standard. 1447 # Simply give a warning that stock items are deprecated even though 1448 # we want to deprecate the non-standard keyword as well here from 1449 # the overrides. 1450 if 'stock' in kwargs and kwargs['stock']: 1451 warnings.warn('Stock items are deprecated. ' 1452 'Please use: Gtk.Button.new_with_mnemonic(label)', 1453 PyGTKDeprecationWarning, stacklevel=2) 1454 new_kwargs = kwargs.copy() 1455 new_kwargs['label'] = new_kwargs['stock'] 1456 new_kwargs['use_stock'] = True 1457 new_kwargs['use_underline'] = True 1458 del new_kwargs['stock'] 1459 Gtk.Button.__init__(self, **new_kwargs) 1460 else: 1461 self._init(*args, **kwargs) 1462 1463 if hasattr(Gtk.Widget, "set_focus_on_click"): 1464 def set_focus_on_click(self, *args, **kwargs): 1465 # Gtk.Widget.set_focus_on_click should be used instead but it's 1466 # no obvious how because of the shadowed method, so override here 1467 return Gtk.Widget.set_focus_on_click(self, *args, **kwargs) 1468 1469 if hasattr(Gtk.Widget, "get_focus_on_click"): 1470 def get_focus_on_click(self, *args, **kwargs): 1471 # Gtk.Widget.get_focus_on_click should be used instead but it's 1472 # no obvious how because of the shadowed method, so override here 1473 return Gtk.Widget.get_focus_on_click(self, *args, **kwargs) 1474 1475 1476Button = override(Button) 1477__all__.append('Button') 1478 1479 1480class LinkButton(Gtk.LinkButton): 1481 __init__ = deprecated_init(Gtk.LinkButton.__init__, 1482 arg_names=('uri', 'label'), 1483 category=PyGTKDeprecationWarning) 1484 1485 1486LinkButton = override(LinkButton) 1487__all__.append('LinkButton') 1488 1489 1490class Label(Gtk.Label): 1491 __init__ = deprecated_init(Gtk.Label.__init__, 1492 arg_names=('label',), 1493 category=PyGTKDeprecationWarning) 1494 1495 1496Label = override(Label) 1497__all__.append('Label') 1498 1499 1500class Adjustment(Gtk.Adjustment): 1501 _init = deprecated_init(Gtk.Adjustment.__init__, 1502 arg_names=('value', 'lower', 'upper', 1503 'step_increment', 'page_increment', 'page_size'), 1504 deprecated_aliases={'page_increment': 'page_incr', 1505 'step_increment': 'step_incr'}, 1506 category=PyGTKDeprecationWarning, 1507 stacklevel=3) 1508 1509 def __init__(self, *args, **kwargs): 1510 self._init(*args, **kwargs) 1511 1512 # The value property is set between lower and (upper - page_size). 1513 # Just in case lower, upper or page_size was still 0 when value 1514 # was set, we set it again here. 1515 if 'value' in kwargs: 1516 self.set_value(kwargs['value']) 1517 elif len(args) >= 1: 1518 self.set_value(args[0]) 1519 1520 1521Adjustment = override(Adjustment) 1522__all__.append('Adjustment') 1523 1524 1525if Gtk._version in ("2.0", "3.0"): 1526 class Table(Gtk.Table, Container): 1527 __init__ = deprecated_init(Gtk.Table.__init__, 1528 arg_names=('n_rows', 'n_columns', 'homogeneous'), 1529 deprecated_aliases={'n_rows': 'rows', 'n_columns': 'columns'}, 1530 category=PyGTKDeprecationWarning) 1531 1532 def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, xpadding=0, ypadding=0): 1533 Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding) 1534 1535 Table = override(Table) 1536 __all__.append('Table') 1537 1538 1539class ScrolledWindow(Gtk.ScrolledWindow): 1540 __init__ = deprecated_init(Gtk.ScrolledWindow.__init__, 1541 arg_names=('hadjustment', 'vadjustment'), 1542 category=PyGTKDeprecationWarning) 1543 1544 1545ScrolledWindow = override(ScrolledWindow) 1546__all__.append('ScrolledWindow') 1547 1548 1549if Gtk._version in ("2.0", "3.0"): 1550 class HScrollbar(Gtk.HScrollbar): 1551 __init__ = deprecated_init(Gtk.HScrollbar.__init__, 1552 arg_names=('adjustment',), 1553 category=PyGTKDeprecationWarning) 1554 1555 HScrollbar = override(HScrollbar) 1556 __all__.append('HScrollbar') 1557 1558 class VScrollbar(Gtk.VScrollbar): 1559 __init__ = deprecated_init(Gtk.VScrollbar.__init__, 1560 arg_names=('adjustment',), 1561 category=PyGTKDeprecationWarning) 1562 1563 VScrollbar = override(VScrollbar) 1564 __all__.append('VScrollbar') 1565 1566 1567class Paned(Gtk.Paned): 1568 def pack1(self, child, resize=False, shrink=True): 1569 super(Paned, self).pack1(child, resize, shrink) 1570 1571 def pack2(self, child, resize=True, shrink=True): 1572 super(Paned, self).pack2(child, resize, shrink) 1573 1574 1575Paned = override(Paned) 1576__all__.append('Paned') 1577 1578 1579if Gtk._version in ("2.0", "3.0"): 1580 class Arrow(Gtk.Arrow): 1581 __init__ = deprecated_init(Gtk.Arrow.__init__, 1582 arg_names=('arrow_type', 'shadow_type'), 1583 category=PyGTKDeprecationWarning) 1584 1585 Arrow = override(Arrow) 1586 __all__.append('Arrow') 1587 1588 class IconSet(Gtk.IconSet): 1589 def __new__(cls, pixbuf=None): 1590 if pixbuf is not None: 1591 warnings.warn('Gtk.IconSet(pixbuf) has been deprecated. Please use: ' 1592 'Gtk.IconSet.new_from_pixbuf(pixbuf)', 1593 PyGTKDeprecationWarning, stacklevel=2) 1594 iconset = Gtk.IconSet.new_from_pixbuf(pixbuf) 1595 else: 1596 iconset = Gtk.IconSet.__new__(cls) 1597 return iconset 1598 1599 def __init__(self, *args, **kwargs): 1600 return super(IconSet, self).__init__() 1601 1602 IconSet = override(IconSet) 1603 __all__.append('IconSet') 1604 1605 1606class Viewport(Gtk.Viewport): 1607 __init__ = deprecated_init(Gtk.Viewport.__init__, 1608 arg_names=('hadjustment', 'vadjustment'), 1609 category=PyGTKDeprecationWarning) 1610 1611 1612Viewport = override(Viewport) 1613__all__.append('Viewport') 1614 1615 1616class TreeModelFilter(Gtk.TreeModelFilter): 1617 def set_visible_func(self, func, data=None): 1618 super(TreeModelFilter, self).set_visible_func(func, data) 1619 1620 def set_value(self, iter, column, value): 1621 # Delegate to child model 1622 iter = self.convert_iter_to_child_iter(iter) 1623 self.get_model().set_value(iter, column, value) 1624 1625 1626TreeModelFilter = override(TreeModelFilter) 1627__all__.append('TreeModelFilter') 1628 1629if Gtk._version == '3.0': 1630 class Menu(Gtk.Menu): 1631 def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time): 1632 self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time) 1633 Menu = override(Menu) 1634 __all__.append('Menu') 1635 1636if Gtk._version in ("2.0", "3.0"): 1637 _Gtk_main_quit = Gtk.main_quit 1638 1639 @override(Gtk.main_quit) 1640 def main_quit(*args): 1641 _Gtk_main_quit() 1642 1643 _Gtk_main = Gtk.main 1644 1645 @override(Gtk.main) 1646 def main(*args, **kwargs): 1647 with register_sigint_fallback(Gtk.main_quit): 1648 with wakeup_on_signal(): 1649 return _Gtk_main(*args, **kwargs) 1650 1651 1652if Gtk._version in ("2.0", "3.0"): 1653 stock_lookup = strip_boolean_result(Gtk.stock_lookup) 1654 __all__.append('stock_lookup') 1655 1656if Gtk._version == "4.0": 1657 initialized = Gtk.init_check() 1658else: 1659 initialized, argv = Gtk.init_check(sys.argv) 1660 sys.argv = list(argv) 1661