~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to libvo/x11_common.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:45:33 UTC
  • Revision ID: siretart@tauware.de-20060708084533-dbc155bde7122e78
imported mplayer_0.99+1.0pre7try2+cvs20060117

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
#include <stdio.h>
 
3
#include <stdlib.h>
 
4
#include <math.h>
 
5
#include <inttypes.h>
 
6
 
 
7
#include "config.h"
 
8
#include "mp_msg.h"
 
9
#include "x11_common.h"
 
10
 
 
11
#ifdef X11_FULLSCREEN
 
12
 
 
13
#include <string.h>
 
14
#include <unistd.h>
 
15
#include <sys/mman.h>
 
16
#include <signal.h>
 
17
#include <assert.h>
 
18
 
 
19
#include "video_out.h"
 
20
#include "aspect.h"
 
21
#include "geometry.h"
 
22
#include "help_mp.h"
 
23
#include "osdep/timer.h"
 
24
 
 
25
#include <X11/Xmd.h>
 
26
#include <X11/Xlib.h>
 
27
#include <X11/Xutil.h>
 
28
#include <X11/Xatom.h>
 
29
 
 
30
#ifdef HAVE_XDPMS
 
31
#include <X11/extensions/dpms.h>
 
32
#endif
 
33
 
 
34
#ifdef HAVE_XINERAMA
 
35
#include <X11/extensions/Xinerama.h>
 
36
#endif
 
37
 
 
38
#ifdef HAVE_XF86VM
 
39
#include <X11/extensions/xf86vmode.h>
 
40
#endif
 
41
 
 
42
#ifdef HAVE_XF86XK
 
43
#include <X11/XF86keysym.h>
 
44
#endif
 
45
 
 
46
#ifdef HAVE_XV
 
47
#include <X11/extensions/Xv.h>
 
48
#include <X11/extensions/Xvlib.h>
 
49
 
 
50
#include "subopt-helper.h"
 
51
#endif
 
52
 
 
53
#include "input/input.h"
 
54
#include "input/mouse.h"
 
55
 
 
56
#ifdef HAVE_NEW_GUI
 
57
#include "Gui/interface.h"
 
58
#include "mplayer.h"
 
59
#endif
 
60
 
 
61
#define WIN_LAYER_ONBOTTOM               2
 
62
#define WIN_LAYER_NORMAL                 4
 
63
#define WIN_LAYER_ONTOP                  6
 
64
#define WIN_LAYER_ABOVE_DOCK             10
 
65
 
 
66
int fs_layer = WIN_LAYER_ABOVE_DOCK;
 
67
static int orig_layer = 0;
 
68
static int old_gravity = NorthWestGravity;
 
69
 
 
70
int stop_xscreensaver = 0;
 
71
 
 
72
static int dpms_disabled = 0;
 
73
static int timeout_save = 0;
 
74
static int kdescreensaver_was_running = 0;
 
75
 
 
76
char *mDisplayName = NULL;
 
77
Display *mDisplay = NULL;
 
78
Window mRootWin;
 
79
int mScreen;
 
80
int mLocalDisplay;
 
81
 
 
82
/* output window id */
 
83
int vo_mouse_autohide = 0;
 
84
int vo_wm_type = 0;
 
85
int vo_fs_type = 0; // needs to be accessible for GUI X11 code
 
86
static int vo_fs_flip = 0;
 
87
char **vo_fstype_list;
 
88
 
 
89
/* if equal to 1 means that WM is a metacity (broken as hell) */
 
90
int metacity_hack = 0;
 
91
 
 
92
static Atom XA_NET_SUPPORTED;
 
93
static Atom XA_NET_WM_STATE;
 
94
static Atom XA_NET_WM_STATE_FULLSCREEN;
 
95
static Atom XA_NET_WM_STATE_ABOVE;
 
96
static Atom XA_NET_WM_STATE_STAYS_ON_TOP;
 
97
static Atom XA_NET_WM_STATE_BELOW;
 
98
static Atom XA_NET_WM_PID;
 
99
static Atom XA_WIN_PROTOCOLS;
 
100
static Atom XA_WIN_LAYER;
 
101
static Atom XA_WIN_HINTS;
 
102
static Atom XA_BLACKBOX_PID;
 
103
 
 
104
#define XA_INIT(x) XA##x = XInternAtom(mDisplay, #x, False)
 
105
 
 
106
static int vo_old_x = 0;
 
107
static int vo_old_y = 0;
 
108
static int vo_old_width = 0;
 
109
static int vo_old_height = 0;
 
110
 
 
111
#ifdef HAVE_XINERAMA
 
112
int xinerama_screen = 0;
 
113
int xinerama_x = 0;
 
114
int xinerama_y = 0;
 
115
#endif
 
116
#ifdef HAVE_XF86VM
 
117
XF86VidModeModeInfo **vidmodes = NULL;
 
118
XF86VidModeModeLine modeline;
 
119
#endif
 
120
 
 
121
static int vo_x11_get_fs_type(int supported);
 
122
 
 
123
 
 
124
/*
 
125
 * Sends the EWMH fullscreen state event.
 
126
 * 
 
127
 * action: could be on of _NET_WM_STATE_REMOVE -- remove state
 
128
 *                        _NET_WM_STATE_ADD    -- add state
 
129
 *                        _NET_WM_STATE_TOGGLE -- toggle
 
130
 */
 
131
void vo_x11_ewmh_fullscreen(int action)
 
132
{
 
133
    assert(action == _NET_WM_STATE_REMOVE ||
 
134
           action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE);
 
135
 
 
136
    if (vo_fs_type & vo_wm_FULLSCREEN)
 
137
    {
 
138
        XEvent xev;
 
139
 
 
140
        /* init X event structure for _NET_WM_FULLSCREEN client msg */
 
141
        xev.xclient.type = ClientMessage;
 
142
        xev.xclient.serial = 0;
 
143
        xev.xclient.send_event = True;
 
144
        xev.xclient.message_type = XInternAtom(mDisplay,
 
145
                                               "_NET_WM_STATE", False);
 
146
        xev.xclient.window = vo_window;
 
147
        xev.xclient.format = 32;
 
148
        xev.xclient.data.l[0] = action;
 
149
        xev.xclient.data.l[1] = XInternAtom(mDisplay,
 
150
                                            "_NET_WM_STATE_FULLSCREEN",
 
151
                                            False);
 
152
        xev.xclient.data.l[2] = 0;
 
153
        xev.xclient.data.l[3] = 0;
 
154
        xev.xclient.data.l[4] = 0;
 
155
 
 
156
        /* finally send that damn thing */
 
157
        if (!XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False,
 
158
                        SubstructureRedirectMask | SubstructureNotifyMask,
 
159
                        &xev))
 
160
        {
 
161
            mp_msg(MSGT_VO, MSGL_ERR, MSGTR_EwmhFullscreenStateFailed);
 
162
        }
 
163
    }
 
164
}
 
165
 
 
166
void vo_hidecursor(Display * disp, Window win)
 
167
{
 
168
    Cursor no_ptr;
 
169
    Pixmap bm_no;
 
170
    XColor black, dummy;
 
171
    Colormap colormap;
 
172
    static char bm_no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
173
 
 
174
    if (WinID == 0)
 
175
        return;                 // do not hide, if we're playing at rootwin
 
176
 
 
177
    colormap = DefaultColormap(disp, DefaultScreen(disp));
 
178
    if ( !XAllocNamedColor(disp, colormap, "black", &black, &dummy) )
 
179
    {
 
180
      return; // color alloc failed, give up
 
181
    }
 
182
    bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8);
 
183
    no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0);
 
184
    XDefineCursor(disp, win, no_ptr);
 
185
    XFreeCursor(disp, no_ptr);
 
186
    if (bm_no != None)
 
187
        XFreePixmap(disp, bm_no);
 
188
    XFreeColors(disp,colormap,&black.pixel,1,0);
 
189
}
 
190
 
 
191
void vo_showcursor(Display * disp, Window win)
 
192
{
 
193
    if (WinID == 0)
 
194
        return;
 
195
    XDefineCursor(disp, win, 0);
 
196
}
 
197
 
 
198
static int x11_errorhandler(Display * display, XErrorEvent * event)
 
199
{
 
200
#define MSGLEN 60
 
201
    char msg[MSGLEN];
 
202
 
 
203
    XGetErrorText(display, event->error_code, (char *) &msg, MSGLEN);
 
204
 
 
205
    mp_msg(MSGT_VO, MSGL_ERR, "X11 error: %s\n", msg);
 
206
 
 
207
    mp_msg(MSGT_VO, MSGL_V,
 
208
           "Type: %x, display: %p, resourceid: %lx, serial: %lx\n",
 
209
           event->type, event->display, event->resourceid, event->serial);
 
210
    mp_msg(MSGT_VO, MSGL_V,
 
211
           "Error code: %x, request code: %x, minor code: %x\n",
 
212
           event->error_code, event->request_code, event->minor_code);
 
213
 
 
214
    abort();
 
215
    //exit_player("X11 error");
 
216
#undef MSGLEN
 
217
}
 
218
 
 
219
void fstype_help(void)
 
220
{
 
221
    mp_msg(MSGT_VO, MSGL_INFO, MSGTR_AvailableFsType);
 
222
    if (identify)
 
223
      mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_FULL_SCREEN_TYPES\n");
 
224
 
 
225
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "none",
 
226
           "don't set fullscreen window layer");
 
227
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "layer",
 
228
           "use _WIN_LAYER hint with default layer");
 
229
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "layer=<0..15>",
 
230
           "use _WIN_LAYER hint with a given layer number");
 
231
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "netwm",
 
232
           "force NETWM style");
 
233
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "above",
 
234
           "use _NETWM_STATE_ABOVE hint if available");
 
235
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "below",
 
236
           "use _NETWM_STATE_BELOW hint if available");
 
237
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "fullscreen",
 
238
           "use _NETWM_STATE_FULLSCREEN hint if availale");
 
239
    mp_msg(MSGT_VO, MSGL_INFO, "    %-15s %s\n", "stays_on_top",
 
240
           "use _NETWM_STATE_STAYS_ON_TOP hint if available");
 
241
    mp_msg(MSGT_VO, MSGL_INFO,
 
242
           "You can also negate the settings with simply putting '-' in the beginning");
 
243
    mp_msg(MSGT_VO, MSGL_INFO, "\n\n");
 
244
}
 
245
 
 
246
static void fstype_dump(int fstype)
 
247
{
 
248
    if (fstype)
 
249
    {
 
250
        mp_msg(MSGT_VO, MSGL_V, "[x11] Current fstype setting honours");
 
251
        if (fstype & vo_wm_LAYER)
 
252
            mp_msg(MSGT_VO, MSGL_V, " LAYER");
 
253
        if (fstype & vo_wm_FULLSCREEN)
 
254
            mp_msg(MSGT_VO, MSGL_V, " FULLSCREEN");
 
255
        if (fstype & vo_wm_STAYS_ON_TOP)
 
256
            mp_msg(MSGT_VO, MSGL_V, " STAYS_ON_TOP");
 
257
        if (fstype & vo_wm_ABOVE)
 
258
            mp_msg(MSGT_VO, MSGL_V, " ABOVE");
 
259
        if (fstype & vo_wm_BELOW)
 
260
            mp_msg(MSGT_VO, MSGL_V, " BELOW");
 
261
        mp_msg(MSGT_VO, MSGL_V, " X atoms\n");
 
262
    } else
 
263
        mp_msg(MSGT_VO, MSGL_V,
 
264
               "[x11] Current fstype setting doesn't honour any X atoms\n");
 
265
}
 
266
 
 
267
static int net_wm_support_state_test(Atom atom)
 
268
{
 
269
#define NET_WM_STATE_TEST(x) { if (atom == XA_NET_WM_STATE_##x) { mp_msg( MSGT_VO,MSGL_V, "[x11] Detected wm supports " #x " state.\n" ); return vo_wm_##x; } }
 
270
 
 
271
    NET_WM_STATE_TEST(FULLSCREEN);
 
272
    NET_WM_STATE_TEST(ABOVE);
 
273
    NET_WM_STATE_TEST(STAYS_ON_TOP);
 
274
    NET_WM_STATE_TEST(BELOW);
 
275
    return 0;
 
276
}
 
277
 
 
278
static int x11_get_property(Atom type, Atom ** args, unsigned long *nitems)
 
279
{
 
280
    int format;
 
281
    unsigned long bytesafter;
 
282
 
 
283
    return (Success ==
 
284
            XGetWindowProperty(mDisplay, mRootWin, type, 0, 16384, False,
 
285
                               AnyPropertyType, &type, &format, nitems,
 
286
                               &bytesafter, (unsigned char **) args)
 
287
            && *nitems > 0);
 
288
}
 
289
 
 
290
static int vo_wm_detect(void)
 
291
{
 
292
    int i;
 
293
    int wm = 0;
 
294
    unsigned long nitems;
 
295
    Atom *args = NULL;
 
296
 
 
297
    if (WinID >= 0)
 
298
        return 0;
 
299
 
 
300
// -- supports layers
 
301
    if (x11_get_property(XA_WIN_PROTOCOLS, &args, &nitems))
 
302
    {
 
303
        mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports layers.\n");
 
304
        for (i = 0; i < nitems; i++)
 
305
        {
 
306
            if (args[i] == XA_WIN_LAYER)
 
307
            {
 
308
                wm |= vo_wm_LAYER;
 
309
                metacity_hack |= 1;
 
310
            } else
 
311
                // metacity is the only manager I know which reports support only for _WIN_LAYER
 
312
                // hint in _WIN_PROTOCOLS (what's more support for it is broken)
 
313
                metacity_hack |= 2;
 
314
        }
 
315
        XFree(args);
 
316
        if (wm && (metacity_hack == 1))
 
317
        {
 
318
            // metacity reports that it supports layers, but it is not really truth :-)
 
319
            wm ^= vo_wm_LAYER;
 
320
            mp_msg(MSGT_VO, MSGL_V,
 
321
                   "[x11] Using workaround for Metacity bugs.\n");
 
322
        }
 
323
    }
 
324
// --- netwm 
 
325
    if (x11_get_property(XA_NET_SUPPORTED, &args, &nitems))
 
326
    {
 
327
        mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports NetWM.\n");
 
328
        for (i = 0; i < nitems; i++)
 
329
            wm |= net_wm_support_state_test(args[i]);
 
330
        XFree(args);
 
331
#if 0
 
332
        // ugly hack for broken OpenBox _NET_WM_STATE_FULLSCREEN support
 
333
        // (in their implementation it only changes internal state of window, nothing more!!!)
 
334
        if (wm & vo_wm_FULLSCREEN)
 
335
        {
 
336
            if (x11_get_property(XA_BLACKBOX_PID, &args, &nitems))
 
337
            {
 
338
                mp_msg(MSGT_VO, MSGL_V,
 
339
                       "[x11] Detected wm is a broken OpenBox.\n");
 
340
                wm ^= vo_wm_FULLSCREEN;
 
341
            }
 
342
            XFree(args);
 
343
        }
 
344
#endif
 
345
    }
 
346
 
 
347
    if (wm == 0)
 
348
        mp_msg(MSGT_VO, MSGL_V, "[x11] Unknown wm type...\n");
 
349
    return wm;
 
350
}
 
351
 
 
352
static void init_atoms(void)
 
353
{
 
354
    XA_INIT(_NET_SUPPORTED);
 
355
    XA_INIT(_NET_WM_STATE);
 
356
    XA_INIT(_NET_WM_STATE_FULLSCREEN);
 
357
    XA_INIT(_NET_WM_STATE_ABOVE);
 
358
    XA_INIT(_NET_WM_STATE_STAYS_ON_TOP);
 
359
    XA_INIT(_NET_WM_STATE_BELOW);
 
360
    XA_INIT(_NET_WM_PID);
 
361
    XA_INIT(_WIN_PROTOCOLS);
 
362
    XA_INIT(_WIN_LAYER);
 
363
    XA_INIT(_WIN_HINTS);
 
364
    XA_INIT(_BLACKBOX_PID);
 
365
}
 
366
 
 
367
int vo_init(void)
 
368
{
 
369
// int       mScreen;
 
370
    int depth, bpp;
 
371
    unsigned int mask;
 
372
 
 
373
// char    * DisplayName = ":0.0";
 
374
// Display * mDisplay;
 
375
    XImage *mXImage = NULL;
 
376
 
 
377
// Window    mRootWin;
 
378
    XWindowAttributes attribs;
 
379
    char *dispName;
 
380
        
 
381
        if (vo_rootwin)
 
382
                WinID = 0; // use root win
 
383
 
 
384
    if (vo_depthonscreen)
 
385
    {
 
386
        saver_off(mDisplay);
 
387
        return 1;               // already called
 
388
    }
 
389
 
 
390
    XSetErrorHandler(x11_errorhandler);
 
391
 
 
392
#if 0
 
393
    if (!mDisplayName)
 
394
        if (!(mDisplayName = getenv("DISPLAY")))
 
395
            mDisplayName = strdup(":0.0");
 
396
#else
 
397
    dispName = XDisplayName(mDisplayName);
 
398
#endif
 
399
 
 
400
    mp_msg(MSGT_VO, MSGL_V, "X11 opening display: %s\n", dispName);
 
401
 
 
402
    mDisplay = XOpenDisplay(dispName);
 
403
    if (!mDisplay)
 
404
    {
 
405
        mp_msg(MSGT_VO, MSGL_ERR,
 
406
               "vo: couldn't open the X11 display (%s)!\n", dispName);
 
407
        return 0;
 
408
    }
 
409
    mScreen = DefaultScreen(mDisplay);  // Screen ID.
 
410
    mRootWin = RootWindow(mDisplay, mScreen);   // Root window ID.
 
411
 
 
412
    init_atoms();
 
413
 
 
414
#ifdef HAVE_XINERAMA
 
415
    if (XineramaIsActive(mDisplay))
 
416
    {
 
417
        XineramaScreenInfo *screens;
 
418
        int num_screens;
 
419
 
 
420
        screens = XineramaQueryScreens(mDisplay, &num_screens);
 
421
        if (xinerama_screen >= num_screens)
 
422
            xinerama_screen = 0;
 
423
        if (!vo_screenwidth)
 
424
            vo_screenwidth = screens[xinerama_screen].width;
 
425
        if (!vo_screenheight)
 
426
            vo_screenheight = screens[xinerama_screen].height;
 
427
        xinerama_x = screens[xinerama_screen].x_org;
 
428
        xinerama_y = screens[xinerama_screen].y_org;
 
429
 
 
430
        XFree(screens);
 
431
    } else
 
432
#endif
 
433
#ifdef HAVE_XF86VM
 
434
    {
 
435
        int clock;
 
436
 
 
437
        XF86VidModeGetModeLine(mDisplay, mScreen, &clock, &modeline);
 
438
        if (!vo_screenwidth)
 
439
            vo_screenwidth = modeline.hdisplay;
 
440
        if (!vo_screenheight)
 
441
            vo_screenheight = modeline.vdisplay;
 
442
    }
 
443
#endif
 
444
    {
 
445
        if (!vo_screenwidth)
 
446
            vo_screenwidth = DisplayWidth(mDisplay, mScreen);
 
447
        if (!vo_screenheight)
 
448
            vo_screenheight = DisplayHeight(mDisplay, mScreen);
 
449
    }
 
450
    // get color depth (from root window, or the best visual):
 
451
    XGetWindowAttributes(mDisplay, mRootWin, &attribs);
 
452
    depth = attribs.depth;
 
453
 
 
454
    if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
 
455
    {
 
456
        Visual *visual;
 
457
 
 
458
        depth = vo_find_depth_from_visuals(mDisplay, mScreen, &visual);
 
459
        if (depth != -1)
 
460
            mXImage = XCreateImage(mDisplay, visual, depth, ZPixmap,
 
461
                                   0, NULL, 1, 1, 8, 1);
 
462
    } else
 
463
        mXImage =
 
464
            XGetImage(mDisplay, mRootWin, 0, 0, 1, 1, AllPlanes, ZPixmap);
 
465
 
 
466
    vo_depthonscreen = depth;   // display depth on screen
 
467
 
 
468
    // get bits/pixel from XImage structure:
 
469
    if (mXImage == NULL)
 
470
    {
 
471
        mask = 0;
 
472
    } else
 
473
    {
 
474
        /*
 
475
         * for the depth==24 case, the XImage structures might use
 
476
         * 24 or 32 bits of data per pixel.  The global variable
 
477
         * vo_depthonscreen stores the amount of data per pixel in the
 
478
         * XImage structure!
 
479
         *
 
480
         * Maybe we should rename vo_depthonscreen to (or add) vo_bpp?
 
481
         */
 
482
        bpp = mXImage->bits_per_pixel;
 
483
        if ((vo_depthonscreen + 7) / 8 != (bpp + 7) / 8)
 
484
            vo_depthonscreen = bpp;     // by A'rpi
 
485
        mask =
 
486
            mXImage->red_mask | mXImage->green_mask | mXImage->blue_mask;
 
487
        mp_msg(MSGT_VO, MSGL_V,
 
488
               "vo: X11 color mask:  %X  (R:%lX G:%lX B:%lX)\n", mask,
 
489
               mXImage->red_mask, mXImage->green_mask, mXImage->blue_mask);
 
490
        XDestroyImage(mXImage);
 
491
    }
 
492
    if (((vo_depthonscreen + 7) / 8) == 2)
 
493
    {
 
494
        if (mask == 0x7FFF)
 
495
            vo_depthonscreen = 15;
 
496
        else if (mask == 0xFFFF)
 
497
            vo_depthonscreen = 16;
 
498
    }
 
499
// XCloseDisplay( mDisplay );
 
500
/* slightly improved local display detection AST */
 
501
    if (strncmp(dispName, "unix:", 5) == 0)
 
502
        dispName += 4;
 
503
    else if (strncmp(dispName, "localhost:", 10) == 0)
 
504
        dispName += 9;
 
505
    if (*dispName == ':' && atoi(dispName + 1) < 10)
 
506
        mLocalDisplay = 1;
 
507
    else
 
508
        mLocalDisplay = 0;
 
509
    mp_msg(MSGT_VO, MSGL_V,
 
510
           "vo: X11 running at %dx%d with depth %d and %d bpp (\"%s\" => %s display)\n",
 
511
           vo_screenwidth, vo_screenheight, depth, vo_depthonscreen,
 
512
           dispName, mLocalDisplay ? "local" : "remote");
 
513
 
 
514
    vo_wm_type = vo_wm_detect();
 
515
 
 
516
    vo_fs_type = vo_x11_get_fs_type(vo_wm_type);
 
517
 
 
518
    fstype_dump(vo_fs_type);
 
519
 
 
520
    saver_off(mDisplay);
 
521
    return 1;
 
522
}
 
523
 
 
524
void vo_uninit(void)
 
525
{
 
526
    if (!mDisplay)
 
527
    {
 
528
        mp_msg(MSGT_VO, MSGL_V,
 
529
               "vo: x11 uninit called but X11 not inited..\n");
 
530
        return;
 
531
    }
 
532
// if( !vo_depthonscreen ) return;
 
533
    mp_msg(MSGT_VO, MSGL_V, "vo: uninit ...\n");
 
534
    XSetErrorHandler(NULL);
 
535
    XCloseDisplay(mDisplay);
 
536
    vo_depthonscreen = 0;
 
537
    mDisplay = NULL;
 
538
}
 
539
 
 
540
#include "osdep/keycodes.h"
 
541
#include "wskeys.h"
 
542
 
 
543
extern void mplayer_put_key(int code);
 
544
 
 
545
#ifdef XF86XK_AudioPause
 
546
void vo_x11_putkey_ext(int keysym)
 
547
{
 
548
    switch (keysym)
 
549
    {
 
550
        case XF86XK_AudioPause:
 
551
            mplayer_put_key(KEY_PAUSE);
 
552
            break;
 
553
        case XF86XK_AudioStop:
 
554
            mplayer_put_key(KEY_STOP);
 
555
            break;
 
556
        case XF86XK_AudioPrev:
 
557
            mplayer_put_key(KEY_PREV);
 
558
            break;
 
559
        case XF86XK_AudioNext:
 
560
            mplayer_put_key(KEY_NEXT);
 
561
            break;
 
562
        default:
 
563
            break;
 
564
    }
 
565
}
 
566
#endif
 
567
 
 
568
void vo_x11_putkey(int key)
 
569
{
 
570
    switch (key)
 
571
    {
 
572
        case wsLeft:
 
573
            mplayer_put_key(KEY_LEFT);
 
574
            break;
 
575
        case wsRight:
 
576
            mplayer_put_key(KEY_RIGHT);
 
577
            break;
 
578
        case wsUp:
 
579
            mplayer_put_key(KEY_UP);
 
580
            break;
 
581
        case wsDown:
 
582
            mplayer_put_key(KEY_DOWN);
 
583
            break;
 
584
        case wsSpace:
 
585
            mplayer_put_key(' ');
 
586
            break;
 
587
        case wsEscape:
 
588
            mplayer_put_key(KEY_ESC);
 
589
            break;
 
590
        case wsTab:
 
591
            mplayer_put_key(KEY_TAB);
 
592
            break;
 
593
        case wsEnter:
 
594
            mplayer_put_key(KEY_ENTER);
 
595
            break;
 
596
        case wsBackSpace:
 
597
            mplayer_put_key(KEY_BS);
 
598
            break;
 
599
        case wsDelete:
 
600
            mplayer_put_key(KEY_DELETE);
 
601
            break;
 
602
        case wsInsert:
 
603
            mplayer_put_key(KEY_INSERT);
 
604
            break;
 
605
        case wsHome:
 
606
            mplayer_put_key(KEY_HOME);
 
607
            break;
 
608
        case wsEnd:
 
609
            mplayer_put_key(KEY_END);
 
610
            break;
 
611
        case wsPageUp:
 
612
            mplayer_put_key(KEY_PAGE_UP);
 
613
            break;
 
614
        case wsPageDown:
 
615
            mplayer_put_key(KEY_PAGE_DOWN);
 
616
            break;
 
617
        case wsF1:
 
618
            mplayer_put_key(KEY_F + 1);
 
619
            break;
 
620
        case wsF2:
 
621
            mplayer_put_key(KEY_F + 2);
 
622
            break;
 
623
        case wsF3:
 
624
            mplayer_put_key(KEY_F + 3);
 
625
            break;
 
626
        case wsF4:
 
627
            mplayer_put_key(KEY_F + 4);
 
628
            break;
 
629
        case wsF5:
 
630
            mplayer_put_key(KEY_F + 5);
 
631
            break;
 
632
        case wsF6:
 
633
            mplayer_put_key(KEY_F + 6);
 
634
            break;
 
635
        case wsF7:
 
636
            mplayer_put_key(KEY_F + 7);
 
637
            break;
 
638
        case wsF8:
 
639
            mplayer_put_key(KEY_F + 8);
 
640
            break;
 
641
        case wsF9:
 
642
            mplayer_put_key(KEY_F + 9);
 
643
            break;
 
644
        case wsF10:
 
645
            mplayer_put_key(KEY_F + 10);
 
646
            break;
 
647
        case wsF11:
 
648
            mplayer_put_key(KEY_F + 11);
 
649
            break;
 
650
        case wsF12:
 
651
            mplayer_put_key(KEY_F + 12);
 
652
            break;
 
653
        case wsMinus:
 
654
        case wsGrayMinus:
 
655
            mplayer_put_key('-');
 
656
            break;
 
657
        case wsPlus:
 
658
        case wsGrayPlus:
 
659
            mplayer_put_key('+');
 
660
            break;
 
661
        case wsGrayMul:
 
662
        case wsMul:
 
663
            mplayer_put_key('*');
 
664
            break;
 
665
        case wsGrayDiv:
 
666
        case wsDiv:
 
667
            mplayer_put_key('/');
 
668
            break;
 
669
        case wsLess:
 
670
            mplayer_put_key('<');
 
671
            break;
 
672
        case wsMore:
 
673
            mplayer_put_key('>');
 
674
            break;
 
675
        case wsGray0:
 
676
            mplayer_put_key(KEY_KP0);
 
677
            break;
 
678
        case wsGrayEnd:
 
679
        case wsGray1:
 
680
            mplayer_put_key(KEY_KP1);
 
681
            break;
 
682
        case wsGrayDown:
 
683
        case wsGray2:
 
684
            mplayer_put_key(KEY_KP2);
 
685
            break;
 
686
        case wsGrayPgDn:
 
687
        case wsGray3:
 
688
            mplayer_put_key(KEY_KP3);
 
689
            break;
 
690
        case wsGrayLeft:
 
691
        case wsGray4:
 
692
            mplayer_put_key(KEY_KP4);
 
693
            break;
 
694
        case wsGray5Dup:
 
695
        case wsGray5:
 
696
            mplayer_put_key(KEY_KP5);
 
697
            break;
 
698
        case wsGrayRight:
 
699
        case wsGray6:
 
700
            mplayer_put_key(KEY_KP6);
 
701
            break;
 
702
        case wsGrayHome:
 
703
        case wsGray7:
 
704
            mplayer_put_key(KEY_KP7);
 
705
            break;
 
706
        case wsGrayUp:
 
707
        case wsGray8:
 
708
            mplayer_put_key(KEY_KP8);
 
709
            break;
 
710
        case wsGrayPgUp:
 
711
        case wsGray9:
 
712
            mplayer_put_key(KEY_KP9);
 
713
            break;
 
714
        case wsGrayDecimal:
 
715
            mplayer_put_key(KEY_KPDEC);
 
716
            break;
 
717
        case wsGrayInsert:
 
718
            mplayer_put_key(KEY_KPINS);
 
719
            break;
 
720
        case wsGrayDelete:
 
721
            mplayer_put_key(KEY_KPDEL);
 
722
            break;
 
723
        case wsGrayEnter:
 
724
            mplayer_put_key(KEY_KPENTER);
 
725
            break;
 
726
        case wsGrave:
 
727
            mplayer_put_key('`');
 
728
            break;
 
729
        case wsTilde:
 
730
            mplayer_put_key('~');
 
731
            break;
 
732
        case wsExclSign:
 
733
            mplayer_put_key('!');
 
734
            break;
 
735
        case wsAt:
 
736
            mplayer_put_key('@');
 
737
            break;
 
738
        case wsHash:
 
739
            mplayer_put_key('#');
 
740
            break;
 
741
        case wsDollar:
 
742
            mplayer_put_key('$');
 
743
            break;
 
744
        case wsPercent:
 
745
            mplayer_put_key('%');
 
746
            break;
 
747
        case wsCircumflex:
 
748
            mplayer_put_key('^');
 
749
            break;
 
750
        case wsAmpersand:
 
751
            mplayer_put_key('&');
 
752
            break;
 
753
        case wsobracket:
 
754
            mplayer_put_key('(');
 
755
            break;
 
756
        case wscbracket:
 
757
            mplayer_put_key(')');
 
758
            break;
 
759
        case wsUnder:
 
760
            mplayer_put_key('_');
 
761
            break;
 
762
        case wsocbracket:
 
763
            mplayer_put_key('{');
 
764
            break;
 
765
        case wsccbracket:
 
766
            mplayer_put_key('}');
 
767
            break;
 
768
        case wsColon:
 
769
            mplayer_put_key(':');
 
770
            break;
 
771
        case wsSemicolon:
 
772
            mplayer_put_key(';');
 
773
            break;
 
774
        case wsDblQuote:
 
775
            mplayer_put_key('\"');
 
776
            break;
 
777
        case wsAcute:
 
778
            mplayer_put_key('\'');
 
779
            break;
 
780
        case wsComma:
 
781
            mplayer_put_key(',');
 
782
            break;
 
783
        case wsPoint:
 
784
            mplayer_put_key('.');
 
785
            break;
 
786
        case wsQuestSign:
 
787
            mplayer_put_key('?');
 
788
            break;
 
789
        case wsBSlash:
 
790
            mplayer_put_key('\\');
 
791
            break;
 
792
        case wsPipe:
 
793
            mplayer_put_key('|');
 
794
            break;
 
795
        case wsEqual:
 
796
            mplayer_put_key('=');
 
797
            break;
 
798
        case wsosbrackets:
 
799
            mplayer_put_key('[');
 
800
            break;
 
801
        case wscsbrackets:
 
802
            mplayer_put_key(']');
 
803
            break;
 
804
 
 
805
 
 
806
        default:
 
807
            if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
 
808
                (key >= '0' && key <= '9'))
 
809
                mplayer_put_key(key);
 
810
    }
 
811
 
 
812
}
 
813
 
 
814
 
 
815
// ----- Motif header: -------
 
816
 
 
817
#define MWM_HINTS_FUNCTIONS     (1L << 0)
 
818
#define MWM_HINTS_DECORATIONS   (1L << 1)
 
819
#define MWM_HINTS_INPUT_MODE    (1L << 2)
 
820
#define MWM_HINTS_STATUS        (1L << 3)
 
821
 
 
822
#define MWM_FUNC_ALL            (1L << 0)
 
823
#define MWM_FUNC_RESIZE         (1L << 1)
 
824
#define MWM_FUNC_MOVE           (1L << 2)
 
825
#define MWM_FUNC_MINIMIZE       (1L << 3)
 
826
#define MWM_FUNC_MAXIMIZE       (1L << 4)
 
827
#define MWM_FUNC_CLOSE          (1L << 5)
 
828
 
 
829
#define MWM_DECOR_ALL           (1L << 0)
 
830
#define MWM_DECOR_BORDER        (1L << 1)
 
831
#define MWM_DECOR_RESIZEH       (1L << 2)
 
832
#define MWM_DECOR_TITLE         (1L << 3)
 
833
#define MWM_DECOR_MENU          (1L << 4)
 
834
#define MWM_DECOR_MINIMIZE      (1L << 5)
 
835
#define MWM_DECOR_MAXIMIZE      (1L << 6)
 
836
 
 
837
#define MWM_INPUT_MODELESS 0
 
838
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
 
839
#define MWM_INPUT_SYSTEM_MODAL 2
 
840
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
 
841
#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
 
842
 
 
843
#define MWM_TEAROFF_WINDOW      (1L<<0)
 
844
 
 
845
typedef struct
 
846
{
 
847
    long flags;
 
848
    long functions;
 
849
    long decorations;
 
850
    long input_mode;
 
851
    long state;
 
852
} MotifWmHints;
 
853
 
 
854
static MotifWmHints vo_MotifWmHints;
 
855
static Atom vo_MotifHints = None;
 
856
 
 
857
void vo_x11_decoration(Display * vo_Display, Window w, int d)
 
858
{
 
859
    static unsigned int olddecor = MWM_DECOR_ALL;
 
860
    static unsigned int oldfuncs =
 
861
        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE |
 
862
        MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
 
863
    Atom mtype;
 
864
    int mformat;
 
865
    unsigned long mn, mb;
 
866
 
 
867
    if (!WinID)
 
868
        return;
 
869
 
 
870
    if (vo_fsmode & 8)
 
871
    {
 
872
        XSetTransientForHint(vo_Display, w,
 
873
                             RootWindow(vo_Display, mScreen));
 
874
    }
 
875
 
 
876
    vo_MotifHints = XInternAtom(vo_Display, "_MOTIF_WM_HINTS", 0);
 
877
    if (vo_MotifHints != None)
 
878
    {
 
879
        if (!d)
 
880
        {
 
881
            MotifWmHints *mhints = NULL;
 
882
 
 
883
            XGetWindowProperty(vo_Display, w, vo_MotifHints, 0, 20, False,
 
884
                               vo_MotifHints, &mtype, &mformat, &mn,
 
885
                               &mb, (unsigned char **) &mhints);
 
886
            if (mhints)
 
887
            {
 
888
                if (mhints->flags & MWM_HINTS_DECORATIONS)
 
889
                    olddecor = mhints->decorations;
 
890
                if (mhints->flags & MWM_HINTS_FUNCTIONS)
 
891
                    oldfuncs = mhints->functions;
 
892
                XFree(mhints);
 
893
            }
 
894
        }
 
895
 
 
896
        memset(&vo_MotifWmHints, 0, sizeof(MotifWmHints));
 
897
        vo_MotifWmHints.flags =
 
898
            MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
 
899
        if (d)
 
900
        {
 
901
            vo_MotifWmHints.functions = oldfuncs;
 
902
            d = olddecor;
 
903
        }
 
904
#if 0
 
905
        vo_MotifWmHints.decorations =
 
906
            d | ((vo_fsmode & 2) ? 0 : MWM_DECOR_MENU);
 
907
#else
 
908
        vo_MotifWmHints.decorations =
 
909
            d | ((vo_fsmode & 2) ? MWM_DECOR_MENU : 0);
 
910
#endif
 
911
        XChangeProperty(vo_Display, w, vo_MotifHints, vo_MotifHints, 32,
 
912
                        PropModeReplace,
 
913
                        (unsigned char *) &vo_MotifWmHints,
 
914
                        (vo_fsmode & 4) ? 4 : 5);
 
915
    }
 
916
}
 
917
 
 
918
void vo_x11_classhint(Display * display, Window window, char *name)
 
919
{
 
920
    XClassHint wmClass;
 
921
    pid_t pid = getpid();
 
922
 
 
923
    wmClass.res_name = name;
 
924
    wmClass.res_class = "MPlayer";
 
925
    XSetClassHint(display, window, &wmClass);
 
926
    XChangeProperty(display, window, XA_NET_WM_PID, XA_CARDINAL, 32,
 
927
                    PropModeReplace, (unsigned char *) &pid, 1);
 
928
}
 
929
 
 
930
Window vo_window = None;
 
931
GC vo_gc = NULL;
 
932
GC f_gc = NULL;
 
933
XSizeHints vo_hint;
 
934
 
 
935
#ifdef HAVE_NEW_GUI
 
936
void vo_setwindow(Window w, GC g)
 
937
{
 
938
    vo_window = w;
 
939
    vo_gc = g;
 
940
}
 
941
#endif
 
942
 
 
943
void vo_x11_uninit()
 
944
{
 
945
    saver_on(mDisplay);
 
946
    if (vo_window != None)
 
947
        vo_showcursor(mDisplay, vo_window);
 
948
 
 
949
    if (f_gc)
 
950
    {
 
951
        XFreeGC(mDisplay, f_gc);
 
952
        f_gc = NULL;
 
953
    }
 
954
#ifdef HAVE_NEW_GUI
 
955
    /* destroy window only if it's not controlled by GUI */
 
956
    if (!use_gui)
 
957
#endif
 
958
    {
 
959
        if (vo_gc)
 
960
        {
 
961
            XSetBackground(mDisplay, vo_gc, 0);
 
962
            XFreeGC(mDisplay, vo_gc);
 
963
            vo_gc = NULL;
 
964
        }
 
965
        if (vo_window != None)
 
966
        {
 
967
            XClearWindow(mDisplay, vo_window);
 
968
            if (WinID < 0)
 
969
            {
 
970
                XEvent xev;
 
971
 
 
972
                XUnmapWindow(mDisplay, vo_window);
 
973
                XDestroyWindow(mDisplay, vo_window);
 
974
                do
 
975
                {
 
976
                    XNextEvent(mDisplay, &xev);
 
977
                }
 
978
                while (xev.type != DestroyNotify
 
979
                       || xev.xdestroywindow.event != vo_window);
 
980
            }
 
981
            vo_window = None;
 
982
        }
 
983
        vo_fs = 0;
 
984
        vo_old_width = vo_old_height = 0;
 
985
    }
 
986
}
 
987
 
 
988
int vo_mouse_timer_const = 30;
 
989
static int vo_mouse_counter = 30;
 
990
 
 
991
int vo_x11_check_events(Display * mydisplay)
 
992
{
 
993
    int ret = 0;
 
994
    XEvent Event;
 
995
    char buf[100];
 
996
    KeySym keySym;
 
997
    static XComposeStatus stat;
 
998
 
 
999
// unsigned long  vo_KeyTable[512];
 
1000
 
 
1001
    if ((vo_mouse_autohide) && (--vo_mouse_counter == 0))
 
1002
        vo_hidecursor(mydisplay, vo_window);
 
1003
 
 
1004
    while (XPending(mydisplay))
 
1005
    {
 
1006
        XNextEvent(mydisplay, &Event);
 
1007
#ifdef HAVE_NEW_GUI
 
1008
        if (use_gui)
 
1009
        {
 
1010
            guiGetEvent(0, (char *) &Event);
 
1011
            if (vo_window != Event.xany.window)
 
1012
                continue;
 
1013
        }
 
1014
#endif
 
1015
//       printf("\rEvent.type=%X  \n",Event.type);
 
1016
        switch (Event.type)
 
1017
        {
 
1018
            case Expose:
 
1019
                ret |= VO_EVENT_EXPOSE;
 
1020
                break;
 
1021
            case ConfigureNotify:
 
1022
//         if (!vo_fs && (Event.xconfigure.width == vo_screenwidth || Event.xconfigure.height == vo_screenheight)) break;
 
1023
//         if (vo_fs && Event.xconfigure.width != vo_screenwidth && Event.xconfigure.height != vo_screenheight) break;
 
1024
                if (vo_window == None)
 
1025
                    break;
 
1026
                vo_dwidth = Event.xconfigure.width;
 
1027
                vo_dheight = Event.xconfigure.height;
 
1028
#if 0
 
1029
                /* when resizing, x and y are zero :( */
 
1030
                vo_dx = Event.xconfigure.x;
 
1031
                vo_dy = Event.xconfigure.y;
 
1032
#else
 
1033
                {
 
1034
                    Window root;
 
1035
                    int foo;
 
1036
                    Window win;
 
1037
 
 
1038
                    XGetGeometry(mydisplay, vo_window, &root, &foo, &foo,
 
1039
                                 &foo /*width */ , &foo /*height */ , &foo,
 
1040
                                 &foo);
 
1041
                    XTranslateCoordinates(mydisplay, vo_window, root, 0, 0,
 
1042
                                          &vo_dx, &vo_dy, &win);
 
1043
                }
 
1044
#endif
 
1045
                ret |= VO_EVENT_RESIZE;
 
1046
                break;
 
1047
            case KeyPress:
 
1048
                {
 
1049
                    int key;
 
1050
 
 
1051
#ifdef HAVE_NEW_GUI
 
1052
                    if ( use_gui ) { break; }
 
1053
#endif
 
1054
 
 
1055
                    XLookupString(&Event.xkey, buf, sizeof(buf), &keySym,
 
1056
                                  &stat);
 
1057
#ifdef XF86XK_AudioPause
 
1058
                    vo_x11_putkey_ext(keySym);
 
1059
#endif
 
1060
                    key =
 
1061
                        ((keySym & 0xff00) !=
 
1062
                         0 ? ((keySym & 0x00ff) + 256) : (keySym));
 
1063
                    vo_x11_putkey(key);
 
1064
                    ret |= VO_EVENT_KEYPRESS;
 
1065
                }
 
1066
                break;
 
1067
            case MotionNotify:
 
1068
                if (vo_mouse_autohide)
 
1069
                {
 
1070
                    vo_showcursor(mydisplay, vo_window);
 
1071
                    vo_mouse_counter = vo_mouse_timer_const;
 
1072
                }
 
1073
                break;
 
1074
            case ButtonPress:
 
1075
                if (vo_mouse_autohide)
 
1076
                {
 
1077
                    vo_showcursor(mydisplay, vo_window);
 
1078
                    vo_mouse_counter = vo_mouse_timer_const;
 
1079
                }
 
1080
                // Ignore mouse whell press event
 
1081
                if (Event.xbutton.button > 3)
 
1082
                {
 
1083
                    mplayer_put_key(MOUSE_BTN0 + Event.xbutton.button - 1);
 
1084
                    break;
 
1085
                }
 
1086
#ifdef HAVE_NEW_GUI
 
1087
                // Ignor mouse button 1 - 3 under gui 
 
1088
                if (use_gui && (Event.xbutton.button >= 1)
 
1089
                    && (Event.xbutton.button <= 3))
 
1090
                    break;
 
1091
#endif
 
1092
                mplayer_put_key((MOUSE_BTN0 + Event.xbutton.button -
 
1093
                                 1) | MP_KEY_DOWN);
 
1094
                break;
 
1095
            case ButtonRelease:
 
1096
                if (vo_mouse_autohide)
 
1097
                {
 
1098
                    vo_showcursor(mydisplay, vo_window);
 
1099
                    vo_mouse_counter = vo_mouse_timer_const;
 
1100
                }
 
1101
#ifdef HAVE_NEW_GUI
 
1102
                // Ignor mouse button 1 - 3 under gui 
 
1103
                if (use_gui && (Event.xbutton.button >= 1)
 
1104
                    && (Event.xbutton.button <= 3))
 
1105
                    break;
 
1106
#endif
 
1107
                mplayer_put_key(MOUSE_BTN0 + Event.xbutton.button - 1);
 
1108
                break;
 
1109
            case PropertyNotify:
 
1110
                {
 
1111
                    char *name =
 
1112
                        XGetAtomName(mydisplay, Event.xproperty.atom);
 
1113
 
 
1114
                    if (!name)
 
1115
                        break;
 
1116
 
 
1117
//          fprintf(stderr,"[ws] PropertyNotify ( 0x%x ) %s ( 0x%x )\n",vo_window,name,Event.xproperty.atom );
 
1118
 
 
1119
                    XFree(name);
 
1120
                }
 
1121
                break;
 
1122
            case MapNotify:
 
1123
                vo_hint.win_gravity = old_gravity;
 
1124
                XSetWMNormalHints(mDisplay, vo_window, &vo_hint);
 
1125
                vo_fs_flip = 0;
 
1126
                break;
 
1127
        }
 
1128
    }
 
1129
    return ret;
 
1130
}
 
1131
 
 
1132
/**
 
1133
 * \brief sets the size and position of the non-fullscreen window.
 
1134
 */
 
1135
void vo_x11_nofs_sizepos(int x, int y, int width, int height)
 
1136
{
 
1137
  if (vo_fs) {
 
1138
    vo_old_x = x;
 
1139
    vo_old_y = y;
 
1140
    vo_old_width = width;
 
1141
    vo_old_height = height;
 
1142
  }
 
1143
  else
 
1144
  {
 
1145
   vo_dwidth = width;
 
1146
   vo_dheight = height;
 
1147
   XMoveResizeWindow(mDisplay, vo_window, x, y, width, height);
 
1148
  }
 
1149
}
 
1150
 
 
1151
void vo_x11_sizehint(int x, int y, int width, int height, int max)
 
1152
{
 
1153
    vo_hint.flags = PPosition | PSize | PWinGravity;
 
1154
    if (vo_keepaspect)
 
1155
    {
 
1156
        vo_hint.flags |= PAspect;
 
1157
        vo_hint.min_aspect.x = width;
 
1158
        vo_hint.min_aspect.y = height;
 
1159
        vo_hint.max_aspect.x = width;
 
1160
        vo_hint.max_aspect.y = height;
 
1161
    }
 
1162
 
 
1163
    vo_hint.x = x;
 
1164
    vo_hint.y = y;
 
1165
    vo_hint.width = width;
 
1166
    vo_hint.height = height;
 
1167
    if (max)
 
1168
    {
 
1169
        vo_hint.max_width = width;
 
1170
        vo_hint.max_height = height;
 
1171
        vo_hint.flags |= PMaxSize;
 
1172
    } else
 
1173
    {
 
1174
        vo_hint.max_width = 0;
 
1175
        vo_hint.max_height = 0;
 
1176
    }
 
1177
 
 
1178
    // set min height/width to 4 to avoid off by one errors
 
1179
    // and because mga_vid requires a minial size of 4 pixel
 
1180
    vo_hint.min_width = vo_hint.min_height = 4;
 
1181
    vo_hint.flags |= PMinSize;
 
1182
 
 
1183
    vo_hint.win_gravity = StaticGravity;
 
1184
    XSetWMNormalHints(mDisplay, vo_window, &vo_hint);
 
1185
}
 
1186
 
 
1187
static int vo_x11_get_gnome_layer(Display * mDisplay, Window win)
 
1188
{
 
1189
    Atom type;
 
1190
    int format;
 
1191
    unsigned long nitems;
 
1192
    unsigned long bytesafter;
 
1193
    unsigned short *args = NULL;
 
1194
 
 
1195
    if (XGetWindowProperty(mDisplay, win, XA_WIN_LAYER, 0, 16384,
 
1196
                           False, AnyPropertyType, &type, &format, &nitems,
 
1197
                           &bytesafter,
 
1198
                           (unsigned char **) &args) == Success
 
1199
        && nitems > 0 && args)
 
1200
    {
 
1201
        mp_msg(MSGT_VO, MSGL_V, "[x11] original window layer is %d.\n",
 
1202
               *args);
 
1203
        return *args;
 
1204
    }
 
1205
    return WIN_LAYER_NORMAL;
 
1206
}
 
1207
 
 
1208
//
 
1209
Window vo_x11_create_smooth_window(Display * mDisplay, Window mRoot,
 
1210
                                   Visual * vis, int x, int y,
 
1211
                                   unsigned int width, unsigned int height,
 
1212
                                   int depth, Colormap col_map)
 
1213
{
 
1214
    unsigned long xswamask = CWBackingStore | CWBorderPixel;
 
1215
    XSetWindowAttributes xswa;
 
1216
    Window ret_win;
 
1217
 
 
1218
    if (col_map != CopyFromParent)
 
1219
    {
 
1220
        xswa.colormap = col_map;
 
1221
        xswamask |= CWColormap;
 
1222
    }
 
1223
    xswa.background_pixel = 0;
 
1224
    xswa.border_pixel = 0;
 
1225
    xswa.backing_store = Always;
 
1226
    xswa.bit_gravity = StaticGravity;
 
1227
 
 
1228
    ret_win =
 
1229
        XCreateWindow(mDisplay, mRootWin, x, y, width, height, 0, depth,
 
1230
                      CopyFromParent, vis, xswamask, &xswa);
 
1231
    if (!f_gc)
 
1232
        f_gc = XCreateGC(mDisplay, ret_win, 0, 0);
 
1233
    XSetForeground(mDisplay, f_gc, 0);
 
1234
 
 
1235
    return ret_win;
 
1236
}
 
1237
 
 
1238
 
 
1239
void vo_x11_clearwindow_part(Display * mDisplay, Window vo_window,
 
1240
                             int img_width, int img_height, int use_fs)
 
1241
{
 
1242
    int u_dheight, u_dwidth, left_ov, left_ov2;
 
1243
 
 
1244
    if (!f_gc)
 
1245
        return;
 
1246
 
 
1247
    u_dheight = use_fs ? vo_screenheight : vo_dheight;
 
1248
    u_dwidth = use_fs ? vo_screenwidth : vo_dwidth;
 
1249
    if ((u_dheight <= img_height) && (u_dwidth <= img_width))
 
1250
        return;
 
1251
 
 
1252
    left_ov = (u_dheight - img_height) / 2;
 
1253
    left_ov2 = (u_dwidth - img_width) / 2;
 
1254
 
 
1255
    XFillRectangle(mDisplay, vo_window, f_gc, 0, 0, u_dwidth, left_ov);
 
1256
    XFillRectangle(mDisplay, vo_window, f_gc, 0, u_dheight - left_ov - 1,
 
1257
                   u_dwidth, left_ov + 1);
 
1258
 
 
1259
    if (u_dwidth > img_width)
 
1260
    {
 
1261
        XFillRectangle(mDisplay, vo_window, f_gc, 0, left_ov, left_ov2,
 
1262
                       img_height);
 
1263
        XFillRectangle(mDisplay, vo_window, f_gc, u_dwidth - left_ov2 - 1,
 
1264
                       left_ov, left_ov2, img_height);
 
1265
    }
 
1266
 
 
1267
    XFlush(mDisplay);
 
1268
}
 
1269
 
 
1270
void vo_x11_clearwindow(Display * mDisplay, Window vo_window)
 
1271
{
 
1272
    if (!f_gc)
 
1273
        return;
 
1274
    XFillRectangle(mDisplay, vo_window, f_gc, 0, 0, vo_screenwidth,
 
1275
                   vo_screenheight);
 
1276
    //
 
1277
    XFlush(mDisplay);
 
1278
}
 
1279
 
 
1280
 
 
1281
void vo_x11_setlayer(Display * mDisplay, Window vo_window, int layer)
 
1282
{
 
1283
    if (WinID >= 0)
 
1284
        return;
 
1285
 
 
1286
    if (vo_fs_type & vo_wm_LAYER)
 
1287
    {
 
1288
        XClientMessageEvent xev;
 
1289
 
 
1290
        if (!orig_layer)
 
1291
            orig_layer = vo_x11_get_gnome_layer(mDisplay, vo_window);
 
1292
 
 
1293
        memset(&xev, 0, sizeof(xev));
 
1294
        xev.type = ClientMessage;
 
1295
        xev.display = mDisplay;
 
1296
        xev.window = vo_window;
 
1297
        xev.message_type = XA_WIN_LAYER;
 
1298
        xev.format = 32;
 
1299
        xev.data.l[0] = layer ? fs_layer : orig_layer;  // if not fullscreen, stay on default layer
 
1300
        xev.data.l[1] = CurrentTime;
 
1301
        mp_msg(MSGT_VO, MSGL_V,
 
1302
               "[x11] Layered style stay on top (layer %ld).\n",
 
1303
               xev.data.l[0]);
 
1304
        XSendEvent(mDisplay, mRootWin, False, SubstructureNotifyMask,
 
1305
                   (XEvent *) & xev);
 
1306
    } else if (vo_fs_type & vo_wm_NETWM)
 
1307
    {
 
1308
        XClientMessageEvent xev;
 
1309
        char *state;
 
1310
 
 
1311
        memset(&xev, 0, sizeof(xev));
 
1312
        xev.type = ClientMessage;
 
1313
        xev.message_type = XA_NET_WM_STATE;
 
1314
        xev.display = mDisplay;
 
1315
        xev.window = vo_window;
 
1316
        xev.format = 32;
 
1317
        xev.data.l[0] = layer;
 
1318
 
 
1319
        if (vo_fs_type & vo_wm_STAYS_ON_TOP)
 
1320
            xev.data.l[1] = XA_NET_WM_STATE_STAYS_ON_TOP;
 
1321
        else if (vo_fs_type & vo_wm_ABOVE)
 
1322
            xev.data.l[1] = XA_NET_WM_STATE_ABOVE;
 
1323
        else if (vo_fs_type & vo_wm_FULLSCREEN)
 
1324
            xev.data.l[1] = XA_NET_WM_STATE_FULLSCREEN;
 
1325
        else if (vo_fs_type & vo_wm_BELOW)
 
1326
            // This is not fallback. We can safely assume that situation where
 
1327
            // only NETWM_STATE_BELOW is supported and others not, doesn't exist.
 
1328
            xev.data.l[1] = XA_NET_WM_STATE_BELOW;
 
1329
 
 
1330
        XSendEvent(mDisplay, mRootWin, False, SubstructureRedirectMask,
 
1331
                   (XEvent *) & xev);
 
1332
        state = XGetAtomName(mDisplay, xev.data.l[1]);
 
1333
        mp_msg(MSGT_VO, MSGL_V,
 
1334
               "[x11] NET style stay on top (layer %d). Using state %s.\n",
 
1335
               layer, state);
 
1336
        XFree(state);
 
1337
    }
 
1338
}
 
1339
 
 
1340
static int vo_x11_get_fs_type(int supported)
 
1341
{
 
1342
    int i;
 
1343
    int type = supported;
 
1344
 
 
1345
    if (vo_fstype_list)
 
1346
    {
 
1347
        i = 0;
 
1348
        for (i = 0; vo_fstype_list[i]; i++)
 
1349
        {
 
1350
            int neg = 0;
 
1351
            char *arg = vo_fstype_list[i];
 
1352
 
 
1353
            if (vo_fstype_list[i][0] == '-')
 
1354
            {
 
1355
                neg = 1;
 
1356
                arg = vo_fstype_list[i] + 1;
 
1357
            }
 
1358
 
 
1359
            if (!strncmp(arg, "layer", 5))
 
1360
            {
 
1361
                if (!neg && (arg[5] == '='))
 
1362
                {
 
1363
                    char *endptr = NULL;
 
1364
                    int layer = strtol(vo_fstype_list[i] + 6, &endptr, 10);
 
1365
 
 
1366
                    if (endptr && *endptr == '\0' && layer >= 0
 
1367
                        && layer <= 15)
 
1368
                        fs_layer = layer;
 
1369
                }
 
1370
                if (neg)
 
1371
                    type &= ~vo_wm_LAYER;
 
1372
                else
 
1373
                    type |= vo_wm_LAYER;
 
1374
            } else if (!strcmp(arg, "above"))
 
1375
            {
 
1376
                if (neg)
 
1377
                    type &= ~vo_wm_ABOVE;
 
1378
                else
 
1379
                    type |= vo_wm_ABOVE;
 
1380
            } else if (!strcmp(arg, "fullscreen"))
 
1381
            {
 
1382
                if (neg)
 
1383
                    type &= ~vo_wm_FULLSCREEN;
 
1384
                else
 
1385
                    type |= vo_wm_FULLSCREEN;
 
1386
            } else if (!strcmp(arg, "stays_on_top"))
 
1387
            {
 
1388
                if (neg)
 
1389
                    type &= ~vo_wm_STAYS_ON_TOP;
 
1390
                else
 
1391
                    type |= vo_wm_STAYS_ON_TOP;
 
1392
            } else if (!strcmp(arg, "below"))
 
1393
            {
 
1394
                if (neg)
 
1395
                    type &= ~vo_wm_BELOW;
 
1396
                else
 
1397
                    type |= vo_wm_BELOW;
 
1398
            } else if (!strcmp(arg, "netwm"))
 
1399
            {
 
1400
                if (neg)
 
1401
                    type &= ~vo_wm_NETWM;
 
1402
                else
 
1403
                    type |= vo_wm_NETWM;
 
1404
            } else if (!strcmp(arg, "none"))
 
1405
                return 0;
 
1406
        }
 
1407
    }
 
1408
 
 
1409
    return type;
 
1410
}
 
1411
 
 
1412
void vo_x11_fullscreen(void)
 
1413
{
 
1414
    int x, y, w, h;
 
1415
 
 
1416
    if (WinID >= 0 || vo_fs_flip)
 
1417
        return;
 
1418
 
 
1419
    if (vo_fs)
 
1420
    {
 
1421
        // fs->win
 
1422
        if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
 
1423
        {
 
1424
            if (vo_dwidth != vo_screenwidth && vo_dheight != vo_screenheight)
 
1425
                return;
 
1426
            x = vo_old_x;
 
1427
            y = vo_old_y;
 
1428
            w = vo_old_width;
 
1429
            h = vo_old_height;
 
1430
        }
 
1431
 
 
1432
        vo_x11_ewmh_fullscreen(_NET_WM_STATE_REMOVE);   // removes fullscreen state if wm supports EWMH
 
1433
        vo_fs = VO_FALSE;
 
1434
    } else
 
1435
    {
 
1436
        // win->fs
 
1437
        vo_x11_ewmh_fullscreen(_NET_WM_STATE_ADD);      // sends fullscreen state to be added if wm supports EWMH
 
1438
 
 
1439
        vo_fs = VO_TRUE;
 
1440
        if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
 
1441
        {
 
1442
            if (vo_old_width &&
 
1443
                (vo_dwidth == vo_screenwidth && vo_dwidth != vo_old_width) &&
 
1444
                (vo_dheight == vo_screenheight && vo_dheight != vo_old_height))
 
1445
                return;
 
1446
            vo_old_x = vo_dx;
 
1447
            vo_old_y = vo_dy;
 
1448
            vo_old_width = vo_dwidth;
 
1449
            vo_old_height = vo_dheight;
 
1450
            x = 0;
 
1451
            y = 0;
 
1452
            w = vo_screenwidth;
 
1453
            h = vo_screenheight;
 
1454
        }
 
1455
    }
 
1456
    {
 
1457
        long dummy;
 
1458
 
 
1459
        XGetWMNormalHints(mDisplay, vo_window, &vo_hint, &dummy);
 
1460
        if (!(vo_hint.flags & PWinGravity))
 
1461
            old_gravity = NorthWestGravity;
 
1462
        else
 
1463
            old_gravity = vo_hint.win_gravity;
 
1464
    }
 
1465
    if (vo_wm_type == 0 && !(vo_fsmode & 16))
 
1466
    {
 
1467
        XUnmapWindow(mDisplay, vo_window);      // required for MWM
 
1468
        XWithdrawWindow(mDisplay, vo_window, mScreen);
 
1469
        vo_fs_flip = 1;
 
1470
    }
 
1471
 
 
1472
    if ( ! (vo_fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs
 
1473
    {
 
1474
        vo_x11_decoration(mDisplay, vo_window, (vo_fs) ? 0 : 1);
 
1475
        vo_x11_sizehint(x, y, w, h, 0);
 
1476
        vo_x11_setlayer(mDisplay, vo_window, vo_fs);
 
1477
 
 
1478
 
 
1479
        XMoveResizeWindow(mDisplay, vo_window, x, y, w, h);
 
1480
    }
 
1481
    /* some WMs lose ontop after fullscreeen */
 
1482
    if ((!(vo_fs)) & vo_ontop)
 
1483
        vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
 
1484
 
 
1485
#ifdef HAVE_XINERAMA
 
1486
    vo_x11_xinerama_move(mDisplay, vo_window);
 
1487
#endif
 
1488
 
 
1489
    XMapRaised(mDisplay, vo_window);
 
1490
    XRaiseWindow(mDisplay, vo_window);
 
1491
    XFlush(mDisplay);
 
1492
}
 
1493
 
 
1494
void vo_x11_ontop(void)
 
1495
{
 
1496
    vo_ontop = (!(vo_ontop));
 
1497
 
 
1498
    vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
 
1499
}
 
1500
 
 
1501
/*
 
1502
 * XScreensaver stuff
 
1503
 */
 
1504
 
 
1505
static int got_badwindow;
 
1506
static XErrorHandler old_handler;
 
1507
 
 
1508
static int badwindow_handler(Display * dpy, XErrorEvent * error)
 
1509
{
 
1510
    if (error->error_code != BadWindow)
 
1511
        return (*old_handler) (dpy, error);
 
1512
 
 
1513
    got_badwindow = True;
 
1514
    return 0;
 
1515
}
 
1516
 
 
1517
static Window find_xscreensaver_window(Display * dpy)
 
1518
{
 
1519
    int i;
 
1520
    Window root = RootWindowOfScreen(DefaultScreenOfDisplay(dpy));
 
1521
    Window root2, parent, *kids;
 
1522
    Window retval = 0;
 
1523
    Atom xs_version;
 
1524
    unsigned int nkids = 0;
 
1525
 
 
1526
    xs_version = XInternAtom(dpy, "_SCREENSAVER_VERSION", True);
 
1527
 
 
1528
    if (!(xs_version != None &&
 
1529
          XQueryTree(dpy, root, &root2, &parent, &kids, &nkids) &&
 
1530
          kids && nkids))
 
1531
        return 0;
 
1532
 
 
1533
    old_handler = XSetErrorHandler(badwindow_handler);
 
1534
 
 
1535
    for (i = 0; i < nkids; i++)
 
1536
    {
 
1537
        Atom type;
 
1538
        int format;
 
1539
        unsigned long nitems, bytesafter;
 
1540
        char *v;
 
1541
        int status;
 
1542
 
 
1543
        got_badwindow = False;
 
1544
        status =
 
1545
            XGetWindowProperty(dpy, kids[i], xs_version, 0, 200, False,
 
1546
                               XA_STRING, &type, &format, &nitems,
 
1547
                               &bytesafter, (unsigned char **) &v);
 
1548
        XSync(dpy, False);
 
1549
        if (got_badwindow)
 
1550
            status = BadWindow;
 
1551
 
 
1552
        if (status == Success && type != None)
 
1553
        {
 
1554
            retval = kids[i];
 
1555
            break;
 
1556
        }
 
1557
    }
 
1558
    XFree(kids);
 
1559
    XSetErrorHandler(old_handler);
 
1560
 
 
1561
    return retval;
 
1562
}
 
1563
 
 
1564
static Window xs_windowid = 0;
 
1565
static Atom deactivate;
 
1566
static Atom screensaver;
 
1567
 
 
1568
static unsigned int time_last;
 
1569
 
 
1570
void xscreensaver_heartbeat(void)
 
1571
{
 
1572
    unsigned int time = GetTimerMS();
 
1573
    XEvent ev;
 
1574
 
 
1575
    if (mDisplay && xs_windowid &&
 
1576
        ((time - time_last) > 30000 || (time - time_last) < 0))
 
1577
    {
 
1578
        time_last = time;
 
1579
 
 
1580
        ev.xany.type = ClientMessage;
 
1581
        ev.xclient.display = mDisplay;
 
1582
        ev.xclient.window = xs_windowid;
 
1583
        ev.xclient.message_type = screensaver;
 
1584
        ev.xclient.format = 32;
 
1585
        memset(&ev.xclient.data, 0, sizeof(ev.xclient.data));
 
1586
        ev.xclient.data.l[0] = (long) deactivate;
 
1587
 
 
1588
        mp_msg(MSGT_VO, MSGL_DBG2, "Pinging xscreensaver.\n");
 
1589
        old_handler = XSetErrorHandler(badwindow_handler);
 
1590
        XSendEvent(mDisplay, xs_windowid, False, 0L, &ev);
 
1591
        XSync(mDisplay, False);
 
1592
        XSetErrorHandler(old_handler);        
 
1593
    }
 
1594
}
 
1595
 
 
1596
static void xscreensaver_disable(Display * dpy)
 
1597
{
 
1598
    mp_msg(MSGT_VO, MSGL_DBG2, "xscreensaver_disable()\n");
 
1599
 
 
1600
    xs_windowid = find_xscreensaver_window(dpy);
 
1601
    if (!xs_windowid)
 
1602
    {
 
1603
        mp_msg(MSGT_VO, MSGL_INFO, MSGTR_CouldNotFindXScreenSaver);
 
1604
        return;
 
1605
    }
 
1606
    mp_msg(MSGT_VO, MSGL_INFO,
 
1607
           "xscreensaver_disable: xscreensaver wid=%ld.\n", xs_windowid);
 
1608
 
 
1609
    deactivate = XInternAtom(dpy, "DEACTIVATE", False);
 
1610
    screensaver = XInternAtom(dpy, "SCREENSAVER", False);
 
1611
}
 
1612
 
 
1613
static void xscreensaver_enable(void)
 
1614
{
 
1615
    xs_windowid = 0;
 
1616
}
 
1617
 
 
1618
/*
 
1619
 * End of XScreensaver stuff
 
1620
 */
 
1621
 
 
1622
void saver_on(Display * mDisplay)
 
1623
{
 
1624
 
 
1625
#ifdef HAVE_XDPMS
 
1626
    int nothing;
 
1627
 
 
1628
    if (dpms_disabled)
 
1629
    {
 
1630
        if (DPMSQueryExtension(mDisplay, &nothing, &nothing))
 
1631
        {
 
1632
            if (!DPMSEnable(mDisplay))
 
1633
            {                   // restoring power saving settings
 
1634
                mp_msg(MSGT_VO, MSGL_WARN, "DPMS not available?\n");
 
1635
            } else
 
1636
            {
 
1637
                // DPMS does not seem to be enabled unless we call DPMSInfo
 
1638
                BOOL onoff;
 
1639
                CARD16 state;
 
1640
 
 
1641
                DPMSForceLevel(mDisplay, DPMSModeOn);
 
1642
                DPMSInfo(mDisplay, &state, &onoff);
 
1643
                if (onoff)
 
1644
                {
 
1645
                    mp_msg(MSGT_VO, MSGL_V,
 
1646
                           "Successfully enabled DPMS\n");
 
1647
                } else
 
1648
                {
 
1649
                    mp_msg(MSGT_VO, MSGL_WARN, "Could not enable DPMS\n");
 
1650
                }
 
1651
            }
 
1652
        }
 
1653
        dpms_disabled = 0;
 
1654
    }
 
1655
#endif
 
1656
 
 
1657
    if (timeout_save)
 
1658
    {
 
1659
        int dummy, interval, prefer_blank, allow_exp;
 
1660
 
 
1661
        XGetScreenSaver(mDisplay, &dummy, &interval, &prefer_blank,
 
1662
                        &allow_exp);
 
1663
        XSetScreenSaver(mDisplay, timeout_save, interval, prefer_blank,
 
1664
                        allow_exp);
 
1665
        XGetScreenSaver(mDisplay, &timeout_save, &interval, &prefer_blank,
 
1666
                        &allow_exp);
 
1667
        timeout_save = 0;
 
1668
    }
 
1669
 
 
1670
    if (stop_xscreensaver)
 
1671
        xscreensaver_enable();
 
1672
    if (kdescreensaver_was_running && stop_xscreensaver)
 
1673
    {
 
1674
        system
 
1675
            ("dcop kdesktop KScreensaverIface enable true 2>/dev/null >/dev/null");
 
1676
        kdescreensaver_was_running = 0;
 
1677
    }
 
1678
 
 
1679
 
 
1680
}
 
1681
 
 
1682
void saver_off(Display * mDisplay)
 
1683
{
 
1684
 
 
1685
    int interval, prefer_blank, allow_exp;
 
1686
 
 
1687
#ifdef HAVE_XDPMS
 
1688
    int nothing;
 
1689
 
 
1690
    if (DPMSQueryExtension(mDisplay, &nothing, &nothing))
 
1691
    {
 
1692
        BOOL onoff;
 
1693
        CARD16 state;
 
1694
 
 
1695
        DPMSInfo(mDisplay, &state, &onoff);
 
1696
        if (onoff)
 
1697
        {
 
1698
            Status stat;
 
1699
 
 
1700
            mp_msg(MSGT_VO, MSGL_V, "Disabling DPMS\n");
 
1701
            dpms_disabled = 1;
 
1702
            stat = DPMSDisable(mDisplay);       // monitor powersave off
 
1703
            mp_msg(MSGT_VO, MSGL_V, "DPMSDisable stat: %d\n", stat);
 
1704
        }
 
1705
    }
 
1706
#endif
 
1707
    if (!timeout_save)
 
1708
    {
 
1709
        XGetScreenSaver(mDisplay, &timeout_save, &interval, &prefer_blank,
 
1710
                        &allow_exp);
 
1711
        if (timeout_save)
 
1712
            XSetScreenSaver(mDisplay, 0, interval, prefer_blank,
 
1713
                            allow_exp);
 
1714
    }
 
1715
    // turning off screensaver
 
1716
    if (stop_xscreensaver)
 
1717
        xscreensaver_disable(mDisplay);
 
1718
    if (stop_xscreensaver && !kdescreensaver_was_running)
 
1719
    {
 
1720
        kdescreensaver_was_running =
 
1721
            (system
 
1722
             ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null | sed 's/1/true/g' | grep true 2>/dev/null >/dev/null")
 
1723
             == 0);
 
1724
        if (kdescreensaver_was_running)
 
1725
            system
 
1726
                ("dcop kdesktop KScreensaverIface enable false 2>/dev/null >/dev/null");
 
1727
    }
 
1728
}
 
1729
 
 
1730
static XErrorHandler old_handler = NULL;
 
1731
static int selectinput_err = 0;
 
1732
static int x11_selectinput_errorhandler(Display * display,
 
1733
                                        XErrorEvent * event)
 
1734
{
 
1735
    if (event->error_code == BadAccess)
 
1736
    {
 
1737
        selectinput_err = 1;
 
1738
        mp_msg(MSGT_VO, MSGL_ERR,
 
1739
               "X11 error: BadAccess during XSelectInput Call\n");
 
1740
        mp_msg(MSGT_VO, MSGL_ERR,
 
1741
               "X11 error: The 'ButtonPressMask' mask of specified window has probably already used by another appication (see man XSelectInput)\n");
 
1742
        /* If you think mplayer should shutdown with this error, comments out following line */
 
1743
        return 0;
 
1744
    }
 
1745
    if (old_handler != NULL)
 
1746
        old_handler(display, event);
 
1747
    else
 
1748
        x11_errorhandler(display, event);
 
1749
    return 0;
 
1750
}
 
1751
 
 
1752
void vo_x11_selectinput_witherr(Display * display, Window w,
 
1753
                                long event_mask)
 
1754
{
 
1755
    XSync(display, False);
 
1756
    old_handler = XSetErrorHandler(x11_selectinput_errorhandler);
 
1757
    selectinput_err = 0;
 
1758
    if (vo_nomouse_input)
 
1759
    {
 
1760
        XSelectInput(display, w,
 
1761
                     event_mask &
 
1762
                     (~(ButtonPressMask | ButtonReleaseMask)));
 
1763
    } else
 
1764
    {
 
1765
        XSelectInput(display, w, event_mask);
 
1766
    }
 
1767
    XSync(display, False);
 
1768
    XSetErrorHandler(old_handler);
 
1769
    if (selectinput_err)
 
1770
    {
 
1771
        mp_msg(MSGT_VO, MSGL_ERR,
 
1772
               "X11 error: MPlayer discards mouse control (reconfiguring)\n");
 
1773
        XSelectInput(display, w,
 
1774
                     event_mask &
 
1775
                     (~
 
1776
                      (ButtonPressMask | ButtonReleaseMask |
 
1777
                       PointerMotionMask)));
 
1778
    }
 
1779
}
 
1780
 
 
1781
#ifdef HAVE_XINERAMA
 
1782
void vo_x11_xinerama_move(Display * dsp, Window w)
 
1783
{
 
1784
    if (XineramaIsActive(dsp) && !geometry_xy_changed)
 
1785
    {
 
1786
        /* printf("XXXX Xinerama screen: x: %hd y: %hd\n",xinerama_x,xinerama_y); */
 
1787
        XMoveWindow(dsp, w, xinerama_x, xinerama_y);
 
1788
    }
 
1789
}
 
1790
#endif
 
1791
 
 
1792
#ifdef HAVE_XF86VM
 
1793
void vo_vm_switch(uint32_t X, uint32_t Y, int *modeline_width,
 
1794
                  int *modeline_height)
 
1795
{
 
1796
    int vm_event, vm_error;
 
1797
    int vm_ver, vm_rev;
 
1798
    int i, j, have_vm = 0;
 
1799
 
 
1800
    int modecount;
 
1801
 
 
1802
    if (XF86VidModeQueryExtension(mDisplay, &vm_event, &vm_error))
 
1803
    {
 
1804
        XF86VidModeQueryVersion(mDisplay, &vm_ver, &vm_rev);
 
1805
        mp_msg(MSGT_VO, MSGL_V, "XF86VidMode Extension v%i.%i\n", vm_ver,
 
1806
               vm_rev);
 
1807
        have_vm = 1;
 
1808
    } else
 
1809
        mp_msg(MSGT_VO, MSGL_WARN,
 
1810
               "XF86VidMode Extenstion not available.\n");
 
1811
 
 
1812
    if (have_vm)
 
1813
    {
 
1814
        if (vidmodes == NULL)
 
1815
            XF86VidModeGetAllModeLines(mDisplay, mScreen, &modecount,
 
1816
                                       &vidmodes);
 
1817
        j = 0;
 
1818
        *modeline_width = vidmodes[0]->hdisplay;
 
1819
        *modeline_height = vidmodes[0]->vdisplay;
 
1820
 
 
1821
        for (i = 1; i < modecount; i++)
 
1822
            if ((vidmodes[i]->hdisplay >= X)
 
1823
                && (vidmodes[i]->vdisplay >= Y))
 
1824
                if ((vidmodes[i]->hdisplay <= *modeline_width)
 
1825
                    && (vidmodes[i]->vdisplay <= *modeline_height))
 
1826
                {
 
1827
                    *modeline_width = vidmodes[i]->hdisplay;
 
1828
                    *modeline_height = vidmodes[i]->vdisplay;
 
1829
                    j = i;
 
1830
                }
 
1831
 
 
1832
        mp_msg(MSGT_VO, MSGL_INFO, MSGTR_SelectedVideoMode,
 
1833
               *modeline_width, *modeline_height, X, Y);
 
1834
        XF86VidModeLockModeSwitch(mDisplay, mScreen, 0);
 
1835
        XF86VidModeSwitchToMode(mDisplay, mScreen, vidmodes[j]);
 
1836
        XF86VidModeSwitchToMode(mDisplay, mScreen, vidmodes[j]);
 
1837
        X = (vo_screenwidth - *modeline_width) / 2;
 
1838
        Y = (vo_screenheight - *modeline_height) / 2;
 
1839
        XF86VidModeSetViewPort(mDisplay, mScreen, X, Y);
 
1840
    }
 
1841
}
 
1842
 
 
1843
void vo_vm_close(Display * dpy)
 
1844
{
 
1845
#ifdef HAVE_NEW_GUI
 
1846
    if (vidmodes != NULL && vo_window != None)
 
1847
#else
 
1848
    if (vidmodes != NULL)
 
1849
#endif
 
1850
    {
 
1851
        int i, modecount;
 
1852
        int screen;
 
1853
 
 
1854
        screen = DefaultScreen(dpy);
 
1855
 
 
1856
        free(vidmodes);
 
1857
        vidmodes = NULL;
 
1858
        XF86VidModeGetAllModeLines(mDisplay, mScreen, &modecount,
 
1859
                                   &vidmodes);
 
1860
        for (i = 0; i < modecount; i++)
 
1861
            if ((vidmodes[i]->hdisplay == vo_screenwidth)
 
1862
                && (vidmodes[i]->vdisplay == vo_screenheight))
 
1863
            {
 
1864
                mp_msg(MSGT_VO, MSGL_INFO,
 
1865
                       "Returning to original mode %dx%d\n",
 
1866
                       vo_screenwidth, vo_screenheight);
 
1867
                break;
 
1868
            }
 
1869
 
 
1870
        XF86VidModeSwitchToMode(dpy, screen, vidmodes[i]);
 
1871
        XF86VidModeSwitchToMode(dpy, screen, vidmodes[i]);
 
1872
        free(vidmodes);
 
1873
        vidmodes = NULL;
 
1874
    }
 
1875
}
 
1876
#endif
 
1877
 
 
1878
#endif                          /* X11_FULLSCREEN */
 
1879
 
 
1880
 
 
1881
/*
 
1882
 * Scan the available visuals on this Display/Screen.  Try to find
 
1883
 * the 'best' available TrueColor visual that has a decent color
 
1884
 * depth (at least 15bit).  If there are multiple visuals with depth
 
1885
 * >= 15bit, we prefer visuals with a smaller color depth.
 
1886
 */
 
1887
int vo_find_depth_from_visuals(Display * dpy, int screen,
 
1888
                               Visual ** visual_return)
 
1889
{
 
1890
    XVisualInfo visual_tmpl;
 
1891
    XVisualInfo *visuals;
 
1892
    int nvisuals, i;
 
1893
    int bestvisual = -1;
 
1894
    int bestvisual_depth = -1;
 
1895
 
 
1896
    visual_tmpl.screen = screen;
 
1897
    visual_tmpl.class = TrueColor;
 
1898
    visuals = XGetVisualInfo(dpy,
 
1899
                             VisualScreenMask | VisualClassMask,
 
1900
                             &visual_tmpl, &nvisuals);
 
1901
    if (visuals != NULL)
 
1902
    {
 
1903
        for (i = 0; i < nvisuals; i++)
 
1904
        {
 
1905
            mp_msg(MSGT_VO, MSGL_V,
 
1906
                   "vo: X11 truecolor visual %#lx, depth %d, R:%lX G:%lX B:%lX\n",
 
1907
                   visuals[i].visualid, visuals[i].depth,
 
1908
                   visuals[i].red_mask, visuals[i].green_mask,
 
1909
                   visuals[i].blue_mask);
 
1910
            /*
 
1911
             * save the visual index and it's depth, if this is the first
 
1912
             * truecolor visul, or a visual that is 'preferred' over the
 
1913
             * previous 'best' visual
 
1914
             */
 
1915
            if (bestvisual_depth == -1
 
1916
                || (visuals[i].depth >= 15
 
1917
                    && (visuals[i].depth < bestvisual_depth
 
1918
                        || bestvisual_depth < 15)))
 
1919
            {
 
1920
                bestvisual = i;
 
1921
                bestvisual_depth = visuals[i].depth;
 
1922
            }
 
1923
        }
 
1924
 
 
1925
        if (bestvisual != -1 && visual_return != NULL)
 
1926
            *visual_return = visuals[bestvisual].visual;
 
1927
 
 
1928
        XFree(visuals);
 
1929
    }
 
1930
    return bestvisual_depth;
 
1931
}
 
1932
 
 
1933
 
 
1934
static Colormap cmap = None;
 
1935
static XColor cols[256];
 
1936
static int cm_size, red_mask, green_mask, blue_mask;
 
1937
 
 
1938
 
 
1939
Colormap vo_x11_create_colormap(XVisualInfo * vinfo)
 
1940
{
 
1941
    unsigned k, r, g, b, ru, gu, bu, m, rv, gv, bv, rvu, gvu, bvu;
 
1942
 
 
1943
    if (vinfo->class != DirectColor)
 
1944
        return XCreateColormap(mDisplay, mRootWin, vinfo->visual,
 
1945
                               AllocNone);
 
1946
 
 
1947
    /* can this function get called twice or more? */
 
1948
    if (cmap)
 
1949
        return cmap;
 
1950
    cm_size = vinfo->colormap_size;
 
1951
    red_mask = vinfo->red_mask;
 
1952
    green_mask = vinfo->green_mask;
 
1953
    blue_mask = vinfo->blue_mask;
 
1954
    ru = (red_mask & (red_mask - 1)) ^ red_mask;
 
1955
    gu = (green_mask & (green_mask - 1)) ^ green_mask;
 
1956
    bu = (blue_mask & (blue_mask - 1)) ^ blue_mask;
 
1957
    rvu = 65536ull * ru / (red_mask + ru);
 
1958
    gvu = 65536ull * gu / (green_mask + gu);
 
1959
    bvu = 65536ull * bu / (blue_mask + bu);
 
1960
    r = g = b = 0;
 
1961
    rv = gv = bv = 0;
 
1962
    m = DoRed | DoGreen | DoBlue;
 
1963
    for (k = 0; k < cm_size; k++)
 
1964
    {
 
1965
        int t;
 
1966
 
 
1967
        cols[k].pixel = r | g | b;
 
1968
        cols[k].red = rv;
 
1969
        cols[k].green = gv;
 
1970
        cols[k].blue = bv;
 
1971
        cols[k].flags = m;
 
1972
        t = (r + ru) & red_mask;
 
1973
        if (t < r)
 
1974
            m &= ~DoRed;
 
1975
        r = t;
 
1976
        t = (g + gu) & green_mask;
 
1977
        if (t < g)
 
1978
            m &= ~DoGreen;
 
1979
        g = t;
 
1980
        t = (b + bu) & blue_mask;
 
1981
        if (t < b)
 
1982
            m &= ~DoBlue;
 
1983
        b = t;
 
1984
        rv += rvu;
 
1985
        gv += gvu;
 
1986
        bv += bvu;
 
1987
    }
 
1988
    cmap = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocAll);
 
1989
    XStoreColors(mDisplay, cmap, cols, cm_size);
 
1990
    return cmap;
 
1991
}
 
1992
 
 
1993
/*
 
1994
 * Via colormaps/gamma ramps we can do gamma, brightness, contrast,
 
1995
 * hue and red/green/blue intensity, but we cannot do saturation.
 
1996
 * Currently only gamma, brightness and contrast are implemented.
 
1997
 * Is there sufficient interest for hue and/or red/green/blue intensity?
 
1998
 */
 
1999
/* these values have range [-100,100] and are initially 0 */
 
2000
static int vo_gamma = 0;
 
2001
static int vo_brightness = 0;
 
2002
static int vo_contrast = 0;
 
2003
 
 
2004
 
 
2005
uint32_t vo_x11_set_equalizer(char *name, int value)
 
2006
{
 
2007
    float gamma, brightness, contrast;
 
2008
    float rf, gf, bf;
 
2009
    int k;
 
2010
 
 
2011
    /*
 
2012
     * IMPLEMENTME: consider using XF86VidModeSetGammaRamp in the case
 
2013
     * of TrueColor-ed window but be careful:
 
2014
     * unlike the colormaps, which are private for the X client
 
2015
     * who created them and thus automatically destroyed on client
 
2016
     * disconnect, this gamma ramp is a system-wide (X-server-wide)
 
2017
     * setting and _must_ be restored before the process exit.
 
2018
     * Unforunately when the process crashes (or get killed
 
2019
     * for some reason) it is impossible to restore the setting,
 
2020
     * and such behaviour could be rather annoying for the users.
 
2021
     */
 
2022
    if (cmap == None)
 
2023
        return VO_NOTAVAIL;
 
2024
 
 
2025
    if (!strcasecmp(name, "brightness"))
 
2026
        vo_brightness = value;
 
2027
    else if (!strcasecmp(name, "contrast"))
 
2028
        vo_contrast = value;
 
2029
    else if (!strcasecmp(name, "gamma"))
 
2030
        vo_gamma = value;
 
2031
    else
 
2032
        return VO_NOTIMPL;
 
2033
 
 
2034
    brightness = 0.01 * vo_brightness;
 
2035
    contrast = tan(0.0095 * (vo_contrast + 100) * M_PI / 4);
 
2036
    gamma = pow(2, -0.02 * vo_gamma);
 
2037
 
 
2038
    rf = (float) ((red_mask & (red_mask - 1)) ^ red_mask) / red_mask;
 
2039
    gf = (float) ((green_mask & (green_mask - 1)) ^ green_mask) /
 
2040
        green_mask;
 
2041
    bf = (float) ((blue_mask & (blue_mask - 1)) ^ blue_mask) / blue_mask;
 
2042
 
 
2043
    /* now recalculate the colormap using the newly set value */
 
2044
    for (k = 0; k < cm_size; k++)
 
2045
    {
 
2046
        float s;
 
2047
 
 
2048
        s = pow(rf * k, gamma);
 
2049
        s = (s - 0.5) * contrast + 0.5;
 
2050
        s += brightness;
 
2051
        if (s < 0)
 
2052
            s = 0;
 
2053
        if (s > 1)
 
2054
            s = 1;
 
2055
        cols[k].red = (unsigned short) (s * 65535);
 
2056
 
 
2057
        s = pow(gf * k, gamma);
 
2058
        s = (s - 0.5) * contrast + 0.5;
 
2059
        s += brightness;
 
2060
        if (s < 0)
 
2061
            s = 0;
 
2062
        if (s > 1)
 
2063
            s = 1;
 
2064
        cols[k].green = (unsigned short) (s * 65535);
 
2065
 
 
2066
        s = pow(bf * k, gamma);
 
2067
        s = (s - 0.5) * contrast + 0.5;
 
2068
        s += brightness;
 
2069
        if (s < 0)
 
2070
            s = 0;
 
2071
        if (s > 1)
 
2072
            s = 1;
 
2073
        cols[k].blue = (unsigned short) (s * 65535);
 
2074
    }
 
2075
 
 
2076
    XStoreColors(mDisplay, cmap, cols, cm_size);
 
2077
    XFlush(mDisplay);
 
2078
    return VO_TRUE;
 
2079
}
 
2080
 
 
2081
uint32_t vo_x11_get_equalizer(char *name, int *value)
 
2082
{
 
2083
    if (cmap == None)
 
2084
        return VO_NOTAVAIL;
 
2085
    if (!strcasecmp(name, "brightness"))
 
2086
        *value = vo_brightness;
 
2087
    else if (!strcasecmp(name, "contrast"))
 
2088
        *value = vo_contrast;
 
2089
    else if (!strcasecmp(name, "gamma"))
 
2090
        *value = vo_gamma;
 
2091
    else
 
2092
        return VO_NOTIMPL;
 
2093
    return VO_TRUE;
 
2094
}
 
2095
 
 
2096
#ifdef HAVE_XV
 
2097
int vo_xv_set_eq(uint32_t xv_port, char *name, int value)
 
2098
{
 
2099
    XvAttribute *attributes;
 
2100
    int i, howmany, xv_atom;
 
2101
 
 
2102
    mp_dbg(MSGT_VO, MSGL_V, "xv_set_eq called! (%s, %d)\n", name, value);
 
2103
 
 
2104
    /* get available attributes */
 
2105
    attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
 
2106
    for (i = 0; i < howmany && attributes; i++)
 
2107
        if (attributes[i].flags & XvSettable)
 
2108
        {
 
2109
            xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
 
2110
/* since we have SET_DEFAULTS first in our list, we can check if it's available
 
2111
   then trigger it if it's ok so that the other values are at default upon query */
 
2112
            if (xv_atom != None)
 
2113
            {
 
2114
                int hue = 0, port_value, port_min, port_max;
 
2115
 
 
2116
                if (!strcmp(attributes[i].name, "XV_BRIGHTNESS") &&
 
2117
                    (!strcasecmp(name, "brightness")))
 
2118
                    port_value = value;
 
2119
                else if (!strcmp(attributes[i].name, "XV_CONTRAST") &&
 
2120
                         (!strcasecmp(name, "contrast")))
 
2121
                    port_value = value;
 
2122
                else if (!strcmp(attributes[i].name, "XV_SATURATION") &&
 
2123
                         (!strcasecmp(name, "saturation")))
 
2124
                    port_value = value;
 
2125
                else if (!strcmp(attributes[i].name, "XV_HUE") &&
 
2126
                         (!strcasecmp(name, "hue")))
 
2127
                {
 
2128
                    port_value = value;
 
2129
                    hue = 1;
 
2130
                } else
 
2131
                    /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
 
2132
                if (!strcmp(attributes[i].name, "XV_RED_INTENSITY") &&
 
2133
                        (!strcasecmp(name, "red_intensity")))
 
2134
                    port_value = value;
 
2135
                else if (!strcmp(attributes[i].name, "XV_GREEN_INTENSITY")
 
2136
                         && (!strcasecmp(name, "green_intensity")))
 
2137
                    port_value = value;
 
2138
                else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY")
 
2139
                         && (!strcasecmp(name, "blue_intensity")))
 
2140
                    port_value = value;
 
2141
                else
 
2142
                    continue;
 
2143
 
 
2144
                port_min = attributes[i].min_value;
 
2145
                port_max = attributes[i].max_value;
 
2146
 
 
2147
                /* nvidia hue workaround */
 
2148
                if (hue && port_min == 0 && port_max == 360)
 
2149
                {
 
2150
                    port_value =
 
2151
                        (port_value >=
 
2152
                         0) ? (port_value - 100) : (port_value + 100);
 
2153
                }
 
2154
                // -100 -> min
 
2155
                //   0  -> (max+min)/2
 
2156
                // +100 -> max
 
2157
                port_value =
 
2158
                    (port_value + 100) * (port_max - port_min) / 200 +
 
2159
                    port_min;
 
2160
                XvSetPortAttribute(mDisplay, xv_port, xv_atom, port_value);
 
2161
                return (VO_TRUE);
 
2162
            }
 
2163
        }
 
2164
    return (VO_FALSE);
 
2165
}
 
2166
 
 
2167
int vo_xv_get_eq(uint32_t xv_port, char *name, int *value)
 
2168
{
 
2169
 
 
2170
    XvAttribute *attributes;
 
2171
    int i, howmany, xv_atom;
 
2172
 
 
2173
    /* get available attributes */
 
2174
    attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
 
2175
    for (i = 0; i < howmany && attributes; i++)
 
2176
        if (attributes[i].flags & XvGettable)
 
2177
        {
 
2178
            xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
 
2179
/* since we have SET_DEFAULTS first in our list, we can check if it's available
 
2180
   then trigger it if it's ok so that the other values are at default upon query */
 
2181
            if (xv_atom != None)
 
2182
            {
 
2183
                int val, port_value = 0, port_min, port_max;
 
2184
 
 
2185
                XvGetPortAttribute(mDisplay, xv_port, xv_atom,
 
2186
                                   &port_value);
 
2187
 
 
2188
                port_min = attributes[i].min_value;
 
2189
                port_max = attributes[i].max_value;
 
2190
                val =
 
2191
                    (port_value - port_min) * 200 / (port_max - port_min) -
 
2192
                    100;
 
2193
 
 
2194
                if (!strcmp(attributes[i].name, "XV_BRIGHTNESS") &&
 
2195
                    (!strcasecmp(name, "brightness")))
 
2196
                    *value = val;
 
2197
                else if (!strcmp(attributes[i].name, "XV_CONTRAST") &&
 
2198
                         (!strcasecmp(name, "contrast")))
 
2199
                    *value = val;
 
2200
                else if (!strcmp(attributes[i].name, "XV_SATURATION") &&
 
2201
                         (!strcasecmp(name, "saturation")))
 
2202
                    *value = val;
 
2203
                else if (!strcmp(attributes[i].name, "XV_HUE") &&
 
2204
                         (!strcasecmp(name, "hue")))
 
2205
                {
 
2206
                    /* nasty nvidia detect */
 
2207
                    if (port_min == 0 && port_max == 360)
 
2208
                        *value = (val >= 0) ? (val - 100) : (val + 100);
 
2209
                    else
 
2210
                        *value = val;
 
2211
                } else
 
2212
                    /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
 
2213
                if (!strcmp(attributes[i].name, "XV_RED_INTENSITY") &&
 
2214
                        (!strcasecmp(name, "red_intensity")))
 
2215
                    *value = val;
 
2216
                else if (!strcmp(attributes[i].name, "XV_GREEN_INTENSITY")
 
2217
                         && (!strcasecmp(name, "green_intensity")))
 
2218
                    *value = val;
 
2219
                else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY")
 
2220
                         && (!strcasecmp(name, "blue_intensity")))
 
2221
                    *value = val;
 
2222
                else
 
2223
                    continue;
 
2224
 
 
2225
                mp_dbg(MSGT_VO, MSGL_V, "xv_get_eq called! (%s, %d)\n",
 
2226
                       name, *value);
 
2227
                return (VO_TRUE);
 
2228
            }
 
2229
        }
 
2230
    return (VO_FALSE);
 
2231
}
 
2232
 
 
2233
/** \brief contains flags changing the execution of the colorkeying code */
 
2234
xv_ck_info_t xv_ck_info = { CK_METHOD_MANUALFILL, CK_SRC_CUR };
 
2235
unsigned long xv_colorkey; ///< The color used for manual colorkeying.
 
2236
unsigned int xv_port; ///< The selected Xv port.
 
2237
 
 
2238
/**
 
2239
 * \brief Interns the requested atom if it is available.
 
2240
 *
 
2241
 * \param atom_name String containing the name of the requested atom.
 
2242
 *
 
2243
 * \return Returns the atom if available, else None is returned.
 
2244
 *
 
2245
 */
 
2246
static Atom xv_intern_atom_if_exists( char const * atom_name )
 
2247
{
 
2248
  XvAttribute * attributes;
 
2249
  int attrib_count,i;
 
2250
  Atom xv_atom = None;
 
2251
 
 
2252
  attributes = XvQueryPortAttributes( mDisplay, xv_port, &attrib_count );
 
2253
  if( attributes!=NULL )
 
2254
  {
 
2255
    for ( i = 0; i < attrib_count; ++i )
 
2256
    {
 
2257
      if ( strcmp(attributes[i].name, atom_name ) == 0 )
 
2258
      {
 
2259
        xv_atom = XInternAtom( mDisplay, atom_name, False );
 
2260
        break; // found what we want, break out
 
2261
      }
 
2262
    }
 
2263
    XFree( attributes );
 
2264
  }
 
2265
 
 
2266
  return xv_atom;
 
2267
}
 
2268
 
 
2269
/**
 
2270
 * \brief Try to enable vsync for xv.
 
2271
 * \return Returns -1 if not available, 0 on failure and 1 on success.
 
2272
 */
 
2273
int vo_xv_enable_vsync()
 
2274
{
 
2275
  Atom xv_atom = xv_intern_atom_if_exists("XV_SYNC_TO_VBLANK");
 
2276
  if (xv_atom == None)
 
2277
    return -1;
 
2278
  return XvSetPortAttribute(mDisplay, xv_port, xv_atom, 1) == Success;
 
2279
}
 
2280
 
 
2281
/**
 
2282
 * \brief Get maximum supported source image dimensions.
 
2283
 *
 
2284
 *   This function does not set the variables pointed to by
 
2285
 * width and height if the information could not be retreived.
 
2286
 * So the caller is reponsible for initing them properly.
 
2287
 *
 
2288
 * \param width [out] The maximum width gets stored here.
 
2289
 * \param height [out] The maximum height gets stored here.
 
2290
 *
 
2291
 */
 
2292
void vo_xv_get_max_img_dim( uint32_t * width, uint32_t * height )
 
2293
{
 
2294
  XvEncodingInfo * encodings;
 
2295
  //unsigned long num_encodings, idx; to int or too long?!
 
2296
  unsigned int num_encodings, idx;
 
2297
 
 
2298
  XvQueryEncodings( mDisplay, xv_port, &num_encodings, &encodings);
 
2299
 
 
2300
  if ( encodings )
 
2301
  {
 
2302
      for ( idx = 0; idx < num_encodings; ++idx )
 
2303
      {
 
2304
          if ( strcmp( encodings[idx].name, "XV_IMAGE" ) == 0 )
 
2305
          {
 
2306
              *width  = encodings[idx].width;
 
2307
              *height = encodings[idx].height;
 
2308
              break;
 
2309
          }
 
2310
      }
 
2311
  }
 
2312
 
 
2313
  mp_msg( MSGT_VO, MSGL_V,
 
2314
          "[xv common] Maximum source image dimensions: %ux%u\n",
 
2315
          *width, *height );
 
2316
 
 
2317
  XvFreeEncodingInfo( encodings );
 
2318
}
 
2319
 
 
2320
/**
 
2321
 * \brief Print information about the colorkey method and source.
 
2322
 *
 
2323
 * \param ck_handling Integer value containing the information about
 
2324
 *                    colorkey handling (see x11_common.h).
 
2325
 *
 
2326
 * Outputs the content of |ck_handling| as a readable message.
 
2327
 *
 
2328
 */
 
2329
void vo_xv_print_ck_info()
 
2330
{
 
2331
  mp_msg( MSGT_VO, MSGL_V, "[xv common] " );
 
2332
 
 
2333
  switch ( xv_ck_info.method )
 
2334
  {
 
2335
    case CK_METHOD_NONE:
 
2336
      mp_msg( MSGT_VO, MSGL_V, "Drawing no colorkey.\n" ); return;
 
2337
    case CK_METHOD_AUTOPAINT:
 
2338
      mp_msg( MSGT_VO, MSGL_V, "Colorkey is drawn by Xv." ); break;
 
2339
    case CK_METHOD_MANUALFILL:
 
2340
      mp_msg( MSGT_VO, MSGL_V, "Drawing colorkey manually." ); break;
 
2341
    case CK_METHOD_BACKGROUND:
 
2342
      mp_msg( MSGT_VO, MSGL_V, "Colorkey is drawn as window background." ); break;
 
2343
  }
 
2344
 
 
2345
  mp_msg( MSGT_VO, MSGL_V, "\n[xv common] " );
 
2346
 
 
2347
  switch ( xv_ck_info.source )
 
2348
  {
 
2349
    case CK_SRC_CUR:      
 
2350
      mp_msg( MSGT_VO, MSGL_V, "Using colorkey from Xv (0x%06lx).\n",
 
2351
              xv_colorkey );
 
2352
      break;
 
2353
    case CK_SRC_USE:
 
2354
      if ( xv_ck_info.method == CK_METHOD_AUTOPAINT )
 
2355
      {
 
2356
        mp_msg( MSGT_VO, MSGL_V,
 
2357
                "Ignoring colorkey from MPlayer (0x%06lx).\n",
 
2358
                xv_colorkey );
 
2359
      }
 
2360
      else
 
2361
      {
 
2362
        mp_msg( MSGT_VO, MSGL_V,
 
2363
                "Using colorkey from MPlayer (0x%06lx)."
 
2364
                " Use -colorkey to change.\n",
 
2365
                xv_colorkey );
 
2366
      }
 
2367
      break;
 
2368
    case CK_SRC_SET:
 
2369
      mp_msg( MSGT_VO, MSGL_V,
 
2370
              "Setting and using colorkey from MPlayer (0x%06lx)."
 
2371
              " Use -colorkey to change.\n",
 
2372
              xv_colorkey );
 
2373
      break;
 
2374
  }
 
2375
}
 
2376
/**
 
2377
 * \brief Init colorkey depending on the settings in xv_ck_info.
 
2378
 *
 
2379
 * \return Returns 0 on failure and 1 on success.
 
2380
 *
 
2381
 * Sets the colorkey variable according to the CK_SRC_* and CK_METHOD_*
 
2382
 * flags in xv_ck_info.
 
2383
 *
 
2384
 * Possiblilities:
 
2385
 *   * Methods
 
2386
 *     - manual colorkey drawing ( CK_METHOD_MANUALFILL )
 
2387
 *     - set colorkey as window background ( CK_METHOD_BACKGROUND )
 
2388
 *     - let Xv paint the colorkey ( CK_METHOD_AUTOPAINT )
 
2389
 *   * Sources
 
2390
 *     - use currently set colorkey ( CK_SRC_CUR )
 
2391
 *     - use colorkey in vo_colorkey ( CK_SRC_USE )
 
2392
 *     - use and set colorkey in vo_colorkey ( CK_SRC_SET )
 
2393
 *
 
2394
 * NOTE: If vo_colorkey has bits set after the first 3 low order bytes
 
2395
 *       we don't draw anything as this means it was forced to off.
 
2396
 */
 
2397
int vo_xv_init_colorkey()
 
2398
{
 
2399
  Atom xv_atom;
 
2400
  int rez;
 
2401
 
 
2402
  /* check if colorkeying is needed */
 
2403
  xv_atom = xv_intern_atom_if_exists( "XV_COLORKEY" );
 
2404
 
 
2405
  /* if we have to deal with colorkeying ... */
 
2406
  if( xv_atom != None && !(vo_colorkey & 0xFF000000) )
 
2407
  {
 
2408
    /* check if we should use the colorkey specified in vo_colorkey */
 
2409
    if ( xv_ck_info.source != CK_SRC_CUR )
 
2410
    {
 
2411
      xv_colorkey = vo_colorkey;
 
2412
  
 
2413
      /* check if we have to set the colorkey too */
 
2414
      if ( xv_ck_info.source == CK_SRC_SET )
 
2415
      {
 
2416
        xv_atom = XInternAtom(mDisplay, "XV_COLORKEY",False);
 
2417
  
 
2418
        rez = XvSetPortAttribute( mDisplay, xv_port, xv_atom, vo_colorkey );
 
2419
        if ( rez != Success )
 
2420
        {
 
2421
          mp_msg( MSGT_VO, MSGL_FATAL,
 
2422
                  "[xv common] Couldn't set colorkey!\n" );
 
2423
          return 0; // error setting colorkey
 
2424
        }
 
2425
      }
 
2426
    }
 
2427
    else 
 
2428
    {
 
2429
      int colorkey_ret;
 
2430
 
 
2431
      rez=XvGetPortAttribute(mDisplay,xv_port, xv_atom, &colorkey_ret);
 
2432
      if ( rez == Success )
 
2433
      {
 
2434
         xv_colorkey = colorkey_ret;
 
2435
      }
 
2436
      else
 
2437
      {
 
2438
        mp_msg( MSGT_VO, MSGL_FATAL,
 
2439
                "[xv common] Couldn't get colorkey!"
 
2440
                "Maybe the selected Xv port has no overlay.\n" );
 
2441
        return 0; // error getting colorkey
 
2442
      }
 
2443
    }
 
2444
 
 
2445
    xv_atom = xv_intern_atom_if_exists( "XV_AUTOPAINT_COLORKEY" );    
 
2446
 
 
2447
    /* should we draw the colorkey ourselves or activate autopainting? */
 
2448
    if ( xv_ck_info.method == CK_METHOD_AUTOPAINT )
 
2449
    {
 
2450
      rez = !Success; // reset rez to something different than Success
 
2451
 
 
2452
      if ( xv_atom != None ) // autopaint is supported
 
2453
      {
 
2454
        rez = XvSetPortAttribute( mDisplay, xv_port, xv_atom, 1 );
 
2455
      }
 
2456
 
 
2457
      if ( rez != Success )
 
2458
      {
 
2459
        // fallback to manual colorkey drawing
 
2460
        xv_ck_info.method = CK_METHOD_MANUALFILL;
 
2461
      }
 
2462
    }
 
2463
    else // disable colorkey autopainting if supported
 
2464
    {
 
2465
      if ( xv_atom != None ) // we have autopaint attribute
 
2466
      {
 
2467
        XvSetPortAttribute( mDisplay, xv_port, xv_atom, 0 );
 
2468
      }
 
2469
    }
 
2470
  }
 
2471
  else // do no colorkey drawing at all
 
2472
  {
 
2473
    xv_ck_info.method = CK_METHOD_NONE;
 
2474
  } /* end: should we draw colorkey */
 
2475
 
 
2476
  /* output information about the curren colorkey settings */
 
2477
  vo_xv_print_ck_info();
 
2478
 
 
2479
  return 1; // success
 
2480
}
 
2481
 
 
2482
/**
 
2483
 * \brief Draw the colorkey on the video window.
 
2484
 *
 
2485
 * Draws the colorkey depending on the set method ( colorkey_handling ).
 
2486
 *
 
2487
 * It also draws the black bars ( when the video doesn't fit to the
 
2488
 * display in full screen ) seperately, so they don't overlap with the
 
2489
 * video area.
 
2490
 * It doesn't call XFlush
 
2491
 *
 
2492
 */
 
2493
inline void vo_xv_draw_colorkey(  int32_t x,  int32_t y,
 
2494
                                  int32_t w,  int32_t h  )
 
2495
{
 
2496
  if( xv_ck_info.method == CK_METHOD_MANUALFILL ||
 
2497
      xv_ck_info.method == CK_METHOD_BACKGROUND   )//less tearing than XClearWindow()
 
2498
  {
 
2499
    XSetForeground( mDisplay, vo_gc, xv_colorkey );
 
2500
    XFillRectangle( mDisplay, vo_window, vo_gc,
 
2501
                    x, y,
 
2502
                    w, h );
 
2503
  }
 
2504
 
 
2505
  /* draw black bars if needed */
 
2506
  /* TODO! move this to vo_x11_clearwindow_part() */
 
2507
  if ( vo_fs )
 
2508
  {
 
2509
    XSetForeground( mDisplay, vo_gc, 0 );
 
2510
    /* making non overlap fills, requiare 8 checks instead of 4*/
 
2511
    if ( y > 0 )
 
2512
      XFillRectangle( mDisplay, vo_window, vo_gc,
 
2513
                      0, 0,
 
2514
                      vo_screenwidth, y);
 
2515
    if (x > 0)
 
2516
      XFillRectangle( mDisplay, vo_window, vo_gc,
 
2517
                      0, 0,
 
2518
                      x, vo_screenheight);
 
2519
    if (x + w < vo_screenwidth)
 
2520
      XFillRectangle( mDisplay, vo_window, vo_gc,
 
2521
                      x + w, 0,
 
2522
                      vo_screenwidth, vo_screenheight);
 
2523
    if (y + h < vo_screenheight)
 
2524
      XFillRectangle( mDisplay, vo_window, vo_gc,
 
2525
                      0, y + h,
 
2526
                      vo_screenwidth, vo_screenheight);
 
2527
  }
 
2528
}
 
2529
 
 
2530
/** \brief tests if a valid arg for the ck suboption was given */ 
 
2531
int xv_test_ck( void * arg )
 
2532
{
 
2533
  strarg_t * strarg = (strarg_t *)arg;
 
2534
 
 
2535
  if ( strargcmp( strarg, "use" ) == 0 ||
 
2536
       strargcmp( strarg, "set" ) == 0 ||
 
2537
       strargcmp( strarg, "cur" ) == 0    )
 
2538
  {
 
2539
    return 1;
 
2540
  }
 
2541
 
 
2542
  return 0;
 
2543
}
 
2544
/** \brief tests if a valid arg for the ck-method suboption was given */ 
 
2545
int xv_test_ckm( void * arg )
 
2546
{
 
2547
  strarg_t * strarg = (strarg_t *)arg;
 
2548
 
 
2549
  if ( strargcmp( strarg, "bg" ) == 0 ||
 
2550
       strargcmp( strarg, "man" ) == 0 ||
 
2551
       strargcmp( strarg, "auto" ) == 0    )
 
2552
  {
 
2553
    return 1;
 
2554
  }
 
2555
 
 
2556
  return 0;
 
2557
}
 
2558
 
 
2559
/**
 
2560
 * \brief Modify the colorkey_handling var according to str
 
2561
 *
 
2562
 * Checks if a valid pointer ( not NULL ) to the string
 
2563
 * was given. And in that case modifies the colorkey_handling
 
2564
 * var to reflect the requested behaviour.
 
2565
 * If nothing happens the content of colorkey_handling stays
 
2566
 * the same.
 
2567
 *
 
2568
 * \param str Pointer to the string or NULL
 
2569
 *
 
2570
 */
 
2571
void xv_setup_colorkeyhandling( char const * ck_method_str,
 
2572
                                char const * ck_str )
 
2573
{
 
2574
  /* check if a valid pointer to the string was passed */
 
2575
  if ( ck_str )
 
2576
  {
 
2577
    if ( strncmp( ck_str, "use", 3 ) == 0 )
 
2578
    {
 
2579
      xv_ck_info.source = CK_SRC_USE;
 
2580
    }
 
2581
    else if ( strncmp( ck_str, "set", 3 ) == 0 )
 
2582
    {
 
2583
      xv_ck_info.source = CK_SRC_SET;
 
2584
    }
 
2585
  }
 
2586
  /* check if a valid pointer to the string was passed */
 
2587
  if ( ck_method_str )
 
2588
  {
 
2589
    if ( strncmp( ck_method_str, "bg", 2 ) == 0 )
 
2590
    {
 
2591
      xv_ck_info.method = CK_METHOD_BACKGROUND;
 
2592
    }
 
2593
    else if ( strncmp( ck_method_str, "man", 3 ) == 0 )
 
2594
    {
 
2595
      xv_ck_info.method = CK_METHOD_MANUALFILL;
 
2596
    }    
 
2597
    else if ( strncmp( ck_method_str, "auto", 4 ) == 0 )
 
2598
    {
 
2599
      xv_ck_info.method = CK_METHOD_AUTOPAINT;
 
2600
    }    
 
2601
  }
 
2602
}
 
2603
 
 
2604
#endif