git.strcat.st

/strcat/wm.git/ - summarytreelogarchivereleases

subject
add a bar, live reload into wmc
commit
7d7e9e1a2c7cd182430712ed6d24b36c097db205
date
2026-05-30T23:41:13Z
message
diff
 Makefile          |   6 ++
 config.mk         |   1 +
 extras/bar.c      | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 extras/bar.h      |  16 +++
 extras/xinerama.c |  16 +++
 extras/xinerama.h |   1 +
 wm.c              | 254 +++++++++++++++++++++++++++++++++++++++++++++++-
 wmc.c             |  47 ++++++++-
 8 files changed, 616 insertions(+), 9 deletions(-)

diff --git a/Makefile b/Makefile
index 894efed..8cafd27 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,12 @@ endif
 ifeq ($(XINERAMA),1)
 WM_EXTRAS += extras/xinerama.c
 LDLIBS += -lXinerama
+CPPFLAGS += -DXINERAMA
+endif
+
+ifeq ($(BAR),1)
+WM_EXTRAS += extras/bar.c
+CPPFLAGS += -DBAR
 endif
 
 all: wm wmc
diff --git a/config.mk b/config.mk
index 969824a..908d91d 100644
--- a/config.mk
+++ b/config.mk
@@ -1,6 +1,7 @@
 # features
 EWMH=1
 XINERAMA=1
+BAR=1
 
 # uncomment on obsd and other systems which use the X11R6 path.
 #CPPFLAGS += -I/usr/X11R6/include
diff --git a/extras/bar.c b/extras/bar.c
new file mode 100644
index 0000000..a966298
--- /dev/null
+++ b/extras/bar.c
@@ -0,0 +1,284 @@
+#include <X11/Xlib.h>
+#ifdef XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define bar_height 18
+#define bar_padding 6
+#define max_status_len 512
+#define max_title_len 512
+#define max_tags 9
+#define max_monitors 16
+
+struct bar_monitor {
+	Window window;
+	int x;
+	int y;
+	int width;
+	int height;
+	int bar_width;
+};
+
+static Display *bar_display;
+static Window bar_root;
+static GC bar_gc;
+static XFontStruct *bar_font;
+static int bar_screen;
+static int bar_selected_tag;
+static int bar_tag_count;
+static int bar_monitor_count;
+static int bar_margin_x;
+static int bar_margin_y;
+static int bar_is_bottom;
+static int bar_tags[max_tags];
+static char bar_status[max_status_len];
+static char bar_title[max_title_len];
+static struct bar_monitor bar_monitors[max_monitors];
+
+void bar_reconfigure(void);
+
+static int
+bar_text_width(const char *text)
+{
+	if (bar_font == NULL || text == NULL)
+	    return 0;
+	return XTextWidth(bar_font, text, (int)strlen(text));
+}
+
+static void
+bar_draw_rect(Window window, unsigned long color, int x, int y, int width, int height)
+{
+	XSetForeground(bar_display, bar_gc, color);
+	XFillRectangle(bar_display, window, bar_gc,
+	    x, y, (unsigned int)width, (unsigned int)height);
+}
+
+static void
+bar_draw_text(Window window, unsigned long fg, int x, int y, const char *text)
+{
+	XSetForeground(bar_display, bar_gc, fg);
+	XDrawString(bar_display, window, bar_gc, x, y, text, (int)strlen(text));
+}
+
+static void
+bar_destroy_windows(void)
+{
+	int i;
+
+	for (i = 0; i < bar_monitor_count; i++) {
+	    if (bar_monitors[i].window != None)
+	        XDestroyWindow(bar_display, bar_monitors[i].window);
+	    bar_monitors[i].window = None;
+	}
+	bar_monitor_count = 0;
+}
+
+static int
+bar_load_monitors(void)
+{
+	XWindowAttributes root_attrs;
+
+	if (!XGetWindowAttributes(bar_display, bar_root, &root_attrs))
+	    return 0;
+	bar_monitor_count = 1;
+	bar_monitors[0].x = 0;
+	bar_monitors[0].y = 0;
+	bar_monitors[0].width = root_attrs.width;
+	bar_monitors[0].height = root_attrs.height;
+#ifdef XINERAMA
+	{
+	    XineramaScreenInfo *screen_info;
+	    int j, major, minor;
+	    int i;
+
+	    if (XineramaQueryExtension(bar_display, &major, &minor) &&
+	        XineramaIsActive(bar_display)) {
+	        screen_info = XineramaQueryScreens(bar_display, &j);
+	        if (screen_info != None && j > 0) {
+	            bar_monitor_count = j;
+	            if (bar_monitor_count > max_monitors)
+	                bar_monitor_count = max_monitors;
+	            for (i = 0; i < bar_monitor_count; i++) {
+	                bar_monitors[i].x = screen_info[i].x_org;
+	                bar_monitors[i].y = screen_info[i].y_org;
+	                bar_monitors[i].width = screen_info[i].width;
+	                bar_monitors[i].height = screen_info[i].height;
+	            }
+	            XFree(screen_info);
+	        }
+	    }
+	}
+#endif
+	return bar_monitor_count;
+}
+
+static void
+bar_create_windows(void)
+{
+	unsigned long black;
+	XSetWindowAttributes attrs;
+	int i, window_x, window_y, window_width;
+
+	black = BlackPixel(bar_display, bar_screen);
+	attrs.override_redirect = True;
+	attrs.background_pixel = black;
+	attrs.event_mask = ExposureMask;
+	for (i = 0; i < bar_monitor_count; i++) {
+	    window_x = bar_monitors[i].x + bar_margin_x;
+	    window_y = bar_monitors[i].y + bar_margin_y;
+	    window_width = bar_monitors[i].width - (bar_margin_x * 2);
+	    if (window_width < 1)
+	        window_width = 1;
+	    if (bar_is_bottom)
+	        window_y = bar_monitors[i].y + bar_monitors[i].height - bar_height - bar_margin_y;
+	    if (window_y < bar_monitors[i].y)
+	        window_y = bar_monitors[i].y;
+	    bar_monitors[i].bar_width = window_width;
+	    bar_monitors[i].window = XCreateWindow(bar_display, bar_root,
+	        window_x, window_y, (unsigned int)window_width, bar_height, 0,
+	        DefaultDepth(bar_display, bar_screen), CopyFromParent,
+	        DefaultVisual(bar_display, bar_screen),
+	        CWOverrideRedirect | CWBackPixel | CWEventMask, &attrs);
+	    XMapRaised(bar_display, bar_monitors[i].window);
+	}
+}
+
+int
+bar_init(Display *display, Window root_window)
+{
+	bar_display = display;
+	bar_root = root_window;
+	bar_screen = DefaultScreen(display);
+	bar_font = XLoadQueryFont(display, "fixed");
+	if (bar_font == NULL)
+	    return 0;
+	bar_gc = XCreateGC(display, root_window, 0, NULL);
+	XSetFont(display, bar_gc, bar_font->fid);
+	if (!bar_load_monitors())
+	    return 0;
+	bar_create_windows();
+	XFlush(display);
+	return 1;
+}
+
+void
+bar_set_status(const char *status)
+{
+	if (status == NULL)
+	    status = "";
+	snprintf(bar_status, sizeof(bar_status), "%s", status);
+}
+
+void
+bar_set_tags(const int *tags, int count, int selected_tag)
+{
+	int i;
+
+	bar_tag_count = count > max_tags ? max_tags : count;
+	bar_selected_tag = selected_tag;
+	for (i = 0; i < bar_tag_count; i++)
+	    bar_tags[i] = tags[i];
+}
+
+void
+bar_set_title(const char *title)
+{
+	if (title == NULL)
+	    title = "";
+	snprintf(bar_title, sizeof(bar_title), "%s", title);
+}
+
+void
+bar_draw(void)
+{
+	unsigned long white, black;
+	int m, x, i, tw, tagw, title_x, status_x, bar_width;
+	char tag_text[8];
+
+	if (bar_display == NULL || bar_monitor_count < 1)
+	    return;
+	white = WhitePixel(bar_display, bar_screen);
+	black = BlackPixel(bar_display, bar_screen);
+	for (m = 0; m < bar_monitor_count; m++) {
+	    if (bar_monitors[m].window == None)
+	        continue;
+	    bar_width = bar_monitors[m].bar_width;
+	    bar_draw_rect(bar_monitors[m].window, black, 0, 0, bar_width, bar_height);
+	    x = 0;
+	    for (i = 0; i < bar_tag_count; i++) {
+	        snprintf(tag_text, sizeof(tag_text), "%d", bar_tags[i]);
+	        tw = bar_text_width(tag_text);
+	        tagw = tw + (bar_padding * 2);
+	        if (i == bar_selected_tag) {
+	            bar_draw_rect(bar_monitors[m].window, white, x, 2, tagw, bar_height - 4);
+	            bar_draw_text(bar_monitors[m].window, black, x + bar_padding, bar_height - 5, tag_text);
+	        } else {
+	            bar_draw_text(bar_monitors[m].window, white, x + bar_padding, bar_height - 5, tag_text);
+	        }
+	        x += tagw + bar_padding;
+	    }
+	    status_x = bar_width - bar_padding - bar_text_width(bar_status);
+	    if (status_x < x + bar_padding)
+	        status_x = x + bar_padding;
+	    bar_draw_text(bar_monitors[m].window, white, status_x, bar_height - 5, bar_status);
+	    title_x = x + bar_padding;
+	    tw = bar_text_width(bar_title);
+	    if (title_x + tw < status_x - bar_padding)
+	        bar_draw_text(bar_monitors[m].window, white, title_x, bar_height - 5, bar_title);
+	}
+	XFlush(bar_display);
+}
+
+void
+bar_set_margins(int margin_x, int margin_y)
+{
+	if (margin_x < 0)
+	    margin_x = bar_margin_x;
+	if (margin_y < 0)
+	    margin_y = bar_margin_y;
+	if (margin_x < 0)
+	    margin_x = 0;
+	if (margin_y < 0)
+	    margin_y = 0;
+	bar_margin_x = margin_x;
+	bar_margin_y = margin_y;
+	bar_reconfigure();
+}
+
+void
+bar_set_bottom(int is_bottom)
+{
+	bar_is_bottom = is_bottom ? 1 : 0;
+	bar_reconfigure();
+}
+
+void
+bar_reconfigure(void)
+{
+	if (bar_display == NULL)
+	    return;
+	bar_destroy_windows();
+	if (!bar_load_monitors())
+	    return;
+	bar_create_windows();
+	bar_draw();
+}
+
+void
+bar_cleanup(void)
+{
+	if (bar_display == NULL)
+	    return;
+	bar_destroy_windows();
+	if (bar_gc != None)
+	    XFreeGC(bar_display, bar_gc);
+	if (bar_font != NULL)
+	    XFreeFont(bar_display, bar_font);
+	bar_gc = None;
+	bar_font = NULL;
+	bar_display = NULL;
+	bar_root = None;
+}
diff --git a/extras/bar.h b/extras/bar.h
new file mode 100644
index 0000000..08f4392
--- /dev/null
+++ b/extras/bar.h
@@ -0,0 +1,16 @@
+#ifndef BAR_H
+#define BAR_H
+
+#include <X11/Xlib.h>
+
+int bar_init(Display *display, Window root_window);
+void bar_set_status(const char *status);
+void bar_set_tags(const int *tags, int count, int selected_tag);
+void bar_set_title(const char *title);
+void bar_set_margins(int margin_x, int margin_y);
+void bar_set_bottom(int is_bottom);
+void bar_reconfigure(void);
+void bar_draw(void);
+void bar_cleanup(void);
+
+#endif
diff --git a/extras/xinerama.c b/extras/xinerama.c
index ba43c9a..4e9a676 100644
--- a/extras/xinerama.c
+++ b/extras/xinerama.c
@@ -84,3 +84,19 @@ xinerama_monitor_for_window(Display *display, Window root_window, Window window)
 	y = window_attrs.y + (window_attrs.height / 2);
 	return xinerama_monitor_for_point(x, y);
 }
+
+int
+xinerama_monitor_geometry(int monitor, int *x, int *y, int *width, int *height)
+{
+	if (monitor < 0 || monitor >= monitor_count)
+	    return 0;
+	if (x != NULL)
+	    *x = monitors[monitor].x;
+	if (y != NULL)
+	    *y = monitors[monitor].y;
+	if (width != NULL)
+	    *width = monitors[monitor].width;
+	if (height != NULL)
+	    *height = monitors[monitor].height;
+	return 1;
+}
diff --git a/extras/xinerama.h b/extras/xinerama.h
index 3241592..4396d0b 100644
--- a/extras/xinerama.h
+++ b/extras/xinerama.h
@@ -6,5 +6,6 @@
 int xinerama_init(Display *display, Window root_window);
 int xinerama_monitor_for_point(int x, int y);
 int xinerama_monitor_for_window(Display *display, Window root_window, Window window);
+int xinerama_monitor_geometry(int monitor, int *x, int *y, int *width, int *height);
 
 #endif
diff --git a/wm.c b/wm.c
index e219d03..d9453e0 100644
--- a/wm.c
+++ b/wm.c
@@ -1,5 +1,13 @@
 #include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <unistd.h>
 #include "extras/ewmh/ewmh.h"
+#ifdef XINERAMA
+#include "extras/xinerama.h"
+#endif
+#ifdef BAR
+#include "extras/bar.h"
+#endif
 
 #define max_val(a, b) ((a) > (b) ? (a) : (b))
 #define mod_key Mod1Mask
@@ -7,13 +15,96 @@
 #define cmd_workspace 1
 #define cmd_move 2
 #define cmd_kill 3
+#define cmd_bar_position 4
+#define cmd_bar_margin_x 5
+#define cmd_bar_margin_y 6
+#define cmd_reload 7
 #define num_workspaces 9
 #define modifier_variants 4
 
 static Window windows[max_windows];
 static int window_workspace[max_windows], window_count, current_workspace;
+static Atom net_wm_desktop_atom;
+#ifdef BAR
+static Atom wm_bar_margin_x_atom, wm_bar_margin_y_atom, wm_bar_bottom_atom;
+#endif
 static int is_root_child(Display *display, Window root_window, Window window);
 
+static int
+find_window_index(Window window)
+{
+	int i;
+
+	for (i = 0; i < window_count; i++)
+	    if (windows[i] == window)
+	        return i;
+	return -1;
+}
+
+static void
+place_window_at_pointer(Display *display, Window root_window, Window window)
+{
+	Window root_return, child_return;
+	XWindowAttributes root_attrs;
+	XWindowAttributes window_attrs;
+	int root_x, root_y, window_x, window_y;
+	int area_x, area_y, area_width, area_height;
+	unsigned int mask;
+
+	if (!XQueryPointer(display, root_window, &root_return, &child_return,
+	    &root_x, &root_y, &window_x, &window_y, &mask))
+	    return;
+	if (!XGetWindowAttributes(display, root_window, &root_attrs))
+	    return;
+	if (!XGetWindowAttributes(display, window, &window_attrs))
+	    return;
+	area_x = 0;
+	area_y = 0;
+	area_width = root_attrs.width;
+	area_height = root_attrs.height;
+#ifdef XINERAMA
+	{
+	    int monitor;
+
+	    monitor = xinerama_monitor_for_point(root_x, root_y);
+	    if (!xinerama_monitor_geometry(monitor, &area_x, &area_y, &area_width, &area_height)) {
+	        area_x = 0;
+	        area_y = 0;
+	        area_width = root_attrs.width;
+	        area_height = root_attrs.height;
+	    }
+	}
+#endif
+	window_x = root_x - (window_attrs.width / 2);
+	window_y = root_y - (window_attrs.height / 2);
+	if (window_x < area_x)
+	    window_x = area_x;
+	if (window_y < area_y)
+	    window_y = area_y;
+	if (window_x + window_attrs.width > area_x + area_width)
+	    window_x = area_x + area_width - window_attrs.width;
+	if (window_y + window_attrs.height > area_y + area_height)
+	    window_y = area_y + area_height - window_attrs.height;
+	if (window_x < area_x)
+	    window_x = area_x;
+	if (window_y < area_y)
+	    window_y = area_y;
+	XMoveWindow(display, window, window_x, window_y);
+}
+
+#ifdef BAR
+static void
+refresh_bar(void)
+{
+	static int tags[num_workspaces] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+	bar_set_tags(tags, num_workspaces, current_workspace);
+	bar_set_title("wm");
+	bar_set_status("");
+	bar_draw();
+}
+#endif
+
 static int
 x_error_handler(Display *display, XErrorEvent *error)
 {
@@ -40,6 +131,71 @@ get_window_index(Window window)
 	return window_count++;
 }
 
+static int
+get_window_desktop(Display *display, Window window)
+{
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char *prop_data;
+	unsigned long desktop;
+
+	if (net_wm_desktop_atom == None)
+	    return -1;
+	prop_data = NULL;
+	if (XGetWindowProperty(display, window, net_wm_desktop_atom, 0, 1, False,
+	    XA_CARDINAL, &actual_type, &actual_format, &nitems, &bytes_after,
+	    &prop_data) != Success)
+	    return -1;
+	if (prop_data == NULL)
+	    return -1;
+	if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1) {
+	    XFree(prop_data);
+	    return -1;
+	}
+	desktop = *((unsigned long *)prop_data);
+	XFree(prop_data);
+	if (desktop >= num_workspaces)
+	    return -1;
+	return (int)desktop;
+}
+
+#ifdef BAR
+static int
+read_root_int_property(Display *display, Window root_window, Atom atom, int default_value)
+{
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char *prop_data;
+	unsigned long value;
+
+	prop_data = NULL;
+	if (XGetWindowProperty(display, root_window, atom, 0, 1, False, XA_CARDINAL,
+	    &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) != Success)
+	    return default_value;
+	if (prop_data == NULL)
+	    return default_value;
+	if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1) {
+	    XFree(prop_data);
+	    return default_value;
+	}
+	value = *((unsigned long *)prop_data);
+	XFree(prop_data);
+	return (int)value;
+}
+
+static void
+write_root_int_property(Display *display, Window root_window, Atom atom, int value)
+{
+	unsigned long card;
+
+	card = (unsigned long)value;
+	XChangeProperty(display, root_window, atom, XA_CARDINAL, 32, PropModeReplace,
+	    (unsigned char *)&card, 1);
+}
+#endif
+
 static void
 remove_window(Window window)
 {
@@ -98,9 +254,16 @@ track_windows(Display *display, Window root_window)
 	int i, j;
 
 	if (XQueryTree(display, root_window, &root_return, &parent, &children, (unsigned int *)&j)) {
-	    for (i = 0; i < j; i++)
-	        if (is_managed_window(display, root_window, children[i]))
-	            get_window_index(children[i]);
+	    for (i = 0; i < j; i++) {
+	        int window_index, desktop;
+
+	        if (!is_managed_window(display, root_window, children[i]))
+	            continue;
+	        window_index = get_window_index(children[i]);
+	        desktop = get_window_desktop(display, children[i]);
+	        if (window_index >= 0 && desktop >= 0)
+	            window_workspace[window_index] = desktop;
+	    }
 	    if (children != None)
 	        XFree(children);
 	}
@@ -145,7 +308,7 @@ show_workspace(Display *display, Window root_window)
 }
 
 int
-main(void)
+main(int argc, char **argv)
 {
 	Display *display;
 	Window root_window;
@@ -160,16 +323,33 @@ main(void)
 
 	is_dragging = 0;
 	drag_window = None;
+	(void)argc;
 	if ((display = XOpenDisplay(NULL)) == NULL)
 	    return 1;
 	XSetErrorHandler(x_error_handler);
 
 	root_window = DefaultRootWindow(display);
 	control_atom = XInternAtom(display, "_WM_CTL", False);
-	XSelectInput(display, root_window, SubstructureNotifyMask);
+	net_wm_desktop_atom = XInternAtom(display, "_NET_WM_DESKTOP", False);
+#ifdef BAR
+	wm_bar_margin_x_atom = XInternAtom(display, "_WM_BAR_MARGIN_X", False);
+	wm_bar_margin_y_atom = XInternAtom(display, "_WM_BAR_MARGIN_Y", False);
+	wm_bar_bottom_atom = XInternAtom(display, "_WM_BAR_BOTTOM", False);
+#endif
+	XSelectInput(display, root_window, SubstructureNotifyMask | StructureNotifyMask);
 	track_windows(display, root_window);
+#ifdef XINERAMA
+	xinerama_init(display, root_window);
+#endif
 	ewmh_init(display, root_window);
 	ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	bar_init(display, root_window);
+	bar_set_margins(read_root_int_property(display, root_window, wm_bar_margin_x_atom, 0),
+	    read_root_int_property(display, root_window, wm_bar_margin_y_atom, 0));
+	bar_set_bottom(read_root_int_property(display, root_window, wm_bar_bottom_atom, 0) ? 1 : 0);
+	refresh_bar();
+#endif
 
 	grab_button_variants(display, 1, 0, root_window, GrabModeSync);
 	grab_button_variants(display, 1, mod_key, root_window, GrabModeAsync);
@@ -179,14 +359,44 @@ main(void)
 	    XNextEvent(display, &event);
 	    if (event.type == ClientMessage && event.xclient.message_type == control_atom) {
 	        int command;
+#ifdef BAR
+	        int value;
+#endif
 
 	        command = (int)event.xclient.data.l[0];
 	        i = (int)event.xclient.data.l[1];
+	       
+#ifdef BAR
+	        value = (int)event.xclient.data.l[1];
+	        if (command == cmd_bar_position) {
+	            bar_set_bottom(value ? 1 : 0);
+	            write_root_int_property(display, root_window, wm_bar_bottom_atom, value ? 1 : 0);
+	            refresh_bar();
+	            continue;
+	        } else if (command == cmd_bar_margin_x) {
+	            bar_set_margins(value, -1);
+	            write_root_int_property(display, root_window, wm_bar_margin_x_atom, value);
+	            refresh_bar();
+	            continue;
+	        } else if (command == cmd_bar_margin_y) {
+	            bar_set_margins(-1, value);
+	            write_root_int_property(display, root_window, wm_bar_margin_y_atom, value);
+	            refresh_bar();
+	            continue;
+	        }
+#endif
 	        if (command == cmd_kill) {
 	            XGetInputFocus(display, &focused_window, &j);
 	            if (!is_root_child(display, root_window, focused_window))
 	                continue;
 	            XKillClient(display, focused_window);
+	        } else if (command == cmd_reload) {
+#ifdef BAR
+	            bar_cleanup();
+#endif
+	            XCloseDisplay(display);
+	            execvp(argv[0], argv);
+	            return 1;
 	        } else if (i >= 0 && i < num_workspaces) {
 	            if (command == cmd_workspace && i != current_workspace) {
 	                track_windows(display, root_window);
@@ -194,6 +404,9 @@ main(void)
 	                show_workspace(display, root_window);
 	                ewmh_set_current_desktop(display, root_window, current_workspace);
 	                ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	                refresh_bar();
+#endif
 	            } else if (command == cmd_move) {
 	                XGetInputFocus(display, &focused_window, &j);
 	                if (!is_root_child(display, root_window, focused_window))
@@ -205,12 +418,32 @@ main(void)
 	                    if (i != current_workspace)
 	                        XUnmapWindow(display, focused_window);
 	                    ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	                    refresh_bar();
+#endif
 	                }
 	            }
 	        }
 	    } else if (event.type == DestroyNotify) {
 	        remove_window(event.xdestroywindow.window);
 	        ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	        refresh_bar();
+#endif
+	    } else if (event.type == MapNotify) {
+	        Window mapped_window;
+
+	        mapped_window = event.xmap.window;
+	        if (!is_managed_window(display, root_window, mapped_window))
+	            continue;
+	        if (find_window_index(mapped_window) < 0) {
+	            place_window_at_pointer(display, root_window, mapped_window);
+	            get_window_index(mapped_window);
+	            ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	            refresh_bar();
+#endif
+	        }
 	    } else if (event.type == ButtonPress && event.xbutton.subwindow != None) {
 	        drag_window = event.xbutton.subwindow;
 	        if (!is_managed_window(display, root_window, drag_window)) {
@@ -224,6 +457,9 @@ main(void)
 	        if (j >= 0)
 	            window_workspace[j] = current_workspace;
 	        ewmh_sync(display, root_window, windows, window_workspace, window_count);
+#ifdef BAR
+	        refresh_bar();
+#endif
 	        if (!(event.xbutton.state & mod_key) && event.xbutton.button == 1) {
 	            XAllowEvents(display, ReplayPointer, event.xbutton.time);
 	            continue;
@@ -260,6 +496,14 @@ main(void)
 	        is_dragging = 0;
 	        drag_window = None;
 	        XUngrabPointer(display, CurrentTime);
+	    } else if (event.type == ConfigureNotify &&
+	        event.xconfigure.window == root_window) {
+#ifdef XINERAMA
+	        xinerama_init(display, root_window);
+#endif
+#ifdef BAR
+	        bar_reconfigure();
+#endif
 	    }
 	}
 }
diff --git a/wmc.c b/wmc.c
index 1ad063a..ab18a9d 100644
--- a/wmc.c
+++ b/wmc.c
@@ -7,6 +7,10 @@
 #define cmd_workspace 1
 #define cmd_move 2
 #define cmd_kill 3
+#define cmd_bar_position 4
+#define cmd_bar_margin_x 5
+#define cmd_bar_margin_y 6
+#define cmd_reload 7
 
 int
 main(int argc, char **argv)
@@ -15,13 +19,40 @@ main(int argc, char **argv)
 	Window root_window;
 	XEvent event;
 	Atom control_atom;
-	int command, workspace;
+	int command, workspace, value;
 	char *end_ptr;
 
 	command = cmd_workspace;
 	workspace = 0;
+	value = 0;
 	if (argc == 2 && !strcmp(argv[1], "kill"))
 	    command = cmd_kill;
+	else if (argc == 2 && !strcmp(argv[1], "reload"))
+	    command = cmd_reload;
+	else if (argc == 3 && !strcmp(argv[1], "bar")) {
+	    if (!strcmp(argv[2], "top")) {
+	        command = cmd_bar_position;
+	        value = 0;
+	    } else if (!strcmp(argv[2], "bottom")) {
+	        command = cmd_bar_position;
+	        value = 1;
+	    } else {
+	        fprintf(stderr, "usage: wmc bar top|bottom\n");
+	        return 1;
+	    }
+	} else if (argc == 4 && !strcmp(argv[1], "bar")) {
+	    value = (int)strtol(argv[3], &end_ptr, 10);
+	    if (*end_ptr != '\0' || value < 0)
+	        return 1;
+	    if (!strcmp(argv[2], "mx"))
+	        command = cmd_bar_margin_x;
+	    else if (!strcmp(argv[2], "my"))
+	        command = cmd_bar_margin_y;
+	    else {
+	        fprintf(stderr, "usage: wmc bar mx <px> | wmc bar my <px>\n");
+	        return 1;
+	    }
+	}
 	else if (argc == 2)
 	    workspace = (int)strtol(argv[1], &end_ptr, 10);
 	else if (argc == 3 && !strcmp(argv[1], "move")) {
@@ -30,11 +61,16 @@ main(int argc, char **argv)
 	} else if (argc == 3 && !strcmp(argv[1], "ws"))
 	    workspace = (int)strtol(argv[2], &end_ptr, 10);
 	else {
-	    fprintf(stderr, "usage: wmc [ws] 1-9 | wmc move 1-9 | wmc kill\n");
+	    fprintf(stderr, "usage: wmc [ws] 1-9 | wmc move 1-9 | wmc kill | wmc reload | "
+	        "wmc bar top|bottom | wmc bar mx <px> | wmc bar my <px>\n");
 	    return 1;
 	}
-	if (command != cmd_kill && (*end_ptr != '\0' || workspace < 1 || workspace > 9))
+	if ((command == cmd_workspace || command == cmd_move) &&
+	    (*end_ptr != '\0' || workspace < 1 || workspace > 9))
 	    return 1;
+	if (command == cmd_bar_position || command == cmd_bar_margin_x ||
+	    command == cmd_bar_margin_y)
+	    workspace = value;
 	if ((display = XOpenDisplay(NULL)) == NULL)
 	    return 1;
 	root_window = DefaultRootWindow(display);
@@ -45,7 +81,10 @@ main(int argc, char **argv)
 	event.xclient.message_type = control_atom;
 	event.xclient.format = 32;
 	event.xclient.data.l[0] = command;
-	event.xclient.data.l[1] = workspace > 0 ? workspace - 1 : 0;
+	if (command == cmd_workspace || command == cmd_move)
+	    event.xclient.data.l[1] = workspace > 0 ? workspace - 1 : 0;
+	else
+	    event.xclient.data.l[1] = workspace;
 	XSendEvent(display, root_window, False, SubstructureNotifyMask, &event);
 	XFlush(display);
 	XCloseDisplay(display);