xembed.c (3033B)
1 /* Copyright ©2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #include "dat.h" 5 #include "fns.h" 6 7 #define DEAD ~0UL 8 9 enum { XEmbedVersion = 0 }; 10 11 enum XEmbedMessage { 12 XEmbedEmbeddedNotify, 13 XEmbedWindowActivate, 14 XEmbedWindowDeactivate, 15 XEmbedRequestFocus, 16 XEmbedFocusIn, 17 XEmbedFocusOut, 18 XEmbedFocusNext, 19 XEmbedFocusPrev, 20 XEmbedModalityOn = 10, 21 XEmbedModalityOff, 22 XEmbedRegisterAccelerator, 23 XEmbedUnregisterAccelerator, 24 XEmbedActivateAccelerator, 25 }; 26 27 enum XEmbedFocusDetail { 28 XEmbedFocusCurrent, 29 XEmbedFocusFirst, 30 XEmbedFocusLast, 31 }; 32 33 static Handlers handlers; 34 35 static void xembed_updateinfo(XEmbed*); 36 static void xembed_sendmessage(XEmbed*, long, long, long, long); 37 38 XEmbed* 39 xembed_swallow(Window *parent, Window *client, void (*cleanup)(XEmbed*)) { 40 XEmbed *xembed; 41 42 xembed = emallocz(sizeof *xembed); 43 xembed->w = client; 44 xembed->owner = parent; 45 xembed->cleanup = cleanup; 46 selectinput(client, client->eventmask | PropertyChangeMask | StructureNotifyMask); 47 pushhandler(client, &handlers, xembed); 48 49 reparentwindow(client, parent, ZP); 50 xembed_updateinfo(xembed); 51 xembed_sendmessage(xembed, XEmbedEmbeddedNotify, 0, parent->xid, min(XEmbedVersion, xembed->version)); 52 return xembed; 53 } 54 55 void 56 xembed_disown(XEmbed *xembed) { 57 58 pophandler(xembed->w, &handlers); 59 if(xembed->flags != DEAD) { 60 reparentwindow(xembed->w, &scr.root, ZP); 61 unmapwin(xembed->w); 62 } 63 if(xembed->cleanup) 64 xembed->cleanup(xembed); 65 free(xembed); 66 } 67 68 static void 69 xembed_updateinfo(XEmbed *xembed) { 70 ulong *res; 71 int n; 72 73 n = getprop_ulong(xembed->w, "_XEMBED_INFO", "_XEMBED_INFO", 0, &res, 2); 74 xembed->flags = 0UL; 75 if(n >= 2) { 76 xembed->version = res[0]; 77 xembed->flags = res[1]; 78 } 79 else { 80 /* Deal with a Qt system tray replacement bug. */ 81 xembed->flags = XEmbedMapped; 82 } 83 free(res); 84 85 Dprint("xembed_updateinfo(0x%ulx) XEmbedMapped=%s\n", 86 xembed->w, 87 xembed->flags & XEmbedMapped ? "true" : "false"); 88 89 if(xembed->flags & XEmbedMapped) 90 mapwin(xembed->w); 91 else 92 unmapwin(xembed->w); 93 } 94 95 static void 96 xembed_sendmessage(XEmbed *xembed, long message, long detail, long data1, long data2) { 97 98 traperrors(true); 99 sendmessage(xembed->w, "_XEMBED", event_xtime, message, detail, data1, data2); 100 traperrors(false); 101 } 102 103 static bool 104 destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) { 105 XEmbed *xembed; 106 107 xembed = aux; 108 xembed->flags = DEAD; 109 xembed_disown(xembed); 110 return false; 111 } 112 113 static bool 114 property_event(Window *w, void *aux, XPropertyEvent *ev) { 115 XEmbed *xembed; 116 117 Dprint("property_event(%W, %p, %A)\n", 118 w, aux, ev->atom); 119 xembed = aux; 120 if(ev->atom == xatom("_XEMBED_INFO")) 121 xembed_updateinfo(xembed); 122 return false; 123 } 124 125 static bool 126 reparent_event(Window *w, void *aux, XReparentEvent *ev) { 127 XEmbed *xembed; 128 129 xembed = aux; 130 if(ev->parent != xembed->owner->xid) { 131 xembed->flags = DEAD; 132 xembed_disown(xembed); 133 } 134 return false; 135 } 136 137 static Handlers handlers = { 138 .destroy = destroy_event, 139 .property = property_event, 140 .reparent = reparent_event, 141 };