Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/shell/model/homeactivity.py
blob: 72b661bd2e8e9a0943a192d36e49f701927974a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# Copyright (C) 2006-2007 Owen Williams.
#
# 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 time
import logging

import gobject
import dbus

from sugar.graphics.xocolor import XoColor
from sugar.presence import presenceservice
from sugar import profile

_SERVICE_NAME = "org.laptop.Activity"
_SERVICE_PATH = "/org/laptop/Activity"
_SERVICE_INTERFACE = "org.laptop.Activity"

class HomeActivity(gobject.GObject):
    """Activity which appears in the "Home View" of the Sugar shell
    
    This class stores the Sugar Shell's metadata regarding a
    given activity/application in the system.  It interacts with
    the sugar.activity.* modules extensively in order to 
    accomplish its tasks.
    """

    __gtype_name__ = 'SugarHomeActivity'

    __gproperties__ = {
        'launching' : (bool, None, None, False,
                       gobject.PARAM_READWRITE),
    }

    def __init__(self, activity_info, activity_id):
        """Initialise the HomeActivity
        
        activity_info -- sugar.activity.registry.ActivityInfo instance,
            provides the information required to actually
            create the new instance.  This is, in effect,
            the "type" of activity being created.
        activity_id -- unique identifier for this instance
            of the activity type
        """
        gobject.GObject.__init__(self)

        self._window = None
        self._xid = None
        self._pid = None
        self._service = None
        self._activity_id = activity_id
        self._activity_info = activity_info
        self._launch_time = time.time()
        self._launching = False

        self._retrieve_service()

        if not self._service:
            bus = dbus.SessionBus()
            bus.add_signal_receiver(self._name_owner_changed_cb,
                                    signal_name="NameOwnerChanged",
                                    dbus_interface="org.freedesktop.DBus")

    def set_window(self, window):
        """An activity is 'launched' once we get its window."""
        if self._window or self._xid:
            raise RuntimeError("Activity is already launched!")
        if not window:
            raise ValueError("window must be valid")

        self._window = window
        self._xid = window.get_xid()
        self._pid = window.get_pid()

    def get_service(self):
        """Get the activity service
        
        Note that non-native Sugar applications will not have
        such a service, so the return value will be None in
        those cases.
        """

        return self._service

    def get_title(self):
        """Retrieve the application's root window's suggested title"""
        return self._window.get_name()

    def get_icon_name(self):
        """Retrieve the activity's icon (file) name"""
        if self._activity_info:
            return self._activity_info.icon
        else:
            return 'image-missing'
    
    def get_icon_color(self):
        """Retrieve the appropriate icon colour for this activity
        
        Uses activity_id to index into the PresenceService's 
        set of activity colours, if the PresenceService does not
        have an entry (implying that this is not a Sugar-shared application)
        uses the local user's profile.get_color() to determine the
        colour for the icon.
        """
        pservice = presenceservice.get_instance()

        # HACK to suppress warning in logs when activity isn't found
        # (if it's locally launched and not shared yet)
        activity = None
        for act in pservice.get_activities():
            if self._activity_id == act.props.id:
                activity = act
                break

        if activity != None:
            return XoColor(activity.props.color)
        else:
            return profile.get_color()
        
    def get_activity_id(self):
        """Retrieve the "activity_id" passed in to our constructor
        
        This is a "globally likely unique" identifier generated by
        sugar.util.unique_id
        """
        return self._activity_id

    def get_xid(self):
        """Retrieve the X-windows ID of our root window"""
        return self._xid

    def get_window(self):
        """Retrieve the X-windows root window of this application
        
        This was stored by the set_window method, which was 
        called by HomeModel._add_activity, which was called 
        via a callback that looks for all 'window-opened'
        events.
        
        HomeModel currently uses a dbus service query on the
        activity to determine to which HomeActivity the newly
        launched window belongs.
        """
        return self._window

    def get_type(self):
        """Retrieve the activity bundle id for future reference"""
        if self._activity_info:
            return self._activity_info.bundle_id
        else:
            return None

    def get_launch_time(self):
        """Return the time at which the activity was first launched
        
        Format is floating-point time.time() value 
        (seconds since the epoch)
        """
        return self._launch_time

    def get_pid(self):
        """Returns the activity's PID"""
        return self._pid

    def equals(self, activity):
        if self._activity_id and activity.get_activity_id():
            return self._activity_id == activity.get_activity_id()
        if self._xid and activity.get_xid():
            return self._xid == activity.get_xid()
        return False

    def do_set_property(self, pspec, value):
        if pspec.name == 'launching':
            self._launching = value

    def do_get_property(self, pspec):
        if pspec.name == 'launching':
            return self._launching

    def _get_service_name(self):
        if self._activity_id:
            return _SERVICE_NAME + self._activity_id
        else:
            return None

    def _retrieve_service(self):
        if not self._activity_id:
            return

        try:
            bus = dbus.SessionBus()
            proxy = bus.get_object(self._get_service_name(),
                                   _SERVICE_PATH + "/" + self._activity_id)
            self._service = dbus.Interface(proxy, _SERVICE_INTERFACE)
        except dbus.DBusException:
            self._service = None

    def _name_owner_changed_cb(self, name, old, new):
        if name == self._get_service_name():
            self._retrieve_service()