e16-keyedit/ipc.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);
}