all repos — fluxbox @ 1a61881ec34a5f3691df1159f63a4b5afb1f53c4

custom fork of the fluxbox windowmanager

Add FocusProtection features

The apps file gets a new key
FocusProtection
supporting a comma separated list.
* None : regular behavior
* Lock : If this window has the focus, no other may claim it
* Deny : This window is not allowed to focus itself

I addition there's preparation for a follow-up patch to incorporate and
substitute the present FocusNewWindow feature:
* Gain : Pass focus to new window
* Refuse : Do not pass focus to new window

rationale:
clients stealing the focus sucks badly and while there's an input driven
timeout, that only protects actual typing flow, but if eg. vlc proceeds on
the playlist, you'll suddenly control vlc instead of your browser
(ie. typing ctrl+w doesn't close the tab, but the playlist ...)
Thomas Lübking thomas.luebking@gmail.com
commit

1a61881ec34a5f3691df1159f63a4b5afb1f53c4

parent

69b0f0fa97f53f601a250dc1b5a6876f64796a91

5 files changed, 102 insertions(+), 2 deletions(-)

jump to
M src/FocusControl.ccsrc/FocusControl.cc

@@ -588,6 +588,13 @@ return;

} } + if (client != expectingFocus() && s_focused_window && + ((s_focused_fbwindow->focusProtection() & Focus::Lock) || + (client && client->fbwindow() && (client->fbwindow()->focusProtection() & Focus::Deny)))) { + s_focused_window->focus(); + return; + } + BScreen *old_screen = FocusControl::focusedWindow() ? &FocusControl::focusedWindow()->screen() : 0;
M src/Remember.ccsrc/Remember.cc

@@ -98,6 +98,7 @@ void forgetFocusHiddenstate() { focushiddenstate_remember= false; }

void forgetIconHiddenstate() { iconhiddenstate_remember= false; } void forgetStuckstate() { stuckstate_remember = false; } void forgetFocusNewWindow() { focusnewwindow_remember = false; } + void forgetFocusProtection() { focusprotection_remember = false; } void forgetJumpworkspace() { jumpworkspace_remember = false; } void forgetLayer() { layer_remember = false; } void forgetSaveOnClose() { save_on_close_remember = false; }

@@ -140,6 +141,8 @@ void rememberStuckstate(bool state)

{ stuckstate = state; stuckstate_remember = true; } void rememberFocusNewWindow(bool state) { focusnewwindow = state; focusnewwindow_remember = true; } + void rememberFocusProtection(unsigned int protect) + { focusprotection = protect; focusprotection_remember = true; } void rememberJumpworkspace(bool state) { jumpworkspace = state; jumpworkspace_remember = true; } void rememberLayer(int layernum)

@@ -191,6 +194,9 @@

bool focusnewwindow_remember; bool focusnewwindow; + bool focusprotection_remember; + unsigned int focusprotection; + bool focushiddenstate_remember; bool focushiddenstate;

@@ -242,6 +248,7 @@ position_remember =

shadedstate_remember = stuckstate_remember = focusnewwindow_remember = + focusprotection_remember = tabstate_remember = workspace_remember = head_remember =

@@ -549,6 +556,26 @@ } else if (str_key == "sticky") {

app.rememberStuckstate(str_label == "yes"); } else if (str_key == "focusnewwindow") { app.rememberFocusNewWindow(str_label == "yes"); + } else if (str_key == "focusprotection") { + Focus::Protection protect = Focus::NoProtection; + std::list<std::string> labels; + FbTk::StringUtil::stringtok(labels, str_label, ", "); + std::list<std::string>::iterator it = labels.begin(); + for (; it != labels.end(); ++it) { + if (*it == "lock") + protect = (protect & ~Focus::Deny) | Focus::Lock; + else if (*it == "deny") + protect = (protect & ~Focus::Lock) | Focus::Deny; + else if (*it == "gain") + protect = (protect & ~Focus::Refuse) | Focus::Gain; + else if (*it == "refuse") + protect = (protect & ~Focus::Gain) | Focus::Refuse; + else if (*it == "none") + protect = Focus::NoProtection; + else + had_error = 1; + } + app.rememberFocusProtection(protect); } else if (str_key == "minimized") { app.rememberMinimizedstate(str_label == "yes"); } else if (str_key == "maximized") {

@@ -1009,6 +1036,31 @@ }

if (a.focusnewwindow_remember) { apps_file << " [FocusNewWindow]\t{" << ((a.focusnewwindow)?"yes":"no") << "}" << endl; } + if (a.focusprotection_remember) { + apps_file << " [FocusProtection]\t{"; + if (a.focusprotection == Focus::NoProtection) { + apps_file << "none"; + } else { + bool b = false; + if (a.focusprotection & Focus::Gain) { + apps_file << (b?",":"") << "gain"; + b = true; + } + if (a.focusprotection & Focus::Refuse) { + apps_file << (b?",":"") << "refuse"; + b = true; + } + if (a.focusprotection & Focus::Lock) { + apps_file << (b?",":"") << "lock"; + b = true; + } + if (a.focusprotection & Focus::Deny) { + apps_file << (b?",":"") << "deny"; + b = true; + } + } + apps_file << "}" << endl; + } if (a.minimizedstate_remember) { apps_file << " [Minimized]\t{" << ((a.minimizedstate)?"yes":"no") << "}" << endl; }

@@ -1082,6 +1134,9 @@ return app->stuckstate_remember;

break; case REM_FOCUSNEWWINDOW: return app->focusnewwindow_remember; + break; + case REM_FOCUSPROTECTION: + return app->focusprotection_remember; break; case REM_MINIMIZEDSTATE: return app->minimizedstate_remember;

@@ -1166,6 +1221,9 @@ break;

case REM_FOCUSNEWWINDOW: app->rememberFocusNewWindow(win->isFocusNew()); break; + case REM_FOCUSPROTECTION: + app->rememberFocusProtection(win->focusProtection()); + break; case REM_MINIMIZEDSTATE: app->rememberMinimizedstate(win->isIconic()); break;

@@ -1228,6 +1286,9 @@ app->forgetStuckstate();

break; case REM_FOCUSNEWWINDOW: app->forgetFocusNewWindow(); + break; + case REM_FOCUSPROTECTION: + app->forgetFocusProtection(); break; case REM_MINIMIZEDSTATE: app->forgetMinimizedstate();

@@ -1354,6 +1415,10 @@ win.stick(); // toggles

if (app->focusnewwindow_remember) win.setFocusNew(app->focusnewwindow); + + if (app->focusprotection_remember) { + win.setFocusProtection(app->focusprotection); + } if (app->minimizedstate_remember) { // if inconsistent...
M src/Remember.hhsrc/Remember.hh

@@ -75,6 +75,7 @@ REM_MINIMIZEDSTATE,

REM_MAXIMIZEDSTATE, REM_FULLSCREENSTATE, REM_FOCUSNEWWINDOW, + REM_FOCUSPROTECTION, REM_LASTATTRIB // not actually used };

@@ -85,7 +86,6 @@ POS_LOWERLEFT,

POS_LOWERRIGHT, POS_CENTER }; - // a "pattern" to the relevant app
M src/Window.ccsrc/Window.cc

@@ -291,6 +291,7 @@ m_old_decoration_mask(0),

m_client(&client), m_toggled_decos(false), m_focus_new(BoolAcc(screen().focusControl(), &FocusControl::focusNew)), + m_focus_protection(Focus::NoProtection), m_mouse_focus(BoolAcc(screen().focusControl(), &FocusControl::isMouseFocus)), m_click_focus(true), m_last_button_x(0), m_last_button_y(0),

@@ -563,7 +564,10 @@ deiconify(false);

// check if we should prevent this window from gaining focus m_focused = false; // deiconify sets this if (!Fluxbox::instance()->isStartup() && m_focus_new) { + Focus::Protection fp = m_focus_protection; + m_focus_protection &= ~Focus::Deny; // new windows run as "Refuse" m_focused = focusRequestFromClient(*m_client); + m_focus_protection = fp; if (!m_focused) lower(); }

@@ -2025,7 +2029,10 @@ deiconify();

if (m_focus_new) { m_focused = false; // deiconify sets this + Focus::Protection fp = m_focus_protection; + m_focus_protection &= ~Focus::Deny; // goes by "Refuse" m_focused = focusRequestFromClient(*client); + m_focus_protection = fp; if (!m_focused) lower(); }

@@ -2041,9 +2048,13 @@ bool ret = true;

FluxboxWindow *cur = FocusControl::focusedFbWindow(); WinClient *client = FocusControl::focusedWindow(); - if (cur && getRootTransientFor(&from) != getRootTransientFor(client)) + if ((from.fbwindow() && (from.fbwindow()->focusProtection() & Focus::Deny)) || + (cur && (cur->focusProtection() & Focus::Lock))) { + ret = false; + } else if (cur && getRootTransientFor(&from) != getRootTransientFor(client)) { ret = !(cur->isFullscreen() && getOnHead() == cur->getOnHead()) && !cur->isTyping(); + } if (!ret) Fluxbox::instance()->attentionHandler().addAttention(from);
M src/Window.hhsrc/Window.hh

@@ -56,6 +56,18 @@ class ImageControl;

class Layer; } +namespace Focus { + enum { + NoProtection = 0, + Gain = 1, + Refuse = 2, + Lock = 4, + Deny = 8 + }; + typedef unsigned int Protection; +} + + /// Creates the window frame and handles any window event for it class FluxboxWindow: public Focusable, public FbTk::EventHandler,

@@ -256,6 +268,8 @@ /// sets the window icon hidden state

void setIconHidden(bool value); /// sets whether or not the window normally gets focus when mapped void setFocusNew(bool value) { m_focus_new = value; } + /// sets how to protect the focus on or against this window + void setFocusProtection(Focus::Protection value) { m_focus_protection = value; } /// sets whether or not the window gets focused with mouse void setMouseFocus(bool value) { m_mouse_focus = value; } /// sets whether or not the window gets focused with click

@@ -384,6 +398,7 @@ bool isClosable() const { return functions.close; }

bool isMoveable() const { return functions.move; } bool isStuck() const { return m_state.stuck; } bool isFocusNew() const { return m_focus_new; } + Focus::Protection focusProtection() const { return m_focus_protection; } bool hasTitlebar() const { return decorations.titlebar; } bool isMoving() const { return moving; } bool isResizing() const { return resizing; }

@@ -572,6 +587,8 @@

typedef FbTk::ConstObjectAccessor<bool, FocusControl> BoolAcc; /// if the window is normally focused when mapped FbTk::DefaultValue<bool, BoolAcc> m_focus_new; + /// special focus permissions + Focus::Protection m_focus_protection; /// if the window is focused with EnterNotify FbTk::DefaultValue<bool, BoolAcc> m_mouse_focus; bool m_click_focus; ///< if the window is focused by clicking