From ab45c6c6c2c624f0488d566c9108326ecf8d2843 Mon Sep 17 00:00:00 2001 From: David Maciejak Date: Fri, 31 Mar 2023 07:18:40 +0800 Subject: [PATCH] Add central position feature for active window This patch adds a new Central feature under the window menu "Other maximization" entry. Shortcut can be configured via WPrefs "Center active window" action. When called the active window is centered on the screen head. If the window height or width are bigger than the head size, the window is resized to fit. There are some transitions defined as below: *from fullscreen to center *from any corner to center *from top half to center top half *from bottom half to center bottom half *from left half to center left half *from right half to center right half Undoing the action is done via the window menu "Unmaximize" entry or the shortcut. --- WPrefs.app/KeyboardShortcuts.c | 1 + src/actions.c | 51 ++++++++++++++++++++++++++++++---- src/actions.h | 5 ++-- src/client.c | 4 +-- src/def_pixmaps.h | 4 +++ src/defaults.c | 2 ++ src/event.c | 8 ++++++ src/keybind.h | 1 + src/menu.c | 7 +++-- src/menu.h | 1 + src/moveres.c | 8 +++--- src/screen.c | 5 ++-- src/screen.h | 5 ++-- src/window.h | 4 +-- src/winmenu.c | 11 ++++++-- 15 files changed, 93 insertions(+), 24 deletions(-) diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index 225eda04..8df69a9e 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -89,6 +89,7 @@ static struct keyOption { { "BLCMaximizeKey", N_("Maximize active window bottom left corner") }, { "BRCMaximizeKey", N_("Maximize active window bottom right corner") }, { "MaximusKey", N_("Tile active window") }, + { "CenterKey", N_("Center active window") }, { "KeepOnTopKey", N_("Toggle window on top status") }, { "KeepAtBottomKey",N_("Toggle window at bottom status") }, { "OmnipresentKey", N_("Toggle window omnipresent status") }, diff --git a/src/actions.c b/src/actions.c index ea34c703..d013d0a2 100644 --- a/src/actions.c +++ b/src/actions.c @@ -404,7 +404,7 @@ void wMaximizeWindow(WWindow *wwin, int directions, int head) usableArea = wGetUsableAreaForHead(scr, head, &totalArea, True); /* Only save directions, not kbd or xinerama hints */ - directions &= (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS); + directions &= (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL); if (WFLAGP(wwin, full_maximize)) usableArea = totalArea; @@ -431,12 +431,31 @@ void wMaximizeWindow(WWindow *wwin, int directions, int head) wwin->maximus_y = new_y; wwin->flags.old_maximized |= MAX_MAXIMUS; } else { + /* center the window if can fit, if not sticking it to the screen edges */ + if (directions & MAX_CENTRAL) { + if (wwin->frame->core->height > (usableArea.y2 - usableArea.y1)) { + new_y = usableArea.y1; + new_height = usableArea.y2 - usableArea.y1 - adj_size; + } else { + new_height = (wwin->old_geometry.height) ? wwin->old_geometry.height : wwin->frame->core->height; + new_height += wwin->frame->top_width + wwin->frame->bottom_width; + new_y = half_scr_height - new_height / 2; + } + if (wwin->frame->core->width > (usableArea.x2 - usableArea.x1)) { + new_x = usableArea.x1; + new_width = usableArea.x2 - usableArea.x1 - adj_size; + } + else { + new_width = (wwin->old_geometry.width) ? wwin->old_geometry.width : wwin->frame->core->width; + new_x = half_scr_width - new_width / 2; + } + } /* set default values if no option set then */ - if (!(directions & (MAX_HORIZONTAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS))) { + if (!(directions & (MAX_HORIZONTAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS | MAX_CENTRAL))) { new_width = (wwin->old_geometry.width) ? wwin->old_geometry.width : wwin->frame->core->width; new_x = (wwin->old_geometry.x) ? wwin->old_geometry.x : wwin->frame_x; } - if (!(directions & (MAX_VERTICAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS))) { + if (!(directions & (MAX_VERTICAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS| MAX_CENTRAL))) { new_height = (wwin->old_geometry.height) ? wwin->old_geometry.height : wwin->frame->core->height; new_y = (wwin->old_geometry.y) ? wwin->old_geometry.y : wwin->frame_y; } @@ -445,17 +464,26 @@ void wMaximizeWindow(WWindow *wwin, int directions, int head) if (directions & MAX_LEFTHALF) { new_width = half_scr_width - adj_size; new_x = usableArea.x1; + if (directions & MAX_CENTRAL) { + new_y = half_scr_height - wwin->old_geometry.height / 2; + } } else if (directions & MAX_RIGHTHALF) { new_width = half_scr_width - adj_size; new_x = usableArea.x1 + half_scr_width; + if (directions & MAX_CENTRAL) + new_y = half_scr_height - wwin->old_geometry.height / 2; } /* top|bottom position */ if (directions & MAX_TOPHALF) { new_height = half_scr_height - adj_size; new_y = usableArea.y1; + if (directions & MAX_CENTRAL) + new_x = half_scr_width - wwin->old_geometry.width / 2; } else if (directions & MAX_BOTTOMHALF) { new_height = half_scr_height - adj_size; new_y = usableArea.y1 + half_scr_height; + if (directions & MAX_CENTRAL) + new_x = half_scr_width - wwin->old_geometry.width / 2; } /* vertical|horizontal position */ @@ -494,7 +522,7 @@ void wMaximizeWindow(WWindow *wwin, int directions, int head) void handleMaximize(WWindow *wwin, int directions) { int current = wwin->flags.maximized; - int requested = directions & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS); + int requested = directions & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL); int effective = requested ^ current; int flags = directions & ~requested; int head = wGetHeadForWindow(wwin); @@ -625,11 +653,24 @@ void handleMaximize(WWindow *wwin, int directions) head); else { + if ((requested == (MAX_HORIZONTAL | MAX_VERTICAL)) || (requested == MAX_MAXIMUS)) effective = requested; else { - if (requested & MAX_LEFTHALF) { + if (requested & MAX_CENTRAL) { + effective |= MAX_CENTRAL; + if (current & (MAX_HORIZONTAL | MAX_VERTICAL)) + effective &= ~(MAX_HORIZONTAL | MAX_VERTICAL); + else if (current & MAX_TOPHALF && current & MAX_LEFTHALF) + effective &= ~(MAX_TOPHALF | MAX_LEFTHALF); + else if (current & MAX_TOPHALF && current & MAX_RIGHTHALF) + effective &= ~(MAX_TOPHALF | MAX_RIGHTHALF); + else if (current & MAX_BOTTOMHALF && current & MAX_LEFTHALF) + effective &= ~(MAX_BOTTOMHALF | MAX_LEFTHALF); + else if (current & MAX_BOTTOMHALF && current & MAX_RIGHTHALF) + effective &= ~(MAX_BOTTOMHALF | MAX_RIGHTHALF); + } else if (requested & MAX_LEFTHALF) { if (!(requested & (MAX_TOPHALF | MAX_BOTTOMHALF))) effective |= MAX_VERTICAL; else diff --git a/src/actions.h b/src/actions.h index fdc1c565..16e5e3f6 100644 --- a/src/actions.h +++ b/src/actions.h @@ -30,8 +30,9 @@ #define MAX_TOPHALF (1 << 4) #define MAX_BOTTOMHALF (1 << 5) #define MAX_MAXIMUS (1 << 6) -#define MAX_IGNORE_XINERAMA (1 << 7) -#define MAX_KEYBOARD (1 << 8) +#define MAX_CENTRAL (1 << 7) +#define MAX_IGNORE_XINERAMA (1 << 8) +#define MAX_KEYBOARD (1 << 9) #define SAVE_GEOMETRY_X (1 << 0) #define SAVE_GEOMETRY_Y (1 << 1) diff --git a/src/client.c b/src/client.c index 2c81eb7c..68c82c52 100644 --- a/src/client.c +++ b/src/client.c @@ -240,9 +240,9 @@ void wClientConfigure(WWindow * wwin, XConfigureRequestEvent * xcre) return; if (nwidth != wwin->old_geometry.width) - wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL); if (nheight != wwin->old_geometry.height) - wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS | MAX_CENTRAL); wWindowConstrainSize(wwin, (unsigned int *)&nwidth, (unsigned int *)&nheight); wWindowConfigure(wwin, nx, ny, nwidth, nheight); diff --git a/src/def_pixmaps.h b/src/def_pixmaps.h index 55923c05..954805bc 100644 --- a/src/def_pixmaps.h +++ b/src/def_pixmaps.h @@ -36,6 +36,10 @@ static unsigned char MENU_SNAP_H_INDICATOR_XBM_DATA[] = { 0xff, 0x03, 0x01, 0x02, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0x03 }; +static unsigned char MENU_CENTRAL_INDICATOR_XBM_DATA[] = { + 0xff, 0x03, 0x01, 0x02, 0x79, 0x02, 0x79, 0x02, 0x79, 0x02, 0x79, 0x02, + 0x79, 0x02, 0x01, 0x02, 0xff, 0x03 }; + static unsigned char MENU_SNAP_RH_INDICATOR_XBM_DATA[] = { 0xff, 0x03, 0x01, 0x02, 0xe1, 0x02, 0xe1, 0x02, 0xe1, 0x02, 0xe1, 0x02, 0xe1, 0x02, 0x01, 0x02, 0xff, 0x03 }; diff --git a/src/defaults.c b/src/defaults.c index 3b848b15..c10f27ff 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -681,6 +681,8 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab, NULL, NULL}, {"MaximusKey", "None", (void*)WKBD_MAXIMUS, NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"CenterKey", "None", (void *)WKBD_CENTRAL, + NULL, getKeybind, setKeyGrab, NULL, NULL}, {"KeepOnTopKey", "None", (void *)WKBD_KEEP_ON_TOP, NULL, getKeybind, setKeyGrab, NULL, NULL}, {"KeepAtBottomKey", "None", (void *)WKBD_KEEP_AT_BOTTOM, diff --git a/src/event.c b/src/event.c index c843b0c0..67d30098 100644 --- a/src/event.c +++ b/src/event.c @@ -1515,6 +1515,14 @@ static void handleKeyPress(XEvent * event) movePointerToWindowCenter(wwin); } break; + case WKBD_CENTRAL: + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { + CloseWindowMenu(scr); + + handleMaximize(wwin, MAX_CENTRAL | MAX_KEYBOARD); + movePointerToWindowCenter(wwin); + } + break; case WKBD_LHMAXIMIZE: if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { CloseWindowMenu(scr); diff --git a/src/keybind.h b/src/keybind.h index b0680d34..a9478574 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -76,6 +76,7 @@ enum { WKBD_FOCUSPREV, WKBD_GROUPNEXT, WKBD_GROUPPREV, + WKBD_CENTRAL, /* window, menu */ WKBD_CLOSE, diff --git a/src/menu.c b/src/menu.c index 025e2894..e84b1caa 100644 --- a/src/menu.c +++ b/src/menu.c @@ -743,10 +743,13 @@ static void paintEntry(WMenu * menu, int index, int selected) indicator = scr->menu_shade_indicator; break; case MI_SNAP_V: - indicator = scr->menu_snap_vertically_indicator; + indicator = scr->menu_snap_vertical_indicator; break; case MI_SNAP_H: - indicator = scr->menu_snap_horizontally_indicator; + indicator = scr->menu_snap_horizontal_indicator; + break; + case MI_CENTRAL: + indicator = scr->menu_central_indicator; break; case MI_SNAP_RH: indicator = scr->menu_snap_rh_indicator; diff --git a/src/menu.h b/src/menu.h index ce8308c7..60ff9555 100644 --- a/src/menu.h +++ b/src/menu.h @@ -40,6 +40,7 @@ #define MI_SNAP_BL 14 #define MI_SNAP_BR 15 #define MI_SNAP_TILED 16 +#define MI_CENTRAL 17 typedef struct WMenuEntry { int order; diff --git a/src/moveres.c b/src/moveres.c index 685f3fc6..24a1bb70 100644 --- a/src/moveres.c +++ b/src/moveres.c @@ -1665,10 +1665,10 @@ int wKeyboardMoveResizeWindow(WWindow * wwin) } } else { if (ww != original_w) - wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL); if (wh != original_h) - wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS | MAX_CENTRAL); wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border); wWindowSynthConfigureNotify(wwin); @@ -2283,10 +2283,10 @@ void wMouseResizeWindow(WWindow * wwin, XEvent * ev) XUngrabServer(dpy); if (fw != original_fw) - wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL); if (fh != original_fh) - wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS); + wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS | MAX_CENTRAL); wWindowConfigure(wwin, fx, fy, fw, fh - vert_border); wWindowSynthConfigureNotify(wwin); diff --git a/src/screen.c b/src/screen.c index 66be4a9d..6ed591c0 100644 --- a/src/screen.c +++ b/src/screen.c @@ -498,8 +498,9 @@ static void createPixmaps(WScreen * scr) LOADPIXMAPINDICATOR(MENU_HIDE_INDICATOR_XBM_DATA, MENU_HIDE_INDICATOR_XBM_SIZE, menu_hide_indicator) LOADPIXMAPINDICATOR(MENU_SHADE_INDICATOR_XBM_DATA, MENU_SHADE_INDICATOR_XBM_SIZE, menu_shade_indicator) - LOADPIXMAPINDICATOR(MENU_SNAP_V_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_vertically_indicator) - LOADPIXMAPINDICATOR(MENU_SNAP_H_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_horizontally_indicator) + LOADPIXMAPINDICATOR(MENU_SNAP_V_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_vertical_indicator) + LOADPIXMAPINDICATOR(MENU_SNAP_H_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_horizontal_indicator) + LOADPIXMAPINDICATOR(MENU_CENTRAL_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_central_indicator) LOADPIXMAPINDICATOR(MENU_SNAP_RH_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_rh_indicator) LOADPIXMAPINDICATOR(MENU_SNAP_LH_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_lh_indicator) LOADPIXMAPINDICATOR(MENU_SNAP_TH_INDICATOR_XBM_DATA, MENU_SNAP_INDICATOR_W_XBM_SIZE, menu_snap_th_indicator) diff --git a/src/screen.h b/src/screen.h index 20e14a8c..dac0be56 100644 --- a/src/screen.h +++ b/src/screen.h @@ -214,8 +214,8 @@ typedef struct _WScreen { struct WPixmap *menu_mini_indicator; /* for miniwindow */ struct WPixmap *menu_hide_indicator; /* for hidden window */ struct WPixmap *menu_shade_indicator; /* for shaded window */ - struct WPixmap *menu_snap_vertically_indicator; /* for vertically snap window */ - struct WPixmap *menu_snap_horizontally_indicator; /* for horizontally snap window */ + struct WPixmap *menu_snap_vertical_indicator; /* for vertical snap window */ + struct WPixmap *menu_snap_horizontal_indicator; /* for horizontal snap window */ struct WPixmap *menu_snap_rh_indicator; /* for righ half snap window */ struct WPixmap *menu_snap_lh_indicator; /* for left half snap window */ struct WPixmap *menu_snap_th_indicator; /* for top half snap window */ @@ -225,6 +225,7 @@ typedef struct _WScreen { struct WPixmap *menu_snap_bl_indicator; /* for bottom left snap window */ struct WPixmap *menu_snap_br_indicator; /* for bottom right snap window */ struct WPixmap *menu_snap_tiled_indicator; /* for tiled window */ + struct WPixmap *menu_central_indicator; /* for central window */ int app_menu_x, app_menu_y; /* position for application menus */ diff --git a/src/window.h b/src/window.h index 7a916497..1e678f7b 100644 --- a/src/window.h +++ b/src/window.h @@ -251,8 +251,8 @@ typedef struct WWindow { unsigned int miniaturized:1; unsigned int hidden:1; unsigned int shaded:1; - unsigned int maximized:7; - unsigned int old_maximized:7; + unsigned int maximized:10; + unsigned int old_maximized:10; unsigned int fullscreen:1; long fullscreen_monitors[4]; unsigned int omnipresent:1; diff --git a/src/winmenu.c b/src/winmenu.c index 3d6f59fd..706378f5 100644 --- a/src/winmenu.c +++ b/src/winmenu.c @@ -124,8 +124,9 @@ static const struct { unsigned int shortcut_idx; int maxim_direction; } menu_maximize_entries[] = { - { MI_SNAP_V, N_("Vertically"), WKBD_VMAXIMIZE, MAX_VERTICAL }, - { MI_SNAP_H, N_("Horizontally"), WKBD_HMAXIMIZE, MAX_HORIZONTAL }, + { MI_SNAP_V, N_("Vertical"), WKBD_VMAXIMIZE, MAX_VERTICAL }, + { MI_SNAP_H, N_("Horizontal"), WKBD_HMAXIMIZE, MAX_HORIZONTAL }, + { MI_CENTRAL, N_("Central"), WKBD_CENTRAL, MAX_CENTRAL }, { MI_SNAP_LH, N_("Left half"), WKBD_LHMAXIMIZE, MAX_VERTICAL | MAX_LEFTHALF }, { MI_SNAP_RH, N_("Right half"), WKBD_RHMAXIMIZE, MAX_VERTICAL | MAX_RIGHTHALF }, { MI_SNAP_TH, N_("Top half"), WKBD_THMAXIMIZE, MAX_HORIZONTAL | MAX_TOPHALF }, @@ -181,7 +182,7 @@ static void updateUnmaximizeShortcut(WMenuEntry * entry, int flags) { int key; - switch (flags & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS)) { + switch (flags & (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_TOPHALF | MAX_BOTTOMHALF | MAX_MAXIMUS | MAX_CENTRAL)) { case MAX_HORIZONTAL: key = WKBD_HMAXIMIZE; break; @@ -190,6 +191,10 @@ static void updateUnmaximizeShortcut(WMenuEntry * entry, int flags) key = WKBD_VMAXIMIZE; break; + case MAX_CENTRAL: + key = WKBD_CENTRAL; + break; + case MAX_LEFTHALF | MAX_VERTICAL: key = WKBD_LHMAXIMIZE; break;