Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[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 /***********************************************************************
248  *              DirectDrawCreate
249  */
250 HRESULT WINAPI DirectDrawCreate(
251         LPGUID lpGUID, LPDIRECTDRAW *lplpDD, LPUNKNOWN pUnkOuter
252 ) {
253     IDirectDrawImpl** ilplpDD=(IDirectDrawImpl**)lplpDD;
254     WNDCLASSA   wc;
255     HRESULT     ret = 0;
256     int         i,drvindex=0;
257     GUID        zeroGUID;
258
259     struct ddraw_driver *ddd = NULL;
260
261     if (!HIWORD(lpGUID)) lpGUID = NULL;
262
263     TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),ilplpDD,pUnkOuter);
264
265     memset(&zeroGUID,0,sizeof(zeroGUID));
266     while (1) {
267         ddd = NULL;
268         if ( ( !lpGUID ) ||
269              ( IsEqualGUID( &zeroGUID,  lpGUID ) ) ||
270              ( IsEqualGUID( &IID_IDirectDraw,  lpGUID ) ) ||
271              ( IsEqualGUID( &IID_IDirectDraw2, lpGUID ) ) ||
272              ( IsEqualGUID( &IID_IDirectDraw4, lpGUID ) )
273         ) {
274             /* choose an interface out of the list */
275             for (i=0;i<nrof_ddraw_drivers;i++) {
276                 ddraw_driver *xddd = ddraw_drivers[i];
277                 if (!xddd)
278                     continue;
279                 if (!ddd || (ddd->preference<xddd->preference)) {
280                     drvindex = i;
281                     ddd = xddd;
282                 }
283             }
284         } else {
285             for (i=0;i<nrof_ddraw_drivers;i++) {
286                 if (!ddraw_drivers[i])
287                     continue;
288                 if (IsEqualGUID(ddraw_drivers[i]->guid,lpGUID)) {
289                     drvindex = i;
290                     ddd = ddraw_drivers[i];
291                     break;
292                 }
293             }
294         }
295         if (!ddd) {
296             if (!nrof_ddraw_drivers) {
297                 ERR("DirectDrawCreate(%s,%p,%p): no DirectDraw drivers compiled in.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
298                 return DDERR_NODIRECTDRAWHW;
299             }
300             ERR("DirectDrawCreate(%s,%p,%p): did not recognize requested GUID.\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter);
301             return DDERR_INVALIDDIRECTDRAWGUID;
302         }
303         TRACE("using \"%s\" driver, calling %p\n",ddd->name,ddd->createDDRAW);
304
305         ret = ddd->createDDRAW(lplpDD);
306         if (!ret)
307             break;
308         ddraw_drivers[drvindex] = NULL; /* mark this one as unusable */
309     }
310     wc.style            = CS_GLOBALCLASS;
311     wc.lpfnWndProc      = DDWndProc;
312     wc.cbClsExtra       = 0;
313     wc.cbWndExtra       = 0;
314
315     /* We can be a child of the desktop since we're really important */
316     wc.hInstance= 0; 
317     wc.hIcon    = 0;
318     wc.hCursor  = (HCURSOR)IDC_ARROWA;
319     wc.hbrBackground    = NULL_BRUSH;
320     wc.lpszMenuName     = 0;
321     wc.lpszClassName    = "WINE_DirectDraw";
322     (*ilplpDD)->d.winclass = RegisterClassA(&wc);
323     return ret;
324 }
325
326 /*******************************************************************************
327  * DirectDraw ClassFactory
328  *
329  *  Heavily inspired (well, can you say completely copied :-) ) from DirectSound
330  *
331  */
332 typedef struct {
333     /* IUnknown fields */
334     ICOM_VFIELD(IClassFactory);
335     DWORD               ref;
336 } IClassFactoryImpl;
337
338 static HRESULT WINAPI 
339 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
340     ICOM_THIS(IClassFactoryImpl,iface);
341
342     FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
343     return E_NOINTERFACE;
344 }
345
346 static ULONG WINAPI
347 DDCF_AddRef(LPCLASSFACTORY iface) {
348     ICOM_THIS(IClassFactoryImpl,iface);
349     return ++(This->ref);
350 }
351
352 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) {
353     ICOM_THIS(IClassFactoryImpl,iface);
354     /* static class, won't be  freed */
355     return --(This->ref);
356 }
357
358 static HRESULT WINAPI DDCF_CreateInstance(
359         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
360 ) {
361     ICOM_THIS(IClassFactoryImpl,iface);
362
363     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
364     if ( ( IsEqualGUID( &IID_IDirectDraw,  riid ) ) ||
365          ( IsEqualGUID( &IID_IDirectDraw2, riid ) ) ||
366          ( IsEqualGUID( &IID_IDirectDraw4, riid ) ) ) {
367             /* FIXME: reuse already created DirectDraw if present? */
368             return DirectDrawCreate((LPGUID) riid,(LPDIRECTDRAW*)ppobj,pOuter);
369     }
370     return CLASS_E_CLASSNOTAVAILABLE;
371 }
372
373 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
374     ICOM_THIS(IClassFactoryImpl,iface);
375     FIXME("(%p)->(%d),stub!\n",This,dolock);
376     return S_OK;
377 }
378
379 static ICOM_VTABLE(IClassFactory) DDCF_Vtbl = 
380 {
381     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
382     DDCF_QueryInterface,
383     DDCF_AddRef,
384     DDCF_Release,
385     DDCF_CreateInstance,
386     DDCF_LockServer
387 };
388 static IClassFactoryImpl DDRAW_CF = {&DDCF_Vtbl, 1 };
389
390 /*******************************************************************************
391  * DllGetClassObject [DDRAW.13]
392  * Retrieves class object from a DLL object
393  *
394  * NOTES
395  *    Docs say returns STDAPI
396  *
397  * PARAMS
398  *    rclsid [I] CLSID for the class object
399  *    riid   [I] Reference to identifier of interface for class object
400  *    ppv    [O] Address of variable to receive interface pointer for riid
401  *
402  * RETURNS
403  *    Success: S_OK
404  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
405  *             E_UNEXPECTED
406  */
407 DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
408 {
409     TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
410     if ( IsEqualGUID( &IID_IClassFactory, riid ) ) {
411         *ppv = (LPVOID)&DDRAW_CF;
412         IClassFactory_AddRef((IClassFactory*)*ppv);
413         return S_OK;
414     }
415     FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
416     return CLASS_E_CLASSNOTAVAILABLE;
417 }
418
419
420 /*******************************************************************************
421  * DllCanUnloadNow [DDRAW.12]  Determines whether the DLL is in use.
422  *
423  * RETURNS
424  *    Success: S_OK
425  *    Failure: S_FALSE
426  */
427 DWORD WINAPI DDRAW_DllCanUnloadNow(void) {
428     FIXME("(void): stub\n");
429     return S_FALSE;
430 }