def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi)
def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK (self, self.figure.dpi)
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase): keyvald = { 65507: 'control', 65505: 'shift', 65513: 'alt', 65508: 'control', 65506: 'shift', 65514: 'alt', 65361: 'left', 65362: 'up', 65363: 'right', 65364: 'down', 65307: 'escape', 65470: 'f1', 65471: 'f2', 65472: 'f3', 65473: 'f4', 65474: 'f5', 65475: 'f6', 65476: 'f7', 65477: 'f8', 65478: 'f9', 65479: 'f10', 65480: 'f11', 65481: 'f12', 65300: 'scroll_lock', 65299: 'break', 65288: 'backspace', 65293: 'enter', 65379: 'insert', 65535: 'delete', 65360: 'home', 65367: 'end', 65365: 'pageup', 65366: 'pagedown', 65438: '0', 65436: '1', 65433: '2', 65435: '3', 65430: '4', 65437: '5', 65432: '6', 65429: '7', 65431: '8', 65434: '9', 65451: '+', 65453: '-', 65450: '*', 65455: '/', 65439: 'dec', 65421: 'enter', } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) def __init__(self, figure): if _debug: print 'FigureCanvasGTK.%s' % fn_name() FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idle_draw_id = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('scroll_event', self.scroll_event) self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.connect('leave_notify_event', self.leave_notify_event) self.connect('enter_notify_event', self.enter_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() self._idle_event_id = gobject.idle_add(self.idle_event) def destroy(self): #gtk.DrawingArea.destroy(self) gobject.source_remove(self._idle_event_id) if self._idle_draw_id != 0: gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction == gdk.SCROLL_UP: step = 1 else: step = -1 FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) return False # finish event propagation? def button_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_press_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "hit", key FigureCanvasBase.key_press_event(self, key, guiEvent=event) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "release", key FigureCanvasBase.key_release_event(self, key, guiEvent=event) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) return False # finish event propagation? def leave_notify_event(self, widget, event): FigureCanvasBase.leave_notify_event(self, event) def enter_notify_event(self, widget, event): FigureCanvasBase.enter_notify_event(self, event) def _get_key(self, event): if event.keyval in self.keyvald: key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None ctrl = event.state & gdk.CONTROL_MASK shift = event.state & gdk.SHIFT_MASK return key def configure_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches(w / dpi, h / dpi) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates(False) def draw_idle(self): def idle_draw(*args): self.draw() self._idle_draw_id = 0 return False if self._idle_draw_id == 0: self._idle_draw_id = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max(int(self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max(int(self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap(self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap(self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height(width, height) self.figure.draw(self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare(w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes['jpg'] = 'JPEG' filetypes['jpeg'] = 'JPEG' filetypes['png'] = 'Portable Network Graphics' def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, 'jpeg') print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') def _print_image(self, filename, format): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap(self.window, width, height) self._renderer.set_pixmap(pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) if is_string_like(filename): try: pixbuf.save(filename, format) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc, ), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, 'save_to_callback'): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc, ), parent=self)
class FigureCanvasGTK (gtk.DrawingArea, FigureCanvasBase): keyvald = {65507 : 'control', 65505 : 'shift', 65513 : 'alt', 65508 : 'control', 65506 : 'shift', 65514 : 'alt', 65361 : 'left', 65362 : 'up', 65363 : 'right', 65364 : 'down', 65307 : 'escape', 65470 : 'f1', 65471 : 'f2', 65472 : 'f3', 65473 : 'f4', 65474 : 'f5', 65475 : 'f6', 65476 : 'f7', 65477 : 'f8', 65478 : 'f9', 65479 : 'f10', 65480 : 'f11', 65481 : 'f12', 65300 : 'scroll_lock', 65299 : 'break', 65288 : 'backspace', 65293 : 'enter', 65379 : 'insert', 65535 : 'delete', 65360 : 'home', 65367 : 'end', 65365 : 'pageup', 65366 : 'pagedown', 65438 : '0', 65436 : '1', 65433 : '2', 65435 : '3', 65430 : '4', 65437 : '5', 65432 : '6', 65429 : '7', 65431 : '8', 65434 : '9', 65451 : '+', 65453 : '-', 65450 : '*', 65455 : '/', 65439 : 'dec', 65421 : 'enter', } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) def __init__(self, figure): if _debug: print 'FigureCanvasGTK.%s' % fn_name() FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idle_draw_id = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('scroll_event', self.scroll_event) self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.connect('leave_notify_event', self.leave_notify_event) self.connect('enter_notify_event', self.enter_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() self._idle_event_id = gobject.idle_add(self.idle_event) def destroy(self): #gtk.DrawingArea.destroy(self) gobject.source_remove(self._idle_event_id) if self._idle_draw_id != 0: gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction==gdk.SCROLL_UP: step = 1 else: step = -1 FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) return False # finish event propagation? def button_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_press_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "hit", key FigureCanvasBase.key_press_event(self, key, guiEvent=event) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "release", key FigureCanvasBase.key_release_event(self, key, guiEvent=event) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) return False # finish event propagation? def leave_notify_event(self, widget, event): FigureCanvasBase.leave_notify_event(self, event) def enter_notify_event(self, widget, event): FigureCanvasBase.enter_notify_event(self, event) def _get_key(self, event): if event.keyval in self.keyvald: key = self.keyvald[event.keyval] elif event.keyval <256: key = chr(event.keyval) else: key = None ctrl = event.state & gdk.CONTROL_MASK shift = event.state & gdk.SHIFT_MASK return key def configure_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches (w/dpi, h/dpi) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates (False) def draw_idle(self): def idle_draw(*args): self.draw() self._idle_draw_id = 0 return False if self._idle_draw_id == 0: self._idle_draw_id = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK (self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max (int (self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max (int (self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap (self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap (self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height (width, height) self.figure.draw (self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare (w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable (self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes['jpg'] = 'JPEG' filetypes['jpeg'] = 'JPEG' filetypes['png'] = 'Portable Network Graphics' def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, 'jpeg') print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') def _print_image(self, filename, format): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap (self.window, width, height) self._renderer.set_pixmap (pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) if is_string_like(filename): try: pixbuf.save(filename, format) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, 'save_to_callback'): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase): keyvald = { 65507: 'control', 65505: 'shift', 65513: 'alt', 65508: 'control', 65506: 'shift', 65514: 'alt', 65361: 'left', 65362: 'up', 65363: 'right', 65364: 'down', 65307: 'escape', 65470: 'f1', 65471: 'f2', 65472: 'f3', 65473: 'f4', 65474: 'f5', 65475: 'f6', 65476: 'f7', 65477: 'f8', 65478: 'f9', 65479: 'f10', 65480: 'f11', 65481: 'f12', 65300: 'scroll_lock', 65299: 'break', 65288: 'backspace', 65293: 'enter', 65379: 'insert', 65535: 'delete', 65360: 'home', 65367: 'end', 65365: 'pageup', 65366: 'pagedown', 65438: '0', 65436: '1', 65433: '2', 65435: '3', 65430: '4', 65437: '5', 65432: '6', 65429: '7', 65431: '8', 65434: '9', 65451: '+', 65453: '-', 65450: '*', 65455: '/', 65439: 'dec', 65421: 'enter', 65511: 'super', 65512: 'super', 65406: 'alt', 65289: 'tab', } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) def __init__(self, figure): if self.__class__ == matplotlib.backends.backend_gtk.FigureCanvasGTK: warn_deprecated('2.0', message="The GTK backend is " "deprecated. It is untested, known to be " "broken and will be removed in Matplotlib 2.2. " "Use the GTKAgg backend instead. " "See Matplotlib usage FAQ for" " more info on backends.", alternative="GTKAgg") FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idle_draw_id = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('scroll_event', self.scroll_event) self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.connect('leave_notify_event', self.leave_notify_event) self.connect('enter_notify_event', self.enter_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() self.last_downclick = {} def destroy(self): #gtk.DrawingArea.destroy(self) self.close_event() if self._idle_draw_id != 0: gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction == gdk.SCROLL_UP: step = 1 else: step = -1 FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) return False # finish event propagation? def button_press_event(self, widget, event): x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y dblclick = (event.type == gdk._2BUTTON_PRESS) if not dblclick: # GTK is the only backend that generates a DOWN-UP-DOWN-DBLCLICK-UP event # sequence for a double click. All other backends have a DOWN-UP-DBLCLICK-UP # sequence. In order to provide consistency to matplotlib users, we will # eat the extra DOWN event in the case that we detect it is part of a double # click. # first, get the double click time in milliseconds. current_time = event.get_time() last_time = self.last_downclick.get(event.button, 0) dblclick_time = gtk.settings_get_for_screen( gdk.screen_get_default()).get_property('gtk-double-click-time') delta_time = current_time - last_time if delta_time < dblclick_time: del self.last_downclick[ event.button] # we do not want to eat more than one event. return False # eat. self.last_downclick[event.button] = current_time FigureCanvasBase.button_press_event(self, x, y, event.button, dblclick=dblclick, guiEvent=event) return False # finish event propagation? def button_release_event(self, widget, event): x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def key_press_event(self, widget, event): key = self._get_key(event) FigureCanvasBase.key_press_event(self, key, guiEvent=event) return True # stop event propagation def key_release_event(self, widget, event): key = self._get_key(event) FigureCanvasBase.key_release_event(self, key, guiEvent=event) return True # stop event propagation def motion_notify_event(self, widget, event): if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) return False # finish event propagation? def leave_notify_event(self, widget, event): FigureCanvasBase.leave_notify_event(self, event) def enter_notify_event(self, widget, event): x, y, state = event.window.get_pointer() FigureCanvasBase.enter_notify_event(self, event, xy=(x, y)) def _get_key(self, event): if event.keyval in self.keyvald: key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None for key_mask, prefix in ( [gdk.MOD4_MASK, 'super'], [gdk.MOD1_MASK, 'alt'], [gdk.CONTROL_MASK, 'ctrl'], ): if event.state & key_mask: key = '{0}+{1}'.format(prefix, key) return key def configure_event(self, widget, event): if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches(w / dpi, h / dpi, forward=False) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates(False) def draw_idle(self): if self._idle_draw_id != 0: return def idle_draw(*args): try: self.draw() finally: self._idle_draw_id = 0 return False self._idle_draw_id = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max(int(self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max(int(self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap(self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap(self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height(width, height) self.figure.draw(self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ toolbar = self.toolbar if toolbar: toolbar.set_cursor(cursors.WAIT) if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare(w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) if toolbar: toolbar.set_cursor(toolbar._lastCursor) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes['jpg'] = 'JPEG' filetypes['jpeg'] = 'JPEG' filetypes['png'] = 'Portable Network Graphics' def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, 'jpeg') print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') def _print_image(self, filename, format, *args, **kwargs): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap(self.window, width, height) self._renderer.set_pixmap(pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) # set the default quality, if we are writing a JPEG. # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save options = {k: kwargs[k] for k in ['quality'] if k in kwargs} if format in ['jpg', 'jpeg']: options.setdefault('quality', rcParams['savefig.jpeg_quality']) options['quality'] = str(options['quality']) if isinstance(filename, six.string_types): try: pixbuf.save(filename, format, options=options) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc, ), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, 'save_to_callback'): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc, ), parent=self) else: raise ValueError( "Saving to a Python file-like object is only supported by PyGTK >= 2.8" ) else: raise ValueError("filename must be a path or a file-like object") def new_timer(self, *args, **kwargs): """ Creates a new backend-specific subclass of :class:`backend_bases.Timer`. This is useful for getting periodic events through the backend's native event loop. Implemented only for backends with GUIs. Other Parameters ---------------- interval : scalar Timer interval in milliseconds callbacks : list Sequence of (func, args, kwargs) where ``func(*args, **kwargs)`` will be executed by the timer every *interval*. """ return TimerGTK(*args, **kwargs) def flush_events(self): gtk.gdk.threads_enter() while gtk.events_pending(): gtk.main_iteration(True) gtk.gdk.flush() gtk.gdk.threads_leave()
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase): keyvald = { 65507: 'control', 65505: 'shift', 65513: 'alt', 65508: 'control', 65506: 'shift', 65514: 'alt', 65361: 'left', 65362: 'up', 65363: 'right', 65364: 'down', } def __init__(self, figure): if _debug: print 'FigureCanvasGTK.%s' % fn_name() FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idleID = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.set_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() def button_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_press_event(self, x, y, event.button) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "hit", key FigureCanvasBase.key_press_event(self, key) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "release", key FigureCanvasBase.key_release_event(self, key) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y) return False # finish event propagation? def _get_key(self, event): if self.keyvald.has_key(event.keyval): key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None ctrl = event.state & gdk.CONTROL_MASK shift = event.state & gdk.SHIFT_MASK return key def configure_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi.get() self.figure.set_figsize_inches(w / dpi, h / dpi) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates(False) ## synchronous draw (needed for animation) #x, y, w, h = self.allocation #if w<3 or h<3: return # empty fig #self._pixmap_prepare (w, h) #self._render_figure(self._pixmap, w, h) #self._need_redraw = False #self.window.draw_drawable (self.style.fg_gc[self.state], # self._pixmap, 0, 0, 0, 0, w, h) def draw_idle(self): def idle_draw(*args): self.draw() self._idleID = 0 return False if self._idleID == 0: self._idleID = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max(int(self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max(int(self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap(self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap(self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height(width, height) self.figure.draw(self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare(w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? def print_figure(self, filename, dpi=150, facecolor='w', edgecolor='w', orientation='portrait'): # TODO - use gdk/cairo/agg print_figure? root, ext = os.path.splitext(filename) ext = ext[1:] if ext == '': ext = IMAGE_FORMAT_DEFAULT filename = filename + '.' + ext # save figure settings origDPI = self.figure.dpi.get() origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() origWIn, origHIn = self.figure.get_size_inches() if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) self.figure.dpi.set(dpi) self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) ext = ext.lower() if ext in ('jpg', 'png'): # native printing width, height = self.get_width_height() pixmap = gdk.Pixmap(self.window, width, height) self._renderer.set_pixmap(pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) # pixbuf.save() recognises 'jpeg' not 'jpg' if ext == 'jpg': ext = 'jpeg' try: pixbuf.save(filename, ext) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc, ), parent=self) elif ext in ( 'eps', 'ps', 'svg', ): if ext == 'svg': from backend_svg import FigureCanvasSVG as FigureCanvas else: from backend_ps import FigureCanvasPS as FigureCanvas try: fc = self.switch_backends(FigureCanvas) fc.print_figure(filename, dpi, facecolor, edgecolor, orientation) except IOError, exc: error_msg_gtk("Save figure failure:\n%s: %s" % (exc.filename, exc.strerror), parent=self)
class FigureCanvasGTK (gtk.DrawingArea, FigureCanvasBase): keyvald = {65507 : 'control', 65505 : 'shift', 65513 : 'alt', 65508 : 'control', 65506 : 'shift', 65514 : 'alt', 65361 : 'left', 65362 : 'up', 65363 : 'right', 65364 : 'down', 65307 : 'escape', 65470 : 'f1', 65471 : 'f2', 65472 : 'f3', 65473 : 'f4', 65474 : 'f5', 65475 : 'f6', 65476 : 'f7', 65477 : 'f8', 65478 : 'f9', 65479 : 'f10', 65480 : 'f11', 65481 : 'f12', 65300 : 'scroll_lock', 65299 : 'break', 65288 : 'backspace', 65293 : 'enter', 65379 : 'insert', 65535 : 'delete', 65360 : 'home', 65367 : 'end', 65365 : 'pageup', 65366 : 'pagedown', 65438 : '0', 65436 : '1', 65433 : '2', 65435 : '3', 65430 : '4', 65437 : '5', 65432 : '6', 65429 : '7', 65431 : '8', 65434 : '9', 65451 : '+', 65453 : '-', 65450 : '*', 65455 : '/', 65439 : 'dec', 65421 : 'enter', 65511 : 'super', 65512 : 'super', 65406 : 'alt', 65289 : 'tab', } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) def __init__(self, figure): if _debug: print('FigureCanvasGTK.%s' % fn_name()) FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idle_draw_id = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('scroll_event', self.scroll_event) self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.connect('leave_notify_event', self.leave_notify_event) self.connect('enter_notify_event', self.enter_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() self._idle_event_id = gobject.idle_add(self.idle_event) self.last_downclick = {} def destroy(self): #gtk.DrawingArea.destroy(self) self.close_event() gobject.source_remove(self._idle_event_id) if self._idle_draw_id != 0: gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction==gdk.SCROLL_UP: step = 1 else: step = -1 FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) return False # finish event propagation? def button_press_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y dblclick = (event.type == gdk._2BUTTON_PRESS) if not dblclick: # GTK is the only backend that generates a DOWN-UP-DOWN-DBLCLICK-UP event # sequence for a double click. All other backends have a DOWN-UP-DBLCLICK-UP # sequence. In order to provide consistency to matplotlib users, we will # eat the extra DOWN event in the case that we detect it is part of a double # click. # first, get the double click time in milliseconds. current_time = event.get_time() last_time = self.last_downclick.get(event.button,0) dblclick_time = gtk.settings_get_for_screen(gdk.screen_get_default()).get_property('gtk-double-click-time') delta_time = current_time-last_time if delta_time < dblclick_time: del self.last_downclick[event.button] # we do not want to eat more than one event. return False # eat. self.last_downclick[event.button] = current_time FigureCanvasBase.button_press_event(self, x, y, event.button, dblclick=dblclick, guiEvent=event) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) key = self._get_key(event) if _debug: print("hit", key) FigureCanvasBase.key_press_event(self, key, guiEvent=event) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) key = self._get_key(event) if _debug: print("release", key) FigureCanvasBase.key_release_event(self, key, guiEvent=event) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) return False # finish event propagation? def leave_notify_event(self, widget, event): FigureCanvasBase.leave_notify_event(self, event) def enter_notify_event(self, widget, event): x, y, state = event.window.get_pointer() FigureCanvasBase.enter_notify_event(self, event, xy=(x,y)) def _get_key(self, event): if event.keyval in self.keyvald: key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None for key_mask, prefix in ( [gdk.MOD4_MASK, 'super'], [gdk.MOD1_MASK, 'alt'], [gdk.CONTROL_MASK, 'ctrl'],): if event.state & key_mask: key = '{0}+{1}'.format(prefix, key) return key def configure_event(self, widget, event): if _debug: print('FigureCanvasGTK.%s' % fn_name()) if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches (w/dpi, h/dpi) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates (False) def draw_idle(self): def idle_draw(*args): self.draw() self._idle_draw_id = 0 return False if self._idle_draw_id == 0: self._idle_draw_id = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK (self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print('FigureCanvasGTK.%s' % fn_name()) create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max (int (self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max (int (self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap (self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap (self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height (width, height) self.figure.draw (self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print('FigureCanvasGTK.%s' % fn_name()) if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare (w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable (self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes['jpg'] = 'JPEG' filetypes['jpeg'] = 'JPEG' filetypes['png'] = 'Portable Network Graphics' def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, 'jpeg') print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') def _print_image(self, filename, format): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap (self.window, width, height) self._renderer.set_pixmap (pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) if is_string_like(filename): try: pixbuf.save(filename, format) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, 'save_to_callback'): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) else: raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8") else: raise ValueError("filename must be a path or a file-like object") def new_timer(self, *args, **kwargs): """ Creates a new backend-specific subclass of :class:`backend_bases.Timer`. This is useful for getting periodic events through the backend's native event loop. Implemented only for backends with GUIs. optional arguments: *interval* Timer interval in milliseconds *callbacks* Sequence of (func, args, kwargs) where func(*args, **kwargs) will be executed by the timer every *interval*. """ return TimerGTK(*args, **kwargs) def flush_events(self): gtk.gdk.threads_enter() while gtk.events_pending(): gtk.main_iteration(True) gtk.gdk.flush() gtk.gdk.threads_leave() def start_event_loop(self,timeout): FigureCanvasBase.start_event_loop_default(self,timeout) start_event_loop.__doc__=FigureCanvasBase.start_event_loop_default.__doc__ def stop_event_loop(self): FigureCanvasBase.stop_event_loop_default(self) stop_event_loop.__doc__=FigureCanvasBase.stop_event_loop_default.__doc__
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase): keyvald = { 65507: "control", 65505: "shift", 65513: "alt", 65508: "control", 65506: "shift", 65514: "alt", 65361: "left", 65362: "up", 65363: "right", 65364: "down", 65307: "escape", 65470: "f1", 65471: "f2", 65472: "f3", 65473: "f4", 65474: "f5", 65475: "f6", 65476: "f7", 65477: "f8", 65478: "f9", 65479: "f10", 65480: "f11", 65481: "f12", 65300: "scroll_lock", 65299: "break", 65288: "backspace", 65293: "enter", 65379: "insert", 65535: "delete", 65360: "home", 65367: "end", 65365: "pageup", 65366: "pagedown", 65438: "0", 65436: "1", 65433: "2", 65435: "3", 65430: "4", 65437: "5", 65432: "6", 65429: "7", 65431: "8", 65434: "9", 65451: "+", 65453: "-", 65450: "*", 65455: "/", 65439: "dec", 65421: "enter", } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = ( gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK ) def __init__(self, figure): if _debug: print "FigureCanvasGTK.%s" % fn_name() FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idleID = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect("scroll_event", self.scroll_event) self.connect("button_press_event", self.button_press_event) self.connect("button_release_event", self.button_release_event) self.connect("configure_event", self.configure_event) self.connect("expose_event", self.expose_event) self.connect("key_press_event", self.key_press_event) self.connect("key_release_event", self.key_release_event) self.connect("motion_notify_event", self.motion_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() def scroll_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction == gdk.SCROLL_UP: direction = "up" else: direction = "down" FigureCanvasBase.scroll_event(self, x, y, direction) return False # finish event propagation? def button_press_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_press_event(self, x, y, event.button) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() key = self._get_key(event) if _debug: print "hit", key FigureCanvasBase.key_press_event(self, key) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() key = self._get_key(event) if _debug: print "release", key FigureCanvasBase.key_release_event(self, key) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y) return False # finish event propagation? def _get_key(self, event): if self.keyvald.has_key(event.keyval): key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None ctrl = event.state & gdk.CONTROL_MASK shift = event.state & gdk.SHIFT_MASK return key def configure_event(self, widget, event): if _debug: print "FigureCanvasGTK.%s" % fn_name() if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches(w / dpi, h / dpi) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates(False) def draw_idle(self): def idle_draw(*args): self.draw() self._idleID = 0 return False if self._idleID == 0: self._idleID = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print "FigureCanvasGTK.%s" % fn_name() create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max(int(self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max(int(self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap(self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap(self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height(width, height) self.figure.draw(self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print "FigureCanvasGTK.%s" % fn_name() if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare(w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes["jpg"] = "JPEG" filetypes["jpeg"] = "JPEG" filetypes["png"] = "Portable Network Graphics" def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, "jpeg") print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, "png") def _print_image(self, filename, format): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap(self.window, width, height) self._renderer.set_pixmap(pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) if is_string_like(filename): try: pixbuf.save(filename, format) except gobject.GError, exc: error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, "save_to_callback"): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename) except gobject.GError, exc: error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self)
class FigureCanvasGTK (gtk.DrawingArea, FigureCanvasBase): keyvald = {65507 : 'control', 65505 : 'shift', 65513 : 'alt', 65508 : 'control', 65506 : 'shift', 65514 : 'alt', 65361 : 'left', 65362 : 'up', 65363 : 'right', 65364 : 'down', } def __init__(self, figure): if _debug: print 'FigureCanvasGTK.%s' % fn_name() FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idleID = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect('button_press_event', self.button_press_event) self.connect('button_release_event', self.button_release_event) self.connect('configure_event', self.configure_event) self.connect('expose_event', self.expose_event) self.connect('key_press_event', self.key_press_event) self.connect('key_release_event', self.key_release_event) self.connect('motion_notify_event', self.motion_notify_event) self.set_events( gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() #def resize(self, w, h): # 'set the drawing area size in pixels' # winw, winh = self.parent.parent.get_size() # tmp, tmp, myw, myh = self.allocation # padw = winw-myw # padh = winh-myh # self.parent.parent.resize(w+padw, h+padh) def button_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_press_event(self, x, y, event.button) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "hit", key FigureCanvasBase.key_press_event(self, key) return False # finish event propagation? def key_release_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() key = self._get_key(event) if _debug: print "release", key FigureCanvasBase.key_release_event(self, key) return False # finish event propagation? def motion_notify_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y) return False # finish event propagation? def _get_key(self, event): if self.keyvald.has_key(event.keyval): key = self.keyvald[event.keyval] elif event.keyval <256: key = chr(event.keyval) else: key = None ctrl = event.state & gdk.CONTROL_MASK shift = event.state & gdk.SHIFT_MASK return key def configure_event(self, widget, event): if _debug: print 'FigureCanvasGTK.%s' % fn_name() if widget.window is None: return w, h = event.width, event.height if w<3 or h<3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi.get() self.figure.set_figsize_inches (w/dpi, h/dpi) self._need_redraw = True #self.resize_event() return False # finish event propagation? def draw(self): # synchronous window redraw (like GTK+ 1.2 used to do) # Note: this does not follow the usual way that GTK redraws, # which is asynchronous redraw using calls to gtk_widget_queue_draw(), # which triggers an expose-event # GTK+ 2.x style draw() #self._need_redraw = True #self.queue_draw() # synchronous draw (needed for animation) x, y, w, h = self.allocation if w<3 or h<3: return # empty fig self._pixmap_prepare (w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False self.window.draw_drawable (self.style.fg_gc[self.state], self._pixmap, 0, 0, 0, 0, w, h) def draw_idle(self): def idle_draw(*args): self.draw() self._idleID = 0 return False if self._idleID==0: self._idleID = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK (self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max (int (self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max (int (self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap (self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap (self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height (width, height) self.figure.draw (self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print 'FigureCanvasGTK.%s' % fn_name() if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare (w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable (self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? def print_figure(self, filename, dpi=150, facecolor='w', edgecolor='w', orientation='portrait'): # TODO - use gdk/cairo/agg print_figure? root, ext = os.path.splitext(filename) ext = ext[1:] if ext == '': ext = IMAGE_FORMAT_DEFAULT filename = filename + '.' + ext # save figure settings origDPI = self.figure.dpi.get() origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() origWIn, origHIn = self.figure.get_size_inches() if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) self.figure.dpi.set(dpi) self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) ext = ext.lower() if ext in ('jpg', 'png'): # native printing width, height = self.get_width_height() pixmap = gdk.Pixmap (self.window, width, height) self._renderer.set_pixmap (pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) # pixbuf.save() recognises 'jpeg' not 'jpg' if ext == 'jpg': ext = 'jpeg' try: pixbuf.save(filename, ext) except gobject.GError, exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) elif ext in ('eps', 'ps', 'svg',): if ext == 'svg': from backend_svg import FigureCanvasSVG as FigureCanvas else: from backend_ps import FigureCanvasPS as FigureCanvas try: fc = self.switch_backends(FigureCanvas) fc.print_figure(filename, dpi, facecolor, edgecolor, orientation) except IOError, exc: error_msg_gtk("Save figure failure:\n%s: %s" % (exc.filename, exc.strerror), parent=self)
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase): keyvald = { 65507: "control", 65505: "shift", 65513: "alt", 65508: "control", 65506: "shift", 65514: "alt", 65361: "left", 65362: "up", 65363: "right", 65364: "down", 65307: "escape", 65470: "f1", 65471: "f2", 65472: "f3", 65473: "f4", 65474: "f5", 65475: "f6", 65476: "f7", 65477: "f8", 65478: "f9", 65479: "f10", 65480: "f11", 65481: "f12", 65300: "scroll_lock", 65299: "break", 65288: "backspace", 65293: "enter", 65379: "insert", 65535: "delete", 65360: "home", 65367: "end", 65365: "pageup", 65366: "pagedown", 65438: "0", 65436: "1", 65433: "2", 65435: "3", 65430: "4", 65437: "5", 65432: "6", 65429: "7", 65431: "8", 65434: "9", 65451: "+", 65453: "-", 65450: "*", 65455: "/", 65439: "dec", 65421: "enter", 65511: "super", 65512: "super", 65406: "alt", 65289: "tab", } # Setting this as a static constant prevents # this resulting expression from leaking event_mask = ( gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK ) def __init__(self, figure): if self.__class__ == matplotlib.backends.backend_gtk.FigureCanvasGTK: warn_deprecated( "2.0", message="The GTK backend is " "deprecated. It is untested, known to be " "broken and will be removed in Matplotlib 2.2. " "Use the GTKAgg backend instead. " "See Matplotlib usage FAQ for" " more info on backends.", alternative="GTKAgg", ) if _debug: print("FigureCanvasGTK.%s" % fn_name()) FigureCanvasBase.__init__(self, figure) gtk.DrawingArea.__init__(self) self._idle_draw_id = 0 self._need_redraw = True self._pixmap_width = -1 self._pixmap_height = -1 self._lastCursor = None self.connect("scroll_event", self.scroll_event) self.connect("button_press_event", self.button_press_event) self.connect("button_release_event", self.button_release_event) self.connect("configure_event", self.configure_event) self.connect("expose_event", self.expose_event) self.connect("key_press_event", self.key_press_event) self.connect("key_release_event", self.key_release_event) self.connect("motion_notify_event", self.motion_notify_event) self.connect("leave_notify_event", self.leave_notify_event) self.connect("enter_notify_event", self.enter_notify_event) self.set_events(self.__class__.event_mask) self.set_double_buffered(False) self.set_flags(gtk.CAN_FOCUS) self._renderer_init() self.last_downclick = {} def destroy(self): # gtk.DrawingArea.destroy(self) self.close_event() if self._idle_draw_id != 0: gobject.source_remove(self._idle_draw_id) def scroll_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y if event.direction == gdk.SCROLL_UP: step = 1 else: step = -1 FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) return False # finish event propagation? def button_press_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y dblclick = event.type == gdk._2BUTTON_PRESS if not dblclick: # GTK is the only backend that generates a DOWN-UP-DOWN-DBLCLICK-UP event # sequence for a double click. All other backends have a DOWN-UP-DBLCLICK-UP # sequence. In order to provide consistency to matplotlib users, we will # eat the extra DOWN event in the case that we detect it is part of a double # click. # first, get the double click time in milliseconds. current_time = event.get_time() last_time = self.last_downclick.get(event.button, 0) dblclick_time = gtk.settings_get_for_screen(gdk.screen_get_default()).get_property("gtk-double-click-time") delta_time = current_time - last_time if delta_time < dblclick_time: del self.last_downclick[event.button] # we do not want to eat more than one event. return False # eat. self.last_downclick[event.button] = current_time FigureCanvasBase.button_press_event(self, x, y, event.button, dblclick=dblclick, guiEvent=event) return False # finish event propagation? def button_release_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) x = event.x # flipy so y=0 is bottom of canvas y = self.allocation.height - event.y FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) return False # finish event propagation? def key_press_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) key = self._get_key(event) if _debug: print("hit", key) FigureCanvasBase.key_press_event(self, key, guiEvent=event) return True # stop event propagation def key_release_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) key = self._get_key(event) if _debug: print("release", key) FigureCanvasBase.key_release_event(self, key, guiEvent=event) return True # stop event propagation def motion_notify_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) if event.is_hint: x, y, state = event.window.get_pointer() else: x, y, state = event.x, event.y, event.state # flipy so y=0 is bottom of canvas y = self.allocation.height - y FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) return False # finish event propagation? def leave_notify_event(self, widget, event): FigureCanvasBase.leave_notify_event(self, event) def enter_notify_event(self, widget, event): x, y, state = event.window.get_pointer() FigureCanvasBase.enter_notify_event(self, event, xy=(x, y)) def _get_key(self, event): if event.keyval in self.keyvald: key = self.keyvald[event.keyval] elif event.keyval < 256: key = chr(event.keyval) else: key = None for key_mask, prefix in ([gdk.MOD4_MASK, "super"], [gdk.MOD1_MASK, "alt"], [gdk.CONTROL_MASK, "ctrl"]): if event.state & key_mask: key = "{0}+{1}".format(prefix, key) return key def configure_event(self, widget, event): if _debug: print("FigureCanvasGTK.%s" % fn_name()) if widget.window is None: return w, h = event.width, event.height if w < 3 or h < 3: return # empty fig # resize the figure (in inches) dpi = self.figure.dpi self.figure.set_size_inches(w / dpi, h / dpi, forward=False) self._need_redraw = True return False # finish event propagation? def draw(self): # Note: FigureCanvasBase.draw() is inconveniently named as it clashes # with the deprecated gtk.Widget.draw() self._need_redraw = True if GTK_WIDGET_DRAWABLE(self): self.queue_draw() # do a synchronous draw (its less efficient than an async draw, # but is required if/when animation is used) self.window.process_updates(False) def draw_idle(self): if self._idle_draw_id != 0: return def idle_draw(*args): try: self.draw() finally: self._idle_draw_id = 0 return False self._idle_draw_id = gobject.idle_add(idle_draw) def _renderer_init(self): """Override by GTK backends to select a different renderer Renderer should provide the methods: set_pixmap () set_width_height () that are used by _render_figure() / _pixmap_prepare() """ self._renderer = RendererGDK(self, self.figure.dpi) def _pixmap_prepare(self, width, height): """ Make sure _._pixmap is at least width, height, create new pixmap if necessary """ if _debug: print("FigureCanvasGTK.%s" % fn_name()) create_pixmap = False if width > self._pixmap_width: # increase the pixmap in 10%+ (rather than 1 pixel) steps self._pixmap_width = max(int(self._pixmap_width * 1.1), width) create_pixmap = True if height > self._pixmap_height: self._pixmap_height = max(int(self._pixmap_height * 1.1), height) create_pixmap = True if create_pixmap: self._pixmap = gdk.Pixmap(self.window, self._pixmap_width, self._pixmap_height) self._renderer.set_pixmap(self._pixmap) def _render_figure(self, pixmap, width, height): """used by GTK and GTKcairo. GTKAgg overrides """ self._renderer.set_width_height(width, height) self.figure.draw(self._renderer) def expose_event(self, widget, event): """Expose_event for all GTK backends. Should not be overridden. """ if _debug: print("FigureCanvasGTK.%s" % fn_name()) if GTK_WIDGET_DRAWABLE(self): if self._need_redraw: x, y, w, h = self.allocation self._pixmap_prepare(w, h) self._render_figure(self._pixmap, w, h) self._need_redraw = False x, y, w, h = event.area self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, x, y, x, y, w, h) return False # finish event propagation? filetypes = FigureCanvasBase.filetypes.copy() filetypes["jpg"] = "JPEG" filetypes["jpeg"] = "JPEG" filetypes["png"] = "Portable Network Graphics" def print_jpeg(self, filename, *args, **kwargs): return self._print_image(filename, "jpeg") print_jpg = print_jpeg def print_png(self, filename, *args, **kwargs): return self._print_image(filename, "png") def _print_image(self, filename, format, *args, **kwargs): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap(self.window, width, height) self._renderer.set_pixmap(pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) # set the default quality, if we are writing a JPEG. # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save options = cbook.restrict_dict(kwargs, ["quality"]) if format in ["jpg", "jpeg"]: if "quality" not in options: options["quality"] = rcParams["savefig.jpeg_quality"] options["quality"] = str(options["quality"]) if is_string_like(filename): try: pixbuf.save(filename, format, options=options) except gobject.GError as exc: error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, "save_to_callback"): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options) except gobject.GError as exc: error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self) else: raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8") else: raise ValueError("filename must be a path or a file-like object") def new_timer(self, *args, **kwargs): """ Creates a new backend-specific subclass of :class:`backend_bases.Timer`. This is useful for getting periodic events through the backend's native event loop. Implemented only for backends with GUIs. Other Parameters ---------------- interval : scalar Timer interval in milliseconds callbacks : list Sequence of (func, args, kwargs) where ``func(*args, **kwargs)`` will be executed by the timer every *interval*. """ return TimerGTK(*args, **kwargs) def flush_events(self): gtk.gdk.threads_enter() while gtk.events_pending(): gtk.main_iteration(True) gtk.gdk.flush() gtk.gdk.threads_leave() def start_event_loop(self, timeout): FigureCanvasBase.start_event_loop_default(self, timeout) start_event_loop.__doc__ = FigureCanvasBase.start_event_loop_default.__doc__ def stop_event_loop(self): FigureCanvasBase.stop_event_loop_default(self) stop_event_loop.__doc__ = FigureCanvasBase.stop_event_loop_default.__doc__