Hi Eliza,

On Tue, Mar 24, 2015 at 10:36:33PM -0700, Eliza Guseva wrote:
> 
> >
> > Ok, great! We have lots of other bugs and oddities, so I'm sure we can 
> > find something :) 
> >
> 
> I've started filing an application for the D-bus project.
> However it turned out that for Python Foundation a patch is a requirement.
> So I pushed it a little further and made an experimental fix or the layout 
> issue  #372 for the case of stacks

Thanks for taking a look!

> I applied it for the commit 989f0f8534ee2e34e14b8cb02920c861d053d49c
> And it worked. It has an issue: the windows order is being saved, but qtile 
> redraws the correct order sometimes only on-click.
> Maybe it's due to the method I used, maybe something else.
> I used OrderedSet class, wich is under MIT license, from here:
> http://code.activestate.com/recipes/576694-orderedset/
> 
> 
> I pulled the lateset commit from qtile/qtile in order to test my fix on the 
> newer version
> I've got a message error, when tried to change layouts:
> ERROR handle_KeyPress:854 KB command error nextlayout: No such command.

Yes, this is due to some deprecated stuff that we (finally) removed;
it should be next_layout.

> Please apply my patch to 989f0f8534ee2e34e14b8cb02920c861d053d49c

Some comments on the patch below.

Tycho

> diff --git a/libqtile/group.py b/libqtile/group.py
> index 2203260..82b1d01 100644
> --- a/libqtile/group.py
> +++ b/libqtile/group.py
> @@ -30,6 +30,7 @@ import contextlib
>  import xcffib
>  import xcffib.xproto
>  
> +from . import ordered_set
>  from . import command
>  from . import hook
>  from . import window
> @@ -45,7 +46,7 @@ class _Group(command.CommandObject):
>      def __init__(self, name, layout=None):
>          self.name = name
>          self.customLayout = layout  # will be set on _configure
> -        self.windows = set()
> +        self.windows = ordered_set.OrderedSet([])
>          self.qtile = None
>          self.layouts = []
>          self.floating_layout = None
> @@ -62,14 +63,37 @@ class _Group(command.CommandObject):
>          self.screen = None
>          self.currentLayout = 0
>          self.focusHistory = []
> -        self.windows = set()
> +        self.windows = ordered_set.OrderedSet([])
>          self.qtile = qtile
>          self.layouts = [i.clone(self) for i in layouts]
>          self.floating_layout = floating_layout.clone(self)
>          if self.customLayout is not None:
>              self.layout = self.customLayout
>              self.customLayout = None
> -
> +    
> +    def __str__(self):
> +        output = 'Group named '+str(self.name)
> +        try:
> +            output+= ' at the screen '+str(self.screen.index)+'\n'
> +        except:
> +            output+= ' at the UNKNOWN screen\n'
> +        output+='and my attributes are:\n'
> +        for item in self.__dict__:
> +            if not (self.__dict__[item] == None):
> +                output+=('  '+item+'\t'+repr(self.__dict__[item])+'\n')
> +            else:
> +                output+=('  '+item)+':\t being 
> '+str(self.__dict__[item])+'!\n'

Is there any way we can use the group's info() cmd to output this
information?

> +        return output
> +    
> +    def __repr__(self):

__repr__ is supposed to be some python code that could be executed to
reconstruct the object. The string generated by this doesn't look to
be valid python, so we should probably just get rid of this method or
roll it into __str__/info somehow.

> +        output = 'Group named '+str(self.name)
> +        try:
> +            output+= ' at the screen '+str(self.screen.index)+'\n'
> +        except:
> +            output+= ' at the UNKNOWN screen\n'
> +        return output
> +    
>      @property
>      def currentWindow(self):
>          try:
> diff --git a/libqtile/ordered_set.py b/libqtile/ordered_set.py
> new file mode 100644
> index 0000000..e2e4156
> --- /dev/null
> +++ b/libqtile/ordered_set.py

We need a licensing header on this file if we want to include it in
tree; distro packaging requires this sort of thing.

> @@ -0,0 +1,67 @@
> +import collections
> +
> +class OrderedSet(collections.MutableSet):
> +
> +    def __init__(self, iterable=None):
> +        self.end = end = [] 
> +        end += [None, end, end]         # sentinel node for doubly linked 
> list
> +        self.map = {}                   # key --> [key, prev, next]
> +        if iterable is not None:
> +            self |= iterable
> +
> +    def __len__(self):
> +        return len(self.map)
> +
> +    def __contains__(self, key):
> +        return key in self.map
> +
> +    def add(self, key):
> +        if key not in self.map:
> +            end = self.end
> +            curr = end[1]
> +            curr[2] = end[1] = self.map[key] = [key, curr, end]
> +
> +    def discard(self, key):
> +        if key in self.map:        
> +            key, prev, next = self.map.pop(key)
> +            prev[2] = next
> +            next[1] = prev
> +
> +    def __iter__(self):
> +        end = self.end
> +        curr = end[2]
> +        while curr is not end:
> +            yield curr[0]
> +            curr = curr[2]
> +
> +    def __reversed__(self):
> +        end = self.end
> +        curr = end[1]
> +        while curr is not end:
> +            yield curr[0]
> +            curr = curr[1]
> +
> +    def pop(self, last=True):
> +        if not self:
> +            raise KeyError('set is empty')
> +        key = self.end[1][0] if last else self.end[2][0]
> +        self.discard(key)
> +        return key
> +
> +    def __repr__(self):
> +        if not self:
> +            return '%s()' % (self.__class__.__name__,)
> +        return '%s(%r)' % (self.__class__.__name__, list(self))
> +
> +    def __eq__(self, other):
> +        if isinstance(other, OrderedSet):
> +            return len(self) == len(other) and list(self) == list(other)
> +        return set(self) == set(other)
> +
> +            
> +if __name__ == '__main__':
> +    s = OrderedSet('abracadaba')
> +    t = OrderedSet('simsalabim')
> +    print(s | t)
> +    print(s & t)
> +    print(s - t)
> \ No newline at end of file
> diff --git a/libqtile/state.py b/libqtile/state.py
> index 5438f38..0b750a1 100644
> --- a/libqtile/state.py
> +++ b/libqtile/state.py
> @@ -31,22 +31,59 @@ class QtileState(object):
>          # configurations.
>          self.groups = {}
>          self.screens = {}
> -
> +        self.layouts ={}
> +        self.windows={}
> +        _windows = {}
>          for group in qtile.groups:
> +            #try:

It would be good if we could get rid of all commented out/debugging
code from the final version of the patch.

> +            self.windows[group.name]=str(group.windows)
> +            _windows[group.name]=list(group.windows)
>              self.groups[group.name] = group.layout.name
> +            qtile.log.info('current layout:\n'+str(group.layout))
> +            self.layouts[group.name] = {}
> +            #qtile.log.info(str(
> +            if group.layout.name == 'stack':

Ideally, I'd like to require layouts to implement the serialization
themselves, so that all this code has to do is call .serialize() or
something, and all the stack layout code can live in
/libqtile/layouts/stack.py and nowhere else.

> +                for indx in range(group.layout.num_stacks):

Is it possible to pickle the layouts themselves? I'm not sure how well
this would work, but it seems like you might not have to do all the
work you're doing below if you just pickle the layout.

> +                    currStack = group.layout.stacks[indx]
> +                    qtile.log.info('indx '+str(indx)+' group.name 
> '+str(group.name))
> +                    self.layouts[group.name][indx]=([],)
> +                    if not currStack.lst==[]:
> +                        windowList=[]
> +                        for window in currStack.lst:
> +                            qtile.log.info(str(window))
> +                            windowList.append(
> +                                _windows[group.name].index(window))
> +                        currentWindow=\
> +                            _windows[group.name].index(currStack.cw)
> +                        
> self.layouts[group.name][indx]=(windowList,currentWindow)
> +                        
>          for index, screen in enumerate(qtile.screens):
>              self.screens[index] = screen.group.name
> -
> +    
> +    def __str__(self):
> +        str1= 'My state is:\n'
> +        str1+='Groups:\t'+str(self.groups)+'\n'
> +        str1+='Screens:\t'+str(self.screens)+'\n'
> +        str1+='Stack Layouts:\t'+str(self.layouts)+'\n'
> +        str1+='Windows:\t'+str(self.windows)+'\n'
> +        return str1
> +    
> +    def __repr__(self):
> +        return self.__str__()

Same thought here about __repr__ vs __str__.

> +    
>      def apply(self, qtile):
>          """
>              Rearrange the windows in the specified Qtile object according to
>              this QtileState.
>          """
> +        qtile.log.info(str(self))
>          for (group, layout) in self.groups.items():
>              try:
>                  qtile.groupMap[group].layout = layout
> +                
>              except KeyError:
>                  pass  # group missing
> +            
>  
>          for (screen, group) in self.screens.items():
>              try:
> @@ -54,3 +91,18 @@ class QtileState(object):
>                  qtile.screens[screen].setGroup(group)
>              except (KeyError, IndexError):
>                  pass  # group or screen missing
> +            
> +        for (group, layout) in self.layouts.items():
> +            currGroup = qtile.groupMap[group]
> +            _windows = list(currGroup.windows)
> +            for stackNum in layout.keys():
> +                currLayout = currGroup.layouts[currGroup.currentLayout]
> +                qtile.log.info(str(currLayout))
> +                if currLayout.name == 'stack':
> +                    for indx in range(currLayout.num_stacks):
> +                        currStack = currLayout.stacks[indx]
> +                        currStack.lst = [_windows[i] for i in 
> layout[indx][0]]
> +                        currStack.current = layout[indx][1]
> +        stateAgain = QtileState(qtile)
> +        qtile.log.info(self)
> +        qtile.log.info(stateAgain)
> \ No newline at end of file

-- 
You received this message because you are subscribed to the Google Groups 
"qtile-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to