1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-04-05 14:53:34 +02:00

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.
This commit is contained in:
David Maciejak
2026-03-30 22:24:42 -04:00
committed by Carlos R. Mafra
parent ac1fa7fc6d
commit 26a296db23
13 changed files with 326 additions and 62 deletions

View File

@@ -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") },

View File

@@ -609,6 +609,7 @@ extern struct wmaker_global_variables {
Atom icon_size;
Atom icon_tile;
Atom mark_key;
} wmaker;
} atom;

View File

@@ -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,

View File

@@ -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 *
* *

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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