diff --git a/.gitignore b/.gitignore index d0ca2394..ffd6362b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,7 @@ po/*.gmo sugar/__installed__.py sugar/__uninstalled__.py tools/sugar-setup-activity -shell/PresenceService/org.laptop.Presence.service +services/presence/org.laptop.Presence.service threadframe config.guess config.sub diff --git a/Makefile.am b/Makefile.am index 72ff820f..323f1f43 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = activities bindings po shell sugar tools +SUBDIRS = activities bindings po shell sugar services tools ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 842a1133..a81c6d59 100644 --- a/configure.ac +++ b/configure.ac @@ -45,12 +45,15 @@ activities/terminal/Makefile bindings/Makefile bindings/globalkeys/Makefile bindings/threadframe/Makefile +services/Makefile +services/presence/Makefile shell/Makefile shell/conf/Makefile shell/data/Makefile -shell/home/Makefile -shell/frame/Makefile -shell/PresenceService/Makefile +shell/view/Makefile +shell/view/home/Makefile +shell/view/frame/Makefile +shell/model/Makefile sugar/Makefile sugar/__installed__.py sugar/__uninstalled__.py diff --git a/services/Makefile.am b/services/Makefile.am new file mode 100644 index 00000000..da404414 --- /dev/null +++ b/services/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = presence diff --git a/shell/PresenceService/Activity.py b/services/presence/Activity.py similarity index 100% rename from shell/PresenceService/Activity.py rename to services/presence/Activity.py diff --git a/shell/PresenceService/Buddy.py b/services/presence/Buddy.py similarity index 100% rename from shell/PresenceService/Buddy.py rename to services/presence/Buddy.py diff --git a/shell/PresenceService/Makefile.am b/services/presence/Makefile.am similarity index 74% rename from shell/PresenceService/Makefile.am rename to services/presence/Makefile.am index 1710d540..c095cb63 100644 --- a/shell/PresenceService/Makefile.am +++ b/services/presence/Makefile.am @@ -5,7 +5,7 @@ service_DATA = $(service_in_files:.service.in=.service) $(service_DATA): $(service_in_files) Makefile @sed -e "s|\@bindir\@|$(bindir)|" $< > $@ -sugardir = $(pkgdatadir)/shell/PresenceService +sugardir = $(pkgdatadir)/services/presence sugar_PYTHON = \ __init__.py \ Activity.py \ @@ -13,6 +13,8 @@ sugar_PYTHON = \ PresenceService.py \ Service.py +bin_SCRIPTS = sugar-presence-service + DISTCLEANFILES = $(service_DATA) -EXTRA_DIST = $(service_in_files) +EXTRA_DIST = $(service_in_files) $(bin_SCRIPTS) diff --git a/shell/PresenceService/PresenceService.py b/services/presence/PresenceService.py similarity index 100% rename from shell/PresenceService/PresenceService.py rename to services/presence/PresenceService.py diff --git a/shell/PresenceService/Service.py b/services/presence/Service.py similarity index 100% rename from shell/PresenceService/Service.py rename to services/presence/Service.py diff --git a/shell/PresenceService/__init__.py b/services/presence/__init__.py similarity index 100% rename from shell/PresenceService/__init__.py rename to services/presence/__init__.py diff --git a/shell/PresenceService/org.laptop.Presence.service.in b/services/presence/org.laptop.Presence.service.in similarity index 100% rename from shell/PresenceService/org.laptop.Presence.service.in rename to services/presence/org.laptop.Presence.service.in diff --git a/shell/sugar-presence-service b/services/presence/sugar-presence-service similarity index 78% rename from shell/sugar-presence-service rename to services/presence/sugar-presence-service index fda0d12c..88fd2e71 100755 --- a/shell/sugar-presence-service +++ b/services/presence/sugar-presence-service @@ -1,7 +1,7 @@ #!/usr/bin/python import logging -from PresenceService import PresenceService +from presence import PresenceService import sugar.logger sugar.logger.start('PresenceService') diff --git a/shell/ChatController.py b/shell/ChatController.py deleted file mode 100644 index 022d6080..00000000 --- a/shell/ChatController.py +++ /dev/null @@ -1,54 +0,0 @@ -import conf -from sugar.chat.BuddyChat import BuddyChat -from sugar.activity import ActivityFactory -from sugar.presence import PresenceService -from sugar.p2p.Stream import Stream -from sugar.chat.Chat import Chat - -class ChatController: - def __init__(self, shell): - self._shell = shell - self._id_to_name = {} - self._name_to_chat = {} - - self._shell.connect('activity-closed', self.__activity_closed_cb) - - def __activity_closed_cb(self, shell, activity): - activity_id = activity.get_id() - if self._id_to_name.has_key(activity_id): - name = self._id_to_name[activity_id] - del self._name_to_chat[name] - del self._id_to_name[activity_id] - - def listen(self): - self._pservice = PresenceService.get_instance() - - self._pservice.register_service_type(BuddyChat.SERVICE_TYPE) - profile = conf.get_profile() - self._service = self._pservice.register_service(profile.get_nick_name(), - BuddyChat.SERVICE_TYPE) - - self._buddy_stream = Stream.new_from_service(self._service) - self._buddy_stream.set_data_listener(self._recv_message) - - def open_chat_activity(self, buddy): - service = buddy.get_service_of_type(BuddyChat.SERVICE_TYPE) - if service: - activity = self._shell.start_activity('com.redhat.Sugar.ChatActivity') - activity.execute('connect', [service.object_path()]) - self._name_to_chat[buddy.get_name()] = activity - self._id_to_name[activity.get_id()] = buddy.get_name() - - def _get_chat_activity(self, buddy): - nick = buddy.get_name() - if not self._name_to_chat.has_key(nick): - self.open_chat_activity(buddy) - return self._name_to_chat[nick] - - def _recv_message(self, address, message): - [nick, msg] = Chat.deserialize_message(message) - buddy = self._pservice.get_buddy_by_name(nick) - if buddy: - activity = self._get_chat_activity(buddy) - if activity: - activity.execute('message', [message]) diff --git a/shell/Makefile.am b/shell/Makefile.am index 4a1d49bc..a4fd7192 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,24 +1,14 @@ -SUBDIRS = conf data frame home PresenceService +SUBDIRS = conf data model view bin_SCRIPTS = \ sugar \ sugar-activity \ sugar-activity-factory \ - sugar-console \ - sugar-presence-service + sugar-console sugardir = $(pkgdatadir)/shell sugar_PYTHON = \ __init__.py \ - ActivityHost.py \ - ChatController.py \ - ConsoleWindow.py \ - FirstTimeDialog.py \ - FriendPopup.py \ - Friends.py \ - Invites.py \ - Owner.py \ - Shell.py \ Session.py EXTRA_DIST = $(bin_SCRIPTS) diff --git a/shell/Session.py b/shell/Session.py index 07337d68..da17cd71 100644 --- a/shell/Session.py +++ b/shell/Session.py @@ -1,8 +1,8 @@ import os import gtk -from Shell import Shell -from ConsoleWindow import ConsoleWindow +from view.Shell import Shell +from model.ShellModel import ShellModel from sugar import env from sugar import logger @@ -10,7 +10,7 @@ from sugar.session.Process import Process from sugar.session.DbusProcess import DbusProcess from sugar.session.MatchboxProcess import MatchboxProcess -from FirstTimeDialog import FirstTimeDialog +from view.FirstTimeDialog import FirstTimeDialog import conf class DBusMonitorProcess(Process): @@ -47,11 +47,8 @@ class Session: dbm = DBusMonitorProcess() dbm.start() - console = ConsoleWindow() - logger.start('Shell', console) - - shell = Shell() - shell.set_console(console) + model = ShellModel() + shell = Shell(model) from sugar import TracebackUtils tbh = TracebackUtils.TracebackHelper() diff --git a/shell/Shell.py b/shell/Shell.py deleted file mode 100755 index 277e2f90..00000000 --- a/shell/Shell.py +++ /dev/null @@ -1,174 +0,0 @@ -import os -import logging - -import dbus -import dbus.glib -import gtk -import gobject -import wnck - -from home.HomeWindow import HomeWindow -from Owner import ShellOwner -from sugar.presence import PresenceService -from ActivityHost import ActivityHost -from ChatController import ChatController -from sugar.activity import ActivityFactory -from sugar.activity import Activity -from frame.Frame import Frame -from globalkeys import KeyGrabber -import conf -import sugar - -class ShellDbusService(dbus.service.Object): - def __init__(self, shell, bus_name): - dbus.service.Object.__init__(self, bus_name, '/com/redhat/Sugar/Shell') - self._shell = shell - - def __show_console_idle(self): - self._shell.show_console() - - @dbus.service.method('com.redhat.Sugar.Shell') - def show_console(self): - gobject.idle_add(self.__show_console_idle) - -class Shell(gobject.GObject): - __gsignals__ = { - 'activity-opened': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'activity-changed': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'activity-closed': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) - } - - def __init__(self): - gobject.GObject.__init__(self) - - self._screen = wnck.screen_get_default() - self._hosts = {} - self._current_window = None - - self._key_grabber = KeyGrabber() - self._key_grabber.connect('key-pressed', self.__global_key_pressed_cb) - self._key_grabber.grab('F1') - self._key_grabber.grab('F2') - self._key_grabber.grab('F3') - self._key_grabber.grab('F4') - self._key_grabber.grab('F5') - self._key_grabber.grab('F6') - - self._home_window = HomeWindow(self) - self._home_window.show() - self.set_zoom_level(sugar.ZOOM_HOME) - - self._screen.connect('window-opened', self.__window_opened_cb) - self._screen.connect('window-closed', self.__window_closed_cb) - self._screen.connect('active-window-changed', - self.__active_window_changed_cb) - - session_bus = dbus.SessionBus() - bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus) - ShellDbusService(self, bus_name) - - PresenceService.start() - self._pservice = PresenceService.get_instance() - - self._owner = ShellOwner(self) - self._owner.announce() - - self._home_window.set_owner(self._owner) - - self._chat_controller = ChatController(self) - self._chat_controller.listen() - - self._frame = Frame(self, self._owner) - self._frame.show_and_hide(10) - - def __global_key_pressed_cb(self, grabber, key): - if key == 'F1': - self.set_zoom_level(sugar.ZOOM_ACTIVITY) - elif key == 'F2': - self.set_zoom_level(sugar.ZOOM_HOME) - elif key == 'F3': - self.set_zoom_level(sugar.ZOOM_FRIENDS) - elif key == 'F4': - self.set_zoom_level(sugar.ZOOM_MESH) - elif key == 'F5': - self._frame.toggle_visibility() - elif key == 'F6': - ActivityFactory.create('org.sugar.Terminal') - - def set_console(self, console): - self._console = console - - def __window_opened_cb(self, screen, window): - if window.get_window_type() == wnck.WINDOW_NORMAL: - host = ActivityHost(self, window) - self._hosts[window.get_xid()] = host - self.emit('activity-opened', host) - - def __active_window_changed_cb(self, screen): - window = screen.get_active_window() - if window and window.get_window_type() == wnck.WINDOW_NORMAL: - if self._current_window != window: - self._current_window = window - self.emit('activity-changed', self.get_current_activity()) - - def __window_closed_cb(self, screen, window): - if window.get_window_type() == wnck.WINDOW_NORMAL: - xid = window.get_xid() - if self._hosts.has_key(xid): - host = self._hosts[xid] - self.emit('activity-closed', host) - - del self._hosts[xid] - - def get_activity(self, activity_id): - for host in self._hosts.values(): - if host.get_id() == activity_id: - return host - return None - - def get_current_activity(self): - if self._current_window != None: - xid = self._current_window.get_xid() - return self._hosts[xid] - else: - return None - - def show_console(self): - self._console.show() - - activity = self.get_current_activity() - if activity: - registry = conf.get_activity_registry() - module = registry.get_activity(activity.get_type()) - self._console.set_page(module.get_id()) - - def join_activity(self, bundle_id, activity_id): - activity = self.get_activity(activity_id) - if activity: - activity.present() - else: - activity_ps = self._pservice.get_activity(activity_id) - - if activity_ps: - activity = ActivityFactory.create(bundle_id) - activity.join(activity_ps.object_path()) - else: - logging.error('Cannot start activity.') - - def start_activity(self, activity_type): - activity = ActivityFactory.create(activity_type) - activity.execute('test', []) - return activity - - def get_chat_controller(self): - return self._chat_controller - - def set_zoom_level(self, level): - if level == sugar.ZOOM_ACTIVITY: - self._screen.toggle_showing_desktop(False) - else: - self._screen.toggle_showing_desktop(True) - self._home_window.set_zoom_level(level) diff --git a/shell/home/FriendsGroup.py b/shell/home/FriendsGroup.py deleted file mode 100644 index 605070ba..00000000 --- a/shell/home/FriendsGroup.py +++ /dev/null @@ -1,84 +0,0 @@ -import random - -import goocanvas - -from sugar.canvas.IconItem import IconItem -from home.IconLayout import IconLayout -from home.MyIcon import MyIcon -from FriendPopup import FriendPopup -from sugar.canvas.Grid import Grid - -class FriendIcon(IconItem): - def __init__(self, shell, friend): - IconItem.__init__(self, icon_name='stock-buddy', - color=friend.get_color(), size=96) - - self._shell = shell - self._friend = friend - self._popup = None - - self.connect('popup', self._popup_cb) - self.connect('popdown', self._popdown_cb) - - def get_friend(self): - return self._friend - - def _popup_cb(self, icon, x1, y1, x2, y2): - grid = Grid() - - if not self._popup: - self._popup = FriendPopup(self._shell, grid, icon.get_friend()) - - [grid_x1, grid_y1] = grid.convert_from_screen(x1, y1) - [grid_x2, grid_y2] = grid.convert_from_screen(x2, y2) - - if grid_x2 + self._popup.get_width() + 1 > Grid.ROWS: - grid_x = grid_x1 - self._popup.get_width() + 1 - else: - grid_x = grid_x2 - 1 - - grid_y = grid_y1 - - if grid_y < 0: - grid_y = 0 - if grid_y + self._popup.get_width() > Grid.ROWS: - grid_y = Grid.ROWS - self._popup.get_width() - - grid.set_constraints(self._popup, grid_x, grid_y, - self._popup.get_width(), self._popup.get_height()) - - self._popup.show() - - def _popup_destroy_cb(self, popup): - self._popup = None - - def _popdown_cb(self, friend): - if self._popup: - self._popup.connect('destroy', self._popup_destroy_cb) - self._popup.popdown() - -class FriendsGroup(goocanvas.Group): - def __init__(self, shell, friends): - goocanvas.Group.__init__(self) - - self._shell = shell - self._icon_layout = IconLayout(1200, 900) - self._friends = friends - - me = MyIcon(100) - me.translate(600 - (me.get_property('size') / 2), - 450 - (me.get_property('size') / 2)) - self.add_child(me) - - for friend in self._friends: - self.add_friend(friend) - - friends.connect('friend-added', self._friend_added_cb) - - def add_friend(self, friend): - icon = FriendIcon(self._shell, friend) - self.add_child(icon) - self._icon_layout.add_icon(icon) - - def _friend_added_cb(self, data_model, friend): - self.add_friend(friend) diff --git a/shell/model/BuddyInfo.py b/shell/model/BuddyInfo.py new file mode 100644 index 00000000..68f0a445 --- /dev/null +++ b/shell/model/BuddyInfo.py @@ -0,0 +1,24 @@ +from sugar.presence import PresenceService +from sugar.canvas.IconColor import IconColor + +class BuddyInfo: + def __init__(self, buddy=None): + if buddy: + self.set_name(buddy.get_name()) + self.set_color(buddy.get_color()) + + def set_name(self, name): + self._name = name + + def set_color(self, color_string): + self._color = IconColor(color_string) + + def get_name(self): + return self._name + + def get_color(self): + return self._color + + def get_buddy(self): + pservice = PresenceService.get_instance() + return pservice.get_buddy_by_name(self._name) diff --git a/shell/Friends.py b/shell/model/Friends.py similarity index 50% rename from shell/Friends.py rename to shell/model/Friends.py index 6beca663..a11acc06 100644 --- a/shell/Friends.py +++ b/shell/model/Friends.py @@ -3,67 +3,54 @@ from ConfigParser import ConfigParser import gobject -from sugar.canvas.IconColor import IconColor -from sugar.presence import PresenceService +from model.BuddyInfo import BuddyInfo from sugar import env -class Friend: - def __init__(self, name, color): - self._name = name - self._color = color - - def get_name(self): - return self._name - - def get_color(self): - return IconColor(self._color) - - def get_buddy(self): - pservice = PresenceService.get_instance() - return pservice.get_buddy_by_name(self._name) - class Friends(gobject.GObject): __gsignals__ = { 'friend-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([object])), 'friend-removed': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([object])), + gobject.TYPE_NONE, ([str])), } def __init__(self): gobject.GObject.__init__(self) - self._list = [] + self._friends = {} self._path = os.path.join(env.get_profile_path(), 'friends') self.load() def has_buddy(self, buddy): - for friend in self: - if friend.get_name() == buddy.get_name(): - return True - return False + return self._friends.has_key(buddy.get_name()) - def add_friend(self, name, color): - friend = Friend(name, color) - self._list.append(friend) + def add_friend(self, buddy_info): + self._friends[buddy_info.get_name()] = buddy_info + self.emit('friend-added', buddy_info) - self.emit('friend-added', friend) - - def add_buddy(self, buddy): + def make_friend(self, buddy): if not self.has_buddy(buddy): - self.add_friend(buddy.get_name(), buddy.get_color()) + self.add_friend(BuddyInfo(buddy)) self.save() + def remove(self, buddy_info): + del self._friends[buddy_info.get_name()] + self.save() + self.emit('friend-removed', buddy_info.get_name()) + def __iter__(self): - return self._list.__iter__() + return self._friends.values().__iter__() def load(self): cp = ConfigParser() if cp.read([self._path]): for name in cp.sections(): - self.add_friend(name, cp.get(name, 'color')) + buddy = BuddyInfo() + buddy.set_name(name) + buddy.set_color(cp.get(name, 'color')) + self.add_friend(buddy) def save(self): cp = ConfigParser() diff --git a/shell/Invites.py b/shell/model/Invites.py similarity index 100% rename from shell/Invites.py rename to shell/model/Invites.py diff --git a/shell/model/Makefile.am b/shell/model/Makefile.am new file mode 100644 index 00000000..ce246686 --- /dev/null +++ b/shell/model/Makefile.am @@ -0,0 +1,8 @@ +sugardir = $(pkgdatadir)/shell/model +sugar_PYTHON = \ + __init__.py \ + BuddyInfo.py \ + Friends.py \ + Invites.py \ + Owner.py \ + ShellModel.py diff --git a/shell/Owner.py b/shell/model/Owner.py similarity index 96% rename from shell/Owner.py rename to shell/model/Owner.py index b4781f9f..24004f0b 100644 --- a/shell/Owner.py +++ b/shell/model/Owner.py @@ -8,8 +8,7 @@ from sugar import env import logging from sugar.p2p import Stream from sugar.presence import PresenceService -from Friends import Friends -from Invites import Invites +from model.Invites import Invites PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" @@ -33,7 +32,7 @@ class ShellOwner(object): break self._pservice = PresenceService.get_instance() - self._friends = Friends() + self._invites = Invites() self._shell = shell @@ -42,9 +41,6 @@ class ShellOwner(object): self._pending_activity_update_timer = None self._pending_activity_update = None - def get_friends(self): - return self._friends - def get_invites(self): return self._invites diff --git a/shell/model/ShellModel.py b/shell/model/ShellModel.py new file mode 100644 index 00000000..0820b443 --- /dev/null +++ b/shell/model/ShellModel.py @@ -0,0 +1,64 @@ +import gobject + +from sugar.presence import PresenceService +from model.Friends import Friends +from model.Owner import ShellOwner + +class ShellModel(gobject.GObject): + __gsignals__ = { + 'activity-opened': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), + 'activity-changed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), + 'activity-closed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) + } + + def __init__(self): + gobject.GObject.__init__(self) + + self._hosts = {} + self._current_activity = None + + PresenceService.start() + self._pservice = PresenceService.get_instance() + + self._owner = ShellOwner(self) + self._owner.announce() + self._friends = Friends() + + def get_friends(self): + return self._friends + + def get_invites(self): + return self._owner.get_invites() + + def get_owner(self): + return self._owner + + def add_activity(self, activity_host): + self._hosts[activity_host.get_xid()] = activity_host + self.emit('activity-opened', activity_host) + + def set_current_activity(self, activity_xid): + activity_host = self._hosts[activity_xid] + if self._current_activity == activity_host: + return + + self._current_activity = activity_host + self.emit('activity-changed', activity_host) + + def remove_activity(self, activity_xid): + if self._hosts.has_key(activity_xid): + host = self._hosts[activity_xid] + self.emit('activity-closed', host) + del self._hosts[activity_xid] + + def get_activity(self, activity_id): + for host in self._hosts.values(): + if host.get_id() == activity_id: + return host + return None + + def get_current_activity(self): + return self._current_activity diff --git a/shell/frame/__init__.py b/shell/model/__init__.py similarity index 100% rename from shell/frame/__init__.py rename to shell/model/__init__.py diff --git a/shell/ActivityHost.py b/shell/view/ActivityHost.py similarity index 97% rename from shell/ActivityHost.py rename to shell/view/ActivityHost.py index b3703e7a..456406bc 100644 --- a/shell/ActivityHost.py +++ b/shell/view/ActivityHost.py @@ -31,6 +31,9 @@ class ActivityHost: def get_id(self): return self._id + def get_xid(self): + return self._xid + def get_icon_name(self): return self._icon_name diff --git a/shell/view/BuddyIcon.py b/shell/view/BuddyIcon.py new file mode 100644 index 00000000..3e26b084 --- /dev/null +++ b/shell/view/BuddyIcon.py @@ -0,0 +1,108 @@ +from sugar.canvas.IconItem import IconItem +from sugar.canvas.Grid import Grid +from view.BuddyPopup import BuddyPopup + +class _PopupShell: + def __init__(self): + self._popup_controller = None + + def set_active(self, controller): + if self._popup_controller: + self._popup_controller._popdown() + self._popup_controller = controller + +class BuddyIcon(IconItem): + _popup_shell = _PopupShell() + + def __init__(self, shell, friend): + IconItem.__init__(self, icon_name='stock-buddy', + color=friend.get_color(), size=96) + + self._shell = shell + self._friend = friend + self._popup = None + self._popup_distance = 0 + self._hover_popup = False + self._popdown_on_leave = False + + self.connect('popup', self._popup_cb) + self.connect('popdown', self._popdown_cb) + + def set_popup_distance(self, distance): + self._popup_distance = distance + + def get_friend(self): + return self._friend + + def _popdown(self): + if self._popup: + self._popup.destroy() + self._popup = None + + def _popup_cb(self, icon, x1, y1, x2, y2): + self._popdown() + + BuddyIcon._popup_shell.set_active(None) + + grid = self._shell.get_grid() + self._popup = BuddyPopup(self._shell, icon.get_friend()) + self._popup.connect('action', self._popup_action_cb) + self._popup.connect('enter-notify-event', + self._popup_enter_notify_event_cb) + self._popup.connect('leave-notify-event', + self._popup_leave_notify_event_cb) + + distance = self._popup_distance + + [grid_x1, grid_y1] = grid.convert_from_screen(x1, y1) + [grid_x2, grid_y2] = grid.convert_from_screen(x2, y2) + + grid_x = grid_x2 + distance + if grid_x + self._popup.get_width() > Grid.ROWS: + grid_x = grid_x1 - self._popup.get_width() + 1 - distance + + grid_y = grid_y1 + + if grid_y < 0: + grid_y = 0 + if grid_y + self._popup.get_width() > Grid.ROWS: + grid_y = Grid.ROWS - self._popup.get_width() + + grid.set_constraints(self._popup, grid_x, grid_y, + self._popup.get_width(), self._popup.get_height()) + + self._popup.show() + + BuddyIcon._popup_shell.set_active(self) + + def _popup_action_cb(self, popup, action): + self._popdown() + + buddy = self._friend.get_buddy() + if buddy == None: + return + + model = self._shell.get_model() + if action == BuddyPopup.ACTION_INVITE: + activity = model.get_current_activity() + activity.invite(buddy) + elif action == BuddyPopup.ACTION_MAKE_FRIEND: + friends = model.get_friends() + friends.make_friend(buddy) + elif action == BuddyPopup.ACTION_REMOVE_FRIEND: + friends = model.get_friends() + friends.remove(buddy) + + def _popdown_cb(self, friend): + if not self._hover_popup: + self._popdown() + else: + self._popdown_on_leave = True + + def _popup_enter_notify_event_cb(self, widget, event): + self._hover_popup = True + + def _popup_leave_notify_event_cb(self, widget, event): + self._hover_popup = False + if self._popdown_on_leave: + self._popdown() diff --git a/shell/FriendPopup.py b/shell/view/BuddyPopup.py similarity index 59% rename from shell/FriendPopup.py rename to shell/view/BuddyPopup.py index 1d309a6d..4aab3f6b 100644 --- a/shell/FriendPopup.py +++ b/shell/view/BuddyPopup.py @@ -1,21 +1,32 @@ import gtk import goocanvas +import gobject from sugar.canvas.CanvasView import CanvasView from sugar.canvas.CanvasBox import CanvasBox from sugar.canvas.IconItem import IconItem -class FriendPopup(gtk.Window): - def __init__(self, shell, grid, friend): +class BuddyPopup(gtk.Window): + ACTION_MAKE_FRIEND = 0 + ACTION_INVITE = 1 + ACTION_REMOVE_FRIEND = 2 + + __gsignals__ = { + 'action': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([int])), + } + + def __init__(self, shell, buddy): gtk.Window.__init__(self, gtk.WINDOW_POPUP) - self._shell = shell - self._friend = friend + self._buddy = buddy self._hover = False self._popdown_on_leave = False self._width = 13 self._height = 10 + grid = shell.get_grid() + canvas = CanvasView() self.add(canvas) canvas.show() @@ -25,14 +36,14 @@ class FriendPopup(gtk.Window): model = goocanvas.CanvasModelSimple() root = model.get_root_item() - color = friend.get_color() + color = buddy.get_color() rect = goocanvas.Rect(fill_color=color.get_fill_color(), stroke_color=color.get_stroke_color(), line_width=3) grid.set_constraints(rect, 0, 0, self._width, self._height) root.add_child(rect) - text = goocanvas.Text(text=friend.get_name(), font="Sans bold 18", + text = goocanvas.Text(text=buddy.get_name(), font="Sans bold 18", fill_color='black', anchor=gtk.ANCHOR_SW) grid.set_constraints(text, 1, 3, self._width, self._height) root.add_child(text) @@ -45,8 +56,16 @@ class FriendPopup(gtk.Window): box = CanvasBox(grid, CanvasBox.HORIZONTAL, 1) grid.set_constraints(box, 0, 5) - icon = IconItem(icon_name='stock-make-friend') - icon.connect('clicked', self._make_friend_clicked_cb) + friends = shell.get_model().get_friends() + if friends.has_buddy(buddy): + icon = IconItem(icon_name='stock-remove-friend') + icon.connect('clicked', self._action_clicked_cb, + BuddyPopup.ACTION_REMOVE_FRIEND) + else: + icon = IconItem(icon_name='stock-make-friend') + icon.connect('clicked', self._action_clicked_cb, + BuddyPopup.ACTION_MAKE_FRIEND) + box.set_constraints(icon, 3, 3) box.add_child(icon) @@ -55,7 +74,8 @@ class FriendPopup(gtk.Window): box.add_child(icon) icon = IconItem(icon_name='stock-invite') - icon.connect('clicked', self._invite_clicked_cb) + icon.connect('clicked', self._action_clicked_cb, + BuddyPopup.ACTION_INVITE) box.set_constraints(icon, 3, 3) box.add_child(icon) @@ -63,33 +83,8 @@ class FriendPopup(gtk.Window): canvas.set_model(model) - self.connect('enter-notify-event', self._enter_notify_event_cb) - self.connect('leave-notify-event', self._leave_notify_event_cb) - - def _invite_clicked_cb(self, icon): - activity = self._shell.get_current_activity() - buddy = self._friend.get_buddy() - if buddy != None: - activity.invite(buddy) - else: - print 'Friend not online' - - def _make_friend_clicked_cb(self, icon): - pass - - def _enter_notify_event_cb(self, widget, event): - self._hover = True - - def _leave_notify_event_cb(self, widget, event): - self._hover = False - if self._popdown_on_leave: - self.popdown() - - def popdown(self): - if not self._hover: - self.destroy() - else: - self._popdown_on_leave = True + def _action_clicked_cb(self, icon, action): + self.emit('action', action) def get_width(self): return self._width diff --git a/shell/ConsoleWindow.py b/shell/view/ConsoleWindow.py similarity index 100% rename from shell/ConsoleWindow.py rename to shell/view/ConsoleWindow.py diff --git a/shell/FirstTimeDialog.py b/shell/view/FirstTimeDialog.py similarity index 100% rename from shell/FirstTimeDialog.py rename to shell/view/FirstTimeDialog.py diff --git a/shell/view/Makefile.am b/shell/view/Makefile.am new file mode 100644 index 00000000..4b1c901d --- /dev/null +++ b/shell/view/Makefile.am @@ -0,0 +1,11 @@ +SUBDIRS = frame home + +sugardir = $(pkgdatadir)/shell/view +sugar_PYTHON = \ + __init__.py \ + ActivityHost.py \ + ConsoleWindow.py \ + FirstTimeDialog.py \ + BuddyIcon.py \ + BuddyPopup.py \ + Shell.py diff --git a/shell/view/Shell.py b/shell/view/Shell.py new file mode 100644 index 00000000..76d3f263 --- /dev/null +++ b/shell/view/Shell.py @@ -0,0 +1,102 @@ +import gtk +import gobject +import wnck + +from sugar.canvas.Grid import Grid +from view.home.HomeWindow import HomeWindow +from sugar.presence import PresenceService +from view.ActivityHost import ActivityHost +from sugar.activity import ActivityFactory +from sugar.activity import Activity +from view.frame.Frame import Frame +from globalkeys import KeyGrabber +import sugar + +class Shell(gobject.GObject): + def __init__(self, model): + gobject.GObject.__init__(self) + + self._model = model + self._screen = wnck.screen_get_default() + self._grid = Grid() + + self._key_grabber = KeyGrabber() + self._key_grabber.connect('key-pressed', self.__global_key_pressed_cb) + self._key_grabber.grab('F1') + self._key_grabber.grab('F2') + self._key_grabber.grab('F3') + self._key_grabber.grab('F4') + self._key_grabber.grab('F5') + self._key_grabber.grab('F6') + + self._home_window = HomeWindow(self) + self._home_window.show() + self.set_zoom_level(sugar.ZOOM_HOME) + + self._screen.connect('window-opened', self.__window_opened_cb) + self._screen.connect('window-closed', self.__window_closed_cb) + self._screen.connect('active-window-changed', + self.__active_window_changed_cb) + + self._frame = Frame(self) + self._frame.show_and_hide(10) + + def __global_key_pressed_cb(self, grabber, key): + if key == 'F1': + self.set_zoom_level(sugar.ZOOM_ACTIVITY) + elif key == 'F2': + self.set_zoom_level(sugar.ZOOM_HOME) + elif key == 'F3': + self.set_zoom_level(sugar.ZOOM_FRIENDS) + elif key == 'F4': + self.set_zoom_level(sugar.ZOOM_MESH) + elif key == 'F5': + self._frame.toggle_visibility() + elif key == 'F6': + self._model.start_activity('org.sugar.Terminal') + + def __window_opened_cb(self, screen, window): + if window.get_window_type() == wnck.WINDOW_NORMAL: + self._model.add_activity(ActivityHost(self, window)) + + def __active_window_changed_cb(self, screen): + window = screen.get_active_window() + if window and window.get_window_type() == wnck.WINDOW_NORMAL: + self._model.set_current_activity(window.get_xid()) + + def __window_closed_cb(self, screen, window): + if window.get_window_type() == wnck.WINDOW_NORMAL: + self._model.remove_activity(window.get_xid()) + + def get_model(self): + return self._model + + def get_grid(self): + return self._grid + + def join_activity(self, bundle_id, activity_id): + pservice = PresenceService.get_instance() + + activity = self._model.get_activity(activity_id) + if activity: + activity.present() + else: + activity_ps = pservice.get_activity(activity_id) + + if activity_ps: + activity = ActivityFactory.create(bundle_id) + activity.join(activity_ps.object_path()) + else: + logging.error('Cannot start activity.') + + def start_activity(self, activity_type): + activity = ActivityFactory.create(activity_type) + activity.execute('test', []) + return activity + + def set_zoom_level(self, level): + if level == sugar.ZOOM_ACTIVITY: + self._screen.toggle_showing_desktop(False) + else: + self._screen.toggle_showing_desktop(True) + self._home_window.set_zoom_level(level) diff --git a/shell/home/__init__.py b/shell/view/__init__.py similarity index 100% rename from shell/home/__init__.py rename to shell/view/__init__.py diff --git a/shell/frame/BottomPanel.py b/shell/view/frame/BottomPanel.py similarity index 86% rename from shell/frame/BottomPanel.py rename to shell/view/frame/BottomPanel.py index 2da51e77..5f98f016 100644 --- a/shell/frame/BottomPanel.py +++ b/shell/view/frame/BottomPanel.py @@ -33,22 +33,22 @@ class InviteItem(IconItem): return self._invite class BottomPanel(CanvasBox): - def __init__(self, grid, shell, invites): - CanvasBox.__init__(self, grid, CanvasBox.HORIZONTAL, 1) + def __init__(self, shell): + CanvasBox.__init__(self, shell.get_grid(), CanvasBox.HORIZONTAL, 1) self._shell = shell self._invite_to_item = {} - self._invites = invites + self._invites = self._shell.get_model().get_invites() registry = conf.get_activity_registry() for activity in registry.list_activities(): if activity.get_show_launcher(): self.add_activity(activity) - for invite in invites: + for invite in self._invites: self.add_invite(invite) - invites.connect('invite-added', self.__invite_added_cb) - invites.connect('invite-removed', self.__invite_removed_cb) + self._invites.connect('invite-added', self.__invite_added_cb) + self._invites.connect('invite-removed', self.__invite_removed_cb) def __activity_clicked_cb(self, icon): self._shell.start_activity(icon.get_bundle_id()) diff --git a/shell/frame/Frame.py b/shell/view/frame/Frame.py similarity index 78% rename from shell/frame/Frame.py rename to shell/view/frame/Frame.py index 1da50f0e..9967a505 100644 --- a/shell/frame/Frame.py +++ b/shell/view/frame/Frame.py @@ -2,39 +2,39 @@ import gtk import gobject import goocanvas -from frame.BottomPanel import BottomPanel -from frame.RightPanel import RightPanel -from frame.TopPanel import TopPanel -from frame.PanelWindow import PanelWindow +from view.frame.BottomPanel import BottomPanel +from view.frame.RightPanel import RightPanel +from view.frame.TopPanel import TopPanel +from view.frame.PanelWindow import PanelWindow from sugar.canvas.Grid import Grid class Frame: - def __init__(self, shell, owner): + def __init__(self, shell): self._windows = [] model = goocanvas.CanvasModelSimple() root = model.get_root_item() - grid = Grid() + grid = shell.get_grid() bg = goocanvas.Rect(fill_color="#4f4f4f", line_width=0) grid.set_constraints(bg, 0, 0, 80, 60) root.add_child(bg) - panel = BottomPanel(grid, shell, owner.get_invites()) + panel = BottomPanel(shell) grid.set_constraints(panel, 5, 55) root.add_child(panel) panel_window = PanelWindow(grid, model, 0, 55, 80, 5) self._windows.append(panel_window) - panel = TopPanel(grid, shell) + panel = TopPanel(shell) root.add_child(panel) panel_window = PanelWindow(grid, model, 0, 0, 80, 5) self._windows.append(panel_window) - panel = RightPanel(grid, shell, owner.get_friends()) + panel = RightPanel(shell) grid.set_constraints(panel, 75, 5) root.add_child(panel) diff --git a/shell/frame/Makefile.am b/shell/view/frame/Makefile.am similarity index 74% rename from shell/frame/Makefile.am rename to shell/view/frame/Makefile.am index 9f455439..a737e018 100644 --- a/shell/frame/Makefile.am +++ b/shell/view/frame/Makefile.am @@ -1,4 +1,4 @@ -sugardir = $(pkgdatadir)/shell/frame +sugardir = $(pkgdatadir)/shell/view/frame sugar_PYTHON = \ __init__.py \ RightPanel.py \ diff --git a/shell/frame/PanelWindow.py b/shell/view/frame/PanelWindow.py similarity index 100% rename from shell/frame/PanelWindow.py rename to shell/view/frame/PanelWindow.py diff --git a/shell/frame/RightPanel.py b/shell/view/frame/RightPanel.py similarity index 80% rename from shell/frame/RightPanel.py rename to shell/view/frame/RightPanel.py index 80729fd3..6ed4a0d6 100644 --- a/shell/frame/RightPanel.py +++ b/shell/view/frame/RightPanel.py @@ -4,12 +4,13 @@ from sugar.canvas.IconItem import IconItem from sugar.canvas.IconColor import IconColor from sugar.canvas.CanvasBox import CanvasBox from sugar.presence import PresenceService +from view.BuddyIcon import BuddyIcon +from model.BuddyInfo import BuddyInfo class RightPanel(CanvasBox): - def __init__(self, grid, shell, friends): - CanvasBox.__init__(self, grid, CanvasBox.VERTICAL, 1) + def __init__(self, shell): + CanvasBox.__init__(self, shell.get_grid(), CanvasBox.VERTICAL, 1) self._shell = shell - self._friends = friends self._activity_ps = None self._joined_hid = -1 self._left_hid = -1 @@ -19,14 +20,13 @@ class RightPanel(CanvasBox): self._pservice.connect('activity-appeared', self.__activity_appeared_cb) - shell.connect('activity-changed', self.__activity_changed_cb) + shell.get_model().connect('activity-changed', + self.__activity_changed_cb) def add(self, buddy): - icon = IconItem(icon_name='stock-buddy', - color=IconColor(buddy.get_color())) + icon = BuddyIcon(self._shell, BuddyInfo(buddy)) + icon.set_popup_distance(1) self.set_constraints(icon, 3, 3) - icon.connect('clicked', self.__buddy_clicked_cb, buddy) - self.add_child(icon) self._buddies[buddy.get_name()] = icon @@ -41,7 +41,7 @@ class RightPanel(CanvasBox): self._buddies = {} def __activity_appeared_cb(self, pservice, activity_ps): - activity = self._shell.get_current_activity() + activity = self._shell.get_model().get_current_activity() if activity and activity_ps.get_id() == activity.get_id(): self._set_activity_ps(activity_ps) @@ -78,6 +78,3 @@ class RightPanel(CanvasBox): def __buddy_left_cb(self, activity, buddy): self.remove(buddy) - - def __buddy_clicked_cb(self, icon, buddy): - self._friends.add_buddy(buddy) diff --git a/shell/frame/TopPanel.py b/shell/view/frame/TopPanel.py similarity index 89% rename from shell/frame/TopPanel.py rename to shell/view/frame/TopPanel.py index 14c0fb7c..b1611d70 100644 --- a/shell/frame/TopPanel.py +++ b/shell/view/frame/TopPanel.py @@ -5,14 +5,15 @@ from sugar.canvas.IconItem import IconItem import sugar class TopPanel(goocanvas.Group): - def __init__(self, grid, shell): + def __init__(self, shell): goocanvas.Group.__init__(self) - self._grid = grid self._shell = shell + grid = shell.get_grid() + box = CanvasBox(grid, CanvasBox.HORIZONTAL, 1) - self._grid.set_constraints(box, 5, 0) + grid.set_constraints(box, 5, 0) self.add_child(box) icon = IconItem(icon_name='stock-zoom-activity') @@ -36,7 +37,7 @@ class TopPanel(goocanvas.Group): box.add_child(icon) box = CanvasBox(grid, CanvasBox.HORIZONTAL, 1) - self._grid.set_constraints(box, 60, 0) + grid.set_constraints(box, 60, 0) self.add_child(box) icon = IconItem(icon_name='stock-share') @@ -58,7 +59,8 @@ class TopPanel(goocanvas.Group): self._shell.set_zoom_level(level) def __share_clicked_cb(self, item): - activity = self._shell.get_current_activity() + shell_model = self._shell.get_model() + activity = shell_model.get_current_activity() if activity != None: activity.share() diff --git a/shell/view/frame/__init__.py b/shell/view/frame/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/shell/home/DonutItem.py b/shell/view/home/DonutItem.py similarity index 100% rename from shell/home/DonutItem.py rename to shell/view/home/DonutItem.py diff --git a/shell/view/home/FriendsGroup.py b/shell/view/home/FriendsGroup.py new file mode 100644 index 00000000..17497388 --- /dev/null +++ b/shell/view/home/FriendsGroup.py @@ -0,0 +1,42 @@ +import random + +import goocanvas + +from view.home.IconLayout import IconLayout +from view.home.MyIcon import MyIcon +from view.BuddyIcon import BuddyIcon + +class FriendsGroup(goocanvas.Group): + def __init__(self, shell): + goocanvas.Group.__init__(self) + + self._shell = shell + self._icon_layout = IconLayout(1200, 900) + self._friends = {} + + me = MyIcon(100) + me.translate(600 - (me.get_property('size') / 2), + 450 - (me.get_property('size') / 2)) + self.add_child(me) + + friends = self._shell.get_model().get_friends() + + for friend in friends: + self.add_friend(friend) + + friends.connect('friend-added', self._friend_added_cb) + friends.connect('friend-removed', self._friend_removed_cb) + + def add_friend(self, buddy_info): + icon = BuddyIcon(self._shell, buddy_info) + self.add_child(icon) + self._icon_layout.add_icon(icon) + + self._friends[buddy_info.get_name()] = icon + + def _friend_added_cb(self, data_model, buddy_info): + self.add_friend(buddy_info) + + def _friend_removed_cb(self, data_model, name): + self.remove_child(self._friends[name]) + del self._friends[name] diff --git a/shell/home/HomeGroup.py b/shell/view/home/HomeGroup.py similarity index 74% rename from shell/home/HomeGroup.py rename to shell/view/home/HomeGroup.py index 0f088132..d01ba167 100644 --- a/shell/home/HomeGroup.py +++ b/shell/view/home/HomeGroup.py @@ -1,7 +1,7 @@ import goocanvas -from home.DonutItem import DonutItem -from home.MyIcon import MyIcon +from view.home.DonutItem import DonutItem +from view.home.MyIcon import MyIcon class TasksItem(DonutItem): def __init__(self, shell): @@ -9,14 +9,14 @@ class TasksItem(DonutItem): self._items = {} - self._shell = shell - self._shell.connect('activity_opened', self.__activity_opened_cb) - self._shell.connect('activity_closed', self.__activity_closed_cb) + shell_model = shell.get_model() + shell_model.connect('activity_opened', self.__activity_opened_cb) + shell_model.connect('activity_closed', self.__activity_closed_cb) - def __activity_opened_cb(self, shell, activity): + def __activity_opened_cb(self, model, activity): self._add(activity) - def __activity_closed_cb(self, shell, activity): + def __activity_closed_cb(self, model, activity): self._remove(activity) def _remove(self, activity): diff --git a/shell/home/HomeWindow.py b/shell/view/home/HomeWindow.py similarity index 77% rename from shell/home/HomeWindow.py rename to shell/view/home/HomeWindow.py index 259ddc4f..ba1129e4 100644 --- a/shell/home/HomeWindow.py +++ b/shell/view/home/HomeWindow.py @@ -3,9 +3,9 @@ import goocanvas import cairo from sugar.canvas.CanvasView import CanvasView -from home.MeshGroup import MeshGroup -from home.HomeGroup import HomeGroup -from home.FriendsGroup import FriendsGroup +from view.home.MeshGroup import MeshGroup +from view.home.HomeGroup import HomeGroup +from view.home.FriendsGroup import FriendsGroup import sugar class HomeWindow(gtk.Window): @@ -23,6 +23,10 @@ class HomeWindow(gtk.Window): self.add(self._nb) self._nb.show() + self._add_page(HomeGroup(shell)) + self._add_page(FriendsGroup(shell)) + self._add_page(MeshGroup(shell)) + def _add_page(self, group): view = CanvasView() self._nb.append_page(view) @@ -37,11 +41,6 @@ class HomeWindow(gtk.Window): root.add_child(bg) root.add_child(group) - def set_owner(self, owner): - self._add_page(HomeGroup(self._shell)) - self._add_page(FriendsGroup(self._shell, owner.get_friends())) - self._add_page(MeshGroup(self._shell)) - def set_zoom_level(self, level): if level == sugar.ZOOM_HOME: self._nb.set_current_page(0) diff --git a/shell/home/IconLayout.py b/shell/view/home/IconLayout.py similarity index 100% rename from shell/home/IconLayout.py rename to shell/view/home/IconLayout.py diff --git a/shell/home/Makefile.am b/shell/view/home/Makefile.am similarity index 79% rename from shell/home/Makefile.am rename to shell/view/home/Makefile.am index 5d5436e3..ddf9653a 100644 --- a/shell/home/Makefile.am +++ b/shell/view/home/Makefile.am @@ -1,4 +1,4 @@ -sugardir = $(pkgdatadir)/shell/home +sugardir = $(pkgdatadir)/shell/view/home sugar_PYTHON = \ __init__.py \ DonutItem.py \ diff --git a/shell/home/MeshGroup.py b/shell/view/home/MeshGroup.py similarity index 98% rename from shell/home/MeshGroup.py rename to shell/view/home/MeshGroup.py index f7bc1c99..61118238 100644 --- a/shell/home/MeshGroup.py +++ b/shell/view/home/MeshGroup.py @@ -6,7 +6,7 @@ import conf from sugar.canvas.IconItem import IconItem from sugar.canvas.IconItem import IconColor from sugar.presence import PresenceService -from home.IconLayout import IconLayout +from view.home.IconLayout import IconLayout class ActivityItem(IconItem): def __init__(self, activity, service): @@ -34,7 +34,9 @@ class ActivityItem(IconItem): class MeshGroup(goocanvas.Group): def __init__(self, shell): goocanvas.Group.__init__(self) + self._shell = shell + self._icon_layout = IconLayout(1200, 900) self._activities = {} diff --git a/shell/home/MyIcon.py b/shell/view/home/MyIcon.py similarity index 100% rename from shell/home/MyIcon.py rename to shell/view/home/MyIcon.py diff --git a/shell/view/home/__init__.py b/shell/view/home/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sugar/__installed__.py.in b/sugar/__installed__.py.in index 5ebed29a..fd1b8554 100644 --- a/sugar/__installed__.py.in +++ b/sugar/__installed__.py.in @@ -6,5 +6,6 @@ sugar_dbus_config = '@prefix@/share/sugar/dbus-installed.conf' sugar_python_path = ['@prefix@/share/sugar/shell', '@prefix@/share/sugar/bindings', - '@prefix@/share/sugar/activities'] + '@prefix@/share/sugar/activities', + '@prefix@/share/sugar/services'] sugar_bin_path = [] diff --git a/sugar/__uninstalled__.py.in b/sugar/__uninstalled__.py.in index 860cb21a..02b43f1c 100644 --- a/sugar/__uninstalled__.py.in +++ b/sugar/__uninstalled__.py.in @@ -14,6 +14,8 @@ sugar_python_path = ['@prefix@/share/sugar/bindings'] sugar_python_path.append(sugar_source_dir) sugar_python_path.append(os.path.join(sugar_source_dir, 'shell')) sugar_python_path.append(os.path.join(sugar_source_dir, 'activities')) +sugar_python_path.append(os.path.join(sugar_source_dir, 'services')) sugar_bin_path = [] sugar_bin_path.append(os.path.join(sugar_source_dir, 'shell')) +sugar_bin_path.append(os.path.join(sugar_source_dir, 'services/presence')) diff --git a/sugar/canvas/Grid.py b/sugar/canvas/Grid.py index e4c377ab..50b5dbe6 100644 --- a/sugar/canvas/Grid.py +++ b/sugar/canvas/Grid.py @@ -10,7 +10,11 @@ class Grid: def convert_from_screen(self, x, y): factor = Grid.COLS / gtk.gdk.screen_width() - return [int(x * factor), int(y * factor)] + + grid_x = round(x * factor) - 1 + grid_y = round(y * factor) - 1 + + return [grid_x, grid_y] def set_constraints(self, component, x, y, width=-1, height=-1): if isinstance(component, gtk.Window): diff --git a/sugar/canvas/IconColor.py b/sugar/canvas/IconColor.py index 8babea0d..84ca409e 100644 --- a/sugar/canvas/IconColor.py +++ b/sugar/canvas/IconColor.py @@ -4,7 +4,7 @@ from sugar.canvas import Colors def _parse_string(color_string): if color_string == 'white': - return ['#4f4f4f', 'white'] + return ['white', '#4f4f4f'] splitted = color_string.split(',') if len(splitted) == 2: @@ -19,9 +19,9 @@ class IconColor: def __init__(self, color_string=None): if color_string == None or not is_valid(color_string): n = int(random.random() * (len(Colors.colors) - 1)) - [self._fill, self._stroke] = Colors.colors[n] + [self._stroke, self._fill] = Colors.colors[n] else: - [self._fill, self._stroke] = _parse_string(color_string) + [self._stroke, self._fill] = _parse_string(color_string) def get_stroke_color(self): return self._stroke @@ -30,5 +30,5 @@ class IconColor: return self._fill def to_string(self): - return '%s,%s' % (self._fill, self._stroke) + return '%s,%s' % (self._stroke, self._fill) diff --git a/sugar/canvas/IconItem.py b/sugar/canvas/IconItem.py index 38850f1d..d4be1e53 100644 --- a/sugar/canvas/IconItem.py +++ b/sugar/canvas/IconItem.py @@ -195,7 +195,7 @@ class IconItem(goocanvas.ItemSimple, goocanvas.Item): self.size = 24 self.color = None self.icon_name = None - self._popdown_timeout = 0 + self._popdown_sid = 0 goocanvas.ItemSimple.__init__(self, **kwargs) @@ -240,29 +240,36 @@ class IconItem(goocanvas.ItemSimple, goocanvas.Item): def _button_press_cb(self, view, target, event): self.emit('clicked') - def _start_popup_timeout(self): - self._stop_popup_timeout() - self._popdown_timeout = gobject.timeout_add(1000, self._popdown) + def _start_popdown_timeout(self): + self._stop_popdown_timeout() + self._popdown_sid = gobject.timeout_add(1000, self._popdown_timeout_cb) - def _stop_popup_timeout(self): - if self._popdown_timeout > 0: - gobject.source_remove(self._popdown_timeout) - self._popdown_timeout = 0 + def _stop_popdown_timeout(self): + if self._popdown_sid > 0: + gobject.source_remove(self._popdown_sid) + self._popdown_sid = 0 def _enter_notify_event_cb(self, view, target, event, canvas): - self._stop_popup_timeout() + self._stop_popdown_timeout() [x1, y1] = canvas.convert_to_pixels(view.get_bounds().x1, view.get_bounds().y1) [x2, y2] = canvas.convert_to_pixels(view.get_bounds().x2, view.get_bounds().y2) + [window_x, window_y] = canvas.window.get_origin() + + x1 += window_x + y1 += window_y + x2 += window_x + y2 += window_y + self.emit('popup', int(x1), int(y1), int(x2), int(y2)) - def _popdown(self): - self._popdown_timeout = 0 + def _popdown_timeout_cb(self): + self._popdown_sid = 0 self.emit('popdown') return False def _leave_notify_event_cb(self, view, target, event): - self._start_popup_timeout() + self._start_popdown_timeout() diff --git a/sugar/env.py b/sugar/env.py index 8fc131a1..b0c5443c 100644 --- a/sugar/env.py +++ b/sugar/env.py @@ -43,7 +43,8 @@ def setup_system(): runner = os.path.join(sugar_source_dir, 'shell/sugar-activity-factory') sugar.setup.setup_activities(source, sugar_activities_dir, runner) - bin = os.path.join(sugar_source_dir, 'shell/sugar-presence-service') + bin = os.path.join(sugar_source_dir, + 'services/presence/sugar-presence-service') sugar.setup.write_service('org.laptop.Presence', bin, sugar_activities_dir)