View Full Version : Python plugin (Python API for Compiz)
mikedee
April 10th, 2007, 04:05 AM
For the interest of those not on the list, here is a recent announcement for my python plugin (thanks to RYX for help and encouragement)
Release 0.5.2 (for Compiz 0.5.2) - http://www.anykeysoftware.co.uk/compiz/python/compiz-python-0.5.2.tar.gz
Here is my python loader plugin which loads plain python scripts as full plugins.
Example plugins
triangle - Just a basic plugin which shows a triangle on a button press. This shows using ctypes to pass values from compiz to the python opengl bindings.
basiczoom - Zooms in on the screen (basically)
desktopmenu - Activates a menu when clicking on the desktop. It uses the menu program in the desktopmenu folder.
doc - Just generates the compiz.html documentation. This is the smallest possible compiz plugin.
inactive - Makes inactive windows desaturated.
pyplane - A python version of the plane plugin, it is planned to add extra features not in plane now.
pywallpaper - A copy of the wallpaper plugin which shows different wallpapers on the root window (ie. without a desktop window). This is improved over the C version because it is more stable and it supports vertical viewports.
rot - An example of how to use the compizcube module to control the cube rotation.
seethru - A copy of fakeargb to test the fragment function interface. It seems to work identically to the C version. It toggles between making everything black transparent and making everything white transparent.
minime - An example using the miniwin class which makes it easy to draw transformed windows. This example acts as a simple pager application.
There is documentation here
HTML - Multiple pages http://www.anykeysoftware.co.uk/compiz/python/doc/html/
HTML - Single page http://www.anykeysoftware.co.uk/compiz/python/doc/html_single/
PDF - http://www.anykeysoftware.co.uk/compiz/python/doc/main.pdf
I think most things are complete, the TODO list contains a list of things I am aware of. You should be able to do most things that can be done with c plugins (without the hassle of pointers)
Git access
This is stored in my personal freedesktop git repo. To get it type this, you can update as normal with git-pull
git-clone git://people.freedesktop.org/~mike/python
For install info read the README file
Git web is available here
http://gitweb.freedesktop.org/?p=users/mike/python.git;a=summary
Its only really for developers at the moment, but hopefully it will lead to some interesting plugins :)
For anyone interested in working on this or embedding Python in general, the reference ownership system is not explained well in the official docs. To me this was much more useful and helped clarify everything.
http://projects.blender.org/pipermail/bf-python/2005-September/003092.html
Sorcerer
April 10th, 2007, 09:05 AM
Excellent work, mikedee!
rememo
April 10th, 2007, 11:56 AM
Truly amazing and important work mikedee!
Now every python-wizard should get on rocking with this :)
wfarr
April 10th, 2007, 12:01 PM
Is this for git only? It doesn't want to build and install here with 0.5.
mikedee
April 10th, 2007, 12:46 PM
Excellent work, mikedee!
Truly amazing and important work mikedee!
Now every python-wizard should get on rocking with this :)
Glad you both like it (and it works :) ) I hope someone can put it to good use
Is this for git only? It doesn't want to build and install here with 0.5.
Yes, sorry. The changes needed for core just missed the 0.5.0 release (people were screaming for it, so it had to go). Don't worry too much though, David is promising much more frequent developer releases. 0.3.6 - 0.5.0 was different because there was a lot of changes and breaks made after 0.3.4.
RYX
April 10th, 2007, 11:37 PM
Well done :D ...
Is it possible that you create a patch for the 0.5 version? I'd really like to try some things but I have no metacity 2.18 and can't compile current git (waiting for Feisty final). That's also the reason I couldn't try your latest version from the list and didn't reply on the last mail. I now have more time to work on this because the new site is up and the domains are moved.
fyi: Only for completeness - mikedee and I followed two very different approaches for creating a python-plugin. I tried to do it from python-space using ctypes to directly connect to the native functions, mikedee tried the C-space approach by creating embedded Py*-functions and wrappers. We ended up with two basically working plugins but we finally agreed to drop my ctypes-approach - the ctypes-version was much more unstable and very hard to debug.
:)
mikedee
April 11th, 2007, 01:58 AM
I think the metacity problem has been fixed recently so you should be able to compile again. If not let me know and I can try to get a patch, problem is git formats all the patches in one, but releases are not git repositories so I doubt a git-diff will apply properly
RYX
April 11th, 2007, 02:16 AM
Cool, you're right - it works with latest git ... (even on Ubuntu Edgy) ... :)
delphinen
April 11th, 2007, 03:34 AM
This is indeed very good news, thank you very much mike
amgeex
April 11th, 2007, 04:17 AM
Woot! Maybe now I'll be able to actually contribute something lol! :D
RYX
April 11th, 2007, 01:16 PM
I have some problem with threading from within the python-plugins. When I start a thread it simply doesn't run - when I try to launch it the second time it says it is already running ...
Do we need any special XLib-threading calls before threads work within the plugins?
mikedee
April 11th, 2007, 01:33 PM
I have some problem with threading from within the python-plugins. When I start a thread it simply doesn't run - when I try to launch it the second time it says it is already running ...
Do we need any special XLib-threading calls before threads work within the plugins?
I didn't have any problems with my quick try. I tried to start a HTTP server from a plugin but I had blocking problems. I used the Thread class to start threads and it seemed to work for the listener.
If you are doing lots of blocking operations, it might be better to rethink the design to use an external app and then communicate via dbus. Polling for dbus and fuse is done by watching a unix file descriptor, I haven't implemented watchFd yet
BTW - I'm almost finished with that HTTP interface so you should be able to do some cool flash things soon :)
RYX
April 11th, 2007, 01:58 PM
I think we have the same problem - blocking calls are not run as thread, they simply block and don't run ... For playing sounds ths is a huge problem.
I already thought about using an external app but I will need a lot of notifcation about various events and compiz's dbus-interface doesn't even offer one of the signals I need.
I can see no reason why the threads don't work ... in case someone wants to give it a try (you'll need python-pymad and python-pyao and two mp3-sounds). If you use run() instead of start(), the sounds are playing ...:
import compiz
import threading
import mad, ao
mypluginref = None
class AsyncMp3Sound (threading.Thread):
"""A simple class for asynchronously playing mp3-sounds using mad/ao."""
# constructor for thread
def __init__ (self, filename, driver='oss'):
threading.Thread.__init__(self)
self.filename = filename
self.driver = driver
self.__playing = True # set False to stop (terminates run()-method)
# run-handler for thread - called on start()
def run (self):
print "Playing sound: %s" % self.filename
mf = mad.MadFile(self.filename)
dev = ao.AudioDevice(self.driver, rate=mf.samplerate())
while self.__playing:
buf = mf.read()
if buf is None:
break
dev.play(buf, len(buf))
def stop (self):
"""Stop playing this sound and end thread."""
self.__playing = False
@classmethod
def create_playing (cls, filename):
"""Create new instance of AsyncSound from 'filename', start playing and
return (playing) instance."""
snd = AsyncMp3Sound(filename)
snd.start()
return snd
class soundfxPlugin:
sounds = {}
soundPath = '/home/ryx/Documents/scripts/python/test/sound/sounds/'
def __init__(self):
self.name = "soundfx"
self.shortDesc = "Sound Effects"
self.longDesc = "Add sound effects to events"
self.getScreenOptions = None
self.setScreenOption = None
self.deps = None
self.features = None
def init (self, p):
global mypluginref
mypluginref = p
# init sounds
try:
self.sounds['windowGrab'] = AsyncMp3Sound(self.soundPath + 'sound4.mp3')
self.sounds['windowUngrab'] = AsyncMp3Sound(self.soundPath + 'sound6.mp3')
except Exception, ex:
print "Error: "+str(ex)
return False
return True
def fini (self):
return
def initDisplay (self, d):
return True
def finiDisplay (self, d):
pass
def windowGrabNotify(self, window, x, y, state, mask):
print "soundfx.windowGrabNotify ..."
#self.sounds['windowGrab'].run()
self.sounds['windowGrab'].start()
def windowUngrabNotify(self, window):
print "soundfx.windowUngrabNotify ..."
#self.sounds['windowUngrab'].run()
self.sounds['windowUngrab'].start()
def initScreen (self, screen):
screen.wrap(compiz.WindowGrabNotify, self, "windowGrabNotify")
screen.wrap(compiz.WindowUngrabNotify, self, "windowUngrabNotify")
return True
def finiScreen (self, screen):
screen.unwrap(compiz.WindowGrabNotify)
screen.unwrap(compiz.WindowUngrabNotify)
pass
def initWindow (self, w):
#w.paint.saturation = int (0.75 * compiz.COLOR)
return True
def finiWindow (self, w):
return
def getDisplayOptions (self, d):
myopts = compiz.CompOptionList ( \
compiz.CompOption ('sound_grab',
compiz.CompOptionTypeString,
"Grab sound",
"Sound when grabbing a window",
"none"
)
)
return myopts
def setDisplayOption (self, d, name, value):
print "set display option ** inside plugin ** %s = %s" % (name, value)
return True
RYX
April 11th, 2007, 09:31 PM
Did you implement the readImageToTexture-function somewhere? Or did you add it to the constructor?
mikedee
April 12th, 2007, 12:06 PM
Did you implement the readImageToTexture-function somewhere? Or did you add it to the constructor?
No - I didn't do that one.
I'll see about adding it, like you say it would either be in the CompTexture constructor, or as a static method like CompTexture.fromImage (image_file)
I was unsure about the wrappable fileToImage functions but I assume readImageToTexture uses them (like with file modification notifications)
mikedee
April 12th, 2007, 01:22 PM
OK - I have added it as a method of a compscreen object.
All of the texture functions need a screen too, so it makes sense to have these objects closely related.
I haven't tested it at all, it may or may not work. If you have problems just post the script and I can work with that. Even if you do not have problems, please post it and I can check for memory leaks.
RYX
April 12th, 2007, 04:52 PM
Cool, thanks! It seems to work (at least it doesn't crash), but I have problems with setting screen.backgroundTexture ... It is read-only. Is there any reason (or equivalent) for that or is it just not implemented yet?
mikedee
April 12th, 2007, 05:36 PM
Cool, thanks! It seems to work (at least it doesn't crash), but I have problems with setting screen.backgroundTexture ... It is read-only. Is there any reason (or equivalent) for that or is it just not implemented yet?
Yeah - most things are read only... I assume you are trying to do wallpaper in python ;)
Ill make that writable, although I don't think you should be doing that... Painting over the background would sound like a better idea.
RYX
April 12th, 2007, 05:48 PM
Yes, you got me :) ... I want to make a python-wallpaper-plugin with support for plane (so also taking vsize into account). I just did a 1:1 port so I missed the writeable backgroundTexture. Do you know any details on how I can paint over the background? Drawing it over using opengl calls? So creating a quad and setting the bgimage-texture as its texture?
Another thing - I already have a working desktopclick-plugin in python but I can't find the toolkitAction-function. Did you plan some other way to do that or is it just not implemented yet? I'd like to try making a python-version of the desktop-menu ...
(I am collecting my thoughts and ideas while playing with those plugins and the python-API and I already have a nice list of improvement-ideas. But I don't want to bother you with all of them yet :D ...)
:)
mikedee
April 12th, 2007, 06:31 PM
Yes, you got me :) ... I want to make a python-wallpaper-plugin with support for plane (so also taking hsize into account). I just did a 1:1 port so I missed the writeable backgroundTexture. Do you know any details on how I can paint over the background? Drawing it over using opengl calls? So creating a quad and setting the bgimage-texture as its texture?
It should work but you need to assign the name to the name rather than the entire texture. Something like this should work.
s.background.texture.name = my_texture.name
Another thing - I already have a working desktopclick-plugin in python but I can't find the toolkitAction-function. Did you plan some other way to do that or is it just not implemented yet? I'd like to try making a python-version of the desktop-menu ...
I have added it as a method for CompScreen like this
CompScreen.toolkitAction (actionAtom, eventTime, windowId, data0, data1, data2)
All of the arguments are ints. CurrentTime == 0
(I am collecting my thoughts and ideas while playing with those plugins and the python-API and I already have a nice list of improvement-ideas. But I don't want to bother you with all of them yet :D ...)
No problems :) Make a list and Ill see what I can do, most things are fairly quick jobs, I just haven't done it all yet.
RYX
April 12th, 2007, 09:55 PM
Hmm - I can't get the toolkitAction to send the data ... This code should work but the action doesn't get send. Other actions like the run-command are received properly by the cmenu.py. I can see no real errors - maybe you can see what's wrong (or test if it is possibly a problem of your plugin and the toolkitAction is not sent the way it should) ...
EDIT: I updated the code and it should be working. The menu-file uses the screenlet's XmlMenu-class - that should be replaced with a common gtk-menu.
The plugin:import compiz
mypluginref = None
#print dir(compiz)
#print dir(compiz.CompDisplay)
#print dir(compiz.CompScreen)
#print dir(compiz.CompWindow)
#print dir(compiz.CompXEvent)
#print compiz.CompWindowTypeDesktopMask
class pydesktopmenuPlugin:
def __init__(self):
self.name = "pydesktopmenu"
self.shortDesc = "Desktopmenu (python)"
self.longDesc = "Desktop-menu"
self.getScreenOptions = None
self.setScreenOption = None
self.initWindow = None
self.finiWindow = None
self.deps = None
self.features = None
def init (self, p):
global mypluginref
mypluginref = p
return True
def fini (self):
return
def showMenu(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
sPriv = screen.getPrivateData (mypluginref)
if sPriv['pointerOnDesktop'] == True:
#if compiz.otherScreenGrabExists("expo", "rotate", 0):
print "ATOM "+(str(display.atoms['toolkitActionMainMenuAtom']))
print "WIN "+str(screen.root)
# return False
time = options.dict['time'].value
print "Show Menu %i" % time
screen.toolkitAction(display.atoms['toolkitActionMainMenuAtom'],
time, screen.root, 5, 5, 5)
return True
return False
def initDisplay (self, display):
display.wrap(compiz.HandleEvent, self, "handleEvent")
return True
def finiDisplay (self, display):
display.unwrap(compiz.HandleEvent)
return
def handleEvent (self, display, xevent):
# always wrap handleEvent in a try/except block to avoid losing
# all input when things crash in here
try:
# get private
#print xevent
sPriv = display.getPrivateData (mypluginref)
# do own event-handling
if xevent.type in (compiz.EnterNotify, compiz.LeaveNotify):
print "Enter/Leave"
screen = display.findScreen(xevent.root)
if screen:
sPriv = screen.getPrivateData (mypluginref)
if xevent.root == xevent.window:
sPriv['pointerOnDesktop'] = True
print "ON DESKTOP (root=win)"
else:
win = screen.findWindow(xevent.window)
if win and win.type & compiz.CompWindowTypeDesktopMask:
print "ON DESKTOP"
sPriv['pointerOnDesktop'] = True
else:
sPriv['pointerOnDesktop'] = False
except Exception, ex:
print "Exception in handleEvent: " + str(ex)
# call base
display.unwrap(compiz.HandleEvent)
display.handleEvent(xevent)
display.wrap(compiz.HandleEvent, self, "handleEvent")
return True
def initScreen (self, screen):
# get private for screen
sPriv = screen.getPrivateData (mypluginref)
sPriv['pointerOnDesktop'] = False
return True
def finiScreen (self, screen):
pass
def getDisplayOptions (self, display):
myopts = compiz.CompOptionList ( \
compiz.CompOption ('show_menu',
compiz.CompOptionTypeAction,
"Show Menu",
"Show desktop menu",
compiz.CompAction ( \
initiate=(self, "showMenu"),
terminate=None,
button="Button1",
key=None,
bell=False,
edgeMask=None
)
)
)
return myopts
def setDisplayOption (self, d, name, value):
print "set display option ** inside plugin ** %s = %s" % (name, value)
return True
And the "receiver" (has no real menu yet):#!/usr/bin/env python
import gtk
import os
import screenlets.XmlMenu # for the XML-menu
# options
MENU_FILENAME = 'cmenu.xml'
# atoms
actionAtom = gtk.gdk.atom_intern('_COMPIZ_TOOLKIT_ACTION', False)
mainMenuAtom = gtk.gdk.atom_intern('_COMPIZ_TOOLKIT_ACTION_MAIN_M ENU', False)
class DesktopMenuApp:
menu = None
def __init__(self):
self.menu = screenlets.XmlMenu.create_menu_from_file(MENU_FILE NAME,
self.xmlmenu_callback)
def popup_menu(self):
self.menu.popup(None, None, None, 0, 0)
def event_callback(self, event, data=None):
#print "Event: " + str(event)
if event.type == gtk.gdk.CLIENT_EVENT:
#print "Type: "+str(event.message_type)
if event.message_type == actionAtom and event.data_format == 32:
#print "POPUP MENU OR DO SOME OTHER ACTION HERE..."
#print "Data: "+str(event.data[0])
"""if event.message_type == actionAtom and \
event.data_format == 32 and \
event.data[0] == mainMenuAtom:"""
self.popup_menu()
#gtk.main_do_event(event)
else:
gtk.main_do_event(event)
def xmlmenu_callback(self, item, id):
print "ID: "+str(id)
# now check id
if id[:5]=="exec:":
# execute shell command
os.system(id[5:] + " &")
def main(self):
gtk.init_check()
# add event-handler to gdk
gtk.gdk.event_handler_set(self.event_callback)
# start gtk mainloop
gtk.main()
# run app
if __name__ == '__main__':
print "Starting menu app"
app = DesktopMenuApp()
app.main()
:)
RYX
April 12th, 2007, 11:01 PM
:D ... I found the problem with the toolkitAction. In compizscreen.c/compizCompScreenToolkitAction the window argument has to be a PyLong instead of a PyInt ...
:)
mikedee
April 13th, 2007, 12:43 AM
:D ... I found the problem with the toolkitAction. In compizscreen.c/compizCompScreenToolkitAction the window argument has to be a PyLong instead of a PyInt ...
:)
Thanks :)
I have uploaded a new version which I think corrects the error, I also changed window.id to be a long.
RYX
April 13th, 2007, 01:11 AM
Here is my wish/suggestions-list :D ... I'll try to help where I can to implement those.
- get rid of mypluginref and make it a property or some hidden attribute
- use "screen.wrap(compiz.PaintScreen, self.paintScreen)" instead of
"screen.wrap(compiz.PaintScreen, self, 'paintScreen')"
- put event-constants into "CompizEvent" or "Event" instead of "compiz" module
(e.g. compiz.EnterNotify should be CompizEvent.EnterNotify) and generally
categorize constants more logical in smaller groups instead of having all
in compiz-module
- add simple alternative to wrap/call/unwrap (like the decorator-method I
sent to the list a while ago), for certain special cases wrap/call/unwrap
can still be used
- add global VERSION-constant to python-API to allow scripts to check the
API-version (ABIVERSION is too complicated because it changes in an
unpredictable manner and requires to much low-level knowledge)
- initDisplay/finiDisplay should become optional, too
- it should be not needed to explicitly set all unused callbacks to None
within the constructor, the pluginloader should handle undefined callbacks
by assigning some stub-function instead
- otherScreenGrabExists is missing?
:)
mikedee
April 13th, 2007, 01:20 AM
- get rid of mypluginref and make it a property or some hidden attribute
I think this might be possible if the plugins can extend CompPlugin, I am not sure how it would work just yet.
- use "screen.wrap(compiz.PaintScreen, self.paintScreen)" instead of
"screen.wrap(compiz.PaintScreen, self, 'paintScreen')"
I tried that originally and it didn't work (I seemed to be losing reference to the object instance)
- put event-constants into "CompizEvent" or "Event" instead of "compiz" module
(e.g. compiz.EnterNotify should be CompizEvent.EnterNotify) and generally
categorize constants more logical in smaller groups instead of having all
in compiz-module
This should be easy enough
- add simple alternative to wrap/call/unwrap (like the decorator-method I
sent to the list a while ago), for certain special cases wrap/call/unwrap
can still be used
Amaranth mentioned maybe just losing wrap and unwrap and automatically doing this before and after the function. I will look into how possible this is. It would still require you to call the core function.
-add global VERSION-constant to python-API to allow scripts to check the
API-version (ABIVERSION is too complicated because it changes in an
unpredictable manner and requires to much low-level knowledge)
Ill probably do this once the metadata stuff is ready, then I can do it all at once.
- initDisplay/finiDisplay should become optional, too
Seems reasonable
- it should be not needed to explicitly set all unused callbacks to None
within the constructor, the pluginloader should handle undefined callbacks
by assigning some stub-function instead
OK - Ill do that
- otherScreenGrabExists is missing?
CompScreen.otherGrabExist (I normally lose the repetitiveness from function names)
mikedee
April 13th, 2007, 01:53 AM
I have uploaded a new version where all the callbacks are optional.
I cannot get your desktop click plugin to work though, can you?
RYX
April 13th, 2007, 01:54 AM
- get rid of mypluginref and make it a property or some hidden attribute
I think this might be possible if the plugins can extend CompPlugin, I am not sure how it would work just yet.
What exactly do you do with mypluginref and what is it needed for? Can it make a difference to store it inside the class?
- add simple alternative to wrap/call/unwrap (like the decorator-method I
sent to the list a while ago), for certain special cases wrap/call/unwrap
can still be used
Amaranth mentioned maybe just losing wrap and unwrap and automatically doing this before and after the function. I will look into how possible this is. It would still require you to call the core function.
The decorator-way would offer that as an alternative while still having the possibility to manually wrap/unwrap. The decorator-function could either wrap before or after the function execution to keep a little flexibility. The call to the original function is common in such case (comparable to the call to a parent's class), unusual is only wrap/unwrap.
- otherScreenGrabExists is missing?
CompScreen.otherGrabExist (I normally lose the repetitiveness from function names)
I thought I tried that - gonna try again :) ...
The desktopmenu-plugin is fully working. Wallpaper causes me some headache because assigning the textures still doesn't work as it should ...
:)
RYX
April 13th, 2007, 01:58 AM
I updated my above post with the pydesktopmenu-plugin. The version works for me, you only need to replace the xml-based menu with a normal gtk-menu (I used the screenlet's XmlMenu for testing).
:)
mikedee
April 13th, 2007, 02:05 AM
The desktopmenu-plugin is fully working. Wallpaper causes me some headache because assigning the textures still doesn't work as it should ...
Post this and Ill see if its something to do with the python plugin
mikedee
April 13th, 2007, 11:12 AM
The desktopmenu-plugin is fully working. Wallpaper causes me some headache because assigning the textures still doesn't work as it should ...
Sorry, my fault.
I have uploaded a new version which allows you to set the backgroundTexture. You should be able to do something like this.
s.backgroundTexture = ws.bgTextures[s.x]
mikedee
April 13th, 2007, 12:04 PM
Does anyone know how I can autogenerate some class documentation?
All of the functions have a doc string which goes with them so I assume I can generate those colourful python docs from them?
mikedee
April 13th, 2007, 01:13 PM
I have just uploaded a new version which includes CompOption.initiate/terminate (CompOptionList list). This means you should be able to do plugins like mousegestures. You dont need to check if there is a method, just call it. It returns None if its not an action option.
It also now updates the cobject on copy which is probably not much interest.
RYX
April 13th, 2007, 01:41 PM
Does anyone know how I can autogenerate some class documentation?
All of the functions have a doc string which goes with them so I assume I can generate those colourful python docs from them?
Normally, you can use doxygen for that but it could get difficult in this case (afaik doxygen needs python-code to parse). I guess it would be quite simple to write a python-script which dumps out a nice XML/HTML-string containing the full documentation for all classes within a module ... (Your docstrings aren't that informative yet, anyway :D ... )
mikedee
April 13th, 2007, 01:48 PM
Normally, you can use doxygen for that but it could get difficult in this case (afaik doxygen needs python-code to parse). I guess it would be quite simple to write a python-script which dumps out a nice XML/HTML-string containing the full documentation for all classes within a module ...
How do they produce the docs for the embedded modules? All I really need for now is one of those colourful python doc things which just lists the objects and their properties. I think there should be a special command in a module somewhere. I could then write a special plugin which outputs this html.
(Your docstrings aren't that informative yet, anyway :D ... )
Yeah - they are based on the compiz ones ;)
EDIT : I think this is what I am looking for
http://docs.python.org/lib/module-pydoc.html
mikedee
April 13th, 2007, 02:08 PM
Here they are :)
http://www.anykeysoftware.co.uk/compiz/pydoc/compiz.html
And here is the most simple compiz python plugin ever
import compiz
import pydoc
class docPlugin:
def __init__(self):
self.name = "doc"
self.shortDesc = "Writes out HTML documentation for modules"
self.longDesc = "Writes out HTML documentation for modules"
pydoc.writedoc (compiz)
return
RYX
April 13th, 2007, 02:18 PM
Very nice :) ...
Looks like I now can reduce the size of my testing plugins by 20 lines each.
btw: Mine is smaller :D ...import compiz
import pydoc
class docPlugin:
name = "doc"
shortDesc = "Writes out HTML documentation for modules"
longDesc = "Writes out HTML documentation for modules"
def __init__(self):
pydoc.writedoc(compiz)
:)
RYX
April 13th, 2007, 02:24 PM
One small thing I wanted to mention since two weeks - can you please add another "PyErr_Print();" between line 50/51 in loader.c? Otherwise there is no real info about errors during module-compilation ... Thanks.
EDIT: Forget it - I was in the wrong line, you already added it :D ...
:)
mikedee
April 13th, 2007, 02:36 PM
One small thing I wanted to mention since two weeks - can you please add another "PyErr_Print();" between line 50/51 in loader.c? Otherwise there is no real info about errors during module-compilation ... Thanks.
EDIT: Forget it - I was in the wrong line, you already added it :D ...
:)
Hmm, there seemed to be certain calls missing so I have added a load more just to be sure. Redownload and see if its any better/
RYX
April 13th, 2007, 02:41 PM
Thanks, I'll try it immediately. Did you change anything with the privates (well, I guess you did because mypluginref is gone - big thanks for that btw)?
(Did you notice that the documentation doesn't contain the function's arguments?)
:)
mikedee
April 13th, 2007, 02:45 PM
Thanks, I'll try it immediately. Did you change anything with the privates (well, I guess you did because mypluginref is gone - big thanks for that btw)?
No I didnt :)
mypluginref is gone for the doc plugin because it does not use privates.
I think I might change it so that you can do self.getScreenPrivate (s) but it will take a few days and I think your plugin will have to extend CompPlugin.
(Did you notice that the documentation doesn't contain the function's arguments?)
It makes sense because when I define methods I only specify METH_VARARGS or METH_NOARGS. They are all by default varargs, not sure how to specify fixed args since it doesnt seem to be documented.
RYX
April 13th, 2007, 02:53 PM
Wouldn't it be possible to pass "self" (which also contains the plugin-reference) to the CompScreen.getPrivateData() instead of defining a global reference and pass that? Maybe I misunderstand the problem, tough ...
And you're right - for METH_VARGARS it makes sense to only contain "(...)" as args ... but it is still quite problematic for the python-coder if he doesn't know which args a function takes. I will read through the docs and see if there is a way to define fixed args, maybe I can find something.
:)
mikedee
April 13th, 2007, 03:00 PM
Wouldn't it be possible to pass "self" (which also contains the plugin-reference) to the CompScreen.getPrivateData() instead of defining a global reference and pass that? Maybe I misunderstand the problem, tough ...
I think it should be possible to do either, its all down to preference really. Thet are both compiz-like because it could be interpreted like this
self.getScreenPrivate (s) == PLUGIN_SCREEN (s)
or
s.getPrivateData (self) basically returns a structure similar to PluginScreen (ie a private data store)
Which do you prefer?
RYX
April 13th, 2007, 03:05 PM
I think the second one makes more sense because you get the screenprivate for self from the screen (instead of getting it from self).
EDIT: And how about calling them ScreenPrivate and DisplayPrivate (instead of the *Screen-naming from C)? Applies better to python because we use it as private-data storage only ...
:)
RYX
April 13th, 2007, 04:51 PM
Here is my unfinished python-version of the wallpaper-plugin. It doesn't work yet and is only a 1:1 port of the C-plugin (no vsize used yet). I think the problem is somewhere outside my script so maybe you can see what's wrong ... It causes a pretty weird flickering background.
EDIT: Updated to the latest version. Works, but causes nasty problems.
import compiz
class pywallpaperPlugin:
name = "pywallpaper"
shortDesc = "Wallpaper (python)"
longDesc = "Set background wallpapers - python version"
images = ['/home/ryx/pictures/ryx_bg_1.png',
'/home/ryx/pictures/ryx_bg_1_blue.png',
'/home/ryx/Documents/SVG/skull_background-1.svg']
def paintBackground(self, screen, region, mask):
# get private
sPriv = screen.getPrivateData (self)
# draw background
if screen.backgroundTexture.name != sPriv['textures'][screen.x].name:
screen.backgroundTexture = sPriv['textures'][screen.x]
screen.damage()
# call base
screen.unwrap (compiz.PaintBackground)
screen.paintBackground (region, mask)
screen.wrap (compiz.PaintBackground, self, "paintBackground")
def initScreen (self, screen):
# get private for screen and init textures
sPriv = screen.getPrivateData (self)
sPriv['textures'] = []
# if more viewports than images, fill array with last entry
print self.images
numImages = len(self.images)
numViewports = screen.hsize * screen.vsize
print "Viewports: %i, images: %i" % (numViewports, numImages)
if numImages < numViewports:
lastImage = self.images[numImages-1]
for i in xrange(numViewports - numImages):
self.images.append(lastImage)
print self.images
# load/create textures
try:
for i in xrange(numViewports):
t = screen.readImageToTexture(self.images[i])
print t
sPriv['textures'].append(t)
except:
return False
# wrap paintBackground
screen.wrap (compiz.PaintBackground, self, "paintBackground")
return True
def finiScreen (self, screen):
# cleanup textures (needed??)
sPriv = screen.getPrivateData (self)
del sPriv['textures']
# unwrap and redraw
screen.unwrap (compiz.PaintBackground)
screen.damage()
"""def getDisplayOptions (self, display):
myopts = compiz.CompOptionList ( \
compiz.CompOption ('image_list',
compiz.CompOptionTypeString,
"Wallpaper Images",
"Wallpaper images to show",
'/usr/share/compiz/background.png'
)
)
return myopts"""
mikedee
April 13th, 2007, 06:36 PM
I have just uploaded a new version which just makes the background go white.
I am sure that must mean its painting the texture correctly but its not loading the image somehow. Ill have a play to see if I can get it working any more.
I have removed the mypluginref, just use self from now on.
mikedee
April 13th, 2007, 07:58 PM
I found the bug in setting the backgroundTexture (or half of it anyway)
I have uploaded a new version which works with the wallpaper plugin but not on viewport 1, that just displays junk.
EDIT : I found its normal wallpaper buggyness :) If you unload and reload the plugin then it solves the problem.
RYX
April 13th, 2007, 09:08 PM
I have just uploaded a new version which just makes the background go white.
I am sure that must mean its painting the texture correctly but its not loading the image somehow. Ill have a play to see if I can get it working any more.
I updated the script in my above post. It seems to work but it causes several problems - e.g. black window bugs or entirely invisible window content. When I activate the plugin, all images show up correctly but when I switch to another viewport all images on all viewports show the same image ... I don't think it is a problem of loading textures, it must be something internal with paintBackground.
I have removed the mypluginref, just use self from now on.
Great work - scripts look much better now (and about 10 lines less code). It starts feeling like higher-level coding :D ...
:)
mikedee
April 13th, 2007, 09:18 PM
I have just uploaded a new version which just makes the background go white.
I am sure that must mean its painting the texture correctly but its not loading the image somehow. Ill have a play to see if I can get it working any more.
I updated the script in my above post. It seems to work but it causes several problems - e.g. black window bugs or entirely invisible window content. When I activate the plugin, all images show up correctly but when I switch to another viewport all images on all viewports show the same image ... I don't think it is a problem of loading textures, it must be something internal with paintBackground.
Thats strange because its working perfectly here (even with multiple images) the only problem is the initial load/unload thing.
Here is the version I am using, maybe I changed something, but I dont think so.
import compiz
class pywallpaperPlugin:
name = "pywallpaper"
shortDesc = "Wallpaper (python)"
longDesc = "Set background wallpapers - python version"
images = ['/home/mike/Desktop/image1.png', '/home/mike/Desktop/image2.png', '/home/mike/Desktop/image3.png']
def __init__(self):
pass
def paintBackground(self, screen, region, mask):
# get private
sPriv = screen.getPrivateData (self)
# draw background
if screen.backgroundTexture.name != sPriv['textures'][screen.x].name:
screen.backgroundTexture = sPriv['textures'][screen.x]
screen.damage()
# call base
screen.unwrap (compiz.PaintBackground)
screen.paintBackground (region, mask)
screen.wrap (compiz.PaintBackground, self, "paintBackground")
def init (self, p):
return True
def initScreen (self, screen):
# get private for screen and init textures
sPriv = screen.getPrivateData (self)
sPriv['textures'] = []
# if more viewports than images, fill array with last entry
print self.images
numImages = len(self.images)
numViewports = screen.hsize * screen.vsize
print "Viewports: %i, images: %i" % (numViewports, numImages)
if numImages < numViewports:
lastImage = self.images[numImages-1]
for i in xrange(numViewports - numImages):
self.images.append(lastImage)
print self.images
# load/create textures
try:
for i in xrange(numViewports):
t = screen.readImageToTexture(self.images[i])
sPriv['textures'].append(t)
except:
return False
# wrap paintBackground
screen.wrap (compiz.PaintBackground, self, "paintBackground")
return True
def finiScreen (self, screen):
screen.unwrap (compiz.PaintBackground)
screen.damage()
RYX
April 13th, 2007, 09:39 PM
I still have those black windows - strange ...
Also there seems to be a very critical memory leak - a few times loading and reloading the wallpaper-plugin causes compiz to use more than 200MB of virtual memory (normal are about 50-60 here). I think the textures need to be manually freed (or maybe freed in their internal constructor?).
EDIT: Could it be that the textures are filling the video memory because they are not unloaded properly?
defer
April 13th, 2007, 10:24 PM
Hi, thanks for the loader.
Is there any chance you can throw this under version control? It would be easier to follow the changes.
Also, you are using a git repo right? Even if it's local, it would be nice to be able to have a look to the development history.
mikedee
April 14th, 2007, 01:33 AM
Hi, thanks for the loader.
Is there any chance you can throw this under version control? It would be easier to follow the changes.
Also, you are using a git repo right? Even if it's local, it would be nice to be able to have a look to the development history.
I am trying to get it to a reasonable level at the moment, I have a few other things to do then I will put it in git.compiz.org. There will probably be a few things that just do not work and I am not very happy with the memory leaks at the moment.
Hopefully next week Ill get it done :)
mikedee
April 14th, 2007, 01:38 AM
I still have those black windows - strange ...
Also there seems to be a very critical memory leak - a few times loading and reloading the wallpaper-plugin causes compiz to use more than 200MB of virtual memory (normal are about 50-60 here). I think the textures need to be manually freed (or maybe freed in their internal constructor?).
EDIT: Could it be that the textures are filling the video memory because they are not unloaded properly?
I have a few other shutdown problems which this might be related to. I have to make sure that all python plugins are unloaded when the python plugin is unloaded, since this happens each time the active plugins are changed its a bit tricky.
I look at the resident memory when looking at leaks, it is very steady with pywallpaper loaded. Inactive really sucks the memory, there is a leak somewhere with handleEvent.
mikedee
April 14th, 2007, 02:20 AM
I have uploaded a new version which fixes the memory leak when unloading and reloading.
RYX
April 14th, 2007, 02:30 AM
Thank you. You're amazingly fast today :D ... (The latest one fixes the problem with the wrong textures and pywallpaper works like wallpaper. Simply cool ...)
Another thing - the latest git-version of your dbus-plugin seems to crash compiz when I try to query the active_plugins when the python-plugin is loaded ... My options-tool entirely locks up my system when I launch it with python-plugin enabled. I simply use the same compiz_call-method from the compiz-profiles app and call the "list"-method with no args ...
EDIT: DBus-problem seems to be solved - for whatever reason ...
:)
RYX
April 14th, 2007, 02:55 AM
CompOptionTypeList doesn't work (unhandled option type 7) ... :)
(but that has time until tomorrow :D)
RYX
April 14th, 2007, 03:51 AM
I had another thought while looking at the code :) ...
How about adding this:CompWindow.isDesktop()
as an alternative for this:CompWindow.type & compiz.CompWindowTypeDesktopMask
... and maybe also for other cases (like isDock, isMenu, isWidget, ...). Would make the code easier to read and I guess it would give a better performance (at least it shouldn't be slower) ...
EDIT: or maybe just call it "WindowType.Desktop" instead of "CompWindowTypeDesktopMask"?
:)
defer
April 14th, 2007, 01:20 PM
Sounds definitely easier, and I believe it should go that way since the whole point of the python load is making it easier to develop compiz plugins.
One thing that is lost however is coherence with the code and if plugins are to be ported to C (for various reasons this is likely to happen for some plugins developed in the future, such as efficiency) it would be harder. But as long as this stuff is well documented it shouldn't be a problem.
Keep it up
mikedee
April 14th, 2007, 05:13 PM
I had another thought while looking at the code :) ...
How about adding this:CompWindow.isDesktop()
as an alternative for this:CompWindow.type & compiz.CompWindowTypeDesktopMask
... and maybe also for other cases (like isDock, isMenu, isWidget, ...). Would make the code easier to read and I guess it would give a better performance (at least it shouldn't be slower) ...
I think this sounds like a good ide, but what about properties like CompWindow.typeDesktop?, then we could add other things without confusing them, eg. CompWindow.stateMaximized which are done with a bitmask too.
RYX
April 14th, 2007, 06:40 PM
I guess it depends on everyone's personal taste whether he prefers properties or functions. Both ways are extensible - we could also add things like isMaximized, isMinimized, isActive, ... either as property or as function. Behind the scenes it should be the same amount of code anyway.
I think in other libs (e.g. gtk) it is common to wrap these things (e.g. CompWindowTypeDesktopMask) in an enum-class like "CompWindowType.Desktop" or "CompWindowState.Maximized", but using the functions we could keep the C-equivalent syntax (for educational purpose and ease of porting) while offering a friendly higher-level alternative (without loss of performance).
Another question - did you implement "moveScreenViewport" and "clearTargetOutput" somewhere?
:)
mikedee
April 14th, 2007, 07:29 PM
I guess it depends on everyone's personal taste whether he prefers properties or functions. Both ways are extensible - we could also add things like isMaximized, isMinimized, isActive, ... either as property or as function. Behind the scenes it should be the same amount of code anyway.
I think in other libs (e.g. gtk) it is common to wrap these things (e.g. CompWindowTypeDesktopMask) in an enum-class like "CompWindowType.Desktop" or "CompWindowState.Maximized", but using the functions we could keep the C-equivalent syntax (for educational purpose and ease of porting) while offering a friendly higher-level alternative (without loss of performance).
OK - Ill try to do something like this, it might be better to have the properties then we can avoid bitmasks totally.
Another question - did you implement "moveScreenViewport" and "clearTargetOutput" somewhere?
I do now :) (CompScreen.moveViewport and CompDisplay.clearTargetOutout). Ive just uploaded a new version which has cleared up a lot of the memory problems.
RYX
April 14th, 2007, 07:56 PM
I guess it depends on everyone's personal taste whether he prefers properties or functions. Both ways are extensible - we could also add things like isMaximized, isMinimized, isActive, ... either as property or as function. Behind the scenes it should be the same amount of code anyway.
I think in other libs (e.g. gtk) it is common to wrap these things (e.g. CompWindowTypeDesktopMask) in an enum-class like "CompWindowType.Desktop" or "CompWindowState.Maximized", but using the functions we could keep the C-equivalent syntax (for educational purpose and ease of porting) while offering a friendly higher-level alternative (without loss of performance).
OK - Ill try to do something like this, it might be better to have the properties then we can avoid bitmasks totally.
Great :) ... I think doing the bitmap-mask-comparison in python is generally slower than doing it within a C-function (without args) which is then called from python. I guess performance is quite important here because these functions are called very often (in speed-critical situations).
Calling those functions as properties (like isDesktop or isMaximized) is absolutely OK, but I think functions are more python-like than properties (properties are more common in JavaScript) - but since we are using camel-case (which is also python-unlike) this shouldn't be too bad. I am happy enough that you agree to do it like this and I leave the decision to you :D ...
Another question - did you implement "moveScreenViewport" and "clearTargetOutput" somewhere?
I do now :) (CompScreen.moveViewport and CompDisplay.clearTargetOutout). Ive just uploaded a new version which has cleared up a lot of the memory problems.
Cool - will try it right away. There was also a problem with crashing plugins. I had a plugin which wrapped handleEvent during initDisplay and then crashed on initScreen. The handleEvent-callback wasn't properly unloaded after initScreen raised an exception and stayed active within the loader-plugin.
:)
mikedee
April 14th, 2007, 08:09 PM
There was also a problem with crashing plugins. I had a plugin which wrapped handleEvent during initDisplay and then crashed on initScreen. The handleEvent-callback wasn't properly unloaded after initScreen raised an exception and stayed active within the loader-plugin.
Yes, that would cause a crash :)
I think thats probably core's fault (unless there is an obvious bug somewhere). Core should call finiDisplay if initScreen fails for a plugin (maybe it does - Ill have a look). If you were missing the unwrap then it would cause problems.
RYX
April 14th, 2007, 08:14 PM
While you're at it, can you add "CompWindow.defaultViewport" (defaultViewportForWindow), please? Thanks in advance ... :D
RYX
April 14th, 2007, 08:22 PM
And is it already possible to access the data of an XEvent? I need to access the data like this: event->xclient.data.l[0]
but the CompXEvent-class has no data-field (yet?) ... I guess it would be enough to have the data-attribute as an array of ints (or maybe a separate class with long/int/* attribs?). I can have a look at it but I guess you are faster.
:)
mikedee
April 14th, 2007, 08:26 PM
While you're at it, can you add "CompWindow.defaultViewport" (defaultViewportForWindow), please? Thanks in advance ... :D
OK - Thats done now, the online docs have been updated too
mikedee
April 14th, 2007, 08:41 PM
BTW - Did you ever get to the bottom of the black windows with the wallpaper plugin?
mikedee
April 14th, 2007, 08:43 PM
And is it already possible to access the data of an XEvent? I need to access the data like this: event->xclient.data.l[0]
but the CompXEvent-class has no data-field (yet?) ... I guess it would be enough to have the data-attribute as an array of ints (or maybe a separate class with long/int/* attribs?). I can have a look at it but I guess you are faster.
:)
I think the data attribute is 4 longs (or 3), so should be easy to return as a list.
Ill have another sweep through the XEvent structure to see if theres anything else useful I can add.
mikedee
April 14th, 2007, 08:45 PM
Also if you have scripts which are testing things or ones which crash, please send them to me so I can put together a test suite group of plugins.
RYX
April 14th, 2007, 08:49 PM
BTW - Did you ever get to the bottom of the black windows with the wallpaper plugin?
No, they seem to appear only when I often load/unload the pywallpaper. I have it running the whole day now and it works really well. Instead I have "white window bugs" from time to time, also with the C-version, but that is fixed by minimize/maximize. Somehow the way of setting the textures isn't perfect (as the original author noted in the C-plugin).
But can it be that the latest compiz git is awfully slow and cpu-hungry during window-movement? Usually moving windows doesn't use any cpu, currently moving windows raises my cpu-usage to 50% ... I first thought it is the python-script or the loader, but it is compiz itself. Do you know any reasons for that?
RYX
April 14th, 2007, 08:53 PM
And is it already possible to access the data of an XEvent? I need to access the data like this: event->xclient.data.l[0]
but the CompXEvent-class has no data-field (yet?) ... I guess it would be enough to have the data-attribute as an array of ints (or maybe a separate class with long/int/* attribs?). I can have a look at it but I guess you are faster.
:)
I think the data attribute is 4 longs (or 3), so should be easy to return as a list.
Ill have another sweep through the XEvent structure to see if theres anything else useful I can add.
I think the message_type is also needed to know if we get an array of 20 bytes (8 ), 10 shorts (16) or 5 longs (32). I don't know what parts of the other events are useful or needed but the ClientMessage is a very important one because it is used for reading the window-attributes (as far as I understood).
mikedee
April 15th, 2007, 01:34 AM
BTW - Did you ever get to the bottom of the black windows with the wallpaper plugin?
No, they seem to appear only when I often load/unload the pywallpaper. I have it running the whole day now and it works really well. Instead I have "white window bugs" from time to time, also with the C-version, but that is fixed by minimize/maximize. Somehow the way of setting the textures isn't perfect (as the original author noted in the C-plugin).
I also have the white windows bug, not sure what could be causing it. I think I have found something which will help with the 'initial viewport messed up' bug. I check for screen.backgroundLoaded before swapping the textures. It means that I do not have to load and unload the plugin to see the first wallpaper.
But can it be that the latest compiz git is awfully slow and cpu-hungry during window-movement? Usually moving windows doesn't use any cpu, currently moving windows raises my cpu-usage to 50% ... I first thought it is the python-script or the loader, but it is compiz itself. Do you know any reasons for that?
Yes, its related to something else.
mikedee
April 15th, 2007, 01:35 AM
And is it already possible to access the data of an XEvent? I need to access the data like this: event->xclient.data.l[0]
but the CompXEvent-class has no data-field (yet?) ... I guess it would be enough to have the data-attribute as an array of ints (or maybe a separate class with long/int/* attribs?). I can have a look at it but I guess you are faster.
:)
I think the data attribute is 4 longs (or 3), so should be easy to return as a list.
Ill have another sweep through the XEvent structure to see if theres anything else useful I can add.
I think the message_type is also needed to know if we get an array of 20 bytes (8 ), 10 shorts (16) or 5 longs (32). I don't know what parts of the other events are useful or needed but the ClientMessage is a very important one because it is used for reading the window-attributes (as far as I understood).
I have added all of these as well as a few other important ones that I saw. Let me know if there are any obvious ones missing.
RYX
April 15th, 2007, 02:05 AM
The handleEvent seems to be broken or I am overlooking something. My desktopmenu-plugin doesn't work anymore since about 3 versions ago. It seems to crash on handleEvent (btw: is it possible to get more info about the error when initScreen fails?).
EDIT: This script is now working like a charm :D ...
Here is the script:import compiz
# TODO:
# - menu doesn't show up after enter/leave of a Screenedge ...
#
class pydesktopmenuPlugin:
name = "pydesktopmenu"
shortDesc = "Desktopmenu (python)"
longDesc = "Desktop-menu"
def initiateShowMenu(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
sPriv = screen.getPrivateData (self)
if sPriv['pointerOnDesktop'] == True:
if screen.otherGrabExist("expo", "rotate", 0):
return False
time = options.dict['time'].value
#print "Show Menu %i" % time
screen.toolkitAction(display.atoms['toolkitActionMainMenuAtom'],
time, screen.root, 5, 5, 5)
return True
return False
def initDisplay (self, display):
display.wrap(compiz.HandleEvent, self, "handleEvent")
return True
def finiDisplay (self, display):
display.unwrap(compiz.HandleEvent)
return
def handleEvent (self, display, xevent):
# always wrap handleEvent in a try/except block to avoid losing input
try:
# check if pointer is on desktop
if xevent.type in (compiz.EnterNotify, compiz.LeaveNotify):
screen = display.findScreen(xevent.root)
if screen:
sPriv = screen.getPrivateData (self)
if sPriv != None:
if xevent.window == xevent.root:
sPriv['pointerOnDesktop'] = True
print "ON DESKTOP (win==root)"
else:
win = screen.findWindow(xevent.window)
if win and win.type & compiz.CompWindowTypeDesktopMask:
print "ON DESKTOP"
sPriv['pointerOnDesktop'] = True
else:
sPriv['pointerOnDesktop'] = False
except Exception, ex:
print "Exception in handleEvent: " + str(ex) + ex.message
# call base
display.unwrap(compiz.HandleEvent)
display.handleEvent(xevent)
display.wrap(compiz.HandleEvent, self, "handleEvent")
return True
def initScreen (self, screen):
# get private for screen
sPriv = screen.getPrivateData (self)
sPriv['pointerOnDesktop'] = False
return True
def getDisplayOptions (self, display):
myopts = compiz.CompOptionList ( \
compiz.CompOption ('show_menu',
compiz.CompOptionTypeAction,
"Show Menu",
"Show desktop menu",
compiz.CompAction ( \
initiate=(self, "initiateShowMenu"),
terminate=None,
button="Button1",
key=None,
bell=False,
edgeMask=None
)
)
)
return myopts
And the menu (which could still use some improvement) ,,,#!/usr/bin/env python
import gtk
import os
# define menu
menu_structure = [\
{'label':'Terminal', 'icon':'terminal', 'id':'exec:gnome-terminal'},
{'label':'Test2', 'id':'test2'},
{'label':'Test3', 'id':'test3'},
{}, # separator
{'label':'Test4', 'children':[\
{'label':'TestChild1', 'id':'test5'},
{'label':'TestChild2', 'id':'test6'},
{'label':'TestChild3', 'id':'test7'}]
},
{},
{'label':'Quit...', 'id':'quit'}
]
# atoms
actionAtom = gtk.gdk.atom_intern('_COMPIZ_TOOLKIT_ACTION', False)
mainMenuAtom = gtk.gdk.atom_intern('_COMPIZ_TOOLKIT_ACTION_MAIN_M ENU', False)
class DesktopMenuApp:
menu = None
def __init__(self):
self.menu = self.create_menu(menu_structure, self.menu_callback)
def popup_menu(self):
self.menu.popup(None, None, None, 0, 0)
def gdk_event_callback(self, event, data=None):
#print "Event: " + str(event)
if event.type == gtk.gdk.CLIENT_EVENT:
#print "Type: "+str(event.message_type)
if event.message_type == actionAtom and event.data_format == 32:
#print "POPUP MENU OR DO SOME OTHER ACTION HERE..."
#print "Data: "+str(event.data[0])
"""if event.message_type == actionAtom and \
event.data_format == 32 and \
event.data[0] == mainMenuAtom:"""
self.popup_menu()
#gtk.main_do_event(event)
else:
gtk.main_do_event(event)
def menu_callback(self, item, id):
print "ID: "+str(id)
# check id
if id[:5]=="exec:":
# execute shell command
os.system(id[5:] + " &")
def create_menu(self, structure, callback):
menu = gtk.Menu()
for e in structure:
if e.has_key('label'):
i = gtk.MenuItem(e['label'])
if e.has_key('id'):
i.connect('activate', callback, e['id'])
if e.has_key('children'):
submenu = self.create_menu(e['children'], callback)
i.set_submenu(submenu)
else:
i = gtk.SeparatorMenuItem()
menu.append(i)
menu.show_all()
return menu
def main(self):
gtk.init_check()
# create menu
self.menu = self.create_menu(menu_structure, self.menu_callback)
# add event-handler to gdk
gtk.gdk.event_handler_set(self.gdk_event_callback)
# start gtk mainloop
gtk.main()
# run app
if __name__ == '__main__':
print "Starting menu app"
app = DesktopMenuApp()
app.main()
:)
mikedee
April 15th, 2007, 02:24 AM
Ive just uploaded a new version which fixes that crash.
I also added CompWindow.move (dx, dy, damage, immediate) as a wrapper for moveWindow
RYX
April 15th, 2007, 02:50 AM
Thank you :D ... I updated the above post and added a simple menu (this time working without anything else).
:)
mikedee
April 15th, 2007, 11:48 AM
The desktop click plugin seems to work perfectly now (as well as the pywallpaper one - no white window bugs).
I have uploaded a new version with CompList, I have not done much testing, but here is my version of the wallpaper plugin.
EDIT : New version which works when changing the options is included in the tarball.
RYX
April 15th, 2007, 01:55 PM
Cool - now it looks the way it should. :) ... Only the vsize is missing in your version :D ...
Here is a big one - my port of the plane-plugin. It doesn't work but it also doesn't crash - it isn't animating as it should and the viewports are switched randomly, though the viewport-offsets seem to be ok. I guess it is a problem of either computeTranslation or another internal thing.
I was finally able to track down the problem with the crashes. I accidentally passed the display instead of the xevent to handleEvent and it caused a total lockup. Maybe there should be some check for that - or at least I should wrap to WHOLE handleEvent in a try/except-block, not only a part of it :D ...
EDIT: This version now works fine and bug-free with the latest python-plugin :D ... (I also added diagonal movement and a scrollTime-option) ...
#
# Desktop-Plane (python-version)
#
# Author: C-version of plane written by Søren Sandmann <sandmann@redhat.com>
# Python-port by RYX (Rico Pfaus) <ryx at ryxperience dot com>
#
#
import compiz
import OpenGL
class pyplanePlugin:
"""A python implementation of the Plane-plugin"""
name = "pyplane"
shortDesc = "Desktop-Plane (python)"
longDesc = __doc__
features = ['largedesktop']
# options
scrollTime = 250
# internals (would be display-privates in C)
draggingWindow = False
dragX = 0
dragY = 0
# -------------------------------------------------------------------------
# functions specific for this plugin
# -------------------------------------------------------------------------
def computeTranslation(self, sPriv):
elapsed = 1 - (float(sPriv['timer']) / float(self.scrollTime))
if elapsed < 0.0:
elapsed = 0.0
if elapsed > 1.0:
elapsed = 1.0
tx = (sPriv['dest_x'] - sPriv['cur_x']) * \
elapsed + sPriv['cur_x']
ty = (sPriv['dest_y'] - sPriv['cur_y']) * \
elapsed + sPriv['cur_y']
return (tx, ty)
# UNUSED (useless in python-version??? or maybe ported the wrong way...)
def getScreen(self, display, options):
return display.findScreen(options.dict['root'].value)
# originally named "moveViewport", renamed to avoid confusion with
# the internal function CompScreen.moveViewport
def movePlane(self, screen, dx, dy):
# no movement? exit
if dx==0 and dy==0:
return False
print "movePlane(%i, %i)" % (dx, dy)
# get private
sPriv = screen.getPrivateData(self)
# move or init movement
if sPriv['timeoutHandle']:
tl = self.computeTranslation(sPriv)
sPriv['cur_x'] = tl[0]
sPriv['cur_y'] = tl[1]
sPriv['dest_x'] += dx
sPriv['dest_y'] += dy
compiz.removeTimeout(sPriv['timeoutHandle'])
else:
sPriv['cur_x'] = 0.0
sPriv['cur_y'] = 0.0
sPriv['dest_x'] = dx
sPriv['dest_y'] = dy
# corrections
if sPriv['dest_x'] + screen.x > screen.hsize - 1:
sPriv['dest_x'] = screen.hsize - screen.x - 1
if sPriv['dest_x'] + screen.x < 0:
sPriv['dest_x'] = -screen.x
if sPriv['dest_y'] + screen.y > screen.vsize - 1:
sPriv['dest_y'] = screen.vsize - screen.y - 1
if sPriv['dest_y'] + screen.y < 0:
sPriv['dest_y'] = -screen.y
# init timeout
print "timeout: %i" % sPriv['timeoutHandle']
print "cur_x, cur_y: %i %i" % (sPriv['cur_x'], sPriv['cur_y'])
print "dest_x, dest_y: %i %i" % (sPriv['dest_x'], sPriv['dest_y'])
sPriv['timer'] = self.scrollTime;
sPriv['timeoutHandle'] = compiz.addTimeout(self.scrollTime,
self.endMove, screen)
# redraw
screen.damage()
def endMove(self, screen):
sPriv = screen.getPrivateData(self)
screen.moveViewport(-sPriv['dest_x'], -sPriv['dest_y'], True);
if self.draggingWindow:
print "Ended move while dragging window"
#screen.display.warpPointer(self.dragX, self.dragY)
# screen.x-(sPriv['dest_x']*screen.width),
# screen.y-(sPriv['dest_y']*screen.height) )
sPriv['dest_x'] = 0
sPriv['dest_y'] = 0
sPriv['timeoutHandle'] = 0
return False
# -------------------------------------------------------------------------
# CompAction initiate-functions (some still missing here ...)
# -------------------------------------------------------------------------
def planeLeft(self, display, action, state, options):
print "PLANE_LEFT"
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, -1, 0)
return False
def planeRight(self, display, action, state, options):
print "PLANE_RIGHT"
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, 1, 0)
return False
def planeUp(self, display, action, state, options):
print "PLANE_UP"
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, 0, -1)
return False
def planeDown(self, display, action, state, options):
print "PLANE_DOWN"
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, 0, 1)
return False
def planeDownRight(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, 1, 1)
return False
def planeDownLeft(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, -1, 1)
return False
def planeUpRight(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, 1, -1)
return False
def planeUpLeft(self, display, action, state, options):
screen = display.findScreen(options.dict['root'].value)
if screen:
self.movePlane(screen, -1, -1)
return False
# -------------------------------------------------------------------------
# wrapped-functions for this plugin
# -------------------------------------------------------------------------
def preparePaintScreen(self, screen, msSinceLastPaint):
sPriv = screen.getPrivateData(self)
sPriv['timer'] -= msSinceLastPaint
# unwrap/call/wrap
screen.unwrap(compiz.PreparePaintScreen)
screen.preparePaintScreen(msSinceLastPaint)
screen.wrap(compiz.PreparePaintScreen, self, 'preparePaintScreen')
def paintScreen(self, screen, attrib, transform, region, output, mask):
sPriv = screen.getPrivateData(self)
# if timeout is set, modify mask
if sPriv['timeoutHandle'] > 0:
mask &= ~compiz.PAINT_SCREEN_REGION_MASK # hmmmmm... ????
mask |= compiz.PAINT_SCREEN_TRANSFORMED_MASK
# unwrap/call/wrap
screen.unwrap(compiz.PaintScreen)
ret = screen.paintScreen(attrib, transform, region, output, mask)
screen.wrap(compiz.PaintScreen, self, 'paintScreen')
# return status
return ret
def paintTransformedScreen(self, screen, attrib, transform, region,
output, mask):
sPriv = screen.getPrivateData(self)
screen.unwrap(compiz.PaintTransformedScreen)
if sPriv['timeoutHandle'] > 0:
screen.display.clearTargetOutput(OpenGL.GL.GL_COLO R_BUFFER_BIT)
tl = self.computeTranslation(sPriv)
sTransform = transform # maybe not needed should we use a copy here?
dx = tl[0] * -1
dy = tl[1] * -1
vx = 0
vy = 0
while dx > 1:
dx -= 1.0
screen.moveViewport(1, 0, False)
vx += 1
while dx < -1:
dx += 1.0
screen.moveViewport(-1, 0, False);
vx -= 1
while dy > 1:
dy -= 1.0
screen.moveViewport(0, 1, False);
vy += 1
while dy < -1:
dy += 1.0
screen.moveViewport(0, -1, False);
vy -= 1
sTransform.matrixTranslate(dx, -dy, 0.0)
screen.paintTransformedScreen(attrib, sTransform, region,
output, mask)
if dx > 0:
sTransform.matrixTranslate(-1.0, 0.0, 0.0)
screen.moveViewport(1, 0, False)
else:
sTransform.matrixTranslate(1.0, 0.0, 0.0)
screen.moveViewport(-1, 0, False);
screen.paintTransformedScreen(attrib, sTransform, region,
output, mask)
if dy > 0:
sTransform.matrixTranslate(0.0, 1.0, 0.0)
screen.moveViewport(0, 1, False);
else:
sTransform.matrixTranslate(0.0, -1.0, 0.0)
screen.moveViewport(0, -1, False);
screen.paintTransformedScreen(attrib, sTransform, region,
output, mask)
if dx > 0:
sTransform.matrixTranslate(1.0, 0.0, 0.0)
screen.moveViewport(-1, 0, False)
else:
sTransform.matrixTranslate(-1.0, 0.0, 0.0)
screen.moveViewport(1, 0, False)
screen.paintTransformedScreen(attrib, sTransform, region,
output, mask)
if dy > 0:
screen.moveViewport(0, -1, False);
pass
else:
screen.moveViewport(0, 1, False);
pass
screen.moveViewport(-vx, -vy, False);
else:
screen.paintTransformedScreen(attrib, transform, region, output, mask)
screen.wrap(compiz.PaintTransformedScreen, self, 'paintTransformedScreen')
def donePaintScreen(self, screen):
sPriv = screen.getPrivateData(self)
if sPriv['timeoutHandle'] > 0:
screen.damage()
# unwrap/call/wrap
screen.unwrap(compiz.DonePaintScreen)
screen.donePaintScreen()
screen.wrap(compiz.DonePaintScreen, self, 'donePaintScreen')
def handleEvent(self, display, event):
try:
if event.type == compiz.ClientMessage:
if event.message_type == display.atoms['winActiveAtom']:
win = display.findWindow(event.window)
if win:
screen = win.screen
if win.placed != False and screen.otherGrabExist(\
"plane", "switcher", "cube") == False:
dv = win.defaultViewport
dx = dv['x'] - screen.x;
dy = dv['y'] - screen.y;
self.movePlane(screen, dx, dy);
elif event.message_type == display.atoms['desktopViewportAtom']:
screen = display.findScreen(event.window)
if screen and screen.otherGrabExist("plane", "switcher", \
"cube") == False:
dx = event.data[0]/ screen.width - screen.x
dy = event.data[1]/ screen.height - screen.y
if dx==0 and dy==0:
return False
self.movePlane(screen, dx, dy)
# unwrap/call/wrap
display.unwrap(compiz.HandleEvent)
display.handleEvent(event)
display.wrap(compiz.HandleEvent, self, 'handleEvent')
except Exception, ex:
print "Exception in handleEvent: " + str(ex)
# NOT NEEDED YET (possibly meant to be used for DnD between viewports??)
def windowGrabNotify(self, window, x, y, state, mask):
# get screen
s = window.screen
# set grabbed state in private
#dPriv = s.display.getPrivateData(self)
#dPriv['grabbed'] = True;
self.draggingWindow = True
self.dragX = x
self.dragY = y
print "Grab @ %i,%i" % (x,y)
# unwrap/call/wrap
s.unwrap(compiz.WindowGrabNotify)
s.windowGrabNotify(window, x, y, state, mask)
s.wrap(compiz.WindowGrabNotify, self, 'windowGrabNotify')
# NOT NEEDED YET (possibly meant to be used for DnD between viewports??)
def windowUngrabNotify(self, window):
self.draggingWindow = False
s = window.screen
# unwrap/call/wrap
s.unwrap(compiz.WindowUngrabNotify)
s.windowUngrabNotify(window)
s.wrap(compiz.WindowUngrabNotify, self, 'windowUngrabNotify')
# -------------------------------------------------------------------------
# default CompPlugin-functions
# -------------------------------------------------------------------------
def initScreen(self, screen):
# init private
sPriv = screen.getPrivateData(self)
if sPriv == None:
return False
sPriv['timeoutHandle'] = 0
sPriv['timer'] = 0
sPriv['cur_x'] = 0.0
sPriv['cur_y'] = 0.0
sPriv['dest_x'] = 0.0
sPriv['dest_y'] = 0.0
# wrap events
screen.wrap(compiz.PreparePaintScreen, self, 'preparePaintScreen')
screen.wrap(compiz.PaintTransformedScreen, self, 'paintTransformedScreen')
screen.wrap(compiz.PaintScreen, self, 'paintScreen')
screen.wrap(compiz.DonePaintScreen, self, 'donePaintScreen')
screen.wrap(compiz.WindowGrabNotify, self, 'windowGrabNotify')
screen.wrap(compiz.WindowUngrabNotify, self, 'windowUngrabNotify')
# ok
return True
def finiScreen(self, screen):
# unwrap events
screen.unwrap(compiz.PreparePaintScreen)
screen.unwrap(compiz.PaintTransformedScreen)
screen.unwrap(compiz.PaintScreen)
screen.unwrap(compiz.DonePaintScreen)
screen.unwrap(compiz.WindowGrabNotify)
screen.unwrap(compiz.WindowUngrabNotify)
def initDisplay(self, display):
dPriv = display.getPrivateData(self)
dPriv['grabbed'] = False;
display.wrap(compiz.HandleEvent, self, 'handleEvent')
return True
def finiDisplay(self, display):
display.unwrap(compiz.HandleEvent)
# -------------------------------------------------------------------------
# option/action-definitions
# -------------------------------------------------------------------------
def getDisplayOptions (self, display):
return compiz.CompOptionList ( \
compiz.CompOption ( \
name = 'scroll_time',
type = compiz.CompOptionTypeInt,
shortDesc = "Scroll-Time",
longDesc = "Duration of the viewport-scrolling (in milliseconds)",
default = self.scrollTime
),
compiz.CompOption ( \
name = 'plane_left',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Left",
longDesc = "Move desktop one viewport to the left",
default = compiz.CompAction ( \
initiate = (self, "planeLeft"),
terminate = None,
button = None,
key = "<Control><Alt>Left",
bell = False,
edgeMask = compiz.SCREEN_EDGE_LEFT_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_right',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Right",
longDesc = "Move desktop one viewport to the right",
default = compiz.CompAction ( \
initiate = (self, "planeRight"),
terminate = None,
button = None,
key = "<Control><Alt>Right",
bell = False,
edgeMask = compiz.SCREEN_EDGE_RIGHT_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_up',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Up",
longDesc = "Move desktop one viewport up",
default = compiz.CompAction ( \
initiate = (self, "planeUp"),
terminate = None,
button = None,
key = "<Control><Alt>Up",
bell = False,
edgeMask = compiz.SCREEN_EDGE_TOP_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_down',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Down",
longDesc = "Move desktop one viewport down",
default = compiz.CompAction ( \
initiate = (self, "planeDown"),
terminate = None,
button = None,
key = "<Control><Alt>Down",
bell = False,
edgeMask = compiz.SCREEN_EDGE_BOTTOM_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_down_right',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Down/Right",
longDesc = "Move desktop one viewport down and one viewport right",
default = compiz.CompAction ( \
initiate = (self, "planeDownRight"),
terminate = None,
button = None,
key = None,
bell = False,
edgeMask = compiz.SCREEN_EDGE_BOTTOMRIGHT_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_down_left',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Down/Left",
longDesc = "Move desktop one viewport down and one viewport left",
default = compiz.CompAction ( \
initiate = (self, "planeDownLeft"),
terminate = None,
button = None,
key = None,
bell = False,
edgeMask = compiz.SCREEN_EDGE_BOTTOMLEFT_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_up_right',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Up/Right",
longDesc = "Move desktop one viewport up and one viewport right",
default = compiz.CompAction ( \
initiate = (self, "planeUpRight"),
terminate = None,
button = None,
key = None,
bell = False,
edgeMask = compiz.SCREEN_EDGE_TOPRIGHT_MASK,
edgeButton = 1
)
),
compiz.CompOption ( \
name = 'plane_up_left',
type = compiz.CompOptionTypeAction,
shortDesc = "Plane Up/Left",
longDesc = "Move desktop one viewport up and one viewport left",
default = compiz.CompAction ( \
initiate = (self, "planeUpLeft"),
terminate = None,
button = None,
key = None,
bell = False,
edgeMask = compiz.SCREEN_EDGE_TOPLEFT_MASK,
edgeButton = 1
)
),
)
def setDisplayOption(self, display, name, value):
if name=='scroll_time':
self.scrollTime = value
:)
RYX
April 15th, 2007, 02:01 PM
Can we somehow change the way to access the private? It is very ugly (and slow) to always access the fields as a dict. Would it be possible to make it like this:priv = screen.getPrivate(self)
priv.addData('timer', 0)
priv.addData('timeoutHandler', 0)
And then retrieve it like a normal property:priv = screen.getPrivate(self)
print priv.timer
print priv.timeoutHandler
It would also make the code better readable and easier to write (x.x instead of x['x']) ...
:)
mikedee
April 15th, 2007, 02:49 PM
I have just uploaded a new version which changes options so that they are initialized with keyword arguments. The examples have been updated so you should be able to see from there.
I also added support for min, max, precision and restrictions as keyword args.
EDIT : I also added support for compiz.removeTimeout () ;)
Can we somehow change the way to access the private? It is very ugly (and slow) to always access the fields as a dict. Would it be possible to make it like this:priv = screen.getPrivate(self)
priv.addData('timer', 0)
priv.addData('timeoutHandler', 0)
And then retrieve it like a normal property:priv = screen.getPrivate(self)
print priv.timer
print priv.timeoutHandler
It would also make the code better readable and easier to write (x.x instead of x['x']) ...
:)
Wouldn't this mean that you have to set up a class definition and I would have to use that class to generate an instance to return back? This is more how the C API works, but I thought dictionaries would be much easier.
mikedee
April 15th, 2007, 04:06 PM
Update to add basic ability to set window attributes.
You have to copy and re-set the whole dict, but Ill create a helper object which will prevent this in the future
a = w.attrib
a['x'] = 10
a['y'] = 10
w.attrib = a
This will move the window to the top left (10, 10).
It should eventually just need this. w.move () can be used for extra control if needed.
w.attrib.x = 10
mikedee
April 15th, 2007, 05:54 PM
I managed to get the pyplane working in the end. You seem to have some x/y problem because I can scroll up and down but if I go left or right, it puts me back to the same viewport.
I have uploaded a new version which includes pywallpaper working with vsize as well as hsize. It copes well with the viewport size changing as well as changing the images. It always defaults back to freedesktop.png (background.png was removed ages ago)
RYX
April 15th, 2007, 09:13 PM
I have just uploaded a new version which changes options so that they are initialized with keyword arguments. The examples have been updated so you should be able to see from there.
I also added support for min, max, precision and restrictions as keyword args.
EDIT : I also added support for compiz.removeTimeout () ;)
Can we somehow change the way to access the private? It is very ugly (and slow) to always access the fields as a dict. Would it be possible to make it like this:priv = screen.getPrivate(self)
priv.addData('timer', 0)
priv.addData('timeoutHandler', 0)
And then retrieve it like a normal property:priv = screen.getPrivate(self)
print priv.timer
print priv.timeoutHandler
It would also make the code better readable and easier to write (x.x instead of x['x']) ...
:)
Wouldn't this mean that you have to set up a class definition and I would have to use that class to generate an instance to return back? This is more how the C API works, but I thought dictionaries would be much easier.
Yes, it would need additional classes like "ScreenPrivate" and "DisplayPrivate" (or ScreenData, DisplayData). But to me it seems a lot more logical, OOP-conform and easier to type. The options-object could inherit from dict instead so you can access options like "options['option_name'].value".
I managed to get the pyplane working in the end. You seem to have some x/y problem because I can scroll up and down but if I go left or right, it puts me back to the same viewport.
I have uploaded a new version which includes pywallpaper working with vsize as well as hsize. It copes well with the viewport size changing as well as changing the images. It always defaults back to freedesktop.png (background.png was removed ages ago)
The x/y problems are very mysterious. I am pretty sure it is exactly like the C-version. If I move left/right the viewport seems to move up/down, if I move up/down I am dropped to 1,3,5,7,9 and then to 2,4,6,8 ... :?: ... So I'll try to find some more bugs ...
:)
RYX
April 15th, 2007, 09:51 PM
I managed to get the pyplane working in the end. You seem to have some x/y problem because I can scroll up and down but if I go left or right, it puts me back to the same viewport.
How did you manage to get pyplane working (and what do you mean with "working")? Do you see the animated viewport-change? I either see flickering or an immediate change without animation ... Did you see any bugs in the code?
I have uploaded a new version which includes pywallpaper working with vsize as well as hsize. It copes well with the viewport size changing as well as changing the images. It always defaults back to freedesktop.png (background.png was removed ages ago)
The new version works well (and I like the keyword-args in the options-constructors), but your pywallpaper doesn't use the images from the list. It seems like it always uses the default values ...
:)
mikedee
April 15th, 2007, 11:09 PM
I managed to get the pyplane working in the end. You seem to have some x/y problem because I can scroll up and down but if I go left or right, it puts me back to the same viewport.
How did you manage to get pyplane working (and what do you mean with "working")? Do you see the animated viewport-change? I either see flickering or an immediate change without animation ... Did you see any bugs in the code?
Yes, I saw a few bugs but I thought youd find them easily. There was one Gl instead of GL and in one place you have moveScreenViewport instead of screen.moveViewport. I saw animated movment but only in 1 direction.
RYX
April 15th, 2007, 11:40 PM
Yes, those two were the ones I found :) But I still have no animation ... Tough all values seem to be correct and the logic is similar to the C-plugin ...
Another question - should I add the isDesktop, isFullscreen, isMaximized (...) functions to the CompWindow.c or are you planning to do it? I think it shouldn't be difficult because they take no args and simply return true or false - so I guess it is no problem for me to add them and send you a diff.
:)
RYX
April 15th, 2007, 11:57 PM
I think I found the problem - in compscreen.c in line 549 you assign to "tx" instead of "ty" ... ty is undefined when it gets passed to moveScreenViewport, that should be the reason for the crazy movement.
EDIT: Yes, movement works now but still no animation. The viewport simply switches without visible effect ... can it be related to the timeout?
:)
mikedee
April 16th, 2007, 12:59 AM
I think I found the problem - in compscreen.c in line 549 you assign to "tx" instead of "ty" ... ty is undefined when it gets passed to moveScreenViewport, that should be the reason for the crazy movement.
Thanks very much, I have patched that now and pyplane works perfectly, animation too :)
It even works with pywallpaper, I am not sure why you are still having problems. The only slight problem was that it didn't update the vsize when I changed that.
mikedee
April 16th, 2007, 01:07 AM
Another question - should I add the isDesktop, isFullscreen, isMaximized (...) functions to the CompWindow.c or are you planning to do it? I think it shouldn't be difficult because they take no args and simply return true or false - so I guess it is no problem for me to add them and send you a diff.
I have a local git repo here, I have tarred it including the .git folder and put it up at the same place as python-git.tar.gz If you untar this and then use git-commit on the files you change I can easily integrate them. You can type git format-patch origin to get a patch for me.
In the new tarball is the working version of pyplane, see if thats any different for you.
As for adding those functions, I think its OK. You are free to add them if you want to, otherwise I can do it :)
mikedee
April 16th, 2007, 01:11 AM
Yes, it would need additional classes like "ScreenPrivate" and "DisplayPrivate" (or ScreenData, DisplayData). But to me it seems a lot more logical, OOP-conform and easier to type. The options-object could inherit from dict instead so you can access options like "options['option_name'].value".
I am not going to add these to the loader because it is very very easy for you to replicate display/screen private variables within your plugin. Each screen has a screenNum which can be used as an index in whatever internal structure you keep.
I think a dictionary is the best datatype for it because it is just kv data and you do not need any of the features of full blown objects (or if you do its easy to get)
RYX
April 16th, 2007, 01:53 AM
The pyplane works for me, too. I had a problem with the transform which is now fixed. I created a new instance like in C, but that failed and paintTransformedScreen never ran as it should. Sometimes it is difficult to see what's wrong because if a function gets invalid args it just silently fails without further notice ... (and adding those notices would result in multplying the codesize of the plugin by 3) ..
mikedee
April 16th, 2007, 02:01 AM
The pyplane works for me, too. I had a problem with the transform which is now fixed. I created a new instance like in C, but that failed and paintTransformedScreen never ran as it should. Sometimes it is difficult to see what's wrong because if a function gets invalid args it just silently fails without further notice ... (and adding those notices would result in multplying the codesize of the plugin by 3) ..
I modified it so that all pointers are automatically copied when you modify anything declared as const. Was that problem only in your version?
RYX
April 16th, 2007, 02:21 AM
Yes, it would need additional classes like "ScreenPrivate" and "DisplayPrivate" (or ScreenData, DisplayData). But to me it seems a lot more logical, OOP-conform and easier to type. The options-object could inherit from dict instead so you can access options like "options['option_name'].value".
I am not going to add these to the loader because it is very very easy for you to replicate display/screen private variables within your plugin. Each screen has a screenNum which can be used as an index in whatever internal structure you keep.
I think a dictionary is the best datatype for it because it is just kv data and you do not need any of the features of full blown objects (or if you do its easy to get)
Its not about features - it is a cleaner and more common way to put those things into own classes. Using associative arrays for that is absolutely ok during testing, but for a final API they are too antiquated, low-level and not very OOP-conform. The private data is used very frequently throughout the whole plugin-code so I think it would make sense to simplify its access as much as possible. Having something like a self.screenOptions-array would result in the same key/value thing (or even worse: indexes) so it's not a real alternative.
(Although if David decides to remove per-Screen-options then I guess the private-system could be entirely removed.)
However - I am sure there are more important things to do. I will try adding some of the utility-functions to compwindow ...
:)
RYX
April 16th, 2007, 02:27 AM
The pyplane works for me, too. I had a problem with the transform which is now fixed. I created a new instance like in C, but that failed and paintTransformedScreen never ran as it should. Sometimes it is difficult to see what's wrong because if a function gets invalid args it just silently fails without further notice ... (and adding those notices would result in multplying the codesize of the plugin by 3) ..
I modified it so that all pointers are automatically copied when you modify anything declared as const. Was that problem only in your version?
Yes, it was a problem with the way I used the transform (I created a new instance for getting a copy which was wrong). I updated my pyplane-plugin on page 6 to the working version. This one activates the viewport-switch by touching the screendedges . I noticed that the CompAction.edgeButton seems to be ignored - or does it need some special mask? I wanted to have edge+button1 but it ignores the button and initiates when hovering the edge ...
EDIT: Do you know how to realize drag&drop of windows between workspaces (while still keeping the edge+button1 as initiate :) ...)? It currently works (i.e. would work with simply warping the pointer), but the "auto-switching" gets pretty annoying after 10 minutes of fun ..
mikedee
April 16th, 2007, 02:53 AM
I noticed that the CompAction.edgeButton seems to be ignored - or does it need some special mask? I wanted to have edge+button1 but it ignores the button and initiates when hovering the edge ...
Ill have a look at that, are you setting edgeButton to 1 or 'Button1'? It should be an int
EDIT : Should have looked first, Ive fixed the problem and will upload it now
mikedee
April 16th, 2007, 06:18 PM
I have uploaded this to include a new test plugin called seethru. It is basically a copy of fakeargb but I am not too keen on the py prefix :)
It helped me work out a few bugs in the fragment interface and it works well
EDIT : I had some problems with =& in python, either its not supported or it does not do what I think it does... Any pointers?
RYX
April 16th, 2007, 07:23 PM
Do you mean &= (short form of assignment/bitwise AND)? That _should_ be supported but I am not sure.
And the py-prefix in the plugin-names was only meant to avoid confusion with existing plugins (because they are only ports). Also I think it makes sense to identify python-plugins as those - if you use C/python plugins together you need to know which one needs to be loaded first. Maybe this will be fixed by a new settings-tool but until then I thought it would be useful ...
:)
mikedee
April 16th, 2007, 07:33 PM
Do you mean &= (short form of assignment/bitwise AND)? That _should_ be supported but I am not sure.
Yes, I thought it was fairly common but it does not seem to work. the ok variable is never updated, but there are no errors.
The documentation is not really helpful either, but I remember having trouble with other basic operators like i++ (is that not supported either?)
This is listed under delimiters, not operators (?)
http://docs.python.org/ref/delimiters.html
And the py-prefix in the plugin-names was only meant to avoid confusion with existing plugins (because they are only ports). Also I think it makes sense to identify python-plugins as those - if you use C/python plugins together you need to know which one needs to be loaded first. Maybe this will be fixed by a new settings-tool but until then I thought it would be useful ...
I prefer to remove the python distinction, it makes then seem second class somehow. I think they are just as powerful (if not more powerful) than the C plugins.
RYX
April 16th, 2007, 07:42 PM
Do you mean &= (short form of assignment/bitwise AND)? That _should_ be supported but I am not sure.
Yes, I thought it was fairly common but it does not seem to work. the ok variable is never updated, but there are no errors.
The documentation is not really helpful either, but I remember having trouble with other basic operators like i++ (is that not supported either?)
Yes, "x++" and "x--" are syntax errors ... (well, maybe it comes with version 2.6 :))
And the py-prefix in the plugin-names was only meant to avoid confusion with existing plugins (because they are only ports). Also I think it makes sense to identify python-plugins as those - if you use C/python plugins together you need to know which one needs to be loaded first. Maybe this will be fixed by a new settings-tool but until then I thought it would be useful ...
I prefer to remove the python distinction, it makes then seem second class somehow. I think they are just as powerful (if not more powerful) than the C plugins.
Of course they are :D .. But if you have two "wallpaper"-plugins in your list it can get pretty confusing. I didn't mean to introduce the py-prefix as a common naming-scheme (and I don't think it makes them second-class, instead it makes them sound more special). It's only a temporary solution for less confusion (until I have replaced all normal plugins with python-ones :D :D :D).
EDIT: I updated my pyplane-plugin on page 6 again - added diagonal movement and scrolltime-option ...
:)
mikedee
April 16th, 2007, 07:51 PM
Do you mean &= (short form of assignment/bitwise AND)? That _should_ be supported but I am not sure.
Yes, I thought it was fairly common but it does not seem to work. the ok variable is never updated, but there are no errors.
The documentation is not really helpful either, but I remember having trouble with other basic operators like i++ (is that not supported either?)
Yes, "x++" and "x--" are syntax errors ... (well, maybe it comes with version 2.6 :))
Maybe Python++ ;)
Is there an official line on why these are missing? Are you supposed to type i = i + 1 or are we allowed i += 1 ?
And the py-prefix in the plugin-names was only meant to avoid confusion with existing plugins (because they are only ports). Also I think it makes sense to identify python-plugins as those - if you use C/python plugins together you need to know which one needs to be loaded first. Maybe this will be fixed by a new settings-tool but until then I thought it would be useful ...
I prefer to remove the python distinction, it makes then seem second class somehow. I think they are just as powerful (if not more powerful) than the C plugins.
Of course they are :D .. But if you have two "wallpaper"-plugins in your list it can get pretty confusing. I didn't mean to introduce the py-prefix as a common naming-scheme (and I don't think it makes them second-class, instead it makes them sound more special). It's only a temporary solution for less confusion (until I have replaced all normal plugins with python-ones :D :D :D).
:P David must be getting slightly worried
RYX
April 16th, 2007, 08:34 PM
Is there an official line on why these are missing? Are you supposed to type i = i + 1 or are we allowed i += 1 ?
No, "+=" works ... otherwise I'd switch to ruby :)
David must be getting slightly worried
Wasn't it his idea to provide the stable core and let plugins do the action? ;)
I am just very amazed by the performance of the python-plugins and I think most of the default usability-plugins could be written in python ...
(btw: Do you have any idea concerning the isFullscreen-problem? I'd like to implement the same helper-functions for the window-states but am unsure about the naming ...)
:)
mikedee
April 16th, 2007, 08:56 PM
Is there an official line on why these are missing? Are you supposed to type i = i + 1 or are we allowed i += 1 ?
No, "+=" works ... otherwise I'd switch to ruby :)
Yeah - It would be worth learning Japanese for :)
David must be getting slightly worried
Wasn't it his idea to provide the stable core and let plugins do the action? ;)
Yeah - But I bet he is glad he made that distinction now ;)
I am just very amazed by the performance of the python-plugins and I think most of the default usability-plugins could be written in python ...
Me too, I half expected them to all run really slowly but I cannot notice any difference. Do you fancy redoing mousegestures? You could finally add that trail...
(btw: Do you have any idea concerning the isFullscreen-problem? I'd like to implement the same helper-functions for the window-states but am unsure about the naming ...)
We have an isFullscreen problem? If its clashing between state and type then I thought originally we could have stateFullscreen () etc but that would have been complicated so I just added how you suggested because it was a nicer API.
Maybe we can check for both state and type in the isFullscreen method?
RYX
April 16th, 2007, 09:16 PM
Is there an official line on why these are missing? Are you supposed to type i = i + 1 or are we allowed i += 1 ?
No, "+=" works ... otherwise I'd switch to ruby :)
Yeah - It would be worth learning Japanese for :)
Actually I always wanted to learn japanese but never found the time and the right encouragement.
I am just very amazed by the performance of the python-plugins and I think most of the default usability-plugins could be written in python ...
Me too, I half expected them to all run really slowly but I cannot notice any difference. Do you fancy redoing mousegestures? You could finally add that trail...
I wanted to delay that until we have software-cursors. Maybe the trail could be part of the cursor itself (generated by some effects-interface) - it would fit in David's way to offer full extensibility ...
(btw: Do you have any idea concerning the isFullscreen-problem? I'd like to implement the same helper-functions for the window-states but am unsure about the naming ...)
We have an isFullscreen problem? If its clashing between state and type then I thought originally we could have stateFullscreen () etc but that would have been complicated so I just added how you suggested because it was a nicer API.
Maybe we can check for both state and type in the isFullscreen method?
You mean by passing an argument for either state or type? That could be a possibility - or we use "inFullscreen" for the state, but that would break consistency ..
:)
bijoux
April 16th, 2007, 09:59 PM
hey guys,
what are the dependencies to build this?
RYX
April 16th, 2007, 10:03 PM
You need python, the development headers for python ("libpython-dev" on Ubuntu) and need to run the compiz git-version. As far as I know it is only tested with python2.4 yet but should work with 2.5 as well (only change version in Makefile if you want to run 2.5).
:)
bijoux
April 16th, 2007, 10:23 PM
thanks guy :D
RYX
April 17th, 2007, 02:01 AM
This plugin seems to not unload properly. I noticed that while tyring to import other plugins into the current module to see if it is possible to call classmethods inside other plugins ... (and it seemed to work).
import compiz
#import pydesktopmenu
#print pydesktopmenu
class test1Plugin:
name = "test1plugin"
shortDesc = "Testplugin 1"
longDesc = "Python Testplugin 1"
def initWindow(self, window):
print window
return True
def finiWindow(self, window):
pass
:)
mikedee
April 17th, 2007, 10:08 AM
I have noticed plugins refusing to unload too, Ill have a look into it at some point, it must be related to the unloader code.
RYX
April 17th, 2007, 09:44 PM
Have you any idea how I can use the region-attribute in the paintScreen-function? I need to access its members but it is only a pointer from what I can see in the source. Did you plan to use ctypes for that or would it maybe make sense to create a CompRegion-class? I don't know much about how it works and where the Region comes from - I assume it is an xlib-structure, right?
:)
mikedee
April 18th, 2007, 12:24 AM
Have you any idea how I can use the region-attribute in the paintScreen-function? I need to access its members but it is only a pointer from what I can see in the source. Did you plan to use ctypes for that or would it maybe make sense to create a CompRegion-class? I don't know much about how it works and where the Region comes from - I assume it is an xlib-structure, right?
:)
Yeah its a an xlib structure, its actually a pointer to a REGION structure. I am half way through writing a compiz.Region object which you can use easily without ctypes. There are only a few region functions and attributes so it shouldn't take long.
RYX
April 18th, 2007, 12:34 AM
Have you any idea how I can use the region-attribute in the paintScreen-function? I need to access its members but it is only a pointer from what I can see in the source. Did you plan to use ctypes for that or would it maybe make sense to create a CompRegion-class? I don't know much about how it wo