|
1 | | -import subprocess |
2 | 1 | import sys |
3 | | -from test import support |
4 | 2 | import tkinter |
5 | 3 | import unittest |
6 | 4 |
|
7 | | -_tk_available = None |
| 5 | +_tk_unavailable = None |
8 | 6 |
|
9 | 7 | def check_tk_availability(): |
10 | 8 | """Check that Tk is installed and available.""" |
11 | | - global _tk_available |
| 9 | + global _tk_unavailable |
12 | 10 |
|
13 | | - if _tk_available is not None: |
14 | | - return |
| 11 | + if _tk_unavailable is None: |
| 12 | + _tk_unavailable = False |
| 13 | + if sys.platform == 'darwin': |
| 14 | + # The Aqua Tk implementations on OS X can abort the process if |
| 15 | + # being called in an environment where a window server connection |
| 16 | + # cannot be made, for instance when invoked by a buildbot or ssh |
| 17 | + # process not running under the same user id as the current console |
| 18 | + # user. To avoid that, raise an exception if the window manager |
| 19 | + # connection is not available. |
| 20 | + from ctypes import cdll, c_int, pointer, Structure |
| 21 | + from ctypes.util import find_library |
15 | 22 |
|
16 | | - if sys.platform == 'darwin': |
17 | | - # The Aqua Tk implementations on OS X can abort the process if |
18 | | - # being called in an environment where a window server connection |
19 | | - # cannot be made, for instance when invoked by a buildbot or ssh |
20 | | - # process not running under the same user id as the current console |
21 | | - # user. Instead, try to initialize Tk under a subprocess. |
22 | | - p = subprocess.Popen( |
23 | | - [sys.executable, '-c', 'import tkinter; tkinter.Button()'], |
24 | | - stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
25 | | - stderr = support.strip_python_stderr(p.communicate()[1]) |
26 | | - if stderr or p.returncode: |
27 | | - raise unittest.SkipTest("tk cannot be initialized: %s" % stderr) |
28 | | - else: |
29 | | - try: |
30 | | - tkinter.Button() |
31 | | - except tkinter.TclError as msg: |
32 | | - # assuming tk is not available |
33 | | - raise unittest.SkipTest("tk not available: %s" % msg) |
| 23 | + app_services = cdll.LoadLibrary(find_library("ApplicationServices")) |
34 | 24 |
|
35 | | - _tk_available = True |
| 25 | + if app_services.CGMainDisplayID() == 0: |
| 26 | + _tk_unavailable = "cannot run without OS X window manager" |
| 27 | + else: |
| 28 | + class ProcessSerialNumber(Structure): |
| 29 | + _fields_ = [("highLongOfPSN", c_int), |
| 30 | + ("lowLongOfPSN", c_int)] |
| 31 | + psn = ProcessSerialNumber() |
| 32 | + psn_p = pointer(psn) |
| 33 | + if ( (app_services.GetCurrentProcess(psn_p) < 0) or |
| 34 | + (app_services.SetFrontProcess(psn_p) < 0) ): |
| 35 | + _tk_unavailable = "cannot run without OS X gui process" |
| 36 | + else: # not OS X |
| 37 | + import tkinter |
| 38 | + try: |
| 39 | + tkinter.Button() |
| 40 | + except tkinter.TclError as msg: |
| 41 | + # assuming tk is not available |
| 42 | + _tk_unavailable = "tk not available: %s" % msg |
| 43 | + |
| 44 | + if _tk_unavailable: |
| 45 | + raise unittest.SkipTest(_tk_unavailable) |
36 | 46 | return |
37 | 47 |
|
38 | 48 | def get_tk_root(): |
|
0 commit comments