src/video/windx5/SDL_dx5video.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 24 Jun 2006 04:31:42 +0000
branchSDL-1.3
changeset 1705 fc731a7d83ed
parent 1668 4da1ee79c9af
permissions -rw-r--r--
Merged fix for bug #258 from SDL 1.2
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "directx.h"
    25 
    26 /* Not yet in the mingw32 cross-compile headers */
    27 #ifndef CDS_FULLSCREEN
    28 #define CDS_FULLSCREEN	4
    29 #endif
    30 
    31 #include "SDL_timer.h"
    32 #include "SDL_events.h"
    33 #include "SDL_syswm.h"
    34 #include "../SDL_sysvideo.h"
    35 #include "../SDL_blit.h"
    36 #include "../SDL_pixels_c.h"
    37 #include "SDL_dx5video.h"
    38 #include "../wincommon/SDL_syswm_c.h"
    39 #include "../wincommon/SDL_sysmouse_c.h"
    40 #include "SDL_dx5events_c.h"
    41 #include "SDL_dx5yuv_c.h"
    42 #include "../wincommon/SDL_wingl_c.h"
    43 
    44 #ifdef _WIN32_WCE
    45 #define NO_CHANGEDISPLAYSETTINGS
    46 #endif
    47 #ifndef WS_MAXIMIZE
    48 #define WS_MAXIMIZE		0
    49 #endif
    50 #ifndef SWP_NOCOPYBITS
    51 #define SWP_NOCOPYBITS	0
    52 #endif
    53 #ifndef PC_NOCOLLAPSE
    54 #define PC_NOCOLLAPSE	0
    55 #endif
    56 
    57 
    58 /* DirectX function pointers for video and events */
    59 HRESULT(WINAPI * DDrawCreate) (GUID FAR * lpGUID, LPDIRECTDRAW FAR * lplpDD,
    60                                IUnknown FAR * pUnkOuter);
    61 HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
    62                                 LPDIRECTINPUT * ppDI, LPUNKNOWN punkOuter);
    63 
    64 /* This is the rect EnumModes2 uses */
    65 struct DX5EnumRect
    66 {
    67     SDL_Rect r;
    68     int refreshRate;
    69     struct DX5EnumRect *next;
    70 };
    71 static struct DX5EnumRect *enumlists[NUM_MODELISTS];
    72 
    73 /*
    74  * Experimentally determined values for c_cfDI* constants used in DirectX 5.0
    75  */
    76 
    77 /* Keyboard */
    78 
    79 static DIOBJECTDATAFORMAT KBD_fmt[] = {
    80     {&GUID_Key, 0, 0x8000000C, 0x00000000},
    81     {&GUID_Key, 1, 0x8000010C, 0x00000000},
    82     {&GUID_Key, 2, 0x8000020C, 0x00000000},
    83     {&GUID_Key, 3, 0x8000030C, 0x00000000},
    84     {&GUID_Key, 4, 0x8000040C, 0x00000000},
    85     {&GUID_Key, 5, 0x8000050C, 0x00000000},
    86     {&GUID_Key, 6, 0x8000060C, 0x00000000},
    87     {&GUID_Key, 7, 0x8000070C, 0x00000000},
    88     {&GUID_Key, 8, 0x8000080C, 0x00000000},
    89     {&GUID_Key, 9, 0x8000090C, 0x00000000},
    90     {&GUID_Key, 10, 0x80000A0C, 0x00000000},
    91     {&GUID_Key, 11, 0x80000B0C, 0x00000000},
    92     {&GUID_Key, 12, 0x80000C0C, 0x00000000},
    93     {&GUID_Key, 13, 0x80000D0C, 0x00000000},
    94     {&GUID_Key, 14, 0x80000E0C, 0x00000000},
    95     {&GUID_Key, 15, 0x80000F0C, 0x00000000},
    96     {&GUID_Key, 16, 0x8000100C, 0x00000000},
    97     {&GUID_Key, 17, 0x8000110C, 0x00000000},
    98     {&GUID_Key, 18, 0x8000120C, 0x00000000},
    99     {&GUID_Key, 19, 0x8000130C, 0x00000000},
   100     {&GUID_Key, 20, 0x8000140C, 0x00000000},
   101     {&GUID_Key, 21, 0x8000150C, 0x00000000},
   102     {&GUID_Key, 22, 0x8000160C, 0x00000000},
   103     {&GUID_Key, 23, 0x8000170C, 0x00000000},
   104     {&GUID_Key, 24, 0x8000180C, 0x00000000},
   105     {&GUID_Key, 25, 0x8000190C, 0x00000000},
   106     {&GUID_Key, 26, 0x80001A0C, 0x00000000},
   107     {&GUID_Key, 27, 0x80001B0C, 0x00000000},
   108     {&GUID_Key, 28, 0x80001C0C, 0x00000000},
   109     {&GUID_Key, 29, 0x80001D0C, 0x00000000},
   110     {&GUID_Key, 30, 0x80001E0C, 0x00000000},
   111     {&GUID_Key, 31, 0x80001F0C, 0x00000000},
   112     {&GUID_Key, 32, 0x8000200C, 0x00000000},
   113     {&GUID_Key, 33, 0x8000210C, 0x00000000},
   114     {&GUID_Key, 34, 0x8000220C, 0x00000000},
   115     {&GUID_Key, 35, 0x8000230C, 0x00000000},
   116     {&GUID_Key, 36, 0x8000240C, 0x00000000},
   117     {&GUID_Key, 37, 0x8000250C, 0x00000000},
   118     {&GUID_Key, 38, 0x8000260C, 0x00000000},
   119     {&GUID_Key, 39, 0x8000270C, 0x00000000},
   120     {&GUID_Key, 40, 0x8000280C, 0x00000000},
   121     {&GUID_Key, 41, 0x8000290C, 0x00000000},
   122     {&GUID_Key, 42, 0x80002A0C, 0x00000000},
   123     {&GUID_Key, 43, 0x80002B0C, 0x00000000},
   124     {&GUID_Key, 44, 0x80002C0C, 0x00000000},
   125     {&GUID_Key, 45, 0x80002D0C, 0x00000000},
   126     {&GUID_Key, 46, 0x80002E0C, 0x00000000},
   127     {&GUID_Key, 47, 0x80002F0C, 0x00000000},
   128     {&GUID_Key, 48, 0x8000300C, 0x00000000},
   129     {&GUID_Key, 49, 0x8000310C, 0x00000000},
   130     {&GUID_Key, 50, 0x8000320C, 0x00000000},
   131     {&GUID_Key, 51, 0x8000330C, 0x00000000},
   132     {&GUID_Key, 52, 0x8000340C, 0x00000000},
   133     {&GUID_Key, 53, 0x8000350C, 0x00000000},
   134     {&GUID_Key, 54, 0x8000360C, 0x00000000},
   135     {&GUID_Key, 55, 0x8000370C, 0x00000000},
   136     {&GUID_Key, 56, 0x8000380C, 0x00000000},
   137     {&GUID_Key, 57, 0x8000390C, 0x00000000},
   138     {&GUID_Key, 58, 0x80003A0C, 0x00000000},
   139     {&GUID_Key, 59, 0x80003B0C, 0x00000000},
   140     {&GUID_Key, 60, 0x80003C0C, 0x00000000},
   141     {&GUID_Key, 61, 0x80003D0C, 0x00000000},
   142     {&GUID_Key, 62, 0x80003E0C, 0x00000000},
   143     {&GUID_Key, 63, 0x80003F0C, 0x00000000},
   144     {&GUID_Key, 64, 0x8000400C, 0x00000000},
   145     {&GUID_Key, 65, 0x8000410C, 0x00000000},
   146     {&GUID_Key, 66, 0x8000420C, 0x00000000},
   147     {&GUID_Key, 67, 0x8000430C, 0x00000000},
   148     {&GUID_Key, 68, 0x8000440C, 0x00000000},
   149     {&GUID_Key, 69, 0x8000450C, 0x00000000},
   150     {&GUID_Key, 70, 0x8000460C, 0x00000000},
   151     {&GUID_Key, 71, 0x8000470C, 0x00000000},
   152     {&GUID_Key, 72, 0x8000480C, 0x00000000},
   153     {&GUID_Key, 73, 0x8000490C, 0x00000000},
   154     {&GUID_Key, 74, 0x80004A0C, 0x00000000},
   155     {&GUID_Key, 75, 0x80004B0C, 0x00000000},
   156     {&GUID_Key, 76, 0x80004C0C, 0x00000000},
   157     {&GUID_Key, 77, 0x80004D0C, 0x00000000},
   158     {&GUID_Key, 78, 0x80004E0C, 0x00000000},
   159     {&GUID_Key, 79, 0x80004F0C, 0x00000000},
   160     {&GUID_Key, 80, 0x8000500C, 0x00000000},
   161     {&GUID_Key, 81, 0x8000510C, 0x00000000},
   162     {&GUID_Key, 82, 0x8000520C, 0x00000000},
   163     {&GUID_Key, 83, 0x8000530C, 0x00000000},
   164     {&GUID_Key, 84, 0x8000540C, 0x00000000},
   165     {&GUID_Key, 85, 0x8000550C, 0x00000000},
   166     {&GUID_Key, 86, 0x8000560C, 0x00000000},
   167     {&GUID_Key, 87, 0x8000570C, 0x00000000},
   168     {&GUID_Key, 88, 0x8000580C, 0x00000000},
   169     {&GUID_Key, 89, 0x8000590C, 0x00000000},
   170     {&GUID_Key, 90, 0x80005A0C, 0x00000000},
   171     {&GUID_Key, 91, 0x80005B0C, 0x00000000},
   172     {&GUID_Key, 92, 0x80005C0C, 0x00000000},
   173     {&GUID_Key, 93, 0x80005D0C, 0x00000000},
   174     {&GUID_Key, 94, 0x80005E0C, 0x00000000},
   175     {&GUID_Key, 95, 0x80005F0C, 0x00000000},
   176     {&GUID_Key, 96, 0x8000600C, 0x00000000},
   177     {&GUID_Key, 97, 0x8000610C, 0x00000000},
   178     {&GUID_Key, 98, 0x8000620C, 0x00000000},
   179     {&GUID_Key, 99, 0x8000630C, 0x00000000},
   180     {&GUID_Key, 100, 0x8000640C, 0x00000000},
   181     {&GUID_Key, 101, 0x8000650C, 0x00000000},
   182     {&GUID_Key, 102, 0x8000660C, 0x00000000},
   183     {&GUID_Key, 103, 0x8000670C, 0x00000000},
   184     {&GUID_Key, 104, 0x8000680C, 0x00000000},
   185     {&GUID_Key, 105, 0x8000690C, 0x00000000},
   186     {&GUID_Key, 106, 0x80006A0C, 0x00000000},
   187     {&GUID_Key, 107, 0x80006B0C, 0x00000000},
   188     {&GUID_Key, 108, 0x80006C0C, 0x00000000},
   189     {&GUID_Key, 109, 0x80006D0C, 0x00000000},
   190     {&GUID_Key, 110, 0x80006E0C, 0x00000000},
   191     {&GUID_Key, 111, 0x80006F0C, 0x00000000},
   192     {&GUID_Key, 112, 0x8000700C, 0x00000000},
   193     {&GUID_Key, 113, 0x8000710C, 0x00000000},
   194     {&GUID_Key, 114, 0x8000720C, 0x00000000},
   195     {&GUID_Key, 115, 0x8000730C, 0x00000000},
   196     {&GUID_Key, 116, 0x8000740C, 0x00000000},
   197     {&GUID_Key, 117, 0x8000750C, 0x00000000},
   198     {&GUID_Key, 118, 0x8000760C, 0x00000000},
   199     {&GUID_Key, 119, 0x8000770C, 0x00000000},
   200     {&GUID_Key, 120, 0x8000780C, 0x00000000},
   201     {&GUID_Key, 121, 0x8000790C, 0x00000000},
   202     {&GUID_Key, 122, 0x80007A0C, 0x00000000},
   203     {&GUID_Key, 123, 0x80007B0C, 0x00000000},
   204     {&GUID_Key, 124, 0x80007C0C, 0x00000000},
   205     {&GUID_Key, 125, 0x80007D0C, 0x00000000},
   206     {&GUID_Key, 126, 0x80007E0C, 0x00000000},
   207     {&GUID_Key, 127, 0x80007F0C, 0x00000000},
   208     {&GUID_Key, 128, 0x8000800C, 0x00000000},
   209     {&GUID_Key, 129, 0x8000810C, 0x00000000},
   210     {&GUID_Key, 130, 0x8000820C, 0x00000000},
   211     {&GUID_Key, 131, 0x8000830C, 0x00000000},
   212     {&GUID_Key, 132, 0x8000840C, 0x00000000},
   213     {&GUID_Key, 133, 0x8000850C, 0x00000000},
   214     {&GUID_Key, 134, 0x8000860C, 0x00000000},
   215     {&GUID_Key, 135, 0x8000870C, 0x00000000},
   216     {&GUID_Key, 136, 0x8000880C, 0x00000000},
   217     {&GUID_Key, 137, 0x8000890C, 0x00000000},
   218     {&GUID_Key, 138, 0x80008A0C, 0x00000000},
   219     {&GUID_Key, 139, 0x80008B0C, 0x00000000},
   220     {&GUID_Key, 140, 0x80008C0C, 0x00000000},
   221     {&GUID_Key, 141, 0x80008D0C, 0x00000000},
   222     {&GUID_Key, 142, 0x80008E0C, 0x00000000},
   223     {&GUID_Key, 143, 0x80008F0C, 0x00000000},
   224     {&GUID_Key, 144, 0x8000900C, 0x00000000},
   225     {&GUID_Key, 145, 0x8000910C, 0x00000000},
   226     {&GUID_Key, 146, 0x8000920C, 0x00000000},
   227     {&GUID_Key, 147, 0x8000930C, 0x00000000},
   228     {&GUID_Key, 148, 0x8000940C, 0x00000000},
   229     {&GUID_Key, 149, 0x8000950C, 0x00000000},
   230     {&GUID_Key, 150, 0x8000960C, 0x00000000},
   231     {&GUID_Key, 151, 0x8000970C, 0x00000000},
   232     {&GUID_Key, 152, 0x8000980C, 0x00000000},
   233     {&GUID_Key, 153, 0x8000990C, 0x00000000},
   234     {&GUID_Key, 154, 0x80009A0C, 0x00000000},
   235     {&GUID_Key, 155, 0x80009B0C, 0x00000000},
   236     {&GUID_Key, 156, 0x80009C0C, 0x00000000},
   237     {&GUID_Key, 157, 0x80009D0C, 0x00000000},
   238     {&GUID_Key, 158, 0x80009E0C, 0x00000000},
   239     {&GUID_Key, 159, 0x80009F0C, 0x00000000},
   240     {&GUID_Key, 160, 0x8000A00C, 0x00000000},
   241     {&GUID_Key, 161, 0x8000A10C, 0x00000000},
   242     {&GUID_Key, 162, 0x8000A20C, 0x00000000},
   243     {&GUID_Key, 163, 0x8000A30C, 0x00000000},
   244     {&GUID_Key, 164, 0x8000A40C, 0x00000000},
   245     {&GUID_Key, 165, 0x8000A50C, 0x00000000},
   246     {&GUID_Key, 166, 0x8000A60C, 0x00000000},
   247     {&GUID_Key, 167, 0x8000A70C, 0x00000000},
   248     {&GUID_Key, 168, 0x8000A80C, 0x00000000},
   249     {&GUID_Key, 169, 0x8000A90C, 0x00000000},
   250     {&GUID_Key, 170, 0x8000AA0C, 0x00000000},
   251     {&GUID_Key, 171, 0x8000AB0C, 0x00000000},
   252     {&GUID_Key, 172, 0x8000AC0C, 0x00000000},
   253     {&GUID_Key, 173, 0x8000AD0C, 0x00000000},
   254     {&GUID_Key, 174, 0x8000AE0C, 0x00000000},
   255     {&GUID_Key, 175, 0x8000AF0C, 0x00000000},
   256     {&GUID_Key, 176, 0x8000B00C, 0x00000000},
   257     {&GUID_Key, 177, 0x8000B10C, 0x00000000},
   258     {&GUID_Key, 178, 0x8000B20C, 0x00000000},
   259     {&GUID_Key, 179, 0x8000B30C, 0x00000000},
   260     {&GUID_Key, 180, 0x8000B40C, 0x00000000},
   261     {&GUID_Key, 181, 0x8000B50C, 0x00000000},
   262     {&GUID_Key, 182, 0x8000B60C, 0x00000000},
   263     {&GUID_Key, 183, 0x8000B70C, 0x00000000},
   264     {&GUID_Key, 184, 0x8000B80C, 0x00000000},
   265     {&GUID_Key, 185, 0x8000B90C, 0x00000000},
   266     {&GUID_Key, 186, 0x8000BA0C, 0x00000000},
   267     {&GUID_Key, 187, 0x8000BB0C, 0x00000000},
   268     {&GUID_Key, 188, 0x8000BC0C, 0x00000000},
   269     {&GUID_Key, 189, 0x8000BD0C, 0x00000000},
   270     {&GUID_Key, 190, 0x8000BE0C, 0x00000000},
   271     {&GUID_Key, 191, 0x8000BF0C, 0x00000000},
   272     {&GUID_Key, 192, 0x8000C00C, 0x00000000},
   273     {&GUID_Key, 193, 0x8000C10C, 0x00000000},
   274     {&GUID_Key, 194, 0x8000C20C, 0x00000000},
   275     {&GUID_Key, 195, 0x8000C30C, 0x00000000},
   276     {&GUID_Key, 196, 0x8000C40C, 0x00000000},
   277     {&GUID_Key, 197, 0x8000C50C, 0x00000000},
   278     {&GUID_Key, 198, 0x8000C60C, 0x00000000},
   279     {&GUID_Key, 199, 0x8000C70C, 0x00000000},
   280     {&GUID_Key, 200, 0x8000C80C, 0x00000000},
   281     {&GUID_Key, 201, 0x8000C90C, 0x00000000},
   282     {&GUID_Key, 202, 0x8000CA0C, 0x00000000},
   283     {&GUID_Key, 203, 0x8000CB0C, 0x00000000},
   284     {&GUID_Key, 204, 0x8000CC0C, 0x00000000},
   285     {&GUID_Key, 205, 0x8000CD0C, 0x00000000},
   286     {&GUID_Key, 206, 0x8000CE0C, 0x00000000},
   287     {&GUID_Key, 207, 0x8000CF0C, 0x00000000},
   288     {&GUID_Key, 208, 0x8000D00C, 0x00000000},
   289     {&GUID_Key, 209, 0x8000D10C, 0x00000000},
   290     {&GUID_Key, 210, 0x8000D20C, 0x00000000},
   291     {&GUID_Key, 211, 0x8000D30C, 0x00000000},
   292     {&GUID_Key, 212, 0x8000D40C, 0x00000000},
   293     {&GUID_Key, 213, 0x8000D50C, 0x00000000},
   294     {&GUID_Key, 214, 0x8000D60C, 0x00000000},
   295     {&GUID_Key, 215, 0x8000D70C, 0x00000000},
   296     {&GUID_Key, 216, 0x8000D80C, 0x00000000},
   297     {&GUID_Key, 217, 0x8000D90C, 0x00000000},
   298     {&GUID_Key, 218, 0x8000DA0C, 0x00000000},
   299     {&GUID_Key, 219, 0x8000DB0C, 0x00000000},
   300     {&GUID_Key, 220, 0x8000DC0C, 0x00000000},
   301     {&GUID_Key, 221, 0x8000DD0C, 0x00000000},
   302     {&GUID_Key, 222, 0x8000DE0C, 0x00000000},
   303     {&GUID_Key, 223, 0x8000DF0C, 0x00000000},
   304     {&GUID_Key, 224, 0x8000E00C, 0x00000000},
   305     {&GUID_Key, 225, 0x8000E10C, 0x00000000},
   306     {&GUID_Key, 226, 0x8000E20C, 0x00000000},
   307     {&GUID_Key, 227, 0x8000E30C, 0x00000000},
   308     {&GUID_Key, 228, 0x8000E40C, 0x00000000},
   309     {&GUID_Key, 229, 0x8000E50C, 0x00000000},
   310     {&GUID_Key, 230, 0x8000E60C, 0x00000000},
   311     {&GUID_Key, 231, 0x8000E70C, 0x00000000},
   312     {&GUID_Key, 232, 0x8000E80C, 0x00000000},
   313     {&GUID_Key, 233, 0x8000E90C, 0x00000000},
   314     {&GUID_Key, 234, 0x8000EA0C, 0x00000000},
   315     {&GUID_Key, 235, 0x8000EB0C, 0x00000000},
   316     {&GUID_Key, 236, 0x8000EC0C, 0x00000000},
   317     {&GUID_Key, 237, 0x8000ED0C, 0x00000000},
   318     {&GUID_Key, 238, 0x8000EE0C, 0x00000000},
   319     {&GUID_Key, 239, 0x8000EF0C, 0x00000000},
   320     {&GUID_Key, 240, 0x8000F00C, 0x00000000},
   321     {&GUID_Key, 241, 0x8000F10C, 0x00000000},
   322     {&GUID_Key, 242, 0x8000F20C, 0x00000000},
   323     {&GUID_Key, 243, 0x8000F30C, 0x00000000},
   324     {&GUID_Key, 244, 0x8000F40C, 0x00000000},
   325     {&GUID_Key, 245, 0x8000F50C, 0x00000000},
   326     {&GUID_Key, 246, 0x8000F60C, 0x00000000},
   327     {&GUID_Key, 247, 0x8000F70C, 0x00000000},
   328     {&GUID_Key, 248, 0x8000F80C, 0x00000000},
   329     {&GUID_Key, 249, 0x8000F90C, 0x00000000},
   330     {&GUID_Key, 250, 0x8000FA0C, 0x00000000},
   331     {&GUID_Key, 251, 0x8000FB0C, 0x00000000},
   332     {&GUID_Key, 252, 0x8000FC0C, 0x00000000},
   333     {&GUID_Key, 253, 0x8000FD0C, 0x00000000},
   334     {&GUID_Key, 254, 0x8000FE0C, 0x00000000},
   335     {&GUID_Key, 255, 0x8000FF0C, 0x00000000},
   336 };
   337 
   338 const DIDATAFORMAT c_dfDIKeyboard = { 24, 16, 0x00000002, 256, 256, KBD_fmt };
   339 
   340 
   341 /* Mouse */
   342 
   343 static DIOBJECTDATAFORMAT PTR_fmt[] = {
   344     {&GUID_XAxis, 0, 0x00FFFF03, 0x00000000},
   345     {&GUID_YAxis, 4, 0x00FFFF03, 0x00000000},
   346     {&GUID_ZAxis, 8, 0x80FFFF03, 0x00000000},
   347     {NULL, 12, 0x00FFFF0C, 0x00000000},
   348     {NULL, 13, 0x00FFFF0C, 0x00000000},
   349     {NULL, 14, 0x80FFFF0C, 0x00000000},
   350     {NULL, 15, 0x80FFFF0C, 0x00000000},
   351 };
   352 
   353 const DIDATAFORMAT c_dfDIMouse = { 24, 16, 0x00000002, 16, 7, PTR_fmt };
   354 
   355 
   356 /* Joystick */
   357 
   358 static DIOBJECTDATAFORMAT JOY_fmt[] = {
   359     {&GUID_XAxis, 0, 0x80FFFF03, 0x00000100},
   360     {&GUID_YAxis, 4, 0x80FFFF03, 0x00000100},
   361     {&GUID_ZAxis, 8, 0x80FFFF03, 0x00000100},
   362     {&GUID_RxAxis, 12, 0x80FFFF03, 0x00000100},
   363     {&GUID_RyAxis, 16, 0x80FFFF03, 0x00000100},
   364     {&GUID_RzAxis, 20, 0x80FFFF03, 0x00000100},
   365     {&GUID_Slider, 24, 0x80FFFF03, 0x00000100},
   366     {&GUID_Slider, 28, 0x80FFFF03, 0x00000100},
   367     {&GUID_POV, 32, 0x80FFFF10, 0x00000000},
   368     {&GUID_POV, 36, 0x80FFFF10, 0x00000000},
   369     {&GUID_POV, 40, 0x80FFFF10, 0x00000000},
   370     {&GUID_POV, 44, 0x80FFFF10, 0x00000000},
   371     {NULL, 48, 0x80FFFF0C, 0x00000000},
   372     {NULL, 49, 0x80FFFF0C, 0x00000000},
   373     {NULL, 50, 0x80FFFF0C, 0x00000000},
   374     {NULL, 51, 0x80FFFF0C, 0x00000000},
   375     {NULL, 52, 0x80FFFF0C, 0x00000000},
   376     {NULL, 53, 0x80FFFF0C, 0x00000000},
   377     {NULL, 54, 0x80FFFF0C, 0x00000000},
   378     {NULL, 55, 0x80FFFF0C, 0x00000000},
   379     {NULL, 56, 0x80FFFF0C, 0x00000000},
   380     {NULL, 57, 0x80FFFF0C, 0x00000000},
   381     {NULL, 58, 0x80FFFF0C, 0x00000000},
   382     {NULL, 59, 0x80FFFF0C, 0x00000000},
   383     {NULL, 60, 0x80FFFF0C, 0x00000000},
   384     {NULL, 61, 0x80FFFF0C, 0x00000000},
   385     {NULL, 62, 0x80FFFF0C, 0x00000000},
   386     {NULL, 63, 0x80FFFF0C, 0x00000000},
   387     {NULL, 64, 0x80FFFF0C, 0x00000000},
   388     {NULL, 65, 0x80FFFF0C, 0x00000000},
   389     {NULL, 66, 0x80FFFF0C, 0x00000000},
   390     {NULL, 67, 0x80FFFF0C, 0x00000000},
   391     {NULL, 68, 0x80FFFF0C, 0x00000000},
   392     {NULL, 69, 0x80FFFF0C, 0x00000000},
   393     {NULL, 70, 0x80FFFF0C, 0x00000000},
   394     {NULL, 71, 0x80FFFF0C, 0x00000000},
   395     {NULL, 72, 0x80FFFF0C, 0x00000000},
   396     {NULL, 73, 0x80FFFF0C, 0x00000000},
   397     {NULL, 74, 0x80FFFF0C, 0x00000000},
   398     {NULL, 75, 0x80FFFF0C, 0x00000000},
   399     {NULL, 76, 0x80FFFF0C, 0x00000000},
   400     {NULL, 77, 0x80FFFF0C, 0x00000000},
   401     {NULL, 78, 0x80FFFF0C, 0x00000000},
   402     {NULL, 79, 0x80FFFF0C, 0x00000000},
   403 };
   404 
   405 const DIDATAFORMAT c_dfDIJoystick = { 24, 16, 0x00000001, 80, 44, JOY_fmt };
   406 
   407 
   408 /* Initialization/Query functions */
   409 static int DX5_VideoInit(_THIS, SDL_PixelFormat * vformat);
   410 static SDL_Rect **DX5_ListModes(_THIS, SDL_PixelFormat * format,
   411                                 Uint32 flags);
   412 static SDL_Surface *DX5_SetVideoMode(_THIS, SDL_Surface * current, int width,
   413                                      int height, int bpp, Uint32 flags);
   414 static int DX5_SetColors(_THIS, int firstcolor, int ncolors,
   415                          SDL_Color * colors);
   416 static int DX5_SetGammaRamp(_THIS, Uint16 * ramp);
   417 static int DX5_GetGammaRamp(_THIS, Uint16 * ramp);
   418 static void DX5_VideoQuit(_THIS);
   419 
   420 /* Hardware surface functions */
   421 static int DX5_AllocHWSurface(_THIS, SDL_Surface * surface);
   422 static int DX5_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst);
   423 static int DX5_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * dstrect,
   424                           Uint32 color);
   425 static int DX5_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key);
   426 static int DX5_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha);
   427 static int DX5_LockHWSurface(_THIS, SDL_Surface * surface);
   428 static void DX5_UnlockHWSurface(_THIS, SDL_Surface * surface);
   429 static int DX5_FlipHWSurface(_THIS, SDL_Surface * surface);
   430 static void DX5_FreeHWSurface(_THIS, SDL_Surface * surface);
   431 
   432 static int DX5_AllocDDSurface(_THIS, SDL_Surface * surface,
   433                               LPDIRECTDRAWSURFACE3 requested, Uint32 flag);
   434 
   435 /* Windows message handling functions */
   436 static void DX5_RealizePalette(_THIS);
   437 static void DX5_PaletteChanged(_THIS, HWND window);
   438 static void DX5_WinPAINT(_THIS, HDC hdc);
   439 
   440 /* WinDIB driver functions for manipulating gamma ramps */
   441 extern int DIB_SetGammaRamp(_THIS, Uint16 * ramp);
   442 extern int DIB_GetGammaRamp(_THIS, Uint16 * ramp);
   443 extern void DIB_QuitGamma(_THIS);
   444 
   445 /* Functions for loading the DirectX functions dynamically */
   446 static int DX5_loaded = 0;
   447 static HINSTANCE DDrawDLL = NULL;
   448 static HINSTANCE DInputDLL = NULL;
   449 
   450 void
   451 DX5_Unload(void)
   452 {
   453     if (--DX5_loaded == 0) {
   454         if (DDrawDLL != NULL) {
   455             FreeLibrary(DDrawDLL);
   456             DDrawCreate = NULL;
   457             DDrawDLL = NULL;
   458         }
   459         if (DInputDLL != NULL) {
   460             FreeLibrary(DInputDLL);
   461             DInputCreate = NULL;
   462             DInputDLL = NULL;
   463         }
   464     }
   465 }
   466 int
   467 DX5_Load(void)
   468 {
   469     int status = 0;
   470 
   471     if (++DX5_loaded == 1) {
   472         DDrawDLL = LoadLibrary(TEXT("DDRAW.DLL"));
   473         if (DDrawDLL != NULL) {
   474             DDrawCreate = (void *) GetProcAddress(DDrawDLL,
   475                                                   TEXT("DirectDrawCreate"));
   476         }
   477         DInputDLL = LoadLibrary(TEXT("DINPUT.DLL"));
   478         if (DInputDLL != NULL) {
   479             DInputCreate = (void *) GetProcAddress(DInputDLL,
   480                                                    TEXT
   481                                                    ("DirectInputCreateA"));
   482         }
   483         if (DDrawDLL && DDrawCreate && DInputDLL && DInputCreate) {
   484             status = 0;
   485         } else {
   486             DX5_Unload();
   487             status = -1;
   488         }
   489     }
   490     return status;
   491 }
   492 
   493 /* DX5 driver bootstrap functions */
   494 
   495 static int
   496 DX5_Available(void)
   497 {
   498     int ddraw_ok = 0;
   499     HRESULT(WINAPI * DDrawCreate) (GUID *, LPDIRECTDRAW *, IUnknown *);
   500     LPDIRECTDRAW DDraw;
   501 
   502     /* Version check DINPUT.DLL and DDRAW.DLL (Is DirectX okay?) */
   503     if (DX5_Load() < 0) {
   504         return -1;
   505     }
   506 
   507     /* Try to create a valid DirectDraw object */
   508     DDrawCreate = (void *) GetProcAddress(DDrawDLL, TEXT("DirectDrawCreate"));
   509     if ((DDrawCreate != NULL) && !FAILED(DDrawCreate(NULL, &DDraw, NULL))) {
   510         if (!FAILED(IDirectDraw_SetCooperativeLevel(DDraw,
   511                                                     NULL, DDSCL_NORMAL))) {
   512             DDSURFACEDESC desc;
   513             LPDIRECTDRAWSURFACE DDrawSurf;
   514             LPDIRECTDRAWSURFACE3 DDrawSurf3;
   515 
   516             /* Try to create a DirectDrawSurface3 object */
   517             SDL_memset(&desc, 0, sizeof(desc));
   518             desc.dwSize = sizeof(desc);
   519             desc.dwFlags = DDSD_CAPS;
   520             desc.ddsCaps.dwCaps =
   521                 DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY;
   522             if (!FAILED
   523                 (IDirectDraw_CreateSurface(DDraw, &desc, &DDrawSurf, NULL))) {
   524                 if (!FAILED
   525                     (IDirectDrawSurface_QueryInterface
   526                      (DDrawSurf, &IID_IDirectDrawSurface3,
   527                       (LPVOID *) & DDrawSurf3))) {
   528                     /* Yay! */
   529                     ddraw_ok = 1;
   530 
   531                     /* Clean up.. */
   532                     IDirectDrawSurface3_Release(DDrawSurf3);
   533                 }
   534                 IDirectDrawSurface_Release(DDrawSurf);
   535             }
   536         }
   537         IDirectDraw_Release(DDraw);
   538     }
   539 
   540     DX5_Unload();
   541 
   542     return ddraw_ok;
   543 }
   544 
   545 static void
   546 DX5_DeleteDevice(SDL_VideoDevice * this)
   547 {
   548     /* Free DirectDraw object */
   549     if (ddraw2 != NULL) {
   550         IDirectDraw2_Release(ddraw2);
   551     }
   552     DX5_Unload();
   553 
   554     if (this) {
   555         if (this->hidden) {
   556             SDL_free(this->hidden);
   557         }
   558         if (this->gl_data) {
   559             SDL_free(this->gl_data);
   560         }
   561         SDL_free(this);
   562     }
   563 }
   564 
   565 static SDL_VideoDevice *
   566 DX5_CreateDevice(int devindex)
   567 {
   568     SDL_VideoDevice *device;
   569 
   570     /* Load DirectX */
   571     if (DX5_Load() < 0) {
   572         return (NULL);
   573     }
   574 
   575     /* Initialize all variables that we clean on shutdown */
   576     device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
   577     if (device) {
   578         SDL_memset(device, 0, (sizeof *device));
   579         device->hidden = (struct SDL_PrivateVideoData *)
   580             SDL_malloc((sizeof *device->hidden));
   581         device->gl_data = (struct SDL_PrivateGLData *)
   582             SDL_malloc((sizeof *device->gl_data));
   583     }
   584     if ((device == NULL) || (device->hidden == NULL) ||
   585         (device->gl_data == NULL)) {
   586         SDL_OutOfMemory();
   587         DX5_DeleteDevice(device);
   588         return (NULL);
   589     }
   590     SDL_memset(device->hidden, 0, (sizeof *device->hidden));
   591     SDL_memset(device->gl_data, 0, (sizeof *device->gl_data));
   592 
   593     /* Set the function pointers */
   594     device->VideoInit = DX5_VideoInit;
   595     device->ListModes = DX5_ListModes;
   596     device->SetVideoMode = DX5_SetVideoMode;
   597     device->UpdateMouse = WIN_UpdateMouse;
   598     device->CreateYUVOverlay = DX5_CreateYUVOverlay;
   599     device->SetColors = DX5_SetColors;
   600     device->UpdateRects = NULL;
   601     device->VideoQuit = DX5_VideoQuit;
   602     device->AllocHWSurface = DX5_AllocHWSurface;
   603     device->CheckHWBlit = DX5_CheckHWBlit;
   604     device->FillHWRect = DX5_FillHWRect;
   605     device->SetHWColorKey = DX5_SetHWColorKey;
   606     device->SetHWAlpha = DX5_SetHWAlpha;
   607     device->LockHWSurface = DX5_LockHWSurface;
   608     device->UnlockHWSurface = DX5_UnlockHWSurface;
   609     device->FlipHWSurface = DX5_FlipHWSurface;
   610     device->FreeHWSurface = DX5_FreeHWSurface;
   611     device->SetGammaRamp = DX5_SetGammaRamp;
   612     device->GetGammaRamp = DX5_GetGammaRamp;
   613 #if SDL_VIDEO_OPENGL
   614     device->GL_LoadLibrary = WIN_GL_LoadLibrary;
   615     device->GL_GetProcAddress = WIN_GL_GetProcAddress;
   616     device->GL_GetAttribute = WIN_GL_GetAttribute;
   617     device->GL_MakeCurrent = WIN_GL_MakeCurrent;
   618     device->GL_SwapBuffers = WIN_GL_SwapBuffers;
   619 #endif
   620     device->SetCaption = WIN_SetWMCaption;
   621     device->SetIcon = WIN_SetWMIcon;
   622     device->IconifyWindow = WIN_IconifyWindow;
   623     device->GrabInput = WIN_GrabInput;
   624     device->GetWMInfo = WIN_GetWMInfo;
   625     device->FreeWMCursor = WIN_FreeWMCursor;
   626     device->CreateWMCursor = WIN_CreateWMCursor;
   627     device->ShowWMCursor = WIN_ShowWMCursor;
   628     device->WarpWMCursor = WIN_WarpWMCursor;
   629     device->CheckMouseMode = WIN_CheckMouseMode;
   630     device->InitOSKeymap = DX5_InitOSKeymap;
   631     device->PumpEvents = DX5_PumpEvents;
   632 
   633     /* Set up the windows message handling functions */
   634     WIN_RealizePalette = DX5_RealizePalette;
   635     WIN_PaletteChanged = DX5_PaletteChanged;
   636     WIN_WinPAINT = DX5_WinPAINT;
   637     HandleMessage = DX5_HandleMessage;
   638 
   639     device->free = DX5_DeleteDevice;
   640 
   641     /* We're finally ready */
   642     return device;
   643 }
   644 
   645 VideoBootStrap DIRECTX_bootstrap = {
   646     "directx", "Win95/98/2000 DirectX",
   647     DX5_Available, DX5_CreateDevice
   648 };
   649 
   650 static int
   651 cmpmodes(const void *va, const void *vb)
   652 {
   653     SDL_Rect *a = *(SDL_Rect **) va;
   654     SDL_Rect *b = *(SDL_Rect **) vb;
   655     if (a->w == b->w)
   656         return b->h - a->h;
   657     else
   658         return b->w - a->w;
   659 }
   660 
   661 static HRESULT WINAPI
   662 EnumModes2(DDSURFACEDESC * desc, VOID * udata)
   663 {
   664     SDL_VideoDevice *this = (SDL_VideoDevice *) udata;
   665     struct DX5EnumRect *enumrect;
   666 #if defined(NONAMELESSUNION)
   667     int bpp = desc->ddpfPixelFormat.u1.dwRGBBitCount;
   668     int refreshRate = desc->u2.dwRefreshRate;
   669 #else
   670     int bpp = desc->ddpfPixelFormat.dwRGBBitCount;
   671     int refreshRate = desc->dwRefreshRate;
   672 #endif
   673     int maxRefreshRate;
   674 
   675     if (desc->dwWidth <= SDL_desktop_mode.dmPelsWidth &&
   676         desc->dwHeight <= SDL_desktop_mode.dmPelsHeight) {
   677         maxRefreshRate = SDL_desktop_mode.dmDisplayFrequency;
   678     } else {
   679         maxRefreshRate = 85;    /* safe value? */
   680     }
   681 
   682     switch (bpp) {
   683     case 8:
   684     case 16:
   685     case 24:
   686     case 32:
   687         bpp /= 8;
   688         --bpp;
   689         if (enumlists[bpp] &&
   690             enumlists[bpp]->r.w == (Uint16) desc->dwWidth &&
   691             enumlists[bpp]->r.h == (Uint16) desc->dwHeight) {
   692             if (refreshRate > enumlists[bpp]->refreshRate &&
   693                 refreshRate <= maxRefreshRate) {
   694                 enumlists[bpp]->refreshRate = refreshRate;
   695 #ifdef DDRAW_DEBUG
   696                 fprintf(stderr,
   697                         "New refresh rate for %d bpp: %dx%d at %d Hz\n",
   698                         (bpp + 1) * 8, (int) desc->dwWidth,
   699                         (int) desc->dwHeight, refreshRate);
   700 #endif
   701             }
   702             break;
   703         }
   704         ++SDL_nummodes[bpp];
   705         enumrect =
   706             (struct DX5EnumRect *) SDL_malloc(sizeof(struct DX5EnumRect));
   707         if (!enumrect) {
   708             SDL_OutOfMemory();
   709             return (DDENUMRET_CANCEL);
   710         }
   711         enumrect->refreshRate = refreshRate;
   712         enumrect->r.x = 0;
   713         enumrect->r.y = 0;
   714         enumrect->r.w = (Uint16) desc->dwWidth;
   715         enumrect->r.h = (Uint16) desc->dwHeight;
   716         enumrect->next = enumlists[bpp];
   717         enumlists[bpp] = enumrect;
   718 #ifdef DDRAW_DEBUG
   719         fprintf(stderr, "New mode for %d bpp: %dx%d at %d Hz\n",
   720                 (bpp + 1) * 8, (int) desc->dwWidth, (int) desc->dwHeight,
   721                 refreshRate);
   722 #endif
   723         break;
   724     }
   725 
   726     return (DDENUMRET_OK);
   727 }
   728 
   729 void
   730 SetDDerror(const char *function, int code)
   731 {
   732     static char *error;
   733     static char errbuf[1024];
   734 
   735     errbuf[0] = 0;
   736     switch (code) {
   737     case DDERR_GENERIC:
   738         error = "Undefined error!";
   739         break;
   740     case DDERR_EXCEPTION:
   741         error = "Exception encountered";
   742         break;
   743     case DDERR_INVALIDOBJECT:
   744         error = "Invalid object";
   745         break;
   746     case DDERR_INVALIDPARAMS:
   747         error = "Invalid parameters";
   748         break;
   749     case DDERR_NOTFOUND:
   750         error = "Object not found";
   751         break;
   752     case DDERR_INVALIDRECT:
   753         error = "Invalid rectangle";
   754         break;
   755     case DDERR_INVALIDCAPS:
   756         error = "Invalid caps member";
   757         break;
   758     case DDERR_INVALIDPIXELFORMAT:
   759         error = "Invalid pixel format";
   760         break;
   761     case DDERR_OUTOFMEMORY:
   762         error = "Out of memory";
   763         break;
   764     case DDERR_OUTOFVIDEOMEMORY:
   765         error = "Out of video memory";
   766         break;
   767     case DDERR_SURFACEBUSY:
   768         error = "Surface busy";
   769         break;
   770     case DDERR_SURFACELOST:
   771         error = "Surface was lost";
   772         break;
   773     case DDERR_WASSTILLDRAWING:
   774         error = "DirectDraw is still drawing";
   775         break;
   776     case DDERR_INVALIDSURFACETYPE:
   777         error = "Invalid surface type";
   778         break;
   779     case DDERR_NOEXCLUSIVEMODE:
   780         error = "Not in exclusive access mode";
   781         break;
   782     case DDERR_NOPALETTEATTACHED:
   783         error = "No palette attached";
   784         break;
   785     case DDERR_NOPALETTEHW:
   786         error = "No palette hardware";
   787         break;
   788     case DDERR_NOT8BITCOLOR:
   789         error = "Not 8-bit color";
   790         break;
   791     case DDERR_EXCLUSIVEMODEALREADYSET:
   792         error = "Exclusive mode was already set";
   793         break;
   794     case DDERR_HWNDALREADYSET:
   795         error = "Window handle already set";
   796         break;
   797     case DDERR_HWNDSUBCLASSED:
   798         error = "Window handle is subclassed";
   799         break;
   800     case DDERR_NOBLTHW:
   801         error = "No blit hardware";
   802         break;
   803     case DDERR_IMPLICITLYCREATED:
   804         error = "Surface was implicitly created";
   805         break;
   806     case DDERR_INCOMPATIBLEPRIMARY:
   807         error = "Incompatible primary surface";
   808         break;
   809     case DDERR_NOCOOPERATIVELEVELSET:
   810         error = "No cooperative level set";
   811         break;
   812     case DDERR_NODIRECTDRAWHW:
   813         error = "No DirectDraw hardware";
   814         break;
   815     case DDERR_NOEMULATION:
   816         error = "No emulation available";
   817         break;
   818     case DDERR_NOFLIPHW:
   819         error = "No flip hardware";
   820         break;
   821     case DDERR_NOTFLIPPABLE:
   822         error = "Surface not flippable";
   823         break;
   824     case DDERR_PRIMARYSURFACEALREADYEXISTS:
   825         error = "Primary surface already exists";
   826         break;
   827     case DDERR_UNSUPPORTEDMODE:
   828         error = "Unsupported mode";
   829         break;
   830     case DDERR_WRONGMODE:
   831         error = "Surface created in different mode";
   832         break;
   833     case DDERR_UNSUPPORTED:
   834         error = "Operation not supported";
   835         break;
   836     case E_NOINTERFACE:
   837         error = "Interface not present";
   838         break;
   839     default:
   840         SDL_snprintf(errbuf, SDL_arraysize(errbuf),
   841                      "%s: Unknown DirectDraw error: 0x%x", function, code);
   842         break;
   843     }
   844     if (!errbuf[0]) {
   845         SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
   846                      error);
   847     }
   848     SDL_SetError("%s", errbuf);
   849     return;
   850 }
   851 
   852 
   853 static int
   854 DX5_UpdateVideoInfo(_THIS)
   855 {
   856     /* This needs to be DDCAPS_DX5 for the DirectDraw2 interface */
   857 #if DIRECTDRAW_VERSION <= 0x300
   858 #error Your version of DirectX must be greater than or equal to 5.0
   859 #endif
   860 #ifndef IDirectDrawGammaControl_SetGammaRamp
   861     /*if gamma is undefined then we really have directx <= 0x500 */
   862     DDCAPS DDCaps;
   863 #else
   864     DDCAPS_DX5 DDCaps;
   865 #endif
   866     HRESULT result;
   867 
   868     /* Fill in our hardware acceleration capabilities */
   869     SDL_memset(&DDCaps, 0, sizeof(DDCaps));
   870     DDCaps.dwSize = sizeof(DDCaps);
   871     result = IDirectDraw2_GetCaps(ddraw2, (DDCAPS *) & DDCaps, NULL);
   872     if (result != DD_OK) {
   873         SetDDerror("DirectDraw2::GetCaps", result);
   874         return (-1);
   875     }
   876     this->info.hw_available = 1;
   877     if ((DDCaps.dwCaps & DDCAPS_BLT) == DDCAPS_BLT) {
   878         this->info.blit_hw = 1;
   879     }
   880     if (((DDCaps.dwCaps & DDCAPS_COLORKEY) == DDCAPS_COLORKEY) &&
   881         ((DDCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) == DDCKEYCAPS_SRCBLT)) {
   882         this->info.blit_hw_CC = 1;
   883     }
   884     if ((DDCaps.dwCaps & DDCAPS_ALPHA) == DDCAPS_ALPHA) {
   885         /* This is only for alpha channel, and DirectX 6
   886            doesn't support 2D alpha blits yet, so set it 0
   887          */
   888         this->info.blit_hw_A = 0;
   889     }
   890     if ((DDCaps.dwCaps & DDCAPS_CANBLTSYSMEM) == DDCAPS_CANBLTSYSMEM) {
   891         this->info.blit_sw = 1;
   892         /* This isn't necessarily true, but the HEL will cover us */
   893         this->info.blit_sw_CC = this->info.blit_hw_CC;
   894         this->info.blit_sw_A = this->info.blit_hw_A;
   895     }
   896     if ((DDCaps.dwCaps & DDCAPS_BLTCOLORFILL) == DDCAPS_BLTCOLORFILL) {
   897         this->info.blit_fill = 1;
   898     }
   899 
   900     /* Find out how much video memory is available */
   901     {
   902         DDSCAPS ddsCaps;
   903         DWORD total_mem;
   904         ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
   905         result = IDirectDraw2_GetAvailableVidMem(ddraw2,
   906                                                  &ddsCaps, &total_mem, NULL);
   907         if (result != DD_OK) {
   908             total_mem = DDCaps.dwVidMemTotal;
   909         }
   910         this->info.video_mem = total_mem / 1024;
   911     }
   912     return (0);
   913 }
   914 
   915 int
   916 DX5_VideoInit(_THIS, SDL_PixelFormat * vformat)
   917 {
   918     HRESULT result;
   919     LPDIRECTDRAW ddraw;
   920     int i, j;
   921     HDC hdc;
   922 
   923     /* Intialize everything */
   924     ddraw2 = NULL;
   925     SDL_primary = NULL;
   926     SDL_clipper = NULL;
   927     SDL_palette = NULL;
   928     for (i = 0; i < NUM_MODELISTS; ++i) {
   929         SDL_nummodes[i] = 0;
   930         SDL_modelist[i] = NULL;
   931         SDL_modeindex[i] = 0;
   932     }
   933     colorchange_expected = 0;
   934 
   935     /* Create the window */
   936     if (DX5_CreateWindow(this) < 0) {
   937         return (-1);
   938     }
   939 #if !SDL_AUDIO_DISABLED
   940     DX5_SoundFocus(SDL_Window);
   941 #endif
   942 
   943     /* Create the DirectDraw object */
   944     result = DDrawCreate(NULL, &ddraw, NULL);
   945     if (result != DD_OK) {
   946         SetDDerror("DirectDrawCreate", result);
   947         return (-1);
   948     }
   949     result = IDirectDraw_QueryInterface(ddraw, &IID_IDirectDraw2,
   950                                         (LPVOID *) & ddraw2);
   951     IDirectDraw_Release(ddraw);
   952     if (result != DD_OK) {
   953         SetDDerror("DirectDraw::QueryInterface", result);
   954         return (-1);
   955     }
   956 
   957     /* Determine the screen depth */
   958     hdc = GetDC(SDL_Window);
   959     vformat->BitsPerPixel = GetDeviceCaps(hdc, PLANES) *
   960         GetDeviceCaps(hdc, BITSPIXEL);
   961     ReleaseDC(SDL_Window, hdc);
   962 
   963 #ifndef NO_CHANGEDISPLAYSETTINGS
   964     /* Query for the desktop resolution */
   965     EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &SDL_desktop_mode);
   966     this->info.current_w = SDL_desktop_mode.dmPelsWidth;
   967     this->info.current_h = SDL_desktop_mode.dmPelsHeight;
   968 #endif
   969 
   970     /* Enumerate the available fullscreen modes */
   971     for (i = 0; i < NUM_MODELISTS; ++i)
   972         enumlists[i] = NULL;
   973 
   974     result =
   975         IDirectDraw2_EnumDisplayModes(ddraw2, DDEDM_REFRESHRATES, NULL, this,
   976                                       EnumModes2);
   977     if (result != DD_OK) {
   978         SetDDerror("DirectDraw2::EnumDisplayModes", result);
   979         return (-1);
   980     }
   981     for (i = 0; i < NUM_MODELISTS; ++i) {
   982         struct DX5EnumRect *rect;
   983         SDL_modelist[i] = (SDL_Rect **)
   984             SDL_malloc((SDL_nummodes[i] + 1) * sizeof(SDL_Rect *));
   985         if (SDL_modelist[i] == NULL) {
   986             SDL_OutOfMemory();
   987             return (-1);
   988         }
   989         for (j = 0, rect = enumlists[i]; rect; ++j, rect = rect->next) {
   990             SDL_modelist[i][j] = &rect->r;
   991         }
   992         SDL_modelist[i][j] = NULL;
   993 
   994         if (SDL_nummodes[i] > 0) {
   995             SDL_qsort(SDL_modelist[i], SDL_nummodes[i],
   996                       sizeof *SDL_modelist[i], cmpmodes);
   997         }
   998     }
   999 
  1000     /* Fill in some window manager capabilities */
  1001     this->info.wm_available = 1;
  1002 
  1003     /* Fill in the video hardware capabilities */
  1004     DX5_UpdateVideoInfo(this);
  1005 
  1006     return (0);
  1007 }
  1008 
  1009 SDL_Rect **
  1010 DX5_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
  1011 {
  1012     int bpp;
  1013 
  1014     bpp = format->BitsPerPixel;
  1015     if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1016         /* FIXME:  No support for 1 bpp or 4 bpp formats */
  1017         switch (bpp) {          /* Does windows support other BPP? */
  1018         case 8:
  1019         case 16:
  1020         case 24:
  1021         case 32:
  1022             bpp = (bpp / 8) - 1;
  1023             if (SDL_nummodes[bpp] > 0)
  1024                 return (SDL_modelist[bpp]);
  1025             /* Fall through */
  1026         default:
  1027             return ((SDL_Rect **) 0);
  1028         }
  1029     } else {
  1030         if (this->screen->format->BitsPerPixel == bpp) {
  1031             return ((SDL_Rect **) - 1);
  1032         } else {
  1033             return ((SDL_Rect **) 0);
  1034         }
  1035     }
  1036 }
  1037 
  1038 /* Various screen update functions available */
  1039 static void DX5_WindowUpdate(_THIS, int numrects, SDL_Rect * rects);
  1040 static void DX5_DirectUpdate(_THIS, int numrects, SDL_Rect * rects);
  1041 
  1042 SDL_Surface *
  1043 DX5_SetVideoMode(_THIS, SDL_Surface * current,
  1044                  int width, int height, int bpp, Uint32 flags)
  1045 {
  1046     SDL_Surface *video;
  1047     HRESULT result;
  1048     DWORD sharemode;
  1049     DWORD style;
  1050     const DWORD directstyle = (WS_POPUP);
  1051     const DWORD windowstyle =
  1052         (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
  1053     const DWORD resizestyle = (WS_THICKFRAME | WS_MAXIMIZEBOX);
  1054     DDSURFACEDESC ddsd;
  1055     LPDIRECTDRAWSURFACE dd_surface1;
  1056     LPDIRECTDRAWSURFACE3 dd_surface3;
  1057 
  1058     SDL_resizing = 1;
  1059 #ifdef DDRAW_DEBUG
  1060     fprintf(stderr, "Setting %dx%dx%d video mode\n", width, height, bpp);
  1061 #endif
  1062     /* Clean up any previous DirectDraw surfaces */
  1063     if (current->hwdata) {
  1064         this->FreeHWSurface(this, current);
  1065         current->hwdata = NULL;
  1066     }
  1067     if (SDL_primary != NULL) {
  1068         IDirectDrawSurface3_Release(SDL_primary);
  1069         SDL_primary = NULL;
  1070     }
  1071 #ifndef NO_CHANGEDISPLAYSETTINGS
  1072     /* Unset any previous OpenGL fullscreen mode */
  1073     if ((current->flags & (SDL_INTERNALOPENGL | SDL_FULLSCREEN)) ==
  1074         (SDL_INTERNALOPENGL | SDL_FULLSCREEN)) {
  1075         ChangeDisplaySettings(NULL, 0);
  1076     }
  1077 #endif
  1078 
  1079     /* Clean up any GL context that may be hanging around */
  1080     if (current->flags & SDL_INTERNALOPENGL) {
  1081         WIN_GL_ShutDown(this);
  1082     }
  1083 
  1084     /* If we are setting a GL mode, use GDI, not DirectX (yuck) */
  1085     if (flags & SDL_INTERNALOPENGL) {
  1086         Uint32 Rmask, Gmask, Bmask;
  1087 
  1088         /* Recalculate the bitmasks if necessary */
  1089         if (bpp == current->format->BitsPerPixel) {
  1090             video = current;
  1091         } else {
  1092             switch (bpp) {
  1093             case 15:
  1094             case 16:
  1095                 if (0 /*DIB_SussScreenDepth() == 15 */ ) {
  1096                     /* 5-5-5 */
  1097                     Rmask = 0x00007c00;
  1098                     Gmask = 0x000003e0;
  1099                     Bmask = 0x0000001f;
  1100                 } else {
  1101                     /* 5-6-5 */
  1102                     Rmask = 0x0000f800;
  1103                     Gmask = 0x000007e0;
  1104                     Bmask = 0x0000001f;
  1105                 }
  1106                 break;
  1107             case 24:
  1108             case 32:
  1109                 /* GDI defined as 8-8-8 */
  1110                 Rmask = 0x00ff0000;
  1111                 Gmask = 0x0000ff00;
  1112                 Bmask = 0x000000ff;
  1113                 break;
  1114             default:
  1115                 Rmask = 0x00000000;
  1116                 Gmask = 0x00000000;
  1117                 Bmask = 0x00000000;
  1118                 break;
  1119             }
  1120             video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, bpp,
  1121                                          Rmask, Gmask, Bmask, 0);
  1122             if (video == NULL) {
  1123                 SDL_OutOfMemory();
  1124                 return (NULL);
  1125             }
  1126         }
  1127 
  1128         /* Fill in part of the video surface */
  1129         video->flags = 0;       /* Clear flags */
  1130         video->w = width;
  1131         video->h = height;
  1132         video->pitch = SDL_CalculatePitch(video);
  1133 
  1134 #ifndef NO_CHANGEDISPLAYSETTINGS
  1135         /* Set fullscreen mode if appropriate.
  1136            Ugh, since our list of valid video modes comes from
  1137            the DirectX driver, we may not actually be able to
  1138            change to the desired resolution here.
  1139            FIXME: Should we do a closest match?
  1140          */
  1141         if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1142             DEVMODE settings;
  1143             BOOL changed;
  1144 
  1145             SDL_memset(&settings, 0, sizeof(DEVMODE));
  1146             settings.dmSize = sizeof(DEVMODE);
  1147             settings.dmBitsPerPel = video->format->BitsPerPixel;
  1148             settings.dmPelsWidth = width;
  1149             settings.dmPelsHeight = height;
  1150             settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  1151             if (width <= (int) SDL_desktop_mode.dmPelsWidth
  1152                 && height <= (int) SDL_desktop_mode.dmPelsHeight) {
  1153                 settings.dmDisplayFrequency =
  1154                     SDL_desktop_mode.dmDisplayFrequency;
  1155                 settings.dmFields |= DM_DISPLAYFREQUENCY;
  1156             }
  1157             changed =
  1158                 (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) ==
  1159                  DISP_CHANGE_SUCCESSFUL);
  1160             if (!changed && (settings.dmFields & DM_DISPLAYFREQUENCY)) {
  1161                 settings.dmFields &= ~DM_DISPLAYFREQUENCY;
  1162                 changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN)
  1163                            == DISP_CHANGE_SUCCESSFUL);
  1164             }
  1165             if (changed) {
  1166                 video->flags |= SDL_FULLSCREEN;
  1167                 SDL_fullscreen_mode = settings;
  1168             }
  1169         }
  1170 #endif /* !NO_CHANGEDISPLAYSETTINGS */
  1171 
  1172         style = GetWindowLong(SDL_Window, GWL_STYLE);
  1173         style &= ~(resizestyle | WS_MAXIMIZE);
  1174         if (video->flags & SDL_FULLSCREEN) {
  1175             style &= ~windowstyle;
  1176             style |= directstyle;
  1177         } else {
  1178             if (flags & SDL_NOFRAME) {
  1179                 style &= ~windowstyle;
  1180                 style |= directstyle;
  1181                 video->flags |= SDL_NOFRAME;
  1182             } else {
  1183                 style &= ~directstyle;
  1184                 style |= windowstyle;
  1185                 if (flags & SDL_RESIZABLE) {
  1186                     style |= resizestyle;
  1187                     video->flags |= SDL_RESIZABLE;
  1188                 }
  1189             }
  1190 #if WS_MAXIMIZE
  1191             if (IsZoomed(SDL_Window))
  1192                 style |= WS_MAXIMIZE;
  1193 #endif
  1194         }
  1195 
  1196         /* DJM: Don't piss of anyone who has setup his own window */
  1197         if (!SDL_windowid)
  1198             SetWindowLong(SDL_Window, GWL_STYLE, style);
  1199 
  1200         /* Resize the window (copied from SDL WinDIB driver) */
  1201         if (!SDL_windowid && !IsZoomed(SDL_Window)) {
  1202             RECT bounds;
  1203             int x, y;
  1204             HWND top;
  1205             UINT swp_flags;
  1206             const char *window = NULL;
  1207             const char *center = NULL;
  1208 
  1209             if (!SDL_windowX && !SDL_windowY) {
  1210                 window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
  1211                 center = SDL_getenv("SDL_VIDEO_CENTERED");
  1212                 if (window) {
  1213                     if (SDL_sscanf(window, "%d,%d", &x, &y) == 2) {
  1214                         SDL_windowX = x;
  1215                         SDL_windowY = y;
  1216                     }
  1217                     if (SDL_strcmp(window, "center") == 0) {
  1218                         center = window;
  1219                     }
  1220                 }
  1221             }
  1222             swp_flags = (SWP_NOCOPYBITS | SWP_SHOWWINDOW);
  1223 
  1224             bounds.left = SDL_windowX;
  1225             bounds.top = SDL_windowY;
  1226             bounds.right = SDL_windowX + video->w;
  1227             bounds.bottom = SDL_windowY + video->h;
  1228             AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE),
  1229                                (GetMenu(SDL_Window) != NULL), 0);
  1230             width = bounds.right - bounds.left;
  1231             height = bounds.bottom - bounds.top;
  1232             if ((flags & SDL_FULLSCREEN)) {
  1233                 x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
  1234                 y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
  1235             } else if (center) {
  1236                 x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
  1237                 y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
  1238             } else if (SDL_windowX || SDL_windowY || window) {
  1239                 x = bounds.left;
  1240                 y = bounds.top;
  1241             } else {
  1242                 x = y = -1;
  1243                 swp_flags |= SWP_NOMOVE;
  1244             }
  1245             if (flags & SDL_FULLSCREEN) {
  1246                 top = HWND_TOPMOST;
  1247             } else {
  1248                 top = HWND_NOTOPMOST;
  1249             }
  1250             SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags);
  1251             if (!(flags & SDL_FULLSCREEN)) {
  1252                 SDL_windowX = SDL_bounds.left;
  1253                 SDL_windowY = SDL_bounds.top;
  1254             }
  1255             SetForegroundWindow(SDL_Window);
  1256         }
  1257         SDL_resizing = 0;
  1258 
  1259         /* Set up for OpenGL */
  1260         if (WIN_GL_SetupWindow(this) < 0) {
  1261             return (NULL);
  1262         }
  1263         video->flags |= SDL_INTERNALOPENGL;
  1264         return (video);
  1265     }
  1266 
  1267     /* Set the appropriate window style */
  1268     style = GetWindowLong(SDL_Window, GWL_STYLE);
  1269     style &= ~(resizestyle | WS_MAXIMIZE);
  1270     if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1271         style &= ~windowstyle;
  1272         style |= directstyle;
  1273     } else {
  1274         if (flags & SDL_NOFRAME) {
  1275             style &= ~windowstyle;
  1276             style |= directstyle;
  1277         } else {
  1278             style &= ~directstyle;
  1279             style |= windowstyle;
  1280             if (flags & SDL_RESIZABLE) {
  1281                 style |= resizestyle;
  1282             }
  1283         }
  1284 #if WS_MAXIMIZE
  1285         if (IsZoomed(SDL_Window))
  1286             style |= WS_MAXIMIZE;
  1287 #endif
  1288     }
  1289     /* DJM: Don't piss of anyone who has setup his own window */
  1290     if (!SDL_windowid)
  1291         SetWindowLong(SDL_Window, GWL_STYLE, style);
  1292 
  1293     /* Set DirectDraw sharing mode.. exclusive when fullscreen */
  1294     if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1295         sharemode = DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT;
  1296     } else {
  1297         sharemode = DDSCL_NORMAL;
  1298     }
  1299     result = IDirectDraw2_SetCooperativeLevel(ddraw2, SDL_Window, sharemode);
  1300     if (result != DD_OK) {
  1301         SetDDerror("DirectDraw2::SetCooperativeLevel", result);
  1302         return (NULL);
  1303     }
  1304 
  1305     /* Set the display mode, if we are in fullscreen mode */
  1306     if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1307         RECT bounds;
  1308         struct DX5EnumRect *rect;
  1309         int maxRefreshRate;
  1310 
  1311         /* Cover up desktop during mode change */
  1312         bounds.left = 0;
  1313         bounds.top = 0;
  1314         bounds.right = GetSystemMetrics(SM_CXSCREEN);
  1315         bounds.bottom = GetSystemMetrics(SM_CYSCREEN);
  1316         AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE),
  1317                            (GetMenu(SDL_Window) != NULL), 0);
  1318         SetWindowPos(SDL_Window, HWND_TOPMOST, bounds.left, bounds.top,
  1319                      bounds.right - bounds.left, bounds.bottom - bounds.top,
  1320                      SWP_NOCOPYBITS);
  1321         ShowWindow(SDL_Window, SW_SHOW);
  1322         while (GetForegroundWindow() != SDL_Window) {
  1323             SetForegroundWindow(SDL_Window);
  1324             SDL_Delay(100);
  1325         }
  1326 
  1327         /* find maximum monitor refresh rate for this resolution */
  1328         /* Dmitry Yakimov ftech@tula.net */
  1329         maxRefreshRate = 0;     /* system default */
  1330         for (rect = enumlists[bpp / 8 - 1]; rect; rect = rect->next) {
  1331             if ((width == rect->r.w) && (height == rect->r.h)) {
  1332                 maxRefreshRate = rect->refreshRate;
  1333                 break;
  1334             }
  1335         }
  1336 #ifdef DDRAW_DEBUG
  1337         fprintf(stderr, "refresh rate = %d Hz\n", maxRefreshRate);
  1338 #endif
  1339 
  1340         result =
  1341             IDirectDraw2_SetDisplayMode(ddraw2, width, height, bpp,
  1342                                         maxRefreshRate, 0);
  1343         if (result != DD_OK) {
  1344             result =
  1345                 IDirectDraw2_SetDisplayMode(ddraw2, width, height, bpp, 0, 0);
  1346             if (result != DD_OK) {
  1347                 /* We couldn't set fullscreen mode, try window */
  1348                 return (DX5_SetVideoMode
  1349                         (this, current, width, height, bpp,
  1350                          flags & ~SDL_FULLSCREEN));
  1351             }
  1352         }
  1353         DX5_DInputReset(this, 1);
  1354     } else {
  1355         DX5_DInputReset(this, 0);
  1356     }
  1357     DX5_UpdateVideoInfo(this);
  1358 
  1359     /* Create a primary DirectDraw surface */
  1360     SDL_memset(&ddsd, 0, sizeof(ddsd));
  1361     ddsd.dwSize = sizeof(ddsd);
  1362     ddsd.dwFlags = DDSD_CAPS;
  1363     ddsd.ddsCaps.dwCaps = (DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY);
  1364     if ((flags & SDL_FULLSCREEN) != SDL_FULLSCREEN) {
  1365         /* There's no windowed double-buffering */
  1366         flags &= ~SDL_DOUBLEBUF;
  1367     }
  1368     if ((flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
  1369         ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
  1370         ddsd.ddsCaps.dwCaps |= (DDSCAPS_COMPLEX | DDSCAPS_FLIP);
  1371         ddsd.dwBackBufferCount = 1;
  1372     }
  1373     result = IDirectDraw2_CreateSurface(ddraw2, &ddsd, &dd_surface1, NULL);
  1374     if ((result != DD_OK) && ((flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF)) {
  1375         ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
  1376         ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_COMPLEX | DDSCAPS_FLIP);
  1377         ddsd.dwBackBufferCount = 0;
  1378         result = IDirectDraw2_CreateSurface(ddraw2,
  1379                                             &ddsd, &dd_surface1, NULL);
  1380     }
  1381     if (result != DD_OK) {
  1382         SetDDerror("DirectDraw2::CreateSurface(PRIMARY)", result);
  1383         return (NULL);
  1384     }
  1385     result = IDirectDrawSurface_QueryInterface(dd_surface1,
  1386                                                &IID_IDirectDrawSurface3,
  1387                                                (LPVOID *) & SDL_primary);
  1388     if (result != DD_OK) {
  1389         SetDDerror("DirectDrawSurface::QueryInterface", result);
  1390         return (NULL);
  1391     }
  1392     IDirectDrawSurface_Release(dd_surface1);
  1393 
  1394     /* Get the format of the primary DirectDraw surface */
  1395     SDL_memset(&ddsd, 0, sizeof(ddsd));
  1396     ddsd.dwSize = sizeof(ddsd);
  1397     ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
  1398     result = IDirectDrawSurface3_GetSurfaceDesc(SDL_primary, &ddsd);
  1399     if (result != DD_OK) {
  1400         SetDDerror("DirectDrawSurface::GetSurfaceDesc", result);
  1401         return (NULL);
  1402     }
  1403     if (!(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB)) {
  1404         SDL_SetError("Primary DDRAW surface is not RGB format");
  1405         return (NULL);
  1406     }
  1407 
  1408     /* Free old palette and create a new one if we're in 8-bit mode */
  1409     if (SDL_palette != NULL) {
  1410         IDirectDrawPalette_Release(SDL_palette);
  1411         SDL_palette = NULL;
  1412     }
  1413 #if defined(NONAMELESSUNION)
  1414     if (ddsd.ddpfPixelFormat.u1.dwRGBBitCount == 8) {
  1415 #else
  1416     if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) {
  1417 #endif
  1418         int i;
  1419 
  1420         if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1421             /* We have access to the entire palette */
  1422             for (i = 0; i < 256; ++i) {
  1423                 SDL_colors[i].peFlags = (PC_NOCOLLAPSE | PC_RESERVED);
  1424                 SDL_colors[i].peRed = 0;
  1425                 SDL_colors[i].peGreen = 0;
  1426                 SDL_colors[i].peBlue = 0;
  1427             }
  1428         } else {
  1429             /* First 10 colors are reserved by Windows */
  1430             for (i = 0; i < 10; ++i) {
  1431                 SDL_colors[i].peFlags = PC_EXPLICIT;
  1432                 SDL_colors[i].peRed = i;
  1433                 SDL_colors[i].peGreen = 0;
  1434                 SDL_colors[i].peBlue = 0;
  1435             }
  1436             for (i = 10; i < (10 + 236); ++i) {
  1437                 SDL_colors[i].peFlags = PC_NOCOLLAPSE;
  1438                 SDL_colors[i].peRed = 0;
  1439                 SDL_colors[i].peGreen = 0;
  1440                 SDL_colors[i].peBlue = 0;
  1441             }
  1442             /* Last 10 colors are reserved by Windows */
  1443             for (i = 246; i < 256; ++i) {
  1444                 SDL_colors[i].peFlags = PC_EXPLICIT;
  1445                 SDL_colors[i].peRed = i;
  1446                 SDL_colors[i].peGreen = 0;
  1447                 SDL_colors[i].peBlue = 0;
  1448             }
  1449         }
  1450         result = IDirectDraw2_CreatePalette(ddraw2,
  1451                                             (DDPCAPS_8BIT |
  1452                                              DDPCAPS_ALLOW256), SDL_colors,
  1453                                             &SDL_palette, NULL);
  1454         if (result != DD_OK) {
  1455             SetDDerror("DirectDraw2::CreatePalette", result);
  1456             return (NULL);
  1457         }
  1458         result = IDirectDrawSurface3_SetPalette(SDL_primary, SDL_palette);
  1459         if (result != DD_OK) {
  1460             SetDDerror("DirectDrawSurface3::SetPalette", result);
  1461             return (NULL);
  1462         }
  1463     }
  1464 
  1465     /* Create our video surface using the same pixel format */
  1466     video = current;
  1467     if ((width != video->w) || (height != video->h)
  1468         || (video->format->BitsPerPixel !=
  1469 #if defined(NONAMELESSUNION)
  1470             ddsd.ddpfPixelFormat.u1.dwRGBBitCount)) {
  1471 #else
  1472             ddsd.ddpfPixelFormat.dwRGBBitCount)) {
  1473 #endif
  1474         SDL_FreeSurface(video);
  1475         video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0,
  1476 #if defined(NONAMELESSUNION)
  1477                                      ddsd.ddpfPixelFormat.u1.dwRGBBitCount,
  1478                                      ddsd.ddpfPixelFormat.u2.dwRBitMask,
  1479                                      ddsd.ddpfPixelFormat.u3.dwGBitMask,
  1480                                      ddsd.ddpfPixelFormat.u4.dwBBitMask,
  1481 #else
  1482                                      ddsd.ddpfPixelFormat.dwRGBBitCount,
  1483                                      ddsd.ddpfPixelFormat.dwRBitMask,
  1484                                      ddsd.ddpfPixelFormat.dwGBitMask,
  1485                                      ddsd.ddpfPixelFormat.dwBBitMask,
  1486 #endif
  1487                                      0);
  1488         if (video == NULL) {
  1489             SDL_OutOfMemory();
  1490             return (NULL);
  1491         }
  1492         video->w = width;
  1493         video->h = height;
  1494         video->pitch = 0;
  1495     }
  1496     video->flags = 0;           /* Clear flags */
  1497 
  1498     /* If not fullscreen, locking is possible, but it doesn't do what 
  1499        the caller really expects -- if the locked surface is written to,
  1500        the appropriate portion of the entire screen is modified, not 
  1501        the application window, as we would like.
  1502        Note that it is still possible to write directly to display
  1503        memory, but the application must respect the clip list of
  1504        the surface.  There might be some odd timing interactions
  1505        involving clip list updates and background refreshing as
  1506        Windows moves other windows across our window.
  1507        We currently don't support this, even though it might be a
  1508        good idea since BeOS has an implementation of BDirectWindow
  1509        that does the same thing.  This would be most useful for
  1510        applications that do complete screen updates every frame.
  1511        -- Fixme?
  1512      */
  1513     if ((flags & SDL_FULLSCREEN) != SDL_FULLSCREEN) {
  1514         /* Necessary if we're going from fullscreen to window */
  1515         if (video->pixels == NULL) {
  1516             video->pitch = (width * video->format->BytesPerPixel);
  1517             /* Pitch needs to be QWORD (8-byte) aligned */
  1518             video->pitch = (video->pitch + 7) & ~7;
  1519             video->pixels = (void *) SDL_malloc(video->h * video->pitch);
  1520             if (video->pixels == NULL) {
  1521                 if (video != current) {
  1522                     SDL_FreeSurface(video);
  1523                 }
  1524                 SDL_OutOfMemory();
  1525                 return (NULL);
  1526             }
  1527         }
  1528         dd_surface3 = NULL;
  1529 #if 0                           /* FIXME: enable this when SDL consistently reports lost surfaces */
  1530         if ((flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
  1531             video->flags |= SDL_HWSURFACE;
  1532         } else {
  1533             video->flags |= SDL_SWSURFACE;
  1534         }
  1535 #else
  1536         video->flags |= SDL_SWSURFACE;
  1537 #endif
  1538         if ((flags & SDL_RESIZABLE) && !(flags & SDL_NOFRAME)) {
  1539             video->flags |= SDL_RESIZABLE;
  1540         }
  1541         if (flags & SDL_NOFRAME) {
  1542             video->flags |= SDL_NOFRAME;
  1543         }
  1544     } else {
  1545         /* Necessary if we're going from window to fullscreen */
  1546         if (video->pixels != NULL) {
  1547             SDL_free(video->pixels);
  1548             video->pixels = NULL;
  1549         }
  1550         dd_surface3 = SDL_primary;
  1551         video->flags |= SDL_HWSURFACE;
  1552     }
  1553 
  1554     /* See if the primary surface has double-buffering enabled */
  1555     if ((ddsd.ddsCaps.dwCaps & DDSCAPS_FLIP) == DDSCAPS_FLIP) {
  1556         video->flags |= SDL_DOUBLEBUF;
  1557     }
  1558 
  1559     /* Allocate the SDL surface associated with the primary surface */
  1560     if (DX5_AllocDDSurface(this, video, dd_surface3,
  1561                            video->flags & SDL_HWSURFACE) < 0) {
  1562         if (video != current) {
  1563             SDL_FreeSurface(video);
  1564         }
  1565         return (NULL);
  1566     }
  1567 
  1568     /* Use the appropriate blitting function */
  1569     if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  1570         video->flags |= SDL_FULLSCREEN;
  1571         if (video->format->palette != NULL) {
  1572             video->flags |= SDL_HWPALETTE;
  1573         }
  1574         this->UpdateRects = DX5_DirectUpdate;
  1575     } else {
  1576         this->UpdateRects = DX5_WindowUpdate;
  1577     }
  1578 
  1579     /* Make our window the proper size, set the clipper, then show it */
  1580     if ((flags & SDL_FULLSCREEN) != SDL_FULLSCREEN) {
  1581         /* Create and set a clipper on our primary surface */
  1582         if (SDL_clipper == NULL) {
  1583             result = IDirectDraw2_CreateClipper(ddraw2,
  1584                                                 0, &SDL_clipper, NULL);
  1585             if (result != DD_OK) {
  1586                 if (video != current) {
  1587                     SDL_FreeSurface(video);
  1588                 }
  1589                 SetDDerror("DirectDraw2::CreateClipper", result);
  1590                 return (NULL);
  1591             }
  1592         }
  1593         result = IDirectDrawClipper_SetHWnd(SDL_clipper, 0, SDL_Window);
  1594         if (result != DD_OK) {
  1595             if (video != current) {
  1596                 SDL_FreeSurface(video);
  1597             }
  1598             SetDDerror("DirectDrawClipper::SetHWnd", result);
  1599             return (NULL);
  1600         }
  1601         result = IDirectDrawSurface3_SetClipper(SDL_primary, SDL_clipper);
  1602         if (result != DD_OK) {
  1603             if (video != current) {
  1604                 SDL_FreeSurface(video);
  1605             }
  1606             SetDDerror("DirectDrawSurface3::SetClipper", result);
  1607             return (NULL);
  1608         }
  1609 
  1610         /* Resize the window (copied from SDL WinDIB driver) */
  1611         if (!SDL_windowid && !IsZoomed(SDL_Window)) {
  1612             RECT bounds;
  1613             int x, y;
  1614             UINT swp_flags;
  1615             const char *window = NULL;
  1616             const char *center = NULL;
  1617 
  1618             if (!SDL_windowX && !SDL_windowY) {
  1619                 window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
  1620                 center = SDL_getenv("SDL_VIDEO_CENTERED");
  1621                 if (window) {
  1622                     if (SDL_sscanf(window, "%d,%d", &x, &y) == 2) {
  1623                         SDL_windowX = x;
  1624                         SDL_windowY = y;
  1625                     }
  1626                     if (SDL_strcmp(window, "center") == 0) {
  1627                         center = window;
  1628                     }
  1629                 }
  1630             }
  1631             swp_flags = SWP_NOCOPYBITS;
  1632 
  1633             bounds.left = SDL_windowX;
  1634             bounds.top = SDL_windowY;
  1635             bounds.right = SDL_windowX + video->w;
  1636             bounds.bottom = SDL_windowY + video->h;
  1637             AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE),
  1638                                (GetMenu(SDL_Window) != NULL), 0);
  1639             width = bounds.right - bounds.left;
  1640             height = bounds.bottom - bounds.top;
  1641             if (center) {
  1642                 x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
  1643                 y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
  1644             } else if (SDL_windowX || SDL_windowY || window) {
  1645                 x = bounds.left;
  1646                 y = bounds.top;
  1647             } else {
  1648                 x = y = -1;
  1649                 swp_flags |= SWP_NOMOVE;
  1650             }
  1651             SetWindowPos(SDL_Window, HWND_NOTOPMOST, x, y, width, height,
  1652                          swp_flags);
  1653             SDL_windowX = SDL_bounds.left;
  1654             SDL_windowY = SDL_bounds.top;
  1655         }
  1656 
  1657     }
  1658     ShowWindow(SDL_Window, SW_SHOW);
  1659     SetForegroundWindow(SDL_Window);
  1660     SDL_resizing = 0;
  1661 
  1662     /* JC 14 Mar 2006
  1663        Flush the message loop or this can cause big problems later
  1664        Especially if the user decides to use dialog boxes or assert()!
  1665      */
  1666     WIN_FlushMessageQueue();
  1667 
  1668     /* We're live! */
  1669     return (video);
  1670 }
  1671 
  1672 struct private_hwdata
  1673 {
  1674     LPDIRECTDRAWSURFACE3 dd_surface;
  1675     LPDIRECTDRAWSURFACE3 dd_writebuf;
  1676 };
  1677 
  1678 static int
  1679 DX5_AllocDDSurface(_THIS, SDL_Surface * surface,
  1680                    LPDIRECTDRAWSURFACE3 requested, Uint32 flag)
  1681 {
  1682     LPDIRECTDRAWSURFACE dd_surface1;
  1683     LPDIRECTDRAWSURFACE3 dd_surface3;
  1684     DDSURFACEDESC ddsd;
  1685     HRESULT result;
  1686 
  1687     /* Clear the hardware flag, in case we fail */
  1688     surface->flags &= ~flag;
  1689 
  1690     /* Allocate the hardware acceleration data */
  1691     surface->hwdata = (struct private_hwdata *)
  1692         SDL_malloc(sizeof(*surface->hwdata));
  1693     if (surface->hwdata == NULL) {
  1694         SDL_OutOfMemory();
  1695         return (-1);
  1696     }
  1697     dd_surface3 = NULL;
  1698 
  1699     /* Set up the surface description */
  1700     SDL_memset(&ddsd, 0, sizeof(ddsd));
  1701     ddsd.dwSize = sizeof(ddsd);
  1702     ddsd.dwFlags = (DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
  1703                     DDSD_PITCH | DDSD_PIXELFORMAT);
  1704     ddsd.dwWidth = surface->w;
  1705     ddsd.dwHeight = surface->h;
  1706 #if defined(NONAMELESSUNION)
  1707     ddsd.u1.lPitch = surface->pitch;
  1708 #else
  1709     ddsd.lPitch = surface->pitch;
  1710 #endif
  1711     if ((flag & SDL_HWSURFACE) == SDL_HWSURFACE) {
  1712         ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY);
  1713     } else {
  1714         ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY);
  1715     }
  1716     ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
  1717     ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
  1718     if (surface->format->palette) {
  1719         ddsd.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8;
  1720     }
  1721 #if defined(NONAMELESSUNION)
  1722     ddsd.ddpfPixelFormat.u1.dwRGBBitCount = surface->format->BitsPerPixel;
  1723     ddsd.ddpfPixelFormat.u2.dwRBitMask = surface->format->Rmask;
  1724     ddsd.ddpfPixelFormat.u3.dwGBitMask = surface->format->Gmask;
  1725     ddsd.ddpfPixelFormat.u4.dwBBitMask = surface->format->Bmask;
  1726 #else
  1727     ddsd.ddpfPixelFormat.dwRGBBitCount = surface->format->BitsPerPixel;
  1728     ddsd.ddpfPixelFormat.dwRBitMask = surface->format->Rmask;
  1729     ddsd.ddpfPixelFormat.dwGBitMask = surface->format->Gmask;
  1730     ddsd.ddpfPixelFormat.dwBBitMask = surface->format->Bmask;
  1731 #endif
  1732 
  1733     /* Create the DirectDraw video surface */
  1734     if (requested != NULL) {
  1735         dd_surface3 = requested;
  1736     } else {
  1737         result = IDirectDraw2_CreateSurface(ddraw2,
  1738                                             &ddsd, &dd_surface1, NULL);
  1739         if (result != DD_OK) {
  1740             SetDDerror("DirectDraw2::CreateSurface", result);
  1741             goto error_end;
  1742         }
  1743         result = IDirectDrawSurface_QueryInterface(dd_surface1,
  1744                                                    &IID_IDirectDrawSurface3,
  1745                                                    (LPVOID *) & dd_surface3);
  1746         IDirectDrawSurface_Release(dd_surface1);
  1747         if (result != DD_OK) {
  1748             SetDDerror("DirectDrawSurface::QueryInterface", result);
  1749             goto error_end;
  1750         }
  1751     }
  1752 
  1753     if ((flag & SDL_HWSURFACE) == SDL_HWSURFACE) {
  1754         /* Check to see whether the surface actually ended up
  1755            in video memory, and fail if not.  We expect the
  1756            surfaces we create here to actually be in hardware!
  1757          */
  1758         result = IDirectDrawSurface3_GetCaps(dd_surface3, &ddsd.ddsCaps);
  1759         if (result != DD_OK) {
  1760             SetDDerror("DirectDrawSurface3::GetCaps", result);
  1761             goto error_end;
  1762         }
  1763         if ((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) !=
  1764             DDSCAPS_VIDEOMEMORY) {
  1765             SDL_SetError("No room in video memory");
  1766             goto error_end;
  1767         }
  1768     } else {
  1769         /* Try to hook our surface memory */
  1770         ddsd.dwFlags = DDSD_LPSURFACE;
  1771         ddsd.lpSurface = surface->pixels;
  1772         result = IDirectDrawSurface3_SetSurfaceDesc(dd_surface3, &ddsd, 0);
  1773         if (result != DD_OK) {
  1774             SetDDerror("DirectDraw2::SetSurfaceDesc", result);
  1775             goto error_end;
  1776         }
  1777 
  1778     }
  1779 
  1780     /* Make sure the surface format was set properly */
  1781     SDL_memset(&ddsd, 0, sizeof(ddsd));
  1782     ddsd.dwSize = sizeof(ddsd);
  1783     result = IDirectDrawSurface3_Lock(dd_surface3, NULL,
  1784                                       &ddsd,
  1785                                       (DDLOCK_NOSYSLOCK | DDLOCK_WAIT), NULL);
  1786     if (result != DD_OK) {
  1787         SetDDerror("DirectDrawSurface3::Lock", result);
  1788         goto error_end;
  1789     }
  1790     IDirectDrawSurface3_Unlock(dd_surface3, NULL);
  1791 
  1792     if ((flag & SDL_HWSURFACE) == SDL_SWSURFACE) {
  1793         if (ddsd.lpSurface != surface->pixels) {
  1794             SDL_SetError("DDraw didn't use SDL surface memory");
  1795             goto error_end;
  1796         }
  1797         if (
  1798 #if defined(NONAMELESSUNION)
  1799                ddsd.u1.lPitch
  1800 #else
  1801                ddsd.lPitch
  1802 #endif
  1803                != (LONG) surface->pitch) {
  1804             SDL_SetError("DDraw created surface with wrong pitch");
  1805             goto error_end;
  1806         }
  1807     } else {
  1808 #if defined(NONAMELESSUNION)
  1809         surface->pitch = (Uint16) ddsd.u1.lPitch;
  1810 #else
  1811         surface->pitch = (Uint16) ddsd.lPitch;
  1812 #endif
  1813     }
  1814 #if defined(NONAMELESSUNION)
  1815     if ((ddsd.ddpfPixelFormat.u1.dwRGBBitCount !=
  1816          surface->format->BitsPerPixel) ||
  1817         (ddsd.ddpfPixelFormat.u2.dwRBitMask != surface->format->Rmask) ||
  1818         (ddsd.ddpfPixelFormat.u3.dwGBitMask != surface->format->Gmask) ||
  1819         (ddsd.ddpfPixelFormat.u4.dwBBitMask != surface->format->Bmask)) {
  1820 #else
  1821     if ((ddsd.ddpfPixelFormat.dwRGBBitCount !=
  1822          surface->format->BitsPerPixel) ||
  1823         (ddsd.ddpfPixelFormat.dwRBitMask != surface->format->Rmask) ||
  1824         (ddsd.ddpfPixelFormat.dwGBitMask != surface->format->Gmask) ||
  1825         (ddsd.ddpfPixelFormat.dwBBitMask != surface->format->Bmask)) {
  1826 #endif
  1827         SDL_SetError("DDraw didn't use SDL surface description");
  1828         goto error_end;
  1829     }
  1830     if ((ddsd.dwWidth != (DWORD) surface->w) ||
  1831         (ddsd.dwHeight != (DWORD) surface->h)) {
  1832         SDL_SetError("DDraw created surface with wrong size");
  1833         goto error_end;
  1834     }
  1835 
  1836     /* Set the surface private data */
  1837     surface->flags |= flag;
  1838     surface->hwdata->dd_surface = dd_surface3;
  1839     if ((surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
  1840         LPDIRECTDRAWSURFACE3 dd_writebuf;
  1841 
  1842         ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
  1843         result = IDirectDrawSurface3_GetAttachedSurface(dd_surface3,
  1844                                                         &ddsd.ddsCaps,
  1845                                                         &dd_writebuf);
  1846         if (result != DD_OK) {
  1847             SetDDerror("DirectDrawSurface3::GetAttachedSurface", result);
  1848         } else {
  1849             dd_surface3 = dd_writebuf;
  1850         }
  1851     }
  1852     surface->hwdata->dd_writebuf = dd_surface3;
  1853 
  1854     /* We're ready to go! */
  1855     return (0);
  1856 
  1857     /* Okay, so goto's are cheesy, but there are so many possible
  1858        errors in this function, and the cleanup is the same in 
  1859        every single case.  Is there a better way, other than deeply
  1860        nesting the code?
  1861      */
  1862   error_end:
  1863     if ((dd_surface3 != NULL) && (dd_surface3 != requested)) {
  1864         IDirectDrawSurface_Release(dd_surface3);
  1865     }
  1866     SDL_free(surface->hwdata);
  1867     surface->hwdata = NULL;
  1868     return (-1);
  1869 }
  1870 
  1871 static int
  1872 DX5_AllocHWSurface(_THIS, SDL_Surface * surface)
  1873 {
  1874     /* DDraw limitation -- you need to set cooperative level first */
  1875     if (SDL_primary == NULL) {
  1876         SDL_SetError("You must set a non-GL video mode first");
  1877         return (-1);
  1878     }
  1879     return (DX5_AllocDDSurface(this, surface, NULL, SDL_HWSURFACE));
  1880 }
  1881 
  1882 #ifdef DDRAW_DEBUG
  1883 void
  1884 PrintSurface(char *title, LPDIRECTDRAWSURFACE3 surface, Uint32 flags)
  1885 {
  1886     DDSURFACEDESC ddsd;
  1887 
  1888     /* Lock and load! */
  1889     SDL_memset(&ddsd, 0, sizeof(ddsd));
  1890     ddsd.dwSize = sizeof(ddsd);
  1891     if (IDirectDrawSurface3_Lock(surface, NULL, &ddsd,
  1892                                  (DDLOCK_NOSYSLOCK | DDLOCK_WAIT),
  1893                                  NULL) != DD_OK) {
  1894         return;
  1895     }
  1896     IDirectDrawSurface3_Unlock(surface, NULL);
  1897 
  1898     fprintf(stderr, "%s:\n", title);
  1899     fprintf(stderr, "\tSize: %dx%d in %s at %ld bpp (pitch = %ld)\n",
  1900             ddsd.dwWidth, ddsd.dwHeight,
  1901             (flags & SDL_HWSURFACE) ? "hardware" : "software",
  1902 #if defined(NONAMELESSUNION)
  1903             ddsd.ddpfPixelFormat.u1.dwRGBBitCount, ddsd.u1.lPitch);
  1904 #else
  1905             ddsd.ddpfPixelFormat.dwRGBBitCount, ddsd.lPitch);
  1906 #endif
  1907     fprintf(stderr, "\tR = 0x%X, G = 0x%X, B = 0x%X\n",
  1908 #if defined(NONAMELESSUNION)
  1909             ddsd.ddpfPixelFormat.u2.dwRBitMask,
  1910             ddsd.ddpfPixelFormat.u3.dwGBitMask,
  1911             ddsd.ddpfPixelFormat.u4.dwBBitMask);
  1912 #else
  1913             ddsd.ddpfPixelFormat.dwRBitMask,
  1914             ddsd.ddpfPixelFormat.dwGBitMask, ddsd.ddpfPixelFormat.dwBBitMask);
  1915 #endif
  1916 }
  1917 #endif /* DDRAW_DEBUG */
  1918 
  1919 static int
  1920 DX5_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect,
  1921                 SDL_Surface * dst, SDL_Rect * dstrect)
  1922 {
  1923     LPDIRECTDRAWSURFACE3 src_surface;
  1924     LPDIRECTDRAWSURFACE3 dst_surface;
  1925     DWORD flags;
  1926     RECT rect;
  1927     HRESULT result;
  1928 
  1929     /* Set it up.. the desination must have a DDRAW surface */
  1930     src_surface = src->hwdata->dd_writebuf;
  1931     dst_surface = dst->hwdata->dd_writebuf;
  1932     rect.top = (LONG) srcrect->y;
  1933     rect.bottom = (LONG) srcrect->y + srcrect->h;
  1934     rect.left = (LONG) srcrect->x;
  1935     rect.right = (LONG) srcrect->x + srcrect->w;
  1936     if ((src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY)
  1937         flags = DDBLTFAST_SRCCOLORKEY;
  1938     else
  1939         flags = DDBLTFAST_NOCOLORKEY;
  1940     /* FIXME:  We can remove this flag for _really_ fast blit queuing,
  1941        but it will affect the return values of locks and flips.
  1942      */
  1943     flags |= DDBLTFAST_WAIT;
  1944 
  1945     /* Do the blit! */
  1946     result = IDirectDrawSurface3_BltFast(dst_surface,
  1947                                          dstrect->x, dstrect->y, src_surface,
  1948                                          &rect, flags);
  1949     if (result != DD_OK) {
  1950         if (result == DDERR_SURFACELOST) {
  1951             result = IDirectDrawSurface3_Restore(src_surface);
  1952             result = IDirectDrawSurface3_Restore(dst_surface);
  1953             /* The surfaces need to be reloaded with artwork */
  1954             SDL_SetError("Blit surfaces were lost, reload them");
  1955             return (-2);
  1956         }
  1957         SetDDerror("IDirectDrawSurface3::BltFast", result);
  1958 #ifdef DDRAW_DEBUG
  1959         fprintf(stderr, "Original dest rect: %dx%d at %d,%d\n", dstrect->w,
  1960                 dstrect->h, dstrect->x, dstrect->y);
  1961         fprintf(stderr,
  1962                 "HW accelerated %sblit to from 0x%p to 0x%p at (%d,%d)\n",
  1963                 (src->flags & SDL_SRCCOLORKEY) ? "colorkey " : "", src,
  1964                 dst, dstrect->x, dstrect->y);
  1965         PrintSurface("SRC", src_surface, src->flags);
  1966         PrintSurface("DST", dst_surface, dst->flags);
  1967         fprintf(stderr, "Source rectangle: (%d,%d) - (%d,%d)\n",
  1968                 rect.left, rect.top, rect.right, rect.bottom);
  1969 #endif
  1970         /* Unexpected error, fall back to software blit */
  1971         return (src->map->sw_blit(src, srcrect, dst, dstrect));
  1972     }
  1973     return (0);
  1974 }
  1975 
  1976 static int
  1977 DX5_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst)
  1978 {
  1979     int accelerated;
  1980 
  1981     /* We need to have a DDraw surface for HW blits */
  1982     if ((src->flags & SDL_HWSURFACE) == SDL_SWSURFACE) {
  1983         /* Allocate a DDraw surface for the blit */
  1984         if (src->hwdata == NULL) {
  1985             DX5_AllocDDSurface(this, src, NULL, SDL_SWSURFACE);
  1986         }
  1987     }
  1988     if (src->hwdata == NULL) {
  1989         return (0);
  1990     }
  1991 
  1992     /* Set initial acceleration on */
  1993     src->flags |= SDL_HWACCEL;
  1994 
  1995     /* Set the surface attributes */
  1996     if ((src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
  1997         if (DX5_SetHWColorKey(this, src, src->format->colorkey) < 0) {
  1998             src->flags &= ~SDL_HWACCEL;
  1999         }
  2000     }
  2001     if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
  2002         if (DX5_SetHWAlpha(this, src, src->format->alpha) < 0) {
  2003             src->flags &= ~SDL_HWACCEL;
  2004         }
  2005     }
  2006 
  2007     /* Check to see if final surface blit is accelerated */
  2008     accelerated = !!(src->flags & SDL_HWACCEL);
  2009     if (accelerated) {
  2010 #ifdef DDRAW_DEBUG
  2011         fprintf(stderr, "Setting accelerated blit on 0x%p\n", src);
  2012 #endif
  2013         src->map->hw_blit = DX5_HWAccelBlit;
  2014     }
  2015     return (accelerated);
  2016 }
  2017 
  2018 static int
  2019 DX5_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
  2020 {
  2021     LPDIRECTDRAWSURFACE3 dst_surface;
  2022     RECT area;
  2023     DDBLTFX bltfx;
  2024     HRESULT result;
  2025 
  2026 #ifdef DDRAW_DEBUG
  2027     fprintf(stderr, "HW accelerated fill at (%d,%d)\n", dstrect->x,
  2028             dstrect->y);
  2029 #endif
  2030     dst_surface = dst->hwdata->dd_writebuf;
  2031     area.top = (LONG) dstrect->y;
  2032     area.bottom = (LONG) dstrect->y + dstrect->h;
  2033     area.left = (LONG) dstrect->x;
  2034     area.right = (LONG) dstrect->x + dstrect->w;
  2035     bltfx.dwSize = sizeof(bltfx);
  2036 #if defined(NONAMELESSUNION)
  2037     bltfx.u5.dwFillColor = color;
  2038 #else
  2039     bltfx.dwFillColor = color;
  2040 #endif
  2041     result = IDirectDrawSurface3_Blt(dst_surface,
  2042                                      &area, NULL, NULL,
  2043                                      DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);
  2044     if (result == DDERR_SURFACELOST) {
  2045         IDirectDrawSurface3_Restore(dst_surface);
  2046         result = IDirectDrawSurface3_Blt(dst_surface,
  2047                                          &area, NULL, NULL,
  2048                                          DDBLT_COLORFILL | DDBLT_WAIT,
  2049                                          &bltfx);
  2050     }
  2051     if (result != DD_OK) {
  2052         SetDDerror("IDirectDrawSurface3::Blt", result);
  2053         return (-1);
  2054     }
  2055     return (0);
  2056 }
  2057 
  2058 static int
  2059 DX5_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key)
  2060 {
  2061     DDCOLORKEY colorkey;
  2062     HRESULT result;
  2063 
  2064     /* Set the surface colorkey */
  2065     colorkey.dwColorSpaceLowValue = key;
  2066     colorkey.dwColorSpaceHighValue = key;
  2067     result =
  2068         IDirectDrawSurface3_SetColorKey(surface->hwdata->dd_surface,
  2069                                         DDCKEY_SRCBLT, &colorkey);
  2070     if (result != DD_OK) {
  2071         SetDDerror("IDirectDrawSurface3::SetColorKey", result);
  2072         return (-1);
  2073     }
  2074     return (0);
  2075 }
  2076 static int
  2077 DX5_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha)
  2078 {
  2079     return (-1);
  2080 }
  2081 
  2082 static int
  2083 DX5_LockHWSurface(_THIS, SDL_Surface * surface)
  2084 {
  2085     HRESULT result;
  2086     LPDIRECTDRAWSURFACE3 dd_surface;
  2087     DDSURFACEDESC ddsd;
  2088 
  2089     /* Lock and load! */
  2090     dd_surface = surface->hwdata->dd_writebuf;
  2091     SDL_memset(&ddsd, 0, sizeof(ddsd));
  2092     ddsd.dwSize = sizeof(ddsd);
  2093     result = IDirectDrawSurface3_Lock(dd_surface, NULL, &ddsd,
  2094                                       (DDLOCK_NOSYSLOCK | DDLOCK_WAIT), NULL);
  2095     if (result == DDERR_SURFACELOST) {
  2096         result = IDirectDrawSurface3_Restore(surface->hwdata->dd_surface);
  2097         result = IDirectDrawSurface3_Lock(dd_surface, NULL, &ddsd,
  2098                                           (DDLOCK_NOSYSLOCK | DDLOCK_WAIT),
  2099                                           NULL);
  2100     }
  2101     if (result != DD_OK) {
  2102         SetDDerror("DirectDrawSurface3::Lock", result);
  2103         return (-1);
  2104     }
  2105     /* Pitch might have changed -- recalculate pitch and offset */
  2106 #if defined(NONAMELESSUNION)
  2107     if (surface->pitch != ddsd.u1.lPitch) {
  2108         surface->pitch = ddsd.u1.lPitch;
  2109 #else
  2110     if (surface->pitch != ddsd.lPitch) {
  2111         surface->pitch = (Uint16) ddsd.lPitch;
  2112 #endif
  2113         surface->offset =
  2114             ((ddsd.dwHeight - surface->h) / 2) * surface->pitch +
  2115             ((ddsd.dwWidth - surface->w) / 2) *
  2116             surface->format->BytesPerPixel;
  2117     }
  2118     surface->pixels = ddsd.lpSurface;
  2119     return (0);
  2120 }
  2121 
  2122 static void
  2123 DX5_UnlockHWSurface(_THIS, SDL_Surface * surface)
  2124 {
  2125     IDirectDrawSurface3_Unlock(surface->hwdata->dd_writebuf, NULL);
  2126     surface->pixels = NULL;
  2127 }
  2128 
  2129 static int
  2130 DX5_FlipHWSurface(_THIS, SDL_Surface * surface)
  2131 {
  2132     HRESULT result;
  2133     LPDIRECTDRAWSURFACE3 dd_surface;
  2134 
  2135     dd_surface = surface->hwdata->dd_surface;
  2136 
  2137     /* to prevent big slowdown on fast computers, wait here instead of driver ring 0 code */
  2138     /* Dmitry Yakimov (ftech@tula.net) */
  2139     while (IDirectDrawSurface3_GetFlipStatus(dd_surface, DDGBS_ISBLTDONE) ==
  2140            DDERR_WASSTILLDRAWING);
  2141 
  2142     result = IDirectDrawSurface3_Flip(dd_surface, NULL, DDFLIP_WAIT);
  2143     if (result == DDERR_SURFACELOST) {
  2144         result = IDirectDrawSurface3_Restore(surface->hwdata->dd_surface);
  2145         while (IDirectDrawSurface3_GetFlipStatus
  2146                (dd_surface, DDGBS_ISBLTDONE) == DDERR_WASSTILLDRAWING);
  2147         result = IDirectDrawSurface3_Flip(dd_surface, NULL, DDFLIP_WAIT);
  2148     }
  2149     if (result != DD_OK) {
  2150         SetDDerror("DirectDrawSurface3::Flip", result);
  2151         return (-1);
  2152     }
  2153     return (0);
  2154 }
  2155 
  2156 static void
  2157 DX5_FreeHWSurface(_THIS, SDL_Surface * surface)
  2158 {
  2159     if (surface->hwdata) {
  2160         if (surface->hwdata->dd_surface != SDL_primary) {
  2161             IDirectDrawSurface3_Release(surface->hwdata->dd_surface);
  2162         }
  2163         SDL_free(surface->hwdata);
  2164         surface->hwdata = NULL;
  2165     }
  2166 }
  2167 
  2168 void
  2169 DX5_WindowUpdate(_THIS, int numrects, SDL_Rect * rects)
  2170 {
  2171     HRESULT result;
  2172     int i;
  2173     RECT src, dst;
  2174 
  2175     for (i = 0; i < numrects; ++i) {
  2176         src.top = (LONG) rects[i].y;
  2177         src.bottom = (LONG) rects[i].y + rects[i].h;
  2178         src.left = (LONG) rects[i].x;
  2179         src.right = (LONG) rects[i].x + rects[i].w;
  2180         dst.top = SDL_bounds.top + src.top;
  2181         dst.left = SDL_bounds.left + src.left;
  2182         dst.bottom = SDL_bounds.top + src.bottom;
  2183         dst.right = SDL_bounds.left + src.right;
  2184         result = IDirectDrawSurface3_Blt(SDL_primary, &dst,
  2185                                          this->screen->hwdata->dd_surface,
  2186                                          &src, DDBLT_WAIT, NULL);
  2187         /* Doh!  Check for lost surface and restore it */
  2188         if (result == DDERR_SURFACELOST) {
  2189             IDirectDrawSurface3_Restore(SDL_primary);
  2190             IDirectDrawSurface3_Blt(SDL_primary, &dst,
  2191                                     this->screen->hwdata->dd_surface,
  2192                                     &src, DDBLT_WAIT, NULL);
  2193         }
  2194     }
  2195 }
  2196 
  2197 void
  2198 DX5_DirectUpdate(_THIS, int numrects, SDL_Rect * rects)
  2199 {
  2200 }
  2201 
  2202 /* Compress a full palette into the limited number of colors given to us
  2203    by windows.
  2204 
  2205    The "best" way to do this is to sort the colors by diversity and place
  2206    the most diverse colors into the limited palette.  Unfortunately this
  2207    results in widely varying colors being displayed in the interval during
  2208    which the windows palette has been set, and the mapping of the shadow
  2209    surface to the new palette.  This is especially noticeable during fades.
  2210 
  2211    To deal with this problem, we can copy a predetermined portion of the
  2212    full palette, and use that as the limited palette.  This allows colors
  2213    to fade smoothly as the remapping is very similar on each palette change.
  2214    Unfortunately, this breaks applications which partition the palette into
  2215    distinct and widely varying areas, expecting all colors to be available.
  2216 
  2217    I'm making them both available, chosen at compile time.
  2218    If you want the chunk-o-palette algorithm, define SIMPLE_COMPRESSION,
  2219    otherwise the sort-by-diversity algorithm will be used.
  2220 */
  2221 #define SIMPLE_COMPRESSION
  2222 #define CS_CS_DIST(A, B) ({						\
  2223 	int r = (A.r - B.r);						\
  2224 	int g = (A.g - B.g);						\
  2225 	int b = (A.b - B.b);						\
  2226 	(r*r + g*g + b*b);						\
  2227 })
  2228 static void
  2229 DX5_CompressPalette(_THIS, SDL_Color * colors, int ncolors, int maxcolors)
  2230 {
  2231 #ifdef SIMPLE_COMPRESSION
  2232     int i, j;
  2233 #else
  2234     static SDL_Color zero = { 0, 0, 0, 0 };
  2235     int i, j;
  2236     int max, dist;
  2237     int prev, next;
  2238     int *pool;
  2239     int *seen, *order;
  2240 #endif
  2241 
  2242     /* Does this happen? */
  2243     if (maxcolors > ncolors) {
  2244         maxcolors = ncolors;
  2245     }
  2246 #ifdef SIMPLE_COMPRESSION
  2247     /* Just copy the first "maxcolors" colors */
  2248     for (j = 10, i = 0; i < maxcolors; ++i, ++j) {
  2249         SDL_colors[j].peRed = colors[i].r;
  2250         SDL_colors[j].peGreen = colors[i].g;
  2251         SDL_colors[j].peBlue = colors[i].b;
  2252     }
  2253 #else
  2254     /* Allocate memory for the arrays we use */
  2255     pool = SDL_stack_alloc(int, 2 * ncolors);
  2256     if (pool == NULL) {
  2257         /* No worries, just return */ ;
  2258         return;
  2259     }
  2260     seen = pool;
  2261     SDL_memset(seen, 0, ncolors * sizeof(int));
  2262     order = pool + ncolors;
  2263 
  2264     /* Start with the brightest color */
  2265     max = 0;
  2266     for (i = 0; i < ncolors; ++i) {
  2267         dist = CS_CS_DIST(zero, colors[i]);
  2268         if (dist >= max) {
  2269             max = dist;
  2270             next = i;
  2271         }
  2272     }
  2273     j = 0;
  2274     order[j++] = next;
  2275     seen[next] = 1;
  2276     prev = next;
  2277 
  2278     /* Keep going through all the colors */
  2279     while (j < maxcolors) {
  2280         max = 0;
  2281         for (i = 0; i < ncolors; ++i) {
  2282             if (seen[i]) {
  2283                 continue;
  2284             }
  2285             dist = CS_CS_DIST(colors[i], colors[prev]);
  2286             if (dist >= max) {
  2287                 max = dist;
  2288                 next = i;
  2289             }
  2290         }
  2291         order[j++] = next;
  2292         seen[next] = 1;
  2293         prev = next;
  2294     }
  2295 
  2296     /* Compress the colors to the palette */
  2297     for (j = 10, i = 0; i < maxcolors; ++i, ++j) {
  2298         SDL_colors[j].peRed = colors[order[i]].r;
  2299         SDL_colors[j].peGreen = colors[order[i]].g;
  2300         SDL_colors[j].peBlue = colors[order[i]].b;
  2301     }
  2302     SDL_stack_free(pool);
  2303 #endif /* SIMPLE_COMPRESSION */
  2304 }
  2305 
  2306 /* Set the system colormap in both fullscreen and windowed modes */
  2307 int
  2308 DX5_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
  2309 {
  2310     int i;
  2311     int alloct_all;
  2312 
  2313     /* Copy palette colors into display palette */
  2314     alloct_all = 0;
  2315     if (SDL_palette != NULL) {
  2316         if ((this->screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
  2317             /* We can set all entries explicitly */
  2318             for (i = 0; i < ncolors; ++i) {
  2319                 int j = firstcolor + i;
  2320                 SDL_colors[j].peRed = colors[i].r;
  2321                 SDL_colors[j].peGreen = colors[i].g;
  2322                 SDL_colors[j].peBlue = colors[i].b;
  2323             }
  2324             IDirectDrawPalette_SetEntries(SDL_palette, 0,
  2325                                           firstcolor, ncolors,
  2326                                           &SDL_colors[firstcolor]);
  2327             alloct_all = 1;
  2328         } else {
  2329             /* Grab the 236 most diverse colors in the palette */
  2330             DX5_CompressPalette(this, colors, ncolors, 236);
  2331             /* This sends an WM_PALETTECHANGED message to us */
  2332             colorchange_expected = 1;
  2333             IDirectDrawPalette_SetEntries(SDL_palette, 0, 0, 256, SDL_colors);
  2334         }
  2335     }
  2336     return (alloct_all);
  2337 }
  2338 
  2339 /* Gamma code is only available on DirectX 7 and newer */
  2340 static int
  2341 DX5_SetGammaRamp(_THIS, Uint16 * ramp)
  2342 {
  2343 #ifdef IDirectDrawGammaControl_SetGammaRamp
  2344     LPDIRECTDRAWGAMMACONTROL gamma;
  2345     DDGAMMARAMP gamma_ramp;
  2346     HRESULT result;
  2347 #endif
  2348 
  2349     /* In windowed or OpenGL mode, use windib gamma code */
  2350     if (!DDRAW_FULLSCREEN()) {
  2351         return DIB_SetGammaRamp(this, ramp);
  2352     }
  2353 #ifndef IDirectDrawGammaControl_SetGammaRamp
  2354     SDL_SetError("SDL compiled without DirectX gamma ramp support");
  2355     return -1;
  2356 #else
  2357     /* Check for a video mode! */
  2358     if (!SDL_primary) {
  2359         SDL_SetError("A video mode must be set for gamma correction");
  2360         return (-1);
  2361     }
  2362 
  2363     /* Get the gamma control object */
  2364     result = IDirectDrawSurface3_QueryInterface(SDL_primary,
  2365                                                 &IID_IDirectDrawGammaControl,
  2366                                                 (LPVOID *) & gamma);
  2367     if (result != DD_OK) {
  2368         SetDDerror("DirectDrawSurface3::QueryInterface(GAMMA)", result);
  2369         return (-1);
  2370     }
  2371 
  2372     /* Set up the gamma ramp */
  2373     SDL_memcpy(gamma_ramp.red, &ramp[0 * 256], 256 * sizeof(*ramp));
  2374     SDL_memcpy(gamma_ramp.green, &ramp[1 * 256], 256 * sizeof(*ramp));
  2375     SDL_memcpy(gamma_ramp.blue, &ramp[2 * 256], 256 * sizeof(*ramp));
  2376     result = IDirectDrawGammaControl_SetGammaRamp(gamma, 0, &gamma_ramp);
  2377     if (result != DD_OK) {
  2378         SetDDerror("DirectDrawGammaControl::SetGammaRamp()", result);
  2379     }
  2380 
  2381     /* Release the interface and return */
  2382     IDirectDrawGammaControl_Release(gamma);
  2383     return (result == DD_OK) ? 0 : -1;
  2384 #endif /* !IDirectDrawGammaControl_SetGammaRamp */
  2385 }
  2386 
  2387 static int
  2388 DX5_GetGammaRamp(_THIS, Uint16 * ramp)
  2389 {
  2390 #ifdef IDirectDrawGammaControl_SetGammaRamp
  2391     LPDIRECTDRAWGAMMACONTROL gamma;
  2392     DDGAMMARAMP gamma_ramp;
  2393     HRESULT result;
  2394 #endif
  2395 
  2396     /* In windowed or OpenGL mode, use windib gamma code */
  2397     if (!DDRAW_FULLSCREEN()) {
  2398         return DIB_GetGammaRamp(this, ramp);
  2399     }
  2400 #ifndef IDirectDrawGammaControl_SetGammaRamp
  2401     SDL_SetError("SDL compiled without DirectX gamma ramp support");
  2402     return -1;
  2403 #else
  2404     /* Check for a video mode! */
  2405     if (!SDL_primary) {
  2406         SDL_SetError("A video mode must be set for gamma correction");
  2407         return (-1);
  2408     }
  2409 
  2410     /* Get the gamma control object */
  2411     result = IDirectDrawSurface3_QueryInterface(SDL_primary,
  2412                                                 &IID_IDirectDrawGammaControl,
  2413                                                 (LPVOID *) & gamma);
  2414     if (result != DD_OK) {
  2415         SetDDerror("DirectDrawSurface3::QueryInterface(GAMMA)", result);
  2416         return (-1);
  2417     }
  2418 
  2419     /* Set up the gamma ramp */
  2420     result = IDirectDrawGammaControl_GetGammaRamp(gamma, 0, &gamma_ramp);
  2421     if (result == DD_OK) {
  2422         SDL_memcpy(&ramp[0 * 256], gamma_ramp.red, 256 * sizeof(*ramp));
  2423         SDL_memcpy(&ramp[1 * 256], gamma_ramp.green, 256 * sizeof(*ramp));
  2424         SDL_memcpy(&ramp[2 * 256], gamma_ramp.blue, 256 * sizeof(*ramp));
  2425     } else {
  2426         SetDDerror("DirectDrawGammaControl::GetGammaRamp()", result);
  2427     }
  2428 
  2429     /* Release the interface and return */
  2430     IDirectDrawGammaControl_Release(gamma);
  2431     return (result == DD_OK) ? 0 : -1;
  2432 #endif /* !IDirectDrawGammaControl_SetGammaRamp */
  2433 }
  2434 
  2435 void
  2436 DX5_VideoQuit(_THIS)
  2437 {
  2438     int i, j;
  2439 
  2440     /* If we're fullscreen GL, we need to reset the display */
  2441     if (this->screen != NULL) {
  2442 #ifndef NO_CHANGEDISPLAYSETTINGS
  2443         if ((this->screen->flags & (SDL_INTERNALOPENGL | SDL_FULLSCREEN)) ==
  2444             (SDL_INTERNALOPENGL | SDL_FULLSCREEN)) {
  2445             ChangeDisplaySettings(NULL, 0);
  2446             ShowWindow(SDL_Window, SW_HIDE);
  2447         }
  2448 #endif
  2449         if (this->screen->flags & SDL_INTERNALOPENGL) {
  2450             WIN_GL_ShutDown(this);
  2451         }
  2452     }
  2453 
  2454     /* Free any palettes we used */
  2455     if (SDL_palette != NULL) {
  2456         IDirectDrawPalette_Release(SDL_palette);
  2457         SDL_palette = NULL;
  2458     }
  2459 
  2460     /* Allow the primary surface to be freed */
  2461     if (SDL_primary != NULL) {
  2462         SDL_primary = NULL;
  2463     }
  2464 
  2465     /* Free video mode lists */
  2466     for (i = 0; i < NUM_MODELISTS; ++i) {
  2467         if (SDL_modelist[i] != NULL) {
  2468             for (j = 0; SDL_modelist[i][j]; ++j)
  2469                 SDL_free(SDL_modelist[i][j]);
  2470             SDL_free(SDL_modelist[i]);
  2471             SDL_modelist[i] = NULL;
  2472         }
  2473     }
  2474 
  2475     /* Free the window */
  2476     DIB_QuitGamma(this);
  2477     if (SDL_Window) {
  2478         DX5_DestroyWindow(this);
  2479     }
  2480 
  2481     /* Free our window icon */
  2482     if (screen_icn) {
  2483         DestroyIcon(screen_icn);
  2484         screen_icn = NULL;
  2485     }
  2486 }
  2487 
  2488 /* Exported for the windows message loop only */
  2489 void
  2490 DX5_RealizePalette(_THIS)
  2491 {
  2492     if (SDL_palette) {
  2493         IDirectDrawSurface3_SetPalette(SDL_primary, SDL_palette);
  2494     }
  2495 }
  2496 static void
  2497 DX5_Recolor8Bit(_THIS, SDL_Surface * surface, Uint8 * mapping)
  2498 {
  2499     int row, col;
  2500     Uint8 *pixels;
  2501 
  2502     if (surface->w && surface->h) {
  2503         if ((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
  2504             if (this->LockHWSurface(this, surface) < 0) {
  2505                 return;
  2506             }
  2507         }
  2508         for (row = 0; row < surface->h; ++row) {
  2509             pixels = (Uint8 *) surface->pixels + row * surface->pitch;
  2510             for (col = 0; col < surface->w; ++col, ++pixels) {
  2511                 *pixels = mapping[*pixels];
  2512             }
  2513         }
  2514         if ((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
  2515             this->UnlockHWSurface(this, surface);
  2516         }
  2517         SDL_UpdateRect(surface, 0, 0, 0, 0);
  2518     }
  2519 }
  2520 void
  2521 DX5_PaletteChanged(_THIS, HWND window)
  2522 {
  2523     SDL_Palette *palette;
  2524     SDL_Color *saved = NULL;
  2525     HDC hdc;
  2526     int i;
  2527     PALETTEENTRY *entries;
  2528 
  2529     /* This is true when the window is closing */
  2530     if ((SDL_primary == NULL) || (SDL_VideoSurface == NULL))
  2531         return;
  2532 
  2533     /* We need to get the colors as they were set */
  2534     palette = this->physpal;
  2535     if (!palette)
  2536         palette = SDL_VideoSurface->format->palette;
  2537     if (palette == NULL) {      /* Sometimes we don't have a palette */
  2538         return;
  2539     }
  2540     entries = SDL_stack_alloc(PALETTEENTRY, palette->ncolors);
  2541     hdc = GetDC(window);
  2542     GetSystemPaletteEntries(hdc, 0, palette->ncolors, entries);
  2543     ReleaseDC(window, hdc);
  2544     if (!colorchange_expected) {
  2545         saved = SDL_stack_alloc(SDL_Color, palette->ncolors);
  2546         SDL_memcpy(saved, palette->colors,
  2547                    palette->ncolors * sizeof(SDL_Color));
  2548     }
  2549     for (i = 0; i < palette->ncolors; ++i) {
  2550         palette->colors[i].r = entries[i].peRed;
  2551         palette->colors[i].g = entries[i].peGreen;
  2552         palette->colors[i].b = entries[i].peBlue;
  2553     }
  2554     SDL_stack_free(entries);
  2555     if (!colorchange_expected) {
  2556         Uint8 mapping[256];
  2557 
  2558         SDL_memset(mapping, 0, sizeof(mapping));
  2559         for (i = 0; i < palette->ncolors; ++i) {
  2560             mapping[i] = SDL_FindColor(palette,
  2561                                        saved[i].r, saved[i].g, saved[i].b);
  2562         }
  2563         DX5_Recolor8Bit(this, SDL_VideoSurface, mapping);
  2564         SDL_stack_free(saved);
  2565     }
  2566     colorchange_expected = 0;
  2567 
  2568     /* Notify all mapped surfaces of the change */
  2569     SDL_FormatChanged(SDL_VideoSurface);
  2570 }
  2571 
  2572 /* Exported for the windows message loop only */
  2573 void
  2574 DX5_WinPAINT(_THIS, HDC hdc)
  2575 {
  2576     SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
  2577 }
  2578 
  2579 /* vi: set ts=4 sw=4 expandtab: */