From a50c7d704cdda27c2bfdeaa1206b24cc5c20ed6c Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 11 Jul 2007 23:53:26 +0000 Subject: [PATCH] merge 7773 from trunk --- openbox/client.c | 456 ++++++++++++++++++++++++--------------- openbox/moveresize.c | 503 ++++++++++++++++++++++++++++--------------- 2 files changed, 613 insertions(+), 346 deletions(-) diff --git a/openbox/client.c b/openbox/client.c index 1b5aff92..071ecc4d 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -88,7 +88,8 @@ static void client_update_transient_tree(ObClient *self, gboolean oldgtran, gboolean newgtran, ObClient* oldparent, ObClient *newparent); -static void client_present(ObClient *self, gboolean here, gboolean raise); +static void client_present(ObClient *self, gboolean here, gboolean raise, + gboolean unshade); static GSList *client_search_all_top_parents_internal(ObClient *self, gboolean bylayer, ObStackingLayer layer); @@ -547,7 +548,7 @@ void client_manage(Window window) if (activate) { gboolean stacked = client_restore_session_stacking(self); - client_present(self, FALSE, !stacked); + client_present(self, FALSE, !stacked, TRUE); } /* add to client list/map */ @@ -935,7 +936,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, frame_rect_to_frame(self->frame, &desired); /* get where the frame would be */ - frame_client_gravity(self->frame, x, y, w, h); + frame_client_gravity(self->frame, x, y); /* get the requested size of the window with decorations */ fw = self->frame->size.left + w + self->frame->size.right; @@ -1023,7 +1024,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h, } /* get where the client should be */ - frame_frame_gravity(self->frame, x, y, w, h); + frame_frame_gravity(self->frame, x, y); return ox != *x || oy != *y; } @@ -2683,7 +2684,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, frame_adjust_area(self->frame, FALSE, TRUE, TRUE); /* gets the frame's position */ - frame_client_gravity(self->frame, x, y, *w, *h); + frame_client_gravity(self->frame, x, y); /* these positions are frame positions, not client positions */ @@ -2730,7 +2731,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, } /* gets the client's position */ - frame_frame_gravity(self->frame, x, y, *w, *h); + frame_frame_gravity(self->frame, x, y); /* work within the prefered sizes given by the window */ if (!(*w == self->area.width && *h == self->area.height)) { @@ -2865,9 +2866,6 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, oldw = self->area.width; oldh = self->area.height; RECT_SET(self->area, x, y, w, h); - ob_debug("Client area %s set to %d %d %d %d\n", - self->title, self->area.x, self->area.y, - self->area.width, self->area.height); /* for app-requested resizes, always resize if 'resized' is true. for user-requested ones, only resize if final is true, or when @@ -3549,6 +3547,10 @@ gboolean client_focus(ObClient *self) "Focusing client \"%s\" (0x%x) at time %u\n", self->title, self->window, event_curtime); + /* if using focus_delay, stop the timer now so that focus doesn't + go moving on us */ + event_halt_focus_delay(); + /* if there is a grab going on, then we need to cancel it. if we move focus during the grab, applications will get NotifyWhileGrabbed events and ignore them ! @@ -3589,17 +3591,9 @@ gboolean client_focus(ObClient *self) return !xerror_occured; } -/*! Present the client to the user. - @param raise If the client should be raised or not. You should only set - raise to false if you don't care if the window is completely - hidden. -*/ -static void client_present(ObClient *self, gboolean here, gboolean raise) +static void client_present(ObClient *self, gboolean here, gboolean raise, + gboolean unshade) { - /* if using focus_delay, stop the timer now so that focus doesn't - go moving on us */ - event_halt_focus_delay(); - if (client_normal(self) && screen_showing_desktop) screen_show_desktop(FALSE, self); if (self->iconic) @@ -3615,7 +3609,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) /* if its not visible for other reasons, then don't mess with it */ return; - if (self->shaded) + if (self->shaded && unshade) client_shade(self, FALSE); if (raise) stacking_raise(CLIENT_AS_WINDOW(self)); @@ -3623,7 +3617,8 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) client_focus(self); } -void client_activate(ObClient *self, gboolean here, gboolean user) +void client_activate(ObClient *self, gboolean here, gboolean raise, + gboolean unshade, gboolean user) { guint32 last_time = focus_client ? focus_client->user_time : CurrentTime; gboolean allow = FALSE; @@ -3649,7 +3644,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user) (user ? "user" : "application"), allow); if (allow) - client_present(self, here, TRUE); + client_present(self, here, raise, unshade); else /* don't focus it but tell the user it wants attention */ client_hilite(self, TRUE); @@ -3854,188 +3849,297 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) return NULL; } -#define WANT_EDGE(cur, c) \ - if (cur == c) \ - continue; \ - if (c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && \ - cur->desktop != screen_desktop) \ - continue; \ - if (cur->iconic) \ - continue; - -#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \ - if ((his_edge_start >= my_edge_start && \ - his_edge_start <= my_edge_end) || \ - (my_edge_start >= his_edge_start && \ - my_edge_start <= his_edge_end)) \ - dest = his_offset; - -/* finds the nearest edge in the given direction from the current client - * note to self: the edge is the -frame- edge (the actual one), not the - * client edge. - */ -gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang) -{ - gint dest, monitor_dest; - gint my_edge_start, my_edge_end, my_offset; +void client_find_edge_directional(ObClient *self, ObDirection dir, + gint my_head, gint my_size, + gint my_edge_start, gint my_edge_size, + gint *dest, gboolean *near_edge) +{ GList *it; Rect *a, *mon; - - if(!client_list) - return -1; + gint edge; - a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area); - mon = screen_area(c->desktop, SCREEN_AREA_ONE_MONITOR, &c->frame->area); + a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS, + &self->frame->area); + mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, + &self->frame->area); switch(dir) { case OB_DIRECTION_NORTH: - my_edge_start = c->frame->area.x; - my_edge_end = c->frame->area.x + c->frame->area.width; - my_offset = c->frame->area.y + (hang ? c->frame->area.height : 0); - - /* default: top of screen */ - dest = a->y + (hang ? c->frame->area.height : 0); - monitor_dest = mon->y + (hang ? c->frame->area.height : 0); - /* if the monitor edge comes before the screen edge, */ - /* use that as the destination instead. (For xinerama) */ - if (monitor_dest != dest && my_offset > monitor_dest) - dest = monitor_dest; - - for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { - gint his_edge_start, his_edge_end, his_offset; - ObClient *cur = it->data; - - WANT_EDGE(cur, c) - - his_edge_start = cur->frame->area.x; - his_edge_end = cur->frame->area.x + cur->frame->area.width; - his_offset = cur->frame->area.y + - (hang ? 0 : cur->frame->area.height); - - if(his_offset + 1 > my_offset) - continue; - - if(his_offset < dest) - continue; - - HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) - } + if (my_head >= RECT_TOP(*mon)) + edge = RECT_TOP(*mon) - 1; + else + edge = RECT_TOP(*a) - 1; break; case OB_DIRECTION_SOUTH: - my_edge_start = c->frame->area.x; - my_edge_end = c->frame->area.x + c->frame->area.width; - my_offset = c->frame->area.y + (hang ? 0 : c->frame->area.height); - - /* default: bottom of screen */ - dest = a->y + a->height - (hang ? c->frame->area.height : 0); - monitor_dest = mon->y + mon->height - - (hang ? c->frame->area.height : 0); - /* if the monitor edge comes before the screen edge, */ - /* use that as the destination instead. (For xinerama) */ - if (monitor_dest != dest && my_offset < monitor_dest) - dest = monitor_dest; + if (my_head <= RECT_BOTTOM(*mon)) + edge = RECT_BOTTOM(*mon) + 1; + else + edge = RECT_BOTTOM(*a) + 1; + break; + case OB_DIRECTION_EAST: + if (my_head <= RECT_RIGHT(*mon)) + edge = RECT_RIGHT(*mon) + 1; + else + edge = RECT_RIGHT(*a) + 1; + break; + case OB_DIRECTION_WEST: + if (my_head >= RECT_LEFT(*mon)) + edge = RECT_LEFT(*mon) - 1; + else + edge = RECT_LEFT(*a) - 1; + break; + default: + g_assert_not_reached(); + } + /* default to the far edge, then narrow it down */ + *dest = edge; + *near_edge = TRUE; - for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { - gint his_edge_start, his_edge_end, his_offset; - ObClient *cur = it->data; + for(it = client_list; it; it = g_list_next(it)) { + ObClient *cur = it->data; + gint edge_start, edge_size, head, tail; + gboolean skip_head = FALSE, skip_tail = FALSE; - WANT_EDGE(cur, c) + /* skip windows to not bump into */ + if (cur == self) + continue; + if (cur->iconic) + continue; + if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && + cur->desktop != screen_desktop) + continue; - his_edge_start = cur->frame->area.x; - his_edge_end = cur->frame->area.x + cur->frame->area.width; - his_offset = cur->frame->area.y + - (hang ? cur->frame->area.height : 0); + ob_debug("trying window %s\n", cur->title); + switch(dir) { + case OB_DIRECTION_NORTH: + case OB_DIRECTION_SOUTH: + edge_start = cur->frame->area.x; + edge_size = cur->frame->area.width; + break; + case OB_DIRECTION_EAST: + case OB_DIRECTION_WEST: + edge_start = cur->frame->area.y; + edge_size = cur->frame->area.height; + break; + default: + g_assert_not_reached(); + } - if(his_offset - 1 < my_offset) - continue; - - if(his_offset > dest) - continue; + /* do we collide with this window? */ + if (!RANGES_INTERSECT(my_edge_start, my_edge_size, + edge_start, edge_size)) + continue; - HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) + switch(dir) { + case OB_DIRECTION_NORTH: + head = RECT_BOTTOM(cur->frame->area); + tail = RECT_TOP(cur->frame->area); + break; + case OB_DIRECTION_SOUTH: + head = RECT_TOP(cur->frame->area); + tail = RECT_BOTTOM(cur->frame->area); + break; + case OB_DIRECTION_EAST: + head = RECT_LEFT(cur->frame->area); + tail = RECT_RIGHT(cur->frame->area); + break; + case OB_DIRECTION_WEST: + head = RECT_RIGHT(cur->frame->area); + tail = RECT_LEFT(cur->frame->area); + break; + default: + g_assert_not_reached(); } - break; - case OB_DIRECTION_WEST: - my_edge_start = c->frame->area.y; - my_edge_end = c->frame->area.y + c->frame->area.height; - my_offset = c->frame->area.x + (hang ? c->frame->area.width : 0); - /* default: leftmost egde of screen */ - dest = a->x + (hang ? c->frame->area.width : 0); - monitor_dest = mon->x + (hang ? c->frame->area.width : 0); - /* if the monitor edge comes before the screen edge, */ - /* use that as the destination instead. (For xinerama) */ - if (monitor_dest != dest && my_offset > monitor_dest) - dest = monitor_dest; + switch(dir) { + case OB_DIRECTION_NORTH: + case OB_DIRECTION_WEST: + if (my_head <= head + 1) + skip_head = TRUE; + if (my_head + my_size - 1 <= tail) + skip_tail = TRUE; + if (head < *dest) + skip_head = TRUE; + if (tail - my_size < *dest) + skip_tail = TRUE; + break; + case OB_DIRECTION_SOUTH: + case OB_DIRECTION_EAST: + if (my_head >= head - 1) + skip_head = TRUE; + if (my_head - my_size + 1 >= tail) + skip_tail = TRUE; + if (head > *dest) + skip_head = TRUE; + if (tail + my_size > *dest) + skip_tail = TRUE; + break; + default: + g_assert_not_reached(); + } - for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { - gint his_edge_start, his_edge_end, his_offset; - ObClient *cur = it->data; + ob_debug("my head %d size %d\n", my_head, my_size); + ob_debug("head %d tail %d deest %d\n", head, tail, *dest); + if (!skip_head) { + ob_debug("using near edge %d\n", head); + *dest = head; + *near_edge = TRUE; + } + else if (!skip_tail) { + ob_debug("using far edge %d\n", tail); + *dest = tail; + *near_edge = FALSE; + } + } +} - WANT_EDGE(cur, c) +void client_find_move_directional(ObClient *self, ObDirection dir, + gint *x, gint *y) +{ + gint head, size; + gint e, e_start, e_size; + gboolean near; - his_edge_start = cur->frame->area.y; - his_edge_end = cur->frame->area.y + cur->frame->area.height; - his_offset = cur->frame->area.x + - (hang ? 0 : cur->frame->area.width); + switch (dir) { + case OB_DIRECTION_EAST: + head = RECT_RIGHT(self->frame->area); + size = self->frame->area.width; + e_start = RECT_TOP(self->frame->area); + e_size = self->frame->area.height; + break; + case OB_DIRECTION_WEST: + head = RECT_LEFT(self->frame->area); + size = self->frame->area.width; + e_start = RECT_TOP(self->frame->area); + e_size = self->frame->area.height; + break; + case OB_DIRECTION_NORTH: + head = RECT_TOP(self->frame->area); + size = self->frame->area.height; + e_start = RECT_LEFT(self->frame->area); + e_size = self->frame->area.width; + break; + case OB_DIRECTION_SOUTH: + head = RECT_BOTTOM(self->frame->area); + size = self->frame->area.height; + e_start = RECT_LEFT(self->frame->area); + e_size = self->frame->area.width; + break; + default: + g_assert_not_reached(); + } - if(his_offset + 1 > my_offset) - continue; + client_find_edge_directional(self, dir, head, size, + e_start, e_size, &e, &near); + *x = self->frame->area.x; + *y = self->frame->area.y; + switch (dir) { + case OB_DIRECTION_EAST: + if (near) e -= self->frame->area.width; + else e++; + *x = e; + break; + case OB_DIRECTION_WEST: + if (near) e++; + else e -= self->frame->area.width; + *x = e; + break; + case OB_DIRECTION_NORTH: + if (near) e++; + else e -= self->frame->area.height; + *y = e; + break; + case OB_DIRECTION_SOUTH: + if (near) e -= self->frame->area.height; + else e++; + *y = e; + break; + default: + g_assert_not_reached(); + } + frame_frame_gravity(self->frame, x, y); +} - if(his_offset < dest) - continue; +void client_find_resize_directional(ObClient *self, ObDirection side, + gboolean grow, + gint *x, gint *y, gint *w, gint *h) +{ + gint head; + gint e, e_start, e_size, delta; + gboolean near; + ObDirection dir; - HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) - } - break; + switch (side) { case OB_DIRECTION_EAST: - my_edge_start = c->frame->area.y; - my_edge_end = c->frame->area.y + c->frame->area.height; - my_offset = c->frame->area.x + (hang ? 0 : c->frame->area.width); - - /* default: rightmost edge of screen */ - dest = a->x + a->width - (hang ? c->frame->area.width : 0); - monitor_dest = mon->x + mon->width - - (hang ? c->frame->area.width : 0); - /* if the monitor edge comes before the screen edge, */ - /* use that as the destination instead. (For xinerama) */ - if (monitor_dest != dest && my_offset < monitor_dest) - dest = monitor_dest; - - for(it = client_list; it && my_offset != dest; it = g_list_next(it)) { - gint his_edge_start, his_edge_end, his_offset; - ObClient *cur = it->data; - - WANT_EDGE(cur, c) - - his_edge_start = cur->frame->area.y; - his_edge_end = cur->frame->area.y + cur->frame->area.height; - his_offset = cur->frame->area.x + - (hang ? cur->frame->area.width : 0); - - if(his_offset - 1 < my_offset) - continue; - - if(his_offset > dest) - continue; - - HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) - } + head = RECT_RIGHT(self->frame->area) + + (self->size_inc.width - 1) * (grow ? 1 : -1); + e_start = RECT_TOP(self->frame->area); + e_size = self->frame->area.height; + dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST; + break; + case OB_DIRECTION_WEST: + head = RECT_LEFT(self->frame->area) - + (self->size_inc.width - 1) * (grow ? 1 : -1); + e_start = RECT_TOP(self->frame->area); + e_size = self->frame->area.height; + dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST; + break; + case OB_DIRECTION_NORTH: + head = RECT_TOP(self->frame->area) - + (self->size_inc.height - 1) * (grow ? 1 : -1); + e_start = RECT_LEFT(self->frame->area); + e_size = self->frame->area.width; + dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH; + break; + case OB_DIRECTION_SOUTH: + head = RECT_BOTTOM(self->frame->area) + + (self->size_inc.height - 1) * (grow ? 1 : -1); + e_start = RECT_LEFT(self->frame->area); + e_size = self->frame->area.width; + dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH; break; - case OB_DIRECTION_NORTHEAST: - case OB_DIRECTION_SOUTHEAST: - case OB_DIRECTION_NORTHWEST: - case OB_DIRECTION_SOUTHWEST: - /* not implemented */ default: g_assert_not_reached(); - dest = 0; /* suppress warning */ } - g_free(a); - g_free(mon); - return dest; + ob_debug("head %d dir %d\n", head, dir); + client_find_edge_directional(self, dir, head, 1, + e_start, e_size, &e, &near); + ob_debug("edge %d\n", e); + *x = self->frame->area.x; + *y = self->frame->area.y; + *w = self->frame->area.width; + *h = self->frame->area.height; + switch (side) { + case OB_DIRECTION_EAST: + if (grow == near) --e; + delta = e - RECT_RIGHT(self->frame->area); + *w += delta; + break; + case OB_DIRECTION_WEST: + if (grow == near) ++e; + delta = RECT_LEFT(self->frame->area) - e; + *x -= delta; + *w += delta; + break; + case OB_DIRECTION_NORTH: + if (grow == near) ++e; + delta = RECT_TOP(self->frame->area) - e; + *y -= delta; + *h += delta; + break; + case OB_DIRECTION_SOUTH: + if (grow == near) --e; + delta = e - RECT_BOTTOM(self->frame->area); + *h += delta; + break; + default: + g_assert_not_reached(); + } + frame_frame_gravity(self->frame, x, y); + *w -= self->frame->size.left + self->frame->size.right; + *h -= self->frame->size.top + self->frame->size.bottom; } ObClient* client_under_pointer() diff --git a/openbox/moveresize.c b/openbox/moveresize.c index 3d411a8d..9f1a9b04 100644 --- a/openbox/moveresize.c +++ b/openbox/moveresize.c @@ -26,6 +26,7 @@ #include "openbox.h" #include "resist.h" #include "mainloop.h" +#include "modkeys.h" #include "popup.h" #include "moveresize.h" #include "config.h" @@ -39,7 +40,7 @@ #include /* how far windows move and resize with the keyboard arrows */ -#define KEY_DIST 4 +#define KEY_DIST 8 gboolean moveresize_in_progress = FALSE; ObClient *moveresize_client = NULL; @@ -50,11 +51,12 @@ XSyncAlarm moveresize_alarm = None; static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */ static gint start_x, start_y, start_cx, start_cy, start_cw, start_ch; -static gint cur_x, cur_y; +static gint cur_x, cur_y, cur_w, cur_h; static guint button; static guint32 corner; static ObCorner lockcorner; static ObDirection edge_warp_dir = -1; +static ObDirection key_resize_edge = -1; #ifdef SYNC static gboolean waiting_for_sync; #endif @@ -63,6 +65,9 @@ static ObPopup *popup = NULL; static void do_edge_warp(gint x, gint y); static void cancel_edge_warp(); +#ifdef SYNC +static gboolean sync_timeout_func(gpointer data); +#endif static void client_dest(ObClient *client, gpointer data) { @@ -91,50 +96,6 @@ void moveresize_shutdown(gboolean reconfig) popup = NULL; } -static void get_resize_position(gint *x, gint *y, gboolean cancel) -{ - gint dw, dh; - gint w, h, lw, lh; - - *x = moveresize_client->frame->area.x; - *y = moveresize_client->frame->area.y; - - if (cancel) { - w = start_cw; - h = start_ch; - } else { - w = cur_x; - h = cur_y; - } - - /* see how much it is actually going to resize */ - { - gint cx = *x, cy = *y; - frame_frame_gravity(moveresize_client->frame, &cx, &cy, w, h); - client_try_configure(moveresize_client, &cx, &cy, &w, &h, - &lw, &lh, TRUE); - } - dw = w - moveresize_client->area.width; - dh = h - moveresize_client->area.height; - - switch (lockcorner) { - case OB_CORNER_TOPLEFT: - break; - case OB_CORNER_TOPRIGHT: - *x -= dw; - break; - case OB_CORNER_BOTTOMLEFT: - *y -= dh; - break; - case OB_CORNER_BOTTOMRIGHT: - *x -= dw; - *y -= dh; - break; - } - - frame_frame_gravity(moveresize_client->frame, x, y, w, h); -} - static void popup_coords(ObClient *c, const gchar *format, gint a, gint b) { gchar *text; @@ -206,17 +167,17 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr) moveresize_client = c; start_cx = c->area.x; start_cy = c->area.y; + start_cw = c->area.width; + start_ch = c->area.height; /* these adjustments for the size_inc make resizing a terminal more friendly. you essentially start the resize in the middle of the increment instead of at 0, so you have to move half an increment - either way instead of a full increment one and 1 px the other. and this - is one large mother fucking comment. */ - start_cw = c->area.width + c->size_inc.width / 2; - start_ch = c->area.height + c->size_inc.height / 2; - start_x = x; - start_y = y; + either way instead of a full increment one and 1 px the other. */ + start_x = x - c->size_inc.width / 2; + start_y = y - c->size_inc.height / 2; corner = cnr; button = b; + key_resize_edge = -1; /* have to change start_cx and start_cy if going to do this.. @@ -226,18 +187,15 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr) c->area.width / 2, c->area.height / 2); */ - if (moving) { - cur_x = start_cx; - cur_y = start_cy; - } else { - cur_x = start_cw; - cur_y = start_ch; - } + cur_x = start_cx; + cur_y = start_cy; + cur_w = start_cw; + cur_h = start_ch; moveresize_in_progress = TRUE; #ifdef SYNC - if (config_resize_redraw && !moving && extensions_shape && + if (config_resize_redraw && !moving && extensions_sync && moveresize_client->sync_request && moveresize_client->sync_counter) { /* Initialize values for the resize syncing, and create an alarm for @@ -280,8 +238,6 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr) void moveresize_end(gboolean cancel) { - gint x, y; - ungrab_keyboard(); ungrab_pointer(); @@ -298,12 +254,15 @@ void moveresize_end(gboolean cancel) XSyncDestroyAlarm(ob_display, moveresize_alarm); moveresize_alarm = None; } + + ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func); #endif - get_resize_position(&x, &y, cancel); - client_configure(moveresize_client, x, y, - (cancel ? start_cw : cur_x), - (cancel ? start_ch : cur_y), + client_configure(moveresize_client, + (cancel ? start_cx : cur_x), + (cancel ? start_cy : cur_y), + (cancel ? start_cw : cur_w), + (cancel ? start_ch : cur_h), TRUE, TRUE, FALSE); } @@ -314,19 +273,17 @@ void moveresize_end(gboolean cancel) moveresize_client = NULL; } -static void do_move(gboolean keyboard) +static void do_move(gboolean keyboard, gint keydist) { gint resist; - if (keyboard) resist = KEY_DIST - 1; /* resist for one key press */ + if (keyboard) resist = keydist - 1; /* resist for one key press */ else resist = config_resist_win; resist_move_windows(moveresize_client, resist, &cur_x, &cur_y); if (!keyboard) resist = config_resist_edge; resist_move_monitors(moveresize_client, resist, &cur_x, &cur_y); - client_configure(moveresize_client, cur_x, cur_y, - moveresize_client->area.width, - moveresize_client->area.height, + client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h, TRUE, FALSE, FALSE); if (config_resize_popup_show == 2) /* == "Always" */ popup_coords(moveresize_client, "%d x %d", @@ -334,6 +291,7 @@ static void do_move(gboolean keyboard) moveresize_client->frame->area.y); } + static void do_resize() { gint x, y, w, h, lw, lh; @@ -341,8 +299,8 @@ static void do_resize() /* see if it is actually going to resize */ x = 0; y = 0; - w = cur_x; - h = cur_y; + w = cur_w; + h = cur_h; client_try_configure(moveresize_client, &x, &y, &w, &h, &lw, &lh, TRUE); if (w == moveresize_client->area.width && @@ -381,11 +339,16 @@ static void do_resize() NoEventMask, &ce); waiting_for_sync = TRUE; + + ob_main_loop_timeout_remove(ob_main_loop, sync_timeout_func); + ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2, + sync_timeout_func, + NULL, NULL, NULL); } #endif - get_resize_position(&x, &y, FALSE); - client_configure(moveresize_client, x, y, cur_x, cur_y, TRUE, FALSE, FALSE); + client_configure(moveresize_client, cur_x, cur_y, cur_w, cur_h, + TRUE, FALSE, FALSE); /* this would be better with a fixed width font ... XXX can do it better if there are 2 text boxes */ @@ -398,26 +361,50 @@ static void do_resize() moveresize_client->logical_size.height); } -static void calc_resize(gboolean keyboard) +#ifdef SYNC +static gboolean sync_timeout_func(gpointer data) +{ + waiting_for_sync = FALSE; /* we timed out waiting for our sync... */ + do_resize(); /* ...so let any pending resizes through */ + + return FALSE; /* don't repeat */ +} +#endif + +static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh, + ObCorner cor) { - gint resist; + gint resist, x, y, lw, lh, ow, oh, nw, nh; + ow = cur_w; + oh = cur_h; /* resist_size_* needs the frame size */ - cur_x += moveresize_client->frame->size.left + + nw = ow + *dw + + moveresize_client->frame->size.left + moveresize_client->frame->size.right; - cur_y += moveresize_client->frame->size.top + + nh = oh + *dh + + moveresize_client->frame->size.top + moveresize_client->frame->size.bottom; - if (keyboard) resist = KEY_DIST - 1; /* resist for one key press */ + if (keyboard) resist = keydist - 1; /* resist for one key press */ else resist = config_resist_win; - resist_size_windows(moveresize_client, resist, &cur_x, &cur_y, lockcorner); + resist_size_windows(moveresize_client, resist, &nw, &nh, cor); if (!keyboard) resist = config_resist_edge; - resist_size_monitors(moveresize_client, resist, &cur_x, &cur_y,lockcorner); + resist_size_monitors(moveresize_client, resist, &nw, &nh, cor); - cur_x -= moveresize_client->frame->size.left + + nw -= moveresize_client->frame->size.left + moveresize_client->frame->size.right; - cur_y -= moveresize_client->frame->size.top + + nh -= moveresize_client->frame->size.top + moveresize_client->frame->size.bottom; + + /* see its actual size */ + x = 0; + y = 0; + client_try_configure(moveresize_client, &x, &y, &nw, &nh, &lw, &lh, TRUE); + + + *dw = nw - ow; + *dh = nh - oh; } static gboolean edge_warp_delay_func(gpointer data) @@ -434,7 +421,7 @@ static gboolean edge_warp_delay_func(gpointer data) static void do_edge_warp(gint x, gint y) { - guint i, d; + guint i; ObDirection dir; if (!config_mouse_screenedgetime) return; @@ -479,11 +466,228 @@ static void cancel_edge_warp() ob_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func); } +static void move_with_keys(gint keycode, gint state) +{ + gint dx = 0, dy = 0, ox = cur_x, oy = cur_y; + gint opx, px, opy, py; + gint dist = 0; + + /* shift means jump to edge */ + if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) { + gint x, y; + ObDirection dir; + + if (keycode == ob_keycode(OB_KEY_RIGHT)) + dir = OB_DIRECTION_EAST; + else if (keycode == ob_keycode(OB_KEY_LEFT)) + dir = OB_DIRECTION_WEST; + else if (keycode == ob_keycode(OB_KEY_DOWN)) + dir = OB_DIRECTION_SOUTH; + else /* if (keycode == ob_keycode(OB_KEY_UP)) */ + dir = OB_DIRECTION_NORTH; + + client_find_move_directional(moveresize_client, dir, &x, &y); + dx = x - moveresize_client->area.x; + dy = y - moveresize_client->area.y; + } else { + /* control means fine grained */ + if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) + dist = 1; + else + dist = KEY_DIST; + + if (keycode == ob_keycode(OB_KEY_RIGHT)) + dx = dist; + else if (keycode == ob_keycode(OB_KEY_LEFT)) + dx = -dist; + else if (keycode == ob_keycode(OB_KEY_DOWN)) + dy = dist; + else /* if (keycode == ob_keycode(OB_KEY_UP)) */ + dy = -dist; + } + + screen_pointer_pos(&opx, &opy); + XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy); + /* steal the motion events this causes */ + XSync(ob_display, FALSE); + { + XEvent ce; + while (XCheckTypedEvent(ob_display, MotionNotify, &ce)); + } + screen_pointer_pos(&px, &py); + + cur_x += dx; + cur_y += dy; + do_move(TRUE, dist); + + /* because the cursor moves even though the window does + not nessesarily (resistance), this adjusts where the curor + thinks it started so that it keeps up with where the window + actually is */ + start_x += (px - opx) - (cur_x - ox); + start_y += (py - opy) - (cur_y - oy); +} + +static void resize_with_keys(gint keycode, gint state) +{ + gint dw = 0, dh = 0, pdx = 0, pdy = 0, opx, opy, px, py; + gint dist = 0; + ObDirection dir; + ObCorner cor; + + /* pick the edge if it needs to move */ + if (keycode == ob_keycode(OB_KEY_RIGHT)) { + dir = OB_DIRECTION_EAST; + if (key_resize_edge != OB_DIRECTION_WEST && + key_resize_edge != OB_DIRECTION_EAST) + { + key_resize_edge = OB_DIRECTION_EAST; + return; + } + } + if (keycode == ob_keycode(OB_KEY_LEFT)) { + dir = OB_DIRECTION_WEST; + if (key_resize_edge != OB_DIRECTION_WEST && + key_resize_edge != OB_DIRECTION_EAST) + { + key_resize_edge = OB_DIRECTION_WEST; + return; + } + } + if (keycode == ob_keycode(OB_KEY_UP)) { + dir = OB_DIRECTION_NORTH; + if (key_resize_edge != OB_DIRECTION_NORTH && + key_resize_edge != OB_DIRECTION_SOUTH) + { + key_resize_edge = OB_DIRECTION_NORTH; + return; + } + } + if (keycode == ob_keycode(OB_KEY_DOWN)) { + dir = OB_DIRECTION_SOUTH; + if (key_resize_edge != OB_DIRECTION_NORTH && + key_resize_edge != OB_DIRECTION_SOUTH) + { + key_resize_edge = OB_DIRECTION_SOUTH; + return; + } + } + + /* shift means jump to edge */ + if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) { + gint x, y, w, h; + + if (keycode == ob_keycode(OB_KEY_RIGHT)) + dir = OB_DIRECTION_EAST; + else if (keycode == ob_keycode(OB_KEY_LEFT)) + dir = OB_DIRECTION_WEST; + else if (keycode == ob_keycode(OB_KEY_DOWN)) + dir = OB_DIRECTION_SOUTH; + else /* if (keycode == ob_keycode(OB_KEY_UP)) */ + dir = OB_DIRECTION_NORTH; + + client_find_resize_directional(moveresize_client, key_resize_edge, + key_resize_edge == dir, + &x, &y, &w, &h); + dw = w - moveresize_client->area.width; + dh = h - moveresize_client->area.height; + } else { + gint distw, disth; + + /* control means fine grained */ + if (moveresize_client->size_inc.width > 1) + distw = moveresize_client->size_inc.width; + else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) + distw = 1; + else + distw = KEY_DIST; + if (moveresize_client->size_inc.height > 1) + disth = moveresize_client->size_inc.height; + else if (state & modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL)) + disth = 1; + else + disth = KEY_DIST; + + if (key_resize_edge == OB_DIRECTION_WEST) { + if (dir == OB_DIRECTION_WEST) + dw = (dist = distw); + else + dw = -(dist = distw); + } + else if (key_resize_edge == OB_DIRECTION_EAST) { + if (dir == OB_DIRECTION_EAST) + dw = (dist = distw); + else + dw = -(dist = distw); + } + else if (key_resize_edge == OB_DIRECTION_NORTH) { + if (dir == OB_DIRECTION_NORTH) + dh = (dist = disth); + else + dh = -(dist = disth); + } + else /*if (key_resize_edge == OB_DIRECTION_SOUTH)*/ { + if (dir == OB_DIRECTION_SOUTH) + dh = (dist = disth); + else + dh = -(dist = disth); + } + } + + /* which corner is locked, for resistance */ + if (key_resize_edge == OB_DIRECTION_WEST) + cor = OB_CORNER_TOPRIGHT; + else if (key_resize_edge == OB_DIRECTION_EAST) + cor = OB_CORNER_TOPLEFT; + else if (key_resize_edge == OB_DIRECTION_NORTH) + cor = OB_CORNER_BOTTOMLEFT; + else if (key_resize_edge == OB_DIRECTION_SOUTH) + cor = OB_CORNER_TOPLEFT; + + calc_resize(TRUE, dist, &dw, &dh, cor); + if (key_resize_edge == OB_DIRECTION_WEST) + cur_x -= dw; + else if (key_resize_edge == OB_DIRECTION_NORTH) + cur_y -= dh; + cur_w += dw; + cur_h += dh; + + /* how to move the pointer to keep up with the change */ + if (key_resize_edge == OB_DIRECTION_WEST) + pdx = -dw; + else if (key_resize_edge == OB_DIRECTION_EAST) + pdx = dw; + else if (key_resize_edge == OB_DIRECTION_NORTH) + pdy = -dh; + else if (key_resize_edge == OB_DIRECTION_SOUTH) + pdy = dh; + + screen_pointer_pos(&opx, &opy); + XWarpPointer(ob_display, None, None, 0, 0, 0, 0, pdx, pdy); + /* steal the motion events this causes */ + XSync(ob_display, FALSE); + { + XEvent ce; + while (XCheckTypedEvent(ob_display, MotionNotify, &ce)); + } + screen_pointer_pos(&px, &py); + + do_resize(); + + /* because the cursor moves even though the window does + not nessesarily (resistance), this adjusts where the cursor + thinks it started so that it keeps up with where the window + actually is */ + start_x += (px - opx) - dw; + start_y += (py - opy) - dh; + +} + gboolean moveresize_event(XEvent *e) { gboolean used = FALSE; - g_assert(moveresize_in_progress); + if (!moveresize_in_progress) return FALSE; if (e->type == ButtonPress) { if (!button) { @@ -501,51 +705,72 @@ gboolean moveresize_event(XEvent *e) if (moving) { cur_x = start_cx + e->xmotion.x_root - start_x; cur_y = start_cy + e->xmotion.y_root - start_y; - do_move(FALSE); + do_move(FALSE, 0); do_edge_warp(e->xmotion.x_root, e->xmotion.y_root); } else { + gint dw, dh; + if (corner == prop_atoms.net_wm_moveresize_size_topleft) { - cur_x = start_cw - (e->xmotion.x_root - start_x); - cur_y = start_ch - (e->xmotion.y_root - start_y); + dw = -(e->xmotion.x_root - start_x); + dh = -(e->xmotion.y_root - start_y); lockcorner = OB_CORNER_BOTTOMRIGHT; } else if (corner == prop_atoms.net_wm_moveresize_size_top) { - cur_x = start_cw; - cur_y = start_ch - (e->xmotion.y_root - start_y); + dw = 0; + dh = -(e->xmotion.y_root - start_y); lockcorner = OB_CORNER_BOTTOMRIGHT; } else if (corner == prop_atoms.net_wm_moveresize_size_topright) { - cur_x = start_cw + (e->xmotion.x_root - start_x); - cur_y = start_ch - (e->xmotion.y_root - start_y); + dw = (e->xmotion.x_root - start_x); + dh = -(e->xmotion.y_root - start_y); lockcorner = OB_CORNER_BOTTOMLEFT; } else if (corner == prop_atoms.net_wm_moveresize_size_right) { - cur_x = start_cw + (e->xmotion.x_root - start_x); - cur_y = start_ch; + dw = (e->xmotion.x_root - start_x); + dh = 0; lockcorner = OB_CORNER_BOTTOMLEFT; } else if (corner == prop_atoms.net_wm_moveresize_size_bottomright) { - cur_x = start_cw + (e->xmotion.x_root - start_x); - cur_y = start_ch + (e->xmotion.y_root - start_y); + dw = (e->xmotion.x_root - start_x); + dh = (e->xmotion.y_root - start_y); lockcorner = OB_CORNER_TOPLEFT; } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) { - cur_x = start_cw; - cur_y = start_ch + (e->xmotion.y_root - start_y); + dw = 0; + dh = (e->xmotion.y_root - start_y); lockcorner = OB_CORNER_TOPLEFT; } else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft) { - cur_x = start_cw - (e->xmotion.x_root - start_x); - cur_y = start_ch + (e->xmotion.y_root - start_y); + dw = -(e->xmotion.x_root - start_x); + dh = (e->xmotion.y_root - start_y); lockcorner = OB_CORNER_TOPRIGHT; } else if (corner == prop_atoms.net_wm_moveresize_size_left) { - cur_x = start_cw - (e->xmotion.x_root - start_x); - cur_y = start_ch; + dw = -(e->xmotion.x_root - start_x); + dh = 0; lockcorner = OB_CORNER_TOPRIGHT; } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) { - cur_x = start_cw + (e->xmotion.x_root - start_x); - cur_y = start_ch + (e->xmotion.y_root - start_y); + dw = (e->xmotion.x_root - start_x); + dh = (e->xmotion.y_root - start_y); lockcorner = OB_CORNER_TOPLEFT; } else g_assert_not_reached(); - calc_resize(FALSE); + dw -= cur_w - start_cw; + dh -= cur_h - start_ch; + + calc_resize(FALSE, 0, &dw, &dh, lockcorner); + cur_w += dw; + cur_h += dh; + + if (corner == prop_atoms.net_wm_moveresize_size_topleft || + corner == prop_atoms.net_wm_moveresize_size_left || + corner == prop_atoms.net_wm_moveresize_size_bottomleft) + { + cur_x -= dw; + } + if (corner == prop_atoms.net_wm_moveresize_size_topleft || + corner == prop_atoms.net_wm_moveresize_size_top || + corner == prop_atoms.net_wm_moveresize_size_topright) + { + cur_y -= dh; + } + do_resize(); } used = TRUE; @@ -562,72 +787,10 @@ gboolean moveresize_event(XEvent *e) e->xkey.keycode == ob_keycode(OB_KEY_UP)) { if (corner == prop_atoms.net_wm_moveresize_size_keyboard) { - gint dx = 0, dy = 0, ox = cur_x, oy = cur_y; - - if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) - dx = MAX(KEY_DIST, moveresize_client->size_inc.width); - else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT)) - dx = -MAX(KEY_DIST, moveresize_client->size_inc.width); - else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN)) - dy = MAX(KEY_DIST, moveresize_client->size_inc.height); - else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */ - dy = -MAX(KEY_DIST, moveresize_client->size_inc.height); - - cur_x += dx; - cur_y += dy; - XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy); - /* steal the motion events this causes */ - XSync(ob_display, FALSE); - { - XEvent ce; - while (XCheckTypedEvent(ob_display, MotionNotify, &ce)); - } - - calc_resize(TRUE); - do_resize(); - - /* because the cursor moves even though the window does - not nessesarily (resistance), this adjusts where the curor - thinks it started so that it keeps up with where the window - actually is */ - start_x += dx - (cur_x - ox); - start_y += dy - (cur_y - oy); - + resize_with_keys(e->xkey.keycode, e->xkey.state); used = TRUE; } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) { - gint dx = 0, dy = 0, ox = cur_x, oy = cur_y; - gint opx, px, opy, py; - - if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) - dx = KEY_DIST; - else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT)) - dx = -KEY_DIST; - else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN)) - dy = KEY_DIST; - else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */ - dy = -KEY_DIST; - - cur_x += dx; - cur_y += dy; - screen_pointer_pos(&opx, &opy); - XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy); - /* steal the motion events this causes */ - XSync(ob_display, FALSE); - { - XEvent ce; - while (XCheckTypedEvent(ob_display, MotionNotify, &ce)); - } - screen_pointer_pos(&px, &py); - - do_move(TRUE); - - /* because the cursor moves even though the window does - not nessesarily (resistance), this adjusts where the curor - thinks it started so that it keeps up with where the window - actually is */ - start_x += (px - opx) - (cur_x - ox); - start_y += (py - opy) - (cur_y - oy); - + move_with_keys(e->xkey.keycode, e->xkey.state); used = TRUE; } } -- 2.34.1