Fix TrayMenu crash after display wake. Add checks if screen exists, else set scaling to 1.0
TrayMenu: Replace PopupPanel with NPanel (for better loading & to prevent QS crash) Overview, Background etc: add screen checks, if it doesnt exist set scaling to 1.0
This commit is contained in:
parent
714f6c058f
commit
51f1923e22
9 changed files with 119 additions and 137 deletions
|
|
@ -12,7 +12,7 @@ Variants {
|
|||
|
||||
required property ShellScreen modelData
|
||||
|
||||
active: Settings.isLoaded
|
||||
active: Settings.isLoaded && modelData
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: root
|
||||
|
|
@ -38,7 +38,7 @@ Variants {
|
|||
property real stripesAngle: 0
|
||||
|
||||
// External state management
|
||||
property string servicedWallpaper: WallpaperService.getWallpaper(modelData.name)
|
||||
property string servicedWallpaper: modelData ? WallpaperService.getWallpaper(modelData.name) : ""
|
||||
property string futureWallpaper: ""
|
||||
onServicedWallpaperChanged: {
|
||||
// Set wallpaper immediately on startup
|
||||
|
|
|
|||
|
|
@ -12,11 +12,13 @@ Variants {
|
|||
delegate: Loader {
|
||||
required property ShellScreen modelData
|
||||
|
||||
active: Settings.isLoaded && CompositorService.isNiri
|
||||
active: Settings.isLoaded && CompositorService.isNiri && modelData
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
Component.onCompleted: {
|
||||
Logger.log("Overview", "Loading Overview component for Niri on", modelData.name)
|
||||
if (modelData) {
|
||||
Logger.log("Overview", "Loading Overview component for Niri on", modelData.name)
|
||||
}
|
||||
}
|
||||
|
||||
color: Color.transparent
|
||||
|
|
@ -36,7 +38,7 @@ Variants {
|
|||
id: bgImage
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: WallpaperService.getWallpaper(modelData.name)
|
||||
source: modelData ? WallpaperService.getWallpaper(modelData.name) : ""
|
||||
smooth: true
|
||||
mipmap: false
|
||||
cache: false
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ Variants {
|
|||
id: root
|
||||
|
||||
required property ShellScreen modelData
|
||||
readonly property real scaling: ScalingService.scale(modelData)
|
||||
readonly property real scaling: modelData ? ScalingService.scale(modelData) : 1.0
|
||||
|
||||
active: Settings.isLoaded && modelData ? (Settings.data.bar.monitors.includes(modelData.name)
|
||||
active: Settings.isLoaded && modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name)
|
||||
|| (Settings.data.bar.monitors.length === 0)) : false
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
screen: modelData
|
||||
screen: modelData || null
|
||||
|
||||
WlrLayershell.namespace: "noctalia-bar"
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ Variants {
|
|||
delegate: NWidgetLoader {
|
||||
widgetName: modelData
|
||||
widgetProps: {
|
||||
"screen": screen
|
||||
"screen": root.modelData || null
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ Variants {
|
|||
delegate: NWidgetLoader {
|
||||
widgetName: modelData
|
||||
widgetProps: {
|
||||
"screen": screen
|
||||
"screen": root.modelData || null
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ Variants {
|
|||
delegate: NWidgetLoader {
|
||||
widgetName: modelData
|
||||
widgetProps: {
|
||||
"screen": screen
|
||||
"screen": root.modelData || null
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,26 +6,23 @@ import qs.Commons
|
|||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
PopupWindow {
|
||||
NPanel {
|
||||
id: root
|
||||
|
||||
objectName: "trayMenu"
|
||||
|
||||
panelWidth: 180 * scaling
|
||||
panelHeight: 220 * scaling
|
||||
panelAnchorRight: true
|
||||
|
||||
property QsMenuHandle menu
|
||||
property var anchorItem: null
|
||||
property real anchorX
|
||||
property real anchorY
|
||||
property bool isSubMenu: false
|
||||
property bool isHovered: rootMouseArea.containsMouse
|
||||
property bool isHovered: false
|
||||
|
||||
readonly property int menuWidth: 180
|
||||
|
||||
implicitWidth: menuWidth * scaling
|
||||
|
||||
// Use the content height of the Flickable for implicit height
|
||||
implicitHeight: Math.min(Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2 * scaling))
|
||||
visible: false
|
||||
color: Color.transparent
|
||||
anchor.item: anchorItem
|
||||
anchor.rect.x: anchorX
|
||||
anchor.rect.y: anchorY - (isSubMenu ? 0 : 4)
|
||||
|
||||
function showAt(item, x, y) {
|
||||
if (!item) {
|
||||
|
|
@ -33,27 +30,18 @@ PopupWindow {
|
|||
return
|
||||
}
|
||||
|
||||
if (!opener.children || opener.children.values.length === 0) {
|
||||
//Logger.warn("TrayMenu", "Menu not ready, delaying show")
|
||||
Qt.callLater(() => showAt(item, x, y))
|
||||
return
|
||||
}
|
||||
|
||||
anchorItem = item
|
||||
anchorX = x
|
||||
anchorY = y
|
||||
|
||||
visible = true
|
||||
forceActiveFocus()
|
||||
// Use NPanel's open method instead of PopupWindow's visible
|
||||
open(screen)
|
||||
|
||||
|
||||
// Force update after showing.
|
||||
Qt.callLater(() => {
|
||||
root.anchor.updateAnchor()
|
||||
})
|
||||
}
|
||||
|
||||
function hideMenu() {
|
||||
visible = false
|
||||
close()
|
||||
|
||||
// Clean up all submenus recursively
|
||||
for (var i = 0; i < columnLayout.children.length; i++) {
|
||||
|
|
@ -66,38 +54,46 @@ PopupWindow {
|
|||
}
|
||||
}
|
||||
|
||||
// Full-sized, transparent MouseArea to track the mouse.
|
||||
MouseArea {
|
||||
id: rootMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
Keys.onEscapePressed: root.hideMenu()
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: opener
|
||||
menu: root.menu
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Color.mSurface
|
||||
border.color: Color.mOutline
|
||||
border.width: Math.max(1, Style.borderS * scaling)
|
||||
radius: Style.radiusM * scaling
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
panelContent: Rectangle {
|
||||
color: Color.transparent
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS * scaling
|
||||
contentHeight: columnLayout.implicitHeight
|
||||
interactive: true
|
||||
clip: true
|
||||
|
||||
// Full-sized, transparent MouseArea to track the mouse.
|
||||
MouseArea {
|
||||
id: rootMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: root.isHovered = true
|
||||
onExited: root.isHovered = false
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: opener
|
||||
menu: root.menu
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (menu && opener.children && opener.children.values.length === 0) {
|
||||
// Menu not ready, try again later
|
||||
Qt.callLater(() => {
|
||||
if (opener.children && opener.children.values.length > 0) {
|
||||
// Menu is now ready
|
||||
root.menuItemCount = opener.children.values.length
|
||||
}
|
||||
})
|
||||
} else if (opener.children && opener.children.values.length > 0) {
|
||||
root.menuItemCount = opener.children.values.length
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS * scaling
|
||||
contentHeight: columnLayout.implicitHeight
|
||||
interactive: true
|
||||
clip: true
|
||||
|
||||
// Use a ColumnLayout to handle menu item arrangement
|
||||
ColumnLayout {
|
||||
|
|
@ -206,28 +202,17 @@ PopupWindow {
|
|||
entry.subMenu.destroy()
|
||||
}
|
||||
|
||||
// Need a slight overlap so that menu don't close when moving the mouse to a submenu
|
||||
const submenuWidth = menuWidth * scaling // Assuming a similar width as the parent
|
||||
const overlap = 4 * scaling // A small overlap to bridge the mouse path
|
||||
|
||||
// Check if there's enough space on the right
|
||||
const globalPos = entry.mapToGlobal(0, 0)
|
||||
const openLeft = (globalPos.x + entry.width + submenuWidth > Screen.width)
|
||||
|
||||
// Position with overlap
|
||||
const anchorX = openLeft ? -submenuWidth + overlap : entry.width - overlap
|
||||
|
||||
// Create submenu
|
||||
// Create submenu using the same TrayMenu component
|
||||
entry.subMenu = Qt.createComponent("TrayMenu.qml").createObject(root, {
|
||||
"menu": modelData,
|
||||
"anchorItem": entry,
|
||||
"anchorX": anchorX,
|
||||
"anchorY": 0,
|
||||
"isSubMenu": true
|
||||
})
|
||||
"menu": modelData,
|
||||
"anchorItem": entry,
|
||||
"anchorX": entry.width,
|
||||
"anchorY": 0,
|
||||
"isSubMenu": true
|
||||
})
|
||||
|
||||
if (entry.subMenu) {
|
||||
entry.subMenu.showAt(entry, anchorX, 0)
|
||||
entry.subMenu.open(screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -254,4 +239,5 @@ PopupWindow {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Rectangle {
|
|||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: ScalingService.scale(screen)
|
||||
property real scaling: screen ? ScalingService.scale(screen) : 1.0
|
||||
readonly property real itemSize: 24 * scaling
|
||||
|
||||
visible: SystemTray.items.values.length > 0
|
||||
|
|
@ -80,35 +80,42 @@ Rectangle {
|
|||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
// Close any open menu first
|
||||
trayPanel.close()
|
||||
var trayMenuPanel = PanelService.getPanel("trayMenu")
|
||||
if (trayMenuPanel && trayMenuPanel.active) {
|
||||
trayMenuPanel.close()
|
||||
}
|
||||
|
||||
if (!modelData.onlyMenu) {
|
||||
modelData.activate()
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
// Close any open menu first
|
||||
trayPanel.close()
|
||||
var trayMenuPanel = PanelService.getPanel("trayMenu")
|
||||
if (trayMenuPanel && trayMenuPanel.active) {
|
||||
trayMenuPanel.close()
|
||||
}
|
||||
|
||||
modelData.secondaryActivate && modelData.secondaryActivate()
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
trayTooltip.hide()
|
||||
|
||||
// Close the menu if it was visible
|
||||
if (trayPanel && trayPanel.visible) {
|
||||
trayPanel.close()
|
||||
// Don't open menu if screen is invalid
|
||||
if (!screen || !screen.name) {
|
||||
Logger.warn("Tray", "Cannot open tray menu: invalid screen object")
|
||||
return
|
||||
}
|
||||
|
||||
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
|
||||
trayPanel.open()
|
||||
|
||||
// Anchor the menu to the tray icon item (parent) and position it below the icon
|
||||
const menuX = (width / 2) - (trayMenu.item.width / 2)
|
||||
const menuY = (Style.barHeight * scaling)
|
||||
trayMenu.item.menu = modelData.menu
|
||||
trayMenu.item.showAt(parent, menuX, menuY)
|
||||
if (modelData.hasMenu && modelData.menu) {
|
||||
// Get the tray menu panel from PanelService
|
||||
var trayMenuPanel = PanelService.getPanel("trayMenu")
|
||||
if (trayMenuPanel) {
|
||||
trayMenuPanel.menu = modelData.menu
|
||||
trayMenuPanel.toggle(screen, this)
|
||||
} else {
|
||||
Logger.warn("Tray", "Tray menu panel not found")
|
||||
}
|
||||
} else {
|
||||
Logger.log("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
||||
Logger.log("Tray", "No menu available for", modelData.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,36 +133,5 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: trayPanel
|
||||
anchors.top: true
|
||||
anchors.left: true
|
||||
anchors.right: true
|
||||
anchors.bottom: true
|
||||
visible: false
|
||||
color: Color.transparent
|
||||
screen: screen
|
||||
|
||||
function open() {
|
||||
visible = true
|
||||
|
||||
PanelService.willOpenPanel(trayPanel)
|
||||
}
|
||||
|
||||
function close() {
|
||||
visible = false
|
||||
trayMenu.item.hideMenu()
|
||||
}
|
||||
|
||||
// Clicking outside of the rectangle to close
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: trayPanel.close()
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: trayMenu
|
||||
source: "../Extras/TrayMenu.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Loader {
|
|||
id: lockBgImage
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: WallpaperService.getWallpaper(screen.name)
|
||||
source: screen ? WallpaperService.getWallpaper(screen.name) : ""
|
||||
cache: true
|
||||
smooth: true
|
||||
mipmap: false
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ ColumnLayout {
|
|||
NImageRounded {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginXS * scaling
|
||||
imagePath: WallpaperService.getWallpaper(screen.name)
|
||||
imagePath: screen ? WallpaperService.getWallpaper(screen.name) : ""
|
||||
fallbackIcon: "image"
|
||||
imageRadius: Style.radiusM * scaling
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
property list<string> wallpapersList: WallpaperService.getWallpapersList(screen.name)
|
||||
property list<string> wallpapersList: screen ? WallpaperService.getWallpapersList(screen.name) : []
|
||||
|
||||
NToggle {
|
||||
label: "Assign selection to all monitors"
|
||||
|
|
@ -115,7 +115,7 @@ ColumnLayout {
|
|||
id: wallpaperItem
|
||||
|
||||
property string wallpaperPath: modelData
|
||||
property bool isSelected: wallpaperPath === WallpaperService.getWallpaper(screen.name)
|
||||
property bool isSelected: screen ? (wallpaperPath === WallpaperService.getWallpaper(screen.name)) : false
|
||||
|
||||
width: wallpaperGridView.itemSize
|
||||
height: Math.floor(wallpaperGridView.itemSize * 0.67)
|
||||
|
|
@ -183,7 +183,7 @@ ColumnLayout {
|
|||
onPressed: {
|
||||
if (Settings.data.wallpaper.setWallpaperOnAllMonitors) {
|
||||
WallpaperService.changeWallpaper(undefined, wallpaperPath)
|
||||
} else {
|
||||
} else if (screen) {
|
||||
WallpaperService.changeWallpaper(screen.name, wallpaperPath)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Loader {
|
|||
asynchronous: true
|
||||
|
||||
property ShellScreen screen
|
||||
readonly property real scaling: ScalingService.scale(screen)
|
||||
readonly property real scaling: screen ? ScalingService.scale(screen) : 1.0
|
||||
|
||||
property Component panelContent: null
|
||||
property int panelWidth: 1500
|
||||
|
|
@ -50,6 +50,12 @@ Loader {
|
|||
|
||||
// -----------------------------------------
|
||||
function toggle(aScreen, buttonItem) {
|
||||
// Don't toggle if screen is null or invalid
|
||||
if (!aScreen || !aScreen.name) {
|
||||
Logger.warn("NPanel", "Cannot toggle panel: invalid screen object")
|
||||
return
|
||||
}
|
||||
|
||||
if (!active || isClosing) {
|
||||
open(aScreen, buttonItem)
|
||||
} else {
|
||||
|
|
@ -59,6 +65,12 @@ Loader {
|
|||
|
||||
// -----------------------------------------
|
||||
function open(aScreen, buttonItem) {
|
||||
// Don't open if screen is null or invalid
|
||||
if (!aScreen || !aScreen.name) {
|
||||
Logger.warn("NPanel", "Cannot open panel: invalid screen object")
|
||||
return
|
||||
}
|
||||
|
||||
if (aScreen !== null) {
|
||||
screen = aScreen
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import qs.Commons
|
|||
import qs.Modules.Launcher
|
||||
import qs.Modules.Background
|
||||
import qs.Modules.Bar
|
||||
import qs.Modules.Bar.Extras
|
||||
import qs.Modules.BluetoothPanel
|
||||
import qs.Modules.Calendar
|
||||
import qs.Modules.Dock
|
||||
|
|
@ -99,6 +100,11 @@ ShellRoot {
|
|||
objectName: "archUpdaterPanel"
|
||||
}
|
||||
|
||||
TrayMenu {
|
||||
id: trayMenuPanel
|
||||
objectName: "trayMenu"
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Save a ref. to our lockScreen so we can access it easily
|
||||
PanelService.lockScreen = lockScreen
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue