289 lines
6.1 KiB
C
289 lines
6.1 KiB
C
#include "config.h"
|
|
|
|
#include <gdk/gdkx.h>
|
|
#include <X11/Xlib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "e16keyedit.h"
|
|
|
|
#define gdk_window_foreign_new(xwin) \
|
|
gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), xwin)
|
|
|
|
#if USE_GTK == 3
|
|
#define gdk_error_trap_push() \
|
|
gdk_x11_display_error_trap_push(gdk_display_get_default())
|
|
#define gdk_error_trap_pop() \
|
|
gdk_x11_display_error_trap_pop(gdk_display_get_default())
|
|
#endif
|
|
|
|
typedef struct {
|
|
Window win;
|
|
char *msg;
|
|
#if 0
|
|
char *name;
|
|
char *clientname;
|
|
char *version;
|
|
char *author;
|
|
char *email;
|
|
char *web;
|
|
char *address;
|
|
char *info;
|
|
#endif
|
|
} Client;
|
|
|
|
static Display *dpy = NULL;
|
|
static Window root_win = None;
|
|
static Window comms_win = None;
|
|
static Window my_msg_win = None;
|
|
static Client *e_client = NULL;
|
|
static void (*msg_receive_callback)(char *msg) = NULL;
|
|
static unsigned int Atom_ENL_MSG;
|
|
|
|
static int
|
|
CommsSetup(void)
|
|
{
|
|
char *str;
|
|
|
|
dpy = gdk_x11_get_default_xdisplay();
|
|
|
|
str = getenv("ENL_WM_ROOT");
|
|
root_win = (str) ? strtoul(str, NULL, 0) : DefaultRootWindow(dpy);
|
|
|
|
gdk_error_trap_push();
|
|
my_msg_win = XCreateSimpleWindow(dpy, root_win, -10, -10, 1, 1, 0, 0, 0);
|
|
XSync(dpy, False);
|
|
if (gdk_error_trap_pop())
|
|
return 1;
|
|
|
|
Atom_ENL_MSG = XInternAtom(dpy, "ENL_MSG", False);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Window
|
|
CommsFindCommsWindow(void)
|
|
{
|
|
unsigned char *s;
|
|
Atom Atom_ENL_COMMS, ar;
|
|
unsigned long num, after;
|
|
int format;
|
|
Window win = None;
|
|
Window rt;
|
|
int dint;
|
|
unsigned int duint;
|
|
|
|
Atom_ENL_COMMS = XInternAtom(dpy, "ENLIGHTENMENT_COMMS", True);
|
|
if (Atom_ENL_COMMS == None)
|
|
return None;
|
|
|
|
s = NULL;
|
|
XGetWindowProperty(dpy, root_win, Atom_ENL_COMMS, 0, 14, False,
|
|
AnyPropertyType, &ar, &format, &num, &after, &s);
|
|
if (s)
|
|
{
|
|
sscanf((char *)s, "%*s %x", (unsigned int *)&win);
|
|
XFree(s);
|
|
}
|
|
|
|
if (win == None)
|
|
return None;
|
|
|
|
if (!XGetGeometry(dpy, win, &rt,
|
|
&dint, &dint, &duint, &duint, &duint, &duint))
|
|
return None;
|
|
|
|
s = NULL;
|
|
XGetWindowProperty(dpy, win, Atom_ENL_COMMS, 0, 14, False,
|
|
AnyPropertyType, &ar, &format, &num, &after, &s);
|
|
if (!s)
|
|
return None;
|
|
|
|
XFree(s);
|
|
|
|
return win;
|
|
}
|
|
|
|
static Client *
|
|
ClientCreate(Window win)
|
|
{
|
|
Client *cl;
|
|
|
|
cl = calloc(1, sizeof(Client));
|
|
if (!cl)
|
|
return cl;
|
|
|
|
cl->win = win;
|
|
|
|
#if 0
|
|
char st[32];
|
|
snprintf(st, sizeof(st), "%8x", (int)win);
|
|
cl->name = strdup(st);
|
|
#endif
|
|
|
|
return cl;
|
|
}
|
|
|
|
static char *
|
|
CommsGet(XEvent *ev)
|
|
{
|
|
char buf[13], *msg;
|
|
unsigned int win;
|
|
Client *cl = e_client;
|
|
|
|
if (!cl)
|
|
return NULL;
|
|
|
|
if (!ev)
|
|
return NULL;
|
|
if (ev->type != ClientMessage)
|
|
return NULL;
|
|
if (ev->xclient.message_type != Atom_ENL_MSG)
|
|
return NULL;
|
|
|
|
/* Message should start with comms_win but we don't check */
|
|
memcpy(buf, ev->xclient.data.b, 8);
|
|
buf[8] = 0;
|
|
sscanf(buf, "%x", &win);
|
|
|
|
memcpy(buf, ev->xclient.data.b + 8, 12);
|
|
buf[12] = 0;
|
|
|
|
if (cl->msg)
|
|
{
|
|
/* append text to end of msg */
|
|
cl->msg = realloc(cl->msg, strlen(cl->msg) + strlen(buf) + 1);
|
|
if (!cl->msg)
|
|
return NULL;
|
|
strcat(cl->msg, buf);
|
|
}
|
|
else
|
|
{
|
|
/* new msg */
|
|
cl->msg = malloc(strlen(buf) + 1);
|
|
if (!cl->msg)
|
|
return NULL;
|
|
strcpy(cl->msg, buf);
|
|
}
|
|
|
|
msg = NULL;
|
|
if (strlen(buf) < 12)
|
|
{
|
|
msg = cl->msg;
|
|
cl->msg = NULL;
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
static GdkFilterReturn
|
|
FilterCommsWin(GdkXEvent *gdk_xevent, GdkEvent *event __UNUSED__,
|
|
void *data __UNUSED__)
|
|
{
|
|
XEvent *xevent = gdk_xevent;
|
|
|
|
switch (xevent->type)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
exit(1);
|
|
}
|
|
|
|
return GDK_FILTER_REMOVE;
|
|
}
|
|
|
|
static GdkFilterReturn
|
|
FilterMyMsgWin(GdkXEvent *gdk_xevent, GdkEvent *event __UNUSED__,
|
|
void *data __UNUSED__)
|
|
{
|
|
XEvent *xevent = gdk_xevent;
|
|
char *msg;
|
|
|
|
switch (xevent->type)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case ClientMessage:
|
|
if (xevent->xclient.message_type != Atom_ENL_MSG)
|
|
return GDK_FILTER_CONTINUE;
|
|
|
|
msg = CommsGet(xevent);
|
|
if (msg)
|
|
{
|
|
if (msg_receive_callback)
|
|
(*msg_receive_callback) (msg);
|
|
free(msg);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return GDK_FILTER_REMOVE;
|
|
}
|
|
|
|
int
|
|
CommsInit(void (*msg_receive_func)(char *msg))
|
|
{
|
|
GdkWindow *gdkwin;
|
|
|
|
if (CommsSetup())
|
|
return 1;
|
|
|
|
comms_win = CommsFindCommsWindow();
|
|
if (comms_win == None)
|
|
return 1;
|
|
|
|
e_client = ClientCreate(comms_win);
|
|
|
|
gdkwin = gdk_window_foreign_new(comms_win);
|
|
gdk_window_set_events(gdkwin, GDK_STRUCTURE_MASK);
|
|
gdk_window_add_filter(gdkwin, FilterCommsWin, NULL);
|
|
|
|
gdkwin = gdk_window_foreign_new(my_msg_win);
|
|
gdk_window_add_filter(gdkwin, FilterMyMsgWin, NULL);
|
|
|
|
msg_receive_callback = msg_receive_func;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
CommsSend(const char *s)
|
|
{
|
|
char ss[21];
|
|
int i, j, k, len;
|
|
XEvent ev;
|
|
Client *cl = e_client;
|
|
|
|
if (!s || !cl)
|
|
return;
|
|
|
|
len = strlen(s);
|
|
|
|
ev.xclient.type = ClientMessage;
|
|
ev.xclient.serial = 0;
|
|
ev.xclient.send_event = True;
|
|
ev.xclient.window = cl->win;
|
|
ev.xclient.message_type = Atom_ENL_MSG;
|
|
ev.xclient.format = 8;
|
|
|
|
for (i = 0; i < len + 1; i += 12)
|
|
{
|
|
snprintf(ss, sizeof(ss), "%8x", (int)my_msg_win);
|
|
for (j = 0; j < 12; j++)
|
|
{
|
|
ss[8 + j] = s[i + j];
|
|
if (!s[i + j])
|
|
j = 12;
|
|
}
|
|
ss[20] = 0;
|
|
for (k = 0; k < 20; k++)
|
|
ev.xclient.data.b[k] = ss[k];
|
|
XSendEvent(dpy, cl->win, False, 0, &ev);
|
|
}
|
|
XFlush(dpy);
|
|
}
|