From 9bed75b8bfcd68c974c97303e78d5f49cb1dfd87 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 5 May 2007 16:19:16 +0000 Subject: [PATCH] merge r6068-6075 from trunk --- data/rc.xml.in | 2 +- openbox/action.c | 17 +---- openbox/client.c | 29 ++++--- openbox/config.c | 2 +- openbox/event.c | 92 ++++++++++++---------- openbox/focus.c | 2 +- openbox/frame.c | 177 ++++++++++++++++++++++++++++++------------- openbox/frame.h | 22 ++++-- openbox/grab.c | 3 +- openbox/moveresize.c | 4 +- openbox/place.c | 3 +- openbox/resist.c | 4 +- tests/Makefile | 2 +- 13 files changed, 226 insertions(+), 133 deletions(-) diff --git a/data/rc.xml.in b/data/rc.xml.in index bfffdd78..4de262d6 100644 --- a/data/rc.xml.in +++ b/data/rc.xml.in @@ -43,7 +43,7 @@ --> yes no - yes + no sans 7 diff --git a/openbox/action.c b/openbox/action.c index b54e888e..2e348c7c 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -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)) { diff --git a/openbox/client.c b/openbox/client.c index 658b05db..02bd74b4 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -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; } diff --git a/openbox/config.c b/openbox/config.c index 367fb2f9..325beeb1 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -809,7 +809,7 @@ void config_startup(ObParseInst *i) 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; diff --git a/openbox/event.c b/openbox/event.c index a0202bf3..ec0789d1 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -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; diff --git a/openbox/focus.c b/openbox/focus.c index 823435c9..94257205 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -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; diff --git a/openbox/frame.c b/openbox/frame.c index 38bbde18..a5a07609 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -27,6 +27,7 @@ #include "mainloop.h" #include "focus.h" #include "moveresize.h" +#include "screen.h" #include "render/theme.h" #define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask) @@ -41,8 +42,8 @@ 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) @@ -480,17 +481,18 @@ void frame_adjust_area(ObFrame *self, gboolean moved, 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); @@ -601,7 +603,8 @@ 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); + 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, @@ -1031,13 +1034,28 @@ void frame_flash_stop(ObFrame *self) 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 */ @@ -1051,12 +1069,13 @@ static gboolean frame_animate_iconify(gpointer p) 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; @@ -1070,63 +1089,113 @@ static gboolean frame_animate_iconify(gpointer p) 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; +} diff --git a/openbox/frame.h b/openbox/frame.h index 8f210b0c..5f31b8c9 100644 --- a/openbox/frame.h +++ b/openbox/frame.h @@ -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; @@ -145,14 +148,12 @@ struct _ObFrame 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; }; @@ -197,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 diff --git a/openbox/grab.c b/openbox/grab.c index 3e1066ba..b6a7a939 100644 --- a/openbox/grab.c +++ b/openbox/grab.c @@ -43,7 +43,8 @@ static Time grab_time = CurrentTime; 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. diff --git a/openbox/moveresize.c b/openbox/moveresize.c index 868c0c25..9f9d4dfd 100644 --- a/openbox/moveresize.c +++ b/openbox/moveresize.c @@ -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; diff --git a/openbox/place.c b/openbox/place.c index 8003270e..eada385f 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -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))) diff --git a/openbox/resist.c b/openbox/resist.c index fc293446..0c7ec87e 100644 --- a/openbox/resist.c +++ b/openbox/resist.c @@ -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) diff --git a/tests/Makefile b/tests/Makefile index 7dbff040..6374b392 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,4 +3,4 @@ files=$(wildcard *.c) 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 -- 2.34.1