-->
<keepBorder>yes</keepBorder>
<hideDisabled>no</hideDisabled>
- <animateIconify>yes</animateIconify>
+ <animateIconify>no</animateIconify>
<font place="ActiveWindow">
<name>sans</name>
<size>7</size>
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
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)) {
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;
(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);
}
}
/* 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))
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);
}
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;
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;
}
config_theme = NULL;
- config_animate_iconify = TRUE;
+ config_animate_iconify = FALSE;
config_title_layout = g_strdup("NLIMC");
config_theme_keepborder = TRUE;
config_theme_hidedisabled = FALSE;
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);
}
#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;
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"),
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;
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;
#include "mainloop.h"
#include "focus.h"
#include "moveresize.h"
+#include "screen.h"
#include "render/theme.h"
#define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
from the frame. */
#define INNER_EVENTMASK (ButtonPressMask)
-#define FRAME_ANIMATE_ICONIFY_STEPS 20
-#define FRAME_ANIMATE_ICONIFY_TIME (G_USEC_PER_SEC/5)
+#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
+#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 + \
f->cbwidth_y)
self->client->area.height);
}
- if (!fake && !self->iconify_animation_step) {
- /* 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);
+ 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);
if (resized) {
framerender_frame(self);
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);
+ ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
+ self, FALSE);
/* check if the app has already reparented its window away */
while (XCheckTypedWindowEvent(ob_display, client->window,
self->flashing = FALSE;
}
+static gulong frame_animate_iconify_time_left(ObFrame *self,
+ const GTimeVal *now)
+{
+ glong sec, usec;
+ sec = self->iconify_animation_end.tv_sec - now->tv_sec;
+ usec = self->iconify_animation_end.tv_usec - now->tv_usec;
+ if (usec < 0) {
+ usec += G_USEC_PER_SEC;
+ sec--;
+ }
+ /* no negative values */
+ return MAX(sec * G_USEC_PER_SEC + usec, 0);
+}
+
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;
+ GTimeVal now;
+ gulong time;
+ gboolean iconifying;
if (self->client->icon_geometry.width == 0) {
/* there is no icon geometry set so just go straight down */
iconw = self->client->icon_geometry.width;
}
- if (step >= 0)
- absstep = FRAME_ANIMATE_ICONIFY_STEPS - step + 1;
- else
- absstep = FRAME_ANIMATE_ICONIFY_STEPS + step + 1;
+ iconifying = self->iconify_animation_going > 0;
- if (step >= 0) {
+ /* how far do we have left to go ? */
+ g_get_current_time(&now);
+ time = frame_animate_iconify_time_left(self, &now);
+
+ if (time == 0 || iconifying) {
/* start where the frame is supposed to be */
x = self->area.x;
y = self->area.y;
h = self->innersize.top; /* just the titlebar */
}
- if (step != 0) {
- gint dx, dy, dw;
+ if (time > 0) {
+ glong dx, dy, dw;
+ glong elapsed;
+
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;
+ if (!iconifying) { dx = -dx; dy = -dy; dw = -dw; }
+
+ elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
+ x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+ y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+ w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
h = self->innersize.top; /* just the titlebar */
}
- /* move one step forward */
- self->iconify_animation_step = step + (step < 0 ? 1 : (step > 0 ? -1 : 0));
+ if (time == 0)
+ frame_end_iconify_animation(self);
+ else {
+ XMoveResizeWindow(ob_display, self->window, x, y, w, h);
+ XFlush(ob_display);
+ }
- /* call the callback when it's done */
- if (step == 0 && self->iconify_animation_cb)
- self->iconify_animation_cb(self->iconify_animation_data);
+ return time > 0; /* repeat until we're out of time */
+}
- /* move to the next spot (after the callback for the animation ending) */
- XMoveResizeWindow(ob_display, self->window, x, y, w, h);
- XFlush(ob_display);
+void frame_end_iconify_animation(ObFrame *self)
+{
+ /* see if there is an animation going */
+ if (self->iconify_animation_going == 0) return;
- return step != 0; /* repeat until step is 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;
+
+ /* 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)
{
- 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;
+ gulong time;
+ gboolean new_anim = FALSE;
+ gboolean set_end = TRUE;
+ GTimeVal now;
+
+ /* if there is no titlebar, just don't animate for now
+ XXX it would be nice tho.. */
+ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR)) {
+ if (callback) callback(data);
+ return;
}
+
+ /* get the current time */
+ g_get_current_time(&now);
+
+ /* get how long until the end */
+ time = FRAME_ANIMATE_ICONIFY_TIME;
+ if (self->iconify_animation_going) {
+ if (!!iconifying != (self->iconify_animation_going > 0)) {
+ /* animation was already going on in the opposite direction */
+ time = time - frame_animate_iconify_time_left(self, &now);
+ } else
+ /* animation was already going in the same direction */
+ set_end = FALSE;
+ } else
+ new_anim = TRUE;
+ self->iconify_animation_going = iconifying ? 1 : -1;
+
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);
+ /* set the ending time */
+ if (set_end) {
+ self->iconify_animation_end.tv_sec = now.tv_sec;
+ self->iconify_animation_end.tv_usec = now.tv_usec;
+ g_time_val_add(&self->iconify_animation_end, time);
+ }
+
+ 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_TIME /
- FRAME_ANIMATE_ICONIFY_STEPS,
+ 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;
+}
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;
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)
+ /*! Is the frame currently in an animation for iconify or restore.
+ 0 means that it is not animating. > 0 means it is animating an iconify.
+ < 0 means it is animating a restore.
*/
- gint iconify_animation_step;
+ gint iconify_animation_going;
+ GTimeVal iconify_animation_end;
ObFrameIconifyAnimateFunc iconify_animation_cb;
gpointer iconify_animation_data;
};
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
static Time ungrab_time()
{
Time t = event_curtime;
- if (!(t == CurrentTime || event_time_after(t, grab_time)))
+ if (grab_time == CurrentTime ||
+ !(t == CurrentTime || event_time_after(t, grab_time)))
/* When the time moves backward on the server, then we can't use
the grab time because that will be in the future. So instead we
have to use CurrentTime.
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;
} 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)))
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)
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)
all: $(files:.c=)
%: %.c
- $(CC) $(CFLAGS) -o $@ $^ -lX11 -L/usr/X11R6/lib -I/usr/X11R6/include
+ $(CC) $(CFLAGS) -o $@ $^ -lX11 -lXext -L/usr/X11R6/lib -I/usr/X11R6/include