rename "Slit" to "Dock".

add config options to the rc3 for the dock.
create a window_map, add DockApps to the ObWindow types, use the window_map for translating windows into objects for event handling (only one lookup now) and remove the old maps (client_map, menu_map).
This commit is contained in:
Dana Jansens 2003-05-16 18:10:10 +00:00
parent 6e42b65bda
commit b77e40e1c7
18 changed files with 744 additions and 608 deletions

View file

@ -53,6 +53,39 @@ names = ("one" "two" "three" "four")
# the theme to display
#theme = "operation"
[dock]
# The position on the screen to place the dock. Options are:
# Floating - uses the floatingX and floatingY options to position itself
# TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left
# - the appropriate corner/edge of the screen
#position = "TopLeft"
# When position is "Floating", this specifies the x-coordinate to place the
# the dock at.
#floatingx = 0
# When position is "Floating", this specifies the y-coordinate to place the
# the dock at.
#floatingy = 0
# The stacking layer that the dock will be in. Options are:
# Top - above all normal windows, same layer as panels
# Normal - can be above and below normal windows
# Bottom - below all normal windows
#stacking = "Top"
# When true, the dock will grow horizontally when dock apps are added to it,
# otherwise it will grow vertically.
#horizontal = no
# When true, the dock will hide itself while the pointer is not over it, and
# will show itself when the pointer is.
#autoHide = no
# The number of milliseconds to wait before hiding the dock when the pointer
# leaves it, if the autoHide option is on.
#hideTimeout = 3000
[keyboard]
#kbind (Key [Key...]) Action [Parameter]

View file

@ -26,13 +26,13 @@ openbox3_SOURCES=parse.tab.c parse.lex.c action.c client.c config.c \
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 window.c
moveresize.c startup.c popup.c dock.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 window.h
dock.h window.h
# kill the implicit .c.y rule
%.c: %.y

View file

@ -1,5 +1,5 @@
#include "client.h"
#include "slit.h"
#include "dock.h"
#include "startup.h"
#include "screen.h"
#include "moveresize.h"
@ -26,7 +26,6 @@
ButtonMotionMask)
GList *client_list = NULL;
GHashTable *client_map = NULL;
static void client_get_all(Client *self);
static void client_toggle_border(Client *self, gboolean show);
@ -41,20 +40,13 @@ static void client_change_allowed_actions(Client *self);
static void client_change_state(Client *self);
static void client_apply_startup_state(Client *self);
static guint map_hash(Window *w) { return *w; }
static gboolean map_key_comp(Window *w1, Window *w2) { return *w1 == *w2; }
void client_startup()
{
client_map = g_hash_table_new((GHashFunc)map_hash,
(GEqualFunc)map_key_comp);
client_set_list();
}
void client_shutdown()
{
g_hash_table_destroy(client_map);
}
void client_set_list()
@ -117,7 +109,6 @@ void client_manage_all()
Window w, *children;
XWMHints *wmhints;
XWindowAttributes attrib;
Client *active;
XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild);
@ -154,19 +145,28 @@ void client_manage_all()
stacking list are on the top where you can see them instead of buried
at the bottom! */
for (i = startup_stack_size; i > 0; --i) {
Client *c;
ObWindow *obw;
w = startup_stack_order[i-1];
c = g_hash_table_lookup(client_map, &w);
if (c) stacking_lower(CLIENT_AS_WINDOW(c));
obw = g_hash_table_lookup(window_map, &w);
if (obw) {
g_assert(WINDOW_IS_CLIENT(obw));
stacking_lower(CLIENT_AS_WINDOW(obw));
}
}
g_free(startup_stack_order);
startup_stack_order = NULL;
startup_stack_size = 0;
if (config_focus_new) {
active = g_hash_table_lookup(client_map, &startup_active);
if (!(active && client_focus(active)))
ObWindow *active;
active = g_hash_table_lookup(window_map, &startup_active);
if (active) {
g_assert(WINDOW_IS_CLIENT(active));
if (!client_focus(WINDOW_AS_CLIENT(active)))
focus_fallback(Fallback_NoFocus);
} else
focus_fallback(Fallback_NoFocus);
}
}
@ -203,7 +203,7 @@ void client_manage(Window window)
if ((wmhint = XGetWMHints(ob_display, window))) {
if ((wmhint->flags & StateHint) &&
wmhint->initial_state == WithdrawnState) {
slit_add(window, wmhint);
dock_add(window, wmhint);
grab_server(FALSE);
XFree(wmhint);
return;
@ -245,7 +245,7 @@ void client_manage(Window window)
/* add to client list/map */
client_list = g_list_append(client_list, self);
g_hash_table_insert(client_map, &self->window, self);
g_hash_table_insert(window_map, &self->window, self);
/* update the focus lists */
focus_order_add_new(self);
@ -330,7 +330,7 @@ void client_unmanage(Client *self)
client_list = g_list_remove(client_list, self);
stacking_remove(self);
g_hash_table_remove(client_map, &self->window);
g_hash_table_remove(window_map, &self->window);
/* update the focus lists */
focus_order_remove(self);
@ -673,9 +673,10 @@ void client_update_transient_for(Client *self)
if (XGetTransientForHint(ob_display, self->window, &t)) {
self->transient = TRUE;
if (t != self->window) { /* cant be transient to itself! */
c = g_hash_table_lookup(client_map, &t);
c = g_hash_table_lookup(window_map, &t);
/* if this happens then we need to check for it*/
g_assert(c != self);
g_assert(!c || WINDOW_IS_CLIENT(c));
if (!c && self->group) {
/* not transient to a client, see if it is transient for a

View file

@ -294,7 +294,6 @@ typedef struct Client {
} Client;
extern GList *client_list;
extern GHashTable *client_map;
void client_startup();
void client_shutdown();

View file

@ -9,12 +9,20 @@ gboolean config_focus_popup;
char *config_theme;
int config_desktops_num;
int config_desktops_num;
GSList *config_desktops_names;
gboolean config_opaque_move;
gboolean config_opaque_resize;
StackLayer config_dock_layer;
DockPosition config_dock_pos;
int config_dock_x;
int config_dock_y;
gboolean config_dock_horz;
gboolean config_dock_hide;
guint config_dock_hide_timeout;
static void parse_focus(char *name, ParseToken *value)
{
if (!g_ascii_strcasecmp(name, "focusnew")) {
@ -118,6 +126,81 @@ static void parse_moveresize(char *name, ParseToken *value)
parse_free_token(value);
}
static void parse_dock(char *name, ParseToken *value)
{
if (!g_ascii_strcasecmp(name, "stacking")) {
if (value->type != TOKEN_STRING)
yyerror("invalid value");
else {
if (!g_ascii_strcasecmp(value->data.string, "bottom"))
config_dock_layer = Layer_Below;
else if (!g_ascii_strcasecmp(value->data.string, "normal"))
config_dock_layer = Layer_Normal;
else if (!g_ascii_strcasecmp(value->data.string, "top"))
config_dock_layer = Layer_Top;
else
yyerror("invalid layer");
}
} else if (!g_ascii_strcasecmp(name, "position")) {
if (value->type != TOKEN_STRING)
yyerror("invalid value");
else {
if (!g_ascii_strcasecmp(value->data.string, "topleft"))
config_dock_pos = DockPos_TopLeft;
else if (!g_ascii_strcasecmp(value->data.string, "top"))
config_dock_pos = DockPos_Top;
else if (!g_ascii_strcasecmp(value->data.string, "topright"))
config_dock_pos = DockPos_TopRight;
else if (!g_ascii_strcasecmp(value->data.string, "right"))
config_dock_pos = DockPos_Right;
else if (!g_ascii_strcasecmp(value->data.string, "bottomright"))
config_dock_pos = DockPos_BottomRight;
else if (!g_ascii_strcasecmp(value->data.string, "bottom"))
config_dock_pos = DockPos_Bottom;
else if (!g_ascii_strcasecmp(value->data.string, "bottomleft"))
config_dock_pos = DockPos_BottomLeft;
else if (!g_ascii_strcasecmp(value->data.string, "left"))
config_dock_pos = DockPos_Left;
else if (!g_ascii_strcasecmp(value->data.string, "floating"))
config_dock_pos = DockPos_Floating;
else
yyerror("invalid position");
}
} else if (!g_ascii_strcasecmp(name, "floatingx")) {
if (value->type != TOKEN_INTEGER)
yyerror("invalid value");
else {
config_dock_x = value->data.integer;
}
} else if (!g_ascii_strcasecmp(name, "floatingy")) {
if (value->type != TOKEN_INTEGER)
yyerror("invalid value");
else {
config_dock_y = value->data.integer;
}
} else if (!g_ascii_strcasecmp(name, "horizontal")) {
if (value->type != TOKEN_BOOL)
yyerror("invalid value");
else {
config_dock_horz = value->data.bool;
}
} else if (!g_ascii_strcasecmp(name, "autohide")) {
if (value->type != TOKEN_BOOL)
yyerror("invalid value");
else {
config_dock_hide = value->data.bool;
}
} else if (!g_ascii_strcasecmp(name, "hidetimeout")) {
if (value->type != TOKEN_INTEGER)
yyerror("invalid value");
else {
config_dock_hide_timeout = value->data.integer;
}
} else
yyerror("invalid option");
parse_free_token(value);
}
void config_startup()
{
config_focus_new = TRUE;
@ -141,6 +224,16 @@ void config_startup()
config_opaque_resize = TRUE;
parse_reg_section("moveresize", NULL, parse_moveresize);
config_dock_layer = Layer_Top;
config_dock_pos = DockPos_TopRight;
config_dock_x = 0;
config_dock_y = 0;
config_dock_horz = FALSE;
config_dock_hide = FALSE;
config_dock_hide_timeout = 3000;
parse_reg_section("dock", NULL, parse_dock);
}
void config_shutdown()

View file

@ -1,6 +1,9 @@
#ifndef __config_h
#define __config_h
#include "dock.h"
#include "stacking.h"
#include <glib.h>
/*! Should new windows be focused */
@ -22,6 +25,23 @@ extern gboolean config_opaque_move;
while they are resize */
extern gboolean config_opaque_resize;
/*! The stacking layer the dock will reside in */
extern StackLayer config_dock_layer;
/*! The position at which to place the dock */
extern DockPosition config_dock_pos;
/*! If config_dock_pos is DockPos_Floating, this is the top-left corner's
position */
extern int config_dock_x;
/*! If config_dock_pos is DockPos_Floating, this is the top-left corner's
position */
extern int config_dock_y;
/*! Whether the dock places the dockapps in it horizontally or vertically */
extern gboolean config_dock_horz;
/*! Whether to auto-hide the dock when the pointer is not over it */
extern gboolean config_dock_hide;
/*! The number of milliseconds to wait before hiding the dock */
extern guint config_dock_hide_timeout;
/* The name of the theme */
char *config_theme;

382
openbox/dock.c Normal file
View file

@ -0,0 +1,382 @@
#include "dock.h"
#include "screen.h"
#include "config.h"
#include "grab.h"
#include "openbox.h"
#include "render/theme.h"
#define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask)
#define DOCKAPP_EVENT_MASK (StructureNotifyMask)
static Dock *dock;
void dock_startup()
{
XSetWindowAttributes attrib;
int i;
dock = g_new0(struct Dock, 1);
dock->obwin.type = Window_Dock;
dock->hidden = TRUE;
attrib.event_mask = DOCK_EVENT_MASK;
attrib.override_redirect = True;
dock->frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
render_depth, InputOutput, render_visual,
CWOverrideRedirect | CWEventMask,
&attrib);
dock->a_frame = appearance_copy(theme_a_unfocused_title);
XSetWindowBorder(ob_display, dock->frame, theme_b_color->pixel);
XSetWindowBorderWidth(ob_display, dock->frame, theme_bwidth);
g_hash_table_insert(window_map, &dock->frame, dock);
stacking_add(DOCK_AS_WINDOW(&dock[i]));
stacking_raise(DOCK_AS_WINDOW(&dock[i]));
}
void dock_shutdown()
{
XDestroyWindow(ob_display, dock->frame);
appearance_free(dock->a_frame);
g_hash_table_remove(window_map, &dock->frame);
stacking_remove(dock);
}
void dock_add(Window win, XWMHints *wmhints)
{
DockApp *app;
XWindowAttributes attrib;
app = g_new0(DockApp, 1);
app->win = win;
app->icon_win = (wmhints->flags & IconWindowHint) ?
wmhints->icon_window : win;
if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
app->w = attrib.width;
app->h = attrib.height;
} else {
app->w = app->h = 64;
}
dock->dock_apps = g_list_append(dock->dock_apps, app);
dock_configure();
XReparentWindow(ob_display, app->icon_win, dock->frame, app->x, app->y);
/*
This is the same case as in frame.c for client windows. When Openbox is
starting, the window is already mapped so we see unmap events occur for
it. There are 2 unmap events generated that we see, one with the 'event'
member set the root window, and one set to the client, but both get
handled and need to be ignored.
*/
if (ob_state == State_Starting)
app->ignore_unmaps += 2;
if (app->win != app->icon_win) {
/* have to map it so that it can be re-managed on a restart */
XMoveWindow(ob_display, app->win, -1000, -1000);
XMapWindow(ob_display, app->win);
}
XMapWindow(ob_display, app->icon_win);
XSync(ob_display, False);
/* specify that if we exit, the window should not be destroyed and should
be reparented back to root automatically */
XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
XSelectInput(ob_display, app->icon_win, DOCKAPP_EVENT_MASK);
grab_button_full(2, 0, app->icon_win,
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
GrabModeAsync, ob_cursors.move);
g_hash_table_insert(window_map, &app->icon_win, app);
g_message("Managed Dock App: 0x%lx", app->icon_win);
}
void dock_remove_all()
{
while (dock->dock_apps)
dock_remove(dock->dock_apps->data, TRUE);
}
void dock_remove(DockApp *app, gboolean reparent)
{
ungrab_button(2, 0, app->icon_win);
XSelectInput(ob_display, app->icon_win, NoEventMask);
/* remove the window from our save set */
XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
XSync(ob_display, False);
g_hash_table_remove(window_map, &app->icon_win);
if (reparent)
XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
dock->dock_apps = g_list_remove(dock->dock_apps, app);
dock_configure();
g_message("Unmanaged Dock App: 0x%lx", app->icon_win);
g_free(app);
}
void dock_configure()
{
GList *it;
int spot;
int gravity;
dock->w = dock->h = spot = 0;
for (it = dock->dock_apps; it; it = it->next) {
struct DockApp *app = it->data;
if (config_dock_horz) {
app->x = spot;
app->y = 0;
dock->w += app->w;
dock->h = MAX(dock->h, app->h);
spot += app->w;
} else {
app->x = 0;
app->y = spot;
dock->w = MAX(dock->w, app->w);
dock->h += app->h;
spot += app->h;
}
XMoveWindow(ob_display, app->icon_win, app->x, app->y);
}
/* used for calculating offsets */
dock->w += theme_bwidth * 2;
dock->h += theme_bwidth * 2;
/* calculate position */
switch (config_dock_pos) {
case DockPos_Floating:
dock->x = config_dock_x;
dock->y = config_dock_y;
gravity = NorthWestGravity;
break;
case DockPos_TopLeft:
dock->x = 0;
dock->y = 0;
gravity = NorthWestGravity;
break;
case DockPos_Top:
dock->x = screen_physical_size.width / 2;
dock->y = 0;
gravity = NorthGravity;
break;
case DockPos_TopRight:
dock->x = screen_physical_size.width;
dock->y = 0;
gravity = NorthEastGravity;
break;
case DockPos_Left:
dock->x = 0;
dock->y = screen_physical_size.height / 2;
gravity = WestGravity;
break;
case DockPos_Right:
dock->x = screen_physical_size.width;
dock->y = screen_physical_size.height / 2;
gravity = EastGravity;
break;
case DockPos_BottomLeft:
dock->x = 0;
dock->y = screen_physical_size.height;
gravity = SouthWestGravity;
break;
case DockPos_Bottom:
dock->x = screen_physical_size.width / 2;
dock->y = screen_physical_size.height;
gravity = SouthGravity;
break;
case DockPos_BottomRight:
dock->x = screen_physical_size.width;
dock->y = screen_physical_size.height;
gravity = SouthEastGravity;
break;
}
switch(gravity) {
case NorthGravity:
case CenterGravity:
case SouthGravity:
dock->x -= dock->w / 2;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
dock->x -= dock->w;
break;
}
switch(gravity) {
case WestGravity:
case CenterGravity:
case EastGravity:
dock->y -= dock->h / 2;
break;
case SouthWestGravity:
case SouthGravity:
case SouthEastGravity:
dock->y -= dock->h;
break;
}
if (config_dock_hide && dock->hidden) {
switch (config_dock_pos) {
case DockPos_Floating:
break;
case DockPos_TopLeft:
if (config_dock_horz)
dock->y -= dock->h - theme_bwidth;
else
dock->x -= dock->w - theme_bwidth;
break;
case DockPos_Top:
dock->y -= dock->h - theme_bwidth;
break;
case DockPos_TopRight:
if (config_dock_horz)
dock->y -= dock->h - theme_bwidth;
else
dock->x += dock->w - theme_bwidth;
break;
case DockPos_Left:
dock->x -= dock->w - theme_bwidth;
break;
case DockPos_Right:
dock->x += dock->w - theme_bwidth;
break;
case DockPos_BottomLeft:
if (config_dock_horz)
dock->y += dock->h - theme_bwidth;
else
dock->x -= dock->w - theme_bwidth;
break;
case DockPos_Bottom:
dock->y += dock->h - theme_bwidth;
break;
case DockPos_BottomRight:
if (config_dock_horz)
dock->y += dock->h - theme_bwidth;
else
dock->x += dock->w - theme_bwidth;
break;
}
}
/* not used for actually sizing shit */
dock->w -= theme_bwidth * 2;
dock->h -= theme_bwidth * 2;
if (dock->w > 0 && dock->h > 0) {
RECT_SET(dock->a_frame->area, 0, 0, dock->w, dock->h);
XMoveResizeWindow(ob_display, dock->frame,
dock->x, dock->y, dock->w, dock->h);
paint(dock->frame, dock->a_frame);
XMapWindow(ob_display, dock->frame);
} else
XUnmapWindow(ob_display, dock->frame);
/* but they are useful outside of this function! */
dock->w += theme_bwidth * 2;
dock->h += theme_bwidth * 2;
}
void dock_app_configure(DockApp *app, int w, int h)
{
app->w = w;
app->h = h;
dock_configure();
}
void dock_app_drag(DockApp *app, XMotionEvent *e)
{
DockApp *over = NULL;
GList *it;
int x, y;
gboolean after;
x = e->x_root;
y = e->y_root;
/* are we on top of the dock? */
if (!(x >= dock->x &&
y >= dock->y &&
x < dock->x + dock->w &&
y < dock->y + dock->h))
return;
x -= dock->x;
y -= dock->y;
/* which dock app are we on top of? */
for (it = dock->dock_apps; it; it = it->next) {
over = it->data;
if (config_dock_horz) {
if (x >= over->x && x < over->x + over->w)
break;
} else {
if (y >= over->y && y < over->y + over->h)
break;
}
}
if (!it || app == over) return;
x -= over->x;
y -= over->y;
if (config_dock_horz)
after = (x > over->w / 2);
else
after = (y > over->h / 2);
/* remove before doing the it->next! */
dock->dock_apps = g_list_remove(dock->dock_apps, app);
if (after) it = it->next;
dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
dock_configure();
}
static void hide_timeout(void *n)
{
/* dont repeat */
timer_stop(dock->hide_timer);
dock->hide_timer = NULL;
/* hide */
dock->hidden = TRUE;
dock_configure();
}
void dock_hide(gboolean hide)
{
if (dock->hidden == hide || !config_dock_hide)
return;
if (!hide) {
/* show */
dock->hidden = FALSE;
dock_configure();
/* if was hiding, stop it */
if (dock->hide_timer) {
timer_stop(dock->hide_timer);
dock->hide_timer = NULL;
}
} else {
g_assert(!dock->hide_timer);
dock->hide_timer = timer_start(config_dock_hide_timeout * 1000,
(TimeoutHandler)hide_timeout,
NULL);
}
}

66
openbox/dock.h Normal file
View file

@ -0,0 +1,66 @@
#ifndef __dock_h
#define __dock_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 enum {
DockPos_Floating,
DockPos_TopLeft,
DockPos_Top,
DockPos_TopRight,
DockPos_Right,
DockPos_BottomRight,
DockPos_Bottom,
DockPos_BottomLeft,
DockPos_Left
} DockPosition;
typedef struct Dock {
ObWindow obwin;
Window frame;
Appearance *a_frame;
/* actual position (when not auto-hidden) */
int x, y;
int w, h;
gboolean hidden;
Timer *hide_timer;
GList *dock_apps;
} Dock;
typedef struct DockApp {
int ignore_unmaps;
Window icon_win;
Window win;
int x;
int y;
int w;
int h;
} DockApp;
void dock_startup();
void dock_shutdown();
void dock_configure();
void dock_hide(gboolean hide);
void dock_add(Window win, XWMHints *wmhints);
void dock_remove_all();
void dock_remove(DockApp *app, gboolean reparent);
void dock_app_drag(DockApp *app, XMotionEvent *e);
void dock_app_configure(DockApp *app, int w, int h);
#endif

View file

@ -1,5 +1,5 @@
#include "openbox.h"
#include "slit.h"
#include "dock.h"
#include "client.h"
#include "xerror.h"
#include "prop.h"
@ -27,8 +27,8 @@
static void event_process(XEvent *e);
static void event_handle_root(XEvent *e);
static void event_handle_slit(Slit *s, XEvent *e);
static void event_handle_slitapp(SlitApp *app, XEvent *e);
static void event_handle_dock(Dock *s, XEvent *e);
static void event_handle_dockapp(DockApp *app, XEvent *e);
static void event_handle_client(Client *c, XEvent *e);
static void event_handle_menu(Menu *menu, XEvent *e);
@ -394,15 +394,32 @@ static void event_process(XEvent *e)
{
Window window;
Client *client = NULL;
Slit *slit = NULL;
SlitApp *slitapp = NULL;
Dock *dock = NULL;
DockApp *dockapp = NULL;
Menu *menu = NULL;
ObWindow *obwin = NULL;
window = event_get_window(e);
if (!(client = g_hash_table_lookup(client_map, &window)))
if (!(slitapp = g_hash_table_lookup(slit_app_map, &window)))
if (!(slit = g_hash_table_lookup(slit_map, &window)))
menu = g_hash_table_lookup(menu_map, &window);
if ((obwin = g_hash_table_lookup(window_map, &window))) {
switch (obwin->type) {
case Window_Dock:
dock = WINDOW_AS_DOCK(obwin);
break;
case Window_DockApp:
dockapp = WINDOW_AS_DOCKAPP(obwin);
break;
case Window_Menu:
menu = WINDOW_AS_MENU(obwin);
break;
case Window_Client:
client = WINDOW_AS_CLIENT(obwin);
break;
case Window_Internal:
/* not to be used for events */
g_assert_not_reached();
break;
}
}
event_set_lasttime(e);
event_hack_mods(e);
@ -415,10 +432,10 @@ static void event_process(XEvent *e)
return;
} else if (client)
event_handle_client(client, e);
else if (slitapp)
event_handle_slitapp(slitapp, e);
else if (slit)
event_handle_slit(slit, e);
else if (dockapp)
event_handle_dockapp(dockapp, e);
else if (dock)
event_handle_dock(dock, e);
else if (window == ob_root)
event_handle_root(e);
else if (e->type == MapRequest)
@ -969,41 +986,41 @@ void fd_event_handle()
g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
}
static void event_handle_slit(Slit *s, XEvent *e)
static void event_handle_dock(Dock *s, XEvent *e)
{
switch (e->type) {
case ButtonPress:
stacking_raise(SLIT_AS_WINDOW(s));
stacking_raise(DOCK_AS_WINDOW(s));
case EnterNotify:
slit_hide(s, FALSE);
dock_hide(FALSE);
break;
case LeaveNotify:
slit_hide(s, TRUE);
dock_hide(TRUE);
break;
}
}
static void event_handle_slitapp(SlitApp *app, XEvent *e)
static void event_handle_dockapp(DockApp *app, XEvent *e)
{
switch (e->type) {
case MotionNotify:
slit_app_drag(app, &e->xmotion);
dock_app_drag(app, &e->xmotion);
break;
case UnmapNotify:
if (app->ignore_unmaps) {
app->ignore_unmaps--;
break;
}
slit_remove(app, TRUE);
dock_remove(app, TRUE);
break;
case DestroyNotify:
slit_remove(app, FALSE);
dock_remove(app, FALSE);
break;
case ReparentNotify:
slit_remove(app, FALSE);
dock_remove(app, FALSE);
break;
case ConfigureNotify:
slit_app_configure(app, e->xconfigure.width, e->xconfigure.height);
dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
break;
}
}

View file

@ -430,20 +430,20 @@ void frame_grab_client(Frame *self, Client *client)
frame_adjust_area(self, TRUE, TRUE);
/* set all the windows for the frame in the client_map */
g_hash_table_insert(client_map, &self->window, client);
g_hash_table_insert(client_map, &self->plate, client);
g_hash_table_insert(client_map, &self->title, client);
g_hash_table_insert(client_map, &self->label, client);
g_hash_table_insert(client_map, &self->max, client);
g_hash_table_insert(client_map, &self->close, client);
g_hash_table_insert(client_map, &self->desk, client);
g_hash_table_insert(client_map, &self->shade, client);
g_hash_table_insert(client_map, &self->icon, client);
g_hash_table_insert(client_map, &self->iconify, client);
g_hash_table_insert(client_map, &self->handle, client);
g_hash_table_insert(client_map, &self->lgrip, client);
g_hash_table_insert(client_map, &self->rgrip, client);
/* set all the windows for the frame in the window_map */
g_hash_table_insert(window_map, &self->window, client);
g_hash_table_insert(window_map, &self->plate, client);
g_hash_table_insert(window_map, &self->title, client);
g_hash_table_insert(window_map, &self->label, client);
g_hash_table_insert(window_map, &self->max, client);
g_hash_table_insert(window_map, &self->close, client);
g_hash_table_insert(window_map, &self->desk, client);
g_hash_table_insert(window_map, &self->shade, client);
g_hash_table_insert(window_map, &self->icon, client);
g_hash_table_insert(window_map, &self->iconify, client);
g_hash_table_insert(window_map, &self->handle, client);
g_hash_table_insert(window_map, &self->lgrip, client);
g_hash_table_insert(window_map, &self->rgrip, client);
}
void frame_release_client(Frame *self, Client *client)
@ -470,20 +470,20 @@ void frame_release_client(Frame *self, Client *client)
client->area.y);
}
/* remove all the windows for the frame from the client_map */
g_hash_table_remove(client_map, &self->window);
g_hash_table_remove(client_map, &self->plate);
g_hash_table_remove(client_map, &self->title);
g_hash_table_remove(client_map, &self->label);
g_hash_table_remove(client_map, &self->max);
g_hash_table_remove(client_map, &self->close);
g_hash_table_remove(client_map, &self->desk);
g_hash_table_remove(client_map, &self->shade);
g_hash_table_remove(client_map, &self->icon);
g_hash_table_remove(client_map, &self->iconify);
g_hash_table_remove(client_map, &self->handle);
g_hash_table_remove(client_map, &self->lgrip);
g_hash_table_remove(client_map, &self->rgrip);
/* remove all the windows for the frame from the window_map */
g_hash_table_remove(window_map, &self->window);
g_hash_table_remove(window_map, &self->plate);
g_hash_table_remove(window_map, &self->title);
g_hash_table_remove(window_map, &self->label);
g_hash_table_remove(window_map, &self->max);
g_hash_table_remove(window_map, &self->close);
g_hash_table_remove(window_map, &self->desk);
g_hash_table_remove(window_map, &self->shade);
g_hash_table_remove(window_map, &self->icon);
g_hash_table_remove(window_map, &self->iconify);
g_hash_table_remove(window_map, &self->handle);
g_hash_table_remove(window_map, &self->lgrip);
g_hash_table_remove(window_map, &self->rgrip);
frame_free(self);
}

View file

@ -8,7 +8,6 @@
#include "plugin.h"
static GHashTable *menu_hash = NULL;
GHashTable *menu_map = NULL;
#define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask | \
LeaveWindowMask)
@ -34,9 +33,9 @@ void menu_destroy_hash_value(Menu *self)
g_free(self->label);
g_free(self->name);
g_hash_table_remove(menu_map, &self->title);
g_hash_table_remove(menu_map, &self->frame);
g_hash_table_remove(menu_map, &self->items);
g_hash_table_remove(window_map, &self->title);
g_hash_table_remove(window_map, &self->frame);
g_hash_table_remove(window_map, &self->items);
stacking_remove(self);
@ -53,7 +52,7 @@ void menu_entry_free(MenuEntry *self)
g_free(self->label);
action_free(self->action);
g_hash_table_remove(menu_map, &self->item);
g_hash_table_remove(window_map, &self->item);
appearance_free(self->a_item);
appearance_free(self->a_disabled);
@ -73,7 +72,6 @@ void menu_startup()
menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
menu_destroy_hash_key,
(GDestroyNotify)menu_destroy_hash_value);
menu_map = g_hash_table_new(g_int_hash, g_int_equal);
m = menu_new(NULL, "root", NULL);
@ -137,7 +135,6 @@ void menu_startup()
void menu_shutdown()
{
g_hash_table_destroy(menu_hash);
g_hash_table_destroy(menu_map);
}
static Window createWindow(Window parent, unsigned long mask,
@ -195,9 +192,9 @@ Menu *menu_new_full(char *label, char *name, Menu *parent,
self->a_title = appearance_copy(theme_a_menu_title);
self->a_items = appearance_copy(theme_a_menu);
g_hash_table_insert(menu_map, &self->frame, self);
g_hash_table_insert(menu_map, &self->title, self);
g_hash_table_insert(menu_map, &self->items, self);
g_hash_table_insert(window_map, &self->frame, self);
g_hash_table_insert(window_map, &self->title, self);
g_hash_table_insert(window_map, &self->items, self);
g_hash_table_insert(menu_hash, g_strdup(name), self);
stacking_add(MENU_AS_WINDOW(self));
@ -259,7 +256,7 @@ void menu_add_entry(Menu *menu, MenuEntry *entry)
menu->invalid = TRUE;
g_hash_table_insert(menu_map, &entry->item, menu);
g_hash_table_insert(window_map, &entry->item, menu);
}
void menu_show(char *name, int x, int y, Client *client)

View file

@ -7,8 +7,6 @@
#include <glib.h>
extern GHashTable *menu_map;
struct Menu;
struct MenuEntry;

View file

@ -1,5 +1,5 @@
#include "openbox.h"
#include "slit.h"
#include "dock.h"
#include "event.h"
#include "menu.h"
#include "client.h"
@ -184,6 +184,7 @@ int main(int argc, char **argv)
g_free(theme);
if (!theme) return 1;
window_startup();
menu_startup();
frame_startup();
moveresize_startup();
@ -191,7 +192,7 @@ int main(int argc, char **argv)
screen_startup();
group_startup();
client_startup();
slit_startup();
dock_startup();
/* call startup for all the plugins */
plugin_startall();
@ -204,11 +205,11 @@ int main(int argc, char **argv)
event_loop();
ob_state = State_Exiting;
slit_remove_all();
dock_remove_all();
client_unmanage_all();
plugin_shutdown(); /* calls all the plugins' shutdown functions */
slit_shutdown();
dock_shutdown();
client_shutdown();
group_shutdown();
screen_shutdown();
@ -216,6 +217,7 @@ int main(int argc, char **argv)
moveresize_shutdown();
frame_shutdown();
menu_shutdown();
window_shutdown();
grab_shutdown();
event_shutdown();
theme_shutdown();

View file

@ -1,5 +1,5 @@
#include "openbox.h"
#include "slit.h"
#include "dock.h"
#include "prop.h"
#include "startup.h"
#include "config.h"
@ -219,7 +219,7 @@ void screen_resize(int w, int h)
if (ob_state == State_Starting)
return;
slit_configure_all();
dock_configure();
screen_update_struts();
for (it = client_list; it; it = it->next)

View file

@ -1,424 +0,0 @@
#include "slit.h"
#include "screen.h"
#include "grab.h"
#include "openbox.h"
#include "render/theme.h"
#define SLIT_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask)
#define SLITAPP_EVENT_MASK (StructureNotifyMask)
GHashTable *slit_map = NULL;
GHashTable *slit_app_map = NULL;
static Slit *slit;
static int nslits;
static guint slit_hide_timeout = 3000; /* XXX make a config option */
static void slit_configure(Slit *self);
void slit_startup()
{
XSetWindowAttributes attrib;
int i;
slit_map = g_hash_table_new(g_int_hash, g_int_equal);
slit_app_map = g_hash_table_new(g_int_hash, g_int_equal);
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;
slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
render_depth, InputOutput, render_visual,
CWOverrideRedirect | CWEventMask,
&attrib);
slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
g_hash_table_insert(slit_map, &slit[i].frame, &slit[i]);
stacking_add(SLIT_AS_WINDOW(&slit[i]));
stacking_raise(SLIT_AS_WINDOW(&slit[i]));
}
}
void slit_shutdown()
{
int i;
for (i = 0; i < nslits; ++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);
}
void slit_add(Window win, XWMHints *wmhints)
{
Slit *s;
SlitApp *app;
XWindowAttributes attrib;
/* XXX pick a slit */
s = &slit[0];
app = g_new0(SlitApp, 1);
app->slit = s;
app->win = win;
app->icon_win = (wmhints->flags & IconWindowHint) ?
wmhints->icon_window : win;
if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
app->w = attrib.width;
app->h = attrib.height;
} else {
app->w = app->h = 64;
}
s->slit_apps = g_list_append(s->slit_apps, app);
slit_configure(s);
XReparentWindow(ob_display, app->icon_win, s->frame, app->x, app->y);
/*
This is the same case as in frame.c for client windows. When Openbox is
starting, the window is already mapped so we see unmap events occur for
it. There are 2 unmap events generated that we see, one with the 'event'
member set the root window, and one set to the client, but both get
handled and need to be ignored.
*/
if (ob_state == State_Starting)
app->ignore_unmaps += 2;
if (app->win != app->icon_win) {
/* have to map it so that it can be re-managed on a restart */
XMoveWindow(ob_display, app->win, -1000, -1000);
XMapWindow(ob_display, app->win);
}
XMapWindow(ob_display, app->icon_win);
XSync(ob_display, False);
/* specify that if we exit, the window should not be destroyed and should
be reparented back to root automatically */
XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
XSelectInput(ob_display, app->icon_win, SLITAPP_EVENT_MASK);
grab_button_full(2, 0, app->icon_win,
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
GrabModeAsync, ob_cursors.move);
g_hash_table_insert(slit_app_map, &app->icon_win, app);
g_message("Managed Slit App: 0x%lx", app->icon_win);
}
void slit_remove_all()
{
int i;
for (i = 0; i < nslits; ++i)
while (slit[i].slit_apps)
slit_remove(slit[i].slit_apps->data, TRUE);
}
void slit_remove(SlitApp *app, gboolean reparent)
{
ungrab_button(2, 0, app->icon_win);
XSelectInput(ob_display, app->icon_win, NoEventMask);
/* remove the window from our save set */
XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
XSync(ob_display, False);
g_hash_table_remove(slit_app_map, &app->icon_win);
if (reparent)
XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
app->slit->slit_apps = g_list_remove(app->slit->slit_apps, app);
slit_configure(app->slit);
g_message("Unmanaged Slit App: 0x%lx", app->icon_win);
g_free(app);
}
void slit_configure_all()
{
int i; for (i = 0; i < nslits; ++i) slit_configure(&slit[i]);
}
static void slit_configure(Slit *self)
{
GList *it;
int spot;
self->w = self->h = spot = 0;
for (it = self->slit_apps; it; it = it->next) {
struct SlitApp *app = it->data;
if (self->horz) {
app->x = spot;
app->y = 0;
self->w += app->w;
self->h = MAX(self->h, app->h);
spot += app->w;
} else {
app->x = 0;
app->y = spot;
self->w = MAX(self->w, app->w);
self->h += app->h;
spot += app->h;
}
XMoveWindow(ob_display, app->icon_win, app->x, app->y);
}
/* used for calculating offsets */
self->w += theme_bwidth * 2;
self->h += theme_bwidth * 2;
/* calculate position */
switch (self->pos) {
case SlitPos_Floating:
self->x = self->user_x;
self->y = self->user_y;
break;
case SlitPos_TopLeft:
self->x = 0;
self->y = 0;
self->gravity = NorthWestGravity;
break;
case SlitPos_Top:
self->x = screen_physical_size.width / 2;
self->y = 0;
self->gravity = NorthGravity;
break;
case SlitPos_TopRight:
self->x = screen_physical_size.width;
self->y = 0;
self->gravity = NorthEastGravity;
break;
case SlitPos_Left:
self->x = 0;
self->y = screen_physical_size.height / 2;
self->gravity = WestGravity;
break;
case SlitPos_Right:
self->x = screen_physical_size.width;
self->y = screen_physical_size.height / 2;
self->gravity = EastGravity;
break;
case SlitPos_BottomLeft:
self->x = 0;
self->y = screen_physical_size.height;
self->gravity = SouthWestGravity;
break;
case SlitPos_Bottom:
self->x = screen_physical_size.width / 2;
self->y = screen_physical_size.height;
self->gravity = SouthGravity;
break;
case SlitPos_BottomRight:
self->x = screen_physical_size.width;
self->y = screen_physical_size.height;
self->gravity = SouthEastGravity;
break;
}
switch(self->gravity) {
case NorthGravity:
case CenterGravity:
case SouthGravity:
self->x -= self->w / 2;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
self->x -= self->w;
break;
}
switch(self->gravity) {
case WestGravity:
case CenterGravity:
case EastGravity:
self->y -= self->h / 2;
break;
case SouthWestGravity:
case SouthGravity:
case SouthEastGravity:
self->y -= self->h;
break;
}
if (self->hide && self->hidden) {
g_message("hidden");
switch (self->pos) {
case SlitPos_Floating:
break;
case SlitPos_TopLeft:
if (self->horz)
self->y -= self->h - theme_bwidth;
else
self->x -= self->w - theme_bwidth;
break;
case SlitPos_Top:
self->y -= self->h - theme_bwidth;
break;
case SlitPos_TopRight:
if (self->horz)
self->y -= self->h - theme_bwidth;
else
self->x += self->w - theme_bwidth;
break;
case SlitPos_Left:
self->x -= self->w - theme_bwidth;
break;
case SlitPos_Right:
self->x += self->w - theme_bwidth;
break;
case SlitPos_BottomLeft:
if (self->horz)
self->y += self->h - theme_bwidth;
else
self->x -= self->w - theme_bwidth;
break;
case SlitPos_Bottom:
self->y += self->h - theme_bwidth;
break;
case SlitPos_BottomRight:
if (self->horz)
self->y += self->h - theme_bwidth;
else
self->x += self->w - theme_bwidth;
break;
}
}
/* not used for actually sizing shit */
self->w -= theme_bwidth * 2;
self->h -= theme_bwidth * 2;
if (self->w > 0 && self->h > 0) {
RECT_SET(self->a_frame->area, 0, 0, self->w, self->h);
XMoveResizeWindow(ob_display, self->frame,
self->x, self->y, self->w, self->h);
paint(self->frame, self->a_frame);
XMapWindow(ob_display, self->frame);
} else
XUnmapWindow(ob_display, self->frame);
/* but they are useful outside of this function! */
self->w += theme_bwidth * 2;
self->h += theme_bwidth * 2;
}
void slit_app_configure(SlitApp *app, int w, int h)
{
app->w = w;
app->h = h;
slit_configure(app->slit);
}
void slit_app_drag(SlitApp *app, XMotionEvent *e)
{
Slit *src, *dest = NULL;
SlitApp *over = NULL;
GList *it;
int i;
int x, y;
gboolean after;
src = app->slit;
x = e->x_root;
y = e->y_root;
/* which slit are we on top of? */
for (i = 0; i < nslits; ++i)
if (x >= slit[i].x &&
y >= slit[i].y &&
x < slit[i].x + slit[i].w &&
y < slit[i].y + slit[i].h) {
dest = &slit[i];
break;
}
if (!dest) return;
x -= dest->x;
y -= dest->y;
/* which slit app are we on top of? */
for (it = dest->slit_apps; it; it = it->next) {
over = it->data;
if (dest->horz) {
if (x >= over->x && x < over->x + over->w)
break;
} else {
if (y >= over->y && y < over->y + over->h)
break;
}
}
if (!it || app == over) return;
x -= over->x;
y -= over->y;
if (dest->horz)
after = (x > over->w / 2);
else
after = (y > over->h / 2);
/* remove before doing the it->next! */
src->slit_apps = g_list_remove(src->slit_apps, app);
if (src != dest) slit_configure(src);
if (after) it = it->next;
dest->slit_apps = g_list_insert_before(dest->slit_apps, it, app);
slit_configure(dest);
}
static void hide_timeout(Slit *self)
{
/* dont repeat */
timer_stop(self->hide_timer);
self->hide_timer = NULL;
/* hide */
self->hidden = TRUE;
slit_configure(self);
}
void slit_hide(Slit *self, gboolean hide)
{
if (self->hidden == hide || !self->hide)
return;
if (!hide) {
/* show */
self->hidden = FALSE;
slit_configure(self);
/* if was hiding, stop it */
if (self->hide_timer) {
timer_stop(self->hide_timer);
self->hide_timer = NULL;
}
} else {
g_assert(!self->hide_timer);
self->hide_timer = timer_start(slit_hide_timeout * 1000,
(TimeoutHandler)hide_timeout, self);
}
}

View file

@ -1,80 +0,0 @@
#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 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;
Slit *slit;
Window icon_win;
Window win;
int x;
int y;
int w;
int h;
} SlitApp;
extern GHashTable *slit_map;
extern GHashTable *slit_app_map;
void slit_startup();
void slit_shutdown();
void slit_configure_all();
void slit_hide(Slit *self, gboolean hide);
void slit_add(Window win, XWMHints *wmhints);
void slit_remove_all();
void slit_remove(SlitApp *app, gboolean reparent);
void slit_app_drag(SlitApp *app, XMotionEvent *e);
void slit_app_configure(SlitApp *app, int w, int h);
#endif

View file

@ -1,16 +1,33 @@
#include "window.h"
#include "menu.h"
#include "slit.h"
#include "config.h"
#include "dock.h"
#include "client.h"
#include "frame.h"
GHashTable *window_map;
void window_startup()
{
window_map = g_hash_table_new(g_int_hash, g_int_equal);
}
void window_shutdown()
{
g_hash_table_destroy(window_map);
}
Window window_top(ObWindow *self)
{
switch (self->type) {
case Window_Menu:
return ((Menu*)self)->frame;
case Window_Slit:
return ((Slit*)self)->frame;
case Window_Dock:
return ((Dock*)self)->frame;
case Window_DockApp:
/* not to be used for stacking */
g_assert_not_reached();
break;
case Window_Client:
return ((Client*)self)->frame->window;
case Window_Internal:
@ -25,8 +42,12 @@ Window window_layer(ObWindow *self)
switch (self->type) {
case Window_Menu:
return Layer_Internal;
case Window_Slit:
return ((Slit*)self)->layer;
case Window_Dock:
return config_dock_layer;
case Window_DockApp:
/* not to be used for stacking */
g_assert_not_reached();
break;
case Window_Client:
return ((Client*)self)->layer;
case Window_Internal:

View file

@ -2,12 +2,14 @@
#define __window_h
#include <X11/Xlib.h>
#include <glib.h>
typedef enum {
Window_Menu,
Window_Slit,
Window_Dock,
Window_DockApp, /* used for events but not stacking */
Window_Client,
Window_Internal
Window_Internal /* used for stacking but not events */
} Window_InternalType;
typedef struct ObWindow {
@ -22,24 +24,33 @@ typedef struct InternalWindow {
} InternalWindow;
#define WINDOW_IS_MENU(win) (((ObWindow*)win)->type == Window_Menu)
#define WINDOW_IS_SLIT(win) (((ObWindow*)win)->type == Window_Slit)
#define WINDOW_IS_DOCK(win) (((ObWindow*)win)->type == Window_Dock)
#define WINDOW_IS_DOCKAPP(win) (((ObWindow*)win)->type == Window_DockApp)
#define WINDOW_IS_CLIENT(win) (((ObWindow*)win)->type == Window_Client)
#define WINDOW_IS_INTERNAL(win) (((ObWindow*)win)->type == Window_Internal)
struct Menu;
struct Slit;
struct Dock;
struct DockApp;
struct Client;
#define WINDOW_AS_MENU(win) ((struct Menu*)win)
#define WINDOW_AS_SLIT(win) ((struct Slit*)win)
#define WINDOW_AS_DOCK(win) ((struct Dock*)win)
#define WINDOW_AS_DOCKAPP(win) ((struct DockApp*)win)
#define WINDOW_AS_CLIENT(win) ((struct Client*)win)
#define WINDOW_AS_INTERNAL(win) ((struct InternalWindow*)win)
#define MENU_AS_WINDOW(menu) ((ObWindow*)menu)
#define SLIT_AS_WINDOW(slit) ((ObWindow*)slit)
#define DOCK_AS_WINDOW(dock) ((ObWindow*)dock)
#define DOCKAPP_AS_WINDOW(dockapp) ((ObWindow*)dockapp)
#define CLIENT_AS_WINDOW(client) ((ObWindow*)client)
#define INTERNAL_AS_WINDOW(intern) ((ObWindow*)intern)
extern GHashTable *window_map;
void window_startup();
void window_shutdown();
Window window_top(ObWindow *self);
Window window_layer(ObWindow *self);