]> git.sesse.net Git - vlc/blob - plugins/directx/vout_directx.c
Win32 changes only:
[vlc] / plugins / directx / vout_directx.c
1 /*****************************************************************************
2  * vout_directx.c: Windows DirectX video output display method
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000 VideoLAN
5  * $Id: vout_directx.c,v 1.6 2001/07/08 17:45:52 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #define MODULE_NAME directx
25 #include "modules_inner.h"
26
27 /* To be fixed:
28  *
29  * When the option: "Display full screen when dragging window" is enabled in
30  * Windows display properties, the overlay surface coordinates won't be updated
31  * (but it won't crash anymore ;-) I know where the problem is in the code, but * I just don't know yet of a nice way to fix this.
32  * 
33  * Double buffering
34  *
35  * Port this plugin to Video Output IV
36  */
37
38 /*****************************************************************************
39  * Preamble:
40  *
41  * This plugin will use YUV overlay if supported, using overlay will result in
42  * the best video quality (hardware interpolation when rescaling the picture)
43  * and the fastest display as it requires less processing.
44  *
45  * If YUV overlay is not supported the plugin will use an RGB offscreen video
46  * surface that will be blitted onto the primary surface (display) to
47  * effectively display the picture. this fallback method enables us to display
48  * video in window mode.
49  * Another fallback method (which isn't implemented yet) would be to use the
50  * primary surface as the video buffer. This would allow for better
51  * performance but this is restricted to fullscreen video. In short,
52  * implementing this is not considered high priority.
53  * 
54  *****************************************************************************/
55 #include "defs.h"
56
57 #include <errno.h>                                                 /* ENOMEM */
58 #include <stdlib.h>                                                /* free() */
59 #include <string.h>                                            /* strerror() */
60
61 #include <windows.h>
62 #include <windowsx.h>
63 #include <directx.h>
64
65 #include "config.h"
66 #include "common.h"
67 #include "threads.h"
68 #include "mtime.h"
69 #include "tests.h"
70 #include "netutils.h"
71
72 #include "video.h"
73 #include "video_output.h"
74
75 #include "intf_msg.h"
76 #include "interface.h"
77 #include "main.h"
78
79 #include "modules.h"
80 #include "modules_export.h"
81
82 /*****************************************************************************
83  * vout_sys_t: video output DirectX method descriptor
84  *****************************************************************************
85  * This structure is part of the video output thread descriptor.
86  * It describes the DirectX specific properties of an output thread.
87  *****************************************************************************/
88 typedef struct vout_sys_s
89 {
90
91     LPDIRECTDRAW2        p_ddobject;                    /* DirectDraw object */
92     LPDIRECTDRAWSURFACE3 p_display;                        /* Display device */
93     LPDIRECTDRAWSURFACE3 p_surface;    /* surface where we display the video */
94     LPDIRECTDRAWCLIPPER  p_clipper;             /* clipper used for blitting */
95     HINSTANCE            hddraw_dll;       /* handle of the opened ddraw dll */
96     HBRUSH               hbrush;           /* window backgound brush (color) */
97     HWND                 hwnd;                  /* Handle of the main window */
98
99     int         i_image_width;                  /* size of the decoded image */
100     int         i_image_height;
101     int         i_window_width;               /* size of the displayed image */
102     int         i_window_height;
103
104     int         i_colorkey;          /* colorkey used to display the overlay */
105  
106     boolean_t   b_display_enabled;
107     boolean_t   b_overlay;
108     boolean_t   b_cursor;
109
110     boolean_t   b_cursor_autohidden;
111     mtime_t     i_lastmoved;
112
113     char       *p_directx_buf[2];                      /* Buffer information */
114
115 } vout_sys_t;
116
117 /*****************************************************************************
118  * Local prototypes.
119  *****************************************************************************/
120 static int  vout_Probe     ( probedata_t *p_data );
121 static int  vout_Create    ( struct vout_thread_s * );
122 static int  vout_Init      ( struct vout_thread_s * );
123 static void vout_End       ( struct vout_thread_s * );
124 static void vout_Destroy   ( struct vout_thread_s * );
125 static int  vout_Manage    ( struct vout_thread_s * );
126 static void vout_Display   ( struct vout_thread_s * );
127 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
128                              u16 *blue, u16 *transp );
129
130 static int  DirectXCreateWindow   ( vout_thread_t *p_vout );
131 static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
132 static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
133 static int  DirectXCreateSurface  ( vout_thread_t *p_vout );
134 static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
135 static int  DirectXUpdateOverlay  ( vout_thread_t *p_vout );
136 static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
137 static void DirectXCloseWindow    ( vout_thread_t *p_vout );
138 static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
139 static void DirectXCloseSurface   ( vout_thread_t *p_vout );
140 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates );
141
142 /*****************************************************************************
143  * Functions exported as capabilities. They are declared as static so that
144  * we don't pollute the namespace too much.
145  *****************************************************************************/
146 void _M( vout_getfunctions )( function_list_t * p_function_list )
147 {
148     p_function_list->pf_probe = vout_Probe;
149     p_function_list->functions.vout.pf_create     = vout_Create;
150     p_function_list->functions.vout.pf_init       = vout_Init;
151     p_function_list->functions.vout.pf_end        = vout_End;
152     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
153     p_function_list->functions.vout.pf_manage     = vout_Manage;
154     p_function_list->functions.vout.pf_display    = vout_Display;
155     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
156 }
157
158 /*****************************************************************************
159  * vout_Probe: probe the video driver and return a score
160  *****************************************************************************
161  * This function tries to initialize Windows DirectX and returns a score to
162  * the plugin manager so that it can select the best plugin.
163  *****************************************************************************/
164 static int vout_Probe( probedata_t *p_data )
165 {
166
167     if( TestMethod( VOUT_METHOD_VAR, "directx" ) )
168     {
169         return( 999 );
170     }
171
172     /* Check that at least DirectX5 is installed on the computer */
173     /* Fixme */
174
175     return( 400 );
176 }
177
178 /*****************************************************************************
179  * vout_Create: allocate DirectX video thread output method
180  *****************************************************************************
181  * This function allocates and initialize the DirectX vout method.
182  *****************************************************************************/
183 static int vout_Create( vout_thread_t *p_vout )
184 {
185     /* Allocate structure */
186     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
187     if( p_vout->p_sys == NULL )
188     {
189         intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
190         return( 1 );
191     }
192
193     /* Initialisations */
194     p_vout->p_sys->p_ddobject = NULL;
195     p_vout->p_sys->p_display = NULL;
196     p_vout->p_sys->p_surface = NULL;
197     p_vout->p_sys->p_clipper = NULL;
198     p_vout->p_sys->hbrush = NULL;
199     p_vout->p_sys->hwnd = NULL;
200     p_vout->p_sys->b_display_enabled = 0;
201     p_vout->b_need_render = 0;      /* by default try an YUV overlay display */
202
203     p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
204
205     p_vout->p_sys->b_cursor_autohidden = 0;
206     p_vout->p_sys->i_lastmoved = mdate();
207
208     p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
209                                                 VOUT_FULLSCREEN_DEFAULT );
210     p_vout->p_sys->b_overlay = main_GetIntVariable( VOUT_OVERLAY_VAR,
211                                                     VOUT_OVERLAY_DEFAULT );
212     p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR,
213                                                          VOUT_WIDTH_DEFAULT );
214     p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
215                                                          VOUT_HEIGHT_DEFAULT );
216     /* We don't know yet the dimensions of the video so the best guess is to
217      * pick the same as the window */
218     p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width;
219     p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height;
220
221     /* Create a window for the video */
222     /* Creating a window under Windows also initializes the thread's event
223      * message qeue */
224     if( DirectXCreateWindow( p_vout ) )
225     {
226         intf_ErrMsg( "vout error: can't create window" );
227         free( p_vout->p_sys );
228         return ( 1 );
229     }
230
231     /* Initialise DirectDraw */
232     if( DirectXInitDDraw( p_vout ) )
233     {
234         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
235         DirectXCloseWindow( p_vout );
236         free( p_vout->p_sys );
237         return ( 1 );
238     }
239
240     /* Create the directx display */
241     if( DirectXCreateDisplay( p_vout ) )
242     {
243         intf_ErrMsg( "vout error: can't initialise DirectDraw" );
244         DirectXCloseDDraw( p_vout );
245         DirectXCloseWindow( p_vout );
246         free( p_vout->p_sys );
247         return ( 1 );
248     }
249
250     return( 0 );
251 }
252
253 /*****************************************************************************
254  * vout_Init: initialize DirectX video thread output method
255  *****************************************************************************
256  *
257  *****************************************************************************/
258 static int vout_Init( vout_thread_t *p_vout )
259 {
260     return( 0 );
261 }
262
263 /*****************************************************************************
264  * vout_End: terminate Sys video thread output method
265  *****************************************************************************
266  * Terminate an output method created by vout_Create.
267  * It is called at the end of the thread.
268  *****************************************************************************/
269 static void vout_End( vout_thread_t *p_vout )
270 {
271     return;
272 }
273
274 /*****************************************************************************
275  * vout_Destroy: destroy Sys video thread output method
276  *****************************************************************************
277  * Terminate an output method created by vout_Create
278  *****************************************************************************/
279 static void vout_Destroy( vout_thread_t *p_vout )
280 {
281     intf_WarnMsg( 3, "vout: vout_Destroy" );
282     DirectXCloseDisplay( p_vout );
283     DirectXCloseDDraw( p_vout );
284     DirectXCloseWindow( p_vout );
285
286     if( p_vout->p_sys != NULL )
287     {
288         free( p_vout->p_sys );
289         p_vout->p_sys = NULL;
290     }
291
292 }
293
294 /*****************************************************************************
295  * vout_Manage: handle Sys events
296  *****************************************************************************
297  * This function should be called regularly by video output thread. It returns
298  * a non null value if an error occured.
299  *****************************************************************************/
300 static int vout_Manage( vout_thread_t *p_vout )
301 {
302     MSG             msg;
303     WINDOWPLACEMENT window_placement;
304     boolean_t       b_dispatch_msg = TRUE;
305
306     while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
307     {
308         switch( msg.message )
309         {
310
311         case WM_CLOSE:
312             intf_WarnMsg( 4, "vout: vout_Manage WM_CLOSE" );
313             p_vout->b_die = 1;
314             break;
315           
316         case WM_QUIT:
317             intf_WarnMsg( 4, "vout: vout_Manage WM_QUIT" );
318             p_main->p_intf->b_die = 1;
319             break;
320           
321         case WM_MOVE:
322             intf_WarnMsg( 3, "vout: vout_Manage WM_MOVE" );
323             if( !p_vout->b_need_render )
324             {
325                 p_vout->i_changes |= VOUT_SIZE_CHANGE;
326             }
327             /* don't create a never ending loop */
328             b_dispatch_msg = FALSE;
329             break;
330           
331         case WM_APP:
332             intf_WarnMsg( 3, "vout: vout_Manage WM_APP" );
333             if( !p_vout->b_need_render )
334             {
335                 p_vout->i_changes |= VOUT_SIZE_CHANGE;
336             }
337             /* don't create a never ending loop */
338             b_dispatch_msg = FALSE;
339             break;
340           
341 #if 0
342         case WM_PAINT:
343             intf_WarnMsg( 4, "vout: vout_Manage WM_PAINT" );
344             break;
345           
346         case WM_ERASEBKGND:
347             intf_WarnMsg( 4, "vout: vout_Manage WM_ERASEBKGND" );
348             break;
349 #endif
350           
351         case WM_MOUSEMOVE:
352             intf_WarnMsg( 4, "vout: vout_Manage WM_MOUSEMOVE" );
353             if( p_vout->p_sys->b_cursor )
354             {
355                 if( p_vout->p_sys->b_cursor_autohidden )
356                 {
357                     p_vout->p_sys->b_cursor_autohidden = 0;
358                     p_vout->p_sys->i_lastmoved = mdate();
359                     ShowCursor( TRUE );
360                 }
361                 else
362                 {
363                     p_vout->p_sys->i_lastmoved = mdate();
364                 }
365             }               
366             break;
367           
368         case WM_KEYDOWN:
369             /* the key events are first processed here. The next
370              * message processed by this main message loop will be the
371              * char translation of the key event */
372             intf_WarnMsg( 3, "vout: vout_Manage WM_KEYDOWN" );
373             switch( msg.wParam )
374             {
375             case VK_ESCAPE:
376             case VK_F12:
377                 p_main->p_intf->b_die = 1;
378                 break;
379             }
380             TranslateMessage(&msg);
381             b_dispatch_msg = FALSE;
382             break;
383           
384         case WM_CHAR:
385             intf_WarnMsg( 3, "vout: vout_Manage WM_CHAR" );
386             switch( msg.wParam )
387             {
388             case 'q':
389             case 'Q':
390                 p_main->p_intf->b_die = 1;
391                 break;
392               
393             case 'f':                                /* switch to fullscreen */
394             case 'F':
395                 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
396                 break;
397               
398             case 'y':                                  /* switch to hard YUV */
399             case 'Y':
400                 p_vout->i_changes |= VOUT_YUV_CHANGE;
401                 break;
402               
403             case 'c':                                    /* toggle grayscale */
404             case 'C':
405                 p_vout->b_grayscale = ! p_vout->b_grayscale;
406                 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
407                 break;
408               
409             case 'i':                                         /* toggle info */
410             case 'I':
411                 p_vout->b_info = ! p_vout->b_info;
412                 p_vout->i_changes |= VOUT_INFO_CHANGE;
413                 break;
414               
415             case 's':                                      /* toggle scaling */
416             case 'S':
417                 p_vout->b_scale = ! p_vout->b_scale;
418                 p_vout->i_changes |= VOUT_SCALE_CHANGE;
419                 break;
420               
421             case ' ':                                    /* toggle interface */
422                 p_vout->b_interface = ! p_vout->b_interface;
423                 p_vout->i_changes |= VOUT_INTF_CHANGE;
424                 break;
425               
426             case '0': network_ChannelJoin( 0 ); break;
427             case '1': network_ChannelJoin( 1 ); break;
428             case '2': network_ChannelJoin( 2 ); break;
429             case '3': network_ChannelJoin( 3 ); break;
430             case '4': network_ChannelJoin( 4 ); break;
431             case '5': network_ChannelJoin( 5 ); break;
432             case '6': network_ChannelJoin( 6 ); break;
433             case '7': network_ChannelJoin( 7 ); break;
434             case '8': network_ChannelJoin( 8 ); break;
435             case '9': network_ChannelJoin( 9 ); break;
436               
437             default:
438                 if( intf_ProcessKey( p_main->p_intf,
439                                      (char )msg.wParam ) )
440                 {
441                     intf_DbgMsg( "unhandled key '%c' (%i)",
442                                  (char)msg.wParam, msg.wParam );
443                 }
444                 break;
445             }
446
447 #if 0          
448         default:
449             intf_WarnMsg( 4, "vout: vout_Manage WM Default %i",
450                           msg.message );
451             break;
452 #endif
453
454         } /* End Switch */
455
456         /* don't create a never ending loop */
457         if( b_dispatch_msg )
458         {
459             TranslateMessage(&msg);
460             DispatchMessage(&msg);
461         }
462         b_dispatch_msg = TRUE;
463
464     } /* End While() */
465
466
467     /*
468      * Scale Change 
469      */
470     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
471     {
472         intf_WarnMsg( 3, "vout: vout_Manage Scale Change" );
473         if( DirectXUpdateOverlay( p_vout ) )
474             /* failed so try again next time */
475             PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
476         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
477     }
478
479     /*
480      * Size Change 
481      */
482     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
483     {
484         intf_WarnMsg( 3, "vout: vout_Manage Size Change" );
485         if( DirectXUpdateOverlay( p_vout ) )
486             /* failed so try again next time */
487             PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0);
488         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
489     }
490
491     /*
492      * YUV Change 
493      */
494     if( p_vout->i_changes & VOUT_YUV_CHANGE )
495     {
496         p_vout->b_need_render = ! p_vout->b_need_render;
497         
498         /* Need to reopen display */
499         DirectXCloseSurface( p_vout );
500         if( DirectXCreateSurface( p_vout ) )
501         {
502           intf_ErrMsg( "error: can't reopen display after YUV change" );
503           return( 1 );
504         }
505
506         /* Repaint the window background (needed by the overlay surface) */
507         if( !p_vout->b_need_render )
508         {
509             InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
510             p_vout->p_sys->b_display_enabled = 1;
511             if( DirectXUpdateOverlay( p_vout ) )
512                 /* failed so try again next time */
513                 PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0);
514         }
515         p_vout->i_changes &= ~VOUT_YUV_CHANGE;
516     }
517
518     /*
519      * Fullscreen change
520      */
521     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
522     {
523         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
524
525         /* We need to switch between Maximized and Normal sized window */
526         window_placement.length = sizeof(WINDOWPLACEMENT);
527         GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
528         if( p_vout->b_fullscreen )
529         {
530             /* Maximized window */
531             window_placement.showCmd = SW_SHOWMAXIMIZED;
532             /* Change window style, no borders and no title bar */
533             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
534
535         }
536         else
537         {
538             /* Normal window */
539             window_placement.showCmd = SW_SHOWNORMAL;
540             /* Change window style, borders and title bar */
541             SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
542                            WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
543         }
544
545         SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
546
547         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
548     }
549
550     /*
551      * Pointer change
552      */
553     if( ! p_vout->p_sys->b_cursor_autohidden &&
554         ( mdate() - p_vout->p_sys->i_lastmoved > 5000000 ) )
555     {
556         /* Hide the mouse automatically */
557         p_vout->p_sys->b_cursor_autohidden = 1;
558         ShowCursor( FALSE );
559     }
560
561     if( p_vout->i_changes & VOUT_CURSOR_CHANGE )
562     {
563         p_vout->p_sys->b_cursor = ! p_vout->p_sys->b_cursor;
564
565         ShowCursor( p_vout->p_sys->b_cursor &&
566                      ! p_vout->p_sys->b_cursor_autohidden );
567
568         p_vout->i_changes &= ~VOUT_CURSOR_CHANGE;
569     }
570
571     return( 0 );
572 }
573
574 /*****************************************************************************
575  * vout_SetPalette: sets an 8 bpp palette
576  *****************************************************************************
577  * This function sets the palette given as an argument. It does not return
578  * anything, but could later send information on which colors it was unable
579  * to set.
580  *****************************************************************************/
581 static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
582                          u16 *blue, u16 *transp)
583 {
584     /* Nothing yet */
585     return;
586 }
587
588 /*****************************************************************************
589  * vout_Display: displays previously rendered output
590  *****************************************************************************
591  * This function send the currently rendered image to the display, wait until
592  * it is displayed and switch the two rendering buffer, preparing next frame.
593  *****************************************************************************/
594 static void vout_Display( vout_thread_t *p_vout )
595 {
596     DDSURFACEDESC ddsd;
597     HRESULT       dxresult;
598     int           i;
599     int           i_image_width;
600     int           i_image_height;
601
602     if( (p_vout->p_sys->p_display == NULL) )
603     {
604         intf_WarnMsg( 3, "vout error: vout_Display no display!!" );
605         return;
606     }
607
608     /* if the size of the decoded pictures has changed then we close the
609      * video surface (which doesn't have the right size anymore). */
610     i_image_width = ( p_vout->p_rendered_pic ) ?
611       p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width;
612     i_image_height = ( p_vout->p_rendered_pic ) ?
613       p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height;
614
615     if( p_vout->p_sys->i_image_width != i_image_width
616         || p_vout->p_sys->i_image_height != i_image_height )
617     {
618         intf_WarnMsg( 3, "vout: video surface size changed" );
619         p_vout->p_sys->i_image_width = i_image_width;
620         p_vout->p_sys->i_image_height = i_image_height;
621         DirectXCloseSurface( p_vout );
622     }
623
624     if( p_vout->b_need_render )
625     {
626         RECT  rect_window;
627         POINT point_window;
628   
629         /* Nothing yet */
630         if( p_vout->p_sys->p_surface == NULL )
631         {
632             intf_WarnMsg( 3, "vout: no video surface, open one..." );
633             if( DirectXCreateSurface( p_vout ) )
634             {
635                 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
636                 return;
637             }
638             /* Display the surface */
639             p_vout->p_sys->b_display_enabled = 1;
640         }
641
642         /* Now get the coordinates of the window. We don't actually want the
643          * window coordinates but these of the usable surface inside the window
644          * By specification GetClientRect will always set rect_window.left and
645          * rect_window.top to 0 because the Client area is always relative to
646          * the container window */
647         GetClientRect(p_vout->p_sys->hwnd, &rect_window);
648         
649         point_window.x = 0;
650         point_window.y = 0;
651         ClientToScreen(p_vout->p_sys->hwnd, &point_window);
652         rect_window.left = point_window.x;
653         rect_window.top = point_window.y;
654         
655         point_window.x = rect_window.right;
656         point_window.y = rect_window.bottom;
657         ClientToScreen(p_vout->p_sys->hwnd, &point_window);
658         rect_window.right = point_window.x;
659         rect_window.bottom = point_window.y;
660
661         /* We want to keep the aspect ratio of the video */
662         if( p_vout->b_scale )
663         {
664             DirectXKeepAspectRatio( p_vout, &rect_window );
665         }
666
667         /* Blit video surface to display */
668         dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display,
669                                            &rect_window,
670                                            p_vout->p_sys->p_surface,
671                                            NULL,
672                                            0, NULL );
673         if( dxresult != DD_OK )
674         {
675             intf_WarnMsg( 3, "vout: could not Blit the surface" );
676             return;
677         }
678
679     }
680     else
681     {
682         /*
683          * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to
684          * render
685          */
686         /* TODO: support for streams other than 4:2:0 */
687
688         if( p_vout->p_sys->p_surface == NULL )
689         {
690             intf_WarnMsg( 3, "vout: no video surface, open one..." );
691             if( DirectXCreateSurface( p_vout ) )
692             {
693                 intf_WarnMsg( 3, "vout: cannot open a new video surface !!" );
694                 return;
695             }
696         }
697
698         /* Lock the overlay surface */
699         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
700         ddsd.dwSize = sizeof(DDSURFACEDESC);
701         dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL,
702                                             &ddsd, DDLOCK_NOSYSLOCK, NULL);
703         if ( dxresult == DDERR_SURFACELOST )
704         {
705             /* Your surface can be lost (thanks to windows) so be sure
706              * to check this and restore it if needed */
707             dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
708             dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
709                                                  NULL, &ddsd, DDLOCK_NOSYSLOCK
710                                                  | DDLOCK_WAIT, NULL);
711         }
712         if( dxresult != DD_OK )
713         {
714             intf_WarnMsg( 3, "vout: could not lock the surface" );
715             return;
716         }
717
718         /* Now we can do the actual image copy.
719          * The copy has to be done line by line because of the special case
720          * when the Pitch does not equal the width of the picture */
721         for( i=0; i < ddsd.dwHeight/2; i++)
722         {
723 #ifdef NONAMELESSUNION
724             /* copy Y, we copy two lines at once */
725             memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch,
726                    p_vout->p_rendered_pic->p_y + i*2*i_image_width,
727                    i_image_width);
728             memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch,
729                    p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
730                    i_image_width);
731             /* then V */
732             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
733                       + i * ddsd.u1.lPitch/2,
734                    p_vout->p_rendered_pic->p_v + i*i_image_width/2,
735                    i_image_width/2);
736             /* and U */
737             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch)
738                       + (ddsd.dwHeight * ddsd.u1.lPitch/4)
739                       + i * ddsd.u1.lPitch/2,
740                    p_vout->p_rendered_pic->p_u + i*i_image_width/2,
741                    i_image_width/2);
742 #else
743             /* copy Y, we copy two lines at once */
744             memcpy(ddsd.lpSurface + i*2*ddsd.lPitch,
745                    p_vout->p_rendered_pic->p_y + i*2*i_image_width,
746                    i_image_width);
747             memcpy(ddsd.lpSurface + (i*2+1)*ddsd.lPitch,
748                    p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width,
749                    i_image_width);
750             /* then V */
751             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
752                       + i * ddsd.lPitch/2,
753                    p_vout->p_rendered_pic->p_v + i*i_image_width/2,
754                    i_image_width/2);
755             /* and U */
756             memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch)
757                       + (ddsd.dwHeight * ddsd.lPitch/4)
758                       + i * ddsd.lPitch/2,
759                    p_vout->p_rendered_pic->p_u + i*i_image_width/2,
760                    i_image_width/2);
761 #endif /* NONAMELESSUNION */
762
763         }
764
765         /* Unlock the Surface */
766         dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
767                                               ddsd.lpSurface );
768
769         /* If display not enabled yet then enable */
770         if( !p_vout->p_sys->b_display_enabled )
771         {
772             p_vout->p_sys->b_display_enabled = 1;
773             DirectXUpdateOverlay( p_vout );
774         }
775
776     }
777
778     /* The first time this function is called it enables the display */
779     p_vout->p_sys->b_display_enabled = 1;
780
781 }
782
783
784 /* following functions are local */
785
786
787 /*****************************************************************************
788  * DirectXEventProc: This is the window event processing function.
789  *****************************************************************************
790  * On Windows, when you create a window you have to attach an event processing
791  * function to it. The aim of this function is to manage "Queued Messages" and
792  * "Nonqueued Messages".
793  * Queued Messages are those picked up and retransmitted by vout_Manage
794  * (using the GetMessage function).
795  * Nonqueued Messages are those that Windows will send directly to this
796  * function (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
797  *****************************************************************************/
798 long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
799                                   WPARAM wParam, LPARAM lParam )
800 {
801     switch( message )
802     {
803
804 #if 0
805     case WM_APP:
806         intf_WarnMsg( 3, "vout: WinProc WM_APP" );
807         break;
808
809     case WM_ACTIVATE:
810         intf_WarnMsg( 4, "vout: WinProc WM_ACTIVED" );
811         break;
812
813     case WM_CREATE:
814         intf_WarnMsg( 4, "vout: WinProc WM_CREATE" );
815         break;
816
817     /* the user wants to close the window */
818     case WM_CLOSE:
819         intf_WarnMsg( 4, "vout: WinProc WM_CLOSE" );
820         break;
821 #endif
822
823     /* the window has been closed so shut down everything now */
824     case WM_DESTROY:
825         intf_WarnMsg( 4, "vout: WinProc WM_DESTROY" );
826         PostQuitMessage( 0 );
827         break;
828
829     case WM_SYSCOMMAND:
830         switch (wParam)
831         {
832             case SC_SCREENSAVE:                     /* catch the screensaver */
833             case SC_MONITORPOWER:              /* catch the monitor turn-off */
834             intf_WarnMsg( 3, "vout: WinProc WM_SYSCOMMAND" );
835             return 0;                      /* this stops them from happening */
836         }
837         break;
838
839 #if 0
840     case WM_MOVE:
841         intf_WarnMsg( 4, "vout: WinProc WM_MOVE" );
842         break;
843
844     case WM_SIZE:
845         intf_WarnMsg( 4, "vout: WinProc WM_SIZE" );
846         break;
847
848     case WM_MOVING:
849         intf_WarnMsg( 4, "vout: WinProc WM_MOVING" );
850         break;
851
852     case WM_ENTERSIZEMOVE:
853         intf_WarnMsg( 4, "vout: WinProc WM_ENTERSIZEMOVE" );
854         break;
855
856     case WM_SIZING:
857         intf_WarnMsg( 4, "vout: WinProc WM_SIZING" );
858         break;
859 #endif
860
861     case WM_WINDOWPOSCHANGED:
862         intf_WarnMsg( 3, "vout: WinProc WM_WINDOWPOSCHANGED" );
863         PostMessage( hwnd, WM_APP, 0, 0);
864         break;
865
866 #if 0
867     case WM_WINDOWPOSCHANGING:
868         intf_WarnMsg( 3, "vout: WinProc WM_WINDOWPOSCHANGING" );
869         break;
870
871     case WM_PAINT:
872         intf_WarnMsg( 4, "vout: WinProc WM_PAINT" );
873         break;
874
875     case WM_ERASEBKGND:
876         intf_WarnMsg( 4, "vout: WinProc WM_ERASEBKGND" );
877         break;
878
879     default:
880         intf_WarnMsg( 4, "vout: WinProc WM Default %i", message );
881         break;
882 #endif
883     }
884
885     return DefWindowProc(hwnd, message, wParam, lParam);
886 }
887
888 /*****************************************************************************
889  * DirectXCreateWindow: create a windows window where the video will play.
890  *****************************************************************************
891  * Before creating a direct draw surface, we need to create a window in which
892  * the video will be displayed. This window will also allow us to capture the
893  * events.
894  *****************************************************************************/
895 static int DirectXCreateWindow( vout_thread_t *p_vout )
896 {
897     HINSTANCE  hInstance;
898     WNDCLASSEX wc;                                /* window class components */
899     RECT       rect_window;
900     COLORREF   colorkey; 
901     HDC        hdc;
902
903     intf_WarnMsg( 3, "vout: WinDX WinDXCreateWindow" );
904
905     /* get this module's instance */
906     hInstance = GetModuleHandle(NULL);
907
908     /* Create a BRUSH that will be used by Windows to paint the window
909      * background.
910      * This window background is important for us as it will be used by the
911      * graphics card to display the overlay.
912      * This is why we carefully choose the color for this background, the goal
913      * being to choose a color which isn't complete black but nearly. We
914      * obviously don't want to use black as a colorkey for the overlay because
915      * black is one of the most used color and thus would give us undesirable
916      * effects */
917     /* the first step is to find the colorkey we want to use. The difficulty
918      * comes from the potential dithering (depends on the display depth)
919      * because we need to know the real RGB value of the chosen colorkey */
920     hdc = GetDC( GetDesktopWindow() );
921     for( colorkey = 5; colorkey < 0xFF /*all shades of red*/; colorkey++ )
922     {
923         if( colorkey == GetNearestColor( hdc, colorkey ) )
924           break;
925     }
926     intf_WarnMsg(3,"vout: DirectXCreateWindow background color:%i", colorkey);
927     ReleaseDC( p_vout->p_sys->hwnd, hdc );
928
929     /* create the actual brush */  
930     p_vout->p_sys->hbrush = CreateSolidBrush(colorkey);
931     p_vout->p_sys->i_colorkey = (int)colorkey;
932
933     /* fill in the window class structure */
934     wc.cbSize        = sizeof(WNDCLASSEX);
935     wc.style         = 0;                               /* no special styles */
936     wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;           /* event handler */
937     wc.cbClsExtra    = 0;                             /* no extra class data */
938     wc.cbWndExtra    = 0;                            /* no extra window data */
939     wc.hInstance     = hInstance;                                /* instance */
940     wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION); /* load the vlc icon */
941     wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
942     wc.hbrBackground = p_vout->p_sys->hbrush;            /* background color */
943     wc.lpszMenuName  = NULL;                                      /* no menu */
944     wc.lpszClassName = "VLC DirectX";                 /* use a special class */
945     wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION); /* load the vlc icon */
946
947     /* register the window class */
948     if (!RegisterClassEx(&wc))
949     {
950         intf_WarnMsg( 3, "vout: DirectXCreateWindow register window FAILED" );
951         return (1);
952     }
953
954     /* when you create a window you give the dimensions you wish it to have.
955      * Unfortunatly these dimensions will include the borders and title bar.
956      * We use the following function to find out the size of the window
957      * corresponding to the useable surface we want */
958     rect_window.top    = 10;
959     rect_window.left   = 10;
960     rect_window.right  = rect_window.left + p_vout->p_sys->i_window_width;
961     rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
962     AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
963
964     /* create the window */
965     p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
966                     "VLC DirectX",                  /* window title bar text */
967                     WS_OVERLAPPEDWINDOW
968                     | WS_SIZEBOX | WS_VISIBLE,               /* window style */
969                     10,                              /* default X coordinate */
970                     10,                              /* default Y coordinate */
971                     rect_window.right - rect_window.left,    /* window width */
972                     rect_window.bottom - rect_window.top,   /* window height */
973                     NULL,                                /* no parent window */
974                     NULL,                          /* no menu in this window */
975                     hInstance,            /* handle of this program instance */
976                     NULL);                        /* no additional arguments */
977
978     if (p_vout->p_sys->hwnd == NULL) {
979         intf_WarnMsg( 3, "vout: DirectXCreateWindow create window FAILED" );
980         return (1);
981     }
982
983     /* now display the window */
984     ShowWindow(p_vout->p_sys->hwnd, SW_SHOW);
985
986     return ( 0 );
987 }
988
989 /*****************************************************************************
990  * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
991  *****************************************************************************
992  * This function initialise and allocate resources for DirectDraw.
993  *****************************************************************************/
994 static int DirectXInitDDraw( vout_thread_t *p_vout )
995 {
996     HRESULT    dxresult;
997     HRESULT    (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
998     LPDIRECTDRAW  p_ddobject;
999
1000     intf_WarnMsg( 3, "vout: DirectXInitDDraw" );
1001
1002     /* load direct draw DLL */
1003     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
1004     if( p_vout->p_sys->hddraw_dll == NULL )
1005     {
1006         intf_WarnMsg( 3, "vout: DirectXInitDDraw failed loading ddraw.dll" );
1007         return( 1 );
1008     }
1009       
1010     OurDirectDrawCreate = 
1011       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
1012     if ( OurDirectDrawCreate == NULL )
1013     {
1014         intf_ErrMsg( "vout error: DirectXInitDDraw failed GetProcAddress" );
1015         FreeLibrary( p_vout->p_sys->hddraw_dll );
1016         p_vout->p_sys->hddraw_dll = NULL;
1017         return( 1 );    
1018     }
1019
1020     /* Initialize DirectDraw now */
1021     dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
1022     if( dxresult != DD_OK )
1023     {
1024         intf_ErrMsg( "vout error: DirectXInitDDraw can't initialize DDraw" );
1025         p_vout->p_sys->p_ddobject = NULL;
1026         FreeLibrary( p_vout->p_sys->hddraw_dll );
1027         p_vout->p_sys->hddraw_dll = NULL;
1028         return( 1 );
1029     }
1030
1031     /* Set DirectDraw Cooperative level, ie what control we want over Windows
1032      * display */
1033     dxresult = IDirectDraw_SetCooperativeLevel( p_ddobject,
1034                                            p_vout->p_sys->hwnd, DDSCL_NORMAL );
1035     if( dxresult != DD_OK )
1036     {
1037         intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
1038         IDirectDraw_Release( p_ddobject );
1039         p_vout->p_sys->p_ddobject = NULL;
1040         FreeLibrary( p_vout->p_sys->hddraw_dll );
1041         p_vout->p_sys->hddraw_dll = NULL;
1042         return( 1 );
1043     }
1044
1045     /* Get the IDirectDraw2 interface */
1046     dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
1047                                         (LPVOID *)&p_vout->p_sys->p_ddobject );
1048     if( dxresult != DD_OK )
1049     {
1050         intf_ErrMsg( "vout error: can't get IDirectDraw2 interface." );
1051         IDirectDraw_Release( p_ddobject );
1052         p_vout->p_sys->p_ddobject = NULL;
1053         FreeLibrary( p_vout->p_sys->hddraw_dll );
1054         p_vout->p_sys->hddraw_dll = NULL;
1055         return( 1 );
1056     }
1057     else
1058     {
1059         /* Release the unused interface */
1060         IDirectDraw_Release( p_ddobject );
1061     }
1062
1063     return( 0 );
1064 }
1065
1066 /*****************************************************************************
1067  * DirectXCreateDisplay: create the DirectDraw display.
1068  *****************************************************************************
1069  * Create and initialize display according to preferences specified in the vout
1070  * thread fields.
1071  *****************************************************************************/
1072 static int DirectXCreateDisplay( vout_thread_t *p_vout )
1073 {
1074     HRESULT              dxresult;
1075     DDSURFACEDESC        ddsd;
1076     LPDIRECTDRAWSURFACE  p_display;
1077     DDPIXELFORMAT        ddpfPixelFormat;
1078
1079     intf_WarnMsg( 3, "vout: DirectXCreateDisplay" );
1080
1081     /* Now create the primary surface. This surface is what you actually see
1082      * on your screen */
1083     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1084     ddsd.dwSize = sizeof(DDSURFACEDESC);
1085     ddsd.dwFlags = DDSD_CAPS;
1086     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1087
1088     dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
1089                                            &ddsd,
1090                                            &p_display, NULL );
1091     if( dxresult != DD_OK )
1092     {
1093         intf_ErrMsg( "vout error: can't create direct draw primary surface." );
1094         p_vout->p_sys->p_display = NULL;
1095         return( 1 );
1096     }
1097
1098     dxresult = IDirectDrawSurface_QueryInterface( p_display,
1099                                          &IID_IDirectDrawSurface3,
1100                                          (LPVOID *)&p_vout->p_sys->p_display );
1101     if ( dxresult != DD_OK )
1102     {
1103         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
1104         IDirectDrawSurface_Release( p_display );
1105         p_vout->p_sys->p_display = NULL;
1106         return( 1 );
1107     }
1108     else
1109     {
1110         /* Release the old interface */
1111         IDirectDrawSurface_Release( p_display );
1112     }
1113
1114
1115     /* We need to fill in some information for the video output thread.
1116      * We do this here because it must be done before the video_output
1117      * thread enters its main loop - and DirectXCreateSurface can be called
1118      * after that ! */
1119     ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1120     IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
1121                                         &ddpfPixelFormat );
1122 #ifdef NONAMELESSUNION
1123     p_vout->i_screen_depth =    ddpfPixelFormat.u1.dwRGBBitCount;
1124     p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8;
1125     
1126     p_vout->i_red_mask =        ddpfPixelFormat.u2.dwRBitMask;
1127     p_vout->i_green_mask =      ddpfPixelFormat.u3.dwGBitMask;
1128     p_vout->i_blue_mask =       ddpfPixelFormat.u4.dwBBitMask;
1129 #else
1130     p_vout->i_screen_depth =    ddpfPixelFormat.dwRGBBitCount;
1131     p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8;
1132
1133     p_vout->i_red_mask =        ddpfPixelFormat.dwRBitMask;
1134     p_vout->i_green_mask =      ddpfPixelFormat.dwGBitMask;
1135     p_vout->i_blue_mask =       ddpfPixelFormat.dwBBitMask;
1136 #endif /* NONAMELESSUNION */
1137
1138     /* Create a video surface. This function will try to create an
1139      * YUV overlay first and if it can't it will create a simple RGB surface */
1140     if( DirectXCreateSurface( p_vout ) )
1141     {
1142         intf_ErrMsg( "vout error: can't create a video surface." );
1143         IDirectDrawSurface3_Release( p_vout->p_sys->p_display );
1144         p_vout->p_sys->p_display = NULL;
1145         return( 1 );
1146     }
1147       
1148     return( 0 );
1149 }
1150
1151 /*****************************************************************************
1152  * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
1153  *****************************************************************************
1154  * The best method of display is with an YUV overlay because the YUV->RGB
1155  * conversion is done in hardware, so we'll try to create this surface first.
1156  * If we fail, we'll try to create a plain RGB surface.
1157  * ( Maybe we could also try an RGB overlay surface, which could have hardware
1158  * scaling and which would also be faster in window mode because you don't
1159  * need to do any blitting to the main display...)
1160  *****************************************************************************/
1161 static int DirectXCreateSurface( vout_thread_t *p_vout )
1162 {
1163     HRESULT dxresult;
1164     DDSURFACEDESC ddsd;
1165     LPDIRECTDRAWSURFACE p_surface;
1166     DDCAPS ddcaps;
1167
1168     intf_WarnMsg( 3, "vout: DirectXCreateSurface" );
1169
1170     /* Disable display */
1171     p_vout->p_sys->b_display_enabled = 0;
1172
1173 #if 1
1174     /* Probe the capabilities of the hardware */
1175     /* This is just an indication of whether or not we'll support overlay,
1176      * but with this test we don't know if we support YUV overlay */
1177     memset( &ddcaps, 0, sizeof( DDCAPS ));
1178     ddcaps.dwSize = sizeof(DDCAPS);
1179     dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
1180                                      &ddcaps, NULL );
1181     if(dxresult != DD_OK )
1182     {
1183         intf_WarnMsg( 3,"vout error: can't get caps." );
1184     }
1185     else
1186     {
1187         BOOL bHasOverlay, bHasColorKey, bCanStretch;
1188
1189         /* Determine if the hardware supports overlay surfaces */
1190         bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) ==
1191                        DDCAPS_OVERLAY) ? TRUE : FALSE;
1192         /* Determine if the hardware supports colorkeying */
1193         bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) ==
1194                         DDCAPS_COLORKEY) ? TRUE : FALSE;
1195         /* Determine if the hardware supports scaling of the overlay surface */
1196         bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ==
1197                        DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
1198         intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i",
1199                          bHasOverlay, bHasColorKey, bCanStretch );
1200
1201 #if 0
1202         if( !bHasOverlay ) p_vout->b_need_render = 1;
1203 #endif
1204     }
1205 #endif
1206
1207
1208     /* Create the video surface */
1209     if( !p_vout->b_need_render )
1210     {
1211         /* Now try to create the YUV overlay surface.
1212          * This overlay will be displayed on top of the primary surface.
1213          * A color key is used to determine whether or not the overlay will be
1214          * displayed, ie the overlay will be displayed in place of the primary
1215          * surface wherever the primary surface will have this color.
1216          * The video window has been created with a background of this color so
1217          * the overlay will be only displayed on top of this window */
1218
1219         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1220         ddsd.dwSize = sizeof(DDSURFACEDESC);
1221         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1222         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
1223         ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
1224 #ifdef NONAMELESSUNION
1225         ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
1226 #else
1227         ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
1228 #endif
1229         ddsd.dwFlags = DDSD_CAPS |
1230                        DDSD_HEIGHT |
1231                        DDSD_WIDTH |
1232                        DDSD_PIXELFORMAT;
1233         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
1234         ddsd.dwHeight =  p_vout->p_sys->i_image_height;
1235         ddsd.dwWidth =  p_vout->p_sys->i_image_width;
1236         ddsd.dwBackBufferCount = 1;                       /* One back buffer */
1237
1238         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
1239                                                &ddsd, &p_surface, NULL );
1240         if( dxresult == DD_OK )
1241         {
1242             intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" );
1243         }
1244         else
1245         {
1246             intf_ErrMsg( "vout error: can't create YUV overlay surface." );
1247             p_vout->b_need_render = 1;
1248         }
1249     }
1250
1251     if( p_vout->b_need_render )
1252     {
1253         /* Now try to create a plain RGB surface. */
1254         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1255         ddsd.dwSize = sizeof(DDSURFACEDESC);
1256         ddsd.dwFlags = DDSD_HEIGHT |
1257                        DDSD_WIDTH |
1258                        DDSD_CAPS;
1259         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1260         ddsd.dwHeight =  p_vout->p_sys->i_image_height;
1261         ddsd.dwWidth =  p_vout->p_sys->i_image_width;
1262
1263         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
1264                                                &ddsd, &p_surface, NULL );
1265         if( dxresult == DD_OK )
1266         {
1267             intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
1268         }
1269         else
1270         {
1271             intf_ErrMsg( "vout error: can't create RGB surface." );
1272             p_vout->p_sys->p_surface = NULL;
1273             return( 1 );
1274         }
1275     }
1276       
1277     /* Now that the surface is created, try to get a newer DirectX interface */
1278     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
1279                                          &IID_IDirectDrawSurface3,
1280                                          (LPVOID *)&p_vout->p_sys->p_surface );
1281     if ( dxresult != DD_OK )
1282     {
1283         intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." );
1284         IDirectDrawSurface_Release( p_surface );
1285         p_vout->p_sys->p_surface = NULL;
1286         return( 1 );
1287     }
1288     else
1289     {
1290         /* Release the old interface */
1291         IDirectDrawSurface_Release( p_surface );
1292     }
1293
1294     if( !p_vout->b_need_render )
1295     {
1296         /* Hide the overlay for now */
1297         IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
1298                                           NULL,
1299                                           p_vout->p_sys->p_display,
1300                                           NULL,
1301                                           DDOVER_HIDE,
1302                                           NULL);
1303     }
1304     else
1305     {
1306          DirectXCreateClipper( p_vout );
1307     }
1308
1309
1310     /* From now on, do some initialisation for video_output */
1311
1312     /* if we want a valid pointer to the surface memory, we must lock
1313      * the surface */
1314
1315     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1316     ddsd.dwSize = sizeof(DDSURFACEDESC);
1317     dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd,
1318                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
1319     if ( dxresult == DDERR_SURFACELOST )
1320     {
1321         /* Your surface can be lost so be sure
1322          * to check this and restore it if needed */
1323         dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface );
1324         dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface,
1325                                              NULL, &ddsd, DDLOCK_NOSYSLOCK
1326                                              | DDLOCK_WAIT, NULL);
1327     }
1328     if( dxresult != DD_OK )
1329     {
1330         intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" );
1331         return( 1 );
1332     }
1333
1334     /* Set the pointer to the surface memory */
1335     p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface;
1336     /* back buffer, none for now */
1337     p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface;
1338
1339     /* Set thread information */
1340     p_vout->i_width =  ddsd.dwWidth;
1341     p_vout->i_height = ddsd.dwHeight;
1342 #ifdef NONAMELESSUNION
1343     p_vout->i_bytes_per_line =  ddsd.u1.lPitch;
1344 #else
1345     p_vout->i_bytes_per_line =  ddsd.lPitch;
1346 #endif /* NONAMELESSUNION */
1347
1348
1349     if( p_vout->b_need_render )
1350     {
1351         /* For an RGB surface we need to fill in some more info */
1352 #ifdef NONAMELESSUNION
1353         p_vout->i_screen_depth =    ddsd.ddpfPixelFormat.u1.dwRGBBitCount;
1354         p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8;
1355
1356         p_vout->i_red_mask =        ddsd.ddpfPixelFormat.u2.dwRBitMask;
1357         p_vout->i_green_mask =      ddsd.ddpfPixelFormat.u3.dwGBitMask;
1358         p_vout->i_blue_mask =       ddsd.ddpfPixelFormat.u4.dwBBitMask;
1359 #else
1360         p_vout->i_screen_depth =    ddsd.ddpfPixelFormat.dwRGBBitCount;
1361         p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8;
1362
1363         p_vout->i_red_mask =        ddsd.ddpfPixelFormat.dwRBitMask;
1364         p_vout->i_green_mask =      ddsd.ddpfPixelFormat.dwGBitMask;
1365         p_vout->i_blue_mask =       ddsd.ddpfPixelFormat.dwBBitMask;
1366
1367 #endif /* NONAMELESSUNION */
1368     }
1369
1370     /* Unlock the Surface */
1371     dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface,
1372                                           ddsd.lpSurface );
1373
1374     /* Set and initialize buffers */
1375     p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ],
1376                            p_vout->p_sys->p_directx_buf[ 1 ] );
1377
1378
1379     return ( 0 );
1380 }
1381
1382
1383 /*****************************************************************************
1384  * DirectXCreateClipper: Create a clipper that will be used when blitting the
1385  *                       RGB surface to the main display.
1386  *****************************************************************************
1387  * This clipper prevents us to modify by mistake anything on the screen
1388  * which doesn't belong to our window. For example when a part of our video
1389  * window is hidden by another window.
1390  *****************************************************************************/
1391 static int DirectXCreateClipper( vout_thread_t *p_vout )
1392 {
1393     HRESULT dxresult;
1394
1395     intf_WarnMsg( 3, "vout: DirectXCreateClipper" );
1396
1397     /* Create the clipper */
1398     dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
1399                                            &p_vout->p_sys->p_clipper, NULL );
1400     if( dxresult != DD_OK )
1401     {
1402         intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." );
1403         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1404         p_vout->p_sys->p_clipper = NULL;
1405         return( 1 );
1406     }
1407     
1408     /* associate the clipper to the window */
1409     dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
1410                                           p_vout->p_sys->hwnd);
1411     if( dxresult != DD_OK )
1412     {
1413         intf_WarnMsg( 3,
1414             "vout: DirectXCreateClipper can't attach clipper to window." );
1415         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1416         p_vout->p_sys->p_clipper = NULL;
1417         return( 1 );
1418     }
1419     
1420     /* associate the clipper with the surface */
1421     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
1422                                              p_vout->p_sys->p_clipper);
1423     if( dxresult != DD_OK )
1424     {
1425         intf_WarnMsg( 3,
1426             "vout: DirectXCreateClipper can't attach clipper to surface." );
1427         IDirectDrawSurface_Release( p_vout->p_sys->p_clipper );
1428         p_vout->p_sys->p_clipper = NULL;
1429         return( 1 );
1430     }    
1431      
1432     return( 0 );
1433 }
1434
1435
1436 /*****************************************************************************
1437  * DirectXUpdateOverlay: Move or resize overlay surface on video display.
1438  *****************************************************************************
1439  * This function is used to move or resize an overlay surface on the screen.
1440  * Ususally the overlay is moved by the user and thus, by a move or resize
1441  * event (in vout_Manage).
1442  *****************************************************************************/
1443 static int DirectXUpdateOverlay( vout_thread_t *p_vout )
1444 {
1445     DDOVERLAYFX     ddofx;
1446     RECT            rect_window, rect_window_backup, rect_image;
1447     POINT           point_window;
1448     DWORD           dwFlags;
1449     HRESULT         dxresult;
1450     DWORD           dw_colorkey;
1451     DDPIXELFORMAT   pixel_format;
1452     DDSURFACEDESC   ddsd;
1453
1454     if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render )
1455     {
1456         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" );
1457         return( 0 );
1458     }
1459
1460     if( !p_vout->p_rendered_pic )
1461     {
1462         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" );
1463         return( 1 );
1464     }
1465
1466     if( !p_vout->p_sys->b_display_enabled )
1467     {
1468         return( 0 );
1469     }
1470
1471     /* Now get the coordinates of the window. We don't actually want the
1472      * window coordinates but these of the usable surface inside the window.
1473      * By specification GetClientRect will always set rect_window.left and
1474      * rect_window.top to 0 because the Client area is always relative to the
1475      * container window */
1476     GetClientRect(p_vout->p_sys->hwnd, &rect_window);
1477
1478     point_window.x = 0;
1479     point_window.y = 0;
1480     ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1481     rect_window.left = point_window.x;
1482     rect_window.top = point_window.y;
1483
1484     point_window.x = rect_window.right;
1485     point_window.y = rect_window.bottom;
1486     ClientToScreen(p_vout->p_sys->hwnd, &point_window);
1487     rect_window.right = point_window.x;
1488     rect_window.bottom = point_window.y;
1489
1490
1491     /* We want to keep the aspect ratio of the video */
1492     if( p_vout->b_scale )
1493     {
1494         DirectXKeepAspectRatio( p_vout, &rect_window );
1495     }
1496
1497     /* It seems we can't feed the UpdateOverlay directdraw function with
1498      * negative values so we have to clip the computed rectangles */
1499     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
1500     ddsd.dwSize = sizeof(DDSURFACEDESC);
1501     ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
1502     IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd );
1503
1504     rect_window_backup = rect_window;
1505
1506     /* Clip the destination window */
1507     rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left;
1508     rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right;
1509     rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top;
1510     rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom;
1511
1512     rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth
1513       : rect_window.left;
1514     rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth
1515       : rect_window.right;
1516     rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight
1517       : rect_window.top;
1518     rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight
1519       : rect_window.bottom;
1520
1521     intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i",
1522                   rect_window.left, rect_window.top,
1523                   rect_window.right, rect_window.bottom);
1524
1525     /* the 2 following lines are to fix a bug when click on Windows desktop */
1526     if( (rect_window.right-rect_window.left)==0 ||
1527         (rect_window.bottom-rect_window.top)==0 ) return 0;
1528
1529     /* Clip the source image */
1530     rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0
1531       : labs(rect_window_backup.left - rect_window.left) *
1532       p_vout->p_rendered_pic->i_width /
1533       (rect_window_backup.right - rect_window_backup.left);
1534     rect_image.right = ( rect_window.right == rect_window_backup.right ) ?
1535       p_vout->p_rendered_pic->i_width
1536       : p_vout->p_rendered_pic->i_width -
1537       labs(rect_window_backup.right - rect_window.right) *
1538       p_vout->p_rendered_pic->i_width /
1539       (rect_window_backup.right - rect_window_backup.left);
1540     rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0
1541       : labs(rect_window_backup.top - rect_window.top) *
1542       p_vout->p_rendered_pic->i_height /
1543       (rect_window_backup.bottom - rect_window_backup.top);
1544     rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ?
1545       p_vout->p_rendered_pic->i_height
1546       : p_vout->p_rendered_pic->i_height -
1547       labs(rect_window_backup.bottom - rect_window.bottom) *
1548       p_vout->p_rendered_pic->i_height /
1549       (rect_window_backup.bottom - rect_window_backup.top);
1550
1551     intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i",
1552                   rect_image.left, rect_image.top,
1553                   rect_image.right, rect_image.bottom);
1554
1555     /* compute the colorkey pixel value from the RGB value we've got */
1556     memset( &pixel_format, 0, sizeof( DDPIXELFORMAT ));
1557     pixel_format.dwSize = sizeof( DDPIXELFORMAT );
1558     dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
1559                                                    &pixel_format );
1560     if( dxresult != DD_OK )
1561         intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" );
1562     dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey;
1563 #ifdef NONAMELESSUNION
1564     dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255)
1565                           & pixel_format.u2.dwRBitMask);
1566 #else
1567     dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255)
1568                           & pixel_format.dwRBitMask);
1569 #endif
1570
1571     /* Position and show the overlay */
1572     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
1573     ddofx.dwSize = sizeof(DDOVERLAYFX);
1574     ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey;
1575     ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey;
1576
1577     dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
1578
1579     dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface,
1580                                                  &rect_image,
1581                                                  p_vout->p_sys->p_display,
1582                                                  &rect_window,
1583                                                  dwFlags,
1584                                                  &ddofx);
1585     if(dxresult != DD_OK)
1586     {
1587         intf_WarnMsg( 3,
1588           "vout: DirectXUpdateOverlay can't move or resize overlay" );
1589     }
1590
1591     return ( 0 );
1592 }
1593
1594 /*****************************************************************************
1595  * DirectXCloseWindow: close the window created by DirectXCreateWindow
1596  *****************************************************************************
1597  * This function returns all resources allocated by DirectXCreateWindow.
1598  *****************************************************************************/
1599 static void DirectXCloseWindow( vout_thread_t *p_vout )
1600 {
1601     HINSTANCE hInstance;
1602
1603     intf_WarnMsg( 3, "vout: DirectXCloseWindow" );
1604     if( p_vout->p_sys->hwnd != NULL )
1605     {
1606         DestroyWindow( p_vout->p_sys->hwnd);
1607         p_vout->p_sys->hwnd = NULL;
1608     }
1609
1610     hInstance = GetModuleHandle(NULL);
1611     UnregisterClass( "VLC DirectX",                            /* class name */
1612                      hInstance );          /* handle to application instance */
1613
1614     /* free window background brush */
1615     if( p_vout->p_sys->hwnd != NULL )
1616     {
1617         DeleteObject( p_vout->p_sys->hbrush );
1618         p_vout->p_sys->hbrush = NULL;
1619     }
1620 }
1621
1622 /*****************************************************************************
1623  * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
1624  *****************************************************************************
1625  * This function returns all resources allocated by DirectXInitDDraw.
1626  *****************************************************************************/
1627 static void DirectXCloseDDraw( vout_thread_t *p_vout )
1628 {
1629     intf_WarnMsg(3, "vout: DirectXCloseDDraw" );
1630     if( p_vout->p_sys->p_ddobject != NULL )
1631     {
1632         IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
1633         p_vout->p_sys->p_ddobject = NULL;
1634     }
1635
1636     if( p_vout->p_sys->hddraw_dll != NULL )
1637     {
1638         FreeLibrary( p_vout->p_sys->hddraw_dll );
1639         p_vout->p_sys->hddraw_dll = NULL;
1640     }
1641 }
1642
1643 /*****************************************************************************
1644  * DirectXCloseDisplay: close and reset the DirectX display device
1645  *****************************************************************************
1646  * This function returns all resources allocated by DirectXCreateDisplay.
1647  *****************************************************************************/
1648 static void DirectXCloseDisplay( vout_thread_t *p_vout )
1649 {
1650     intf_WarnMsg( 3, "vout: DirectXCloseDisplay" );
1651     if( p_vout->p_sys->p_display != NULL )
1652     {
1653         DirectXCloseSurface( p_vout );
1654
1655         intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" );
1656         IDirectDraw2_Release( p_vout->p_sys->p_display );
1657         p_vout->p_sys->p_display = NULL;
1658     }
1659 }
1660
1661 /*****************************************************************************
1662  * DirectXCloseSurface: close the YUV overlay or RGB surface.
1663  *****************************************************************************
1664  * This function returns all resources allocated by the surface.
1665  * We also call this function when the decoded picture change its dimensions
1666  * (in that case we close the overlay surface and reopen another with the
1667  * right dimensions).
1668  *****************************************************************************/
1669 static void DirectXCloseSurface( vout_thread_t *p_vout )
1670 {
1671     intf_WarnMsg( 3, "vout: DirectXCloseSurface" );
1672     if( p_vout->p_sys->p_surface != NULL )
1673     {
1674         intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" );
1675         IDirectDraw2_Release( p_vout->p_sys->p_surface );
1676         p_vout->p_sys->p_surface = NULL;
1677     }
1678
1679     if( p_vout->p_sys->p_clipper != NULL )
1680     {
1681         intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" );
1682         IDirectDraw2_Release( p_vout->p_sys->p_clipper );
1683         p_vout->p_sys->p_clipper = NULL;
1684     }
1685
1686     /* Disable any display */
1687     p_vout->p_sys->b_display_enabled = 0;
1688 }
1689
1690 /*****************************************************************************
1691  * DirectXKeepAspectRatio: 
1692  *****************************************************************************
1693  * This function adjusts the coordinates of the video rectangle to keep the
1694  * aspect/ratio of the video.
1695  *****************************************************************************/
1696 static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window )
1697 {
1698
1699   if( !p_vout->p_rendered_pic ) return;
1700
1701   switch( p_vout->p_rendered_pic->i_aspect_ratio )
1702   {
1703       case AR_16_9_PICTURE:
1704       if( ((rect_window->right-rect_window->left)*9)
1705           > ((rect_window->bottom-rect_window->top)*16) )
1706       {
1707         int temp;
1708         temp = (rect_window->bottom-rect_window->top)*16/9;
1709         temp = (rect_window->right-rect_window->left) - temp;
1710         rect_window->left += (temp/2);
1711         rect_window->right -= (temp/2);
1712       }
1713       else
1714         {
1715           int temp;
1716           temp = (rect_window->right-rect_window->left)*9/16;
1717           temp = (rect_window->bottom-rect_window->top) - temp;
1718           rect_window->top += (temp/2);
1719           rect_window->bottom -= (temp/2);
1720         }
1721       break;
1722       
1723   case AR_221_1_PICTURE:
1724     if( ((rect_window->right-rect_window->left)*100)
1725         > ((rect_window->bottom-rect_window->top)*221) )
1726       {
1727         int temp;
1728         temp = (rect_window->bottom-rect_window->top)*221/100;
1729         temp = (rect_window->right-rect_window->left) - temp;
1730         rect_window->left += (temp/2);
1731         rect_window->right -= (temp/2);
1732       }
1733     else
1734       {
1735         int temp;
1736         temp = (rect_window->right-rect_window->left)*100/221;
1737         temp = (rect_window->bottom-rect_window->top) - temp;
1738         rect_window->top += (temp/2);
1739         rect_window->bottom -= (temp/2);
1740       }
1741     break;
1742     
1743   case AR_3_4_PICTURE:
1744     if( ((rect_window->right-rect_window->left)*3)
1745         > ((rect_window->bottom-rect_window->top)*4) )
1746       {
1747         int temp;
1748         temp = (rect_window->bottom-rect_window->top)*4/3;
1749         temp = (rect_window->right-rect_window->left) - temp;
1750         rect_window->left += (temp/2);
1751         rect_window->right -= (temp/2);
1752       }
1753     else
1754       {
1755         int temp;
1756         temp = (rect_window->right-rect_window->left)*3/4;
1757         temp = (rect_window->bottom-rect_window->top) - temp;
1758         rect_window->top += (temp/2);
1759         rect_window->bottom -= (temp/2);
1760       }
1761     break;
1762
1763   case AR_SQUARE_PICTURE:
1764   default:
1765     if( (rect_window->right-rect_window->left)
1766         > (rect_window->bottom-rect_window->top) )
1767       {
1768         int temp;
1769         temp = (rect_window->bottom-rect_window->top);
1770         temp = (rect_window->right-rect_window->left) - temp;
1771         rect_window->left += (temp/2);
1772         rect_window->right -= (temp/2);
1773       }
1774     else
1775       {
1776         int temp;
1777         temp = (rect_window->right-rect_window->left);
1778         temp = (rect_window->bottom-rect_window->top) - temp;
1779         rect_window->top += (temp/2);
1780         rect_window->bottom -= (temp/2);
1781       }
1782     break;
1783     
1784   }
1785
1786 }