chiark / gitweb /
New option: movres.ignore_transience.
[e16] / src / comms.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "comms.h"
26 #include "hints.h"
27 #include "ipc.h"
28 #include "e16-ecore_hints.h"
29 #include "e16-ecore_list.h"
30 #include "xwin.h"
31
32 typedef struct {
33    char               *name;
34    Window              xwin;
35    char               *msg;
36    char               *clientname;
37    char               *version;
38    char               *info;
39    char                replied;
40 } Client;
41
42 static void         CommsSend(Client * c, const char *s);
43
44 static Ecore_List  *client_list = NULL;
45
46 static Win          comms_win = NULL;
47
48 static Client      *
49 ClientCreate(Window xwin)
50 {
51    Client             *c;
52    char                st[32];
53
54    c = ECALLOC(Client, 1);
55    if (!c)
56       return NULL;
57
58    Esnprintf(st, sizeof(st), "%8x", (int)xwin);
59    c->name = Estrdup(st);
60    c->xwin = xwin;
61
62    if (!client_list)
63       client_list = ecore_list_new();
64    ecore_list_prepend(client_list, c);
65
66    return c;
67 }
68
69 static void
70 ClientDestroy(Client * c)
71 {
72    if (!c)
73       return;
74
75    ecore_list_node_remove(client_list, c);
76
77    Efree(c->name);
78    Efree(c->msg);
79    Efree(c->clientname);
80    Efree(c->version);
81    Efree(c->info);
82
83    Efree(c);
84 }
85
86 static int
87 ClientConfigure(Client * c, const char *str)
88 {
89    char                param[64];
90    const char         *value;
91    int                 len;
92
93    len = 0;
94    sscanf(str, "%*s %60s %n", param, &len);
95    value = str + len;
96
97    if (!strcmp(param, "clientname"))
98      {
99         Efree(c->clientname);
100         c->clientname = Estrdup(value);
101      }
102    else if (!strcmp(param, "version"))
103      {
104         Efree(c->version);
105         c->version = Estrdup(value);
106      }
107    else if (!strcmp(param, "author"))
108      {
109      }
110    else if (!strcmp(param, "email"))
111      {
112      }
113    else if (!strcmp(param, "web"))
114      {
115      }
116    else if (!strcmp(param, "address"))
117      {
118      }
119    else if (!strcmp(param, "info"))
120      {
121         Efree(c->info);
122         c->info = Estrdup(value);
123      }
124    else if (!strcmp(param, "pixmap"))
125      {
126      }
127    else
128      {
129         return -1;
130      }
131
132    return 0;
133 }
134
135 static int
136 ClientMatchWindow(const void *data, const void *match)
137 {
138    return ((const Client *)data)->xwin != (Window) match;
139 }
140
141 static Client      *
142 ClientFind(Window xwin)
143 {
144    return (Client *) ecore_list_find(client_list, ClientMatchWindow,
145                                      (void *)xwin);
146 }
147
148 static char        *
149 ClientCommsGet(Client ** c, XClientMessageEvent * ev)
150 {
151    char                s[13], s2[9], *msg;
152    unsigned int        i;
153    Window              xwin;
154    Client             *cl;
155
156    if ((!ev) || (!c))
157       return NULL;
158    if (ev->message_type != E16_ATOM_COMMS_MSG)
159       return NULL;
160
161    s[12] = 0;
162    s2[8] = 0;
163    for (i = 0; i < 8; i++)
164       s2[i] = ev->data.b[i];
165    for (i = 0; i < 12; i++)
166       s[i] = ev->data.b[i + 8];
167    xwin = None;
168    sscanf(s2, "%lx", &xwin);
169    if (xwin == None)
170       return NULL;
171    cl = ClientFind(xwin);
172    if (!cl)
173      {
174         cl = ClientCreate(xwin);
175         if (!cl)
176            return NULL;
177      }
178
179    /* append text to end of msg */
180    i = (cl->msg) ? strlen(cl->msg) : 0;
181    cl->msg = EREALLOC(char, cl->msg, i + strlen(s) + 1);
182    if (!cl->msg)
183       return NULL;
184    strcpy(cl->msg + i, s);
185
186    msg = NULL;
187    if (strlen(s) < 12)
188      {
189         msg = cl->msg;
190         cl->msg = NULL;
191         *c = cl;
192      }
193
194    return msg;
195 }
196
197 static void
198 ClientIpcReply(void *data, const char *str)
199 {
200    Client             *c = (Client *) data;
201
202    if (!str)
203      {
204         /* Don't send empty replies (ack's) if we ever have replied to this
205          * client. Without this hack communication with e.g. epplets fails. */
206         if (c->replied)
207            return;
208         str = "";
209      }
210    CommsSend(c, str);
211    c->replied = 1;
212 }
213
214 static void
215 ClientHandleComms(XClientMessageEvent * ev)
216 {
217    Client             *c;
218    char               *s;
219
220    s = ClientCommsGet(&c, ev);
221    if (!s)
222       return;
223
224    if (EDebug(EDBUG_TYPE_IPC))
225       Eprintf("ClientHandleComms: %s\n", s);
226
227    if (!strncmp(s, "set ", 4))
228      {
229         /* The old Client set command (used by epplets) */
230         if (ClientConfigure(c, s) == 0)
231            goto done;
232      }
233
234    if (!IpcExecReply(s, ClientIpcReply, c))
235      {
236         const char         *s1, *s2;
237
238         s1 = (c->clientname) ? c->clientname : "UNKNOWN";
239         s2 = (c->version) ? c->version : "UNKNOWN";
240         DialogOK(_("E IPC Error"),
241                  _("Received Unknown Client Message.\n"
242                    "Client Name:    %s\n" "Client Version: %s\n"
243                    "Message Contents:\n\n" "%s\n"), s1, s2, s);
244         SoundPlay(SOUND_ERROR_IPC);
245      }
246
247  done:
248    Efree(s);
249 }
250
251 static void
252 ClientHandleRootEvents(Win win __UNUSED__, XEvent * ev, void *prm __UNUSED__)
253 {
254    Client             *c;
255
256 #if 0
257    Eprintf("ClientHandleRootEvents: type=%d win=%#lx\n", ev->type,
258            ev->xany.window);
259 #endif
260    switch (ev->type)
261      {
262      case DestroyNotify:
263         c = ClientFind(ev->xdestroywindow.window);
264         if (!c)
265            break;
266         ClientDestroy(c);
267         break;
268      }
269 }
270
271 static void
272 ClientHandleCommsEvents(Win win __UNUSED__, XEvent * ev, void *prm __UNUSED__)
273 {
274 #if 0
275    Eprintf("ClientHandleCommsEvents: type=%d win=%#lx\n", ev->type,
276            ev->xany.window);
277 #endif
278    switch (ev->type)
279      {
280      case ClientMessage:
281         ClientHandleComms(&(ev->xclient));
282         break;
283      }
284 }
285
286 void
287 CommsInit(void)
288 {
289    char                s[1024];
290
291    comms_win = ECreateEventWindow(VROOT, -100, -100, 5, 5);
292    ESelectInput(comms_win, StructureNotifyMask | SubstructureNotifyMask);
293    EventCallbackRegister(comms_win, 0, ClientHandleCommsEvents, NULL);
294    EventCallbackRegister(VROOT, 0, ClientHandleRootEvents, NULL);
295
296    Esnprintf(s, sizeof(s), "WINID %8lx", WinGetXwin(comms_win));
297    ecore_x_window_prop_string_set(WinGetXwin(comms_win), E16_ATOM_COMMS_WIN, s);
298    ecore_x_window_prop_string_set(WinGetXwin(VROOT), E16_ATOM_COMMS_WIN, s);
299 }
300
301 static void
302 CommsDoSend(Window win, const char *s)
303 {
304    char                ss[21];
305    int                 i, j, k, len;
306    XEvent              ev;
307
308    if ((!win) || (!s))
309       return;
310
311    len = strlen(s);
312    ev.xclient.type = ClientMessage;
313    ev.xclient.serial = 0;
314    ev.xclient.send_event = True;
315    ev.xclient.window = win;
316    ev.xclient.message_type = E16_ATOM_COMMS_MSG;
317    ev.xclient.format = 8;
318    for (i = 0; i < len + 1; i += 12)
319      {
320         Esnprintf(ss, sizeof(ss), "%8lx", WinGetXwin(comms_win));
321         for (j = 0; j < 12; j++)
322           {
323              ss[8 + j] = s[i + j];
324              if (!s[i + j])
325                 j = 12;
326           }
327         ss[20] = 0;
328         for (k = 0; k < 20; k++)
329            ev.xclient.data.b[k] = ss[k];
330         EXSendEvent(win, 0, (XEvent *) & ev);
331      }
332 }
333
334 static void
335 CommsSend(Client * c, const char *s)
336 {
337    if (!c)
338       return;
339
340    CommsDoSend(c->xwin, s);
341 }