ntdll: Implement DVD_ReadStructure.
[wine] / dlls / x11drv / desktop.c
1 /*
2  * X11DRV desktop window handling
3  *
4  * Copyright 2001 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include <X11/cursorfont.h>
23 #include <X11/Xlib.h>
24
25 #include "wine/winuser16.h"
26 #include "win.h"
27 #include "ddrawi.h"
28 #include "x11drv.h"
29 #include "x11ddraw.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
33
34
35 /* desktop window procedure */
36 static LRESULT WINAPI desktop_winproc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
37 {
38     switch(message)
39     {
40     case WM_NCCREATE:
41         SystemParametersInfoA( SPI_SETDESKPATTERN, -1, NULL, FALSE );
42         SetDeskWallPaper( (LPSTR)-1 );
43         return TRUE;
44
45     case WM_ERASEBKGND:
46         PaintDesktop( (HDC)wParam );
47         return TRUE;
48
49     case WM_SYSCOMMAND:
50         if ((wParam & 0xfff0) == SC_CLOSE) ExitWindows( 0, 0 );
51         break;
52
53     case WM_SETCURSOR:
54         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
55
56     case WM_NCHITTEST:
57         return HTCLIENT;
58     }
59     return 0;
60 }
61
62
63 /* desktop window manager thread */
64 static DWORD CALLBACK desktop_thread( LPVOID driver_data )
65 {
66     Display *display;
67     MSG msg;
68     HWND hwnd;
69     Atom atom = x11drv_atom(WM_DELETE_WINDOW);
70
71     TlsSetValue( thread_data_tls_index, driver_data );
72     display = thread_display();
73     hwnd = GetDesktopWindow();
74
75     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_winproc );
76     wine_tsx11_lock();
77     XSaveContext( display, root_window, winContext, (char *)hwnd );
78     XChangeProperty ( display, root_window, x11drv_atom(WM_PROTOCOLS),
79                       XA_ATOM, 32, PropModeReplace, (unsigned char *)&atom, 1 );
80     XMapWindow( display, root_window );
81     wine_tsx11_unlock();
82
83     SendMessageW( hwnd, WM_NCCREATE, 0, 0 /* should be CREATESTRUCT */ );
84
85     while (GetMessageW( &msg, hwnd, 0, 0 )) DispatchMessageW( &msg );
86     return 0;
87 }
88
89
90 /***********************************************************************
91  *              X11DRV_create_desktop_thread
92  *
93  * Create the thread that manages the desktop window
94  */
95 void X11DRV_create_desktop_thread(void)
96 {
97     HANDLE handle = CreateThread( NULL, 0, desktop_thread,
98                                   TlsGetValue( thread_data_tls_index ), 0, &desktop_tid );
99     if (!handle)
100     {
101         MESSAGE( "Could not create desktop thread\n" );
102         ExitProcess(1);
103     }
104     /* we transferred our driver data to the new thread */
105     TlsSetValue( thread_data_tls_index, NULL );
106     CloseHandle( handle );
107 }
108
109
110 /* data for resolution changing */
111 static LPDDHALMODEINFO dd_modes;
112 static unsigned int dd_mode_count;
113
114 static unsigned int max_width;
115 static unsigned int max_height;
116
117 static const unsigned int widths[]  = {320, 400, 512, 640, 800, 1024, 1152, 1280, 1400, 1600};
118 static const unsigned int heights[] = {200, 300, 384, 480, 600,  768,  864, 1024, 1050, 1200};
119 #define NUM_DESKTOP_MODES (sizeof(widths) / sizeof(widths[0]))
120
121 /* create the mode structures */
122 static void make_modes(void)
123 {
124     int i;
125     /* original specified desktop size */
126     X11DRV_Settings_AddOneMode(screen_width, screen_height, 0, 0);
127     for (i=0; i<NUM_DESKTOP_MODES; i++)
128     {
129         if ( (widths[i] <= max_width) && (heights[i] <= max_height) )
130         {
131             if ( ( (widths[i] != max_width) || (heights[i] != max_height) ) &&
132                  ( (widths[i] != screen_width) || (heights[i] != screen_height) ) )
133             {
134                 /* only add them if they are smaller than the root window and unique */
135                 X11DRV_Settings_AddOneMode(widths[i], heights[i], 0, 0);
136             }
137         }
138     }
139     if ((max_width != screen_width) && (max_height != screen_height))
140     {
141         /* root window size (if different from desktop window) */
142         X11DRV_Settings_AddOneMode(max_width, max_height, 0, 0);
143     }
144 }
145
146 /***********************************************************************
147  *              X11DRV_resize_desktop
148  *
149  * Reset the desktop window size and WM hints
150  */
151 static int X11DRV_resize_desktop( unsigned int width, unsigned int height )
152 {
153     XSizeHints *size_hints;
154     Display *display = thread_display();
155     Window w = root_window;
156     /* set up */
157     wine_tsx11_lock();
158     size_hints  = XAllocSizeHints();
159     if (!size_hints)
160     {
161         ERR("Not enough memory for window manager hints.\n" );
162         wine_tsx11_unlock();
163         return 0;
164     }
165     size_hints->min_width = size_hints->max_width = width;
166     size_hints->min_height = size_hints->max_height = height;
167     size_hints->flags = PMinSize | PMaxSize | PSize;
168
169     /* do the work */
170     XSetWMNormalHints( display, w, size_hints );
171     XResizeWindow( display, w, width, height );
172
173     /* clean up */
174     XFree( size_hints );
175     XFlush( display );
176     wine_tsx11_unlock();
177     X11DRV_handle_desktop_resize( width, height );
178     return 1;
179 }
180
181 static int X11DRV_desktop_GetCurrentMode(void)
182 {
183     unsigned int i;
184     DWORD dwBpp = screen_depth;
185     if (dwBpp == 24) dwBpp = 32;
186     for (i=0; i<dd_mode_count; i++)
187     {
188         if ( (screen_width == dd_modes[i].dwWidth) &&
189              (screen_height == dd_modes[i].dwHeight) && 
190              (dwBpp == dd_modes[i].dwBPP))
191             return i;
192     }
193     ERR("In unknown mode, returning default\n");
194     return 0;
195 }
196
197 static void X11DRV_desktop_SetCurrentMode(int mode)
198 {
199     DWORD dwBpp = screen_depth;
200     if (dwBpp == 24) dwBpp = 32;
201     TRACE("Resizing Wine desktop window to %ldx%ld\n", dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
202     X11DRV_resize_desktop(dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
203     if (dwBpp != dd_modes[mode].dwBPP)
204     {
205         FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
206     }
207 }
208
209 /***********************************************************************
210  *              X11DRV_create_desktop
211  *
212  * Create the X11 desktop window for the desktop mode.
213  */
214 Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry )
215 {
216     int x = 0, y = 0, flags;
217     unsigned int width = 640, height = 480;  /* Default size = 640x480 */
218     char *name = GetCommandLineA();
219     XSizeHints *size_hints;
220     XWMHints   *wm_hints;
221     XClassHint *class_hints;
222     XSetWindowAttributes win_attr;
223     XTextProperty window_name;
224     Window win;
225     Display *display = thread_display();
226
227     wine_tsx11_lock();
228     flags = XParseGeometry( geometry, &x, &y, &width, &height );
229     max_width = screen_width;
230     max_height = screen_height;
231     screen_width  = width;
232     screen_height = height;
233
234     /* Create window */
235     win_attr.background_pixel = BlackPixel(display, 0);
236     win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
237                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
238     win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );
239
240     if (desktop_vi)
241         win_attr.colormap = XCreateColormap( display, DefaultRootWindow(display),
242                                              visual, AllocNone );
243     else
244         win_attr.colormap = None;
245
246     win = XCreateWindow( display, DefaultRootWindow(display),
247                          x, y, width, height, 0, screen_depth, InputOutput, visual,
248                          CWBackPixel | CWEventMask | CWCursor | CWColormap, &win_attr );
249
250     /* Set window manager properties */
251     size_hints  = XAllocSizeHints();
252     wm_hints    = XAllocWMHints();
253     class_hints = XAllocClassHint();
254     if (!size_hints || !wm_hints || !class_hints)
255     {
256         MESSAGE("Not enough memory for window manager hints.\n" );
257         ExitProcess(1);
258     }
259     size_hints->min_width = size_hints->max_width = width;
260     size_hints->min_height = size_hints->max_height = height;
261     size_hints->flags = PMinSize | PMaxSize;
262     if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
263     if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
264     else size_hints->flags |= PSize;
265
266     wm_hints->flags = InputHint | StateHint;
267     wm_hints->input = True;
268     wm_hints->initial_state = NormalState;
269     class_hints->res_name  = "wine";
270     class_hints->res_class = "Wine";
271
272     XStringListToTextProperty( &name, 1, &window_name );
273     XSetWMProperties( display, win, &window_name, &window_name,
274                       NULL, 0, size_hints, wm_hints, class_hints );
275     XFree( size_hints );
276     XFree( wm_hints );
277     XFree( class_hints );
278     XFlush( display );
279     wine_tsx11_unlock();
280     /* initialize the available resolutions */
281     dd_modes = X11DRV_Settings_SetHandlers("desktop", 
282                                            X11DRV_desktop_GetCurrentMode, 
283                                            X11DRV_desktop_SetCurrentMode, 
284                                            NUM_DESKTOP_MODES+2, 1);
285     make_modes();
286     X11DRV_Settings_AddDepthModes();
287     dd_mode_count = X11DRV_Settings_GetModeCount();
288     X11DRV_Settings_SetDefaultMode(0);
289     return win;
290 }