From fbd159c68b5cd599e711051a256911a03853a421 Mon Sep 17 00:00:00 2001
From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com>
Date: Fri, 15 Nov 2024 12:29:36 +1000
Subject: [PATCH 1/2] Fix focus issue when opening Qopy
Fixes #10
Implement platform-specific focus management to prevent the underlying window from losing focus when the shortcut is pressed.
* **src-tauri/src/api/hotkeys.rs**
- Add platform-specific modules for Windows, macOS, and Linux to manage focus between windows.
- Modify the `setup` function to use platform-specific APIs to manage focus between windows.
- Replace `window.set_focus()` with `platform::manage_focus(&window)`.
* **src-tauri/src/api/tray.rs**
- Add platform-specific modules for Windows, macOS, and Linux to manage focus between windows when the tray menu is used.
- Modify the `setup` function to use platform-specific APIs to manage focus between windows.
- Replace `window_clone_for_tray.set_focus()` with `platform::manage_focus(&window_clone_for_tray)`.
* **app.vue**
- Add `manageFocus` function to handle platform-specific focus management.
- Call `manageFocus` function when the `change_keybind` event is triggered.
* **src-tauri/src/main.rs**
- Remove logic to hide the window when it loses focus.
---
For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/0PandaDEV/Qopy/issues/10?shareId=XXXX-XXXX-XXXX-XXXX).
---
app.vue | 26 ++++++++++++++++++-
src-tauri/src/api/hotkeys.rs | 50 ++++++++++++++++++++++++++++++++++--
src-tauri/src/api/tray.rs | 48 +++++++++++++++++++++++++++++++++-
src-tauri/src/main.rs | 4 +--
4 files changed, 121 insertions(+), 7 deletions(-)
diff --git a/app.vue b/app.vue
index 72fdf7e..f3d4bfc 100644
--- a/app.vue
+++ b/app.vue
@@ -14,12 +14,36 @@ onMounted(async () => {
await navigateTo('/keybind')
await app.show();
await window.getCurrentWindow().show();
+ manageFocus();
})
await listen('main_route', async () => {
await navigateTo('/')
})
})
+
+function manageFocus() {
+ if (process.platform === 'win32') {
+ const { SetForegroundWindow, AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId } = require('windows-api');
+ const foregroundWindow = GetForegroundWindow();
+ const currentThreadId = GetWindowThreadProcessId(foregroundWindow, null);
+ const targetThreadId = GetWindowThreadProcessId(window.hwnd(), null);
+
+ AttachThreadInput(currentThreadId, targetThreadId, 1);
+ SetForegroundWindow(window.hwnd());
+ AttachThreadInput(currentThreadId, targetThreadId, 0);
+ } else if (process.platform === 'darwin') {
+ const { NSWindow } = require('cocoa');
+ const nsWindow = window.ns_window();
+ nsWindow.makeKeyAndOrderFront(true);
+ } else if (process.platform === 'linux') {
+ const { XOpenDisplay, XDefaultRootWindow, XSetInputFocus, XCloseDisplay, RevertToParent } = require('xlib');
+ const display = XOpenDisplay(null);
+ const rootWindow = XDefaultRootWindow(display);
+ XSetInputFocus(display, rootWindow, RevertToParent, 0);
+ XCloseDisplay(display);
+ }
+}
\ No newline at end of file
+
diff --git a/src-tauri/src/api/hotkeys.rs b/src-tauri/src/api/hotkeys.rs
index 8edcd7f..44774e9 100644
--- a/src-tauri/src/api/hotkeys.rs
+++ b/src-tauri/src/api/hotkeys.rs
@@ -3,6 +3,52 @@ use crate::utils::commands::center_window_on_current_monitor;
use rdev::{listen, EventType, Key};
use tauri::Manager;
+#[cfg(target_os = "windows")]
+mod platform {
+ use std::ptr::null_mut;
+ use winapi::um::winuser::{AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId, SetForegroundWindow};
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let foreground_window = GetForegroundWindow();
+ let current_thread_id = GetWindowThreadProcessId(foreground_window, null_mut());
+ let target_thread_id = GetWindowThreadProcessId(window.hwnd() as _, null_mut());
+
+ AttachThreadInput(current_thread_id, target_thread_id, 1);
+ SetForegroundWindow(window.hwnd() as _);
+ AttachThreadInput(current_thread_id, target_thread_id, 0);
+ }
+ }
+}
+
+#[cfg(target_os = "macos")]
+mod platform {
+ use cocoa::appkit::NSWindow;
+ use cocoa::base::id;
+ use objc::runtime::YES;
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let ns_window: id = window.ns_window().unwrap() as _;
+ ns_window.makeKeyAndOrderFront_(YES);
+ }
+ }
+}
+
+#[cfg(target_os = "linux")]
+mod platform {
+ use x11::xlib::{Display, XSetInputFocus, XDefaultRootWindow, XOpenDisplay, XCloseDisplay, RevertToParent};
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let display: *mut Display = XOpenDisplay(null_mut());
+ let root_window = XDefaultRootWindow(display);
+ XSetInputFocus(display, root_window, RevertToParent, 0);
+ XCloseDisplay(display);
+ }
+ }
+}
+
fn key_to_string(key: &Key) -> String {
format!("{:?}", key)
}
@@ -35,10 +81,10 @@ pub fn setup(app_handle: tauri::AppHandle) {
pressed_keys.iter_mut().for_each(|k| *k = false);
let window = app_handle.get_webview_window("main").unwrap();
window.show().unwrap();
- window.set_focus().unwrap();
center_window_on_current_monitor(&window);
+ platform::manage_focus(&window);
}
})
.unwrap();
});
-}
\ No newline at end of file
+}
diff --git a/src-tauri/src/api/tray.rs b/src-tauri/src/api/tray.rs
index 6b78b8c..abd4c07 100644
--- a/src-tauri/src/api/tray.rs
+++ b/src-tauri/src/api/tray.rs
@@ -2,6 +2,52 @@ use tauri::{
menu::{MenuBuilder, MenuItemBuilder}, tray::TrayIconBuilder, Emitter, Manager
};
+#[cfg(target_os = "windows")]
+mod platform {
+ use std::ptr::null_mut;
+ use winapi::um::winuser::{AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId, SetForegroundWindow};
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let foreground_window = GetForegroundWindow();
+ let current_thread_id = GetWindowThreadProcessId(foreground_window, null_mut());
+ let target_thread_id = GetWindowThreadProcessId(window.hwnd() as _, null_mut());
+
+ AttachThreadInput(current_thread_id, target_thread_id, 1);
+ SetForegroundWindow(window.hwnd() as _);
+ AttachThreadInput(current_thread_id, target_thread_id, 0);
+ }
+ }
+}
+
+#[cfg(target_os = "macos")]
+mod platform {
+ use cocoa::appkit::NSWindow;
+ use cocoa::base::id;
+ use objc::runtime::YES;
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let ns_window: id = window.ns_window().unwrap() as _;
+ ns_window.makeKeyAndOrderFront_(YES);
+ }
+ }
+}
+
+#[cfg(target_os = "linux")]
+mod platform {
+ use x11::xlib::{Display, XSetInputFocus, XDefaultRootWindow, XOpenDisplay, XCloseDisplay, RevertToParent};
+
+ pub fn manage_focus(window: &tauri::Window) {
+ unsafe {
+ let display: *mut Display = XOpenDisplay(null_mut());
+ let root_window = XDefaultRootWindow(display);
+ XSetInputFocus(display, root_window, RevertToParent, 0);
+ XCloseDisplay(display);
+ }
+ }
+}
+
pub fn setup(app: &mut tauri::App) -> Result<(), Box> {
let window = app.get_webview_window("main").unwrap();
let window_clone_for_tray = window.clone();
@@ -30,7 +76,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box> {
window_clone_for_tray.hide().unwrap();
} else {
window_clone_for_tray.show().unwrap();
- window_clone_for_tray.set_focus().unwrap();
+ platform::manage_focus(&window_clone_for_tray);
}
window_clone_for_tray.emit("main_route", ()).unwrap();
}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 10c61f3..758274b 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -64,9 +64,7 @@ fn main() {
.on_window_event(|app, event| {
#[cfg(not(dev))]
if let tauri::WindowEvent::Focused(false) = event {
- if let Some(window) = app.get_webview_window("main") {
- let _ = window.hide();
- }
+ return;
}
})
.invoke_handler(tauri::generate_handler![
From 3c54fa284a4c1c2a2e2fc4b2fb0a64f5c815efed Mon Sep 17 00:00:00 2001
From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com>
Date: Fri, 15 Nov 2024 18:19:22 +1000
Subject: [PATCH 2/2] feat: branch specific action runs
---
.github/workflows/build.yml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c6c199b..214f7f2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,6 +8,12 @@ on:
branches:
- main
workflow_dispatch:
+ inputs:
+ ref:
+ description: 'Branch or tag to build e.g. main or v0.1.0'
+ required: true
+ type: string
+ default: 'main'
jobs:
prepare:
@@ -16,6 +22,8 @@ jobs:
version: ${{ steps.get_version.outputs.VERSION }}
steps:
- uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.inputs.ref }}
- name: Get version
id: get_version
run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT
@@ -31,6 +39,8 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
steps:
- uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.inputs.ref }}
- name: setup node
uses: actions/setup-node@v4