e16-epplets/api/comms.c

212 lines
4.5 KiB
C

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "comms.h"
#define EXID unsigned int
static EXID comms_win = 0;
static EXID my_win = 0;
static EXID Atom_ENL_COMMS = 0;
static EXID Atom_ENL_MSG = 0;
static EXID
_CommsFindCommsWindow(void)
{
unsigned char *s;
Atom ar;
unsigned long num, after;
int format;
EXID cwin;
/* Get root window ENLIGHTENMENT_COMMS property */
cwin = 0;
s = NULL;
XGetWindowProperty(disp, root, Atom_ENL_COMMS, 0, 14, False,
AnyPropertyType, &ar, &format, &num, &after, &s);
if (!s)
goto done;
sscanf((char *)s, "%*s %x", &cwin);
XFree(s);
/* Check that cwin exists and has ENLIGHTENMENT_COMMS */
s = NULL;
XGetWindowProperty(disp, cwin, Atom_ENL_COMMS, 0, 14, False,
AnyPropertyType, &ar, &format, &num, &after, &s);
if (!s)
goto done;
XFree(s);
XSelectInput(disp, cwin, StructureNotifyMask | SubstructureNotifyMask);
done:
return cwin;
}
void
CommsSetup(void)
{
if (Atom_ENL_COMMS == 0)
Atom_ENL_COMMS = XInternAtom(disp, "ENLIGHTENMENT_COMMS", False);
if (Atom_ENL_MSG == 0)
Atom_ENL_MSG = XInternAtom(disp, "ENL_MSG", False);
for (;;)
{
comms_win = _CommsFindCommsWindow();
if (comms_win != None)
break;
sleep(1);
}
if (!my_win)
{
my_win = XCreateWindow(disp, root, -10, -10, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
0, NULL);
XSelectInput(disp, my_win,
StructureNotifyMask | SubstructureNotifyMask);
}
}
void
CommsHandleDestroy(Window xwin)
{
if (xwin == comms_win)
comms_win = 0;
}
int
CommsHandlePropertyNotify(XEvent *ev)
{
if (comms_win)
return 0;
if (ev->xproperty.atom == Atom_ENL_COMMS)
CommsSetup();
if (comms_win)
return 1;
return 0;
}
int
CommsSend(const char *buf, unsigned int len)
{
char ss[21];
unsigned int i, j, k;
XEvent ev;
ev.xclient.type = ClientMessage;
ev.xclient.serial = 0;
ev.xclient.send_event = True;
ev.xclient.window = comms_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_win);
for (j = 0; j < 12; j++)
{
ss[8 + j] = buf[i + j];
if (!buf[i + j])
j = 12;
}
ss[20] = 0;
for (k = 0; k < 20; k++)
ev.xclient.data.b[k] = ss[k];
XSendEvent(disp, comms_win, False, 0, &ev);
}
return len;
}
static Bool
ev_check(Display *d __UNUSED__, XEvent *ev, XPointer p __UNUSED__)
{
if (ev->type == ClientMessage)
{
if (ev->xclient.window == my_win)
return True;
}
else if (ev->type == DestroyNotify)
{
if (ev->xdestroywindow.window == comms_win)
return True;
}
return False;
}
char *
CommsWaitForMessage(void)
{
XEvent ev;
char *msg = NULL;
for (;;)
{
XIfEvent(disp, &ev, ev_check, NULL);
if (ev.type == DestroyNotify)
{
comms_win = 0;
break;
}
else
{
msg = CommsHandleClientMessage(&ev);
if (msg)
break;
}
}
return msg;
}
char *
CommsHandleClientMessage(XEvent *ev)
{
char s[13], s2[9], *msg = NULL;
int i;
Window win = 0;
static char *c_msg = NULL;
if (!ev)
return NULL;
if (ev->type != ClientMessage)
return NULL;
s[12] = 0;
s2[8] = 0;
msg = NULL;
for (i = 0; i < 8; i++)
s2[i] = ev->xclient.data.b[i];
for (i = 0; i < 12; i++)
s[i] = ev->xclient.data.b[i + 8];
sscanf(s2, "%x", (int *)&win);
if (win == comms_win)
{
if (c_msg)
{
c_msg = realloc(c_msg, strlen(c_msg) + strlen(s) + 1);
if (!c_msg)
return NULL;
strcat(c_msg, s);
}
else
{
c_msg = malloc(strlen(s) + 1);
if (!c_msg)
return NULL;
strcpy(c_msg, s);
}
if (strlen(s) < 12)
{
msg = c_msg;
c_msg = NULL;
}
}
return msg;
}