Author: ArcRiley Date: 2008-02-24 21:59:12 -0500 (Sun, 24 Feb 2008) New Revision: 979
Added: trunk/pysoy/src/windows/ trunk/pysoy/src/windows/Window-x11.pxi trunk/pysoy/src/windows/soy.windows.pxd trunk/pysoy/src/windows/soy.windows.pyx Log: #910 - created directory and initial work Property changes on: trunk/pysoy/src/windows ___________________________________________________________________ Name: svn:ignore + soy.windows.c Copied: trunk/pysoy/src/windows/Window-x11.pxi (from rev 939, trunk/pysoy/src/_core/Window-x11.pxi) =================================================================== --- trunk/pysoy/src/windows/Window-x11.pxi (rev 0) +++ trunk/pysoy/src/windows/Window-x11.pxi 2008-02-25 02:59:12 UTC (rev 979) @@ -0,0 +1,451 @@ +# PySoy windows.Window Class +# +# Copyright (C) 2006,2007,2008 PySoy Group +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see http://www.gnu.org/licenses +# +# $Id$ + +cdef glx.Display *_display +cdef glx.GLXContext _glxContext +_display = NULL +_glxContext = NULL + +# Window._opened states: +DEF OpInit = 0 +DEF OpReadyCreate = 1 +DEF OpReadyMap = 2 +DEF OpWaitMap = 3 +DEF OpReadyRender = 4 +DEF OpReadyUnmap = 5 +DEF OpWaitUnmap = 6 +DEF OpWaitDestroy = 7 +DEF OpClosed = 8 + + +cdef class Window : + '''Window Class + + Each instance of this class is a separate window. + ''' + + def __cinit__(self, screen, title='', icon=None, background=None, + splash=False, position=(0,0), size=(320,240), *args, **kw) : + if not isinstance(screen, Screen) : + raise TypeError('first argument must be of type soy.Screen') + self._screen = screen + self._controllers = soy._internals.Children() + self._widgets = soy._internals.Children() + self.title = title + self._iconCanvas = soy.widgets.Canvas() + if icon : + self.icon = icon + if background : + self._background = background + else : + self._background = soy.colors.black + if splash : + self._splash = 1 + _windows.lock() + _windows.append(<void *>self) + _windows.unlock() + self._create(position[0], position[1], size[0], size[1]) + + def __dealloc__(self) : + if self._windowID : + self._destroy() + _windows.lock() + _windows.remove(<void *>self) + _windows.unlock() + + cdef void _openedWait(self, int _op) : + # Use with care + while self._opened < _op : + soy._internals._sleep(100) + + + cdef void _create(self, int _x, int _y, int _width, int _height) : + # + # Since the CoreLoop thread must handle X traffic, we set self._opened + # flag to OpReadyCreate which instructs _coreRender to _coreCreate. + # + # This command will wait patiently for the CoreLoop thread to set the + # self._opened parameter to OpReadyRender + # + self._x = _x + self._y = _y + self._width = _width + self._height = _height + self._opened = OpReadyCreate + self._openedWait(OpReadyRender) + + + cdef void _destroy(self) : + # + # Since the CoreLoop thread must handle X traffic, we set self._opened + # flag to OpReadyUnmap which instructs _coreRender to XUnmapWindow. + # That should, in turn, generate an UnmapNotify event upon success which + # then issues the XDestroyWindow command and deletes the window. + # + # This command will wait patiently for the CoreLoop thread to set the + # self._opened parameter to OpClosed. + # + self._opened = OpReadyUnmap + self._openedWait(OpClosed) + + cdef void _resize(self, int _width, int _height) : + # + # Resize _topLevel widgets whenever the window changes size + # + cdef int _i + self._widgets.lock() + for _i from 0 <= _i < self._widgets.current : + if (<soy.widgets.Widget> self._widgets.list[_i])._topLevel : + (<soy.widgets.Widget> self._widgets.list[_i])._resize(0, 0, + _width, _height) + self._widgets.unlock() + + + cdef void _coreCreate(self) : + cdef int _fullScreen + cdef glx.Colormap _colormap + cdef glx.Atom _atom + cdef unsigned long _override + cdef glx.XSetWindowAttributes _winAttr + if <void*> self == <void*> self._screen._fullScreen : + _fullScreen = 1 + else : + _fullScreen = 0 + _winAttr.colormap = glx.XCreateColormap(_display, + glx.RootWindowOfScreen(self._screen._screen), + self._screen._xVisualInfo.visual, glx.AllocNone) + _winAttr.border_pixel = 0 + _winAttr.event_mask = glx.KeyPressMask | glx.KeyReleaseMask | \ + glx.ButtonPressMask | glx.ButtonReleaseMask | \ + glx.EnterWindowMask | glx.LeaveWindowMask | \ + glx.PointerMotionMask | glx.ExposureMask | \ + glx.StructureNotifyMask + if _fullScreen or self._splash : + _winAttr.override_redirect = 1 + _override = glx.CWOverrideRedirect + else : + _override = 0 + self._windowID = glx.XCreateWindow( + _display, glx.RootWindowOfScreen(self._screen._screen), + self._x, self._y, self._width, self._height, 0, + self._screen._xVisualInfo.depth, + glx.InputOutput, self._screen._xVisualInfo.visual, + glx.CWBorderPixel | glx.CWColormap | glx.CWEventMask | _override, + &_winAttr) + self._iconPixmap = glx.XCreatePixmap(_display, self._windowID, 16, 16, + self._screen._xVisualInfo.depth) + #glx.XSetWMProtocols(_display, self._windowID, &self._screen._wmDelWin, 1) + if not (_fullScreen or self._splash) : + _atom = glx.XInternAtom(_display, "WM_DELETE_WINDOW", 1) + glx.XSetWMProtocols(_display, self._windowID, &_atom, 1) + self._setProperties() + self._opened = OpReadyMap + glx.XFlush(_display) + + + cdef void _coreRender(self) : + cdef int i + cdef glx.Display *_display + _display = glx.DisplayOfScreen(self._screen._screen) + # + if self._opened != OpReadyRender : + # + # Not ready to render, handle window opening/closing stuff instead + if self._opened == OpReadyCreate : + self._coreCreate() + elif self._opened == OpReadyUnmap : + glx.glXMakeCurrent(_display, 0, NULL) + glx.XUnmapWindow(_display, self._windowID) + self._opened = OpWaitUnmap + glx.XFlush(_display) + return + # + # We need a test for if the icon needs to be rendered here + if 1 : #self._iconCanvas._texture != None : + glx.glXMakeCurrent(_display, self._windowID, _glxContext) + gl.glViewport(0, 0, 16, 16) + gl.glClearColor(0.0, 0.0, 0.0, 1.0) + gl.glClear(gl.GL_COLOR_BUFFER_BIT) + gl.glEnableClientState(gl.GL_VERTEX_ARRAY) + gl.glEnableClientState(gl.GL_NORMAL_ARRAY) + gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) + (<soy.widgets.Canvas> self._iconCanvas)._coreRender() + gl.glDisableClientState(gl.GL_VERTEX_ARRAY) + gl.glDisableClientState(gl.GL_NORMAL_ARRAY) + gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY) + gl.glFlush() + # + glx.glXMakeCurrent(_display, self._windowID, _glxContext) + gl.glViewport(0, 0, self._width, self._height) + gl.glClearColor(self._background._r, self._background._g, + self._background._b, 1.0) + gl.glClear(gl.GL_COLOR_BUFFER_BIT) + # + # For some reason we've yet to discover, these client states MUST be + # enabled and later disabled each render cycle or nothing renders. + # Putting them in the window __cinit__ code doesn't work. + gl.glEnableClientState(gl.GL_VERTEX_ARRAY) + gl.glEnableClientState(gl.GL_NORMAL_ARRAY) + gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY) + gl.glEnable(gl.GL_CULL_FACE) + gl.glFrontFace(gl.GL_CCW) + gl.glCullFace(gl.GL_BACK) + + # Render each widget in order + self._widgets.lock() + for i from 0 <= i < self._widgets.current : + (<soy.widgets.Widget> self._widgets.list[i])._coreRender() + self._widgets.unlock() + + gl.glDisableClientState(gl.GL_VERTEX_ARRAY) + gl.glDisableClientState(gl.GL_NORMAL_ARRAY) + gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY) + gl.glDisable(gl.GL_CULL_FACE) + gl.glFlush() + glx.glXSwapBuffers(_display, self._windowID) + + + cdef void _setProperties(self) : + cdef glx.Display *_display + _display = glx.DisplayOfScreen(self._screen._screen) + glx.XSetStandardProperties(_display, self._windowID, + self._title, self._title, self._iconPixmap-1, + NULL, 0, NULL) + glx.XFlush(_display) + + cdef void _coreEventKeyDown(self, glx.Time _time, + glx.KeyCode _code, glx.KeySym _key) : + cdef int i + self._controllers.lock() + for i from 0 <= i < self._controllers.current : + (<soy.controllers.Controller> self._controllers.list[i])._coreEventKeyDown( + _code, _key) + self._controllers.unlock() + + cdef void _coreEventKeyUp(self, glx.Time _time, + glx.KeyCode _code, glx.KeySym _key) : + cdef int i + self._controllers.lock() + for i from 0 <= i < self._controllers.current : + (<soy.controllers.Controller> self._controllers.list[i])._coreEventKeyUp( + _code, _key) + self._controllers.unlock() + + cdef void _coreEventButtonDown(self, glx.Time _time, unsigned int _button, + int _xpos, int _ypos) : + # Nothing (yet) + # 0=any, 1 2 3, 4=up, 5=down + return + + cdef void _coreEventButtonUp(self, glx.Time _time, unsigned int _button, + int _xpos, int _ypos) : + return + + cdef void _coreEventMotion(self, glx.Time _time, int _xpos, int _ypos) : + # Nothing (yet) + return + + + cdef void _coreEventConfigure(self, int _x, int _y, int _width,int _height) : + if self._width != _width or self._height != _height : + self._width = _width + self._height = _height + self._resize(_width, _height) + + + cdef void _coreEventCreate(self) : + cdef glx.Display *_display + _display = glx.DisplayOfScreen(self._screen._screen) + if self._opened != OpReadyMap : + return + glx.XMapWindow(_display, self._windowID) + self._opened = OpWaitMap + glx.XFlush(_display) + + cdef void _coreEventDestroy(self) : + if self._opened != OpWaitDestroy : + stdio.printf('Unexpected DestroyNotify Event received\n') + return + self._opened = OpClosed + + cdef void _coreEventMap(self) : + if self._opened != OpWaitMap : + stdio.printf('Unexpected MapNotify Event received\n') + return + self._resize(self._width, self._height) + if <void*> self == <void*> self._screen._fullScreen : + glx.XSetInputFocus(_display, self._windowID, + glx.RevertToParent, glx.CurrentTime) + # _screen._coreGlewInit won't work until the first window is opened + if self._screen._glVersion == 0 : + glx.glXMakeCurrent(_display, self._windowID, _glxContext) + self._screen._coreGlewInit() + self._opened = OpReadyRender + + cdef void _coreEventUnmap(self) : + cdef glx.Display *_display + _display = glx.DisplayOfScreen(self._screen._screen) + if self._opened != OpWaitUnmap : + stdio.printf('Unexpected UnmapNotify Event received\n') + return + glx.XDestroyWindow(_display, self._windowID) + self._opened = OpWaitDestroy + glx.XFlush(_display) + + cdef void _coreEventWinClose(self) : + cdef int _i + self._controllers.lock() + for _i from 0 <= _i < self._controllers.current : + (<soy.controllers.Controller> self._controllers.list[_i])._coreEventWinClose() + self._controllers.unlock() + + + property title: + '''Window's title string + + This is the "title" of the window, typically displayed at the top of the + window in a decorated area. It may also appear in other places based on + the window manager being used. + + Accepts any string value, defaults to an empty string. + ''' + def __get__(self) : + return self._title + def __set__(self, value) : + if type(value) == str : + self._title = value + else : + self._title = '' + if self._opened : + _windows.lock() + self._setProperties() + _windows.unlock() + + + property icon: + '''Window's icon texture + + This property is the window's "icon", however the window manager uses it. + Textures must be 1D or 2D (not 3D) and /should/ be square. + Defaults to None. + ''' + def __get__(self) : + return self._iconCanvas.texture + def __set__(self, value) : + self._iconCanvas.texture = value + + + property background: + '''Window's background color + + Behind every widget is a background color the window is "cleared" to + before rendering each frame. + + This is an instance of soy.colors.Color which is either created for you + (default is black) or passed with background= during a window's creation. + ''' + def __get__(self) : + return self._background + + property position: + '''Window's position on the screen + + This is the position of the window in respect to the whole screen. + Changing this property will move the window. + + Takes a (x,y) as an argument and defaults to whatever position the + window manager chooses. + ''' + def __get__(self) : + cdef int _status + cdef glx.Window _root, _parent + cdef glx.Window *_children + cdef int _xpos, _ypos + cdef unsigned int _width, _height, _border, _depth, _nchildren + _windows.lock() + _status = glx.XQueryTree(_display, self._windowID, + &_root, &_parent, &_children, &_nchildren) + if not _status : + _windows.unlock() + raise RuntimeError('could not XQueryTree') + if _root == _parent : + _status = glx.XGetGeometry(_display, self._windowID, &_root, + &_xpos, &_ypos, &_width, &_height, + &_border, &_depth) + else : + # Help, we're in a decoration window! + _status = glx.XGetGeometry(_display, _parent, &_root, + &_xpos, &_ypos, &_width, &_height, + &_border, &_depth) + _windows.unlock() + if not _status : + raise RuntimeError('could not XGetGeometry') + return (_xpos, _ypos) + def __set__(self, value) : + cdef int _status + cdef glx.Display *_display + _display = glx.DisplayOfScreen(self._screen._screen) + if len(value)!=2 or type(value[0])!=int or type(value[1])!=int : + raise TypeError('Must provide an (int,int) for position') + _windows.lock() + _status = glx.XMoveWindow(_display, self._windowID, value[0], value[1]) + if not _status : + raise RuntimeError('could not XMoveWindow') + _status = glx.XFlush(_display) + if not _status : + _windows.unlock() + raise RuntimeError('could not XFlush') + _windows.unlock() + + property size : + '''Window size + + This is the pixel size of the window on the screen. It determines the + aspect ratio of the window thus may squeeze/stretch widgets accordingly. + + Takes an (x,y), defaults to (320,240). + ''' + def __get__(self) : + return (self._width, self._height) + def __set__(self, value) : + cdef int _status + if len(value)!=2 or type(value[0])!=int or type(value[1])!=int : + raise TypeError('Must provide an (int,int) for size') + _windows.lock() + _status = glx.XResizeWindow(_display, self._windowID, value[0], value[1]) + if not _status : + _windows.unlock() + raise RuntimeError('could not XResizeWindow') + _status = glx.XFlush(_display) + if not _status : + _windows.unlock() + raise RuntimeError('could not XFlush') + self._width = value[0] + self._height = value[1] + _windows.unlock() + + def __repr__(self) : + report = [] + if self._widgets.current == 1 : + report.append('1 widget') + elif self._widgets.current > 1 : + report.append('%d widgets' % self._widgets.current) + + if report == [] : return '<Empty Window>' + else : return '<Window with %s>' % ', '.join(report) Copied: trunk/pysoy/src/windows/soy.windows.pxd (from rev 939, trunk/pysoy/src/stubs/soy.stubs.pxd) =================================================================== --- trunk/pysoy/src/windows/soy.windows.pxd (rev 0) +++ trunk/pysoy/src/windows/soy.windows.pxd 2008-02-25 02:59:12 UTC (rev 979) @@ -0,0 +1,33 @@ +# PySoy soy.windows Declarations +# +# Copyright (C) 2006,2007,2008 PySoy Group +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see http://www.gnu.org/licenses +# +# $Id $ + +IF UNAME_SYSNAME == "Windows" : + cimport windows +ELIF UNAME_SYSNAME == "Darwin" : + cimport carbon +ELSE: + cimport glx + +cimport soy._internals +cimport soy.colors + +cdef int _glVersion + +cdef class Window : + Copied: trunk/pysoy/src/windows/soy.windows.pyx (from rev 936, trunk/pysoy/src/stubs/soy.stubs.pyx) =================================================================== --- trunk/pysoy/src/windows/soy.windows.pyx (rev 0) +++ trunk/pysoy/src/windows/soy.windows.pyx 2008-02-25 02:59:12 UTC (rev 979) @@ -0,0 +1,61 @@ +'''PySoy Windows + + This extension contains classes which create and manage rendering windows. + The following classes are available: + * Window : generic window with border and title bar + * Splash : borderless window which can be positioned/etc + * Fullscreen : borderless window which fills the whole screen + + These classes are available on all platforms with the same API, however, + not all of their functionality may be present. + + See help() for any of these classes for more information. +''' +__credits__ = '''Copyright (C) 2006,2007,2008 PySoy Group + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see http://www.gnu.org/licenses +''' +__author__ = 'PySoy Group' +__date__ = 'Last change on '+ \ + '$Date$'[7:-20]+ \ + 'by '+'$Author$'[9:-2] +__version__ = 'Trunk (r'+'$Rev$'[6:-2]+')' + +cimport stdlib +cimport soy.widgets + +IF UNAME_SYSNAME == "Windows" : + include "_windowproc.pxi" + include "Window-w32.pxi" +ELSE : + cdef glx.Display *_display + cdef glx.GLXContext _glxContext + cdef soy._internals.Thread _windows + _display = NULL + _glxContext = NULL + _windows = soy._internals.Thread(Window, name='RenderLoop') + + # Window._opened states: + DEF OpInit = 0 + DEF OpReadyCreate = 1 + DEF OpReadyMap = 2 + DEF OpWaitMap = 3 + DEF OpReadyRender = 4 + DEF OpReadyUnmap = 5 + DEF OpWaitUnmap = 6 + DEF OpWaitDestroy = 7 + DEF OpClosed = 8 + + include "Window-x11.pxi" + _______________________________________________ PySoy-SVN mailing list PySoy-SVN@pysoy.org http://www.pysoy.org/mailman/listinfo/pysoy-svn