From b2928461c5651cf3db4edcbce0256d98ee87925f Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Sun, 3 May 2026 17:35:11 +0800
Subject: [PATCH] OpenGL patch

---
 Rendering/OpenGL2/CMakeLists.txt              |   4 +
 Rendering/OpenGL2/vtkCocoaGLView.mm           |  36 ++---
 Rendering/OpenGL2/vtkCocoaRenderWindow.mm     |  96 ++++++++-----
 Rendering/OpenGL2/vtkOSOpenGLRenderWindow.cxx |  38 +++++-
 Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx   | 128 +++++++++++++++---
 Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx  |  38 +++++-
 6 files changed, 260 insertions(+), 80 deletions(-)

diff --git a/Rendering/OpenGL2/CMakeLists.txt b/Rendering/OpenGL2/CMakeLists.txt
index 4098a99638..b8f1e10090 100644
--- a/Rendering/OpenGL2/CMakeLists.txt
+++ b/Rendering/OpenGL2/CMakeLists.txt
@@ -451,6 +451,10 @@ endif()
 
 if (VTK_USE_COCOA)
   vtk_module_link(VTK::RenderingOpenGL2 PUBLIC "-framework Cocoa")
+elseif (VTK_USE_X)
+  # Link GL library explicitly for X11 backend (including macOS with XQuartz)
+  vtk_module_find_package(PACKAGE OpenGL COMPONENTS OpenGL)
+  vtk_module_link(VTK::RenderingOpenGL2 PUBLIC OpenGL::GL)
 elseif (VTK_USE_WIN32_OPENGL)
   # vtkWin32OpenGLDXRenderWindow requires D3D.
   vtk_module_find_package(PRIVATE_IF_SHARED
diff --git a/Rendering/OpenGL2/vtkCocoaGLView.mm b/Rendering/OpenGL2/vtkCocoaGLView.mm
index 007b6b50a4..03771a76f9 100644
--- a/Rendering/OpenGL2/vtkCocoaGLView.mm
+++ b/Rendering/OpenGL2/vtkCocoaGLView.mm
@@ -49,13 +49,13 @@
   // on older versions of macOS.  Conditionally using it would require conditionally
   // linking to that new framework, which just isn't worth the hassle when both
   // are just syntactic sugar for the string "public.file-url".
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  VTK_DIAG_OFF(deprecated-declarations)
   NSString* supportedDragType = (NSString*)kUTTypeFileURL;
-#pragma clang diagnostic pop
+  VTK_DIAG_ON(deprecated-declarations)
 
   // Register the view for file drops.
-  [self registerForDraggedTypes:@[ supportedDragType ]];
+  // Use explicit NSArray creation instead of @[] literal for gcc compatibility
+  [self registerForDraggedTypes:[NSArray arrayWithObject:supportedDragType]];
 }
 
 //----------------------------------------------------------------------------
@@ -234,7 +234,7 @@
   // first responder.
   NSPoint windowLoc = [[self window] mouseLocationOutsideOfEventStream];
   NSPoint viewLoc = [self convertPoint:windowLoc fromView:nil];
-  NSPoint backingLoc = [self convertPointToBacking:viewLoc];
+  NSPoint backingLoc = vtkCocoaConvertPointToBacking(self, viewLoc);
 
   NSUInteger flags = [theEvent modifierFlags];
   int shiftDown = ((flags & NSEventModifierFlagShift) != 0);
@@ -353,7 +353,7 @@
   // left corner. Since this is a mouse event, we can use locationInWindow.
   NSPoint windowLoc = [theEvent locationInWindow];
   NSPoint viewLoc = [self convertPoint:windowLoc fromView:nil];
-  NSPoint backingLoc = [self convertPointToBacking:viewLoc];
+  NSPoint backingLoc = vtkCocoaConvertPointToBacking(self, viewLoc);
 
   NSUInteger flags = [theEvent modifierFlags];
   int shiftDown = ((flags & NSEventModifierFlagShift) != 0);
@@ -382,7 +382,7 @@
   // left corner. Since this is a mouse event, we can use locationInWindow.
   NSPoint windowLoc = [theEvent locationInWindow];
   NSPoint viewLoc = [self convertPoint:windowLoc fromView:nil];
-  NSPoint backingLoc = [self convertPointToBacking:viewLoc];
+  NSPoint backingLoc = vtkCocoaConvertPointToBacking(self, viewLoc);
 
   int clickCount = static_cast<int>([theEvent clickCount]);
   int repeatCount = ((clickCount > 1) ? clickCount - 1 : 0);
@@ -550,10 +550,9 @@
   // on older versions of macOS.  Conditionally using it would require conditionally
   // linking to that new framework, which just isn't worth the hassle when both
   // are just syntactic sugar for the string "public.file-url".
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  VTK_DIAG_OFF(deprecated-declarations)
   NSString* supportedDragType = (NSString*)kUTTypeFileURL;
-#pragma clang diagnostic pop
+  VTK_DIAG_ON(deprecated-declarations)
 
   if ([types containsObject:supportedDragType])
   {
@@ -570,7 +569,7 @@
 
   NSPoint pt = [sender draggingLocation];
   NSPoint viewLoc = [self convertPoint:pt fromView:nil];
-  NSPoint backingLoc = [self convertPointToBacking:viewLoc];
+  NSPoint backingLoc = vtkCocoaConvertPointToBacking(self, viewLoc);
   double location[2];
   location[0] = backingLoc.x;
   location[1] = backingLoc.y;
@@ -578,10 +577,16 @@
 
   vtkNew<vtkStringArray> filePaths;
   NSPasteboard* pboard = [sender draggingPasteboard];
-  NSArray* fileURLs = [pboard readObjectsForClasses:@[ [NSURL class] ] options:nil];
-  for (NSURL* fileURL in fileURLs)
-  {
-    const char* filePath = [fileURL fileSystemRepresentation];
+  // Use explicit NSArray creation instead of @[] literal for gcc compatibility
+  NSArray* fileURLs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:nil];
+  // Use NSEnumerator instead of fast enumeration for gcc compatibility
+  NSEnumerator* urlEnumerator = [fileURLs objectEnumerator];
+  NSURL* fileURL;
+  while ((fileURL = [urlEnumerator nextObject]) != nil)
+  {
+    // Use -path and UTF8String instead of -fileSystemRepresentation for 10.5/10.6 SDK compatibility
+    // (-fileSystemRepresentation was added in 10.9)
+    const char* filePath = [[fileURL path] UTF8String];
     filePaths->InsertNextValue(filePath);
   }
 
@@ -617,7 +622,7 @@
 {
   // Convert from points to pixels.
   NSRect viewRect = [self frame];
-  NSRect backingViewRect = [self convertRectToBacking:viewRect];
+  NSRect backingViewRect = vtkCocoaConvertRectToBacking(self, viewRect);
   CGFloat viewHeight = NSHeight(viewRect);
   CGFloat backingViewHeight = NSHeight(backingViewRect);
   CGFloat backingScaleFactor = 1.0;
@@ -629,7 +634,7 @@
   else if (window)
   {
     // fall back to less reliable method
-    backingScaleFactor = [window backingScaleFactor];
+    backingScaleFactor = vtkCocoaGetBackingScaleFactor(window);
   }
   assert(backingScaleFactor >= 1.0);
 
@@ -653,13 +658,18 @@
 }
 
 //----------------------------------------------------------------------------
-// Overridden (from NSView).
+// Overridden (from NSView). Available in 10.7+.
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
 - (void)viewDidChangeBackingProperties
 {
-  [super viewDidChangeBackingProperties];
+  if ([NSView instancesRespondToSelector:@selector(viewDidChangeBackingProperties)])
+  {
+    [super viewDidChangeBackingProperties];
+  }
 
   NSWindow* window = [self window];
   [self modifyDPIForBackingScaleFactorOfWindow:window];
 }
+#endif
 
 @end

diff --git a/Rendering/OpenGL2/vtkCocoaRenderWindow.mm b/Rendering/OpenGL2/vtkCocoaRenderWindow.mm
index f941872365..17ce47388a 100644
--- a/Rendering/OpenGL2/vtkCocoaRenderWindow.mm
+++ b/Rendering/OpenGL2/vtkCocoaRenderWindow.mm
@@ -169,7 +169,7 @@
   NSRect viewRect = [view frame];
 
   // Convert from points to pixels.
-  NSRect backingViewRect = [view convertRectToBacking:viewRect];
+  NSRect backingViewRect = vtkCocoaConvertRectToBacking(view, viewRect);
 
   int newWidth = static_cast<int>(NSWidth(backingViewRect));
   int newHeight = static_cast<int>(NSHeight(backingViewRect));
@@ -401,12 +401,26 @@
        << "\nOpenGL version string:  " << glVersion << endl;
 
   strm << "OpenGL extensions:  " << endl;
-  GLint n, i;
-  glGetIntegerv(GL_NUM_EXTENSIONS, &n);
-  for (i = 0; i < n; i++)
+  // glGetStringi and GL_NUM_EXTENSIONS are OpenGL 3.0+
+  // For OpenGL 2.x, use the old glGetString(GL_EXTENSIONS) method
+  if (glGetStringi != nullptr)
+  {
+    GLint n, i;
+    glGetIntegerv(GL_NUM_EXTENSIONS, &n);
+    for (i = 0; i < n; i++)
+    {
+      const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
+      strm << "  " << ext << endl;
+    }
+  }
+  else
   {
-    const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
-    strm << "  " << ext << endl;
+    // Legacy OpenGL 2.x path
+    const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
+    if (extensions)
+    {
+      strm << "  " << extensions << endl;
+    }
   }
 
   // Obtain the OpenGL context in order to keep track of the current screen.
@@ -439,11 +453,10 @@
 
   // "NSOpenGLPFAStereo" is deprecated in the 10.12 SDK, suppress warning about its use.
   // No explanation is given for the deprecation, and no alternative is suggested.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+  VTK_DIAG_OFF(deprecated-declarations)
   [pixelFormat getValues:&pfd forAttribute:NSOpenGLPFAStereo forVirtualScreen:currentScreen];
   strm << "  stereo:  " << (pfd == 0 ? "No" : "Yes") << endl;
-#pragma clang diagnostic pop
+  VTK_DIAG_ON(deprecated-declarations)
 
   [pixelFormat getValues:&pfd forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:currentScreen];
   strm << "  stencil:  " << pfd << endl;
@@ -451,8 +464,14 @@
   [pixelFormat getValues:&pfd forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:currentScreen];
   strm << "  hardware acceleration:  " << (pfd == 0 ? "No" : "Yes") << endl;
 
-  [pixelFormat getValues:&pfd forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:currentScreen];
-  strm << "  profile version:  0x" << std::hex << pfd << endl;
+  // NSOpenGLPFAOpenGLProfile is only available on 10.7+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+  if ([pixelFormat respondsToSelector:@selector(getValues:forAttribute:forVirtualScreen:)])
+  {
+    [pixelFormat getValues:&pfd forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:currentScreen];
+    strm << "  profile version:  0x" << std::hex << pfd << endl;
+  }
+#endif
 
   delete[] this->Capabilities;
 
@@ -497,7 +516,7 @@
 
         // Convert the given new size from pixels to points.
         NSSize backingNewSize = NSMakeSize((CGFloat)width, (CGFloat)height);
-        NSSize newSize = [theView convertSizeFromBacking:backingNewSize];
+        NSSize newSize = vtkCocoaConvertSizeFromBacking(theView, backingNewSize);
 
         // Test that there's actually a change so as not to recurse into viewFrameDidChange:.
         if (!NSEqualSizes(newSize, viewRect.size))
@@ -527,7 +546,7 @@
 
         // Convert the given new size from pixels to points.
         NSRect backingNewRect = NSMakeRect(0.0, 0.0, (CGFloat)width, (CGFloat)height);
-        NSRect newRect = [window convertRectFromBacking:backingNewRect];
+        NSRect newRect = vtkCocoaWindowConvertRectFromBacking(window, backingNewRect);
 
         // Test that there's actually a change so as not to recurse into viewFrameDidChange:.
         if (!NSEqualSizes(newRect.size, [window frame].size))
@@ -576,7 +595,7 @@
 
         // Convert the given new position from pixels to points.
         NSPoint backingNewPosition = NSMakePoint((CGFloat)x, (CGFloat)y);
-        NSPoint newPosition = [theView convertPointFromBacking:backingNewPosition];
+        NSPoint newPosition = vtkCocoaConvertPointFromBacking(theView, backingNewPosition);
 
         // Update the view's frameOrigin (in points) keeping the bottom-left
         // corner in the same place.
@@ -608,7 +627,7 @@
         // We use a dummy NSRect because NSWindow doesn't have convertPointFromBacking: before
         // macOS 10.14.
         NSRect backingNewPosition = NSMakeRect((CGFloat)x, (CGFloat)y, 0.0, 0.0);
-        NSRect newPosition = [window convertRectFromBacking:backingNewPosition];
+        NSRect newPosition = vtkCocoaWindowConvertRectFromBacking(window, backingNewPosition);
 
         // Test that there's actually a change so as not to recurse into viewFrameDidChange:.
         if (!NSEqualPoints([window frame].origin, newPosition.origin))
@@ -709,7 +728,7 @@
     NSRect screenRect = [screen frame];
 
     // Convert from points to pixels.
-    NSRect backingScreenRect = [screen convertRectToBacking:screenRect];
+    NSRect backingScreenRect = vtkCocoaConvertRectToBacking(screen, screenRect);
 
     if (this->FullScreen && screen)
     {
@@ -744,15 +763,8 @@
         (CGFloat)this->Size[0], (CGFloat)this->Size[1]);
 
       // Convert from pixels to points.
-      NSRect contentRect;
-      if (screen)
-      {
-        contentRect = [screen convertRectFromBacking:backingContentRect];
-      }
-      else
-      {
-        contentRect = backingContentRect;
-      }
+      NSRect contentRect = screen ? vtkCocoaScreenConvertRectFromBacking(screen, backingContentRect)
+                                  : backingContentRect;
 
       NSWindowStyleMask styleMask = (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
         NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);
@@ -808,7 +820,7 @@
       assert(window);
       NSRect backingViewRect = NSMakeRect((CGFloat)this->Position[0], (CGFloat)this->Position[1],
         (CGFloat)this->Size[0], (CGFloat)this->Size[1]);
-      NSRect viewRect = [window convertRectFromBacking:backingViewRect];
+      NSRect viewRect = vtkCocoaWindowConvertRectFromBacking(window, backingViewRect);
 
       CGFloat width = NSWidth(viewRect);
       CGFloat height = NSHeight(viewRect);
@@ -845,10 +857,7 @@
       // SetParentId() was added for) then the Tk superview handles the events.
       NSRect glRect = NSMakeRect(x, y, width, height);
       NSView* glView = [[NSView alloc] initWithFrame:glRect];
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-      [glView setWantsBestResolutionOpenGLSurface:wantsBest];
-#pragma clang diagnostic pop
+      vtkCocoaSetWantsBestResolutionOpenGLSurface(glView, wantsBest);
       [parent addSubview:glView];
       this->SetWindowId(glView);
       this->ViewCreated = 1;
@@ -864,14 +873,11 @@
       // Convert from points to pixels.
       NSWindow* window = (NSWindow*)this->GetRootWindow();
       assert(window);
-      NSRect viewRect = [window convertRectFromBacking:backingViewRect];
+      NSRect viewRect = vtkCocoaWindowConvertRectFromBacking(window, backingViewRect);
 
       // Create a vtkCocoaGLView.
       vtkCocoaGLView* glView = [[vtkCocoaGLView alloc] initWithFrame:viewRect];
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-      [glView setWantsBestResolutionOpenGLSurface:wantsBest];
-#pragma clang diagnostic pop
+      vtkCocoaSetWantsBestResolutionOpenGLSurface(glView, wantsBest);
       [window setContentView:glView];
       // We have to set the frame's view rect again to work around rounding
       // that occurs when setting the window's content view.
@@ -893,10 +899,9 @@
   if (connectContextToNSView)
   {
     NSView* view = (NSView*)this->GetWindowId();
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    VTK_DIAG_OFF(deprecated-declarations)
     [context setView:view];
-#pragma clang diagnostic pop
+    VTK_DIAG_ON(deprecated-declarations)
   }
 
   // the error "invalid drawable" in the console from this call can appear
@@ -933,12 +938,18 @@
 {
   // If the deployment target is at least 10.10, prefer the 'OpenGL 4.1 Core
   // Implementation', otherwise we'll fall back to the 'OpenGL 3.2 Core
-  // Implementation' (available since 10.7).
+  // Implementation' (available since 10.7), or legacy OpenGL for pre-10.7.
   NSOpenGLPixelFormatAttribute profileVersion;
+  bool useProfile = true;  // Whether to include NSOpenGLPFAOpenGLProfile
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
   profileVersion = NSOpenGLProfileVersion4_1Core;
-#else
+#elif MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
   profileVersion = NSOpenGLProfileVersion3_2Core;
+#else
+  // For 10.5/10.6, start with legacy profile (no NSOpenGLPFAOpenGLProfile)
+  // and only try core profiles at runtime if the system supports them.
+  profileVersion = NSOpenGLProfileVersionLegacy;
+  useProfile = false;  // Don't request a profile on legacy systems initially
 #endif
 
   // Prefer hardware acceleration
@@ -951,8 +962,12 @@
     int i = 0;
     NSOpenGLPixelFormatAttribute attribs[20];
 
-    attribs[i++] = NSOpenGLPFAOpenGLProfile;
-    attribs[i++] = profileVersion;
+    // Only include OpenGL profile on 10.7+ systems
+    if (useProfile)
+    {
+      attribs[i++] = NSOpenGLPFAOpenGLProfile;
+      attribs[i++] = profileVersion;
+    }
 
     attribs[i++] = NSOpenGLPFADepthSize;
     attribs[i++] = (NSOpenGLPixelFormatAttribute)32;
@@ -981,11 +996,16 @@
 
     if (pixelFormat == nil)
     {
-      if (profileVersion != NSOpenGLProfileVersion3_2Core)
+      if (useProfile && profileVersion != NSOpenGLProfileVersion3_2Core)
       {
         // Try falling back to the 3.2 Core Profile
         profileVersion = NSOpenGLProfileVersion3_2Core;
       }
+      else if (useProfile && profileVersion == NSOpenGLProfileVersion3_2Core)
+      {
+        // Try falling back to legacy OpenGL (no profile specification)
+        useProfile = false;
+      }
       else if (hardware == NSOpenGLPFAAccelerated)
       {
         // Try falling back to the software renderer
@@ -1018,10 +1038,9 @@
 
     // This syncs the OpenGL context to the VBL to prevent tearing
     GLint one = 1;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    VTK_DIAG_OFF(deprecated-declarations)
     [context setValues:&one forParameter:NSOpenGLCPSwapInterval];
-#pragma clang diagnostic pop
+    VTK_DIAG_ON(deprecated-declarations)
   }
 
   this->SetPixelFormat((void*)pixelFormat);
@@ -1060,10 +1079,9 @@
     if (connectContextToNSView)
     {
       NSView* view = (NSView*)this->GetWindowId();
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+      VTK_DIAG_OFF(deprecated-declarations)
       [context setView:view];
-#pragma clang diagnostic pop
+      VTK_DIAG_ON(deprecated-declarations)
     }
 
     // the error "invalid drawable" in the console from this call can appear
@@ -1133,7 +1151,7 @@
     NSRect viewRect = [view frame];
 
     // Convert from points to pixels.
-    NSRect backingViewRect = [view convertRectToBacking:viewRect];
+    NSRect backingViewRect = vtkCocoaConvertRectToBacking(view, viewRect);
 
     // Update the ivar.
     this->Size[0] = static_cast<int>(NSWidth(backingViewRect));
@@ -1177,7 +1195,7 @@
   NSRect screenRect = [screen frame];
 
   // Convert from points to pixels.
-  NSRect backingScreenRect = [screen convertRectToBacking:screenRect];
+  NSRect backingScreenRect = vtkCocoaConvertRectToBacking(screen, screenRect);
 
   this->ScreenSize[0] = static_cast<int>(NSWidth(backingScreenRect));
   this->ScreenSize[1] = static_cast<int>(NSHeight(backingScreenRect));
@@ -1204,8 +1222,8 @@
     NSRect viewRect = [view frame];
 
     // Convert from points to pixels.
-    NSRect backingParentRect = [parent convertRectToBacking:parentRect];
-    NSRect backingViewRect = [view convertRectToBacking:viewRect];
+    NSRect backingParentRect = vtkCocoaConvertRectToBacking(parent, parentRect);
+    NSRect backingViewRect = vtkCocoaConvertRectToBacking(view, viewRect);
 
     this->Position[0] = static_cast<int>(NSMinX(backingViewRect));
     this->Position[1] = static_cast<int>(
@@ -1224,7 +1242,7 @@
       NSRect windowRect = [window frame];
 
       // Convert from points to pixels.
-      NSRect backingWindowRect = [window convertRectToBacking:windowRect];
+      NSRect backingWindowRect = vtkCocoaWindowConvertRectToBacking(window, windowRect);
 
       this->Position[0] = static_cast<int>(NSMinX(backingWindowRect));
       this->Position[1] = static_cast<int>(NSMinY(backingWindowRect));

diff --git a/Rendering/OpenGL2/vtkOSOpenGLRenderWindow.cxx b/Rendering/OpenGL2/vtkOSOpenGLRenderWindow.cxx
index 649afafd11..0a72520126 100644
--- a/Rendering/OpenGL2/vtkOSOpenGLRenderWindow.cxx
+++ b/Rendering/OpenGL2/vtkOSOpenGLRenderWindow.cxx
@@ -548,13 +548,43 @@ const char* vtkOSOpenGLRenderWindow::ReportCapabilities()
   strm << "OpenGL vendor string:  " << glVendor << endl;
   strm << "OpenGL renderer string:  " << glRenderer << endl;
   strm << "OpenGL version string:  " << glVersion << endl;
-  strm << "OpenGL extensions:  " << endl;
+  strm << "OpenGL extensions:" << endl;
+  // Try GL 3.0+ method first (glGetStringi)
   int n = 0;
   glGetIntegerv(GL_NUM_EXTENSIONS, &n);
-  for (int i = 0; i < n; i++)
+  if (glGetError() == GL_NO_ERROR && n > 0 && glGetStringi != nullptr)
   {
-    const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
-    strm << "  " << ext << endl;
+    for (int i = 0; i < n; i++)
+    {
+      const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
+      if (ext)
+      {
+        strm << "  " << ext << endl;
+      }
+    }
+  }
+  else
+  {
+    // Fallback for GL 2.x - use glGetString(GL_EXTENSIONS)
+    const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
+    if (extensions)
+    {
+      std::string extStr(extensions);
+      size_t start = 0;
+      size_t end = 0;
+      while ((end = extStr.find(' ', start)) != std::string::npos)
+      {
+        if (end > start)
+        {
+          strm << "  " << extStr.substr(start, end - start) << endl;
+        }
+        start = end + 1;
+      }
+      if (start < extStr.length())
+      {
+        strm << "  " << extStr.substr(start) << endl;
+      }
+    }
   }
   delete[] this->Capabilities;
   size_t len = strm.str().length();
diff --git a/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx b/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx
index 5e45d57d89..7429251204 100644
--- a/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx
+++ b/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx
@@ -696,13 +696,43 @@ const char* vtkOpenGLRenderWindow::ReportCapabilities()
     strm << "OpenGL version string:  " << glVersion << endl;
   }
 
-  strm << "OpenGL extensions:  " << endl;
-  GLint n, i;
+  strm << "OpenGL extensions:" << endl;
+  // Try GL 3.0+ method first (glGetStringi)
+  GLint n = 0;
   glGetIntegerv(GL_NUM_EXTENSIONS, &n);
-  for (i = 0; i < n; i++)
+  if (glGetError() == GL_NO_ERROR && n > 0 && glGetStringi != nullptr)
   {
-    const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
-    strm << "  " << ext << endl;
+    for (GLint i = 0; i < n; i++)
+    {
+      const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
+      if (ext)
+      {
+        strm << "  " << ext << endl;
+      }
+    }
+  }
+  else
+  {
+    // Fallback for GL 2.x - use glGetString(GL_EXTENSIONS)
+    const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
+    if (extensions)
+    {
+      std::string extStr(extensions);
+      size_t start = 0;
+      size_t end = 0;
+      while ((end = extStr.find(' ', start)) != std::string::npos)
+      {
+        if (end > start)
+        {
+          strm << "  " << extStr.substr(start, end - start) << endl;
+        }
+        start = end + 1;
+      }
+      if (start < extStr.length())
+      {
+        strm << "  " << extStr.substr(start) << endl;
+      }
+    }
   }
 
   delete[] this->Capabilities;
@@ -872,6 +902,37 @@ int vtkOpenGLRenderWindow::GetDefaultTextureInternalFormat(
     vtktype, numComponents, needInt, needFloat, needSRGB);
 }
 
+//------------------------------------------------------------------------------
+// Helper to parse GL version from GL_VERSION string (for GL 2.x)
+static bool vtkParseOpenGLVersionString(const char* versionString, int& major, int& minor)
+{
+  if (!versionString)
+  {
+    return false;
+  }
+  const char* ptr = versionString;
+  // Skip "OpenGL ES " prefix if present
+  if (strncmp(ptr, "OpenGL ES ", 10) == 0)
+  {
+    ptr += 10;
+  }
+  char* endptr;
+  long majorVal = strtol(ptr, &endptr, 10);
+  if (endptr == ptr || *endptr != '.')
+  {
+    return false;
+  }
+  ptr = endptr + 1;
+  long minorVal = strtol(ptr, &endptr, 10);
+  if (endptr == ptr)
+  {
+    return false;
+  }
+  major = static_cast<int>(majorVal);
+  minor = static_cast<int>(minorVal);
+  return true;
+}
+
 //------------------------------------------------------------------------------
 void vtkOpenGLRenderWindow::GetOpenGLVersion(int& major, int& minor)
 {
@@ -880,8 +941,23 @@ void vtkOpenGLRenderWindow::GetOpenGLVersion(int& major, int& minor)
 
   if (this->Initialized)
   {
+    // Try GL 3.0+ method first
     this->GetState()->vtkglGetIntegerv(GL_MAJOR_VERSION, &glMajorVersion);
-    this->GetState()->vtkglGetIntegerv(GL_MINOR_VERSION, &glMinorVersion);
+    GLenum err = glGetError();
+    if (err == GL_NO_ERROR)
+    {
+      this->GetState()->vtkglGetIntegerv(GL_MINOR_VERSION, &glMinorVersion);
+    }
+    else
+    {
+      // Fallback: parse GL_VERSION string for GL 2.x
+      const char* versionStr = (const char*)glGetString(GL_VERSION);
+      if (!vtkParseOpenGLVersionString(versionStr, glMajorVersion, glMinorVersion))
+      {
+        glMajorVersion = 2;
+        glMinorVersion = 0;
+      }
+    }
   }
 
   major = glMajorVersion;
@@ -921,23 +997,35 @@ void vtkOpenGLRenderWindow::OpenGLInitContext()
     }
     int major = 0;
     int minor = 0;
+    // Try GL 3.0+ method, fallback to parsing GL_VERSION
     glGetIntegerv(GL_MAJOR_VERSION, &major);
-    glGetIntegerv(GL_MINOR_VERSION, &minor);
-    // Require at least OpenGL 3.2
-    if (major < 3 || (major == 3 && minor < 2))
-    {
-      vtkWarningMacro(<< "Unable to find a valid OpenGL 3.2 or later implementation. "
-                      << "(" << major << "." << minor
-                      << " found). "
-                         "Please update your video card driver to the latest version. "
-                         "If you are using Mesa please make sure you have version 11.2 or "
-                         "later and make sure your driver in Mesa supports OpenGL 3.2 such "
-                         "as llvmpipe or openswr. If you are on windows and using Microsoft "
-                         "remote desktop note that it only supports OpenGL 3.2 with nvidia "
-                         "quadro cards. You can use other remoting software such as nomachine "
-                         "to avoid this issue.");
+    if (glGetError() != GL_NO_ERROR)
+    {
+      const char* versionStr = (const char*)glGetString(GL_VERSION);
+      if (!vtkParseOpenGLVersionString(versionStr, major, minor))
+      {
+        major = 2;
+        minor = 0;
+      }
+    }
+    else
+    {
+      glGetIntegerv(GL_MINOR_VERSION, &minor);
+    }
+    // Warn but don't fail for GL 2.x - some basic functionality may work
+    if (major < 2)
+    {
+      vtkErrorMacro(<< "OpenGL version " << major << "." << minor
+                    << " is too old. VTK requires at least OpenGL 2.0.");
       return;
     }
+    else if (major < 3 || (major == 3 && minor < 2))
+    {
+      vtkWarningMacro(<< "OpenGL " << major << "." << minor << " detected. "
+                      << "VTK works best with OpenGL 3.2 or later. "
+                      << "Some features may not work correctly.");
+      // Continue anyway for basic rendering support
+    }
 #else // gles
     this->Initialized = true;
 #endif
diff --git a/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx b/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx
index db5d836766..a7ba8b6c1a 100644
--- a/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx
+++ b/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx
@@ -1603,13 +1603,43 @@ const char* vtkXOpenGLRenderWindow::ReportCapabilities()
   strm << "OpenGL vendor string:  " << glVendor << endl;
   strm << "OpenGL renderer string:  " << glRenderer << endl;
   strm << "OpenGL version string:  " << glVersion << endl;
-  strm << "OpenGL extensions:  " << endl;
+  strm << "OpenGL extensions:" << endl;
+  // Try GL 3.0+ method first (glGetStringi)
   int n = 0;
   glGetIntegerv(GL_NUM_EXTENSIONS, &n);
-  for (int i = 0; i < n; i++)
+  if (glGetError() == GL_NO_ERROR && n > 0 && glGetStringi != nullptr)
+  {
+    for (int i = 0; i < n; i++)
+    {
+      const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
+      if (ext)
+      {
+        strm << "  " << ext << endl;
+      }
+    }
+  }
+  else
   {
-    const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
-    strm << "  " << ext << endl;
+    // Fallback for GL 2.x - use glGetString(GL_EXTENSIONS)
+    const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
+    if (extensions)
+    {
+      std::string extStr(extensions);
+      size_t start = 0;
+      size_t end = 0;
+      while ((end = extStr.find(' ', start)) != std::string::npos)
+      {
+        if (end > start)
+        {
+          strm << "  " << extStr.substr(start, end - start) << endl;
+        }
+        start = end + 1;
+      }
+      if (start < extStr.length())
+      {
+        strm << "  " << extStr.substr(start) << endl;
+      }
+    }
   }
 
   strm << "X Extensions:  ";

diff --git a/ThirdParty/glad/vtkglad/CMakeLists.txt b/ThirdParty/glad/vtkglad/CMakeLists.txt
index 4bb73ab9b3..5f4d293059 100644
--- a/ThirdParty/glad/vtkglad/CMakeLists.txt
+++ b/ThirdParty/glad/vtkglad/CMakeLists.txt
@@ -66,4 +66,7 @@ if (WIN32)
 elseif (VTK_OPENGL_USE_GLES)
   vtk_module_find_package(PACKAGE OpenGL COMPONENTS GLES3)
   vtk_module_link(VTK::glad PUBLIC OpenGL::GLES3)
+elseif (VTK_USE_X AND NOT WIN32)
+  vtk_module_find_package(PACKAGE OpenGL COMPONENTS OpenGL)
+  vtk_module_link(VTK::glad PUBLIC OpenGL::GL)
 endif ()

--- a/Rendering/OpenGL2/vtkCocoaGLView.h	2026-05-16 04:34:56.000000000 +0800
+++ b/Rendering/OpenGL2/vtkCocoaGLView.h	2026-06-03 13:36:49.000000000 +0800
@@ -59,8 +59,14 @@
 typedef void* vtkCocoaRenderWindowInteractorRef;
 #endif
 
+// NSDraggingDestination was an informal protocol before 10.7
+// On older SDKs we don't declare conformance but still implement the methods
 VTKRENDERINGOPENGL2_EXPORT
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
 @interface vtkCocoaGLView : NSView<NSDraggingDestination>
+#else
+@interface vtkCocoaGLView : NSView
+#endif
 {
 @private
   vtkCocoaRenderWindowRef _myVTKRenderWindow;
