Repository: ipython/ipython

Issue:
Cannot close last figure window
After updating ipython to 5.0 (from macports), I cannot close last figure window (neither with button in window bar, nor with 'close()'). The mouse cursor becomes spinning wheel inside the window, but I can still type command in the terminal window.

However, if I type clf(), the figure window closes and a new one appears.

This happens only when there is only one figure window remaining. 

Here's my system (OS X  El Capitan, with python/ipython etc. installed via macports) :

```
[~] $ python -c "import IPython; print(IPython.sys_info())"
{'commit_hash': u'<not found>',
 'commit_source': '(none found)',
 'default_encoding': 'UTF-8',
 'ipython_path': '/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/IPython',
 'ipython_version': '5.0.0',
 'os_name': 'posix',
 'platform': 'Darwin-15.5.0-x86_64-i386-64bit',
 'sys_executable': '/opt/local/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python',
 'sys_platform': 'darwin',
 'sys_version': '2.7.12 (default, Jun 29 2016, 12:52:38) \n[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)]'}
```



Discussion:
Do you use the `%matplotlib` magic ? And/or which matplotlib backend are you using to plot ?

Oh, sorry I forgot to mention : I am using the OS X backend (as defined in my matplotlibrc file, so that it is selected automatically when calling "ipython --pylab"). I also tried starting with "ipython" and then doing "%matplotlib osx" but I get the same behavior.

Hum, that might be a macport issue, I'm unable to reproduce with other Python install like homebrew. Whether on py2 or py3, though I'm on Yosemite... 

Can you try a pip-installed version ?

@Carreau I'm experiencing the same issue with py3 on OSX 10.11.5 (EL Capitan) with ipython pip-installed, python3 installed through homebrew. 

Same issue with python27 installed with macports and ipython-5.0 installed via pip.

However, it works fine with Tk backend (macports install, starting with ipython --pylab-tk), I can close the figure window normally.

hum.. what about pure python shell ?

Pure python 3 shell does not seem to exhibit the same problem as ipython running the same version of python.

@minrk which version of OS X do you have ?

No problem when using pure python 2.7 directly (same macports version, with osx backend).

Same problem here:
- El Capitan 10.11.5
- Python 3.4.5
- Matplotlib 1.5.2
- IPython 5.0.0  

Python stack installed with Macports. It works fine with TkAgg as backend.

I also started encountering this problem today, after updating to IPython 5.0.0, with Python 3.5.2 and matplotlib 1.5.1 on OS X 10.11.5. Python installed with homebrew, IPython & matplotlib installed with pip.

This happens regardless of starting IPython with `--pylab` or not. The issue started with my IPython upgrade today.

I can reproduce this. We didn't need any eventloop integration for OS X before, so we don't have it in the PT stuff. Apparently we need something there, now. I'll investigate what we need.

Oops, we do have it and I wrote it. Apparently I wrote it wrong. Still self-assigning and investigating why it misbehaves when the window closes. I'm guessing it's because the app loop has stopped.

@minrk did you get anywhere with this? Should it block 5.1, or shall we bump it to 5.2?

I didn't get anywhere last time I looked into it. Let me spend a bit more time on it today. If everything else is done for 5.1 and I still haven't figured it out, we can bump it, but I'd prefer not to.

@minrk Perhaps related: https://github.com/ipython/ipython/pull/9312

Perhaps unrelated but Matplotlib 1.5 deprecated idle_event on all but wx http://matplotlib.org/api/api_changes.html?highlight=event%20loop#deprecated-idle-event


Resolving patch:
diff --git a/IPython/terminal/pt_inputhooks/osx.py b/IPython/terminal/pt_inputhooks/osx.py
--- a/IPython/terminal/pt_inputhooks/osx.py
+++ b/IPython/terminal/pt_inputhooks/osx.py
@@ -7,6 +7,7 @@
 
 import ctypes
 import ctypes.util
+from threading import Event
 
 objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
 
@@ -97,8 +98,11 @@ def _wake(NSApp):
     msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
 
 
+_triggered = Event()
+
 def _input_callback(fdref, flags, info):
     """Callback to fire when there's input to be read"""
+    _triggered.set()
     CFFileDescriptorInvalidate(fdref)
     CFRelease(fdref)
     NSApp = _NSApp()
@@ -111,6 +115,7 @@ def _input_callback(fdref, flags, info):
 
 def _stop_on_read(fd):
     """Register callback to stop eventloop when there's data on fd"""
+    _triggered.clear()
     fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
     CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
     source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
@@ -130,4 +135,9 @@ def inputhook(context):
         return
     _stop_on_read(context.fileno())
     msg(NSApp, n('run'))
-
+    if not _triggered.is_set():
+        # app closed without firing callback,
+        # probably due to last window being closed.
+        # Run the loop manually in this case,
+        # since there may be events still to process (#9734)
+        CoreFoundation.CFRunLoopRun()


Test patch: