Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar

This commit is contained in:
Marco Pesenti Gritti 2007-06-20 12:05:32 +02:00
commit b01684ef27
5 changed files with 142 additions and 89 deletions

View File

@ -71,12 +71,6 @@ class HomeModel(gobject.GObject):
screen.connect('active-window-changed', screen.connect('active-window-changed',
self._active_window_changed_cb) self._active_window_changed_cb)
bus = dbus.SessionBus()
bus.add_signal_receiver(self._dbus_name_owner_changed_cb,
'NameOwnerChanged',
'org.freedesktop.DBus',
'org.freedesktop.DBus')
def get_current_activity(self): def get_current_activity(self):
return self._current_activity return self._current_activity
@ -111,7 +105,7 @@ class HomeModel(gobject.GObject):
activity = HomeActivity(bundle, activity_id) activity = HomeActivity(bundle, activity_id)
self._add_activity(activity) self._add_activity(activity)
service = self._get_activity_service(window.get_xid()) service = self._get_activity_service(activity_id)
activity.set_service(service) activity.set_service(service)
activity.set_window(window) activity.set_window(window)
@ -125,19 +119,6 @@ class HomeModel(gobject.GObject):
self.emit('active-activity-changed', None) self.emit('active-activity-changed', None)
self._notify_activity_activation(self._current_activity, None) self._notify_activity_activation(self._current_activity, None)
def _dbus_name_owner_changed_cb(self, name, old, new):
"""Detect new activity instances on the DBus"""
if name.startswith(_SERVICE_NAME) and new and not old:
try:
xid = int(name[len(_SERVICE_NAME):])
activity = self._get_activity_by_xid(xid)
if activity and not activity.get_service():
service = self._get_activity_service(xid)
activity.set_service(service)
except ValueError:
logging.error('Invalid activity service name, '
'cannot extract the xid')
def _get_activity_by_xid(self, xid): def _get_activity_by_xid(self, xid):
for activity in self._activities: for activity in self._activities:
if activity.get_xid() == xid: if activity.get_xid() == xid:
@ -185,12 +166,12 @@ class HomeModel(gobject.GObject):
self.emit('active-activity-changed', self._current_activity) self.emit('active-activity-changed', self._current_activity)
def _get_activity_service(self, xid): def _get_activity_service(self, activity_id):
bus = dbus.SessionBus() bus = dbus.SessionBus()
try: try:
service = dbus.Interface( service = dbus.Interface(
bus.get_object(_SERVICE_NAME + '%d' % xid, bus.get_object(_SERVICE_NAME + activity_id,
_SERVICE_PATH + "/%s" % xid), _SERVICE_PATH + "/" + activity_id),
_SERVICE_INTERFACE) _SERVICE_INTERFACE)
except dbus.DBusException: except dbus.DBusException:
service = None service = None

View File

@ -26,10 +26,6 @@ from sugar.presence import presenceservice
from sugar.activity.activityhandle import ActivityHandle from sugar.activity.activityhandle import ActivityHandle
from sugar import util from sugar import util
_ACTIVITY_SERVICE_NAME = "org.laptop.Activity"
_ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
_ACTIVITY_INTERFACE = "org.laptop.Activity"
_ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory" _ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory"
def create_activity_id(): def create_activity_id():

View File

@ -33,24 +33,21 @@ class ActivityService(dbus.service.Object):
def __init__(self, activity): def __init__(self, activity):
"""Initialise the service for the given activity """Initialise the service for the given activity
activity -- sugar.activity.activity.Activity instance, activity -- sugar.activity.activity.Activity instance
must have already bound it's window (i.e. it must
have already initialised to the point of having
the X window available).
Creates dbus services that use the xid of the activity's Creates dbus services that use the instance's activity_id
root window as discriminants among all active services as discriminants among all active services
of this type. That is, the services are all available of this type. That is, the services are all available
as names/paths derived from the xid for the window. as names/paths derived from the instance's activity_id.
The various methods exposed on dbus are just forwarded The various methods exposed on dbus are just forwarded
to the client Activity object's equally-named methods. to the client Activity object's equally-named methods.
""" """
activity.realize() activity.realize()
xid = activity.window.xid activity_id = activity.get_id()
service_name = _ACTIVITY_SERVICE_NAME + '%d' % xid service_name = _ACTIVITY_SERVICE_NAME + activity_id
object_path = _ACTIVITY_SERVICE_PATH + "/%s" % xid object_path = _ACTIVITY_SERVICE_PATH + "/" + activity_id
bus = dbus.SessionBus() bus = dbus.SessionBus()
bus_name = dbus.service.BusName(service_name, bus=bus) bus_name = dbus.service.BusName(service_name, bus=bus)

View File

@ -21,6 +21,7 @@ import gtk
from gtk import gdk, keysyms from gtk import gdk, keysyms
import gobject import gobject
import time import time
import hippo
ALIGNMENT_AUTOMATIC = 0 ALIGNMENT_AUTOMATIC = 0
ALIGNMENT_BOTTOM_LEFT = 1 ALIGNMENT_BOTTOM_LEFT = 1
@ -36,7 +37,7 @@ class Palette(gtk.Window):
__gtype_name__ = 'SugarPalette' __gtype_name__ = 'SugarPalette'
__gproperties__ = { __gproperties__ = {
'parent': (object, None, None, gobject.PARAM_READWRITE), 'invoker': (object, None, None, gobject.PARAM_READWRITE),
'alignment': (gobject.TYPE_INT, None, None, 0, 8, ALIGNMENT_AUTOMATIC, 'alignment': (gobject.TYPE_INT, None, None, 0, 8, ALIGNMENT_AUTOMATIC,
gobject.PARAM_READWRITE), gobject.PARAM_READWRITE),
@ -46,7 +47,6 @@ class Palette(gtk.Window):
_PADDING = 1 _PADDING = 1
_WIN_BORDER = 5 _WIN_BORDER = 5
_POPUP_PALETTE_DELAY = 0.15
def __init__(self, **kwargs): def __init__(self, **kwargs):
gobject.GObject.__init__(self, type=gtk.WINDOW_POPUP, **kwargs) gobject.GObject.__init__(self, type=gtk.WINDOW_POPUP, **kwargs)
@ -85,7 +85,7 @@ class Palette(gtk.Window):
self.add(vbox) self.add(vbox)
# Widget events # Widget events
self.connect('motion-notify-event', self._mouse_over_widget_cb) self.connect('enter-notify-event', self._mouse_over_widget_cb)
self.connect('leave-notify-event', self._mouse_out_widget_cb) self.connect('leave-notify-event', self._mouse_out_widget_cb)
self.connect('button-press-event', self._close_palette_cb) self.connect('button-press-event', self._close_palette_cb)
self.connect('key-press-event', self._on_key_press_event_cb) self.connect('key-press-event', self._on_key_press_event_cb)
@ -96,8 +96,8 @@ class Palette(gtk.Window):
self._scr_height = gtk.gdk.screen_height() self._scr_height = gtk.gdk.screen_height()
def do_set_property(self, pspec, value): def do_set_property(self, pspec, value):
if pspec.name == 'parent': if pspec.name == 'invoker':
self._parent_widget = value self._invoker = value
elif pspec.name == 'alignment': elif pspec.name == 'alignment':
self._alignment = value self._alignment = value
elif pspec.name == 'is-tooltip': elif pspec.name == 'is-tooltip':
@ -155,41 +155,41 @@ class Palette(gtk.Window):
return True return True
def _calc_position(self, alignment): def _calc_position(self, alignment):
win_x, win_y = self._parent_widget.window.get_origin() # Invoker: x, y, width and height
parent_rectangle = self._parent_widget.get_allocation() inv_rect = self._invoker.get_rect()
palette_rectangle = self.get_allocation() palette_rectangle = self.get_allocation()
if alignment == ALIGNMENT_BOTTOM_LEFT: if alignment == ALIGNMENT_BOTTOM_LEFT:
move_x = win_x + parent_rectangle.x move_x = inv_rect.x
move_y = win_y + parent_rectangle.y + parent_rectangle.height move_y = inv_rect.y + inv_rect.height
elif alignment == ALIGNMENT_BOTTOM_RIGHT: elif alignment == ALIGNMENT_BOTTOM_RIGHT:
move_x = (win_x + parent_rectangle.x + parent_rectangle.width) - self._width move_x = (inv_rect.x + inv_rect.width) - self._width
move_y = win_y + parent_rectangle.y + parent_rectangle.height move_y = inv_rect.y + inv_rect.height
elif alignment == ALIGNMENT_LEFT_BOTTOM: elif alignment == ALIGNMENT_LEFT_BOTTOM:
move_x = (win_x + parent_rectangle.x) - self._width move_x = inv_rect.x - self._width
move_y = win_y + parent_rectangle.y move_y = inv_rect.y
elif alignment == ALIGNMENT_LEFT_TOP: elif alignment == ALIGNMENT_LEFT_TOP:
move_x = (win_x + parent_rectangle.x) - self._width move_x = inv_rect.x - self._width
move_y = (win_y + parent_rectangle.y + parent_rectangle.height) - palette_rectangle.height move_y = (inv_rect.y + inv_rect.height) - palette_rectangle.height
elif alignment == ALIGNMENT_RIGHT_BOTTOM: elif alignment == ALIGNMENT_RIGHT_BOTTOM:
move_x = win_x + parent_rectangle.x + parent_rectangle.width move_x = inv_rect.x + inv_rect.width
move_y = win_y + parent_rectangle.y move_y = inv_rect.y
elif alignment == ALIGNMENT_RIGHT_TOP: elif alignment == ALIGNMENT_RIGHT_TOP:
move_x = win_x + parent_rectangle.x + parent_rectangle.width move_x = inv_rect.x + inv_rect.width
move_y = (win_y + parent_rectangle.y + parent_rectangle.height) - palette_rectangle.height move_y = (inv_rect.y + inv_rect.height) - palette_rectangle.height
elif alignment == ALIGNMENT_TOP_LEFT: elif alignment == ALIGNMENT_TOP_LEFT:
move_x = (win_x + parent_rectangle.x) move_x = inv_rect.x
move_y = (win_y + parent_rectangle.y) - (palette_rectangle.height) move_y = inv_rect.y - palette_rectangle.height
elif alignment == ALIGNMENT_TOP_RIGHT: elif alignment == ALIGNMENT_TOP_RIGHT:
move_x = (win_x + parent_rectangle.x + parent_rectangle.width) - self._width move_x = (inv_rect.x + inv_rect.width) - self._width
move_y = (win_y + parent_rectangle.y) - (palette_rectangle.height) move_y = inv_rect.y - palette_rectangle.height
return move_x, move_y return move_x, move_y
@ -219,18 +219,13 @@ class Palette(gtk.Window):
# Display the palette and set the position on the screen # Display the palette and set the position on the screen
def popup(self): def popup(self):
# We need to know if the mouse pointer continue inside
# the parent widget (opener)
pointer_x, pointer_y = self._parent_widget.get_pointer()
self._parent_alloc = self._parent_widget.get_allocation()
pointer_rect = gdk.Rectangle(pointer_x + self._parent_alloc.x, pointer_y + self._parent_alloc.y, 1, 1)
if (self._parent_widget.allocation.intersect(pointer_rect).width == 0):
return
self.realize() self.realize()
self.set_position() self.set_position()
self._pointer_grab() self._pointer_ungrab()
def popdown(self):
self._pointer_ungrab()
self.hide()
# PRIVATE METHODS # PRIVATE METHODS
@ -244,32 +239,29 @@ class Palette(gtk.Window):
else: else:
return False return False
def _pointer_grab(self): def _pointer_ungrab(self):
gtk.gdk.pointer_grab(self.window, owner_events=False, gdk.keyboard_ungrab()
event_mask=gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.ENTER_NOTIFY_MASK |
gtk.gdk.LEAVE_NOTIFY_MASK |
gtk.gdk.POINTER_MOTION_MASK)
def _pointer_grab(self):
gdk.keyboard_grab(self.window, False) gdk.keyboard_grab(self.window, False)
# SIGNAL HANDLERS # SIGNAL HANDLERS
# Release the GDK pointer and hide the palette # Release the GDK pointer and hide the palette
def _close_palette_cb(self, widget=None, event=None): def _close_palette_cb(self, widget=None, event=None):
gtk.gdk.pointer_ungrab() self.popdown()
self.hide()
# Mouse is out of the widget # Mouse is out of the widget
def _mouse_out_widget_cb(self, widget, event): def _mouse_out_widget_cb(self, widget, event):
time.sleep(self._POPUP_PALETTE_DELAY)
if (widget == self) and self._is_mouse_out(widget): if (widget == self) and self._is_mouse_out(widget):
self._close_palette_cb() self._close_palette_cb()
return
self._pointer_grab()
# Mouse inside the widget # Mouse inside the widget
def _mouse_over_widget_cb(self, widget, event): def _mouse_over_widget_cb(self, widget, event):
gtk.gdk.pointer_ungrab() self._pointer_ungrab()
# Some key is pressed # Some key is pressed
def _on_key_press_event_cb(self, window, event): def _on_key_press_event_cb(self, window, event):
@ -282,3 +274,46 @@ class Palette(gtk.Window):
((keyval == keysyms.Up or keyval == keysyms.KP_Up) and ((keyval == keysyms.Up or keyval == keysyms.KP_Up) and
state == gdk.MOD1_MASK)): state == gdk.MOD1_MASK)):
self._close_palette_cb() self._close_palette_cb()
class WidgetInvoker:
def __init__(self, parent):
self._parent = parent
def get_rect(self):
win_x, win_y = self._parent.window.get_origin()
rectangle = self._parent.get_allocation()
x = win_x + rectangle.x
y = win_y + rectangle.y
width = rectangle.width
height = rectangle.height
return gtk.gdk.Rectangle(x, y, width, height)
# Is mouse over self._parent ?
def is_mouse_over(self):
pointer_x, pointer_y = self._parent.get_pointer()
self._parent_alloc = self._parent.get_allocation()
pointer_rect = gdk.Rectangle(pointer_x + self._parent_alloc.x, \
pointer_y + self._parent_alloc.y, 1, 1)
if (self._parent.allocation.intersect(pointer_rect).width == 0):
return False
return True
class CanvasInvoker:
def __init__(self, parent):
self._parent = parent
def get_rect(self):
context = self._parent.get_context()
x, y = context.translate_to_screen(self._parent)
width, height = self._parent.get_allocation()
return gtk.gdk.Rectangle(x, y, width, height)
# Is mouse over self._parent ?
def is_mouse_over(self):
return True

View File

@ -16,18 +16,23 @@
# Boston, MA 02111-1307, USA. # Boston, MA 02111-1307, USA.
import gtk import gtk
import gobject
import time import time
from sugar.graphics.icon import Icon from sugar.graphics.icon import Icon
from sugar.graphics.palette import * from sugar.graphics.palette import *
class ToolButton(gtk.ToolButton): class ToolButton(gtk.ToolButton):
_POPUP_PALETTE_DELAY = 0.15 _POPUP_PALETTE_DELAY = 100
def __init__(self, icon_name=None): def __init__(self, icon_name=None):
gtk.ToolButton.__init__(self) gtk.ToolButton.__init__(self)
self._palette = None self._palette = None
self.set_icon(icon_name) self.set_icon(icon_name)
self.child.connect('enter-notify-event',self._enter_notify_event_cb)
self.child.connect('leave-notify-event',self._leave_notify_event_cb)
self._enter_tag = None
self._leave_tag = None
def set_icon(self, icon_name): def set_icon(self, icon_name):
icon = Icon(icon_name) icon = Icon(icon_name)
@ -36,8 +41,7 @@ class ToolButton(gtk.ToolButton):
def set_palette(self, palette): def set_palette(self, palette):
self._palette = palette self._palette = palette
self._palette.props.parent = self self._palette.props.invoker = WidgetInvoker(self)
self.child.connect('enter-notify-event', self._show_palette_timeout_cb)
def set_tooltip(self, text): def set_tooltip(self, text):
if self._palette: if self._palette:
@ -45,9 +49,49 @@ class ToolButton(gtk.ToolButton):
self._palette = Palette(is_tooltip=True) self._palette = Palette(is_tooltip=True)
self._palette.set_primary_state(text) self._palette.set_primary_state(text)
self._palette.props.parent = self self._palette.props.invoker = WidgetInvoker(self)
self.child.connect('enter-notify-event', self._show_palette_timeout_cb)
def _show_palette_timeout_cb(self, widget, event): def _enter_notify_event_cb(self, widget, event):
time.sleep(self._POPUP_PALETTE_DELAY) gtk.gdk.pointer_ungrab()
if self._leave_tag:
gobject.source_remove(self._leave_tag)
self._leave_tag = None
self._enter_tag = gobject.timeout_add(self._POPUP_PALETTE_DELAY, \
self._show_palette)
def _leave_notify_event_cb(self, widget, event):
if self._enter_tag:
gobject.source_remove(self._enter_tag)
self._enter_tag = None
self._leave_tag = gobject.timeout_add(self._POPUP_PALETTE_DELAY,\
self._hide_palette)
def _show_palette(self):
self._palette.popup() self._palette.popup()
return False
def _hide_palette(self):
# Just hide the palette if the mouse pointer is
# out of the toolbutton and the palette
if self._is_mouse_out(self._palette):
self._palette.popdown()
else:
gtk.gdk.pointer_ungrab()
return False
def _pointer_grab(self):
gtk.gdk.pointer_grab(self.window, owner_events=True,\
event_mask=gtk.gdk.PROPERTY_CHANGE_MASK )
def _is_mouse_out(self, widget):
mouse_x, mouse_y = widget.get_pointer()
event_rect = gdk.Rectangle(mouse_x, mouse_y, 1, 1)
if (widget.allocation.intersect(event_rect).width==0):
return True
else:
return False