+# ifdef BACKBUFFER_OPENGL
+
+ NSAssert ([ogl_ctx isKindOfClass:[NSOpenGLContext class]],
+ @"ogl_ctx is not an NSOpenGLContext");
+
+ NSAssert (! (CGBitmapContextGetBytesPerRow (backbuffer) % 4),
+ @"improperly-aligned backbuffer");
+
+ // This gets width and height from the backbuffer in case
+ // APPLE_client_storage is in use. See the note in createBackbuffer.
+ // This still has to happen every frame even when APPLE_client_storage has
+ // the video adapter pulling texture data straight from
+ // XScreenSaverView-owned memory.
+ glTexImage2D (gl_texture_target, 0, GL_RGBA,
+ (GLsizei)(CGBitmapContextGetBytesPerRow (backbuffer) / 4),
+ gl_texture_h, 0, gl_pixel_format, gl_pixel_type,
+ backbuffer_data);
+
+ GLfloat w = xwindow->frame.width, h = xwindow->frame.height;
+
+ GLfloat vertices[4][2] = {{-w, h}, {w, h}, {w, -h}, {-w, -h}};
+
+ GLfloat tex_coords[4][2];
+
+# ifndef USE_IPHONE
+ if (gl_texture_target != GL_TEXTURE_RECTANGLE_EXT)
+# endif // USE_IPHONE
+ {
+ w /= gl_texture_w;
+ h /= gl_texture_h;
+ }
+
+ tex_coords[0][0] = 0;
+ tex_coords[0][1] = 0;
+ tex_coords[1][0] = w;
+ tex_coords[1][1] = 0;
+ tex_coords[2][0] = w;
+ tex_coords[2][1] = h;
+ tex_coords[3][0] = 0;
+ tex_coords[3][1] = h;
+
+ glVertexPointer (2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer (2, GL_FLOAT, 0, tex_coords);
+ glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+# if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR
+ check_gl_error ("drawBackbuffer");
+# endif
+# endif // BACKBUFFER_OPENGL
+}
+
+#endif // JWXYZ_QUARTZ
+
+#ifdef JWXYZ_GL
+
+- (void)enableBackbuffer:(CGSize)new_backbuffer_size;
+{
+ jwxyz_set_matrices (new_backbuffer_size.width, new_backbuffer_size.height);
+ check_gl_error ("enableBackbuffer");
+}
+
+- (void)createBackbuffer:(CGSize)new_size
+{
+ NSAssert ([NSOpenGLContext currentContext] ==
+ ogl_ctx, @"invalid GL context");
+ NSAssert (xwindow->window.current_drawable == xwindow,
+ @"current_drawable not set properly");
+
+# ifndef USE_IPHONE
+ /* On iOS, Retina means glViewport gets called with the screen size instead
+ of the backbuffer/xwindow size. This happens in startAnimation.
+
+ The GL screenhacks call glViewport themselves.
+ */
+ glViewport (0, 0, new_size.width, new_size.height);
+# endif
+
+ // TODO: Preserve contents on resize.
+ glClear (GL_COLOR_BUFFER_BIT);
+ check_gl_error ("createBackbuffer");
+}
+
+#endif // JWXYZ_GL
+
+
+- (void)flushBackbuffer
+{
+# ifdef JWXYZ_GL
+ // Make sure the right context is active: there's two under JWXYZ_GL.
+ jwxyz_bind_drawable (xwindow, xwindow);
+# endif // JWXYZ_GL
+
+# ifndef USE_IPHONE
+
+# ifdef JWXYZ_QUARTZ
+ // The OpenGL pipeline is not automatically synchronized with the contents
+ // of the backbuffer, so without glFinish, OpenGL can start rendering from
+ // the backbuffer texture at the same time that JWXYZ is clearing and
+ // drawing the next frame in the backing store for the backbuffer texture.
+ // This is only a concern under JWXYZ_QUARTZ because of
+ // APPLE_client_storage; JWXYZ_GL doesn't use that.
+ glFinish();
+# endif // JWXYZ_QUARTZ
+
+ // If JWXYZ_GL was single-buffered, there would need to be a glFinish (or
+ // maybe just glFlush?) here, because single-buffered contexts don't always
+ // update what's on the screen after drawing finishes. (i.e., in safe mode)
+
+# ifdef JWXYZ_QUARTZ
+ // JWXYZ_GL is always double-buffered.
+ if (double_buffered_p)
+# endif // JWXYZ_QUARTZ
+ [ogl_ctx flushBuffer]; // despite name, this actually swaps
+# else // USE_IPHONE
+
+ // jwxyz_bind_drawable() only binds the framebuffer, not the renderbuffer.
+# ifdef JWXYZ_GL
+ GLint gl_renderbuffer = xwindow->gl_renderbuffer;
+# endif
+
+ glBindRenderbufferOES (GL_RENDERBUFFER_OES, gl_renderbuffer);
+ [ogl_ctx presentRenderbuffer:GL_RENDERBUFFER_OES];
+# endif // USE_IPHONE
+
+# if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR
+ // glGetError waits for the OpenGL command pipe to flush, so skip it in
+ // release builds.
+ // OpenGL Programming Guide for Mac -> OpenGL Application Design
+ // Strategies -> Allow OpenGL to Manage Your Resources
+ // https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_designstrategies/opengl_designstrategies.html#//apple_ref/doc/uid/TP40001987-CH2-SW7
+ check_gl_error ("flushBackbuffer");
+# endif
+}
+
+
+/* Inform X11 that the size of our window has changed.
+ */
+- (void) resize_x11
+{
+ if (!xdpy) return; // early
+
+ NSSize new_size; // pixels, not points
+
+ new_size = self.bounds.size;
+
+# ifdef USE_IPHONE
+
+ // If this hack ignores rotation, then that means that it pretends to
+ // always be in portrait mode. If the View has been resized to a
+ // landscape shape, swap width and height to keep the backbuffer
+ // in portrait.
+ //
+ double rot = current_device_rotation();
+ if ([self ignoreRotation] && (rot == 90 || rot == -90)) {
+ CGFloat swap = new_size.width;
+ new_size.width = new_size.height;
+ new_size.height = swap;
+ }
+
+ double s = self.hackedContentScaleFactor;
+ new_size.width *= s;
+ new_size.height *= s;
+# endif // USE_IPHONE
+
+ [self prepareContext];
+ [self setViewport];
+
+ // On first resize, xwindow->frame is 0x0.
+ if (xwindow->frame.width == new_size.width &&
+ xwindow->frame.height == new_size.height)
+ return;
+
+# if defined(BACKBUFFER_OPENGL) && !defined(USE_IPHONE)
+ [ogl_ctx update];
+# endif // BACKBUFFER_OPENGL && !USE_IPHONE
+
+ NSAssert (xwindow && xwindow->type == WINDOW, @"not a window");
+ xwindow->frame.x = 0;
+ xwindow->frame.y = 0;
+ xwindow->frame.width = new_size.width;
+ xwindow->frame.height = new_size.height;
+
+ [self createBackbuffer:CGSizeMake(xwindow->frame.width,
+ xwindow->frame.height)];
+
+# if defined JWXYZ_QUARTZ
+ xwindow->cgc = backbuffer;
+ NSAssert (xwindow->cgc, @"no CGContext");
+# elif defined JWXYZ_GL && !defined USE_IPHONE
+ [ogl_ctx update];
+ [ogl_ctx setView:xwindow->window.view]; // (Is this necessary?)
+# endif // JWXYZ_GL && USE_IPHONE
+
+ jwxyz_window_resized (xdpy);
+
+# if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR
+ NSLog(@"reshape %.0fx%.0f", new_size.width, new_size.height);
+# endif