Ticket #3715: Initial-Gtk3-Port.diff
File Initial-Gtk3-Port.diff, 43.9 KB (added by humitos, 12 years ago) |
---|
-
anim.py
diff --git a/anim.py b/anim.py index 2c19a15..f34406e 100644
a b 16 16 # along with this program; if not, write to the Free Software 17 17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 18 19 import gobject19 from gi.repository import GObject 20 20 21 21 # Animation timer interval (in msec) 22 22 _TIMER_INTERVAL = 20 … … class Anim(object): 34 34 def start(self): 35 35 self._animating = True 36 36 self._update_func() 37 gobject.timeout_add(_TIMER_INTERVAL, self._timer)37 GObject.timeout_add(_TIMER_INTERVAL, self._timer) 38 38 39 39 def stop(self): 40 40 if self._animating: -
gridwidget.py
diff --git a/gridwidget.py b/gridwidget.py index 8ee3aad..470f37c 100644
a b import logging 20 20 _logger = logging.getLogger('implode-activity.gridwidget') 21 21 22 22 import cairo 23 import gobject 24 import gtk 23 from gi.repository import GObject 24 from gi.repository import Gtk 25 from gi.repository import Gdk 25 26 import math 26 27 import random 27 28 import time … … _ANIM_STAGES = [ 79 80 # Animation time scaling factor (in seconds per tick). 80 81 _ANIM_SCALE = 0.04 81 82 82 #import traceback 83 #def _log_errors(func): 84 # # A function decorator to add error logging to selected functions. 85 # # (For when GTK eats exceptions). 86 # def wrapper(*args, **kwargs): 87 # try: 88 # return func(*args, **kwargs) 89 # except: 90 # _logger.debug(traceback.format_exc()) 91 # raise 92 # return wrapper 93 def _log_errors(func): 94 return func 95 96 class GridWidget(gtk.DrawingArea): 83 84 class GridWidget(Gtk.DrawingArea): 97 85 """Gtk widget for rendering the game board.""" 98 86 99 87 __gsignals__ = { 100 'piece-selected' : ( gobject.SIGNAL_RUN_LAST, None, (int, int)),101 'undo-key-pressed': ( gobject.SIGNAL_RUN_LAST, None, (int,)),102 'redo-key-pressed': ( gobject.SIGNAL_RUN_LAST, None, (int,)),103 'new-key-pressed' : ( gobject.SIGNAL_RUN_LAST, None, (int,)),88 'piece-selected' : (GObject.SignalFlags.RUN_LAST, None, (int, int)), 89 'undo-key-pressed': (GObject.SignalFlags.RUN_LAST, None, (int,)), 90 'redo-key-pressed': (GObject.SignalFlags.RUN_LAST, None, (int,)), 91 'new-key-pressed' : (GObject.SignalFlags.RUN_LAST, None, (int,)), 104 92 'button-press-event': 'override', 105 93 'key-press-event': 'override', 106 'expose-event': 'override', 94 # 'expose-event': 'override', 95 96 # 'draw': 'override', 97 # 'configure-event': 'override', 98 107 99 'size-allocate': 'override', 108 100 'motion-notify-event': 'override', 109 101 } 110 102 111 103 def __init__(self, *args, **kwargs): 112 104 super(GridWidget, self).__init__(*args, **kwargs) 113 self.set_events( gtk.gdk.BUTTON_PRESS_MASK114 | gtk.gdk.POINTER_MOTION_MASK115 | gtk.gdk.KEY_PRESS_MASK)116 self.set_flags(gtk.CAN_FOCUS)105 self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK 106 | Gdk.EventMask.POINTER_MOTION_MASK 107 | Gdk.EventMask.KEY_PRESS_MASK) 108 # self.set_flags(Gtk.CAN_FOCUS) 117 109 118 110 self._board_drawer = BoardDrawer(self._get_size, self._invalidate_rect) 119 111 self._win_drawer = WinDrawer(self._get_size, self._invalidate_rect) 120 112 self._removal_drawer = RemovalDrawer(self._get_size, self._invalidate_rect) 121 113 self._set_current_drawer(self._board_drawer) 122 114 115 self.connect('draw', self.do_draw_event) 116 123 117 def _get_size(self): 124 return (self. allocation.width, self.allocation.height)118 return (self.get_allocated_width(), self.get_allocated_height()) 125 119 126 120 def _invalidate_rect(self, rect): 127 if self. window:128 self. window.invalidate_rect(rect, True)121 if self.get_window(): 122 self.get_window().invalidate_rect(rect, True) 129 123 130 124 def set_board(self, board): 131 125 self._board_drawer.set_board(board) … … class GridWidget(gtk.DrawingArea): 141 135 142 136 def _invalidate_board(self): 143 137 (width, height) = self._get_size() 144 self._invalidate_rect(gtk.gdk.Rectangle(0, 0, width, height)) 138 rect = Gdk.Rectangle() 139 rect.x, rect.y, rect.width, rect.height = (0, 0, width, height) 140 self._invalidate_rect(rect) 145 141 146 142 def get_win_draw_flag(self): 147 143 return (self._current_drawer is self._win_drawer) … … class GridWidget(gtk.DrawingArea): 159 155 def select_center_cell(self): 160 156 self._board_drawer.select_center_cell() 161 157 162 @_log_errors163 158 def do_button_press_event(self, event): 164 159 # Ignore mouse clicks while animating. 165 160 if self._is_animating(): 166 161 return True 167 162 # Ignore double- and triple-clicks. 168 if event.type != gtk.gdk.BUTTON_PRESS:163 if event.type != Gdk.EventType.BUTTON_PRESS: 169 164 return True 170 165 self.grab_focus() 171 166 self._board_drawer.set_mouse_selection(event.x, event.y) … … class GridWidget(gtk.DrawingArea): 174 169 self.emit('piece-selected', *selected_cell) 175 170 return True 176 171 177 @_log_errors178 172 def do_key_press_event(self, event): 179 173 action = KEY_MAP.get(event.keyval, None) 180 174 if action == 'new': … … class GridWidget(gtk.DrawingArea): 209 203 else: 210 204 return False 211 205 212 @_log_errors213 206 def do_motion_notify_event(self, event): 214 207 # Ignore mouse motion while animating. 215 208 if self._is_animating(): … … class GridWidget(gtk.DrawingArea): 219 212 else: 220 213 x = event.x 221 214 y = event.y 222 state = event. state215 state = event.get_state() 223 216 self._board_drawer.set_mouse_selection(x, y) 224 217 225 @_log_errors226 def do_expose_event(self, event):227 cr = self. window.cairo_create()218 def do_draw_event(self, event): 219 logging.debug('do_draw_event()') 220 cr = self.get_window().cairo_create() 228 221 cr.rectangle(event.area.x, 229 222 event.area.y, 230 223 event.area.width, 231 224 event.area.height) 232 225 cr.clip() 233 (width, height) = self. window.get_size()226 (width, height) = self.get_window().get_size() 234 227 self._current_drawer.draw(cr, width, height) 235 228 236 @_log_errors237 229 def do_size_allocate(self, allocation): 238 super(GridWidget, self).do_size_allocate(self, allocation) 230 # super(GridWidget, self).do_size_allocate(self, allocation) 231 logging.debug('do_size_allocate(): %s, %s', allocation.width, allocation.height) 232 self.allocation = allocation 239 233 self._current_drawer.resize(allocation.width, allocation.height) 240 234 241 235 def _set_current_drawer(self, drawer): … … class BoardDrawer(object): 382 376 383 377 def _invalidate_board(self): 384 378 (width, height) = self._get_size_func() 385 rect = gtk.gdk.Rectangle(0, 0, width, height) 379 rect = Gdk.Rectangle() 380 rect.x, rect.y, rect.width, rect.height = (0, 0, width, height) 386 381 self._invalidate_rect_func(rect) 387 382 388 383 def _invalidate_selection(self, selection_coord): … … class BoardDrawer(object): 407 402 max_x2 = math.ceil( max(pt1[0], pt2[0])) + 1 408 403 min_y2 = math.floor(min(pt1[1], pt2[1])) - 1 409 404 max_y2 = math.ceil( max(pt1[1], pt2[1])) + 1 410 rect = gtk.gdk.Rectangle(int(min_x2), 405 rect = Gdk.Rectangle() 406 rect.x, rect.y, rect.width, rect.height = (int(min_x2), 411 407 int(min_y2), 412 408 int(max_x2 - min_x2), 413 409 int(max_y2 - min_y2)) … … class BoardDrawer(object): 425 421 if not self.board_is_valid(): 426 422 self._board_transform = _BoardTransform() 427 423 else: 424 # logging.debug('width: %s, height: %s | self._board_width: %s, self._board_height: %s', 425 # width, height, self._board_width, self._board_height) 428 426 self._board_transform = _BoardTransform() 429 self._board_transform.setup(width, 430 height, 431 self._board_width, 432 self._board_height) 427 self._board_transform.setup(width, height, self._board_width, 428 self._board_height) 433 429 434 430 def draw(self, cr, width, height): 435 431 # Draws the widget. … … class RemovalDrawer(object): 564 560 565 561 def _invalidate_board(self): 566 562 (width, height) = self._get_size_func() 567 rect = gtk.gdk.Rectangle(0, 0, width, height) 563 rect = Gdk.Rectangle() 564 rect.x, rect.y, rect.width, rect.height = (0, 0, width, height) 568 565 self._invalidate_rect_func(rect) 569 566 570 567 def _recalc_game_anim_frames(self): … … class WinDrawer(object): 810 807 811 808 def _invalidate_board(self): 812 809 (width, height) = self._get_size_func() 813 rect = gtk.gdk.Rectangle(0, 0, width, height) 810 rect = Gdk.Rectangle() 811 rect.x, rect.y, rect.width, rect.height = (0, 0, width, height) 814 812 self._invalidate_rect_func(rect) 815 813 816 814 def _get_win_tiles(self): -
helpwidget.py
diff --git a/helpwidget.py b/helpwidget.py index af205e6..c4a2919 100644
a b from __future__ import with_statement 21 21 from gettext import gettext as _ 22 22 23 23 import cairo 24 import gobject 25 import gtk 24 25 from gi.repository import GObject 26 from gi.repository import Gtk 27 from gi.repository import Gdk 28 from gi.repository import Rsvg 29 26 30 import math 27 31 import os 28 import rsvg29 32 import time 30 33 31 34 import board … … from anim import Anim 33 36 from gridwidget import BoardDrawer, RemovalDrawer, WinDrawer 34 37 35 38 if 'SUGAR_BUNDLE_PATH' in os.environ: 36 from sugar .graphics import style39 from sugar3.graphics import style 37 40 _DEFAULT_SPACING = style.DEFAULT_SPACING 38 41 _DEFAULT_PADDING = style.DEFAULT_PADDING 39 42 _BG_COLOR = tuple(style.COLOR_SELECTION_GREY.get_rgba()[:3]) … … _CLICK_SPEED = 0.2 75 78 # Speed of the mouse, in units (4x3 per screen) per second. 76 79 _MOUSE_SPEED = 0.5 77 80 78 class HelpWidget( gtk.EventBox):81 class HelpWidget(Gtk.EventBox): 79 82 def __init__(self, icon_file_func, *args, **kwargs): 80 83 super(HelpWidget, self).__init__(*args, **kwargs) 81 84 82 vbox = gtk.VBox()85 vbox = Gtk.VBox() 83 86 self.add(vbox) 84 87 85 88 self._stages = [ … … class HelpWidget(gtk.EventBox): 90 93 _HelpStage5(icon_file_func), 91 94 ] 92 95 self._stage_index = 0 93 self._notebook = gtk.Notebook()96 self._notebook = Gtk.Notebook() 94 97 self._notebook.set_show_tabs(False) 95 98 for stage in self._stages: 96 self._notebook.append_page(stage )97 vbox.pack_start(self._notebook )99 self._notebook.append_page(stage, None) 100 vbox.pack_start(self._notebook, True, True, 0) 98 101 99 102 self._reset_current_stage() 100 103 … … class HelpWidget(gtk.EventBox): 128 131 self._stages[self._stage_index].reset() 129 132 130 133 131 class _HelpStage( gtk.EventBox):134 class _HelpStage(Gtk.EventBox): 132 135 # An abstract parent class for objects that represent an animated help 133 136 # screen widget with a description. 134 137 def __init__(self, icon_file_func, *args, **kwargs): 135 138 super(_HelpStage, self).__init__(*args, **kwargs) 136 139 137 hbox = gtk.HBox()140 hbox = Gtk.HBox() 138 141 self.add(hbox) 139 142 140 vbox = gtk.VBox() 141 hbox.pack_start(vbox, expand=True, padding=_DEFAULT_SPACING) 143 vbox = Gtk.VBox() 144 hbox.pack_start(vbox, expand=True, fill=False, 145 padding=_DEFAULT_SPACING) 142 146 143 147 self.preview = _PreviewWidget(icon_file_func) 144 vbox.pack_start(self.preview, expand=True, padding=_DEFAULT_PADDING) 148 vbox.pack_start(self.preview, expand=True, fill=False, 149 padding=_DEFAULT_PADDING) 145 150 146 label = gtk.Label(self.get_message())151 label = Gtk.Label(label=self.get_message()) 147 152 label.set_line_wrap(True) 148 vbox.pack_start(label, expand=False, padding=_DEFAULT_PADDING) 153 vbox.pack_start(label, expand=False, fill=False, 154 padding=_DEFAULT_PADDING) 149 155 150 156 self.board = None 151 157 self.undo_stack = [] … … def _undo(): 552 558 stage.next_action() 553 559 return action 554 560 555 class _PreviewWidget( gtk.DrawingArea):561 class _PreviewWidget(Gtk.DrawingArea): 556 562 __gsignals__ = { 557 'expose-event': 'override',563 # 'expose-event': 'override', 558 564 'size-allocate': 'override', 559 565 } 560 566 … … class _PreviewWidget(gtk.DrawingArea): 573 579 574 580 self._icon_file_func = icon_file_func 575 581 576 self._preview_rect = gtk.gdk.Rectangle(0, 0, 0, 0) 577 self._toolbar_rect = gtk.gdk.Rectangle(0, 0, 0, 0) 578 self._drawer_rect = gtk.gdk.Rectangle(0, 0, 0, 0) 582 # self._preview_rect = (0, 0, 0, 0) 583 # self._toolbar_rect = (0, 0, 0, 0) 584 # self._drawer_rect = (0, 0, 0, 0) 585 586 self._preview_rect = Gdk.Rectangle() 587 self._preview_rect.x = self._preview_rect.y = \ 588 self._preview_rect.width = self._preview_rect.height = 0 589 590 self._toolbar_rect = Gdk.Rectangle() 591 self._toolbar_rect.x = self._toolbar_rect.y = \ 592 self._toolbar_rect.width = self._toolbar_rect.height = 0 593 594 self._drawer_rect = Gdk.Rectangle() 595 self._drawer_rect.x = self._drawer_rect.y = \ 596 self._drawer_rect.width = self._drawer_rect.height = 0 579 597 580 598 self._drawer = self.board_drawer 581 599 … … class _PreviewWidget(gtk.DrawingArea): 593 611 return (self._drawer_rect.width, self._drawer_rect.height) 594 612 595 613 def _invalidate_drawer_rect(self, rect): 596 if self. window:614 if self.get_window(): 597 615 (x, y) = (self._drawer_rect.x, self._drawer_rect.y) 598 offset_rect = gtk.gdk.Rectangle(rect.x + x, 599 rect.y + y, 600 rect.width, 601 rect.height) 602 self.window.invalidate_rect(offset_rect, True) 616 rect = Gdk.Rectangle() 617 rect.x, rect.y, rect.width, rect.height = ( 618 rect.x + x, 619 rect.y + y, 620 rect.width, 621 rect.height) 622 self.get_window().invalidate_rect(rect, True) 603 623 604 624 def set_drawer(self, drawer): 605 625 self._drawer = drawer … … class _PreviewWidget(gtk.DrawingArea): 667 687 self._invalidate_client_rect(pixel_x - r, pixel_y - r, r2, r2) 668 688 669 689 def _invalidate_client_rect(self, x, y, width, height): 670 if self.window: 671 rect = gtk.gdk.Rectangle( 690 if self.get_window(): 691 rect = Gdk.Rectangle() 692 rect.x, rect.y, rect.width, rect.height = ( 672 693 int(math.floor(x)) + self._preview_rect.x, 673 694 int(math.floor(y)) + self._preview_rect.y, 674 695 int(math.ceil(width)) + 1, 675 696 int(math.ceil(height)) + 1) 676 self. window.invalidate_rect(rect, True)697 self.get_window().invalidate_rect(rect, True) 677 698 678 699 def _update_mouse_position(self): 679 700 (pixel_x, pixel_y) = self._get_cursor_pixel_coords() … … class _PreviewWidget(gtk.DrawingArea): 681 702 self.board_drawer.set_mouse_selection(x, y) 682 703 683 704 def do_expose_event(self, event): 684 cr = self. window.cairo_create()705 cr = self.get_window().cairo_create() 685 706 cr.rectangle(event.area.x, 686 707 event.area.y, 687 708 event.area.width, 688 709 event.area.height) 689 710 cr.clip() 690 (width, height) = self. window.get_size()711 (width, height) = self.get_window().get_size() 691 712 self._draw(cr, width, height) 692 713 693 714 def _draw(self, cr, width, height): … … class _PreviewWidget(gtk.DrawingArea): 804 825 cr.restore() 805 826 806 827 def do_size_allocate(self, allocation): 807 super(_PreviewWidget, self).do_size_allocate(self, allocation)828 # super(_PreviewWidget, self).do_size_allocate(self, allocation) 808 829 (width, height) = (allocation.width, allocation.height) 809 830 810 831 avail_width = width - _DEFAULT_SPACING * 2 … … class _PreviewWidget(gtk.DrawingArea): 829 850 old_width = self._preview_rect.width 830 851 old_height = self._preview_rect.height 831 852 832 self._preview_rect = gtk.gdk.Rectangle(x_offset, 833 y_offset, 834 actual_width, 835 actual_height) 836 self._toolbar_rect = gtk.gdk.Rectangle(x_offset, 837 y_offset, 838 actual_width, 839 icon_height) 840 self._drawer_rect = gtk.gdk.Rectangle(x_offset, 841 y_offset + icon_height, 842 actual_width, 843 board_height) 853 # self._preview_rect = (x_offset, 854 # y_offset, 855 # actual_width, 856 # actual_height) 857 858 self._preview_rect = Gdk.Rectangle() 859 self._preview_rect.x = x_offset 860 self._preview_rect.y = y_offset 861 self._preview_rect.width = actual_width 862 self._preview_rect.height = actual_height 863 864 # self._toolbar_rect = (x_offset, 865 # y_offset, 866 # actual_width, 867 # icon_height) 868 869 self.toolbar_rect = Gdk.Rectangle() 870 self.toolbar_rect.x = x_offset 871 self.toolbar_rect.y = y_offset 872 self.toolbar_rect.width = actual_width 873 self.toolbar_rect.height = icon_height 874 875 # self._drawer_rect = (x_offset, 876 # y_offset + icon_height, 877 # actual_width, 878 # board_height) 879 880 self._drawer_rect = Gdk.Rectangle() 881 self._drawer_rect.x = x_offset 882 self._drawer_rect.y = y_offset + icon_height 883 self._drawer_rect.width = actual_width 884 self._drawer_rect.height = board_height 885 844 886 self.board_drawer.resize(actual_width, board_height) 845 887 self.removal_drawer.resize(actual_width, board_height) 846 888 self.win_drawer.resize(actual_width, board_height) … … def _get_icon_handle(file_path): 886 928 if file_path not in _icon_handles: 887 929 with open(file_path, 'r') as f: 888 930 data = f.read() 889 _icon_handles[file_path] = rsvg.Handle(data=data)931 _icon_handles[file_path] = Rsvg.Handle.new_from_data(data) 890 932 891 933 return _icon_handles[file_path] -
implodeactivity.py
diff --git a/implodeactivity.py b/implodeactivity.py index 3e4cb2f..e3a4386 100644
a b _logger = logging.getLogger('implode-activity') 21 21 22 22 from gettext import gettext as _ 23 23 24 from sugar.activity.activity import Activity, get_bundle_path 25 from sugar.graphics import style 26 from sugar.graphics.icon import Icon 27 from sugar.graphics.radiotoolbutton import RadioToolButton 28 from sugar.graphics.toolbutton import ToolButton 29 30 try: 31 # 0.86+ toolbar widgets 32 from sugar.activity.widgets import ActivityToolbarButton, StopButton 33 from sugar.graphics.toolbarbox import ToolbarBox, ToolbarButton 34 _USE_OLD_TOOLBARS = False 35 except ImportError: 36 # Pre-0.86 toolbar widgets 37 from sugar.activity.activity import ActivityToolbox 38 _USE_OLD_TOOLBARS = True 24 from sugar3.activity.activity import Activity, get_bundle_path 25 from sugar3.graphics import style 26 from sugar3.graphics.icon import Icon 27 from sugar3.graphics.radiotoolbutton import RadioToolButton 28 from sugar3.graphics.toolbutton import ToolButton 29 30 from sugar3.activity.widgets import ActivityToolbarButton, StopButton 31 from sugar3.graphics.toolbarbox import ToolbarBox, ToolbarButton 39 32 40 33 from implodegame import ImplodeGame 41 34 from helpwidget import HelpWidget 42 35 43 36 import os 44 37 45 try: 46 import json 47 json.dumps 48 except (ImportError, AttributeError): 49 import simplejson as json 38 import json 50 39 from StringIO import StringIO 51 import gtk 52 import gobject 40 from gi.repository import Gtk 41 from gi.repository import GObject 42 from gi.repository import Gdk 53 43 54 44 from keymap import KEY_MAP 55 45 … … class ImplodeActivity(Activity): 63 53 64 54 self._game = ImplodeGame() 65 55 66 game_box = gtk.VBox()67 game_box.pack_start(self._game )56 game_box = Gtk.VBox() 57 game_box.pack_start(self._game, True, True, 0) 68 58 self._stuck_strip = _StuckStrip() 69 59 70 60 self._configure_toolbars() … … class ImplodeActivity(Activity): 73 63 74 64 # Show everything except the stuck strip. 75 65 self.show_all() 76 game_box.pack_end(self._stuck_strip, expand=False )66 game_box.pack_end(self._stuck_strip, expand=False, fill=False, padding=0) 77 67 78 68 self._game.connect('show-stuck', self._show_stuck_cb) 79 69 self._stuck_strip.connect('undo-clicked', self._stuck_undo_cb) … … class ImplodeActivity(Activity): 121 111 if data: 122 112 self._stuck_strip.show_all() 123 113 else: 124 if self._stuck_strip.focus_child: 125 self._game.grab_focus() 114 # if self._stuck_strip.focus_child: 115 # self._game.grab_focus() 116 self._game.grab_focus() 126 117 self._stuck_strip.hide() 127 118 128 119 def _stuck_undo_cb(self, state, data=None): … … class ImplodeActivity(Activity): 133 124 action = KEY_MAP.get(event.keyval, None) 134 125 if action is None: 135 126 return False 136 if not self._stuck_strip.flags() & gtk.VISIBLE:127 if not self._stuck_strip.flags() & Gtk.VISIBLE: 137 128 return True 138 129 if self._game.focus_child: 139 130 if action == 'down': … … class ImplodeActivity(Activity): 152 143 controls, difficulty selector, help button, and stop button. All 153 144 callbacks are locally defined.""" 154 145 155 if _USE_OLD_TOOLBARS: 156 toolbox = ActivityToolbox(self) 157 toolbar = gtk.Toolbar() 158 else: 159 toolbar_box = ToolbarBox() 160 toolbar = toolbar_box.toolbar 146 toolbar_box = ToolbarBox() 147 toolbar = toolbar_box.toolbar 161 148 162 163 164 149 activity_button = ActivityToolbarButton(self) 150 toolbar_box.toolbar.insert(activity_button, 0) 151 activity_button.show() 165 152 166 toolbar.add(gtk.SeparatorToolItem())153 toolbar.add(Gtk.SeparatorToolItem()) 167 154 168 155 def add_button(icon_name, tooltip, func): 169 156 def callback(source): … … class ImplodeActivity(Activity): 176 163 add_button('new-game' , _("New") , self._game.new_game) 177 164 add_button('replay-game', _("Replay"), self._game.replay_game) 178 165 179 toolbar.add( gtk.SeparatorToolItem())166 toolbar.add(Gtk.SeparatorToolItem()) 180 167 181 168 add_button('edit-undo' , _("Undo") , self._game.undo) 182 169 add_button('edit-redo' , _("Redo") , self._game.redo) 183 170 184 toolbar.add( gtk.SeparatorToolItem())171 toolbar.add(Gtk.SeparatorToolItem()) 185 172 186 173 self._levels_buttons = [] 187 174 def add_level_button(icon_name, tooltip, numeric_level): … … class ImplodeActivity(Activity): 217 204 # right now, however. 218 205 add_button('help-icon', _("Help"), _help_clicked_cb) 219 206 220 if _USE_OLD_TOOLBARS: 221 toolbox.add_toolbar(_("Game"), toolbar) 222 toolbox.set_current_toolbar(1) 223 224 self.set_toolbox(toolbox) 225 toolbox.show() 226 else: 227 stop_button = StopButton(self) 228 stop_button.props.accelerator = '<Ctrl><Shift>Q' 229 toolbar_box.toolbar.insert(stop_button, -1) 230 stop_button.show() 207 stop_button = StopButton(self) 208 stop_button.props.accelerator = '<Ctrl><Shift>Q' 209 toolbar_box.toolbar.insert(stop_button, -1) 210 stop_button.show() 231 211 232 233 212 self.set_toolbar_box(toolbar_box) 213 toolbar_box.show() 234 214 235 215 def _add_expander(self, toolbar, expand=True): 236 216 """Insert a toolbar item which will expand to fill the available 237 217 space.""" 238 separator = gtk.SeparatorToolItem()218 separator = Gtk.SeparatorToolItem() 239 219 separator.props.draw = False 240 220 separator.set_expand(expand) 241 221 toolbar.insert(separator, -1) 242 222 separator.show() 243 223 244 224 245 class _DialogWindow( gtk.Window):225 class _DialogWindow(Gtk.Window): 246 226 # A base class for a modal dialog window. 247 227 def __init__(self, icon_name, title): 248 228 super(_DialogWindow, self).__init__() 249 229 250 230 self.set_border_width(style.LINE_WIDTH) 251 231 offset = style.GRID_CELL_SIZE 252 width = gtk.gdk.screen_width() / 2253 height = gtk.gdk.screen_height() / 2232 width = Gdk.Screen.width() / 2 233 height = Gdk.Screen.height() / 2 254 234 self.set_size_request(width, height) 255 self.set_position( gtk.WIN_POS_CENTER_ALWAYS)235 self.set_position(Gtk.WindowPosition.CENTER_ALWAYS) 256 236 self.set_decorated(False) 257 237 self.set_resizable(False) 258 238 self.set_modal(True) 259 239 260 vbox = gtk.VBox()240 vbox = Gtk.VBox() 261 241 self.add(vbox) 262 242 263 243 toolbar = _DialogToolbar(icon_name, title) 264 244 toolbar.connect('stop-clicked', self._stop_clicked_cb) 265 vbox.pack_start(toolbar, False)245 vbox.pack_start(toolbar, expand=False, fill=False, padding=0) 266 246 267 self.content_vbox = gtk.VBox()247 self.content_vbox = Gtk.VBox() 268 248 self.content_vbox.set_border_width(style.DEFAULT_SPACING) 269 249 vbox.add(self.content_vbox) 270 250 … … class _DialogWindow(gtk.Window): 274 254 self.destroy() 275 255 276 256 def _realize_cb(self, source): 277 self. window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)278 self. window.set_accept_focus(True)257 self.set_type_hint(Gdk.WindowTypeHint.DIALOG) 258 self.get_window().set_accept_focus(True) 279 259 280 260 281 261 class _HelpWindow(_DialogWindow): … … class _HelpWindow(_DialogWindow): 284 264 super(_HelpWindow, self).__init__('help-icon', _("Help")) 285 265 286 266 offset = style.GRID_CELL_SIZE 287 width = gtk.gdk.screen_width() - offset * 2288 height = gtk.gdk.screen_height() - offset * 2267 width = Gdk.Screen.width() - offset * 2 268 height = Gdk.Screen.height() - offset * 2 289 269 self.set_size_request(width, height) 290 270 291 271 self._help_widget = HelpWidget(self._icon_file) 292 self.content_vbox.pack_start(self._help_widget )272 self.content_vbox.pack_start(self._help_widget, True, True, 0) 293 273 294 274 self._help_nav_bar = _HelpNavBar() 295 self.content_vbox.pack_end(self._help_nav_bar, 296 expand=False, 297 padding=style.DEFAULT_SPACING) 275 self.content_vbox.pack_end(self._help_nav_bar, expand=False, 276 fill=False, padding=style.DEFAULT_SPACING) 298 277 299 278 for (signal_name, callback) in [ 300 279 ('forward-clicked', self._forward_clicked_cb), … … class _HelpWindow(_DialogWindow): 316 295 self._help_widget.replay_stage() 317 296 318 297 def _icon_file(self, icon_name): 319 theme = gtk.icon_theme_get_default()298 theme = Gtk.IconTheme.get_default() 320 299 info = theme.lookup_icon(icon_name, 0, 0) 321 300 return info.get_filename() 322 301 … … class _HelpWindow(_DialogWindow): 326 305 self._help_nav_bar.set_can_next_stage(hw.can_next_stage()) 327 306 328 307 329 class _DialogToolbar( gtk.Toolbar):308 class _DialogToolbar(Gtk.Toolbar): 330 309 # Displays a dialog window's toolbar, with title, icon, and close box. 331 310 __gsignals__ = { 332 'stop-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),311 'stop-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 333 312 } 334 313 def __init__(self, icon_name, title): 335 314 super(_DialogToolbar, self).__init__() 336 315 337 316 icon = Icon() 338 icon.set_from_icon_name(icon_name, gtk.ICON_SIZE_LARGE_TOOLBAR)317 icon.set_from_icon_name(icon_name, Gtk.IconSize.LARGE_TOOLBAR) 339 318 self._add_widget(icon) 340 319 341 320 self._add_separator() 342 321 343 label = gtk.Label(title)322 label = Gtk.Label(label=title) 344 323 self._add_widget(label) 345 324 346 325 self._add_separator(expand=True) … … class _DialogToolbar(gtk.Toolbar): 351 330 self.add(stop) 352 331 353 332 def _add_separator(self, expand=False): 354 separator = gtk.SeparatorToolItem()333 separator = Gtk.SeparatorToolItem() 355 334 separator.set_expand(expand) 356 335 separator.set_draw(False) 357 336 self.add(separator) 358 337 359 338 def _add_widget(self, widget): 360 tool_item = gtk.ToolItem()339 tool_item = Gtk.ToolItem() 361 340 tool_item.add(widget) 362 341 self.add(tool_item) 363 342 … … class _DialogToolbar(gtk.Toolbar): 365 344 self.emit('stop-clicked') 366 345 367 346 368 class _HelpNavBar( gtk.HButtonBox):347 class _HelpNavBar(Gtk.HButtonBox): 369 348 # A widget to display the navigation controls at the bottom of the help 370 349 # dialog. 371 350 __gsignals__ = { 372 'forward-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),373 'back-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),374 'reload-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),351 'forward-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 352 'back-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 353 'reload-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 375 354 } 376 355 377 356 def __init__(self): 378 357 super(_HelpNavBar, self).__init__() 379 358 380 self.set_layout( gtk.BUTTONBOX_SPREAD)359 self.set_layout(Gtk.ButtonBoxStyle.SPREAD) 381 360 382 361 def add_button(icon_name, tooltip, signal_name): 383 362 icon = Icon() 384 icon.set_from_icon_name(icon_name, gtk.ICON_SIZE_LARGE_TOOLBAR)385 button = gtk.Button()363 icon.set_from_icon_name(icon_name, Gtk.IconSize.LARGE_TOOLBAR) 364 button = Gtk.Button() 386 365 button.set_image(icon) 387 366 button.set_tooltip_text(tooltip) 388 367 self.add(button) … … class _HelpNavBar(gtk.HButtonBox): 404 383 self._forward_button.set_sensitive(can_next_stage) 405 384 406 385 407 class _StuckStrip( gtk.HBox):386 class _StuckStrip(Gtk.HBox): 408 387 __gsignals__ = { 409 'undo-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),388 'undo-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 410 389 } 411 390 def __init__(self, *args, **kwargs): 412 391 super(_StuckStrip, self).__init__(*args, **kwargs) 413 392 414 spacer1 = gtk.Label('')415 self.pack_start(spacer1, expand=True)393 spacer1 = Gtk.Label(label='') 394 self.pack_start(spacer1, True, True, 0) 416 395 417 spacer2 = gtk.Label('')418 self.pack_end(spacer2, expand=True )396 spacer2 = Gtk.Label(label='') 397 self.pack_end(spacer2, expand=True, fill=False, padding=0) 419 398 420 399 self.set_spacing(10) 421 400 422 401 self.set_border_width(10) 423 402 424 label = gtk.Label(_("Stuck? You can still solve the puzzle."))425 self.pack_start(label, expand=False)403 label = Gtk.Label(label=_("Stuck? You can still solve the puzzle.")) 404 self.pack_start(label, False, True, 0) 426 405 427 406 icon = Icon() 428 icon.set_from_icon_name('edit-undo', gtk.ICON_SIZE_LARGE_TOOLBAR)429 self.button = gtk.Button(stock=gtk.STOCK_UNDO)407 icon.set_from_icon_name('edit-undo', Gtk.IconSize.LARGE_TOOLBAR) 408 self.button = Gtk.Button(stock=Gtk.STOCK_UNDO) 430 409 self.button.set_image(icon) 431 410 self.button.set_label(_("Undo some moves")) 432 self.pack_end(self.button, expand=False )411 self.pack_end(self.button, expand=False, fill=False, padding=0) 433 412 434 413 def callback(source): 435 414 self.emit('undo-clicked') -
implodegame.py
diff --git a/implodegame.py b/implodegame.py index 60c507c..7841d69 100644
a b _logger = logging.getLogger('implode-activity.implodegame') 21 21 22 22 from gettext import gettext as _ 23 23 24 import gtk25 import gobject24 from gi.repository import Gtk 25 from gi.repository import GObject 26 26 import random 27 27 import time 28 28 … … _STUCK_DELAY = 0.5 39 39 # state after the player gets stuck, in seconds. 40 40 _UNDO_DELAY = 0.3 41 41 42 class ImplodeGame( gtk.EventBox):42 class ImplodeGame(Gtk.EventBox): 43 43 """Gtk widget for playing the implode game.""" 44 44 45 45 __gsignals__ = { 46 'show-stuck': ( gobject.SIGNAL_RUN_LAST, None, (int,)),46 'show-stuck': (GObject.SignalFlags.RUN_LAST, None, (int,)), 47 47 } 48 48 49 49 def __init__(self, *args, **kwargs): -
keymap.py
diff --git a/keymap.py b/keymap.py index b420ace..0322b22 100644
a b 16 16 # along with this program; if not, write to the Free Software 17 17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 18 19 import gtk19 from gi.repository import Gdk 20 20 21 21 KEY_MAP = { 22 gtk.keysyms.KP_Up : 'up',23 gtk.keysyms.KP_Down : 'down',24 gtk.keysyms.KP_Left : 'left',25 gtk.keysyms.KP_Right : 'right',26 27 gtk.keysyms.w : 'up',28 gtk.keysyms.s : 'down',29 gtk.keysyms.a : 'left',30 gtk.keysyms.d : 'right',31 32 gtk.keysyms.KP_8 : 'up',33 gtk.keysyms.KP_2 : 'down',34 gtk.keysyms.KP_4 : 'left',35 gtk.keysyms.KP_6 : 'right',36 37 gtk.keysyms.Up : 'up',38 gtk.keysyms.Down : 'down',39 gtk.keysyms.Left : 'left',40 gtk.keysyms.Right : 'right',41 42 gtk.keysyms.uparrow : 'up',43 gtk.keysyms.downarrow : 'down',44 gtk.keysyms.leftarrow : 'left',45 gtk.keysyms.rightarrow : 'right',46 47 gtk.keysyms.Return : 'select',48 gtk.keysyms.KP_Space : 'select',49 gtk.keysyms.KP_Enter : 'select',50 gtk.keysyms.space : 'select',51 gtk.keysyms.End : 'select',52 gtk.keysyms.KP_End : 'select',53 gtk.keysyms.KP_1 : 'select',54 gtk.keysyms.q : 'select',55 56 gtk.keysyms.Home : 'new',57 gtk.keysyms.KP_Home : 'new',58 gtk.keysyms.Page_Down : 'redo',59 gtk.keysyms.KP_Page_Down : 'redo',60 gtk.keysyms.Page_Up : 'undo',61 gtk.keysyms.KP_Page_Up : 'undo',22 Gdk.KEY_KP_Up : 'up', 23 Gdk.KEY_KP_Down : 'down', 24 Gdk.KEY_KP_Left : 'left', 25 Gdk.KEY_KP_Right : 'right', 26 27 Gdk.KEY_w : 'up', 28 Gdk.KEY_s : 'down', 29 Gdk.KEY_a : 'left', 30 Gdk.KEY_d : 'right', 31 32 Gdk.KEY_KP_8 : 'up', 33 Gdk.KEY_KP_2 : 'down', 34 Gdk.KEY_KP_4 : 'left', 35 Gdk.KEY_KP_6 : 'right', 36 37 Gdk.KEY_Up : 'up', 38 Gdk.KEY_Down : 'down', 39 Gdk.KEY_Left : 'left', 40 Gdk.KEY_Right : 'right', 41 42 Gdk.KEY_uparrow : 'up', 43 Gdk.KEY_downarrow : 'down', 44 Gdk.KEY_leftarrow : 'left', 45 Gdk.KEY_rightarrow : 'right', 46 47 Gdk.KEY_Return : 'select', 48 Gdk.KEY_KP_Space : 'select', 49 Gdk.KEY_KP_Enter : 'select', 50 Gdk.KEY_space : 'select', 51 Gdk.KEY_End : 'select', 52 Gdk.KEY_KP_End : 'select', 53 Gdk.KEY_KP_1 : 'select', 54 Gdk.KEY_q : 'select', 55 56 Gdk.KEY_Home : 'new', 57 Gdk.KEY_KP_Home : 'new', 58 Gdk.KEY_Page_Down : 'redo', 59 Gdk.KEY_KP_Page_Down : 'redo', 60 Gdk.KEY_Page_Up : 'undo', 61 Gdk.KEY_KP_Page_Up : 'undo', 62 62 } -
setup.py
diff --git a/setup.py b/setup.py index 211f104..cbdf097 100644
a b 1 1 #!/usr/bin/env python 2 2 3 from sugar .activity import bundlebuilder3 from sugar3.activity import bundlebuilder 4 4 if __name__ == "__main__": 5 5 bundlebuilder.start() -
sugarless.py
diff --git a/sugarless.py b/sugarless.py index 6a9f3ea..911096d 100644
a b 19 19 # A stub file for running the application on a sugarless GTK, when the Activity 20 20 # framework is not available. 21 21 22 import pygtk 23 pygtk.require('2.0') 24 import gtk 25 import gobject 22 from gi.repository import Gtk 23 from gi.repository import Gdk 24 from gi.repository import GObject 26 25 27 26 import os 28 27 … … from keymap import KEY_MAP 32 31 33 32 _DEFAULT_SPACING = 15 34 33 35 class ImplodeWindow( gtk.Window):34 class ImplodeWindow(Gtk.Window): 36 35 def __init__(self): 37 super(ImplodeWindow, self).__init__(gtk.WINDOW_TOPLEVEL) 38 self.set_geometry_hints(None, min_width=640, min_height=480) 36 super(ImplodeWindow, self).__init__(Gtk.WindowType.TOPLEVEL) 37 38 geometry = Gdk.Geometry() 39 geometry.min_width = 640 40 geometry.min_height = 480 41 42 self.set_geometry_hints(None, geometry, Gdk.WindowHints.MIN_SIZE) 39 43 self.set_title("Implode") 40 44 41 45 self.connect("delete_event", self._delete_event_cb) 42 46 43 toolbar = gtk.Toolbar()47 toolbar = Gtk.Toolbar() 44 48 self.game = implodegame.ImplodeGame() 45 49 46 50 def add_button(id, func): 47 button = gtk.ToolButton(id)51 button = Gtk.ToolButton(id) 48 52 toolbar.add(button) 49 53 50 54 def callback(source): … … class ImplodeWindow(gtk.Window): 53 57 54 58 return button 55 59 56 add_button( gtk.STOCK_NEW, self.game.new_game)57 add_button( gtk.STOCK_MEDIA_PREVIOUS, self.game.replay_game)58 add_button( gtk.STOCK_UNDO, self.game.undo)59 add_button( gtk.STOCK_REDO, self.game.redo)60 add_button(Gtk.STOCK_NEW, self.game.new_game) 61 add_button(Gtk.STOCK_MEDIA_PREVIOUS, self.game.replay_game) 62 add_button(Gtk.STOCK_UNDO, self.game.undo) 63 add_button(Gtk.STOCK_REDO, self.game.redo) 60 64 61 toolbar.add( gtk.SeparatorToolItem())65 toolbar.add(Gtk.SeparatorToolItem()) 62 66 63 67 radio_buttons = [] 64 68 def add_radio_button(label, func): 65 button = gtk.RadioToolButton()69 button = Gtk.RadioToolButton() 66 70 button.set_label(label) 67 71 toolbar.add(button) 68 72 radio_buttons.append(button) … … class ImplodeWindow(gtk.Window): 77 81 add_radio_button('easy', self._easy_clicked) 78 82 add_radio_button('medium', self._medium_clicked) 79 83 add_radio_button('hard', self._hard_clicked) 80 for button in radio_buttons[1:]: 81 button.set_group(radio_buttons[0]) 84 # FIXME: 85 # for button in radio_buttons[1:]: 86 # button.set_group(radio_buttons[0]) 82 87 83 separator = gtk.SeparatorToolItem()88 separator = Gtk.SeparatorToolItem() 84 89 separator.set_expand(True) 85 90 separator.set_draw(False) 86 91 toolbar.add(separator) 87 92 88 add_button( gtk.STOCK_HELP, self._help_clicked)93 add_button(Gtk.STOCK_HELP, self._help_clicked) 89 94 90 95 self._stuck_strip = _StuckStrip() 91 96 92 game_box = gtk.VBox() 93 game_box.pack_start(self.game) 94 game_box.pack_end(self._stuck_strip, expand=False) 97 game_box = Gtk.VBox() 98 game_box.pack_start(self.game, True, True, 0) 99 game_box.pack_end(self._stuck_strip, expand=False, 100 fill=False, padding=0) 95 101 96 main_box = gtk.VBox()97 main_box.pack_start(toolbar, expand=False)98 main_box.pack_end(game_box )102 main_box = Gtk.VBox() 103 main_box.pack_start(toolbar, False, True, 0) 104 main_box.pack_end(game_box, expand=False, fill=False, padding=0) 99 105 self.add(main_box) 100 106 101 107 # Show everything except the stuck strip. … … class ImplodeWindow(gtk.Window): 111 117 self.show() 112 118 113 119 def _delete_event_cb(self, window, event): 114 gtk.main_quit()120 Gtk.main_quit() 115 121 return False 116 122 117 123 def _easy_clicked(self): … … class ImplodeWindow(gtk.Window): 144 150 action = KEY_MAP.get(event.keyval, None) 145 151 if action is None: 146 152 return False 147 if not self._stuck_strip.flags() & gtk.VISIBLE:153 if not self._stuck_strip.flags() & Gtk.VISIBLE: 148 154 return True 149 155 if self.game.focus_child: 150 156 if action == 'down': … … class ImplodeWindow(gtk.Window): 158 164 return True 159 165 return True 160 166 161 class _HelpWindow( gtk.Window):167 class _HelpWindow(Gtk.Window): 162 168 def __init__(self): 163 169 super(_HelpWindow, self).__init__() 164 170 165 171 self.set_size_request(640, 480) 166 self.set_position( gtk.WIN_POS_CENTER_ON_PARENT)172 self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) 167 173 self.set_modal(True) 168 174 169 vbox = gtk.VBox()175 vbox = Gtk.VBox() 170 176 self.add(vbox) 171 177 172 178 self._help_widget = HelpWidget(self._icon_file) 173 vbox.pack_start(self._help_widget )179 vbox.pack_start(self._help_widget, True, True, 0) 174 180 175 181 self._help_nav_bar = _HelpNavBar() 176 182 vbox.pack_end(self._help_nav_bar, … … class _HelpWindow(gtk.Window): 207 213 self._help_nav_bar.set_can_next_stage(hw.can_next_stage()) 208 214 209 215 210 class _HelpNavBar( gtk.HButtonBox):216 class _HelpNavBar(Gtk.HButtonBox): 211 217 __gsignals__ = { 212 'forward-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),213 'back-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),214 'reload-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),218 'forward-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 219 'back-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 220 'reload-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 215 221 } 216 222 217 223 def __init__(self): 218 224 super(_HelpNavBar, self).__init__() 219 225 220 self.set_layout( gtk.BUTTONBOX_SPREAD)226 self.set_layout(Gtk.ButtonBoxStyle.SPREAD) 221 227 222 228 def add_button(id, signal_name): 223 button = gtk.Button(stock=id)229 button = Gtk.Button(stock=id) 224 230 self.add(button) 225 231 226 232 def callback(source): … … class _HelpNavBar(gtk.HButtonBox): 229 235 230 236 return button 231 237 232 self._back_button = add_button( gtk.STOCK_GO_BACK, 'back-clicked')233 add_button( gtk.STOCK_MEDIA_PLAY, 'reload-clicked')234 self._forward_button = add_button( gtk.STOCK_GO_FORWARD, 'forward-clicked')238 self._back_button = add_button(Gtk.STOCK_GO_BACK, 'back-clicked') 239 add_button(Gtk.STOCK_MEDIA_PLAY, 'reload-clicked') 240 self._forward_button = add_button(Gtk.STOCK_GO_FORWARD, 'forward-clicked') 235 241 236 242 def set_can_prev_stage(self, can_prev_stage): 237 243 self._back_button.set_sensitive(can_prev_stage) … … class _HelpNavBar(gtk.HButtonBox): 240 246 self._forward_button.set_sensitive(can_next_stage) 241 247 242 248 243 class _StuckStrip( gtk.HBox):249 class _StuckStrip(Gtk.HBox): 244 250 __gsignals__ = { 245 'undo-clicked' : ( gobject.SIGNAL_RUN_LAST, None, ()),251 'undo-clicked' : (GObject.SignalFlags.RUN_LAST, None, ()), 246 252 } 247 253 def __init__(self, *args, **kwargs): 248 254 super(_StuckStrip, self).__init__(*args, **kwargs) 249 255 250 spacer1 = gtk.Label('')251 self.pack_start(spacer1, expand=True)256 spacer1 = Gtk.Label(label='') 257 self.pack_start(spacer1, True, True, 0) 252 258 253 spacer2 = gtk.Label('')254 self.pack_end(spacer2, expand=True )259 spacer2 = Gtk.Label(label='') 260 self.pack_end(spacer2, expand=True, fill=False, padding=0) 255 261 256 262 self.set_spacing(10) 257 263 258 264 self.set_border_width(10) 259 265 260 label = gtk.Label("Stuck? You can still solve the puzzle.")261 self.pack_start(label, expand=False)266 label = Gtk.Label(label="Stuck? You can still solve the puzzle.") 267 self.pack_start(label, False, True, 0) 262 268 263 self.button = gtk.Button(stock=gtk.STOCK_UNDO)269 self.button = Gtk.Button(stock=Gtk.STOCK_UNDO) 264 270 self.button.set_label("Undo some moves") 265 self.pack_end(self.button, expand=False )271 self.pack_end(self.button, expand=False, fill=False, padding=0) 266 272 267 273 def callback(source): 268 274 self.emit('undo-clicked') … … class _StuckStrip(gtk.HBox): 271 277 272 278 def main(): 273 279 w = ImplodeWindow() 274 gtk.main()280 Gtk.main() 275 281 276 282 if __name__ == "__main__": 277 283 main()