This is an automated email generated because a ref change occurred in the
git repository for project wmaker-crm.git.
The branch, master has been updated
via 33fba87ed1ed891e6efb0ceb8bf7e33e1e5699b0 (commit)
via a3c02a22bd0d042670012b91c4605c654be642e0 (commit)
via 0d74066aea317d2d573953b4e6aacfa9eb78614e (commit)
via 26a296db23b89296bf136044898658c0c2b410fc (commit)
from ac1fa7fc6d5ffacc4521802d9e73bb93a2c17c85 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 33fba87ed1ed891e6efb0ceb8bf7e33e1e5699b0
Author: David Maciejak <
david.m...@gmail.com>
Date: Wed, 1 Apr 2026 20:06:40 -0400
URL: <
https://repo.or.cz/wmaker-crm.git/33fba87ed1ed891e>
wmaker: add directional window focus
This patch is adding directional window focus
(like in openbox), where the focus can be passed to
the current window neighboors with a shortcut key.
Comparisons are performed using window centres.
New options are FocusWindowLeftKey, FocusWindowRightKey,
FocusWindowUpKey, FocusWindowDownKey.
Other WM are setting those to SUPER+LEFT/RIGHT/UP/DOWN keys
but currently those are not set by default.
CirculateRaise option which is described in WPrefs as
'Raise window when switching focus with keyboard' is also
used to raise/not raise windows that are fully covered by
other windows.
---
WPrefs.app/KeyboardShortcuts.c | 5 ++
src/actions.c | 94 ++++++++++++++++++++++++++++++++++
src/actions.h | 1 +
src/defaults.c | 9 ++++
src/event.c | 16 ++++++
src/keybind.h | 4 ++
src/window.c | 29 +++++++++++
src/window.h | 1 +
8 files changed, 159 insertions(+)
diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c
index f6750c1bbb5a..6e3277292fd8 100644
--- a/WPrefs.app/KeyboardShortcuts.c
+++ b/WPrefs.app/KeyboardShortcuts.c
@@ -103,6 +103,11 @@ static struct keyOption {
{ "SelectKey", N_("Select active window") },
{ "FocusNextKey", N_("Focus next window") },
{ "FocusPrevKey", N_("Focus previous window") },
+ /* Directional window focus */
+ { "FocusWindowLeftKey", N_("Focus the window to the left") },
+ { "FocusWindowRightKey", N_("Focus the window to the right") },
+ { "FocusWindowUpKey", N_("Focus the window above") },
+ { "FocusWindowDownKey", N_("Focus the window below") },
{ "GroupNextKey", N_("Focus next group window") },
{ "GroupPrevKey", N_("Focus previous group window") },
diff --git a/src/actions.c b/src/actions.c
index 460c916624a4..1205a67fd792 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -240,6 +240,100 @@ void wSetFocusTo(WScreen *scr, WWindow *wwin)
old_scr = scr;
}
+/*
+ *----------------------------------------------------------------------
+ * wSetFocusToDirection--
+ * Moves focus to the nearest window in the given cardinal
+ * direction (DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_UP,
+ * DIRECTION_DOWN from xinerama.h).
+ *
+ * Selection algorithm: candidate windows are scored by
+ * (primary_distance + perpendicular_offset). A large penalty is
+ * added when the perpendicular offset exceeds the primary distance
+ * (i.e. the candidate is more than 45 degrees off-axis). The window
+ * with the lowest score wins. If no candidate exists in the requested
+ * direction the call is silently ignored.
+ *----------------------------------------------------------------------
+ */
+void wSetFocusToDirection(WScreen *scr, int direction)
+{
+ WWindow *focused = scr->focused_window;
+ WWindow *best = NULL;
+ WWindow *candidate = NULL;
+ int my_cx, my_cy;
+ long best_score = -1;
+
+ if (!focused || !focused->flags.mapped)
+ return;
+
+ /* centre of the focused window */
+ my_cx = focused->frame_x + (int)focused->frame->core->width / 2;
+ my_cy = focused->frame_y + (int)focused->frame->core->height / 2;
+
+ /* Iterate from most-recently-focused to least-recently-focused */
+ for (candidate = focused->prev; candidate != NULL; candidate = candidate->prev) {
+ int his_cx, his_cy, distance, offset;
+ long score;
+
+ if (!candidate->flags.mapped)
+ continue;
+ if (WFLAGP(candidate, no_focusable))
+ continue;
+ if (!candidate->frame || candidate->frame->workspace != scr->current_workspace)
+ continue;
+
+ /* ignore fully covered windows if cannot raised them */
+ if (!wPreferences.circ_raise && wWindowIsFullyCovered(candidate))
+ continue;
+
+ /* relative centre of candidate */
+ his_cx = (candidate->frame_x - my_cx) + (int)candidate->frame->core->width / 2;
+ his_cy = (candidate->frame_y - my_cy) + (int)candidate->frame->core->height / 2;
+
+ switch (direction) {
+ case DIRECTION_RIGHT:
+ distance = his_cx;
+ offset = his_cy < 0 ? -his_cy : his_cy;
+ break;
+ case DIRECTION_LEFT:
+ distance = -his_cx;
+ offset = his_cy < 0 ? -his_cy : his_cy;
+ break;
+ case DIRECTION_DOWN:
+ distance = his_cy;
+ offset = his_cx < 0 ? -his_cx : his_cx;
+ break;
+ case DIRECTION_UP:
+ distance = -his_cy;
+ offset = his_cx < 0 ? -his_cx : his_cx;
+ break;
+ default:
+ continue;
+ }
+
+ /* candidate must be strictly in the requested direction */
+ if (distance <= 0)
+ continue;
+
+ score = distance + offset;
+
+ /* heavy penalty for windows more than 45 degrees off-axis */
+ if (offset > distance)
+ score += 1000000L;
+
+ if (best_score < 0 || score < best_score) {
+ best = candidate;
+ best_score = score;
+ }
+ }
+
+ if (best) {
+ if (wPreferences.circ_raise)
+ wRaiseFrame(best->frame->core);
+ wSetFocusTo(scr, best);
+ }
+}
+
void wShadeWindow(WWindow *wwin)
{
diff --git a/src/actions.h b/src/actions.h
index 16e5e3f6956c..f9aa0efc6b03 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -41,6 +41,7 @@
#define SAVE_GEOMETRY_ALL SAVE_GEOMETRY_X | SAVE_GEOMETRY_Y | SAVE_GEOMETRY_WIDTH | SAVE_GEOMETRY_HEIGHT
void wSetFocusTo(WScreen *scr, WWindow *wwin);
+void wSetFocusToDirection(WScreen *scr, int direction);
int wMouseMoveWindow(WWindow *wwin, XEvent *ev);
int wKeyboardMoveResizeWindow(WWindow *wwin);
diff --git a/src/defaults.c b/src/defaults.c
index 0a9da90090e0..42bc344562e9 100644
--- a/src/defaults.c
+++ b/src/defaults.c
@@ -721,6 +721,15 @@ WDefaultEntry optionList[] = {
NULL, getKeybind, setKeyGrab, NULL, NULL},
{"FocusPrevKey", "Mod1+Shift+Tab", (void *)WKBD_FOCUSPREV,
NULL, getKeybind, setKeyGrab, NULL, NULL},
+ /* Directional window focus */
+ {"FocusWindowLeftKey", "None", (void *)WKBD_FOCUSLEFT,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"FocusWindowRightKey", "None", (void *)WKBD_FOCUSRIGHT,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"FocusWindowUpKey", "None", (void *)WKBD_FOCUSUP,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"FocusWindowDownKey", "None", (void *)WKBD_FOCUSDOWN,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
{"GroupNextKey", "None", (void *)WKBD_GROUPNEXT,
NULL, getKeybind, setKeyGrab, NULL, NULL},
{"GroupPrevKey", "None", (void *)WKBD_GROUPPREV,
diff --git a/src/event.c b/src/event.c
index c306364290b4..93669b1ea5cd 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1732,6 +1732,22 @@ static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent
StartWindozeCycle(wwin, event, False, False);
break;
+ case WKBD_FOCUSLEFT:
+ wSetFocusToDirection(scr, DIRECTION_LEFT);
+ break;
+
+ case WKBD_FOCUSRIGHT:
+ wSetFocusToDirection(scr, DIRECTION_RIGHT);
+ break;
+
+ case WKBD_FOCUSUP:
+ wSetFocusToDirection(scr, DIRECTION_UP);
+ break;
+
+ case WKBD_FOCUSDOWN:
+ wSetFocusToDirection(scr, DIRECTION_DOWN);
+ break;
+
case WKBD_GROUPNEXT:
StartWindozeCycle(wwin, event, True, True);
break;
diff --git a/src/keybind.h b/src/keybind.h
index ae9a5022d614..25b7aac8dd77 100644
--- a/src/keybind.h
+++ b/src/keybind.h
@@ -77,6 +77,10 @@ enum {
WKBD_WORKSPACEMAP,
WKBD_FOCUSNEXT,
WKBD_FOCUSPREV,
+ WKBD_FOCUSLEFT,
+ WKBD_FOCUSRIGHT,
+ WKBD_FOCUSUP,
+ WKBD_FOCUSDOWN,
WKBD_GROUPNEXT,
WKBD_GROUPPREV,
WKBD_CENTRAL,
diff --git a/src/window.c b/src/window.c
index 470cfcabaf74..857deec8ed96 100644
--- a/src/window.c
+++ b/src/window.c
@@ -470,6 +470,35 @@ void wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace)
wwin->client_flags.no_focusable = 1;
}
+/*
+ * Returns True if every pixel of 'wwin' is covered by at least one other
+ * mapped window on the same workspace, making it invisible to the user
+ */
+Bool wWindowIsFullyCovered(WWindow *wwin)
+{
+ WScreen *scr = wwin->screen_ptr;
+ int cx = wwin->frame_x;
+ int cy = wwin->frame_y;
+ int cright = cx + (int)wwin->frame->core->width;
+ int cbottom = cy + (int)wwin->frame->core->height;
+ WWindow *w;
+
+ for (w = scr->focused_window; w != NULL; w = w->prev) {
+ if (w == wwin)
+ continue;
+ if (!w->flags.mapped)
+ continue;
+ if (!w->frame || w->frame->workspace != scr->current_workspace)
+ continue;
+ if (w->frame_x <= cx &&
+ w->frame_y <= cy &&
+ w->frame_x + (int)w->frame->core->width >= cright &&
+ w->frame_y + (int)w->frame->core->height >= cbottom)
+ return True;
+ }
+ return False;
+}
+
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured)
{
int w1, h1, w2, h2;
diff --git a/src/window.h b/src/window.h
index 1229eed38e28..9ccabdeb4585 100644
--- a/src/window.h
+++ b/src/window.h
@@ -405,6 +405,7 @@ WMagicNumber wWindowGetSavedState(Window win);
void wWindowDeleteSavedState(WMagicNumber id);
+Bool wWindowIsFullyCovered(WWindow *wwin);
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
commit a3c02a22bd0d042670012b91c4605c654be642e0
Author: David Maciejak <
david.m...@gmail.com>
Date: Thu, 2 Apr 2026 17:45:47 -0400
URL: <
https://repo.or.cz/wmaker-crm.git/a3c02a22bd0d0426>
NEWS: add new feature descriptions
---
NEWS | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 174 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index fc9ac579419d..6d0d80c8d8a8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,183 @@
NEWS for veteran Window Maker users
-----------------------------------
+-- 0.97.0
+
+Directional window focus
+------------------------
+
+The keyboard focus can now be moved in a specific direction (left, right,
+up, down) relative to the currently focused window, using window centres
+for comparison. The shortcuts can be configured in WPrefs under
+"Keyboard Shortcuts", or set directly in ~/GNUstep/Defaults/WindowMaker
+via "FocusWindowLeftKey", "FocusWindowRightKey", "FocusWindowUpKey" and
+"FocusWindowDownKey" (disabled by default).
+
+The existing "CirculateRaise" option ("Raise window when switching focus
+with keyboard" in WPrefs) also controls whether windows that are fully
+obscured by others are raised when receiving focus this way.
+
+
+Vim-like window marking
+-----------------------
+
+Windows can now be dynamically assigned a mark label (a key or
+modifier+key combination) allowing them to be instantly recalled without
+searching. This is inspired by vim's mark-and-jump navigation.
+
+The mark label is displayed in the window list menu between the window
+title and the workspace name.
+
+Five actions can be configured in ~/GNUstep/Defaults/WindowMaker
+(or in WPrefs under "Keyboard Shortcuts")
+
+ "MarkSetKey": assign a label to the focused window (e.g. with the
+ action bound to "Super+M", pressing "Super+M x" marks the focused
+ window with label 'x').
+
+ "MarkUnsetKey": remove the mark from a labeled window.
+
+ "MarkJumpKey": focus and raise the window with the given label.
+
+ "MarkBringKey": move the marked window to the current workspace and
+ focus it.
+
+ "MarkSwapKey": swap the focused window with the marked window.
+
+Those are disabled by default.
+Marks are persistent across sessions and saved in the WMState file.
+
+
+Multi-key and sticky-chain keybindings
+--------------------------------------
+
+Keyboard shortcuts now support multi-key sequences, similar to
+Emacs-style prefix bindings (e.g. pressing a leader key followed by
+one or more continuation keys).
+
+An optional sticky-chain mode allows a prefix key to remain active
+until a cancel key is pressed or a timeout expires, making it possible
+to trigger multiple actions in sequence without re-entering the prefix.
+New options in ~/GNUstep/Defaults/WindowMaker:
+
+ "KeychainTimeoutDelay" is the timeout in milliseconds after which an
+ active chain expires. Default is 500. Set to 0 to disable the
+ timeout.
+
+ "KeychainCancelKey" sets a key to explicitly cancel an active chain.
+ (disabled by default).
+
+
+Configurable modifier key labels
+---------------------------------
+
+A new "ModifierKeyShortLabels" option in ~/GNUstep/Defaults/WindowMaker
+allows customizing the labels shown for modifier keys in menus and
+keyboard shortcut displays. Unicode symbols can be used in place of the
+default text labels. For example to use the same symbol as defined on
+MacOS:
+
+ModifierKeyShortLabels = (
+ "\342\207\247",
+ "\342\214\203",
+ "\342\214\245",
+ "\342\207\255",
+ "\342\207\263",
+ "\342\214\230",
+ "\342\207\252",
+ "\342\227\206",
+ "\342\214\245"
+);
+
+Configurable mouse wheel focus behavior
+----------------------------------------
+
+Scrolling the mouse wheel over a window can now optionally move the
+keyboard focus to that window. The option is available in WPrefs under
+"Expert User Preferences", or by setting "MouseWheelFocusEnable" in
+~/GNUstep/Defaults/WindowMaker (NO by default).
+
+
+Application icons in the window list
+-------------------------------------
+
+Application icons can now be shown in the window list menu. This behavior
+can be configured by setting the "WindowListAppIcons" option in
+~/GNUstep/Defaults/WindowMaker or "Show app icons in window list." in
+WPrefs under "Expert User Preferences" (NO by default).
+
+
+Configurable screenshot filename template
+-----------------------------------------
+
+The filename (strftime compatible) format used when saving screenshots
+can now be customized by setting the "ScreenshotFileNameTemplate"
+option in ~/GNUstep/Defaults/WindowMaker. The default remains the
+format introduced in 0.96.0.
+
+
+JPEG XL image support
+---------------------
+
+WRaster can now optionally load JPEG XL images if the libjxl
+library is present at build time. The feature can be toggled at
+configure time with --enable-jxl/--disable-jxl.
+
+
+wmiv: archive files and unknown format handling
+-----------------------------------------------
+
+wmiv can now open images stored inside archive files (with libarchive).
+A new option to silently skip unknown image formats is also available.
+It supports ctrl+c shortcut to copy the current image to the clipboard.
+
+
+Support for _NET_WM_MOVERESIZE
+------------------------------
+
+Window Maker now handles the _NET_WM_MOVERESIZE EWMH message, which
+allows applications to initiate interactive window moves and resizes
+through a standard protocol request (for those applications without
+decorations: VS Code, Google Chrome, Steam and Discord, ...).
+
+
+Cycle windows across all workspaces
+-----------------------------------
+
+A new 'Cycle all windows from all workspaces' expert option allows
+the Alt-Tab window switcher to include windows from all workspaces,
+not only the current one. Which is the "CycleAllWorkspaces" option
+in ~/GNUstep/Defaults/WindowMaker (NO by default).
+
+
+RandR and multi-monitor improvements
+------------------------------------
+
+RandR version >= 1.3 is automatically enabled when detected. By default,
+it operates in static mode, requiring the screen layout to be defined
+manually. A new "HotplugMonitor" option in ~/GNUstep/Defaults/WindowMaker
+(NO by default) enables automatic monitor detection on hotplug events,
+adding newly connected monitors to the right of the existing layout.
+This option is also available in WPrefs expert panel under
+"Automatically (de)activate monitors on hotplug events".
+
+
+Titlebar language button revamp
+-------------------------------
+
+When the modelock feature is enabled, the legacy hardcoded language
+dropdown icons in the titlebar are replaced by a compact button
+displaying the short name of the current XKB locale (those are
+basically the layouts displayed via setxkbmap -query).
+Clicking the button cycles through up to four keyboard layouts
+(matching the four XKB groups). The xkbfile library is required for
+this feature.
+
+
-- 0.96.0
Hot Corners feature
---------------------------
+-------------------
Screen corners can be assigned an external command to be
executed when the mouse pointer is entering those areas.
commit 0d74066aea317d2d573953b4e6aacfa9eb78614e
Author: David Maciejak <
david.m...@gmail.com>
Date: Mon, 30 Mar 2026 17:45:32 -0400
URL: <
https://repo.or.cz/wmaker-crm.git/0d74066aea317d2d>
wmaker: treat _NET_WM_WINDOW_TYPE property as a list
This patch is treating the _NET_WM_WINDOW_TYPE property as an array
of atoms as defined in X11. Currently, we are only getting the first one,
while the client can set multiple window types ordered from most specific
to least specific.
---
src/wmspec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/wmspec.c b/src/wmspec.c
index 2621200bbe0b..8f4a3ccf0da9 100644
--- a/src/wmspec.c
+++ b/src/wmspec.c
@@ -1535,7 +1535,7 @@ void wNETWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
XFree(data);
}
- if (XGetWindowProperty(dpy, wwin->client_win, net_wm_window_type, 0, 1, False,
+ if (XGetWindowProperty(dpy, wwin->client_win, net_wm_window_type, 0, 1024L, False,
XA_ATOM, &type_ret, &fmt_ret, &nitems_ret,
&bytes_after_ret, (unsigned char **)&data) == Success && data) {
commit 26a296db23b89296bf136044898658c0c2b410fc
Author: David Maciejak <
david.m...@gmail.com>
Date: Mon, 30 Mar 2026 22:24:42 -0400
URL: <
https://repo.or.cz/wmaker-crm.git/26a296db23b89296>
wmaker: dynamic vim-like window marking feature
This patch is adding vim-like window marking, like in i3.
A window can be dynamically assigned a mark label.
Then a marked window can be pulled or jumped to.
Or the current focused window can be swapped with a marked window.
The mark label appears in the Window List in between the window
title and the workspace name.
Those new options in WindowMaker conf file are used to control
the actions: MarkSetKey, MarkUnsetKey, MarkBringKey, MarkJumpKey
and MarkSwapKey.
Those actions are set to None by default.
---
WPrefs.app/KeyboardShortcuts.c | 7 ++
src/WindowMaker.h | 1 +
src/defaults.c | 11 +++
src/event.c | 141 +++++++++++++++++++++++++++++++++
src/keybind.h | 5 ++
src/misc.c | 78 ++++++++----------
src/misc.h | 1 +
src/screen.h | 10 +++
src/session.c | 20 +++++
src/startup.c | 2 +
src/switchmenu.c | 46 ++++++-----
src/window.c | 60 +++++++++++++-
src/window.h | 6 ++
13 files changed, 326 insertions(+), 62 deletions(-)
diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c
index 7d18a90a15d1..f6750c1bbb5a 100644
--- a/WPrefs.app/KeyboardShortcuts.c
+++ b/WPrefs.app/KeyboardShortcuts.c
@@ -106,6 +106,13 @@ static struct keyOption {
{ "GroupNextKey", N_("Focus next group window") },
{ "GroupPrevKey", N_("Focus previous group window") },
+ /* Vim-like Window Marking */
+ { "MarkSetKey", N_("Mark window: set mark") },
+ { "MarkUnsetKey", N_("Mark window: unset mark") },
+ { "MarkBringKey", N_("Mark window: bring marked window here") },
+ { "MarkJumpKey", N_("Mark window: jump to marked window") },
+ { "MarkSwapKey", N_("Mark window: swap with marked window") },
+
/* Workspace Related */
{ "WorkspaceMapKey", N_("Open workspace pager") },
{ "NextWorkspaceKey", N_("Switch to next workspace") },
diff --git a/src/WindowMaker.h b/src/WindowMaker.h
index f979573f7596..da727b37a37b 100644
--- a/src/WindowMaker.h
+++ b/src/WindowMaker.h
@@ -609,6 +609,7 @@ extern struct wmaker_global_variables {
Atom icon_size;
Atom icon_tile;
+ Atom mark_key;
} wmaker;
} atom;
diff --git a/src/defaults.c b/src/defaults.c
index 101e4dc1f673..0a9da90090e0 100644
--- a/src/defaults.c
+++ b/src/defaults.c
@@ -823,6 +823,17 @@ WDefaultEntry optionList[] = {
NULL, getKeybind, setKeyGrab, NULL, NULL},
{"PartialCaptureKey", "None", (void *)WKBD_PRINTP,
NULL, getKeybind, setKeyGrab, NULL, NULL},
+ /* Vim-like Window Marking */
+ {"MarkSetKey", "None", (void *)WKBD_MARK_SET,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"MarkUnsetKey", "None", (void *)WKBD_MARK_UNSET,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"MarkBringKey", "None", (void *)WKBD_MARK_BRING,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"MarkJumpKey", "None", (void *)WKBD_MARK_JUMP,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
+ {"MarkSwapKey", "None", (void *)WKBD_MARK_SWAP,
+ NULL, getKeybind, setKeyGrab, NULL, NULL},
#ifdef KEEP_XKB_LOCK_STATUS
{"ToggleKbdModeKey", "None", (void *)WKBD_TOGGLE,
diff --git a/src/event.c b/src/event.c
index e5422ea461eb..c306364290b4 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1471,6 +1471,12 @@ static void wCancelChainTimer(void)
#define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
#define ISFOCUSED(w) ((w) && (w)->flags.focused)
+static void startMarkCapture(WScreen *scr, Display *dpy, WMarkCaptureMode mode)
+{
+ scr->flags.mark_capture_mode = mode;
+ XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
+}
+
static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent *event)
{
short widx;
@@ -1975,6 +1981,29 @@ static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent
}
break;
#endif /* KEEP_XKB_LOCK_STATUS */
+
+ case WKBD_MARK_SET:
+ if (ISMAPPED(wwin) && ISFOCUSED(wwin))
+ startMarkCapture(scr, dpy, MARK_CAPTURE_SET);
+ break;
+
+ case WKBD_MARK_UNSET:
+ if (ISMAPPED(wwin) && ISFOCUSED(wwin) && wwin->mark_key_label != NULL)
+ wWindowUnsetMark(wwin);
+ break;
+
+ case WKBD_MARK_BRING:
+ startMarkCapture(scr, dpy, MARK_CAPTURE_BRING);
+ break;
+
+ case WKBD_MARK_JUMP:
+ startMarkCapture(scr, dpy, MARK_CAPTURE_JUMP);
+ break;
+
+ case WKBD_MARK_SWAP:
+ if (ISMAPPED(wwin) && ISFOCUSED(wwin))
+ startMarkCapture(scr, dpy, MARK_CAPTURE_SWAP);
+ break;
}
}
@@ -1990,6 +2019,118 @@ static void handleKeyPress(XEvent * event)
/* ignore CapsLock */
modifiers = event->xkey.state & w_global.shortcut.modifiers_mask;
+ /* ----------------------------------------------------------- *
+ * Window mark capture mode *
+ * *
+ * We grabbed the keyboard so all keypresses come here until *
+ * we release the grab. *
+ * ------------------------------------------------------------ */
+ if (scr->flags.mark_capture_mode != MARK_CAPTURE_IDLE) {
+ int capture_mode = scr->flags.mark_capture_mode;
+ KeySym cap_ksym;
+ char label[MAX_SHORTCUT_LENGTH];
+
+ /* Skip modifier-only keypresses */
+ cap_ksym = XLookupKeysym(&event->xkey, 0);
+ if (cap_ksym == NoSymbol || IsModifierKey(cap_ksym))
+ return;
+
+ /* Real key received: exit capture mode and release grab */
+ scr->flags.mark_capture_mode = MARK_CAPTURE_IDLE;
+ XUngrabKeyboard(dpy, CurrentTime);
+
+ if (!GetCanonicalShortcutLabel(modifiers, cap_ksym, label, sizeof(label)))
+ wstrlcpy(label, "?", sizeof(label));
+
+ if (capture_mode == MARK_CAPTURE_SET) {
+ WWindow *target = scr->focused_window;
+ Bool conflict = False;
+ int i;
+
+ /* Conflict check against static wmaker bindings */
+ for (i = 0; i < WKBD_LAST; i++) {
+ if (wKeyBindings[i].keycode == event->xkey.keycode && wKeyBindings[i].modifier == modifiers) {
+ wwarning("window mark: '%s' is already a wmaker binding, mark not assigned", label);
+ conflict = True;
+ break;
+ }
+ }
+
+ /* Conflict check against existing marks on other windows */
+ if (!conflict) {
+ WWindow *tw = scr->focused_window;
+ while (tw) {
+ if (tw != target && tw->mark_key_label != NULL && strcmp(tw->mark_key_label, label) == 0) {
+ wwarning("window mark: label '%s' is already used by another window, mark not assigned", label);
+ conflict = True;
+ break;
+ }
+ tw = tw->prev;
+ }
+ }
+
+ if (!conflict && target != NULL)
+ wWindowSetMark(target, label);
+
+ } else {
+ /* Find marked window by label */
+ WWindow *tw = scr->focused_window;
+
+ while (tw) {
+ if (tw->mark_key_label != NULL && strcmp(tw->mark_key_label, label) == 0)
+ break;
+ tw = tw->prev;
+ }
+ if (tw == NULL) {
+ wwarning("window mark: no window labelled '%s'", label);
+ } else if (capture_mode == MARK_CAPTURE_BRING) {
+ if (tw->frame->workspace != scr->current_workspace)
+ wWindowChangeWorkspace(tw, scr->current_workspace);
+ wMakeWindowVisible(tw);
+ } else if (capture_mode == MARK_CAPTURE_JUMP) {
+ wMakeWindowVisible(tw);
+ } else {
+ /* MARK_CAPTURE_SWAP: swap position, size and workspace between focused and tw */
+ WWindow *focused = scr->focused_window;
+ int fx, fy, fw, fh, tx, ty, tw_w, tw_h;
+ int f_ws, t_ws;
+
+ if (focused == NULL || focused == tw)
+ return;
+
+ /* Snapshot both geometries */
+ fx = focused->frame_x;
+ fy = focused->frame_y;
+ fw = focused->client.width;
+ fh = focused->client.height;
+ f_ws = focused->frame->workspace;
+
+ tx = tw->frame_x;
+ ty = tw->frame_y;
+ tw_w = tw->client.width;
+ tw_h = tw->client.height;
+ t_ws = tw->frame->workspace;
+
+ /* Swap workspaces first so configure lands in the right one */
+ if (f_ws != t_ws) {
+ wWindowChangeWorkspace(focused, t_ws);
+ wWindowChangeWorkspace(tw, f_ws);
+ }
+
+ /* Swap positions and sizes */
+ wWindowConfigure(focused, tx, ty, tw_w, tw_h);
+ wWindowConfigure(tw, fx, fy, fw, fh);
+
+ /* Follow origin window: switch view to the workspace it landed in,
+ * then restore focus to it */
+ if (f_ws != t_ws)
+ wWorkspaceChange(scr, t_ws);
+ wSetFocusTo(scr, focused);
+ }
+ }
+ return;
+ }
+
/* ------------------------------------------------------------------ *
* Trie-based key-chain matching *
* *
diff --git a/src/keybind.h b/src/keybind.h
index 292cbb71506c..ae9a5022d614 100644
--- a/src/keybind.h
+++ b/src/keybind.h
@@ -80,6 +80,11 @@ enum {
WKBD_GROUPNEXT,
WKBD_GROUPPREV,
WKBD_CENTRAL,
+ WKBD_MARK_SET,
+ WKBD_MARK_UNSET,
+ WKBD_MARK_BRING,
+ WKBD_MARK_JUMP,
+ WKBD_MARK_SWAP,
/* window, menu */
WKBD_CLOSE,
diff --git a/src/misc.c b/src/misc.c
index 38d6238c8d04..788c1b5d585f 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -847,6 +847,34 @@ static char *keysymToString(KeySym keysym, unsigned int state)
}
#endif
+Bool GetCanonicalShortcutLabel(unsigned int modifiers, KeySym ksym, char *buf, size_t bufsz)
+{
+ static const struct { unsigned int mask; const char *name; } mt[] = {
+ { ShiftMask, "Shift+" },
+ { ControlMask, "Control+" },
+ { Mod1Mask, "Mod1+" },
+ { Mod2Mask, "Mod2+" },
+ { Mod3Mask, "Mod3+" },
+ { Mod4Mask, "Mod4+" },
+ { Mod5Mask, "Mod5+" },
+ { 0, NULL }
+ };
+ const char *kname = XKeysymToString(ksym);
+ size_t i;
+
+ if (!kname)
+ return False;
+
+ buf[0] = '\0';
+ for (i = 0; mt[i].mask; i++) {
+ if (modifiers & mt[i].mask)
+ wstrlcat(buf, mt[i].name, bufsz);
+ }
+ wstrlcat(buf, kname, bufsz);
+
+ return True;
+}
+
char *GetShortcutString(const char *shortcut)
{
char *buffer = NULL;
@@ -882,50 +910,12 @@ char *GetShortcutString(const char *shortcut)
char *GetShortcutKey(WShortKey key)
{
char buf[MAX_SHORTCUT_LENGTH];
- char *wr, *result, *seg;
+ char *result, *seg;
int step;
- void append_string(const char *text)
- {
- const char *s = text;
-
- while (*s) {
- if (wr >= buf + sizeof(buf) - 1)
- break;
- *wr++ = *s++;
- }
- }
-
- void append_modifier(int modifier_index, const char *fallback_name)
- {
- if (wPreferences.modifier_labels[modifier_index])
- append_string(wPreferences.modifier_labels[modifier_index]);
- else
- append_string(fallback_name);
- }
-
- Bool build_token(unsigned int mod, KeyCode kcode)
- {
- const char *kname = XKeysymToString(W_KeycodeToKeysym(dpy, kcode, 0));
-
- if (!kname)
- return False;
-
- wr = buf;
- if (mod & ControlMask) append_modifier(1, "Control+");
- if (mod & ShiftMask) append_modifier(0, "Shift+");
- if (mod & Mod1Mask) append_modifier(2, "Mod1+");
- if (mod & Mod2Mask) append_modifier(3, "Mod2+");
- if (mod & Mod3Mask) append_modifier(4, "Mod3+");
- if (mod & Mod4Mask) append_modifier(5, "Mod4+");
- if (mod & Mod5Mask) append_modifier(6, "Mod5+");
- append_string(kname);
- *wr = '\0';
-
- return True;
- }
-
- if (!build_token(key.modifier, key.keycode))
+ if (!GetCanonicalShortcutLabel(key.modifier,
+ W_KeycodeToKeysym(dpy, key.keycode, 0),
+ buf, sizeof(buf)))
return NULL;
/* Convert the leader token to its display string */
@@ -938,7 +928,9 @@ char *GetShortcutKey(WShortKey key)
if (key.chain_keycodes[step] == 0)
break;
- if (!build_token(key.chain_modifiers[step], key.chain_keycodes[step]))
+ if (!GetCanonicalShortcutLabel(key.chain_modifiers[step],
+ W_KeycodeToKeysym(dpy, key.chain_keycodes[step], 0),
+ buf, sizeof(buf)))
break;
seg = GetShortcutString(buf);
diff --git a/src/misc.h b/src/misc.h
index 5fc15a8f5d96..288a8bb4076d 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -50,6 +50,7 @@ char *ExpandOptions(WScreen * scr, const char *cmdline);
void ExecuteInputCommand(WScreen *scr, const char *cmdline);
void ExecuteExitCommand(WScreen *scr, long quickmode);
char *GetShortcutString(const char *text);
+Bool GetCanonicalShortcutLabel(unsigned int modifiers, KeySym ksym, char *buf, size_t bufsz);
char *GetShortcutKey(WShortKey key);
char *EscapeWM_CLASS(const char *name, const char *class);
char *StrConcatDot(const char *a, const char *b);
diff --git a/src/screen.h b/src/screen.h
index c3100b0bb2ee..9ecb1253efce 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -59,6 +59,14 @@ typedef struct WDrawerChain {
struct WDrawerChain *next;
} WDrawerChain;
+typedef enum {
+ MARK_CAPTURE_IDLE = 0,
+ MARK_CAPTURE_SET = 1,
+ MARK_CAPTURE_BRING = 2,
+ MARK_CAPTURE_JUMP = 3,
+ MARK_CAPTURE_SWAP = 4
+} WMarkCaptureMode;
+
/*
* each WScreen is saved into a context associated with its root window
*/
@@ -332,6 +340,8 @@ typedef struct _WScreen {
unsigned int jump_back_pending:1;
unsigned int ignore_focus_events:1;
unsigned int in_hot_corner:3;
+ unsigned int mark_capture_mode:3; /* one of WMarkCaptureMode */
+
} flags;
} WScreen;
diff --git a/src/session.c b/src/session.c
index 89df5b54c423..9d66b21831a3 100644
--- a/src/session.c
+++ b/src/session.c
@@ -97,6 +97,7 @@ static WMPropList *sMaximized;
static WMPropList *sHidden;
static WMPropList *sGeometry;
static WMPropList *sShortcutMask;
+static WMPropList *sMarkKey;
static WMPropList *sDock;
static WMPropList *sYes, *sNo;
@@ -118,6 +119,7 @@ static void make_keys(void)
sGeometry = WMCreatePLString("Geometry");
sDock = WMCreatePLString("Dock");
sShortcutMask = WMCreatePLString("ShortcutMask");
+ sMarkKey = WMCreatePLString("MarkKey");
sYes = WMCreatePLString("Yes");
sNo = WMCreatePLString("No");
@@ -165,6 +167,7 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
WMPropList *win_state, *cmd, *name, *workspace;
WMPropList *shaded, *miniaturized, *maximized, *hidden, *geometry;
WMPropList *dock, *shortcut;
+ WMPropList *mark_key_pl = NULL;
if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
win = wwin->orig_main_window;
@@ -215,6 +218,9 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
snprintf(buffer, sizeof(buffer), "%u", mask);
shortcut = WMCreatePLString(buffer);
+ if (wwin->mark_key_label)
+ mark_key_pl = WMCreatePLString(wwin->mark_key_label);
+
win_state = WMCreatePLDictionary(sName, name,
sCommand, cmd,
sWorkspace, workspace,
@@ -224,6 +230,11 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
sHidden, hidden,
sShortcutMask, shortcut, sGeometry, geometry, NULL);
+ if (mark_key_pl) {
+ WMPutInPLDictionary(win_state, sMarkKey, mark_key_pl);
+ WMReleasePropList(mark_key_pl);
+ }
+
WMReleasePropList(name);
WMReleasePropList(cmd);
WMReleasePropList(workspace);
@@ -418,6 +429,13 @@ static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
state->window_shortcuts = mask;
}
+ value = WMGetFromPLDictionary(win_state, sMarkKey);
+ if (value != NULL && WMIsPLString(value)) {
+ char *s = WMGetFromPLString(value);
+ if (s && *s)
+ state->mark_key = wstrdup(s);
+ }
+
value = WMGetFromPLDictionary(win_state, sGeometry);
if (value && WMIsPLString(value)) {
if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
@@ -531,6 +549,8 @@ void wSessionRestoreState(WScreen *scr)
} else if ((pid = execCommand(scr, command)) > 0) {
wWindowAddSavedState(instance, class, command, pid, state);
} else {
+ if (state->mark_key)
+ wfree(state->mark_key);
wfree(state);
}
diff --git a/src/startup.c b/src/startup.c
index ed992901b1b6..b0e676b29e6d 100644
--- a/src/startup.c
+++ b/src/startup.c
@@ -387,6 +387,7 @@ static char *atomNames[] = {
"_WINDOWMAKER_COMMAND",
"_WINDOWMAKER_ICON_SIZE",
"_WINDOWMAKER_ICON_TILE",
+ "_WINDOWMAKER_MARK_KEY",
GNUSTEP_WM_ATTR_NAME,
GNUSTEP_WM_MINIATURIZE_WINDOW,
@@ -474,6 +475,7 @@ void StartUp(Bool defaultScreenOnly)
w_global.atom.desktop.gtk_object_path = atom[20];
w_global.atom.wm.ignore_focus_events = atom[21];
+ w_global.atom.wmaker.mark_key = atom[22];
#ifdef USE_DOCK_XDND
wXDNDInitializeAtoms();
diff --git a/src/switchmenu.c b/src/switchmenu.c
index a8c3937f9ab1..0f1746f60ff7 100644
--- a/src/switchmenu.c
+++ b/src/switchmenu.c
@@ -44,6 +44,8 @@
((w)->wm_gnustep_attr->window_level == WMMainMenuWindowLevel || \
(w)->wm_gnustep_attr->window_level == WMSubmenuWindowLevel))
+#define MAX_RTEXT_LENGTH (MAX_WORKSPACENAME_WIDTH + MAX_SHORTCUT_LENGTH + 16)
+
static int initialized = 0;
static void observer(void *self, WMNotification * notif);
static void wsobserver(void *self, WMNotification * notif);
@@ -214,6 +216,26 @@ static int menuIndexForWindow(WMenu * menu, WWindow * wwin, int old_pos)
return idx;
}
+static void fillRtext(char *buf, size_t bufsz, WWindow *wwin, WScreen *scr)
+{
+ char *mlbl = wwin->mark_key_label ? GetShortcutString(wwin->mark_key_label) : NULL;
+
+ if (IS_OMNIPRESENT(wwin)) {
+ if (mlbl)
+ snprintf(buf, bufsz, "[%s] [*]", mlbl);
+ else
+ snprintf(buf, bufsz, "[*]");
+ } else {
+ if (mlbl)
+ snprintf(buf, bufsz, "[%s] [%s]", mlbl,
+ scr->workspaces[wwin->frame->workspace]->name);
+ else
+ snprintf(buf, bufsz, "[%s]",
+ scr->workspaces[wwin->frame->workspace]->name);
+ }
+ wfree(mlbl);
+}
+
/*
* Update switch menu
*/
@@ -263,12 +285,8 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
entry->icon = switchMenuIconForWindow(scr, wwin);
entry->flags.indicator = 1;
- entry->rtext = wmalloc(MAX_WORKSPACENAME_WIDTH + 8);
- if (IS_OMNIPRESENT(wwin))
- snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
- else
- snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
- scr->workspaces[wwin->frame->workspace]->name);
+ entry->rtext = wmalloc(MAX_RTEXT_LENGTH);
+ fillRtext(entry->rtext, MAX_RTEXT_LENGTH, wwin, scr);
if (wwin->flags.hidden) {
entry->flags.indicator_type = MI_HIDDEN;
@@ -311,6 +329,8 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
t = ShrinkString(scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
entry->text = t;
+ fillRtext(entry->rtext, MAX_RTEXT_LENGTH, wwin, scr);
+
wMenuRealize(switchmenu);
checkVisibility = 1;
break;
@@ -322,13 +342,7 @@ void UpdateSwitchMenu(WScreen * scr, WWindow * wwin, int action)
WPixmap *ipix;
int it, ion;
- if (IS_OMNIPRESENT(wwin)) {
- snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
- } else {
- snprintf(entry->rtext, MAX_WORKSPACENAME_WIDTH,
- "[%s]",
- scr->workspaces[wwin->frame->workspace]->name);
- }
+ fillRtext(entry->rtext, MAX_RTEXT_LENGTH, wwin, scr);
rt = entry->rtext;
entry->rtext = NULL;
@@ -404,11 +418,7 @@ static void UpdateSwitchMenuWorkspace(WScreen *scr, int workspace)
wwin = (WWindow *) menu->entries[i]->clientdata;
if (wwin->frame->workspace == workspace && !IS_OMNIPRESENT(wwin)) {
- if (IS_OMNIPRESENT(wwin))
- snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[*]");
- else
- snprintf(menu->entries[i]->rtext, MAX_WORKSPACENAME_WIDTH, "[%s]",
- scr->workspaces[wwin->frame->workspace]->name);
+ fillRtext(menu->entries[i]->rtext, MAX_RTEXT_LENGTH, wwin, scr);
menu->flags.realized = 0;
}
}
diff --git a/src/window.c b/src/window.c
index 9cb1188219e6..470cfcabaf74 100644
--- a/src/window.c
+++ b/src/window.c
@@ -75,6 +75,7 @@
#include "startup.h"
#include "winmenu.h"
#include "osdep.h"
+#include "switchmenu.h"
#ifdef USE_MWM_HINTS
# include "motif.h"
@@ -200,6 +201,10 @@ void wWindowDestroy(WWindow *wwin)
}
}
+ /* clean up any mark assigned to this window */
+ if (wwin->mark_key_label != NULL)
+ wWindowUnsetMark(wwin);
+
if (wwin->fake_group && wwin->fake_group->retainCount > 0) {
wwin->fake_group->retainCount--;
if (wwin->fake_group->retainCount == 0 && wwin->fake_group->leader != None) {
@@ -1006,8 +1011,17 @@ WWindow *wManageWindow(WScreen *scr, Window window)
}
}
- if (wstate != NULL)
+ /* restore mark: prefer session state, fall back to warm-restart hint */
+ if (win_state != NULL && win_state->state->mark_key != NULL)
+ wWindowSetMark(wwin, win_state->state->mark_key);
+ else if (wstate != NULL && wstate->mark_key != NULL)
+ wWindowSetMark(wwin, wstate->mark_key);
+
+ if (wstate != NULL) {
+ if (wstate->mark_key != NULL)
+ wfree(wstate->mark_key);
wfree(wstate);
+ }
}
/* don't let transients start miniaturized if their owners are not */
@@ -2527,6 +2541,14 @@ void wWindowSaveState(WWindow *wwin)
XChangeProperty(dpy, wwin->client_win, w_global.atom.wmaker.state,
w_global.atom.wmaker.state, 32, PropModeReplace, (unsigned char *)data, 10);
+
+ if (wwin->mark_key_label != NULL)
+ XChangeProperty(dpy, wwin->client_win, w_global.atom.wmaker.mark_key,
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *)wwin->mark_key_label,
+ strlen(wwin->mark_key_label));
+ else
+ XDeleteProperty(dpy, wwin->client_win, w_global.atom.wmaker.mark_key);
}
static int getSavedState(Window window, WSavedState ** state)
@@ -2536,6 +2558,7 @@ static int getSavedState(Window window, WSavedState ** state)
unsigned long nitems_ret;
unsigned long bytes_after_ret;
long *data;
+ unsigned char *mk_data = NULL;
if (XGetWindowProperty(dpy, window, w_global.atom.wmaker.state, 0, 10,
True, w_global.atom.wmaker.state,
@@ -2563,6 +2586,15 @@ static int getSavedState(Window window, WSavedState ** state)
XFree(data);
+ (*state)->mark_key = NULL;
+ if (XGetWindowProperty(dpy, window, w_global.atom.wmaker.mark_key, 0, 256,
+ True, XA_STRING, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
+ &mk_data) == Success && mk_data && nitems_ret > 0 && type_ret == XA_STRING)
+ (*state)->mark_key = wstrdup((char *)mk_data);
+
+ if (mk_data)
+ XFree(mk_data);
+
return 1;
}
@@ -2889,6 +2921,9 @@ static void release_wwindowstate(WWindowState *wstate)
if (wstate->command)
wfree(wstate->command);
+ if (wstate->state && wstate->state->mark_key)
+ wfree(wstate->state->mark_key);
+
wfree(wstate->state);
wfree(wstate);
}
@@ -2902,6 +2937,29 @@ void wWindowSetOmnipresent(WWindow *wwin, Bool flag)
WMPostNotificationName(WMNChangedState, wwin, "omnipresent");
}
+void wWindowSetMark(WWindow *wwin, const char *label)
+{
+ /* Remove any previous mark first */
+ if (wwin->mark_key_label != NULL)
+ wWindowUnsetMark(wwin);
+
+ wwin->mark_key_label = wstrdup(label);
+
+ UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
+}
+
+void wWindowUnsetMark(WWindow *wwin)
+{
+ if (wwin->mark_key_label == NULL)
+ return;
+
+ wfree(wwin->mark_key_label);
+ wwin->mark_key_label = NULL;
+
+ UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE);
+}
+
+
static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
{
WWindow *wwin = data;
diff --git a/src/window.h b/src/window.h
index 8b14564e20d1..1229eed38e28 100644
--- a/src/window.h
+++ b/src/window.h
@@ -299,6 +299,7 @@ typedef struct WWindow {
int icon_w, icon_h;
RImage *net_icon_image; /* Window Image */
Atom type;
+ char *mark_key_label; /* Vim-like Window Marking */
} WWindow;
#define HAS_TITLEBAR(w) (!(WFLAGP((w), no_titlebar) || (w)->flags.fullscreen))
@@ -323,6 +324,7 @@ typedef struct WSavedState {
unsigned int w;
unsigned int h;
unsigned window_shortcuts; /* mask like 1<<shortcut_number */
+ char *mark_key; /* serialised mark key label */
} WSavedState;
typedef struct WWindowState {
@@ -407,6 +409,10 @@ Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
+/* Vim-like window marking management */
+void wWindowSetMark(WWindow *wwin, const char *label);
+void wWindowUnsetMark(WWindow *wwin);
+
#ifdef XKB_BUTTON_HINT
void wWindowGetLanguageLabel(int group_index, char *label);
#endif
-----------------------------------------------------------------------
Summary of changes:
NEWS | 175 ++++++++++++++++++++++++++++++++-
WPrefs.app/KeyboardShortcuts.c | 12 +++
src/WindowMaker.h | 1 +
src/actions.c | 94 ++++++++++++++++++
src/actions.h | 1 +
src/defaults.c | 20 ++++
src/event.c | 157 +++++++++++++++++++++++++++++
src/keybind.h | 9 ++
src/misc.c | 78 +++++++--------
src/misc.h | 1 +
src/screen.h | 10 ++
src/session.c | 20 ++++
src/startup.c | 2 +
src/switchmenu.c | 46 +++++----
src/window.c | 89 ++++++++++++++++-
src/window.h | 7 ++
src/wmspec.c | 2 +-
17 files changed, 660 insertions(+), 64 deletions(-)
repo.or.cz automatic notification. Contact project admin
crm...@gmail.com
if you want to unsubscribe, or site admin
ad...@repo.or.cz if you receive
no reply.
--
wmaker-crm.git ("The Window Maker window manager")