]> git.saurik.com Git - wxWidgets.git/blame - wxPython/src/_core_ex.py
fixed deadlock when calling wxPostEvent() from worker thread
[wxWidgets.git] / wxPython / src / _core_ex.py
CommitLineData
d14a1e28
RD
1#----------------------------------------------------------------------------
2
322913ce 3# Use Python's bool constants if available, make some if not
d14a1e28
RD
4try:
5 True
6except NameError:
322913ce
RD
7 __builtins__.True = 1==1
8 __builtins__.False = 1==0
c19bd0a3
RD
9 def bool(value): return not not value
10 __builtins__.bool = bool
d14a1e28 11
d14a1e28
RD
12
13
14# workarounds for bad wxRTTI names
15__wxPyPtrTypeMap['wxGauge95'] = 'wxGauge'
16__wxPyPtrTypeMap['wxSlider95'] = 'wxSlider'
17__wxPyPtrTypeMap['wxStatusBar95'] = 'wxStatusBar'
18
19
20#----------------------------------------------------------------------------
21# Load version numbers from __version__... Ensure that major and minor
611190df 22# versions are the same for both wxPython and wxWidgets.
d14a1e28
RD
23
24from __version__ import *
25__version__ = VERSION_STRING
26
611190df
RD
27assert MAJOR_VERSION == _core_.MAJOR_VERSION, "wxPython/wxWidgets version mismatch"
28assert MINOR_VERSION == _core_.MINOR_VERSION, "wxPython/wxWidgets version mismatch"
54f9ee45 29if RELEASE_VERSION != _core_.RELEASE_VERSION:
d14a1e28 30 import warnings
611190df 31 warnings.warn("wxPython/wxWidgets release number mismatch")
d14a1e28 32
a47418db
RD
33
34def version():
35 """Returns a string containing version and port info"""
36 ctype = wx.USE_UNICODE and 'unicode' or 'ansi'
37 if wx.Platform == '__WXMSW__':
38 port = 'msw'
39 elif wx.Platform == '__WXMAC__':
40 port = 'mac'
41 elif wx.Platform == '__WXGTK__':
42 port = 'gtk'
43 if 'gtk2' in wx.PlatformInfo:
44 port = 'gtk2'
45 else:
46 port = '?'
47
48 return "%s (%s-%s)" % (wx.VERSION_STRING, port, ctype)
49
50
d14a1e28
RD
51#----------------------------------------------------------------------------
52
ac3b7152
RD
53# Set wxPython's default string<-->unicode conversion encoding from
54# the locale, but only if Python's default hasn't been changed. (We
55# assume that if the user has customized it already then that is the
56# encoding we need to use as well.)
57#
58# The encoding selected here is used when string or unicode objects
59# need to be converted in order to pass them to wxWidgets. Please be
60# aware that the default encoding within the same locale may be
61# slightly different on different platforms. For example, please see
669e06d7
RD
62# http://www.alanwood.net/demos/charsetdiffs.html for differences
63# between the common latin/roman encodings.
dd898dd8
RD
64
65default = _sys.getdefaultencoding()
66if default == 'ascii':
67 import locale
68 import codecs
69 try:
474e2ff2
RD
70 if hasattr(locale, 'getpreferredencoding'):
71 default = locale.getpreferredencoding()
72 else:
73 default = locale.getdefaultlocale()[1]
dd898dd8 74 codecs.lookup(default)
bbf07386 75 except (ValueError, LookupError, TypeError):
dd898dd8
RD
76 default = _sys.getdefaultencoding()
77 del locale
78 del codecs
4293f847
RD
79if default:
80 wx.SetDefaultPyEncoding(default)
81del default
4293f847
RD
82
83#----------------------------------------------------------------------------
84
d14a1e28
RD
85class PyDeadObjectError(AttributeError):
86 pass
87
d14a1e28
RD
88class _wxPyDeadObject(object):
89 """
90 Instances of wx objects that are OOR capable will have their __class__
91 changed to this class when the C++ object is deleted. This should help
92 prevent crashes due to referencing a bogus C++ pointer.
93 """
94 reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)"
95 attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed."
96
9e58eb56 97 def __repr__(self):
d14a1e28
RD
98 if not hasattr(self, "_name"):
99 self._name = "[unknown]"
100 return self.reprStr % self._name
101
9e58eb56 102 def __getattr__(self, *args):
d14a1e28
RD
103 if not hasattr(self, "_name"):
104 self._name = "[unknown]"
9e58eb56
RD
105 raise PyDeadObjectError(self.attrStr % self._name)
106
107 def __nonzero__(self):
108 return 0
109
110
111
112class PyUnbornObjectError(AttributeError):
113 pass
114
115class _wxPyUnbornObject(object):
116 """
54f9ee45 117 Some stock objects are created when the wx._core module is
9e58eb56
RD
118 imported, but their C++ instance is not created until the wx.App
119 object is created and initialized. These object instances will
120 temporarily have their __class__ changed to this class so an
121 exception will be raised if they are used before the C++ instance
122 is ready.
123 """
124
125 reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)"
126 attrStr = "The C++ part of this object has not been initialized, attribute access not allowed."
127
128 def __repr__(self):
129 #if not hasattr(self, "_name"):
130 # self._name = "[unknown]"
131 return self.reprStr #% self._name
132
133 def __getattr__(self, *args):
134 #if not hasattr(self, "_name"):
135 # self._name = "[unknown]"
136 raise PyUnbornObjectError(self.attrStr) # % self._name )
d14a1e28
RD
137
138 def __nonzero__(self):
139 return 0
140
141
142#----------------------------------------------------------------------------
d14a1e28
RD
143
144def CallAfter(callable, *args, **kw):
145 """
146 Call the specified function after the current and pending event
147 handlers have been completed. This is also good for making GUI
61863841
RD
148 method calls from non-GUI threads. Any extra positional or
149 keyword args are passed on to the callable when it is called.
150
8feec28c 151 :see: `wx.CallLater`
d14a1e28
RD
152 """
153 app = wx.GetApp()
2148e701 154 assert app is not None, 'No wx.App created yet'
d14a1e28 155
b0cafb91
RD
156 if not hasattr(app, "_CallAfterId"):
157 app._CallAfterId = wx.NewEventType()
158 app.Connect(-1, -1, app._CallAfterId,
159 lambda event: event.callable(*event.args, **event.kw) )
d14a1e28 160 evt = wx.PyEvent()
b0cafb91 161 evt.SetEventType(app._CallAfterId)
d14a1e28
RD
162 evt.callable = callable
163 evt.args = args
164 evt.kw = kw
165 wx.PostEvent(app, evt)
166
d14a1e28
RD
167#----------------------------------------------------------------------------
168
169
8feec28c 170class CallLater:
d14a1e28 171 """
a3c9f064 172 A convenience class for `wx.Timer`, that calls the given callable
d14a1e28
RD
173 object once after the given amount of milliseconds, passing any
174 positional or keyword args. The return value of the callable is
61863841 175 availbale after it has been run with the `GetResult` method.
d14a1e28
RD
176
177 If you don't need to get the return value or restart the timer
178 then there is no need to hold a reference to this object. It will
179 hold a reference to itself while the timer is running (the timer
180 has a reference to self.Notify) but the cycle will be broken when
8feec28c 181 the timer completes, automatically cleaning up the wx.CallLater
d14a1e28 182 object.
61863841
RD
183
184 :see: `wx.CallAfter`
d14a1e28
RD
185 """
186 def __init__(self, millis, callable, *args, **kwargs):
187 self.millis = millis
188 self.callable = callable
189 self.SetArgs(*args, **kwargs)
190 self.runCount = 0
66065839 191 self.running = False
d14a1e28
RD
192 self.hasRun = False
193 self.result = None
194 self.timer = None
195 self.Start()
196
197 def __del__(self):
198 self.Stop()
199
200
201 def Start(self, millis=None, *args, **kwargs):
202 """
203 (Re)start the timer
204 """
205 self.hasRun = False
206 if millis is not None:
207 self.millis = millis
208 if args or kwargs:
209 self.SetArgs(*args, **kwargs)
210 self.Stop()
211 self.timer = wx.PyTimer(self.Notify)
212 self.timer.Start(self.millis, wx.TIMER_ONE_SHOT)
66065839 213 self.running = True
d14a1e28
RD
214 Restart = Start
215
216
217 def Stop(self):
218 """
219 Stop and destroy the timer.
220 """
221 if self.timer is not None:
222 self.timer.Stop()
223 self.timer = None
224
225
226 def GetInterval(self):
227 if self.timer is not None:
228 return self.timer.GetInterval()
229 else:
230 return 0
231
232
233 def IsRunning(self):
234 return self.timer is not None and self.timer.IsRunning()
235
236
237 def SetArgs(self, *args, **kwargs):
238 """
239 (Re)set the args passed to the callable object. This is
240 useful in conjunction with Restart if you want to schedule a
241 new call to the same callable object but with different
242 parameters.
243 """
244 self.args = args
245 self.kwargs = kwargs
246
247
248 def HasRun(self):
249 return self.hasRun
250
251 def GetResult(self):
252 return self.result
253
254 def Notify(self):
255 """
256 The timer has expired so call the callable.
257 """
258 if self.callable and getattr(self.callable, 'im_self', True):
259 self.runCount += 1
66065839 260 self.running = False
d14a1e28
RD
261 self.result = self.callable(*self.args, **self.kwargs)
262 self.hasRun = True
66065839
RD
263 if not self.running:
264 # if it wasn't restarted, then cleanup
265 wx.CallAfter(self.Stop)
d14a1e28 266
42e2bbb9
RD
267 Interval = property(GetInterval)
268 Result = property(GetResult)
d14a1e28 269
5b29df3f 270
8feec28c 271class FutureCall(CallLater):
846c181b 272 """A compatibility alias for `CallLater`."""
8feec28c 273
5b29df3f
RD
274#----------------------------------------------------------------------------
275# Control which items in this module should be documented by epydoc.
276# We allow only classes and functions, which will help reduce the size
277# of the docs by filtering out the zillions of constants, EVT objects,
278# and etc that don't make much sense by themselves, but are instead
279# documented (or will be) as part of the classes/functions/methods
280# where they should be used.
281
99109c0f
RD
282class __DocFilter:
283 """
284 A filter for epydoc that only allows non-Ptr classes and
955e46d2 285 functions, in order to reduce the clutter in the API docs.
99109c0f
RD
286 """
287 def __init__(self, globals):
288 self._globals = globals
289
290 def __call__(self, name):
291 import types
292 obj = self._globals.get(name, None)
a8ec3708
RD
293
294 # only document classes and function
99109c0f
RD
295 if type(obj) not in [type, types.ClassType, types.FunctionType, types.BuiltinFunctionType]:
296 return False
a8ec3708
RD
297
298 # skip other things that are private or will be documented as part of somethign else
ace78e27 299 if name.startswith('_') or name.startswith('EVT') or name.endswith('_swigregister') or name.endswith('Ptr') :
99109c0f 300 return False
a8ec3708
RD
301
302 # skip functions that are duplicates of static functions in a class
303 if name.find('_') != -1:
304 cls = self._globals.get(name.split('_')[0], None)
305 methname = name.split('_')[1]
306 if hasattr(cls, methname) and type(getattr(cls, methname)) is types.FunctionType:
307 return False
308
99109c0f 309 return True
5b29df3f 310
d14a1e28
RD
311#----------------------------------------------------------------------------
312#----------------------------------------------------------------------------
313
314# Import other modules in this package that should show up in the
315# "core" wx namespace
54f9ee45
RD
316from _gdi import *
317from _windows import *
318from _controls import *
319from _misc import *
d14a1e28
RD
320
321#----------------------------------------------------------------------------
322#----------------------------------------------------------------------------