diff options
-rw-r--r-- | services/clipboard/ClipboardService.py | 76 | ||||
-rw-r--r-- | services/clipboard/Makefile.am | 4 | ||||
-rw-r--r-- | services/clipboard/clipboardobject.py | 38 | ||||
-rw-r--r-- | services/clipboard/clipboardservice.py | 119 | ||||
-rwxr-xr-x | services/clipboard/sugar-clipboard | 2 | ||||
-rw-r--r-- | shell/view/Makefile.am | 4 | ||||
-rw-r--r-- | shell/view/clipboardicon.py (renamed from shell/view/ClipboardIcon.py) | 22 | ||||
-rw-r--r-- | shell/view/clipboardmenu.py (renamed from shell/view/ClipboardMenu.py) | 3 | ||||
-rw-r--r-- | shell/view/frame/ClipboardBox.py | 42 | ||||
-rw-r--r-- | shell/view/frame/Frame.py | 46 | ||||
-rw-r--r-- | shell/view/frame/Makefile.am | 3 | ||||
-rw-r--r-- | shell/view/frame/PanelWindow.py | 5 | ||||
-rw-r--r-- | shell/view/frame/clipboardbox.py | 183 | ||||
-rw-r--r-- | shell/view/frame/clipboardpanelwindow.py | 64 | ||||
-rw-r--r-- | sugar/clipboard/Makefile.am | 2 | ||||
-rw-r--r-- | sugar/clipboard/clipboardservice.py (renamed from sugar/clipboard/ClipboardService.py) | 50 |
16 files changed, 496 insertions, 167 deletions
diff --git a/services/clipboard/ClipboardService.py b/services/clipboard/ClipboardService.py deleted file mode 100644 index d8a151d..0000000 --- a/services/clipboard/ClipboardService.py +++ /dev/null @@ -1,76 +0,0 @@ -# vi: ts=4 ai noet -# -# Copyright (C) 2006, Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import logging -import gobject -import dbus -import dbus.service -from sugar import env - -class ClipboardDBusServiceHelper(dbus.service.Object): - - _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard" - _CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard" - - def __init__(self, parent): - self._parent = parent - - bus = dbus.SessionBus() - bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus) - dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH) - - @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, - in_signature="sss", out_signature="") - def add_object(self, name, mimeType, fileName): - self.object_added(name, mimeType, fileName) - logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName) - - @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, - in_signature="s", out_signature="") - def delete_object(self, fileName): - self.object_deleted(fileName) - logging.debug('Deleted object with path at ' + fileName) - - @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, - in_signature="si", out_signature="") - def set_object_state(self, fileName, percent): - logging.debug('Changed object with path at ' + fileName + ' with percent ' + str(percent)) - self.object_state_changed(fileName, percent) - - @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="sss") - def object_added(self, name, mimeType, fileName): - pass - - @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s") - def object_deleted(self, fileName): - pass - - @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si") - def object_state_changed(self, fileName, percent): - pass - -class ClipboardService(object): - def __init__(self): - self._dbus_helper = ClipboardDBusServiceHelper(self) - - def run(self): - loop = gobject.MainLoop() - try: - loop.run() - except KeyboardInterrupt: - print 'Ctrl+C pressed, exiting...' diff --git a/services/clipboard/Makefile.am b/services/clipboard/Makefile.am index 4f4d8a3..130a33c 100644 --- a/services/clipboard/Makefile.am +++ b/services/clipboard/Makefile.am @@ -8,7 +8,9 @@ $(service_DATA): $(service_in_files) Makefile sugardir = $(pkgdatadir)/services/clipboard sugar_PYTHON = \ __init__.py \ - ClipboardService.py + clipboardobject.py \ + clipboardservice.py + bin_SCRIPTS = sugar-clipboard diff --git a/services/clipboard/clipboardobject.py b/services/clipboard/clipboardobject.py new file mode 100644 index 0000000..fd15363 --- /dev/null +++ b/services/clipboard/clipboardobject.py @@ -0,0 +1,38 @@ +class ClipboardObject: + + def __init__(self, id, name): + self._id = id + self._name = name + self._percent = 0 + self._formats = {} + + def get_id(self): + return self._id + + def get_name(self): + return self._name + + def get_percent(self): + return self._percent + + def set_percent(self, percent): + self._percent = percent + + def add_format(self, format): + self._formats[format.get_type()] = format + + def get_formats(self): + return self._formats + +class Format: + + def __init__(self, type, data, on_disk): + self._type = type + self._data = data + self._on_disk = on_disk + + def get_type(self): + return self._type + + def get_data(self): + return self._data diff --git a/services/clipboard/clipboardservice.py b/services/clipboard/clipboardservice.py new file mode 100644 index 0000000..02ee7ac --- /dev/null +++ b/services/clipboard/clipboardservice.py @@ -0,0 +1,119 @@ +# Copyright (C) 2006, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import logging +import gobject +import dbus +import dbus.service +from sugar import env +from clipboardobject import ClipboardObject, Format + +class ClipboardDBusServiceHelper(dbus.service.Object): + + _CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard" + _CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard" + + def __init__(self, parent): + self._parent = parent + self._objects = {} + + bus = dbus.SessionBus() + bus_name = dbus.service.BusName(self._CLIPBOARD_DBUS_INTERFACE, bus=bus) + dbus.service.Object.__init__(self, bus_name, self._CLIPBOARD_OBJECT_PATH) + + # dbus methods + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="ss", out_signature="") + def add_object(self, object_id, name): + self._objects[object_id] = ClipboardObject(object_id, name) + self.object_added(object_id, name) + logging.debug('Added object ' + object_id + ' with name ' + name) + + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="ssayb", out_signature="") + def add_object_format(self, object_id, format_type, data, on_disk): + + # FIXME: Take it out when using the 0.80 dbus bindings + s = "" + for i in data: + s += chr(i) + + cb_object = self._objects[object_id] + cb_object.add_format(Format(format_type, s, on_disk)) + + if on_disk: + logging.debug('Added format of type ' + format_type + ' with path at ' + s) + else: + logging.debug('Added in-memory format of type ' + format_type + '.') + + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="s", out_signature="") + def delete_object(self, object_id): + del self._objects[object_id] + self.object_deleted(object_id) + logging.debug('Deleted object with object_id ' + object_id) + + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="si", out_signature="") + def set_object_state(self, object_id, percent): + cb_object = self._objects[object_id] + cb_object.set_percent(percent) + self.object_state_changed(object_id, percent) + logging.debug('Changed object with object_id ' + object_id + ' with percent ' + str(percent)) + + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="s", out_signature="as") + def get_object_format_types(self, object_id): + cb_object = self._objects[object_id] + formats = cb_object.get_formats() + array = [] + + for type, format in formats.iteritems(): + array.append(type) + + return array + + @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, + in_signature="ss", out_signature="ay") + def get_object_data(self, object_id, format_type): + cb_object = self._objects[object_id] + formats = cb_object.get_formats() + + return formats[format_type].get_data() + + # dbus signals + @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="ss") + def object_added(self, object_id, name): + pass + + @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="s") + def object_deleted(self, object_id): + pass + + @dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="si") + def object_state_changed(self, object_id, percent): + pass + +class ClipboardService(object): + def __init__(self): + self._dbus_helper = ClipboardDBusServiceHelper(self) + + def run(self): + loop = gobject.MainLoop() + try: + loop.run() + except idboardInterrupt: + print 'Ctrl+C pressed, exiting...' diff --git a/services/clipboard/sugar-clipboard b/services/clipboard/sugar-clipboard index bcbd280..3f7ef9f 100755 --- a/services/clipboard/sugar-clipboard +++ b/services/clipboard/sugar-clipboard @@ -33,7 +33,7 @@ from sugar import env sys.path.insert(0, env.get_services_dir()) -from clipboard.ClipboardService import ClipboardService +from clipboard.clipboardservice import ClipboardService logging.info('Starting clipboard service.') diff --git a/shell/view/Makefile.am b/shell/view/Makefile.am index bd90a2d..0f9573a 100644 --- a/shell/view/Makefile.am +++ b/shell/view/Makefile.am @@ -7,8 +7,8 @@ sugar_PYTHON = \ FirstTimeDialog.py \ BuddyIcon.py \ BuddyMenu.py \ - ClipboardIcon.py \ - ClipboardMenu.py \ + clipboardicon.py \ + clipboardmenu.py \ OverlayWindow.py \ Shell.py \ dconmanager.py \ diff --git a/shell/view/ClipboardIcon.py b/shell/view/clipboardicon.py index 41f3e09..25a14e9 100644 --- a/shell/view/ClipboardIcon.py +++ b/shell/view/clipboardicon.py @@ -1,14 +1,14 @@ from sugar.graphics.menuicon import MenuIcon -from view.ClipboardMenu import ClipboardMenu +from view.clipboardmenu import ClipboardMenu from sugar.activity import ActivityFactory -from sugar.clipboard import ClipboardService +from sugar.clipboard import clipboardservice class ClipboardIcon(MenuIcon): - def __init__(self, menu_shell, name, file_name): + def __init__(self, menu_shell, object_id, name): MenuIcon.__init__(self, menu_shell, icon_name='activity-xbook') + self._object_id = object_id self._name = name - self._file_name = file_name self._percent = 0 self.connect('activated', self._icon_activated_cb) self._menu = None @@ -25,8 +25,11 @@ class ClipboardIcon(MenuIcon): def _icon_activated_cb(self, icon): if self._percent == 100: - activity = ActivityFactory.create("org.laptop.sugar.Xbook") - activity.execute("open_document", [self._file_name]) + cb_service = clipboardservice.get_instance() + format_types = cb_service.get_object_format_types(self._object_id) + if len(format_types) > 0 and format_types[0] == "application/pdf": + activity = ActivityFactory.create("org.laptop.sugar.Xbook") + activity.execute("open_document", [self._object_id]) def _popup_action_cb(self, popup, action): self.popdown() @@ -34,5 +37,8 @@ class ClipboardIcon(MenuIcon): if action == ClipboardMenu.ACTION_STOP_DOWNLOAD: raise "Stopping downloads still not implemented." elif action == ClipboardMenu.ACTION_DELETE: - cb_service = ClipboardService.get_instance() - cb_service.delete_object(self._file_name) + cb_service = clipboardservice.get_instance() + cb_service.delete_object(self._object_id) + + def get_object_id(self): + return self._object_id diff --git a/shell/view/ClipboardMenu.py b/shell/view/clipboardmenu.py index 625c897..cd521e0 100644 --- a/shell/view/ClipboardMenu.py +++ b/shell/view/clipboardmenu.py @@ -24,9 +24,6 @@ class ClipboardMenu(Menu): self._progress_bar = ClipboardMenuItem(percent) self._root.append(self._progress_bar) - - #icon = CanvasIcon(icon_name='stock-share-mesh') - #self.add_action(icon, ClipboardMenu.ACTION_SHARE) self._remove_icon = None self._stop_icon = None diff --git a/shell/view/frame/ClipboardBox.py b/shell/view/frame/ClipboardBox.py deleted file mode 100644 index 82dccb6..0000000 --- a/shell/view/frame/ClipboardBox.py +++ /dev/null @@ -1,42 +0,0 @@ -import logging -import dbus -import hippo - -from sugar.graphics import style -from view.ClipboardIcon import ClipboardIcon -from sugar.clipboard import ClipboardService - -class ClipboardBox(hippo.CanvasBox): - - def __init__(self, frame, menu_shell): - hippo.CanvasBox.__init__(self) - self._frame = frame - self._menu_shell = menu_shell - self._icons = {} - - cb_service = ClipboardService.get_instance() - cb_service.connect('object-added', self._object_added_cb) - cb_service.connect('object-deleted', self._object_deleted_cb) - cb_service.connect('object-state-changed', self._object_state_changed_cb) - - def _object_added_cb(self, cb_service, name, mimeType, fileName): - icon = ClipboardIcon(self._menu_shell, name, fileName) - style.apply_stylesheet(icon, 'frame.BuddyIcon') - self.append(icon) - self._icons[fileName] = icon - - if not self._frame.is_visible(): - self._frame.show_and_hide(0.1) - - logging.debug('ClipboardBox: ' + fileName + ' was added.') - - def _object_deleted_cb(self, cb_service, fileName): - icon = self._icons[fileName] - self.remove(icon) - del self._icons[fileName] - logging.debug('ClipboardBox: ' + fileName + ' was deleted.') - - def _object_state_changed_cb(self, cb_service, fileName, percent): - icon = self._icons[fileName] - icon.set_percent(percent) - logging.debug('ClipboardBox: ' + fileName + ' state was changed.') diff --git a/shell/view/frame/Frame.py b/shell/view/frame/Frame.py index c865219..f2c6312 100644 --- a/shell/view/frame/Frame.py +++ b/shell/view/frame/Frame.py @@ -14,6 +14,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import logging import gtk import gobject import hippo @@ -23,8 +24,8 @@ from view.frame.ActivitiesBox import ActivitiesBox from view.frame.ZoomBox import ZoomBox from view.frame.overlaybox import OverlayBox from view.frame.FriendsBox import FriendsBox -from view.frame.ClipboardBox import ClipboardBox from view.frame.PanelWindow import PanelWindow +from view.frame.clipboardpanelwindow import ClipboardPanelWindow from view.frame.notificationtray import NotificationTray from view.frame.shutdownicon import ShutdownIcon from sugar.graphics.timeline import Timeline @@ -154,7 +155,10 @@ class Frame: grid = Grid() # Top panel - [menu_shell, root] = self._create_panel(grid, 0, 0, 16, 1) + panel = self._create_panel(grid, 0, 0, 16, 1) + menu_shell = panel.get_menu_shell() + root = panel.get_root() + menu_shell.set_position(MenuShell.BOTTOM) box = ZoomBox(self._shell, menu_shell) @@ -189,7 +193,10 @@ class Frame: root.move(shutdown_icon, x, y) # Bottom panel - [menu_shell, root] = self._create_panel(grid, 0, 11, 16, 1) + panel = self._create_panel(grid, 0, 11, 16, 1) + menu_shell = panel.get_menu_shell() + root = panel.get_root() + menu_shell.set_position(MenuShell.TOP) box = ActivitiesBox(self._shell) @@ -199,21 +206,35 @@ class Frame: root.move(box, x, y) # Right panel - [menu_shell, root] = self._create_panel(grid, 15, 1, 1, 10) + panel = self._create_panel(grid, 15, 1, 1, 10) + menu_shell = panel.get_menu_shell() + root = panel.get_root() + menu_shell.set_position(MenuShell.LEFT) box = FriendsBox(self._shell, menu_shell) root.append(box) # Left panel - [menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10) + panel = self._create_clipboard_panel(grid, 0, 1, 1, 10) + + def _create_clipboard_panel(self, grid, x, y, width, height): + [x, y, width, height] = grid.rectangle(x, y, width, height) + panel = ClipboardPanelWindow(x, y, width, height) + self._connect_to_panel(panel) + self._windows.append(panel) - box = ClipboardBox(self, menu_shell) - root.append(box) + return panel def _create_panel(self, grid, x, y, width, height): - panel = PanelWindow() + [x, y, width, height] = grid.rectangle(x, y, width, height) + panel = PanelWindow(x, y, width, height) + self._connect_to_panel(panel) + self._windows.append(panel) + + return panel + def _connect_to_panel(self, panel): panel.connect('enter-notify-event', self._enter_notify_cb) panel.connect('leave-notify-event', self._leave_notify_cb) @@ -221,15 +242,6 @@ class Frame: menu_shell.connect('activated', self._menu_shell_activated_cb) menu_shell.connect('deactivated', self._menu_shell_deactivated_cb) - [x, y, width, height] = grid.rectangle(x, y, width, height) - - panel.move(x, y) - panel.resize(width, height) - - self._windows.append(panel) - - return [panel.get_menu_shell(), panel.get_root()] - def _menu_shell_activated_cb(self, menu_shell): self._active_menus += 1 self._timeline.goto('slide_in', True) diff --git a/shell/view/frame/Makefile.am b/shell/view/frame/Makefile.am index 5d96a23..4b51ece 100644 --- a/shell/view/frame/Makefile.am +++ b/shell/view/frame/Makefile.am @@ -2,7 +2,8 @@ sugardir = $(pkgdatadir)/shell/view/frame sugar_PYTHON = \ __init__.py \ ActivitiesBox.py \ - ClipboardBox.py \ + clipboardbox.py \ + clipboardpanelwindow.py \ FriendsBox.py \ PanelWindow.py \ Frame.py \ diff --git a/shell/view/frame/PanelWindow.py b/shell/view/frame/PanelWindow.py index 8fd8145..a690b80 100644 --- a/shell/view/frame/PanelWindow.py +++ b/shell/view/frame/PanelWindow.py @@ -20,7 +20,7 @@ import hippo from sugar.graphics.menushell import MenuShell class PanelWindow(gtk.Window): - def __init__(self): + def __init__(self, x, y, width, height): gtk.Window.__init__(self) self.set_decorated(False) @@ -36,6 +36,9 @@ class PanelWindow(gtk.Window): self._menu_shell = MenuShell(canvas) + self.move(x, y) + self.resize(width, height) + def get_menu_shell(self): return self._menu_shell diff --git a/shell/view/frame/clipboardbox.py b/shell/view/frame/clipboardbox.py new file mode 100644 index 0000000..98a30a0 --- /dev/null +++ b/shell/view/frame/clipboardbox.py @@ -0,0 +1,183 @@ +import logging +import hippo +import gtk + +from sugar import util +from sugar.graphics import style +from view.clipboardicon import ClipboardIcon +from sugar.clipboard import clipboardservice + +class _ContextMap: + """Maps a drag context to the clipboard object involved in the dragging.""" + def __init__(self): + self._context_map = {} + + def add_context(self, context, object_id, data_types): + """Establishes the mapping. data_types will serve us for reference- + counting this mapping. + """ + self._context_map[context] = [object_id, data_types] + + def get_object_id(self, context): + """Retrieves the object_id associated with context. + Will release the association when this function was called as many times + as the number of data_types that this clipboard object contains. + """ + [object_id, data_types_left] = self._context_map[context] + + data_types_left = data_types_left - 1 + if data_types_left == 0: + del self._context_map[context] + else: + self._context_map[context] = [object_id, data_types_left] + + return object_id + +class ClipboardBox(hippo.CanvasBox): + + def __init__(self, menu_shell): + hippo.CanvasBox.__init__(self) + self._menu_shell = menu_shell + self._icons = {} + self._context_map = _ContextMap() + + self._pressed_button = None + self._press_start_x = None + self._press_start_y = None + + cb_service = clipboardservice.get_instance() + cb_service.connect('object-added', self._object_added_cb) + cb_service.connect('object-deleted', self._object_deleted_cb) + cb_service.connect('object-state-changed', self._object_state_changed_cb) + + def _get_icon_at_coords(self, x, y): + for object_id, icon in self._icons.iteritems(): + [icon_x, icon_y] = self.get_position(icon) + [icon_width, icon_height] = icon.get_allocation() + + if (x >= icon_x ) and (x <= icon_x + icon_width) and \ + (y >= icon_y ) and (y <= icon_y + icon_height): + return icon + + return None + + def _add_selection(self, object_id, selection): + if selection.data: + logging.debug('ClipboardBox: adding type ' + selection.type + '.') + + cb_service = clipboardservice.get_instance() + cb_service.add_object_format(object_id, + selection.type, + selection.data, + on_disk = False) + + def _object_added_cb(self, cb_service, object_id, name): + icon = ClipboardIcon(self._menu_shell, object_id, name) + style.apply_stylesheet(icon, 'frame.BuddyIcon') + self.append(icon) + self._icons[object_id] = icon + + logging.debug('ClipboardBox: ' + object_id + ' was added.') + + def _object_deleted_cb(self, cb_service, object_id): + icon = self._icons[object_id] + self.remove(icon) + del self._icons[object_id] + logging.debug('ClipboardBox: ' + object_id + ' was deleted.') + + def _object_state_changed_cb(self, cb_service, object_id, percent): + icon = self._icons[object_id] + icon.set_percent(percent) + logging.debug('ClipboardBox: ' + object_id + ' state was changed.') + + def drag_motion_cb(self, widget, context, x, y, time): + context.drag_status(gtk.gdk.ACTION_COPY, time) + return True + + def drag_drop_cb(self, widget, context, x, y, time): + object_id = util.unique_id() + self._context_map.add_context(context, object_id, len(context.targets)) + + cb_service = clipboardservice.get_instance() + cb_service.add_object(object_id, "name") + + for target in context.targets: + if str(target) not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'): + widget.drag_get_data(context, target, time) + + cb_service.set_object_state(object_id, percent = 100) + + return True + + def drag_data_received_cb(self, widget, context, x, y, selection, targetType, time): + logging.debug('ClipboardBox: got data for target ' + selection.target) + if selection: + object_id = self._context_map.get_object_id(context) + self._add_selection(object_id, selection) + else: + logging.warn('ClipboardBox: empty selection for target ' + selection.target) + + def drag_data_get_cb(self, widget, context, selection, targetType, eventTime): + logging.debug("drag_data_get_cb: requested target " + selection.target) + + object_id = self._last_clicked_icon.get_object_id() + cb_service = clipboardservice.get_instance() + data = cb_service.get_object_data(object_id, selection.target) + + selection.set(selection.target, 8, data) + + def button_press_event_cb(self, widget, event): + logging.debug("button_press_event_cb") + + if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: + self._last_clicked_icon = self._get_icon_at_coords(event.x, event.y) + if self._last_clicked_icon: + self._pressed_button = event.button + self._press_start_x = event.x + self._press_start_y = event.y + + return True; + + def motion_notify_event_cb(self, widget, event): + + if not self._pressed_button: + return True + + logging.debug("motion_notify_event_cb") + + if event.is_hint: + x, y, state = event.window.get_pointer() + else: + x = event.x + y = event.y + state = event.state + + if widget.drag_check_threshold(self._press_start_x, + self._press_start_y, + x, + y): + targets = self._get_targets_for_dnd( + self._last_clicked_icon.get_object_id()) + + context = widget.drag_begin(targets, + gtk.gdk.ACTION_COPY, + 1, + event); + + return True + + def drag_end_cb(self, widget, drag_context): + logging.debug("drag_end_cb") + self._pressed_button = None + + def _get_targets_for_dnd(self, object_id): + cb_service = clipboardservice.get_instance() + format_types = cb_service.get_object_format_types(object_id) + targets = [] + + for format_type in format_types: + targets.append((format_type, 0, 0)) + + logging.debug(str(targets)) + + return targets diff --git a/shell/view/frame/clipboardpanelwindow.py b/shell/view/frame/clipboardpanelwindow.py new file mode 100644 index 0000000..08344c9 --- /dev/null +++ b/shell/view/frame/clipboardpanelwindow.py @@ -0,0 +1,64 @@ +import logging +import gtk +import hippo + +from view.frame.PanelWindow import PanelWindow +from view.frame.clipboardbox import ClipboardBox +from sugar.clipboard import clipboardservice +from sugar import util + +class ClipboardPanelWindow(PanelWindow): + def __init__(self, x, y, width, height): + PanelWindow.__init__(self, x, y, width, height) + + # Listening for new clipboard objects + clipboard = gtk.Clipboard() + clipboard.connect("owner-change", self._owner_change_cb) + + menu_shell = self.get_menu_shell() + root = self.get_root() + + box = ClipboardBox(menu_shell) + root.append(box) + + # Receiving dnd drops + self.drag_dest_set(0, [], 0) + self.connect("drag_motion", box.drag_motion_cb) + self.connect("drag_drop", box.drag_drop_cb) + self.connect("drag_data_received", box.drag_data_received_cb) + + # Offering dnd drags + self.drag_source_set(0, [], 0) + self.add_events(gtk.gdk.BUTTON_PRESS_MASK | + gtk.gdk.POINTER_MOTION_MASK | + gtk.gdk.POINTER_MOTION_HINT_MASK) + self.connect("motion_notify_event", box.motion_notify_event_cb) + self.connect("button_press_event", box.button_press_event_cb) + self.connect("drag_end", box.drag_end_cb) + self.connect("drag_data_get", box.drag_data_get_cb) + + def _owner_change_cb(self, clipboard, event): + logging.debug("owner_change_cb") + + key = util.unique_id() + + cb_service = clipboardservice.get_instance() + cb_service.add_object(key, "name") + cb_service.set_object_state(key, percent = 100) + + targets = clipboard.wait_for_targets() + for target in targets: + if target not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'): + selection = clipboard.wait_for_contents(target) + if selection: + self._add_selection(key, selection) + + def _add_selection(self, key, selection): + if selection.data: + logging.debug('adding type ' + selection.type + '.') + + cb_service = clipboardservice.get_instance() + cb_service.add_object_format(key, + selection.type, + selection.data, + on_disk = False) diff --git a/sugar/clipboard/Makefile.am b/sugar/clipboard/Makefile.am index dbfabe9..0d61c29 100644 --- a/sugar/clipboard/Makefile.am +++ b/sugar/clipboard/Makefile.am @@ -1,5 +1,5 @@ sugardir = $(pythondir)/sugar/clipboard sugar_PYTHON = \ __init__.py \ - ClipboardService.py + clipboardservice.py diff --git a/sugar/clipboard/ClipboardService.py b/sugar/clipboard/clipboardservice.py index 254d6b2..425a16d 100644 --- a/sugar/clipboard/ClipboardService.py +++ b/sugar/clipboard/clipboardservice.py @@ -1,6 +1,9 @@ +import logging import dbus import gobject +from sugar import util + DBUS_SERVICE = "org.laptop.Clipboard" DBUS_INTERFACE = "org.laptop.Clipboard" DBUS_PATH = "/org/laptop/Clipboard" @@ -9,7 +12,7 @@ class ClipboardService(gobject.GObject): __gsignals__ = { 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([str, str, str])), + ([str, str])), 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([str])), 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, @@ -49,24 +52,43 @@ class ClipboardService(gobject.GObject): # ClipboardService started up self._connect_clipboard_signals() - def _object_added_cb(self, name, mimeType, fileName): - self.emit('object-added', name, mimeType, fileName) + def _object_added_cb(self, object_id, name): + self.emit('object-added', object_id, name) - def _object_deleted_cb(self, fileName): - self.emit('object-deleted', fileName) + def _object_deleted_cb(self, object_id): + self.emit('object-deleted', object_id) - def _object_state_changed_cb(self, fileName, percent): - self.emit('object-state-changed', fileName, percent) - - def add_object(self, name, mimeType, fileName): - self._dbus_service.add_object(name, mimeType, fileName) + def _object_state_changed_cb(self, object_id, percent): + self.emit('object-state-changed', object_id, percent) - def delete_object(self, fileName): - self._dbus_service.delete_object(fileName) + def add_object(self, object_id, name): + self._dbus_service.add_object(object_id, name) + + def add_object_format(self, object_id, formatType, data, on_disk): + self._dbus_service.add_object_format(object_id, + formatType, + dbus.types.ByteArray(data), + on_disk) + + def delete_object(self, object_id): + self._dbus_service.delete_object(object_id) - def set_object_state(self, fileName, percent): - self._dbus_service.set_object_state(fileName, percent) + def set_object_state(self, object_id, percent): + self._dbus_service.set_object_state(object_id, percent) + def get_object_format_types(self, object_id): + return self._dbus_service.get_object_format_types(object_id) + + def get_object_data(self, object_id, formatType): + data = self._dbus_service.get_object_data(object_id, formatType) + + # FIXME: Take it out when using the 0.80 dbus bindings + s = "" + for i in data: + s += chr(i) + + return s + _clipboard_service = None def get_instance(): global _clipboard_service |