lots of fixes for the iconify animation. i think it should all work perfectly now ?
one change in action.c may affect bindings... THIS COULD BREAK CURRENT CONFIG FILES. ya. so, if you used a press binding and it moved the window, no enter event will be generated for that anymore because you are holding down the button when the window moves. if you don't like that then use a click binding instead. 1
This commit is contained in:
parent
99daa7f523
commit
b5e597f1b3
9 changed files with 147 additions and 98 deletions
|
@ -48,19 +48,8 @@ inline void client_action_start(union ActionData *data)
|
|||
inline void client_action_end(union ActionData *data)
|
||||
{
|
||||
if (config_focus_follow)
|
||||
if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
|
||||
if (!data->any.button) {
|
||||
grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
|
||||
} else {
|
||||
ObClient *c;
|
||||
|
||||
/* usually this is sorta redundant, but with a press action
|
||||
the enter event will come as a GrabNotify which is
|
||||
ignored, so this will handle that case */
|
||||
if ((c = client_under_pointer()))
|
||||
event_enter_client(c);
|
||||
}
|
||||
}
|
||||
if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button)
|
||||
grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
@ -1275,7 +1264,7 @@ void action_raiselower(union ActionData *data)
|
|||
if (cit == c) break;
|
||||
if (client_normal(cit) == client_normal(c) &&
|
||||
cit->layer == c->layer &&
|
||||
cit->frame->visible &&
|
||||
frame_visible(cit->frame) &&
|
||||
!client_search_transient(c, cit))
|
||||
{
|
||||
if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
|
||||
|
|
|
@ -2061,7 +2061,7 @@ static void client_change_wm_state(ObClient *self)
|
|||
|
||||
old = self->wmstate;
|
||||
|
||||
if (self->shaded || self->iconic || !self->frame->visible)
|
||||
if (self->shaded || self->iconic || !frame_visible(self->frame))
|
||||
self->wmstate = IconicState;
|
||||
else
|
||||
self->wmstate = NormalState;
|
||||
|
@ -2731,15 +2731,19 @@ static void client_iconify_recursive(ObClient *self,
|
|||
(self->frame, iconic,
|
||||
(ObFrameIconifyAnimateFunc)client_showhide, self);
|
||||
/* but focus a new window now please */
|
||||
focus_fallback(TRUE);
|
||||
focus_fallback(FALSE);
|
||||
} 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);
|
||||
/* the animation will show the window when it is hidden,
|
||||
but the window state needs to be adjusted after the
|
||||
animation finishes, so call showhide when it's done to make
|
||||
sure everything is updated appropriately
|
||||
*/
|
||||
frame_begin_iconify_animation
|
||||
(self->frame, iconic,
|
||||
(ObFrameIconifyAnimateFunc)client_showhide, self);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3184,7 +3188,7 @@ gboolean client_can_focus(ObClient *self)
|
|||
/* choose the correct target */
|
||||
self = client_focus_target(self);
|
||||
|
||||
if (!self->frame->visible)
|
||||
if (!frame_visible(self->frame))
|
||||
return FALSE;
|
||||
|
||||
if (!(self->can_focus || self->focus_notify))
|
||||
|
@ -3217,7 +3221,7 @@ gboolean client_focus(ObClient *self)
|
|||
self = client_focus_target(self);
|
||||
|
||||
if (!client_can_focus(self)) {
|
||||
if (!self->frame->visible) {
|
||||
if (!frame_visible(self->frame)) {
|
||||
/* update the focus lists */
|
||||
focus_order_to_top(self);
|
||||
}
|
||||
|
@ -3302,7 +3306,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user)
|
|||
client_set_desktop(self, screen_desktop, FALSE);
|
||||
else
|
||||
screen_set_desktop(self->desktop);
|
||||
} else if (!self->frame->visible)
|
||||
} else if (!frame_visible(self->frame))
|
||||
/* if its not visible for other reasons, then don't mess
|
||||
with it */
|
||||
return;
|
||||
|
@ -3729,8 +3733,11 @@ ObClient* client_under_pointer()
|
|||
for (it = stacking_list; it; it = g_list_next(it)) {
|
||||
if (WINDOW_IS_CLIENT(it->data)) {
|
||||
ObClient *c = WINDOW_AS_CLIENT(it->data);
|
||||
if (c->frame->visible &&
|
||||
RECT_CONTAINS(c->frame->area, x, y)) {
|
||||
if (frame_visible(c->frame) &&
|
||||
/* ignore all animating windows */
|
||||
!frame_iconify_animating(c->frame) &&
|
||||
RECT_CONTAINS(c->frame->area, x, y))
|
||||
{
|
||||
ret = c;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ static void event_handle_dock(ObDock *s, XEvent *e);
|
|||
static void event_handle_dockapp(ObDockApp *app, XEvent *e);
|
||||
static void event_handle_client(ObClient *c, XEvent *e);
|
||||
static void event_handle_group(ObGroup *g, XEvent *e);
|
||||
static void event_handle_user_input(ObClient *client, XEvent *e);
|
||||
|
||||
static void focus_delay_dest(gpointer data);
|
||||
static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
|
||||
|
@ -530,49 +531,13 @@ static void event_process(const XEvent *ec, gpointer data)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* user input (action-bound) events */
|
||||
if (e->type == ButtonPress || e->type == ButtonRelease ||
|
||||
e->type == MotionNotify || e->type == KeyPress ||
|
||||
e->type == KeyRelease)
|
||||
{
|
||||
gboolean useevent = TRUE;
|
||||
|
||||
if (menu_frame_visible) {
|
||||
if (event_handle_menu(e))
|
||||
/* don't use the event if the menu used it, but if the menu
|
||||
didn't use it and it's a keypress that is bound, it will
|
||||
close the menu and be used */
|
||||
useevent = FALSE;
|
||||
}
|
||||
|
||||
if (useevent) {
|
||||
/* if the keyboard interactive action uses the event then dont
|
||||
use it for bindings. likewise is moveresize uses the event. */
|
||||
if (!keyboard_process_interactive_grab(e, &client) &&
|
||||
!(moveresize_in_progress && moveresize_event(e)))
|
||||
{
|
||||
if (moveresize_in_progress)
|
||||
/* make further actions work on the client being
|
||||
moved/resized */
|
||||
client = moveresize_client;
|
||||
|
||||
|
||||
menu_can_hide = FALSE;
|
||||
ob_main_loop_timeout_add(ob_main_loop,
|
||||
config_menu_hide_delay * 1000,
|
||||
menu_hide_delay_func,
|
||||
NULL, g_direct_equal, NULL);
|
||||
|
||||
if (e->type == ButtonPress || e->type == ButtonRelease ||
|
||||
e->type == MotionNotify) {
|
||||
mouse_event(client, e);
|
||||
} else if (e->type == KeyPress) {
|
||||
keyboard_event((focus_cycle_target ? focus_cycle_target :
|
||||
(client ? client : focus_client)), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
event_handle_user_input(client, e);
|
||||
}
|
||||
|
||||
/* if something happens and it's not from an XEvent, then we don't know
|
||||
the time */
|
||||
event_curtime = CurrentTime;
|
||||
|
@ -732,6 +697,12 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
|||
frame_adjust_state(client->frame);
|
||||
break;
|
||||
case OB_FRAME_CONTEXT_FRAME:
|
||||
/* When the mouse leaves an animating window, don't use the
|
||||
corresponding enter events. Pretend like the animating window
|
||||
doesn't even exist..! */
|
||||
if (frame_iconify_animating(client->frame))
|
||||
event_ignore_queued_enters();
|
||||
|
||||
ob_debug_type(OB_DEBUG_FOCUS,
|
||||
"%sNotify mode %d detail %d on %lx\n",
|
||||
(e->type == EnterNotify ? "Enter" : "Leave"),
|
||||
|
@ -1379,6 +1350,51 @@ static gboolean event_handle_menu(XEvent *ev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void event_handle_user_input(ObClient *client, XEvent *e)
|
||||
{
|
||||
g_assert(e->type == ButtonPress || e->type == ButtonRelease ||
|
||||
e->type == MotionNotify || e->type == KeyPress ||
|
||||
e->type == KeyRelease);
|
||||
|
||||
if (menu_frame_visible) {
|
||||
if (event_handle_menu(e))
|
||||
/* don't use the event if the menu used it, but if the menu
|
||||
didn't use it and it's a keypress that is bound, it will
|
||||
close the menu and be used */
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the keyboard interactive action uses the event then dont
|
||||
use it for bindings. likewise is moveresize uses the event. */
|
||||
if (!keyboard_process_interactive_grab(e, &client) &&
|
||||
!(moveresize_in_progress && moveresize_event(e)))
|
||||
{
|
||||
if (moveresize_in_progress)
|
||||
/* make further actions work on the client being
|
||||
moved/resized */
|
||||
client = moveresize_client;
|
||||
|
||||
menu_can_hide = FALSE;
|
||||
ob_main_loop_timeout_add(ob_main_loop,
|
||||
config_menu_hide_delay * 1000,
|
||||
menu_hide_delay_func,
|
||||
NULL, g_direct_equal, NULL);
|
||||
|
||||
if (e->type == ButtonPress ||
|
||||
e->type == ButtonRelease ||
|
||||
e->type == MotionNotify)
|
||||
{
|
||||
/* the frame may not be "visible" but they can still click on it
|
||||
in the case where it is animating before disappearing */
|
||||
if (client && frame_visible(client->frame))
|
||||
mouse_event(client, e);
|
||||
} else if (e->type == KeyPress) {
|
||||
keyboard_event((focus_cycle_target ? focus_cycle_target :
|
||||
(client ? client : focus_client)), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean menu_hide_delay_func(gpointer data)
|
||||
{
|
||||
menu_can_hide = TRUE;
|
||||
|
|
|
@ -499,7 +499,7 @@ static gboolean valid_focus_target(ObClient *ft, gboolean dock_windows)
|
|||
for (it = ft->transients; it; it = g_slist_next(it)) {
|
||||
ObClient *c = it->data;
|
||||
|
||||
if (c->frame->visible)
|
||||
if (frame_visible(c->frame))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
from the frame. */
|
||||
#define INNER_EVENTMASK (ButtonPressMask)
|
||||
|
||||
#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
|
||||
//#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
|
||||
#define FRAME_ANIMATE_ICONIFY_TIME 2000000
|
||||
#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 30) /* 30 Hz */
|
||||
|
||||
#define FRAME_HANDLE_Y(f) (f->innersize.top + f->client->area.height + \
|
||||
|
@ -481,17 +482,18 @@ void frame_adjust_area(ObFrame *self, gboolean moved,
|
|||
self->client->area.height);
|
||||
}
|
||||
|
||||
if (!fake && !self->iconify_animation_going) {
|
||||
/* move and resize the top level frame.
|
||||
shading can change without being moved or resized.
|
||||
if (!fake) {
|
||||
if (!frame_iconify_animating(self))
|
||||
/* move and resize the top level frame.
|
||||
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,
|
||||
self->area.height - self->bwidth * 2);
|
||||
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,
|
||||
self->area.height - self->bwidth * 2);
|
||||
|
||||
if (resized) {
|
||||
framerender_frame(self);
|
||||
|
@ -839,10 +841,6 @@ ObFrameContext frame_context(ObClient *client, Window win)
|
|||
if (win == RootWindow(ob_display, ob_screen))
|
||||
return OB_FRAME_CONTEXT_DESKTOP;
|
||||
if (client == NULL) return OB_FRAME_CONTEXT_NONE;
|
||||
|
||||
self = client->frame;
|
||||
if (self->iconify_animation_going) return OB_FRAME_CONTEXT_NONE;
|
||||
|
||||
if (win == client->window) {
|
||||
/* conceptually, this is the desktop, as far as users are
|
||||
concerned */
|
||||
|
@ -851,6 +849,7 @@ ObFrameContext frame_context(ObClient *client, Window win)
|
|||
return OB_FRAME_CONTEXT_CLIENT;
|
||||
}
|
||||
|
||||
self = client->frame;
|
||||
if (win == self->inner || win == self->plate) {
|
||||
/* conceptually, this is the desktop, as far as users are
|
||||
concerned */
|
||||
|
@ -1108,27 +1107,41 @@ static gboolean frame_animate_iconify(gpointer p)
|
|||
h = self->innersize.top; /* just the titlebar */
|
||||
}
|
||||
|
||||
if (time == 0) {
|
||||
/* call the callback when it's done */
|
||||
if (self->iconify_animation_cb)
|
||||
self->iconify_animation_cb(self->iconify_animation_data);
|
||||
/* we're not animating any more ! */
|
||||
self->iconify_animation_going = 0;
|
||||
if (time == 0)
|
||||
frame_end_iconify_animation(self);
|
||||
else {
|
||||
XMoveResizeWindow(ob_display, self->window, x, y, w, h);
|
||||
XFlush(ob_display);
|
||||
}
|
||||
|
||||
/* 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 time > 0; /* repeat until we're out of time */
|
||||
}
|
||||
|
||||
void frame_end_iconify_animation(ObFrame *self)
|
||||
{
|
||||
/* see if there is an animation going */
|
||||
if (self->iconify_animation_going == 0) return;
|
||||
|
||||
/* call the callback when it's done */
|
||||
if (self->iconify_animation_cb)
|
||||
self->iconify_animation_cb(self->iconify_animation_data);
|
||||
/* we're not animating any more ! */
|
||||
self->iconify_animation_going = 0;
|
||||
|
||||
/* move after the callback for the animation ending */
|
||||
XMoveResizeWindow(ob_display, self->window,
|
||||
self->area.x, self->area.y,
|
||||
self->area.width - self->bwidth * 2,
|
||||
self->area.height - self->bwidth * 2);
|
||||
XFlush(ob_display);
|
||||
}
|
||||
|
||||
void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
||||
ObFrameIconifyAnimateFunc callback,
|
||||
gpointer data)
|
||||
{
|
||||
gulong time;
|
||||
gboolean start_timer = TRUE;
|
||||
gboolean new_anim = FALSE;
|
||||
gboolean set_end = TRUE;
|
||||
GTimeVal now;
|
||||
|
||||
|
@ -1151,8 +1164,8 @@ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
|||
} else
|
||||
/* animation was already going in the same direction */
|
||||
set_end = FALSE;
|
||||
start_timer = FALSE;
|
||||
}
|
||||
} else
|
||||
new_anim = TRUE;
|
||||
self->iconify_animation_going = iconifying ? 1 : -1;
|
||||
|
||||
self->iconify_animation_cb = callback;
|
||||
|
@ -1165,14 +1178,25 @@ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
|||
g_time_val_add(&self->iconify_animation_end, time);
|
||||
}
|
||||
|
||||
if (start_timer) {
|
||||
if (new_anim) {
|
||||
ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
|
||||
self, FALSE);
|
||||
ob_main_loop_timeout_add(ob_main_loop,
|
||||
FRAME_ANIMATE_ICONIFY_STEP_TIME,
|
||||
frame_animate_iconify, self,
|
||||
g_direct_equal, NULL);
|
||||
|
||||
/* do the first step */
|
||||
frame_animate_iconify(self);
|
||||
|
||||
if (!self->visible)
|
||||
frame_show(self);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean frame_visible(ObFrame *self)
|
||||
{
|
||||
/* if it is animating back from iconic state then it is considered
|
||||
visible. but if it is iconifying then it is not visible. */
|
||||
return self->visible && self->iconify_animation_going <= 0;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,9 @@ struct _ObFrame
|
|||
|
||||
Strut size;
|
||||
Rect area;
|
||||
/*! Is the frame visible? Don't read this directly ! Use frame_visible()
|
||||
instead, because that takes into account if the frame is visible but
|
||||
animating to the iconic (invisible) state. */
|
||||
gboolean visible;
|
||||
|
||||
guint decorations;
|
||||
|
@ -195,5 +198,12 @@ void frame_flash_stop(ObFrame *self);
|
|||
void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying,
|
||||
ObFrameIconifyAnimateFunc callback,
|
||||
gpointer data);
|
||||
void frame_end_iconify_animation(ObFrame *self);
|
||||
|
||||
/* Returns true if the frame is visible (but false if it is only visible
|
||||
because it is animating */
|
||||
gboolean frame_visible(ObFrame *self);
|
||||
|
||||
#define frame_iconify_animating(f) (f->iconify_animation_going != 0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,12 +153,14 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
|
|||
moving = (cnr == prop_atoms.net_wm_moveresize_move ||
|
||||
cnr == prop_atoms.net_wm_moveresize_move_keyboard);
|
||||
|
||||
if (moveresize_in_progress || !c->frame->visible ||
|
||||
if (moveresize_in_progress || !frame_visible(c->frame) ||
|
||||
!(moving ?
|
||||
(c->functions & OB_CLIENT_FUNC_MOVE) :
|
||||
(c->functions & OB_CLIENT_FUNC_RESIZE)))
|
||||
return;
|
||||
|
||||
frame_end_iconify_animation(c->frame);
|
||||
|
||||
moveresize_client = c;
|
||||
start_cx = c->area.x;
|
||||
start_cy = c->area.y;
|
||||
|
|
|
@ -251,7 +251,8 @@ typedef enum
|
|||
} ObSmartType;
|
||||
|
||||
#define SMART_IGNORE(placer, c) \
|
||||
(placer == c || !c->frame->visible || c->shaded || !client_normal(c) || \
|
||||
(placer == c || c->shaded || !client_normal(c) || \
|
||||
!frame_visible(c->frame) || \
|
||||
(c->desktop != DESKTOP_ALL && \
|
||||
c->desktop != (placer->desktop == DESKTOP_ALL ? \
|
||||
screen_desktop : placer->desktop)))
|
||||
|
|
|
@ -57,7 +57,7 @@ void resist_move_windows(ObClient *c, gint *x, gint *y)
|
|||
target = it->data;
|
||||
|
||||
/* don't snap to self or non-visibles */
|
||||
if (!target->frame->visible || target == c) continue;
|
||||
if (!frame_visible(target->frame) || target == c) continue;
|
||||
|
||||
/* don't snap to windows in layers beneath */
|
||||
if(target->layer < c->layer && !config_resist_layers_below)
|
||||
|
@ -199,7 +199,7 @@ void resist_size_windows(ObClient *c, gint *w, gint *h, ObCorner corn)
|
|||
target = it->data;
|
||||
|
||||
/* don't snap to invisibles or ourself */
|
||||
if (!target->frame->visible || target == c) continue;
|
||||
if (!frame_visible(target->frame) || target == c) continue;
|
||||
|
||||
/* don't snap to windows in layers beneath */
|
||||
if(target->layer < c->layer && !config_resist_layers_below)
|
||||
|
|
Loading…
Reference in a new issue