If using the default values, also set dwType to REG_SZ as our default
[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
24 #include "ts_xlib.h"
25
26 #include "wine/winuser16.h"
27 #include "win.h"
28 #include "ddrawi.h"
29 #include "x11drv.h"
30 #include "x11ddraw.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
34
35
36 /* desktop window procedure */
37 static LRESULT WINAPI desktop_winproc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
38 {
39     switch(message)
40     {
41     case WM_NCCREATE:
42         SystemParametersInfoA( SPI_SETDESKPATTERN, -1, NULL, FALSE );
43         SetDeskWallPaper( (LPSTR)-1 );
44         return TRUE;
45
46     case WM_ERASEBKGND:
47         PaintDesktop( (HDC)wParam );
48         ValidateRect( hwnd, NULL );
49         break;
50
51     case WM_SYSCOMMAND:
52         if ((wParam & 0xfff0) == SC_CLOSE) ExitWindows( 0, 0 );
53         break;
54
55     case WM_SETCURSOR:
56         return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
57
58     case WM_NCHITTEST:
59         return HTCLIENT;
60     }
61     return 0;
62 }
63
64
65 /* desktop window manager thread */
66 static DWORD CALLBACK desktop_thread( LPVOID driver_data )
67 {
68     Display *display;
69     MSG msg;
70     HWND hwnd;
71     WND *win;
72
73     NtCurrentTeb()->driver_data = driver_data;
74     display = thread_display();
75     hwnd = GetDesktopWindow();
76
77     /* patch the desktop window queue to point to our queue */
78     win = WIN_GetPtr( hwnd );
79     win->tid = GetCurrentThreadId();
80     X11DRV_register_window( display, hwnd, win->pDriverData );
81     WIN_ReleasePtr( win );
82
83     SetWindowLongW( hwnd, GWL_WNDPROC, (LONG)desktop_winproc );
84     wine_tsx11_lock();
85     XSetWMProtocols( display, root_window, &wmDeleteWindow, 1 );
86     XMapWindow( display, root_window );
87     wine_tsx11_unlock();
88
89     SendMessageW( hwnd, WM_NCCREATE, 0, 0 /* should be CREATESTRUCT */ );
90
91     while (GetMessageW( &msg, hwnd, 0, 0 )) DispatchMessageW( &msg );
92     return 0;
93 }
94
95
96 /***********************************************************************
97  *              X11DRV_create_desktop_thread
98  *
99  * Create the thread that manages the desktop window
100  */
101 void X11DRV_create_desktop_thread(void)
102 {
103     HANDLE handle = CreateThread( NULL, 0, desktop_thread, NtCurrentTeb()->driver_data,
104                                   0, &desktop_tid );
105     if (!handle)
106     {
107         MESSAGE( "Could not create desktop thread\n" );
108         ExitProcess(1);
109     }
110     /* we transferred our driver data to the new thread */
111     NtCurrentTeb()->driver_data = NULL;
112     CloseHandle( handle );
113 }
114
115
116 /* data for resolution changing */
117 static LPDDHALMODEINFO dd_modes;
118 static unsigned int dd_mode_count;
119
120 static unsigned int max_width;
121 static unsigned int max_height;
122
123 static const unsigned int widths[]  = {320, 512, 640, 800, 1024, 1152, 1280, 1600};
124 static const unsigned int heights[] = {200, 384, 480, 600,  768,  864, 1024, 1200};
125 #define NUM_DESKTOP_MODES (8)
126
127 /* create the mode structures */
128 static void make_modes(void)
129 {
130     int i;
131     /* original specified desktop size */
132     X11DRV_Settings_AddOneMode(screen_width, screen_height, 0, 0);
133     for (i=0; i<NUM_DESKTOP_MODES; i++)
134     {
135         if ( (widths[i] <= max_width) && (heights[i] <= max_height) )
136         {
137             if ( ( (widths[i] != max_width) || (heights[i] != max_height) ) &&
138                  ( (widths[i] != screen_width) || (heights[i] != screen_height) ) )
139             {
140                 /* only add them if they are smaller than the root window and unique */
141                 X11DRV_Settings_AddOneMode(widths[i], heights[i], 0, 0);
142             }
143         }
144     }
145     if ((max_width != screen_width) && (max_height != screen_height))
146     {
147         /* root window size (if different from desktop window) */
148         X11DRV_Settings_AddOneMode(max_width, max_height, 0, 0);
149     }
150 }
151
152 /***********************************************************************
153  *              X11DRV_resize_desktop
154  *
155  * Reset the desktop window size and WM hints
156  */
157 int X11DRV_resize_desktop( unsigned int width, unsigned int height )
158 {
159     XSizeHints *size_hints;
160     Display *display = thread_display();
161     Window w = root_window;
162     /* set up */
163     wine_tsx11_lock();
164     size_hints  = XAllocSizeHints();
165     if (!size_hints)
166     {
167         ERR("Not enough memory for window manager hints.\n" );
168         wine_tsx11_unlock();
169         return 0;
170     }
171     size_hints->min_width = size_hints->max_width = width;
172     size_hints->min_height = size_hints->max_height = height;
173     size_hints->flags = PMinSize | PMaxSize | PSize;
174
175     /* do the work */
176     XSetWMNormalHints( display, w, size_hints );
177     XResizeWindow( display, w, width, height );
178     screen_width  = width;
179     screen_height = height;
180 #if 0 /* FIXME */
181     SYSMETRICS_Set( SM_CXSCREEN, width );
182     SYSMETRICS_Set( SM_CYSCREEN, height );
183 #else
184     FIXME("Need to update SYSMETRICS after resizing display (now %dx%d)\n", 
185           width, height);
186 #endif
187
188     /* clean up */
189     XFree( size_hints );
190     XFlush( display );
191     wine_tsx11_unlock();
192     return 1;
193 }
194
195 int X11DRV_desktop_GetCurrentMode(void)
196 {
197     int i;
198     DWORD dwBpp = screen_depth;
199     if (dwBpp == 24) dwBpp = 32;
200     for (i=0; i<dd_mode_count; i++)
201     {
202         if ( (screen_width == dd_modes[i].dwWidth) &&
203              (screen_height == dd_modes[i].dwHeight) && 
204              (dwBpp == dd_modes[i].dwBPP))
205             return i;
206     }
207     ERR("In unknown mode, returning default\n");
208     return 0;
209 }
210
211 void X11DRV_desktop_SetCurrentMode(int mode)
212 {
213     DWORD dwBpp = screen_depth;
214     if (dwBpp == 24) dwBpp = 32;
215     TRACE("Resizing Wine desktop window to %ldx%ld\n", dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
216     X11DRV_resize_desktop(dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
217     if (dwBpp != dd_modes[mode].dwBPP)
218     {
219         FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
220     }
221 }
222
223 /***********************************************************************
224  *              X11DRV_create_desktop
225  *
226  * Create the X11 desktop window for the desktop mode.
227  */
228 Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry )
229 {
230     int x = 0, y = 0, flags;
231     unsigned int width = 640, height = 480;  /* Default size = 640x480 */
232     char *name = GetCommandLineA();
233     XSizeHints *size_hints;
234     XWMHints   *wm_hints;
235     XClassHint *class_hints;
236     XSetWindowAttributes win_attr;
237     XTextProperty window_name;
238     Window win;
239     Display *display = thread_display();
240
241     wine_tsx11_lock();
242     flags = XParseGeometry( geometry, &x, &y, &width, &height );
243     max_width = screen_width;
244     max_height = screen_height;
245     screen_width  = width;
246     screen_height = height;
247
248     /* Create window */
249     win_attr.background_pixel = BlackPixel(display, 0);
250     win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
251                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
252     win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );
253
254     if (desktop_vi)
255         win_attr.colormap = XCreateColormap( display, DefaultRootWindow(display),
256                                              visual, AllocNone );
257     else
258         win_attr.colormap = None;
259
260     win = XCreateWindow( display, DefaultRootWindow(display),
261                          x, y, width, height, 0, screen_depth, InputOutput, visual,
262                          CWBackPixel | CWEventMask | CWCursor | CWColormap, &win_attr );
263
264     /* Set window manager properties */
265     size_hints  = XAllocSizeHints();
266     wm_hints    = XAllocWMHints();
267     class_hints = XAllocClassHint();
268     if (!size_hints || !wm_hints || !class_hints)
269     {
270         MESSAGE("Not enough memory for window manager hints.\n" );
271         ExitProcess(1);
272     }
273     size_hints->min_width = size_hints->max_width = width;
274     size_hints->min_height = size_hints->max_height = height;
275     size_hints->flags = PMinSize | PMaxSize;
276     if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
277     if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
278     else size_hints->flags |= PSize;
279
280     wm_hints->flags = InputHint | StateHint;
281     wm_hints->input = True;
282     wm_hints->initial_state = NormalState;
283     class_hints->res_name  = "wine";
284     class_hints->res_class = "Wine";
285
286     XStringListToTextProperty( &name, 1, &window_name );
287     XSetWMProperties( display, win, &window_name, &window_name,
288                       NULL, 0, size_hints, wm_hints, class_hints );
289     XFree( size_hints );
290     XFree( wm_hints );
291     XFree( class_hints );
292     XFlush( display );
293     wine_tsx11_unlock();
294     /* initialize the available resolutions */
295     dd_modes = X11DRV_Settings_SetHandlers("desktop", 
296                                            X11DRV_desktop_GetCurrentMode, 
297                                            X11DRV_desktop_SetCurrentMode, 
298                                            NUM_DESKTOP_MODES+2, 1);
299     make_modes();
300     X11DRV_Settings_AddDepthModes();
301     dd_mode_count = X11DRV_Settings_GetModeCount();
302     X11DRV_Settings_SetDefaultMode(0);
303     return win;
304 }