mirror of
https://github.com/gryf/wmaker.git
synced 2026-04-29 12:04:06 +02:00
Compare commits
4 Commits
ac1fa7fc6d
...
33fba87ed1
| Author | SHA1 | Date | |
|---|---|---|---|
| 33fba87ed1 | |||
| a3c02a22bd | |||
| 0d74066aea | |||
| 26a296db23 |
@@ -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.
|
||||
|
||||
@@ -103,9 +103,21 @@ 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") },
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
@@ -823,6 +832,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,
|
||||
|
||||
+157
@@ -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;
|
||||
@@ -1726,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;
|
||||
@@ -1975,6 +1997,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 +2035,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 *
|
||||
* *
|
||||
|
||||
@@ -77,9 +77,18 @@ enum {
|
||||
WKBD_WORKSPACEMAP,
|
||||
WKBD_FOCUSNEXT,
|
||||
WKBD_FOCUSPREV,
|
||||
WKBD_FOCUSLEFT,
|
||||
WKBD_FOCUSRIGHT,
|
||||
WKBD_FOCUSUP,
|
||||
WKBD_FOCUSDOWN,
|
||||
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,
|
||||
|
||||
+35
-43
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
+28
-18
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+88
-1
@@ -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) {
|
||||
@@ -465,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;
|
||||
@@ -1006,9 +1040,18 @@ 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 */
|
||||
if (transientOwner && !transientOwner->flags.miniaturized && wwin->flags.miniaturized && !withdraw) {
|
||||
@@ -2527,6 +2570,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 +2587,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 +2615,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 +2950,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 +2966,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 {
|
||||
@@ -403,10 +405,15 @@ WMagicNumber wWindowGetSavedState(Window win);
|
||||
|
||||
void wWindowDeleteSavedState(WMagicNumber id);
|
||||
|
||||
Bool wWindowIsFullyCovered(WWindow *wwin);
|
||||
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
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user