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:
parent
6e42b65bda
commit
b77e40e1c7
18 changed files with 744 additions and 608 deletions
33
data/rc3
33
data/rc3
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -294,7 +294,6 @@ typedef struct Client {
|
|||
} Client;
|
||||
|
||||
extern GList *client_list;
|
||||
extern GHashTable *client_map;
|
||||
|
||||
void client_startup();
|
||||
void client_shutdown();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
382
openbox/dock.c
Normal 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
66
openbox/dock.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include <glib.h>
|
||||
|
||||
extern GHashTable *menu_map;
|
||||
|
||||
struct Menu;
|
||||
struct MenuEntry;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
424
openbox/slit.c
424
openbox/slit.c
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue