1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
4 # Copyright (C) 2009 Johan Dahlin <johan@gnome.org>
5 # 2010 Simon van der Linden <svdlinden@src.gnome.org>
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.
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.
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
23 from gi.repository import GObject
24 from ..overrides import override
25 from ..importer import modules
27 if sys.version_info >= (3, 0):
29 _callable = lambda c: hasattr(c, '__call__')
31 _basestring = basestring
34 Gtk = modules['Gtk']._introspection_module
37 if Gtk._version == '2.0':
39 warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \
40 was not designed for use with introspection some of the \
41 interfaces and API will fail. As such this is not supported \
42 by the pygobject development team and we encourage you to \
43 port your app to Gtk 3 or greater. PyGTK is the recomended \
44 python module to use with Gtk 2.0"
46 warnings.warn(warn_msg, RuntimeWarning)
49 class Widget(Gtk.Widget):
51 def translate_coordinates(self, dest_widget, src_x, src_y):
52 success, dest_x, dest_y = super(Widget, self).translate_coordinates(
53 dest_widget, src_x, src_y)
55 return (dest_x, dest_y,)
57 def render_icon(self, stock_id, size, detail=None):
58 return super(Widget, self).render_icon(stock_id, size, detail)
60 Widget = override(Widget)
61 __all__.append('Widget')
64 class Container(Gtk.Container, Widget):
67 return len(self.get_children())
69 def __contains__(self, child):
70 return child in self.get_children()
73 return iter(self.get_children())
78 # alias for Python 2.x object protocol
79 __nonzero__ = __bool__
81 def get_focus_chain(self):
82 success, widgets = super(Container, self).get_focus_chain()
86 Container = override(Container)
87 __all__.append('Container')
90 class Editable(Gtk.Editable):
92 def insert_text(self, text, position):
93 pos = super(Editable, self).insert_text(text, -1, position)
97 def get_selection_bounds(self):
98 success, start_pos, end_pos = super(Editable, self).get_selection_bounds()
100 return (start_pos, end_pos,)
104 Editable = override(Editable)
105 __all__.append("Editable")
108 class Action(Gtk.Action):
109 def __init__(self, name, label, tooltip, stock_id, **kwds):
110 Gtk.Action.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, **kwds)
112 Action = override(Action)
113 __all__.append("Action")
116 class RadioAction(Gtk.RadioAction):
117 def __init__(self, name, label, tooltip, stock_id, value, **kwds):
118 Gtk.RadioAction.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=value, **kwds)
120 RadioAction = override(RadioAction)
121 __all__.append("RadioAction")
124 class ActionGroup(Gtk.ActionGroup):
125 def __init__(self, name, **kwds):
126 super(ActionGroup, self).__init__(name=name, **kwds)
128 def add_actions(self, entries, user_data=None):
130 The add_actions() method is a convenience method that creates a number
131 of gtk.Action objects based on the information in the list of action
132 entry tuples contained in entries and adds them to the action group.
133 The entry tuples can vary in size from one to six items with the
134 following information:
136 * The name of the action. Must be specified.
137 * The stock id for the action. Optional with a default value of None
138 if a label is specified.
139 * The label for the action. This field should typically be marked
140 for translation, see the set_translation_domain() method. Optional
141 with a default value of None if a stock id is specified.
142 * The accelerator for the action, in the format understood by the
143 gtk.accelerator_parse() function. Optional with a default value of
145 * The tooltip for the action. This field should typically be marked
146 for translation, see the set_translation_domain() method. Optional
147 with a default value of None.
148 * The callback function invoked when the action is activated.
149 Optional with a default value of None.
151 The "activate" signals of the actions are connected to the callbacks and
152 their accel paths are set to <Actions>/group-name/action-name.
157 raise TypeError('entries must be iterable')
159 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
160 action = Action(name, label, tooltip, stock_id)
161 if callback is not None:
162 if user_data is None:
163 action.connect('activate', callback)
165 action.connect('activate', callback, user_data)
167 self.add_action_with_accel(action, accelerator)
170 # using inner function above since entries can leave out optional arguments
173 def add_toggle_actions(self, entries, user_data=None):
175 The add_toggle_actions() method is a convenience method that creates a
176 number of gtk.ToggleAction objects based on the information in the list
177 of action entry tuples contained in entries and adds them to the action
178 group. The toggle action entry tuples can vary in size from one to seven
179 items with the following information:
181 * The name of the action. Must be specified.
182 * The stock id for the action. Optional with a default value of None
183 if a label is specified.
184 * The label for the action. This field should typically be marked
185 for translation, see the set_translation_domain() method. Optional
186 with a default value of None if a stock id is specified.
187 * The accelerator for the action, in the format understood by the
188 gtk.accelerator_parse() function. Optional with a default value of
190 * The tooltip for the action. This field should typically be marked
191 for translation, see the set_translation_domain() method. Optional
192 with a default value of None.
193 * The callback function invoked when the action is activated.
194 Optional with a default value of None.
195 * A flag indicating whether the toggle action is active. Optional
196 with a default value of False.
198 The "activate" signals of the actions are connected to the callbacks and
199 their accel paths are set to <Actions>/group-name/action-name.
205 raise TypeError('entries must be iterable')
207 def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
208 action = Gtk.ToggleAction(name, label, tooltip, stock_id)
209 action.set_active(is_active)
210 if callback is not None:
211 if user_data is None:
212 action.connect('activate', callback)
214 action.connect('activate', callback, user_data)
216 self.add_action_with_accel(action, accelerator)
219 # using inner function above since entries can leave out optional arguments
222 def add_radio_actions(self, entries, value=None, on_change=None, user_data=None):
224 The add_radio_actions() method is a convenience method that creates a
225 number of gtk.RadioAction objects based on the information in the list
226 of action entry tuples contained in entries and adds them to the action
227 group. The entry tuples can vary in size from one to six items with the
228 following information:
230 * The name of the action. Must be specified.
231 * The stock id for the action. Optional with a default value of None
232 if a label is specified.
233 * The label for the action. This field should typically be marked
234 for translation, see the set_translation_domain() method. Optional
235 with a default value of None if a stock id is specified.
236 * The accelerator for the action, in the format understood by the
237 gtk.accelerator_parse() function. Optional with a default value of
239 * The tooltip for the action. This field should typically be marked
240 for translation, see the set_translation_domain() method. Optional
241 with a default value of None.
242 * The value to set on the radio action. Optional with a default
243 value of 0. Should be specified in applications.
245 The value parameter specifies the radio action that should be set
246 active. The "changed" signal of the first radio action is connected to
247 the on_change callback (if specified and not None) and the accel paths
248 of the actions are set to <Actions>/group-name/action-name.
253 raise TypeError('entries must be iterable')
257 def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
258 action = RadioAction(name, label, tooltip, stock_id, entry_value)
260 # FIXME: join_group is a patch to Gtk+ 3.0
261 # otherwise we can't effectively add radio actions to a
262 # group. Should we depend on 3.0 and error out here
263 # or should we offer the functionality via a compat
265 if hasattr(action, 'join_group'):
266 action.join_group(group_source)
268 if value == entry_value:
269 action.set_active(True)
271 self.add_action_with_accel(action, accelerator)
275 # using inner function above since entries can leave out optional arguments
276 action = _process_action(first_action, *e)
277 if first_action is None:
278 first_action = action
280 if first_action is not None and on_change is not None:
281 if user_data is None:
282 first_action.connect('changed', on_change)
284 first_action.connect('changed', on_change, user_data)
286 ActionGroup = override(ActionGroup)
287 __all__.append('ActionGroup')
290 class UIManager(Gtk.UIManager):
291 def add_ui_from_string(self, buffer):
292 if not isinstance(buffer, _basestring):
293 raise TypeError('buffer must be a string')
297 return Gtk.UIManager.add_ui_from_string(self, buffer, length)
299 def insert_action_group(self, buffer, length=-1):
300 return Gtk.UIManager.insert_action_group(self, buffer, length)
302 UIManager = override(UIManager)
303 __all__.append('UIManager')
306 class ComboBox(Gtk.ComboBox, Container):
308 def get_active_iter(self):
309 success, aiter = super(ComboBox, self).get_active_iter()
313 ComboBox = override(ComboBox)
314 __all__.append('ComboBox')
318 def __init__(self, homogeneous=False, spacing=0, **kwds):
319 super(Box, self).__init__(**kwds)
320 self.set_homogeneous(homogeneous)
321 self.set_spacing(spacing)
324 __all__.append('Box')
327 class SizeGroup(Gtk.SizeGroup):
328 def __init__(self, mode=Gtk.SizeGroupMode.VERTICAL):
329 super(SizeGroup, self).__init__(mode=mode)
331 SizeGroup = override(SizeGroup)
332 __all__.append('SizeGroup')
335 class MenuItem(Gtk.MenuItem):
336 def __init__(self, label=None, **kwds):
337 super(MenuItem, self).__init__(label=label, **kwds)
339 MenuItem = override(MenuItem)
340 __all__.append('MenuItem')
343 class Builder(Gtk.Builder):
345 def connect_signals(self, obj_or_map):
346 def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map):
348 if isinstance(obj_or_map, dict):
349 handler = obj_or_map.get(handler_name, None)
351 handler = getattr(obj_or_map, handler_name, None)
354 raise AttributeError('Handler %s not found' % handler_name)
356 if not _callable(handler):
357 raise TypeError('Handler %s is not a method or function' % handler_name)
359 after = flags & GObject.ConnectFlags.AFTER
360 if connect_obj is not None:
362 gobj.connect_object_after(signal_name, handler, connect_obj)
364 gobj.connect_object(signal_name, handler, connect_obj)
367 gobj.connect_after(signal_name, handler)
369 gobj.connect(signal_name, handler)
371 self.connect_signals_full(_full_callback, obj_or_map)
373 def add_from_string(self, buffer):
374 if not isinstance(buffer, _basestring):
375 raise TypeError('buffer must be a string')
379 return Gtk.Builder.add_from_string(self, buffer, length)
381 def add_objects_from_string(self, buffer, object_ids):
382 if not isinstance(buffer, _basestring):
383 raise TypeError('buffer must be a string')
387 return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids)
389 Builder = override(Builder)
390 __all__.append('Builder')
393 # NOTE: This must come before any other Window/Dialog subclassing, to ensure
394 # that we have a correct inheritance hierarchy.
397 class Window(Gtk.Window):
398 def __init__(self, type=Gtk.WindowType.TOPLEVEL, **kwds):
399 Gtk.Window.__init__(self, type=type, **kwds)
401 Window = override(Window)
402 __all__.append('Window')
405 class Dialog(Gtk.Dialog, Container):
412 _buttons_property=None,
415 # buttons is overloaded by PyGtk so we have to do the same here
416 # this breaks some subclasses of Dialog so add a _buttons_property
417 # keyword to work around this
418 if _buttons_property is not None:
419 kwds['buttons'] = _buttons_property
421 Gtk.Dialog.__init__(self, **kwds)
423 self.set_title(title)
425 self.set_transient_for(parent)
426 if flags & Gtk.DialogFlags.MODAL:
428 if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT:
429 self.set_destroy_with_parent(True)
431 # NO_SEPARATOR has been removed from Gtk 3
432 if hasattr(Gtk.DialogFlags, "NO_SEPARATOR") and (flags & Gtk.DialogFlags.NO_SEPARATOR):
433 self.set_has_separator(False)
435 warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", DeprecationWarning)
437 if buttons is not None:
438 self.add_buttons(*buttons)
440 action_area = property(lambda dialog: dialog.get_action_area())
441 vbox = property(lambda dialog: dialog.get_content_area())
443 def add_buttons(self, *args):
445 The add_buttons() method adds several buttons to the Gtk.Dialog using
446 the button data passed as arguments to the method. This method is the
447 same as calling the Gtk.Dialog.add_button() repeatedly. The button data
448 pairs - button text (or stock ID) and a response ID integer are passed
449 individually. For example:
451 >>> dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE)
453 will add "Open" and "Close" buttons to dialog.
462 for text, response in _button(args):
463 self.add_button(text, response)
465 raise TypeError('Must pass an even number of arguments')
467 Dialog = override(Dialog)
468 __all__.append('Dialog')
471 class MessageDialog(Gtk.MessageDialog, Dialog):
475 message_type=Gtk.MessageType.INFO,
476 buttons=Gtk.ButtonsType.NONE,
480 if message_format != None:
481 kwds['text'] = message_format
483 # type keyword is used for backwards compat with PyGTK
486 warnings.warn("The use of the keyword type as a parameter of the Gtk.MessageDialog constructor has been depricated. Please use message_type instead.", DeprecationWarning)
487 message_type = kwds.pop('type')
489 Gtk.MessageDialog.__init__(self,
490 _buttons_property=buttons,
491 message_type=message_type,
496 def format_secondary_text(self, message_format):
497 self.set_property('secondary-use-markup', False)
498 self.set_property('secondary-text', message_format)
500 def format_secondary_markup(self, message_format):
501 self.set_property('secondary-use-markup', True)
502 self.set_property('secondary-text', message_format)
504 MessageDialog = override(MessageDialog)
505 __all__.append('MessageDialog')
508 class AboutDialog(Gtk.AboutDialog):
509 def __init__(self, **kwds):
510 Gtk.AboutDialog.__init__(self, **kwds)
512 AboutDialog = override(AboutDialog)
513 __all__.append('AboutDialog')
516 class ColorSelectionDialog(Gtk.ColorSelectionDialog):
517 def __init__(self, title=None, **kwds):
518 Gtk.ColorSelectionDialog.__init__(self, title=title, **kwds)
520 ColorSelectionDialog = override(ColorSelectionDialog)
521 __all__.append('ColorSelectionDialog')
524 class FileChooserDialog(Gtk.FileChooserDialog):
528 action=Gtk.FileChooserAction.OPEN,
531 Gtk.FileChooserDialog.__init__(self,
537 FileChooserDialog = override(FileChooserDialog)
538 __all__.append('FileChooserDialog')
541 class FontSelectionDialog(Gtk.FontSelectionDialog):
542 def __init__(self, title=None, **kwds):
543 Gtk.FontSelectionDialog.__init__(self, title=title, **kwds)
545 FontSelectionDialog = override(FontSelectionDialog)
546 __all__.append('FontSelectionDialog')
549 class RecentChooserDialog(Gtk.RecentChooserDialog):
557 Gtk.RecentChooserDialog.__init__(self,
558 recent_manager=manager,
564 RecentChooserDialog = override(RecentChooserDialog)
565 __all__.append('RecentChooserDialog')
568 class IconView(Gtk.IconView):
570 def __init__(self, model=None, **kwds):
571 Gtk.IconView.__init__(self, model=model, **kwds)
573 def get_item_at_pos(self, x, y):
574 success, path, cell = super(IconView, self).get_item_at_pos(x, y)
578 def get_visible_range(self):
579 success, start_path, end_path = super(IconView, self).get_visible_range()
581 return (start_path, end_path,)
583 def get_dest_item_at_pos(self, drag_x, drag_y):
584 success, path, pos = super(IconView, self).get_dest_item_at_pos(drag_x, drag_y)
588 IconView = override(IconView)
589 __all__.append('IconView')
592 class ToolButton(Gtk.ToolButton):
594 def __init__(self, stock_id=None, **kwds):
595 Gtk.ToolButton.__init__(self, stock_id=stock_id, **kwds)
597 ToolButton = override(ToolButton)
598 __all__.append('ToolButton')
601 class IMContext(Gtk.IMContext):
603 def get_surrounding(self):
604 success, text, cursor_index = super(IMContext, self).get_surrounding()
606 return (text, cursor_index,)
608 IMContext = override(IMContext)
609 __all__.append('IMContext')
612 class RecentInfo(Gtk.RecentInfo):
614 def get_application_info(self, app_name):
615 success, app_exec, count, time = super(RecentInfo, self).get_application_info(app_name)
617 return (app_exec, count, time,)
619 RecentInfo = override(RecentInfo)
620 __all__.append('RecentInfo')
623 class TextBuffer(Gtk.TextBuffer):
624 def _get_or_create_tag_table(self):
625 table = self.get_tag_table()
627 table = Gtk.TextTagTable()
628 self.set_tag_table(table)
632 def create_tag(self, tag_name=None, **properties):
634 @tag_name: name of the new tag, or None
635 @properties: keyword list of properties and their values
637 Creates a tag and adds it to the tag table of the TextBuffer.
638 Equivalent to creating a Gtk.TextTag and then adding the
639 tag to the buffer's tag table. The returned tag is owned by
640 the buffer's tag table.
642 If @tag_name is None, the tag is anonymous.
644 If @tag_name is not None, a tag called @tag_name must not already
645 exist in the tag table for this buffer.
647 Properties are passed as a keyword list of names and values (e.g.
648 foreground = 'DodgerBlue', weight = Pango.Weight.BOLD)
650 Return value: a new tag
653 tag = Gtk.TextTag(name=tag_name, **properties)
654 self._get_or_create_tag_table().add(tag)
657 def create_mark(self, mark_name, where, left_gravity=False):
658 return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
660 def set_text(self, text, length=-1):
661 Gtk.TextBuffer.set_text(self, text, length)
663 def insert(self, iter, text, length=-1):
664 if not isinstance(text, _basestring):
665 raise TypeError('text must be a string, not %s' % type(text))
667 Gtk.TextBuffer.insert(self, iter, text, length)
669 def insert_with_tags(self, iter, text, *tags):
670 start_offset = iter.get_offset()
671 self.insert(iter, text)
676 start = self.get_iter_at_offset(start_offset)
679 self.apply_tag(tag, start, iter)
681 def insert_with_tags_by_name(self, iter, text, *tags):
688 tag_obj = self.get_tag_table().lookup(tag)
690 raise ValueError('unknown text tag: %s' % tag)
691 tag_objs.append(tag_obj)
693 self.insert_with_tags(iter, text, *tag_objs)
695 def insert_at_cursor(self, text, length=-1):
696 if not isinstance(text, _basestring):
697 raise TypeError('text must be a string, not %s' % type(text))
699 Gtk.TextBuffer.insert_at_cursor(self, text, length)
701 def get_selection_bounds(self):
702 success, start, end = super(TextBuffer, self).get_selection_bounds()
708 TextBuffer = override(TextBuffer)
709 __all__.append('TextBuffer')
712 class TextIter(Gtk.TextIter):
714 def forward_search(self, string, flags, limit):
715 success, match_start, match_end = super(TextIter, self).forward_search(string,
718 return (match_start, match_end)
722 def backward_search(self, string, flags, limit):
723 success, match_start, match_end = super(TextIter, self).backward_search(string,
726 return (match_start, match_end)
730 def begins_tag(self, tag=None):
731 return super(TextIter, self).begins_tag(tag)
733 def ends_tag(self, tag=None):
734 return super(TextIter, self).ends_tag(tag)
736 def toggles_tag(self, tag=None):
737 return super(TextIter, self).toggles_tag(tag)
739 TextIter = override(TextIter)
740 __all__.append('TextIter')
743 class TreeModel(Gtk.TreeModel):
745 return self.iter_n_children(None)
750 # alias for Python 2.x object protocol
751 __nonzero__ = __bool__
753 def __getitem__(self, key):
754 if isinstance(key, Gtk.TreeIter):
755 return TreeModelRow(self, key)
756 elif isinstance(key, int) and key < 0:
757 index = len(self) + key
759 raise IndexError("row index is out of bounds: %d" % key)
761 aiter = self.get_iter(index)
763 raise IndexError("could not find tree path '%s'" % key)
764 return TreeModelRow(self, aiter)
767 aiter = self.get_iter(key)
769 raise IndexError("could not find tree path '%s'" % key)
770 return TreeModelRow(self, aiter)
772 def __setitem__(self, key, value):
774 self.set_row(row.iter, value)
777 return TreeModelRowIter(self, self.get_iter_first())
779 def get_iter(self, path):
780 if not isinstance(path, Gtk.TreePath):
781 path = TreePath(path)
783 success, aiter = super(TreeModel, self).get_iter(path)
785 raise ValueError("invalid tree path '%s'" % path)
788 def get_iter_first(self):
789 success, aiter = super(TreeModel, self).get_iter_first()
793 def get_iter_from_string(self, path_string):
794 success, aiter = super(TreeModel, self).get_iter_from_string(path_string)
796 raise ValueError("invalid tree path '%s'" % path_string)
799 def iter_next(self, aiter):
800 next_iter = aiter.copy()
801 success = super(TreeModel, self).iter_next(next_iter)
805 def iter_previous(self, aiter):
806 prev_iter = aiter.copy()
807 success = super(TreeModel, self).iter_previous(prev_iter)
811 def iter_children(self, aiter):
812 success, child_iter = super(TreeModel, self).iter_children(aiter)
816 def iter_nth_child(self, parent, n):
817 success, child_iter = super(TreeModel, self).iter_nth_child(parent, n)
821 def iter_parent(self, aiter):
822 success, parent_iter = super(TreeModel, self).iter_parent(aiter)
826 def _convert_row(self, row):
827 # TODO: Accept a dictionary for row
828 # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
829 if isinstance(row, str):
830 raise TypeError('Expected a list or tuple, but got str')
832 n_columns = self.get_n_columns()
833 if len(row) != n_columns:
834 raise ValueError('row sequence has the incorrect number of elements')
838 for cur_col, value in enumerate(row):
839 # do not try to set None values, they are causing warnings
842 result.append(self._convert_value(cur_col, value))
843 columns.append(cur_col)
844 return (result, columns)
846 def set_row(self, treeiter, row):
847 converted_row, columns = self._convert_row(row)
848 for column in columns:
851 continue # None means skip this row
853 self.set_value(treeiter, column, value)
855 def _convert_value(self, column, value):
859 # we may need to convert to a basic type
860 type_ = self.get_column_type(column)
861 if type_ == GObject.TYPE_STRING:
862 if isinstance(value, str):
864 elif sys.version_info < (3, 0):
865 if isinstance(value, unicode):
866 value = value.encode('UTF-8')
868 raise ValueError('Expected string or unicode for column %i but got %s%s' % (column, value, type(value)))
870 raise ValueError('Expected a string for column %i but got %s' % (column, type(value)))
871 elif type_ == GObject.TYPE_FLOAT or type_ == GObject.TYPE_DOUBLE:
872 if isinstance(value, float):
875 raise ValueError('Expected a float for column %i but got %s' % (column, type(value)))
876 elif type_ == GObject.TYPE_LONG or type_ == GObject.TYPE_INT:
877 if isinstance(value, int):
879 elif sys.version_info < (3, 0):
880 if isinstance(value, long):
883 raise ValueError('Expected an long for column %i but got %s' % (column, type(value)))
885 raise ValueError('Expected an integer for column %i but got %s' % (column, type(value)))
886 elif type_ == GObject.TYPE_BOOLEAN:
888 if sys.version_info < (3, 0):
889 cmp_classes.append(long)
891 if isinstance(value, tuple(cmp_classes)):
894 raise ValueError('Expected a bool for column %i but got %s' % (column, type(value)))
896 # use GValues directly to marshal to the correct type
897 # standard object checks should take care of validation
898 # so we don't have to do it here
899 value_container = GObject.Value()
900 value_container.init(type_)
901 if type_ == GObject.TYPE_CHAR:
902 value_container.set_char(value)
903 value = value_container
904 elif type_ == GObject.TYPE_UCHAR:
905 value_container.set_uchar(value)
906 value = value_container
907 elif type_ == GObject.TYPE_UNICHAR:
909 if sys.version_info < (3, 0):
910 cmp_classes.append(unicode)
912 if isinstance(value, tuple(cmp_classes)):
913 value = ord(value[0])
915 value_container.set_uint(value)
916 value = value_container
917 elif type_ == GObject.TYPE_UINT:
918 value_container.set_uint(value)
919 value = value_container
920 elif type_ == GObject.TYPE_ULONG:
921 value_container.set_ulong(value)
922 value = value_container
923 elif type_ == GObject.TYPE_INT64:
924 value_container.set_int64(value)
925 value = value_container
926 elif type_ == GObject.TYPE_UINT64:
927 value_container.set_uint64(value)
928 value = value_container
929 elif type_ == GObject.TYPE_PYOBJECT:
930 value_container.set_boxed(value)
931 value = value_container
935 def get(self, treeiter, *columns):
936 n_columns = self.get_n_columns()
940 if not isinstance(col, int):
941 raise TypeError("column numbers must be ints")
943 if col < 0 or col >= n_columns:
944 raise ValueError("column number is out of range")
946 values.append(self.get_value(treeiter, col))
950 def filter_new(self, root=None):
951 return super(TreeModel, self).filter_new(root)
953 TreeModel = override(TreeModel)
954 __all__.append('TreeModel')
957 class TreeSortable(Gtk.TreeSortable, ):
959 def get_sort_column_id(self):
960 success, sort_column_id, order = super(TreeSortable, self).get_sort_column_id()
962 return (sort_column_id, order,)
966 def set_sort_func(self, sort_column_id, sort_func, user_data=None):
967 super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data)
969 def set_default_sort_func(self, sort_func, user_data=None):
970 super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
972 TreeSortable = override(TreeSortable)
973 __all__.append('TreeSortable')
976 class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
977 def __init__(self, *column_types):
978 Gtk.ListStore.__init__(self)
979 self.set_column_types(column_types)
981 def _do_insert(self, position, row):
983 row, columns = self._convert_row(row)
984 treeiter = self.insert_with_valuesv(position, columns, row)
986 treeiter = Gtk.ListStore.insert(self, position)
990 def append(self, row=None):
992 return self._do_insert(-1, row)
993 # gtk_list_store_insert() does not know about the "position == -1"
994 # case, so use append() here
996 return Gtk.ListStore.append(self)
998 def prepend(self, row=None):
999 return self._do_insert(0, row)
1001 def insert(self, position, row=None):
1002 return self._do_insert(position, row)
1004 # FIXME: sends two signals; check if this can use an atomic
1005 # insert_with_valuesv()
1007 def insert_before(self, sibling, row=None):
1008 treeiter = Gtk.ListStore.insert_before(self, sibling)
1011 self.set_row(treeiter, row)
1015 # FIXME: sends two signals; check if this can use an atomic
1016 # insert_with_valuesv()
1018 def insert_after(self, sibling, row=None):
1019 treeiter = Gtk.ListStore.insert_after(self, sibling)
1022 self.set_row(treeiter, row)
1026 def set_value(self, treeiter, column, value):
1027 value = self._convert_value(column, value)
1028 Gtk.ListStore.set_value(self, treeiter, column, value)
1030 def set(self, treeiter, *args):
1032 def _set_lists(columns, values):
1033 if len(columns) != len(values):
1034 raise TypeError('The number of columns do not match the number of values')
1035 for col_num, val in zip(columns, values):
1036 if not isinstance(col_num, int):
1037 raise TypeError('TypeError: Expected integer argument for column.')
1038 self.set_value(treeiter, col_num, val)
1041 if isinstance(args[0], int):
1044 _set_lists(columns, values)
1045 elif isinstance(args[0], (tuple, list)):
1047 raise TypeError('Too many arguments')
1048 _set_lists(args[0], args[1])
1049 elif isinstance(args[0], dict):
1050 columns = args[0].keys()
1051 values = args[0].values()
1052 _set_lists(columns, values)
1054 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1056 ListStore = override(ListStore)
1057 __all__.append('ListStore')
1060 class TreeModelRow(object):
1062 def __init__(self, model, iter_or_path):
1063 if not isinstance(model, Gtk.TreeModel):
1064 raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__)
1066 if isinstance(iter_or_path, Gtk.TreePath):
1067 self.iter = model.get_iter(iter_or_path)
1068 elif isinstance(iter_or_path, Gtk.TreeIter):
1069 self.iter = iter_or_path
1071 raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \
1072 %s found" % type(iter_or_path).__name__)
1076 return self.model.get_path(self.iter)
1080 return self.get_next()
1084 return self.get_parent()
1087 next_iter = self.model.iter_next(self.iter)
1089 return TreeModelRow(self.model, next_iter)
1091 def get_parent(self):
1092 parent_iter = self.model.iter_parent(self.iter)
1094 return TreeModelRow(self.model, parent_iter)
1096 def __getitem__(self, key):
1097 if isinstance(key, int):
1098 if key >= self.model.get_n_columns():
1099 raise IndexError("column index is out of bounds: %d" % key)
1101 key = self._convert_negative_index(key)
1102 return self.model.get_value(self.iter, key)
1103 elif isinstance(key, slice):
1104 start, stop, step = key.indices(self.model.get_n_columns())
1106 for i in range(start, stop, step):
1107 alist.append(self.model.get_value(self.iter, i))
1110 raise TypeError("indices must be integers, not %s" % type(key).__name__)
1112 def __setitem__(self, key, value):
1113 if isinstance(key, int):
1114 if key >= self.model.get_n_columns():
1115 raise IndexError("column index is out of bounds: %d" % key)
1117 key = self._convert_negative_index(key)
1118 self.model.set_value(self.iter, key, value)
1119 elif isinstance(key, slice):
1120 start, stop, step = key.indices(self.model.get_n_columns())
1121 indexList = range(start, stop, step)
1122 if len(indexList) != len(value):
1124 "attempt to assign sequence of size %d to slice of size %d"
1125 % (len(value), len(indexList)))
1127 for i, v in enumerate(indexList):
1128 self.model.set_value(self.iter, v, value[i])
1130 raise TypeError("index must be an integer or slice, not %s" % type(key).__name__)
1132 def _convert_negative_index(self, index):
1133 new_index = self.model.get_n_columns() + index
1135 raise IndexError("column index is out of bounds: %d" % index)
1138 def iterchildren(self):
1139 child_iter = self.model.iter_children(self.iter)
1140 return TreeModelRowIter(self.model, child_iter)
1142 __all__.append('TreeModelRow')
1145 class TreeModelRowIter(object):
1147 def __init__(self, model, aiter):
1154 row = TreeModelRow(self.model, self.iter)
1155 self.iter = self.model.iter_next(self.iter)
1158 # alias for Python 2.x object protocol
1164 __all__.append('TreeModelRowIter')
1167 class TreePath(Gtk.TreePath):
1169 def __new__(cls, path=0):
1170 if isinstance(path, int):
1172 elif isinstance(path, tuple):
1173 path = ":".join(str(val) for val in path)
1176 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1178 return TreePath.new_from_string(path)
1180 raise TypeError("could not parse subscript '%s' as a tree path" % path)
1183 return self.to_string()
1185 def __lt__(self, other):
1186 return not other is None and self.compare(other) < 0
1188 def __le__(self, other):
1189 return not other is None and self.compare(other) <= 0
1191 def __eq__(self, other):
1192 return not other is None and self.compare(other) == 0
1194 def __ne__(self, other):
1195 return other is None or self.compare(other) != 0
1197 def __gt__(self, other):
1198 return other is None or self.compare(other) > 0
1200 def __ge__(self, other):
1201 return other is None or self.compare(other) >= 0
1204 return (int(part) for part in str(self).split(':'))
1206 TreePath = override(TreePath)
1207 __all__.append('TreePath')
1210 class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
1212 def __init__(self, *column_types):
1213 Gtk.TreeStore.__init__(self)
1214 self.set_column_types(column_types)
1216 def _do_insert(self, parent, position, row):
1218 row, columns = self._convert_row(row)
1219 treeiter = self.insert_with_values(parent, position, columns, row)
1221 treeiter = Gtk.TreeStore.insert(self, parent, position)
1225 def append(self, parent, row=None):
1226 return self._do_insert(parent, -1, row)
1228 def prepend(self, parent, row=None):
1229 return self._do_insert(parent, 0, row)
1231 def insert(self, parent, position, row=None):
1232 return self._do_insert(parent, position, row)
1234 # FIXME: sends two signals; check if this can use an atomic
1235 # insert_with_valuesv()
1237 def insert_before(self, parent, sibling, row=None):
1238 treeiter = Gtk.TreeStore.insert_before(self, parent, sibling)
1241 self.set_row(treeiter, row)
1245 # FIXME: sends two signals; check if this can use an atomic
1246 # insert_with_valuesv()
1248 def insert_after(self, parent, sibling, row=None):
1249 treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
1252 self.set_row(treeiter, row)
1256 def set_value(self, treeiter, column, value):
1257 value = self._convert_value(column, value)
1258 Gtk.TreeStore.set_value(self, treeiter, column, value)
1260 def set(self, treeiter, *args):
1262 def _set_lists(columns, values):
1263 if len(columns) != len(values):
1264 raise TypeError('The number of columns do not match the number of values')
1265 for col_num, val in zip(columns, values):
1266 if not isinstance(col_num, int):
1267 raise TypeError('TypeError: Expected integer argument for column.')
1268 self.set_value(treeiter, col_num, val)
1271 if isinstance(args[0], int):
1274 _set_lists(columns, values)
1275 elif isinstance(args[0], (tuple, list)):
1277 raise TypeError('Too many arguments')
1278 _set_lists(args[0], args[1])
1279 elif isinstance(args[0], dict):
1280 columns = args[0].keys()
1281 values = args[0].values()
1282 _set_lists(columns, values)
1284 raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.')
1286 TreeStore = override(TreeStore)
1287 __all__.append('TreeStore')
1290 class TreeView(Gtk.TreeView, Container):
1292 def __init__(self, model=None):
1293 Gtk.TreeView.__init__(self)
1295 self.set_model(model)
1297 def get_path_at_pos(self, x, y):
1298 success, path, column, cell_x, cell_y = super(TreeView, self).get_path_at_pos(x, y)
1300 return (path, column, cell_x, cell_y,)
1302 def get_visible_range(self):
1303 success, start_path, end_path = super(TreeView, self).get_visible_range()
1305 return (start_path, end_path,)
1307 def get_dest_row_at_pos(self, drag_x, drag_y):
1308 success, path, pos = super(TreeView, self).get_dest_row_at_pos(drag_x, drag_y)
1312 def _construct_target_list(self, targets):
1313 # FIXME: this should most likely be part of Widget or a global helper
1317 entry = Gtk.TargetEntry.new(*t)
1318 target_entries.append(entry)
1319 return target_entries
1321 def enable_model_drag_source(self, start_button_mask, targets, actions):
1322 target_entries = self._construct_target_list(targets)
1323 super(TreeView, self).enable_model_drag_source(start_button_mask,
1327 def enable_model_drag_dest(self, targets, actions):
1328 target_entries = self._construct_target_list(targets)
1329 super(TreeView, self).enable_model_drag_dest(target_entries,
1332 def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0):
1333 if not isinstance(path, Gtk.TreePath):
1334 path = TreePath(path)
1335 super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align)
1337 def set_cursor(self, path, column=None, start_editing=False):
1338 if not isinstance(path, Gtk.TreePath):
1339 path = TreePath(path)
1340 super(TreeView, self).set_cursor(path, column, start_editing)
1342 def get_cell_area(self, path, column=None):
1343 if not isinstance(path, Gtk.TreePath):
1344 path = TreePath(path)
1345 return super(TreeView, self).get_cell_area(path, column)
1347 TreeView = override(TreeView)
1348 __all__.append('TreeView')
1351 class TreeViewColumn(Gtk.TreeViewColumn):
1352 def __init__(self, title='',
1355 Gtk.TreeViewColumn.__init__(self, title=title)
1357 self.pack_start(cell_renderer, True)
1359 for (name, value) in attributes.items():
1360 self.add_attribute(cell_renderer, name, value)
1362 def cell_get_position(self, cell_renderer):
1363 success, start_pos, width = super(TreeViewColumn, self).cell_get_position(cell_renderer)
1365 return (start_pos, width,)
1367 def set_cell_data_func(self, cell_renderer, func, func_data=None):
1368 super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data)
1370 TreeViewColumn = override(TreeViewColumn)
1371 __all__.append('TreeViewColumn')
1374 class TreeSelection(Gtk.TreeSelection):
1376 def select_path(self, path):
1377 if not isinstance(path, Gtk.TreePath):
1378 path = TreePath(path)
1379 super(TreeSelection, self).select_path(path)
1381 def get_selected(self):
1382 success, model, aiter = super(TreeSelection, self).get_selected()
1384 return (model, aiter)
1386 return (model, None)
1388 # for compatibility with PyGtk
1390 def get_selected_rows(self):
1391 rows, model = super(TreeSelection, self).get_selected_rows()
1392 return (model, rows)
1395 TreeSelection = override(TreeSelection)
1396 __all__.append('TreeSelection')
1399 class Button(Gtk.Button, Container):
1400 def __init__(self, label=None, stock=None, use_stock=False, use_underline=False, **kwds):
1404 use_underline = True
1405 Gtk.Button.__init__(self, label=label, use_stock=use_stock,
1406 use_underline=use_underline, **kwds)
1407 Button = override(Button)
1408 __all__.append('Button')
1411 class LinkButton(Gtk.LinkButton):
1412 def __init__(self, uri, label=None, **kwds):
1413 Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds)
1415 LinkButton = override(LinkButton)
1416 __all__.append('LinkButton')
1419 class Label(Gtk.Label):
1420 def __init__(self, label=None, **kwds):
1421 Gtk.Label.__init__(self, label=label, **kwds)
1423 Label = override(Label)
1424 __all__.append('Label')
1427 class Adjustment(Gtk.Adjustment):
1428 def __init__(self, *args, **kwds):
1429 arg_names = ('value', 'lower', 'upper',
1430 'step_increment', 'page_increment', 'page_size')
1431 new_args = dict(zip(arg_names, args))
1432 new_args.update(kwds)
1434 # PyGTK compatiblity
1435 if 'page_incr' in new_args:
1436 new_args['page_increment'] = new_args.pop('page_incr')
1437 if 'step_incr' in new_args:
1438 new_args['step_increment'] = new_args.pop('step_incr')
1439 Gtk.Adjustment.__init__(self, **new_args)
1441 # The value property is set between lower and (upper - page_size).
1442 # Just in case lower, upper or page_size was still 0 when value
1443 # was set, we set it again here.
1444 if 'value' in new_args:
1445 self.set_value(new_args['value'])
1447 Adjustment = override(Adjustment)
1448 __all__.append('Adjustment')
1451 class Table(Gtk.Table, Container):
1452 def __init__(self, rows=1, columns=1, homogeneous=False, **kwds):
1453 if 'n_rows' in kwds:
1454 rows = kwds.pop('n_rows')
1456 if 'n_columns' in kwds:
1457 columns = kwds.pop('n_columns')
1459 Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds)
1461 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):
1462 Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
1464 Table = override(Table)
1465 __all__.append('Table')
1468 class ScrolledWindow(Gtk.ScrolledWindow):
1469 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1470 Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds)
1472 ScrolledWindow = override(ScrolledWindow)
1473 __all__.append('ScrolledWindow')
1476 class HScrollbar(Gtk.HScrollbar):
1477 def __init__(self, adjustment=None, **kwds):
1478 Gtk.HScrollbar.__init__(self, adjustment=adjustment, **kwds)
1480 HScrollbar = override(HScrollbar)
1481 __all__.append('HScrollbar')
1484 class VScrollbar(Gtk.VScrollbar):
1485 def __init__(self, adjustment=None, **kwds):
1486 Gtk.VScrollbar.__init__(self, adjustment=adjustment, **kwds)
1488 VScrollbar = override(VScrollbar)
1489 __all__.append('VScrollbar')
1492 class Paned(Gtk.Paned):
1493 def pack1(self, child, resize=False, shrink=True):
1494 super(Paned, self).pack1(child, resize, shrink)
1496 def pack2(self, child, resize=True, shrink=True):
1497 super(Paned, self).pack2(child, resize, shrink)
1499 Paned = override(Paned)
1500 __all__.append('Paned')
1503 class Arrow(Gtk.Arrow):
1504 def __init__(self, arrow_type, shadow_type, **kwds):
1505 Gtk.Arrow.__init__(self, arrow_type=arrow_type,
1506 shadow_type=shadow_type,
1509 Arrow = override(Arrow)
1510 __all__.append('Arrow')
1513 class IconSet(Gtk.IconSet):
1514 def __new__(cls, pixbuf=None):
1515 if pixbuf is not None:
1516 iconset = Gtk.IconSet.new_from_pixbuf(pixbuf)
1518 iconset = Gtk.IconSet.__new__(cls)
1521 IconSet = override(IconSet)
1522 __all__.append('IconSet')
1525 class Viewport(Gtk.Viewport):
1526 def __init__(self, hadjustment=None, vadjustment=None, **kwds):
1527 Gtk.Viewport.__init__(self, hadjustment=hadjustment,
1528 vadjustment=vadjustment,
1531 Viewport = override(Viewport)
1532 __all__.append('Viewport')
1535 class TreeModelFilter(Gtk.TreeModelFilter):
1536 def set_visible_func(self, func, data=None):
1537 super(TreeModelFilter, self).set_visible_func(func, data)
1539 TreeModelFilter = override(TreeModelFilter)
1540 __all__.append('TreeModelFilter')
1542 if Gtk._version != '2.0':
1543 class Menu(Gtk.Menu):
1544 def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time):
1545 self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time)
1546 Menu = override(Menu)
1547 __all__.append('Menu')
1549 _Gtk_main_quit = Gtk.main_quit
1552 @override(Gtk.main_quit)
1553 def main_quit(*args):
1556 _Gtk_stock_lookup = Gtk.stock_lookup
1559 @override(Gtk.stock_lookup)
1560 def stock_lookup(*args):
1561 success, item = _Gtk_stock_lookup(*args)
1567 initialized, argv = Gtk.init_check(sys.argv)
1568 sys.argv = list(argv)
1570 raise RuntimeError("Gtk couldn't be initialized")