Wayland: Use XDG_ACTIVATION_TOKEN when present at launch

This commit is contained in:
Kovid Goyal 2022-09-11 13:30:14 +05:30
parent b247759d30
commit 58a3baaf0f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
12 changed files with 39 additions and 12 deletions

View File

@ -245,6 +245,7 @@ def generate_wrappers(glfw_header: str) -> None:
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void) const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive) int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback) void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
void glfwWaylandActivateWindow(GLFWwindow *handle, const char *activation_token)
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color) bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \ unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data) const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)

6
glfw/wl_window.c vendored
View File

@ -2217,6 +2217,12 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
return window->wl.surface; return window->wl.surface;
} }
GLFWAPI void glfwWaylandActivateWindow(GLFWwindow* handle, const char *activation_token) {
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT();
if (activation_token && activation_token[0]) xdg_activation_v1_activate(_glfw.wl.xdg_activation_v1, activation_token, window->wl.surface);
}
GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) { GLFWAPI int glfwGetNativeKeyForName(const char* keyName, bool caseSensitive) {
return glfw_xkb_keysym_from_name(keyName, caseSensitive); return glfw_xkb_keysym_from_name(keyName, caseSensitive);
} }

View File

@ -296,7 +296,8 @@ class Boss:
def startup_first_child(self, os_window_id: Optional[int], startup_sessions: Iterable[Session] = ()) -> None: def startup_first_child(self, os_window_id: Optional[int], startup_sessions: Iterable[Session] = ()) -> None:
si = startup_sessions or create_sessions(get_options(), self.args, default_session=get_options().startup_session) si = startup_sessions or create_sessions(get_options(), self.args, default_session=get_options().startup_session)
focused_os_window = 0 focused_os_window = wid = 0
token = os.environ.pop('XDG_ACTIVATION_TOKEN', '')
for startup_session in si: for startup_session in si:
wid = self.add_os_window(startup_session, os_window_id=os_window_id) wid = self.add_os_window(startup_session, os_window_id=os_window_id)
if startup_session.focus_os_window: if startup_session.focus_os_window:
@ -308,7 +309,9 @@ class Boss:
else: else:
change_os_window_state(self.args.start_as) change_os_window_state(self.args.start_as)
if focused_os_window > 0: if focused_os_window > 0:
focus_os_window(focused_os_window, True) focus_os_window(focused_os_window, True, token)
elif token and is_wayland() and wid:
focus_os_window(wid, True, token)
def add_os_window( def add_os_window(
self, self,
@ -630,6 +633,7 @@ class Boss:
if isinstance(data, dict) and data.get('cmd') == 'new_instance': if isinstance(data, dict) and data.get('cmd') == 'new_instance':
from .cli_stub import CLIOptions from .cli_stub import CLIOptions
startup_id = data.get('startup_id') startup_id = data.get('startup_id')
activation_token = data.get('activation_token', '')
args, rest = parse_args(data['args'][1:], result_class=CLIOptions) args, rest = parse_args(data['args'][1:], result_class=CLIOptions)
cmdline_args_for_open = data.get('cmdline_args_for_open') cmdline_args_for_open = data.get('cmdline_args_for_open')
if cmdline_args_for_open: if cmdline_args_for_open:
@ -642,7 +646,7 @@ class Boss:
args.session = PreReadSession(data['stdin']) args.session = PreReadSession(data['stdin'])
if not os.path.isabs(args.directory): if not os.path.isabs(args.directory):
args.directory = os.path.join(data['cwd'], args.directory) args.directory = os.path.join(data['cwd'], args.directory)
focused_os_window = 0 focused_os_window = os_window_id = 0
for session in create_sessions(opts, args, respect_cwd=True): for session in create_sessions(opts, args, respect_cwd=True):
os_window_id = self.add_os_window( os_window_id = self.add_os_window(
session, wclass=args.cls, wname=args.name, opts_for_size=opts, startup_id=startup_id, session, wclass=args.cls, wname=args.name, opts_for_size=opts, startup_id=startup_id,
@ -654,7 +658,9 @@ class Boss:
if data.get('notify_on_os_window_death'): if data.get('notify_on_os_window_death'):
self.os_window_death_actions[os_window_id] = partial(self.notify_on_os_window_death, data['notify_on_os_window_death']) self.os_window_death_actions[os_window_id] = partial(self.notify_on_os_window_death, data['notify_on_os_window_death'])
if focused_os_window > 0: if focused_os_window > 0:
focus_os_window(focused_os_window, True) focus_os_window(focused_os_window, True, activation_token or '')
elif activation_token and is_wayland() and os_window_id:
focus_os_window(os_window_id, True, activation_token or '')
else: else:
log_error('Unknown message received from peer, ignoring') log_error('Unknown message received from peer, ignoring')
return None return None

View File

@ -148,6 +148,7 @@ def process_env() -> Dict[str, str]:
ssl_env_var = getattr(sys, 'kitty_ssl_env_var', None) ssl_env_var = getattr(sys, 'kitty_ssl_env_var', None)
if ssl_env_var is not None: if ssl_env_var is not None:
ans.pop(ssl_env_var, None) ans.pop(ssl_env_var, None)
ans.pop('XDG_ACTIVATION_TOKEN', None)
return ans return ans

View File

@ -754,7 +754,7 @@ def global_font_size(val: float = -1.) -> float:
pass pass
def focus_os_window(os_window_id: int, also_raise: bool = True) -> bool: def focus_os_window(os_window_id: int, also_raise: bool = True, activation_token: Optional[str] = None) -> bool:
pass pass

3
kitty/glfw-wrapper.c generated
View File

@ -449,6 +449,9 @@ load_glfw(const char* path) {
*(void **) (&glfwRequestWaylandFrameEvent_impl) = dlsym(handle, "glfwRequestWaylandFrameEvent"); *(void **) (&glfwRequestWaylandFrameEvent_impl) = dlsym(handle, "glfwRequestWaylandFrameEvent");
if (glfwRequestWaylandFrameEvent_impl == NULL) dlerror(); // clear error indicator if (glfwRequestWaylandFrameEvent_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwWaylandActivateWindow_impl) = dlsym(handle, "glfwWaylandActivateWindow");
if (glfwWaylandActivateWindow_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwWaylandSetTitlebarColor_impl) = dlsym(handle, "glfwWaylandSetTitlebarColor"); *(void **) (&glfwWaylandSetTitlebarColor_impl) = dlsym(handle, "glfwWaylandSetTitlebarColor");
if (glfwWaylandSetTitlebarColor_impl == NULL) dlerror(); // clear error indicator if (glfwWaylandSetTitlebarColor_impl == NULL) dlerror(); // clear error indicator

5
kitty/glfw-wrapper.h generated
View File

@ -1454,6 +1454,7 @@ typedef void (* GLFWjoystickfun)(int,int);
typedef void (* GLFWuserdatafun)(unsigned long long, void*); typedef void (* GLFWuserdatafun)(unsigned long long, void*);
typedef void (* GLFWtickcallback)(void*); typedef void (* GLFWtickcallback)(void*);
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin); typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
typedef char* (* GLFWcurrentselectionfun)(void); typedef char* (* GLFWcurrentselectionfun)(void);
typedef void (* GLFWclipboarddatafreefun)(void* data); typedef void (* GLFWclipboarddatafreefun)(void* data);
@ -2205,6 +2206,10 @@ typedef void (*glfwRequestWaylandFrameEvent_func)(GLFWwindow*, unsigned long lon
GFW_EXTERN glfwRequestWaylandFrameEvent_func glfwRequestWaylandFrameEvent_impl; GFW_EXTERN glfwRequestWaylandFrameEvent_func glfwRequestWaylandFrameEvent_impl;
#define glfwRequestWaylandFrameEvent glfwRequestWaylandFrameEvent_impl #define glfwRequestWaylandFrameEvent glfwRequestWaylandFrameEvent_impl
typedef void (*glfwWaylandActivateWindow_func)(GLFWwindow*, const char*);
GFW_EXTERN glfwWaylandActivateWindow_func glfwWaylandActivateWindow_impl;
#define glfwWaylandActivateWindow glfwWaylandActivateWindow_impl
typedef bool (*glfwWaylandSetTitlebarColor_func)(GLFWwindow*, uint32_t, bool); typedef bool (*glfwWaylandSetTitlebarColor_func)(GLFWwindow*, uint32_t, bool);
GFW_EXTERN glfwWaylandSetTitlebarColor_func glfwWaylandSetTitlebarColor_impl; GFW_EXTERN glfwWaylandSetTitlebarColor_func glfwWaylandSetTitlebarColor_impl;
#define glfwWaylandSetTitlebarColor glfwWaylandSetTitlebarColor_impl #define glfwWaylandSetTitlebarColor glfwWaylandSetTitlebarColor_impl

View File

@ -1037,13 +1037,17 @@ destroy_os_window(OSWindow *w) {
} }
void void
focus_os_window(OSWindow *w, bool also_raise) { focus_os_window(OSWindow *w, bool also_raise, const char *activation_token) {
if (w->handle) { if (w->handle) {
#ifdef __APPLE__ #ifdef __APPLE__
if (!also_raise) cocoa_focus_window(glfwGetCocoaWindow(w->handle)); if (!also_raise) cocoa_focus_window(glfwGetCocoaWindow(w->handle));
else glfwFocusWindow(w->handle); else glfwFocusWindow(w->handle);
(void)activation_token;
#else #else
(void)also_raise; if (global_state.is_wayland && activation_token && activation_token[0] && also_raise) {
glfwWaylandActivateWindow(w->handle, activation_token);
return;
}
glfwFocusWindow(w->handle); glfwFocusWindow(w->handle);
#endif #endif
} }

View File

@ -61,7 +61,7 @@ def talk_to_instance(args: CLIOptions) -> None:
if args.session == '-': if args.session == '-':
stdin = sys.stdin.read() stdin = sys.stdin.read()
data = {'cmd': 'new_instance', 'args': tuple(sys.argv), 'cmdline_args_for_open': getattr(sys, 'cmdline_args_for_open', []), data = {'cmd': 'new_instance', 'args': tuple(sys.argv), 'cmdline_args_for_open': getattr(sys, 'cmdline_args_for_open', []),
'startup_id': os.environ.get('DESKTOP_STARTUP_ID'), 'startup_id': os.environ.get('DESKTOP_STARTUP_ID'), 'activation_token': os.environ.get('XDG_ACTIVATION_TOKEN'),
'cwd': os.getcwd(), 'stdin': stdin} 'cwd': os.getcwd(), 'stdin': stdin}
notify_socket = None notify_socket = None
if args.wait_for_single_instance_window_close: if args.wait_for_single_instance_window_close:

View File

@ -653,7 +653,7 @@ enter_event() {
// On cocoa there is no way to configure the window manager to // On cocoa there is no way to configure the window manager to
// focus windows on mouse enter, so we do it ourselves // focus windows on mouse enter, so we do it ourselves
if (OPT(focus_follows_mouse) && !global_state.callback_os_window->is_focused) { if (OPT(focus_follows_mouse) && !global_state.callback_os_window->is_focused) {
focus_os_window(global_state.callback_os_window, false); focus_os_window(global_state.callback_os_window, false, NULL);
} }
#endif #endif
} }

View File

@ -822,9 +822,10 @@ PYWRAP0(current_application_quit_request) {
PYWRAP1(focus_os_window) { PYWRAP1(focus_os_window) {
id_type os_window_id; id_type os_window_id;
int also_raise = 1; int also_raise = 1;
PA("K|p", &os_window_id, &also_raise); const char *activation_token = NULL;
PA("K|pz", &os_window_id, &also_raise, &activation_token);
WITH_OS_WINDOW(os_window_id) WITH_OS_WINDOW(os_window_id)
if (!os_window->is_focused) focus_os_window(os_window, also_raise); if (!os_window->is_focused || (activation_token && activation_token[0])) focus_os_window(os_window, also_raise, activation_token);
Py_RETURN_TRUE; Py_RETURN_TRUE;
END_WITH_OS_WINDOW END_WITH_OS_WINDOW
Py_RETURN_FALSE; Py_RETURN_FALSE;

View File

@ -270,7 +270,7 @@ bool make_window_context_current(id_type);
void hide_mouse(OSWindow *w); void hide_mouse(OSWindow *w);
bool is_mouse_hidden(OSWindow *w); bool is_mouse_hidden(OSWindow *w);
void destroy_os_window(OSWindow *w); void destroy_os_window(OSWindow *w);
void focus_os_window(OSWindow *w, bool also_raise); void focus_os_window(OSWindow *w, bool also_raise, const char *activation_token);
void set_os_window_title(OSWindow *w, const char *title); void set_os_window_title(OSWindow *w, const char *title);
OSWindow* os_window_for_kitty_window(id_type); OSWindow* os_window_for_kitty_window(id_type);
OSWindow* add_os_window(void); OSWindow* add_os_window(void);