mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge pull request #1566 from frap129/refactor/current-screen
refactor(CurrentScreenDector): Use WM native methods when possible
This commit is contained in:
@@ -316,6 +316,14 @@ Singleton {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get focused screen from compositor
|
||||
function getFocusedScreen() {
|
||||
if (backend && backend.getFocusedScreen) {
|
||||
return backend.getFocusedScreen();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get focused window title
|
||||
function getFocusedWindowTitle() {
|
||||
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.count) {
|
||||
|
||||
@@ -472,4 +472,17 @@ Item {
|
||||
Logger.e("HyprlandService", "Failed to cycle keyboard layout:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusedScreen() {
|
||||
const hyprMon = Hyprland.focusedMonitor;
|
||||
if (hyprMon) {
|
||||
const monitorName = hyprMon.name;
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
if (Quickshell.screens[i].name === monitorName) {
|
||||
return Quickshell.screens[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,4 +133,12 @@ Item {
|
||||
function queryDisplayScales() {
|
||||
Logger.w("LabwcService", "Display scale queries not supported via ToplevelManager");
|
||||
}
|
||||
|
||||
function getFocusedScreen() {
|
||||
const activeToplevel = ToplevelManager.activeToplevel;
|
||||
if (activeToplevel && activeToplevel.screens && activeToplevel.screens.length > 0) {
|
||||
return activeToplevel.screens[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,4 +677,12 @@ Item {
|
||||
function cycleKeyboardLayout() {
|
||||
Logger.w("MangoService", "Keyboard layout cycling not supported");
|
||||
}
|
||||
|
||||
function getFocusedScreen() {
|
||||
const activeToplevel = ToplevelManager.activeToplevel;
|
||||
if (activeToplevel && activeToplevel.screens && activeToplevel.screens.length > 0) {
|
||||
return activeToplevel.screens[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,4 +486,12 @@ Item {
|
||||
Logger.e("NiriService", "Failed to cycle keyboard layout:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusedScreen() {
|
||||
const activeToplevel = ToplevelManager.activeToplevel;
|
||||
if (activeToplevel && activeToplevel.screens && activeToplevel.screens.length > 0) {
|
||||
return activeToplevel.screens[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,4 +385,17 @@ Item {
|
||||
Logger.e("SwayService", "Failed to cycle keyboard layout:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusedScreen() {
|
||||
const i3Mon = I3.focusedMonitor;
|
||||
if (i3Mon) {
|
||||
const monitorName = i3Mon.name;
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
if (Quickshell.screens[i].name === monitorName) {
|
||||
return Quickshell.screens[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
|
||||
/**
|
||||
* Detects which screen the cursor is currently on by creating a temporary
|
||||
@@ -41,72 +42,90 @@ Item {
|
||||
* On multi-monitor setups, briefly opens an invisible window to detect the screen.
|
||||
*/
|
||||
function withCurrentScreen(callback: var): void {
|
||||
if (root.pendingCallback) {
|
||||
Logger.w("CurrentScreenDetector", "Another detection is pending, ignoring new call");
|
||||
return;
|
||||
}
|
||||
if (root.pendingCallback) {
|
||||
Logger.w("CurrentScreenDetector", "Another detection is pending, ignoring new call");
|
||||
return;
|
||||
}
|
||||
|
||||
// Single monitor setup can execute immediately
|
||||
if (Quickshell.screens.length === 1) {
|
||||
callback(Quickshell.screens[0]);
|
||||
} else {
|
||||
// Multi-monitor setup needs async detection
|
||||
root.detectedScreen = null;
|
||||
root.pendingCallback = callback;
|
||||
screenDetectorLoader.active = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Try compositor-specific focused monitor detection first
|
||||
let screen = CompositorService.getFocusedScreen();
|
||||
|
||||
if (screen) {
|
||||
// Apply the bar check if configured
|
||||
if (!Settings.data.general.allowPanelsOnScreenWithoutBar) {
|
||||
const monitors = Settings.data.bar.monitors || [];
|
||||
const hasBar = monitors.length === 0 || monitors.includes(screen.name);
|
||||
if (!hasBar) {
|
||||
screen = Quickshell.screens[0];
|
||||
}
|
||||
}
|
||||
Logger.d("CurrentScreenDetector", "Using compositor-detected screen:", screen.name);
|
||||
callback(screen);
|
||||
return;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: screenDetectorDebounce
|
||||
running: false
|
||||
interval: 40
|
||||
onTriggered: {
|
||||
Logger.d("CurrentScreenDetector", "Screen debounced to:", root.detectedScreen?.name || "null");
|
||||
// Fallback: Multi-monitor setup needs async detection via invisible PanelWindow
|
||||
root.detectedScreen = null;
|
||||
root.pendingCallback = callback;
|
||||
screenDetectorLoader.active = true;
|
||||
}
|
||||
|
||||
// Execute pending callback if any
|
||||
if (root.pendingCallback) {
|
||||
if (!Settings.data.general.allowPanelsOnScreenWithoutBar) {
|
||||
// If we explicitly disabled panels on screen without bar, check if bar is configured
|
||||
// for this screen, and fallback to primary screen if necessary
|
||||
var monitors = Settings.data.bar.monitors || [];
|
||||
const hasBar = monitors.length === 0 || monitors.includes(root.detectedScreen?.name);
|
||||
if (!hasBar) {
|
||||
root.detectedScreen = Quickshell.screens[0];
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: screenDetectorDebounce
|
||||
running: false
|
||||
interval: 40
|
||||
onTriggered: {
|
||||
Logger.d("CurrentScreenDetector", "Screen debounced to:", root.detectedScreen?.name || "null");
|
||||
|
||||
Logger.d("CurrentScreenDetector", "Executing callback on screen:", root.detectedScreen.name);
|
||||
// Store callback locally and clear pendingCallback first to prevent deadlock
|
||||
// if the callback throws an error
|
||||
var callback = root.pendingCallback;
|
||||
root.pendingCallback = null;
|
||||
try {
|
||||
callback(root.detectedScreen);
|
||||
} catch (e) {
|
||||
Logger.e("CurrentScreenDetector", "Callback failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
screenDetectorLoader.active = false;
|
||||
// Execute pending callback if any
|
||||
if (root.pendingCallback) {
|
||||
if (!Settings.data.general.allowPanelsOnScreenWithoutBar) {
|
||||
// If we explicitly disabled panels on screen without bar, check if bar is configured
|
||||
// for this screen, and fallback to primary screen if necessary
|
||||
var monitors = Settings.data.bar.monitors || [];
|
||||
const hasBar = monitors.length === 0 || monitors.includes(root.detectedScreen?.name);
|
||||
if (!hasBar) {
|
||||
root.detectedScreen = Quickshell.screens[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Invisible dummy PanelWindow to detect which screen should receive the action
|
||||
Loader {
|
||||
id: screenDetectorLoader
|
||||
active: false
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
implicitWidth: 0
|
||||
implicitHeight: 0
|
||||
color: "transparent"
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "noctalia-screen-detector"
|
||||
mask: Region {}
|
||||
|
||||
onScreenChanged: root.screenDetected(screen)
|
||||
}
|
||||
Logger.d("CurrentScreenDetector", "Executing callback on screen:", root.detectedScreen.name);
|
||||
// Store callback locally and clear pendingCallback first to prevent deadlock
|
||||
// if the callback throws an error
|
||||
var callback = root.pendingCallback;
|
||||
root.pendingCallback = null;
|
||||
try {
|
||||
callback(root.detectedScreen);
|
||||
} catch (e) {
|
||||
Logger.e("CurrentScreenDetector", "Callback failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
screenDetectorLoader.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Invisible dummy PanelWindow to detect which screen should receive the action
|
||||
Loader {
|
||||
id: screenDetectorLoader
|
||||
active: false
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
implicitWidth: 0
|
||||
implicitHeight: 0
|
||||
color: "transparent"
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "noctalia-screen-detector"
|
||||
mask: Region {}
|
||||
|
||||
onScreenChanged: root.screenDetected(screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user