@@ -385,7 +385,7 @@ def __init__(
385385 if not self ._is_active :
386386 if self ._exception :
387387 raise RuntimeError ("Unable to initialize an OpenGL 3+ context." ) from self ._exception
388- raise OpenGL .error .Error ("Invalid OpenGL context." )
388+ raise OpenGL .error .Error ("Invalid OpenGL context (unknown exception) ." )
389389 else :
390390 if self .auto_start :
391391 self .start ()
@@ -1116,38 +1116,73 @@ def start(self, auto_refresh=True):
11161116 confs [1 ],
11171117 ]
11181118 while confs :
1119- # Keep the window invisible for now. It will be displayed only if everything is working fine.
1120- # This approach avoids "flickering" when creating and closing an invalid context. Besides, it avoids
1121- # "frozen" graphical window during compilation that would be interpreted as as bug by the end-user.
11221119 conf = confs .pop (0 )
1120+
1121+ # Close any existing context and window
11231122 try :
1124- super ().__init__ (
1125- config = conf ,
1126- visible = False ,
1127- resizable = True ,
1128- width = self ._viewport_size [0 ],
1129- height = self ._viewport_size [1 ],
1130- )
1123+ OpenGL .contextdata .cleanupContext ()
1124+ self .set_visible (False )
1125+ except Exception :
1126+ pass
1127+ try :
1128+ super ().close ()
1129+ except Exception :
1130+ pass
1131+
1132+ try :
1133+ # Keep the window invisible for now. It will be displayed only if everything is working fine.
1134+ # This approach avoids "flickering" when creating and closing an invalid context. Besides, it avoids
1135+ # "frozen" graphical window during compilation that would be interpreted as as bug by the end-user.
1136+ try :
1137+ super ().__init__ (
1138+ config = conf ,
1139+ visible = False ,
1140+ resizable = True ,
1141+ width = self ._viewport_size [0 ],
1142+ height = self ._viewport_size [1 ],
1143+ )
1144+ except xlib_exceptions as e :
1145+ # Trying again without UTF8 support as a fallback.
1146+ # See: https://github.com/pyglet/pyglet/issues/1024
1147+ if pyglet .window .xlib ._have_utf8 :
1148+ pyglet .window .xlib ._have_utf8 = False
1149+ confs .insert (0 , conf )
1150+ raise
1151+
1152+ # At this point, we are all set to display the graphical window if requested
1153+ if not pyglet .options ["headless" ]:
1154+ self .set_visible (True )
1155+
1156+ # Run the entire rendering pipeline once, to make sure that everything is fine
1157+ self .refresh ()
1158+
11311159 break
1132- except xlib_exceptions as e :
1133- # Trying again without UTF8 support as a fallback.
1134- # See: https://github.com/pyglet/pyglet/issues/1024
1135- if not pyglet .window .xlib ._have_utf8 :
1136- if self ._run_in_thread :
1137- self .on_close ()
1138- self ._exception = e
1139- return
1140- else :
1141- raise RuntimeError ("Unable to initialize an OpenGL 3+ context." ) from e
1142- pyglet .window .xlib ._have_utf8 = False
1143- confs .insert (0 , conf )
1144- except (pyglet .window .NoSuchConfigException , pyglet .gl .ContextException ) as e :
1160+ except (
1161+ pyglet .window .NoSuchConfigException ,
1162+ pyglet .gl .ContextException ,
1163+ pyglet .gl .GLException ,
1164+ OpenGL .error .Error ,
1165+ AttributeError ,
1166+ ArgumentError ,
1167+ RuntimeError ,
1168+ ) as e :
11451169 if not confs :
1170+ # It is essential to set the exception before closing the viewer, otherwise the main thread preempt
1171+ # execution of this thread and wrongly report unknown exception.
11461172 if self ._run_in_thread :
1147- self .on_close ()
11481173 self ._exception = e
1174+
1175+ # Now the viewer can be safely cause to avoid leaving any global OpenGL context or window dangling
1176+ try :
1177+ self .on_close ()
1178+ except Exception :
1179+ pass
1180+
1181+ if self ._run_in_thread :
1182+ # Reporting the exception for the main thread to raise it
11491183 return
11501184 else :
1185+ # Raise the exception right away
11511186 raise RuntimeError ("Unable to initialize an OpenGL 3+ context." ) from e
11521187
11531188 if self ._run_in_thread :
@@ -1157,27 +1192,7 @@ def start(self, auto_refresh=True):
11571192 pyglet .clock .schedule (Viewer ._time_event , self )
11581193
11591194 # Update window title
1160- self .switch_to ()
11611195 self .set_caption (self .viewer_flags ["window_title" ])
1162-
1163- # Run the entire rendering pipeline once, to make sure that everything is fine
1164- try :
1165- self .refresh ()
1166- except (OpenGL .error .Error , RuntimeError ) as e :
1167- # Invalid OpenGL context and crossing threading boundaries. Closing before anything else
1168- self .on_close ()
1169-
1170- if self ._run_in_thread :
1171- # Reporting the exception for the main thread to raise it
1172- self ._exception = e
1173- return
1174- else :
1175- # Raise the exception right away
1176- raise
1177-
1178- # At this point, we are all set to display the graphical window if requested, finally!
1179- if not pyglet .options ["headless" ]:
1180- self .set_visible (True )
11811196 self .activate ()
11821197
11831198 # The viewer can be considered as fully initialized at this point
@@ -1220,6 +1235,7 @@ def refresh(self):
12201235 self ._event_loop_step_offscreen ()
12211236 self ._offscreen_event .clear ()
12221237
1238+ self .switch_to ()
12231239 pyglet .clock .tick ()
12241240
12251241 if gs .platform != "Windows" :
@@ -1229,7 +1245,6 @@ def refresh(self):
12291245 # this is a workaround on Windows. not sure if it's correct
12301246 time .sleep (0.001 )
12311247
1232- self .switch_to ()
12331248 self .dispatch_pending_events ()
12341249 if self ._is_active :
12351250 self .dispatch_events ()
0 commit comments