* some small cleanup
[LazOpenGLCore.git] / uglcContextGtk2GLX.pas
1 unit uglcContextGtk2GLX;\r
2 \r
3 { Package:      OpenGLCore\r
4   Prefix:       glc - OpenGL Core\r
5   Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Kontexte für Linux\r
6   Hint:         diese Unit sollte niemals direkt genutzt werden (siehe uglcContext) }\r
7 \r
8 interface\r
9 \r
10 uses\r
11   SysUtils, Controls, uglcContext, LCLType, XUtil, XLib, gdk2x, gtk2, gdk2, dglOpenGL,\r
12   LMessages, uglcContextGtkCustomVisual;\r
13 \r
14 type\r
15   EGLXError = class(EGLError);\r
16 \r
17   TRenderControl = class(TCustomVisualControl)\r
18   private\r
19     fTarget: TWinControl;\r
20   protected\r
21     procedure WndProc(var Message: TLMessage); override;\r
22   public\r
23     property Target: TWinControl read fTarget write fTarget;\r
24   end;\r
25 \r
26   { TglcContextGtk2GLX }\r
27 \r
28   TglcContextGtk2GLX = class(TglcContext)\r
29   private\r
30     FVisual: PXVisualInfo;\r
31     FDisplay: PDisplay;\r
32     FWidget: PGtkWidget;\r
33     FContext: GLXContext;\r
34     FRenderControl: TRenderControl;\r
35     procedure UpdateVisual(const aControl: TWinControl);\r
36   protected\r
37     procedure OpenContext; override;\r
38   public\r
39     constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings); override; overload;\r
40     constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings); override; overload;\r
41     destructor Destroy; override;\r
42 \r
43     procedure CloseContext; override;\r
44     procedure Activate; override;\r
45     procedure Deactivate; override;\r
46     function IsActive: boolean; override;\r
47     procedure SwapBuffers; override;\r
48     procedure SetSwapInterval(const aInterval: GLint); override;\r
49     procedure Share(const aContext: TglcContext); override;\r
50 \r
51     class function ChangeDisplaySettings(const aWidth, aHeight,\r
52       aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean; override;\r
53     class function IsAnyContextActive: boolean; override;\r
54   end;\r
55 \r
56 implementation\r
57 \r
58 type\r
59   TGLIntArray = packed array of GLInt;\r
60 \r
61 {$region messages -fold}\r
62 procedure TRenderControl.WndProc(var Message: TLMessage);\r
63 var\r
64   handled: Boolean;\r
65 begin\r
66   handled := false;\r
67   case Message.msg of\r
68     //LM_ACTIVATEITEM,\r
69     //LM_CHANGED,\r
70     //LM_FOCUS,\r
71     LM_CLICKED,\r
72     //LM_RELEASED,\r
73     LM_ENTER,\r
74     LM_LEAVE,\r
75     //LM_CHECKRESIZE,\r
76     //LM_SETEDITABLE,\r
77     //LM_MOVEWORD,\r
78     //LM_MOVEPAGE,\r
79     //LM_MOVETOROW,\r
80     //LM_MOVETOCOLUMN,\r
81     //LM_KILLCHAR,\r
82     //LM_KILLWORD,\r
83     //LM_KILLLINE,\r
84     //LM_CLOSEQUERY,\r
85     //LM_DRAGSTART,\r
86     //LM_MONTHCHANGED,\r
87     //LM_YEARCHANGED,\r
88     //LM_DAYCHANGED,\r
89     LM_LBUTTONTRIPLECLK,\r
90     LM_LBUTTONQUADCLK,\r
91     LM_MBUTTONTRIPLECLK,\r
92     LM_MBUTTONQUADCLK,\r
93     LM_RBUTTONTRIPLECLK,\r
94     LM_RBUTTONQUADCLK,\r
95     LM_MOUSEENTER,\r
96     LM_MOUSELEAVE,\r
97     LM_XBUTTONTRIPLECLK,\r
98     LM_XBUTTONQUADCLK,\r
99 \r
100     //SC_SIZE,\r
101     //SC_MOVE,\r
102     //SC_MINIMIZE,\r
103     //SC_MAXIMIZE,\r
104     //SC_NEXTWINDOW,\r
105     //SC_PREVWINDOW,\r
106     //SC_CLOSE,\r
107     SC_VSCROLL,\r
108     SC_HSCROLL,\r
109     SC_MOUSEMENU,\r
110     SC_KEYMENU,\r
111     //SC_ARRANGE,\r
112     //SC_RESTORE,\r
113     //SC_TASKLIST,\r
114     //SC_SCREENSAVE,\r
115     //SC_HOTKEY,\r
116     //SC_DEFAULT,\r
117     //SC_MONITORPOWER,\r
118     //SC_CONTEXTHELP,\r
119     //SC_SEPARATOR,\r
120 \r
121     //LM_MOVE,\r
122     //LM_SIZE,\r
123     LM_ACTIVATE,\r
124     LM_SETFOCUS,\r
125     LM_KILLFOCUS,\r
126     //LM_ENABLE,\r
127     //LM_GETTEXTLENGTH,\r
128     //LM_SHOWWINDOW,\r
129     //LM_CANCELMODE,\r
130     //LM_DRAWITEM,\r
131     //LM_MEASUREITEM,\r
132     //LM_DELETEITEM,\r
133     //LM_VKEYTOITEM,\r
134     //LM_CHARTOITEM,\r
135     //LM_COMPAREITEM,\r
136     //LM_WINDOWPOSCHANGING,\r
137     //LM_WINDOWPOSCHANGED,\r
138     //LM_NOTIFY,\r
139     //LM_HELP,\r
140     //LM_NOTIFYFORMAT,\r
141     //LM_CONTEXTMENU,\r
142     //LM_NCCALCSIZE,\r
143     //LM_NCHITTEST,\r
144     //LM_NCPAINT,\r
145     //LM_NCACTIVATE,\r
146     //LM_GETDLGCODE,\r
147     LM_NCMOUSEMOVE,\r
148     LM_NCLBUTTONDOWN,\r
149     LM_NCLBUTTONUP,\r
150     LM_NCLBUTTONDBLCLK,\r
151     LM_KEYDOWN,\r
152     LM_KEYUP,\r
153     LM_CHAR,\r
154     LM_SYSKEYDOWN,\r
155     LM_SYSKEYUP,\r
156     LM_SYSCHAR,\r
157     LM_COMMAND,\r
158     LM_SYSCOMMAND,\r
159     LM_TIMER,\r
160     LM_HSCROLL,\r
161     LM_VSCROLL,\r
162     //LM_CTLCOLORMSGBOX,\r
163     //LM_CTLCOLOREDIT,\r
164     //LM_CTLCOLORLISTBOX,\r
165     //LM_CTLCOLORBTN,\r
166     //LM_CTLCOLORDLG,\r
167     //LM_CTLCOLORSCROLLBAR,\r
168     //LM_CTLCOLORSTATIC,\r
169     LM_MOUSEMOVE,\r
170     LM_LBUTTONDOWN,\r
171     LM_LBUTTONUP,\r
172     LM_LBUTTONDBLCLK,\r
173     LM_RBUTTONDOWN,\r
174     LM_RBUTTONUP,\r
175     LM_RBUTTONDBLCLK,\r
176     LM_MBUTTONDOWN,\r
177     LM_MBUTTONUP,\r
178     LM_MBUTTONDBLCLK,\r
179     LM_MOUSEWHEEL,\r
180     LM_XBUTTONDOWN,\r
181     LM_XBUTTONUP,\r
182     LM_XBUTTONDBLCLK,\r
183     //LM_PARENTNOTIFY,\r
184     //LM_CAPTURECHANGED,\r
185     //LM_DROPFILES,\r
186     //LM_SELCHANGE,\r
187     LM_CUT,\r
188     LM_COPY,\r
189     LM_PASTE,\r
190     //LM_CLEAR,\r
191     //LM_CONFIGUREEVENT,\r
192     //LM_EXIT,\r
193     //LM_QUIT,\r
194     //LM_NULL,\r
195     //LM_PAINT,\r
196     //LM_ERASEBKGND,\r
197     //LM_SETCURSOR,\r
198     //LM_SETFONT:\r
199 \r
200     //CM_ACTIVATE,\r
201     //CM_DEACTIVATE,\r
202     //CM_FOCUSCHANGED,\r
203     //CM_PARENTFONTCHANGED,\r
204     //CM_PARENTCOLORCHANGED,\r
205     //CM_HITTEST,\r
206     //CM_VISIBLECHANGED,\r
207     //CM_ENABLEDCHANGED,\r
208     //CM_COLORCHANGED,\r
209     //CM_FONTCHANGED,\r
210     //CM_CURSORCHANGED,\r
211     //CM_TEXTCHANGED,\r
212     CM_MOUSEENTER,\r
213     CM_MOUSELEAVE,\r
214     //CM_MENUCHANGED,\r
215     //CM_APPSYSCOMMAND,\r
216     //CM_BUTTONPRESSED,\r
217     //CM_SHOWINGCHANGED,\r
218     //CM_ENTER,\r
219     //CM_EXIT,\r
220     //CM_DESIGNHITTEST,\r
221     //CM_ICONCHANGED,\r
222     //CM_WANTSPECIALKEY,\r
223     //CM_RELEASE,\r
224     //CM_FONTCHANGE,\r
225     //CM_TABSTOPCHANGED,\r
226     //CM_UIACTIVATE,\r
227     //CM_CONTROLLISTCHANGE,\r
228     //CM_GETDATALINK,\r
229     //CM_CHILDKEY,\r
230     //CM_HINTSHOW,\r
231     //CM_SYSFONTCHANGED,\r
232     //CM_CONTROLCHANGE,\r
233     //CM_CHANGED,\r
234     //CM_BORDERCHANGED,\r
235     //CM_BIDIMODECHANGED,\r
236     //CM_PARENTBIDIMODECHANGED,\r
237     //CM_ALLCHILDRENFLIPPED,\r
238     //CM_ACTIONUPDATE,\r
239     //CM_ACTIONEXECUTE,\r
240     //CM_HINTSHOWPAUSE,\r
241     //CM_DOCKNOTIFICATION,\r
242     CM_MOUSEWHEEL,\r
243     //CM_APPSHOWBTNGLYPHCHANGED,\r
244     //CM_APPSHOWMENUGLYPHCHANGED,\r
245 \r
246     //CN_BASE,\r
247     //CN_CHARTOITEM,\r
248     //CN_COMMAND,\r
249     //CN_COMPAREITEM,\r
250     //CN_CTLCOLORBTN,\r
251     //CN_CTLCOLORDLG,\r
252     //CN_CTLCOLOREDIT,\r
253     //CN_CTLCOLORLISTBOX,\r
254     //CN_CTLCOLORMSGBOX,\r
255     //CN_CTLCOLORSCROLLBAR,\r
256     //CN_CTLCOLORSTATIC,\r
257     //CN_DELETEITEM,\r
258     //CN_DRAWITEM,\r
259     CN_HSCROLL,\r
260     //CN_MEASUREITEM,\r
261     //CN_PARENTNOTIFY,\r
262     //CN_VKEYTOITEM,\r
263     CN_VSCROLL,\r
264     CN_KEYDOWN,\r
265     CN_KEYUP,\r
266     CN_CHAR,\r
267     CN_SYSKEYUP,\r
268     CN_SYSKEYDOWN,\r
269     CN_SYSCHAR,\r
270     CN_NOTIFY:\r
271     begin\r
272       if Assigned(fTarget) then begin\r
273         Message.Result := fTarget.Perform(Message.msg, Message.wParam, Message.lParam);\r
274         handled := true;\r
275       end;\r
276     end;\r
277   end;\r
278   inherited WndProc(Message);\r
279 end;\r
280 \r
281 {$endregion}\r
282 \r
283 function CreateOpenGLContextAttrList(UseFB: boolean; pf: TglcContextPixelFormatSettings): TGLIntArray;\r
284 var\r
285   p: integer;\r
286 \r
287   procedure Add(i: integer);\r
288   begin\r
289     SetLength(Result, p+1);\r
290     Result[p]:=i;\r
291     inc(p);\r
292   end;\r
293 \r
294   procedure CreateList;\r
295   begin\r
296     if UseFB then begin Add(GLX_X_RENDERABLE); Add(1); end;\r
297     if pf.DoubleBuffered then begin\r
298       if UseFB then begin\r
299         Add(GLX_DOUBLEBUFFER); Add(1);\r
300       end else\r
301         Add(GLX_DOUBLEBUFFER);\r
302     end;\r
303     if not UseFB and (pf.ColorBits>24) then Add(GLX_RGBA);\r
304     if UseFB then begin\r
305       Add(GLX_DRAWABLE_TYPE);\r
306       Add(GLX_WINDOW_BIT);\r
307     end;\r
308     Add(GLX_RED_SIZE);  Add(8);\r
309     Add(GLX_GREEN_SIZE);  Add(8);\r
310     Add(GLX_BLUE_SIZE);  Add(8);\r
311     if pf.ColorBits>24 then\r
312       Add(GLX_ALPHA_SIZE);  Add(8);\r
313     Add(GLX_DEPTH_SIZE);  Add(pf.DepthBits);\r
314     Add(GLX_STENCIL_SIZE);  Add(pf.StencilBits);\r
315     Add(GLX_AUX_BUFFERS);  Add(pf.AUXBuffers);\r
316 \r
317     if pf.MultiSampling > 1 then begin\r
318       Add(GLX_SAMPLE_BUFFERS_ARB); Add(1);\r
319       Add(GLX_SAMPLES_ARB); Add(pf.MultiSampling);\r
320     end;\r
321 \r
322     Add(0); { 0 = X.None (be careful: GLX_NONE is something different) }\r
323   end;\r
324 \r
325 begin\r
326   SetLength(Result, 0);\r
327   p:=0;\r
328   CreateList;\r
329 end;\r
330 \r
331 function FBglXChooseVisual(dpy:PDisplay; screen:longint; attrib_list:Plongint):PXVisualInfo;\r
332 type\r
333   PGLXFBConfig = ^GLXFBConfig;\r
334 var\r
335   FBConfigsCount: integer;\r
336   FBConfigs: PGLXFBConfig;\r
337   FBConfig: GLXFBConfig;\r
338 begin\r
339   Result:= nil;\r
340   FBConfigsCount:=0;\r
341   FBConfigs:= glXChooseFBConfig(dpy, screen, attrib_list, @FBConfigsCount);\r
342   if FBConfigsCount = 0 then\r
343     exit;\r
344 \r
345   { just choose the first FB config from the FBConfigs list.\r
346     More involved selection possible. }\r
347   FBConfig := FBConfigs^;\r
348   Result:=glXGetVisualFromFBConfig(dpy, FBConfig);\r
349 end;\r
350 \r
351 \r
352 { TglcContextGtk2GLX }\r
353 \r
354 procedure TglcContextGtk2GLX.UpdateVisual(const aControl: TWinControl);\r
355 var\r
356   attrList: TGLIntArray;\r
357   drawable: PGdkDrawable;\r
358 begin\r
359   {\r
360     Temporary (realized) widget to get to display\r
361   }\r
362   FWidget:= {%H-}PGtkWidget(PtrUInt(aControl.Handle));\r
363   gtk_widget_realize(FWidget);\r
364   drawable:= GTK_WIDGET(FWidget)^.window;\r
365 \r
366   FDisplay:= GDK_WINDOW_XDISPLAY(drawable);\r
367 \r
368   {\r
369     Find a suitable visual from PixelFormat using GLX 1.3 FBConfigs or\r
370     old-style Visuals\r
371   }\r
372   if Assigned(glXChooseFBConfig) then begin\r
373     attrList := CreateOpenGLContextAttrList(true, fPixelFormatSettings);\r
374     FVisual  := FBglXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);\r
375     if not Assigned(FVisual) and (fPixelFormatSettings.MultiSampling > 1) then begin\r
376       fPixelFormatSettings.MultiSampling := 1;\r
377       attrList := CreateOpenGLContextAttrList(true, fPixelFormatSettings);\r
378       FVisual  := FBglXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);\r
379     end;\r
380   end;\r
381   if not Assigned(FVisual) then begin\r
382     attrList := CreateOpenGLContextAttrList(false, fPixelFormatSettings);\r
383     FVisual  := glXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);\r
384     if not Assigned(FVisual) and (fPixelFormatSettings.MultiSampling > 1) then begin\r
385       fPixelFormatSettings.MultiSampling := 1;\r
386       attrList := CreateOpenGLContextAttrList(false, fPixelFormatSettings);\r
387       FVisual  := glXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);\r
388     end;\r
389   end;\r
390 \r
391   {\r
392     Most widgets inherit the drawable of their parent. In contrast to Windows, descending from\r
393     TWinControl does not mean it's actually always a window of its own.\r
394     Famous example: TPanel is just a frame painted on a canvas.\r
395     Also, the LCL does somethin weird to colormaps in window creation, so we have\r
396     to use a custom widget here to have full control about visual selection.\r
397   }\r
398   FRenderControl:= TRenderControl.Create(aControl, FVisual^.visual^.visualid);\r
399   try\r
400     FRenderControl.Parent := aControl;\r
401     FRenderControl.HandleNeeded;\r
402     FRenderControl.Target := aControl;\r
403   except\r
404     FreeAndNil(FRenderControl);\r
405     raise;\r
406   end;\r
407 \r
408   {\r
409     Real Widget handle, unrealized!!!\r
410   }\r
411   FWidget:= FRenderControl.Widget;\r
412   gtk_widget_realize(FWidget);\r
413   drawable:= GTK_WIDGET(FWidget)^.window;\r
414   FDisplay:= GDK_WINDOW_XDISPLAY(drawable);\r
415 \r
416   // FRenderControl.Align:= alClient breaks the context or something\r
417   FRenderControl.BoundsRect := aControl.ClientRect;\r
418   FRenderControl.Anchors    := [akLeft, akTop, akRight, akBottom];\r
419 end;\r
420 \r
421 procedure TglcContextGtk2GLX.OpenContext;\r
422 var\r
423   Attribs: array of GLint;\r
424   tmpContext: GLXContext;\r
425 begin\r
426   inherited OpenContext;\r
427 \r
428   if not Assigned(FVisual) then\r
429     raise EGLXError.Create('Failed to find Visual');\r
430 \r
431   tmpContext := glXCreateContext(FDisplay, FVisual, nil, true);\r
432   if fUseVersion and\r
433      (fVersionSettings.Major <> GLC_CONTEXT_VERSION_UNKNOWN) and\r
434      (fVersionSettings.Minor <> GLC_CONTEXT_VERSION_UNKNOWN) then\r
435   begin\r
436     // Set attributes to describe our requested context\r
437     SetLength(Attribs, 5);\r
438     Attribs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB;\r
439     Attribs[1] := fVersionSettings.Major;\r
440     Attribs[2] := WGL_CONTEXT_MINOR_VERSION_ARB;\r
441     Attribs[3] := fVersionSettings.Minor;\r
442 \r
443     // Add context flag for forward compatible context\r
444     // Forward compatible means no more support for legacy functions like\r
445     // immediate mode (glvertex, glrotate, gltranslate, etc.)\r
446     if fVersionSettings.ForwardCompatible then begin\r
447       SetLength(Attribs, Length(Attribs)+2);\r
448       Attribs[4] := WGL_CONTEXT_FLAGS_ARB;\r
449       Attribs[5] := WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;\r
450     end;\r
451 \r
452     // Attribute flags must be finalized with a zero\r
453     SetLength(Attribs, 1);\r
454     Attribs[High(Attribs)] := 0;\r
455 \r
456     glXMakeCurrent(FDisplay, GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window), tmpContext);\r
457     ReadImplementationProperties;\r
458     if not Assigned(glXCreateContextAttribsARB) or not GLX_ARB_create_context then begin\r
459       glXDestroyContext(FDisplay, tmpContext);\r
460       raise Exception.Create('GLX_ARB_create_context not supported');\r
461     end;\r
462     FContext := glXCreateContextAttribsARB(FDisplay, FVisual, nil, true, @Attribs[0]);\r
463 \r
464     glXDestroyContext(FDisplay, tmpContext);\r
465   end else\r
466     FContext := tmpContext;\r
467 \r
468   if (FContext = nil) then\r
469     raise EGLXError.Create('Failed to create Context');\r
470 end;\r
471 \r
472 constructor TglcContextGtk2GLX.Create(const aControl: TWinControl;\r
473   const aPixelFormatSettings: TglcContextPixelFormatSettings);\r
474 begin\r
475   inherited Create(aControl, aPixelFormatSettings);\r
476   UpdateVisual(aControl);\r
477 end;\r
478 \r
479 constructor TglcContextGtk2GLX.Create(const aControl: TWinControl;\r
480   const aPixelFormatSettings: TglcContextPixelFormatSettings;\r
481   const aVersionSettings: TglcContextVersionSettings);\r
482 begin\r
483   inherited Create(aControl, aPixelFormatSettings, aVersionSettings);\r
484   UpdateVisual(aControl);\r
485 end;\r
486 \r
487 destructor TglcContextGtk2GLX.Destroy;\r
488 begin\r
489   FreeAndNil(FRenderControl);\r
490   XFree(FVisual);\r
491   inherited Destroy;\r
492 end;\r
493 \r
494 procedure TglcContextGtk2GLX.CloseContext;\r
495 begin\r
496   if not Assigned(FWidget) then exit;\r
497   if Assigned(FContext) then\r
498     glXDestroyContext(FDisplay, FContext);\r
499   FreeAndNil(FRenderControl);\r
500 end;\r
501 \r
502 procedure TglcContextGtk2GLX.Activate;\r
503 begin\r
504   if not Assigned(FWidget) then exit;\r
505   // make sure the widget is realized\r
506   gtk_widget_realize(FWidget);\r
507   if not GTK_WIDGET_REALIZED(FWidget) then exit;\r
508 \r
509   // make current\r
510 \r
511   glXMakeCurrent(FDisplay, GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window), FContext);\r
512 end;\r
513 \r
514 procedure TglcContextGtk2GLX.Deactivate;\r
515 begin\r
516   if not Assigned(FWidget) then exit;\r
517   glXMakeCurrent(FDisplay, GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window), nil);\r
518 end;\r
519 \r
520 function TglcContextGtk2GLX.IsActive: boolean;\r
521 begin\r
522   Result:= (FContext = glXGetCurrentContext()) and\r
523            Assigned(FWidget) and\r
524            (GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window) = glXGetCurrentDrawable());\r
525 end;\r
526 \r
527 procedure TglcContextGtk2GLX.SwapBuffers;\r
528 var\r
529   drawable: PGdkDrawable;\r
530 begin\r
531   if not Assigned(FWidget) then exit;\r
532   drawable:= GTK_WIDGET(FWidget)^.window;\r
533   glXSwapBuffers(FDisplay, GDK_DRAWABLE_XID(drawable));\r
534 end;\r
535 \r
536 procedure TglcContextGtk2GLX.SetSwapInterval(const aInterval: GLint);\r
537 var\r
538   drawable: PGdkDrawable;\r
539 begin\r
540   drawable:= GTK_WIDGET(FWidget)^.window;\r
541   if GLX_EXT_swap_control then\r
542     glXSwapIntervalEXT(FDisplay, GDK_WINDOW_XWINDOW(drawable), aInterval);\r
543 end;\r
544 \r
545 procedure TglcContextGtk2GLX.Share(const aContext: TglcContext);\r
546 begin\r
547   raise Exception.Create('not yet implemented');\r
548 end;\r
549 \r
550 class function TglcContextGtk2GLX.ChangeDisplaySettings(const aWidth, aHeight,\r
551   aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean;\r
552 begin\r
553   raise Exception.Create('not yet implemented');\r
554 end;\r
555 \r
556 class function TglcContextGtk2GLX.IsAnyContextActive: boolean;\r
557 begin\r
558   Result:= (glXGetCurrentContext()<>nil) and (glXGetCurrentDrawable()<>0);\r
559 end;\r
560 \r
561 end.\r
562 \r