First version of the ClipboardService. Added support for showing the progress of a pdf download in the clipboard.

This commit is contained in:
Tomeu Vizoso 2006-11-01 19:43:59 +01:00
parent cf508c1d22
commit 23565cfd48
21 changed files with 593 additions and 37 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -1,3 +1,5 @@
VOID:OBJECT,STRING,LONG,LONG
VOID:OBJECT,LONG
VOID:STRING,STRING,STRING
VOID:STRING,INT
VOID:STRING

View File

@ -1 +1 @@
SUBDIRS = presence nm
SUBDIRS = presence nm clipboard

View 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...'

View 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)

View File

View File

@ -0,0 +1,4 @@
[D-BUS Service]
Name = org.laptop.Clipboard
Exec = @bindir@/sugar-clipboard

View 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()

View 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

View 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)

View File

@ -7,6 +7,8 @@ sugar_PYTHON = \
FirstTimeDialog.py \
BuddyIcon.py \
BuddyMenu.py \
ClipboardIcon.py \
ClipboardMenu.py \
OverlayWindow.py \
Shell.py \
stylesheet.py

View 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.')

View File

@ -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()

View File

@ -2,6 +2,7 @@ sugardir = $(pkgdatadir)/shell/view/frame
sugar_PYTHON = \
__init__.py \
ActivitiesBox.py \
ClipboardBox.py \
FriendsBox.py \
PanelWindow.py \
Frame.py \

View File

@ -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'

View 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();