Mercurial > sdl-ios-xcode
diff src/video/x11/SDL_x11window.c @ 1951:7177581dc9fa
Initial work on X11 window code in.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 27 Jul 2006 06:53:23 +0000 |
parents | |
children | 420716272158 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/x11/SDL_x11window.c Thu Jul 27 06:53:23 2006 +0000 @@ -0,0 +1,611 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2006 Sam Lantinga + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_syswm.h" +#include "../SDL_sysvideo.h" +#include "../../events/SDL_keyboard_c.h" + +#include "SDL_x11video.h" + + +static int +SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created) +{ + SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; + SDL_WindowData *data; + int numwindows = videodata->numwindows; + SDL_WindowData **windowlist = videodata->windowlist; + + /* Allocate the window data */ + data = (SDL_WindowData *) SDL_malloc(sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + data->windowID = window->id; + data->window = w; +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + data->ic = + pXCreateIC(videodata->im, XNClientWindow, w, XNFocusWindow, w, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNResourceName, videodata->classname, XNResourceClass, + videodata->classname, NULL); + } +#endif + data->created = created; + data->videodata = videodata; + + /* Associate the data with the window */ + windowlist = + (SDL_WindowData **) SDL_realloc(windowlist, + (numwindows + + 1) * sizeof(*windowlist)); + if (!windowlist) { + SDL_OutOfMemory(); + SDL_free(data); + return -1; + } + windowlist[numwindows++] = data; + videodata->numwindows = numwindows; + videodata->windowlist = windowlist; + + /* Fill in the SDL window with the window data */ + { + XWindowAttributes attrib; + + XGetWindowAttributes(data->videodata->display, w, &attrib); + window->x = attrib.x; + window->y = attrib.y; + window->w = attrib.width; + window->h = attrib.height; + if (attrib.map_state != IsUnmapped) { + window->flags |= SDL_WINDOW_SHOWN; + } else { + window->flags &= ~SDL_WINDOW_SHOWN; + } + } + /* FIXME: How can I tell? + { + DWORD style = GetWindowLong(hwnd, GWL_STYLE); + if (style & WS_VISIBLE) { + if (style & (WS_BORDER | WS_THICKFRAME)) { + window->flags &= ~SDL_WINDOW_BORDERLESS; + } else { + window->flags |= SDL_WINDOW_BORDERLESS; + } + if (style & WS_THICKFRAME) { + window->flags |= SDL_WINDOW_RESIZABLE; + } else { + window->flags &= ~SDL_WINDOW_RESIZABLE; + } + if (style & WS_MAXIMIZE) { + window->flags |= SDL_WINDOW_MAXIMIZED; + } else { + window->flags &= ~SDL_WINDOW_MAXIMIZED; + } + if (style & WS_MINIMIZE) { + window->flags |= SDL_WINDOW_MINIMIZED; + } else { + window->flags &= ~SDL_WINDOW_MINIMIZED; + } + } + if (GetFocus() == hwnd) { + int index = data->videodata->keyboard; + window->flags |= SDL_WINDOW_INPUT_FOCUS; + SDL_SetKeyboardFocus(index, data->windowID); + + if (window->flags & SDL_WINDOW_INPUT_GRABBED) { + RECT rect; + GetClientRect(hwnd, &rect); + ClientToScreen(hwnd, (LPPOINT) & rect); + ClientToScreen(hwnd, (LPPOINT) & rect + 1); + ClipCursor(&rect); + } + } + */ + + /* All done! */ + window->driverdata = data; + return 0; +} + +int +X11_CreateWindow(_THIS, SDL_Window * window) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + SDL_DisplayData *displaydata = + (SDL_DisplayData *) SDL_CurrentDisplay.driverdata; + Visual *visual; + int depth; + XSetWindowAttributes xattr; + int x, y; + Window w; + XSizeHints *sizehints; + XWMHints *wmhints; + XClassHint *classhints; + +#if SDL_VIDEO_DRIVER_X11_XINERAMA +/* FIXME + if ( use_xinerama ) { + x = xinerama_info.x_org; + y = xinerama_info.y_org; + } +*/ +#endif + if (window->flags & SDL_WINDOW_OPENGL) { + /* FIXME: get the glx visual */ + } else { + visual = displaydata->visual; + depth = displaydata->depth; + } + + if (window->flags & SDL_WINDOW_FULLSCREEN) { + xattr.override_redirect = True; + } else { + xattr.override_redirect = False; + } + xattr.background_pixel = 0; + xattr.border_pixel = 0; + if (visual->class == PseudoColor || visual->class == DirectColor) { + xattr.colormap = + XCreateColormap(data->display, + RootWindow(data->display, displaydata->screen), + visual, AllocAll); + } else { + xattr.colormap = + XCreateColormap(data->display, + RootWindow(data->display, displaydata->screen), + visual, AllocNone); + } + + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->x == SDL_WINDOWPOS_CENTERED) { + x = (DisplayWidth(data->display, displaydata->screen) - + window->w) / 2; + } else if (window->x == SDL_WINDOWPOS_UNDEFINED) { + x = 0; + } else { + x = window->x; + } + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->y == SDL_WINDOWPOS_CENTERED) { + y = (DisplayHeight(data->display, displaydata->screen) - + window->h) / 2; + } else if (window->y == SDL_WINDOWPOS_UNDEFINED) { + y = 0; + } else { + y = window->y; + } + + w = XCreateWindow(data->display, + RootWindow(data->display, displaydata->screen), x, y, + window->w, window->h, 0, depth, InputOutput, visual, + (CWOverrideRedirect | CWBackPixel | CWBorderPixel | + CWColormap), &xattr); + + sizehints = XAllocSizeHints(); + if (sizehints) { + if (window->flags & SDL_WINDOW_RESIZABLE) { + sizehints->min_width = 32; + sizehints->min_height = 32; + sizehints->max_height = 4096; + sizehints->max_width = 4096; + } else { + sizehints->min_width = sizehints->max_width = window->w; + sizehints->min_height = sizehints->max_height = window->h; + } + sizehints->flags = PMaxSize | PMinSize; + if (!(window->flags & SDL_WINDOW_FULLSCREEN) + && window->x != SDL_WINDOWPOS_UNDEFINED + && window->y != SDL_WINDOWPOS_UNDEFINED) { + sizehints->x = x; + sizehints->y = y; + sizehints->flags |= USPosition; + } + XSetWMNormalHints(data->display, w, sizehints); + XFree(sizehints); + } + + if (window->flags & SDL_WINDOW_BORDERLESS) { + SDL_bool set; + Atom WM_HINTS; + + /* We haven't modified the window manager hints yet */ + set = SDL_FALSE; + + /* First try to set MWM hints */ + WM_HINTS = XInternAtom(data->display, "_MOTIF_WM_HINTS", True); + if (WM_HINTS != None) { + /* Hints used by Motif compliant window managers */ + struct + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } MWMHints = { + (1L << 1), 0, 0, 0, 0}; + + XChangeProperty(data->display, w, WM_HINTS, WM_HINTS, 32, + PropModeReplace, (unsigned char *) &MWMHints, + sizeof(MWMHints) / sizeof(long)); + set = SDL_TRUE; + } + /* Now try to set KWM hints */ + WM_HINTS = XInternAtom(data->display, "KWM_WIN_DECORATION", True); + if (WM_HINTS != None) { + long KWMHints = 0; + + XChangeProperty(data->display, w, + WM_HINTS, WM_HINTS, 32, + PropModeReplace, + (unsigned char *) &KWMHints, + sizeof(KWMHints) / sizeof(long)); + set = SDL_TRUE; + } + /* Now try to set GNOME hints */ + WM_HINTS = XInternAtom(data->display, "_WIN_HINTS", True); + if (WM_HINTS != None) { + long GNOMEHints = 0; + + XChangeProperty(data->display, w, + WM_HINTS, WM_HINTS, 32, + PropModeReplace, + (unsigned char *) &GNOMEHints, + sizeof(GNOMEHints) / sizeof(long)); + set = SDL_TRUE; + } + /* Finally set the transient hints if necessary */ + if (!set) { + XSetTransientForHint(data->display, w, + RootWindow(data->display, + displaydata->screen)); + } + } else { + SDL_bool set; + Atom WM_HINTS; + + /* We haven't modified the window manager hints yet */ + set = SDL_FALSE; + + /* First try to unset MWM hints */ + WM_HINTS = XInternAtom(data->display, "_MOTIF_WM_HINTS", True); + if (WM_HINTS != None) { + XDeleteProperty(data->display, w, WM_HINTS); + set = SDL_TRUE; + } + /* Now try to unset KWM hints */ + WM_HINTS = XInternAtom(data->display, "KWM_WIN_DECORATION", True); + if (WM_HINTS != None) { + XDeleteProperty(data->display, w, WM_HINTS); + set = SDL_TRUE; + } + /* Now try to unset GNOME hints */ + WM_HINTS = XInternAtom(data->display, "_WIN_HINTS", True); + if (WM_HINTS != None) { + XDeleteProperty(data->display, w, WM_HINTS); + set = SDL_TRUE; + } + /* Finally unset the transient hints if necessary */ + if (!set) { + /* NOTE: Does this work? */ + XSetTransientForHint(data->display, w, None); + } + } + + /* Tell KDE to keep fullscreen windows on top */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + XEvent ev; + long mask; + + SDL_zero(ev); + ev.xclient.type = ClientMessage; + ev.xclient.window = RootWindow(data->display, displaydata->screen); + ev.xclient.message_type = + XInternAtom(data->display, "KWM_KEEP_ON_TOP", False); + ev.xclient.format = 32; + ev.xclient.data.l[0] = w; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(data->display, + RootWindow(data->display, displaydata->screen), False, + SubstructureRedirectMask, &ev); + } + + /* Set the input hints so we get keyboard input */ + wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + if (window->flags & SDL_WINDOW_MINIMIZED) { + wmhints->initial_state = IconicState; + } else if (window->flags & SDL_WINDOW_SHOWN) { + wmhints->initial_state = NormalState; + } else { + wmhints->initial_state = WithdrawnState; + } + wmhints->flags = InputHint | StateHint; + XSetWMHints(data->display, w, wmhints); + XFree(wmhints); + } + + XSelectInput(data->display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + /* Set the class hints so we can get an icon (AfterStep) */ + classhints = XAllocClassHint(); + if (classhints != NULL) { + classhints->res_name = data->classname; + classhints->res_class = data->classname; + XSetClassHint(data->display, w, classhints); + XFree(classhints); + } + + /* Allow the window to be deleted by the window manager */ + XSetWMProtocols(data->display, w, &data->WM_DELETE_WINDOW, 1); + + /* Finally, show the window */ + if (window->flags & SDL_WINDOW_SHOWN) { + XMapRaised(data->display, w); + } + XSync(data->display, False); + + if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) { + XDestroyWindow(data->display, w); + return -1; + } + + X11_SetWindowTitle(_this, window); + +#ifdef SDL_VIDEO_OPENGL + /* + if (window->flags & SDL_WINDOW_OPENGL) { + if (X11_GL_SetupWindow(_this, window) < 0) { + X11_DestroyWindow(_this, window); + return -1; + } + } + */ +#endif + return 0; +} + +int +X11_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) +{ + Window w = (Window) data; + + /* FIXME: Query the title from the existing window */ + + if (SetupWindowData(_this, window, w, SDL_FALSE) < 0) { + return -1; + } + return 0; +} + +void +X11_SetWindowTitle(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + XTextProperty titleprop, iconprop; + Status status; + const char *title = window->title; + const char *icon = NULL; + +#ifdef X_HAVE_UTF8_STRING + Atom _NET_WM_NAME = 0; + Atom _NET_WM_ICON_NAME = 0; + + /* Look up some useful Atoms */ + if (SDL_X11_HAVE_UTF8) { + _NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", False); + _NET_WM_ICON_NAME = XInternAtom(display, "_NET_WM_ICON_NAME", False); + } +#endif + + if (title != NULL) { + char *title_latin1 = SDL_iconv_utf8_latin1((char *) title); + if (!title_latin1) { + SDL_OutOfMemory(); + return; + } + status = XStringListToTextProperty(&title_latin1, 1, &titleprop); + SDL_free(title_latin1); + if (status) { + XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME); + XFree(titleprop.value); + } +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + status = + Xutf8TextListToTextProperty(display, (char **) &title, 1, + XUTF8StringStyle, &titleprop); + if (status == Success) { + XSetTextProperty(display, data->window, &titleprop, + _NET_WM_NAME); + XFree(titleprop.value); + } + } +#endif + } + if (icon != NULL) { + char *icon_latin1 = SDL_iconv_utf8_latin1((char *) icon); + if (!icon_latin1) { + SDL_OutOfMemory(); + return; + } + status = XStringListToTextProperty(&icon_latin1, 1, &iconprop); + SDL_free(icon_latin1); + if (status) { + XSetTextProperty(display, data->window, &iconprop, + XA_WM_ICON_NAME); + XFree(iconprop.value); + } +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + status = + Xutf8TextListToTextProperty(display, (char **) &icon, 1, + XUTF8StringStyle, &iconprop); + if (status == Success) { + XSetTextProperty(display, data->window, &iconprop, + _NET_WM_ICON_NAME); + XFree(iconprop.value); + } + } +#endif + } +} + +void +X11_SetWindowPosition(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_DisplayData *displaydata = + (SDL_DisplayData *) SDL_CurrentDisplay.driverdata; + Display *display = data->videodata->display; + int x, y; + + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->x == SDL_WINDOWPOS_CENTERED) { + x = (DisplayWidth(display, displaydata->screen) - window->w) / 2; + } else if (window->x == SDL_WINDOWPOS_UNDEFINED) { + x = 0; + } else { + x = window->x; + } + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->y == SDL_WINDOWPOS_CENTERED) { + y = (DisplayHeight(display, displaydata->screen) - window->h) / 2; + } else if (window->y == SDL_WINDOWPOS_UNDEFINED) { + y = 0; + } else { + y = window->y; + } + XMoveWindow(display, data->window, x, y); +} + +void +X11_SetWindowSize(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + + XMoveWindow(display, data->window, window->w, window->h); +} + +void +X11_ShowWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + + XMapRaised(display, data->window); +} + +void +X11_HideWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + + XUnmapWindow(display, data->window); +} + +void +X11_RaiseWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + + XRaiseWindow(display, data->window); +} + +void +X11_MaximizeWindow(_THIS, SDL_Window * window) +{ + /* FIXME: is this even possible? */ +} + +void +X11_MinimizeWindow(_THIS, SDL_Window * window) +{ + X11_HideWindow(_this, window); +} + +void +X11_RestoreWindow(_THIS, SDL_Window * window) +{ + X11_ShowWindow(_this, window); +} + +void +X11_SetWindowGrab(_THIS, SDL_Window * window) +{ + /* FIXME */ +} + +void +X11_DestroyWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + if (data) { + Display *display = data->videodata->display; +#ifdef SDL_VIDEO_OPENGL + /* + if (window->flags & SDL_WINDOW_OPENGL) { + X11_GL_CleanupWindow(_this, window); + } + */ +#endif +#ifdef X_HAVE_UTF8_STRING + if (data->ic) { + XDestroyIC(data->ic); + } +#endif + if (data->created) { + XDestroyWindow(display, data->window); + } + SDL_free(data); + } +} + +SDL_bool +X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) +{ + if (info->version.major <= SDL_MAJOR_VERSION) { + /* FIXME! */ + return SDL_TRUE; + } else { + SDL_SetError("Application not compiled with SDL %d.%d\n", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION); + return SDL_FALSE; + } +} + +/* vi: set ts=4 sw=4 expandtab: */