Stacking is done with ObWindows.
Slits add themselves to the stacking order, as do clients of course.
Added some macros for adding/removing to the stacking order.
extensions.c focus.c frame.c grab.c menu.c menu_render.c \
openbox.c framerender.c parse.c plugin.c prop.c screen.c \
stacking.c dispatch.c event.c group.c timer.c xerror.c \
- moveresize.c startup.c popup.c slit.c
+ moveresize.c startup.c popup.c slit.c window.c
noinst_HEADERS=action.h client.h config.h dispatch.h event.h extensions.h \
focus.h frame.h framerender.h geom.h gettext.h grab.h group.h \
menu.h openbox.h parse.h parse.tab.h plugin.h prop.h screen.h \
stacking.h timer.h xerror.h moveresize.h startup.h popup.h \
- slit.h
+ slit.h window.h
# kill the implicit .c.y rule
%.c: %.y
{
if (data->client.c) {
client_focus(data->client.c);
- stacking_raise(data->client.c);
+ stacking_raise(CLIENT_AS_WINDOW(data->client.c));
}
}
void action_raise(union ActionData *data)
{
if (data->client.c)
- stacking_raise(data->client.c);
+ stacking_raise(CLIENT_AS_WINDOW(data->client.c));
}
void action_unshaderaise(union ActionData *data)
if (data->client.c->shaded)
client_shade(data->client.c, FALSE);
else
- stacking_raise(data->client.c);
+ stacking_raise(CLIENT_AS_WINDOW(data->client.c));
}
}
{
if (data->client.c) {
if (data->client.c->shaded)
- stacking_lower(data->client.c);
+ stacking_lower(CLIENT_AS_WINDOW(data->client.c));
else
client_shade(data->client.c, TRUE);
}
void action_lower(union ActionData *data)
{
if (data->client.c)
- stacking_lower(data->client.c);
+ stacking_lower(CLIENT_AS_WINDOW(data->client.c));
}
void action_close(union ActionData *data)
w = startup_stack_order[i-1];
c = g_hash_table_lookup(client_map, &w);
- if (c) stacking_lower(c);
+ if (c) stacking_lower(CLIENT_AS_WINDOW(c));
}
g_free(startup_stack_order);
startup_stack_order = NULL;
/* create the Client struct, and populate it from the hints on the
window */
self = g_new(Client, 1);
+ self->obwin.type = Window_Client;
self->window = window;
client_get_all(self);
grab_server(FALSE);
client_list = g_list_append(client_list, self);
- stacking_list = g_list_append(stacking_list, self);
+ stacking_add(self);
g_assert(!g_hash_table_lookup(client_map, &self->window));
g_hash_table_insert(client_map, &self->window, self);
/* update the focus lists */
focus_order_add_new(self);
- stacking_raise(self);
+ stacking_raise(CLIENT_AS_WINDOW(self));
screen_update_struts();
frame_hide(self->frame);
client_list = g_list_remove(client_list, self);
- stacking_list = g_list_remove(stacking_list, self);
+ stacking_remove(self);
g_hash_table_remove(client_map, &self->window);
/* update the focus lists */
{
StackLayer l;
- if (self->iconic) l = Layer_Icon;
- else if (self->fullscreen) l = Layer_Fullscreen;
+ if (self->fullscreen) l = Layer_Fullscreen;
else if (self->type == Type_Desktop) l = Layer_Desktop;
else if (self->type == Type_Dock) {
if (!self->below) l = Layer_Top;
if (!raised && l != old)
if (orig->frame) /* only restack if the original window is managed */
- stacking_raise(self);
+ stacking_raise(CLIENT_AS_WINDOW(self));
}
void client_calc_layer(Client *self)
client_showhide(self);
/* raise if it was not already on the desktop */
if (old != DESKTOP_ALL)
- stacking_raise(self);
+ stacking_raise(CLIENT_AS_WINDOW(self));
screen_update_struts();
/* add to the new desktop(s) */
if (self->shaded)
client_shade(self, FALSE);
client_focus(self);
- stacking_raise(self);
+ stacking_raise(CLIENT_AS_WINDOW(self));
}
gboolean client_focused(Client *self)
typedef struct Client {
+ ObWindow obwin;
+
Window window;
/*! The window's decorations. NULL while the window is being managed! */
extern gboolean config_focus_last_on_desktop;
/*! Show a popup dialog while cycling focus */
extern gboolean config_focus_popup;
+/*! The number of slits to create */
+extern int config_slit_number;
/* The name of the theme */
char *config_theme;
static void event_handle_slit(Slit *s, XEvent *e)
{
switch (e->type) {
+ case ButtonPress:
+ stacking_raise(SLIT_AS_WINDOW(s));
case EnterNotify:
slit_hide(s, FALSE);
break;
-100, -100, 1, 1, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect, &attrib);
- XMapWindow(ob_display, focus_backup);
- stacking_raise_internal(focus_backup);
+ XMapRaised(ob_display, focus_backup);
/* start with nothing focused */
focus_set_client(NULL);
Menu *self;
self = g_new0(Menu, 1);
+ self->obwin.type = Window_Menu;
self->label = g_strdup(label);
self->name = g_strdup(name);
self->parent = parent;
MIN(y, screen_physical_size.height - self->size.height));
if (!self->shown) {
- stacking_raise_internal(self->frame);
+ /* XXX gotta add to the stacking list first!
+ stacking_raise(MENU_AS_WINDOW(self));
+ */
XMapWindow(ob_display, self->frame);
self->shown = TRUE;
} else if (self->shown && self->open_submenu) {
gboolean enter);
typedef struct Menu {
+ ObWindow obwin;
+
char *label;
char *name;
menu_startup();
frame_startup();
- stacking_startup();
moveresize_startup();
focus_startup();
screen_startup();
screen_shutdown();
focus_shutdown();
moveresize_shutdown();
- stacking_shutdown();
frame_shutdown();
menu_shutdown();
grab_shutdown();
#include "slit.h"
#include "screen.h"
#include "grab.h"
-#include "timer.h"
#include "openbox.h"
#include "render/theme.h"
-#include "render/render.h"
#define SLIT_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask)
#define SLITAPP_EVENT_MASK (StructureNotifyMask)
-struct Slit {
- Window frame;
-
- /* user-requested position stuff */
- SlitPosition pos;
- int gravity;
- int user_x, user_y;
-
- /* actual position (when not auto-hidden) */
- int x, y;
- int w, h;
-
- gboolean horz;
- gboolean hide;
- gboolean hidden;
-
- Appearance *a_frame;
-
- Timer *hide_timer;
-
- GList *slit_apps;
-};
-
GHashTable *slit_map = NULL;
GHashTable *slit_app_map = NULL;
nslits = 1;
slit = g_new0(struct Slit, nslits);
+ slit->obwin.type = Window_Slit;
for (i = 0; i < nslits; ++i) {
slit[i].horz = FALSE;
slit[i].hide = FALSE;
slit[i].hidden = TRUE;
slit[i].pos = SlitPos_TopRight;
+ slit[i].layer = Layer_Top;
attrib.event_mask = SLIT_EVENT_MASK;
attrib.override_redirect = True;
XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
g_hash_table_insert(slit_map, &slit[i].frame, &slit[i]);
+ stacking_add(&slit[i]);
+ stacking_raise(SLIT_AS_WINDOW(&slit[i]));
}
}
XDestroyWindow(ob_display, slit[i].frame);
appearance_free(slit[i].a_frame);
g_hash_table_remove(slit_map, &slit[i].frame);
+ stacking_remove(&slit[i]);
}
g_hash_table_destroy(slit_app_map);
g_hash_table_destroy(slit_map);
#ifndef __slit_h
#define __slit_h
+#include "timer.h"
+#include "render/render.h"
+#include "window.h"
+#include "stacking.h"
+
#include <glib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
-typedef struct Slit Slit;
+typedef enum {
+ SlitPos_Floating,
+ SlitPos_TopLeft,
+ SlitPos_Top,
+ SlitPos_TopRight,
+ SlitPos_Right,
+ SlitPos_BottomRight,
+ SlitPos_Bottom,
+ SlitPos_BottomLeft,
+ SlitPos_Left
+} SlitPosition;
+
+typedef struct Slit {
+ ObWindow obwin;
+
+ Window frame;
+ StackLayer layer;
+
+ /* user-requested position stuff */
+ SlitPosition pos;
+ int gravity;
+ int user_x, user_y;
+
+ /* actual position (when not auto-hidden) */
+ int x, y;
+ int w, h;
+
+ gboolean horz;
+ gboolean hide;
+ gboolean hidden;
+
+ Appearance *a_frame;
+
+ Timer *hide_timer;
+
+ GList *slit_apps;
+} Slit;
typedef struct SlitApp {
int ignore_unmaps;
int h;
} SlitApp;
-typedef enum {
- SlitPos_Floating,
- SlitPos_TopLeft,
- SlitPos_Top,
- SlitPos_TopRight,
- SlitPos_Right,
- SlitPos_BottomRight,
- SlitPos_Bottom,
- SlitPos_BottomLeft,
- SlitPos_Left
-} SlitPosition;
-
extern GHashTable *slit_map;
extern GHashTable *slit_app_map;
#include "client.h"
#include "group.h"
#include "frame.h"
+#include "window.h"
#include <glib.h>
GList *stacking_list = NULL;
-static Window top_window = None;
-
-void stacking_startup()
-{
- XSetWindowAttributes attrib;
- attrib.override_redirect = TRUE;
- top_window = XCreateWindow(ob_display, ob_root,
- -100, -100, 1, 1, 0,
- CopyFromParent, InputOutput, CopyFromParent,
- CWOverrideRedirect, &attrib);
- XMapWindow(ob_display, top_window);
-}
-
-void stacking_shutdown()
-{
- XDestroyWindow(ob_display, top_window);
-}
-
void stacking_set_list()
{
Window *windows, *win_it;
win_it = windows;
for (it = g_list_last(stacking_list); it != NULL;
it = it->prev, ++win_it)
- *win_it = ((Client*)it->data)->window;
+ if (WINDOW_IS_CLIENT(it->data))
+ *win_it = window_top(it->data);
} else
windows = NULL;
return NULL;
}
-static void raise_recursive(Client *client)
+static void raise_recursive(ObWindow *window)
{
Window wins[2]; /* only ever restack 2 windows. */
GList *it, *low;
g_assert(stacking_list != NULL); /* this would be bad */
- /* remove the client before looking so we can't run into ourselves and our
+ /* remove the window before looking so we can't run into ourselves and our
transients can't either. */
- stacking_list = g_list_remove(stacking_list, client);
+ stacking_list = g_list_remove(stacking_list, window);
/* raise transients first */
- for (sit = client->transients; sit; sit = sit->next)
- raise_recursive(sit->data);
+ if (WINDOW_IS_CLIENT(window)) {
+ Client *client = WINDOW_AS_CLIENT(window);
+ for (sit = client->transients; sit; sit = sit->next)
+ raise_recursive(sit->data);
+ }
/* find 'it' where it is the positiion in the stacking order where
- 'client' will be inserted *before* */
+ 'window' will be inserted *before* */
- low = find_lowest_transient(client);
+ if (WINDOW_IS_CLIENT(window))
+ low = find_lowest_transient(WINDOW_AS_CLIENT(window));
+ else
+ low = NULL;
/* the stacking list is from highest to lowest */
for (it = g_list_last(stacking_list); it; it = it->prev) {
- if (it == low || client->layer < ((Client*)it->data)->layer) {
+ if (it == low || window_layer(window) < window_layer(it->data)) {
it = it->next;
break;
}
if (it == stacking_list)
wins[0] = focus_backup;
else if (it != NULL)
- wins[0] = ((Client*)it->prev->data)->frame->window;
+ wins[0] = window_top(it->prev->data);
else
- wins[0] = ((Client*)g_list_last(stacking_list)->data)->frame->window;
- wins[1] = client->frame->window;
+ wins[0] = window_top(g_list_last(stacking_list)->data);
+ wins[1] = window_top(window);
- stacking_list = g_list_insert_before(stacking_list, it, client);
+ stacking_list = g_list_insert_before(stacking_list, it, window);
XRestackWindows(ob_display, wins, 2);
}
-void stacking_raise(Client *client)
+void stacking_raise(ObWindow *window)
{
g_assert(stacking_list != NULL); /* this would be bad */
- /* move up the transient chain as far as possible first */
- while (client->transient_for) {
- if (client->transient_for != TRAN_GROUP) {
- client = client->transient_for;
- } else {
- GSList *it;
-
- /* the check for TRAN_GROUP is to prevent an infinate loop with
- 2 transients of the same group at the head of the group's
- members list */
- for (it = client->group->members; it; it = it->next) {
- Client *c = it->data;
-
- if (c != client && c->transient_for != TRAN_GROUP) {
- client = it->data;
- break;
+ if (WINDOW_IS_CLIENT(window)) {
+ Client *client = WINDOW_AS_CLIENT(window);
+ /* move up the transient chain as far as possible first */
+ while (client->transient_for) {
+ if (client->transient_for != TRAN_GROUP) {
+ client = client->transient_for;
+ } else {
+ GSList *it;
+
+ /* the check for TRAN_GROUP is to prevent an infinate loop with
+ 2 transients of the same group at the head of the group's
+ members list */
+ for (it = client->group->members; it; it = it->next) {
+ Client *c = it->data;
+
+ if (c != client && c->transient_for != TRAN_GROUP) {
+ client = it->data;
+ break;
+ }
}
+ if (it == NULL) break;
}
- if (it == NULL) break;
}
+ window = CLIENT_AS_WINDOW(client);
}
- raise_recursive(client);
+ raise_recursive(window);
stacking_set_list();
}
-static void lower_recursive(Client *client, Client *above)
+static void lower_recursive(ObWindow *window, ObWindow *above)
{
Window wins[2]; /* only ever restack 2 windows. */
GList *it;
GSList *sit;
/* find 'it' where 'it' is the position in the stacking_list where the
- 'client' will be placed *after* */
+ 'window' will be placed *after* */
for (it = g_list_last(stacking_list); it != stacking_list; it = it->prev)
- if (client->layer <= ((Client*)it->data)->layer && it->data != above)
+ if (window_layer(window) <= window_layer(it->data) &&
+ it->data != above)
break;
- if (it->data != client) { /* not already the bottom */
- wins[0] = ((Client*)it->data)->frame->window;
- wins[1] = client->frame->window;
+ if (it->data != window) { /* not already the bottom */
+ wins[0] = window_top(it->data);
+ wins[1] = window_top(window);
- stacking_list = g_list_remove(stacking_list, client);
- stacking_list = g_list_insert_before(stacking_list, it->next, client);
+ stacking_list = g_list_remove(stacking_list, window);
+ stacking_list = g_list_insert_before(stacking_list, it->next, window);
XRestackWindows(ob_display, wins, 2);
}
- for (sit = client->transients; sit; sit = sit->next)
- lower_recursive(sit->data, client);
+ if (WINDOW_IS_CLIENT(window)) {
+ Client *client = WINDOW_AS_CLIENT(window);
+ for (sit = client->transients; sit; sit = sit->next)
+ lower_recursive(CLIENT_AS_WINDOW(sit->data), window);
+ }
}
-void stacking_lower(Client *client)
+void stacking_lower(ObWindow *window)
{
g_assert(stacking_list != NULL); /* this would be bad */
- /* move up the transient chain as far as possible first */
- while (client->transient_for) {
- if (client->transient_for != TRAN_GROUP) {
- client = client->transient_for;
- } else {
- GSList *it;
-
- /* the check for TRAN_GROUP is to prevent an infinate loop with
- 2 transients of the same group at the head of the group's
- members list */
- for (it = client->group->members; it; it = it->next) {
- Client *c = it->data;
-
- if (c != client && c->transient_for != TRAN_GROUP) {
- client = it->data;
- break;
+ if (WINDOW_IS_CLIENT(window)) {
+ Client *client = WINDOW_AS_CLIENT(window);
+ /* move up the transient chain as far as possible first */
+ while (client->transient_for) {
+ if (client->transient_for != TRAN_GROUP) {
+ client = client->transient_for;
+ } else {
+ GSList *it;
+
+ /* the check for TRAN_GROUP is to prevent an infinate loop with
+ 2 transients of the same group at the head of the group's
+ members list */
+ for (it = client->group->members; it; it = it->next) {
+ Client *c = it->data;
+
+ if (c != client && c->transient_for != TRAN_GROUP) {
+ client = it->data;
+ break;
+ }
}
+ if (it == NULL) break;
}
- if (it == NULL) break;
}
+ window = CLIENT_AS_WINDOW(client);
}
- lower_recursive(client, NULL);
+ lower_recursive(window, NULL);
stacking_set_list();
}
-
-void stacking_raise_internal(Window win)
-{
- Window wins[2]; /* only ever restack 2 windows. */
-
- wins[0] = top_window;
- wins[1] = win;
-
- XRestackWindows(ob_display, wins, 2);
-}
#ifndef __stacking_h
#define __stacking_h
+#include "window.h"
+
#include <glib.h>
#include <X11/Xlib.h>
-struct Client;
-
/*! The possible stacking layers a client window can be a part of */
typedef enum {
- Layer_Icon, /*!< 0 - iconified windows, in any order at all */
- Layer_Desktop, /*!< 1 - desktop windows */
- Layer_Below, /*!< 2 - normal windows w/ below */
- Layer_Normal, /*!< 3 - normal windows */
- Layer_Above, /*!< 4 - normal windows w/ above */
- Layer_Top, /*!< 5 - always-on-top-windows (docks?) */
- Layer_Fullscreen, /*!< 6 - fullscreeen windows */
- Layer_Internal /*!< 7 - openbox windows/menus */
+ Layer_Desktop, /*!< 0 - desktop windows */
+ Layer_Below, /*!< 1 - normal windows w/ below */
+ Layer_Normal, /*!< 2 - normal windows */
+ Layer_Above, /*!< 3 - normal windows w/ above */
+ Layer_Top, /*!< 4 - always-on-top-windows (docks?) */
+ Layer_Fullscreen, /*!< 5 - fullscreeen windows */
+ Layer_Internal /*!< 6 - openbox windows/menus */
} StackLayer;
-/* list of Client*s in stacking order from highest to lowest */
+/* list of ObWindow*s in stacking order from highest to lowest */
extern GList *stacking_list;
-void stacking_startup();
-void stacking_shutdown();
-
-/*! Sets the client stacking list on the root window from the
- stacking_clientlist */
+/*! Sets the window stacking list on the root window from the
+ stacking_list */
void stacking_set_list();
-/*! Raises a client window above all others in its stacking layer
+#define stacking_add(win) stacking_list = g_list_append(stacking_list, win);
+#define stacking_remove(win) stacking_list = g_list_remove(stacking_list, win);
+
+/*! Raises a window above all others in its stacking layer
raiseWindow has a couple of constraints that lowerWindow does not.<br>
- 1) raiseWindow can be called after changing a Client's stack layer, and
+ 1) raiseWindow can be called after changing a Window's stack layer, and
the list will be reorganized properly.<br>
2) raiseWindow guarantees that XRestackWindows() will <i>always</i> be
- called for the specified client.
+ called for the specified window.
*/
-void stacking_raise(struct Client *client);
+void stacking_raise(ObWindow *window);
/*! Lowers a client window below all others in its stacking layer */
-void stacking_lower(struct Client *client);
-
-/*! Raises an internal window (e.g. menus) */
-void stacking_raise_internal(Window win);
+void stacking_lower(ObWindow *window);
#endif
--- /dev/null
+#include "window.h"
+#include "menu.h"
+#include "slit.h"
+#include "client.h"
+#include "frame.h"
+
+Window window_top(ObWindow *self)
+{
+ switch (self->type) {
+ case Window_Menu:
+ return ((Menu*)self)->frame;
+ case Window_Slit:
+ return ((Slit*)self)->frame;
+ case Window_Client:
+ return ((Client*)self)->frame->window;
+ }
+ g_assert_not_reached();
+ return None;
+}
+
+Window window_layer(ObWindow *self)
+{
+ switch (self->type) {
+ case Window_Menu:
+ return Layer_Internal;
+ case Window_Slit:
+ return ((Slit*)self)->layer;
+ case Window_Client:
+ return ((Client*)self)->layer;
+ }
+ g_assert_not_reached();
+ return None;
+}
--- /dev/null
+#ifndef __window_h
+#define __window_h
+
+#include <X11/Xlib.h>
+
+typedef enum {
+ Window_Menu,
+ Window_Slit,
+ Window_Client
+} Window_InternalType;
+
+typedef struct ObWindow {
+ Window_InternalType type;
+} ObWindow;
+
+#define WINDOW_IS_MENU(win) (((ObWindow*)win)->type == Window_Menu)
+#define WINDOW_IS_SLIT(win) (((ObWindow*)win)->type == Window_Slit)
+#define WINDOW_IS_CLIENT(win) (((ObWindow*)win)->type == Window_Client)
+
+struct Menu;
+struct Slit;
+struct Client;
+
+#define WINDOW_AS_MENU(win) ((struct Menu*)win)
+#define WINDOW_AS_SLIT(win) ((struct Slit*)win)
+#define WINDOW_AS_CLIENT(win) ((struct Client*)win)
+
+#define MENU_AS_WINDOW(menu) ((ObWindow*)menu)
+#define SLIT_AS_WINDOW(slit) ((ObWindow*)slit)
+#define CLIENT_AS_WINDOW(client) ((ObWindow*)client)
+
+Window window_top(ObWindow *self);
+Window window_layer(ObWindow *self);
+
+#endif
Client *target;
int tl, tt, tr, tb; /* 1 past the target's edges on each side */
+ if (!WINDOW_IS_CLIENT(it->data))
+ continue;
target = it->data;
/* don't snap to self or non-visibles */
if (!target->frame->visible || target == c) continue;