From a0ff58a370a21cedcc4088985324d30fd4576811 Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Thu, 10 Jun 2021 19:19:10 +0100 Subject: [PATCH] EdgeScroll: a few improvements This addresses some edgescroll improvements and simplifies the logic between how panframes are handled between being in global and per-monitor mode. Now, monitor edges which border one another don't have a panframe added for global mode (only the outside edges are). With the same logic, per-screen panframes are drawn for all edges. This also helps to reduce problems where some screens have different resolutions, and so now dead spave between monitors is handled much better. Fixes #523 --- fvwm/events.c | 1 + fvwm/virtual.c | 324 +++++++++++++++++++++++-------------------------- libs/FScreen.c | 37 +++++- libs/FScreen.h | 10 ++ 4 files changed, 198 insertions(+), 174 deletions(-) diff --git a/fvwm/events.c b/fvwm/events.c index caa11c301..76b7ab277 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -4089,6 +4089,7 @@ void dispatch_event(XEvent *e) XRRUpdateConfiguration(e); monitor_update_ewmh(); monitor_emit_broadcast(); + initPanFrames(); break; } } diff --git a/fvwm/virtual.c b/fvwm/virtual.c index 1930ebd14..cc2c6e642 100644 --- a/fvwm/virtual.c +++ b/fvwm/virtual.c @@ -706,7 +706,7 @@ static void MapDesk(struct monitor *m, int desk, Bool grab) * * Returns * 0: no paging - * 1: paging occured + * 1: paging occurred * -1: no need to call the function again before a new event arrives */ int HandlePaging( @@ -980,7 +980,7 @@ int HandlePaging( if (*xl <= (m->si->x + edge_thickness)) *xl = m->si->x + edge_thickness; if (*yt <= (m->si->y + edge_thickness)) - *yt = edge_thickness; + *yt = m->si->y + edge_thickness; if (*xl >= (m->si->x + m->si->w) - edge_thickness) *xl = (m->si->x + m->si->w) - edge_thickness -1; if (*yt >= (m->si->y + m->si->h) - edge_thickness) @@ -1016,7 +1016,7 @@ int HandlePaging( * one of these windows causes a Paging. The windows have the according cursor * pointing in the pan direction or are hidden if there is no more panning * in that direction. This is mostly intended to get a panning even atop - * of Motif applictions, which does not work yet. It seems Motif windows + * of Motif applications, which does not work yet. It seems Motif windows * eat all mouse events. * * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94 @@ -1034,6 +1034,11 @@ void checkPanFrames(struct monitor *m) bool do_unmap_t = false; bool do_unmap_b = false; bool global = (monitor_mode == MONITOR_TRACKING_G && !is_tracking_shared); + int h = m->si->y + m->si->h; + int w = m->si->x + m->si->w; + int x = m->si->x; + int y = m->si->y; + if (!Scr.flags.are_windows_captured) return; @@ -1047,161 +1052,165 @@ void checkPanFrames(struct monitor *m) do_unmap_b = true; } + /* Remove Pan frames if paging by edge-scroll is permanently or + * temporarily disabled */ + if (m->virtual_scr.EdgeScrollX == 0 || m->virtual_scr.VxMax == 0) { - int h = global ? monitor_get_all_heights() : (m->si->y + m->si->h); - int w = global ? monitor_get_all_widths() : (m->si->x + m->si->w); - int x = global ? 0 : m->si->x; - int y = global ? 0 : m->si->y; + do_unmap_l = true; + do_unmap_r = true; + } + if (m->virtual_scr.EdgeScrollY == 0 || m->virtual_scr.VyMax == 0) + { + do_unmap_t = true; + do_unmap_b = true; + } + if (m->virtual_scr.Vx == 0 && !Scr.flags.do_edge_wrap_x) + { + do_unmap_l = true; + } + if (m->virtual_scr.Vx == m->virtual_scr.VxMax && + !Scr.flags.do_edge_wrap_x) + { + do_unmap_r = true; + } + if (m->virtual_scr.Vy == 0 && !Scr.flags.do_edge_wrap_y) + { + do_unmap_t = true; + } + if (m->virtual_scr.Vy == m->virtual_scr.VyMax && + !Scr.flags.do_edge_wrap_y) + { + do_unmap_b = true; + } - /* Remove Pan frames if paging by edge-scroll is permanently or - * temporarily disabled */ - if (m->virtual_scr.EdgeScrollX == 0 || m->virtual_scr.VxMax == 0) - { + /* correct the unmap variables if pan frame commands are set */ + if (edge_thickness != 0) { + if (m->PanFrameLeft.command != NULL || + m->PanFrameLeft.command_leave != NULL) { + do_unmap_l = false; + } + if (m->PanFrameRight.command != NULL || + m->PanFrameRight.command_leave != NULL) { + do_unmap_r = false; + } + if (m->PanFrameBottom.command != NULL || + m->PanFrameBottom.command_leave != NULL) { + do_unmap_b = false; + } + if (m->PanFrameTop.command != NULL || + m->PanFrameTop.command_leave != NULL) { + do_unmap_t = false; + } + } + /* Remove panframes if in global mode and on inside edge */ + if (global) { + if (m->edge.left) do_unmap_l = true; + if (m->edge.right) do_unmap_r = true; - } - if (m->virtual_scr.EdgeScrollY == 0 || m->virtual_scr.VyMax == 0) - { - do_unmap_t = true; + if (m->edge.bottom) do_unmap_b = true; - } - if (m->virtual_scr.Vx == 0 && !Scr.flags.do_edge_wrap_x) + if (m->edge.top) + do_unmap_t = true; + } + + /* + * hide or show the windows + */ + /* left */ + if (do_unmap_l) + { + if (m->PanFrameLeft.isMapped) { - do_unmap_l = true; + XUnmapWindow(dpy, m->PanFrameLeft.win); + m->PanFrameLeft.isMapped = False; } - if (m->virtual_scr.Vx == m->virtual_scr.VxMax && - !Scr.flags.do_edge_wrap_x) + } + else + { + if (edge_thickness != last_edge_thickness) { - do_unmap_r = true; + XResizeWindow( + dpy, m->PanFrameLeft.win, edge_thickness, + h); } - if (m->virtual_scr.Vy == 0 && !Scr.flags.do_edge_wrap_y) + if (!m->PanFrameLeft.isMapped) { - do_unmap_t = true; + XMapRaised(dpy, m->PanFrameLeft.win); + m->PanFrameLeft.isMapped = true; } - if (m->virtual_scr.Vy == m->virtual_scr.VyMax && - !Scr.flags.do_edge_wrap_y) + } + /* right */ + if (do_unmap_r) + { + if (m->PanFrameRight.isMapped) { - do_unmap_b = true; - } - - /* correct the unmap variables if pan frame commands are set */ - if (edge_thickness != 0) { - if (m->PanFrameLeft.command != NULL || - m->PanFrameLeft.command_leave != NULL) { - do_unmap_l = false; - } - if (m->PanFrameRight.command != NULL || - m->PanFrameRight.command_leave != NULL) { - do_unmap_r = false; - } - if (m->PanFrameBottom.command != NULL || - m->PanFrameBottom.command_leave != NULL) { - do_unmap_b = false; - } - if (m->PanFrameTop.command != NULL || - m->PanFrameTop.command_leave != NULL) { - do_unmap_t = false; - } + XUnmapWindow(dpy, m->PanFrameRight.win); + m->PanFrameRight.isMapped = false; } - /* - * hide or show the windows - */ - - /* left */ - if (do_unmap_l) + } + else + { + if (edge_thickness != last_edge_thickness) { - if (m->PanFrameLeft.isMapped) - { - XUnmapWindow(dpy, m->PanFrameLeft.win); - m->PanFrameLeft.isMapped = False; - } + XMoveResizeWindow( + dpy, m->PanFrameRight.win, + w - edge_thickness, + y, edge_thickness, h); } - else + if (!m->PanFrameRight.isMapped) { - if (edge_thickness != last_edge_thickness) - { - XResizeWindow( - dpy, m->PanFrameLeft.win, edge_thickness, - h); - } - if (!m->PanFrameLeft.isMapped) - { - XMapRaised(dpy, m->PanFrameLeft.win); - m->PanFrameLeft.isMapped = true; - } + XMapRaised(dpy, m->PanFrameRight.win); + m->PanFrameRight.isMapped = true; } - /* right */ - if (do_unmap_r) + } + /* top */ + if (do_unmap_t) + { + if (m->PanFrameTop.isMapped) { - if (m->PanFrameRight.isMapped) - { - XUnmapWindow(dpy, m->PanFrameRight.win); - m->PanFrameRight.isMapped = false; - } + XUnmapWindow(dpy, m->PanFrameTop.win); + m->PanFrameTop.isMapped = false; } - else + } + else + { + if (edge_thickness != last_edge_thickness) { - if (edge_thickness != last_edge_thickness) - { - XMoveResizeWindow( - dpy, m->PanFrameRight.win, - w - edge_thickness, - y, edge_thickness, h); - } - if (!m->PanFrameRight.isMapped) - { - XMapRaised(dpy, m->PanFrameRight.win); - m->PanFrameRight.isMapped = true; - } + XResizeWindow( dpy, m->PanFrameTop.win, w, + edge_thickness); } - /* top */ - if (do_unmap_t) + if (!m->PanFrameTop.isMapped) { - if (m->PanFrameTop.isMapped) - { - XUnmapWindow(dpy, m->PanFrameTop.win); - m->PanFrameTop.isMapped = false; - } + XMapRaised(dpy, m->PanFrameTop.win); + m->PanFrameTop.isMapped = true; } - else + } + /* bottom */ + if (do_unmap_b) + { + if (m->PanFrameBottom.isMapped) { - if (edge_thickness != last_edge_thickness) - { - XResizeWindow( dpy, m->PanFrameTop.win, w, - edge_thickness); - } - if (!m->PanFrameTop.isMapped) - { - XMapRaised(dpy, m->PanFrameTop.win); - m->PanFrameTop.isMapped = true; - } + XUnmapWindow(dpy, m->PanFrameBottom.win); + m->PanFrameBottom.isMapped = false; } - /* bottom */ - if (do_unmap_b) + } + else + { + if (edge_thickness != last_edge_thickness) { - if (m->PanFrameBottom.isMapped) - { - XUnmapWindow(dpy, m->PanFrameBottom.win); - m->PanFrameBottom.isMapped = false; - } + XMoveResizeWindow( + dpy, m->PanFrameBottom.win, x, + h - edge_thickness, + w, edge_thickness); } - else + if (!m->PanFrameBottom.isMapped) { - if (edge_thickness != last_edge_thickness) - { - XMoveResizeWindow( - dpy, m->PanFrameBottom.win, x, - h - edge_thickness, - w, edge_thickness); - } - if (!m->PanFrameBottom.isMapped) - { - XMapRaised(dpy, m->PanFrameBottom.win); - m->PanFrameBottom.isMapped = true; - } + XMapRaised(dpy, m->PanFrameBottom.win); + m->PanFrameBottom.isMapped = true; } - } + last_edge_thickness = edge_thickness; monitor_assign_virtual(m); } @@ -1314,55 +1323,17 @@ void initPanFrames(void) } } - if (monitor_mode == MONITOR_TRACKING_G && !is_tracking_shared) { - /* Treat the global panframes separately -- the logic for - * handling these along with per-monitor ones was getting too - * cumbersome. - */ - struct monitor *m, *mloop; - int gw = monitor_get_all_widths(); - int gh = monitor_get_all_heights(); - - m = TAILQ_FIRST(&monitor_q); - - init_one_panframe(&m->PanFrameTop, 0, 0, gw, edge_thickness, - CRS_TOP_EDGE); - init_one_panframe(&m->PanFrameLeft, 0, 0, edge_thickness, gh, - CRS_LEFT_EDGE); - init_one_panframe(&m->PanFrameRight, gw - edge_thickness, 0, - edge_thickness, gh, CRS_RIGHT_EDGE); - init_one_panframe(&m->PanFrameBottom, 0, gh - edge_thickness, - gw, edge_thickness, CRS_BOTTOM_EDGE); - - m->PanFrameTop.isMapped=m->PanFrameLeft.isMapped= - m->PanFrameRight.isMapped= m->PanFrameBottom.isMapped=false; - - TAILQ_FOREACH(mloop, &monitor_q, entry) { - if (mloop == m) - continue; - memcpy(&mloop->PanFrameTop, &m->PanFrameTop, sizeof(m->PanFrameTop)); - memcpy(&mloop->PanFrameLeft, &m->PanFrameLeft, sizeof(m->PanFrameLeft)); - memcpy(&mloop->PanFrameRight, &m->PanFrameRight, sizeof(m->PanFrameRight)); - memcpy(&mloop->PanFrameBottom, &m->PanFrameBottom, sizeof(m->PanFrameBottom)); - } - checkPanFrames(m); - edge_thickness = saved_thickness; - fvwm_debug(__func__, "finished setting up global panframes"); - return; - } - TAILQ_FOREACH(m, &monitor_q, entry) { init_one_panframe(&m->PanFrameTop, m->si->x, m->si->y, m->si->w, edge_thickness, CRS_TOP_EDGE); init_one_panframe(&m->PanFrameLeft, m->si->x, m->si->y, edge_thickness, m->si->h, CRS_LEFT_EDGE); init_one_panframe(&m->PanFrameRight, - (m->si->x + m->si->w) - edge_thickness, - (m->si->y + m->si->h) - m->si->h, edge_thickness, m->si->h, - CRS_RIGHT_EDGE); + (m->si->x + m->si->w) - edge_thickness, m->si->y, + edge_thickness, m->si->h, CRS_RIGHT_EDGE); init_one_panframe(&m->PanFrameBottom, m->si->x, - m->si->h - edge_thickness, m->si->w, edge_thickness, - CRS_BOTTOM_EDGE); + (m->si->y + m->si->h) - edge_thickness, m->si->w, + edge_thickness, CRS_BOTTOM_EDGE); m->PanFrameTop.isMapped=m->PanFrameLeft.isMapped= m->PanFrameRight.isMapped= m->PanFrameBottom.isMapped=false; @@ -1413,11 +1384,13 @@ Bool is_pan_frame(Window w) */ void MoveViewport(struct monitor *m, int newx, int newy, Bool grab) { + struct monitor *m_loop; FvwmWindow *t, *t1; int deltax,deltay; int PageTop, PageLeft; int PageBottom, PageRight; int txl, txr, tyt, tyb; + bool global = (monitor_mode == MONITOR_TRACKING_G && !is_tracking_shared); if (grab) { @@ -1622,6 +1595,17 @@ void MoveViewport(struct monitor *m, int newx, int newy, Bool grab) } } checkPanFrames(m); + + if (!global) + goto done; + + TAILQ_FOREACH(m_loop, &monitor_q, entry) { + if (m == m_loop) + continue; + checkPanFrames(m_loop); + } + +done: /* regrab buttons in case something got obscured or unobscured */ focus_grab_buttons_all(); diff --git a/libs/FScreen.c b/libs/FScreen.c index 41fe38de3..bd274419b 100644 --- a/libs/FScreen.c +++ b/libs/FScreen.c @@ -49,6 +49,7 @@ static void scan_screens(Display *); static void monitor_check_primary(void); static void monitor_refresh_global(void); static struct monitor *monitor_by_name(const char *); +static void monitor_scan_edges(struct monitor *); enum monitor_tracking monitor_mode; bool is_tracking_shared; @@ -81,6 +82,33 @@ monitor_new(void) return (m); } +static void +monitor_scan_edges(struct monitor *m) +{ + struct monitor *m_loop; + + m->edge.top = m->edge.bottom = m->edge.left = m->edge.right = + MONITOR_OUTSIDE_EDGE; + + TAILQ_FOREACH(m_loop, &monitor_q, entry) { + if (m_loop == m) + continue; + + /* Top Edge */ + if ( m->si->y == m_loop->si->y + m_loop->si->h ) + m->edge.top = MONITOR_INSIDE_EDGE; + /* Bottom Edge */ + if ( m->si->y + m->si->h == m_loop->si->y ) + m->edge.bottom = MONITOR_INSIDE_EDGE; + /* Left Edge */ + if ( m->si->x == m_loop->si->x + m_loop->si->w ) + m->edge.left = MONITOR_INSIDE_EDGE; + /* Right Edge */ + if ( m->si->x + m->si->w == m_loop->si->x ) + m->edge.right = MONITOR_INSIDE_EDGE; + } +} + void monitor_refresh_global(void) { @@ -305,10 +333,6 @@ monitor_assign_virtual(struct monitor *ref) continue; memcpy(&m->virtual_scr, &ref->virtual_scr, sizeof(m->virtual_scr)); - memcpy(&m->PanFrameTop, &ref->PanFrameTop, sizeof(m->PanFrameTop)); - memcpy(&m->PanFrameLeft, &ref->PanFrameLeft, sizeof(m->PanFrameLeft)); - memcpy(&m->PanFrameRight, &ref->PanFrameRight, sizeof(m->PanFrameRight)); - memcpy(&m->PanFrameBottom, &ref->PanFrameBottom, sizeof(m->PanFrameBottom)); } } @@ -394,6 +418,9 @@ monitor_output_change(Display *dpy, XRRScreenChangeNotifyEvent *e) } XRRFreeScreenResources(res); + TAILQ_FOREACH(m, &monitor_q, entry) + monitor_scan_edges(m); + monitor_check_primary(); } @@ -455,6 +482,7 @@ scan_screens(Display *dpy) XFree(name); } + monitor_scan_edges(m); monitor_check_primary(); XRRFreeMonitors(rrm); } @@ -513,6 +541,7 @@ void FScreenInit(Display *dpy) m->Desktops->next = NULL; m->Desktops->desk = 0; m->flags |= (MONITOR_NEW|MONITOR_ENABLED); + monitor_scan_edges(m); } monitor_check_primary(); diff --git a/libs/FScreen.h b/libs/FScreen.h index 1138e6906..1827ba03d 100644 --- a/libs/FScreen.h +++ b/libs/FScreen.h @@ -92,6 +92,9 @@ struct screen_info *screen_info_by_name(const char *); #define MONITOR_CHANGED 0x10 #define MONITOR_ALL (MONITOR_DISABLED|MONITOR_ENABLED|MONITOR_CHANGED) +#define MONITOR_OUTSIDE_EDGE 0 +#define MONITOR_INSIDE_EDGE 1 + struct monitor { struct screen_info *si; int flags; @@ -119,6 +122,13 @@ struct monitor { } ewmhc; + struct { + bool top; + bool bottom; + bool left; + bool right; + } edge; + struct { int VxMax; int VyMax;