Re: [Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-17 Thread Simon Schampijer

Pushed as dc8f6ed7852f919fe7123d458706fb82430257e9

Sascha gave his formal bless, too.

Regards,
   Simon
___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


Re: [Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-17 Thread Simon Schampijer

On 02/17/2011 01:21 PM, Martin Langhoff wrote:

On Wed, Feb 16, 2011 at 12:54 PM, Simon Schampijer  wrote:

the general approach - just a few small comments inline.


Thanks! There's a patch in reply, and a few comments from me here...


+def remove_window_by_xid(self, xid):
+"""Remove a window from the windows stack."""
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+# must break after changing array


I think this comment can go away. The code itself should be clear enough.


Sugar developers are smarter than I expect then :-) My concern is
about someone "expanding" the code inside the loop, and getting bitten
by my doing something that is not quite kosher.


I think this code is ok without the comment :) Actually there is another 
occasion of the same code that has no comment - if we think it is 
necessary we should have it in both.



@@ -510,11 +529,12 @@ class ShellModel(gobject.GObject):
  home_activity = Activity(activity_info, activity_id,
window)
  self._add_activity(home_activity)
  else:
-home_activity.set_window(window)
+logging.debug('setting new window for existing activity')
+home_activity.add_window(window)


This code gets called for each window including the launcher. To make that
clear maybe you can come up with another message.


I tried to make things clearer with a comment block for the function,
and more explicit debug lines. HTH.


Yes, looks good now.


  logging.debug('%s launched in %f seconds.',
  home_activity.get_type(), startup_time)


With the current logic the debug log does not log what we expect,


Here is where we were crashing in race conditions :-/ Anyway, I had
that as a separate patch (posted together w this one). Now I've merged
this change in the patch too.


Thanks - looks good now.

Regards,
   Simon
___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


Re: [Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-17 Thread Martin Langhoff
On Wed, Feb 16, 2011 at 12:54 PM, Simon Schampijer  wrote:
> the general approach - just a few small comments inline.

Thanks! There's a patch in reply, and a few comments from me here...

>> +    def remove_window_by_xid(self, xid):
>> +        """Remove a window from the windows stack."""
>> +        for wnd in self._windows:
>> +            if wnd.get_xid() == xid:
>> +                # must break after changing array
>
> I think this comment can go away. The code itself should be clear enough.

Sugar developers are smarter than I expect then :-) My concern is
about someone "expanding" the code inside the loop, and getting bitten
by my doing something that is not quite kosher.

>> @@ -510,11 +529,12 @@ class ShellModel(gobject.GObject):
>>                  home_activity = Activity(activity_info, activity_id,
>> window)
>>                  self._add_activity(home_activity)
>>              else:
>> -                home_activity.set_window(window)
>> +                logging.debug('setting new window for existing activity')
>> +                home_activity.add_window(window)
>
> This code gets called for each window including the launcher. To make that
> clear maybe you can come up with another message.

I tried to make things clearer with a comment block for the function,
and more explicit debug lines. HTH.

>>                  logging.debug('%s launched in %f seconds.',
>>                      home_activity.get_type(), startup_time)
>
> With the current logic the debug log does not log what we expect,

Here is where we were crashing in race conditions :-/ Anyway, I had
that as a separate patch (posted together w this one). Now I've merged
this change in the patch too.

cheers,



m
-- 
 martin.langh...@gmail.com
 mar...@laptop.org -- Software Architect - OLPC
 - ask interesting questions
 - don't get distracted with shiny stuff  - working code first
 - http://wiki.laptop.org/go/User:Martinlanghoff
___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


Re: [Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-16 Thread Simon Schampijer

On 02/12/2011 05:27 PM, martin.langh...@gmail.com wrote:

From: Martin Langhoff

Now activities have a stack of windows (Activity._windows). The
lowest still-valid window in the stack is considered the main window.

When a window is closed, the shell finds what activity had that window,
tells it to remove it from its stack. If that was the last window
in the activities' stack, the activity is marked as closed.

With this patch, activities can switch from one window to another
safely, without sugar shell losing track of them. Activities based
on AdobeAIR have been seen to switch windows (perhaps when they navigate
from one SWF to another).

This replaces the one-window = one-activity model, where the moment
an activity closed one window (perhaps one of many) it was considered
closed by the shell.
---
Amended version, with a fixup in the call to wm.get_sugar_window_type().


Hi Martin,

thanks for your patch and the detailed description. The case you 
describe is valid and I know that you have been testing your patch 
thoroughly. I like the general approach - just a few small comments inline.


Regards,
   Simon


  src/jarabe/model/shell.py |   81 +---
  1 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
index 661e370..135d1a1 100644
--- a/src/jarabe/model/shell.py
+++ b/src/jarabe/model/shell.py
@@ -62,11 +62,12 @@ class Activity(gobject.GObject):
  the "type" of activity being created.
  activity_id -- unique identifier for this instance
  of the activity type
-window -- Main WnckWindow of the activity
+_windows -- WnckWindows registered for the activity. The lowest
+one in the stack is the main window.
  """
  gobject.GObject.__init__(self)

-self._window = None
+self._windows = []
  self._service = None
  self._activity_id = activity_id
  self._activity_info = activity_info
@@ -74,7 +75,7 @@ class Activity(gobject.GObject):
  self._launch_status = Activity.LAUNCHING

  if window is not None:
-self.set_window(window)
+self.add_window(window)

  self._retrieve_service()

@@ -96,15 +97,20 @@ class Activity(gobject.GObject):

  launch_status = gobject.property(getter=get_launch_status)

-def set_window(self, window):
-"""Set the window for the activity
-
-We allow resetting the window for an activity so that we
-can replace the launcher once we get its real window.
-"""
+def add_window(self, window):
+"""Add a window to the windows stack."""
  if not window:
  raise ValueError('window must be valid')
-self._window = window
+self._windows.append(window)
+
+def remove_window_by_xid(self, xid):
+"""Remove a window from the windows stack."""
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+# must break after changing array


I think this comment can go away. The code itself should be clear enough.


+self._windows.remove(wnd)
+return True
+return False

  def get_service(self):
  """Get the activity service
@@ -118,8 +124,8 @@ class Activity(gobject.GObject):

  def get_title(self):
  """Retrieve the application's root window's suggested title"""
-if self._window:
-return self._window.get_name()
+if self._windows:
+return self._windows[0].get_name()
  else:
  return ''

@@ -171,31 +177,44 @@ class Activity(gobject.GObject):

  def get_xid(self):
  """Retrieve the X-windows ID of our root window"""
-if self._window is not None:
-return self._window.get_xid()
+if self._windows:
+return self._windows[0].get_xid()
  else:
  return None

+def has_xid(self, xid):
+"""Retrieve the X-windows ID of our root window"""
+if self._windows:
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+return True
+return None


We should return False here if we do not find a window and for the 
docstring I would recommend something like "Check if an X-window with 
the given xid is in the windows stack".



  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
+This was stored by the add_window method, which was
+called by HomeModel._add_activity, which was called
  via a callback that looks for all 'window-opened'
  events.

+We keep a stack of the windows. The lowest window in the
+stack that is still valid we consider the main one.
+
   

[Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-12 Thread martin . langhoff
From: Martin Langhoff 

Now activities have a stack of windows (Activity._windows). The
lowest still-valid window in the stack is considered the main window.

When a window is closed, the shell finds what activity had that window,
tells it to remove it from its stack. If that was the last window
in the activities' stack, the activity is marked as closed.

With this patch, activities can switch from one window to another
safely, without sugar shell losing track of them. Activities based
on AdobeAIR have been seen to switch windows (perhaps when they navigate
from one SWF to another).

This replaces the one-window = one-activity model, where the moment
an activity closed one window (perhaps one of many) it was considered
closed by the shell.
---
Amended version, with a fixup in the call to wm.get_sugar_window_type().
---
 src/jarabe/model/shell.py |   81 +---
 1 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
index 661e370..135d1a1 100644
--- a/src/jarabe/model/shell.py
+++ b/src/jarabe/model/shell.py
@@ -62,11 +62,12 @@ class Activity(gobject.GObject):
 the "type" of activity being created.
 activity_id -- unique identifier for this instance
 of the activity type
-window -- Main WnckWindow of the activity
+_windows -- WnckWindows registered for the activity. The lowest
+one in the stack is the main window.
 """
 gobject.GObject.__init__(self)
 
-self._window = None
+self._windows = []
 self._service = None
 self._activity_id = activity_id
 self._activity_info = activity_info
@@ -74,7 +75,7 @@ class Activity(gobject.GObject):
 self._launch_status = Activity.LAUNCHING
 
 if window is not None:
-self.set_window(window)
+self.add_window(window)
 
 self._retrieve_service()
 
@@ -96,15 +97,20 @@ class Activity(gobject.GObject):
 
 launch_status = gobject.property(getter=get_launch_status)
 
-def set_window(self, window):
-"""Set the window for the activity
-
-We allow resetting the window for an activity so that we
-can replace the launcher once we get its real window.
-"""
+def add_window(self, window):
+"""Add a window to the windows stack."""
 if not window:
 raise ValueError('window must be valid')
-self._window = window
+self._windows.append(window)
+
+def remove_window_by_xid(self, xid):
+"""Remove a window from the windows stack."""
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+# must break after changing array
+self._windows.remove(wnd)
+return True
+return False
 
 def get_service(self):
 """Get the activity service
@@ -118,8 +124,8 @@ class Activity(gobject.GObject):
 
 def get_title(self):
 """Retrieve the application's root window's suggested title"""
-if self._window:
-return self._window.get_name()
+if self._windows:
+return self._windows[0].get_name()
 else:
 return ''
 
@@ -171,31 +177,44 @@ class Activity(gobject.GObject):
 
 def get_xid(self):
 """Retrieve the X-windows ID of our root window"""
-if self._window is not None:
-return self._window.get_xid()
+if self._windows:
+return self._windows[0].get_xid()
 else:
 return None
 
+def has_xid(self, xid):
+"""Retrieve the X-windows ID of our root window"""
+if self._windows:
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+return True
+return None
+
 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
+This was stored by the add_window method, which was 
+called by HomeModel._add_activity, which was called 
 via a callback that looks for all 'window-opened'
 events.
 
+We keep a stack of the windows. The lowest window in the
+stack that is still valid we consider the main one.
+
 HomeModel currently uses a dbus service query on the
 activity to determine to which HomeActivity the newly
 launched window belongs.
 """
-return self._window
+   if self._windows:
+return self._windows[0]
+return None
 
 def get_type(self):
 """Retrieve the activity bundle id for future reference"""
-if self._window is None:
+if not self._windows:
 return None
 else:
-return wm.get_bundle_id(self._window)
+return wm.get_bundle_id(s

Re: [Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-12 Thread Martin Langhoff
On Sat, Feb 12, 2011 at 2:09 PM,   wrote:
> diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
> index 661e370..bd7e367 100644

I'd like to recall this particular patch. Apologies, posted the wrong version.

cheers,


m
-- 
 martin.langh...@gmail.com
 mar...@laptop.org -- Software Architect - OLPC
 - ask interesting questions
 - don't get distracted with shiny stuff  - working code first
 - http://wiki.laptop.org/go/User:Martinlanghoff
___
Sugar-devel mailing list
Sugar-devel@lists.sugarlabs.org
http://lists.sugarlabs.org/listinfo/sugar-devel


[Sugar-devel] [PATCH 1/2] shell: handle activities that cycle through windows dlo#10695

2011-02-12 Thread martin . langhoff
From: Martin Langhoff 

Now activities have a stack of windows (Activity._windows). The
lowest still-valid window in the stack is considered the main window.

When a window is closed, the shell finds what activity had that window,
tells it to remove it from its stack. If that was the last window
in the activities' stack, the activity is marked as closed.

With this patch, activities can switch from one window to another
safely, without sugar shell losing track of them. Activities based
on AdobeAIR have been seen to switch windows (perhaps when they navigate
from one SWF to another).

This replaces the one-window = one-activity model, where the moment
an activity closed one window (perhaps one of many) it was considered
closed by the shell.
---
 src/jarabe/model/shell.py |   81 +---
 1 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
index 661e370..bd7e367 100644
--- a/src/jarabe/model/shell.py
+++ b/src/jarabe/model/shell.py
@@ -62,11 +62,12 @@ class Activity(gobject.GObject):
 the "type" of activity being created.
 activity_id -- unique identifier for this instance
 of the activity type
-window -- Main WnckWindow of the activity
+_windows -- WnckWindows registered for the activity. The lowest
+one in the stack is the main window.
 """
 gobject.GObject.__init__(self)
 
-self._window = None
+self._windows = []
 self._service = None
 self._activity_id = activity_id
 self._activity_info = activity_info
@@ -74,7 +75,7 @@ class Activity(gobject.GObject):
 self._launch_status = Activity.LAUNCHING
 
 if window is not None:
-self.set_window(window)
+self.add_window(window)
 
 self._retrieve_service()
 
@@ -96,15 +97,20 @@ class Activity(gobject.GObject):
 
 launch_status = gobject.property(getter=get_launch_status)
 
-def set_window(self, window):
-"""Set the window for the activity
-
-We allow resetting the window for an activity so that we
-can replace the launcher once we get its real window.
-"""
+def add_window(self, window):
+"""Add a window to the windows stack."""
 if not window:
 raise ValueError('window must be valid')
-self._window = window
+self._windows.append(window)
+
+def remove_window_by_xid(self, xid):
+"""Remove a window from the windows stack."""
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+# must break after changing array
+self._windows.remove(wnd)
+return True
+return False
 
 def get_service(self):
 """Get the activity service
@@ -118,8 +124,8 @@ class Activity(gobject.GObject):
 
 def get_title(self):
 """Retrieve the application's root window's suggested title"""
-if self._window:
-return self._window.get_name()
+if self._windows:
+return self._windows[0].get_name()
 else:
 return ''
 
@@ -171,31 +177,44 @@ class Activity(gobject.GObject):
 
 def get_xid(self):
 """Retrieve the X-windows ID of our root window"""
-if self._window is not None:
-return self._window.get_xid()
+if self._windows:
+return self._windows[0].get_xid()
 else:
 return None
 
+def has_xid(self, xid):
+"""Retrieve the X-windows ID of our root window"""
+if self._windows:
+for wnd in self._windows:
+if wnd.get_xid() == xid:
+return True
+return None
+
 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
+This was stored by the add_window method, which was 
+called by HomeModel._add_activity, which was called 
 via a callback that looks for all 'window-opened'
 events.
 
+We keep a stack of the windows. The lowest window in the
+stack that is still valid we consider the main one.
+
 HomeModel currently uses a dbus service query on the
 activity to determine to which HomeActivity the newly
 launched window belongs.
 """
-return self._window
+   if self._windows:
+return self._windows[0]
+return None
 
 def get_type(self):
 """Retrieve the activity bundle id for future reference"""
-if self._window is None:
+if not self._windows:
 return None
 else:
-return wm.get_bundle_id(self._window)
+return wm.get_bundle_id(self._windows[0])
 
 def is_journal(self):
 """Returns boolean if