Handle control characters in VkKeyScanEx similar to what Windows
[wine] / dlls / x11drv / dga2.c
1 /*
2  * DirectDraw DGA2 interface
3  *
4  * Copyright 2001 TransGaming Technologies, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_LIBXXF86DGA2
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include <X11/Xlib.h>
28 #include <X11/extensions/xf86dga.h>
29
30 #include "x11drv.h"
31 #include "x11ddraw.h"
32 #include "dga2.h"
33
34 #include "windef.h"
35 #include "wingdi.h"
36 #include "ddrawi.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
40
41 extern int usedga;
42
43 LPDDHALMODEINFO xf86dga2_modes;
44 unsigned xf86dga2_mode_count;
45 HWND DGAhwnd = 0;
46 static XDGAMode* modes;
47
48 static void convert_mode(XDGAMode *mode, LPDDHALMODEINFO info)
49 {
50   info->dwWidth        = mode->viewportWidth;
51   info->dwHeight       = mode->viewportHeight;
52   info->wRefreshRate   = mode->verticalRefresh;
53   info->lPitch         = mode->bytesPerScanline;
54   info->dwBPP          = (mode->depth < 24) ? mode->depth : mode->bitsPerPixel;
55   info->wFlags         = (mode->depth == 8) ? DDMODEINFO_PALETTIZED : 0;
56   info->dwRBitMask     = mode->redMask;
57   info->dwGBitMask     = mode->greenMask;
58   info->dwBBitMask     = mode->blueMask;
59   info->dwAlphaBitMask = 0;
60   TRACE(" width=%ld, height=%ld, bpp=%ld, refresh=%d\n",
61         info->dwWidth, info->dwHeight, info->dwBPP, info->wRefreshRate);
62 }
63
64 static int DGA2ErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
65 {
66     return 1;
67 }
68
69 static void X11DRV_DGAKeyPressEvent( HWND hwnd, XEvent *xev )
70 {
71     /* Fill a XKeyEvent to send to EVENT_Key */
72     XDGAKeyEvent *event = (XDGAKeyEvent *)xev;
73     XEvent ke;
74
75     ke.xkey.type = KeyPress;
76     ke.xkey.serial = event->serial;
77     ke.xkey.send_event = FALSE;
78     ke.xkey.display = event->display;
79     ke.xkey.window = 0;
80     ke.xkey.root = 0;
81     ke.xkey.subwindow = 0;
82     ke.xkey.time = event->time;
83     ke.xkey.x = -1;
84     ke.xkey.y = -1;
85     ke.xkey.x_root = -1;
86     ke.xkey.y_root = -1;
87     ke.xkey.state = event->state;
88     ke.xkey.keycode = event->keycode;
89     ke.xkey.same_screen = TRUE;
90     X11DRV_KeyEvent( 0, &ke );
91 }
92
93 static void X11DRV_DGAKeyReleaseEvent( HWND hwnd, XEvent *xev )
94 {
95     /* Fill a XKeyEvent to send to EVENT_Key */
96     XDGAKeyEvent *event = (XDGAKeyEvent *)xev;
97     XEvent ke;
98
99     ke.xkey.type = KeyRelease;
100     ke.xkey.serial = event->serial;
101     ke.xkey.send_event = FALSE;
102     ke.xkey.display = event->display;
103     ke.xkey.window = 0;
104     ke.xkey.root = 0;
105     ke.xkey.subwindow = 0;
106     ke.xkey.time = event->time;
107     ke.xkey.x = -1;
108     ke.xkey.y = -1;
109     ke.xkey.x_root = -1;
110     ke.xkey.y_root = -1;
111     ke.xkey.state = event->state;
112     ke.xkey.keycode = event->keycode;
113     ke.xkey.same_screen = TRUE;
114     X11DRV_KeyEvent( 0, &ke );
115 }
116
117
118 void X11DRV_XF86DGA2_Init(void)
119 {
120   int nmodes, major, minor, i, event_base, error_base;
121   Bool ok;
122
123   TRACE("\n");
124
125   if (xf86dga2_modes) return; /* already initialized? */
126
127   /* if in desktop mode, don't use DGA */
128   if (root_window != DefaultRootWindow(gdi_display)) return;
129
130   if (!usedga) return;
131
132   wine_tsx11_lock();
133   ok = XDGAQueryExtension(gdi_display, &event_base, &error_base);
134   if (ok)
135   {
136       X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL);
137       ok = XDGAQueryVersion(gdi_display, &major, &minor);
138       if (X11DRV_check_error()) ok = FALSE;
139   }
140   wine_tsx11_unlock();
141   if (!ok) return;
142
143   if (major < 2) return; /* only bother with DGA 2+ */
144
145   /* test that it works */
146   wine_tsx11_lock();
147   X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL);
148   ok = XDGAOpenFramebuffer(gdi_display, DefaultScreen(gdi_display));
149   if (X11DRV_check_error()) ok = FALSE;
150   if (ok)
151   {
152       XDGACloseFramebuffer(gdi_display, DefaultScreen(gdi_display));
153       /* retrieve modes */
154       modes = XDGAQueryModes(gdi_display, DefaultScreen(gdi_display), &nmodes);
155       if (!modes) ok = FALSE;
156   }
157   else WARN("disabling XF86DGA2 (insufficient permissions?)\n");
158   wine_tsx11_unlock();
159   if (!ok) return;
160
161   TRACE("DGA modes: count=%d\n", nmodes);
162
163   xf86dga2_mode_count = nmodes+1;
164   xf86dga2_modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DDHALMODEINFO) * (nmodes+1));
165
166   /* make dummy mode for exiting DGA */
167   memset(&xf86dga2_modes[0], 0, sizeof(xf86dga2_modes[0]));
168
169   /* convert modes to DDHALMODEINFO format */
170   for (i=0; i<nmodes; i++)
171     convert_mode(&modes[i], &xf86dga2_modes[i+1]);
172
173   /* register event handlers */
174   X11DRV_register_event_handler( event_base + MotionNotify, X11DRV_DGAMotionEvent );
175   X11DRV_register_event_handler( event_base + ButtonPress, X11DRV_DGAButtonPressEvent );
176   X11DRV_register_event_handler( event_base + ButtonRelease, X11DRV_DGAButtonReleaseEvent );
177   X11DRV_register_event_handler( event_base + KeyPress, X11DRV_DGAKeyPressEvent );
178   X11DRV_register_event_handler( event_base + KeyRelease, X11DRV_DGAKeyReleaseEvent );
179
180   TRACE("Enabling XF86DGA2 mode\n");
181 }
182
183 void X11DRV_XF86DGA2_Cleanup(void)
184 {
185     wine_tsx11_lock();
186     if (modes) XFree(modes);
187     wine_tsx11_unlock();
188 }
189
190 static XDGADevice *dga_dev;
191
192 static VIDMEM dga_mem = {
193   VIDMEM_ISRECTANGULAR | VIDMEM_ISHEAP
194 };
195
196 static DWORD PASCAL X11DRV_XF86DGA2_SetMode(LPDDHAL_SETMODEDATA data)
197 {
198   LPDDRAWI_DIRECTDRAW_LCL ddlocal = data->lpDD->lpExclusiveOwner;
199   DWORD vram;
200   Display *display = gdi_display;
201
202   data->ddRVal = DD_OK;
203   wine_tsx11_lock();
204   if (data->dwModeIndex) {
205     /* enter DGA */
206     XDGADevice *new_dev = NULL;
207     if (dga_dev || XDGAOpenFramebuffer(display, DefaultScreen(display)))
208       new_dev = XDGASetMode(display, DefaultScreen(display), modes[data->dwModeIndex-1].num);
209     if (new_dev) {
210       XDGASetViewport(display, DefaultScreen(display), 0, 0, XDGAFlipImmediate);
211       if (dga_dev) {
212         VirtualFree(dga_dev->data, 0, MEM_RELEASE);
213         XFree(dga_dev);
214       } else {
215         XDGASelectInput(display, DefaultScreen(display),
216                           KeyPressMask|KeyReleaseMask|
217                           ButtonPressMask|ButtonReleaseMask|
218                           PointerMotionMask);
219         DGAhwnd = (HWND)ddlocal->hWnd;
220       }
221       dga_dev = new_dev;
222       vram = dga_dev->mode.bytesPerScanline * dga_dev->mode.imageHeight;
223       VirtualAlloc(dga_dev->data, vram, MEM_SYSTEM, PAGE_READWRITE);
224       dga_mem.fpStart = (FLATPTR)dga_dev->data;
225       dga_mem.u1.dwWidth = dga_dev->mode.bytesPerScanline;
226       dga_mem.u2.dwHeight = dga_dev->mode.imageHeight;
227       X11DRV_DDHAL_SwitchMode(data->dwModeIndex, dga_dev->data, &dga_mem);
228       X11DRV_DD_IsDirect = TRUE;
229     }
230     else {
231       ERR("failed\n");
232       if (!dga_dev) XDGACloseFramebuffer(display, DefaultScreen(display));
233       data->ddRVal = DDERR_GENERIC;
234     }
235   }
236   else if (dga_dev) {
237     /* exit DGA */
238     X11DRV_DD_IsDirect = FALSE;
239     X11DRV_DDHAL_SwitchMode(0, NULL, NULL);
240     XDGASetMode(display, DefaultScreen(display), 0);
241     VirtualFree(dga_dev->data, 0, MEM_RELEASE);
242     DGAhwnd = 0;
243     XFree(dga_dev);
244     XDGACloseFramebuffer(display, DefaultScreen(display));
245     dga_dev = NULL;
246   }
247   wine_tsx11_unlock();
248   return DDHAL_DRIVER_HANDLED;
249 }
250
251 static LPDDHAL_CREATESURFACE X11DRV_XF86DGA2_old_create_surface;
252
253 static DWORD PASCAL X11DRV_XF86DGA2_CreateSurface(LPDDHAL_CREATESURFACEDATA data)
254 {
255   LPDDRAWI_DDRAWSURFACE_LCL lcl = *data->lplpSList;
256   LPDDRAWI_DDRAWSURFACE_GBL gbl = lcl->lpGbl;
257   LPDDSURFACEDESC2 desc = (LPDDSURFACEDESC2)data->lpDDSurfaceDesc;
258   HRESULT hr = DDHAL_DRIVER_NOTHANDLED;
259
260   if (X11DRV_XF86DGA2_old_create_surface)
261     hr = X11DRV_XF86DGA2_old_create_surface(data);
262
263   if (desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)) {
264     gbl->fpVidMem = 0; /* tell ddraw to allocate the memory */
265     hr = DDHAL_DRIVER_HANDLED;
266   }
267   return hr;
268 }
269
270 static DWORD PASCAL X11DRV_XF86DGA2_CreatePalette(LPDDHAL_CREATEPALETTEDATA data)
271 {
272   Display *display = gdi_display;
273   wine_tsx11_lock();
274   data->lpDDPalette->u1.dwReserved1 = XDGACreateColormap(display, DefaultScreen(display),
275                                                          dga_dev, AllocAll);
276   wine_tsx11_unlock();
277   if (data->lpColorTable)
278     X11DRV_DDHAL_SetPalEntries(data->lpDDPalette->u1.dwReserved1, 0, 256,
279                                data->lpColorTable);
280   data->ddRVal = DD_OK;
281   return DDHAL_DRIVER_HANDLED;
282 }
283
284 static DWORD PASCAL X11DRV_XF86DGA2_Flip(LPDDHAL_FLIPDATA data)
285 {
286   Display *display = gdi_display;
287   if (data->lpSurfCurr == X11DRV_DD_Primary) {
288     DWORD ofs = data->lpSurfCurr->lpGbl->fpVidMem - dga_mem.fpStart;
289     wine_tsx11_lock();
290     XDGASetViewport(display, DefaultScreen(display),
291                     (ofs % dga_dev->mode.bytesPerScanline)*8/dga_dev->mode.bitsPerPixel,
292                     ofs / dga_dev->mode.bytesPerScanline,
293                     XDGAFlipImmediate);
294     wine_tsx11_unlock();
295   }
296   data->ddRVal = DD_OK;
297   return DDHAL_DRIVER_HANDLED;
298 }
299
300 static DWORD PASCAL X11DRV_XF86DGA2_SetPalette(LPDDHAL_SETPALETTEDATA data)
301 {
302   Display *display = gdi_display;
303   if ((data->lpDDSurface == X11DRV_DD_Primary) &&
304       data->lpDDPalette && data->lpDDPalette->u1.dwReserved1)
305   {
306       wine_tsx11_lock();
307       XDGAInstallColormap(display, DefaultScreen(display), data->lpDDPalette->u1.dwReserved1);
308       wine_tsx11_unlock();
309   }
310   data->ddRVal = DD_OK;
311   return DDHAL_DRIVER_HANDLED;
312 }
313
314 int X11DRV_XF86DGA2_CreateDriver(LPDDHALINFO info)
315 {
316   if (!xf86dga2_mode_count) return 0; /* no DGA */
317
318   info->dwNumModes = xf86dga2_mode_count;
319   info->lpModeInfo = xf86dga2_modes;
320   info->dwModeIndex = 0;
321
322   X11DRV_XF86DGA2_old_create_surface = info->lpDDCallbacks->CreateSurface;
323   info->lpDDCallbacks->SetMode = X11DRV_XF86DGA2_SetMode;
324   info->lpDDCallbacks->CreateSurface = X11DRV_XF86DGA2_CreateSurface;
325   info->lpDDCallbacks->CreatePalette = X11DRV_XF86DGA2_CreatePalette;
326   info->lpDDSurfaceCallbacks->Flip = X11DRV_XF86DGA2_Flip;
327   info->lpDDSurfaceCallbacks->SetPalette = X11DRV_XF86DGA2_SetPalette;
328   return TRUE;
329 }
330
331 #endif /* HAVE_LIBXXF86DGA2 */