From 08e42acaadf8868abb94dc75da0daa9c6e4e2d1c Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 5 May 2007 05:58:35 +0000 Subject: [PATCH] animate iconify/reestore. yeah. --- data/rc.xml.in | 1 + data/rc.xsd | 1 + openbox/client.c | 37 +++++++++++++-- openbox/client.h | 5 +++ openbox/config.c | 5 +++ openbox/config.h | 2 + openbox/event.c | 3 ++ openbox/frame.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++- openbox/frame.h | 20 +++++++++ openbox/prop.c | 1 + openbox/prop.h | 1 + 11 files changed, 186 insertions(+), 5 deletions(-) diff --git a/data/rc.xml.in b/data/rc.xml.in index 69b2484b..bfffdd78 100644 --- a/data/rc.xml.in +++ b/data/rc.xml.in @@ -43,6 +43,7 @@ --> yes no + yes sans 7 diff --git a/data/rc.xsd b/data/rc.xsd index 4da392a8..01fd525c 100644 --- a/data/rc.xsd +++ b/data/rc.xsd @@ -112,6 +112,7 @@ + diff --git a/openbox/client.c b/openbox/client.c index 3ebcc69a..658b05db 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -970,6 +970,7 @@ static void client_get_all(ObClient *self) client_update_strut(self); client_update_icons(self); client_update_user_time(self); + client_update_icon_geometry(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) { gchar *data = NULL; @@ -2707,9 +2724,23 @@ static void client_iconify_recursive(ObClient *self, if (changed) { client_change_state(self); - client_showhide(self); - if (STRUT_EXISTS(self->strut)) - screen_update_areas(); + 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); + } else { + 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 diff --git a/openbox/client.h b/openbox/client.h index 1273a687..afdeac50 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -287,6 +287,9 @@ struct _ObClient /*! The number of icons in icons */ guint nicons; + /* Where the window should iconify to/from */ + Rect icon_geometry; + guint32 user_time; }; @@ -587,6 +590,8 @@ void client_update_strut(ObClient *self); void client_update_icons(ObClient *self); /*! Updates the window's user time */ 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 be allowed (ObClient::decorations and ObClient::functions). diff --git a/openbox/config.c b/openbox/config.c index 4e3f6f9a..367fb2f9 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -42,6 +42,8 @@ gboolean config_theme_hidedisabled; gchar *config_title_layout; +gboolean config_animate_iconify; + RrFont *config_font_activewindow; RrFont *config_font_inactivewindow; 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); if ((n = parse_find_node("hideDisabled", node))) 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); while (n) { @@ -805,6 +809,7 @@ void config_startup(ObParseInst *i) config_theme = NULL; + config_animate_iconify = TRUE; config_title_layout = g_strdup("NLIMC"); config_theme_keepborder = TRUE; config_theme_hidedisabled = FALSE; diff --git a/openbox/config.h b/openbox/config.h index e6a441b0..f85f4f11 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -88,6 +88,8 @@ extern gboolean config_theme_keepborder; extern gboolean config_theme_hidedisabled; /*! Titlebar button layout */ extern gchar *config_title_layout; +/*! Animate windows iconifying and restoring */ +extern gboolean config_animate_iconify; /*! The font for the active window's title */ extern RrFont *config_font_activewindow; diff --git a/openbox/event.c b/openbox/event.c index badef3d9..a0202bf3 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -1125,6 +1125,9 @@ static void event_handle_client(ObClient *client, XEvent *e) else if (msgtype == prop_atoms.net_wm_icon) { 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) { client_update_user_time(client); } diff --git a/openbox/frame.c b/openbox/frame.c index 8feef931..8092e6c6 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -41,6 +41,9 @@ from the frame. */ #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 + \ f->cbwidth_y) @@ -50,6 +53,7 @@ static gboolean flash_timeout(gpointer data); static void set_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, gulong mask, XSetWindowAttributes *attrib) @@ -476,9 +480,13 @@ void frame_adjust_area(ObFrame *self, gboolean moved, self->client->area.height); } - if (!fake) { + if (!fake && !self->iconify_animation_step) { /* 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, self->area.x, self->area.y, self->area.width - self->bwidth * 2, @@ -592,6 +600,9 @@ void frame_release_client(ObFrame *self, ObClient *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 */ while (XCheckTypedWindowEvent(ob_display, client->window, ReparentNotify, &ev)) @@ -1019,3 +1030,103 @@ void frame_flash_stop(ObFrame *self) { 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); + } +} diff --git a/openbox/frame.h b/openbox/frame.h index 19bade78..8f210b0c 100644 --- a/openbox/frame.h +++ b/openbox/frame.h @@ -27,6 +27,8 @@ typedef struct _ObFrame ObFrame; struct _ObClient; +typedef void (*ObFrameIconifyAnimateFunc)(gpointer data); + typedef enum { OB_FRAME_CONTEXT_NONE, OB_FRAME_CONTEXT_DESKTOP, @@ -142,6 +144,17 @@ struct _ObFrame gboolean flashing; gboolean flash_on; 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); @@ -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_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 diff --git a/openbox/prop.c b/openbox/prop.c index 22519873..e622c7dd 100644 --- a/openbox/prop.c +++ b/openbox/prop.c @@ -85,6 +85,7 @@ void prop_startup() CREATE(net_wm_strut, "_NET_WM_STRUT"); CREATE(net_wm_strut_partial, "_NET_WM_STRUT_PARTIAL"); 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_allowed_actions, "_NET_WM_ALLOWED_ACTIONS"); CREATE(net_wm_user_time, "_NET_WM_USER_TIME"); diff --git a/openbox/prop.h b/openbox/prop.h index f4d7f8b6..49c342f6 100644 --- a/openbox/prop.h +++ b/openbox/prop.h @@ -93,6 +93,7 @@ typedef struct Atoms { Atom net_wm_strut; Atom net_wm_strut_partial; Atom net_wm_icon; + Atom net_wm_icon_geometry; /* Atom net_wm_pid; */ Atom net_wm_allowed_actions; Atom net_wm_user_time; -- 2.39.2