Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1238 lines
34 KiB

  1. /****************************************************************************
  2. *
  3. * DRAWPROC.C
  4. *
  5. * Standard AVI drawing handler.
  6. *
  7. * Copyright (c) 1992 Microsoft Corporation. All Rights Reserved.
  8. *
  9. * You have a royalty-free right to use, modify, reproduce and
  10. * distribute the Sample Files (and/or any modified version) in
  11. * any way you find useful, provided that you agree that
  12. * Microsoft has no warranty obligations or liability for any
  13. * Sample Application Files which are modified.
  14. *
  15. ***************************************************************************/
  16. #ifdef _WIN32
  17. #include "graphic.h"
  18. #include <mmddk.h>
  19. #include "profile.h"
  20. #endif
  21. #include <win32.h>
  22. #include <vfw.h>
  23. #include <dispdib.h>
  24. #ifdef _WIN32
  25. static SZCODE szAtomFlag[] = TEXT("aviFullscreen");
  26. static SZCODE szDisplayDibLib[] = TEXT("DISPDB32.DLL");
  27. #else
  28. static SZCODE szDisplayDibLib[] = TEXT("DISPDIB.DLL");
  29. #endif
  30. static SZCODEA szDisplayDibEx[] = "DisplayDibEx";
  31. #define FOURCC_VIDS mmioFOURCC('v','i','d','s')
  32. #define FOURCC_AVIFull mmioFOURCC('F','U','L','L')
  33. #define VERSION_AVIFull 0x00010000 // 1.00
  34. #ifndef HUGE
  35. #define HUGE _huge
  36. #endif
  37. extern FAR PASCAL LockCurrentTask(BOOL);
  38. static int siUsage = 0;
  39. static HINSTANCE ghDISPDIB = NULL; // handle to DISPDIB.DLL module
  40. UINT (FAR PASCAL *DisplayDibExProc)(LPBITMAPINFOHEADER lpbi, int x, int y, LPSTR hpBits, UINT wFlags)=NULL;
  41. /***************************************************************************
  42. ***************************************************************************/
  43. typedef struct {
  44. int xDst; // destination rectangle
  45. int yDst;
  46. int dxDst;
  47. int dyDst;
  48. int xSrc; // source rectangle
  49. int ySrc;
  50. int dxSrc;
  51. int dySrc;
  52. HWND hwnd;
  53. HWND hwndOldFocus;
  54. BOOL fRle;
  55. DWORD biSizeImage;
  56. } INSTINFO, *PINSTINFO;
  57. // static stuff in this file.
  58. LRESULT FAR PASCAL _loadds ICAVIFullProc(DWORD_PTR id, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2);
  59. static LRESULT AVIFullOpen(ICOPEN FAR * icopen);
  60. static LONG AVIFullClose(PINSTINFO pi);
  61. static LONG AVIFullGetInfo(ICINFO FAR *icinfo, LONG lSize);
  62. static LONG AVIFullQuery(PINSTINFO pi, LPBITMAPINFOHEADER lpbiIn);
  63. static LONG AVIFullSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd);
  64. static LONG AVIFullBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd);
  65. static LONG AVIFullDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd);
  66. static LONG AVIFullEnd(PINSTINFO pi);
  67. /* -------------------------------------------------------------------------
  68. ** Private Globals
  69. ** These are only valid in the process that started playing the movie.
  70. ** -------------------------------------------------------------------------
  71. */
  72. #include "common.h"
  73. HWND hwndFullScreen;
  74. HDC hdcFullScreen;
  75. HDRAWDIB hdd;
  76. BOOL fClassRegistered;
  77. int dxScreen;
  78. int dyScreen;
  79. int iMovieSizeMultiplier;
  80. /***************************************************************************
  81. ***************************************************************************/
  82. LRESULT FAR PASCAL _loadds ICAVIFullProc(DWORD_PTR id, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2)
  83. {
  84. INSTINFO *pi = (INSTINFO *)id;
  85. switch (uiMessage)
  86. {
  87. case DRV_LOAD:
  88. return 1;
  89. case DRV_FREE:
  90. return 1;
  91. /*********************************************************************
  92. open
  93. *********************************************************************/
  94. case DRV_OPEN:
  95. if (ghDISPDIB == NULL) {
  96. UINT w;
  97. w = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  98. if ((INT_PTR)(ghDISPDIB = (HINSTANCE)LoadLibrary(szDisplayDibLib)) > HINSTANCE_ERROR) {
  99. (FARPROC)DisplayDibExProc = GetProcAddress(ghDISPDIB, szDisplayDibEx);
  100. }
  101. else
  102. ghDISPDIB = (HINSTANCE)-1;
  103. SetErrorMode(w);
  104. }
  105. if (DisplayDibExProc == NULL)
  106. DisplayDibExProc = DisplayDibEx;
  107. if (lParam2 == 0L)
  108. return 1;
  109. return AVIFullOpen((ICOPEN FAR *)lParam2);
  110. case DRV_CLOSE:
  111. if (id == 1)
  112. return 1;
  113. return AVIFullClose(pi);
  114. /*********************************************************************
  115. Configure/Info messages
  116. *********************************************************************/
  117. case DRV_QUERYCONFIGURE: // configuration from drivers applet
  118. return 0;
  119. case DRV_CONFIGURE:
  120. return 1;
  121. case ICM_CONFIGURE:
  122. case ICM_ABOUT:
  123. return ICERR_UNSUPPORTED;
  124. /*********************************************************************
  125. state messages
  126. *********************************************************************/
  127. case ICM_GETSTATE:
  128. case ICM_SETSTATE:
  129. return 0L;
  130. #if 0
  131. case ICM_GETINFO:
  132. return AVIFullGetInfo((ICINFO FAR *)lParam1, lParam2);
  133. #endif
  134. /*********************************************************************
  135. decompress messages
  136. *********************************************************************/
  137. case ICM_DRAW_QUERY:
  138. return AVIFullQuery(pi, (LPBITMAPINFOHEADER)lParam1);
  139. case ICM_DRAW_SUGGESTFORMAT:
  140. return AVIFullSuggestFormat(pi, (ICDRAWSUGGEST FAR *) lParam1, (LONG) lParam2);
  141. case ICM_DRAW_BEGIN:
  142. return AVIFullBegin(pi, (ICDRAWBEGIN FAR *) lParam1, (LONG) lParam2);
  143. case ICM_DRAW_REALIZE:
  144. if (DisplayDibExProc == DisplayDibEx) {
  145. if (hdd == NULL || hdcFullScreen == NULL) {
  146. break;
  147. }
  148. return DrawDibRealize( hdd, hdcFullScreen, (BOOL)lParam2 );
  149. }
  150. break;
  151. case ICM_DRAW_GET_PALETTE:
  152. if (DisplayDibExProc == DisplayDibEx) {
  153. if (NULL != hdd) {
  154. return (LONG_PTR)DrawDibGetPalette(hdd);
  155. }
  156. }
  157. break;
  158. case ICM_DRAW:
  159. return AVIFullDraw(pi, (ICDRAW FAR *)lParam1, (LONG) lParam2);
  160. case ICM_DRAW_CHANGEPALETTE:
  161. DisplayDibExProc((LPBITMAPINFOHEADER) lParam1, 0, 0, NULL,
  162. DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE);
  163. return ICERR_OK;
  164. case ICM_DRAW_END:
  165. return AVIFullEnd(pi);
  166. /*********************************************************************
  167. standard driver messages
  168. *********************************************************************/
  169. case DRV_DISABLE:
  170. case DRV_ENABLE:
  171. return 1;
  172. case DRV_INSTALL:
  173. case DRV_REMOVE:
  174. return 1;
  175. }
  176. if (uiMessage < DRV_USER)
  177. return DefDriverProc(id,hDriver,uiMessage,lParam1,lParam2);
  178. else
  179. return ICERR_UNSUPPORTED;
  180. }
  181. /*****************************************************************************
  182. *
  183. * AVIFullOpen() is called from the DRV_OPEN message
  184. *
  185. ****************************************************************************/
  186. static LONG_PTR AVIFullOpen(ICOPEN FAR * icopen)
  187. {
  188. INSTINFO * pinst;
  189. //
  190. // refuse to open if we are not being opened as a Video compressor
  191. //
  192. if (icopen->dwFlags & ICMODE_COMPRESS)
  193. return 0;
  194. if (icopen->dwFlags & ICMODE_DECOMPRESS)
  195. return 0;
  196. pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
  197. if (!pinst)
  198. {
  199. icopen->dwError = ICERR_MEMORY;
  200. return 0;
  201. }
  202. ++siUsage;
  203. //
  204. // return success.
  205. //
  206. icopen->dwError = ICERR_OK;
  207. return (LONG_PTR) (UINT_PTR) pinst;
  208. }
  209. /*****************************************************************************
  210. *
  211. * Close() is called on the DRV_CLOSE message.
  212. *
  213. ****************************************************************************/
  214. static LONG AVIFullClose(PINSTINFO pi)
  215. {
  216. LocalFree((HLOCAL) pi);
  217. if (--siUsage == 0) {
  218. /* unload DISPDIB library (if loaded) */
  219. if (ghDISPDIB != NULL && ghDISPDIB != (HINSTANCE) -1)
  220. FreeLibrary(ghDISPDIB), ghDISPDIB = NULL;
  221. }
  222. return 1;
  223. }
  224. #if 0
  225. /*****************************************************************************
  226. *
  227. * AVIFullGetInfo() implements the ICM_GETINFO message
  228. *
  229. ****************************************************************************/
  230. static LONG AVIFullGetInfo(ICINFO FAR *icinfo, LONG lSize)
  231. {
  232. if (icinfo == NULL)
  233. return sizeof(ICINFO);
  234. if (lSize < sizeof(ICINFO))
  235. return 0;
  236. icinfo->dwSize = sizeof(ICINFO);
  237. icinfo->fccType = FOURCC_VIDS;
  238. icinfo->fccHandler = FOURCC_AVIFull;
  239. icinfo->dwFlags = VIDCF_DRAW;
  240. icinfo->dwVersion = VERSION_AVIFull;
  241. icinfo->dwVersionICM = ICVERSION;
  242. lstrcpy(icinfo->szDescription, szDescription);
  243. lstrcpy(icinfo->szName, szName);
  244. return sizeof(ICINFO);
  245. }
  246. #endif
  247. /*****************************************************************************
  248. *
  249. * AVIFullQuery() implements ICM_DRAW_QUERY
  250. *
  251. ****************************************************************************/
  252. static LONG AVIFullQuery(PINSTINFO pi,
  253. LPBITMAPINFOHEADER lpbiIn)
  254. {
  255. //
  256. // determine if the input DIB data is in a format we like.
  257. //
  258. if (lpbiIn == NULL)
  259. return ICERR_BADFORMAT;
  260. if (DisplayDibExProc(lpbiIn, 0, 0, 0,
  261. DISPLAYDIB_MODE_DEFAULT|DISPLAYDIB_NOWAIT|DISPLAYDIB_TEST) != 0)
  262. return ICERR_BADFORMAT;
  263. return ICERR_OK;
  264. }
  265. static LONG AVIFullSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd)
  266. {
  267. HIC hic;
  268. static int iFull = -1;
  269. int iDepth;
  270. if (iFull < 0) {
  271. BITMAPINFOHEADER bih;
  272. bih.biSize = sizeof(bih);
  273. bih.biBitCount = 16;
  274. bih.biCompression = BI_RGB;
  275. bih.biWidth = 160;
  276. bih.biHeight = 120;
  277. iFull = (AVIFullQuery(pi, &bih) == ICERR_OK) ? 1 : 0;
  278. }
  279. iDepth = lpicd->lpbiIn->biBitCount > 8 && iFull == 1 ? 16 : 8;
  280. if (lpicd->lpbiSuggest == NULL)
  281. return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
  282. hic = ICGetDisplayFormat(NULL, lpicd->lpbiIn,
  283. lpicd->lpbiSuggest,
  284. iDepth, 0, 0);
  285. if (hic)
  286. ICClose(hic);
  287. return sizeof(BITMAPINFOHEADER) + lpicd->lpbiSuggest->biClrUsed * sizeof(RGBQUAD);
  288. }
  289. /*****************************************************************************
  290. *
  291. * AVIFullBegin() implements ICM_DRAW_BEGIN
  292. *
  293. ****************************************************************************/
  294. static LONG AVIFullBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd)
  295. {
  296. UINT w;
  297. LONG lRet;
  298. UINT wFlags = DISPLAYDIB_BEGIN | DISPLAYDIB_NOWAIT;
  299. if (!(lpicd->dwFlags & ICDRAW_FULLSCREEN))
  300. return ICERR_UNSUPPORTED; // !!! Necessary?
  301. lRet = AVIFullQuery(pi, lpicd->lpbi);
  302. if (lRet != 0 || (lpicd->dwFlags & ICDRAW_QUERY))
  303. return lRet;
  304. // Copy over whatever we want to remember
  305. pi->hwnd = lpicd->hwnd;
  306. pi->xDst = lpicd->xDst;
  307. pi->yDst = lpicd->yDst;
  308. pi->dxDst = lpicd->dxDst;
  309. pi->dyDst = lpicd->dyDst;
  310. pi->xSrc = lpicd->xSrc;
  311. pi->ySrc = lpicd->ySrc;
  312. pi->dxSrc = lpicd->dxSrc;
  313. pi->dySrc = lpicd->dySrc;
  314. if (pi->dxDst > pi->dxSrc)
  315. wFlags |= DISPLAYDIB_ZOOM2;
  316. //
  317. // remember if this is RLE because we may need to hack it later.
  318. //
  319. pi->fRle = lpicd->lpbi->biCompression == BI_RLE8;
  320. pi->biSizeImage = (DWORD)(((UINT)lpicd->lpbi->biWidth+3)&~3)*(DWORD)(UINT)lpicd->lpbi->biHeight;
  321. pi->hwndOldFocus = GetFocus();
  322. SetFocus(NULL);
  323. /*
  324. ** If we are using the built in fullscreen support we have to
  325. ** get the hdd and set its palette here. This is because I am unable to
  326. ** pass this information to DispDib code (there arn't any free parameters).
  327. */
  328. if (DisplayDibExProc == DisplayDibEx) {
  329. hdd = DrawDibOpen();
  330. if (lpicd->hpal == (HPALETTE)MCI_AVI_SETVIDEO_PALETTE_HALFTONE) {
  331. DrawDibSetPalette(hdd, NULL);
  332. }
  333. else {
  334. DrawDibSetPalette(hdd, lpicd->hpal);
  335. }
  336. }
  337. // Don't animate if we're realizing in the background
  338. if (lpicd->dwFlags & ICDRAW_ANIMATE) {
  339. wFlags |= DISPLAYDIB_ANIMATE;
  340. }
  341. if (lpicd->hpal == (HPALETTE)MCI_AVI_SETVIDEO_PALETTE_HALFTONE) {
  342. wFlags |= DISPLAYDIB_HALFTONE;
  343. }
  344. //
  345. // we dont need to do this, DISPDIB will do it for us
  346. //
  347. #if 0
  348. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  349. LockCurrentTask(TRUE);
  350. #endif
  351. /* Capture the mouse, so other apps don't get called. */
  352. SetCapture(pi->hwnd);
  353. /* We don't explicitly specify a graphics mode; DispDib will
  354. ** choose one for us.
  355. */
  356. w = DisplayDibExProc(lpicd->lpbi, 0, 0, NULL, wFlags );
  357. switch (w) {
  358. case DISPLAYDIB_INVALIDFORMAT:
  359. return ICERR_BADFORMAT;
  360. case 0:
  361. return ICERR_OK;
  362. default:
  363. return ICERR_UNSUPPORTED;
  364. }
  365. }
  366. /*****************************************************************************
  367. *
  368. * AVIFullDraw() implements ICM_DRAW
  369. *
  370. ****************************************************************************/
  371. STATICFN LONG AVIFullDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd)
  372. {
  373. UINT wFlags;
  374. UINT w;
  375. wFlags = DISPLAYDIB_NOPALETTE | DISPLAYDIB_NOWAIT;
  376. if (pi->dxDst > pi->dxSrc) {
  377. wFlags |= DISPLAYDIB_ZOOM2;
  378. }
  379. if (lpicd->dwFlags & ICDRAW_NULLFRAME) {
  380. return ICERR_OK; // !!!
  381. }
  382. if (lpicd->dwFlags & ICDRAW_PREROLL) {
  383. if (((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression == BI_RGB) // !!!
  384. return ICERR_OK;
  385. }
  386. if (lpicd->dwFlags & ICDRAW_HURRYUP)
  387. ; // !!! DONTDRAW?
  388. if (lpicd->lpData == NULL)
  389. return ICERR_UNSUPPORTED;
  390. //
  391. // We need a hack here for the RLE case, to make sure that
  392. // DIBs are marked correctly as BI_RLE8 or BI_RGB....
  393. //
  394. if (pi->fRle) {
  395. if (lpicd->cbData == pi->biSizeImage)
  396. ((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RGB;
  397. else {
  398. ((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RLE8;
  399. // We MUST set the correct size
  400. ((LPBITMAPINFOHEADER)lpicd->lpFormat)->biSizeImage = lpicd->cbData;
  401. }
  402. }
  403. w = DisplayDibExProc(lpicd->lpFormat, 0, 0, lpicd->lpData, wFlags);
  404. if (pi->fRle)
  405. ((LPBITMAPINFOHEADER)lpicd->lpFormat)->biCompression = BI_RLE8;
  406. switch (w) {
  407. case DISPLAYDIB_STOP: return ICERR_STOPDRAWING;
  408. case DISPLAYDIB_NOERROR: return ICERR_OK;
  409. default: return ICERR_ERROR;
  410. }
  411. }
  412. /*****************************************************************************
  413. *
  414. * AVIFullEnd() implements ICM_DRAW_END
  415. *
  416. ****************************************************************************/
  417. static LONG AVIFullEnd(PINSTINFO pi)
  418. {
  419. MSG msg;
  420. DisplayDibExProc(NULL, 0, 0, NULL, DISPLAYDIB_END | DISPLAYDIB_NOWAIT);
  421. //
  422. // we dont need to do this, DISPDIB will do it for us
  423. //
  424. #if 0
  425. LockCurrentTask(FALSE);
  426. /* Can we assume the error mode should be 0? */
  427. SetErrorMode(0);
  428. #endif
  429. ReleaseCapture();
  430. /* Clear out left-over key messages */
  431. while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
  432. PM_REMOVE | PM_NOYIELD))
  433. ;
  434. /* Clear out left-over mouse messages */
  435. while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
  436. PM_REMOVE | PM_NOYIELD))
  437. ;
  438. SetFocus(pi->hwndOldFocus);
  439. return ICERR_OK;
  440. }
  441. /* -------------------------------------------------------------------------
  442. ** Private constants
  443. ** -------------------------------------------------------------------------
  444. */
  445. #define CX_MAX_MOVIE_DEFAULT 640
  446. #define CY_MAX_MOVIE_DEFAULT 480
  447. /* -------------------------------------------------------------------------
  448. ** Private functions prototypes
  449. ** -------------------------------------------------------------------------
  450. */
  451. LRESULT CALLBACK
  452. FullScreenWndProc(
  453. HWND hwnd,
  454. UINT message,
  455. WPARAM wParam,
  456. LPARAM lParam
  457. );
  458. LRESULT CALLBACK
  459. KeyboardHookProc(
  460. int nCode,
  461. WPARAM wParam,
  462. LPARAM lParam
  463. );
  464. UINT
  465. DisplayDibEnter(
  466. LPBITMAPINFOHEADER lpbi,
  467. UINT wFlags
  468. );
  469. void
  470. DisplayDibLeave(
  471. UINT wFlags
  472. );
  473. int
  474. DisplayCalcMovieMultiplier(
  475. int cxOriginal,
  476. int cyOriginal,
  477. DWORD dwCompression
  478. );
  479. /* -------------------------------------------------------------------------
  480. ** Global data shared between all processes that attach to this library.
  481. ** This is required to make the keyboard hook work correctly.
  482. ** -------------------------------------------------------------------------
  483. */
  484. //#define StopRequested() (fStop)
  485. #define StopRequested() (GlobalFindAtom(szAtomFlag))
  486. #pragma data_seg( ".sdata" , "DATA")
  487. BOOL fStop;
  488. HHOOK hHookK;
  489. #pragma data_seg()
  490. /******************************Public*Routine******************************\
  491. * @doc EXTERNAL DISPDIB
  492. *
  493. * @api UINT | DisplayDibEx | This function displays a 256-color bitmap on a
  494. * standard VGA display. It reduces the display resolution to 320-by-200
  495. * or 320-by-240 and uses the full screen to display the bitmap, clipping
  496. * and centering it as necessary. The function normally does not return to
  497. * the application until the user presses a key or clicks a mouse button.
  498. *
  499. * To call <f DisplayDibEx>, an application must be the active
  500. * application. All inactive applications and GDI screen updates
  501. * are suspended while <f DisplayDib> temporarily reconfigures
  502. * the display.
  503. *
  504. * @parm LPBITMAPINFO | lpbi | Specifies a pointer to a <t BITMAPINFO>
  505. * header describing the bitmap to be displayed.
  506. *
  507. * @parm int | x | x position to place DIB iff DISPLAYDIB_NOCENTER flags is set
  508. * the lower left is (0,0)
  509. *
  510. * @parm int | y | y position to place DIB iff DISPLAYDIB_NOCENTER flags is set
  511. * the lower left is (0,0)
  512. *
  513. * @parm LPSTR | lpBits | Specifies a pointer to the bitmap bits. If this
  514. * parameter is NULL, the bits are assumed to follow the
  515. * <t BITMAPINFO> structure pointed to by <p lpbi>.
  516. *
  517. * @parm UINT | wFlags | Specifies options for displaying the bitmap. Use
  518. * the following flags:
  519. *
  520. * @flag DISPLAYDIB_MODE_DEFAULT | Use the default mode (320 by 240)
  521. * to display the bitmap.
  522. * @flag DISPLAYDIB_MODE_320x200x8 | Use 320-by-200 mode to display
  523. * the bitmap.
  524. * @flag DISPLAYDIB_MODE_320x240x8 | Use 320-by-240 mode to display
  525. * the bitmap. This is the default.
  526. * @flag DISPLAYDIB_NOWAIT | Return immediately after displaying the
  527. * bitmap; don't wait for a key press or mouse click before returning.
  528. * @flag DISPLAYDIB_NOPALETTE | Ignore the palette associated
  529. * with the bitmap. You can use this flag when displaying a series
  530. * of bitmaps that use a common palette.
  531. * @flag DISPLAYDIB_NOCENTER | Don't center the image. The function
  532. * displays the bitmap in the lower-left corner of the display.
  533. * @flag DISPLAYDIB_NOIMAGE | Don't draw image
  534. * @flag DISPLAYDIB_ZOOM2 | Stretch image by 2
  535. * @flag DISPLAYDIB_DONTLOCKTASK | dont lock out other tasks
  536. * @flag DISPLAYDIB_TEST | dont do any thing just test for support
  537. * @flag DISPLAYDIB_BEGIN | Switch to the low-resolution
  538. * display mode and set the palette. The bitmap is not displayed.
  539. *
  540. * If you are displaying a series of images that use the same palette,
  541. * you can call <f DisplayDib> with this flag to prepare the display for
  542. * the bitmaps, then make a series of <f DisplayDib> calls with the
  543. * DISPLAYDIB_NOPALETTE flag. This technique
  544. * eliminates the screen flicker that occurs when the display is
  545. * switched between the low-resolution and standard VGA modes.
  546. * To return the display to standard VGA mode, subsequently
  547. * call <f DisplayDib> with the DISPLAYDIB_END flag.
  548. *
  549. * @flag DISPLAYDIB_END | Switch back to standard VGA mode
  550. * and return without displaying a bitmap. Signifies the end of multiple
  551. * calls to <f DisplayDib>. With this flag, you can specify
  552. * NULL for the <p lpbi> and <p lpBits> parameters.
  553. *
  554. * @rdesc Returns zero if successful, otherwise returns an error code.
  555. * Error codes are as follows:
  556. *
  557. * @flag DISPLAYDIB_NOTSUPPORTED | <f DisplayDib> is not supported
  558. * in the current mode.
  559. * @flag DISPLAYDIB_INVALIDDIB | The bitmap specified by
  560. * <p lpbi> is not a valid bitmap.
  561. * @flag DISPLAYDIB_INVALIDFORMAT | The bitmap specified by
  562. * <p lpbi> specifes a type of bitmap that is not supported.
  563. * @flag DISPLAYDIB_INVALIDTASK | The caller is an inactive application.
  564. * <f DisplayDib> can only be called by an active application.
  565. *
  566. * @comm The <f DisplayDib> function displays bitmaps described with
  567. * the Windows 3.0 <t BITMAPINFO> data structure in either BI_RGB
  568. * or BI_RLE8 format; it does not support bitmaps described with
  569. * the OS/2 <t BITMAPCOREHEADER> data structure.
  570. *
  571. * When <f DisplayDib> switches to a low-resolution display, it
  572. * disables the current display driver. As a result, you cannot use GDI
  573. * functions to update the display while <f DisplayDib> is displaying a
  574. * bitmap.
  575. *
  576. *
  577. * History:
  578. * 23-03-94 - StephenE - Created
  579. *
  580. \**************************************************************************/
  581. UINT FAR PASCAL
  582. DisplayDibEx(
  583. LPBITMAPINFOHEADER lpbi,
  584. int x,
  585. int y,
  586. LPSTR lpBits,
  587. UINT wFlags
  588. )
  589. {
  590. DWORD wNumColors;
  591. LONG yExt;
  592. LONG xExt;
  593. int xScreen,yScreen;
  594. /*
  595. ** If not already done so:
  596. ** Register our class and Create our window "fullscreen"
  597. */
  598. if (wFlags & DISPLAYDIB_BEGIN) {
  599. DPF4(( "DISPLAYDIB_BEGIN..." ));
  600. return DisplayDibEnter( lpbi, wFlags );
  601. }
  602. /*
  603. ** Just testing return OK
  604. */
  605. else if (wFlags & DISPLAYDIB_TEST) {
  606. DPF1(( "lpbi->biCompression = 0x%X = %c%c%c%c",
  607. lpbi->biCompression,
  608. *((LPSTR)&lpbi->biCompression + 0),
  609. *((LPSTR)&lpbi->biCompression + 1),
  610. *((LPSTR)&lpbi->biCompression + 2),
  611. *((LPSTR)&lpbi->biCompression + 3) ));
  612. DPF4(( "DISPLAYDIB_TEST... returning OK" ));
  613. return DISPLAYDIB_NOERROR;
  614. }
  615. /*
  616. ** Palette change message
  617. */
  618. else if ( (wFlags & (DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE)) ==
  619. (DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE) ) {
  620. PALETTEENTRY ape[256];
  621. LPRGBQUAD lprgb;
  622. int i;
  623. lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize);
  624. for (i = 0; i < (int) lpbi->biClrUsed; i++) {
  625. ape[i].peRed = lprgb[i].rgbRed;
  626. ape[i].peGreen = lprgb[i].rgbGreen;
  627. ape[i].peBlue = lprgb[i].rgbBlue;
  628. ape[i].peFlags = 0;
  629. }
  630. DrawDibChangePalette(hdd, 0, (int)lpbi->biClrUsed, (LPPALETTEENTRY)ape);
  631. return DISPLAYDIB_NOERROR;
  632. }
  633. /*
  634. ** Time to kill the window and the class
  635. */
  636. else if (wFlags & DISPLAYDIB_END) {
  637. DPF4(( "DISPLAYDIB_END..." ));
  638. DisplayDibLeave( wFlags );
  639. return DISPLAYDIB_NOERROR;
  640. }
  641. /*
  642. ** Do the drawing here !!
  643. */
  644. else if ( !StopRequested() ) {
  645. /*
  646. ** If we were'nt asked to draw anything just return.
  647. */
  648. if ( wFlags & DISPLAYDIB_NOIMAGE ) {
  649. return DISPLAYDIB_NOERROR;
  650. }
  651. xExt = lpbi->biWidth;
  652. yExt = lpbi->biHeight;
  653. if ( wFlags & DISPLAYDIB_ZOOM2 ) {
  654. xExt <<= 1;
  655. yExt <<= 1;
  656. }
  657. else if ( iMovieSizeMultiplier ) {
  658. //The movie needs to be stretched to full screen.
  659. xExt = GetSystemMetrics( SM_CXSCREEN );
  660. yExt = GetSystemMetrics( SM_CYSCREEN );
  661. }
  662. wNumColors = lpbi->biClrUsed;
  663. if (wNumColors == 0 && lpbi->biBitCount <= 8) {
  664. wNumColors = 1 << (UINT)lpbi->biBitCount;
  665. }
  666. /*
  667. ** setup pointers
  668. */
  669. if (lpBits == NULL) {
  670. lpBits = (LPBYTE)lpbi + lpbi->biSize + wNumColors * sizeof(RGBQUAD);
  671. }
  672. /*
  673. ** center the image
  674. */
  675. if (!(wFlags & DISPLAYDIB_NOCENTER)) {
  676. xScreen = ((int)dxScreen - xExt) / 2;
  677. yScreen = ((int)dyScreen - yExt) / 2;
  678. }
  679. else {
  680. xScreen = 0;
  681. yScreen = 0;
  682. }
  683. DPF4(( "Drawing to the screen..." ));
  684. DrawDibDraw( hdd, hdcFullScreen,
  685. xScreen, yScreen, xExt, yExt,
  686. lpbi, lpBits,
  687. 0, 0, lpbi->biWidth, lpbi->biHeight,
  688. DDF_SAME_HDC | DDF_SAME_DRAW );
  689. /*
  690. ** Hack time !!
  691. **
  692. ** We have to remove keyboard message from the queue to enable the
  693. ** keyboard hook to see them !!
  694. */
  695. {
  696. MSG msg;
  697. PeekMessage( &msg, NULL, WM_KEYFIRST, WM_KEYLAST,
  698. PM_REMOVE | PM_NOYIELD );
  699. }
  700. return DISPLAYDIB_NOERROR;
  701. // return fStop;
  702. }
  703. /*
  704. ** The user pressed a key... time to stop
  705. */
  706. else {
  707. DPF1(( "The keyboard hook is telling us to stop..." ));
  708. //DisplayDibLeave( wFlags );
  709. return DISPLAYDIB_STOP;
  710. }
  711. }
  712. /*****************************Private*Routine******************************\
  713. * DisplayDibEnter
  714. *
  715. *
  716. *
  717. * History:
  718. * 23-03-94 - StephenE - Created
  719. *
  720. \**************************************************************************/
  721. UINT
  722. DisplayDibEnter(
  723. LPBITMAPINFOHEADER lpbi,
  724. UINT wFlags
  725. )
  726. {
  727. WNDCLASS wc;
  728. HINSTANCE hInst = GetModuleHandle( NULL );
  729. /*
  730. ** If our class isn't already registered with windows register it
  731. */
  732. fClassRegistered = GetClassInfo( hInst, TEXT("SJE_FULLSCREEN"), &wc );
  733. if ( fClassRegistered == FALSE ) {
  734. ZeroMemory( &wc, sizeof(wc) );
  735. wc.style = CS_OWNDC;
  736. wc.lpfnWndProc = FullScreenWndProc;
  737. wc.hInstance = hInst;
  738. wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
  739. wc.lpszClassName = TEXT("SJE_FULLSCREEN");
  740. fClassRegistered = RegisterClass( &wc );
  741. DPF4(( "Class registered... %s", fClassRegistered ? "OK" : "FAILED" ));
  742. }
  743. if ( fClassRegistered ) {
  744. /*
  745. ** Do we already have a window ??
  746. */
  747. if ( hwndFullScreen == NULL ) {
  748. hwndFullScreen = CreateWindowEx( WS_EX_TOPMOST,
  749. TEXT("SJE_FULLSCREEN"),
  750. NULL,
  751. WS_POPUP,
  752. 0, 0, 0, 0,
  753. NULL, NULL,
  754. hInst, NULL );
  755. DPF4(( "Window created... %s", hwndFullScreen ? "OK" : "FAILED" ));
  756. }
  757. if ( hwndFullScreen ) {
  758. LONG yExt;
  759. LONG xExt;
  760. fStop = FALSE;
  761. hHookK = SetWindowsHookEx( WH_KEYBOARD, KeyboardHookProc,
  762. ghModule,
  763. 0 );
  764. DPF4(( "Hook created... %s", hHookK ? "OK" : "FAILED" ));
  765. dxScreen = GetSystemMetrics( SM_CXSCREEN );
  766. dyScreen = GetSystemMetrics( SM_CYSCREEN );
  767. hdcFullScreen = GetDC( hwndFullScreen );
  768. SetStretchBltMode(hdcFullScreen, COLORONCOLOR);
  769. xExt = lpbi->biWidth;
  770. yExt = lpbi->biHeight;
  771. iMovieSizeMultiplier =
  772. DisplayCalcMovieMultiplier( xExt, yExt, lpbi->biCompression );
  773. if ( wFlags & DISPLAYDIB_ZOOM2 ) {
  774. xExt <<= 1;
  775. yExt <<= 1;
  776. }
  777. else if ( iMovieSizeMultiplier ) {
  778. //The movie needs to be stretched to full screen.
  779. xExt = GetSystemMetrics( SM_CXSCREEN );
  780. yExt = GetSystemMetrics( SM_CYSCREEN );
  781. }
  782. if ( wFlags & DISPLAYDIB_ANIMATE ) {
  783. wFlags = DDF_ANIMATE;
  784. }
  785. else if ( wFlags & DISPLAYDIB_HALFTONE ) {
  786. wFlags = DDF_HALFTONE;
  787. }
  788. else {
  789. wFlags = 0;
  790. }
  791. DPF1(( "Drawing at %d by %d... Flags = 0x%X", xExt, yExt, wFlags ));
  792. DrawDibBegin( hdd, hdcFullScreen, xExt, yExt,
  793. lpbi, lpbi->biWidth, lpbi->biHeight, wFlags );
  794. MoveWindow( hwndFullScreen, 0, 0, dxScreen, dyScreen, FALSE );
  795. ShowWindow( hwndFullScreen, SW_SHOW );
  796. UpdateWindow( hwndFullScreen );
  797. ShowCursor( FALSE );
  798. SetForegroundWindow( hwndFullScreen );
  799. SetFocus( hwndFullScreen );
  800. }
  801. }
  802. return hwndFullScreen != NULL ? DISPLAYDIB_NOERROR : DISPLAYDIB_NOTSUPPORTED;
  803. }
  804. /*****************************Private*Routine******************************\
  805. * DisplayDibLeave
  806. *
  807. *
  808. *
  809. * History:
  810. * 23-03-94 - StephenE - Created
  811. *
  812. \**************************************************************************/
  813. void
  814. DisplayDibLeave(
  815. UINT wFlags
  816. )
  817. {
  818. if (hwndFullScreen) {
  819. DestroyWindow( hwndFullScreen );
  820. hwndFullScreen = NULL;
  821. }
  822. }
  823. /*****************************Private*Routine******************************\
  824. * DisplayCalcMovieMultiplier
  825. *
  826. * Determines the largest movie that the display is capable of displaying.
  827. *
  828. * History:
  829. * dd-mm-94 - StephenE - Created
  830. *
  831. \**************************************************************************/
  832. int
  833. DisplayCalcMovieMultiplier(
  834. int cxOriginal,
  835. int cyOriginal,
  836. DWORD dwCompression
  837. )
  838. {
  839. SYSTEM_INFO SysInfo;
  840. int iMult;
  841. int iMultTemp;
  842. int cxOriginalSave, cyOriginalSave;
  843. int iMax = 8;
  844. GetSystemInfo( &SysInfo );
  845. iMultTemp = iMult = 0;
  846. cxOriginalSave = cxOriginal;
  847. cyOriginalSave = cyOriginal;
  848. switch ( SysInfo.wProcessorArchitecture ) {
  849. case PROCESSOR_ARCHITECTURE_INTEL:
  850. if ( SysInfo.wProcessorLevel <= 3 ) {
  851. break;
  852. } else
  853. if ( SysInfo.wProcessorLevel == 4 ) {
  854. iMax = 2;
  855. iMax = mmGetProfileInt(szIni, TEXT("MaxFullScreenShift"), iMax);
  856. //DPF0(("Setting the maximum shift multiplier to %d\n", iMax));
  857. }
  858. /*
  859. ** maybe later we will do something more different for i486's
  860. ** for now they just fall through to the RISC / Pentium default
  861. ** case below.
  862. */
  863. default:
  864. while ( ( (cxOriginal<<=1) <= CX_MAX_MOVIE_DEFAULT)
  865. && ( (cyOriginal<<=1) <= CY_MAX_MOVIE_DEFAULT)
  866. && (iMax >= iMult)) {
  867. ++iMult;
  868. }
  869. break;
  870. }
  871. return iMult;
  872. }
  873. /******************************Public*Routine******************************\
  874. * FullScreenWndProc
  875. *
  876. *
  877. *
  878. * History:
  879. * 23-03-94 - StephenE - Created
  880. *
  881. \**************************************************************************/
  882. LRESULT CALLBACK
  883. FullScreenWndProc(
  884. HWND hwnd,
  885. UINT message,
  886. WPARAM wParam,
  887. LPARAM lParam
  888. )
  889. {
  890. switch ( message ) {
  891. case WM_PAINT:
  892. {
  893. PAINTSTRUCT ps;
  894. RECT rc;
  895. DPF4(( "Window needs painting" ));
  896. BeginPaint( hwnd, &ps );
  897. GetUpdateRect( hwnd, &rc, FALSE );
  898. FillRect( hdcFullScreen, &rc, GetStockObject( BLACK_BRUSH ) );
  899. EndPaint( hwnd, &ps );
  900. }
  901. break;
  902. case WM_PALETTECHANGED:
  903. if ( (HWND)wParam == hwnd ) {
  904. break;
  905. }
  906. /* fall thru */
  907. case WM_QUERYNEWPALETTE:
  908. if ( DrawDibRealize( hdd, hdcFullScreen, FALSE ) > 0 ) {
  909. InvalidateRect( hwnd, NULL, TRUE );
  910. return TRUE;
  911. }
  912. break;
  913. case WM_DESTROY:
  914. {
  915. ATOM atm;
  916. DPF4(( "Window destroyed releasing DC" ));
  917. ReleaseDC( hwnd, hdcFullScreen );
  918. DrawDibEnd( hdd );
  919. DrawDibClose( hdd );
  920. hdd = NULL;
  921. hdcFullScreen = NULL;
  922. UnregisterClass( TEXT("SJE_FULLSCREEN"), GetModuleHandle( NULL ) );
  923. fClassRegistered = FALSE;
  924. ShowCursor( TRUE );
  925. UnhookWindowsHookEx( hHookK );
  926. while (atm = GlobalFindAtom(szAtomFlag)) {
  927. GlobalDeleteAtom(atm);
  928. }
  929. }
  930. break;
  931. //case WM_KILLFOCUS:
  932. //case WM_ACTIVATE:
  933. //case WM_SETFOCUS:
  934. // DPF0(("FullWindowProc, message==%8x, wp/lp %8x/%8x\n", message, wParam, lParam));
  935. default:
  936. return DefWindowProc( hwnd, message, wParam, lParam );
  937. }
  938. return (LRESULT)FALSE;
  939. }
  940. /******************************Public*Routine******************************\
  941. * KeyboardHookProc
  942. *
  943. *
  944. *
  945. * History:
  946. * 23-03-94 - StephenE - Created
  947. *
  948. \**************************************************************************/
  949. LRESULT CALLBACK
  950. KeyboardHookProc(
  951. int nCode,
  952. WPARAM wParam,
  953. LPARAM lParam
  954. )
  955. {
  956. //DPF0(("HookProc, ncode == %d, lParam==%8x\n", nCode, lParam));
  957. if ( nCode == HC_ACTION) {
  958. DPF1(( "lParam = 0x%X", lParam ));
  959. DPF1(( "! wParam = 0x%X\n", wParam ));
  960. /*
  961. ** Don't mess about with the control or shift key. This is because
  962. ** mciwnd uses them to start playing fullscreen. This causes the movie
  963. ** to start start playing and then immediately stop. 0x001D0000 is
  964. ** the scan code for the control keys, 0x002A0000 is the scan code
  965. ** for the shift key.
  966. */
  967. if ( (lParam & 0x00FF0000) == 0x001D0000
  968. || (lParam & 0x00FF0000) == 0x002A0000 ) {
  969. return CallNextHookEx( hHookK, nCode, wParam, lParam );
  970. }
  971. /*
  972. ** The most significant bit of lParam is set if the key is being
  973. ** released. We are only interested in keydowns. Bits 16 - 23 are
  974. ** the hardware scan code of the key being pressed, 0x00010000
  975. ** is the scan code for the escape key.
  976. */
  977. if ( !(lParam & 0x80000000) || ((lParam & 0x00FF0000) == 0x00010000)) {
  978. if (!fStop) {
  979. fStop = TRUE;
  980. GlobalAddAtom(szAtomFlag);
  981. /*
  982. ** Don't let windows see this message.
  983. */
  984. return -1;
  985. }
  986. DPF1(( "Stop requested from the keyboard hook" ));
  987. }
  988. }
  989. return CallNextHookEx( hHookK, nCode, wParam, lParam );
  990. }