First version of the ClipboardService. Added support for showing the progress of a pdf download in the clipboard.
This commit is contained in:
parent
cf508c1d22
commit
23565cfd48
@ -18,6 +18,7 @@ from gettext import gettext as _
|
||||
import gtk
|
||||
import gtkmozembed
|
||||
import logging
|
||||
import dbus
|
||||
|
||||
import _sugar
|
||||
from sugar.activity import ActivityFactory
|
||||
@ -105,11 +106,34 @@ def start():
|
||||
style.load_stylesheet(web.stylesheet)
|
||||
|
||||
chandler = _sugar.get_browser_chandler()
|
||||
chandler.connect('handle-content', handle_content_cb)
|
||||
chandler.connect('download-started', download_started_cb)
|
||||
chandler.connect('download-completed', download_completed_cb)
|
||||
chandler.connect('download-cancelled', download_started_cb)
|
||||
chandler.connect('download-progress', download_progress_cb)
|
||||
|
||||
def stop():
|
||||
gtkmozembed.pop_startup()
|
||||
|
||||
def handle_content_cb(chandler, url, mimeType, tmpFileName):
|
||||
activity = ActivityFactory.create("org.laptop.sugar.Xbook")
|
||||
activity.execute("open_document", [tmpFileName])
|
||||
def download_started_cb(chandler, url, mimeType, tmpFileName):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('org.laptop.Clipboard', '/org/laptop/Clipboard')
|
||||
iface = dbus.Interface(proxy_obj, 'org.laptop.Clipboard')
|
||||
iface.add_object(mimeType, tmpFileName)
|
||||
|
||||
def download_completed_cb(chandler, tmpFileName):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('org.laptop.Clipboard', '/org/laptop/Clipboard')
|
||||
iface = dbus.Interface(proxy_obj, 'org.laptop.Clipboard')
|
||||
iface.update_object_state(tmpFileName, 100)
|
||||
|
||||
def download_cancelled_cb(chandler, tmpFileName):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('org.laptop.Clipboard', '/org/laptop/Clipboard')
|
||||
iface = dbus.Interface(proxy_obj, 'org.laptop.Clipboard')
|
||||
iface.delete_object(tmpFileName, 100)
|
||||
|
||||
def download_progress_cb(chandler, tmpFileName, progress):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object('org.laptop.Clipboard', '/org/laptop/Clipboard')
|
||||
iface = dbus.Interface(proxy_obj, 'org.laptop.Clipboard')
|
||||
iface.update_object_state(tmpFileName, progress)
|
||||
|
@ -64,6 +64,7 @@ lib/threadframe/Makefile
|
||||
services/Makefile
|
||||
services/presence/Makefile
|
||||
services/nm/Makefile
|
||||
services/clipboard/Makefile
|
||||
shell/Makefile
|
||||
shell/conf/Makefile
|
||||
shell/data/Makefile
|
||||
|
@ -36,24 +36,36 @@ NS_IMETHODIMP
|
||||
GSugarDownload::OnStateChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest,
|
||||
PRUint32 aStateFlags, nsresult aStatus)
|
||||
{
|
||||
SugarBrowserChandler *browser_chandler = sugar_get_browser_chandler();
|
||||
|
||||
if (((aStateFlags & STATE_IS_REQUEST) &&
|
||||
(aStateFlags & STATE_IS_NETWORK) &&
|
||||
(aStateFlags & STATE_START)) ||
|
||||
aStateFlags == STATE_START) {
|
||||
|
||||
nsCString url;
|
||||
nsCString mimeType;
|
||||
nsCString targetURI;
|
||||
|
||||
if ((((aStateFlags & STATE_IS_REQUEST) &&
|
||||
(aStateFlags & STATE_IS_NETWORK) &&
|
||||
(aStateFlags & STATE_STOP)) ||
|
||||
aStateFlags == STATE_STOP) &&
|
||||
NS_SUCCEEDED (aStatus)) {
|
||||
|
||||
mMIMEInfo->GetMIMEType(mimeType);
|
||||
mSource->GetSpec(url);
|
||||
|
||||
SugarBrowserChandler *browser_chandler = sugar_get_browser_chandler();
|
||||
sugar_browser_chandler_handle_content(browser_chandler,
|
||||
sugar_browser_chandler_download_started(browser_chandler,
|
||||
url.get(),
|
||||
mimeType.get(),
|
||||
mTargetFileName.get());
|
||||
|
||||
} else if (((aStateFlags & STATE_IS_REQUEST) &&
|
||||
(aStateFlags & STATE_IS_NETWORK) &&
|
||||
(aStateFlags & STATE_STOP)) ||
|
||||
aStateFlags == STATE_STOP) {
|
||||
|
||||
if (NS_SUCCEEDED (aStatus)) {
|
||||
sugar_browser_chandler_download_completed(browser_chandler,
|
||||
mTargetFileName.get());
|
||||
} else {
|
||||
sugar_browser_chandler_download_cancelled(browser_chandler,
|
||||
mTargetFileName.get());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -80,6 +92,14 @@ GSugarDownload::OnProgressChange64 (nsIWebProgress *aWebProgress,
|
||||
PRInt64 aCurTotalProgress,
|
||||
PRInt64 aMaxTotalProgress)
|
||||
{
|
||||
SugarBrowserChandler *browser_chandler = sugar_get_browser_chandler();
|
||||
PRInt32 percentComplete =
|
||||
(PRInt32)(((float)aCurSelfProgress / (float)aMaxSelfProgress) * 100.0);
|
||||
|
||||
sugar_browser_chandler_update_progress(browser_chandler,
|
||||
mTargetFileName.get(),
|
||||
percentComplete);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,10 @@
|
||||
#include "sugar-browser-chandler.h"
|
||||
|
||||
enum {
|
||||
HANDLE_CONTENT,
|
||||
DOWNLOAD_STARTED,
|
||||
DOWNLOAD_COMPLETED,
|
||||
DOWNLOAD_CANCELLED,
|
||||
DOWNLOAD_PROGRESS,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
@ -19,8 +22,8 @@ sugar_browser_chandler_init(SugarBrowserChandler *browserChandler)
|
||||
static void
|
||||
sugar_browser_chandler_class_init(SugarBrowserChandlerClass *browser_chandler_class)
|
||||
{
|
||||
signals[HANDLE_CONTENT] =
|
||||
g_signal_new ("handle-content",
|
||||
signals[DOWNLOAD_STARTED] =
|
||||
g_signal_new ("download-started",
|
||||
G_OBJECT_CLASS_TYPE (browser_chandler_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (SugarBrowserChandlerClass, handle_content),
|
||||
@ -30,6 +33,37 @@ sugar_browser_chandler_class_init(SugarBrowserChandlerClass *browser_chandler_cl
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING);
|
||||
|
||||
signals[DOWNLOAD_COMPLETED] =
|
||||
g_signal_new ("download-completed",
|
||||
G_OBJECT_CLASS_TYPE (browser_chandler_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (SugarBrowserChandlerClass, handle_content),
|
||||
NULL, NULL,
|
||||
sugar_marshal_VOID__STRING,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
signals[DOWNLOAD_CANCELLED] =
|
||||
g_signal_new ("download-cancelled",
|
||||
G_OBJECT_CLASS_TYPE (browser_chandler_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (SugarBrowserChandlerClass, handle_content),
|
||||
NULL, NULL,
|
||||
sugar_marshal_VOID__STRING,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
signals[DOWNLOAD_PROGRESS] =
|
||||
g_signal_new ("download-progress",
|
||||
G_OBJECT_CLASS_TYPE (browser_chandler_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (SugarBrowserChandlerClass, handle_content),
|
||||
NULL, NULL,
|
||||
sugar_marshal_VOID__STRING_INT,
|
||||
G_TYPE_NONE, 2,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_INT);
|
||||
}
|
||||
|
||||
SugarBrowserChandler *
|
||||
@ -42,15 +76,46 @@ sugar_get_browser_chandler()
|
||||
}
|
||||
|
||||
void
|
||||
sugar_browser_chandler_handle_content (SugarBrowserChandler *browser_chandler,
|
||||
sugar_browser_chandler_download_started (SugarBrowserChandler *browser_chandler,
|
||||
const char *url,
|
||||
const char *mime_type,
|
||||
const char *tmp_file_name)
|
||||
{
|
||||
g_signal_emit(browser_chandler,
|
||||
signals[HANDLE_CONTENT],
|
||||
signals[DOWNLOAD_STARTED],
|
||||
0 /* details */,
|
||||
url,
|
||||
mime_type,
|
||||
tmp_file_name);
|
||||
}
|
||||
|
||||
void
|
||||
sugar_browser_chandler_download_completed (SugarBrowserChandler *browser_chandler,
|
||||
const char *tmp_file_name)
|
||||
{
|
||||
g_signal_emit(browser_chandler,
|
||||
signals[DOWNLOAD_COMPLETED],
|
||||
0 /* details */,
|
||||
tmp_file_name);
|
||||
}
|
||||
|
||||
void sugar_browser_chandler_download_cancelled (SugarBrowserChandler *browser_chandler,
|
||||
const char *tmp_file_name)
|
||||
{
|
||||
g_signal_emit(browser_chandler,
|
||||
signals[DOWNLOAD_CANCELLED],
|
||||
0 /* details */,
|
||||
tmp_file_name);
|
||||
}
|
||||
|
||||
void
|
||||
sugar_browser_chandler_update_progress (SugarBrowserChandler *browser_chandler,
|
||||
const char *tmp_file_name,
|
||||
const int percent)
|
||||
{
|
||||
g_signal_emit(browser_chandler,
|
||||
signals[DOWNLOAD_PROGRESS],
|
||||
0 /* details */,
|
||||
tmp_file_name,
|
||||
percent);
|
||||
}
|
||||
|
@ -29,10 +29,17 @@ struct _SugarBrowserChandlerClass {
|
||||
|
||||
GType sugar_browser_chandler_get_type (void);
|
||||
SugarBrowserChandler *sugar_get_browser_chandler (void);
|
||||
void sugar_browser_chandler_handle_content (SugarBrowserChandler *chandler,
|
||||
void sugar_browser_chandler_download_started (SugarBrowserChandler *chandler,
|
||||
const char *url,
|
||||
const char *mime_type,
|
||||
const char *tmp_file_name);
|
||||
void sugar_browser_chandler_download_completed (SugarBrowserChandler *chandler,
|
||||
const char *tmp_file_name);
|
||||
void sugar_browser_chandler_download_cancelled (SugarBrowserChandler *chandler,
|
||||
const char *tmp_file_name);
|
||||
void sugar_browser_chandler_update_progress (SugarBrowserChandler *chandler,
|
||||
const char *tmp_file_name,
|
||||
const int percent);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
VOID:OBJECT,STRING,LONG,LONG
|
||||
VOID:OBJECT,LONG
|
||||
VOID:STRING,STRING,STRING
|
||||
VOID:STRING,INT
|
||||
VOID:STRING
|
||||
|
@ -1 +1 @@
|
||||
SUBDIRS = presence nm
|
||||
SUBDIRS = presence nm clipboard
|
||||
|
76
services/clipboard/ClipboardService.py
Normal file
76
services/clipboard/ClipboardService.py
Normal file
@ -0,0 +1,76 @@
|
||||
# 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
|
||||
|
||||
_CLIPBOARD_SERVICE = "org.laptop.Clipboard"
|
||||
_CLIPBOARD_DBUS_INTERFACE = "org.laptop.Clipboard"
|
||||
_CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard"
|
||||
|
||||
class ClipboardDBusServiceHelper(dbus.service.Object):
|
||||
def __init__(self, parent):
|
||||
self._parent = parent
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
bus_name = dbus.service.BusName(_CLIPBOARD_DBUS_INTERFACE, bus=bus)
|
||||
dbus.service.Object.__init__(self, bus_name, _CLIPBOARD_OBJECT_PATH)
|
||||
|
||||
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
|
||||
in_signature="ss", out_signature="")
|
||||
def add_object(self, mimeType, fileName):
|
||||
logging.debug('Added object of type ' + mimeType + ' with path at ' + fileName)
|
||||
self.object_added(mimeType, fileName)
|
||||
|
||||
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
|
||||
in_signature="s", out_signature="")
|
||||
def delete_object(self, fileName):
|
||||
logging.debug('Deleted object with path at ' + fileName)
|
||||
self.object_deleted(fileName)
|
||||
|
||||
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
|
||||
in_signature="si", out_signature="")
|
||||
def update_object_state(self, fileName, percent):
|
||||
logging.debug('Updated object with path at ' + fileName + ' with percent ' + str(percent))
|
||||
self.object_state_updated(fileName, percent)
|
||||
|
||||
@dbus.service.signal(_CLIPBOARD_DBUS_INTERFACE, signature="ss")
|
||||
def object_added(self, 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_updated(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...'
|
15
services/clipboard/Makefile.am
Normal file
15
services/clipboard/Makefile.am
Normal file
@ -0,0 +1,15 @@
|
||||
servicedir = $(datadir)/sugar/services
|
||||
service_in_files = org.laptop.Clipboard.service.in
|
||||
service_DATA = $(service_in_files:.service.in=.service)
|
||||
|
||||
$(service_DATA): $(service_in_files) Makefile
|
||||
@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
|
||||
|
||||
sugardir = $(pkgdatadir)/services/clipboard
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
ClipboardService.py
|
||||
|
||||
bin_SCRIPTS = sugar-clipboard
|
||||
|
||||
EXTRA_DIST = $(service_in_files) $(bin_SCRIPTS)
|
0
services/clipboard/__init__.py
Normal file
0
services/clipboard/__init__.py
Normal file
4
services/clipboard/org.laptop.Clipboard.service.in
Normal file
4
services/clipboard/org.laptop.Clipboard.service.in
Normal file
@ -0,0 +1,4 @@
|
||||
[D-BUS Service]
|
||||
Name = org.laptop.Clipboard
|
||||
Exec = @bindir@/sugar-clipboard
|
||||
|
44
services/clipboard/sugar-clipboard
Executable file
44
services/clipboard/sugar-clipboard
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/python
|
||||
# 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 sys
|
||||
import logging
|
||||
|
||||
from sugar import logger
|
||||
logger.start('clipboard')
|
||||
|
||||
import gobject
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
import dbus.glib
|
||||
|
||||
from sugar import env
|
||||
|
||||
sys.path.insert(0, env.get_services_dir())
|
||||
|
||||
from clipboard.ClipboardService import ClipboardService
|
||||
|
||||
logging.info('Starting clipboard service.')
|
||||
|
||||
gobject.threads_init()
|
||||
dbus.glib.threads_init()
|
||||
|
||||
app = ClipboardService()
|
||||
app.run()
|
33
shell/view/ClipboardIcon.py
Normal file
33
shell/view/ClipboardIcon.py
Normal file
@ -0,0 +1,33 @@
|
||||
from sugar.graphics.menuicon import MenuIcon
|
||||
from view.ClipboardMenu import ClipboardMenu
|
||||
from sugar.activity import ActivityFactory
|
||||
|
||||
class ClipboardIcon(MenuIcon):
|
||||
def __init__(self, menu_shell, file_name):
|
||||
MenuIcon.__init__(self, menu_shell, icon_name='stock-written-doc')
|
||||
self._file_name = file_name
|
||||
self._percent = 0
|
||||
self.connect('activated', self._icon_activated_cb)
|
||||
self._menu = None
|
||||
|
||||
def create_menu(self):
|
||||
self._menu = ClipboardMenu(self._file_name, self._percent)
|
||||
self._menu.connect('action', self._popup_action_cb)
|
||||
return self._menu
|
||||
|
||||
def set_percent(self, percent):
|
||||
self._percent = percent
|
||||
if self._menu:
|
||||
self._menu.set_percent(percent)
|
||||
|
||||
def _icon_activated_cb(self, icon):
|
||||
activity = ActivityFactory.create("org.laptop.sugar.Xbook")
|
||||
activity.execute("open_document", [self._file_name])
|
||||
|
||||
def _popup_action_cb(self, popup, action):
|
||||
# self.popdown()
|
||||
#
|
||||
# if action == ClipboardMenu.ACTION_DELETE:
|
||||
# activity = self._shell.get_current_activity()
|
||||
# activity.invite(ps_buddy)
|
||||
pass
|
58
shell/view/ClipboardMenu.py
Normal file
58
shell/view/ClipboardMenu.py
Normal file
@ -0,0 +1,58 @@
|
||||
import gtk
|
||||
import gobject
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.menu import Menu
|
||||
from sugar.graphics.canvasicon import CanvasIcon
|
||||
from sugar.graphics.ClipboardBubble import ClipboardBubble
|
||||
from sugar.graphics import style
|
||||
|
||||
clipboard_bubble = {
|
||||
'fill-color' : 0x646464FF,
|
||||
'stroke-color' : 0x646464FF,
|
||||
'progress-color': 0x333333FF,
|
||||
'spacing' : style.space_unit,
|
||||
'padding' : style.space_unit * 1.5
|
||||
}
|
||||
|
||||
clipboard_menu_item_title = {
|
||||
'xalign': hippo.ALIGNMENT_START,
|
||||
'padding-left': 5,
|
||||
'color' : 0xFFFFFFFF,
|
||||
'font' : style.get_font_description('Bold', 1.2)
|
||||
}
|
||||
|
||||
style.register_stylesheet("clipboard.Bubble", clipboard_bubble)
|
||||
style.register_stylesheet("clipboard.MenuItem.Title", clipboard_menu_item_title)
|
||||
|
||||
class ClipboardMenuItem(ClipboardBubble):
|
||||
|
||||
def __init__(self, percent = 0, stylesheet="clipboard.Bubble"):
|
||||
ClipboardBubble.__init__(self, percent = percent)
|
||||
style.apply_stylesheet(self, stylesheet)
|
||||
|
||||
class ClipboardMenu(Menu):
|
||||
|
||||
ACTION_DELETE = 0
|
||||
ACTION_SHARE = 1
|
||||
ACTION_STOP_DOWNLOAD = 2
|
||||
|
||||
def __init__(self, file_name, percent):
|
||||
Menu.__init__(self, file_name)
|
||||
|
||||
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)
|
||||
|
||||
if percent == 100:
|
||||
icon = CanvasIcon(icon_name='stock-remove')
|
||||
self.add_action(icon, ClipboardMenu.ACTION_DELETE)
|
||||
else:
|
||||
icon = CanvasIcon(icon_name='stock-close')
|
||||
self.add_action(icon, ClipboardMenu.ACTION_STOP_DOWNLOAD)
|
||||
|
||||
def set_percent(self, percent):
|
||||
self._progress_bar.set_property('percent', percent)
|
||||
|
@ -7,6 +7,8 @@ sugar_PYTHON = \
|
||||
FirstTimeDialog.py \
|
||||
BuddyIcon.py \
|
||||
BuddyMenu.py \
|
||||
ClipboardIcon.py \
|
||||
ClipboardMenu.py \
|
||||
OverlayWindow.py \
|
||||
Shell.py \
|
||||
stylesheet.py
|
||||
|
61
shell/view/frame/ClipboardBox.py
Normal file
61
shell/view/frame/ClipboardBox.py
Normal file
@ -0,0 +1,61 @@
|
||||
import logging
|
||||
import dbus
|
||||
import hippo
|
||||
|
||||
from sugar.graphics import style
|
||||
from view.ClipboardIcon import ClipboardIcon
|
||||
|
||||
class ClipboardBox(hippo.CanvasBox):
|
||||
|
||||
_CLIPBOARD_SERVICE = "org.laptop.Clipboard"
|
||||
_CLIPBOARD_OBJECT_PATH = "/org/laptop/Clipboard"
|
||||
|
||||
def __init__(self, shell, menu_shell):
|
||||
hippo.CanvasBox.__init__(self)
|
||||
self._shell = shell
|
||||
self._menu_shell = menu_shell
|
||||
self._icons = {}
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
bus.add_signal_receiver(self.name_owner_changed_cb,
|
||||
signal_name="NameOwnerChanged",
|
||||
dbus_interface="org.freedesktop.DBus")
|
||||
# Try to register to ClipboardService, if we fail, we'll try later.
|
||||
try:
|
||||
self._connect_clipboard_signals()
|
||||
except dbus.DBusException, exception:
|
||||
pass
|
||||
|
||||
def _connect_clipboard_signals(self):
|
||||
bus = dbus.SessionBus()
|
||||
proxy_obj = bus.get_object(self._CLIPBOARD_SERVICE, self._CLIPBOARD_OBJECT_PATH)
|
||||
iface = dbus.Interface(proxy_obj, self._CLIPBOARD_SERVICE)
|
||||
iface.connect_to_signal('object_added', self.object_added_callback)
|
||||
iface.connect_to_signal('object_deleted', self.object_deleted_callback)
|
||||
iface.connect_to_signal('object_state_updated', self.object_state_updated_callback)
|
||||
|
||||
def name_owner_changed_cb(self, name, old, new):
|
||||
if name != self._CLIPBOARD_SERVICE:
|
||||
return
|
||||
if (not old and not len(old)) and (new and len(new)):
|
||||
# ClipboardService started up
|
||||
self._connect_clipboard_signals()
|
||||
|
||||
def object_added_callback(self, mimeType, fileName):
|
||||
icon = ClipboardIcon(self._menu_shell, fileName)
|
||||
style.apply_stylesheet(icon, 'frame.BuddyIcon')
|
||||
self.append(icon)
|
||||
self._icons[fileName] = icon
|
||||
|
||||
logging.debug('ClipboardBox: ' + fileName + ' was added.')
|
||||
|
||||
def object_deleted_callback(self, fileName):
|
||||
icon = self._icons[fileName]
|
||||
self.remove(icon)
|
||||
self._icons.remove(icon)
|
||||
logging.debug('ClipboardBox: ' + fileName + ' was deleted.')
|
||||
|
||||
def object_state_updated_callback(self, fileName, percent):
|
||||
icon = self._icons[fileName]
|
||||
icon.set_percent(percent)
|
||||
logging.debug('ClipboardBox: ' + fileName + ' state was updated.')
|
@ -23,6 +23,7 @@ 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.notificationtray import NotificationTray
|
||||
from sugar.graphics.timeline import Timeline
|
||||
@ -198,7 +199,10 @@ class Frame:
|
||||
root.append(box)
|
||||
|
||||
# Left panel
|
||||
self._create_panel(grid, 0, 1, 1, 10)
|
||||
[menu_shell, root] = self._create_panel(grid, 0, 1, 1, 10)
|
||||
|
||||
box = ClipboardBox(self._shell, menu_shell)
|
||||
root.append(box)
|
||||
|
||||
def _create_panel(self, grid, x, y, width, height):
|
||||
panel = PanelWindow()
|
||||
|
@ -2,6 +2,7 @@ sugardir = $(pkgdatadir)/shell/view/frame
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
ActivitiesBox.py \
|
||||
ClipboardBox.py \
|
||||
FriendsBox.py \
|
||||
PanelWindow.py \
|
||||
Frame.py \
|
||||
|
@ -40,6 +40,7 @@ if sourcedir:
|
||||
bin_path = sourcedir
|
||||
bin_path += ':' + os.path.join(sourcedir, 'shell')
|
||||
bin_path += ':' + os.path.join(sourcedir, 'services/presence')
|
||||
bin_path += ':' + os.path.join(sourcedir, 'services/clipboard')
|
||||
|
||||
if os.environ.has_key('PATH'):
|
||||
old_path = os.environ['PATH']
|
||||
@ -56,6 +57,11 @@ if sourcedir:
|
||||
setup.write_service('org.laptop.Presence', bin,
|
||||
env.get_activity_info_dir())
|
||||
|
||||
bin = os.path.join(sourcedir,
|
||||
'services/clipboard/sugar-clipboard')
|
||||
setup.write_service('org.laptop.Clipboard', bin,
|
||||
env.get_activity_info_dir())
|
||||
|
||||
from sugar.emulator import Emulator
|
||||
|
||||
program = 'sugar-shell'
|
||||
|
133
sugar/graphics/ClipboardBubble.py
Normal file
133
sugar/graphics/ClipboardBubble.py
Normal file
@ -0,0 +1,133 @@
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the
|
||||
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
#TODO: has to be merged with all the existing bubbles in a generic progress bar widget
|
||||
|
||||
import math
|
||||
|
||||
import gobject
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
|
||||
__gtype_name__ = 'ClipboardBubble'
|
||||
|
||||
__gproperties__ = {
|
||||
'fill-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'stroke-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'progress-color': (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
'percent' : (object, None, None,
|
||||
gobject.PARAM_READWRITE),
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._stroke_color = 0xFFFFFFFF
|
||||
self._fill_color = 0xFFFFFFFF
|
||||
self._progress_color = 0x000000FF
|
||||
self._percent = 0
|
||||
self._radius = 8
|
||||
|
||||
hippo.CanvasBox.__init__(self, **kwargs)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'fill-color':
|
||||
self._fill_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'stroke-color':
|
||||
self._stroke_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'progress-color':
|
||||
self._progress_color = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
elif pspec.name == 'percent':
|
||||
self._percent = value
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'fill-color':
|
||||
return self._fill_color
|
||||
elif pspec.name == 'stroke-color':
|
||||
return self._stroke_color
|
||||
elif pspec.name == 'progress-color':
|
||||
return self._progress_color
|
||||
elif pspec.name == 'percent':
|
||||
return self._percent
|
||||
|
||||
def _int_to_rgb(self, int_color):
|
||||
red = (int_color >> 24) & 0x000000FF
|
||||
green = (int_color >> 16) & 0x000000FF
|
||||
blue = (int_color >> 8) & 0x000000FF
|
||||
alpha = int_color & 0x000000FF
|
||||
return (red / 255.0, green / 255.0, blue / 255.0)
|
||||
|
||||
def do_paint_below_children(self, cr, damaged_box):
|
||||
[width, height] = self.get_allocation()
|
||||
|
||||
line_width = 3.0
|
||||
x = line_width
|
||||
y = line_width
|
||||
width -= line_width * 2
|
||||
height -= line_width * 2
|
||||
|
||||
cr.move_to(x + self._radius, y);
|
||||
cr.arc(x + width - self._radius, y + self._radius,
|
||||
self._radius, math.pi * 1.5, math.pi * 2);
|
||||
cr.arc(x + width - self._radius, x + height - self._radius,
|
||||
self._radius, 0, math.pi * 0.5);
|
||||
cr.arc(x + self._radius, y + height - self._radius,
|
||||
self._radius, math.pi * 0.5, math.pi);
|
||||
cr.arc(x + self._radius, y + self._radius, self._radius,
|
||||
math.pi, math.pi * 1.5);
|
||||
|
||||
color = self._int_to_rgb(self._fill_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
||||
|
||||
color = self._int_to_rgb(self._stroke_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.set_line_width(line_width)
|
||||
cr.stroke();
|
||||
|
||||
self._paint_progress_bar(cr, x, y, width, height, line_width)
|
||||
|
||||
def _paint_progress_bar(self, cr, x, y, width, height, line_width):
|
||||
prog_x = x + line_width
|
||||
prog_y = y + line_width
|
||||
prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
|
||||
prog_height = (height - (line_width * 2))
|
||||
|
||||
x = prog_x
|
||||
y = prog_y
|
||||
width = prog_width
|
||||
height = prog_height
|
||||
|
||||
cr.move_to(x + self._radius, y);
|
||||
cr.arc(x + width - self._radius, y + self._radius,
|
||||
self._radius, math.pi * 1.5, math.pi * 2);
|
||||
cr.arc(x + width - self._radius, x + height - self._radius,
|
||||
self._radius, 0, math.pi * 0.5);
|
||||
cr.arc(x + self._radius, y + height - self._radius,
|
||||
self._radius, math.pi * 0.5, math.pi);
|
||||
cr.arc(x + self._radius, y + self._radius, self._radius,
|
||||
math.pi, math.pi * 1.5);
|
||||
|
||||
color = self._int_to_rgb(self._progress_color)
|
||||
cr.set_source_rgb(*color)
|
||||
cr.fill_preserve();
|
Loading…
Reference in New Issue
Block a user