diff --git a/include/config.h b/include/config.h index 9a0af0e6..5b534fb7 100644 --- a/include/config.h +++ b/include/config.h @@ -167,6 +167,18 @@ struct Config { * flag can be delayed using an urgency timer. */ float workspace_urgency_timer; + /** Behavior when a window sends a NET_ACTIVE_WINDOW message. */ + enum { + /* Focus if the target workspace is visible, set urgency hint otherwise. */ + FOWA_SMART, + /* Always set the urgency hint. */ + FOWA_URGENT, + /* Always focus the window. */ + FOWA_FOCUS, + /* Ignore the request (no focus, no urgency hint). */ + FOWA_NONE + } focus_on_window_activation; + /** The default border style for new windows. */ border_style_t default_border; diff --git a/include/config_directives.h b/include/config_directives.h index 6c960b1f..8f99e648 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -51,6 +51,7 @@ CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_xinerama, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); +CFGFUN(focus_on_window_activation, const char *mode); CFGFUN(hide_edge_borders, const char *borders); CFGFUN(assign, const char *workspace); CFGFUN(ipc_socket, const char *path); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 25be5cf1..e23c37c8 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -38,6 +38,7 @@ state INITIAL: 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT + 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION 'workspace' -> WORKSPACE 'ipc_socket', 'ipc-socket' -> IPC_SOCKET 'restart_state' -> RESTART_STATE @@ -210,6 +211,11 @@ state FORCE_DISPLAY_URGENCY_HINT_MS: end -> call cfg_force_display_urgency_hint(&duration_ms) +# focus_on_window_activation +state FOCUS_ON_WINDOW_ACTIVATION: + mode = word + -> call cfg_focus_on_window_activation($mode) + # workspace output state WORKSPACE: workspace = word diff --git a/src/config_directives.c b/src/config_directives.c index c8b25c76..039cb29e 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -329,6 +329,23 @@ CFGFUN(force_display_urgency_hint, const long duration_ms) { config.workspace_urgency_timer = duration_ms / 1000.0; } +CFGFUN(focus_on_window_activation, const char *mode) { + if (strcmp(mode, "smart") == 0) + config.focus_on_window_activation = FOWA_SMART; + else if (strcmp(mode, "urgent") == 0) + config.focus_on_window_activation = FOWA_URGENT; + else if (strcmp(mode, "focus") == 0) + config.focus_on_window_activation = FOWA_FOCUS; + else if (strcmp(mode, "none") == 0) + config.focus_on_window_activation = FOWA_NONE; + else { + ELOG("Unknown focus_on_window_activation mode \"%s\", ignoring it.\n", mode); + return; + } + + DLOG("Set new focus_on_window_activation mode = %i", config.focus_on_window_activation); +} + CFGFUN(workspace, const char *workspace, const char *output) { DLOG("Assigning workspace \"%s\" to output \"%s\"\n", workspace, output); /* Check for earlier assignments of the same workspace so that we diff --git a/src/handlers.c b/src/handlers.c index 041f7e36..c80c279e 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -743,16 +743,17 @@ static void handle_client_message(xcb_client_message_event_t *event) { workspace_show(ws); con_focus(con); } else { - /* If the request is from an application, only focus if the - * workspace is visible. Otherwise set the urgency hint. */ - if (workspace_is_visible(ws)) { - DLOG("Request to focus con on a visible workspace. Focusing con = %p\n", con); + /* Request is from an application. */ + + if (config.focus_on_window_activation == FOWA_FOCUS || (config.focus_on_window_activation == FOWA_SMART && workspace_is_visible(ws))) { + DLOG("Focusing con = %p\n", con); workspace_show(ws); con_focus(con); - } else { - DLOG("Request to focus con on a hidden workspace. Setting urgent con = %p\n", con); + } else if (config.focus_on_window_activation == FOWA_URGENT || (config.focus_on_window_activation == FOWA_SMART && !workspace_is_visible(ws))) { + DLOG("Marking con = %p urgent\n", con); con_set_urgency(con, true); - } + } else + DLOG("Ignoring request for con = %p", con); } tree_render(); diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 1e91d47f..a6b1fe0c 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -433,7 +433,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT';