11
11
12
12
import sys
13
13
import time
14
- import atexit
15
14
16
15
import glfw
17
16
@@ -151,14 +150,21 @@ def enable_glfw():
151
150
glfw ._rc_alive = True
152
151
153
152
154
- @atexit .register
155
- def terminate_glfw ():
156
- glfw .terminate ()
157
- glfw ._rc_alive = False
158
-
159
-
160
153
class GlfwCanvasGroup (BaseCanvasGroup ):
161
- pass
154
+ glfw = glfw # make sure we can access the glfw module in the __del__
155
+
156
+ def __del__ (self ):
157
+ # Because this object is used as a class attribute (on the canvas), this
158
+ # __del__ method gets called later than a function registed to atexit.
159
+ # This is important when used in combination with wgpu, where the release of the surface
160
+ # should happen before the termination of glfw. On some systems this can otherwiser
161
+ # result in a segfault, see https://github.com/pygfx/pygfx/issues/642
162
+ try :
163
+ self .glfw ._rc_alive = False
164
+ self .glfw .terminate ()
165
+ except Exception :
166
+ pass
167
+ super ().__del__ ()
162
168
163
169
164
170
class GlfwRenderCanvas (BaseRenderCanvas ):
@@ -260,7 +266,7 @@ def _on_want_close(self, *args):
260
266
def _maybe_close (self ):
261
267
if self ._window is not None :
262
268
if glfw .window_should_close (self ._window ):
263
- self ._rc_close ()
269
+ self .close ()
264
270
265
271
def _set_logical_size (self , new_logical_size ):
266
272
if self ._window is None :
@@ -341,10 +347,6 @@ def _rc_set_logical_size(self, width, height):
341
347
self ._set_logical_size ((float (width ), float (height )))
342
348
343
349
def _rc_close (self ):
344
- if not glfw ._rc_alive :
345
- # May not always be able to close the proper way on system exit
346
- self ._window = None
347
- return
348
350
if self ._window is not None :
349
351
glfw .destroy_window (self ._window ) # not just glfw.hide_window
350
352
self ._window = None
@@ -353,14 +355,13 @@ def _rc_close(self):
353
355
# But on some systems glfw needs a bit of time to properly close the window.
354
356
if not self ._rc_canvas_group .get_canvases ():
355
357
poll_glfw_briefly (0.05 )
356
- # Could also terminate glfw, but we don't know if the application is using glfw in other places.
357
- # terminate_glfw()
358
358
359
359
def _rc_get_closed (self ):
360
360
return self ._window is None
361
361
362
362
def _rc_set_title (self , title ):
363
- glfw .set_window_title (self ._window , title )
363
+ if self ._window is not None :
364
+ glfw .set_window_title (self ._window , title )
364
365
365
366
# %% Turn glfw events into rendercanvas events
366
367
@@ -565,14 +566,13 @@ def _on_char(self, window, char):
565
566
566
567
def poll_glfw_briefly (poll_time = 0.1 ):
567
568
"""Briefly poll glfw for a set amount of time.
568
-
569
569
Intended to work around the bug that destroyed windows sometimes hang
570
570
around if the mainloop exits: https://github.com/glfw/glfw/issues/1766
571
-
572
571
I found that 10ms is enough, but make it 100ms just in case. You should
573
572
only run this right after your mainloop stops.
574
-
575
573
"""
574
+ if not glfw ._rc_alive :
575
+ return
576
576
end_time = time .perf_counter () + poll_time
577
577
while time .perf_counter () < end_time :
578
578
glfw .wait_events_timeout (end_time - time .perf_counter ())
0 commit comments