winemac: Add support for delay-rendered (a.k.a. promised) clipboard data.
[wine] / dlls / winemac.drv / cocoa_opengl.m
1 /*
2  * MACDRV Cocoa OpenGL code
3  *
4  * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #import "cocoa_opengl.h"
22
23 #include "macdrv_cocoa.h"
24 #include "cocoa_event.h"
25
26
27 @interface WineOpenGLContext ()
28 @property (retain, nonatomic) NSView* latentView;
29 @end
30
31
32 @implementation WineOpenGLContext
33 @synthesize latentView, needsUpdate;
34
35     - (void) dealloc
36     {
37         [latentView release];
38         [super dealloc];
39     }
40
41     /* On at least some versions of Mac OS X, -[NSOpenGLContext clearDrawable] has the
42        undesirable side effect of ordering the view's GL surface off-screen.  This isn't
43        done when just changing the context's view to a different view (which I would
44        think would be analogous, since the old view and surface end up without a
45        context attached).  So, we finesse things by first setting the context's view to
46        a different view (the content view of an off-screen window) and then letting the
47        original implementation proceed. */
48     - (void) clearDrawable
49     {
50         static NSWindow* dummyWindow;
51         static dispatch_once_t once;
52
53         dispatch_once(&once, ^{
54             OnMainThread(^{
55                 dummyWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
56                                                           styleMask:NSBorderlessWindowMask
57                                                             backing:NSBackingStoreBuffered
58                                                               defer:NO];
59             });
60         });
61
62         [self setView:[dummyWindow contentView]];
63         [super clearDrawable];
64     }
65
66 @end
67
68
69 /***********************************************************************
70  *              macdrv_create_opengl_context
71  *
72  * Returns a Cocoa OpenGL context created from a CoreGL context.  The
73  * caller is responsible for calling macdrv_dispose_opengl_context()
74  * when done with the context object.
75  */
76 macdrv_opengl_context macdrv_create_opengl_context(void* cglctx)
77 {
78     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
79     WineOpenGLContext *context;
80
81     context = [[WineOpenGLContext alloc] initWithCGLContextObj:cglctx];
82
83     [pool release];
84     return (macdrv_opengl_context)context;
85 }
86
87 /***********************************************************************
88  *              macdrv_dispose_opengl_context
89  *
90  * Destroys a Cocoa OpenGL context previously created by
91  * macdrv_create_opengl_context();
92  */
93 void macdrv_dispose_opengl_context(macdrv_opengl_context c)
94 {
95     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
96     WineOpenGLContext *context = (WineOpenGLContext*)c;
97
98     if ([context view])
99         macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
100     if ([context latentView])
101         macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
102     [context clearDrawable];
103     [context release];
104
105     [pool release];
106 }
107
108 /***********************************************************************
109  *              macdrv_make_context_current
110  */
111 void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
112 {
113     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
114     WineOpenGLContext *context = (WineOpenGLContext*)c;
115     NSView* view = (NSView*)v;
116
117     if (context)
118     {
119         if ([context view])
120             macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
121         if ([context latentView])
122             macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
123         context.needsUpdate = FALSE;
124         if (view)
125         {
126             __block BOOL windowHasDevice;
127
128             macdrv_add_view_opengl_context(v, c);
129
130             OnMainThread(^{
131                 windowHasDevice = [[view window] windowNumber] > 0;
132             });
133             if (windowHasDevice)
134             {
135                 [context setView:view];
136                 [context setLatentView:nil];
137             }
138             else
139                 [context setLatentView:view];
140
141             [context makeCurrentContext];
142         }
143         else
144         {
145             [WineOpenGLContext clearCurrentContext];
146             [context clearDrawable];
147         }
148     }
149     else
150         [WineOpenGLContext clearCurrentContext];
151
152     [pool release];
153 }
154
155 /***********************************************************************
156  *              macdrv_update_opengl_context
157  */
158 void macdrv_update_opengl_context(macdrv_opengl_context c)
159 {
160     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
161     WineOpenGLContext *context = (WineOpenGLContext*)c;
162
163     if (context.needsUpdate)
164     {
165         context.needsUpdate = FALSE;
166         if (context.latentView)
167         {
168             [context setView:context.latentView];
169             context.latentView = nil;
170         }
171         else
172             [context update];
173     }
174
175     [pool release];
176 }
177
178 /***********************************************************************
179  *              macdrv_flush_opengl_context
180  *
181  * Performs an implicit glFlush() and then swaps the back buffer to the
182  * front (if the context is double-buffered).
183  */
184 void macdrv_flush_opengl_context(macdrv_opengl_context c)
185 {
186     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
187     WineOpenGLContext *context = (WineOpenGLContext*)c;
188
189     macdrv_update_opengl_context(c);
190     [context flushBuffer];
191
192     [pool release];
193 }