Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Glut #742

Merged
merged 13 commits into from

3 participants

Nicolas P. Rougier Min RK Fernando Perez
Nicolas P. Rougier

This is the experimental glut event loop integration.
It requires PyOpenGL.

IPython/lib/inputhook.py
((57 lines not shown))
+ import OpenGL.platform as platform
+
+ def timer_none(fps):
+ ''' Dummy timer function '''
+ pass
+
+ def display():
+ ''' Dummy display function '''
+ pass
+
+ def timer(fps):
+ # We should normally set the active window to 1 and post a
+ # redisplay for each window. The problem is that we do not know
+ # how much active windows we have and there is no function in glut
+ # to get that number.
+ # glut.glutSetWindow(1)
Fernando Perez Owner
fperez added a note

This is commented out, but it's not clear to me if you mean that eventually there will be a better solution or not. With the code as it stands, it states the problem but doesn't let us know what we should do next...

Did you mean this comment for discussion with us, or for future authors to perhaps make improvements?

Nicolas P. Rougier
rougier added a note

In fact, I do not see a better solution by now but if someone comes with a better solution, that would be great. However, since glut is very old (but widely used) and pretty frozen, it might not be that easy. So to answer your question is more a comment for future authors to make improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/lib/inputhook.py
((71 lines not shown))
+ # to get that number.
+ # glut.glutSetWindow(1)
+ glut.glutTimerFunc( int(1000.0/fps), timer, fps)
+ glut.glutPostRedisplay()
+
+ glutMainLoopEvent = None
+ if sys.platform == 'darwin':
+ try:
+ glutCheckLoop = platform.createBaseFunction(
+ 'glutCheckLoop', dll=platform.GLUT, resultType=None,
+ argTypes=[],
+ doc='glutCheckLoop( ) -> None',
+ argNames=(),
+ )
+ except AttributeError:
+ raise RuntimeError,\
Fernando Perez Owner
fperez added a note

Exceptions should be raised as

raise RuntimeError("message....")

using (), as the raise E, "msg" syntax is valid but deprecated.

Nicolas P. Rougier
rougier added a note

Corrected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/lib/inputhook.py
((78 lines not shown))
+ try:
+ glutCheckLoop = platform.createBaseFunction(
+ 'glutCheckLoop', dll=platform.GLUT, resultType=None,
+ argTypes=[],
+ doc='glutCheckLoop( ) -> None',
+ argNames=(),
+ )
+ except AttributeError:
+ raise RuntimeError,\
+ 'Your glut implementation does not allow interactive sessions' \
+ 'Consider installing freeglut.'
+ glutMainLoopEvent = glutCheckLoop
+ elif glut.HAVE_FREEGLUT:
+ glutMainLoopEvent = glut.glutMainLoopEvent
+ else:
+ raise RuntimeError,\
Fernando Perez Owner
fperez added a note

Same comment as above about exceptions.

Nicolas P. Rougier
rougier added a note

Corrected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/lib/inputhook.py
((88 lines not shown))
+ 'Consider installing freeglut.'
+ glutMainLoopEvent = glutCheckLoop
+ elif glut.HAVE_FREEGLUT:
+ glutMainLoopEvent = glut.glutMainLoopEvent
+ else:
+ raise RuntimeError,\
+ 'Your glut implementation does not allow interactive sessions. ' \
+ 'Consider installing freeglut.'
+
+ def inputhook_glut():
+ """ Process pending GLUT events only. """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ glutMainLoopEvent()
+ except KeyboardInterrupt:
Fernando Perez Owner
fperez added a note

I see you're trapping it here, but I still get a traceback from the crash handler if I hit Ctrl-C. Do you have any idea why? Does it work ok for you? I'm on linux...

Nicolas P. Rougier
rougier added a note

Same on OSX. I did not test that simple case and I'm investigating why I can't catch the KeyboardInterrupt. Is suspect that the keyboard interrupt is disturbing the glutMainLoopEvent for some reason and it do something weird. I also tried to catch any other exception but still get the traceback from the crash handler.

Nicolas P. Rougier
rougier added a note

I found this thread that seems to explain the situation and provide a solution but I'm unable to translate it for my case (lack some comments in the code):
http://osdir.com/ml/python.ctypes/2006-10/msg00001.html

Asking for help if someone is able to decrypt the code...

Nicolas P. Rougier
rougier added a note

Using the following code before the glutMainLoopEvent, I'm able to catch the SIGINT but it'll bring more problems I guess:

import signal
def handler(signum, frame): return 0
signal.signal(signal.SIGINT, handler)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/lib/inputhook.py
((22 lines not shown))
+ integration within IPython since original GLUT does not allow to handle
+ events one by one. Instead, it requires for the mainloop to be entered
+ and never returned (there is not even a function to exit he
+ mainloop). Fortunately, there are alternatives such as freeglut
+ (available for linux and windows) and the OSX implementation gives
+ access to a glutCheckLoop() function that blocks itself until a new
+ event is received. This means we have to setup a default timer to
+ ensure we got at least one event that will unblock the function. We set
+ a default timer of 60fps.
+
+ Furthermore, it is not possible to install these handlers without a
+ window being first created. We choose to make this window invisible and
+ the user is supposed to make it visible when needed (see gui-glut.py in
+ the docs/examples/lib directory). This means that display mode options
+ are set at this level and user won't be able to change them later
+ without modifying the code. This should probably be made available via
Fernando Perez Owner
fperez added a note

Since this is a user-facing docstring and the comment about making it an option is more of a note/discussion for developers, that sentence should be removed from the docstring (it's indicated below in the code in any case, for the developers).

Nicolas P. Rougier
rougier added a note

I've reorganized into docstrings and comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/lib/inputhook.py
((98 lines not shown))
+ """ Process pending GLUT events only. """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ glutMainLoopEvent()
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+ # Frame per second : 60
+ # Should be probably an IPython option
+ fps = 60
+ if not self._apps.has_key(GUI_GLUT):
+ glut.glutInit(sys.argv)
+
+ # Display mode shoudl be also an Ipython option since user won't be able
Fernando Perez Owner
fperez added a note

typo: shoudl -> should

Fernando Perez Owner
fperez added a note

@minrk, what are your thoughts on hooking up these gl/glut options into the config system? Also, since you have more experience with GL in general than I do, your thoughts on this PR would be welcome.

Nicolas P. Rougier
rougier added a note

The display mode is quite important for people working with OpenGL. Basically it tells OpenGL what kind of buffers are needed (color buffer, depth buffer, double buffer, stencil buyer, etc.). I provided reasonable default values but user might want to be able to specify them in the python configuration.

Concerning fps, it is bit more tricky since it is also a quite common setting for OpenGL developers but the actual value is not really free to set since it will directly impact console responsiveness. For example if you set it to 4, it means glutMainLoopEvent will sleep for 250ms, hence making the console quite unusable. 60fps is quite standard and makes both things smooth on screen and make console quite responsive.

For options, I do not know yet very well the internal system but I will read the doc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Min RK
Owner

@fperez, Sure, anything that's likely to have multiple options should be configurable. I don't think there's any inputhook configuration, so we really have two options:

  1. Configurable per-eventloop
  2. Single Configurable for the InputHookManager, that handles options

While 2. is more extensible/O-O friendly, I think 1. would probably be cleaner in the long run.
We already need to make the timers in the Wx backend configurable as well (see #96).

Fernando Perez
Owner

@rougier, I tried testing it by running the gui-glut.py example script, but the moment I close the GUI window, ipython crashes completely and leaves the terminal in a broken state that doesn't echo any characters typed. I can restore the terminal by typing reset<ENTER> blind, but this isn't a very good long-term solution. Does it work on your side of things normally?

Basically we want to integrate these GUI modes if they provide users the ability to repeatedly run a GUI script while maintaining an interactive shell working. But if they only allow for a script to execute once ever and everything crashes after that, it doesn't seem too useful. What do you think?

Nicolas P. Rougier
Fernando Perez
Owner

I know very little about this, but given what you've told me, I'd suggest you go for the freeglut-only route at this point. It's better to have something robust and easy to implement that works, even if it works with some restrictions, than to try to make something very general that's impossible to maintain later on.

Once this is out, if there's a user out there for whom the freeglut restriction is a problem, then it's their job to improve the code towards full glut support. But that shouldn't be your problem for now :)

In general, when in doubt, go for the simpler solution. It's almost always the right one :)

Nicolas P. Rougier
Fernando Perez
Owner

I just replied on list a second ago. short story: don't worry, just print 'KeyboardInterrupt' and let the user hit 'enter' to get a new prompt.

By the way, I just noticed that right now this doesn't merge cleanly anymore, there are conflicts. You may want to rebase it on top of master (and just do a push --force) so it can be merged.

Nicolas P. Rougier
rougier added some commits
Nicolas P. Rougier rougier Added code for the GLUT interactive session f4b8b67
Nicolas P. Rougier rougier Event loop integration example 0afe6a7
Nicolas P. Rougier rougier Canceled window reshape to 1x1 since the idea is now for the user to …
…use this window as the main one because of weird seg-faults problem after user creates its own window (any subsequent gl error would lead to a segfault, even a simple one line requiring a non existent function
c92f130
Nicolas P. Rougier rougier Fixed typos in comments eb76eab
Nicolas P. Rougier rougier Replaced deprecated raise call 81308e3
Nicolas P. Rougier
Fernando Perez
Owner

Hi Nicolas,

I'm really sorry you're having trouble! As it turns out, this really was a fairly tricky rebase/merge to do, because it was going to inevitably lead to conflicts, since the pyglet code and the glut one were pretty much in the same place.

So I went ahead and manually, carefully rebased the whole thing and cleared all the conflicts, ensuring that there's a glut branch that now sits cleanly on top of master (so it has the pyglet code in it). You can get it here:

https://github.com/fperez/ipython/tree/glut-rebased

This has the last changes you had pushed to github from your glut branch, but all rebased to apply correctly on top of master, with all conflicts against the pyglet code fixed.

So I suggest you grab my rebased branch above and start working from this one, if you had any additional local changes.

By the way, a very useful thing to know about git, when you get into trouble, is the reflog command. This is a history of everything you've done in a git repo, for example in my ipython repo:

0c6df48 HEAD@{0}: checkout: moving from rougier-glut to glut-rebased
80f77d9 HEAD@{1}: checkout: moving from glut-rebased to rougier-glut
0c6df48 HEAD@{2}: rebase: Added the command line option
02ff6fe HEAD@{3}: rebase: Fix code in disable_glut which was not tested and quite buggy
cf4c326 HEAD@{4}: rebase: Tried to fix the CTRL-C problem (https://github.com/ipython/ipython/pull/742) and take other comments/typos into account
81308e3 HEAD@{5}: rebase: Replaced deprecated raise call
eb76eab HEAD@{6}: rebase: Fixed typos in comments
etc...

If you realize that any of those points was the one you wanted to be at, you can always manually go to it. Let's say that 02ff6fe was a 'safe' point and that you want to undo things after that. You can:

git checkout 02ff6fe
git branch "new branch name here"

The first command puts you in that point in the history, and the second makes it a named branch so you can start working again.

Sorry if this one turned out to be a little complicated, unfortunately the pyglet and glut changes were in the same parts of a file and they caused a conflict... But I'm willing to help you until we sort things out, so just let me know how it goes and I'm sure we'll be able to finish it.

Once you're OK again, we'll resume review. There is enough complexity in the glut code that I'd like to break some of that into a separate file rather than having so many nested function definitions, which make the code very hard to read and test.

Fernando Perez
Owner

Ah!! I did all that yesterday night to try to help you, but once I finished my internet connection died, and I wasn't able to send it until this morning. Which means you ended up repeating the same work :)

Oh well, good learning experience nonetheless!

By the way, it seems you changed the original branch name, so now github is showing us a diff against the wrong branch. I think the simplest solution will be to open a new pull request, so that we start with a clean slate for review. Can you do that? Just open a fresh pull request with your currently clean branch, and we'll take it from there. I can add a link back to this discussion to make it easy to find previous parts of the conversation.

Sorry this one turned out to be so tricky... Thanks for your patience!

Nicolas P. Rougier
Fernando Perez
Owner

Quite the opposite, it's my fault for not giving you clearer instructions at the start! In any case, thanks for being patient, and we'll work together through it, don't worry :)

One more thing I should have told you that I didn't: when I said to pull from my branch, I meant that you could grab my branch, while keeping your fork off the official one. In general, it's not a good idea to fork off personal repos that may or may not be normally updated. For example, I don't update my master branch regularly at all, since I only use my repo for development of new branches, and when I want the official branch I just follow the ipython/ipython repo.

So what I meant was that you could keep your fork like you had it, and you could have just pulled that one branch from me with

git pull origin master  # assuming 'origin' is the name you have for the official one, if not adjust
git checkout -b glut
git reset --hard master
git pull git://github.com/fperez/ipython.git glut-rebased
git push rougier glut  # assuming 'rougier' is the name you have for your fork, if not adjust

That would have given you a copy of my branch as your new starting point.

If you want to update to this, I'm happy to help you. Let me know if you'd like a bit of help via skype or on IRC and I'm happy to do so.

Nicolas P. Rougier
Fernando Perez
Owner
rougier added some commits
Nicolas P. Rougier rougier Merge branch 'glut-rebased' of git://github.com/fperez/ipython into glut
* 'glut-rebased' of git://github.com/fperez/ipython:
  Added the command line option
  Fix code in disable_glut which was not tested and quite buggy
  Tried to fix the CTRL-C problem (ipython#742) and take other comments/typos into account
  Replaced deprecated raise call
  Fixed typos in comments
  Canceled window reshape to 1x1 since the idea is now for the user to use this window as the main one because of weird seg-faults problem after user creates its own window (any subsequent gl error would lead to a segfault, even a simple one line requiring a non existent function
  Event loop integration example
  Added code for the GLUT interactive session
89161a5
Nicolas P. Rougier rougier Factorized glut code into glut_support.py e095f42
Nicolas P. Rougier

I Did not find the error you're talking about. Where is the comment exactly ?

Fernando Perez
Owner

Mmh, actually I have no idea! Sorry, I can't find the comment either and I don't remember what I was referring to...

But anyway: right now there's still the problem that if I close the glut window, it crashes ipython immediately and leaves the terminal 'wedged', so that you have to type reset blind (no echo) to restore it to a functional state.

Do you have a way to fix that problem? Or do you not get it on your box? I'm seeing it on an ubuntu 10.10 machine...

Nicolas P. Rougier rougier Removed the timer callback in favor of the idle one and re-use wx wai…
…ting time after an event is processed. This make things more reactive. Also, the created window is now made insivisible and is not supposed to be ever show or detroyed. Finally, fixed the bug in window closing for linux platform using the glutSetOption available on Freeglut.
c675614
Nicolas P. Rougier
Fernando Perez
Owner

Ah, I found the error I was talking about earlier! I don't know why it disappeared from the comments, probably got lost in the rebase confusion.

In any case, if you now try to run ipython with --gui glut, you get these error messages:

/home/fperez/usr/lib/python2.6/site-packages/IPython/lib/inputhook.py:289: SyntaxWarning: import * only allowed at module level
  def enable_glut(self, app=None):
/home/fperez/usr/lib/python2.6/site-packages/IPython/lib/inputhook.py:339: SyntaxWarning: import * only allowed at module level
  def disable_glut(self):

the reason is that you are never allowed to say from x import * inside a function. The import * idiom is only allowed at the module level. In a function, you can only use from x import a, b, c.

I suggest that you always test your changes both with --gui glut and with %gui glut, to catch these issues.

But we're almost there :) The crash is indeed gone, and the code looks much cleaner. So once you fix the above little problem by importing specifically the functions you need, or using import x; x.a() inside your functions, I'll be able to merge.

Thanks for your patience in working through this, I know it's hard work but we need the code that goes in to be really clean and solid, as we'll need to maintain it for a long time to come... This is one of the pull requests with the highest number of comments we've had in a while, but in the end I'm sure it will be worth it :)

Nicolas P. Rougier
Fernando Perez
Owner

In its final form it looks great, thanks a lot Nicolas! Merging now.

Fernando Perez fperez merged commit 833bbcc into from
matthew von rocketstein mattvonrocketstein referenced this pull request from a commit in mattvonrocketstein/ipython
Nicolas P. Rougier rougier Tried to fix the CTRL-C problem (ipython#742) and take other comments…
…/typos into account
d9cd725
matthew von rocketstein mattvonrocketstein referenced this pull request from a commit in mattvonrocketstein/ipython
Nicolas P. Rougier rougier Merge branch 'glut-rebased' of git://github.com/fperez/ipython into glut
* 'glut-rebased' of git://github.com/fperez/ipython:
  Added the command line option
  Fix code in disable_glut which was not tested and quite buggy
  Tried to fix the CTRL-C problem (ipython#742) and take other comments/typos into account
  Replaced deprecated raise call
  Fixed typos in comments
  Canceled window reshape to 1x1 since the idea is now for the user to use this window as the main one because of weird seg-faults problem after user creates its own window (any subsequent gl error would lead to a segfault, even a simple one line requiring a non existent function
  Event loop integration example
  Added code for the GLUT interactive session
c21461b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 14, 2011
  1. Nicolas P. Rougier Fernando Perez

    Added code for the GLUT interactive session

    rougier authored fperez committed
  2. Nicolas P. Rougier Fernando Perez

    Event loop integration example

    rougier authored fperez committed
  3. Nicolas P. Rougier Fernando Perez

    Canceled window reshape to 1x1 since the idea is now for the user to …

    rougier authored fperez committed
    …use this window as the main one because of weird seg-faults problem after user creates its own window (any subsequent gl error would lead to a segfault, even a simple one line requiring a non existent function
  4. Nicolas P. Rougier Fernando Perez

    Fixed typos in comments

    rougier authored fperez committed
  5. Nicolas P. Rougier Fernando Perez

    Replaced deprecated raise call

    rougier authored fperez committed
  6. Nicolas P. Rougier Fernando Perez

    Tried to fix the CTRL-C problem (ipython#742) and take other comments…

    rougier authored fperez committed
    …/typos into account
  7. Nicolas P. Rougier Fernando Perez
  8. Nicolas P. Rougier Fernando Perez

    Added the command line option

    rougier authored fperez committed
Commits on Sep 15, 2011
  1. Nicolas P. Rougier

    Merge branch 'glut-rebased' of git://github.com/fperez/ipython into glut

    rougier authored
    * 'glut-rebased' of git://github.com/fperez/ipython:
      Added the command line option
      Fix code in disable_glut which was not tested and quite buggy
      Tried to fix the CTRL-C problem (ipython#742) and take other comments/typos into account
      Replaced deprecated raise call
      Fixed typos in comments
      Canceled window reshape to 1x1 since the idea is now for the user to use this window as the main one because of weird seg-faults problem after user creates its own window (any subsequent gl error would lead to a segfault, even a simple one line requiring a non existent function
      Event loop integration example
      Added code for the GLUT interactive session
  2. Nicolas P. Rougier
Commits on Sep 16, 2011
  1. Nicolas P. Rougier

    Removed the timer callback in favor of the idle one and re-use wx wai…

    rougier authored
    …ting time after an event is processed. This make things more reactive. Also, the created window is now made insivisible and is not supposed to be ever show or detroyed. Finally, fixed the bug in window closing for linux platform using the glutSetOption available on Freeglut.
  2. Nicolas P. Rougier
Commits on Sep 17, 2011
  1. Nicolas P. Rougier
This page is out of date. Refresh to see the latest.
4 IPython/frontend/terminal/ipapp.py
View
@@ -229,8 +229,8 @@ def _quick_changed(self, name, old, new):
self.load_config_file = lambda *a, **kw: None
self.ignore_old_config=True
- gui = CaselessStrEnum(('qt','wx','gtk', 'pyglet'), config=True,
- help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'pyglet')."
+ gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
+ help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
)
pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
config=True,
1  IPython/lib/__init__.py
View
@@ -19,6 +19,7 @@
enable_gtk, disable_gtk,
enable_qt4, disable_qt4,
enable_tk, disable_tk,
+ enable_glut, disable_glut,
enable_pyglet, disable_pyglet,
set_inputhook, clear_inputhook,
current_gui
70 IPython/lib/inputhook.py
View
@@ -29,6 +29,7 @@
GUI_GTK = 'gtk'
GUI_TK = 'tk'
GUI_OSX = 'osx'
+GUI_GLUT = 'glut'
GUI_PYGLET = 'pyglet'
#-----------------------------------------------------------------------------
@@ -285,6 +286,71 @@ def disable_tk(self):
self.clear_inputhook()
+ def enable_glut(self, app=None):
+ """ Enable event loop integration with GLUT.
+
+ Parameters
+ ----------
+
+ app : ignored
+ Ignored, it's only a placeholder to keep the call signature of all
+ gui activation methods consistent, which simplifies the logic of
+ supporting magics.
+
+ Notes
+ -----
+
+ This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
+ integrate with terminal based applications like IPython. Due to GLUT
+ limitations, it is currently not possible to start the event loop
+ without first creating a window. You should thus not create another
+ window but use instead the created one. See 'gui-glut.py' in the
+ docs/examples/lib directory.
+
+ The default screen mode is set to:
+ glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
+ """
+
+ import OpenGL.GLUT as glut
+ from IPython.lib.inputhookglut import glut_display_mode, \
+ glut_close, glut_display, \
+ glut_idle, inputhook_glut
+
+ if not self._apps.has_key( GUI_GLUT ):
+ glut.glutInit( sys.argv )
+ glut.glutInitDisplayMode( glut_display_mode )
+ # This is specific to freeglut
+ if bool(glut.glutSetOption):
+ glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
+ glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
+ glut.glutCreateWindow( sys.argv[0] )
+ glut.glutReshapeWindow( 1, 1 )
+ glut.glutHideWindow( )
+ glut.glutWMCloseFunc( glut_close )
+ glut.glutDisplayFunc( glut_display )
+ glut.glutIdleFunc( glut_idle )
+ else:
+ glut.glutWMCloseFunc( glut_close )
+ glut.glutDisplayFunc( glut_display )
+ glut.glutIdleFunc( glut_idle)
+ self.set_inputhook( inputhook_glut )
+ self._current_gui = GUI_GLUT
+ self._apps[GUI_GLUT] = True
+
+
+ def disable_glut(self):
+ """Disable event loop integration with glut.
+
+ This sets PyOS_InputHook to NULL and set the display function to a
+ dummy one and set the timer to a dummy timer that will be triggered
+ very far in the future.
+ """
+ import OpenGL.GLUT as glut
+ from glut_support import glutMainLoopEvent
+
+ glut.glutHideWindow() # This is an event to be processed below
+ glutMainLoopEvent()
+ self.clear_inputhook()
def enable_pyglet(self, app=None):
"""Enable event loop integration with pyglet.
@@ -316,7 +382,6 @@ def disable_pyglet(self):
"""
self.clear_inputhook()
-
def current_gui(self):
"""Return a string indicating the currently active GUI or None."""
return self._current_gui
@@ -331,6 +396,8 @@ def current_gui(self):
disable_gtk = inputhook_manager.disable_gtk
enable_tk = inputhook_manager.enable_tk
disable_tk = inputhook_manager.disable_tk
+enable_glut = inputhook_manager.enable_glut
+disable_glut = inputhook_manager.disable_glut
enable_pyglet = inputhook_manager.enable_pyglet
disable_pyglet = inputhook_manager.disable_pyglet
clear_inputhook = inputhook_manager.clear_inputhook
@@ -371,6 +438,7 @@ def enable_gui(gui=None, app=None):
GUI_WX: enable_wx,
GUI_QT: enable_qt4, # qt3 not supported
GUI_QT4: enable_qt4,
+ GUI_GLUT: enable_glut,
GUI_PYGLET: enable_pyglet,
}
try:
176 IPython/lib/inputhookglut.py
View
@@ -0,0 +1,176 @@
+# coding: utf-8
+"""
+GLUT Inputhook support functions
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+# GLUT is quite an old library and it is difficult to ensure proper
+# integration within IPython since original GLUT does not allow to handle
+# events one by one. Instead, it requires for the mainloop to be entered
+# and never returned (there is not even a function to exit he
+# mainloop). Fortunately, there are alternatives such as freeglut
+# (available for linux and windows) and the OSX implementation gives
+# access to a glutCheckLoop() function that blocks itself until a new
+# event is received. This means we have to setup the idle callback to
+# ensure we got at least one event that will unblock the function.
+#
+# Furthermore, it is not possible to install these handlers without a window
+# being first created. We choose to make this window invisible. This means that
+# display mode options are set at this level and user won't be able to change
+# them later without modifying the code. This should probably be made available
+# via IPython options system.
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+import os
+import sys
+import time
+import signal
+import OpenGL
+import OpenGL.GLUT as glut
+import OpenGL.platform as platform
+from timeit import default_timer as clock
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+# Frame per second : 60
+# Should probably be an IPython option
+glut_fps = 60
+
+
+# Display mode : double buffeed + rgba + depth
+# Should probably be an IPython option
+glut_display_mode = (glut.GLUT_DOUBLE |
+ glut.GLUT_RGBA |
+ glut.GLUT_DEPTH)
+
+glutMainLoopEvent = None
+if sys.platform == 'darwin':
+ try:
+ glutCheckLoop = platform.createBaseFunction(
+ 'glutCheckLoop', dll=platform.GLUT, resultType=None,
+ argTypes=[],
+ doc='glutCheckLoop( ) -> None',
+ argNames=(),
+ )
+ except AttributeError:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions'''
+ '''Consider installing freeglut.''')
+ glutMainLoopEvent = glutCheckLoop
+elif glut.HAVE_FREEGLUT:
+ glutMainLoopEvent = glut.glutMainLoopEvent
+else:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions. '''
+ '''Consider installing freeglut.''')
+
+
+#-----------------------------------------------------------------------------
+# Platform-dependent imports and functions
+#-----------------------------------------------------------------------------
+
+if os.name == 'posix':
+ import select
+
+ def stdin_ready():
+ infds, outfds, erfds = select.select([sys.stdin],[],[],0)
+ if infds:
+ return True
+ else:
+ return False
+
+elif sys.platform == 'win32':
+ import msvcrt
+
+ def stdin_ready():
+ return msvcrt.kbhit()
+
+#-----------------------------------------------------------------------------
+# Callback functions
+#-----------------------------------------------------------------------------
+
+def glut_display():
+ # Dummy display function
+ pass
+
+def glut_idle():
+ # Dummy idle function
+ pass
+
+def glut_close():
+ # Close function only hides the current window
+ glut.glutHideWindow()
+ glutMainLoopEvent()
+
+def glut_int_handler(signum, frame):
+ # Catch sigint and print the defautl message
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+ print '\nKeyboardInterrupt'
+ # Need to reprint the prompt at this stage
+
+
+
+#-----------------------------------------------------------------------------
+# Code
+#-----------------------------------------------------------------------------
+def inputhook_glut():
+ """Run the pyglet event loop by processing pending events only.
+
+ This keeps processing pending events until stdin is ready. After
+ processing all pending events, a call to time.sleep is inserted. This is
+ needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
+ though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+
+ signal.signal(signal.SIGINT, glut_int_handler)
+
+ try:
+ t = clock()
+
+ # Make sure the default window is set after a window has been closed
+ if glut.glutGetWindow() == 0:
+ glut.glutSetWindow( 1 )
+ glutMainLoopEvent()
+ return 0
+
+ while not stdin_ready():
+ glutMainLoopEvent()
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 5*60.0:
+ # print 'Sleep for 5 s' # dbg
+ time.sleep(5.0)
+ elif used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ except KeyboardInterrupt:
+ pass
+ return 0
51 docs/examples/lib/gui-glut.py
View
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+"""Simple GLUT example to manually test event loop integration.
+
+This is meant to run tests manually in ipython as:
+
+In [5]: %gui glut
+
+In [6]: %run gui-glut.py
+
+In [7]: gl.glClearColor(1,1,1,1)
+"""
+
+#!/usr/bin/env python
+import sys
+import OpenGL.GL as gl
+import OpenGL.GLUT as glut
+
+def close():
+ glut.glutDestroyWindow(glut.glutGetWindow())
+
+def display():
+ gl.glClear (gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
+ glut.glutSwapBuffers()
+
+def resize(width,height):
+ gl.glViewport(0, 0, width, height+4)
+ gl.glMatrixMode(gl.GL_PROJECTION)
+ gl.glLoadIdentity()
+ gl.glOrtho(0, width, 0, height+4, -1, 1)
+ gl.glMatrixMode(gl.GL_MODELVIEW)
+
+if glut.glutGetWindow() > 0:
+ interactive = True
+ glut.glutInit(sys.argv)
+ glut.glutInitDisplayMode(glut.GLUT_DOUBLE |
+ glut.GLUT_RGBA |
+ glut.GLUT_DEPTH)
+else:
+ interactive = False
+
+glut.glutCreateWindow('gui-glut')
+glut.glutDisplayFunc(display)
+glut.glutReshapeFunc(resize)
+# This is necessary on osx to be able to close the window
+# (else the close button is disabled)
+if sys.platform == 'darwin' and not bool(glut.HAVE_FREEGLUT):
+ glut.glutWMCloseFunc(close)
+gl.glClearColor(0,0,0,1)
+
+if not interactive:
+ glut.glutMainLoop()
Something went wrong with that request. Please try again.