desktop.c 9.62 KB
Newer Older
1 2 3 4
/*
 * X11DRV desktop window handling
 *
 * Copyright 2001 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 20 21 22
 */

#include "config.h"
#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 36 37 38 39


/* desktop window procedure */
static LRESULT WINAPI desktop_winproc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch(message)
    {
40 41 42 43 44
    case WM_NCCREATE:
        SystemParametersInfoA( SPI_SETDESKPATTERN, -1, NULL, FALSE );
        SetDeskWallPaper( (LPSTR)-1 );
        return TRUE;

45 46 47 48 49 50 51 52 53 54
    case WM_ERASEBKGND:
        PaintDesktop( (HDC)wParam );
        ValidateRect( hwnd, NULL );
        break;

    case WM_SYSCOMMAND:
        if ((wParam & 0xfff0) == SC_CLOSE) ExitWindows( 0, 0 );
        break;

    case WM_SETCURSOR:
55
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

    case WM_NCHITTEST:
        return HTCLIENT;
    }
    return 0;
}


/* desktop window manager thread */
static DWORD CALLBACK desktop_thread( LPVOID driver_data )
{
    Display *display;
    MSG msg;
    HWND hwnd;
    WND *win;
71
    Atom atom = x11drv_atom(WM_DELETE_WINDOW);
72 73 74 75 76 77

    NtCurrentTeb()->driver_data = driver_data;
    display = thread_display();
    hwnd = GetDesktopWindow();

    /* 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 86
    XChangeProperty ( display, root_window, x11drv_atom(WM_PROTOCOLS),
                      XA_ATOM, 32, PropModeReplace, (char *)&atom, 1 );
87 88
    XMapWindow( display, root_window );
    wine_tsx11_unlock();
89

90 91
    SendMessageW( hwnd, WM_NCCREATE, 0, 0 /* should be CREATESTRUCT */ );

92 93 94 95 96 97 98 99 100 101 102 103
    while (GetMessageW( &msg, hwnd, 0, 0 )) DispatchMessageW( &msg );
    return 0;
}


/***********************************************************************
 *		X11DRV_create_desktop_thread
 *
 * Create the thread that manages the desktop window
 */
void X11DRV_create_desktop_thread(void)
{
104 105
    HANDLE handle = CreateThread( NULL, 0, desktop_thread, NtCurrentTeb()->driver_data,
                                  0, &desktop_tid );
106 107 108 109 110 111 112 113 114 115 116
    if (!handle)
    {
        MESSAGE( "Could not create desktop thread\n" );
        ExitProcess(1);
    }
    /* we transferred our driver data to the new thread */
    NtCurrentTeb()->driver_data = NULL;
    CloseHandle( handle );
}


117 118
/* data for resolution changing */
static LPDDHALMODEINFO dd_modes;
119
static unsigned int dd_mode_count;
120 121 122 123

static unsigned int max_width;
static unsigned int max_height;

124 125
static const unsigned int widths[]  = {320, 512, 640, 800, 1024, 1152, 1280, 1600};
static const unsigned int heights[] = {200, 384, 480, 600,  768,  864, 1024, 1200};
126
#define NUM_DESKTOP_MODES (8)
127 128 129 130

/* create the mode structures */
static void make_modes(void)
{
131
    int i;
132
    /* original specified desktop size */
133 134
    X11DRV_Settings_AddOneMode(screen_width, screen_height, 0, 0);
    for (i=0; i<NUM_DESKTOP_MODES; i++)
135
    {
136 137 138 139 140 141
        if ( (widths[i] <= max_width) && (heights[i] <= max_height) )
        {
            if ( ( (widths[i] != max_width) || (heights[i] != max_height) ) &&
                 ( (widths[i] != screen_width) || (heights[i] != screen_height) ) )
            {
                /* only add them if they are smaller than the root window and unique */
142
                X11DRV_Settings_AddOneMode(widths[i], heights[i], 0, 0);
143 144
            }
        }
145
    }
146
    if ((max_width != screen_width) && (max_height != screen_height))
147
    {
148
        /* root window size (if different from desktop window) */
149
        X11DRV_Settings_AddOneMode(max_width, max_height, 0, 0);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    }
}

/***********************************************************************
 *		X11DRV_resize_desktop
 *
 * Reset the desktop window size and WM hints
 */
int X11DRV_resize_desktop( unsigned int width, unsigned int height )
{
    XSizeHints *size_hints;
    Display *display = thread_display();
    Window w = root_window;
    /* set up */
    wine_tsx11_lock();
    size_hints  = XAllocSizeHints();
    if (!size_hints)
    {
        ERR("Not enough memory for window manager hints.\n" );
169
        wine_tsx11_unlock();
170 171 172 173 174 175 176 177 178 179 180 181 182 183
        return 0;
    }
    size_hints->min_width = size_hints->max_width = width;
    size_hints->min_height = size_hints->max_height = height;
    size_hints->flags = PMinSize | PMaxSize | PSize;

    /* do the work */
    XSetWMNormalHints( display, w, size_hints );
    XResizeWindow( display, w, width, height );
    screen_width  = width;
    screen_height = height;
#if 0 /* FIXME */
    SYSMETRICS_Set( SM_CXSCREEN, width );
    SYSMETRICS_Set( SM_CYSCREEN, height );
184 185 186
#else
    FIXME("Need to update SYSMETRICS after resizing display (now %dx%d)\n", 
          width, height);
187 188 189 190 191 192 193 194 195
#endif

    /* clean up */
    XFree( size_hints );
    XFlush( display );
    wine_tsx11_unlock();
    return 1;
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
int X11DRV_desktop_GetCurrentMode(void)
{
    int i;
    DWORD dwBpp = screen_depth;
    if (dwBpp == 24) dwBpp = 32;
    for (i=0; i<dd_mode_count; i++)
    {
        if ( (screen_width == dd_modes[i].dwWidth) &&
             (screen_height == dd_modes[i].dwHeight) && 
             (dwBpp == dd_modes[i].dwBPP))
            return i;
    }
    ERR("In unknown mode, returning default\n");
    return 0;
}

void X11DRV_desktop_SetCurrentMode(int mode)
{
    DWORD dwBpp = screen_depth;
    if (dwBpp == 24) dwBpp = 32;
    TRACE("Resizing Wine desktop window to %ldx%ld\n", dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
    X11DRV_resize_desktop(dd_modes[mode].dwWidth, dd_modes[mode].dwHeight);
    if (dwBpp != dd_modes[mode].dwBPP)
    {
        FIXME("Cannot change screen BPP from %ld to %ld\n", dwBpp, dd_modes[mode].dwBPP);
    }
}
223

224 225 226 227 228 229 230 231 232
/***********************************************************************
 *		X11DRV_create_desktop
 *
 * Create the X11 desktop window for the desktop mode.
 */
Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry )
{
    int x = 0, y = 0, flags;
    unsigned int width = 640, height = 480;  /* Default size = 640x480 */
233
    char *name = GetCommandLineA();
234 235 236 237 238 239 240 241 242 243
    XSizeHints *size_hints;
    XWMHints   *wm_hints;
    XClassHint *class_hints;
    XSetWindowAttributes win_attr;
    XTextProperty window_name;
    Window win;
    Display *display = thread_display();

    wine_tsx11_lock();
    flags = XParseGeometry( geometry, &x, &y, &width, &height );
244 245
    max_width = screen_width;
    max_height = screen_height;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
    screen_width  = width;
    screen_height = height;

    /* Create window */
    win_attr.background_pixel = BlackPixel(display, 0);
    win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
                          PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
    win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );

    if (desktop_vi)
        win_attr.colormap = XCreateColormap( display, DefaultRootWindow(display),
                                             visual, AllocNone );
    else
        win_attr.colormap = None;

    win = XCreateWindow( display, DefaultRootWindow(display),
                         x, y, width, height, 0, screen_depth, InputOutput, visual,
                         CWBackPixel | CWEventMask | CWCursor | CWColormap, &win_attr );

    /* Set window manager properties */
    size_hints  = XAllocSizeHints();
    wm_hints    = XAllocWMHints();
    class_hints = XAllocClassHint();
    if (!size_hints || !wm_hints || !class_hints)
    {
        MESSAGE("Not enough memory for window manager hints.\n" );
        ExitProcess(1);
    }
    size_hints->min_width = size_hints->max_width = width;
    size_hints->min_height = size_hints->max_height = height;
    size_hints->flags = PMinSize | PMaxSize;
    if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
    if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
    else size_hints->flags |= PSize;

    wm_hints->flags = InputHint | StateHint;
    wm_hints->input = True;
    wm_hints->initial_state = NormalState;
    class_hints->res_name  = "wine";
    class_hints->res_class = "Wine";

    XStringListToTextProperty( &name, 1, &window_name );
    XSetWMProperties( display, win, &window_name, &window_name,
                      NULL, 0, size_hints, wm_hints, class_hints );
    XFree( size_hints );
    XFree( wm_hints );
    XFree( class_hints );
    XFlush( display );
    wine_tsx11_unlock();
295
    /* initialize the available resolutions */
296 297 298 299
    dd_modes = X11DRV_Settings_SetHandlers("desktop", 
                                           X11DRV_desktop_GetCurrentMode, 
                                           X11DRV_desktop_SetCurrentMode, 
                                           NUM_DESKTOP_MODES+2, 1);
300
    make_modes();
301 302 303
    X11DRV_Settings_AddDepthModes();
    dd_mode_count = X11DRV_Settings_GetModeCount();
    X11DRV_Settings_SetDefaultMode(0);
304 305
    return win;
}