static void client_get_startup_id(ObClient *self);
static void client_get_session_ids(ObClient *self);
static void client_save_app_rule_values(ObClient *self);
-static void client_get_area(ObClient *self);
+static gboolean client_get_area(ObClient *self);
static void client_get_desktop(ObClient *self);
static void client_get_state(ObClient *self);
static void client_get_shaped(ObClient *self);
ob_debug("Managing window: 0x%lx", window);
- /* choose the events we want to receive on the CLIENT window
- (ObPrompt windows can request events too) */
- attrib_set.event_mask = CLIENT_EVENTMASK |
- (prompt ? prompt->event_mask : 0);
- attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
- XChangeWindowAttributes(obt_display, window,
- CWEventMask|CWDontPropagate, &attrib_set);
-
/* create the ObClient struct, and populate it from the hints on the
window */
self = window_new(OB_WINDOW_CLASS_CLIENT, ObClient);
self->gravity = NorthWestGravity;
self->desktop = screen_num_desktops; /* always an invalid value */
+ /* this is needed for the frame to set itself up */
+ if (!client_get_area(self)) {
+ ob_debug("Failed to manage window %lx, could not get area", window);
+ window_free(CLIENT_AS_WINDOW(self));
+ return;
+ }
+
+ /* choose the events we want to receive on the CLIENT window
+ (ObPrompt windows can request events too) */
+ attrib_set.event_mask = CLIENT_EVENTMASK |
+ (prompt ? prompt->event_mask : 0);
+ attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
+ XChangeWindowAttributes(obt_display, window,
+ CWEventMask|CWDontPropagate, &attrib_set);
+
/* get all the stuff off the window */
client_get_all(self, TRUE);
self = window_new(OB_WINDOW_CLASS_CLIENT, ObClient);
self->window = window;
+ /* this is needed for the frame to set itself up */
+ if (!client_get_area(self)) {
+ ob_debug("Failed to manage window %lx, could not get area", window);
+ window_free(CLIENT_AS_WINDOW(self));
+ return NULL;
+ }
+
client_get_all(self, FALSE);
/* per-app settings override stuff, and return the settings for other
uses too. this returns a shallow copy that needs to be freed */
self->kill_prompt = NULL;
client_list = g_list_remove(client_list, self);
- stacking_remove(self);
+ stacking_remove(CLIENT_AS_WINDOW(self));
window_remove(self->window);
/* once the client is out of the list, update the struts to remove its
static void client_get_all(ObClient *self, gboolean real)
{
- /* this is needed for the frame to set itself up */
- client_get_area(self);
-
/* these things can change the decor and functions of the window */
client_get_mwm_hints(self);
NET_STARTUP_ID, utf8, &self->startup_id);
}
-static void client_get_area(ObClient *self)
+static gboolean client_get_area(ObClient *self)
{
XWindowAttributes wattrib;
- Status ret;
- ret = XGetWindowAttributes(obt_display, self->window, &wattrib);
- g_assert(ret != BadWindow);
+ if (!XGetWindowAttributes(obt_display, self->window, &wattrib))
+ return FALSE;
RECT_SET(self->area, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
POINT_SET(self->root_pos, wattrib.x, wattrib.y);
ob_debug("client area: %d,%d %dx%d bw %d", wattrib.x, wattrib.y,
wattrib.width, wattrib.height, wattrib.border_width);
+ return TRUE;
}
static void client_get_desktop(ObClient *self)
/*! Turn composite redirection off for a window */
static void composite_window_unredir(struct _ObWindow *w);
-static GLXContext composite_ctx = NULL;
+static GLXContext composite_ctx = NULL;
static ObCompositeFBConfig pixmap_config[MAX_DEPTH + 1]; /* depth is index */
-static gboolean composite_enabled = FALSE;
-static guint composite_idle_source = 0;
-static gboolean need_redraw = FALSE;
-static gboolean animating = FALSE;
-static Window composite_support_win = None;
+static gboolean composite_enabled = FALSE;
+static guint composite_idle_source = 0;
+static gboolean need_redraw = FALSE;
+static gboolean animating = FALSE;
+static Window composite_support_win = None;
#ifdef DEBUG
static gboolean composite_started = FALSE;
#endif
g_assert(composite_support_win == None);
attrib.override_redirect = TRUE;
- composite_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
+ composite_support_win = XCreateWindow(obt_display, screen_support_win,
-100, -100, 1, 1, 0,
CopyFromParent, InputOnly,
CopyFromParent,
g_free(astr);
cm_owner = XGetSelectionOwner(obt_display, composite_cm_atom);
- if (cm_owner != None) return FALSE;
+ if (cm_owner != None) {
+ XDestroyWindow(obt_display, composite_support_win);
+ composite_support_win = None;
+ return FALSE;
+ }
timestamp = event_time();
XSetSelectionOwner(obt_display, composite_cm_atom, composite_support_win,
timestamp);
cm_owner = XGetSelectionOwner(obt_display, composite_cm_atom);
- if (cm_owner != composite_support_win) return FALSE;
+ if (cm_owner != composite_support_win) {
+ XDestroyWindow(obt_display, composite_support_win);
+ composite_support_win = None;
+ return FALSE;
+ }
/* Send client message indicating that we are now the CM */
obt_prop_message(ob_screen, obt_root(ob_screen), OBT_PROP_ATOM(MANAGER),
static gboolean composite(gpointer data)
{
struct timeval start, end, dif;
- GList *it;
ObWindow *win;
ObClient *client;
+ ObStackingIter *it;
if (!composite_enabled) {
composite_idle_source = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-/* XXX for (it = stacking_list_last; it; it = g_list_previous(it)) { */
- for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
+ it = stacking_iter_tail();
+ for (; (win = stacking_iter_win(it)); stacking_iter_prev(it)) {
gint d, x, y, w, h;
- win = it->data;
- if (win->type == OB_WINDOW_CLASS_PROMPT)
- continue;
-
if (!win->mapped || !win->is_redir)
continue;
if (obt_display_error_occured)
g_assert(0 && "ERROR RELEASING GLX PIXMAP");
}
+ stacking_iter_free(it);
glXSwapBuffers(obt_display, composite_overlay);
glFinish();
XDestroyWindow(obt_display, dock->frame);
RrAppearanceFree(dock->a_frame);
window_remove(dock->frame);
- stacking_remove(dock);
+ stacking_remove(DOCK_AS_WINDOW(dock));
window_free(DOCK_AS_WINDOW(dock));
dock = NULL;
}
static void event_process(const XEvent *e, gpointer data);
static void event_handle_root(XEvent *e);
static gboolean event_handle_menu_input(XEvent *e);
-static gboolean event_handle_window(ObWindow *w, XEvent *e);
+static void event_handle_window(ObWindow *w, XEvent *e);
static void event_handle_menu(ObMenuFrame *frame, XEvent *e);
static gboolean event_handle_prompt(ObPrompt *p, XEvent *e);
static void event_handle_dock(ObDock *s, XEvent *e);
/* deal with it in the kernel */
+ if (obwin) event_handle_window(obwin, e);
+
if (e->type == FocusIn) {
print_focusevent(e);
if (!wanted_focusevent(e, FALSE)) {
{
obwin = UNMANAGED_AS_WINDOW(unmanaged_new(e->xreparent.window));
}
- else if (obwin && event_handle_window(obwin, e))
- /* handled it ! */;
else if (client)
event_handle_client(client, e);
else if (um)
}
}
-static gboolean event_handle_window(ObWindow *wi, XEvent *e)
+static void event_handle_window(ObWindow *wi, XEvent *e)
{
- gboolean used = FALSE, pixchange = FALSE;
+ gboolean pixchange = FALSE;
gboolean same_window;
- if (wi->type == OB_WINDOW_CLASS_PROMPT) return used;
+ if (wi->type == OB_WINDOW_CLASS_PROMPT) return;
switch (e->type) {
case ConfigureNotify:
h = xe->height;
}
RECT_SET(wi->area, x, y, w, h);
- used = TRUE;
}
/* set the top window's area/border */
XConfigureEvent const *xe = &e->xconfigure;
RECT_SET(wi->toparea, xe->x, xe->y, xe->width, xe->height);
wi->topborder = xe->border_width;
- used = TRUE;
}
+
break;
case MapNotify:
if (e->xmap.window == window_redir(wi)) {
wi->mapped = TRUE;
pixchange = TRUE;
- used = TRUE;
}
break;
case UnmapNotify:
composite_dirty();
if (e->xunmap.window == window_top(wi)) {
wi->mapped = FALSE;
- used = TRUE;
}
break;
default:
composite_dirty();
if (s->window == window_redir(wi) && s->kind == ShapeBounding) {
window_adjust_redir_shape(wi);
- used = FALSE; /* let other people get this event also */
}
}
#endif
{
XDamageNotifyEvent *ev = (XDamageNotifyEvent *)e;
composite_dirty();
- used = TRUE;
}
#endif
}
if (pixchange)
composite_window_invalid(wi);
- return used;
}
static void event_handle_unmanaged(ObUnmanaged *um, XEvent *e)
e->xconfigurerequest.value_mask, &xwc);
obt_display_ignore_errors(FALSE);
break;
+ case ConfigureNotify:
+ /* XXX check if above changed */
+ stacking_unmanaged_above_notify(um, e->xconfigure.above);
}
}
#include "frame.h"
#include "framerender.h"
#include "keyboard.h"
+#include "stacking.h"
#include "mouse.h"
#include "menuframe.h"
#include "grab.h"
/* focus_backup is used for stacking, so this needs to come before
anything that calls stacking_add */
sn_startup(reconfigure);
+ stacking_startup(reconfigure);
window_startup(reconfigure);
composite_startup(reconfigure);
focus_startup(reconfigure);
focus_shutdown(reconfigure);
composite_shutdown(reconfigure);
window_shutdown(reconfigure);
+ stacking_shutdown(reconfigure);
sn_shutdown(reconfigure);
event_shutdown(reconfigure);
config_shutdown();
RrAppearanceFree(self->a_bg);
RrAppearanceFree(self->a_text);
window_remove(self->bg);
- stacking_remove(self);
+ stacking_remove(INTERNAL_AS_WINDOW(self));
window_free(INTERNAL_AS_WINDOW(self));
}
}
Time screen_desktop_user_time = CurrentTime;
Atom screen_wm_sn_atom = None;
+static ObInternalWindow *screen_support_obwin;
static Size screen_physical_size;
static guint screen_old_desktop;
static gboolean screen_desktop_timeout = TRUE;
pid_t pid;
gint i, num_support;
gulong *supported;
+ const Rect r = {-100, -100, 1, 1};
+ const gint b = 0;
/* create the netwm support window */
attrib.override_redirect = TRUE;
attrib.event_mask = PropertyChangeMask;
screen_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
- -100, -100, 1, 1, 0,
- CopyFromParent, InputOnly,
- CopyFromParent,
+ r.x, r.y, r.width, r.height, b, 0,
+ InputOnly, CopyFromParent,
CWEventMask | CWOverrideRedirect,
&attrib);
XMapWindow(obt_display, screen_support_win);
return FALSE;
}
+ screen_support_obwin = window_internal_new(screen_support_win, &r, b, 0);
+ screen_support_obwin->layer = OB_STACKING_LAYER_TOPMOST;
+ stacking_set_topmost(INTERNAL_AS_WINDOW(screen_support_obwin));
+
screen_set_root_cursor();
/* set the OPENBOX_PID hint */
OBT_PROP_ERASE(obt_root(ob_screen), NET_SHOWING_DESKTOP);
XDestroyWindow(obt_display, screen_support_win);
+ stacking_remove(INTERNAL_AS_WINDOW(screen_support_obwin));
+ window_free(INTERNAL_AS_WINDOW(screen_support_obwin));
g_strfreev(screen_desktop_names);
screen_desktop_names = NULL;
#include "frame.h"
#include "window.h"
#include "event.h"
+#include "unmanaged.h"
#include "debug.h"
#include "obt/prop.h"
+/*! A node holding an unmanaged window for the secondary list stacking_ulist */
+typedef struct _ObUNode {
+ ObUnmanaged *um;
+ /*! Points to the node in stacking_list which is the highest window in
+ the list below this window */
+ GList *belowme;
+} ObUNode;
+
+/* A list of managed ObWindow*s in stacking order from highest to lowest */
GList *stacking_list = NULL;
-GList *stacking_list_tail = NULL;
+/*! A list of unmanaged windows in OBUNode objects in stacking order from
+ highest to lowest */
+GList *stacking_ulist = NULL;
+
+static GHashTable *stacking_map = NULL;
+static GHashTable *stacking_umap = NULL;
/*! When true, stacking changes will not be reflected on the screen. This is
to freeze the on-screen stacking order while a window is being temporarily
raised during focus cycling */
static gboolean pause_changes = FALSE;
+static void list_split(GList **l1, GList **l2)
+{
+ if (*l1 == *l2) *l2 = NULL;
+ else if (*l2) {
+ if ((*l2)->prev) (*l2)->prev->next = NULL;
+ (*l2)->prev = NULL;
+ }
+}
+
+static GList* list_insert_link_before(GList *list, GList *before, GList *link)
+{
+ /* split the list at 'before' */
+ if (before) {
+ if (before->prev) before->prev->next = NULL;
+ before->prev = NULL;
+ /* and stick it at the front of the 'before' list */
+ link = g_list_concat(link, before);
+ /* if before is the whole list, then we have replaced the list */
+ if (before == list) list = NULL;
+ }
+ /* append the node and the rest of the list back onto the original list */
+ return g_list_concat(list, link);
+}
+
+void stacking_startup(gboolean reconfig)
+{
+ if (reconfig) return;
+ stacking_map = g_hash_table_new(g_int_hash, g_int_equal);
+ stacking_umap = g_hash_table_new(g_int_hash, g_int_equal);
+}
+
+void stacking_shutdown(gboolean reconfig)
+{
+ if (reconfig) return;
+ g_hash_table_destroy(stacking_map);
+ stacking_map = NULL;
+ g_hash_table_destroy(stacking_umap);
+ stacking_umap = NULL;
+}
+
+void stacking_set_topmost(ObWindow *win)
+{
+ g_assert(win && stacking_list == NULL);
+ g_assert(WINDOW_IS_INTERNAL(win));
+ g_assert(window_layer(win) == OB_STACKING_LAYER_TOPMOST);
+ stacking_list = g_list_prepend(stacking_list, win);
+}
+
void stacking_set_list(void)
{
Window *windows = NULL;
g_assert(wins);
/* pls only restack stuff in the same layer at a time */
for (it = wins; it; it = next) {
- while (it && window_layer(it->data) == OB_STACKING_LAYER_ALL)
- it = g_list_next(it);
next = g_list_next(it);
- while (next && window_layer(next->data) == OB_STACKING_LAYER_ALL)
- next = g_list_next(next);
+ /* and there should be no unmanaged windows in the stacking_list */
+ g_assert(!WINDOW_IS_UNMANAGED(it->data));
if (!next) break;
g_assert (window_layer(it->data) == window_layer(next->data));
}
win = g_new(Window, g_list_length(wins) + 1);
- if (before == stacking_list)
- win[0] = screen_support_win;
- else if (!before)
+ g_assert(before != stacking_list);
+
+ if (!before)
win[0] = window_top(g_list_last(stacking_list)->data);
else
win[0] = window_top(g_list_previous(before)->data);
for (i = 1, it = wins; it; ++i, it = g_list_next(it)) {
win[i] = window_top(it->data);
- g_assert(win[i] != None); /* better not call stacking shit before
- setting your top level window value */
- stacking_list = g_list_insert_before(stacking_list, before, it->data);
+ /* don't call stacking shit before setting your top level window */
+ g_assert(win[i] != None);
}
+ list_split(&stacking_list, &before);
+ stacking_list = g_list_concat(stacking_list, g_list_concat(wins, before));
+
#ifdef DEBUG
/* some debug checking of the stacking list's order */
for (it = stacking_list; ; it = next) {
- while (it && window_layer(it->data) == OB_STACKING_LAYER_ALL)
- it = g_list_next(it);
next = g_list_next(it);
- while (next && window_layer(next->data) == OB_STACKING_LAYER_ALL)
- next = g_list_next(next);
+ g_assert(window_layer(it->data) != OB_STACKING_LAYER_INVALID);
if (!next) break;
g_assert(window_layer(it->data) >= window_layer(next->data));
}
gulong start;
win = g_new(Window, g_list_length(stacking_list) + 1);
- win[0] = screen_support_win;
- for (i = 1, it = stacking_list; it; ++i, it = g_list_next(it))
+ for (i = 0, it = stacking_list; it; ++i, it = g_list_next(it))
win[i] = window_top(it->data);
start = event_start_ignore_all_enters();
XRestackWindows(obt_display, win, i);
static void do_raise(GList *wins)
{
- GList *it;
+ GList *it, *next;
GList *layer[OB_NUM_STACKING_LAYERS] = {NULL};
gint i;
- for (it = wins; it; it = g_list_next(it)) {
- ObStackingLayer l;
+ for (it = wins; it; it = next) {
+ const ObStackingLayer l = window_layer(it->data);
- l = window_layer(it->data);
- layer[l] = g_list_append(layer[l], it->data);
+ next = g_list_next(it);
+ wins = g_list_remove_link(wins, it); /* remove it from wins */
+ layer[l] = g_list_concat(layer[l], it); /* stick it in the layer */
}
it = stacking_list;
break;
}
do_restack(layer[i], it);
- g_list_free(layer[i]);
}
}
}
static void do_lower(GList *wins)
{
- GList *it;
+ GList *it, *next;
GList *layer[OB_NUM_STACKING_LAYERS] = {NULL};
gint i;
- for (it = wins; it; it = g_list_next(it)) {
- ObStackingLayer l;
+ for (it = wins; it; it = next) {
+ const ObStackingLayer l = window_layer(it->data);
- l = window_layer(it->data);
- layer[l] = g_list_append(layer[l], it->data);
+ next = g_list_next(it);
+ wins = g_list_remove_link(wins, it); /* remove it from wins */
+ layer[l] = g_list_concat(layer[l], it); /* stick it in the layer */
}
it = stacking_list;
break;
}
do_restack(layer[i], it);
- g_list_free(layer[i]);
}
}
}
static void restack_windows(ObClient *selected, gboolean raise)
{
- GList *it, *last, *below, *above, *next;
+ GList *it, *last, *below, *above, *next, *selit;
GList *wins = NULL;
GList *group_helpers = NULL;
}
/* remove first so we can't run into ourself */
- it = g_list_find(stacking_list, selected);
- g_assert(it);
- stacking_list = g_list_delete_link(stacking_list, it);
+ selit = g_list_find(stacking_list, selected);
+ g_assert(selit);
+ stacking_list = g_list_remove_link(stacking_list, selit);
/* go from the bottom of the stacking list up. don't move any other windows
when lowering, we call this for each window independently */
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *ch = it->data;
+ GList **addto = NULL;
/* only move windows in the same stacking layer */
if (ch->layer == selected->layer &&
{
if (client_is_direct_child(selected, ch)) {
if (ch->modal)
- modals = g_list_prepend(modals, ch);
+ addto = &modals;
else
- trans = g_list_prepend(trans, ch);
+ addto = &trans;
}
else if (client_helper(ch)) {
if (selected->transient) {
/* helpers do not stay above transient windows */
continue;
}
- group_helpers = g_list_prepend(group_helpers, ch);
+ addto = &group_helpers;
}
else {
if (ch->modal)
- group_modals = g_list_prepend(group_modals, ch);
+ addto = &group_modals;
else
- group_trans = g_list_prepend(group_trans, ch);
+ addto = &group_trans;
}
- stacking_list = g_list_delete_link(stacking_list, it);
+ g_assert(addto != NULL);
+ /* move it from the stacking list onto the front of the
+ list pointed at by addto */
+ stacking_list = g_list_remove_link(stacking_list, it);
+ *addto = g_list_concat(it, *addto);
}
}
}
wins = g_list_concat(wins, group_helpers);
/* put the selected window right below these children */
- wins = g_list_append(wins, selected);
+ wins = g_list_concat(wins, selit);
/* if selected window is transient for group then raise it above others */
if (selected->transient_for_group) {
wins = g_list_concat(group_modals, wins);
do_restack(wins, below);
- g_list_free(wins);
/* lower our parents after us, so they go below us */
if (!raise && selected->parents) {
selected = WINDOW_AS_CLIENT(window);
restack_windows(selected, TRUE);
} else {
- GList *wins;
- wins = g_list_append(NULL, window);
- stacking_list = g_list_remove(stacking_list, window);
- do_raise(wins);
- g_list_free(wins);
+ GList *selit = g_list_find(stacking_list, window);
+ stacking_list = g_list_remove_link(stacking_list, selit);
+ do_raise(selit);
}
- stacking_list_tail = g_list_last(stacking_list);
}
void stacking_lower(ObWindow *window)
selected = WINDOW_AS_CLIENT(window);
restack_windows(selected, FALSE);
} else {
- GList *wins;
- wins = g_list_append(NULL, window);
- stacking_list = g_list_remove(stacking_list, window);
- do_lower(wins);
- g_list_free(wins);
+ GList *selit = g_list_find(stacking_list, window);
+ stacking_list = g_list_remove_link(stacking_list, selit);
+ do_lower(selit);
}
- stacking_list_tail = g_list_last(stacking_list);
}
void stacking_below(ObWindow *window, ObWindow *below)
{
- GList *wins, *before;
+ GList *selit, *before;
if (window_layer(window) != window_layer(below))
return;
- wins = g_list_append(NULL, window);
- stacking_list = g_list_remove(stacking_list, window);
+ selit = g_list_find(stacking_list, window);
+ stacking_list = g_list_remove_link(stacking_list, selit);
before = g_list_next(g_list_find(stacking_list, below));
- do_restack(wins, before);
- g_list_free(wins);
- stacking_list_tail = g_list_last(stacking_list);
+ do_restack(selit, before);
}
void stacking_add(ObWindow *win)
{
- g_assert(screen_support_win != None); /* make sure I dont break this in the
- future */
+ /* the topmost window should already be present */
+ g_assert(stacking_list != NULL);
+
/* don't add windows that are being unmanaged ! */
if (WINDOW_IS_CLIENT(win)) g_assert(WINDOW_AS_CLIENT(win)->managed);
- if (WINDOW_IS_UNMANAGED(win))
- stacking_list = g_list_prepend(stacking_list, win);
+ if (WINDOW_IS_UNMANAGED(win)) {
+ ObUNode *n = g_slice_new(ObUNode);
+ n->um = WINDOW_AS_UNMANAGED(win);
+ n->belowme = stacking_list;
+ stacking_ulist = g_list_prepend(stacking_ulist, n);
+ g_hash_table_insert(stacking_umap, &window_top(win), stacking_ulist);
+ }
else {
- stacking_list = g_list_append(stacking_list, win);
+ GList *newit = g_list_append(NULL, win);
+ stacking_list = g_list_concat(stacking_list, newit);
stacking_raise(win);
- /* stacking_list_tail set by stacking_raise() */
+ g_hash_table_insert(stacking_map, &window_top(win), newit);
+ }
+}
+
+void stacking_remove(ObWindow *win)
+{
+ if (WINDOW_IS_UNMANAGED(win)) {
+ GList *it;
+ for (it = stacking_ulist; it; it = g_list_next(it)) {
+ ObUNode *n = it->data;
+ if (n->um == WINDOW_AS_UNMANAGED(win)) {
+ stacking_ulist = g_list_delete_link(stacking_ulist, it);
+ g_slice_free(ObUNode, n);
+ break;
+ }
+ }
+ g_hash_table_remove(stacking_umap, &window_top(win));
+ }
+ else {
+ stacking_list = g_list_remove(stacking_list, win);
+ g_hash_table_remove(stacking_map, &window_top(win));
}
}
ObClient *client;
GList *it_below = NULL; /* this client will be below us */
GList *it_above;
- GList *wins;
+ GList *newit;
if (!WINDOW_IS_CLIENT(win)) {
stacking_add(win); /* no special rules for others */
break;
}
- wins = g_list_append(NULL, win);
- do_restack(wins, it_below);
- g_list_free(wins);
- stacking_list_tail = g_list_last(stacking_list);
+ newit = g_list_append(NULL, win);
+ do_restack(newit, it_below);
+ g_hash_table_insert(stacking_map, &window_top(win), newit);
}
/*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
}
return ret;
}
+
+void stacking_unmanaged_above_notify(ObUnmanaged *win, Window above)
+{
+ GList *aboveit, *winit, *uit, *mit;
+ ObUNode *un, *an;
+
+ g_assert(WINDOW_IS_UNMANAGED(win));
+
+ winit = g_hash_table_lookup(stacking_umap, &window_top(win));
+
+ if (!above) {
+ /* at the very bottom of the stacking order */
+ stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+ stacking_ulist = list_insert_link_before(stacking_ulist, NULL, winit);
+ un = winit->data;
+ un->belowme = NULL;
+ }
+ else if ((aboveit = g_hash_table_lookup(stacking_map, &above))) {
+ /* directly above a managed window, so put it at the bottom of
+ any siblings which are also above it */
+
+ stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+ un = winit->data;
+ un->belowme = aboveit;
+
+ /* go through the managed windows in the stacking list from top to
+ bottom.
+ follow along in the list of unmanaged windows, until we come to the
+ managed window @winit is now above. then keep moving through the
+ unmanaged windows until we find something above a different
+ managed window, and insert @winit into the unmanaged list before it.
+ */
+ mit = stacking_list;
+ uit = stacking_ulist;
+ for (; mit; mit = g_list_next(mit)) {
+ /* skip thru the unmanged windows above 'mit' */
+ while (uit && ((ObUNode*)uit->data)->belowme == mit)
+ uit = g_list_next(uit);
+ if (mit == aboveit) {
+ /* @win is above 'mit', so stick it in the unmanaged list
+ before 'uit' (the first window above something lower in the
+ managed stacking list */
+ stacking_ulist = list_insert_link_before(stacking_ulist,
+ uit, winit);
+ break; /* done */
+ }
+ }
+ }
+ else if ((aboveit = g_hash_table_lookup(stacking_umap, &above))) {
+ /* directly above another unmanaged window, put it in that position
+ in the stacking_ulist */
+
+ stacking_ulist = g_list_remove_link(stacking_ulist, winit);
+ stacking_ulist = list_insert_link_before(stacking_ulist,
+ aboveit, winit);
+ /* we share the same neighbour in stacking_list */
+ un = winit->data;
+ an = aboveit->data;
+ un->belowme = an->belowme;
+ }
+}
+
+struct _ObStackingIter {
+ GList *mit, *uit, *mitprev, *uitprev;
+};
+
+ObStackingIter* stacking_iter_head(void)
+{
+ ObStackingIter *it = g_slice_new(ObStackingIter);
+ it->mit = stacking_list;
+ it->mitprev = NULL;
+ it->uit = stacking_ulist;
+ it->uitprev = NULL;
+ return it;
+}
+
+ObStackingIter* stacking_iter_tail(void)
+{
+ ObStackingIter *it = g_slice_new(ObStackingIter);
+ it->uit = g_list_last(stacking_ulist);
+ if (it->uit && ((ObUNode*)it->uit->data)->belowme == NULL) {
+ /* it is below all managed windows */
+ it->uitprev = g_list_previous(it->uit);
+ it->mit = NULL;
+ it->mitprev = g_list_last(stacking_list);
+ }
+ else {
+ /* it is above some managed window */
+ it->uitprev = it->uit;
+ it->uit = NULL;
+ it->mit = g_list_last(stacking_list);
+ it->mitprev = it->mit ? g_list_previous(it->mit) : NULL;
+ }
+ return it;
+}
+
+/*! Returns 1 if it->mit is the current, and 2 if it->uit is. */
+static gint stacking_iter_current(ObStackingIter *it)
+{
+ if (!it->uit)
+ return 1;
+ else {
+ ObUNode *un = it->uit->data;
+ if (un->belowme == it->mit) return 2;
+ else return 1;
+ }
+}
+
+void stacking_iter_next(ObStackingIter *it)
+{
+ g_assert(it->mit || it->uit); /* went past the end of the list */
+
+ if (!it->uit) it->mit = g_list_next(it->mit);
+ else {
+ gint at = stacking_iter_current(it);
+ if (at == 1) {
+ it->mitprev = it->mit;
+ it->mit = g_list_next(it->mit);
+ }
+ else {
+ it->uitprev = it->uit;
+ it->uit = g_list_next(it->uit);
+ }
+ }
+}
+
+void stacking_iter_prev(ObStackingIter *it)
+{
+ g_assert(it->mit || it->uit); /* went past the end of the list */
+
+ /* if the prev unmanged points at the managed, it should be the
+ previous position */
+ if (it->uitprev && ((ObUNode*)it->uitprev->data)->belowme == it->mit) {
+ it->uit = it->uitprev;
+ it->uitprev = g_list_previous(it->uitprev);
+ }
+ else {
+ it->mit = it->mitprev;
+ if (it->mitprev) it->mitprev = g_list_previous(it->mitprev);
+ if (!it->mit) it->uit = NULL;
+ }
+}
+
+ObWindow* stacking_iter_win(ObStackingIter *it)
+{
+ gint at;
+
+ if (!it->mit && !it->uit) return NULL;
+
+ at = stacking_iter_current(it);
+ if (at == 1) return it->mit->data; /* list of ObWindow */
+ else return UNMANAGED_AS_WINDOW(((ObUNode*)it->uit->data)->um);
+}
+
+void stacking_iter_free(ObStackingIter *it)
+{
+ g_slice_free(ObStackingIter, it);
+}
struct _ObWindow;
struct _ObClient;
+struct _ObUnmanaged;
+
+typedef struct _ObStackingIter ObStackingIter;
/*! The possible stacking layers a client window can be a part of */
typedef enum {
OB_STACKING_LAYER_INVALID,
- OB_STACKING_LAYER_DESKTOP, /*!< 0 - desktop windows */
- OB_STACKING_LAYER_BELOW, /*!< 1 - normal windows w/ below */
- OB_STACKING_LAYER_NORMAL, /*!< 2 - normal windows */
- OB_STACKING_LAYER_ABOVE, /*!< 3 - normal windows w/ above */
- OB_STACKING_LAYER_FULLSCREEN, /*!< 4 - fullscreeen windows */
- OB_STACKING_LAYER_INTERNAL, /*!< 5 - openbox windows/menus */
+ OB_STACKING_LAYER_DESKTOP, /*!< 1 - desktop windows */
+ OB_STACKING_LAYER_BELOW, /*!< 2 - normal windows w/ below */
+ OB_STACKING_LAYER_NORMAL, /*!< 3 - normal windows */
+ OB_STACKING_LAYER_ABOVE, /*!< 4 - normal windows w/ above */
+ OB_STACKING_LAYER_FULLSCREEN, /*!< 5 - fullscreeen windows */
+ OB_STACKING_LAYER_INTERNAL, /*!< 6 - openbox windows/menus */
+ OB_STACKING_LAYER_TOPMOST, /*!< 7 - topmost window */
OB_NUM_STACKING_LAYERS,
- OB_STACKING_LAYER_ALL = 0xffffffff /*!< 0xffffffff - unmamnaged windows */
} ObStackingLayer;
-/* list of ObWindow*s in stacking order from highest to lowest */
extern GList *stacking_list;
/* list of ObWindow*s in stacking order from lowest to highest */
extern GList *stacking_list_tail;
+void stacking_startup(gboolean reconfig);
+void stacking_shutdown(gboolean reconfig);
+
+void stacking_set_topmost(struct _ObWindow *win);
+
/*! Sets the window stacking list on the root window from the
stacking_list */
void stacking_set_list(void);
void stacking_add(struct _ObWindow *win);
void stacking_add_nonintrusive(struct _ObWindow *win);
-#define stacking_remove(win) stacking_list = g_list_remove(stacking_list, win);
+void stacking_remove(struct _ObWindow *win);
/*! Raises a window above all others in its stacking layer */
void stacking_raise(struct _ObWindow *window);
struct _ObClient *sibling,
gint detail);
+void stacking_unmanaged_above_notify(struct _ObUnmanaged *win, Window above);
+
+ObStackingIter* stacking_iter_head(void);
+ObStackingIter* stacking_iter_tail(void);
+void stacking_iter_next(ObStackingIter *it);
+void stacking_iter_prev(ObStackingIter *it);
+struct _ObWindow* stacking_iter_win(ObStackingIter *it);
+void stacking_iter_free(ObStackingIter *it);
+
#endif
ObStackingLayer layer;
gint depth;
guint32 alpha;
+ gboolean output;
};
static GSList *unmanaged_list = NULL;
if (w == composite_overlay)
return NULL;
if (!XGetWindowAttributes(obt_display, w, &at))
- return NULL;
- if (at.class == InputOnly)
return NULL;
self = window_new(OB_WINDOW_CLASS_UNMANAGED, ObUnmanaged);
self->window = w;
- self->layer = OB_STACKING_LAYER_ALL;
+ self->layer = OB_STACKING_LAYER_INVALID;
self->depth = at.depth;
self->alpha = 0xffffffff;
+ self->output = at.class != InputOnly;
+
+ self->super.mapped = at.map_state != IsUnmapped;
XSelectInput(obt_display, self->window, PropertyChangeMask);
#ifdef SHAPE
XShapeSelectInput(obt_display, self->window, ShapeNotifyMask);
#endif
- unmanaged_update_opacity(self);
+ if (self->output) unmanaged_update_opacity(self);
RECT_SET(r, at.x, at.y, at.width, at.height);
window_set_top_area(UNMANAGED_AS_WINDOW(self), &r, at.border_width);
window_set_abstract(UNMANAGED_AS_WINDOW(self),
&self->window,
- &self->window,
+ (self->output ? &self->window : NULL),
&self->layer,
&self->depth,
&self->alpha);
void unmanaged_destroy_all(void);
void unmanaged_update_opacity(ObUnmanaged *self);
+gboolean unmanaged_output(ObUnmanaged *self);
#endif
#ifdef SHAPE
#ifdef USE_COMPOSITING
- {
+ if (window_redir(self)) {
gint foo;
guint ufoo;
gint s;
#endif
#endif
- composite_window_setup(self);
+ if (window_redir(self))
+ composite_window_setup(self);
}
void window_set_top_area(ObWindow *self, const Rect *r, gint border)
void window_cleanup(ObWindow *self)
{
- composite_window_cleanup(self);
+ if (window_redir(self))
+ composite_window_cleanup(self);
}
void window_free(ObWindow *self)
self->depth = depth;
window_set_top_area(INTERNAL_AS_WINDOW(self), area, border);
window_set_abstract(INTERNAL_AS_WINDOW(self),
- &self->window, /* top-most window */
- &self->window, /* composite redir window */
- &self->layer, /* stacking layer */
- &self->depth, /* window depth */
- NULL); /* opacity */
+ &self->window, /* top-most window */
+ (depth ? &self->window : NULL), /* comp redir window */
+ &self->layer, /* stacking layer */
+ &self->depth, /* window depth */
+ NULL); /* opacity */
return self;
}
for (i = 0; i < nchild; ++i) {
if (children[i] == None) continue;
if (window_find(children[i])) continue; /* skip our own windows */
- if (XGetWindowAttributes(obt_display, children[i], &attrib)) {
- if (attrib.map_state == IsUnmapped)
- unmanaged_new(children[i]);
- else
- window_manage(children[i]);
- }
+ if (!XGetWindowAttributes(obt_display, children[i], &attrib)) continue;
+ if (attrib.map_state == IsUnmapped || attrib.override_redirect)
+ unmanaged_new(children[i]);
+ else
+ window_manage(children[i]);
}
if (children) XFree(children);
}
-static gboolean check_unmap(XEvent *e, gpointer data)
-{
- const Window win = *(Window*)data;
- return ((e->type == DestroyNotify && e->xdestroywindow.window == win) ||
- (e->type == UnmapNotify && e->xunmap.window == win));
-}
-
void window_manage(Window win)
{
- XWindowAttributes attrib;
- gboolean no_manage = FALSE;
gboolean is_dockapp = FALSE;
Window icon_win = None;
+ XWMHints *wmhints;
- grab_server(TRUE);
-
- /* check if it has already been unmapped by the time we started
- mapping. the grab does a sync so we don't have to here */
- if (xqueue_exists_local(check_unmap, &win)) {
- ob_debug("Trying to manage unmapped window. Aborting that.");
- no_manage = TRUE;
- }
- else if (!XGetWindowAttributes(obt_display, win, &attrib))
- no_manage = TRUE;
- else {
- XWMHints *wmhints;
-
- /* is the window a docking app */
- is_dockapp = FALSE;
- if ((wmhints = XGetWMHints(obt_display, win))) {
- if ((wmhints->flags & StateHint) &&
- wmhints->initial_state == WithdrawnState)
- {
- if (wmhints->flags & IconWindowHint)
- icon_win = wmhints->icon_window;
- is_dockapp = TRUE;
- }
- XFree(wmhints);
+ /* is the window a docking app */
+ is_dockapp = FALSE;
+ if ((wmhints = XGetWMHints(obt_display, win))) {
+ if ((wmhints->flags & StateHint) &&
+ wmhints->initial_state == WithdrawnState)
+ {
+ if (wmhints->flags & IconWindowHint)
+ icon_win = wmhints->icon_window;
+ is_dockapp = TRUE;
}
+ XFree(wmhints);
}
- if (!no_manage) {
- if (attrib.override_redirect) {
- ob_debug("not managing override redirect window 0x%x", win);
- grab_server(FALSE);
- }
- else if (is_dockapp) {
- if (!icon_win)
- icon_win = win;
- dock_manage(icon_win, win);
- }
- else
- client_manage(win, NULL);
- }
- else {
- grab_server(FALSE);
- ob_debug("FAILED to manage window 0x%x", win);
+ grab_server(TRUE);
+
+ if (is_dockapp) {
+ if (!icon_win)
+ icon_win = win;
+ dock_manage(icon_win, win);
}
+ else
+ client_manage(win, NULL);
}
void window_unmanage_all(void)
void window_foreach(ObWindowForeachFunc func);
#define window_top(w) (*((ObWindow*)w)->top)
-#define window_redir(w) (*((ObWindow*)w)->redir)
+#define window_redir(w) (((ObWindow*)w)->redir ? *((ObWindow*)w)->redir : None)
#define window_layer(w) (*((ObWindow*)w)->layer)
#define window_area(w) (*((ObWindow*)w)->area)
#define window_depth(w) (*((ObWindow*)w)->depth)