all my changes while i was offline.
better alt-tabbing. better transient handling. i dont even know. lots of fucking cool shit so WATCH the FUCK OUT.
This commit is contained in:
parent
60065663ba
commit
f26f23de50
37 changed files with 753 additions and 393 deletions
4
HACKING
4
HACKING
|
@ -13,6 +13,10 @@ which is not a valid pointer. You must ALWAYS check for TRAN_GROUP before
|
|||
following transient_for. When TRAN_GROUP is found, Client.group will always
|
||||
be !NULL. Some smart action should be taken using all members of the group in
|
||||
this case.
|
||||
Smart action idea:
|
||||
Skip over members of the group that are also transients of the group
|
||||
(have Client.transient_for set to TRAN_GROUP). These windows are not
|
||||
ancestors and using them will also end up causing infinite loops!
|
||||
|
||||
When using coordinates/sizes of windows, make sure you use the right area. The
|
||||
Client.area rect is the reference point and size of the *CLIENT* window. This
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#SUBDIRS = po themes doc render cwmcc obcl kernel plugins
|
||||
SUBDIRS = po themes data render kernel plugins
|
||||
SUBDIRS = po themes data render kernel plugins tools
|
||||
MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in stamp-h.in
|
||||
|
||||
doc:
|
||||
|
|
|
@ -57,6 +57,8 @@ AC_SUBST(XFT_LIBS)
|
|||
|
||||
# Check for X11 extensions
|
||||
X11_EXT_XKB
|
||||
X11_EXT_XRANDR
|
||||
X11_EXT_VIDMODE
|
||||
X11_EXT_SHAPE
|
||||
X11_EXT_XINERAMA
|
||||
|
||||
|
@ -69,7 +71,9 @@ AC_CONFIG_FILES([Makefile
|
|||
plugins/Makefile
|
||||
plugins/placement/Makefile
|
||||
plugins/mouse/Makefile
|
||||
plugins/keyboard/Makefile])
|
||||
plugins/keyboard/Makefile
|
||||
tools/Makefile
|
||||
tools/slit/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT
|
||||
|
|
3
data/rc3
3
data/rc3
|
@ -27,6 +27,9 @@
|
|||
# set, the previously focused window on the desktop is focused when switching
|
||||
#focusLastOnDesktop = yes
|
||||
|
||||
# shows a helpful dialog while cycling focus
|
||||
#cyclingDialog = yes
|
||||
|
||||
[desktops]
|
||||
|
||||
# The number of virtual desktops to use
|
||||
|
|
126
m4/x11.m4
126
m4/x11.m4
|
@ -211,6 +211,11 @@ AC_DEFUN([X11_EXT_XKB],
|
|||
AC_MSG_RESULT([yes])
|
||||
XKB="yes"
|
||||
AC_DEFINE([XKB], [1], [Found the XKB extension])
|
||||
|
||||
XKB_CFLAGS=""
|
||||
XKB_LIBS=""
|
||||
AC_SUBST(XKB_CFLAGS)
|
||||
AC_SUBST(XKB_LIBS)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
|
@ -229,6 +234,63 @@ AC_DEFUN([X11_EXT_XKB],
|
|||
fi
|
||||
])
|
||||
|
||||
# X11_EXT_XRANDR()
|
||||
#
|
||||
# Check for the presence of the "XRandR" X Window System extension.
|
||||
# Defines "XRANDR" and sets the $(XRANDR) variable to "yes" if the extension is
|
||||
# present.
|
||||
AC_DEFUN([X11_EXT_XRANDR],
|
||||
[
|
||||
AC_REQUIRE([X11_DEVEL])
|
||||
|
||||
# Store these
|
||||
OLDLIBS=$LIBS
|
||||
OLDCPPFLAGS=$CPPFLAGS
|
||||
|
||||
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
|
||||
LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS -lXext -lXrender -lXrandr"
|
||||
|
||||
AC_CHECK_LIB([Xrandr], [XRRSelectInput],
|
||||
AC_MSG_CHECKING([for X11/extensions/Xrandr.h])
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
],
|
||||
[
|
||||
Display *d;
|
||||
Drawable r;
|
||||
int i;
|
||||
XRRQueryExtension(d, &i, &i);
|
||||
XRRGetScreenInfo(d, r);
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
XRANDR="yes"
|
||||
AC_DEFINE([XRANDR], [1], [Found the XRandR extension])
|
||||
|
||||
XRANDR_CFLAGS=""
|
||||
XRANDR_LIBS="-lXext -lXrender -lXrandr"
|
||||
AC_SUBST(XRANDR_CFLAGS)
|
||||
AC_SUBST(XRANDR_LIBS)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
XRANDR="no"
|
||||
])
|
||||
)
|
||||
|
||||
LIBS=$OLDLIBS
|
||||
CPPFLAGS=$OLDCPPFLAGS
|
||||
|
||||
AC_MSG_CHECKING([for the XRandR extension])
|
||||
if test "$XRANDR" = "yes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
# X11_EXT_SHAPE()
|
||||
#
|
||||
# Check for the presence of the "Shape" X Window System extension.
|
||||
|
@ -260,7 +322,11 @@ AC_DEFUN([X11_EXT_SHAPE],
|
|||
AC_MSG_RESULT([yes])
|
||||
SHAPE="yes"
|
||||
AC_DEFINE([SHAPE], [1], [Found the XShape extension])
|
||||
LIBS="$LIBS -lXext"
|
||||
|
||||
XSHAPE_CFLAGS=""
|
||||
XSHAPE_LIBS="-lXext"
|
||||
AC_SUBST(XSHAPE_CFLAGS)
|
||||
AC_SUBST(XSHAPE_LIBS)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
|
@ -271,7 +337,7 @@ AC_DEFUN([X11_EXT_SHAPE],
|
|||
LIBS=$OLDLIBS
|
||||
CPPFLAGS=$OLDCPPFLAGS
|
||||
|
||||
AC_MSG_CHECKING([for the Shape extension])
|
||||
AC_MSG_CHECKING([for the Shape extension])
|
||||
if test "$SHAPE" = "yes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
|
@ -330,3 +396,59 @@ AC_DEFUN([X11_EXT_XINERAMA],
|
|||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
||||
# VIDMODE()
|
||||
#
|
||||
# Check for the presence of the "VidMode" X Window System extension.
|
||||
# Defines "VIDMODE" and sets the $(VIDMODE) variable to "yes" if the extension
|
||||
# is present.
|
||||
AC_DEFUN([X11_EXT_VIDMODE],
|
||||
[
|
||||
AC_REQUIRE([X11_DEVEL])
|
||||
|
||||
# Store these
|
||||
OLDLIBS=$LIBS
|
||||
OLDCPPFLAGS=$CPPFLAGS
|
||||
|
||||
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
|
||||
LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS -lXext -lXxf86vm"
|
||||
|
||||
AC_CHECK_LIB([Xxf86vm], [XF86VidModeGetViewPort],
|
||||
AC_MSG_CHECKING([for X11/extensions/xf86vmode.h])
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/xf86vmode.h>
|
||||
],
|
||||
[
|
||||
Display *d;
|
||||
int i;
|
||||
XF86VidModeQueryExtension(d, &i, &i);
|
||||
XF86VidModeGetViewPort(d, i, &i, &i);
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
VIDMODE="yes"
|
||||
AC_DEFINE([VIDMODE], [1], [Found the VidMode extension])
|
||||
|
||||
VIDMODE_CFLAGS=""
|
||||
VIDMODE_LIBS="-lXext -lXxf86vm"
|
||||
AC_SUBST(VIDMODE_CFLAGS)
|
||||
AC_SUBST(VIDMODE_LIBS)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
VIDMODE="no"
|
||||
])
|
||||
)
|
||||
|
||||
LIBS=$OLDLIBS
|
||||
CPPFLAGS=$OLDCPPFLAGS
|
||||
|
||||
AC_MSG_CHECKING([for the VidMode extension])
|
||||
if test "$VIDMODE" = "yes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
])
|
||||
|
|
|
@ -14,22 +14,24 @@ CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) \
|
|||
-DBINARY=\"$(binary)\"
|
||||
|
||||
INCLUDES=-I..
|
||||
LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) @LIBS@
|
||||
LIBS=$(X_LIBS) $(XFT_LIBS) $(XINERAMA_LIBS) $(XKB_LIBS) $(XRANDR_LIBS) \
|
||||
$(VIDMODE_LIBS) $(XSHAPE_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) @LIBS@ \
|
||||
@LIBINTL@
|
||||
|
||||
bin_PROGRAMS=$(binary)
|
||||
|
||||
openbox3_LDADD=@LIBINTL@ -lobrender -L../render
|
||||
openbox3_LDADD=-lobrender -L../render
|
||||
openbox3_LDFLAGS=-export-dynamic
|
||||
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
|
||||
moveresize.c startup.c popup.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
|
||||
stacking.h timer.h xerror.h moveresize.h startup.h popup.h
|
||||
|
||||
# kill the implicit .c.y rule
|
||||
%.c: %.y
|
||||
|
|
250
openbox/client.c
250
openbox/client.c
|
@ -38,10 +38,7 @@ static void client_get_gravity(Client *self);
|
|||
static void client_showhide(Client *self);
|
||||
static void client_change_allowed_actions(Client *self);
|
||||
static void client_change_state(Client *self);
|
||||
static void client_move_onscreen(Client *self);
|
||||
static Client *search_focus_tree(Client *node, Client *skip);
|
||||
static void client_apply_startup_state(Client *self);
|
||||
static Client *search_modal_tree(Client *node, Client *skip);
|
||||
|
||||
static guint map_hash(Window *w) { return *w; }
|
||||
static gboolean map_key_comp(Window *w1, Window *w2) { return *w1 == *w2; }
|
||||
|
@ -82,6 +79,37 @@ void client_set_list()
|
|||
stacking_set_list();
|
||||
}
|
||||
|
||||
/*
|
||||
void client_foreach_transient(Client *self, ClientForeachFunc func, void *data)
|
||||
{
|
||||
GSList *it;
|
||||
|
||||
for (it = self->transients; it; it = it->next) {
|
||||
if (!func(it->data, data)) return;
|
||||
client_foreach_transient(it->data, func, data);
|
||||
}
|
||||
}
|
||||
|
||||
void client_foreach_ancestor(Client *self, ClientForeachFunc func, void *data)
|
||||
{
|
||||
if (self->transient_for) {
|
||||
if (self->transient_for != TRAN_GROUP) {
|
||||
if (!func(self->transient_for, data)) return;
|
||||
client_foreach_ancestor(self->transient_for, func, data);
|
||||
} else {
|
||||
GSList *it;
|
||||
|
||||
for (it = self->group->members; it; it = it->next)
|
||||
if (it->data != self &&
|
||||
((Client*)it->data)->transient_for != TRAN_GROUP) {
|
||||
if (!func(it->data, data)) return;
|
||||
client_foreach_ancestor(it->data, func, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void client_manage_all()
|
||||
{
|
||||
unsigned int i, j, nchild;
|
||||
|
@ -137,7 +165,7 @@ void client_manage_all()
|
|||
|
||||
if (config_focus_new) {
|
||||
active = g_hash_table_lookup(client_map, &startup_active);
|
||||
if (!active || !client_focus(active))
|
||||
if (!(active && client_focus(active)))
|
||||
focus_fallback(Fallback_NoFocus);
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +294,7 @@ void client_manage(Window window)
|
|||
(!parent && (!self->group ||
|
||||
!self->group->members->next)))))) ||
|
||||
(parent && (client_focused(parent) ||
|
||||
search_focus_tree(parent, parent)))) {
|
||||
client_search_focus_tree(parent)))) {
|
||||
client_focus(self);
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +427,7 @@ void client_unmanage(Client *self)
|
|||
client_set_list();
|
||||
}
|
||||
|
||||
static void client_move_onscreen(Client *self)
|
||||
void client_move_onscreen(Client *self)
|
||||
{
|
||||
Rect *a;
|
||||
int x = self->frame->area.x, y = self->frame->area.y;
|
||||
|
@ -415,7 +443,7 @@ static void client_move_onscreen(Client *self)
|
|||
y = a->y;
|
||||
|
||||
frame_frame_gravity(self->frame, &x, &y); /* get where the client
|
||||
should be */
|
||||
should be */
|
||||
client_configure(self , Corner_TopLeft, x, y,
|
||||
self->area.width, self->area.height,
|
||||
TRUE, TRUE);
|
||||
|
@ -496,6 +524,7 @@ static void client_get_all(Client *self)
|
|||
/* defaults */
|
||||
self->frame = NULL;
|
||||
self->title = self->icon_title = NULL;
|
||||
self->title_count = 1;
|
||||
self->name = self->class = self->role = NULL;
|
||||
self->wmstate = NormalState;
|
||||
self->transient = FALSE;
|
||||
|
@ -529,7 +558,6 @@ static void client_get_all(Client *self)
|
|||
client_setup_decor_and_functions(self);
|
||||
|
||||
client_update_title(self);
|
||||
client_update_icon_title(self);
|
||||
client_update_class(self);
|
||||
client_update_strut(self);
|
||||
client_update_icons(self);
|
||||
|
@ -782,10 +810,6 @@ void client_get_type(Client *self)
|
|||
else
|
||||
self->type = Type_Normal;
|
||||
}
|
||||
|
||||
/* this makes sure that these windows appear on all desktops */
|
||||
if (self->type == Type_Desktop)
|
||||
self->desktop = DESKTOP_ALL;
|
||||
}
|
||||
|
||||
void client_update_protocols(Client *self)
|
||||
|
@ -991,11 +1015,19 @@ void client_setup_decor_and_functions(Client *self)
|
|||
client_change_allowed_actions(self);
|
||||
|
||||
if (self->frame) {
|
||||
/* this makes sure that these windows appear on all desktops */
|
||||
if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL)
|
||||
client_set_desktop(self, DESKTOP_ALL, FALSE);
|
||||
|
||||
/* change the decors on the frame, and with more/less decorations,
|
||||
we may also need to be repositioned */
|
||||
frame_adjust_area(self->frame, TRUE, TRUE);
|
||||
/* with new decor, the window's maximized size may change */
|
||||
client_remaximize(self);
|
||||
} else {
|
||||
/* this makes sure that these windows appear on all desktops */
|
||||
if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL)
|
||||
self->desktop = DESKTOP_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1036,9 @@ static void client_change_allowed_actions(Client *self)
|
|||
guint32 actions[9];
|
||||
int num = 0;
|
||||
|
||||
actions[num++] = prop_atoms.net_wm_action_change_desktop;
|
||||
/* desktop windows are kept on all desktops */
|
||||
if (self->type != Type_Desktop)
|
||||
actions[num++] = prop_atoms.net_wm_action_change_desktop;
|
||||
|
||||
if (self->functions & Func_Shade)
|
||||
actions[num++] = prop_atoms.net_wm_action_shade;
|
||||
|
@ -1154,6 +1188,9 @@ void client_update_wmhints(Client *self)
|
|||
|
||||
void client_update_title(Client *self)
|
||||
{
|
||||
GList *it;
|
||||
guint32 nums;
|
||||
guint i;
|
||||
char *data = NULL;
|
||||
|
||||
g_free(self->title);
|
||||
|
@ -1165,6 +1202,29 @@ void client_update_title(Client *self)
|
|||
data = g_strdup("Unnamed Window");
|
||||
|
||||
/* look for duplicates and append a number */
|
||||
nums = 0;
|
||||
for (it = client_list; it; it = it->next)
|
||||
if (it->data != self) {
|
||||
Client *c = it->data;
|
||||
if (0 == strncmp(c->title, data, strlen(data)))
|
||||
nums |= 1 << c->title_count;
|
||||
}
|
||||
/* find first free number */
|
||||
for (i = 1; i <= 32; ++i)
|
||||
if (!(nums & (1 << i))) {
|
||||
if (self->title_count == 1 || i == 1)
|
||||
self->title_count = i;
|
||||
break;
|
||||
}
|
||||
/* dont display the number for the first window */
|
||||
if (self->title_count > 1) {
|
||||
char *vdata, *ndata;
|
||||
ndata = g_strdup_printf(" - [%u]", self->title_count);
|
||||
vdata = g_strconcat(data, ndata, NULL);
|
||||
g_free(ndata);
|
||||
g_free(data);
|
||||
data = vdata;
|
||||
}
|
||||
|
||||
PROP_SETS(self->window, net_wm_visible_name, data);
|
||||
|
||||
|
@ -1172,12 +1232,9 @@ void client_update_title(Client *self)
|
|||
|
||||
if (self->frame)
|
||||
frame_adjust_title(self->frame);
|
||||
}
|
||||
|
||||
void client_update_icon_title(Client *self)
|
||||
{
|
||||
char *data = NULL;
|
||||
|
||||
/* update the icon title */
|
||||
data = NULL;
|
||||
g_free(self->icon_title);
|
||||
|
||||
/* try netwm */
|
||||
|
@ -1186,6 +1243,16 @@ void client_update_icon_title(Client *self)
|
|||
if (!PROP_GETS(self->window, wm_icon_name, locale, &data))
|
||||
data = g_strdup("Unnamed Window");
|
||||
|
||||
/* append the title count, dont display the number for the first window */
|
||||
if (self->title_count > 1) {
|
||||
char *vdata, *ndata;
|
||||
ndata = g_strdup_printf(" - [%u]", self->title_count);
|
||||
vdata = g_strconcat(data, ndata, NULL);
|
||||
g_free(ndata);
|
||||
g_free(data);
|
||||
data = vdata;
|
||||
}
|
||||
|
||||
PROP_SETS(self->window, net_wm_visible_icon_name, data);
|
||||
|
||||
self->icon_title = data;
|
||||
|
@ -1342,28 +1409,70 @@ static void client_change_state(Client *self)
|
|||
frame_adjust_state(self->frame);
|
||||
}
|
||||
|
||||
static Client *search_focus_tree(Client *node, Client *skip)
|
||||
Client *client_search_focus_tree(Client *self)
|
||||
{
|
||||
GSList *it;
|
||||
Client *ret;
|
||||
|
||||
for (it = node->transients; it != NULL; it = it->next) {
|
||||
Client *c = it->data;
|
||||
if (c == skip) continue; /* circular? */
|
||||
if ((ret = search_focus_tree(c, skip))) return ret;
|
||||
if (client_focused(c)) return c;
|
||||
for (it = self->transients; it != NULL; it = it->next) {
|
||||
if (client_focused(it->data)) return it->data;
|
||||
if ((ret = client_search_focus_tree(it->data))) return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Client *client_search_focus_tree_full(Client *self)
|
||||
{
|
||||
if (self->transient_for) {
|
||||
if (self->transient_for != TRAN_GROUP) {
|
||||
return client_search_focus_tree_full(self->transient_for);
|
||||
} else {
|
||||
GSList *it;
|
||||
|
||||
for (it = self->group->members; it; it = it->next)
|
||||
if (((Client*)it->data)->transient_for != TRAN_GROUP) {
|
||||
Client *c;
|
||||
if ((c = client_search_focus_tree_full(it->data)))
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* this function checks the whole tree, the client_search_focus_tree
|
||||
does not, so we need to check this window */
|
||||
if (client_focused(self))
|
||||
return self;
|
||||
return client_search_focus_tree(self);
|
||||
}
|
||||
}
|
||||
|
||||
static StackLayer calc_layer(Client *self)
|
||||
{
|
||||
StackLayer l;
|
||||
|
||||
if (self->iconic) l = Layer_Icon;
|
||||
else if (self->fullscreen) l = Layer_Fullscreen;
|
||||
else if (self->type == Type_Desktop) l = Layer_Desktop;
|
||||
else if (self->type == Type_Dock) {
|
||||
if (!self->below) l = Layer_Top;
|
||||
else l = Layer_Normal;
|
||||
}
|
||||
else if (self->above) l = Layer_Above;
|
||||
else if (self->below) l = Layer_Below;
|
||||
else l = Layer_Normal;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void calc_recursive(Client *self, Client *orig, StackLayer l,
|
||||
gboolean raised)
|
||||
{
|
||||
StackLayer old;
|
||||
StackLayer old, own;
|
||||
GSList *it;
|
||||
|
||||
old = self->layer;
|
||||
self->layer = l;
|
||||
own = calc_layer(self);
|
||||
self->layer = l > own ? l : own;
|
||||
|
||||
for (it = self->transients; it; it = it->next)
|
||||
calc_recursive(it->data, orig, l, raised ? raised : l != old);
|
||||
|
@ -1376,7 +1485,6 @@ static void calc_recursive(Client *self, Client *orig, StackLayer l,
|
|||
void client_calc_layer(Client *self)
|
||||
{
|
||||
StackLayer l;
|
||||
gboolean f;
|
||||
Client *orig;
|
||||
|
||||
orig = self;
|
||||
|
@ -1397,25 +1505,7 @@ void client_calc_layer(Client *self)
|
|||
}
|
||||
}
|
||||
|
||||
/* is us or one of our transients focused? */
|
||||
if (client_focused(self))
|
||||
f = TRUE;
|
||||
else if (search_focus_tree(self, self))
|
||||
f = TRUE;
|
||||
else
|
||||
f = FALSE;
|
||||
|
||||
if (self->iconic) l = Layer_Icon;
|
||||
/* fullscreen windows are only in the fullscreen layer while focused */
|
||||
else if (self->fullscreen && f) l = Layer_Fullscreen;
|
||||
else if (self->type == Type_Desktop) l = Layer_Desktop;
|
||||
else if (self->type == Type_Dock) {
|
||||
if (!self->below) l = Layer_Top;
|
||||
else l = Layer_Normal;
|
||||
}
|
||||
else if (self->above) l = Layer_Above;
|
||||
else if (self->below) l = Layer_Below;
|
||||
else l = Layer_Normal;
|
||||
l = calc_layer(self);
|
||||
|
||||
calc_recursive(self, orig, l, FALSE);
|
||||
}
|
||||
|
@ -1698,31 +1788,30 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
|
|||
{
|
||||
GSList *it;
|
||||
|
||||
/* move up the transient chain as far as possible first if deiconifying */
|
||||
if (!iconic)
|
||||
while (self->transient_for) {
|
||||
if (self->transient_for != TRAN_GROUP) {
|
||||
if (self->transient_for->iconic == iconic)
|
||||
break;
|
||||
self = self->transient_for;
|
||||
} else {
|
||||
GSList *it;
|
||||
|
||||
/* the check for TRAN_GROUP is to prevent an infinate loop with
|
||||
2 transients of the same group at the head of the group's
|
||||
members list */
|
||||
for (it = self->group->members; it; it = it->next) {
|
||||
Client *c = it->data;
|
||||
|
||||
if (c != self && c->transient_for->iconic != iconic &&
|
||||
c->transient_for != TRAN_GROUP) {
|
||||
self = it->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (it == NULL) break;
|
||||
/* move up the transient chain as far as possible first */
|
||||
if (self->transient_for) {
|
||||
if (self->transient_for != TRAN_GROUP) {
|
||||
if (self->transient_for->iconic != iconic) {
|
||||
client_iconify(self->transient_for, iconic, curdesk);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
GSList *it;
|
||||
|
||||
/* the check for TRAN_GROUP is to prevent an infinate loop with
|
||||
2 transients of the same group at the head of the group's
|
||||
members list */
|
||||
for (it = self->group->members; it; it = it->next) {
|
||||
Client *c = it->data;
|
||||
if (c != self && c->iconic != iconic &&
|
||||
c->transient_for != TRAN_GROUP) {
|
||||
client_iconify(it->data, iconic, curdesk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (it != NULL) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->iconic == iconic) return; /* nothing to do */
|
||||
|
||||
|
@ -1738,13 +1827,18 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk)
|
|||
and because the ICCCM tells us to! */
|
||||
XUnmapWindow(ob_display, self->window);
|
||||
|
||||
/* update the focus lists.. iconic windows go to the bottom */
|
||||
focus_order_to_bottom(self);
|
||||
/* update the focus lists.. iconic windows go to the bottom of the
|
||||
list, put the new iconic window at the 'top of the bottom'. */
|
||||
focus_order_to_top(self);
|
||||
} else {
|
||||
if (curdesk)
|
||||
client_set_desktop(self, screen_desktop, FALSE);
|
||||
self->wmstate = self->shaded ? IconicState : NormalState;
|
||||
XMapWindow(ob_display, self->window);
|
||||
|
||||
/* this puts it after the current focused window */
|
||||
focus_order_remove(self);
|
||||
focus_order_add_new(self);
|
||||
}
|
||||
client_change_state(self);
|
||||
client_showhide(self);
|
||||
|
@ -1941,25 +2035,19 @@ void client_set_desktop(Client *self, guint target, gboolean donthide)
|
|||
dispatch_client(Event_Client_Desktop, self, target, old);
|
||||
}
|
||||
|
||||
static Client *search_modal_tree(Client *node, Client *skip)
|
||||
Client *client_search_modal_child(Client *self)
|
||||
{
|
||||
GSList *it;
|
||||
Client *ret;
|
||||
|
||||
for (it = node->transients; it != NULL; it = it->next) {
|
||||
for (it = self->transients; it != NULL; it = it->next) {
|
||||
Client *c = it->data;
|
||||
if (c == skip) continue; /* circular? */
|
||||
if ((ret = search_modal_tree(c, skip))) return ret;
|
||||
if ((ret = client_search_modal_child(c))) return ret;
|
||||
if (c->modal) return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Client *client_find_modal_child(Client *self)
|
||||
{
|
||||
return search_modal_tree(self, self);
|
||||
}
|
||||
|
||||
gboolean client_validate(Client *self)
|
||||
{
|
||||
XEvent e;
|
||||
|
@ -2118,7 +2206,7 @@ Client *client_focus_target(Client *self)
|
|||
Client *child;
|
||||
|
||||
/* if we have a modal child, then focus it, not us */
|
||||
child = client_find_modal_child(self);
|
||||
child = client_search_modal_child(self);
|
||||
if (child) return child;
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ typedef enum {
|
|||
typedef struct Client {
|
||||
Window window;
|
||||
|
||||
/*! The window's decorations. NULL while the window is being managed! */
|
||||
struct Frame *frame;
|
||||
|
||||
/*! The number of unmap events to ignore on the window */
|
||||
|
@ -133,10 +134,13 @@ typedef struct Client {
|
|||
GSList *transients;
|
||||
/*! The desktop on which the window resides (0xffffffff for all
|
||||
desktops) */
|
||||
unsigned int desktop;
|
||||
guint desktop;
|
||||
|
||||
/*! Normal window title */
|
||||
gchar *title;
|
||||
/*! The count for the title. When another window with the same title
|
||||
exists, a count will be appended to it. */
|
||||
guint title_count;
|
||||
/*! Window title when iconified */
|
||||
gchar *icon_title;
|
||||
|
||||
|
@ -341,6 +345,11 @@ gboolean client_focused(Client *self);
|
|||
void client_configure(Client *self, Corner anchor, int x, int y, int w, int h,
|
||||
gboolean user, gboolean final);
|
||||
|
||||
/*! Moves a client so that it is on screen if it is entirely out of the
|
||||
viewable screen.
|
||||
*/
|
||||
void client_move_onscreen(Client *self);
|
||||
|
||||
/*! Fullscreen's or unfullscreen's the client window
|
||||
@param fs true if the window should be made fullscreen; false if it should
|
||||
be returned to normal state.
|
||||
|
@ -389,11 +398,6 @@ void client_kill(Client *self);
|
|||
desktop has been changed. Generally this should be FALSE. */
|
||||
void client_set_desktop(Client *self, guint target, gboolean donthide);
|
||||
|
||||
/*! Return a modal child of the client window
|
||||
@return A modal child of the client window, or 0 if none was found.
|
||||
*/
|
||||
Client *client_find_modal_child(Client *self);
|
||||
|
||||
/*! Validate client, by making sure no Destroy or Unmap events exist in
|
||||
the event queue for the window.
|
||||
@return true if the client is valid; false if the client has already
|
||||
|
@ -440,10 +444,8 @@ void client_update_normal_hints(Client *self);
|
|||
process.
|
||||
*/
|
||||
void client_update_wmhints(Client *self);
|
||||
/*! Updates the window's title */
|
||||
/*! Updates the window's title and icon title */
|
||||
void client_update_title(Client *self);
|
||||
/*! Updates the window's icon title */
|
||||
void client_update_icon_title(Client *self);
|
||||
/*! Updates the window's application name and class */
|
||||
void client_update_class(Client *self);
|
||||
/*! Updates the strut for the client */
|
||||
|
@ -464,4 +466,21 @@ void client_get_type(Client *self);
|
|||
|
||||
Icon *client_icon(Client *self, int w, int h);
|
||||
|
||||
/*! Searches a client's transients for a focused window. The function does not
|
||||
check for the passed client, only for its transients.
|
||||
If no focused transient is found, NULL is returned.
|
||||
*/
|
||||
Client *client_search_focus_tree(Client *self);
|
||||
|
||||
/*! Searches a client's transient tree for a focused window. The function
|
||||
searches up the tree and down other branches as well as the passed client's.
|
||||
If no focused client is found, NULL is returned.
|
||||
*/
|
||||
Client *client_search_focus_tree_full(Client *self);
|
||||
|
||||
/*! Return a modal child of the client window
|
||||
@return A modal child of the client window, or 0 if none was found.
|
||||
*/
|
||||
Client *client_search_modal_child(Client *self);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@ gboolean config_focus_new;
|
|||
gboolean config_focus_follow;
|
||||
gboolean config_focus_last;
|
||||
gboolean config_focus_last_on_desktop;
|
||||
gboolean config_focus_popup;
|
||||
|
||||
char *config_theme;
|
||||
|
||||
|
@ -37,6 +38,12 @@ static void parse_focus(char *name, ParseToken *value)
|
|||
else {
|
||||
config_focus_last_on_desktop = value->data.bool;
|
||||
}
|
||||
} else if (!g_ascii_strcasecmp(name, "cyclingdialog")) {
|
||||
if (value->type != TOKEN_BOOL)
|
||||
yyerror("invalid value");
|
||||
else {
|
||||
config_focus_popup = value->data.bool;
|
||||
}
|
||||
} else
|
||||
yyerror("invalid option");
|
||||
parse_free_token(value);
|
||||
|
@ -95,6 +102,7 @@ void config_startup()
|
|||
config_focus_follow = FALSE;
|
||||
config_focus_last = TRUE;
|
||||
config_focus_last_on_desktop = TRUE;
|
||||
config_focus_popup = TRUE;
|
||||
|
||||
parse_reg_section("focus", NULL, parse_focus);
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ extern gboolean config_focus_follow;
|
|||
extern gboolean config_focus_last;
|
||||
/*! Focus the last focused window as a fallback when switching desktops */
|
||||
extern gboolean config_focus_last_on_desktop;
|
||||
/*! Show a popup dialog while cycling focus */
|
||||
extern gboolean config_focus_popup;
|
||||
|
||||
/* The name of the theme */
|
||||
char *config_theme;
|
||||
|
|
|
@ -144,6 +144,9 @@ static Window event_get_window(XEvent *e)
|
|||
case ConfigureRequest:
|
||||
window = e->xconfigurerequest.window;
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
window = e->xconfigure.window;
|
||||
break;
|
||||
default:
|
||||
#ifdef XKB
|
||||
if (extensions_xkb && e->type == extensions_xkb_event_basep) {
|
||||
|
@ -308,6 +311,16 @@ static gboolean event_ignore(XEvent *e, Client *client)
|
|||
#ifdef DEBUG_FOCUS
|
||||
g_message("found pending FocusIn");
|
||||
#endif
|
||||
/* is the focused window getting a FocusOut/In back to
|
||||
itself? */
|
||||
if (fe.xfocus.window == e->xfocus.window) {
|
||||
#ifdef DEBUG_FOCUS
|
||||
g_message("focused window got an Out/In back to "
|
||||
"itself IGNORED both");
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* once all the FocusOut's have been dealt with, if there
|
||||
is a FocusIn still left and it is valid, then use it */
|
||||
event_process(&fe);
|
||||
|
@ -451,6 +464,21 @@ static void event_handle_root(XEvent *e)
|
|||
else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
|
||||
screen_update_layout();
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
#ifdef XRANDR
|
||||
XRRUpdateConfiguration(e);
|
||||
#endif
|
||||
if (e->xconfigure.width != screen_physical_size.width ||
|
||||
e->xconfigure.height != screen_physical_size.height)
|
||||
screen_resize(e->xconfigure.width, e->xconfigure.height);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
#ifdef VIDMODE
|
||||
if (extensions_vidmode && e->type == extensions_vidmode_event_basep) {
|
||||
g_message("VIDMODE EVENT");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,15 +518,25 @@ static void event_handle_client(Client *client, XEvent *e)
|
|||
}
|
||||
break;
|
||||
case FocusIn:
|
||||
#ifdef DEBUG_FOCUS
|
||||
g_message("FocusIn on client for %lx", client->window);
|
||||
#endif
|
||||
focus_set_client(client);
|
||||
frame_adjust_focus(client->frame, TRUE);
|
||||
break;
|
||||
case FocusOut:
|
||||
#ifdef DEBUG_FOCUS
|
||||
g_message("Focus%s on client for %lx", (e->type==FocusIn?"In":"Out"),
|
||||
client->window);
|
||||
g_message("FocusOut on client for %lx", client->window);
|
||||
#endif
|
||||
/* focus state can affect the stacking layer */
|
||||
client_calc_layer(client);
|
||||
frame_adjust_focus(client->frame, e->type == FocusIn);
|
||||
/* are we a fullscreen window or a transient of one? (checks layer)
|
||||
if we are then we need to be iconified since we are losing focus
|
||||
*/
|
||||
if (client->layer == Layer_Fullscreen && !client->iconic &&
|
||||
!client_search_focus_tree_full(client))
|
||||
/* iconify fullscreen windows when they and their transients
|
||||
aren't focused */
|
||||
client_iconify(client, TRUE, TRUE);
|
||||
frame_adjust_focus(client->frame, FALSE);
|
||||
break;
|
||||
case EnterNotify:
|
||||
if (client_normal(client)) {
|
||||
|
@ -797,11 +835,10 @@ static void event_handle_client(Client *client, XEvent *e)
|
|||
client_setup_decor_and_functions(client);
|
||||
}
|
||||
else if (msgtype == prop_atoms.net_wm_name ||
|
||||
msgtype == prop_atoms.wm_name)
|
||||
client_update_title(client);
|
||||
else if (msgtype == prop_atoms.net_wm_icon_name ||
|
||||
msgtype == prop_atoms.wm_name ||
|
||||
msgtype == prop_atoms.net_wm_icon_name ||
|
||||
msgtype == prop_atoms.wm_icon_name)
|
||||
client_update_icon_title(client);
|
||||
client_update_title(client);
|
||||
else if (msgtype == prop_atoms.wm_class)
|
||||
client_update_class(client);
|
||||
else if (msgtype == prop_atoms.wm_protocols) {
|
||||
|
|
|
@ -7,7 +7,10 @@ gboolean extensions_shape = FALSE;
|
|||
int extensions_shape_event_basep;
|
||||
gboolean extensions_xinerama = FALSE;
|
||||
int extensions_xinerama_event_basep;
|
||||
|
||||
gboolean extensions_randr = FALSE;
|
||||
int extensions_randr_event_basep;
|
||||
gboolean extensions_vidmode = FALSE;
|
||||
int extensions_vidmode_event_basep;
|
||||
|
||||
void extensions_query_all()
|
||||
{
|
||||
|
@ -31,4 +34,16 @@ void extensions_query_all()
|
|||
XineramaQueryExtension(ob_display, &extensions_xinerama_event_basep,
|
||||
&junk);
|
||||
#endif
|
||||
|
||||
#ifdef XRANDR
|
||||
extensions_randr =
|
||||
XRRQueryExtension(ob_display, &extensions_randr_event_basep,
|
||||
&junk);
|
||||
#endif
|
||||
|
||||
#ifdef VIDMODE
|
||||
extensions_vidmode =
|
||||
XF86VidModeQueryExtension(ob_display, &extensions_vidmode_event_basep,
|
||||
&junk);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#ifdef XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
#ifdef XRANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
#ifdef VIDMODE
|
||||
#include <X11/extensions/xf86vmode.h>
|
||||
#endif
|
||||
#include <glib.h>
|
||||
|
||||
/*! Does the display have the XKB extension? */
|
||||
|
@ -28,6 +34,16 @@ extern gboolean extensions_xinerama;
|
|||
/*! Base for events for the Xinerama extension */
|
||||
extern int extensions_xinerama_event_basep;
|
||||
|
||||
/*! Does the display have the RandR extension? */
|
||||
extern gboolean extensions_randr;
|
||||
/*! Base for events for the Randr extension */
|
||||
extern int extensions_randr_event_basep;
|
||||
|
||||
/*! Does the display have the VidMode extension? */
|
||||
extern gboolean extensions_vidmode;
|
||||
/*! Base for events for the VidMode extension */
|
||||
extern int extensions_vidmode_event_basep;
|
||||
|
||||
void extensions_query_all();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "event.h"
|
||||
#include "openbox.h"
|
||||
#include "grab.h"
|
||||
#include "framerender.h"
|
||||
#include "client.h"
|
||||
#include "config.h"
|
||||
|
@ -12,6 +11,7 @@
|
|||
#include "focus.h"
|
||||
#include "parse.h"
|
||||
#include "stacking.h"
|
||||
#include "popup.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
|
@ -23,6 +23,7 @@ GList **focus_order = NULL; /* these lists are created when screen_startup
|
|||
Window focus_backup = None;
|
||||
|
||||
static Client *focus_cycle_target = NULL;
|
||||
static Popup *focus_cycle_popup = NULL;
|
||||
|
||||
void focus_startup()
|
||||
{
|
||||
|
@ -32,6 +33,7 @@ void focus_startup()
|
|||
XSetWindowAttributes attrib;
|
||||
|
||||
focus_client = NULL;
|
||||
focus_cycle_popup = popup_new(TRUE);
|
||||
|
||||
attrib.override_redirect = TRUE;
|
||||
focus_backup = XCreateWindow(ob_display, ob_root,
|
||||
|
@ -54,6 +56,9 @@ void focus_shutdown()
|
|||
g_free(focus_order);
|
||||
focus_order = NULL;
|
||||
|
||||
popup_free(focus_cycle_popup);
|
||||
focus_cycle_popup = NULL;
|
||||
|
||||
XDestroyWindow(ob_display, focus_backup);
|
||||
|
||||
/* reset focus to root */
|
||||
|
@ -98,9 +103,11 @@ void focus_set_client(Client *client)
|
|||
if (client != NULL)
|
||||
push_to_top(client);
|
||||
|
||||
/* set the NET_ACTIVE_WINDOW hint */
|
||||
active = client ? client->window : None;
|
||||
PROP_SET32(ob_root, net_active_window, window, active);
|
||||
/* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
|
||||
if (ob_state != State_Exiting) {
|
||||
active = client ? client->window : None;
|
||||
PROP_SET32(ob_root, net_active_window, window, active);
|
||||
}
|
||||
|
||||
if (focus_client != NULL)
|
||||
dispatch_client(Event_Client_Focus, focus_client, 0, 0);
|
||||
|
@ -206,7 +213,11 @@ void focus_fallback(FallbackType type)
|
|||
|
||||
for (it = focus_order[screen_desktop]; it != NULL; it = it->next)
|
||||
if (type != Fallback_Unfocusing || it->data != old)
|
||||
if (client_normal(it->data) && client_focus(it->data))
|
||||
if (client_normal(it->data) &&
|
||||
/* dont fall back to 'anonymous' fullscreen windows. theres no
|
||||
checks for this is in transient/group fallbacks. */
|
||||
!((Client*)it->data)->fullscreen &&
|
||||
client_focus(it->data))
|
||||
return;
|
||||
|
||||
/* nothing to focus */
|
||||
|
@ -215,38 +226,28 @@ void focus_fallback(FallbackType type)
|
|||
|
||||
static void popup_cycle(Client *c, gboolean show)
|
||||
{
|
||||
XSetWindowAttributes attrib;
|
||||
static Window coords = None;
|
||||
|
||||
if (coords == None) {
|
||||
attrib.override_redirect = TRUE;
|
||||
coords = XCreateWindow(ob_display, ob_root,
|
||||
0, 0, 1, 1, 0, render_depth, InputOutput,
|
||||
render_visual, CWOverrideRedirect, &attrib);
|
||||
g_assert(coords != None);
|
||||
|
||||
grab_pointer(TRUE, None);
|
||||
|
||||
XMapWindow(ob_display, coords);
|
||||
}
|
||||
|
||||
if (!show) {
|
||||
XDestroyWindow(ob_display, coords);
|
||||
coords = None;
|
||||
|
||||
grab_pointer(FALSE, None);
|
||||
popup_hide(focus_cycle_popup);
|
||||
} else {
|
||||
Rect *a;
|
||||
Size s;
|
||||
|
||||
a = screen_area(c->desktop);
|
||||
popup_position(focus_cycle_popup, CenterGravity,
|
||||
a->x + a->width / 2, a->y + a->height / 2);
|
||||
/* popup_size(focus_cycle_popup, a->height/2, a->height/16);
|
||||
popup_show(focus_cycle_popup, c->title,
|
||||
client_icon(c, a->height/16, a->height/16));
|
||||
*/
|
||||
/* XXX the size and the font extents need to be related on some level
|
||||
*/
|
||||
popup_size(focus_cycle_popup, 320, 48);
|
||||
|
||||
framerender_size_popup_label(c->title, &s);
|
||||
XMoveResizeWindow(ob_display, coords,
|
||||
a->x + (a->width - s.width) / 2,
|
||||
a->y + (a->height - s.height) / 2,
|
||||
s.width, s.height);
|
||||
framerender_popup_label(coords, &s, c->title);
|
||||
/* use the transient's parent's title/icon */
|
||||
while (c->transient_for && c->transient_for != TRAN_GROUP)
|
||||
c = c->transient_for;
|
||||
|
||||
popup_show(focus_cycle_popup, (c->iconic ? c->icon_title : c->title),
|
||||
client_icon(c, 48, 48));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,15 +295,18 @@ Client *focus_cycle(gboolean forward, gboolean linear, gboolean done,
|
|||
it = it->prev;
|
||||
if (it == NULL) it = g_list_last(list);
|
||||
}
|
||||
ft = client_focus_target(it->data);
|
||||
if (ft == it->data && client_normal(ft) &&
|
||||
/*ft = client_focus_target(it->data);*/
|
||||
ft = it->data;
|
||||
if (ft->transients == NULL && /*ft == it->data &&*/client_normal(ft) &&
|
||||
(ft->can_focus || ft->focus_notify) &&
|
||||
(ft->desktop == screen_desktop || ft->desktop == DESKTOP_ALL)) {
|
||||
if (focus_cycle_target)
|
||||
frame_adjust_focus(focus_cycle_target->frame, FALSE);
|
||||
focus_cycle_target = ft;
|
||||
frame_adjust_focus(focus_cycle_target->frame, TRUE);
|
||||
popup_cycle(ft, TRUE);
|
||||
if (ft != focus_cycle_target) { /* prevents flicker */
|
||||
if (focus_cycle_target)
|
||||
frame_adjust_focus(focus_cycle_target->frame, FALSE);
|
||||
focus_cycle_target = ft;
|
||||
frame_adjust_focus(focus_cycle_target->frame, TRUE);
|
||||
}
|
||||
popup_cycle(ft, config_focus_popup);
|
||||
return ft;
|
||||
}
|
||||
} while (it != start);
|
||||
|
|
|
@ -218,34 +218,3 @@ static void framerender_close(Frame *self, Appearance *a)
|
|||
theme_button_size, theme_button_size);
|
||||
paint(self->close, a);
|
||||
}
|
||||
|
||||
void framerender_popup_label(Window win, Size *sz, char *text)
|
||||
{
|
||||
Appearance *a;
|
||||
|
||||
a = theme_app_hilite_label;
|
||||
a->texture[0].data.text.string = text;
|
||||
RECT_SET(a->area, 0, 0, sz->width, sz->height);
|
||||
a->texture[0].position = a->area;
|
||||
a->texture[0].position.x += theme_bevel;
|
||||
a->texture[0].position.y += theme_bevel;
|
||||
a->texture[0].position.width -= theme_bevel * 2;
|
||||
a->texture[0].position.height -= theme_bevel * 2;
|
||||
|
||||
XSetWindowBorderWidth(ob_display, win, theme_bwidth);
|
||||
XSetWindowBorder(ob_display, win, theme_b_color->pixel);
|
||||
|
||||
paint(win, a);
|
||||
}
|
||||
|
||||
void framerender_size_popup_label(char *text, Size *sz)
|
||||
{
|
||||
Appearance *a;
|
||||
|
||||
a = theme_app_hilite_label;
|
||||
a->texture[0].data.text.string = text;
|
||||
|
||||
appearance_minsize(a, &sz->width, &sz->height);
|
||||
sz->width += theme_bevel * 2;
|
||||
sz->height += theme_bevel * 2;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,4 @@
|
|||
|
||||
void framerender_frame(Frame *self);
|
||||
|
||||
void framerender_popup_label(Window win, Size *sz, char *text);
|
||||
void framerender_size_popup_label(char *text, Size *sz);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -76,6 +76,16 @@ void menu_startup()
|
|||
menu_add_entry(m, menu_entry_new("--", NULL));
|
||||
a = action_from_string("exit");
|
||||
menu_add_entry(m, menu_entry_new("exit", a));
|
||||
|
||||
m = menu_new("client menu", "client", NULL);
|
||||
a = action_from_string("iconify");
|
||||
menu_add_entry(m, menu_entry_new("iconify", a));
|
||||
a = action_from_string("toggleshade");
|
||||
menu_add_entry(m, menu_entry_new("(un)shade", a));
|
||||
a = action_from_string("togglemaximizefull");
|
||||
menu_add_entry(m, menu_entry_new("(un)maximize", a));
|
||||
a = action_from_string("close");
|
||||
menu_add_entry(m, menu_entry_new("close", a));
|
||||
}
|
||||
|
||||
void menu_shutdown()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "client.h"
|
||||
#include "dispatch.h"
|
||||
#include "openbox.h"
|
||||
#include "popup.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <glib.h>
|
||||
|
@ -13,7 +14,6 @@ Client *moveresize_client = NULL;
|
|||
|
||||
static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
|
||||
|
||||
static Window coords = None;
|
||||
static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
|
||||
static int cur_x, cur_y;
|
||||
static guint button;
|
||||
|
@ -23,6 +23,8 @@ static Corner lockcorner;
|
|||
static guint button_return, button_escape, button_left, button_right,
|
||||
button_up, button_down;
|
||||
|
||||
static Popup *popup = NULL;
|
||||
|
||||
#define POPUP_X (10)
|
||||
#define POPUP_Y (10)
|
||||
|
||||
|
@ -34,29 +36,24 @@ void moveresize_startup()
|
|||
button_right = XKeysymToKeycode(ob_display, XStringToKeysym("Right"));
|
||||
button_up = XKeysymToKeycode(ob_display, XStringToKeysym("Up"));
|
||||
button_down = XKeysymToKeycode(ob_display, XStringToKeysym("Down"));
|
||||
|
||||
popup = popup_new(FALSE);
|
||||
popup_size_to_string(popup, "W: 0000 W: 0000");
|
||||
popup_position(popup, NorthWestGravity, POPUP_X, POPUP_Y);
|
||||
}
|
||||
|
||||
void moveresize_shutdown()
|
||||
{
|
||||
popup_free(popup);
|
||||
popup = NULL;
|
||||
}
|
||||
|
||||
static void popup_coords(char *format, int a, int b)
|
||||
{
|
||||
XSetWindowAttributes attrib;
|
||||
Size s;
|
||||
char *text;
|
||||
|
||||
if (coords == None) {
|
||||
attrib.override_redirect = TRUE;
|
||||
coords = XCreateWindow(ob_display, ob_root,
|
||||
0, 0, 1, 1, 0, render_depth, InputOutput,
|
||||
render_visual, CWOverrideRedirect, &attrib);
|
||||
g_assert(coords != None);
|
||||
|
||||
XMapWindow(ob_display, coords);
|
||||
}
|
||||
|
||||
text = g_strdup_printf(format, a, b);
|
||||
framerender_size_popup_label(text, &s);
|
||||
XMoveResizeWindow(ob_display, coords,
|
||||
POPUP_X, POPUP_Y, s.width, s.height);
|
||||
framerender_popup_label(coords, &s, text);
|
||||
popup_show(popup, text, NULL);
|
||||
g_free(text);
|
||||
}
|
||||
|
||||
|
@ -127,8 +124,7 @@ void moveresize_end(gboolean cancel)
|
|||
grab_keyboard(FALSE);
|
||||
grab_pointer(FALSE, None);
|
||||
|
||||
XDestroyWindow(ob_display, coords);
|
||||
coords = None;
|
||||
popup_hide(popup);
|
||||
|
||||
if (moving) {
|
||||
client_configure(moveresize_client, Corner_TopLeft,
|
||||
|
@ -156,7 +152,9 @@ static void do_move()
|
|||
client_configure(moveresize_client, Corner_TopLeft, cur_x, cur_y,
|
||||
start_cw, start_ch, TRUE, FALSE);
|
||||
|
||||
popup_coords("X: %d Y: %d", moveresize_client->frame->area.x,
|
||||
/* this would be better with a fixed width font ... XXX can do it better
|
||||
if there are 2 text boxes */
|
||||
popup_coords("X: %4d Y: %4d", moveresize_client->frame->area.x,
|
||||
moveresize_client->frame->area.y);
|
||||
}
|
||||
|
||||
|
@ -178,7 +176,9 @@ static void do_resize()
|
|||
client_configure(moveresize_client, lockcorner, moveresize_client->area.x,
|
||||
moveresize_client->area.y, cur_x, cur_y, TRUE, FALSE);
|
||||
|
||||
popup_coords("W: %d H: %d", moveresize_client->logical_size.width,
|
||||
/* this would be better with a fixed width font ... XXX can do it better
|
||||
if there are 2 text boxes */
|
||||
popup_coords("W: %4d H: %4d", moveresize_client->logical_size.width,
|
||||
moveresize_client->logical_size.height);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ extern gboolean moveresize_in_progress;
|
|||
extern Client *moveresize_client;
|
||||
|
||||
void moveresize_startup();
|
||||
void moveresize_shutdown();
|
||||
|
||||
void moveresize_start(Client *c, int x, int y, guint button, guint32 corner);
|
||||
void moveresize_end(gboolean cancel);
|
||||
|
|
|
@ -166,7 +166,6 @@ int main(int argc, char **argv)
|
|||
font_startup();
|
||||
theme_startup();
|
||||
event_startup();
|
||||
moveresize_startup();
|
||||
grab_startup();
|
||||
plugin_startup();
|
||||
/* load the plugins specified in the pluginrc */
|
||||
|
@ -187,6 +186,7 @@ int main(int argc, char **argv)
|
|||
menu_startup();
|
||||
frame_startup();
|
||||
stacking_startup();
|
||||
moveresize_startup();
|
||||
focus_startup();
|
||||
screen_startup();
|
||||
group_startup();
|
||||
|
@ -210,6 +210,7 @@ int main(int argc, char **argv)
|
|||
group_shutdown();
|
||||
screen_shutdown();
|
||||
focus_shutdown();
|
||||
moveresize_shutdown();
|
||||
stacking_shutdown();
|
||||
frame_shutdown();
|
||||
menu_shutdown();
|
||||
|
|
|
@ -11,7 +11,7 @@ typedef enum {
|
|||
TOKEN_INTEGER = INTEGER,
|
||||
TOKEN_STRING = STRING,
|
||||
TOKEN_IDENTIFIER = IDENTIFIER,
|
||||
TOKEN_BOOL = BOOL,
|
||||
TOKEN_BOOL = BOOLEAN,
|
||||
TOKEN_LIST,
|
||||
TOKEN_LBRACE = '{',
|
||||
TOKEN_RBRACE = '}',
|
||||
|
|
|
@ -31,7 +31,7 @@ bool ([tT][rR][uU][eE]|[fF][aA][lL][sS][eE]|[yY][eE][sS]|[nN][oO]|[oO][nN]|[oO][
|
|||
{bool} { yylval.bool = (!g_ascii_strcasecmp("true", yytext) ||
|
||||
!g_ascii_strcasecmp("yes", yytext) ||
|
||||
!g_ascii_strcasecmp("on", yytext));
|
||||
return BOOL;
|
||||
return BOOLEAN;
|
||||
}
|
||||
{identifier} { yylval.identifier = g_strdup(yytext); return IDENTIFIER; }
|
||||
[{}()\[\]=,] { yylval.character = *yytext; return *yytext; }
|
||||
|
|
|
@ -41,7 +41,7 @@ void parse_set_section(char *section);
|
|||
%token <integer> INTEGER
|
||||
%token <string> STRING
|
||||
%token <identifier> IDENTIFIER
|
||||
%token <bool> BOOL
|
||||
%token <bool> BOOLEAN
|
||||
%token <character> '('
|
||||
%token <character> ')'
|
||||
%token <character> '{'
|
||||
|
@ -78,7 +78,7 @@ token:
|
|||
| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; }
|
||||
| STRING { t.type = TOKEN_STRING; t.data.string = $1; }
|
||||
| IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; }
|
||||
| BOOL { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| list { t.type = TOKEN_LIST; t.data.list = $1; }
|
||||
| '{' { t.type = $1; t.data.character = $1; }
|
||||
| '}' { t.type = $1; t.data.character = $1; }
|
||||
|
@ -107,7 +107,7 @@ listtoken:
|
|||
| INTEGER { t.type = TOKEN_INTEGER; t.data.integer = $1; }
|
||||
| STRING { t.type = TOKEN_STRING; t.data.string = $1; }
|
||||
| IDENTIFIER { t.type = TOKEN_IDENTIFIER; t.data.identifier = $1; }
|
||||
| BOOL { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| BOOLEAN { t.type = TOKEN_BOOL; t.data.bool = $1; }
|
||||
| list { t.type = TOKEN_LIST; t.data.list = $1; }
|
||||
| '{' { t.type = $1; t.data.character = $1; }
|
||||
| '}' { t.type = $1; t.data.character = $1; }
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "frame.h"
|
||||
#include "focus.h"
|
||||
#include "dispatch.h"
|
||||
#include "extensions.h"
|
||||
#include "../render/render.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
@ -16,7 +17,7 @@
|
|||
#endif
|
||||
|
||||
/*! The event mask to grab on the root window */
|
||||
#define ROOT_EVENTMASK (/*ColormapChangeMask |*/ PropertyChangeMask | \
|
||||
#define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \
|
||||
EnterWindowMask | LeaveWindowMask | \
|
||||
SubstructureNotifyMask | SubstructureRedirectMask | \
|
||||
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
|
||||
|
@ -160,7 +161,8 @@ void screen_startup()
|
|||
guint i;
|
||||
|
||||
/* get the initial size */
|
||||
screen_resize();
|
||||
screen_resize(WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)),
|
||||
HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)));
|
||||
|
||||
/* set the names */
|
||||
screen_desktop_names = g_new(char*,
|
||||
|
@ -201,14 +203,14 @@ void screen_shutdown()
|
|||
g_free(area);
|
||||
}
|
||||
|
||||
void screen_resize()
|
||||
void screen_resize(int w, int h)
|
||||
{
|
||||
/* XXX RandR support here? */
|
||||
GList *it;
|
||||
guint32 geometry[2];
|
||||
|
||||
/* Set the _NET_DESKTOP_GEOMETRY hint */
|
||||
geometry[0] = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
|
||||
geometry[1] = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen));
|
||||
geometry[0] = w;
|
||||
geometry[1] = h;
|
||||
PROP_SETA32(ob_root, net_desktop_geometry, cardinal, geometry, 2);
|
||||
screen_physical_size.width = geometry[0];
|
||||
screen_physical_size.height = geometry[1];
|
||||
|
@ -218,7 +220,8 @@ void screen_resize()
|
|||
|
||||
screen_update_struts();
|
||||
|
||||
/* XXX adjust more stuff ? */
|
||||
for (it = client_list; it; it = it->next)
|
||||
client_move_onscreen(it->data);
|
||||
}
|
||||
|
||||
void screen_set_num_desktops(guint num)
|
||||
|
|
|
@ -43,7 +43,7 @@ void screen_startup();
|
|||
void screen_shutdown();
|
||||
|
||||
/*! Figure out the new size of the screen and adjust stuff for it */
|
||||
void screen_resize();
|
||||
void screen_resize(int w, int h);
|
||||
|
||||
/*! Change the number of available desktops */
|
||||
void screen_set_num_desktops(guint num);
|
||||
|
|
|
@ -70,7 +70,7 @@ static GList *find_lowest_transient(Client *c)
|
|||
static void raise_recursive(Client *client)
|
||||
{
|
||||
Window wins[2]; /* only ever restack 2 windows. */
|
||||
GList *it;
|
||||
GList *it, *low;
|
||||
GSList *sit;
|
||||
|
||||
g_assert(stacking_list != NULL); /* this would be bad */
|
||||
|
@ -86,15 +86,15 @@ static void raise_recursive(Client *client)
|
|||
/* find 'it' where it is the positiion in the stacking order where
|
||||
'client' will be inserted *before* */
|
||||
|
||||
it = find_lowest_transient(client);
|
||||
if (it)
|
||||
it = it->next;
|
||||
else {
|
||||
/* the stacking list is from highest to lowest */
|
||||
for (it = stacking_list; it; it = it->next) {
|
||||
if (client->layer >= ((Client*)it->data)->layer)
|
||||
break;
|
||||
low = find_lowest_transient(client);
|
||||
/* the stacking list is from highest to lowest */
|
||||
for (it = g_list_last(stacking_list); it; it = it->prev) {
|
||||
if (it == low || client->layer < ((Client*)it->data)->layer) {
|
||||
it = it->next;
|
||||
break;
|
||||
}
|
||||
if (it == stacking_list)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -56,12 +56,15 @@ gboolean kbind(GList *keylist, Action *action)
|
|||
|
||||
if (!(tree = tree_build(keylist)))
|
||||
return FALSE;
|
||||
|
||||
if ((t = tree_find(tree, &conflict)) != NULL) {
|
||||
/* already bound to something */
|
||||
g_message("keychain is already bound");
|
||||
/* already bound to something, use the existing tree */
|
||||
tree_destroy(tree);
|
||||
return FALSE;
|
||||
}
|
||||
tree = NULL;
|
||||
} else
|
||||
t = tree;
|
||||
while (t->first_child) t = t->first_child;
|
||||
|
||||
if (conflict) {
|
||||
g_message("conflict with binding");
|
||||
tree_destroy(tree);
|
||||
|
@ -73,12 +76,10 @@ gboolean kbind(GList *keylist, Action *action)
|
|||
grab_keys(FALSE);
|
||||
|
||||
/* set the action */
|
||||
t = tree;
|
||||
while (t->first_child) t = t->first_child;
|
||||
t->action = action;
|
||||
t->actions = g_slist_append(t->actions, action);
|
||||
/* assimilate this built tree into the main tree. assimilation
|
||||
destroys/uses the tree */
|
||||
tree_assimilate(tree);
|
||||
if (tree) tree_assimilate(tree);
|
||||
|
||||
grab_keys(TRUE);
|
||||
grab_server(FALSE);
|
||||
|
@ -100,17 +101,25 @@ static void event(ObEvent *e, void *foo)
|
|||
if (e->data.x.e->xkey.keycode == button_return)
|
||||
done = TRUE;
|
||||
else if (e->data.x.e->xkey.keycode == button_escape) {
|
||||
grabbed_key->action->data.cycle.cancel = TRUE;
|
||||
GSList *it;
|
||||
for (it = grabbed_key->actions; it; it = it->next) {
|
||||
Action *act = it->data;
|
||||
act->data.cycle.cancel = TRUE;
|
||||
}
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
grabbed_key->action->data.cycle.final = TRUE;
|
||||
grabbed_key->action->func(&grabbed_key->action->data);
|
||||
grab_keyboard(FALSE);
|
||||
grabbed_key = NULL;
|
||||
reset_chains();
|
||||
return;
|
||||
if (done) {
|
||||
GSList *it;
|
||||
for (it = grabbed_key->actions; it; it = it->next) {
|
||||
Action *act = it->data;
|
||||
act->data.cycle.final = TRUE;
|
||||
act->func(&act->data);
|
||||
grab_keyboard(FALSE);
|
||||
grabbed_key = NULL;
|
||||
reset_chains();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e->type == Event_X_KeyRelease)
|
||||
|
@ -140,20 +149,24 @@ static void event(ObEvent *e, void *foo)
|
|||
}
|
||||
curpos = p;
|
||||
} else {
|
||||
if (p->action->func != NULL) {
|
||||
p->action->data.any.c = focus_client;
|
||||
GSList *it;
|
||||
for (it = p->actions; it; it = it->next) {
|
||||
Action *act = it->data;
|
||||
if (act->func != NULL) {
|
||||
act->data.any.c = focus_client;
|
||||
|
||||
if (p->action->func == action_cycle_windows) {
|
||||
p->action->data.cycle.final = FALSE;
|
||||
p->action->data.cycle.cancel = FALSE;
|
||||
}
|
||||
if (act->func == action_cycle_windows) {
|
||||
act->data.cycle.final = FALSE;
|
||||
act->data.cycle.cancel = FALSE;
|
||||
}
|
||||
|
||||
p->action->func(&p->action->data);
|
||||
act->func(&act->data);
|
||||
|
||||
if (p->action->func == action_cycle_windows &&
|
||||
!grabbed_key) {
|
||||
grab_keyboard(TRUE);
|
||||
grabbed_key = p;
|
||||
if (act->func == action_cycle_windows &&
|
||||
!grabbed_key) {
|
||||
grab_keyboard(TRUE);
|
||||
grabbed_key = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,13 @@ void tree_destroy(KeyBindingTree *tree)
|
|||
c = tree->first_child;
|
||||
if (c == NULL) {
|
||||
GList *it;
|
||||
GSList *sit;
|
||||
for (it = tree->keylist; it != NULL; it = it->next)
|
||||
g_free(it->data);
|
||||
g_list_free(tree->keylist);
|
||||
action_free(tree->action);
|
||||
for (it = tree->actions; it != NULL; it = it->next)
|
||||
action_free(it->data);
|
||||
g_slist_free(tree->actions);
|
||||
}
|
||||
g_free(tree);
|
||||
tree = c;
|
||||
|
|
|
@ -8,7 +8,7 @@ typedef struct KeyBindingTree {
|
|||
guint state;
|
||||
guint key;
|
||||
GList *keylist;
|
||||
Action *action;
|
||||
GSList *actions; /* list of Action pointers */
|
||||
|
||||
/* the next binding in the tree at the same level */
|
||||
struct KeyBindingTree *next_sibling;
|
||||
|
|
|
@ -96,9 +96,13 @@ static void clearall()
|
|||
int j;
|
||||
|
||||
MouseBinding *b = it->data;
|
||||
for (j = 0; j < NUM_MOUSEACTION; ++j)
|
||||
if (b->action[j] != NULL)
|
||||
action_free(b->action[j]);
|
||||
for (j = 0; j < NUM_MOUSEACTION; ++j) {
|
||||
GSList *it;
|
||||
for (it = b->actions[j]; it; it = it->next) {
|
||||
action_free(it->data);
|
||||
}
|
||||
g_slist_free(b->actions[j]);
|
||||
}
|
||||
g_free(b);
|
||||
}
|
||||
g_slist_free(bound_contexts[i]);
|
||||
|
@ -119,17 +123,20 @@ static void fire_button(MouseAction a, Context context, Client *c, guint state,
|
|||
/* if not bound, then nothing to do! */
|
||||
if (it == NULL) return;
|
||||
|
||||
if (b->action[a] != NULL && b->action[a]->func != NULL) {
|
||||
b->action[a]->data.any.c = c;
|
||||
for (it = b->actions[a]; it; it = it->next) {
|
||||
Action *act = it->data;
|
||||
if (act->func != NULL) {
|
||||
act->data.any.c = c;
|
||||
|
||||
g_assert(b->action[a]->func != action_moveresize);
|
||||
g_assert(act->func != action_moveresize);
|
||||
|
||||
if (b->action[a]->func == action_showmenu) {
|
||||
b->action[a]->data.showmenu.x = x;
|
||||
b->action[a]->data.showmenu.y = y;
|
||||
if (act->func == action_showmenu) {
|
||||
act->data.showmenu.x = x;
|
||||
act->data.showmenu.y = y;
|
||||
}
|
||||
|
||||
act->func(&act->data);
|
||||
}
|
||||
|
||||
b->action[a]->func(&b->action[a]->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,24 +155,27 @@ static void fire_motion(MouseAction a, Context context, Client *c,
|
|||
/* if not bound, then nothing to do! */
|
||||
if (it == NULL) return;
|
||||
|
||||
if (b->action[a] != NULL && b->action[a]->func != NULL) {
|
||||
b->action[a]->data.any.c = c;
|
||||
for (it = b->actions[a]; it; it = it->next) {
|
||||
Action *act = it->data;
|
||||
if (act->func != NULL) {
|
||||
act->data.any.c = c;
|
||||
|
||||
if (b->action[a]->func == action_moveresize) {
|
||||
b->action[a]->data.moveresize.x = x_root;
|
||||
b->action[a]->data.moveresize.y = y_root;
|
||||
b->action[a]->data.moveresize.button = button;
|
||||
if (!(b->action[a]->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_move ||
|
||||
b->action[a]->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_move_keyboard ||
|
||||
b->action[a]->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_size_keyboard))
|
||||
b->action[a]->data.moveresize.corner = corner;
|
||||
} else
|
||||
g_assert_not_reached();
|
||||
if (act->func == action_moveresize) {
|
||||
act->data.moveresize.x = x_root;
|
||||
act->data.moveresize.y = y_root;
|
||||
act->data.moveresize.button = button;
|
||||
if (!(act->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_move ||
|
||||
act->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_move_keyboard ||
|
||||
act->data.moveresize.corner ==
|
||||
prop_atoms.net_wm_moveresize_size_keyboard))
|
||||
act->data.moveresize.corner = corner;
|
||||
} else
|
||||
g_assert_not_reached();
|
||||
|
||||
b->action[a]->func(&b->action[a]->data);
|
||||
act->func(&act->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,12 +348,7 @@ gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
|
|||
for (it = bound_contexts[context]; it != NULL; it = it->next){
|
||||
b = it->data;
|
||||
if (b->state == state && b->button == button) {
|
||||
/* already bound */
|
||||
if (b->action[mact] != NULL) {
|
||||
g_warning("duplicate binding");
|
||||
return FALSE;
|
||||
}
|
||||
b->action[mact] = action;
|
||||
b->actions[mact] = g_slist_append(b->actions[mact], action);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -354,7 +359,7 @@ gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
|
|||
b = g_new0(MouseBinding, 1);
|
||||
b->state = state;
|
||||
b->button = button;
|
||||
b->action[mact] = action;
|
||||
b->actions[mact] = g_slist_append(NULL, action);
|
||||
bound_contexts[context] = g_slist_append(bound_contexts[context], b);
|
||||
|
||||
grab_all_clients(TRUE);
|
||||
|
|
|
@ -15,7 +15,7 @@ typedef enum {
|
|||
typedef struct {
|
||||
guint state;
|
||||
guint button;
|
||||
Action *action[NUM_MOUSEACTION];
|
||||
GSList *actions[NUM_MOUSEACTION]; /* lists of Action pointers */
|
||||
} MouseBinding;
|
||||
|
||||
gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include <glib.h>
|
||||
#include "../kernel/geom.h"
|
||||
|
||||
#define ELIPSES "..."
|
||||
#define ELIPSES_LENGTH(font, shadow, offset) \
|
||||
(font->elipses_length + (shadow ? offset : 0))
|
||||
|
||||
void font_startup(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
|
@ -38,6 +42,11 @@ static void measure_height(ObFont *f)
|
|||
XftTextExtentsUtf8(ob_display, f->xftfont,
|
||||
(FcChar8*)str, strlen(str), &info);
|
||||
f->height = (signed) info.height;
|
||||
|
||||
/* measure an elipses */
|
||||
XftTextExtentsUtf8(ob_display, f->xftfont,
|
||||
(FcChar8*)ELIPSES, strlen(ELIPSES), &info);
|
||||
f->elipses_length = (signed) info.xOff;
|
||||
}
|
||||
|
||||
ObFont *font_open(char *fontstring)
|
||||
|
@ -98,9 +107,10 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
|
|||
{
|
||||
int x,y,w,h;
|
||||
XftColor c;
|
||||
char *text;
|
||||
int m;
|
||||
GString *text;
|
||||
int m, em;
|
||||
size_t l;
|
||||
gboolean shortened = FALSE;
|
||||
|
||||
y = position->y;
|
||||
w = position->width;
|
||||
|
@ -110,12 +120,22 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
|
|||
y -= (2 * (t->font->xftfont->ascent + t->font->xftfont->descent) -
|
||||
(t->font->height + h) - 1) / 2;
|
||||
|
||||
text = g_strdup(t->string);
|
||||
l = strlen(text);
|
||||
m = font_measure_string(t->font, text, t->shadow, t->offset);
|
||||
text = g_string_new(t->string);
|
||||
l = g_utf8_strlen(text->str, -1);
|
||||
m = font_measure_string(t->font, text->str, t->shadow, t->offset);
|
||||
while (l && m > position->width) {
|
||||
text[--l] = '\0';
|
||||
m = font_measure_string(t->font, text, t->shadow, t->offset);
|
||||
shortened = TRUE;
|
||||
/* remove a character from the middle */
|
||||
text = g_string_erase(text, l-- / 2, 1);
|
||||
em = ELIPSES_LENGTH(t->font, t->shadow, t->offset);
|
||||
/* if the elipses are too large, don't show them at all */
|
||||
if (em > position->width)
|
||||
shortened = FALSE;
|
||||
m = font_measure_string(t->font, text->str, t->shadow, t->offset) + em;
|
||||
}
|
||||
if (shortened) {
|
||||
text = g_string_insert(text, (l + 1) / 2, ELIPSES);
|
||||
l += 3;
|
||||
}
|
||||
if (!l) return;
|
||||
|
||||
|
@ -147,7 +167,7 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
|
|||
}
|
||||
XftDrawStringUtf8(d, &c, t->font->xftfont, x + t->offset,
|
||||
t->font->xftfont->ascent + y + t->offset,
|
||||
(FcChar8*)text, l);
|
||||
(FcChar8*)text->str, l);
|
||||
}
|
||||
c.color.red = t->color->r | t->color->r << 8;
|
||||
c.color.green = t->color->g | t->color->g << 8;
|
||||
|
@ -157,6 +177,6 @@ void font_draw(XftDraw *d, TextureText *t, Rect *position)
|
|||
|
||||
XftDrawStringUtf8(d, &c, t->font->xftfont, x,
|
||||
t->font->xftfont->ascent + y,
|
||||
(FcChar8*)text, l);
|
||||
(FcChar8*)text->str, l);
|
||||
return;
|
||||
}
|
||||
|
|
120
render/image.c
120
render/image.c
|
@ -5,66 +5,72 @@
|
|||
void image_draw(pixel32 *target, TextureRGBA *rgba, Rect *position,
|
||||
Rect *surarea)
|
||||
{
|
||||
unsigned long *draw = rgba->data;
|
||||
int c, sfw, sfh;
|
||||
unsigned int i, e;
|
||||
sfw = position->width;
|
||||
sfh = position->height;
|
||||
gulong *draw = rgba->data;
|
||||
guint c, i, e, t, sfw, sfh;
|
||||
sfw = position->width;
|
||||
sfh = position->height;
|
||||
|
||||
/* it would be nice if this worked, but this function is well broken in these
|
||||
cercumstances. */
|
||||
g_assert(position->width == surarea->width &&
|
||||
position->height == surarea->height);
|
||||
/* it would be nice if this worked, but this function is well broken in
|
||||
these circumstances. */
|
||||
g_assert(position->width == surarea->width &&
|
||||
position->height == surarea->height);
|
||||
|
||||
g_assert(rgba->data != NULL);
|
||||
g_assert(rgba->data != NULL);
|
||||
|
||||
if ((rgba->width != sfw || rgba->height != sfh) &&
|
||||
(rgba->width != rgba->cwidth || rgba->height != rgba->cheight)) {
|
||||
double dx = rgba->width / (double)sfw;
|
||||
double dy = rgba->height / (double)sfh;
|
||||
double px = 0.0;
|
||||
double py = 0.0;
|
||||
int iy = 0;
|
||||
if ((rgba->width != sfw || rgba->height != sfh) &&
|
||||
(rgba->width != rgba->cwidth || rgba->height != rgba->cheight)) {
|
||||
double dx = rgba->width / (double)sfw;
|
||||
double dy = rgba->height / (double)sfh;
|
||||
double px = 0.0;
|
||||
double py = 0.0;
|
||||
int iy = 0;
|
||||
|
||||
/* scale it and cache it */
|
||||
if (rgba->cache != NULL)
|
||||
g_free(rgba->cache);
|
||||
rgba->cache = g_new(unsigned long, sfw * sfh);
|
||||
rgba->cwidth = sfw;
|
||||
rgba->cheight = sfh;
|
||||
for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
|
||||
rgba->cache[i] = rgba->data[(int)px + iy];
|
||||
if (++c >= sfw) {
|
||||
c = 0;
|
||||
px = 0;
|
||||
py += dy;
|
||||
iy = (int)py * rgba->width;
|
||||
} else
|
||||
px += dx;
|
||||
/* scale it and cache it */
|
||||
if (rgba->cache != NULL)
|
||||
g_free(rgba->cache);
|
||||
rgba->cache = g_new(unsigned long, sfw * sfh);
|
||||
rgba->cwidth = sfw;
|
||||
rgba->cheight = sfh;
|
||||
for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
|
||||
rgba->cache[i] = rgba->data[(int)px + iy];
|
||||
if (++c >= sfw) {
|
||||
c = 0;
|
||||
px = 0;
|
||||
py += dy;
|
||||
iy = (int)py * rgba->width;
|
||||
} else
|
||||
px += dx;
|
||||
}
|
||||
|
||||
/* do we use the cache we may have just created, or the original? */
|
||||
if (rgba->width != sfw || rgba->height != sfh)
|
||||
draw = rgba->cache;
|
||||
|
||||
/* apply the alpha channel */
|
||||
for (i = 0, c = 0, t = position->x, e = sfw*sfh; i < e; ++i, ++t) {
|
||||
guchar alpha, r, g, b, bgr, bgg, bgb;
|
||||
|
||||
alpha = draw[i] >> 24;
|
||||
r = draw[i] >> 16;
|
||||
g = draw[i] >> 8;
|
||||
b = draw[i];
|
||||
|
||||
if (c >= sfw) {
|
||||
c = 0;
|
||||
t += surarea->width - sfw;
|
||||
}
|
||||
|
||||
/* background color */
|
||||
bgr = target[t] >> default_red_shift;
|
||||
bgg = target[t] >> default_green_shift;
|
||||
bgb = target[t] >> default_blue_shift;
|
||||
|
||||
r = bgr + (((r - bgr) * alpha) >> 8);
|
||||
g = bgg + (((g - bgg) * alpha) >> 8);
|
||||
b = bgb + (((b - bgb) * alpha) >> 8);
|
||||
|
||||
target[t] = (r << default_red_shift) | (g << default_green_shift) |
|
||||
(b << default_blue_shift);
|
||||
}
|
||||
}
|
||||
|
||||
/* do we use the cache we may have just created, or the original? */
|
||||
if (rgba->width != sfw || rgba->height != sfh)
|
||||
draw = rgba->cache;
|
||||
|
||||
/* apply the alpha channel */
|
||||
for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
|
||||
unsigned char alpha = draw[i] >> 24;
|
||||
unsigned char r = draw[i] >> 16;
|
||||
unsigned char g = draw[i] >> 8;
|
||||
unsigned char b = draw[i];
|
||||
|
||||
/* background color */
|
||||
unsigned char bgr = target[i] >> default_red_shift;
|
||||
unsigned char bgg = target[i] >> default_green_shift;
|
||||
unsigned char bgb = target[i] >> default_blue_shift;
|
||||
|
||||
r = bgr + (((r - bgr) * alpha) >> 8);
|
||||
g = bgg + (((g - bgg) * alpha) >> 8);
|
||||
b = bgb + (((b - bgb) * alpha) >> 8);
|
||||
|
||||
target[i] = (r << default_red_shift) | (g << default_green_shift) |
|
||||
(b << default_blue_shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "mask.h"
|
||||
#include "color.h"
|
||||
#include "image.h"
|
||||
#include "theme.h"
|
||||
#include "kernel/openbox.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
|
@ -421,6 +422,7 @@ void pixel32_to_pixmap(pixel32 *in, Pixmap out, int x, int y, int w, int h)
|
|||
void appearance_minsize(Appearance *l, int *w, int *h)
|
||||
{
|
||||
int i;
|
||||
int m;
|
||||
*w = *h = 1;
|
||||
|
||||
switch (l->surface.type) {
|
||||
|
@ -437,20 +439,22 @@ void appearance_minsize(Appearance *l, int *w, int *h)
|
|||
} else if (l->surface.data.planar.border)
|
||||
*w = *h = 2;
|
||||
|
||||
for (i = 0; i < l->textures; ++i)
|
||||
for (i = 0; i < l->textures; ++i) {
|
||||
switch (l->texture[i].type) {
|
||||
case Bitmask:
|
||||
*w += l->texture[i].data.mask.mask->w;
|
||||
*h += l->texture[i].data.mask.mask->h;
|
||||
break;
|
||||
case Text:
|
||||
*w +=font_measure_string(l->texture[i].data.text.font,
|
||||
l->texture[i].data.text.string,
|
||||
l->texture[i].data.text.shadow,
|
||||
l->texture[i].data.text.offset);
|
||||
*h += font_height(l->texture[i].data.text.font,
|
||||
l->texture[i].data.text.shadow,
|
||||
l->texture[i].data.text.offset);
|
||||
m = font_measure_string(l->texture[i].data.text.font,
|
||||
l->texture[i].data.text.string,
|
||||
l->texture[i].data.text.shadow,
|
||||
l->texture[i].data.text.offset);
|
||||
*w += m;
|
||||
m = font_height(l->texture[i].data.text.font,
|
||||
l->texture[i].data.text.shadow,
|
||||
l->texture[i].data.text.offset);
|
||||
*h += m;
|
||||
break;
|
||||
case RGBA:
|
||||
*w += l->texture[i].data.rgba.width;
|
||||
|
@ -458,7 +462,8 @@ void appearance_minsize(Appearance *l, int *w, int *h)
|
|||
break;
|
||||
case NoTexture:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct Surface {
|
|||
typedef struct {
|
||||
XftFont *xftfont;
|
||||
int height;
|
||||
int elipses_length;
|
||||
} ObFont;
|
||||
|
||||
typedef enum {
|
||||
|
@ -109,12 +110,12 @@ typedef struct TextureMask {
|
|||
} TextureMask;
|
||||
|
||||
typedef struct TextureRGBA {
|
||||
int width;
|
||||
int height;
|
||||
guint width;
|
||||
guint height;
|
||||
unsigned long *data;
|
||||
/* cached scaled so we don't have to scale often */
|
||||
int cwidth;
|
||||
int cheight;
|
||||
guint cwidth;
|
||||
guint cheight;
|
||||
unsigned long *cache;
|
||||
} TextureRGBA;
|
||||
|
||||
|
|
|
@ -93,8 +93,11 @@ Appearance *theme_a_menu_item;
|
|||
Appearance *theme_a_menu_disabled;
|
||||
Appearance *theme_a_menu_hilite;
|
||||
|
||||
Appearance *theme_app_hilite_bg;
|
||||
Appearance *theme_app_unhilite_bg;
|
||||
Appearance *theme_app_hilite_label;
|
||||
Appearance *theme_app_unhilite_label;
|
||||
Appearance *theme_app_icon;
|
||||
|
||||
void theme_startup()
|
||||
{
|
||||
|
@ -151,8 +154,11 @@ void theme_startup()
|
|||
theme_a_menu_disabled = appearance_new(Surface_Planar, 1);
|
||||
theme_a_menu_hilite = appearance_new(Surface_Planar, 1);
|
||||
|
||||
theme_app_hilite_bg = appearance_new(Surface_Planar, 0);
|
||||
theme_app_unhilite_bg = appearance_new(Surface_Planar, 0);
|
||||
theme_app_hilite_label = appearance_new(Surface_Planar, 1);
|
||||
theme_app_unhilite_label = appearance_new(Surface_Planar, 1);
|
||||
theme_app_icon = appearance_new(Surface_Planar, 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -221,8 +227,11 @@ void theme_shutdown()
|
|||
appearance_free(theme_a_menu_item);
|
||||
appearance_free(theme_a_menu_disabled);
|
||||
appearance_free(theme_a_menu_hilite);
|
||||
appearance_free(theme_app_hilite_bg);
|
||||
appearance_free(theme_app_unhilite_bg);
|
||||
appearance_free(theme_app_hilite_label);
|
||||
appearance_free(theme_app_unhilite_label);
|
||||
appearance_free(theme_app_icon);
|
||||
}
|
||||
|
||||
static XrmDatabase loaddb(char *theme)
|
||||
|
@ -330,7 +339,7 @@ static gboolean read_mask(XrmDatabase db, char *rname, char *theme,
|
|||
if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) &&
|
||||
retvalue.addr != NULL) {
|
||||
|
||||
button_dir = g_strdup_printf("%s_buttons", theme);
|
||||
button_dir = g_strdup_printf("%s_data", theme);
|
||||
|
||||
s = g_build_filename(g_get_home_dir(), ".openbox", "themes",
|
||||
button_dir, retvalue.addr, NULL);
|
||||
|
@ -348,7 +357,7 @@ static gboolean read_mask(XrmDatabase db, char *rname, char *theme,
|
|||
|
||||
g_free(s);
|
||||
themename = g_path_get_basename(theme);
|
||||
s = g_strdup_printf("%s/%s_buttons/%s", theme,
|
||||
s = g_strdup_printf("%s/%s_data/%s", theme,
|
||||
themename, retvalue.addr);
|
||||
g_free(themename);
|
||||
if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) ==
|
||||
|
@ -728,26 +737,15 @@ char *theme_load(char *theme)
|
|||
if (!read_appearance(db, "menu.hilite", theme_a_menu_hilite))
|
||||
set_default_appearance(theme_a_menu_hilite);
|
||||
|
||||
/* read the appearances for rendering non-decorations. these cannot be
|
||||
parent-relative */
|
||||
if (theme_a_focused_label->surface.data.planar.grad !=
|
||||
Background_ParentRelative) {
|
||||
if (!read_appearance(db, "window.label.focus", theme_app_hilite_label))
|
||||
set_default_appearance(theme_app_hilite_label);
|
||||
} else {
|
||||
if (!read_appearance(db, "window.title.focus", theme_app_hilite_label))
|
||||
set_default_appearance(theme_app_hilite_label);
|
||||
}
|
||||
if (theme_a_unfocused_label->surface.data.planar.grad !=
|
||||
Background_ParentRelative) {
|
||||
if (!read_appearance(db, "window.label.unfocus",
|
||||
theme_app_unhilite_label))
|
||||
set_default_appearance(theme_app_unhilite_label);
|
||||
} else {
|
||||
if (!read_appearance(db, "window.title.unfocus",
|
||||
theme_app_unhilite_label))
|
||||
set_default_appearance(theme_app_unhilite_label);
|
||||
}
|
||||
/* read the appearances for rendering non-decorations */
|
||||
if (!read_appearance(db, "window.title.focus", theme_app_hilite_bg))
|
||||
set_default_appearance(theme_app_hilite_bg);
|
||||
if (!read_appearance(db, "window.label.focus", theme_app_hilite_label))
|
||||
set_default_appearance(theme_app_hilite_label);
|
||||
if (!read_appearance(db, "window.title.unfocus", theme_app_unhilite_bg))
|
||||
set_default_appearance(theme_app_unhilite_bg);
|
||||
if (!read_appearance(db, "window.label.unfocus", theme_app_unhilite_label))
|
||||
set_default_appearance(theme_app_unhilite_label);
|
||||
|
||||
/* read buttons textures */
|
||||
if (!read_appearance(db, "window.button.pressed.focus",
|
||||
|
@ -817,8 +815,8 @@ char *theme_load(char *theme)
|
|||
/* set up the textures */
|
||||
theme_a_focused_label->texture[0].type =
|
||||
theme_app_hilite_label->texture[0].type = Text;
|
||||
theme_a_focused_label->texture[0].data.text.justify =
|
||||
theme_app_hilite_label->texture[0].data.text.justify = winjust;
|
||||
theme_a_focused_label->texture[0].data.text.justify = winjust;
|
||||
theme_app_hilite_label->texture[0].data.text.justify = Justify_Left;
|
||||
theme_a_focused_label->texture[0].data.text.font =
|
||||
theme_app_hilite_label->texture[0].data.text.font = theme_winfont;
|
||||
theme_a_focused_label->texture[0].data.text.shadow =
|
||||
|
@ -836,8 +834,8 @@ char *theme_load(char *theme)
|
|||
|
||||
theme_a_unfocused_label->texture[0].type =
|
||||
theme_app_unhilite_label->texture[0].type = Text;
|
||||
theme_a_unfocused_label->texture[0].data.text.justify =
|
||||
theme_app_unhilite_label->texture[0].data.text.justify = winjust;
|
||||
theme_a_unfocused_label->texture[0].data.text.justify = winjust;
|
||||
theme_app_unhilite_label->texture[0].data.text.justify = Justify_Left;
|
||||
theme_a_unfocused_label->texture[0].data.text.font =
|
||||
theme_app_unhilite_label->texture[0].data.text.font = theme_winfont;
|
||||
theme_a_unfocused_label->texture[0].data.text.shadow =
|
||||
|
@ -865,6 +863,7 @@ char *theme_load(char *theme)
|
|||
|
||||
theme_a_menu_item->surface.data.planar.grad =
|
||||
theme_a_menu_disabled->surface.data.planar.grad =
|
||||
theme_app_icon->surface.data.planar.grad =
|
||||
Background_ParentRelative;
|
||||
|
||||
theme_a_menu_item->texture[0].type =
|
||||
|
|
|
@ -78,8 +78,11 @@ extern Appearance *theme_a_menu_item;
|
|||
extern Appearance *theme_a_menu_disabled;
|
||||
extern Appearance *theme_a_menu_hilite;
|
||||
|
||||
extern Appearance *theme_app_hilite_bg;
|
||||
extern Appearance *theme_app_unhilite_bg;
|
||||
extern Appearance *theme_app_hilite_label;
|
||||
extern Appearance *theme_app_unhilite_label;
|
||||
extern Appearance *theme_app_icon;
|
||||
|
||||
void theme_startup();
|
||||
void theme_shutdown();
|
||||
|
|
Loading…
Reference in a new issue