animate iconify/reestore. yeah.
This commit is contained in:
parent
fde5ca09e9
commit
08e42acaad
11 changed files with 186 additions and 5 deletions
|
@ -43,6 +43,7 @@
|
||||||
-->
|
-->
|
||||||
<keepBorder>yes</keepBorder>
|
<keepBorder>yes</keepBorder>
|
||||||
<hideDisabled>no</hideDisabled>
|
<hideDisabled>no</hideDisabled>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
<font place="ActiveWindow">
|
<font place="ActiveWindow">
|
||||||
<name>sans</name>
|
<name>sans</name>
|
||||||
<size>7</size>
|
<size>7</size>
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
<xsd:element minOccurs="0" name="titleNumber" type="ob:bool"/>
|
<xsd:element minOccurs="0" name="titleNumber" type="ob:bool"/>
|
||||||
<xsd:element minOccurs="0" name="keepBorder" type="ob:bool"/>
|
<xsd:element minOccurs="0" name="keepBorder" type="ob:bool"/>
|
||||||
<xsd:element minOccurs="0" name="hideDisabled" type="ob:bool"/>
|
<xsd:element minOccurs="0" name="hideDisabled" type="ob:bool"/>
|
||||||
|
<xsd:element minOccurs="0" name="animateIconify" type="ob:bool"/>
|
||||||
<xsd:element minOccurs="0" name="font" type="ob:font"/>
|
<xsd:element minOccurs="0" name="font" type="ob:font"/>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
<xsd:complexType name="font">
|
<xsd:complexType name="font">
|
||||||
|
|
|
@ -970,6 +970,7 @@ static void client_get_all(ObClient *self)
|
||||||
client_update_strut(self);
|
client_update_strut(self);
|
||||||
client_update_icons(self);
|
client_update_icons(self);
|
||||||
client_update_user_time(self);
|
client_update_user_time(self);
|
||||||
|
client_update_icon_geometry(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_get_startup_id(ObClient *self)
|
static void client_get_startup_id(ObClient *self)
|
||||||
|
@ -2022,6 +2023,22 @@ void client_update_user_time(ObClient *self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_update_icon_geometry(ObClient *self)
|
||||||
|
{
|
||||||
|
guint num;
|
||||||
|
guint32 *data;
|
||||||
|
|
||||||
|
RECT_SET(self->icon_geometry, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
if (PROP_GETA32(self->window, net_wm_icon_geometry, cardinal, &data, &num)
|
||||||
|
&& num == 4)
|
||||||
|
{
|
||||||
|
/* don't let them set it with an area < 0 */
|
||||||
|
RECT_SET(self->icon_geometry, data[0], data[1],
|
||||||
|
MAX(data[2],0), MAX(data[3],0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void client_get_client_machine(ObClient *self)
|
static void client_get_client_machine(ObClient *self)
|
||||||
{
|
{
|
||||||
gchar *data = NULL;
|
gchar *data = NULL;
|
||||||
|
@ -2707,9 +2724,23 @@ static void client_iconify_recursive(ObClient *self,
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
client_change_state(self);
|
client_change_state(self);
|
||||||
|
if (iconic) {
|
||||||
|
if (ob_state() != OB_STATE_STARTING && config_animate_iconify) {
|
||||||
|
/* delay the showhide until the window is done the animation */
|
||||||
|
frame_begin_iconify_animation
|
||||||
|
(self->frame, iconic,
|
||||||
|
(ObFrameIconifyAnimateFunc)client_showhide, self);
|
||||||
|
/* but focus a new window now please */
|
||||||
|
focus_fallback(TRUE);
|
||||||
|
} else
|
||||||
client_showhide(self);
|
client_showhide(self);
|
||||||
if (STRUT_EXISTS(self->strut))
|
} else {
|
||||||
screen_update_areas();
|
if (config_animate_iconify)
|
||||||
|
/* start the animation then show it, this way the whole window
|
||||||
|
doesnt get shown, just the first step of the animation */
|
||||||
|
frame_begin_iconify_animation(self->frame, iconic, NULL, NULL);
|
||||||
|
client_showhide(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iconify all direct transients, and deiconify all transients
|
/* iconify all direct transients, and deiconify all transients
|
||||||
|
|
|
@ -287,6 +287,9 @@ struct _ObClient
|
||||||
/*! The number of icons in icons */
|
/*! The number of icons in icons */
|
||||||
guint nicons;
|
guint nicons;
|
||||||
|
|
||||||
|
/* Where the window should iconify to/from */
|
||||||
|
Rect icon_geometry;
|
||||||
|
|
||||||
guint32 user_time;
|
guint32 user_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -587,6 +590,8 @@ void client_update_strut(ObClient *self);
|
||||||
void client_update_icons(ObClient *self);
|
void client_update_icons(ObClient *self);
|
||||||
/*! Updates the window's user time */
|
/*! Updates the window's user time */
|
||||||
void client_update_user_time(ObClient *self);
|
void client_update_user_time(ObClient *self);
|
||||||
|
/*! Updates the window's icon geometry (where to iconify to/from) */
|
||||||
|
void client_update_icon_geometry(ObClient *self);
|
||||||
|
|
||||||
/*! Set up what decor should be shown on the window and what functions should
|
/*! Set up what decor should be shown on the window and what functions should
|
||||||
be allowed (ObClient::decorations and ObClient::functions).
|
be allowed (ObClient::decorations and ObClient::functions).
|
||||||
|
|
|
@ -42,6 +42,8 @@ gboolean config_theme_hidedisabled;
|
||||||
|
|
||||||
gchar *config_title_layout;
|
gchar *config_title_layout;
|
||||||
|
|
||||||
|
gboolean config_animate_iconify;
|
||||||
|
|
||||||
RrFont *config_font_activewindow;
|
RrFont *config_font_activewindow;
|
||||||
RrFont *config_font_inactivewindow;
|
RrFont *config_font_inactivewindow;
|
||||||
RrFont *config_font_menuitem;
|
RrFont *config_font_menuitem;
|
||||||
|
@ -454,6 +456,8 @@ static void parse_theme(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
|
||||||
config_theme_keepborder = parse_bool(doc, n);
|
config_theme_keepborder = parse_bool(doc, n);
|
||||||
if ((n = parse_find_node("hideDisabled", node)))
|
if ((n = parse_find_node("hideDisabled", node)))
|
||||||
config_theme_hidedisabled = parse_bool(doc, n);
|
config_theme_hidedisabled = parse_bool(doc, n);
|
||||||
|
if ((n = parse_find_node("animateIconify", node)))
|
||||||
|
config_animate_iconify = parse_bool(doc, n);
|
||||||
|
|
||||||
n = parse_find_node("font", node);
|
n = parse_find_node("font", node);
|
||||||
while (n) {
|
while (n) {
|
||||||
|
@ -805,6 +809,7 @@ void config_startup(ObParseInst *i)
|
||||||
|
|
||||||
config_theme = NULL;
|
config_theme = NULL;
|
||||||
|
|
||||||
|
config_animate_iconify = TRUE;
|
||||||
config_title_layout = g_strdup("NLIMC");
|
config_title_layout = g_strdup("NLIMC");
|
||||||
config_theme_keepborder = TRUE;
|
config_theme_keepborder = TRUE;
|
||||||
config_theme_hidedisabled = FALSE;
|
config_theme_hidedisabled = FALSE;
|
||||||
|
|
|
@ -88,6 +88,8 @@ extern gboolean config_theme_keepborder;
|
||||||
extern gboolean config_theme_hidedisabled;
|
extern gboolean config_theme_hidedisabled;
|
||||||
/*! Titlebar button layout */
|
/*! Titlebar button layout */
|
||||||
extern gchar *config_title_layout;
|
extern gchar *config_title_layout;
|
||||||
|
/*! Animate windows iconifying and restoring */
|
||||||
|
extern gboolean config_animate_iconify;
|
||||||
|
|
||||||
/*! The font for the active window's title */
|
/*! The font for the active window's title */
|
||||||
extern RrFont *config_font_activewindow;
|
extern RrFont *config_font_activewindow;
|
||||||
|
|
|
@ -1125,6 +1125,9 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
else if (msgtype == prop_atoms.net_wm_icon) {
|
else if (msgtype == prop_atoms.net_wm_icon) {
|
||||||
client_update_icons(client);
|
client_update_icons(client);
|
||||||
}
|
}
|
||||||
|
else if (msgtype == prop_atoms.net_wm_icon_geometry) {
|
||||||
|
client_update_icon_geometry(client);
|
||||||
|
}
|
||||||
else if (msgtype == prop_atoms.net_wm_user_time) {
|
else if (msgtype == prop_atoms.net_wm_user_time) {
|
||||||
client_update_user_time(client);
|
client_update_user_time(client);
|
||||||
}
|
}
|
||||||
|
|
115
openbox/frame.c
115
openbox/frame.c
|
@ -41,6 +41,9 @@
|
||||||
from the frame. */
|
from the frame. */
|
||||||
#define INNER_EVENTMASK (ButtonPressMask)
|
#define INNER_EVENTMASK (ButtonPressMask)
|
||||||
|
|
||||||
|
#define FRAME_ANIMATE_ICONIFY_STEPS 20
|
||||||
|
#define FRAME_ANIMATE_ICONIFY_TIME (G_USEC_PER_SEC/10)
|
||||||
|
|
||||||
#define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
|
#define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
|
||||||
f->cbwidth_y)
|
f->cbwidth_y)
|
||||||
|
|
||||||
|
@ -50,6 +53,7 @@ static gboolean flash_timeout(gpointer data);
|
||||||
|
|
||||||
static void set_theme_statics(ObFrame *self);
|
static void set_theme_statics(ObFrame *self);
|
||||||
static void free_theme_statics(ObFrame *self);
|
static void free_theme_statics(ObFrame *self);
|
||||||
|
static gboolean frame_animate_iconify(gpointer self);
|
||||||
|
|
||||||
static Window createWindow(Window parent, Visual *visual,
|
static Window createWindow(Window parent, Visual *visual,
|
||||||
gulong mask, XSetWindowAttributes *attrib)
|
gulong mask, XSetWindowAttributes *attrib)
|
||||||
|
@ -476,9 +480,13 @@ void frame_adjust_area(ObFrame *self, gboolean moved,
|
||||||
self->client->area.height);
|
self->client->area.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fake) {
|
if (!fake && !self->iconify_animation_step) {
|
||||||
/* move and resize the top level frame.
|
/* move and resize the top level frame.
|
||||||
shading can change without being moved or resized */
|
shading can change without being moved or resized.
|
||||||
|
|
||||||
|
but don't do this during an iconify animation. it will be
|
||||||
|
reflected afterwards.
|
||||||
|
*/
|
||||||
XMoveResizeWindow(ob_display, self->window,
|
XMoveResizeWindow(ob_display, self->window,
|
||||||
self->area.x, self->area.y,
|
self->area.x, self->area.y,
|
||||||
self->area.width - self->bwidth * 2,
|
self->area.width - self->bwidth * 2,
|
||||||
|
@ -592,6 +600,9 @@ void frame_release_client(ObFrame *self, ObClient *client)
|
||||||
|
|
||||||
g_assert(self->client == client);
|
g_assert(self->client == client);
|
||||||
|
|
||||||
|
/* if there was any animation going on, kill it */
|
||||||
|
ob_main_loop_timeout_remove(ob_main_loop, frame_animate_iconify);
|
||||||
|
|
||||||
/* check if the app has already reparented its window away */
|
/* check if the app has already reparented its window away */
|
||||||
while (XCheckTypedWindowEvent(ob_display, client->window,
|
while (XCheckTypedWindowEvent(ob_display, client->window,
|
||||||
ReparentNotify, &ev))
|
ReparentNotify, &ev))
|
||||||
|
@ -1019,3 +1030,103 @@ void frame_flash_stop(ObFrame *self)
|
||||||
{
|
{
|
||||||
self->flashing = FALSE;
|
self->flashing = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean frame_animate_iconify(gpointer p)
|
||||||
|
{
|
||||||
|
ObFrame *self = p;
|
||||||
|
gint step = self->iconify_animation_step;
|
||||||
|
gint absstep, nextstep;
|
||||||
|
gint x, y, w, h;
|
||||||
|
gint iconx, icony, iconw;
|
||||||
|
|
||||||
|
if (self->client->icon_geometry.width == 0) {
|
||||||
|
/* there is no icon geometry set so just go straight down */
|
||||||
|
Rect *a = screen_physical_area();
|
||||||
|
iconx = self->area.x + self->area.width / 2 + 32;
|
||||||
|
icony = a->y + a->width;
|
||||||
|
iconw = 64;
|
||||||
|
} else {
|
||||||
|
iconx = self->client->icon_geometry.x;
|
||||||
|
icony = self->client->icon_geometry.y;
|
||||||
|
iconw = self->client->icon_geometry.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step >= 0)
|
||||||
|
absstep = FRAME_ANIMATE_ICONIFY_STEPS - step + 1;
|
||||||
|
else
|
||||||
|
absstep = FRAME_ANIMATE_ICONIFY_STEPS + step + 1;
|
||||||
|
|
||||||
|
if (step >= 0) {
|
||||||
|
/* start where the frame is supposed to be */
|
||||||
|
x = self->area.x;
|
||||||
|
y = self->area.y;
|
||||||
|
w = self->area.width - self->bwidth * 2;
|
||||||
|
h = self->area.height - self->bwidth * 2;
|
||||||
|
} else {
|
||||||
|
/* start at the icon */
|
||||||
|
x = iconx;
|
||||||
|
y = icony;
|
||||||
|
w = iconw;
|
||||||
|
h = self->innersize.top; /* just the titlebar */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step != 0) {
|
||||||
|
gint dx, dy, dw;
|
||||||
|
dx = self->area.x - iconx;
|
||||||
|
dy = self->area.y - icony;
|
||||||
|
dw = self->area.width - self->bwidth * 2 - iconw;
|
||||||
|
/* if restoring, we move in the opposite direction */
|
||||||
|
if (step < 0) { dx = -dx; dy = -dy; dw = -dw; }
|
||||||
|
x = x - dx / FRAME_ANIMATE_ICONIFY_STEPS * absstep;
|
||||||
|
y = y - dy / FRAME_ANIMATE_ICONIFY_STEPS * absstep;
|
||||||
|
w = w - dw / FRAME_ANIMATE_ICONIFY_STEPS * absstep;
|
||||||
|
h = self->innersize.top; /* just the titlebar */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move one step forward */
|
||||||
|
self->iconify_animation_step = step + (step < 0 ? 1 : (step > 0 ? -1 : 0));
|
||||||
|
|
||||||
|
/* call the callback when it's done */
|
||||||
|
if (step == 0 && self->iconify_animation_cb)
|
||||||
|
self->iconify_animation_cb(self->iconify_animation_data);
|
||||||
|
|
||||||
|
/* move to the next spot (after the callback for the animation ending) */
|
||||||
|
XMoveResizeWindow(ob_display, self->window, x, y, w, h);
|
||||||
|
XFlush(ob_display);
|
||||||
|
|
||||||
|
return step != 0; /* repeat until step is 0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
||||||
|
ObFrameIconifyAnimateFunc callback,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
if (iconifying) {
|
||||||
|
if (self->iconify_animation_step == 0) /* wasnt doing anything */
|
||||||
|
self->iconify_animation_step = FRAME_ANIMATE_ICONIFY_STEPS;
|
||||||
|
else if (self->iconify_animation_step < 0) /* was deiconifying */
|
||||||
|
self->iconify_animation_step =
|
||||||
|
FRAME_ANIMATE_ICONIFY_STEPS + self->iconify_animation_step;
|
||||||
|
} else {
|
||||||
|
if (self->iconify_animation_step == 0) /* wasnt doing anything */
|
||||||
|
self->iconify_animation_step = -FRAME_ANIMATE_ICONIFY_STEPS;
|
||||||
|
else if (self->iconify_animation_step > 0) /* was iconifying */
|
||||||
|
self->iconify_animation_step =
|
||||||
|
-FRAME_ANIMATE_ICONIFY_STEPS + self->iconify_animation_step;
|
||||||
|
}
|
||||||
|
self->iconify_animation_cb = callback;
|
||||||
|
self->iconify_animation_data = data;
|
||||||
|
|
||||||
|
if (self->iconify_animation_step == FRAME_ANIMATE_ICONIFY_STEPS ||
|
||||||
|
self->iconify_animation_step == -FRAME_ANIMATE_ICONIFY_STEPS)
|
||||||
|
{
|
||||||
|
ob_main_loop_timeout_remove(ob_main_loop, frame_animate_iconify);
|
||||||
|
ob_main_loop_timeout_add(ob_main_loop,
|
||||||
|
FRAME_ANIMATE_ICONIFY_TIME /
|
||||||
|
FRAME_ANIMATE_ICONIFY_STEPS,
|
||||||
|
frame_animate_iconify, self,
|
||||||
|
g_direct_equal, NULL);
|
||||||
|
/* do the first step */
|
||||||
|
frame_animate_iconify(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ typedef struct _ObFrame ObFrame;
|
||||||
|
|
||||||
struct _ObClient;
|
struct _ObClient;
|
||||||
|
|
||||||
|
typedef void (*ObFrameIconifyAnimateFunc)(gpointer data);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OB_FRAME_CONTEXT_NONE,
|
OB_FRAME_CONTEXT_NONE,
|
||||||
OB_FRAME_CONTEXT_DESKTOP,
|
OB_FRAME_CONTEXT_DESKTOP,
|
||||||
|
@ -142,6 +144,17 @@ struct _ObFrame
|
||||||
gboolean flashing;
|
gboolean flashing;
|
||||||
gboolean flash_on;
|
gboolean flash_on;
|
||||||
GTimeVal flash_end;
|
GTimeVal flash_end;
|
||||||
|
|
||||||
|
/*! The step which the client is currently in for animating iconify and
|
||||||
|
restore.
|
||||||
|
0 means that it is not animating. FRAME_ANIMATE_ICONIFY_STEPS is the
|
||||||
|
first step for iconifying, and -FRAME_ANIMATE_ICONIFY_STEPS is the
|
||||||
|
forst step for restoring. It counts towards 0 either way. Visually,
|
||||||
|
+x == -(FRAME_ANIMATE_ICONIFY_STEPS-x+1)
|
||||||
|
*/
|
||||||
|
gint iconify_animation_step;
|
||||||
|
ObFrameIconifyAnimateFunc iconify_animation_cb;
|
||||||
|
gpointer iconify_animation_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
ObFrame *frame_new(struct _ObClient *c);
|
ObFrame *frame_new(struct _ObClient *c);
|
||||||
|
@ -178,4 +191,11 @@ void frame_frame_gravity(ObFrame *self, gint *x, gint *y, gint w, gint h);
|
||||||
void frame_flash_start(ObFrame *self);
|
void frame_flash_start(ObFrame *self);
|
||||||
void frame_flash_stop(ObFrame *self);
|
void frame_flash_stop(ObFrame *self);
|
||||||
|
|
||||||
|
/*! Start an animation for iconifying or restoring a frame. The callback
|
||||||
|
will be called when the animation finishes. But if another animation is
|
||||||
|
started in the meantime, the callback will never get called. */
|
||||||
|
void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
||||||
|
ObFrameIconifyAnimateFunc callback,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -85,6 +85,7 @@ void prop_startup()
|
||||||
CREATE(net_wm_strut, "_NET_WM_STRUT");
|
CREATE(net_wm_strut, "_NET_WM_STRUT");
|
||||||
CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL");
|
CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL");
|
||||||
CREATE(net_wm_icon, "_NET_WM_ICON");
|
CREATE(net_wm_icon, "_NET_WM_ICON");
|
||||||
|
CREATE(net_wm_icon_geometry, "_NET_WM_ICON_GEOMETRY");
|
||||||
/* CREATE(net_wm_pid, "_NET_WM_PID"); */
|
/* CREATE(net_wm_pid, "_NET_WM_PID"); */
|
||||||
CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
|
CREATE(net_wm_allowed_actions, "_NET_WM_ALLOWED_ACTIONS");
|
||||||
CREATE(net_wm_user_time, "_NET_WM_USER_TIME");
|
CREATE(net_wm_user_time, "_NET_WM_USER_TIME");
|
||||||
|
|
|
@ -93,6 +93,7 @@ typedef struct Atoms {
|
||||||
Atom net_wm_strut;
|
Atom net_wm_strut;
|
||||||
Atom net_wm_strut_partial;
|
Atom net_wm_strut_partial;
|
||||||
Atom net_wm_icon;
|
Atom net_wm_icon;
|
||||||
|
Atom net_wm_icon_geometry;
|
||||||
/* Atom net_wm_pid; */
|
/* Atom net_wm_pid; */
|
||||||
Atom net_wm_allowed_actions;
|
Atom net_wm_allowed_actions;
|
||||||
Atom net_wm_user_time;
|
Atom net_wm_user_time;
|
||||||
|
|
Loading…
Reference in a new issue