diff --git a/fvwm/move_resize.c b/fvwm/move_resize.c index 7091a984d..f411a43bd 100644 --- a/fvwm/move_resize.c +++ b/fvwm/move_resize.c @@ -106,6 +106,10 @@ static void grow_to_closest_type(FvwmWindow *, rectangle *, rectangle, int *, int, bool); static void set_geom_win_visible_val(char *, bool); static bool set_geom_win_position_val(char *, int *, bool *, bool *); +static void DoSnapGrid(FvwmWindow *, rectangle, int *, int *); +static void DoSnapMonitor(FvwmWindow *, rectangle, int *, int *, int, bool, + bool); +static void DoSnapWindow(FvwmWindow *, rectangle, int *, int *); /* ----- end of resize globals ----- */ @@ -2258,319 +2262,282 @@ static void update_pos( return; } -/* This function does the SnapAttraction stuff. It takes x and y coordinates +/* These functions do the SnapAttraction stuff. It takes x and y coordinates * (*px and *py) and returns the snapped values. */ -static void DoSnapAttract( - FvwmWindow *fw, int Width, int Height, int *px, int *py) +#define NOSNAP -99999 +#define MAXSCORE 99999999 +static void DoSnapGrid(FvwmWindow *fw, rectangle self, int *nxl, int *nyt) { - int nyt,nxl; - rectangle self; - int score_x; - int score_y; - int scr_w, scr_h; - int mon_w, mon_h, mon_x, mon_y; + int grid_x = self.x / fw->snap_grid_x * fw->snap_grid_x; + int grid_y = self.y / fw->snap_grid_y * fw->snap_grid_y; + + if (fw->snap_grid_x > 1 && self.x != grid_x) + *nxl = (self.x - grid_x <= fw->snap_grid_x / 2) ? grid_x : + grid_x + fw->snap_grid_x; + + if (fw->snap_grid_y > 1 && self.y != grid_y) + *nyt = (self.y - grid_y <= fw->snap_grid_y / 2) ? grid_y : + grid_y + fw->snap_grid_y; +} +static void DoSnapMonitor( + FvwmWindow *fw, rectangle self, int *nxl, int *nyt, + int snapd, bool resist, bool all_edges) +{ + int mon_x, mon_y, mon_r, mon_b, tmp; + int bottom = self.y + self.height; + int right = self.x + self.width; + int score_x = MAXSCORE, score_y = MAXSCORE; struct monitor *m; - nxl = -99999; - nyt = -99999; - score_x = 99999999; - score_y = 99999999; - self.x = *px; - self.y = *py; - self.width = Width; - self.height = Height; + TAILQ_FOREACH(m, &monitor_q, entry) { - rectangle g; - Bool rc; + mon_x = m->si->x; + mon_y = m->si->y; + mon_r = mon_x + m->si->w; + mon_b = mon_y + m->si->h; - rc = get_visible_icon_title_geometry(fw, &g); - if (rc == True) + /* vertically */ + if (!(right < mon_x || self.x > mon_r) && + (all_edges || m->edge.bottom == MONITOR_OUTSIDE_EDGE)) { - self.height += g.height; + tmp = resist ? mon_b : mon_b - snapd; + if (bottom <= mon_b + snapd && bottom >= tmp) + update_pos(&score_y, nyt, self.y, + mon_b - self.height); + } + if (!(right < mon_x || self.x > mon_r) && + (all_edges || m->edge.top == MONITOR_OUTSIDE_EDGE)) + { + tmp = resist ? mon_y : mon_y + snapd; + if (self.y <= tmp && self.y >= mon_y - snapd) + update_pos(&score_y, nyt, self.y, mon_y); } - } - - scr_w = monitor_get_all_widths(); - scr_h = monitor_get_all_heights(); - /* - * Snap grid handling - */ - if (fw->snap_grid_x > 1 && nxl == -99999) - { - if (*px != *px / fw->snap_grid_x * fw->snap_grid_x) + /* horizontally */ + if (!(bottom < mon_y || self.y > mon_b) && + (all_edges || m->edge.right == MONITOR_OUTSIDE_EDGE)) { - nxl = (*px + ((*px >= 0) ? - fw->snap_grid_x : -fw->snap_grid_x) / - 2) / fw->snap_grid_x * fw->snap_grid_x; + tmp = resist ? mon_r : mon_r - snapd; + if (right <= mon_r + snapd && right >= tmp) + update_pos(&score_x, nxl, self.x, + mon_r - self.width); } - } - if (fw->snap_grid_y > 1 && nyt == -99999) - { - if (*py != *py / fw->snap_grid_y * fw->snap_grid_y) + if (!(bottom < mon_y || self.y > mon_b) && + (all_edges || m->edge.left == MONITOR_OUTSIDE_EDGE)) { - nyt = (*py + ((*py >= 0) ? - fw->snap_grid_y : -fw->snap_grid_y) / - 2) / fw->snap_grid_y * fw->snap_grid_y; + tmp = resist ? mon_x : mon_x + snapd; + if (self.x <= tmp && self.x >= mon_x - snapd) + update_pos(&score_x, nxl, self.x, mon_x); } } +} +static void DoSnapWindow(FvwmWindow *fw, rectangle self, int *nxl, int *nyt) +{ + int score_x = MAXSCORE, score_y = MAXSCORE; + FvwmWindow *tmp; + int maskout = (SNAP_SCREEN | SNAP_SCREEN_WINDOWS | + SNAP_SCREEN_ICONS | SNAP_SCREEN_ALL); - /* - * snap attraction - */ - /* snap to other windows or icons*/ - if (fw->snap_attraction.proximity > 0 && - (fw->snap_attraction.mode & (SNAP_ICONS | SNAP_WINDOWS | SNAP_SAME))) + int scr_w, scr_h; + scr_w = monitor_get_all_widths(); + scr_h = monitor_get_all_heights(); + + for (tmp = Scr.FvwmRoot.next; tmp; tmp = tmp->next) { - FvwmWindow *tmp; - int maskout = (SNAP_SCREEN | SNAP_SCREEN_WINDOWS | - SNAP_SCREEN_ICONS | SNAP_SCREEN_ALL); + rectangle other; - for (tmp = Scr.FvwmRoot.next; tmp; tmp = tmp->next) - { - rectangle other; + if (fw->Desk != tmp->Desk || fw == tmp) + continue; - if (fw->Desk != tmp->Desk || fw == tmp) - { + /* check snapping type */ + switch (fw->snap_attraction.mode & ~(maskout)) + { + case SNAP_WINDOWS: /* we only snap windows */ + if (IS_ICONIFIED(tmp) || IS_ICONIFIED(fw)) continue; - } - /* check snapping type */ - switch (fw->snap_attraction.mode & ~(maskout)) - { - case SNAP_WINDOWS: /* we only snap windows */ - if (IS_ICONIFIED(tmp) || IS_ICONIFIED(fw)) - { - continue; - } - break; - case SNAP_ICONS: /* we only snap icons */ - if (!IS_ICONIFIED(tmp) || !IS_ICONIFIED(fw)) - { - continue; - } - break; - case SNAP_SAME: /* we don't snap unequal */ - if (IS_ICONIFIED(tmp) != IS_ICONIFIED(fw)) - { - continue; - } - break; - default: /* All */ - /* NOOP */ - break; - } - /* get other window dimensions */ - get_visible_window_or_icon_geometry(tmp, &other); - if (other.x >= scr_w || - other.x + other.width <= 0 || - other.y >= scr_h || - other.y + other.height <= 0) - { - /* do not snap to windows that are not currently - * visible */ + break; + case SNAP_ICONS: /* we only snap icons */ + if (!IS_ICONIFIED(tmp) || !IS_ICONIFIED(fw)) continue; - } - /* snap horizontally */ - if (other.y + other.height > *py && - other.y < *py + self.height) + case SNAP_SAME: /* we don't snap unequal */ + if (IS_ICONIFIED(tmp) != IS_ICONIFIED(fw)) + continue; + break; + default: /* All */ + /* NOOP */ + break; + } + + /* get other window dimensions */ + get_visible_window_or_icon_geometry(tmp, &other); + if (other.x >= scr_w || + other.x + other.width <= 0 || + other.y >= scr_h || + other.y + other.height <= 0) + { + /* do not snap to windows that are not currently + * visible */ + continue; + } + + /* snap horizontally */ + if (other.y + other.height > self.y && + other.y < self.y + self.height) + { + if (self.x + self.width >= other.x - + fw->snap_attraction.proximity && + self.x + self.width <= other.x + + fw->snap_attraction.proximity) { - if (*px + self.width >= other.x - - fw->snap_attraction.proximity && - *px + self.width <= other.x + - fw->snap_attraction.proximity) - { - update_pos(&score_x, &nxl, *px, - other.x - self.width); - } - if (*px <= other.x + other.width + - fw->snap_attraction.proximity && - *px >= other.x + other.width - - fw->snap_attraction.proximity) - { - update_pos(&score_x, &nxl, *px, - other.x + other.width); - } + update_pos(&score_x, nxl, self.x, + other.x - self.width); } - /* snap vertically */ - if (other.x + other.width > *px && - other.x < *px + self.width) + if (self.x <= other.x + other.width + + fw->snap_attraction.proximity && + self.x >= other.x + other.width - + fw->snap_attraction.proximity) { - if (*py + self.height >= other.y - - fw->snap_attraction.proximity && - *py + self.height <= other.y + - fw->snap_attraction.proximity) - { - update_pos(&score_y, &nyt, *py, - other.y - self.height); - } - if (*py <= other.y + other.height + - fw->snap_attraction.proximity && - *py >= other.y + other.height - - fw->snap_attraction.proximity) - { - update_pos(&score_y, &nyt, *py, - other.y + other.height); - } + update_pos(&score_x, nxl, self.x, + other.x + other.width); } - } /* for */ - } /* snap to other windows */ - - /* snap to monitor edges */ - if (fw->snap_attraction.proximity > 0 && ( - ( fw->snap_attraction.mode & SNAP_SCREEN && ( - fw->snap_attraction.mode & SNAP_SAME || - ( IS_ICONIFIED(fw) && - fw->snap_attraction.mode & SNAP_ICONS ) || - ( !IS_ICONIFIED(fw) && - fw->snap_attraction.mode & SNAP_WINDOWS ))) || - ( !IS_ICONIFIED(fw) && - fw->snap_attraction.mode & SNAP_SCREEN_WINDOWS ) || - ( IS_ICONIFIED(fw) && - fw->snap_attraction.mode & SNAP_SCREEN_ICONS ) || - fw->snap_attraction.mode & SNAP_SCREEN_ALL )) - { - /* Loop over each monitor */ - TAILQ_FOREACH(m, &monitor_q, entry) - { - mon_x = m->si->x; - mon_y = m->si->y; - mon_w = m->si->w; - mon_h = m->si->h; - - /* vertically */ - if (!(*px + self.width < mon_x || *px > mon_x + mon_w)) + } + + /* snap vertically */ + if (other.x + other.width > self.x && + other.x < self.x + self.width) + { + if (self.y + self.height >= other.y - + fw->snap_attraction.proximity && + self.y + self.height <= other.y + + fw->snap_attraction.proximity) { - if (*py + self.height >= - mon_h + mon_y - fw->snap_attraction.proximity && - *py + self.height <= - mon_h + mon_y + fw->snap_attraction.proximity) - { - update_pos(&score_y, &nyt, *py, - mon_h + mon_y - self.height); - } - if (*py <= mon_y + fw->snap_attraction.proximity && - *py > mon_y - fw->snap_attraction.proximity) - { - update_pos(&score_y, &nyt, *py, mon_y); - } + update_pos(&score_y, nyt, self.y, + other.y - self.height); } - /* horizontally */ - if (!(*py + self.height < mon_y || *py > mon_y + mon_h)) + if (self.y <= other.y + other.height + + fw->snap_attraction.proximity && + self.y >= other.y + other.height - + fw->snap_attraction.proximity) { - if (*px + self.width >= - mon_w + mon_x - fw->snap_attraction.proximity && - *px + self.width <= - mon_w + mon_x + fw->snap_attraction.proximity) - { - update_pos(&score_x, &nxl, *px, - mon_w + mon_x - self.width); - } - if ((*px <= mon_x + fw->snap_attraction.proximity) && - (*px >= mon_x - fw->snap_attraction.proximity)) - { - update_pos(&score_x, &nxl, *px, mon_x); - } + update_pos(&score_y, nyt, self.y, + other.y + other.height); } - } /* monitor loop */ - } /* snap to monitor edges */ - - if (nxl != -99999) - { - *px = nxl; - } - if (nyt != -99999) - { - *py = nyt; + } } - /* - * Resist moving windows beyond the edge of the screen - */ - if (fw->edge_resistance_move > 0) + /* Ignore snapping to window sides on monitor edges */ + struct monitor *m; + + TAILQ_FOREACH(m, &monitor_q, entry) { - /* snap to right edge */ - if ( - *px + Width > scr_w && - *px + Width < scr_w + - fw->edge_resistance_move) - { - *px = scr_w - Width; - } - /* snap to left edge */ - else if ((*px < 0) && (*px > -fw->edge_resistance_move)) + if ((*nxl == m->si->x || *nxl == m->si->x + m->si->w) && + (self.y >= m->si->y && + self.y + self.height <= m->si->y + m->si->h)) { - *px = 0; + *nxl = NOSNAP; } - /* snap to bottom edge */ - if ( - *py + Height > scr_h && - *py + Height < scr_h + - fw->edge_resistance_move) - { - *py = scr_h - Height; - } - /* snap to top edge */ - else if (*py < 0 && *py > -fw->edge_resistance_move) + if ((*nyt == m->si->y || *nyt == m->si->y + m->si->h) && + (self.x >= m->si->y && + self.x + self.width <= m->si->x + m->si->w)) { - *py = 0; + *nyt = NOSNAP; } } - /* Resist moving windows between xineramascreens */ - if (fw->edge_resistance_xinerama_move) + +} +static void DoSnapAttract( + FvwmWindow *fw, int Width, int Height, int *px, int *py) +{ + int nyt = NOSNAP, nxl = NOSNAP; + int win_yt = NOSNAP, win_xl = NOSNAP; + int mon_yt = NOSNAP, mon_xl = NOSNAP; + rectangle self, g; + + self.x = *px; + self.y = *py; + self.width = Width; + self.height = Height; + if (get_visible_icon_title_geometry(fw, &g)) + self.height += g.height; + + int icon_mask = IS_ICONIFIED(fw) ? SNAP_SCREEN_ICONS : + SNAP_SCREEN_WINDOWS; + bool snap_mon = (fw->snap_attraction.mode & SNAP_SCREEN_ALL || + fw->snap_attraction.mode & (SNAP_SCREEN & icon_mask)) ? + true : false; + bool snap_win = (fw->snap_attraction.mode & + (SNAP_ICONS | SNAP_WINDOWS | SNAP_SAME)) ? true : false; + bool snap_grid = (fw->snap_grid_x > 1 || fw->snap_grid_y > 1) ? true : + false; + + /* + * Checks both monitor edges and windows. Snaps to closer of the two. + * If no monitor edge or window are found, snap to SnapGrid. + */ + if (fw->snap_attraction.proximity > 0) { - int scr_x0, scr_y0; - int scr_x1, scr_y1; - Bool do_recalc_rectangle = False; + if (snap_mon) + DoSnapMonitor(fw, self, &mon_xl, &mon_yt, + fw->snap_attraction.proximity, false, true); - FScreenGetResistanceRect( - *px, *py, Width, Height, &scr_x0, &scr_y0, &scr_x1, - &scr_y1); + if (snap_win) + DoSnapWindow(fw, self, &win_xl, &win_yt); - /* snap to right edge */ - if (scr_x1 < scr_w && - *px + Width >= scr_x1 && *px + Width < - scr_x1 + fw->edge_resistance_xinerama_move) - { - *px = scr_x1 - Width; - do_recalc_rectangle = True; - } - /* snap to left edge */ - else if ( - scr_x0 > 0 && - *px <= scr_x0 && scr_x0 - *px < - fw->edge_resistance_xinerama_move) - { - *px = scr_x0; - do_recalc_rectangle = True; - } - if (do_recalc_rectangle) - { - /* Snapping in X direction can move the window off a - * screen. Thus, it may no longer be necessary to snap - * in Y direction. */ - FScreenGetResistanceRect( - *px, *py, Width, Height, &scr_x0, &scr_y0, - &scr_x1, &scr_y1); - } - /* snap to bottom edge */ - if (scr_y1 < scr_h && - *py + Height >= scr_y1 && *py + Height < - scr_y1 + fw->edge_resistance_xinerama_move) - { - *py = scr_y1 - Height; - } - /* snap to top edge */ - else if ( - scr_y0 > 0 && - *py <= scr_y0 && scr_y0 - *py < - fw->edge_resistance_xinerama_move) + if (mon_xl != NOSNAP || win_xl != NOSNAP) + nxl = (abs(self.x - mon_xl) < abs(self.x - win_xl)) ? + mon_xl : win_xl; + + if (mon_yt != NOSNAP || win_yt != NOSNAP) + nyt = (abs(self.y - mon_yt) < abs(self.y - win_yt)) ? + mon_yt : win_yt; + + if ((nxl == NOSNAP || nyt == NOSNAP) && snap_grid) { - *py = scr_y0; + win_xl = NOSNAP; + win_yt = NOSNAP; + DoSnapGrid(fw, self, &win_xl, &win_yt); + if (nxl == NOSNAP && win_xl != NOSNAP) + nxl = win_xl; + if (nyt == NOSNAP && win_yt != NOSNAP) + nyt = win_yt; } } + if (nxl != NOSNAP) + *px = nxl; + if (nyt != NOSNAP) + *py = nyt; + + /* Resist moving windows beyond outside edges of the monitor */ + if (fw->edge_resistance_move > 0) + { + nxl = NOSNAP; + nyt = NOSNAP; + DoSnapMonitor(fw, self, &nxl, &nyt, + fw->edge_resistance_move, true, false); + if (nxl != NOSNAP) + *px = nxl; + if (nyt != NOSNAP) + *py = nyt; + } + + /* Resist moving windows beyond all edges of the monitor. */ + if (fw->edge_resistance_xinerama_move > 0) + { + nxl = NOSNAP; + nyt = NOSNAP; + DoSnapMonitor(fw, self, &nxl, &nyt, + fw->edge_resistance_xinerama_move, true, true); + if (nxl != NOSNAP) + *px = nxl; + if (nyt != NOSNAP) + *py = nyt; + } + return; } +#undef NOSNAP +#undef MAXSCORE /* *