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

This commit is contained in:
Simon Schampijer
2007-10-15 19:04:05 +02:00
51 changed files with 120 additions and 4577 deletions
+4 -28
View File
@@ -2,9 +2,7 @@ SUBDIRS = activity bundle clipboard graphics objects presence datastore
sugardir = $(pythondir)/sugar
sugar_PYTHON = \
__init__.py \
env.py \
logger.py \
ltihooks.py \
network.py \
profile.py \
@@ -13,37 +11,19 @@ sugar_PYTHON = \
pkgpyexecdir = $(pythondir)/sugar
pkgpyexec_LTLIBRARIES = _sugarext.la _sugaruiext.la
_sugarext_la_CFLAGS = \
$(LIB_CFLAGS) \
$(LIB_BINDINGS_CFLAGS) \
$(PYTHON_INCLUDES) \
-I$(top_srcdir)/lib
_sugarext_la_LDFLAGS = -module -avoid-version
_sugarext_la_LIBADD = \
$(LIB_BINDINGS_LIBS) \
$(top_builddir)/lib/libsugar.la
_sugarext_la_SOURCES = \
_sugarextmodule.c
nodist__sugarext_la_SOURCES = _sugarext.c
_sugarext.c: _sugarext.defs _sugarext.override
pkgpyexec_LTLIBRARIES = _sugaruiext.la
_sugaruiext_la_CFLAGS = \
$(LIBUI_CFLAGS) \
$(LIBUI_BINDINGS_CFLAGS) \
$(PYTHON_INCLUDES) \
-I$(top_srcdir)/lib/ui
-I$(top_srcdir)/lib
_sugaruiext_la_LDFLAGS = -module -avoid-version
_sugaruiext_la_LIBADD = \
$(LIBUI_BINDINGS_LIBS) \
$(LIBUI_LIBS) \
$(top_builddir)/lib/ui/libsugarui.la
$(top_builddir)/lib/libsugarui.la
_sugaruiext_la_SOURCES = \
_sugaruiextmodule.c
@@ -52,13 +32,9 @@ nodist__sugaruiext_la_SOURCES = _sugaruiext.c
_sugaruiext.c: _sugaruiext.defs _sugaruiext.override
CLEANFILES = \
_sugarext.c \
_sugaruiext.c
CLEANFILES = _sugaruiext.c
EXTRA_DIST = \
_sugarext.override \
_sugarext.defs \
_sugaruiext.defs \
_sugaruiext.override
-25
View File
@@ -1,25 +0,0 @@
"""OLPC Sugar User Interface"""
# Copyright (C) 2006-2007, 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.
import os
from sugar import ltihooks
if os.path.isfile(os.path.join(os.path.dirname(__file__), 'Makefile.am')):
ltihooks.install()
-41
View File
@@ -1,41 +0,0 @@
; functions
(define-function get_mime_type_from_file_name
(c-name "sugar_mime_get_mime_type_from_file_name")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)
(define-function get_mime_type_for_file
(c-name "sugar_mime_get_mime_type_for_file")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)
(define-function get_prgname
(c-name "g_get_prgname")
(return-type "const-char*")
)
(define-function get_application_name
(c-name "g_get_application_name")
(return-type "const-char*")
)
(define-function set_prgname
(c-name "g_set_prgname")
(parameters
'("const-char*" "name")
)
)
(define-function set_application_name
(c-name "g_set_application_name")
(parameters
'("const-char*" "name")
)
)
-32
View File
@@ -1,32 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#include "xdgmime.h"
#include <glib.h>
%%
modulename _sugarext
%%
ignore-glob
*_get_type
_*
%%
override sugar_mime_get_mime_type_for_file kwargs
static PyObject *
_wrap_sugar_mime_get_mime_type_for_file(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "filename", NULL };
char *filename;
const gchar *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:get_mime_type_for_file", kwlist, &filename))
return NULL;
ret = sugar_mime_get_mime_type_for_file(filename, NULL);
if (ret)
return PyString_FromString(ret);
Py_INCREF(Py_None);
return Py_None;
}
%%
-42
View File
@@ -1,42 +0,0 @@
/*
* Copyright (C) 2006-2007, 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <pygobject.h>
extern PyMethodDef py_sugarext_functions[];
DL_EXPORT(void)
init_sugarext(void)
{
PyObject *m, *d;
init_pygobject ();
m = Py_InitModule ("_sugarext", py_sugarext_functions);
d = PyModule_GetDict (m);
if (PyErr_Occurred ()) {
Py_FatalError ("can't initialise module _sugarext");
}
}
+7 -3
View File
@@ -42,7 +42,7 @@ from sugar.graphics.toolcombobox import ToolComboBox
from sugar.datastore import datastore
from sugar import wm
from sugar import profile
from sugar import _sugarext
from sugar import _sugarbaseext
SCOPE_PRIVATE = "private"
SCOPE_INVITE_ONLY = "invite" # shouldn't be shown in UI, it's implicit when you invite somebody
@@ -261,6 +261,7 @@ class Activity(Window, gtk.Container):
self.connect('realize', self._realize_cb)
self.connect('delete-event', self._delete_event_cb)
self.connect('window-state-event', self._window_state_event_cb)
self._active = False
self._activity_id = handle.activity_id
@@ -344,6 +345,9 @@ class Activity(Window, gtk.Container):
else:
logging.debug("Unknown share scope %r" % share_scope)
def _window_state_event_cb(self, window, event):
logging.info(event.new_window_state)
def do_set_property(self, pspec, value):
if pspec.name == 'active':
if self._active != value:
@@ -363,7 +367,7 @@ class Activity(Window, gtk.Container):
return self._activity_id
def get_bundle_id(self):
return _sugarext.get_prgname()
return _sugarbaseext.get_prgname()
def set_canvas(self, canvas):
Window.set_canvas(self, canvas)
@@ -634,7 +638,7 @@ class Activity(Window, gtk.Container):
def get_bundle_name():
"""Return the bundle name for the current process' bundle
"""
return _sugarext.get_application_name()
return _sugarbaseext.get_application_name()
def get_bundle_path():
"""Return the bundle path for the current process' bundle
+1 -1
View File
@@ -28,7 +28,7 @@ from sugar.activity.activityhandle import ActivityHandle
from sugar.bundle.contentbundle import ContentBundle
from sugar.bundle.activitybundle import ActivityBundle
from sugar.bundle.contentbundle import ContentBundle
from sugar.objects import mime
from sugar import mime
class DSMetadata(gobject.GObject):
__gsignals__ = {
-52
View File
@@ -1,52 +0,0 @@
# Copyright (C) 2007 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.
import sys
import os
import logging
import time
# Let's keep this self contained so that it can be easily
# pasted in external sugar service like the datastore.
def get_logs_dir():
profile = os.environ.get('SUGAR_PROFILE', 'default')
logs_dir = os.path.join(os.path.expanduser('~'),
'.sugar', profile, 'logs')
return logs_dir
def set_level(level):
levels = { 'error' : logging.ERROR,
'warning' : logging.WARNING,
'debug' : logging.DEBUG,
'info' : logging.INFO }
if levels.has_key(level):
logging.getLogger('').setLevel(levels[level])
def start(log_filename=None):
logging.basicConfig(level=logging.WARNING,
format="%(created)f %(levelname)s %(message)s")
if os.environ.has_key('SUGAR_LOGGER_LEVEL'):
set_level(os.environ['SUGAR_LOGGER_LEVEL'])
if log_filename and not sys.stdin.isatty():
log_path = os.path.join(get_logs_dir(), log_filename + '.log')
log_file = open(log_path, 'w')
os.dup2(log_file.fileno(), sys.stdout.fileno())
os.dup2(log_file.fileno(), sys.stderr.fileno())
-1
View File
@@ -1,6 +1,5 @@
sugardir = $(pythondir)/sugar/objects
sugar_PYTHON = \
__init__.py \
mime.py \
objecttype.py
-2
View File
@@ -14,5 +14,3 @@
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
from sugar.objects import mime
-120
View File
@@ -1,120 +0,0 @@
# Copyright (C) 2006-2007, Red Hat, Inc.
# Copyright (C) 2007, One Laptop Per Child
#
# 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.
import logging
from sugar import _sugarext
def get_for_file(file_name):
mime_type = _sugarext.get_mime_type_for_file(file_name)
if mime_type == 'application/octet-stream':
if _file_looks_like_text(file_name):
return 'text/plain'
else:
return 'application/octet-stream'
return mime_type
def get_from_file_name(file_name):
return _sugarext.get_mime_type_from_file_name(file_name)
_extensions_cache = {}
def get_primary_extension(mime_type):
if _extensions_cache.has_key(mime_type):
return _extensions_cache[mime_type]
f = open('/etc/mime.types')
while True:
line = f.readline()
if not line:
break
cols = line.replace('\t', ' ').split(' ')
if mime_type == cols[0]:
for col in cols[1:]:
if col:
col = col.replace('\n', '')
_extensions_cache[mime_type] = col
return col
_extensions_cache[mime_type] = None
return None
def choose_most_significant(mime_types):
logging.debug('Choosing between %r.' % mime_types)
if not mime_types:
return ''
if 'text/uri-list' in mime_types:
return 'text/uri-list'
for mime_category in ['image/', 'application/']:
for mime_type in mime_types:
if mime_type.startswith(mime_category):
# skip mozilla private types (second component starts with '_'
# or ends with '-priv')
if mime_type.split('/')[1].startswith('_') or \
mime_type.split('/')[1].endswith('-priv'):
continue
# take out the specifier after ';' that mozilla likes to add
mime_type = mime_type.split(';')[0]
logging.debug('Choosed %r!' % mime_type)
return mime_type
if 'text/x-moz-url' in mime_types:
logging.debug('Choosed text/x-moz-url!')
return 'text/x-moz-url'
if 'text/html' in mime_types:
logging.debug('Choosed text/html!')
return 'text/html'
if 'text/plain' in mime_types:
logging.debug('Choosed text/plain!')
return 'text/plain'
logging.debug('Returning first: %r.' % mime_types[0])
return mime_types[0]
def split_uri_list(uri_list):
result = []
splitted = uri_list.split('\n')
for uri in splitted:
result.append(uri.strip())
return result
def _file_looks_like_text(file_name):
f = open(file_name, 'r')
try:
sample = f.read(256)
finally:
f.close()
if '\000' in sample:
return False
for encoding in ('ascii', 'latin_1', 'utf_8', 'utf_16'):
try:
string = unicode(sample, encoding)
return True
except Exception, e:
pass
return False
+35 -13
View File
@@ -26,9 +26,8 @@ _logger = logging.getLogger('sugar.presence.activity')
class Activity(gobject.GObject):
"""UI interface for an Activity in the presence service
Activities in the presence service represent other user's
shared activities and your own activities (XXX shared or
otherwise?)
Activities in the presence service represent your and other user's
shared activities.
Properties:
id
@@ -69,8 +68,10 @@ class Activity(gobject.GObject):
self._ps_del_object = del_obj_cb
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
self._activity.connect_to_signal('BuddyJoined', self._buddy_joined_cb)
self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
self._activity.connect_to_signal('BuddyHandleJoined',
self._buddy_handle_joined_cb)
self._activity.connect_to_signal('BuddyLeft',
self._buddy_left_cb)
self._activity.connect_to_signal('NewChannel', self._new_channel_cb)
self._activity.connect_to_signal('PropertiesChanged',
self._properties_changed_cb,
@@ -90,6 +91,9 @@ class Activity(gobject.GObject):
self._tags = None
self._private = True
self._joined = False
# Cache for get_buddy_by_handle, maps handles to buddy object paths
self._handle_to_buddy_path = {}
self._buddy_path_to_handle = {}
def _get_properties_reply_cb(self, new_props):
self._properties_changed_cb(new_props)
@@ -178,8 +182,10 @@ class Activity(gobject.GObject):
self.emit('buddy-joined', self._ps_new_object(object_path))
return False
def _buddy_joined_cb(self, object_path):
def _buddy_handle_joined_cb(self, object_path, handle):
gobject.idle_add(self._emit_buddy_joined_signal, object_path)
self._handle_to_buddy_path[handle] = object_path
self._buddy_path_to_handle[object_path] = handle
def _emit_buddy_left_signal(self, object_path):
"""Generate buddy-left GObject signal with presence Buddy object
@@ -191,6 +197,8 @@ class Activity(gobject.GObject):
def _buddy_left_cb(self, object_path):
gobject.idle_add(self._emit_buddy_left_signal, object_path)
handle = self._buddy_path_to_handle.pop(object_path)
self._handle_to_buddy_path.pop(handle, None)
def _emit_new_channel_signal(self, object_path):
"""Generate new-channel GObject signal with channel object path
@@ -214,6 +222,18 @@ class Activity(gobject.GObject):
buddies.append(self._ps_new_object(item))
return buddies
def get_buddy_by_handle(self, handle):
"""Retrieve the Buddy object given a telepathy handle.
buddy object paths are cached in self._handle_to_buddy_path,
so we can get the buddy without calling PS.
"""
object_path = self._handle_to_buddy_path.get(handle, None)
if object_path:
buddy = self._ps_new_object(object_path)
return buddy
return None
def invite(self, buddy, message, response_cb):
"""Invite the given buddy to join this activity.
@@ -244,9 +264,13 @@ class Activity(gobject.GObject):
def get_channels(self):
"""Retrieve communications channel descriptions for the activity
Returns (bus name, connection, channels) for the activity
XXX what are those values?
Returns a tuple containing:
- the D-Bus well-known service name of the connection
(FIXME: this is redundant; in Telepathy it can be derived
from that of the connection)
- the D-Bus object path of the connection
- a list of D-Bus object paths representing the channels
associated with this activity
"""
(bus_name, connection, channels) = self._activity.GetChannels()
return bus_name, connection, channels
@@ -256,10 +280,8 @@ class Activity(gobject.GObject):
self.emit("joined", False, "left activity")
def _leave_error_cb(self, err):
"""Callback for error in async leaving of shared activity.
XXX Add logging!"""
pass
"""Callback for error in async leaving of shared activity."""
_logger.debug('Failed to leave activity: %s', err)
def leave(self):
"""Leave this shared activity"""