2014-10-01 23:28:34 +02:00
|
|
|
#include "xtra.h"
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
// #include <X11/X.h>
|
|
|
|
// #include <X11/Xutil.h>
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
static Display *the_d = NULL;
|
|
|
|
static Window self_window; /* We will assume that during initialization
|
|
|
|
* we have this window focused */
|
|
|
|
|
|
|
|
Atom XdndAware,
|
|
|
|
XdndEnter,
|
|
|
|
XdndLeave,
|
|
|
|
XdndPosition,
|
|
|
|
XdndStatus,
|
|
|
|
XdndDrop,
|
|
|
|
XdndSelection,
|
|
|
|
XdndDATA,
|
2014-10-03 16:59:32 +02:00
|
|
|
XdndActionCopy,
|
|
|
|
XdndActionAsk,
|
|
|
|
XdndTypeList;
|
|
|
|
|
2014-10-01 23:28:34 +02:00
|
|
|
|
|
|
|
void *event_loop(void* p)
|
|
|
|
{
|
|
|
|
(void) p;
|
|
|
|
|
|
|
|
XEvent event;
|
|
|
|
while (the_d)
|
|
|
|
{
|
|
|
|
XNextEvent(the_d, &event);
|
|
|
|
|
|
|
|
switch (event.type)
|
|
|
|
{
|
|
|
|
case ClientMessage:
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
if(event.xclient.message_type == XdndEnter) {
|
|
|
|
} else if(event.xclient.message_type == XdndPosition) {
|
|
|
|
Window src = event.xclient.data.l[0];
|
|
|
|
XEvent event = {
|
|
|
|
.xclient = {
|
|
|
|
.type = ClientMessage,
|
|
|
|
.display = the_d,
|
|
|
|
.window = src,
|
|
|
|
.message_type = XdndStatus,
|
|
|
|
.format = 32,
|
|
|
|
.data = {
|
|
|
|
.l = {self_window, 1, 0, 0, XdndActionCopy}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
XSendEvent(the_d, src, 0, 0, &event);
|
|
|
|
} else if(event.xclient.message_type == XdndStatus) {
|
|
|
|
} else if(event.xclient.message_type == XdndDrop) {
|
|
|
|
XConvertSelection(the_d, XdndSelection, XA_STRING, XdndDATA, self_window, CurrentTime);
|
|
|
|
} else if(event.xclient.message_type == XdndLeave) {
|
|
|
|
} else {
|
2014-10-03 16:59:32 +02:00
|
|
|
goto exit;
|
2014-10-01 23:28:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
2014-10-03 16:59:32 +02:00
|
|
|
// XSendEvent(the_d, self_window, 0, 0, &event);
|
2014-10-01 23:28:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
/* Actual XTRA termination
|
|
|
|
* Please call xtra_terminate() at exit
|
|
|
|
* otherwise bad stuff happens
|
|
|
|
*/
|
|
|
|
if (the_d) XCloseDisplay(the_d);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void xtra_init()
|
|
|
|
{
|
|
|
|
the_d = XOpenDisplay(NULL);
|
|
|
|
self_window = xtra_focused_window_id();
|
|
|
|
|
2014-10-03 16:59:32 +02:00
|
|
|
Window m_wndProxy;
|
|
|
|
|
|
|
|
{
|
|
|
|
/* Create an invisible window which will act as proxy for the DnD
|
|
|
|
* operation. This window will be used for both the GH and HG
|
|
|
|
* direction.
|
|
|
|
*/
|
|
|
|
XSetWindowAttributes attr = {0};
|
|
|
|
attr.event_mask = EnterWindowMask |
|
|
|
|
LeaveWindowMask |
|
|
|
|
ButtonMotionMask |
|
|
|
|
ButtonPressMask |
|
|
|
|
ButtonReleaseMask |
|
|
|
|
ResizeRedirectMask;
|
|
|
|
|
|
|
|
attr.do_not_propagate_mask = NoEventMask;
|
|
|
|
|
|
|
|
Window root;
|
|
|
|
int x, y;
|
|
|
|
unsigned int wht, hht, b, d;
|
|
|
|
|
|
|
|
/* Since we cannot capture resize events for parent window we will have to create
|
|
|
|
* this window to have maximum size as defined in root window
|
|
|
|
*/
|
|
|
|
XGetGeometry(the_d, XDefaultRootWindow(the_d), &root, &x, &y, &wht, &hht, &b, &d);
|
|
|
|
|
|
|
|
m_wndProxy = XCreateWindow(the_d, self_window /* Parent */,
|
|
|
|
0, 0, /* Position */
|
|
|
|
wht, hht, /* Width + height */
|
|
|
|
0, /* Border width */
|
|
|
|
CopyFromParent, /* Depth */
|
|
|
|
InputOnly, /* Class */
|
|
|
|
CopyFromParent, /* Visual */
|
|
|
|
CWDontPropagate | CWEventMask | CWCursor, /* Value mask */
|
|
|
|
&attr /* Attributes for value mask */);
|
|
|
|
if (!m_wndProxy)
|
|
|
|
{
|
|
|
|
//TODO return status
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XMapWindow(the_d, m_wndProxy);
|
|
|
|
XLowerWindow(the_d, m_wndProxy); /* Don't interfere with parent lmao */
|
|
|
|
|
|
|
|
self_window = m_wndProxy;
|
|
|
|
|
2014-10-01 23:28:34 +02:00
|
|
|
XdndAware = XInternAtom(the_d, "XdndAware", False);
|
|
|
|
XdndEnter = XInternAtom(the_d, "XdndEnter", False);
|
|
|
|
XdndLeave = XInternAtom(the_d, "XdndLeave", False);
|
|
|
|
XdndPosition = XInternAtom(the_d, "XdndPosition", False);
|
|
|
|
XdndStatus = XInternAtom(the_d, "XdndStatus", False);
|
|
|
|
XdndDrop = XInternAtom(the_d, "XdndDrop", False);
|
|
|
|
XdndSelection = XInternAtom(the_d, "XdndSelection", False);
|
|
|
|
XdndDATA = XInternAtom(the_d, "XdndDATA", False);
|
|
|
|
XdndActionCopy = XInternAtom(the_d, "XdndActionCopy", False);
|
2014-10-03 16:59:32 +02:00
|
|
|
XdndActionAsk = XInternAtom(the_d, "XdndActionAsk", False);
|
|
|
|
XdndTypeList = XInternAtom(the_d, "XdndTypeList", False);
|
2014-10-01 23:28:34 +02:00
|
|
|
|
|
|
|
Atom Xdndversion = 3;
|
2014-10-03 16:59:32 +02:00
|
|
|
XChangeProperty(the_d, m_wndProxy, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&Xdndversion, 1);
|
|
|
|
|
2014-10-01 23:28:34 +02:00
|
|
|
pthread_t id;
|
|
|
|
pthread_create(&id, NULL, event_loop, NULL);
|
|
|
|
pthread_detach(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void xtra_terminate()
|
|
|
|
{
|
|
|
|
XEvent terminate_event;
|
|
|
|
terminate_event.xclient.display = the_d;
|
|
|
|
terminate_event.type = ClientMessage;
|
|
|
|
|
|
|
|
|
|
|
|
XDeleteProperty(the_d, self_window, XdndAware);
|
|
|
|
XSendEvent(the_d, self_window, 0, NoEventMask, &terminate_event);
|
|
|
|
}
|
|
|
|
|
|
|
|
long unsigned int xtra_focused_window_id()
|
|
|
|
{
|
|
|
|
if (!the_d) return 0;
|
|
|
|
|
|
|
|
Window focus;
|
|
|
|
int revert;
|
|
|
|
XGetInputFocus(the_d, &focus, &revert);
|
|
|
|
return focus;
|
|
|
|
}
|
|
|
|
|
|
|
|
int xtra_is_this_focused()
|
|
|
|
{
|
|
|
|
return self_window == xtra_focused_window_id();
|
|
|
|
}
|