Mercurial > mplayer.hg
view gui/wm/ws.c @ 36194:829983f984ad
Handle events while waiting for window being mapped.
Reported by Jens Stimpfle, debian jstimpfle de.
author | ib |
---|---|
date | Sun, 26 May 2013 15:54:34 +0000 |
parents | 9beb155c77a0 |
children | 9a319cd3ee66 |
line wrap: on
line source
/* * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPlayer 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with MPlayer; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * based on: AutoSpace Window System for Linux/Win32, * written by pontscho/fresh!mindworkz */ #include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <X11/Xatom.h> #include "ws.h" #include "wsxdnd.h" #include "gui/interface.h" #include "gui/app/gui.h" #include "config.h" #include "help_mp.h" #include "mp_core.h" #include "mp_msg.h" #include "mpbswap.h" #include "mplayer.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" #include "libswscale/swscale.h" #include "libvo/video_out.h" #include "libvo/x11_common.h" #include "osdep/timer.h" #ifdef HAVE_SHM #include <sys/shm.h> #endif #ifdef CONFIG_XSHAPE #include <X11/extensions/shape.h> #endif #ifdef CONFIG_XF86VM #include <X11/extensions/xf86vmode.h> #endif #define MOUSEHIDE_DELAY 1000 // in milliseconds static wsWindow *mouse_win; static unsigned int mouse_time; int wsMaxX; // Screen width. int wsMaxY; // Screen height. int wsOrgX; // Screen origin x. int wsOrgY; // Screen origin y. Display *wsDisplay; static int wsScreen; static Window wsRootWin; static int wsScreenDepth; static int wsRedMask; static int wsGreenMask; static int wsBlueMask; static int wsNonNativeOrder; #define wsWLCount 5 static wsWindow *wsWindowList[wsWLCount]; static int wsUseXShm = True; static int wsUseXShape = True; static enum AVPixelFormat out_pix_fmt = PIX_FMT_NONE; /* --- */ #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) /** * @brief Update screen width, screen height and screen origin x and y * from xinerama information. * * Set wsOrgX, wsOrgY, wsMaxX and wsMaxY as well as * win->X, win->Y, win->Width and win->Height. * * @param win pointer to a ws window structure or NULL */ static void wsWindowUpdateXinerama(wsWindow *win) { if (win) { vo_dx = win->X; vo_dy = win->Y; vo_dwidth = win->Width; vo_dheight = win->Height; } vo_screenwidth = wsMaxX; vo_screenheight = wsMaxY; update_xinerama_info(); wsMaxX = vo_screenwidth; wsMaxY = vo_screenheight; wsOrgX = xinerama_x; wsOrgY = xinerama_y; if (win) { win->X = wsOrgX; win->Y = wsOrgY; win->Width = wsMaxX; win->Height = wsMaxY; } } static int wsGetScreenDepth(void) { int depth; XImage *mXImage; Visual *visual; if ((depth = vo_find_depth_from_visuals(wsDisplay, wsScreen, &visual)) > 0) { mXImage = XCreateImage(wsDisplay, visual, depth, ZPixmap, 0, NULL, 1, 1, 32, 0); wsScreenDepth = mXImage->bits_per_pixel; wsRedMask = mXImage->red_mask; wsGreenMask = mXImage->green_mask; wsBlueMask = mXImage->blue_mask; #if HAVE_BIGENDIAN wsNonNativeOrder = mXImage->byte_order == LSBFirst; #else wsNonNativeOrder = mXImage->byte_order == MSBFirst; #endif XDestroyImage(mXImage); } else { int bpp, ibpp; XWindowAttributes attribs; mXImage = XGetImage(wsDisplay, wsRootWin, 0, 0, 1, 1, AllPlanes, ZPixmap); bpp = mXImage->bits_per_pixel; XGetWindowAttributes(wsDisplay, wsRootWin, &attribs); ibpp = attribs.depth; mXImage = XGetImage(wsDisplay, wsRootWin, 0, 0, 1, 1, AllPlanes, ZPixmap); bpp = mXImage->bits_per_pixel; if ((ibpp + 7) / 8 != (bpp + 7) / 8) ibpp = bpp; wsScreenDepth = ibpp; wsRedMask = mXImage->red_mask; wsGreenMask = mXImage->green_mask; wsBlueMask = mXImage->blue_mask; XDestroyImage(mXImage); } return wsScreenDepth; } void wsInit(Display *display) { int eventbase; int errorbase; mp_msg(MSGT_GPLAYER, MSGL_V, "X init.\n"); wsDisplay = display; wsSetErrorHandler(); /* enable DND atoms */ wsXDNDInitialize(); { /* on remote display XShm will be disabled - LGB */ char *dispname = DisplayString(wsDisplay); int localdisp = 1; if (dispname && *dispname != ':') { localdisp = 0; wsUseXShm = False; } mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] display name: %s => %s display.\n", dispname, localdisp ? "local" : "REMOTE"); if (!localdisp) mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_RemoteDisplay); } #ifdef HAVE_SHM if (!XShmQueryExtension(wsDisplay)) #endif wsUseXShm = False; if (!wsUseXShm) mp_msg(MSGT_GPLAYER, MSGL_INFO, MSGTR_WS_NoXshm); #ifdef CONFIG_XSHAPE if (!XShapeQueryExtension(wsDisplay, &eventbase, &errorbase)) #endif wsUseXShape = False; if (!wsUseXShape) mp_msg(MSGT_GPLAYER, MSGL_WARN, MSGTR_WS_NoXshape); XSynchronize(wsDisplay, True); wsScreen = DefaultScreen(wsDisplay); wsRootWin = RootWindow(wsDisplay, wsScreen); #ifdef CONFIG_XF86VM { int clock; XF86VidModeModeLine modeline; XF86VidModeGetModeLine(wsDisplay, wsScreen, &clock, &modeline); wsMaxX = modeline.hdisplay; wsMaxY = modeline.vdisplay; } #endif { wsOrgX = wsOrgY = 0; if (!wsMaxX) wsMaxX = DisplayWidth(wsDisplay, wsScreen); if (!wsMaxY) wsMaxY = DisplayHeight(wsDisplay, wsScreen); } wsWindowUpdateXinerama(NULL); wsGetScreenDepth(); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Screen depth: %d\n", wsScreenDepth); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] size: %dx%d\n", wsMaxX, wsMaxY); #ifdef CONFIG_XINERAMA mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] origin: +%d+%d\n", wsOrgX, wsOrgY); #endif mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] red mask: 0x%x\n", wsRedMask); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] green mask: 0x%x\n", wsGreenMask); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] blue mask: 0x%x\n", wsBlueMask); #ifdef HAVE_SHM if (wsUseXShm) { int minor, major, shp; XShmQueryVersion(wsDisplay, &major, &minor, &shp); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShm version is %d.%d\n", major, minor); } #endif #ifdef CONFIG_XSHAPE if (wsUseXShape) { int minor, major; XShapeQueryVersion(wsDisplay, &major, &minor); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] XShape version is %d.%d\n", major, minor); } #endif if (wsScreenDepth == 32 && wsRedMask == 0xff0000 && wsGreenMask == 0x00ff00 && wsBlueMask == 0x0000ff) out_pix_fmt = PIX_FMT_RGB32; else if (wsScreenDepth == 32 && wsRedMask == 0x0000ff && wsGreenMask == 0x00ff00 && wsBlueMask == 0xff0000) out_pix_fmt = PIX_FMT_BGR32; else if (wsScreenDepth == 24 && wsRedMask == 0xff0000 && wsGreenMask == 0x00ff00 && wsBlueMask == 0x0000ff) out_pix_fmt = PIX_FMT_RGB24; else if (wsScreenDepth == 24 && wsRedMask == 0x0000ff && wsGreenMask == 0x00ff00 && wsBlueMask == 0xff0000) out_pix_fmt = PIX_FMT_BGR24; else if (wsScreenDepth == 16 && wsRedMask == 0xf800 && wsGreenMask == 0x7e0 && wsBlueMask == 0x1f) out_pix_fmt = PIX_FMT_RGB565; else if (wsScreenDepth == 16 && wsRedMask == 0x1f && wsGreenMask == 0x7e0 && wsBlueMask == 0xf800) out_pix_fmt = PIX_FMT_BGR565; else if (wsScreenDepth == 15 && wsRedMask == 0x7c00 && wsGreenMask == 0x3e0 && wsBlueMask == 0x1f) out_pix_fmt = PIX_FMT_RGB555; else if (wsScreenDepth == 15 && wsRedMask == 0x1f && wsGreenMask == 0x3e0 && wsBlueMask == 0x7c00) out_pix_fmt = PIX_FMT_BGR555; } void wsDone(void) { // NOTE TO MYSELF: uninit wsInit stuff? //XCloseDisplay(wsDisplay); } /** * @brief Inform about an X error that has occurred. * * @param display display * @param event pointer to an X error event structure * * @return 0 */ static int wsErrorHandler(Display *display, XErrorEvent *event) { char type[128]; XGetErrorText(display, event->error_code, type, sizeof(type)); mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] " MSGTR_WS_XError); mp_msg(MSGT_GPLAYER, MSGL_ERR, "[ws] Error code: %d - %s\n", event->error_code, type); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] Request code: %d (minor code: %d)\n", event->request_code, event->minor_code); mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] MPlayer module: %s\n", current_module ? current_module : "(none)"); return 0; } /** * @brief Set the X error handler. */ void wsSetErrorHandler(void) { XSetErrorHandler(wsErrorHandler); } // ---------------------------------------------------------------------------------------------- // Handle events. // ---------------------------------------------------------------------------------------------- static int wsWindowListSearch(Window win) { int i; for (i = 0; i < wsWLCount; i++) if (wsWindowList[i] && wsWindowList[i]->WindowID == win) return i; return -1; } void wsEvent(XEvent *event) { unsigned long i = 0; int l; int x, y; Window child_window = 0; l = wsWindowListSearch(event->xany.window); if (l == -1) return; wsWindowList[l]->State = wsNone; switch (event->type) { case ClientMessage: if (event->xclient.message_type == wsWindowList[l]->AtomProtocols) { if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomDeleteWindow) { i = wsWindowClosed; goto expose; } if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomTakeFocus) { i = wsWindowFocusIn; wsWindowList[l]->Focused = wsFocused; goto expose; } if ((Atom)event->xclient.data.l[0] == wsWindowList[l]->AtomRolle) { mp_msg(MSGT_GPLAYER, MSGL_V, "[ws] role set.\n"); } } else { /* try to process DND events */ wsXDNDProcessClientMessage(&event->xclient); } break; case MapNotify: i = wsWindowMapped; wsWindowList[l]->Mapped = wsMapped; goto expose; case UnmapNotify: i = wsWindowUnmapped; wsWindowList[l]->Mapped = wsNo; goto expose; case FocusIn: if (wsWindowList[l]->Focused == wsFocused) break; i = wsWindowFocusIn; wsWindowList[l]->Focused = wsFocused; goto expose; case FocusOut: if (wsWindowList[l]->Focused == wsNo) break; i = wsWindowFocusOut; wsWindowList[l]->Focused = wsNo; goto expose; case VisibilityNotify: switch (event->xvisibility.state) { case VisibilityUnobscured: i = wsWindowVisible; wsWindowList[l]->Visible = wsVisible; goto expose; case VisibilityFullyObscured: i = wsWindowNotVisible; wsWindowList[l]->Visible = wsNotVisible; goto expose; case VisibilityPartiallyObscured: i = wsWindowPartialVisible; wsWindowList[l]->Visible = wsPVisible; goto expose; } expose: wsWindowList[l]->State = i; if (wsWindowList[l]->DrawHandler) wsWindowList[l]->DrawHandler(); break; case Expose: wsWindowList[l]->State = wsWindowExpose; if ((wsWindowList[l]->DrawHandler) && (!event->xexpose.count)) wsWindowList[l]->DrawHandler(); break; case ConfigureNotify: XTranslateCoordinates(wsDisplay, wsWindowList[l]->WindowID, wsRootWin, 0, 0, &x, &y, &child_window); if ((wsWindowList[l]->X != x) || (wsWindowList[l]->Y != y) || (wsWindowList[l]->Width != event->xconfigure.width) || (wsWindowList[l]->Height != event->xconfigure.height)) { wsWindowList[l]->X = x; wsWindowList[l]->Y = y; wsWindowList[l]->Width = event->xconfigure.width; wsWindowList[l]->Height = event->xconfigure.height; } wsWindowList[l]->Rolled = wsNo; if (event->xconfigure.y < 0) { i = wsWindowRolled; wsWindowList[l]->Rolled = wsRolled; goto expose; } break; case KeyPress: i = wsKeyPressed; goto keypressed; case KeyRelease: i = wsKeyReleased; keypressed: wsWindowList[l]->Alt = False; wsWindowList[l]->Shift = False; wsWindowList[l]->NumLock = False; wsWindowList[l]->Control = False; wsWindowList[l]->CapsLock = False; if (event->xkey.state & Mod1Mask) wsWindowList[l]->Alt = True; if (event->xkey.state & Mod2Mask) wsWindowList[l]->NumLock = True; if (event->xkey.state & ControlMask) wsWindowList[l]->Control = True; if (event->xkey.state & ShiftMask) wsWindowList[l]->Shift = True; if (event->xkey.state & LockMask) wsWindowList[l]->CapsLock = True; #if 0 { KeySym keySym; keySym = XKeycodeToKeysym(wsDisplay, event->xkey.keycode, 0); if (keySym != NoSymbol) { keySym = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym)); if (wsWindowList[l]->KeyHandler) wsWindowList[l]->KeyHandler(event->xkey.state, i, keySym); } } #else { int key; char buf[100]; KeySym keySym; static XComposeStatus stat; XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat); key = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym)); if (wsWindowList[l]->KeyHandler) wsWindowList[l]->KeyHandler(event->xkey.keycode, i, key); } #endif break; case MotionNotify: i = wsMoveMouse; { /* pump all motion events from the display queue: * this way it works faster when moving the window */ static XEvent e; if (event->xmotion.state) { while (XCheckTypedWindowEvent(wsDisplay, event->xany.window, MotionNotify, &e)) { /* FIXME: need to make sure we didn't release/press the button in between...*/ /* FIXME: do we need some timeout here to make sure we don't spend too much time * removing events from the queue? */ event = &e; } } } if (wsWindowList[l]->wsCursor != None) { wsMouseVisibility(wsWindowList[l], wsShowMouseCursor); mouse_win = wsWindowList[l]; mouse_time = GetTimerMS(); } goto buttonreleased; case ButtonRelease: i = event->xbutton.button + 128; if (wsWindowList[l]->wsCursor != None) { wsMouseVisibility(wsWindowList[l], wsShowMouseCursor); mouse_win = wsWindowList[l]; mouse_time = GetTimerMS(); } goto buttonreleased; case ButtonPress: i = event->xbutton.button; if (wsWindowList[l]->wsCursor != None) { wsMouseVisibility(wsWindowList[l], wsShowMouseCursor); mouse_win = wsWindowList[l]; mouse_time = GetTimerMS(); } goto buttonreleased; case EnterNotify: i = wsEnterWindow; goto buttonreleased; case LeaveNotify: i = wsLeaveWindow; buttonreleased: if (wsWindowList[l]->MouseHandler) wsWindowList[l]->MouseHandler(i, event->xbutton.x, event->xbutton.y, event->xmotion.x_root, event->xmotion.y_root); break; case SelectionNotify: /* Handle drag & drop */ wsXDNDProcessSelection(wsWindowList[l], event); break; } XFlush(wsDisplay); XSync(wsDisplay, False); } /** * @brief Process all pending events. */ void wsEvents(void) { XEvent xev; while (XPending(wsDisplay)) { XNextEvent(wsDisplay, &xev); wsEvent(&xev); } } /** * @brief Calculate and store the x and y position for a window. * * @param win pointer to a ws window structure * @param x x position of the window (real/absolute or mock) * @param y y position of the window (real/absolute or mock) * @param width width of the area to place the window in * @param height height of the area to place the window in */ static void wsWindowUpdatePosition(wsWindow *win, int x, int y, int width, int height) { switch (x) { case -1: win->X = wsOrgX + (wsMaxX - width) / 2; break; case -2: win->X = wsOrgX + wsMaxX - width; break; default: win->X = x; break; } switch (y) { case -1: win->Y = wsOrgY + (wsMaxY - height) / 2; break; case -2: win->Y = wsOrgY + wsMaxY - height; break; default: win->Y = y; break; } } /** * @brief Replace the size hints for the WM_NORMAL_HINTS property of a window. * * @param win pointer to a ws window structure */ static void wsWindowSizeHint(wsWindow *win) { XSizeHints size; size.flags = 0; /* obsolete, solely for compatibility reasons */ size.flags |= PPosition; size.x = win->X; size.y = win->Y; /* obsolete, solely for compatibility reasons */ size.flags |= PSize; size.width = win->Width; size.height = win->Height; /* a minimum of 4 is said to avoid off-by-one errors and be required by mga_vid */ size.flags |= PMinSize; size.min_width = 4; size.min_height = 4; if (win->Property & wsMinSize) { size.min_width = win->Width; size.min_height = win->Height; } if (win->Property & wsMaxSize) { size.flags |= PMaxSize; size.max_width = win->Width; size.max_height = win->Height; } if (vo_keepaspect && (win->Property & wsAspect)) { size.flags |= PAspect; size.min_aspect.x = win->Width; size.min_aspect.y = win->Height; size.max_aspect.x = win->Width; size.max_aspect.y = win->Height; } size.flags |= PBaseSize; size.base_width = 0; size.base_height = 0; size.flags |= PWinGravity; size.win_gravity = StaticGravity; XSetWMNormalHints(wsDisplay, win->WindowID, &size); } static void wsWindowDecoration(wsWindow *win) { Atom wsMotifHints; struct { unsigned long flags; unsigned long functions; unsigned long decorations; long input_mode; unsigned long status; } wsMotifWmHints; wsMotifHints = XInternAtom(wsDisplay, "_MOTIF_WM_HINTS", 0); if (wsMotifHints == None) return; memset(&wsMotifWmHints, 0, sizeof(wsMotifWmHints)); wsMotifWmHints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; if (win->Decoration) { wsMotifWmHints.functions = MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE; if (!(win->Property & wsMinSize) || !(win->Property & wsMaxSize)) wsMotifWmHints.functions |= MWM_FUNC_RESIZE; wsMotifWmHints.decorations = MWM_DECOR_ALL; } XChangeProperty(wsDisplay, win->WindowID, wsMotifHints, wsMotifHints, 32, PropModeReplace, (unsigned char *)&wsMotifWmHints, 5); } /** * @brief Wait until a window is mapped if its property requires it. * * @param win pointer to a ws window structure */ static void wsWindowMapWait(wsWindow *win) { XEvent xev; if (win->Property & wsWaitMap) { do { XNextEvent(wsDisplay, &xev); wsEvent(&xev); } while (xev.type != MapNotify || xev.xmap.event != win->WindowID); win->Mapped = wsMapped; } } // ---------------------------------------------------------------------------------------------- // Create window. // X,Y : window position // wX,wY : size of window // bW : border width // cV : visible mouse cursor on window // D : visible frame, title, etc. // sR : screen ratio // ---------------------------------------------------------------------------------------------- XClassHint wsClassHint; XTextProperty wsTextProperty; Window LeaderWindow; // ---------------------------------------------------------------------------------------------- // wsWindowCreate: create a new window on the screen. // x,y : window position // w,h : window size // c : mouse cursor visible // p : properties - "decoration", visible titlebar, etc ... // ---------------------------------------------------------------------------------------------- void wsWindowCreate(wsWindow *win, int x, int y, int w, int h, int p, int c, char *label) { int i, depth; for (i = 0; i < wsWLCount; i++) if (wsWindowList[i] == NULL) break; if (i == wsWLCount) { mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_TooManyOpenWindows); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } wsWindowList[i] = win; win->Property = p; win->Decoration = ((p & wsShowFrame) != 0); wsWindowUpdatePosition(win, x, y, w, h); win->Width = w; win->Height = h; win->OldX = win->X; win->OldY = win->Y; win->OldWidth = win->Width; win->OldHeight = win->Height; /* Hide Mouse Cursor */ win->wsCursor = None; win->wsMouseEventType = c; win->wsCursorData[0] = 0; win->wsCursorPixmap = XCreateBitmapFromData(wsDisplay, wsRootWin, win->wsCursorData, 1, 1); if (!(c & wsShowMouseCursor)) win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0); depth = vo_find_depth_from_visuals(wsDisplay, wsScreen, NULL); if (depth < 15) { mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ColorDepthTooLow); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } XMatchVisualInfo(wsDisplay, wsScreen, depth, TrueColor, &win->VisualInfo); /* --- */ win->AtomLeaderClient = XInternAtom(wsDisplay, "WM_CLIENT_LEADER", False); win->AtomDeleteWindow = XInternAtom(wsDisplay, "WM_DELETE_WINDOW", False); win->AtomTakeFocus = XInternAtom(wsDisplay, "WM_TAKE_FOCUS", False); win->AtomRolle = XInternAtom(wsDisplay, "WM_WINDOW_ROLE", False); win->AtomWMSizeHint = XInternAtom(wsDisplay, "WM_SIZE_HINT", False); win->AtomWMNormalHint = XInternAtom(wsDisplay, "WM_NORMAL_HINT", False); win->AtomProtocols = XInternAtom(wsDisplay, "WM_PROTOCOLS", False); win->AtomsProtocols[0] = win->AtomDeleteWindow; win->AtomsProtocols[1] = win->AtomTakeFocus; win->AtomsProtocols[2] = win->AtomRolle; /* --- */ win->WindowAttrib.border_pixel = WhitePixel(wsDisplay, wsScreen); win->WindowAttrib.colormap = XCreateColormap(wsDisplay, wsRootWin, win->VisualInfo.visual, AllocNone); win->WindowAttrib.event_mask = StructureNotifyMask | FocusChangeMask | ExposureMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask; if ((c & wsHandleMouseButton)) win->WindowAttrib.event_mask |= ButtonPressMask | ButtonReleaseMask; if ((c & wsHandleMouseMove)) win->WindowAttrib.event_mask |= PointerMotionMask; win->WindowAttrib.cursor = win->wsCursor; win->WindowAttrib.override_redirect = False; if (p & wsOverredirect) win->WindowAttrib.override_redirect = True; win->WindowMask = CWBorderPixel | CWColormap | CWEventMask | CWCursor | CWOverrideRedirect; win->WindowID = XCreateWindow(wsDisplay, (win->Parent != 0 ? win->Parent : wsRootWin), win->X, win->Y, win->Width, win->Height, 0, win->VisualInfo.depth, InputOutput, win->VisualInfo.visual, win->WindowMask, &win->WindowAttrib); wsClassHint.res_name = "GUI"; wsClassHint.res_class = MPlayer; XSetClassHint(wsDisplay, win->WindowID, &wsClassHint); wsWindowSizeHint(win); win->WMHints.flags = InputHint | StateHint; win->WMHints.input = True; win->WMHints.initial_state = NormalState; XSetWMHints(wsDisplay, win->WindowID, &win->WMHints); wsWindowDecoration(win); XStoreName(wsDisplay, win->WindowID, label); XmbSetWMProperties(wsDisplay, win->WindowID, label, label, NULL, 0, NULL, NULL, NULL); XSetWMProtocols(wsDisplay, win->WindowID, win->AtomsProtocols, 3); XChangeProperty(wsDisplay, win->WindowID, win->AtomLeaderClient, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&LeaderWindow, 1); wsTextProperty.value = label; wsTextProperty.encoding = XA_STRING; wsTextProperty.format = 8; wsTextProperty.nitems = strlen(label); XSetWMIconName(wsDisplay, win->WindowID, &wsTextProperty); win->wGC = XCreateGC(wsDisplay, win->WindowID, 0, NULL); win->Visible = wsNo; win->Focused = wsNo; win->Mapped = wsNo; win->Rolled = wsNo; if (p & wsShowWindow) { XMapWindow(wsDisplay, win->WindowID); wsWindowMapWait(win); } wsImageCreate(win, win->Width, win->Height); /* End of creating -------------------------------------------------------------------------- */ XFlush(wsDisplay); XSync(wsDisplay, False); win->DrawHandler = NULL; win->MouseHandler = NULL; win->KeyHandler = NULL; mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[ws] window is created. ( %s ).\n", label); } void wsWindowDestroy(wsWindow *win) { int l; l = wsWindowListSearch(win->WindowID); if (l != -1) wsWindowList[l] = NULL; win->DrawHandler = NULL; win->MouseHandler = NULL; win->KeyHandler = NULL; win->DNDHandler = NULL; if (win->wsCursor != None) { XFreeCursor(wsDisplay, win->wsCursor); win->wsCursor = None; } XFreeGC(wsDisplay, win->wGC); XUnmapWindow(wsDisplay, win->WindowID); wsImageDestroy(win); XDestroyWindow(wsDisplay, win->WindowID); #if 0 win->Visible = wsNo; win->Focused = wsNo; win->Mapped = wsNo; win->Rolled = wsNo; #endif } void wsWindowShape(wsWindow *win, char *data) { #ifdef CONFIG_XSHAPE if (!wsUseXShape) return; if (data) { win->Mask = XCreateBitmapFromData(wsDisplay, win->WindowID, data, win->Width, win->Height); XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, win->Mask, ShapeSet); XFreePixmap(wsDisplay, win->Mask); } else XShapeCombineMask(wsDisplay, win->WindowID, ShapeBounding, 0, 0, None, ShapeSet); #endif } /** * @brief Set differently sized icons to a window. * * This function sets the X icon hint as well as * the properties KWM_WIN_ICON and _NET_WM_ICON. * * @param display display * @param Win window * @param icon pointer to the icons */ void wsWindowIcon(Display *display, Window Win, guiIcon_t *icon) { XWMHints *wm; Atom iconatom; long data[2]; if (icon->normal) { wm = XGetWMHints(display, Win); if (!wm) wm = XAllocWMHints(); wm->icon_pixmap = icon->normal; wm->icon_mask = icon->normal_mask; wm->flags |= IconPixmapHint | IconMaskHint; XSetWMHints(display, Win, wm); XFree(wm); } if (icon->small || icon->normal) { iconatom = XInternAtom(display, "KWM_WIN_ICON", False); data[0] = (icon->small ? icon->small : icon->normal); data[1] = (icon->small ? icon->small_mask : icon->normal_mask); XChangeProperty(display, Win, iconatom, iconatom, 32, PropModeReplace, (unsigned char *)data, 2); } if (icon->collection) { iconatom = XInternAtom(display, "_NET_WM_ICON", False); XChangeProperty(display, Win, iconatom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)icon->collection, icon->collection_size); } } /** * @brief Pack color components @a r, @a g and @a b into 15 bits. * * @param r red (0 - 255) * @param g green (0 - 255) * @param b blue (0 - 255) * * @return pixel suitable for a RGB 15 bits color format */ static int pack_rgb15(int r, int g, int b) { int pixel; pixel = r >> 3; pixel <<= 5; pixel |= g >> 3; pixel <<= 5; pixel |= b >> 3; return pixel; } /** * @brief Pack color components @a r, @a g and @a b into 16 bits. * * @param r red (0 - 255) * @param g green (0 - 255) * @param b blue (0 - 255) * * @return pixel suitable for a RGB 16 bits color format */ static int pack_rgb16(int r, int g, int b) { int pixel; pixel = r >> 3; pixel <<= 6; pixel |= g >> 2; pixel <<= 5; pixel |= b >> 3; return pixel; } /** * @brief Set and fill, or unset a window background. * * @param win pointer to a ws window structure * @param r red (0 - 255, or -1) * @param g green (0 - 255, or -1) * @param b blue (0 - 255, or -1) * * @note Passing -1 for @a r, @a g and @a b unsets the background. */ void wsWindowBackground(wsWindow *win, int r, int g, int b) { int color = 0; switch (out_pix_fmt) { case PIX_FMT_RGB32: case PIX_FMT_RGB24: color = (r << 16) + (g << 8) + b; break; case PIX_FMT_BGR32: case PIX_FMT_BGR24: color = (b << 16) + (g << 8) + r; break; case PIX_FMT_RGB565: color = pack_rgb16(r, g, b); break; case PIX_FMT_BGR565: color = pack_rgb16(b, g, r); break; case PIX_FMT_RGB555: color = pack_rgb15(r, g, b); break; case PIX_FMT_BGR555: color = pack_rgb15(b, g, r); break; default: ; } if (r == -1 && g == -1 && b == -1) XSetWindowBackgroundPixmap(wsDisplay, win->WindowID, None); else { XSetWindowBackground(wsDisplay, win->WindowID, color); XClearWindow(wsDisplay, win->WindowID); } } // ---------------------------------------------------------------------------------------------- // Move window to x, y. // ---------------------------------------------------------------------------------------------- void wsWindowMove(wsWindow *win, Bool abs, int x, int y) { if (abs) { win->X = x; win->Y = y; } else wsWindowUpdatePosition(win, x, y, win->Width, win->Height); wsWindowSizeHint(win); XMoveWindow(wsDisplay, win->WindowID, win->X, win->Y); } /** * @brief Move the window to the x and y position, but if it no longer fits * into the screen, reposition it towards the upper left. * * @param win pointer to a ws window structure * @param abs flag whether the position is real/absolute (True) or mock (False) * @param x x position of the window (real/absolute or mock) * @param y y position of the window (real/absolute or mock) */ void wsWindowMoveWithin(wsWindow *win, Bool abs, int x, int y) { Bool fitting = True; wsWindowMove(win, abs, x, y); if (win->X + win->Width + 1 > wsMaxX) { fitting = False; win->X = wsMaxX - win->Width; if (win->X < 0) win->X = 0; } if (win->Y + win->Height + 1 > wsMaxY) { fitting = False; win->Y = wsMaxY - win->Height; if (win->Y < 0) win->Y = 0; } if (!fitting) wsWindowMove(win, True, win->X, win->Y); } // ---------------------------------------------------------------------------------------------- // Resize window to sx, sy. // ---------------------------------------------------------------------------------------------- void wsWindowResize(wsWindow *win, int w, int h) { win->Width = w; win->Height = h; if (vo_wm_type == 0) XUnmapWindow(wsDisplay, win->WindowID); wsWindowSizeHint(win); XResizeWindow(wsDisplay, win->WindowID, w, h); if (vo_wm_type == 0) XMapWindow(wsDisplay, win->WindowID); } /** * @brief Switch window fullscreen state. * * Switch normal window to fullscreen and fullscreen window to normal. * * @param win pointer to a ws window structure */ void wsWindowFullscreen(wsWindow *win) { if (win->isFullScreen) { if (vo_fs_type & vo_wm_FULLSCREEN) /* window manager supports EWMH */ vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_REMOVE); else { win->X = win->OldX; win->Y = win->OldY; win->Width = win->OldWidth; win->Height = win->OldHeight; } win->isFullScreen = False; } else { if (vo_fs_type & vo_wm_FULLSCREEN) /* window manager supports EWMH */ vo_x11_ewmh_fullscreen(win->WindowID, _NET_WM_STATE_ADD); else { win->OldX = win->X; win->OldY = win->Y; win->OldWidth = win->Width; win->OldHeight = win->Height; } win->isFullScreen = True; wsWindowUpdateXinerama(win); } /* unknown window manager and obsolete option -fsmode used */ if (vo_wm_type == 0 && !(vo_fsmode & 16)) { XUnmapWindow(wsDisplay, win->WindowID); // required for MWM XWithdrawWindow(wsDisplay, win->WindowID, wsScreen); } /* restore window if window manager doesn't support EWMH */ if (!(vo_fs_type & vo_wm_FULLSCREEN)) { if (!win->isFullScreen) wsWindowDecoration(win); wsWindowSizeHint(win); wsWindowLayer(wsDisplay, win->WindowID, win->isFullScreen); XMoveResizeWindow(wsDisplay, win->WindowID, win->X, win->Y, win->Width, win->Height); } /* some window managers lose ontop after fullscreen */ if (!win->isFullScreen & vo_ontop) wsWindowLayer(wsDisplay, win->WindowID, vo_ontop); wsWindowRaiseTop(wsDisplay, win->WindowID); XFlush(wsDisplay); } /** * @brief Iconify a window. * * @param win pointer to a ws window structure */ void wsWindowIconify(wsWindow *win) { XIconifyWindow(wsDisplay, win->WindowID, 0); } void wsWindowVisibility(wsWindow *win, int vis) { switch (vis) { case wsShowWindow: XMapRaised(wsDisplay, win->WindowID); wsWindowMapWait(win); if (vo_fs_type & vo_wm_FULLSCREEN) win->isFullScreen = False; break; case wsHideWindow: XUnmapWindow(wsDisplay, win->WindowID); break; } XFlush(wsDisplay); } /** * @brief Map a window and raise it to the top. * * @param display display * @param Win window */ void wsWindowRaiseTop(Display *display, Window Win) { XMapRaised(display, Win); // NOTE TO MYSELF: is that really enough? XRaiseWindow(display, Win); // NOTE TO MYSELF: is that really enough? } // ---------------------------------------------------------------------------------------------- // Move window to selected layer // ---------------------------------------------------------------------------------------------- /** * @brief Set the layer for a window. * * @param display display * @param Win window * @param fullscreen whether to set fullscreen or normal layer */ void wsWindowLayer(Display *display, Window Win, Bool fullscreen) { vo_x11_setlayer(display, Win, fullscreen); } // ---------------------------------------------------------------------------------------------- // Redraw screen. // ---------------------------------------------------------------------------------------------- void wsWindowRedraw(wsWindow *win) { if (win->DrawHandler) { win->State = wsWindowExpose; win->DrawHandler(); XFlush(wsDisplay); } } // ---------------------------------------------------------------------------------------------- // Put 'Image' to window. // ---------------------------------------------------------------------------------------------- void wsImageCreate(wsWindow *win, int w, int h) { #ifdef HAVE_SHM if (wsUseXShm) { win->xImage = XShmCreateImage(wsDisplay, win->VisualInfo.visual, win->VisualInfo.depth, ZPixmap, NULL, &win->Shminfo, w, h); if (win->xImage == NULL) { mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ShmError); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } win->Shminfo.shmid = shmget(IPC_PRIVATE, win->xImage->bytes_per_line * win->xImage->height, IPC_CREAT | 0777); if (win->Shminfo.shmid < 0) { XDestroyImage(win->xImage); mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ShmError); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } win->Shminfo.shmaddr = (char *)shmat(win->Shminfo.shmid, 0, 0); if (win->Shminfo.shmaddr == ((char *)-1)) { XDestroyImage(win->xImage); if (win->Shminfo.shmaddr != ((char *)-1)) shmdt(win->Shminfo.shmaddr); mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_ShmError); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } win->xImage->data = win->Shminfo.shmaddr; win->Shminfo.readOnly = False; XShmAttach(wsDisplay, &win->Shminfo); XSync(wsDisplay, False); shmctl(win->Shminfo.shmid, IPC_RMID, 0); } else #endif { win->xImage = XCreateImage(wsDisplay, win->VisualInfo.visual, win->VisualInfo.depth, ZPixmap, 0, 0, w, h, (wsScreenDepth == 3) ? 32 : wsScreenDepth, 0); if ((win->xImage->data = malloc(win->xImage->bytes_per_line * win->xImage->height)) == NULL) { mp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_WS_NotEnoughMemoryDrawBuffer); mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0); } } win->ImageData = (unsigned char *)win->xImage->data; win->ImageDataw = (unsigned short int *)win->xImage->data; win->ImageDatadw = (unsigned int *)win->xImage->data; } void wsImageDestroy(wsWindow *win) { if (win->xImage) { XDestroyImage(win->xImage); #ifdef HAVE_SHM if (wsUseXShm) { XShmDetach(wsDisplay, &win->Shminfo); shmdt(win->Shminfo.shmaddr); } #endif } win->xImage = NULL; } void wsImageRender(wsWindow *win, unsigned char *img) { static struct SwsContext *sws_ctx; const uint8_t *src[4] = { img, NULL, NULL, NULL }; int src_stride[4] = { 4 * win->xImage->width, 0, 0, 0 }; uint8_t *dst[4] = { win->ImageData, NULL, NULL, NULL }; int dst_stride[4]; int i; sws_ctx = sws_getCachedContext(sws_ctx, win->xImage->width, win->xImage->height, PIX_FMT_RGB32, win->xImage->width, win->xImage->height, out_pix_fmt, SWS_POINT, NULL, NULL, NULL); av_image_fill_linesizes(dst_stride, out_pix_fmt, win->xImage->width); sws_scale(sws_ctx, src, src_stride, 0, win->xImage->height, dst, dst_stride); if (!wsNonNativeOrder) return; switch (win->xImage->bits_per_pixel) { case 32: { uint32_t *d = (uint32_t *)win->ImageData; for (i = 0; i < win->xImage->width * win->xImage->height; i++) d[i] = bswap_32(d[i]); break; } case 16: case 15: { uint16_t *d = (uint16_t *)win->ImageData; for (i = 0; i < win->xImage->width * win->xImage->height; i++) d[i] = bswap_16(d[i]); break; } } } void wsImageDraw(wsWindow *win) { #ifdef HAVE_SHM if (wsUseXShm) { XShmPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage, 0, 0, (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2, win->xImage->width, win->xImage->height, 0); } else #endif { XPutImage(wsDisplay, win->WindowID, win->wGC, win->xImage, 0, 0, (win->Width - win->xImage->width) / 2, (win->Height - win->xImage->height) / 2, win->xImage->width, win->xImage->height); } } void wsImageResize(wsWindow *win, int w, int h) { wsImageDestroy(win); wsImageCreate(win, w, h); } // ---------------------------------------------------------------------------------------------- // Show / hide mouse cursor. // ---------------------------------------------------------------------------------------------- void wsMouseVisibility(wsWindow *win, int vis) { switch (vis) { case wsShowMouseCursor: if (win->wsCursor != None) { XFreeCursor(wsDisplay, win->wsCursor); win->wsCursor = None; } XDefineCursor(wsDisplay, win->WindowID, 0); break; case wsHideMouseCursor: win->wsCursor = XCreatePixmapCursor(wsDisplay, win->wsCursorPixmap, win->wsCursorPixmap, &win->wsColor, &win->wsColor, 0, 0); XDefineCursor(wsDisplay, win->WindowID, win->wsCursor); break; } XFlush(wsDisplay); } /** * @brief Handle automatic hiding of the cursor. */ void wsMouseAutohide(void) { if (mouse_win && (GetTimerMS() - mouse_time >= MOUSEHIDE_DELAY)) { wsMouseVisibility(mouse_win, wsHideMouseCursor); mouse_win = NULL; } }