/* * Copyright (C) 2000-2005 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2005 Kim Woelders * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software, its documentation and marketing & publicity * materials, and acknowledgment shall be given in the documentation, materials * and software packages that this Software was used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "E.h" struct _client { char *name; Window win; char *msg; char *clientname; char *version; char *info; char replied; }; static Window comms_win = 0; static Atom XA_ENLIGHTENMENT_COMMS = 0; static Atom XA_ENL_MSG = 0; static void ClientHandleEvents(XEvent * ev, void *cc); static Client * ClientCreate(Window win) { Client *c; char st[32]; c = Ecalloc(1, sizeof(Client)); if (!c) return NULL; Esnprintf(st, sizeof(st), "%8x", (int)win); c->name = Estrdup(st); c->win = win; ERegisterWindow(win); EventCallbackRegister(win, 0, ClientHandleEvents, c); AddItem(c, st, win, LIST_TYPE_CLIENT); XSelectInput(disp, win, StructureNotifyMask | SubstructureNotifyMask); return c; } static void ClientDestroy(Client * c) { Window win; if (!c) return; win = c->win; RemoveItem(NULL, win, LIST_FINDBY_ID, LIST_TYPE_CLIENT); EventCallbackUnregister(win, 0, ClientHandleEvents, c); EUnregisterWindow(win); if (c->name) Efree(c->name); if (c->msg) Efree(c->msg); if (c->clientname) Efree(c->clientname); if (c->version) Efree(c->version); if (c->info) Efree(c->info); Efree(c); } static int ClientConfigure(Client * c, const char *str) { char param[64]; const char *value; int len; len = 0; sscanf(str, "%*s %60s %n", param, &len); value = str + len; if (!strcmp(param, "clientname")) { if (c->clientname) Efree(c->clientname); c->clientname = Estrdup(value); } else if (!strcmp(param, "version")) { if (c->version) Efree(c->version); c->version = Estrdup(value); } else if (!strcmp(param, "author")) { } else if (!strcmp(param, "email")) { } else if (!strcmp(param, "web")) { } else if (!strcmp(param, "address")) { } else if (!strcmp(param, "info")) { if (c->info) Efree(c->info); c->info = Estrdup(value); } else if (!strcmp(param, "pixmap")) { } else { return -1; } return 0; } static char * ClientCommsGet(Client ** c, XClientMessageEvent * ev) { char s[13], s2[9], *msg; int i; Window win = 0; Client *cl; if ((!ev) || (!c)) return NULL; if (ev->message_type != XA_ENL_MSG) return NULL; s[12] = 0; s2[8] = 0; msg = NULL; for (i = 0; i < 8; i++) s2[i] = ev->data.b[i]; for (i = 0; i < 12; i++) s[i] = ev->data.b[i + 8]; sscanf(s2, "%lx", &win); cl = (Client *) FindItem(NULL, win, LIST_FINDBY_ID, LIST_TYPE_CLIENT); if (!cl) { cl = ClientCreate(win); if (!cl) return NULL; } if (cl->msg) { /* append text to end of msg */ cl->msg = Erealloc(cl->msg, strlen(cl->msg) + strlen(s) + 1); if (!cl->msg) return NULL; strcat(cl->msg, s); } else { /* new msg */ cl->msg = Emalloc(strlen(s) + 1); if (!cl->msg) return NULL; strcpy(cl->msg, s); } if (strlen(s) < 12) { msg = cl->msg; cl->msg = NULL; *c = cl; } return msg; } static void ClientHandleComms(XClientMessageEvent * ev) { Client *c; char *s; const char *s1, *s2; s = ClientCommsGet(&c, ev); if (!s) return; if (EventDebug(EDBUG_TYPE_IPC)) Eprintf("ClientHandleComms: %s\n", s); if (!strncmp(s, "set ", 4)) { /* The old Client set command (used by epplets) */ if (ClientConfigure(c, s) == 0) goto done; } if (!HandleIPC(s, c)) { s1 = (c->clientname) ? c->clientname : "UNKNOWN"; s2 = (c->version) ? c->version : "UNKNOWN"; DialogOK(_("E IPC Error"), _("Received Unknown Client Message.\n" "Client Name: %s\n" "Client Version: %s\n" "Message Contents:\n\n" "%s\n"), s1, s2, s); SoundPlay("SOUND_ERROR_IPC"); } done: Efree(s); } static void ClientHandleEvents(XEvent * ev, void *cc) { Client *c = (Client *) cc; #if 0 Eprintf("ClientHandleEvents: type=%d win=%#lx\n", ev->type, ev->xany.window); #endif switch (ev->type) { case DestroyNotify: ClientDestroy(c); break; case ClientMessage: ClientHandleComms(&(ev->xclient)); break; } } void CommsInit(void) { char s[1024]; comms_win = ECreateEventWindow(VRoot.win, -100, -100, 5, 5); ERegisterWindow(comms_win); XSelectInput(disp, comms_win, StructureNotifyMask | SubstructureNotifyMask); EventCallbackRegister(comms_win, 0, ClientHandleEvents, NULL); Esnprintf(s, sizeof(s), "WINID %8x", (int)comms_win); XA_ENLIGHTENMENT_COMMS = XInternAtom(disp, "ENLIGHTENMENT_COMMS", False); ecore_x_window_prop_string_set(comms_win, XA_ENLIGHTENMENT_COMMS, s); ecore_x_window_prop_string_set(VRoot.win, XA_ENLIGHTENMENT_COMMS, s); XA_ENL_MSG = XInternAtom(disp, "ENL_MSG", False); } static void CommsDoSend(Window win, const char *s) { char ss[21]; int i, j, k, len; XEvent ev; if ((!win) || (!s)) return; len = strlen(s); ev.xclient.type = ClientMessage; ev.xclient.serial = 0; ev.xclient.send_event = True; ev.xclient.window = win; ev.xclient.message_type = XA_ENL_MSG; ev.xclient.format = 8; for (i = 0; i < len + 1; i += 12) { Esnprintf(ss, sizeof(ss), "%8x", (int)comms_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(disp, win, False, 0, (XEvent *) & ev); } } void CommsSend(Client * c, const char *s) { if (!c) return; c->replied = 1; CommsDoSend(c->win, s); } void CommsFlush(Client * c) { if (!c) return; if (!c->replied) CommsDoSend(c->win, ""); } /* * When we are running in multi-head, connect to the master wm process * and send the message */ void CommsSendToMasterWM(const char *s) { if (Mode.wm.master) return; CommsDoSend(RootWindow(disp, Mode.wm.master_screen), s); } /* * When we are running in multi-head, connect to the slave wm processes * and broadcast the message */ void CommsBroadcastToSlaveWMs(const char *s) { int screen; if (!Mode.wm.master || Mode.wm.single) return; for (screen = 0; screen < Mode.display.screens; screen++) { if (screen != Mode.wm.master_screen) CommsDoSend(RootWindow(disp, screen), s); } } void CommsBroadcast(const char *s) { char **l; int num, i; Client *c; l = ListItems(&num, LIST_TYPE_CLIENT); if (!s) return; for (i = 0; i < num; i++) { c = (Client *) FindItem(l[i], 0, LIST_FINDBY_NAME, LIST_TYPE_CLIENT); if (c) CommsSend(c, s); } EstrlistFree(l, num); }