diff options
author | wm4 <wm4@nowhere> | 2012-11-05 17:02:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-12 20:06:14 +0100 |
commit | d4bdd0473d6f43132257c9fb3848d829755167a3 (patch) | |
tree | 8021c2f7da1841393c8c832105e20cd527826d6c /video/out/x11_common.c | |
parent | bd48deba77bd5582c5829d6fe73a7d2571088aba (diff) | |
download | mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.bz2 mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.xz |
Rename directories, move files (step 1 of 2) (does not compile)
Tis drops the silly lib prefixes, and attempts to organize the tree in
a more logical way. Make the top-level directory less cluttered as
well.
Renames the following directories:
libaf -> audio/filter
libao2 -> audio/out
libvo -> video/out
libmpdemux -> demux
Split libmpcodecs:
vf* -> video/filter
vd*, dec_video.* -> video/decode
mp_image*, img_format*, ... -> video/
ad*, dec_audio.* -> audio/decode
libaf/format.* is moved to audio/ - this is similar to how mp_image.*
is located in video/.
Move most top-level .c/.h files to core. (talloc.c/.h is left on top-
level, because it's external.) Park some of the more annoying files
in compat/. Some of these are relicts from the time mplayer used
ffmpeg internals.
sub/ is not split, because it's too much of a mess (subtitle code is
mixed with OSD display and rendering).
Maybe the organization of core is not ideal: it mixes playback core
(like mplayer.c) and utility helpers (like bstr.c/h). Should the need
arise, the playback core will be moved somewhere else, while core
contains all helper and common code.
Diffstat (limited to 'video/out/x11_common.c')
-rw-r--r-- | video/out/x11_common.c | 2404 |
1 files changed, 2404 insertions, 0 deletions
diff --git a/video/out/x11_common.c b/video/out/x11_common.c new file mode 100644 index 0000000000..04d5c6880b --- /dev/null +++ b/video/out/x11_common.c @@ -0,0 +1,2404 @@ +/* + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <inttypes.h> +#include <limits.h> + +#include "config.h" +#include "bstr.h" +#include "options.h" +#include "mp_msg.h" +#include "mp_fifo.h" +#include "libavutil/common.h" +#include "x11_common.h" +#include "talloc.h" + +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include "video_out.h" +#include "aspect.h" +#include "geometry.h" +#include "osdep/timer.h" + +#include <X11/Xmd.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#ifdef CONFIG_XSS +#include <X11/extensions/scrnsaver.h> +#endif + +#ifdef CONFIG_XDPMS +#include <X11/extensions/dpms.h> +#endif + +#ifdef CONFIG_XINERAMA +#include <X11/extensions/Xinerama.h> +#endif + +#ifdef CONFIG_XF86VM +#include <X11/extensions/xf86vmode.h> +#endif + +#ifdef CONFIG_XF86XK +#include <X11/XF86keysym.h> +#endif + +#ifdef CONFIG_XV +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> + +#include "subopt-helper.h" +#endif + +#include "input/input.h" +#include "input/keycodes.h" + +#define WIN_LAYER_ONBOTTOM 2 +#define WIN_LAYER_NORMAL 4 +#define WIN_LAYER_ONTOP 6 +#define WIN_LAYER_ABOVE_DOCK 10 + +int fs_layer = WIN_LAYER_ABOVE_DOCK; + +int stop_xscreensaver = 1; + +static int dpms_disabled = 0; + +char *mDisplayName = NULL; + +char **vo_fstype_list; + +/* 1 means that the WM is metacity (broken as hell) */ +int metacity_hack = 0; + +#ifdef CONFIG_XF86VM +static int modecount; +static XF86VidModeModeInfo **vidmodes; +static XF86VidModeModeLine modeline; +#endif + +static int vo_x11_get_fs_type(int supported); +static void saver_off(Display *); +static void saver_on(Display *); + +/* + * Sends the EWMH fullscreen state event. + * + * action: could be one of _NET_WM_STATE_REMOVE -- remove state + * _NET_WM_STATE_ADD -- add state + * _NET_WM_STATE_TOGGLE -- toggle + */ +void vo_x11_ewmh_fullscreen(struct vo_x11_state *x11, int action) +{ + assert(action == _NET_WM_STATE_REMOVE || + action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE); + + if (x11->fs_type & vo_wm_FULLSCREEN) + { + XEvent xev; + + /* init X event structure for _NET_WM_FULLSCREEN client message */ + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.message_type = x11->XA_NET_WM_STATE; + xev.xclient.window = x11->window; + xev.xclient.format = 32; + xev.xclient.data.l[0] = action; + xev.xclient.data.l[1] = x11->XA_NET_WM_STATE_FULLSCREEN; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + /* finally send that damn thing */ + if (!XSendEvent(x11->display, DefaultRootWindow(x11->display), False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev)) + { + mp_tmsg(MSGT_VO, MSGL_ERR, "\nX11: Couldn't send EWMH fullscreen event!\n"); + } + } +} + +static void vo_hidecursor(Display * disp, Window win) +{ + Cursor no_ptr; + Pixmap bm_no; + XColor black, dummy; + Colormap colormap; + const char bm_no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + if (WinID == 0) + return; // do not hide if playing on the root window + + colormap = DefaultColormap(disp, DefaultScreen(disp)); + if ( !XAllocNamedColor(disp, colormap, "black", &black, &dummy) ) + { + return; // color alloc failed, give up + } + bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8); + no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0); + XDefineCursor(disp, win, no_ptr); + XFreeCursor(disp, no_ptr); + if (bm_no != None) + XFreePixmap(disp, bm_no); + XFreeColors(disp,colormap,&black.pixel,1,0); +} + +static void vo_showcursor(Display * disp, Window win) +{ + if (WinID == 0) + return; + XDefineCursor(disp, win, 0); +} + +static int x11_errorhandler(Display * display, XErrorEvent * event) +{ +#define MSGLEN 60 + char msg[MSGLEN]; + + XGetErrorText(display, event->error_code, (char *) &msg, MSGLEN); + + mp_msg(MSGT_VO, MSGL_ERR, "X11 error: %s\n", msg); + + mp_msg(MSGT_VO, MSGL_V, + "Type: %x, display: %p, resourceid: %lx, serial: %lx\n", + event->type, event->display, event->resourceid, event->serial); + mp_msg(MSGT_VO, MSGL_V, + "Error code: %x, request code: %x, minor code: %x\n", + event->error_code, event->request_code, event->minor_code); + +// abort(); + return 0; +#undef MSGLEN +} + +void fstype_help(void) +{ + mp_tmsg(MSGT_VO, MSGL_INFO, "Available fullscreen layer change modes:\n"); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FULL_SCREEN_TYPES\n"); + + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "none", + "don't set fullscreen window layer"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer", + "use _WIN_LAYER hint with default layer"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer=<0..15>", + "use _WIN_LAYER hint with a given layer number"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "netwm", + "force NETWM style"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "above", + "use _NETWM_STATE_ABOVE hint if available"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "below", + "use _NETWM_STATE_BELOW hint if available"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "fullscreen", + "use _NETWM_STATE_FULLSCREEN hint if available"); + mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "stays_on_top", + "use _NETWM_STATE_STAYS_ON_TOP hint if available"); + mp_msg(MSGT_VO, MSGL_INFO, + "You can also negate the settings with simply putting '-' in the beginning"); + mp_msg(MSGT_VO, MSGL_INFO, "\n"); +} + +static void fstype_dump(int fstype) +{ + if (fstype) + { + mp_msg(MSGT_VO, MSGL_V, "[x11] Current fstype setting honours"); + if (fstype & vo_wm_LAYER) + mp_msg(MSGT_VO, MSGL_V, " LAYER"); + if (fstype & vo_wm_FULLSCREEN) + mp_msg(MSGT_VO, MSGL_V, " FULLSCREEN"); + if (fstype & vo_wm_STAYS_ON_TOP) + mp_msg(MSGT_VO, MSGL_V, " STAYS_ON_TOP"); + if (fstype & vo_wm_ABOVE) + mp_msg(MSGT_VO, MSGL_V, " ABOVE"); + if (fstype & vo_wm_BELOW) + mp_msg(MSGT_VO, MSGL_V, " BELOW"); + mp_msg(MSGT_VO, MSGL_V, " X atoms\n"); + } else + mp_msg(MSGT_VO, MSGL_V, + "[x11] Current fstype setting doesn't honour any X atoms\n"); +} + +static int net_wm_support_state_test(struct vo_x11_state *x11, Atom atom) +{ +#define NET_WM_STATE_TEST(x) { if (atom == x11->XA_NET_WM_STATE_##x) { mp_msg( MSGT_VO,MSGL_V, "[x11] Detected wm supports " #x " state.\n" ); return vo_wm_##x; } } + + NET_WM_STATE_TEST(FULLSCREEN); + NET_WM_STATE_TEST(ABOVE); + NET_WM_STATE_TEST(STAYS_ON_TOP); + NET_WM_STATE_TEST(BELOW); + return 0; +} + +static int x11_get_property(struct vo_x11_state *x11, Atom type, Atom ** args, + unsigned long *nitems) +{ + int format; + unsigned long bytesafter; + + return Success == + XGetWindowProperty(x11->display, x11->rootwin, type, 0, 16384, False, + AnyPropertyType, &type, &format, nitems, + &bytesafter, (unsigned char **) args) + && *nitems > 0; +} + +static int vo_wm_detect(struct vo *vo) +{ + struct vo_x11_state *x11 = vo->x11; + int i; + int wm = 0; + unsigned long nitems; + Atom *args = NULL; + + if (WinID >= 0) + return 0; + +// -- supports layers + if (x11_get_property(x11, x11->XA_WIN_PROTOCOLS, &args, &nitems)) + { + mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports layers.\n"); + for (i = 0; i < nitems; i++) + { + if (args[i] == x11->XA_WIN_LAYER) + { + wm |= vo_wm_LAYER; + metacity_hack |= 1; + } else + /* metacity is the only window manager I know which reports + * supporting only the _WIN_LAYER hint in _WIN_PROTOCOLS. + * (what's more support for it is broken) */ + metacity_hack |= 2; + } + XFree(args); + if (wm && (metacity_hack == 1)) + { + // metacity claims to support layers, but it is not the truth :-) + wm ^= vo_wm_LAYER; + mp_msg(MSGT_VO, MSGL_V, + "[x11] Using workaround for Metacity bugs.\n"); + } + } +// --- netwm + if (x11_get_property(x11, x11->XA_NET_SUPPORTED, &args, &nitems)) + { + mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports NetWM.\n"); + for (i = 0; i < nitems; i++) + wm |= net_wm_support_state_test(vo->x11, args[i]); + XFree(args); + } + + if (wm == 0) + mp_msg(MSGT_VO, MSGL_V, "[x11] Unknown wm type...\n"); + return wm; +} + +#define XA_INIT(x) x11->XA##x = XInternAtom(x11->display, #x, False) +static void init_atoms(struct vo_x11_state *x11) +{ + XA_INIT(_NET_SUPPORTED); + XA_INIT(_NET_WM_STATE); + XA_INIT(_NET_WM_STATE_FULLSCREEN); + XA_INIT(_NET_WM_STATE_ABOVE); + XA_INIT(_NET_WM_STATE_STAYS_ON_TOP); + XA_INIT(_NET_WM_STATE_BELOW); + XA_INIT(_NET_WM_PID); + XA_INIT(_NET_WM_NAME); + XA_INIT(_NET_WM_ICON_NAME); + XA_INIT(_WIN_PROTOCOLS); + XA_INIT(_WIN_LAYER); + XA_INIT(_WIN_HINTS); + XA_INIT(WM_PROTOCOLS); + XA_INIT(WM_DELETE_WINDOW); + XA_INIT(UTF8_STRING); + char buf[50]; + sprintf(buf, "_NET_WM_CM_S%d", x11->screen); + x11->XA_NET_WM_CM = XInternAtom(x11->display, buf, False); +} + +void update_xinerama_info(struct vo *vo) { + struct MPOpts *opts = vo->opts; + xinerama_x = xinerama_y = 0; +#ifdef CONFIG_XINERAMA + if (xinerama_screen >= -1 && XineramaIsActive(vo->x11->display)) + { + int screen = xinerama_screen; + XineramaScreenInfo *screens; + int num_screens; + + screens = XineramaQueryScreens(vo->x11->display, &num_screens); + if (screen >= num_screens) + screen = num_screens - 1; + if (screen == -1) { + int x = vo->dx + vo->dwidth / 2; + int y = vo->dy + vo->dheight / 2; + for (screen = num_screens - 1; screen > 0; screen--) { + int left = screens[screen].x_org; + int right = left + screens[screen].width; + int top = screens[screen].y_org; + int bottom = top + screens[screen].height; + if (left <= x && x <= right && top <= y && y <= bottom) + break; + } + } + if (screen < 0) + screen = 0; + opts->vo_screenwidth = screens[screen].width; + opts->vo_screenheight = screens[screen].height; + xinerama_x = screens[screen].x_org; + xinerama_y = screens[screen].y_org; + + XFree(screens); + } +#endif + aspect_save_screenres(vo, opts->vo_screenwidth, opts->vo_screenheight); +} + +int vo_init(struct vo *vo) +{ + struct MPOpts *opts = vo->opts; +// int mScreen; + int depth, bpp; + unsigned int mask; + +// char * DisplayName = ":0.0"; +// Display * mDisplay; + XImage *mXImage = NULL; + +// Window mRootWin; + XWindowAttributes attribs; + char *dispName; + + if (vo->x11) + return 1; + + vo->x11 = vo_x11_init_state(); + struct vo_x11_state *x11 = vo->x11; + + if (vo_rootwin) + WinID = 0; // use root window + + if (x11->depthonscreen) + { + saver_off(x11->display); + return 1; // already called + } + + XSetErrorHandler(x11_errorhandler); + +#if 0 + if (!mDisplayName) + if (!(mDisplayName = getenv("DISPLAY"))) + mDisplayName = strdup(":0.0"); +#else + dispName = XDisplayName(mDisplayName); +#endif + + mp_msg(MSGT_VO, MSGL_V, "X11 opening display: %s\n", dispName); + + x11->display = XOpenDisplay(dispName); + if (!x11->display) + { + mp_msg(MSGT_VO, MSGL_ERR, + "vo: couldn't open the X11 display (%s)!\n", dispName); + talloc_free(x11); + vo->x11 = NULL; + return 0; + } + x11->screen = DefaultScreen(x11->display); // screen ID + x11->rootwin = RootWindow(x11->display, x11->screen); // root window ID + + x11->xim = XOpenIM(x11->display, NULL, NULL, NULL); + + init_atoms(vo->x11); + +#ifdef CONFIG_XF86VM + { + int clock; + + XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline); + if (!opts->vo_screenwidth) + opts->vo_screenwidth = modeline.hdisplay; + if (!opts->vo_screenheight) + opts->vo_screenheight = modeline.vdisplay; + } +#endif + { + if (!opts->vo_screenwidth) + opts->vo_screenwidth = DisplayWidth(x11->display, x11->screen); + if (!opts->vo_screenheight) + opts->vo_screenheight = DisplayHeight(x11->display, x11->screen); + } + // get color depth (from root window, or the best visual): + XGetWindowAttributes(x11->display, x11->rootwin, &attribs); + depth = attribs.depth; + + if (depth != 15 && depth != 16 && depth != 24 && depth != 32) + { + Visual *visual; + + depth = vo_find_depth_from_visuals(x11->display, x11->screen, &visual); + if (depth != -1) + mXImage = XCreateImage(x11->display, visual, depth, ZPixmap, + 0, NULL, 1, 1, 8, 1); + } else + mXImage = + XGetImage(x11->display, x11->rootwin, 0, 0, 1, 1, AllPlanes, ZPixmap); + + x11->depthonscreen = depth; // display depth on screen + + // get bits/pixel from XImage structure: + if (mXImage == NULL) + { + mask = 0; + } else + { + /* + * for the depth==24 case, the XImage structures might use + * 24 or 32 bits of data per pixel. The x11->depthonscreen + * field stores the amount of data per pixel in the + * XImage structure! + * + * Maybe we should rename vo_depthonscreen to (or add) vo_bpp? + */ + bpp = mXImage->bits_per_pixel; + if ((x11->depthonscreen + 7) / 8 != (bpp + 7) / 8) + x11->depthonscreen = bpp; // by A'rpi + mask = + mXImage->red_mask | mXImage->green_mask | mXImage->blue_mask; + mp_msg(MSGT_VO, MSGL_V, + "vo: X11 color mask: %X (R:%lX G:%lX B:%lX)\n", mask, + mXImage->red_mask, mXImage->green_mask, mXImage->blue_mask); + XDestroyImage(mXImage); + } + if (((x11->depthonscreen + 7) / 8) == 2) + { + if (mask == 0x7FFF) + x11->depthonscreen = 15; + else if (mask == 0xFFFF) + x11->depthonscreen = 16; + } +// XCloseDisplay( mDisplay ); +/* slightly improved local display detection AST */ + if (strncmp(dispName, "unix:", 5) == 0) + dispName += 4; + else if (strncmp(dispName, "localhost:", 10) == 0) + dispName += 9; + if (*dispName == ':' && atoi(dispName + 1) < 10) + x11->display_is_local = 1; + else + x11->display_is_local = 0; + mp_msg(MSGT_VO, MSGL_V, + "vo: X11 running at %dx%d with depth %d and %d bpp (\"%s\" => %s display)\n", + opts->vo_screenwidth, opts->vo_screenheight, depth, x11->depthonscreen, + dispName, x11->display_is_local ? "local" : "remote"); + + x11->wm_type = vo_wm_detect(vo); + + x11->fs_type = vo_x11_get_fs_type(x11->wm_type); + + fstype_dump(x11->fs_type); + + saver_off(x11->display); + return 1; +} + +void vo_uninit(struct vo_x11_state *x11) +{ + if (!x11) + return; + if (!x11->display) + { + mp_msg(MSGT_VO, MSGL_V, + "vo: x11 uninit called but X11 not initialized..\n"); + } else { + mp_msg(MSGT_VO, MSGL_V, "vo: uninit ...\n"); + if (x11->xim) + XCloseIM(x11->xim); + XSetErrorHandler(NULL); + XCloseDisplay(x11->display); + x11->depthonscreen = 0; + x11->display = NULL; + } + talloc_free(x11); +} + +static const struct mp_keymap keymap[] = { + // special keys + {XK_Pause, KEY_PAUSE}, {XK_Escape, KEY_ESC}, {XK_BackSpace, KEY_BS}, + {XK_Tab, KEY_TAB}, {XK_Return, KEY_ENTER}, + {XK_Menu, KEY_MENU}, {XK_Print, KEY_PRINT}, + + // cursor keys + {XK_Left, KEY_LEFT}, {XK_Right, KEY_RIGHT}, {XK_Up, KEY_UP}, {XK_Down, KEY_DOWN}, + + // navigation block + {XK_Insert, KEY_INSERT}, {XK_Delete, KEY_DELETE}, {XK_Home, KEY_HOME}, {XK_End, KEY_END}, + {XK_Page_Up, KEY_PAGE_UP}, {XK_Page_Down, KEY_PAGE_DOWN}, + + // F-keys + {XK_F1, KEY_F+1}, {XK_F2, KEY_F+2}, {XK_F3, KEY_F+3}, {XK_F4, KEY_F+4}, + {XK_F5, KEY_F+5}, {XK_F6, KEY_F+6}, {XK_F7, KEY_F+7}, {XK_F8, KEY_F+8}, + {XK_F9, KEY_F+9}, {XK_F10, KEY_F+10}, {XK_F11, KEY_F+11}, {XK_F12, KEY_F+12}, + + // numpad independent of numlock + {XK_KP_Subtract, '-'}, {XK_KP_Add, '+'}, {XK_KP_Multiply, '*'}, {XK_KP_Divide, '/'}, + {XK_KP_Enter, KEY_KPENTER}, + + // numpad with numlock + {XK_KP_0, KEY_KP0}, {XK_KP_1, KEY_KP1}, {XK_KP_2, KEY_KP2}, + {XK_KP_3, KEY_KP3}, {XK_KP_4, KEY_KP4}, {XK_KP_5, KEY_KP5}, + {XK_KP_6, KEY_KP6}, {XK_KP_7, KEY_KP7}, {XK_KP_8, KEY_KP8}, + {XK_KP_9, KEY_KP9}, {XK_KP_Decimal, KEY_KPDEC}, + {XK_KP_Separator, KEY_KPDEC}, + + // numpad without numlock + {XK_KP_Insert, KEY_KPINS}, {XK_KP_End, KEY_KP1}, {XK_KP_Down, KEY_KP2}, + {XK_KP_Page_Down, KEY_KP3}, {XK_KP_Left, KEY_KP4}, {XK_KP_Begin, KEY_KP5}, + {XK_KP_Right, KEY_KP6}, {XK_KP_Home, KEY_KP7}, {XK_KP_Up, KEY_KP8}, + {XK_KP_Page_Up, KEY_KP9}, {XK_KP_Delete, KEY_KPDEL}, + +#ifdef XF86XK_AudioPause + {XF86XK_MenuKB, KEY_MENU}, + {XF86XK_AudioPlay, KEY_PLAY}, {XF86XK_AudioPause, KEY_PAUSE}, {XF86XK_AudioStop, KEY_STOP}, + {XF86XK_AudioPrev, KEY_PREV}, {XF86XK_AudioNext, KEY_NEXT}, + {XF86XK_AudioMute, KEY_MUTE}, {XF86XK_AudioLowerVolume, KEY_VOLUME_DOWN}, {XF86XK_AudioRaiseVolume, KEY_VOLUME_UP}, +#endif + + {0, 0} +}; + +static int vo_x11_lookupkey(int key) +{ + static const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]"; + int mpkey = 0; + if ((key >= 'a' && key <= 'z') || + (key >= 'A' && key <= 'Z') || + (key >= '0' && key <= '9') || + (key > 0 && key < 256 && strchr(passthrough_keys, key))) + mpkey = key; + + if (!mpkey) + mpkey = lookup_keymap_table(keymap, key); + + return mpkey; +} + + +// ----- Motif header: ------- + +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) + +#define MWM_FUNC_ALL (1L << 0) +#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) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) + +#define MWM_INPUT_MODELESS 0 +#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 +#define MWM_INPUT_SYSTEM_MODAL 2 +#define MWM_INPUT_FULL_APPLICATION_MODAL 3 +#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL + +#define MWM_TEAROFF_WINDOW (1L<<0) + +typedef struct +{ + long flags; + long functions; + long decorations; + long input_mode; + long state; +} MotifWmHints; + +static MotifWmHints vo_MotifWmHints; +static Atom vo_MotifHints = None; + +void vo_x11_decoration(struct vo *vo, int d) +{ + struct vo_x11_state *x11 = vo->x11; + Atom mtype; + int mformat; + unsigned long mn, mb; + + if (!WinID) + return; + + if (vo_fsmode & 8) + { + XSetTransientForHint(x11->display, x11->window, + RootWindow(x11->display, x11->screen)); + } + + vo_MotifHints = XInternAtom(x11->display, "_MOTIF_WM_HINTS", 0); + if (vo_MotifHints != None) + { + if (!d) + { + MotifWmHints *mhints = NULL; + + XGetWindowProperty(x11->display, x11->window, + vo_MotifHints, 0, 20, False, + vo_MotifHints, &mtype, &mformat, &mn, + &mb, (unsigned char **) &mhints); + if (mhints) + { + if (mhints->flags & MWM_HINTS_DECORATIONS) + x11->olddecor = mhints->decorations; + if (mhints->flags & MWM_HINTS_FUNCTIONS) + x11->oldfuncs = mhints->functions; + XFree(mhints); + } + } + + memset(&vo_MotifWmHints, 0, sizeof(MotifWmHints)); + vo_MotifWmHints.flags = + MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + if (d) + { + vo_MotifWmHints.functions = x11->oldfuncs; + d = x11->olddecor; + } +#if 0 + vo_MotifWmHints.decorations = + d | ((vo_fsmode & 2) ? 0 : MWM_DECOR_MENU); +#else + vo_MotifWmHints.decorations = + d | ((vo_fsmode & 2) ? MWM_DECOR_MENU : 0); +#endif + XChangeProperty(x11->display, x11->window, vo_MotifHints, + vo_MotifHints, 32, + PropModeReplace, + (unsigned char *) &vo_MotifWmHints, + (vo_fsmode & 4) ? 4 : 5); + } +} + +void vo_x11_classhint(struct vo *vo, Window window, const char *name) +{ + struct MPOpts *opts = vo->opts; + struct vo_x11_state *x11 = vo->x11; + XClassHint wmClass; + pid_t pid = getpid(); + + wmClass.res_name = opts->vo_winname ? opts->vo_winname : (char *)name; + wmClass.res_class = "mpv"; + XSetClassHint(x11->display, window, &wmClass); + XChangeProperty(x11->display, window, x11->XA_NET_WM_PID, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *) &pid, 1); +} + +void vo_x11_uninit(struct vo *vo) +{ + struct vo_x11_state *x11 = vo->x11; + saver_on(x11->display); + if (x11->window != None) + vo_showcursor(x11->display, x11->window); + + if (x11->f_gc != None) + { + XFreeGC(vo->x11->display, x11->f_gc); + x11->f_gc = None; + } + { + if (x11->vo_gc != None) + { + XFreeGC(vo->x11->display, x11->vo_gc); + x11->vo_gc = None; + } + if (x11->window != None) + { + XClearWindow(x11->display, x11->window); + if (WinID < 0) + { + XEvent xev; + + if (x11->xic) + XDestroyIC(x11->xic); + x11->xic = NULL; + + XUnmapWindow(x11->display, x11->window); + XSelectInput(x11->display, x11->window, StructureNotifyMask); + XDestroyWindow(x11->display, x11->window); + do + { + XNextEvent(x11->display, &xev); + } + while (xev.type != DestroyNotify + || xev.xdestroywindow.event != x11->window); + } + x11->window = None; + } + vo_fs = 0; + x11->vo_old_width = x11->vo_old_height = 0; + x11->last_video_width = 0; + x11->last_video_height = 0; + x11->size_changed_during_fs = false; + } + vo_uninit(x11); + vo->x11 = NULL; +} + +static int check_resize(struct vo *vo) +{ + int old_w = vo->dwidth, old_h = vo->dheight; + int old_x = vo->dx, old_y = vo->dy; + int rc = 0; + vo_x11_update_geometry(vo, true); + if (vo->dwidth != old_w || vo->dheight != old_h) + rc |= VO_EVENT_RESIZE; + if (vo->dx != old_x || vo->dy != old_y) + rc |= VO_EVENT_MOVE; + return rc; +} + +int vo_x11_check_events(struct vo *vo) +{ + struct vo_x11_state *x11 = vo->x11; + struct MPOpts *opts = vo->opts; + Display *display = vo->x11->display; + int ret = 0; + XEvent Event; + + if (x11->mouse_waiting_hide && opts->cursor_autohide_delay != -1 && + (GetTimerMS() - x11->mouse_timer >= opts->cursor_autohide_delay)) { + vo_hidecursor(display, x11->window); + x11->mouse_waiting_hide = 0; + } + + if (WinID > 0) + ret |= check_resize(vo); + while (XPending(display)) + { + XNextEvent(display, &Event); +// printf("\rEvent.type=%X \n",Event.type); + switch (Event.type) + { + case Expose: + ret |= VO_EVENT_EXPOSE; + break; + case ConfigureNotify: + if (x11->window == None) + break; + ret |= check_resize(vo); + break; + case KeyPress: + { + char buf[100]; + KeySym keySym = 0; + int modifiers = 0; + if (Event.xkey.state & ShiftMask) + modifiers |= KEY_MODIFIER_SHIFT; + if (Event.xkey.state & ControlMask) + modifiers |= KEY_MODIFIER_CTRL; + if (Event.xkey.state & Mod1Mask) + modifiers |= KEY_MODIFIER_ALT; + if (Event.xkey.state & Mod4Mask) + modifiers |= KEY_MODIFIER_META; + if (x11->xic) { + Status status; + int len = Xutf8LookupString(x11->xic, &Event.xkey, buf, + sizeof(buf), &keySym, + &status); + int mpkey = vo_x11_lookupkey(keySym); + if (mpkey) { + mplayer_put_key(vo->key_fifo, mpkey | modifiers); + } else if (status == XLookupChars + || status == XLookupBoth) + { + struct bstr t = { buf, len }; + mplayer_put_key_utf8(vo->key_fifo, modifiers, t); + } + } else { + XLookupString(&Event.xkey, buf, sizeof(buf), &keySym, + &x11->compose_status); + int mpkey = vo_x11_lookupkey(keySym); + if (mpkey) + mplayer_put_key(vo->key_fifo, mpkey | modifiers); + } + ret |= VO_EVENT_KEYPRESS; + } + break; + case MotionNotify: + vo_mouse_movement(vo, Event.xmotion.x, Event.xmotion.y); + + if (opts->cursor_autohide_delay > -2) { + vo_showcursor(display, x11->window); + x11->mouse_waiting_hide = 1; + x11->mouse_timer = GetTimerMS(); + } + break; + case ButtonPress: + if (opts->cursor_autohide_delay > -2) { + vo_showcursor(display, x11->window); + x11->mouse_waiting_hide = 1; + x11->mouse_timer = GetTimerMS(); + } + mplayer_put_key(vo->key_fifo, + (MOUSE_BTN0 + Event.xbutton.button - 1) + | MP_KEY_DOWN); + break; + case ButtonRelease: + if (opts->cursor_autohide_delay > -2) { + vo_showcursor(display, x11->window); + x11->mouse_waiting_hide = 1; + x11->mouse_timer = GetTimerMS(); + } + mplayer_put_key(vo->key_fifo, + MOUSE_BTN0 + Event.xbutton.button - 1); + break; + case PropertyNotify: + { + char *name = + XGetAtomName(display, Event.xproperty.atom); + + if (!name) + break; + +// fprintf(stderr,"[ws] PropertyNotify ( 0x%x ) %s ( 0x%x )\n",vo_window,name,Event.xproperty.atom ); + + XFree(name); + } + break; + case MapNotify: + x11->vo_hint.win_gravity = x11->old_gravity; + XSetWMNormalHints(display, x11->window, &x11->vo_hint); + x11->fs_flip = 0; + break; + case DestroyNotify: + mp_msg(MSGT_VO, MSGL_WARN, "Our window was destroyed, exiting\n"); + mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); + break; + case ClientMessage: + if (Event.xclient.message_type == x11->XAWM_PROTOCOLS && + Event.xclient.data.l[0] == x11->XAWM_DELETE_WINDOW) + mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); + break; + } + } + return ret; +} + +/** + * \brief sets the size and position of the non-fullscreen window. + */ +static void vo_x11_nofs_sizepos(struct vo *vo, int x, int y, + int width, int height) +{ + struct vo_x11_state *x11 = vo->x11; + if (width == x11->last_video_width && height == x11->last_video_height) { + if (!vo->opts->force_window_position && !x11->size_changed_during_fs) + return; + } else if (vo_fs) + x11->size_changed_during_fs = true; + x11->last_video_height = height; + x11->last_video_width = width; + vo_x11_sizehint(vo, x, y, width, height, 0); + if (vo_fs) { + x11->vo_old_x = x; + x11->vo_old_y = y; + x11->vo_old_width = width; + x11->vo_old_height = height; + } + else + { + vo->dwidth = width; + vo->dheight = height; + if (vo->opts->force_window_position) + XMoveResizeWindow(vo->x11->display, vo->x11->window, x, y, width, + height); + else + XResizeWindow(vo->x11->display, vo->x11->window, width, height); + } +} + +void vo_x11_sizehint(struct vo *vo, int x, int y, int width, int height, int max) +{ + struct vo_x11_state *x11 = vo->x11; + x11->vo_hint.flags = 0; + if (vo_keepaspect) + { + x11->vo_hint.flags |= PAspect; + x11->vo_hint.min_aspect.x = width; + x11->vo_hint.min_aspect.y = height; + x11->vo_hint.max_aspect.x = width; + x11->vo_hint.max_aspect.y = height; + } + + x11->vo_hint.flags |= PPosition | PSize; + x11->vo_hint.x = x; + x11->vo_hint.y = y; + x11->vo_hint.width = width; + x11->vo_hint.height = height; + if (max) + { + x11->vo_hint.flags |= PMaxSize; + x11->vo_hint.max_width = width; + x11->vo_hint.max_height = height; + } else + { + x11->vo_hint.max_width = 0; + x11->vo_hint.max_height = 0; + } |