Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/sugar3/graphics/palettewindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/sugar3/graphics/palettewindow.py')
-rw-r--r--src/sugar3/graphics/palettewindow.py489
1 files changed, 362 insertions, 127 deletions
diff --git a/src/sugar3/graphics/palettewindow.py b/src/sugar3/graphics/palettewindow.py
index 562f1d5..fe0b5a1 100644
--- a/src/sugar3/graphics/palettewindow.py
+++ b/src/sugar3/graphics/palettewindow.py
@@ -1,6 +1,8 @@
# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>
# Copyright (C) 2008, One Laptop Per Child
# Copyright (C) 2009, Tomeu Vizoso
+# Copyright (C) 2011, Benjamin Berg <benjamin@sipsolutions.net>
+# Copyright (C) 2011, Marco Pesenti Gritti <marco@marcopg.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -65,6 +67,269 @@ def _calculate_gap(a, b):
return False
+class _PaletteMenuWidget(Gtk.Menu):
+
+ __gtype_name__ = "SugarPaletteMenuWidget"
+
+ __gsignals__ = {
+ 'enter-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
+ 'leave-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
+ }
+
+ def __init__(self):
+ Gtk.Menu.__init__(self)
+
+ accel_group = Gtk.AccelGroup()
+ self.set_data('sugar-accel-group', accel_group)
+ self.get_toplevel().add_accel_group(accel_group)
+
+ self._popup_position = (0, 0)
+ self._entered = False
+ self._mouse_in_palette = False
+ self._mouse_in_invoker = False
+ self._up = False
+ self._invoker = None
+ self._menus = []
+
+ def set_accept_focus(self, focus):
+ pass
+
+ def get_origin(self):
+ res_, x, y = self.get_toplevel().get_window().get_origin()
+ return x, y
+
+ def do_size_request(self, requisition):
+ Gtk.Window.do_size_request(self, requisition)
+ requisition.width = max(requisition.width, style.GRID_CELL_SIZE * 2)
+
+ def move(self, x, y):
+ self._popup_position = (x, y)
+
+ def set_transient_for(self, window):
+ pass
+
+ def _position(self, widget, data):
+ return self._popup_position[0], self._popup_position[1], False
+
+ def popup(self, invoker):
+ if self._up:
+ return
+
+ # We need to track certain mouse events in order to close the palette
+ # when the mouse leaves the palette and the invoker widget, but
+ # GtkMenu makes our lives hard here.
+ #
+ # GtkMenu takes a grab on the root window, meaning that normal
+ # enter/leave events are not sent to the relevant widgets.
+ # However, connecting enter-notify and leave-notify events in this
+ # GtkMenu subclass mean that we get to see the events being grabbed.
+ # With certain filtering in place (see _enter_notify_cb and
+ # _leave_notify_cb) we are able to accurately determine when the
+ # mouse leaves/enters the palette menu. Some spurious events are
+ # generated but the important thing is that the last event generated
+ # in response to a user action is always reliable (i.e. we will
+ # always get a leave event last if the user left the menu,
+ # even if we get some strange enter events leading up to it).
+ #
+ # This is complicated with submenus; in this case the submenu takes
+ # the grab, so we must also listen for events on any submenus of
+ # the palette and apply the same considerations.
+ #
+ # The remaining challenge is tracking when the mouse enters or leaves
+ # the invoker area. While the appropriate GtkMenu grab is active,
+ # we do get informed of such events, however these events will only
+ # arrive if the user has entered the menu. If the user hovers over
+ # the invoker and then leaves the invoker without entering the palette,
+ # we get no enter/leave event.
+ # We work around this by tracking mouse motion events. When the mouse
+ # moves, we compare the mouse coordinates to the region occupied by the
+ # invoker, and this lets us track enter/leave for the invoker widget.
+
+ self._invoker = invoker
+ self._find_all_menus(self)
+ for menu in self._menus:
+ if self._invoker:
+ menu.connect('motion-notify-event', self._motion_notify_cb)
+ menu.connect('enter-notify-event', self._enter_notify_cb)
+ menu.connect('leave-notify-event', self._leave_notify_cb)
+ self._entered = False
+ self._mouse_in_palette = False
+ self._mouse_in_invoker = False
+ Gtk.Menu.popup(self, None, None, self._position, None, 0, 0)
+ self._up = True
+
+ def popdown(self):
+ if not self._up:
+ return
+ Gtk.Menu.popdown(self)
+
+ for menu in self._menus:
+ menu.disconnect_by_func(self._motion_notify_cb)
+ menu.disconnect_by_func(self._enter_notify_cb)
+ menu.disconnect_by_func(self._leave_notify_cb)
+
+ self._up = False
+ self._menus = []
+ self._invoker = None
+
+ def _find_all_menus(self, menu):
+ """
+ Recursively find all submenus of menu, adding them to self._menus.
+ """
+ self._menus.append(menu)
+ for child in menu.get_children():
+ if not isinstance(child, Gtk.MenuItem):
+ continue
+ submenu = child.get_submenu()
+ if submenu and isinstance(submenu, Gtk.Menu):
+ self._find_all_menus(submenu)
+
+ def _enter_notify_cb(self, widget, event):
+ if event.mode in (Gdk.CrossingMode.GRAB, Gdk.CrossingMode.GTK_GRAB):
+ return False
+ if Gtk.get_event_widget(event) not in self._menus:
+ return False
+
+ self._mouse_in_palette = True
+ self._reevaluate_state()
+ return False
+
+ def _leave_notify_cb(self, widget, event):
+ if event.mode in (Gdk.CrossingMode.GRAB, Gdk.CrossingMode.GTK_GRAB):
+ return False
+ if Gtk.get_event_widget(event) not in self._menus:
+ return False
+
+ self._mouse_in_palette = False
+ self._reevaluate_state()
+ return False
+
+ def _motion_notify_cb(self, widget, event):
+ rect = self._invoker.get_rect()
+ x = event.x_root
+ y = event.y_root
+ in_invoker = x >= rect.x and x < (rect.x + rect.width) \
+ and y >= rect.y and y < (rect.y + rect.height)
+ if in_invoker != self._mouse_in_invoker:
+ self._mouse_in_invoker = in_invoker
+ self._reevaluate_state()
+
+ def _reevaluate_state(self):
+ if self._entered:
+ # If we previously advised that the mouse was inside, but now the
+ # mouse is outside both the invoker and the palette, notify that
+ # the mouse has left.
+ if not self._mouse_in_palette and not self._mouse_in_invoker:
+ self._entered = False
+ self.emit('leave-notify')
+ else:
+ # If we previously advised that the mouse had left, but now the
+ # mouse is inside either the palette or the invoker, notify that
+ # the mouse has entered.
+ if self._mouse_in_palette or self._mouse_in_invoker:
+ self._entered = True
+ self.emit('enter-notify')
+
+
+class _PaletteWindowWidget(Gtk.Window):
+
+ __gtype_name__ = 'SugarPaletteWindowWidget'
+
+ __gsignals__ = {
+ 'enter-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
+ 'leave-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
+ }
+
+ def __init__(self):
+ Gtk.Window.__init__(self)
+
+ self.set_decorated(False)
+ self.set_resizable(False)
+ self.set_position(Gtk.WindowPosition.NONE)
+
+ accel_group = Gtk.AccelGroup()
+ self.set_data('sugar-accel-group', accel_group)
+ self.add_accel_group(accel_group)
+
+ self._old_alloc = None
+
+ self._should_accept_focus = True
+
+ def set_accept_focus(self, focus):
+ self._should_accept_focus = focus
+ if self.get_window() != None:
+ self.get_window().set_accept_focus(focus)
+
+ def get_origin(self):
+ res_, x, y = self.get_window().get_origin()
+ return x, y
+
+ def do_realize(self):
+ Gtk.Window.do_realize(self)
+
+ self.get_window().set_accept_focus(self._should_accept_focus)
+ self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
+
+ def do_size_request(self, requisition):
+ Gtk.Window.do_size_request(self, requisition)
+ requisition.width = max(requisition.width, style.GRID_CELL_SIZE * 2)
+
+ def do_size_allocate(self, allocation):
+ Gtk.Window.do_size_allocate(self, allocation)
+
+ if self._old_alloc is None or \
+ self._old_alloc.x != allocation.x or \
+ self._old_alloc.y != allocation.y or \
+ self._old_alloc.width != allocation.width or \
+ self._old_alloc.height != allocation.height:
+ self.queue_draw()
+
+ # We need to store old allocation because when size_allocate
+ # is called widget.allocation is already updated.
+ # Gtk.Window resizing is different from normal containers:
+ # the X window is resized, widget.allocation is updated from
+ # the configure request handler and finally size_allocate is called.
+ self._old_alloc = allocation
+
+ def do_button_release_event(self, event):
+ alloc = self.get_allocation()
+ x, y = self.get_window().get_position()
+
+ in_window = event.x_root >= x and event.x_root < x + alloc.width and \
+ event.y_root >= y and event.y_root < y + alloc.height
+
+ if not in_window:
+ self.popdown()
+ return True
+
+ def __enter_notify_event_cb(self, widget, event):
+ if event.mode == Gdk.CrossingMode.NORMAL and \
+ event.detail != Gdk.NotifyType.INFERIOR:
+ self.emit('enter-notify')
+ return False
+
+ def __leave_notify_event_cb(self, widget, event):
+ if event.mode != Gdk.CrossingMode.NORMAL:
+ return False
+
+ if event.detail != Gdk.NotifyType.INFERIOR:
+ self.emit('leave-notify')
+
+ def popup(self, invoker):
+ if self.get_visible():
+ return
+ self.connect('enter-notify-event', self.__enter_notify_event_cb)
+ self.connect('leave-notify-event', self.__leave_notify_event_cb)
+ self.show()
+
+ def popdown(self):
+ if not self.get_visible():
+ return
+ self.disconnect_by_func(self.__enter_notify_event_cb)
+ self.disconnect_by_func(self.__leave_notify_event_cb)
+ self.hide()
+
+
class MouseSpeedDetector(GObject.GObject):
__gsignals__ = {
@@ -75,15 +340,15 @@ class MouseSpeedDetector(GObject.GObject):
_MOTION_SLOW = 1
_MOTION_FAST = 2
- def __init__(self, parent, delay, thresh):
+ def __init__(self, delay, thresh):
"""Create MouseSpeedDetector object,
delay in msec
threshold in pixels (per tick of 'delay' msec)"""
GObject.GObject.__init__(self)
+ self.parent = None
self._threshold = thresh
- self._parent = parent
self._delay = delay
self._state = None
self._timeout_hid = None
@@ -101,8 +366,10 @@ class MouseSpeedDetector(GObject.GObject):
self._state = None
def _get_mouse_position(self):
- display = Gdk.Display.get_default()
- screen_, x, y, mask_ = display.get_pointer()
+ display = self.parent.get_display()
+ manager = display.get_device_manager()
+ pointer_device = manager.get_client_pointer()
+ screen, x, y = pointer_device.get_position()
return (x, y)
def _detect_motion(self):
@@ -128,14 +395,16 @@ class MouseSpeedDetector(GObject.GObject):
return True
-class PaletteWindow(Gtk.Window):
+class PaletteWindow(GObject.GObject):
+ """
+ Base class for _ToolbarPalette and Palette.
- __gtype_name__ = 'SugarPaletteWindow'
+ Provides basic management of child widget, invoker, and animation.
+ """
__gsignals__ = {
'popup': (GObject.SignalFlags.RUN_FIRST, None, ([])),
'popdown': (GObject.SignalFlags.RUN_FIRST, None, ([])),
- 'activate': (GObject.SignalFlags.RUN_FIRST, None, ([])),
}
def __init__(self, **kwargs):
@@ -146,8 +415,8 @@ class PaletteWindow(Gtk.Window):
self._cursor_y = 0
self._alignment = None
self._up = False
- self._old_alloc = None
self._palette_state = None
+ self._widget = None
self._popup_anim = animator.Animator(.5, 10)
self._popup_anim.add(_PopupAnimation(self))
@@ -157,29 +426,31 @@ class PaletteWindow(Gtk.Window):
GObject.GObject.__init__(self, **kwargs)
- self.set_decorated(False)
- self.set_resizable(False)
- # Just assume xthickness and ythickness are the same
- self.set_border_width(self.get_style().xthickness)
+ self.set_group_id('default')
- accel_group = Gtk.AccelGroup()
- self.set_data('sugar-accel-group', accel_group)
- self.add_accel_group(accel_group)
+ self._mouse_detector = MouseSpeedDetector(200, 5)
- self.set_group_id('default')
+ def _setup_widget(self):
+ self._widget.connect('show', self.__show_cb)
+ self._widget.connect('hide', self.__hide_cb)
+ self._widget.connect('destroy', self.__destroy_cb)
+ self._widget.connect('enter-notify', self.__enter_notify_cb)
+ self._widget.connect('leave-notify', self.__leave_notify_cb)
- self.connect('show', self.__show_cb)
- self.connect('hide', self.__hide_cb)
- self.connect('realize', self.__realize_cb)
- self.connect('destroy', self.__destroy_cb)
- self.connect('enter-notify-event', self.__enter_notify_event_cb)
- self.connect('leave-notify-event', self.__leave_notify_event_cb)
+ self._set_effective_group_id(self._group_id)
- self._mouse_detector = MouseSpeedDetector(self, 200, 5)
self._mouse_detector.connect('motion-slow', self._mouse_slow_cb)
+ self._mouse_detector.parent = self._widget
+
+ def _teardown_widget(self):
+ self._widget.disconnect_by_func(self.__show_cb)
+ self._widget.disconnect_by_func(self.__hide_cb)
+ self._widget.disconnect_by_func(self.__destroy_cb)
+ self._widget.disconnect_by_func(self.__enter_notify_cb)
+ self._widget.disconnect_by_func(self.__leave_notify_cb)
+ self._set_effective_group_id(None)
def __destroy_cb(self, palette):
- self.set_group_id(None)
self._mouse_detector.disconnect_by_func(self._mouse_slow_cb)
def set_invoker(self, invoker):
@@ -203,9 +474,6 @@ class PaletteWindow(Gtk.Window):
getter=get_invoker,
setter=set_invoker)
- def __realize_cb(self, widget):
- self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
-
def _mouse_slow_cb(self, widget):
self._mouse_detector.stop()
self._palette_do_popup()
@@ -228,15 +496,18 @@ class PaletteWindow(Gtk.Window):
def is_up(self):
return self._up
- def set_group_id(self, group_id):
+ def _set_effective_group_id(self, group_id):
if self._group_id:
group = palettegroup.get_group(self._group_id)
group.remove(self)
if group_id:
- self._group_id = group_id
group = palettegroup.get_group(group_id)
group.add(self)
+ def set_group_id(self, group_id):
+ self._set_effective_group_id(group_id)
+ self._group_id = group_id
+
def get_group_id(self):
return self._group_id
@@ -244,69 +515,21 @@ class PaletteWindow(Gtk.Window):
getter=get_group_id,
setter=set_group_id)
- def do_size_request(self, requisition):
- Gtk.Window.do_size_request(self, requisition)
- requisition.width = max(requisition.width, style.GRID_CELL_SIZE * 2)
-
- def do_size_allocate(self, allocation):
- Gtk.Window.do_size_allocate(self, allocation)
-
- if self._old_alloc is None or \
- self._old_alloc.x != allocation.x or \
- self._old_alloc.y != allocation.y or \
- self._old_alloc.width != allocation.width or \
- self._old_alloc.height != allocation.height:
- self.queue_draw()
-
- # We need to store old allocation because when size_allocate
- # is called widget.allocation is already updated.
- # Gtk.Window resizing is different from normal containers:
- # the X window is resized, widget.allocation is updated from
- # the configure request handler and finally size_allocate is called.
- self._old_alloc = allocation
-
- def do_expose_event(self, event):
- # We want to draw a border with a beautiful gap
- if self._invoker is not None and self._invoker.has_rectangle_gap():
- invoker = self._invoker.get_rect()
- palette = self.get_rect()
-
- gap = _calculate_gap(palette, invoker)
- else:
- gap = False
-
- allocation = self.get_allocation()
- wstyle = self.get_style()
-
- if gap:
- wstyle.paint_box_gap(event.window, Gtk.StateType.PRELIGHT,
- Gtk.ShadowType.IN, event.area, self, 'palette',
- 0, 0, allocation.width, allocation.height,
- gap[0], gap[1], gap[2])
- else:
- wstyle.paint_box(event.window, Gtk.StateType.PRELIGHT,
- Gtk.ShadowType.IN, event.area, self, 'palette',
- 0, 0, allocation.width, allocation.height)
-
- # Fall trough to the container expose handler.
- # (Leaving out the window expose handler which redraws everything)
- Gtk.Bin.do_expose_event(self, event)
-
def update_position(self):
invoker = self._invoker
if invoker is None or self._alignment is None:
logging.error('Cannot update the palette position.')
return
- rect = self.size_request()
+ rect = self._widget.size_request()
position = invoker.get_position_for_alignment(self._alignment, rect)
if position is None:
position = invoker.get_position(rect)
- self.move(position.x, position.y)
+ self._widget.move(position.x, position.y)
def get_full_size_request(self):
- return self.size_request()
+ return self._widget.size_request()
def popup(self, immediate=False):
if self._invoker is not None:
@@ -314,7 +537,7 @@ class PaletteWindow(Gtk.Window):
self._alignment = self._invoker.get_alignment(full_size_request)
self.update_position()
- self.set_transient_for(self._invoker.get_toplevel())
+ self._widget.set_transient_for(self._invoker.get_toplevel())
self._popdown_anim.stop()
@@ -322,7 +545,7 @@ class PaletteWindow(Gtk.Window):
self._popup_anim.start()
else:
self._popup_anim.stop()
- self.show()
+ self._widget.popup(self._invoker)
# we have to invoke update_position() twice
# since WM could ignore first move() request
self.update_position()
@@ -335,8 +558,8 @@ class PaletteWindow(Gtk.Window):
self._popdown_anim.start()
else:
self._popdown_anim.stop()
- self.size_request()
- self.hide()
+ if self._widget is not None:
+ self._widget.popdown()
def on_invoker_enter(self):
self._popdown_anim.stop()
@@ -346,10 +569,10 @@ class PaletteWindow(Gtk.Window):
self._mouse_detector.stop()
self.popdown()
- def on_enter(self, event):
+ def on_enter(self):
self._popdown_anim.stop()
- def on_leave(self, event):
+ def on_leave(self):
self.popdown()
def _invoker_mouse_enter_cb(self, invoker):
@@ -361,15 +584,11 @@ class PaletteWindow(Gtk.Window):
def _invoker_right_click_cb(self, invoker):
self.popup(immediate=True)
- def __enter_notify_event_cb(self, widget, event):
- if event.detail != Gdk.NOTIFY_INFERIOR and \
- event.mode == Gdk.CROSSING_NORMAL:
- self.on_enter(event)
+ def __enter_notify_cb(self, widget):
+ self.on_enter()
- def __leave_notify_event_cb(self, widget, event):
- if event.detail != Gdk.NOTIFY_INFERIOR and \
- event.mode == Gdk.CROSSING_NORMAL:
- self.on_leave(event)
+ def __leave_notify_cb(self, widget):
+ self.on_leave()
def __show_cb(self, widget):
if self._invoker is not None:
@@ -386,14 +605,20 @@ class PaletteWindow(Gtk.Window):
self.emit('popdown')
def get_rect(self):
- win_x, win_y = self.get_window().get_origin()
+ win_x, win_y = self._widget.get_origin()
rectangle = self.get_allocation()
x = win_x + rectangle.x
y = win_y + rectangle.y
- width, height = self.size_request()
+ requisition = self._widget.size_request()
- return (x, y, width, height)
+ rect = Gdk.Rectangle()
+ rect.x = x
+ rect.y = y
+ rect.width = requisition.width
+ rect.height = requisition.height
+
+ return rect
def get_palette_state(self):
return self._palette_state
@@ -453,8 +678,10 @@ class Invoker(GObject.GObject):
self.parent = None
- self._screen_area = (0, 0, Gdk.Screen.width(),
- Gdk.Screen.height())
+ self._screen_area = Gdk.Rectangle()
+ self._screen_area.x = self._screen_area.y = 0
+ self._screen_area.width = Gdk.Screen.width()
+ self._screen_area.height = Gdk.Screen.height()
self._position_hint = self.ANCHORED
self._cursor_x = -1
self._cursor_y = -1
@@ -477,8 +704,10 @@ class Invoker(GObject.GObject):
invoker_valign = alignment[3]
if self._cursor_x == -1 or self._cursor_y == -1:
- display = Gdk.Display.get_default()
- screen_, x, y, mask_ = display.get_pointer()
+ display = self.parent.get_display()
+ manager = display.get_device_manager()
+ pointer_device = manager.get_client_pointer()
+ screen, x, y = pointer_device.get_position()
self._cursor_x = x
self._cursor_y = y
@@ -486,11 +715,12 @@ class Invoker(GObject.GObject):
rect = self.get_rect()
else:
dist = style.PALETTE_CURSOR_DISTANCE
- rect = (self._cursor_x - dist,
- self._cursor_y - dist,
- dist * 2, dist * 2)
+ rect = Gdk.Rectangle()
+ rect.x = self._cursor_x - dist
+ rect.y = self._cursor_y - dist
+ rect.width = rect.height = dist * 2
- palette_width, palette_height = palette_dim
+ palette_width, palette_height = palette_dim.width, palette_dim.height
x = rect.x + rect.width * invoker_halign + \
palette_width * palette_halign
@@ -498,8 +728,12 @@ class Invoker(GObject.GObject):
y = rect.y + rect.height * invoker_valign + \
palette_height * palette_valign
- return (int(x), int(y),
- palette_width, palette_height)
+ rect = Gdk.Rectangle()
+ rect.x = int(x)
+ rect.y = int(y)
+ rect.width = palette_width
+ rect.height = palette_height
+ return rect
def _in_screen(self, rect):
return rect.x >= self._screen_area.x and \
@@ -582,12 +816,12 @@ class Invoker(GObject.GObject):
# Set palette_valign to align to screen on the top
if dtop > dbottom:
- pv = -float(dtop) / palette_dim[1]
+ pv = -float(dtop) / palette_dim.height
# Set palette_valign to align to screen on the bottom
else:
- pv = -float(palette_dim[1] - dbottom - rect.height) \
- / palette_dim[1]
+ pv = -float(palette_dim.height - dbottom - rect.height) \
+ / palette_dim.height
elif best_alignment in self.TOP or best_alignment in self.BOTTOM:
dleft = rect.x - screen_area.x
@@ -597,12 +831,12 @@ class Invoker(GObject.GObject):
# Set palette_halign to align to screen on left
if dleft > dright:
- ph = -float(dleft) / palette_dim[0]
+ ph = -float(dleft) / palette_dim.width
# Set palette_halign to align to screen on right
else:
- ph = -float(palette_dim[0] - dright - rect.width) \
- / palette_dim[0]
+ ph = -float(palette_dim.width - dright - rect.width) \
+ / palette_dim.width
return (ph, pv, ih, iv)
@@ -717,30 +951,31 @@ class WidgetInvoker(Invoker):
allocation = self._widget.get_allocation()
window = self._widget.get_window()
if window is not None:
- x, y = window.get_origin()
+ res, x, y = window.get_origin()
else:
logging.warning(
"Trying to position palette with invoker that's not realized.")
x = 0
y = 0
- if self._widget.flags() & Gtk.NO_WINDOW:
- x += allocation.x
- y += allocation.y
+ x += allocation.x
+ y += allocation.y
width = allocation.width
height = allocation.height
- return (x, y, width, height)
+ rect = Gdk.Rectangle()
+ rect.x = x
+ rect.y = y
+ rect.width = width
+ rect.height = height
+ return rect
def has_rectangle_gap(self):
return True
def draw_rectangle(self, event, palette):
- if self._widget.flags() & Gtk.NO_WINDOW:
- x, y = self._widget.allocation.x, self._widget.allocation.y
- else:
- x = y = 0
+ x, y = self._widget.allocation.x, self._widget.allocation.y
wstyle = self._widget.get_style()
gap = _calculate_gap(self.get_rect(), palette.get_rect())
@@ -763,7 +998,8 @@ class WidgetInvoker(Invoker):
self.notify_mouse_enter()
def __leave_notify_event_cb(self, widget, event):
- self.notify_mouse_leave()
+ if event.mode == Gdk.CrossingMode.NORMAL:
+ self.notify_mouse_leave()
def __button_release_event_cb(self, widget, event):
if event.button == 3:
@@ -908,16 +1144,15 @@ class CellRendererInvoker(Invoker):
allocation = self._tree_view.get_allocation()
window = self._tree_view.get_window()
if window is not None:
- x, y = window.get_origin()
+ res, x, y = window.get_origin()
else:
logging.warning(
"Trying to position palette with invoker that's not realized.")
x = 0
y = 0
- if self._tree_view.flags() & Gtk.NO_WINDOW:
- x += allocation.x
- y += allocation.y
+ x += allocation.x
+ y += allocation.y
width = allocation.width
height = allocation.height