If the variable does not exist, just return.
[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     WND *win;
70     Atom atom = x11drv_atom(WM_DELETE_WINDOW);
71
72     NtCurrentTeb()->driver_data = driver_data;
73     display = thread_display();
74     hwnd = GetDesktopWindow();
75
76     /* patch the desktop window queue to point to our queue */
77     win = WIN_GetPtr( hwnd );
78     win->tid = GetCurrentThreadId();
79     WIN_ReleasePtr( win );
80
81     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_winproc );
82     wine_tsx11_lock();
83     XSaveContext( display, root_window, winContext, (char *)hwnd );
84     XChangeProperty ( display, root_window, x11drv_atom(WM_PROTOCOLS),
85                       XA_ATOM, 32, PropModeReplace, (char *)&atom, 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
179     /* clean up */
180     XFree( size_hints );
181     XFlush( display );
182     wine_tsx11_unlock();
183     X11DRV_handle_desktop_resize( width, height );
184     return 1;
185 }
186
187 int X11DRV_desktop_GetCurrentMode(void)
188 {
189     unsigned int i;
190     DWORD dwBpp = screen_depth;
191     if (dwBpp == 24) dwBpp = 32;
192     for (i=0; i<dd_mode_count; i++)
193     {
194         if ( (screen_width == dd_modes[i].dwWidth) &&
195              (screen_height == dd_modes[i].dwHeight) && 
196              (dwBpp == dd_modes[i].dwBPP))
197             return i;
198     }
199     ERR("In unknown mode, returning default\n");
200     return 0;
201 }
202
203 void X11DRV_desktop_SetCurrentMode(int mode)
204 {
205     DWORD dwBpp = screen_depth;
206     if (dwBpp == 24) dwBpp = 32;
207     TRACE("Resizing Wine desktop window to %ldx%ld\n", dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
208     X11DRV_resize_desktop(dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
209     if (dwBpp != dd_modes[mode].dwBPP)
210     {
211         FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
212     }
213 }
214
215 /***********************************************************************
216  *              X11DRV_create_desktop
217  *
218  * Create the X11 desktop window for the desktop mode.
219  */
220 Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry )
221 {
222     int x = 0, y = 0, flags;
223     unsigned int width = 640, height = 480;  /* Default size = 640x480 */
224     char *name = GetCommandLineA();
225     XSizeHints *size_hints;
226     XWMHints   *wm_hints;
227     XClassHint *class_hints;
228     XSetWindowAttributes win_attr;
229     XTextProperty window_name;
230     Window win;
231     Display *display = thread_display();
232
233     wine_tsx11_lock();
234     flags = XParseGeometry( geometry, &x, &y, &width, &height );
235     max_width = screen_width;
236     max_height = screen_height;
237     screen_width  = width;
238     screen_height = height;
239
240     /* Create window */
241     win_attr.background_pixel = BlackPixel(display, 0);
242     win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
243                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
244     win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );
245
246     if (desktop_vi)
247         win_attr.colormap = XCreateColormap( display, DefaultRootWindow(display),
248                                              visual, AllocNone );
249     else
250         win_attr.colormap = None;
251
252     win = XCreateWindow( display, DefaultRootWindow(display),
253                          x, y, width, height, 0, screen_depth, InputOutput, visual,
254                          CWBackPixel | CWEventMask | CWCursor | CWColormap, &win_attr );
255
256     /* Set window manager properties */
257     size_hints  = XAllocSizeHints();
258     wm_hints    = XAllocWMHints();
259     class_hints = XAllocClassHint();
260     if (!size_hints || !wm_hints || !class_hints)
261     {
262         MESSAGE("Not enough memory for window manager hints.\n" );
263         ExitProcess(1);
264     }
265     size_hints->min_width = size_hints->max_width = width;
266     size_hints->min_height = size_hints->max_height = height;
267     size_hints->flags = PMinSize | PMaxSize;
268     if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
269     if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
270     else size_hints->flags |= PSize;
271
272     wm_hints->flags = InputHint | StateHint;
273     wm_hints->input = True;
274     wm_hints->initial_state = NormalState;
275     class_hints->res_name  = "wine";
276     class_hints->res_class = "Wine";
277
278     XStringListToTextProperty( &name, 1, &window_name );
279     XSetWMProperties( display, win, &window_name, &window_name,
280                       NULL, 0, size_hints, wm_hints, class_hints );
281     XFree( size_hints );
282     XFree( wm_hints );
283     XFree( class_hints );
284     XFlush( display );
285     wine_tsx11_unlock();
286     /* initialize the available resolutions */
287     dd_modes = X11DRV_Settings_SetHandlers("desktop", 
288                                            X11DRV_desktop_GetCurrentMode, 
289                                            X11DRV_desktop_SetCurrentMode, 
290                                            NUM_DESKTOP_MODES+2, 1);
291     make_modes();
292     X11DRV_Settings_AddDepthModes();
293     dd_mode_count = X11DRV_Settings_GetModeCount();
294     X11DRV_Settings_SetDefaultMode(0);
295     return win;
296 }