mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-23 01:33:02 +01:00
Finished drag and drop support
This commit is contained in:
commit
75dd26518f
@ -1,16 +1,18 @@
|
|||||||
# Variables for X11 support
|
# Variables for X11 support
|
||||||
X11_LIBS = x11
|
X11_LIBS = x11
|
||||||
X11_CFLAGS = -DX11
|
X11_CFLAGS = -DX11
|
||||||
|
X11_OBJ = xtra.o
|
||||||
|
|
||||||
# Check if we can build X11 support
|
# Check if we can build X11 support
|
||||||
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
|
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_X11_LIBS), error)
|
ifneq ($(CHECK_X11_LIBS), error)
|
||||||
LIBS += $(X11_LIBS)
|
LIBS += $(X11_LIBS)
|
||||||
CFLAGS += $(X11_CFLAGS)
|
CFLAGS += $(X11_CFLAGS)
|
||||||
|
OBJ += $(X11_OBJ)
|
||||||
else
|
else
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking))
|
$(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking and drag&drop support))
|
||||||
$(warning WARNING -- You need these libraries for x11 support)
|
$(warning WARNING -- You need these libraries for x11 support)
|
||||||
$(warning WARNING -- $(MISSING_X11_LIBS))
|
$(warning WARNING -- $(MISSING_X11_LIBS))
|
||||||
endif
|
endif
|
||||||
|
28
src/notify.c
28
src/notify.c
@ -35,6 +35,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "xtra.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -53,10 +54,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef X11
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
#include <libnotify/notify.h>
|
#include <libnotify/notify.h>
|
||||||
#endif
|
#endif
|
||||||
@ -70,10 +67,6 @@ extern struct user_settings *user_settings;
|
|||||||
struct Control {
|
struct Control {
|
||||||
time_t cooldown;
|
time_t cooldown;
|
||||||
time_t notif_timeout;
|
time_t notif_timeout;
|
||||||
#ifdef X11
|
|
||||||
Display *display;
|
|
||||||
unsigned long this_window;
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
pthread_mutex_t poll_mutex[1];
|
pthread_mutex_t poll_mutex[1];
|
||||||
@ -122,23 +115,11 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
|
|||||||
self->alert = WINDOW_ALERT_2;
|
self->alert = WINDOW_ALERT_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef X11
|
|
||||||
long unsigned int get_focused_window_id()
|
|
||||||
{
|
|
||||||
if (!Control.display) return 0;
|
|
||||||
|
|
||||||
Window focus;
|
|
||||||
int revert;
|
|
||||||
XGetInputFocus(Control.display, &focus, &revert);
|
|
||||||
return focus;
|
|
||||||
}
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
static bool notifications_are_disabled(uint64_t flags)
|
static bool notifications_are_disabled(uint64_t flags)
|
||||||
{
|
{
|
||||||
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
return res || (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id());
|
return res || (flags & NT_NOFOCUS && is_focused());
|
||||||
#else
|
#else
|
||||||
return res;
|
return res;
|
||||||
#endif
|
#endif
|
||||||
@ -389,12 +370,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
|
|
||||||
Control.poll_active = 1;
|
Control.poll_active = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Control.cooldown = get_unix_time() + login_cooldown;
|
Control.cooldown = get_unix_time() + login_cooldown;
|
||||||
#ifdef X11
|
|
||||||
Control.display = XOpenDisplay(NULL);
|
|
||||||
Control.this_window = get_focused_window_id();
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
29
src/toxic.c
29
src/toxic.c
@ -58,18 +58,19 @@
|
|||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
#include "xtra.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
|
ToxAv *av;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
#ifndef PACKAGE_DATADIR
|
||||||
#define PACKAGE_DATADIR "."
|
#define PACKAGE_DATADIR "."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
ToxAv *av;
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
/* Export for use in Callbacks */
|
/* Export for use in Callbacks */
|
||||||
char *DATA_FILE = NULL;
|
char *DATA_FILE = NULL;
|
||||||
char *BLOCK_FILE = NULL;
|
char *BLOCK_FILE = NULL;
|
||||||
@ -134,6 +135,14 @@ void exit_toxic_success(Tox *m)
|
|||||||
|
|
||||||
tox_kill(m);
|
tox_kill(m);
|
||||||
endwin();
|
endwin();
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
/* We have to terminate xtra last coz reasons
|
||||||
|
* Please don't call this anywhere else coz trust me
|
||||||
|
*/
|
||||||
|
terminate_xtra();
|
||||||
|
#endif /* X11 */
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -969,6 +978,14 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
|
|||||||
return new_sleep;
|
return new_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
void cb(const char* asdv, DropType dt)
|
||||||
|
{
|
||||||
|
if (dt != DT_plain)
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
|
||||||
|
}
|
||||||
|
#endif /* X11 */
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
@ -1005,6 +1022,10 @@ int main(int argc, char *argv[])
|
|||||||
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||||
int settings_err = settings_load(user_settings, p);
|
int settings_err = settings_load(user_settings, p);
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
init_xtra(cb);
|
||||||
|
#endif
|
||||||
|
|
||||||
Tox *m = init_tox();
|
Tox *m = init_tox();
|
||||||
|
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
|
355
src/xtra.c
Normal file
355
src/xtra.c
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
#include "xtra.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
const Atom XtraTerminate = 1;
|
||||||
|
const Atom XtraNil = 0;
|
||||||
|
|
||||||
|
static Atom XdndAware;
|
||||||
|
static Atom XdndEnter;
|
||||||
|
static Atom XdndLeave;
|
||||||
|
static Atom XdndPosition;
|
||||||
|
static Atom XdndStatus;
|
||||||
|
static Atom XdndDrop;
|
||||||
|
static Atom XdndSelection;
|
||||||
|
static Atom XdndDATA;
|
||||||
|
static Atom XdndTypeList;
|
||||||
|
static Atom XdndActionCopy;
|
||||||
|
static Atom XdndFinished;
|
||||||
|
|
||||||
|
struct _Xtra {
|
||||||
|
drop_callback on_drop;
|
||||||
|
Display *display;
|
||||||
|
Window terminal_window;
|
||||||
|
Window proxy_window;
|
||||||
|
Window source_window; /* When we have a drop */
|
||||||
|
Atom handling_version;
|
||||||
|
Atom expecting_type;
|
||||||
|
} Xtra;
|
||||||
|
|
||||||
|
typedef struct _Property
|
||||||
|
{
|
||||||
|
unsigned char *data;
|
||||||
|
int read_format;
|
||||||
|
unsigned long read_num;
|
||||||
|
Atom read_type;
|
||||||
|
} Property;
|
||||||
|
|
||||||
|
Property read_property(Window s, Atom p)
|
||||||
|
{
|
||||||
|
Atom read_type;
|
||||||
|
int read_format;
|
||||||
|
unsigned long read_num;
|
||||||
|
unsigned long left_bytes;
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
|
||||||
|
int read_bytes = 1024;
|
||||||
|
|
||||||
|
/* Keep trying to read the property until there are no bytes unread */
|
||||||
|
do {
|
||||||
|
if (data) XFree(data);
|
||||||
|
|
||||||
|
XGetWindowProperty(Xtra.display, s,
|
||||||
|
p, 0,
|
||||||
|
read_bytes,
|
||||||
|
False, AnyPropertyType,
|
||||||
|
&read_type, &read_format,
|
||||||
|
&read_num, &left_bytes,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
read_bytes *= 2;
|
||||||
|
} while (left_bytes != 0);
|
||||||
|
|
||||||
|
Property property = {data, read_format, read_num, read_type};
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom get_dnd_type(long *a, int l)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (; i < l; i ++) {
|
||||||
|
if (a[i] != XtraNil) return a[i]; /* Get first valid */
|
||||||
|
}
|
||||||
|
return XtraNil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO maybe support only certain types in the future */
|
||||||
|
static void handle_xdnd_enter(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
Xtra.handling_version = (e->data.l[1] >> 24);
|
||||||
|
|
||||||
|
if ((e->data.l[1] & 1)) {
|
||||||
|
// Fetch the list of possible conversions
|
||||||
|
Property p = read_property(e->data.l[0], XdndTypeList);
|
||||||
|
Xtra.expecting_type = get_dnd_type((long*)p.data, p.read_num);
|
||||||
|
XFree(p.data);
|
||||||
|
} else {
|
||||||
|
// Use the available list
|
||||||
|
Xtra.expecting_type = get_dnd_type(e->data.l + 2, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_position(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = e->display,
|
||||||
|
.window = e->data.l[0],
|
||||||
|
.message_type = XdndStatus,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {
|
||||||
|
Xtra.proxy_window,
|
||||||
|
(Xtra.expecting_type != XtraNil),
|
||||||
|
0, 0,
|
||||||
|
XdndActionCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
|
XFlush(Xtra.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_drop(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
/* Not expecting any type */
|
||||||
|
if (Xtra.expecting_type == XtraNil) {
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = e->display,
|
||||||
|
.window = e->data.l[0],
|
||||||
|
.message_type = XdndFinished,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {Xtra.proxy_window, 0, 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
|
} else {
|
||||||
|
Xtra.source_window = e->data.l[0];
|
||||||
|
XConvertSelection(Xtra.display,
|
||||||
|
XdndSelection,
|
||||||
|
Xtra.expecting_type,
|
||||||
|
XdndSelection,
|
||||||
|
Xtra.proxy_window,
|
||||||
|
Xtra.handling_version >= 1 ? e->data.l[2] : CurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_selection(XSelectionEvent* e)
|
||||||
|
{
|
||||||
|
/* DnD succesfully finished, send finished and call callback */
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = Xtra.display,
|
||||||
|
.window = Xtra.source_window,
|
||||||
|
.message_type = XdndFinished,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {Xtra.proxy_window, 1, XdndActionCopy}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
|
||||||
|
|
||||||
|
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
||||||
|
DropType dt;
|
||||||
|
|
||||||
|
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
|
||||||
|
dt = DT_file_list;
|
||||||
|
else /* text/uri-list */
|
||||||
|
dt = DT_plain;
|
||||||
|
|
||||||
|
|
||||||
|
/* Call callback for every entry */
|
||||||
|
if (Xtra.on_drop && p.read_num)
|
||||||
|
{
|
||||||
|
char *sptr;
|
||||||
|
char *str = strtok_r((char*)p.data, "\n\r", &sptr);
|
||||||
|
|
||||||
|
if (str) Xtra.on_drop(str, dt);
|
||||||
|
while ((str = strtok_r(NULL, "\n\r", &sptr)))
|
||||||
|
Xtra.on_drop(str, dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.data) XFree(p.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *event_loop(void* p)
|
||||||
|
{
|
||||||
|
/* Handle events like a real nigga */
|
||||||
|
|
||||||
|
(void) p; /* DINDUNOTHIN */
|
||||||
|
|
||||||
|
XEvent event;
|
||||||
|
int pending;
|
||||||
|
|
||||||
|
while (Xtra.display)
|
||||||
|
{
|
||||||
|
/* NEEDMOEVENTSFODEMPROGRAMS */
|
||||||
|
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
||||||
|
|
||||||
|
if (!pending)
|
||||||
|
{
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
usleep(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == ClientMessage)
|
||||||
|
{
|
||||||
|
Atom type = event.xclient.message_type;
|
||||||
|
|
||||||
|
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
||||||
|
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
||||||
|
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
||||||
|
else if (type == XtraTerminate) break;
|
||||||
|
}
|
||||||
|
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
||||||
|
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
||||||
|
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
||||||
|
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actual XTRA termination
|
||||||
|
* Please call xtra_terminate() at exit
|
||||||
|
* otherwise HEWUSAGUDBOI happens
|
||||||
|
*/
|
||||||
|
if (Xtra.display) XCloseDisplay(Xtra.display);
|
||||||
|
return (Xtra.display = NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_xtra(drop_callback d)
|
||||||
|
{
|
||||||
|
memset(&Xtra, 0, sizeof(Xtra));
|
||||||
|
|
||||||
|
if (!d) return -1;
|
||||||
|
else Xtra.on_drop = d;
|
||||||
|
|
||||||
|
XInitThreads();
|
||||||
|
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
||||||
|
|
||||||
|
Xtra.terminal_window = focused_window_id();
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
|
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(Xtra.display,
|
||||||
|
XDefaultRootWindow(Xtra.display),
|
||||||
|
&root, &x, &y, &wht, &hht, &b, &d);
|
||||||
|
|
||||||
|
if (! (Xtra.proxy_window = XCreateWindow
|
||||||
|
(Xtra.display, Xtra.terminal_window, /* Parent */
|
||||||
|
0, 0, /* Position */
|
||||||
|
wht, hht, /* Width + height */
|
||||||
|
0, /* Border width */
|
||||||
|
CopyFromParent, /* Depth */
|
||||||
|
InputOnly, /* Class */
|
||||||
|
CopyFromParent, /* Visual */
|
||||||
|
CWEventMask | CWCursor, /* Value mask */
|
||||||
|
&attr)) ) /* Attributes for value mask */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
||||||
|
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
||||||
|
|
||||||
|
XdndAware = XInternAtom(Xtra.display, "XdndAware", False);
|
||||||
|
XdndEnter = XInternAtom(Xtra.display, "XdndEnter", False);
|
||||||
|
XdndLeave = XInternAtom(Xtra.display, "XdndLeave", False);
|
||||||
|
XdndPosition = XInternAtom(Xtra.display, "XdndPosition", False);
|
||||||
|
XdndStatus = XInternAtom(Xtra.display, "XdndStatus", False);
|
||||||
|
XdndDrop = XInternAtom(Xtra.display, "XdndDrop", False);
|
||||||
|
XdndSelection = XInternAtom(Xtra.display, "XdndSelection", False);
|
||||||
|
XdndDATA = XInternAtom(Xtra.display, "XdndDATA", False);
|
||||||
|
XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
|
||||||
|
XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
|
||||||
|
XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
|
||||||
|
|
||||||
|
/* Inform my nigga windows that we are aware of dnd */
|
||||||
|
Atom XdndVersion = 3;
|
||||||
|
XChangeProperty(Xtra.display,
|
||||||
|
Xtra.proxy_window,
|
||||||
|
XdndAware,
|
||||||
|
XA_ATOM,
|
||||||
|
32,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*)&XdndVersion, 1);
|
||||||
|
|
||||||
|
pthread_t id;
|
||||||
|
pthread_create(&id, NULL, event_loop, NULL);
|
||||||
|
pthread_detach(id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminate_xtra()
|
||||||
|
{
|
||||||
|
if (!Xtra.display) return;
|
||||||
|
|
||||||
|
XEvent terminate = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = Xtra.display,
|
||||||
|
.message_type = XtraTerminate,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
|
||||||
|
XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
|
||||||
|
while (Xtra.display); /* Wait for termination */
|
||||||
|
}
|
||||||
|
|
||||||
|
long unsigned int focused_window_id()
|
||||||
|
{
|
||||||
|
if (!Xtra.display) return 0;
|
||||||
|
|
||||||
|
Window focus;
|
||||||
|
int revert;
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
XGetInputFocus(Xtra.display, &focus, &revert);
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_focused()
|
||||||
|
{
|
||||||
|
return Xtra.proxy_window == focused_window_id();
|
||||||
|
}
|
19
src/xtra.h
Normal file
19
src/xtra.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef XTRA_H
|
||||||
|
#define XTRA_H
|
||||||
|
|
||||||
|
/* NOTE: If no xlib present don't compile */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DT_plain,
|
||||||
|
DT_file_list
|
||||||
|
}
|
||||||
|
DropType;
|
||||||
|
|
||||||
|
typedef void (*drop_callback) (const char*, DropType);
|
||||||
|
|
||||||
|
int init_xtra(drop_callback d);
|
||||||
|
void terminate_xtra();
|
||||||
|
long unsigned int focused_window_id();
|
||||||
|
int is_focused(); /* returns bool */
|
||||||
|
|
||||||
|
#endif /* XTRA_H */
|
Loading…
Reference in New Issue
Block a user