diff --git a/src/action.c b/src/action.c index 6c504a1..019ba51 100644 --- a/src/action.c +++ b/src/action.c @@ -8,6 +8,7 @@ #include "monitor.h" #include "types.h" #include "wm.h" +#include "xcursor.h" void focus_client_in_same_tag(const user_action_arg_t *arg) { bool next = arg->b; @@ -72,9 +73,16 @@ void quit(const user_action_arg_t *arg) { void raise_or_run(const user_action_arg_t *arg) { const char *class = ((const char **)arg->ptr)[0]; client_t *client = client_get_next_by_class(wm.client_focused, class); - if (client && client == wm.client_focused) return; if (client) { + bool monitor_changed = client->monitor != wm.current_monitor; + bool tag_changed = client->tags != client->monitor->selected_tag->mask; + if (monitor_changed || tag_changed) { + point_t point = monitor_changed ? monitor_get_restore_cursor_point( + client->monitor) + : xcursor_query_pointer_position(); + wm_ignore_enter_notify_at_point(point); + } wm_set_current_monitor(client->monitor, true); monitor_select_tag(client->monitor, client->tags); client_stack_raise(client); diff --git a/src/event.c b/src/event.c index f148e3b..cc0f4c7 100644 --- a/src/event.c +++ b/src/event.c @@ -313,6 +313,8 @@ static void expose(xcb_expose_event_t *ev) { } static void enter_notify(xcb_enter_notify_event_t *ev) { + if (wm_should_ignore_enter_notify(ev)) return; + client_t *client = client_get_by_window(ev->event); if (!client || wm.client_focused == client) return; diff --git a/src/monitor.c b/src/monitor.c index 27dd5be..ebf72e0 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -437,7 +437,7 @@ void monitor_save_cursor_point(monitor_t *monitor) { monitor->position_inited = true; } -void monitor_restore_cursor_point(monitor_t *monitor) { +point_t monitor_get_restore_cursor_point(monitor_t *monitor) { if (!monitor->position_inited) { point_t point = xcursor_query_pointer_position(); monitor_t *m = wm_get_monitor_by_point(point); @@ -446,5 +446,9 @@ void monitor_restore_cursor_point(monitor_t *monitor) { monitor->position_inited = true; } - xcursor_set_pointer_position(monitor->cursor_position); + return monitor->cursor_position; +} + +void monitor_restore_cursor_point(monitor_t *monitor) { + xcursor_set_pointer_position(monitor_get_restore_cursor_point(monitor)); } diff --git a/src/monitor.h b/src/monitor.h index 067ef95..acd99d4 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -13,4 +13,5 @@ void monitor_init_bar(monitor_t *monitor); void monitor_draw_bar(monitor_t *monitor); void monitor_arrange(monitor_t *monitor); void monitor_save_cursor_point(monitor_t *monitor); +point_t monitor_get_restore_cursor_point(monitor_t *monitor); void monitor_restore_cursor_point(monitor_t *monitor); diff --git a/src/wm.c b/src/wm.c index 89f0a64..f303e30 100644 --- a/src/wm.c +++ b/src/wm.c @@ -57,6 +57,7 @@ static void wm_update_status(status_t *status); static void wm_run_autostart(const char *const commands[]); static void run_once(const char *command); static bool command_already_running(const char *command); +static gboolean clear_ignore_enter_notify(gpointer data); wm_t wm; @@ -81,6 +82,39 @@ static void signal_fatal(int signal_number) { static guint sources[3] = {0}; +static gboolean clear_ignore_enter_notify(gpointer data) { + wm.ignore_enter_notify = false; + wm.ignored_enter_notify_point = (point_t){0}; + wm.clear_ignore_enter_notify_source = 0; + return G_SOURCE_REMOVE; +} + +void wm_ignore_enter_notify_at_point(point_t point) { + wm.ignore_enter_notify = true; + wm.ignored_enter_notify_point = point; + if (wm.clear_ignore_enter_notify_source) { + g_source_remove(wm.clear_ignore_enter_notify_source); + } + wm.clear_ignore_enter_notify_source = + g_idle_add(clear_ignore_enter_notify, nullptr); +} + +bool wm_should_ignore_enter_notify(const xcb_enter_notify_event_t *ev) { + if (!wm.ignore_enter_notify) return false; + if (ev->root_x != wm.ignored_enter_notify_point.x || + ev->root_y != wm.ignored_enter_notify_point.y) { + return false; + } + + if (wm.clear_ignore_enter_notify_source) { + g_source_remove(wm.clear_ignore_enter_notify_source); + wm.clear_ignore_enter_notify_source = 0; + } + wm.ignore_enter_notify = false; + wm.ignored_enter_notify_point = (point_t){0}; + return true; +} + void wm_setup_signal(void) { sources[0] = g_unix_signal_add(SIGINT, exit_on_signal, nullptr); sources[1] = g_unix_signal_add(SIGTERM, exit_on_signal, nullptr); @@ -405,6 +439,12 @@ void wm_clean(void) { guint source_id = sources[i]; if (source_id) g_source_remove(source_id); } + if (wm.clear_ignore_enter_notify_source) { + g_source_remove(wm.clear_ignore_enter_notify_source); + wm.clear_ignore_enter_notify_source = 0; + } + wm.ignore_enter_notify = false; + wm.ignored_enter_notify_point = (point_t){0}; xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_ACTIVE_WINDOW); xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_SUPPORTING_WM_CHECK); diff --git a/src/wm.h b/src/wm.h index a7185d6..12b9bfe 100644 --- a/src/wm.h +++ b/src/wm.h @@ -28,6 +28,9 @@ typedef struct wm_t { client_t *client_focused; monitor_t *monitor_list; monitor_t *current_monitor; + bool ignore_enter_notify; + point_t ignored_enter_notify_point; + guint clear_ignore_enter_notify_source; const layout_t *layout_list; char *font_family; @@ -63,6 +66,8 @@ extern wm_t wm; void wm_restart(void); void wm_quit(void); void wm_restack_clients(void); +void wm_ignore_enter_notify_at_point(point_t point); +bool wm_should_ignore_enter_notify(const xcb_enter_notify_event_t *ev); void wm_set_current_monitor(monitor_t *monitor, bool restore_cursor); monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_area(area_t area); monitor_t *__attribute__((returns_nonnull)) wm_get_monitor_by_point(