summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--hidden.c215
2 files changed, 216 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index fdb94fe..f72f875 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ LDFLAGS+=-L/usr/local/lib -lxcb -lxcb-randr -lxcb-keysyms -lxcb-icccm \
RM=/bin/rm
PREFIX=/usr/local
-TARGETS=mcwm
+TARGETS=mcwm hidden
OBJS=mcwm.o list.o
all: $(TARGETS)
diff --git a/hidden.c b/hidden.c
new file mode 100644
index 0000000..c86bedb
--- /dev/null
+++ b/hidden.c
@@ -0,0 +1,215 @@
+/*
+ *
+ * hidden - A small program to listen all windows with WM_STATE set to
+ * Iconic.
+ *
+ * Copyright (c) 2012 Michael Cardell Widerkrantz, mc at the domain
+ * hack.org.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <xcb/xcb.h>
+#include <xcb/xcb_icccm.h>
+
+xcb_connection_t *conn;
+xcb_screen_t *screen;
+
+xcb_atom_t wm_state;
+xcb_atom_t wm_icon_name;
+
+static uint32_t get_wm_state(xcb_drawable_t win);
+static int findhidden(void);
+static void init(void);
+static void cleanup(void);
+static xcb_atom_t getatom(char *atom_name);
+
+uint32_t get_wm_state(xcb_drawable_t win)
+{
+ xcb_get_property_reply_t *reply;
+ xcb_get_property_cookie_t cookie;
+ uint32_t *statep;
+ uint32_t state = 0;
+
+ cookie = xcb_get_property(conn, false, win, wm_state, wm_state, 0,
+ sizeof (int32_t));
+
+ reply = xcb_get_property_reply(conn, cookie, NULL);
+ if (NULL == reply)
+ {
+ fprintf(stderr, "mcwm: Couldn't get properties for win %d\n", win);
+ return -1;
+ }
+
+ /* Length is 0 if we didn't find it. */
+ if (0 == xcb_get_property_value_length(reply))
+ {
+ goto bad;
+ }
+
+ statep = xcb_get_property_value(reply);
+ state = *statep;
+
+bad:
+ free(reply);
+ return state;
+}
+
+/*
+ * List all hidden windows.
+ *
+ */
+int findhidden(void)
+{
+ xcb_query_tree_reply_t *reply;
+ int i;
+ int len;
+ xcb_window_t *children;
+ xcb_get_window_attributes_reply_t *attr;
+ uint32_t state;
+ xcb_get_property_cookie_t cookie;
+ xcb_icccm_get_text_property_reply_t prop;
+ xcb_generic_error_t *error;
+
+ /* Get all children. */
+ reply = xcb_query_tree_reply(conn,
+ xcb_query_tree(conn, screen->root), 0);
+ if (NULL == reply)
+ {
+ return -1;
+ }
+
+ len = xcb_query_tree_children_length(reply);
+ children = xcb_query_tree_children(reply);
+
+ /* List all hidden windows on this root. */
+ for (i = 0; i < len; i ++)
+ {
+ attr = xcb_get_window_attributes_reply(
+ conn, xcb_get_window_attributes(conn, children[i]), NULL);
+
+ if (!attr)
+ {
+ fprintf(stderr, "Couldn't get attributes for window %d.",
+ children[i]);
+ continue;
+ }
+
+ /*
+ * Don't bother windows in override redirect mode.
+ *
+ * This mode means they wouldn't have been reported to us
+ * with a MapRequest if we had been running, so in the
+ * normal case we wouldn't have seen them.
+ */
+ if (!attr->override_redirect)
+ {
+ state = get_wm_state(children[i]);
+ if (state == XCB_ICCCM_WM_STATE_ICONIC)
+ {
+ /*
+ * Example names:
+ *
+ * _NET_WM_ICON_NAME(UTF8_STRING) = 0x75, 0x72, 0x78, 0x76, 0x74
+ * WM_ICON_NAME(STRING) = "urxvt"
+ * _NET_WM_NAME(UTF8_STRING) = 0x75, 0x72, 0x78, 0x76, 0x74
+ * WM_NAME(STRING) = "urxvt"
+ */
+ cookie = xcb_icccm_get_wm_icon_name(conn, children[i]);
+ xcb_icccm_get_wm_icon_name_reply(conn, cookie, &prop, &error);
+
+ puts(prop.name);
+ }
+ } /* if not override redirect */
+
+ free(attr);
+ } /* for */
+
+ free(reply);
+
+ return 0;
+}
+
+void init(void)
+{
+ int scrno;
+ xcb_screen_iterator_t iter;
+
+ conn = xcb_connect(NULL, &scrno);
+ if (!conn)
+ {
+ fprintf(stderr, "can't connect to an X server\n");
+ exit(1);
+ }
+
+ iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
+
+ for (int i = 0; i < scrno; ++i)
+ {
+ xcb_screen_next(&iter);
+ }
+
+ screen = iter.data;
+
+ if (!screen)
+ {
+ fprintf(stderr, "can't get the current screen\n");
+ xcb_disconnect(conn);
+ exit(1);
+ }
+}
+
+void cleanup(void)
+{
+ xcb_disconnect(conn);
+}
+
+/*
+ * Get a defined atom from the X server.
+ */
+xcb_atom_t getatom(char *atom_name)
+{
+ xcb_intern_atom_cookie_t atom_cookie;
+ xcb_atom_t atom;
+ xcb_intern_atom_reply_t *rep;
+
+ atom_cookie = xcb_intern_atom(conn, 0, strlen(atom_name), atom_name);
+ rep = xcb_intern_atom_reply(conn, atom_cookie, NULL);
+ if (NULL != rep)
+ {
+ atom = rep->atom;
+ free(rep);
+ return atom;
+ }
+
+ /*
+ * XXX Note that we return 0 as an atom if anything goes wrong.
+ * Might become interesting.
+ */
+ return 0;
+}
+
+int main(void)
+{
+
+ init();
+
+ wm_state = getatom("WM_STATE");
+
+ findhidden();
+ cleanup();
+ exit(0);
+}