aboutsummaryrefslogtreecommitdiff
path: root/src/swallow.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/swallow.c')
-rw-r--r--src/swallow.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/src/swallow.c b/src/swallow.c
new file mode 100644
index 0000000..26836f1
--- /dev/null
+++ b/src/swallow.c
@@ -0,0 +1,274 @@
+/**
+ * @file swallow.c
+ * @author Joe Wingbermuehle
+ * @date 2005-2006
+ *
+ * @brief Swallow tray component.
+ *
+ */
+
+#include "jwm.h"
+#include "swallow.h"
+#include "main.h"
+#include "tray.h"
+#include "error.h"
+#include "root.h"
+#include "color.h"
+#include "client.h"
+#include "event.h"
+#include "misc.h"
+
+typedef struct SwallowNode {
+
+ TrayComponentType *cp;
+
+ char *name;
+ char *command;
+ int border;
+ int userWidth;
+ int userHeight;
+
+ struct SwallowNode *next;
+
+} SwallowNode;
+
+static SwallowNode *swallowNodes;
+
+static void Destroy(TrayComponentType *cp);
+static void Resize(TrayComponentType *cp);
+
+/** Initialize swallow data. */
+void InitializeSwallow() {
+ swallowNodes = NULL;
+}
+
+/** Start swallow processing. */
+void StartupSwallow() {
+
+ SwallowNode *np;
+
+ for(np = swallowNodes; np; np = np->next) {
+ if(np->command) {
+ RunCommand(np->command);
+ }
+ }
+
+}
+
+/** Stop swallow processing. */
+void ShutdownSwallow() {
+}
+
+/** Destroy swallow data. */
+void DestroySwallow() {
+
+ SwallowNode *np;
+
+ while(swallowNodes) {
+
+ np = swallowNodes->next;
+
+ Assert(swallowNodes->name);
+ Release(swallowNodes->name);
+
+ if(swallowNodes->command) {
+ Release(swallowNodes->command);
+ }
+
+ Release(swallowNodes);
+ swallowNodes = np;
+
+ }
+
+}
+
+/** Create a swallowed application tray component. */
+TrayComponentType *CreateSwallow(const char *name, const char *command,
+ int width, int height) {
+
+ TrayComponentType *cp;
+ SwallowNode *np;
+
+ if(!name) {
+ Warning("cannot swallow a client with no name");
+ return NULL;
+ }
+
+ /* Make sure this name isn't already used. */
+ for(np = swallowNodes; np; np = np->next) {
+ if(!strcmp(np->name, name)) {
+ Warning("cannot swallow the same client multiple times");
+ return NULL;
+ }
+ }
+
+ np = Allocate(sizeof(SwallowNode));
+ np->name = CopyString(name);
+ np->command = CopyString(command);
+
+ np->next = swallowNodes;
+ swallowNodes = np;
+
+ cp = CreateTrayComponent();
+ np->cp = cp;
+ cp->object = np;
+ cp->Destroy = Destroy;
+ cp->Resize = Resize;
+
+ if(width) {
+ cp->requestedWidth = width;
+ np->userWidth = 1;
+ } else {
+ cp->requestedWidth = 1;
+ np->userWidth = 0;
+ }
+ if(height) {
+ cp->requestedHeight = height;
+ np->userHeight = 1;
+ } else {
+ cp->requestedHeight = 1;
+ np->userHeight = 0;
+ }
+
+ return cp;
+
+}
+
+/** Process an event on a swallowed window. */
+int ProcessSwallowEvent(const XEvent *event) {
+
+ SwallowNode *np;
+ int width, height;
+
+ for(np = swallowNodes; np; np = np->next) {
+ if(event->xany.window == np->cp->window) {
+ switch(event->type) {
+ case DestroyNotify:
+ np->cp->window = None;
+ np->cp->requestedWidth = 1;
+ np->cp->requestedHeight = 1;
+ ResizeTray(np->cp->tray);
+ break;
+ case ResizeRequest:
+ np->cp->requestedWidth
+ = event->xresizerequest.width + np->border * 2;
+ np->cp->requestedHeight
+ = event->xresizerequest.height + np->border * 2;
+ ResizeTray(np->cp->tray);
+ break;
+ case ConfigureNotify:
+ /* I don't think this should be necessary, but somehow
+ * resize requests slip by sometimes... */
+ width = event->xconfigure.width + np->border * 2;
+ height = event->xconfigure.height + np->border * 2;
+ if( width != np->cp->requestedWidth
+ && height != np->cp->requestedHeight) {
+ np->cp->requestedWidth = width;
+ np->cp->requestedHeight = height;
+ ResizeTray(np->cp->tray);
+ }
+ break;
+ default:
+ break;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+
+}
+
+/** Handle a tray resize. */
+void Resize(TrayComponentType *cp) {
+
+ int width, height;
+
+ SwallowNode *np = (SwallowNode*)cp->object;
+
+ if(cp->window != None) {
+
+ width = cp->width - np->border * 2;
+ height = cp->height - np->border * 2;
+
+ JXResizeWindow(display, cp->window, width, height);
+
+ }
+
+}
+
+/** Destroy a swallow tray component. */
+void Destroy(TrayComponentType *cp) {
+
+ ClientProtocolType protocols;
+
+ if(cp->window) {
+
+ JXReparentWindow(display, cp->window, rootWindow, 0, 0);
+ JXRemoveFromSaveSet(display, cp->window);
+
+ protocols = ReadWMProtocols(cp->window);
+ if(protocols & PROT_DELETE) {
+ SendClientMessage(cp->window, ATOM_WM_PROTOCOLS,
+ ATOM_WM_DELETE_WINDOW);
+ } else {
+ JXKillClient(display, cp->window);
+ }
+
+ }
+
+}
+
+/** Determine if this is a window to be swallowed, if it is, swallow it. */
+int CheckSwallowMap(const XMapEvent *event) {
+
+ SwallowNode *np;
+ XClassHint hint;
+ XWindowAttributes attr;
+
+ for(np = swallowNodes; np; np = np->next) {
+
+ if(np->cp->window != None) {
+ continue;
+ }
+
+ Assert(np->cp->tray->window != None);
+
+ if(JXGetClassHint(display, event->window, &hint)) {
+ if(!strcmp(hint.res_name, np->name)) {
+
+ /* Swallow the window. */
+ JXSelectInput(display, event->window,
+ StructureNotifyMask | ResizeRedirectMask);
+ JXAddToSaveSet(display, event->window);
+ JXSetWindowBorder(display, event->window, colors[COLOR_TRAY_BG]);
+ JXReparentWindow(display, event->window,
+ np->cp->tray->window, 0, 0);
+ JXMapRaised(display, event->window);
+ JXFree(hint.res_name);
+ JXFree(hint.res_class);
+ np->cp->window = event->window;
+
+ /* Update the size. */
+ JXGetWindowAttributes(display, event->window, &attr);
+ np->border = attr.border_width;
+ if(!np->userWidth) {
+ np->cp->requestedWidth = attr.width + 2 * np->border;
+ }
+ if(!np->userHeight) {
+ np->cp->requestedHeight = attr.height + 2 * np->border;
+ }
+
+ ResizeTray(np->cp->tray);
+
+ return 1;
+
+ }
+ }
+
+ }
+
+ return 0;
+
+}
+