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:
committed by
Carlos R. Mafra
parent
ac1fa7fc6d
commit
26a296db23
@@ -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") },
|
||||
|
||||
@@ -609,6 +609,7 @@ extern struct wmaker_global_variables {
|
||||
|
||||
Atom icon_size;
|
||||
Atom icon_tile;
|
||||
Atom mark_key;
|
||||
} wmaker;
|
||||
|
||||
} atom;
|
||||
|
||||
@@ -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,
|
||||
|
||||
141
src/event.c
141
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 *
|
||||
* *
|
||||
|
||||
@@ -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,
|
||||
|
||||
78
src/misc.c
78
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
10
src/screen.h
10
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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
60
src/window.c
60
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user