POSIX threads emulation, tricks glibc into being threadsafe.
[wine] / dlls / ddraw / main.c
1 /*              DirectDraw Base Functions
2  *
3  * Copyright 1997-1999 Marcus Meissner
4  * Copyright 1998 Lionel Ulmer (most of Direct3D stuff)
5  */
6
7 #include "config.h"
8
9 #include <unistd.h>
10 #include <assert.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15
16 #include "winerror.h"
17 #include "heap.h"
18 #include "dc.h"
19 #include "win.h"
20 #include "wine/exception.h"
21 #include "ddraw.h"
22 #include "d3d.h"
23 #include "debugtools.h"
24 #include "message.h"
25 #include "monitor.h"
26
27 /* This for all the enumeration and creation of D3D-related objects */
28 #include "ddraw_private.h"
29
30 #define MAX_DDRAW_DRIVERS       3
31 static ddraw_driver * ddraw_drivers[MAX_DDRAW_DRIVERS];
32 static int nrof_ddraw_drivers                   = 0;
33
34 DEFAULT_DEBUG_CHANNEL(ddraw);
35
36 /* register a direct draw driver. We better not use malloc for we are in 
37  * the ELF startup initialisation at this point.
38  */
39 void ddraw_register_driver(ddraw_driver *driver) {
40     ddraw_drivers[nrof_ddraw_drivers++] = driver;
41
42     /* increase MAX_DDRAW_DRIVERS if the line below triggers */
43     assert(nrof_ddraw_drivers <= MAX_DDRAW_DRIVERS);
44 }
45
46 /**********************************************************************/
47
48 typedef struct {
49     LPVOID lpCallback;
50     LPVOID lpContext; 
51 } DirectDrawEnumerateProcData;
52
53 /***********************************************************************
54  *              DirectDrawEnumerateExA (DDRAW.*)
55  */
56 HRESULT WINAPI DirectDrawEnumerateExA(
57     LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags)
58 {
59     int i;
60     TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags);
61
62     if (TRACE_ON(ddraw)) {
63         DPRINTF("  Flags : ");
64         if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES)
65             DPRINTF("DDENUM_ATTACHEDSECONDARYDEVICES ");
66         if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES)
67             DPRINTF("DDENUM_DETACHEDSECONDARYDEVICES ");
68         if (dwFlags & DDENUM_NONDISPLAYDEVICES)
69             DPRINTF("DDENUM_NONDISPLAYDEVICES ");
70         DPRINTF("\n");
71     }
72
73     if (dwFlags & DDENUM_NONDISPLAYDEVICES) {
74         FIXME("no non-display devices supported.\n");
75         return DD_OK;
76     }
77 /* Hmm. Leave this out.
78     if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) {
79         FIXME("no attached secondary devices supported.\n");
80         return DD_OK;
81     }
82  */
83     if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) {
84         FIXME("no detached secondary devices supported.\n");
85         return DD_OK;
86     }
87
88     for (i=0;i<MAX_DDRAW_DRIVERS;i++) {
89         if (!ddraw_drivers[i])
90             continue;
91         if (ddraw_drivers[i]->createDDRAW(NULL)) /* !0 is failing */
92             continue;
93         TRACE("Enumerating %s/%s interface\n",ddraw_drivers[i]->name,ddraw_drivers[i]->type);
94         if (!lpCallback(
95             ddraw_drivers[i]->guid,
96             (LPSTR)ddraw_drivers[i]->name,
97             (LPSTR)ddraw_drivers[i]->type,
98             lpContext,
99             0           /* FIXME: flags not supported here */
100         ))
101             return DD_OK;
102     }
103     if (nrof_ddraw_drivers) {
104         TRACE("Enumerating the default interface\n");
105         if (!lpCallback(NULL,"WINE (default)", "display", lpContext, 0))
106             return DD_OK;
107     }
108     return DD_OK;
109 }
110
111 /***********************************************************************
112  *              DirectDrawEnumerateExW (DDRAW.*)
113  */
114
115 static BOOL CALLBACK DirectDrawEnumerateExProcW(
116     GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, 
117     LPVOID lpContext, HMONITOR hm)
118 {
119     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
120     LPWSTR lpDriverDescriptionW =
121         HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverDescription);
122     LPWSTR lpDriverNameW =
123         HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverName);
124
125     BOOL bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(
126         lpGUID, lpDriverDescriptionW, lpDriverNameW, pEPD->lpContext, hm);
127
128     HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW);
129     HeapFree(GetProcessHeap(), 0, lpDriverNameW);
130     return bResult;
131 }
132
133 /**********************************************************************/
134
135 HRESULT WINAPI DirectDrawEnumerateExW(
136   LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags)
137 {
138     DirectDrawEnumerateProcData epd;
139     epd.lpCallback = (LPVOID) lpCallback;
140     epd.lpContext = lpContext;
141
142     return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0);
143 }
144
145 /***********************************************************************
146  *              DirectDrawEnumerateA (DDRAW.*)
147  */
148
149 static BOOL CALLBACK DirectDrawEnumerateProcA(
150         GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, 
151         LPVOID lpContext, HMONITOR hm)
152 {
153     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
154
155     return ((LPDDENUMCALLBACKA) pEPD->lpCallback)(
156         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
157 }
158
159 /**********************************************************************/
160
161 HRESULT WINAPI DirectDrawEnumerateA(
162   LPDDENUMCALLBACKA lpCallback, LPVOID lpContext) 
163 {
164     DirectDrawEnumerateProcData epd;  
165     epd.lpCallback = (LPVOID) lpCallback;
166     epd.lpContext = lpContext;
167
168     return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0);
169 }
170
171 /***********************************************************************
172  *              DirectDrawEnumerateW (DDRAW.*)
173  */
174
175 static BOOL WINAPI DirectDrawEnumerateProcW(
176   GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName, 
177   LPVOID lpContext, HMONITOR hm)
178 {
179     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
180   
181     return ((LPDDENUMCALLBACKW) pEPD->lpCallback)(
182         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
183 }
184
185 /**********************************************************************/
186
187 HRESULT WINAPI DirectDrawEnumerateW(
188   LPDDENUMCALLBACKW lpCallback, LPVOID lpContext) 
189 {
190     DirectDrawEnumerateProcData epd;
191     epd.lpCallback = (LPVOID) lpCallback;
192     epd.lpContext = lpContext;
193
194     return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0);
195 }
196
197 /******************************************************************************
198  *                              DirectDraw Window Procedure
199  */
200 static LRESULT WINAPI DDWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
201 {
202     LRESULT ret;
203     IDirectDrawImpl* ddraw = NULL;
204     DWORD lastError;
205
206     /* FIXME(ddraw,"(0x%04x,%s,0x%08lx,0x%08lx),stub!\n",(int)hwnd,SPY_GetMsgName(msg),(long)wParam,(long)lParam); */
207
208     SetLastError( ERROR_SUCCESS );
209     ddraw  = (IDirectDrawImpl*)GetPropA( hwnd, ddProp );
210     if( (!ddraw)  && ( ( lastError = GetLastError() ) != ERROR_SUCCESS )) 
211         ERR("Unable to retrieve this ptr from window. Error %08lx\n",lastError);
212
213     if( ddraw ) {
214     /* Perform any special direct draw functions */
215         if (msg==WM_PAINT)
216             ddraw->d.paintable = 1;
217
218         /* Now let the application deal with the rest of this */
219         if( ddraw->d.mainWindow ) {
220
221             /* Don't think that we actually need to call this but... 
222              * might as well be on the safe side of things...
223              */
224
225             /* I changed hwnd to ddraw->d.mainWindow as I did not see why
226              * it should be the procedures of our fake window that gets called
227              * instead of those of the window provided by the application.
228              * And with this patch, mouse clicks work with Monkey Island III
229              * - Lionel
230              */
231             ret = DefWindowProcA( ddraw->d.mainWindow, msg, wParam, lParam );
232
233             if( !ret ) {
234                 WND *tmpWnd =WIN_FindWndPtr(ddraw->d.mainWindow);
235                 /* We didn't handle the message - give it to the application */
236                 if (ddraw && ddraw->d.mainWindow && tmpWnd)
237                     ret = CallWindowProcA(tmpWnd->winproc,
238                 ddraw->d.mainWindow, msg, wParam, lParam );
239                 WIN_ReleaseWndPtr(tmpWnd);
240             }
241             return ret;
242         } /* else FALLTHROUGH */
243     } /* else FALLTHROUGH */
244     return DefWindowProcA(hwnd,msg,wParam,lParam);
245 }
246
247 HRESULT WINAPI DirectDrawCreate(
248         LPGUID lpGUID, LPDIRECTDRAW *lplpDD, LPUNKNOWN pUnkOuter
249 ) {
250     IDirectDrawImpl** ilplpDD=(IDirectDrawImpl**)lplpDD;
251     WNDCLASSA   wc;
252     HRESULT     ret = 0;
253     int         i,drvindex=0;
254
255     struct ddraw_driver *ddd = NULL;
256
257     if (!HIWORD(lpGUID)) lpGUID = NULL;
258
259     TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),ilplpDD,pUnkOuter);
260
261     while (1) {
262         ddd = NULL;
263         if ( ( !lpGUID ) ||
264              ( IsEqualGUID( &IID_IDirectDraw,  lpGUID ) ) ||
265              ( IsEqualGUID( &IID_IDirectDraw2, lpGUID ) ) ||
266              ( IsEqualGUID( &IID_IDirectDraw4, lpGUID ) )
267         ) {
268             /* choose an interface out of the list */
269             for (i=0;i<nrof_ddraw_drivers;i++) {
270                 ddraw_driver *xddd = ddraw_drivers[i];
271                 if (!xddd)
272                     continue;
273                 if (!ddd || (ddd->preference<xddd->preference)) {
274                     drvindex = i;
275                     ddd = xddd;
276                 }
277             }
278         } else {
279             for (i=0;i<nrof_ddraw_drivers;i++) {
280                 if (!ddraw_drivers[i])
281                     continue;
282                 if (IsEqualGUID(ddraw_drivers[i]->guid,lpGUID)) {
283                     drvindex = i;
284                     ddd = ddraw_drivers[i];
285                     break;
286                 }
287             }
288         }
289         if (!ddd) {
290             if (!nrof_ddraw_drivers) {
291                 ERR("DirectDrawCreate(%s,%p,%p): no DirectDraw drivers compiled in.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
292                 return DDERR_NODIRECTDRAWHW;
293             }
294             ERR("DirectDrawCreate(%s,%p,%p): did not recognize requested GUID.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
295             return DDERR_INVALIDDIRECTDRAWGUID;
296         }
297         TRACE("using \"%s\" driver, calling %p\n",ddd->name,ddd->createDDRAW);
298
299         ret = ddd->createDDRAW(lplpDD);
300         if (!ret)
301             break;
302         ddraw_drivers[drvindex] = NULL; /* mark this one as unusable */
303     }
304     wc.style            = CS_GLOBALCLASS;
305     wc.lpfnWndProc      = DDWndProc;
306     wc.cbClsExtra       = 0;
307     wc.cbWndExtra       = 0;
308
309     /* We can be a child of the desktop since we're really important */
310     wc.hInstance= 0; 
311     wc.hIcon    = 0;
312     wc.hCursor  = (HCURSOR)IDC_ARROWA;
313     wc.hbrBackground    = NULL_BRUSH;
314     wc.lpszMenuName     = 0;
315     wc.lpszClassName    = "WINE_DirectDraw";
316     (*ilplpDD)->d.winclass = RegisterClassA(&wc);
317     return ret;
318 }
319
320 /*******************************************************************************
321  * DirectDraw ClassFactory
322  *
323  *  Heavily inspired (well, can you say completely copied :-) ) from DirectSound
324  *
325  */
326 typedef struct {
327     /* IUnknown fields */
328     ICOM_VFIELD(IClassFactory);
329     DWORD               ref;
330 } IClassFactoryImpl;
331
332 static HRESULT WINAPI 
333 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
334     ICOM_THIS(IClassFactoryImpl,iface);
335
336     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
337     return E_NOINTERFACE;
338 }
339
340 static ULONG WINAPI
341 DDCF_AddRef(LPCLASSFACTORY iface) {
342     ICOM_THIS(IClassFactoryImpl,iface);
343     return ++(This->ref);
344 }
345
346 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) {
347     ICOM_THIS(IClassFactoryImpl,iface);
348     /* static class, won't be  freed */
349     return --(This->ref);
350 }
351
352 static HRESULT WINAPI DDCF_CreateInstance(
353         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
354 ) {
355     ICOM_THIS(IClassFactoryImpl,iface);
356
357     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
358     if ( ( IsEqualGUID( &IID_IDirectDraw,  riid ) ) ||
359          ( IsEqualGUID( &IID_IDirectDraw2, riid ) ) ||
360          ( IsEqualGUID( &IID_IDirectDraw4, riid ) ) ) {
361             /* FIXME: reuse already created DirectDraw if present? */
362             return DirectDrawCreate((LPGUID) riid,(LPDIRECTDRAW*)ppobj,pOuter);
363     }
364     return CLASS_E_CLASSNOTAVAILABLE;
365 }
366
367 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
368     ICOM_THIS(IClassFactoryImpl,iface);
369     FIXME("(%p)->(%d),stub!\n",This,dolock);
370     return S_OK;
371 }
372
373 static ICOM_VTABLE(IClassFactory) DDCF_Vtbl = 
374 {
375     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
376     DDCF_QueryInterface,
377     DDCF_AddRef,
378     DDCF_Release,
379     DDCF_CreateInstance,
380     DDCF_LockServer
381 };
382 static IClassFactoryImpl DDRAW_CF = {&DDCF_Vtbl, 1 };
383
384 /*******************************************************************************
385  * DllGetClassObject [DDRAW.13]
386  * Retrieves class object from a DLL object
387  *
388  * NOTES
389  *    Docs say returns STDAPI
390  *
391  * PARAMS
392  *    rclsid [I] CLSID for the class object
393  *    riid   [I] Reference to identifier of interface for class object
394  *    ppv    [O] Address of variable to receive interface pointer for riid
395  *
396  * RETURNS
397  *    Success: S_OK
398  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
399  *             E_UNEXPECTED
400  */
401 DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
402 {
403     TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
404     if ( IsEqualGUID( &IID_IClassFactory, riid ) ) {
405         *ppv = (LPVOID)&DDRAW_CF;
406         IClassFactory_AddRef((IClassFactory*)*ppv);
407         return S_OK;
408     }
409     FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
410     return CLASS_E_CLASSNOTAVAILABLE;
411 }
412
413
414 /*******************************************************************************
415  * DllCanUnloadNow [DDRAW.12]  Determines whether the DLL is in use.
416  *
417  * RETURNS
418  *    Success: S_OK
419  *    Failure: S_FALSE
420  */
421 DWORD WINAPI DDRAW_DllCanUnloadNow(void) {
422     FIXME("(void): stub\n");
423     return S_FALSE;
424 }