mirror of
https://github.com/gryf/wmaker.git
synced 2026-04-05 14:53:34 +02:00
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.
This commit is contained in:
committed by
Carlos R. Mafra
parent
a3c02a22bd
commit
33fba87ed1
@@ -103,6 +103,11 @@ static struct keyOption {
|
|||||||
{ "SelectKey", N_("Select active window") },
|
{ "SelectKey", N_("Select active window") },
|
||||||
{ "FocusNextKey", N_("Focus next window") },
|
{ "FocusNextKey", N_("Focus next window") },
|
||||||
{ "FocusPrevKey", N_("Focus previous 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") },
|
{ "GroupNextKey", N_("Focus next group window") },
|
||||||
{ "GroupPrevKey", N_("Focus previous group window") },
|
{ "GroupPrevKey", N_("Focus previous group window") },
|
||||||
|
|
||||||
|
|||||||
@@ -240,6 +240,100 @@ void wSetFocusTo(WScreen *scr, WWindow *wwin)
|
|||||||
old_scr = scr;
|
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)
|
void wShadeWindow(WWindow *wwin)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#define SAVE_GEOMETRY_ALL SAVE_GEOMETRY_X | SAVE_GEOMETRY_Y | SAVE_GEOMETRY_WIDTH | SAVE_GEOMETRY_HEIGHT
|
#define SAVE_GEOMETRY_ALL SAVE_GEOMETRY_X | SAVE_GEOMETRY_Y | SAVE_GEOMETRY_WIDTH | SAVE_GEOMETRY_HEIGHT
|
||||||
|
|
||||||
void wSetFocusTo(WScreen *scr, WWindow *wwin);
|
void wSetFocusTo(WScreen *scr, WWindow *wwin);
|
||||||
|
void wSetFocusToDirection(WScreen *scr, int direction);
|
||||||
|
|
||||||
int wMouseMoveWindow(WWindow *wwin, XEvent *ev);
|
int wMouseMoveWindow(WWindow *wwin, XEvent *ev);
|
||||||
int wKeyboardMoveResizeWindow(WWindow *wwin);
|
int wKeyboardMoveResizeWindow(WWindow *wwin);
|
||||||
|
|||||||
@@ -721,6 +721,15 @@ WDefaultEntry optionList[] = {
|
|||||||
NULL, getKeybind, setKeyGrab, NULL, NULL},
|
NULL, getKeybind, setKeyGrab, NULL, NULL},
|
||||||
{"FocusPrevKey", "Mod1+Shift+Tab", (void *)WKBD_FOCUSPREV,
|
{"FocusPrevKey", "Mod1+Shift+Tab", (void *)WKBD_FOCUSPREV,
|
||||||
NULL, getKeybind, setKeyGrab, NULL, NULL},
|
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,
|
{"GroupNextKey", "None", (void *)WKBD_GROUPNEXT,
|
||||||
NULL, getKeybind, setKeyGrab, NULL, NULL},
|
NULL, getKeybind, setKeyGrab, NULL, NULL},
|
||||||
{"GroupPrevKey", "None", (void *)WKBD_GROUPPREV,
|
{"GroupPrevKey", "None", (void *)WKBD_GROUPPREV,
|
||||||
|
|||||||
16
src/event.c
16
src/event.c
@@ -1732,6 +1732,22 @@ static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent
|
|||||||
StartWindozeCycle(wwin, event, False, False);
|
StartWindozeCycle(wwin, event, False, False);
|
||||||
break;
|
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:
|
case WKBD_GROUPNEXT:
|
||||||
StartWindozeCycle(wwin, event, True, True);
|
StartWindozeCycle(wwin, event, True, True);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ enum {
|
|||||||
WKBD_WORKSPACEMAP,
|
WKBD_WORKSPACEMAP,
|
||||||
WKBD_FOCUSNEXT,
|
WKBD_FOCUSNEXT,
|
||||||
WKBD_FOCUSPREV,
|
WKBD_FOCUSPREV,
|
||||||
|
WKBD_FOCUSLEFT,
|
||||||
|
WKBD_FOCUSRIGHT,
|
||||||
|
WKBD_FOCUSUP,
|
||||||
|
WKBD_FOCUSDOWN,
|
||||||
WKBD_GROUPNEXT,
|
WKBD_GROUPNEXT,
|
||||||
WKBD_GROUPPREV,
|
WKBD_GROUPPREV,
|
||||||
WKBD_CENTRAL,
|
WKBD_CENTRAL,
|
||||||
|
|||||||
29
src/window.c
29
src/window.c
@@ -470,6 +470,35 @@ void wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace)
|
|||||||
wwin->client_flags.no_focusable = 1;
|
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)
|
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured)
|
||||||
{
|
{
|
||||||
int w1, h1, w2, h2;
|
int w1, h1, w2, h2;
|
||||||
|
|||||||
@@ -405,6 +405,7 @@ WMagicNumber wWindowGetSavedState(Window win);
|
|||||||
|
|
||||||
void wWindowDeleteSavedState(WMagicNumber id);
|
void wWindowDeleteSavedState(WMagicNumber id);
|
||||||
|
|
||||||
|
Bool wWindowIsFullyCovered(WWindow *wwin);
|
||||||
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
|
Bool wWindowObscuresWindow(WWindow *wwin, WWindow *obscured);
|
||||||
|
|
||||||
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
|
void wWindowSetOmnipresent(WWindow *wwin, Bool flag);
|
||||||
|
|||||||
Reference in New Issue
Block a user