You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kplayer/kplayer/x11.cpp

426 lines
15 KiB

/***************************************************************************
x11.cpp
-------
begin : Wed Feb 26 2003
copyright : (C) 2003-2007 by kiriuja
email : http://kplayer.sourceforge.net/email.html
***************************************************************************/
/***************************************************************************
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <kdebug.h>
#include <X11/Xlib.h>
#ifdef DEBUG
kdbgstream kdDebugTime (void);
#define DEBUG_KPLAYER_GRAB
//#define DEBUG_KPLAYER_PROPERTY
//#define DEBUG_KPLAYER_X11
//#define DEBUG_KPLAYER_FOCUS
//#define DEBUG_KPLAYER_KEY
//#define DEBUG_KPLAYER_RESIZE
//#define DEBUG_KPLAYER_CLIENT
#endif
#ifdef DEBUG_KPLAYER_CLIENT
extern Atom qt_xdnd_position;
extern Atom qt_xdnd_status;
#endif
/*bool KPlayerX11TestGrab (Display* display, int winid)
{
if ( int status = XGrabPointer (display, winid, False,
(uint)(ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask),
GrabModeAsync, GrabModeAsync, None, None, CurrentTime) )
{
const char *s =
status == GrabNotViewable ? "GrabNotViewable" :
status == AlreadyGrabbed ? "AlreadyGrabbed" :
status == GrabFrozen ? "GrabFrozen" :
status == GrabInvalidTime ? "GrabInvalidTime" : "Unknown";
#ifdef DEBUG_KPLAYER_GRAB
kdDebugTime() << "Grab failed, status: " << s << "\n";
#endif
return false;
}
#define DEBUG_KPLAYER_GRAB
kdDebugTime() << "Grab succeeded\n";
#endif
XUngrabPointer (display, CurrentTime);
return true;
}*/
extern void KPlayerSetControlShiftState (bool control, bool shift);
extern void KPlayerWidgetResizeHandler (bool);
extern void KPlayerWidgetMapHandler (uint);
extern void KPlayerWidgetUnmapHandler (uint);
extern void KPlayerWindowStateChanged (uint);
typedef int (*QX11EventFilter) (XEvent*);
static QX11EventFilter PreviousX11EventFilter = 0;
#ifdef DEBUG_KPLAYER_RESIZE
const char* KPlayerX11EventTypeNames [LASTEvent] = {
"EVENT0",
"EVENT1",
"KeyPress",
"KeyRelease",
"ButtonPress",
"ButtonRelease",
"MotionNotify",
"EnterNotify",
"LeaveNotify",
"FocusIn",
"FocusOut",
"KeymapNotify",
"Expose",
"GraphicsExpose",
"NoExpose",
"VisibilityNotify",
"CreateNotify",
"DestroyNotify",
"UnmapNotify",
"MapNotify",
"MapRequest",
"ReparentNotify",
"ConfigureNotify",
"ConfigureRequest",
"GravityNotify",
"ResizeRequest",
"CirculateNotify",
"CirculateRequest",
"PropertyNotify",
"SelectionClear",
"SelectionRequest",
"SelectionNotify",
"ColormapNotify",
"ClientMessage",
"MappingNotify"
};
#endif
#ifdef DEBUG_KPLAYER_RESIZE
const char* KPlayerX11EventModeNames [4] = {
"NotifyNormal",
"NotifyGrab",
"NotifyUngrab",
"NotifyWhileGrabbed"
};
const char* KPlayerX11EventDetailNames [8] = {
"NotifyAncestor",
"NotifyVirtual",
"NotifyInferior",
"NotifyNonlinear",
"NotifyNonlinearVirtual",
"NotifyPointer",
"NotifyPointerRoot",
"NotifyDetailNone"
};
#endif
int KPlayerX11EventFilter (XEvent* event)
{
#ifdef DEBUG_KPLAYER_X11
XAnyEvent* anyev = (XAnyEvent*) event;
kdDebugTime() << "X11 event " << KPlayerX11EventTypeNames [event -> type] << " " << anyev -> window
<< " " << anyev -> send_event << " " << anyev -> serial << "\n";
#endif
if ( event -> type == FocusIn || event -> type == FocusOut )
{
XFocusChangeEvent* ev = (XFocusChangeEvent*) event;
#ifdef DEBUG_KPLAYER_FOCUS
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> window << " "
<< ev -> send_event << " " << ev -> serial << " mode " << KPlayerX11EventModeNames [ev -> mode]
<< " detail " << KPlayerX11EventDetailNames [ev -> detail] << "\n";
#endif
if ( event -> type == FocusIn && ev -> mode == NotifyUngrab
|| event -> type == FocusOut && ev -> mode == NotifyGrab && ev -> detail == NotifyAncestor )
{
#ifdef DEBUG_KPLAYER_GRAB
kdDebugTime() << "Calling KPlayerWidgetResizeHandler (" << (ev -> mode == NotifyGrab) << ")\n";
#endif
KPlayerWidgetResizeHandler (ev -> mode == NotifyGrab);
}
}
else if ( event -> type == KeyPress || event -> type == KeyRelease )
{
XKeyEvent* ev = (XKeyEvent*) event;
#ifdef DEBUG_KPLAYER_KEY
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> window << " "
<< ev -> send_event << " " << ev -> serial << " root " << ev -> root << " subwindow "
<< ev -> subwindow << " " << ev -> x << "x" << ev -> y << " " << ev -> x_root << "x" << ev -> y_root
<< " keycode " << ev -> keycode << " state " << ev -> state << " same " << ev -> same_screen << "\n";
#endif
KPlayerSetControlShiftState ((ev -> state & ControlMask) == ControlMask, (ev -> state & ShiftMask) == ShiftMask);
if ( (ev -> state & ShiftMask) == ShiftMask && (ev -> state & (ControlMask | Mod1Mask)) != 0
&& ev -> keycode != 100 && ev -> keycode != 102
&& ((ev -> state & Mod1Mask) != Mod1Mask || ev -> keycode != 98 && ev -> keycode != 104) )
ev -> state &= ~ ShiftMask;
}
#ifdef DEBUG_KPLAYER_CLIENT
else if ( event -> type == ClientMessage && (event -> xclient.message_type == qt_xdnd_position
|| event -> xclient.message_type == qt_xdnd_status) )
{
XClientMessageEvent* ev = (XClientMessageEvent*) event;
kdDebugTime() << "X11 ClientMessage " << ev -> message_type << " " << ev -> window << " "
<< ev -> send_event << " " << ev -> serial << " format " << ev -> format << " window " << ev -> data.l[0]
<< " flags " << ev -> data.l[1] << " position " << ((ev -> data.l[2] & 0xffff0000) >> 16)
<< "x" << (ev -> data.l[2] & 0x0000ffff) << " size " << ((ev -> data.l[3] & 0xffff0000) >> 16)
<< "x" << (ev -> data.l[3] & 0x0000ffff) << " action " << ev -> data.l[4] << "\n";
}
#endif
#ifdef DEBUG_KPLAYER_RESIZE
else if ( event -> type == ConfigureNotify )
{
XConfigureEvent* ev = (XConfigureEvent*) event;
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> event
<< " " << ev -> window << " " << ev -> send_event << " " << ev -> serial
<< " " << ev -> x << "x" << ev -> y << " " << ev -> width << "x" << ev -> height
<< " border " << ev -> border_width << " above " << ev -> above << " override " << ev -> override_redirect << "\n";
}
else if ( event -> type == ConfigureRequest )
{
XConfigureRequestEvent* ev = (XConfigureRequestEvent*) event;
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> parent
<< " " << ev -> window << " " << ev -> send_event << " " << ev -> serial
<< " " << ev -> x << "x" << ev -> y << " " << ev -> width << "x" << ev -> height
<< " border " << ev -> border_width << " above " << ev -> above
<< " detail " << ev -> detail << " mask " << ev -> value_mask << "\n";
}
else if ( event -> type == ResizeRequest )
{
XResizeRequestEvent* ev = (XResizeRequestEvent*) event;
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type]
<< " " << ev -> window << " " << ev -> send_event << " " << ev -> serial
<< " " << ev -> width << "x" << ev -> height << "\n";
}
else if ( event -> type == ReparentNotify )
{
XReparentEvent* ev = (XReparentEvent*) event;
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> event
<< " " << ev -> window << " " << ev -> parent << " " << ev -> send_event << " " << ev -> serial
<< " " << ev -> x << "x" << ev -> y << " override " << ev -> override_redirect << "\n";
}
else if ( event -> type == MapNotify )
{
XMapEvent* ev = (XMapEvent*) event;
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> event << " " << ev -> window
<< " " << ev -> send_event << " " << ev -> serial << " override " << ev -> override_redirect << "\n";
}
#endif
else if ( event -> type == MapRequest )
{
XMapRequestEvent* ev = (XMapRequestEvent*) event;
#ifdef DEBUG_KPLAYER_RESIZE
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> parent
<< " " << ev -> window << " " << ev -> send_event << " " << ev -> serial << "\n";
#endif
KPlayerWidgetMapHandler (ev -> window);
}
else if ( event -> type == UnmapNotify )
{
XUnmapEvent* ev = (XUnmapEvent*) event;
#ifdef DEBUG_KPLAYER_RESIZE
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> event << " " << ev -> window
<< " " << ev -> send_event << " " << ev -> serial << " from configure " << ev -> from_configure << "\n";
#endif
KPlayerWidgetUnmapHandler (ev -> window);
}
else if ( event -> type == PropertyNotify )
{
XPropertyEvent* ev = (XPropertyEvent*) event;
#ifdef DEBUG_KPLAYER_PROPERTY
kdDebugTime() << "X11 " << KPlayerX11EventTypeNames [event -> type] << " " << ev -> send_event
<< " " << ev -> window << " " << ev -> atom << " " << ev -> time << " " << ev -> state << "\n";
#endif
char* propname = XGetAtomName (ev -> display, ev -> atom);
if ( propname )
{
if ( strcmp (propname, "_NET_WM_STATE") == 0 )
KPlayerWindowStateChanged (ev -> window);
#ifdef DEBUG_KPLAYER_PROPERTY
kdDebugTime() << "X11 property name " << propname << "\n";
#endif
}
#ifdef DEBUG_KPLAYER_PROPERTY
if ( ev -> state == PropertyNewValue )
{
Atom type;
int format;
unsigned long items, bytes;
unsigned char* data;
if ( XGetWindowProperty (ev -> display, ev -> window, ev -> atom, 0, 32, false, AnyPropertyType,
&type, &format, &items, &bytes, &data) == Success && type != None )
{
kdDebugTime() << "X11 property type " << type << " format " << format
<< " items " << items << " bytes " << bytes << "\n";
if ( data )
{
if ( format == 8 )
kdDebugTime() << "X11 property value " << data << "\n";
else if ( format == 16 )
{
short* sdata = (short*) data;
for ( unsigned long i = 0; i < items; ++ i )
kdDebugTime() << "X11 property value " << sdata[i] << "\n";
}
else if ( format == 32 )
if ( strcmp (propname, "_NET_SUPPORTED") == 0
|| strcmp (propname, "_NET_WM_WINDOW_TYPE") == 0
|| strcmp (propname, "_NET_WM_STATE") == 0
|| strcmp (propname, "_NET_WM_ALLOWED_ACTIONS") == 0 )
{
Atom* adata = (Atom*) data;
for ( unsigned long i = 0; i < items; ++ i )
{
char* atomname = XGetAtomName (ev -> display, adata[i]);
if ( atomname )
{
kdDebugTime() << "X11 property name " << atomname << "\n";
XFree (atomname);
}
else
kdDebugTime() << "X11 property value " << adata[i] << "\n";
}
}
else
{
long* ldata = (long*) data;
for ( unsigned long i = 0; i < items; ++ i )
kdDebugTime() << "X11 property value " << ldata[i] << "\n";
}
XFree (data);
}
}
}
#endif
if ( propname )
XFree (propname);
}
if ( PreviousX11EventFilter )
return PreviousX11EventFilter (event);
return 0;
}
Display* tqt_xdisplay (void);
extern Time tqt_x_time;
void KPlayerX11SetInputFocus (uint id)
{
XSetInputFocus (tqt_xdisplay(), id, RevertToNone, tqt_x_time);
XFlush (tqt_xdisplay());
}
void KPlayerX11MapWindow (uint id)
{
XMapWindow (tqt_xdisplay(), id);
XFlush (tqt_xdisplay());
}
void KPlayerX11UnmapWindow (uint id)
{
XUnmapWindow (tqt_xdisplay(), id);
XFlush (tqt_xdisplay());
}
void KPlayerX11ClearExposeWindow (uint id)
{
XClearArea (tqt_xdisplay(), id, 0, 0, 0, 0, True);
XFlush (tqt_xdisplay());
}
void KPlayerX11SendConfigureEvent (uint id, int w, int h)
{
#ifdef DEBUG_KPLAYER_RESIZE
kdDebugTime() << "KPlayerX11SendConfigureEvent " << id << " " << w << "x" << h << "\n";
#endif
XConfigureEvent event = { ConfigureNotify, 0, True, tqt_xdisplay(), id, id, 0, 0, w, h, 0, None, False };
XSendEvent (tqt_xdisplay(), event.event, True, StructureNotifyMask, (XEvent*) &event);
XFlush (tqt_xdisplay());
}
void KPlayerX11SendConfigureEvent (uint id, int x, int y, int w, int h)
{
#ifdef DEBUG_KPLAYER_RESIZE
kdDebugTime() << "KPlayerX11SendConfigureEvent " << id << " " << x << "x" << y << " " << w << "x" << h << "\n";
#endif
XConfigureEvent event = { ConfigureNotify, 0, True, tqt_xdisplay(), id, id, x, y, w, h, 0, None, False };
XSendEvent (tqt_xdisplay(), event.event, True, StructureNotifyMask, (XEvent*) &event);
XFlush (tqt_xdisplay());
}
void KPlayerX11DiscardConfigureEvents (uint id)
{
XEvent event;
while ( XCheckTypedWindowEvent (tqt_xdisplay(), id, ConfigureNotify, &event) )
#ifdef DEBUG_KPLAYER_RESIZE
kdDebugTime() << "Discarded ConfigureEvent " << event.xconfigure.event << " " << event.xconfigure.window
<< " " << event.xconfigure.send_event << " " << event.xconfigure.serial
<< " " << event.xconfigure.x << "x" << event.xconfigure.y
<< " " << event.xconfigure.width << "x" << event.xconfigure.height
<< " border " << event.xconfigure.border_width << " above " << event.xconfigure.above
<< " override " << event.xconfigure.override_redirect << "\n"
#endif
;
}
void KPlayerX11GetKeyboardMouseState (uint id)
{
#ifdef DEBUG_KPLAYER_KEY
kdDebugTime() << "KPlayerX11GetKeyboardMouseState " << id << "\n";
#endif
Window root, child;
int root_x, root_y, win_x, win_y;
uint state;
if ( XQueryPointer (tqt_xdisplay(), id, &root, &child, &root_x, &root_y, &win_x, &win_y, &state) )
{
#ifdef DEBUG_KPLAYER_KEY
kdDebugTime() << " root " << root << " " << root_x << "x" << root_y << " child " << child
<< " " << win_x << "x" << win_y << " state " << state << "\n";
#endif
KPlayerSetControlShiftState ((state & ControlMask) == ControlMask, (state & ShiftMask) == ShiftMask);
}
}
extern QX11EventFilter tqt_set_x11_event_filter (QX11EventFilter);
static int KPlayerX11EventFilterCount = 0;
void KPlayerSetX11EventFilter (void)
{
if ( ! KPlayerX11EventFilterCount ++ )
PreviousX11EventFilter = tqt_set_x11_event_filter (KPlayerX11EventFilter);
}
void KPlayerResetX11EventFilter (void)
{
if ( -- KPlayerX11EventFilterCount )
return;
tqt_set_x11_event_filter (PreviousX11EventFilter);
PreviousX11EventFilter = 0;
}
// fixed for enable-final
#undef Above
#undef Always
#undef Below
#undef Bool
#undef CursorShape
#undef FocusIn
#undef FocusOut
#undef KeyPress
#undef KeyRelease
#undef None
#undef Unsorted