Simplification
This commit is contained in:
parent
8d494f7799
commit
621713b617
38 changed files with 30 additions and 3062 deletions
|
@ -13,15 +13,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
find_package(Qt5 CONFIG REQUIRED Widgets DBus X11Extras Concurrent Svg LinguistTools QuickControls2)
|
find_package(Qt5 CONFIG REQUIRED Widgets DBus X11Extras Concurrent Svg LinguistTools QuickControls2)
|
||||||
|
|
||||||
find_package(KF5WindowSystem REQUIRED)
|
find_package(KF5WindowSystem REQUIRED)
|
||||||
find_package(dbusmenu-qt5 REQUIRED)
|
|
||||||
find_package(MeuiKit REQUIRED)
|
find_package(MeuiKit REQUIRED)
|
||||||
|
|
||||||
set(SRCS
|
set(SRCS
|
||||||
src/applicationitem.h
|
src/applicationitem.h
|
||||||
src/applicationmodel.cpp
|
src/applicationmodel.cpp
|
||||||
src/battery.cpp
|
|
||||||
src/brightness.cpp
|
|
||||||
src/controlcenterdialog.cpp
|
|
||||||
src/docksettings.cpp
|
src/docksettings.cpp
|
||||||
src/iconthemeimageprovider.cpp
|
src/iconthemeimageprovider.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
@ -30,43 +26,19 @@ set(SRCS
|
||||||
src/systemappitem.cpp
|
src/systemappitem.cpp
|
||||||
src/processprovider.cpp
|
src/processprovider.cpp
|
||||||
src/trashmanager.cpp
|
src/trashmanager.cpp
|
||||||
src/volumemanager.cpp
|
|
||||||
src/utils.cpp
|
src/utils.cpp
|
||||||
src/xwindowinterface.cpp
|
src/xwindowinterface.cpp
|
||||||
src/popupwindow.cpp
|
src/popupwindow.cpp
|
||||||
|
|
||||||
src/appearance.cpp
|
|
||||||
src/fakewindow.cpp
|
src/fakewindow.cpp
|
||||||
src/iconitem.cpp
|
src/iconitem.cpp
|
||||||
src/managedtexturenode.cpp
|
src/managedtexturenode.cpp
|
||||||
|
|
||||||
src/systemtray/statusnotifieritemjob.cpp
|
|
||||||
src/systemtray/statusnotifieritemsource.cpp
|
|
||||||
src/systemtray/systemtraytypes.cpp
|
|
||||||
src/systemtray/systemtraytypedefs.h
|
|
||||||
src/systemtray/systemtraymodel.cpp
|
|
||||||
src/systemtray/statusnotifierwatcher.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(RESOURCES
|
set(RESOURCES
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
set(statusnotifierwatcher_xml src/systemtray/org.kde.StatusNotifierWatcher.xml)
|
|
||||||
qt5_add_dbus_interface(SRCS ${statusnotifierwatcher_xml} statusnotifierwatcher_interface)
|
|
||||||
qt5_add_dbus_interface(SRCS src/systemtray/org.freedesktop.DBus.Properties.xml dbusproperties)
|
|
||||||
|
|
||||||
set(statusnotifieritem_xml src/systemtray/org.kde.StatusNotifierItem.xml)
|
|
||||||
set_source_files_properties(${statusnotifieritem_xml} PROPERTIES
|
|
||||||
NO_NAMESPACE false
|
|
||||||
INCLUDE "src/systemtray/systemtraytypes.h"
|
|
||||||
CLASSNAME OrgKdeStatusNotifierItem
|
|
||||||
)
|
|
||||||
qt5_add_dbus_interface(SRCS ${statusnotifieritem_xml} statusnotifieritem_interface)
|
|
||||||
|
|
||||||
qt5_add_dbus_adaptor(SRCS src/systemtray/org.kde.StatusNotifierWatcher.xml
|
|
||||||
src/systemtray/statusnotifierwatcher.h StatusNotifierWatcher)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SRCS} ${DBUS_SRCS} ${RESOURCES})
|
add_executable(${PROJECT_NAME} ${SRCS} ${DBUS_SRCS} ${RESOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
|
@ -81,7 +53,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
MeuiKit
|
MeuiKit
|
||||||
|
|
||||||
KF5::WindowSystem
|
KF5::WindowSystem
|
||||||
dbusmenu-qt5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB TS_FILES translations/*.ts)
|
file(GLOB TS_FILES translations/*.ts)
|
||||||
|
|
120
qml/CardItem.qml
120
qml/CardItem.qml
|
@ -1,120 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: control
|
|
||||||
|
|
||||||
property bool checked: false
|
|
||||||
property alias icon: _image.source
|
|
||||||
property alias label: _titleLabel.text
|
|
||||||
property alias text: _label.text
|
|
||||||
|
|
||||||
signal clicked
|
|
||||||
|
|
||||||
property var hoverColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.secondBackgroundColor, 2)
|
|
||||||
: Qt.darker(Meui.Theme.secondBackgroundColor, 1.3)
|
|
||||||
property var pressedColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.secondBackgroundColor, 1.8)
|
|
||||||
: Qt.darker(Meui.Theme.secondBackgroundColor, 1.5)
|
|
||||||
|
|
||||||
property var highlightHoverColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.highlightColor, 1.1)
|
|
||||||
: Qt.darker(Meui.Theme.highlightColor, 1.1)
|
|
||||||
property var highlightPressedColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.highlightColor, 1.1)
|
|
||||||
: Qt.darker(Meui.Theme.highlightColor, 1.2)
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: _mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
acceptedButtons: Qt.LeftButton
|
|
||||||
onClicked: control.clicked()
|
|
||||||
|
|
||||||
onPressedChanged: {
|
|
||||||
control.scale = pressed ? 0.95 : 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on scale {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.RoundedRect {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Meui.Theme.bigRadius
|
|
||||||
backgroundOpacity: control.checked ? 0.9 : 0.3
|
|
||||||
animationEnabled: false
|
|
||||||
|
|
||||||
color: {
|
|
||||||
if (control.checked) {
|
|
||||||
if (_mouseArea.pressed)
|
|
||||||
return highlightPressedColor
|
|
||||||
else if (_mouseArea.containsMouse)
|
|
||||||
return highlightHoverColor
|
|
||||||
else
|
|
||||||
return Meui.Theme.highlightColor
|
|
||||||
} else {
|
|
||||||
if (_mouseArea.pressed)
|
|
||||||
return pressedColor
|
|
||||||
else if (_mouseArea.containsMouse)
|
|
||||||
return hoverColor
|
|
||||||
else
|
|
||||||
return Meui.Theme.secondBackgroundColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: root.smallSpacing
|
|
||||||
anchors.rightMargin: root.smallSpacing
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: _image
|
|
||||||
Layout.preferredWidth: control.height * 0.3
|
|
||||||
Layout.preferredHeight: control.height * 0.3
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
asynchronous: true
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
Layout.topMargin: root.largeSpacing
|
|
||||||
|
|
||||||
// ColorOverlay {
|
|
||||||
// anchors.fill: _image
|
|
||||||
// source: _image
|
|
||||||
// color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.disabledTextColor
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: _titleLabel
|
|
||||||
color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
|
|
||||||
Layout.preferredHeight: control.height * 0.15
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: _label
|
|
||||||
color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
|
|
||||||
elide: Label.ElideRight
|
|
||||||
Layout.preferredHeight: control.height * 0.1
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
// Layout.fillWidth: true
|
|
||||||
Layout.bottomMargin: root.largeSpacing
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
|
|
||||||
import Cutefish.Dock 1.0
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
|
|
||||||
StandardItem {
|
|
||||||
id: controlItem
|
|
||||||
|
|
||||||
Layout.preferredWidth: isHorizontal ? controlLayout.implicitWidth + root.largeSpacing * 2 : mainLayout.width * 0.7
|
|
||||||
Layout.preferredHeight: isHorizontal ? mainLayout.height * 0.7 : controlLayout.implicitHeight + root.largeSpacing * 2
|
|
||||||
Layout.rightMargin: isHorizontal ? root.windowRadius ? root.windowRadius / 2 : root.largeSpacing : 0
|
|
||||||
Layout.bottomMargin: isHorizontal ? 0 : root.windowRadius ? root.windowRadius / 2 : root.largeSpacing
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (controlCenter.visible)
|
|
||||||
controlCenter.visible = false
|
|
||||||
else {
|
|
||||||
// 先初始化,用户可能会通过Alt鼠标左键移动位置
|
|
||||||
controlCenter.position = Qt.point(0, 0)
|
|
||||||
|
|
||||||
controlCenter.visible = true
|
|
||||||
controlCenter.position = Qt.point(mapToGlobal(0, 0).x, mapToGlobal(0, 0).y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: controlLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: isHorizontal ? root.smallSpacing : 0
|
|
||||||
anchors.rightMargin: isHorizontal ? root.smallSpacing : 0
|
|
||||||
anchors.topMargin: isHorizontal ? root.smallSpacing : 0
|
|
||||||
anchors.bottomMargin: isHorizontal ? root.smallSpacing : 0
|
|
||||||
columnSpacing: isHorizontal ? root.largeSpacing + root.smallSpacing : 0
|
|
||||||
rowSpacing: isHorizontal ? 0 : root.largeSpacing + root.smallSpacing
|
|
||||||
flow: isHorizontal ? Grid.LeftToRight : Grid.TopToBottom
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: volumeIcon
|
|
||||||
visible: volume.isValid && status === Image.Ready
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + volume.iconName + ".svg"
|
|
||||||
width: root.trayItemSize
|
|
||||||
height: width
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
asynchronous: true
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: wirelessIcon
|
|
||||||
width: root.trayItemSize
|
|
||||||
height: width
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: network.wirelessIconName ? "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + network.wirelessIconName + ".svg" : ""
|
|
||||||
asynchronous: true
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
visible: network.enabled &&
|
|
||||||
network.wirelessEnabled &&
|
|
||||||
network.wirelessConnectionName !== "" &&
|
|
||||||
wirelessIcon.status === Image.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: batteryIcon
|
|
||||||
visible: battery.available && status === Image.Ready
|
|
||||||
height: root.trayItemSize
|
|
||||||
width: height + 6
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + battery.iconSource
|
|
||||||
asynchronous: true
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: timeLabel
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
font.pixelSize: isHorizontal ? controlLayout.height / 3 : controlLayout.width / 5
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 1000
|
|
||||||
repeat: true
|
|
||||||
running: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: {
|
|
||||||
timeLabel.text = new Date().toLocaleTimeString(Qt.locale(), Locale.ShortFormat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,361 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Window 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
|
|
||||||
import Cutefish.Dock 1.0
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
import Cutefish.Accounts 1.0 as Accounts
|
|
||||||
|
|
||||||
ControlCenterDialog {
|
|
||||||
id: control
|
|
||||||
width: 500
|
|
||||||
height: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
|
||||||
|
|
||||||
minimumWidth: 500
|
|
||||||
maximumWidth: 500
|
|
||||||
minimumHeight: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
|
||||||
maximumHeight: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
|
||||||
|
|
||||||
property point position: Qt.point(0, 0)
|
|
||||||
|
|
||||||
onWidthChanged: adjustCorrectLocation()
|
|
||||||
onHeightChanged: adjustCorrectLocation()
|
|
||||||
onPositionChanged: adjustCorrectLocation()
|
|
||||||
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Appearance {
|
|
||||||
id: appearance
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjustCorrectLocation() {
|
|
||||||
var posX = control.position.x
|
|
||||||
var posY = control.position.y
|
|
||||||
|
|
||||||
// left
|
|
||||||
if (posX < 0)
|
|
||||||
posX = Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
// top
|
|
||||||
if (posY < 0)
|
|
||||||
posY = Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
// right
|
|
||||||
if (posX + control.width > Screen.width)
|
|
||||||
posX = Screen.width - control.width - (root.windowRadius ? Meui.Units.largeSpacing : 0)
|
|
||||||
|
|
||||||
// bottom
|
|
||||||
if (posY > control.height > Screen.width)
|
|
||||||
posY = Screen.width - control.width - Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
control.x = posX
|
|
||||||
control.y = posY
|
|
||||||
}
|
|
||||||
|
|
||||||
Brightness {
|
|
||||||
id: brightness
|
|
||||||
}
|
|
||||||
|
|
||||||
Accounts.UserAccount {
|
|
||||||
id: currentUser
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.WindowBlur {
|
|
||||||
view: control
|
|
||||||
geometry: Qt.rect(control.x, control.y, control.width, control.height)
|
|
||||||
windowRadius: _background.radius
|
|
||||||
enabled: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.RoundedRect {
|
|
||||||
id: _background
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: control.height * 0.05
|
|
||||||
color: Meui.Theme.backgroundColor
|
|
||||||
backgroundOpacity: Meui.Theme.darkMode ? 0.3 : 0.4
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.WindowShadow {
|
|
||||||
view: control
|
|
||||||
geometry: Qt.rect(control.x, control.y, control.width, control.height)
|
|
||||||
radius: _background.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: _mainLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Meui.Units.largeSpacing * 2
|
|
||||||
anchors.topMargin: Meui.Units.largeSpacing * 1.5
|
|
||||||
anchors.rightMargin: Meui.Units.largeSpacing * 2
|
|
||||||
anchors.bottomMargin: Meui.Units.largeSpacing
|
|
||||||
spacing: Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: topItem
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 50
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: topItemLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
spacing: Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: userIcon
|
|
||||||
Layout.fillHeight: true
|
|
||||||
width: height
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: currentUser.iconFileName ? "file:///" + currentUser.iconFileName : "image://icontheme/default-user"
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: OpacityMask {
|
|
||||||
maskSource: Item {
|
|
||||||
width: userIcon.width
|
|
||||||
height: userIcon.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: parent.height / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: userLabel
|
|
||||||
text: currentUser.userName
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Label.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: settingsButton
|
|
||||||
implicitWidth: topItem.height * 0.8
|
|
||||||
implicitHeight: topItem.height * 0.8
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + "settings.svg"
|
|
||||||
onLeftButtonClicked: {
|
|
||||||
control.visible = false
|
|
||||||
process.startDetached("cutefish-settings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: shutdownButton
|
|
||||||
implicitWidth: topItem.height * 0.8
|
|
||||||
implicitHeight: topItem.height * 0.8
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + "system-shutdown-symbolic.svg"
|
|
||||||
onLeftButtonClicked: {
|
|
||||||
control.visible = false
|
|
||||||
process.startDetached("cutefish-shutdown")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: controlItem
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 120
|
|
||||||
visible: wirelessItem.visible || bluetoothItem.visible
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
spacing: Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
CardItem {
|
|
||||||
id: wirelessItem
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
|
||||||
icon: Meui.Theme.darkMode || checked ? "qrc:/svg/dark/network-wireless-connected-100.svg"
|
|
||||||
: "qrc:/svg/light/network-wireless-connected-100.svg"
|
|
||||||
visible: network.wirelessHardwareEnabled
|
|
||||||
checked: network.wirelessEnabled
|
|
||||||
label: qsTr("Wi-Fi")
|
|
||||||
text: network.wirelessEnabled ? network.wirelessConnectionName ?
|
|
||||||
network.wirelessConnectionName :
|
|
||||||
qsTr("On") : qsTr("Off")
|
|
||||||
onClicked: network.wirelessEnabled = !network.wirelessEnabled
|
|
||||||
}
|
|
||||||
|
|
||||||
CardItem {
|
|
||||||
id: bluetoothItem
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
|
||||||
icon: Meui.Theme.darkMode || checked ? "qrc:/svg/dark/bluetooth-symbolic.svg"
|
|
||||||
: "qrc:/svg/light/bluetooth-symbolic.svg"
|
|
||||||
checked: false
|
|
||||||
label: qsTr("Bluetooth")
|
|
||||||
text: qsTr("Off")
|
|
||||||
}
|
|
||||||
|
|
||||||
CardItem {
|
|
||||||
id: darkModeItem
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
|
||||||
icon: Meui.Theme.darkMode || checked ? "qrc:/svg/dark/dark-mode.svg"
|
|
||||||
: "qrc:/svg/light/dark-mode.svg"
|
|
||||||
checked: Meui.Theme.darkMode
|
|
||||||
label: qsTr("Dark Mode")
|
|
||||||
text: Meui.Theme.darkMode ? qsTr("On") : qsTr("Off")
|
|
||||||
onClicked: appearance.switchDarkMode(!Meui.Theme.darkMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MprisController {
|
|
||||||
height: 100
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: brightnessItem
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 50
|
|
||||||
visible: brightness.enabled
|
|
||||||
|
|
||||||
Meui.RoundedRect {
|
|
||||||
id: brightnessItemBg
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 0
|
|
||||||
radius: Meui.Theme.bigRadius
|
|
||||||
color: Meui.Theme.backgroundColor
|
|
||||||
backgroundOpacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: brightnessItemBg
|
|
||||||
anchors.margins: Meui.Units.largeSpacing
|
|
||||||
spacing: Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
Image {
|
|
||||||
width: parent.height * 0.6
|
|
||||||
height: parent.height * 0.6
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/brightness.svg"
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
id: brightnessSlider
|
|
||||||
from: 0
|
|
||||||
to: 100
|
|
||||||
stepSize: 1
|
|
||||||
value: brightness.value
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
onMoved: {
|
|
||||||
brightness.setValue(brightnessSlider.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: volumeItem
|
|
||||||
Layout.fillWidth: true
|
|
||||||
height: 50
|
|
||||||
visible: volume.isValid
|
|
||||||
|
|
||||||
Meui.RoundedRect {
|
|
||||||
id: volumeItemBg
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 0
|
|
||||||
radius: Meui.Theme.bigRadius
|
|
||||||
color: Meui.Theme.backgroundColor
|
|
||||||
backgroundOpacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: volumeItemBg
|
|
||||||
anchors.margins: Meui.Units.largeSpacing
|
|
||||||
spacing: Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
Image {
|
|
||||||
width: parent.height * 0.6
|
|
||||||
height: parent.height * 0.6
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/" + volume.iconName + ".svg"
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
id: slider
|
|
||||||
from: 0
|
|
||||||
to: 100
|
|
||||||
stepSize: 1
|
|
||||||
value: volume.volume
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
onValueChanged: {
|
|
||||||
volume.setVolume(value)
|
|
||||||
|
|
||||||
if (volume.isMute && value > 0)
|
|
||||||
volume.setMute(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Label {
|
|
||||||
id: timeLabel
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 1000
|
|
||||||
repeat: true
|
|
||||||
running: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: {
|
|
||||||
timeLabel.text = new Date().toLocaleString(Qt.locale(), Locale.ShortFormat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
StandardItem {
|
|
||||||
width: batteryLayout.implicitWidth + Meui.Units.largeSpacing
|
|
||||||
height: batteryLayout.implicitHeight + Meui.Units.largeSpacing
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
control.visible = false
|
|
||||||
process.startDetached("cutefish-settings", ["-m", "battery"])
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: batteryLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: battery.available
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: batteryIcon
|
|
||||||
width: 22
|
|
||||||
height: 16
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + battery.iconSource
|
|
||||||
asynchronous: true
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: battery.chargePercent + "%"
|
|
||||||
color: Meui.Theme.textColor
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: control
|
|
||||||
|
|
||||||
property url source
|
|
||||||
property real size: 24
|
|
||||||
property string popupText
|
|
||||||
|
|
||||||
signal leftButtonClicked
|
|
||||||
signal rightButtonClicked
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
hoverEnabled: control.visible ? true : false
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (mouse.button === Qt.LeftButton)
|
|
||||||
control.leftButtonClicked()
|
|
||||||
else if (mouse.button === Qt.RightButton)
|
|
||||||
control.rightButtonClicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 1
|
|
||||||
radius: parent.height * 0.2
|
|
||||||
|
|
||||||
color: {
|
|
||||||
if (mouseArea.containsMouse) {
|
|
||||||
if (mouseArea.containsPress)
|
|
||||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.3)
|
|
||||||
else
|
|
||||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: iconImage
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.height * 0.8
|
|
||||||
height: width
|
|
||||||
sourceSize.width: width
|
|
||||||
sourceSize.height: height
|
|
||||||
source: control.source
|
|
||||||
asynchronous: true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
import Cutefish.Mpris 1.0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: control
|
|
||||||
|
|
||||||
visible: available && (_songLabel.text != "" || _artistLabel.text != "")
|
|
||||||
|
|
||||||
property bool available: mprisManager.availableServices.length > 1
|
|
||||||
property bool isPlaying: currentService && mprisManager.playbackStatus === Mpris.Playing
|
|
||||||
property alias currentService: mprisManager.currentService
|
|
||||||
property var artUrlTag: Mpris.metadataToString(Mpris.ArtUrl)
|
|
||||||
property var titleTag: Mpris.metadataToString(Mpris.Title)
|
|
||||||
property var artistTag: Mpris.metadataToString(Mpris.Artist)
|
|
||||||
|
|
||||||
MprisManager {
|
|
||||||
id: mprisManager
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.RoundedRect {
|
|
||||||
id: _background
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 0
|
|
||||||
radius: Meui.Theme.bigRadius
|
|
||||||
color: Meui.Theme.backgroundColor
|
|
||||||
backgroundOpacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: _mainLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: root.largeSpacing
|
|
||||||
anchors.rightMargin: root.largeSpacing * 2
|
|
||||||
spacing: root.largeSpacing
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: artImage
|
|
||||||
Layout.fillHeight: true
|
|
||||||
width: height
|
|
||||||
visible: status === Image.Ready
|
|
||||||
sourceSize: Qt.size(width, height)
|
|
||||||
source: control.available ? (artUrlTag in mprisManager.metadata) ? mprisManager.metadata[artUrlTag].toString() : "" : ""
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: OpacityMask {
|
|
||||||
maskSource: Item {
|
|
||||||
width: artImage.width
|
|
||||||
height: artImage.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Meui.Theme.bigRadius
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: _songLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
visible: _songLabel.text !== ""
|
|
||||||
text: control.available ? (titleTag in mprisManager.metadata) ? mprisManager.metadata[titleTag].toString() : "" : ""
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: _artistLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
visible: _artistLabel.text !== ""
|
|
||||||
text: control.available ? (artistTag in mprisManager.metadata) ? mprisManager.metadata[artistTag].toString() : "" : ""
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: _buttons
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredWidth: _mainLayout.width / 3
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
width: 33
|
|
||||||
height: 33
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-skip-backward-symbolic.svg"
|
|
||||||
onLeftButtonClicked: if (mprisManager.canGoPrevious) mprisManager.previous()
|
|
||||||
visible: control.available ? mprisManager.canGoPrevious : false
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
width: 33
|
|
||||||
height: 33
|
|
||||||
source: control.isPlaying ? "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-playback-pause-symbolic.svg"
|
|
||||||
: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-playback-start-symbolic.svg"
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
visible: mprisManager.canPause || mprisManager.canPlay
|
|
||||||
onLeftButtonClicked:
|
|
||||||
if ((control.isPlaying && mprisManager.canPause) || (!control.isPlaying && mprisManager.canPlay)) {
|
|
||||||
mprisManager.playPause()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
width: 33
|
|
||||||
height: 33
|
|
||||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-skip-forward-symbolic.svg"
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
onLeftButtonClicked: if (mprisManager.canGoNext) mprisManager.next()
|
|
||||||
visible: control.available ? mprisManager.canGoNext : false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
import QtQuick 2.12
|
|
||||||
import QtQuick.Controls 2.12
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
|
|
||||||
import MeuiKit 1.0 as Meui
|
|
||||||
import Cutefish.Dock 1.0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: control
|
|
||||||
|
|
||||||
property var popupText: ""
|
|
||||||
|
|
||||||
signal clicked
|
|
||||||
signal rightClicked
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: _mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (mouse.button == Qt.LeftButton)
|
|
||||||
control.clicked()
|
|
||||||
else if (mouse.button == Qt.RightButton)
|
|
||||||
control.rightClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
onPressed: {
|
|
||||||
popupTips.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
|
||||||
if (containsMouse && control.popupText !== "") {
|
|
||||||
popupTips.popupText = control.popupText
|
|
||||||
|
|
||||||
if (Settings.direction === DockSettings.Left)
|
|
||||||
popupTips.position = Qt.point(root.width + Meui.Units.largeSpacing,
|
|
||||||
control.mapToGlobal(0, 0).y + (control.height / 2 - popupTips.height / 2))
|
|
||||||
else
|
|
||||||
popupTips.position = Qt.point(control.mapToGlobal(0, 0).x + (control.width / 2 - popupTips.width / 2),
|
|
||||||
mainWindow.y - popupTips.height - Meui.Units.smallSpacing / 2)
|
|
||||||
|
|
||||||
popupTips.show()
|
|
||||||
} else {
|
|
||||||
popupTips.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Meui.Theme.smallRadius
|
|
||||||
|
|
||||||
color: {
|
|
||||||
if (_mouseArea.containsMouse) {
|
|
||||||
if (_mouseArea.containsPress)
|
|
||||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.2)
|
|
||||||
else
|
|
||||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return "transparent"
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 125
|
|
||||||
easing.type: Easing.InOutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
145
qml/main.qml
145
qml/main.qml
|
@ -15,43 +15,12 @@ Item {
|
||||||
property real windowRadius: Settings.roundedWindowEnabled ? (Settings.direction === DockSettings.Left) ? root.width * 0.25 : root.height * 0.25
|
property real windowRadius: Settings.roundedWindowEnabled ? (Settings.direction === DockSettings.Left) ? root.width * 0.25 : root.height * 0.25
|
||||||
: 0
|
: 0
|
||||||
property bool isHorizontal: Settings.direction !== DockSettings.Left
|
property bool isHorizontal: Settings.direction !== DockSettings.Left
|
||||||
property var appViewLength: isHorizontal ? appItemView.width : appItemView.height
|
|
||||||
property var appViewHeight: isHorizontal ? appItemView.height : appItemView.width
|
|
||||||
property var trayItemSize: 16
|
|
||||||
property var iconSize: 0
|
|
||||||
|
|
||||||
property real smallSpacing: 4 * Meui.Theme.devicePixelRatio
|
|
||||||
property real largeSpacing: smallSpacing * 2
|
|
||||||
|
|
||||||
DropArea {
|
DropArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: calcIconSizeTimer
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
interval: 10
|
|
||||||
onTriggered: calcIconSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
function calcIconSize() {
|
|
||||||
const appCount = appItemView.count
|
|
||||||
const size = (appViewLength - (appViewLength % appCount)) / appCount
|
|
||||||
const rootHeight = isHorizontal ? root.height : root.width
|
|
||||||
const calcSize = size >= rootHeight ? rootHeight : Math.min(size, rootHeight)
|
|
||||||
root.iconSize = calcSize
|
|
||||||
}
|
|
||||||
|
|
||||||
function delayCalcIconSize() {
|
|
||||||
if (calcIconSizeTimer.running)
|
|
||||||
calcIconSizeTimer.stop()
|
|
||||||
|
|
||||||
calcIconSizeTimer.interval = 100
|
|
||||||
calcIconSizeTimer.restart()
|
|
||||||
}
|
|
||||||
|
|
||||||
Meui.WindowShadow {
|
Meui.WindowShadow {
|
||||||
view: mainWindow
|
view: mainWindow
|
||||||
geometry: Qt.rect(root.x, root.y, root.width, root.height)
|
geometry: Qt.rect(root.x, root.y, root.width, root.height)
|
||||||
|
@ -135,28 +104,10 @@ Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
onCountChanged: root.delayCalcIconSize()
|
|
||||||
|
|
||||||
delegate: AppItem {
|
delegate: AppItem {
|
||||||
id: appItemDelegate
|
id: appItemDelegate
|
||||||
implicitWidth: isHorizontal ? root.iconSize : ListView.view.width
|
implicitWidth: isHorizontal ? appItemView.height : appItemView.width
|
||||||
implicitHeight: isHorizontal ? ListView.view.height : root.iconSize
|
implicitHeight: isHorizontal ? appItemView.height : appItemView.width
|
||||||
|
|
||||||
// Behavior on implicitWidth {
|
|
||||||
// NumberAnimation {
|
|
||||||
// from: root.iconSize
|
|
||||||
// easing.type: Easing.InOutQuad
|
|
||||||
// duration: isHorizontal ? 250 : 0
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Behavior on implicitHeight {
|
|
||||||
// NumberAnimation {
|
|
||||||
// from: root.iconSize
|
|
||||||
// easing.type: Easing.InOutQuad
|
|
||||||
// duration: !isHorizontal ? 250 : 0
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moveDisplaced: Transition {
|
moveDisplaced: Transition {
|
||||||
|
@ -167,82 +118,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: trayView
|
|
||||||
|
|
||||||
property var itemWidth: isHorizontal ? root.trayItemSize + root.largeSpacing * 2 : mainLayout.width * 0.7
|
|
||||||
property var itemHeight: isHorizontal ? mainLayout.height * 0.7 : root.trayItemSize + root.largeSpacing * 2
|
|
||||||
|
|
||||||
Layout.preferredWidth: isHorizontal ? itemWidth * count + count * trayView.spacing : mainLayout.width * 0.7
|
|
||||||
Layout.preferredHeight: isHorizontal ? mainLayout.height * 0.7 : itemHeight * count + count * trayView.spacing
|
|
||||||
Layout.alignment: Qt.AlignCenter
|
|
||||||
|
|
||||||
orientation: isHorizontal ? Qt.Horizontal : Qt.Vertical
|
|
||||||
layoutDirection: Qt.RightToLeft
|
|
||||||
interactive: false
|
|
||||||
model: SystemTrayModel { id: trayModel }
|
|
||||||
spacing: root.smallSpacing / 2
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
onCountChanged: delayCalcIconSize()
|
|
||||||
|
|
||||||
delegate: StandardItem {
|
|
||||||
height: trayView.itemHeight
|
|
||||||
width: trayView.itemWidth
|
|
||||||
|
|
||||||
property bool darkMode: Meui.Theme.darkMode
|
|
||||||
|
|
||||||
onDarkModeChanged: updateTimer.restart()
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: updateTimer
|
|
||||||
interval: 10
|
|
||||||
onTriggered: iconItem.updateIcon()
|
|
||||||
}
|
|
||||||
|
|
||||||
IconItem {
|
|
||||||
id: iconItem
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: root.trayItemSize
|
|
||||||
height: root.trayItemSize
|
|
||||||
source: model.icon ? model.icon : model.iconName
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: trayModel.leftButtonClick(id)
|
|
||||||
onRightClicked: trayModel.rightButtonClick(id)
|
|
||||||
popupText: toolTip ? toolTip : title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: root.smallSpacing
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlCenterItem {
|
|
||||||
onWidthChanged: delayCalcIconSize()
|
|
||||||
onHeightChanged: delayCalcIconSize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlDialog {
|
|
||||||
id: controlCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Volume {
|
|
||||||
id: volume
|
|
||||||
}
|
|
||||||
|
|
||||||
Battery {
|
|
||||||
id: battery
|
|
||||||
}
|
|
||||||
|
|
||||||
NM.ConnectionIcon {
|
|
||||||
id: connectionIconProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
NM.Network {
|
|
||||||
id: network
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -252,20 +127,4 @@ Item {
|
||||||
popupTips.hide()
|
popupTips.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: mainWindow
|
|
||||||
|
|
||||||
function onResizingFished() {
|
|
||||||
root.calcIconSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
function onIconSizeChanged() {
|
|
||||||
root.calcIconSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPositionChanged() {
|
|
||||||
root.delayCalcIconSize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,11 +66,8 @@
|
||||||
<file>svg/dark/minimize_normal.svg</file>
|
<file>svg/dark/minimize_normal.svg</file>
|
||||||
<file>svg/dark/restore_normal.svg</file>
|
<file>svg/dark/restore_normal.svg</file>
|
||||||
<file>svg/dark/system-shutdown-symbolic.svg</file>
|
<file>svg/dark/system-shutdown-symbolic.svg</file>
|
||||||
<file>qml/StandardItem.qml</file>
|
|
||||||
<file>qml/ControlDialog.qml</file>
|
|
||||||
<file>svg/dark/brightness.svg</file>
|
<file>svg/dark/brightness.svg</file>
|
||||||
<file>svg/light/brightness.svg</file>
|
<file>svg/light/brightness.svg</file>
|
||||||
<file>qml/IconButton.qml</file>
|
|
||||||
<file>svg/light/settings.svg</file>
|
<file>svg/light/settings.svg</file>
|
||||||
<file>svg/dark/settings.svg</file>
|
<file>svg/dark/settings.svg</file>
|
||||||
<file>svg/dark/network-wired.svg</file>
|
<file>svg/dark/network-wired.svg</file>
|
||||||
|
@ -87,9 +84,7 @@
|
||||||
<file>svg/light/network-wireless-connected-50.svg</file>
|
<file>svg/light/network-wireless-connected-50.svg</file>
|
||||||
<file>svg/light/network-wireless-connected-75.svg</file>
|
<file>svg/light/network-wireless-connected-75.svg</file>
|
||||||
<file>svg/light/network-wireless-connected-100.svg</file>
|
<file>svg/light/network-wireless-connected-100.svg</file>
|
||||||
<file>qml/CardItem.qml</file>
|
|
||||||
<file>svg/light/bluetooth-symbolic.svg</file>
|
<file>svg/light/bluetooth-symbolic.svg</file>
|
||||||
<file>qml/MprisController.qml</file>
|
|
||||||
<file>svg/dark/media-playback-pause-symbolic.svg</file>
|
<file>svg/dark/media-playback-pause-symbolic.svg</file>
|
||||||
<file>svg/dark/media-playback-start-symbolic.svg</file>
|
<file>svg/dark/media-playback-start-symbolic.svg</file>
|
||||||
<file>svg/dark/media-skip-backward-symbolic.svg</file>
|
<file>svg/dark/media-skip-backward-symbolic.svg</file>
|
||||||
|
@ -98,7 +93,6 @@
|
||||||
<file>svg/light/media-playback-start-symbolic.svg</file>
|
<file>svg/light/media-playback-start-symbolic.svg</file>
|
||||||
<file>svg/light/media-skip-backward-symbolic.svg</file>
|
<file>svg/light/media-skip-backward-symbolic.svg</file>
|
||||||
<file>svg/light/media-skip-forward-symbolic.svg</file>
|
<file>svg/light/media-skip-forward-symbolic.svg</file>
|
||||||
<file>qml/ControlCenterItem.qml</file>
|
|
||||||
<file>svg/light/dark-mode.svg</file>
|
<file>svg/light/dark-mode.svg</file>
|
||||||
<file>svg/dark/dark-mode.svg</file>
|
<file>svg/dark/dark-mode.svg</file>
|
||||||
<file>svg/dark/bluetooth-symbolic.svg</file>
|
<file>svg/dark/bluetooth-symbolic.svg</file>
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 CutefishOS Team.
|
|
||||||
*
|
|
||||||
* Author: revenmartin <revenmartin@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "appearance.h"
|
|
||||||
|
|
||||||
#include <QDBusConnection>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
#include <QDBusReply>
|
|
||||||
#include <QDBusServiceWatcher>
|
|
||||||
#include <QDBusPendingCall>
|
|
||||||
|
|
||||||
Appearance::Appearance(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_interface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus())
|
|
||||||
, m_dockSettings(new QSettings(QSettings::UserScope, "cutefishos", "dock"))
|
|
||||||
, m_dockConfigWacher(new QFileSystemWatcher(this))
|
|
||||||
, m_dockIconSize(0)
|
|
||||||
, m_dockDirection(0)
|
|
||||||
, m_fontPointSize(11)
|
|
||||||
{
|
|
||||||
m_dockIconSize = m_dockSettings->value("IconSize").toInt();
|
|
||||||
m_dockDirection = m_dockSettings->value("Direction").toInt();
|
|
||||||
|
|
||||||
m_dockConfigWacher->addPath(m_dockSettings->fileName());
|
|
||||||
connect(m_dockConfigWacher, &QFileSystemWatcher::fileChanged, this, [=] {
|
|
||||||
m_dockSettings->sync();
|
|
||||||
m_dockIconSize = m_dockSettings->value("IconSize").toInt();
|
|
||||||
m_dockDirection = m_dockSettings->value("Direction").toInt();
|
|
||||||
m_dockConfigWacher->addPath(m_dockSettings->fileName());
|
|
||||||
emit dockIconSizeChanged();
|
|
||||||
emit dockDirectionChanged();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Init
|
|
||||||
if (m_interface.isValid()) {
|
|
||||||
m_fontPointSize = m_interface.property("systemFontPointSize").toInt();
|
|
||||||
|
|
||||||
connect(&m_interface, SIGNAL(darkModeDimsWallpaerChanged()), this, SIGNAL(dimsWallpaperChanged()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::switchDarkMode(bool darkMode)
|
|
||||||
{
|
|
||||||
if (m_interface.isValid()) {
|
|
||||||
m_interface.call("setDarkMode", darkMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Appearance::dimsWallpaper() const
|
|
||||||
{
|
|
||||||
return m_interface.property("darkModeDimsWallpaer").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setDimsWallpaper(bool value)
|
|
||||||
{
|
|
||||||
m_interface.call("setDarkModeDimsWallpaer", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Appearance::dockIconSize() const
|
|
||||||
{
|
|
||||||
return m_dockIconSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setDockIconSize(int dockIconSize)
|
|
||||||
{
|
|
||||||
if (m_dockIconSize == dockIconSize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_dockIconSize = dockIconSize;
|
|
||||||
m_dockSettings->setValue("IconSize", m_dockIconSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Appearance::dockDirection() const
|
|
||||||
{
|
|
||||||
return m_dockDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setDockDirection(int dockDirection)
|
|
||||||
{
|
|
||||||
if (m_dockDirection == dockDirection)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_dockDirection = dockDirection;
|
|
||||||
m_dockSettings->setValue("Direction", m_dockDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setGenericFontFamily(const QString &name)
|
|
||||||
{
|
|
||||||
if (name.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QDBusInterface iface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus(), this);
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setSystemFont", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setFixedFontFamily(const QString &name)
|
|
||||||
{
|
|
||||||
if (name.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QDBusInterface iface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus(), this);
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setSystemFixedFont", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Appearance::fontPointSize() const
|
|
||||||
{
|
|
||||||
return m_fontPointSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setFontPointSize(int fontPointSize)
|
|
||||||
{
|
|
||||||
m_fontPointSize = fontPointSize;
|
|
||||||
|
|
||||||
QDBusInterface iface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus(), this);
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setSystemFontPointSize", m_fontPointSize * 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setAccentColor(int accentColor)
|
|
||||||
{
|
|
||||||
QDBusInterface iface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus(), this);
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setAccentColor", accentColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double Appearance::devicePixelRatio() const
|
|
||||||
{
|
|
||||||
return m_interface.property("devicePixelRatio").toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Appearance::setDevicePixelRatio(double value)
|
|
||||||
{
|
|
||||||
QDBusInterface iface("org.cutefish.Settings",
|
|
||||||
"/Theme",
|
|
||||||
"org.cutefish.Theme",
|
|
||||||
QDBusConnection::sessionBus(), this);
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setDevicePixelRatio", value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 CutefishOS Team.
|
|
||||||
*
|
|
||||||
* Author: revenmartin <revenmartin@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef APPEARANCE_H
|
|
||||||
#define APPEARANCE_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSettings>
|
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
|
|
||||||
class Appearance : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(int dockIconSize READ dockIconSize WRITE setDockIconSize NOTIFY dockIconSizeChanged)
|
|
||||||
Q_PROPERTY(int dockDirection READ dockDirection WRITE setDockDirection NOTIFY dockDirectionChanged)
|
|
||||||
Q_PROPERTY(int fontPointSize READ fontPointSize WRITE setFontPointSize NOTIFY fontPointSizeChanged)
|
|
||||||
Q_PROPERTY(bool dimsWallpaper READ dimsWallpaper WRITE setDimsWallpaper NOTIFY dimsWallpaperChanged)
|
|
||||||
Q_PROPERTY(double devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Appearance(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
Q_INVOKABLE void switchDarkMode(bool darkMode);
|
|
||||||
|
|
||||||
bool dimsWallpaper() const;
|
|
||||||
Q_INVOKABLE void setDimsWallpaper(bool value);
|
|
||||||
|
|
||||||
int dockIconSize() const;
|
|
||||||
Q_INVOKABLE void setDockIconSize(int dockIconSize);
|
|
||||||
|
|
||||||
int dockDirection() const;
|
|
||||||
Q_INVOKABLE void setDockDirection(int dockDirection);
|
|
||||||
|
|
||||||
Q_INVOKABLE void setGenericFontFamily(const QString &name);
|
|
||||||
Q_INVOKABLE void setFixedFontFamily(const QString &name);
|
|
||||||
|
|
||||||
int fontPointSize() const;
|
|
||||||
Q_INVOKABLE void setFontPointSize(int fontPointSize);
|
|
||||||
|
|
||||||
Q_INVOKABLE void setAccentColor(int accentColor);
|
|
||||||
|
|
||||||
double devicePixelRatio() const;
|
|
||||||
Q_INVOKABLE void setDevicePixelRatio(double value);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void dockIconSizeChanged();
|
|
||||||
void dockDirectionChanged();
|
|
||||||
void fontPointSizeChanged();
|
|
||||||
void dimsWallpaperChanged();
|
|
||||||
void devicePixelRatioChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QDBusInterface m_interface;
|
|
||||||
QSettings *m_dockSettings;
|
|
||||||
QFileSystemWatcher *m_dockConfigWacher;
|
|
||||||
|
|
||||||
int m_dockIconSize;
|
|
||||||
int m_dockDirection;
|
|
||||||
int m_fontPointSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // APPEARANCE_H
|
|
130
src/battery.cpp
130
src/battery.cpp
|
@ -1,130 +0,0 @@
|
||||||
#include "battery.h"
|
|
||||||
|
|
||||||
static const QString s_sServer = "org.cutefish.Settings";
|
|
||||||
static const QString s_sPath = "/PrimaryBattery";
|
|
||||||
static const QString s_sInterface = "org.cutefish.PrimaryBattery";
|
|
||||||
|
|
||||||
Battery::Battery(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_upowerInterface("org.freedesktop.UPower",
|
|
||||||
"/org/freedesktop/UPower",
|
|
||||||
"org.freedesktop.UPower",
|
|
||||||
QDBusConnection::systemBus())
|
|
||||||
, m_interface("org.cutefish.Settings",
|
|
||||||
"/PrimaryBattery",
|
|
||||||
"org.cutefish.PrimaryBattery",
|
|
||||||
QDBusConnection::sessionBus())
|
|
||||||
, m_available(false)
|
|
||||||
, m_onBattery(false)
|
|
||||||
{
|
|
||||||
m_available = m_interface.isValid() && !m_interface.lastError().isValid();
|
|
||||||
|
|
||||||
if (m_available) {
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargeStateChanged", this, SLOT(chargeStateChanged(int)));
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargePercentChanged", this, SLOT(chargePercentChanged(int)));
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "lastChargedPercentChanged", this, SLOT(lastChargedPercentChanged()));
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "capacityChanged", this, SLOT(capacityChanged(int)));
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "remainingTimeChanged", this, SLOT(remainingTimeChanged(qlonglong)));
|
|
||||||
|
|
||||||
// Update Icon
|
|
||||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargePercentChanged", this, SLOT(iconSourceChanged()));
|
|
||||||
|
|
||||||
QDBusInterface interface("org.freedesktop.UPower", "/org/freedesktop/UPower",
|
|
||||||
"org.freedesktop.UPower", QDBusConnection::systemBus());
|
|
||||||
|
|
||||||
QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower",
|
|
||||||
"org.freedesktop.DBus.Properties",
|
|
||||||
"PropertiesChanged", this,
|
|
||||||
SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
|
||||||
|
|
||||||
if (interface.isValid()) {
|
|
||||||
m_onBattery = interface.property("OnBattery").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit validChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Battery::available() const
|
|
||||||
{
|
|
||||||
return m_available;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Battery::onBattery() const
|
|
||||||
{
|
|
||||||
return m_onBattery;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Battery::chargeState() const
|
|
||||||
{
|
|
||||||
return m_interface.property("chargeState").toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Battery::chargePercent() const
|
|
||||||
{
|
|
||||||
return m_interface.property("chargePercent").toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Battery::lastChargedPercent() const
|
|
||||||
{
|
|
||||||
return m_interface.property("lastChargedPercent").toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Battery::capacity() const
|
|
||||||
{
|
|
||||||
return m_interface.property("capacity").toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Battery::statusString() const
|
|
||||||
{
|
|
||||||
return m_interface.property("statusString").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Battery::iconSource() const
|
|
||||||
{
|
|
||||||
int percent = this->chargePercent();
|
|
||||||
int range = 0;
|
|
||||||
|
|
||||||
if (percent >= 95)
|
|
||||||
range = 100;
|
|
||||||
else if (percent >= 85)
|
|
||||||
range = 90;
|
|
||||||
else if (percent>= 75)
|
|
||||||
range = 80;
|
|
||||||
else if (percent >= 65)
|
|
||||||
range = 70;
|
|
||||||
else if (percent >= 55)
|
|
||||||
range = 60;
|
|
||||||
else if (percent >= 45)
|
|
||||||
range = 50;
|
|
||||||
else if (percent >= 35)
|
|
||||||
range = 40;
|
|
||||||
else if (percent >= 25)
|
|
||||||
range = 30;
|
|
||||||
else if (percent >= 15)
|
|
||||||
range = 20;
|
|
||||||
else if (percent >= 5)
|
|
||||||
range = 10;
|
|
||||||
else
|
|
||||||
range = 0;
|
|
||||||
|
|
||||||
if (m_onBattery)
|
|
||||||
return QString("battery-level-%1-symbolic.svg").arg(range);
|
|
||||||
|
|
||||||
return QString("battery-level-%1-charging-symbolic.svg").arg(range);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Battery::onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps)
|
|
||||||
{
|
|
||||||
Q_UNUSED(ifaceName);
|
|
||||||
Q_UNUSED(changedProps);
|
|
||||||
Q_UNUSED(invalidatedProps);
|
|
||||||
|
|
||||||
bool onBattery = m_upowerInterface.property("OnBattery").toBool();
|
|
||||||
if (onBattery != m_onBattery) {
|
|
||||||
m_onBattery = onBattery;
|
|
||||||
m_interface.call("refresh");
|
|
||||||
emit onBatteryChanged();
|
|
||||||
emit iconSourceChanged();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
#ifndef BATTERY_H
|
|
||||||
#define BATTERY_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
|
|
||||||
class Battery : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(bool available READ available NOTIFY validChanged)
|
|
||||||
Q_PROPERTY(int chargeState READ chargeState NOTIFY chargeStateChanged)
|
|
||||||
Q_PROPERTY(int chargePercent READ chargePercent NOTIFY chargePercentChanged)
|
|
||||||
Q_PROPERTY(int lastChargedPercent READ lastChargedPercent NOTIFY lastChargedPercentChanged)
|
|
||||||
Q_PROPERTY(int capacity READ capacity NOTIFY capacityChanged)
|
|
||||||
Q_PROPERTY(QString statusString READ statusString NOTIFY remainingTimeChanged)
|
|
||||||
Q_PROPERTY(bool onBattery READ onBattery NOTIFY onBatteryChanged)
|
|
||||||
Q_PROPERTY(QString iconSource READ iconSource NOTIFY iconSourceChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Battery(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
bool available() const;
|
|
||||||
bool onBattery() const;
|
|
||||||
|
|
||||||
int chargeState() const;
|
|
||||||
int chargePercent() const;
|
|
||||||
int lastChargedPercent() const;
|
|
||||||
int capacity() const;
|
|
||||||
QString statusString() const;
|
|
||||||
|
|
||||||
QString iconSource() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void validChanged();
|
|
||||||
void chargeStateChanged(int);
|
|
||||||
void chargePercentChanged(int);
|
|
||||||
void capacityChanged(int);
|
|
||||||
void remainingTimeChanged(qlonglong time);
|
|
||||||
void onBatteryChanged();
|
|
||||||
void lastChargedPercentChanged();
|
|
||||||
void iconSourceChanged();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QDBusInterface m_upowerInterface;
|
|
||||||
QDBusInterface m_interface;
|
|
||||||
bool m_available;
|
|
||||||
bool m_onBattery;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BATTERY_H
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 CutefishOS Team.
|
|
||||||
*
|
|
||||||
* Author: revenmartin <revenmartin@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "brightness.h"
|
|
||||||
|
|
||||||
Brightness::Brightness(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_dbusConnection(QDBusConnection::sessionBus())
|
|
||||||
, m_iface("org.cutefish.Settings",
|
|
||||||
"/Brightness",
|
|
||||||
"org.cutefish.Brightness", m_dbusConnection)
|
|
||||||
, m_value(0)
|
|
||||||
, m_enabled(false)
|
|
||||||
{
|
|
||||||
if (!m_iface.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_value = m_iface.property("brightness").toInt();
|
|
||||||
m_enabled = m_iface.property("brightnessEnabled").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Brightness::setValue(int value)
|
|
||||||
{
|
|
||||||
m_iface.call("setValue", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Brightness::value() const
|
|
||||||
{
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Brightness::enabled() const
|
|
||||||
{
|
|
||||||
return m_enabled;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 CutefishOS Team.
|
|
||||||
*
|
|
||||||
* Author: revenmartin <revenmartin@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BRIGHTNESS_H
|
|
||||||
#define BRIGHTNESS_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
|
|
||||||
class Brightness : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(int value READ value NOTIFY valueChanged)
|
|
||||||
Q_PROPERTY(bool enabled READ enabled CONSTANT)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Brightness(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
Q_INVOKABLE void setValue(int value);
|
|
||||||
|
|
||||||
int value() const;
|
|
||||||
bool enabled() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void valueChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QDBusConnection m_dbusConnection;
|
|
||||||
QDBusInterface m_iface;
|
|
||||||
int m_value;
|
|
||||||
bool m_enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BRIGHTNESS_H
|
|
|
@ -1,25 +0,0 @@
|
||||||
#include "controlcenterdialog.h"
|
|
||||||
#include "xwindowinterface.h"
|
|
||||||
#include <KWindowSystem>
|
|
||||||
|
|
||||||
ControlCenterDialog::ControlCenterDialog(QQuickView *parent)
|
|
||||||
: QQuickView(parent)
|
|
||||||
{
|
|
||||||
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
|
||||||
|
|
||||||
connect(this, &QQuickView::activeChanged, this, [=] {
|
|
||||||
if (!isActive())
|
|
||||||
hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControlCenterDialog::showEvent(QShowEvent *event)
|
|
||||||
{
|
|
||||||
KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher);
|
|
||||||
QQuickView::showEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControlCenterDialog::hideEvent(QHideEvent *event)
|
|
||||||
{
|
|
||||||
QQuickView::hideEvent(event);
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
#ifndef CONTROLCENTERDIALOG_H
|
|
||||||
#define CONTROLCENTERDIALOG_H
|
|
||||||
|
|
||||||
#include <QQuickView>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
class ControlCenterDialog : public QQuickView
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ControlCenterDialog(QQuickView *view = nullptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void showEvent(QShowEvent *event) override;
|
|
||||||
void hideEvent(QHideEvent *event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTROLCENTERDIALOG_H
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -26,12 +26,6 @@
|
||||||
#include "applicationmodel.h"
|
#include "applicationmodel.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include "volumemanager.h"
|
|
||||||
#include "battery.h"
|
|
||||||
#include "brightness.h"
|
|
||||||
#include "controlcenterdialog.h"
|
|
||||||
#include "systemtray/systemtraymodel.h"
|
|
||||||
#include "appearance.h"
|
|
||||||
#include "iconitem.h"
|
#include "iconitem.h"
|
||||||
#include "popupwindow.h"
|
#include "popupwindow.h"
|
||||||
|
|
||||||
|
@ -41,12 +35,6 @@ int main(int argc, char *argv[])
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
qmlRegisterType<DockSettings>("Cutefish.Dock", 1, 0, "DockSettings");
|
qmlRegisterType<DockSettings>("Cutefish.Dock", 1, 0, "DockSettings");
|
||||||
qmlRegisterType<VolumeManager>("Cutefish.Dock", 1, 0, "Volume");
|
|
||||||
qmlRegisterType<Battery>("Cutefish.Dock", 1, 0, "Battery");
|
|
||||||
qmlRegisterType<Brightness>("Cutefish.Dock", 1, 0, "Brightness");
|
|
||||||
qmlRegisterType<ControlCenterDialog>("Cutefish.Dock", 1, 0, "ControlCenterDialog");
|
|
||||||
qmlRegisterType<SystemTrayModel>("Cutefish.Dock", 1, 0, "SystemTrayModel");
|
|
||||||
qmlRegisterType<Appearance>("Cutefish.Dock", 1, 0, "Appearance");
|
|
||||||
qmlRegisterType<IconItem>("Cutefish.Dock", 1, 0, "IconItem");
|
qmlRegisterType<IconItem>("Cutefish.Dock", 1, 0, "IconItem");
|
||||||
qmlRegisterType<PopupWindow>("Cutefish.Dock", 1, 0, "PopupWindow");
|
qmlRegisterType<PopupWindow>("Cutefish.Dock", 1, 0, "PopupWindow");
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ MainWindow::MainWindow(QQuickView *parent)
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_settings, &DockSettings::roundedWindowEnabledChanged, this, &MainWindow::resizeWindow);
|
connect(m_appModel, &ApplicationModel::countChanged, this, &MainWindow::resizeWindow);
|
||||||
|
|
||||||
connect(m_settings, &DockSettings::directionChanged, this, &MainWindow::onPositionChanged);
|
connect(m_settings, &DockSettings::directionChanged, this, &MainWindow::onPositionChanged);
|
||||||
connect(m_settings, &DockSettings::iconSizeChanged, this, &MainWindow::onIconSizeChanged);
|
connect(m_settings, &DockSettings::iconSizeChanged, this, &MainWindow::onIconSizeChanged);
|
||||||
|
@ -85,32 +85,31 @@ QRect MainWindow::windowRect() const
|
||||||
QSize newSize(0, 0);
|
QSize newSize(0, 0);
|
||||||
QPoint position(0, 0);
|
QPoint position(0, 0);
|
||||||
|
|
||||||
|
const int maxLength = (m_settings->direction() == DockSettings::Left) ?
|
||||||
|
screenGeometry.height() - m_settings->edgeMargins() / 2:
|
||||||
|
screenGeometry.width() - m_settings->edgeMargins() / 2;
|
||||||
|
|
||||||
|
int appCount = m_appModel->rowCount();
|
||||||
|
int iconSize = m_settings->iconSize();
|
||||||
|
int length = appCount * iconSize;
|
||||||
|
|
||||||
|
if (length > maxLength) {
|
||||||
|
iconSize = (maxLength - (maxLength % appCount)) / appCount;
|
||||||
|
length = appCount * iconSize;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_settings->direction()) {
|
switch (m_settings->direction()) {
|
||||||
case DockSettings::Left:
|
case DockSettings::Left:
|
||||||
if (m_settings->roundedWindowEnabled()) {
|
newSize = QSize(iconSize, length);
|
||||||
newSize = QSize(m_settings->iconSize(), screenGeometry.height() - m_settings->edgeMargins());
|
position = { screenGeometry.x() + DockSettings::self()->edgeMargins() / 2,
|
||||||
position = { screenGeometry.x() + DockSettings::self()->edgeMargins() / 2,
|
screenGeometry.y() };
|
||||||
(screenGeometry.height() - newSize.height()) / 2
|
position.setY((screenGeometry.height() - newSize.height()) / 2);
|
||||||
};
|
|
||||||
} else {
|
|
||||||
newSize = QSize(m_settings->iconSize(), screenGeometry.height());
|
|
||||||
position = { screenGeometry.x(), (screenGeometry.height() - newSize.height()) / 2 };
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case DockSettings::Bottom:
|
case DockSettings::Bottom:
|
||||||
if (m_settings->roundedWindowEnabled()) {
|
newSize = QSize(length, iconSize);
|
||||||
newSize = QSize(screenGeometry.width() - DockSettings::self()->edgeMargins(), m_settings->iconSize());
|
position = { screenGeometry.x(),
|
||||||
position = { (screenGeometry.width() - newSize.width()) / 2,
|
screenGeometry.y() + screenGeometry.height() - newSize.height() - DockSettings::self()->edgeMargins() / 2};
|
||||||
screenGeometry.y() + screenGeometry.height() - newSize.height()
|
position.setX((screenGeometry.width() - newSize.width()) / 2);
|
||||||
- DockSettings::self()->edgeMargins() / 2
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
newSize = QSize(screenGeometry.width(), m_settings->iconSize());
|
|
||||||
position = { screenGeometry.x(),
|
|
||||||
screenGeometry.y() + screenGeometry.height() - newSize.height()
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
set(TRAY_SRCS
|
|
||||||
statusnotifieritemjob.cpp
|
|
||||||
statusnotifieritemsource.cpp
|
|
||||||
systemtraytypes.cpp
|
|
||||||
systemtraytypedefs.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(statusnotifierwatcher_xml org.kde.StatusNotifierWatcher.xml)
|
|
||||||
qt5_add_dbus_interface(SRCS ${statusnotifierwatcher_xml} statusnotifierwatcher_interface)
|
|
||||||
qt5_add_dbus_interface(SRCS org.freedesktop.DBus.Properties.xml dbusproperties)
|
|
||||||
|
|
||||||
set(statusnotifieritem_xml org.kde.StatusNotifierItem.xml)
|
|
||||||
set_source_files_properties(${statusnotifieritem_xml} PROPERTIES
|
|
||||||
NO_NAMESPACE false
|
|
||||||
INCLUDE "systemtraytypes.h"
|
|
||||||
CLASSNAME OrgKdeStatusNotifierItem
|
|
||||||
)
|
|
||||||
qt5_add_dbus_interface(SRCS ${statusnotifieritem_xml} statusnotifieritem_interface)
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<node>
|
|
||||||
<interface name="org.freedesktop.DBus.Properties">
|
|
||||||
<method name="Get">
|
|
||||||
<arg type="s" name="interface_name" direction="in"/>
|
|
||||||
<arg type="s" name="property_name" direction="in"/>
|
|
||||||
<arg type="v" name="value" direction="out"/>
|
|
||||||
</method>
|
|
||||||
<method name="GetAll">
|
|
||||||
<arg type="s" name="interface_name" direction="in"/>
|
|
||||||
<arg type="a{sv}" name="properties" direction="out"/>
|
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
|
||||||
</method>
|
|
||||||
<method name="Set">
|
|
||||||
<arg type="s" name="interface_name" direction="in"/>
|
|
||||||
<arg type="s" name="property_name" direction="in"/>
|
|
||||||
<arg type="v" name="value" direction="in"/>
|
|
||||||
</method>
|
|
||||||
<signal name="PropertiesChanged">
|
|
||||||
<arg type="s" name="interface_name"/>
|
|
||||||
<arg type="a{sv}" name="changed_properties"/>
|
|
||||||
<arg type="as" name="invalidated_properties"/>
|
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
|
|
||||||
</signal>
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
||||||
<!-- vim:set sw=2 sts=2 et ft=xml: -->
|
|
|
@ -1,96 +0,0 @@
|
||||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
|
||||||
<node>
|
|
||||||
<interface name="org.kde.StatusNotifierItem">
|
|
||||||
|
|
||||||
<property name="Category" type="s" access="read"/>
|
|
||||||
<property name="Id" type="s" access="read"/>
|
|
||||||
<property name="Title" type="s" access="read"/>
|
|
||||||
<property name="Status" type="s" access="read"/>
|
|
||||||
<property name="WindowId" type="i" access="read"/>
|
|
||||||
|
|
||||||
<!-- An additional path to add to the theme search path to find the icons specified above. -->
|
|
||||||
<!-- <property name="IconThemePath" type="s" access="read"/> -->
|
|
||||||
<!-- <property name="Menu" type="o" access="read"/> -->
|
|
||||||
<property name="ItemIsMenu" type="b" access="read"/>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- main icon -->
|
|
||||||
<!-- names are preferred over pixmaps -->
|
|
||||||
<!-- <property name="IconName" type="s" access="read"/> -->
|
|
||||||
|
|
||||||
<!--struct containing width, height and image data-->
|
|
||||||
<property name="IconPixmap" type="(iiay)" access="read">
|
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- <property name="OverlayIconName" type="s" access="read"/> -->
|
|
||||||
|
|
||||||
<!-- <property name="OverlayIconPixmap" type="(iiay)" access="read"> -->
|
|
||||||
<!-- <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> -->
|
|
||||||
<!-- </property> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Requesting attention icon -->
|
|
||||||
<!-- <property name="AttentionIconName" type="s" access="read"/> -->
|
|
||||||
|
|
||||||
<!--same definition as image-->
|
|
||||||
<!-- <property name="AttentionIconPixmap" type="(iiay)" access="read"> -->
|
|
||||||
<!-- <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> -->
|
|
||||||
<!-- </property> -->
|
|
||||||
|
|
||||||
<!-- <property name="AttentionMovieName" type="s" access="read"/> -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- tooltip data -->
|
|
||||||
|
|
||||||
<!--(iiay) is an image-->
|
|
||||||
<!-- <property name="ToolTip" type="(s(iiay)ss)" access="read"> -->
|
|
||||||
<!-- <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusToolTipStruct"/> -->
|
|
||||||
<!-- </property> -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- interaction: the systemtray wants the application to do something -->
|
|
||||||
<method name="ContextMenu">
|
|
||||||
<!-- we're passing the coordinates of the icon, so the app knows where to put the popup window -->
|
|
||||||
<arg name="x" type="i" direction="in"/>
|
|
||||||
<arg name="y" type="i" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="Activate">
|
|
||||||
<arg name="x" type="i" direction="in"/>
|
|
||||||
<arg name="y" type="i" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="SecondaryActivate">
|
|
||||||
<arg name="x" type="i" direction="in"/>
|
|
||||||
<arg name="y" type="i" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="Scroll">
|
|
||||||
<arg name="delta" type="i" direction="in"/>
|
|
||||||
<arg name="orientation" type="s" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- Signals: the client wants to change something in the status-->
|
|
||||||
<signal name="NewTitle">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="NewIcon">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="NewAttentionIcon">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="NewOverlayIcon">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="NewToolTip">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="NewStatus">
|
|
||||||
<arg name="status" type="s"/>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
|
@ -1,42 +0,0 @@
|
||||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
|
||||||
<node>
|
|
||||||
<interface name="org.kde.StatusNotifierWatcher">
|
|
||||||
|
|
||||||
<!-- methods -->
|
|
||||||
<method name="RegisterStatusNotifierItem">
|
|
||||||
<arg name="service" type="s" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="RegisterStatusNotifierHost">
|
|
||||||
<arg name="service" type="s" direction="in"/>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- properties -->
|
|
||||||
|
|
||||||
<property name="RegisteredStatusNotifierItems" type="as" access="read">
|
|
||||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QStringList"/>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="IsStatusNotifierHostRegistered" type="b" access="read"/>
|
|
||||||
|
|
||||||
<property name="ProtocolVersion" type="i" access="read"/>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- signals -->
|
|
||||||
|
|
||||||
<signal name="StatusNotifierItemRegistered">
|
|
||||||
<arg type="s"/>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="StatusNotifierItemUnregistered">
|
|
||||||
<arg type="s"/>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="StatusNotifierHostRegistered">
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<signal name="StatusNotifierHostUnregistered">
|
|
||||||
</signal>
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
|
@ -1,25 +0,0 @@
|
||||||
#include "statusnotifieritemjob.h"
|
|
||||||
|
|
||||||
StatusNotifierItemJob::StatusNotifierItemJob(StatusNotifierItemSource *source, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_source(source)
|
|
||||||
{
|
|
||||||
// Queue connection, so that all 'deleteLater' are performed before we use updated menu.
|
|
||||||
connect(source, SIGNAL(contextMenuReady(QMenu *)), this, SLOT(contextMenuReady(QMenu *)), Qt::QueuedConnection);
|
|
||||||
connect(source, &StatusNotifierItemSource::activateResult, this, &StatusNotifierItemJob::activateCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemJob::start()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemJob::activateCallback(bool success)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemJob::contextMenuReady(QMenu *menu)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef STATUSNOTIFIERITEMJOB_H
|
|
||||||
#define STATUSNOTIFIERITEMJOB_H
|
|
||||||
|
|
||||||
#include <QThread>
|
|
||||||
#include <QMenu>
|
|
||||||
|
|
||||||
#include "statusnotifieritemsource.h"
|
|
||||||
|
|
||||||
class StatusNotifierItemJob : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit StatusNotifierItemJob(StatusNotifierItemSource *source, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void start();
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void activateCallback(bool success);
|
|
||||||
void contextMenuReady(QMenu *menu);
|
|
||||||
|
|
||||||
private:
|
|
||||||
StatusNotifierItemSource *m_source;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // STATUSNOTIFIERITEMJOB_H
|
|
|
@ -1,355 +0,0 @@
|
||||||
#include "statusnotifieritemsource.h"
|
|
||||||
#include "systemtraytypes.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <dbusmenuimporter.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
class MenuImporter : public DBusMenuImporter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using DBusMenuImporter::DBusMenuImporter;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QIcon iconForName(const QString & name) override {
|
|
||||||
return QIcon::fromTheme(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
StatusNotifierItemSource::StatusNotifierItemSource(const QString ¬ifierItemId, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_menuImporter(nullptr)
|
|
||||||
, m_refreshing(false)
|
|
||||||
, m_needsReRefreshing(false)
|
|
||||||
, m_titleUpdate(true)
|
|
||||||
, m_iconUpdate(true)
|
|
||||||
, m_tooltipUpdate(true)
|
|
||||||
, m_statusUpdate(true)
|
|
||||||
, m_id(notifierItemId)
|
|
||||||
{
|
|
||||||
setObjectName(notifierItemId);
|
|
||||||
|
|
||||||
qDBusRegisterMetaType<KDbusImageStruct>();
|
|
||||||
qDBusRegisterMetaType<KDbusImageVector>();
|
|
||||||
qDBusRegisterMetaType<KDbusToolTipStruct>();
|
|
||||||
|
|
||||||
m_name = notifierItemId;
|
|
||||||
|
|
||||||
int slash = notifierItemId.indexOf('/');
|
|
||||||
if (slash == -1) {
|
|
||||||
qWarning() << "Invalid notifierItemId:" << notifierItemId;
|
|
||||||
m_valid = false;
|
|
||||||
m_statusNotifierItemInterface = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString service = notifierItemId.left(slash);
|
|
||||||
QString path = notifierItemId.mid(slash);
|
|
||||||
|
|
||||||
m_statusNotifierItemInterface = new org::kde::StatusNotifierItem(service, path, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
m_refreshTimer.setSingleShot(true);
|
|
||||||
m_refreshTimer.setInterval(10);
|
|
||||||
connect(&m_refreshTimer, &QTimer::timeout, this, &StatusNotifierItemSource::performRefresh);
|
|
||||||
|
|
||||||
m_valid = !service.isEmpty() && m_statusNotifierItemInterface->isValid();
|
|
||||||
|
|
||||||
if (m_valid) {
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewTitle, this, &StatusNotifierItemSource::refreshTitle);
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewIcon, this, &StatusNotifierItemSource::refreshIcons);
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewAttentionIcon, this, &StatusNotifierItemSource::refreshIcons);
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewOverlayIcon, this, &StatusNotifierItemSource::refreshIcons);
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewToolTip, this, &StatusNotifierItemSource::refreshToolTip);
|
|
||||||
connect(m_statusNotifierItemInterface, &OrgKdeStatusNotifierItem::NewStatus, this, &StatusNotifierItemSource::syncStatus);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusNotifierItemSource::~StatusNotifierItemSource()
|
|
||||||
{
|
|
||||||
delete m_statusNotifierItemInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StatusNotifierItemSource::id() const
|
|
||||||
{
|
|
||||||
return m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StatusNotifierItemSource::title() const
|
|
||||||
{
|
|
||||||
return m_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StatusNotifierItemSource::tooltip() const
|
|
||||||
{
|
|
||||||
return m_tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StatusNotifierItemSource::subtitle() const
|
|
||||||
{
|
|
||||||
return m_subTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString StatusNotifierItemSource::iconName() const
|
|
||||||
{
|
|
||||||
return m_iconName;
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon StatusNotifierItemSource::icon() const
|
|
||||||
{
|
|
||||||
return m_icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::activate(int x, int y)
|
|
||||||
{
|
|
||||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
|
||||||
QDBusMessage message = QDBusMessage::createMethodCall(m_statusNotifierItemInterface->service(),
|
|
||||||
m_statusNotifierItemInterface->path(),
|
|
||||||
m_statusNotifierItemInterface->interface(),
|
|
||||||
QStringLiteral("Activate"));
|
|
||||||
|
|
||||||
message << x << y;
|
|
||||||
QDBusPendingCall call = m_statusNotifierItemInterface->connection().asyncCall(message);
|
|
||||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
|
||||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, &StatusNotifierItemSource::activateCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::secondaryActivate(int x, int y)
|
|
||||||
{
|
|
||||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
|
||||||
m_statusNotifierItemInterface->call(QDBus::NoBlock, QStringLiteral("SecondaryActivate"), x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::scroll(int delta, const QString &direction)
|
|
||||||
{
|
|
||||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
|
||||||
m_statusNotifierItemInterface->call(QDBus::NoBlock, QStringLiteral("Scroll"), delta, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::contextMenu(int x, int y)
|
|
||||||
{
|
|
||||||
if (m_menuImporter) {
|
|
||||||
m_menuImporter->updateMenu();
|
|
||||||
|
|
||||||
// Popup menu
|
|
||||||
if (m_menuImporter->menu()) {
|
|
||||||
m_menuImporter->menu()->popup(QPoint(x, y));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << "Could not find DBusMenu interface, falling back to calling ContextMenu()";
|
|
||||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
|
||||||
m_statusNotifierItemInterface->call(QDBus::NoBlock, QStringLiteral("ContextMenu"), x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::contextMenuReady()
|
|
||||||
{
|
|
||||||
emit contextMenuReady(m_menuImporter->menu());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::refreshTitle()
|
|
||||||
{
|
|
||||||
m_titleUpdate = true;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::refreshIcons()
|
|
||||||
{
|
|
||||||
m_iconUpdate = true;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::refreshToolTip()
|
|
||||||
{
|
|
||||||
m_tooltipUpdate = true;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::refresh()
|
|
||||||
{
|
|
||||||
if (!m_refreshTimer.isActive()) {
|
|
||||||
m_refreshTimer.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::performRefresh()
|
|
||||||
{
|
|
||||||
if (m_refreshing) {
|
|
||||||
m_needsReRefreshing = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_refreshing = true;
|
|
||||||
QDBusMessage message = QDBusMessage::createMethodCall(m_statusNotifierItemInterface->service(),
|
|
||||||
m_statusNotifierItemInterface->path(),
|
|
||||||
QStringLiteral("org.freedesktop.DBus.Properties"),
|
|
||||||
QStringLiteral("GetAll"));
|
|
||||||
|
|
||||||
message << m_statusNotifierItemInterface->interface();
|
|
||||||
QDBusPendingCall call = m_statusNotifierItemInterface->connection().asyncCall(message);
|
|
||||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
|
||||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, &StatusNotifierItemSource::refreshCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::syncStatus(QString)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::refreshCallback(QDBusPendingCallWatcher *call)
|
|
||||||
{
|
|
||||||
m_refreshing = false;
|
|
||||||
if (m_needsReRefreshing) {
|
|
||||||
m_needsReRefreshing = false;
|
|
||||||
performRefresh();
|
|
||||||
call->deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDBusPendingReply<QVariantMap> reply = *call;
|
|
||||||
if (reply.isError()) {
|
|
||||||
m_valid = false;
|
|
||||||
} else {
|
|
||||||
QVariantMap properties = reply.argumentAt<0>();
|
|
||||||
QString path = properties[QStringLiteral("IconThemePath")].toString();
|
|
||||||
|
|
||||||
m_title = properties[QStringLiteral("Title")].toString();
|
|
||||||
m_iconName = properties[QStringLiteral("IconName")].toString();
|
|
||||||
|
|
||||||
// ToolTip
|
|
||||||
KDbusToolTipStruct toolTip;
|
|
||||||
properties[QStringLiteral("ToolTip")].value<QDBusArgument>() >> toolTip;
|
|
||||||
m_tooltip = toolTip.title;
|
|
||||||
|
|
||||||
// Icon
|
|
||||||
KDbusImageVector image;
|
|
||||||
properties[QStringLiteral("IconPixmap")].value<QDBusArgument>() >> image;
|
|
||||||
if (!image.isEmpty()) {
|
|
||||||
m_icon = imageVectorToPixmap(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
// QString newTitle;
|
|
||||||
// QString newIconName;
|
|
||||||
// QString newToolTip;
|
|
||||||
|
|
||||||
// QString overlayIconName = properties[QStringLiteral("OverlayIconName")].toString();
|
|
||||||
// QString iconName = properties[QStringLiteral("IconName")].toString();
|
|
||||||
|
|
||||||
// bool changed = false;
|
|
||||||
|
|
||||||
// newTitle = properties[QStringLiteral("Title")].toString();
|
|
||||||
|
|
||||||
// if (!overlayIconName.isEmpty())
|
|
||||||
// newIconName = iconName;
|
|
||||||
// if (!iconName.isEmpty())
|
|
||||||
// newIconName = iconName;
|
|
||||||
|
|
||||||
// KDbusToolTipStruct toolTip;
|
|
||||||
// properties[QStringLiteral("ToolTip")].value<QDBusArgument>() >> toolTip;
|
|
||||||
// // newToolTip = !toolTip.title.isEmpty() ? toolTip.title : toolTip.subTitle;
|
|
||||||
|
|
||||||
// if (newTitle != m_title) {
|
|
||||||
// m_title = newTitle;
|
|
||||||
// changed = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (newIconName != m_iconName) {
|
|
||||||
// m_iconName = iconName;
|
|
||||||
// changed = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (newToolTip != m_tooltip) {
|
|
||||||
// m_tooltip = newToolTip;
|
|
||||||
// changed = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Icon
|
|
||||||
// KDbusImageVector image;
|
|
||||||
// properties[QStringLiteral("AttentionIconPixmap")].value<QDBusArgument>() >> image;
|
|
||||||
// if (!image.isEmpty()) {
|
|
||||||
// m_icon = imageVectorToPixmap(image);
|
|
||||||
// changed = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// properties[QStringLiteral("IconPixmap")].value<QDBusArgument>() >> image;
|
|
||||||
// if (!image.isEmpty()) {
|
|
||||||
// m_icon = imageVectorToPixmap(image);
|
|
||||||
// changed = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Menu
|
|
||||||
if (!m_menuImporter) {
|
|
||||||
QString menuObjectPath = properties[QStringLiteral("Menu")].value<QDBusObjectPath>().path();
|
|
||||||
if (!menuObjectPath.isEmpty()) {
|
|
||||||
if (menuObjectPath.startsWith(QLatin1String("/NO_DBUSMENU"))) {
|
|
||||||
// This is a hack to make it possible to disable DBusMenu in an
|
|
||||||
// application. The string "/NO_DBUSMENU" must be the same as in
|
|
||||||
// KStatusNotifierItem::setContextMenu().
|
|
||||||
qWarning() << "DBusMenu disabled for this application";
|
|
||||||
} else {
|
|
||||||
m_menuImporter = new MenuImporter(m_statusNotifierItemInterface->service(),
|
|
||||||
menuObjectPath, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// qDebug() << newTitle << newIconName << newToolTip << image.isEmpty();
|
|
||||||
|
|
||||||
emit updated(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
call->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierItemSource::activateCallback(QDBusPendingCallWatcher *call)
|
|
||||||
{
|
|
||||||
QDBusPendingReply<void> reply = *call;
|
|
||||||
emit activateResult(!reply.isError());
|
|
||||||
call->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap StatusNotifierItemSource::KDbusImageStructToPixmap(const KDbusImageStruct &image) const
|
|
||||||
{
|
|
||||||
// swap from network byte order if we are little endian
|
|
||||||
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
|
|
||||||
uint *uintBuf = (uint *)image.data.data();
|
|
||||||
for (uint i = 0; i < image.data.size() / sizeof(uint); ++i) {
|
|
||||||
*uintBuf = ntohl(*uintBuf);
|
|
||||||
++uintBuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (image.width == 0 || image.height == 0) {
|
|
||||||
return QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid a deep copy of the image data
|
|
||||||
// we need to keep a reference to the image.data alive for the lifespan of the image, even if the image is copied
|
|
||||||
// we create a new QByteArray with a shallow copy of the original data on the heap, then delete this in the QImage cleanup
|
|
||||||
auto dataRef = new QByteArray(image.data);
|
|
||||||
|
|
||||||
QImage iconImage(
|
|
||||||
reinterpret_cast<const uchar *>(dataRef->data()),
|
|
||||||
image.width,
|
|
||||||
image.height,
|
|
||||||
QImage::Format_ARGB32,
|
|
||||||
[](void *ptr) {
|
|
||||||
delete static_cast<QByteArray *>(ptr);
|
|
||||||
},
|
|
||||||
dataRef);
|
|
||||||
return QPixmap::fromImage(iconImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon StatusNotifierItemSource::imageVectorToPixmap(const KDbusImageVector &vector) const
|
|
||||||
{
|
|
||||||
QIcon icon;
|
|
||||||
|
|
||||||
for (int i = 0; i < vector.size(); ++i) {
|
|
||||||
icon.addPixmap(KDbusImageStructToPixmap(vector[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
#ifndef STATUSNOTIFIERITEMSOURCE_H
|
|
||||||
#define STATUSNOTIFIERITEMSOURCE_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QDBusPendingCallWatcher>
|
|
||||||
|
|
||||||
#include "statusnotifieritem_interface.h"
|
|
||||||
|
|
||||||
class DBusMenuImporter;
|
|
||||||
class StatusNotifierItemSource : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit StatusNotifierItemSource(const QString &service, QObject *parent = nullptr);
|
|
||||||
~StatusNotifierItemSource();
|
|
||||||
|
|
||||||
QString id() const;
|
|
||||||
QString title() const;
|
|
||||||
QString tooltip() const;
|
|
||||||
QString subtitle() const;
|
|
||||||
QString iconName() const;
|
|
||||||
QIcon icon() const;
|
|
||||||
|
|
||||||
void activate(int x, int y);
|
|
||||||
void secondaryActivate(int x, int y);
|
|
||||||
void scroll(int delta, const QString &direction);
|
|
||||||
void contextMenu(int x, int y);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void contextMenuReady(QMenu *menu);
|
|
||||||
void activateResult(bool success);
|
|
||||||
void updated(StatusNotifierItemSource *);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void contextMenuReady();
|
|
||||||
void refreshTitle();
|
|
||||||
void refreshIcons();
|
|
||||||
void refreshToolTip();
|
|
||||||
void refresh();
|
|
||||||
void performRefresh();
|
|
||||||
void syncStatus(QString);
|
|
||||||
void refreshCallback(QDBusPendingCallWatcher *);
|
|
||||||
void activateCallback(QDBusPendingCallWatcher *);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPixmap KDbusImageStructToPixmap(const KDbusImageStruct &image) const;
|
|
||||||
QIcon imageVectorToPixmap(const KDbusImageVector &vector) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_valid;
|
|
||||||
QString m_name;
|
|
||||||
QTimer m_refreshTimer;
|
|
||||||
DBusMenuImporter *m_menuImporter;
|
|
||||||
org::kde::StatusNotifierItem *m_statusNotifierItemInterface;
|
|
||||||
bool m_refreshing : 1;
|
|
||||||
bool m_needsReRefreshing : 1;
|
|
||||||
bool m_titleUpdate : 1;
|
|
||||||
bool m_iconUpdate : 1;
|
|
||||||
bool m_tooltipUpdate : 1;
|
|
||||||
bool m_statusUpdate : 1;
|
|
||||||
|
|
||||||
QString m_id;
|
|
||||||
QString m_title;
|
|
||||||
QString m_tooltip;
|
|
||||||
QString m_subTitle;
|
|
||||||
QString m_iconName;
|
|
||||||
QIcon m_icon;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // STATUSNOTIFIERITEMSOURCE_H
|
|
|
@ -1,104 +0,0 @@
|
||||||
#include "statusnotifierwatcher.h"
|
|
||||||
#include "statusnotifieritem_interface.h"
|
|
||||||
#include "statusnotifierwatcheradaptor.h"
|
|
||||||
|
|
||||||
#include <QDBusConnection>
|
|
||||||
#include <QDBusServiceWatcher>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
StatusNotifierWatcher::StatusNotifierWatcher(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
new StatusNotifierWatcherAdaptor(this);
|
|
||||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
|
||||||
dbus.registerObject(QStringLiteral("/StatusNotifierWatcher"), this);
|
|
||||||
dbus.registerService(QStringLiteral("org.kde.StatusNotifierWatcher"));
|
|
||||||
|
|
||||||
m_serviceWatcher = new QDBusServiceWatcher(this);
|
|
||||||
m_serviceWatcher->setConnection(dbus);
|
|
||||||
m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
|
|
||||||
|
|
||||||
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &StatusNotifierWatcher::serviceUnregistered);
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusNotifierWatcher::~StatusNotifierWatcher()
|
|
||||||
{
|
|
||||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
|
||||||
dbus.unregisterService(QStringLiteral("org.kde.StatusNotifierWatcher"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList StatusNotifierWatcher::RegisteredStatusNotifierItems() const
|
|
||||||
{
|
|
||||||
return m_registeredServices;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StatusNotifierWatcher::IsStatusNotifierHostRegistered() const
|
|
||||||
{
|
|
||||||
return !m_statusNotifierHostServices.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierWatcher::RegisterStatusNotifierItem(const QString &serviceOrPath)
|
|
||||||
{
|
|
||||||
QString service;
|
|
||||||
QString path;
|
|
||||||
if (serviceOrPath.startsWith(QLatin1Char('/'))) {
|
|
||||||
service = message().service();
|
|
||||||
path = serviceOrPath;
|
|
||||||
} else {
|
|
||||||
service = serviceOrPath;
|
|
||||||
path = QStringLiteral("/StatusNotifierItem");
|
|
||||||
}
|
|
||||||
QString notifierItemId = service + path;
|
|
||||||
if (m_registeredServices.contains(notifierItemId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_serviceWatcher->addWatchedService(service);
|
|
||||||
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value()) {
|
|
||||||
// check if the service has registered a SystemTray object
|
|
||||||
org::kde::StatusNotifierItem trayclient(service, path, QDBusConnection::sessionBus());
|
|
||||||
if (trayclient.isValid()) {
|
|
||||||
qDebug() << "Registering" << notifierItemId << "to system tray";
|
|
||||||
m_registeredServices.append(notifierItemId);
|
|
||||||
emit StatusNotifierItemRegistered(notifierItemId);
|
|
||||||
} else {
|
|
||||||
m_serviceWatcher->removeWatchedService(service);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_serviceWatcher->removeWatchedService(service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierWatcher::RegisterStatusNotifierHost(const QString &service)
|
|
||||||
{
|
|
||||||
if (service.contains(QLatin1String("org.kde.StatusNotifierHost-")) && QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value()
|
|
||||||
&& !m_statusNotifierHostServices.contains(service)) {
|
|
||||||
qDebug() << "Registering" << service << "as system tray";
|
|
||||||
|
|
||||||
m_statusNotifierHostServices.insert(service);
|
|
||||||
m_serviceWatcher->addWatchedService(service);
|
|
||||||
emit StatusNotifierHostRegistered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusNotifierWatcher::serviceUnregistered(const QString &name)
|
|
||||||
{
|
|
||||||
qDebug() << "Service " << name << "unregistered";
|
|
||||||
m_serviceWatcher->removeWatchedService(name);
|
|
||||||
|
|
||||||
QString match = name + QLatin1Char('/');
|
|
||||||
QStringList::Iterator it = m_registeredServices.begin();
|
|
||||||
while (it != m_registeredServices.end()) {
|
|
||||||
if (it->startsWith(match)) {
|
|
||||||
QString name = *it;
|
|
||||||
it = m_registeredServices.erase(it);
|
|
||||||
emit StatusNotifierItemUnregistered(name);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_statusNotifierHostServices.contains(name)) {
|
|
||||||
m_statusNotifierHostServices.remove(name);
|
|
||||||
emit StatusNotifierHostUnregistered();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
#ifndef STATUSNOTIFIERWATCHER_H
|
|
||||||
#define STATUSNOTIFIERWATCHER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDBusContext>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
class QDBusServiceWatcher;
|
|
||||||
class StatusNotifierWatcher : public QObject, protected QDBusContext
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_SCRIPTABLE Q_PROPERTY(bool IsStatusNotifierHostRegistered READ IsStatusNotifierHostRegistered)
|
|
||||||
Q_SCRIPTABLE Q_PROPERTY(int ProtocolVersion READ protocolVersion)
|
|
||||||
Q_SCRIPTABLE Q_PROPERTY(QStringList RegisteredStatusNotifierItems READ RegisteredStatusNotifierItems)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit StatusNotifierWatcher(QObject *parent = nullptr);
|
|
||||||
~StatusNotifierWatcher();
|
|
||||||
|
|
||||||
QStringList RegisteredStatusNotifierItems() const;
|
|
||||||
bool IsStatusNotifierHostRegistered() const;
|
|
||||||
int protocolVersion() const { return 0; }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void RegisterStatusNotifierItem(const QString &service);
|
|
||||||
void RegisterStatusNotifierHost(const QString &service);
|
|
||||||
|
|
||||||
protected Q_SLOTS:
|
|
||||||
void serviceUnregistered(const QString &name);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void StatusNotifierItemRegistered(const QString &service);
|
|
||||||
// TODO: decide if this makes sense, the systray itself could notice the vanishing of items, but looks complete putting it here
|
|
||||||
void StatusNotifierItemUnregistered(const QString &service);
|
|
||||||
void StatusNotifierHostRegistered();
|
|
||||||
void StatusNotifierHostUnregistered();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QDBusServiceWatcher *m_serviceWatcher = nullptr;
|
|
||||||
QStringList m_registeredServices;
|
|
||||||
QSet<QString> m_statusNotifierHostServices;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // STATUSNOTIFIERWATCHER_H
|
|
|
@ -1,144 +0,0 @@
|
||||||
#include "systemtraymodel.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
SystemTrayModel::SystemTrayModel(QObject *parent)
|
|
||||||
: QAbstractListModel(parent)
|
|
||||||
{
|
|
||||||
m_hostName = "org.kde.StatusNotifierHost-" + QString::number(QCoreApplication::applicationPid());
|
|
||||||
QDBusConnection::sessionBus().interface()->registerService(m_hostName, QDBusConnectionInterface::DontQueueService);
|
|
||||||
|
|
||||||
m_watcher = new StatusNotifierWatcher;
|
|
||||||
m_watcher->RegisterStatusNotifierHost(m_hostName);
|
|
||||||
m_watcher->moveToThread(QApplication::instance()->thread());
|
|
||||||
|
|
||||||
connect(m_watcher, &StatusNotifierWatcher::StatusNotifierItemRegistered, this, &SystemTrayModel::onItemAdded);
|
|
||||||
connect(m_watcher, &StatusNotifierWatcher::StatusNotifierItemUnregistered, this, &SystemTrayModel::onItemRemoved);
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemTrayModel::~SystemTrayModel()
|
|
||||||
{
|
|
||||||
QDBusConnection::sessionBus().unregisterService(m_hostName);
|
|
||||||
|
|
||||||
delete m_watcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SystemTrayModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent)
|
|
||||||
return m_items.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> SystemTrayModel::roleNames() const
|
|
||||||
{
|
|
||||||
QHash<int, QByteArray> roles;
|
|
||||||
roles[IdRole] = "id";
|
|
||||||
roles[IconNameRole] = "iconName";
|
|
||||||
roles[IconRole] = "icon";
|
|
||||||
roles[TitleRole] = "title";
|
|
||||||
roles[ToolTipRole] = "toolTip";
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant SystemTrayModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
StatusNotifierItemSource *item = m_items.at(index.row());
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case IdRole:
|
|
||||||
return item->id();
|
|
||||||
case IconNameRole:
|
|
||||||
return item->iconName();
|
|
||||||
case IconRole: {
|
|
||||||
if (!item->icon().isNull())
|
|
||||||
return item->icon();
|
|
||||||
else
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
case TitleRole:
|
|
||||||
return item->title();
|
|
||||||
case ToolTipRole:
|
|
||||||
return item->tooltip();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SystemTrayModel::indexOf(const QString &id)
|
|
||||||
{
|
|
||||||
for (StatusNotifierItemSource *item : m_items) {
|
|
||||||
if (item->id() == id)
|
|
||||||
return m_items.indexOf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusNotifierItemSource *SystemTrayModel::findItemById(const QString &id)
|
|
||||||
{
|
|
||||||
int index = indexOf(id);
|
|
||||||
|
|
||||||
if (index == -1)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return m_items.at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayModel::leftButtonClick(const QString &id)
|
|
||||||
{
|
|
||||||
StatusNotifierItemSource *item = findItemById(id);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
QPoint p(QCursor::pos());
|
|
||||||
item->activate(p.x(), p.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayModel::rightButtonClick(const QString &id)
|
|
||||||
{
|
|
||||||
StatusNotifierItemSource *item = findItemById(id);
|
|
||||||
if (item) {
|
|
||||||
QPoint p(QCursor::pos());
|
|
||||||
item->contextMenu(p.x(), p.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayModel::onItemAdded(const QString &service)
|
|
||||||
{
|
|
||||||
StatusNotifierItemSource *source = new StatusNotifierItemSource(service, this);
|
|
||||||
|
|
||||||
connect(source, &StatusNotifierItemSource::updated, this, &SystemTrayModel::updated);
|
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
|
||||||
m_items.append(source);
|
|
||||||
endInsertRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayModel::onItemRemoved(const QString &service)
|
|
||||||
{
|
|
||||||
int index = indexOf(service);
|
|
||||||
|
|
||||||
if (index != -1) {
|
|
||||||
beginRemoveRows(QModelIndex(), index, index);
|
|
||||||
StatusNotifierItemSource *item = m_items.at(index);
|
|
||||||
m_items.removeAll(item);
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemTrayModel::updated(StatusNotifierItemSource *item)
|
|
||||||
{
|
|
||||||
if (!item)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int idx = indexOf(item->id());
|
|
||||||
|
|
||||||
// update
|
|
||||||
if (idx != -1) {
|
|
||||||
dataChanged(index(idx, 0), index(idx, 0));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
#ifndef SYSTEMTRAYMODEL_H
|
|
||||||
#define SYSTEMTRAYMODEL_H
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
|
|
||||||
#include "statusnotifierwatcher.h"
|
|
||||||
#include "statusnotifieritemsource.h"
|
|
||||||
|
|
||||||
class SystemTrayModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
IdRole = Qt::UserRole + 1,
|
|
||||||
IconNameRole,
|
|
||||||
IconRole,
|
|
||||||
TitleRole,
|
|
||||||
ToolTipRole
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit SystemTrayModel(QObject *parent = nullptr);
|
|
||||||
~SystemTrayModel();
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
|
|
||||||
int indexOf(const QString &id);
|
|
||||||
StatusNotifierItemSource *findItemById(const QString &id);
|
|
||||||
|
|
||||||
Q_INVOKABLE void leftButtonClick(const QString &id);
|
|
||||||
Q_INVOKABLE void rightButtonClick(const QString &id);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onItemAdded(const QString &service);
|
|
||||||
void onItemRemoved(const QString &service);
|
|
||||||
void updated(StatusNotifierItemSource *item);
|
|
||||||
|
|
||||||
private:
|
|
||||||
StatusNotifierWatcher *m_watcher;
|
|
||||||
QList<StatusNotifierItemSource *> m_items;
|
|
||||||
QString m_hostName;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SYSTEMTRAYMODEL_H
|
|
|
@ -1,48 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef SYSTEMTRAYTYPEDEFS_H
|
|
||||||
#define SYSTEMTRAYTYPEDEFS_H
|
|
||||||
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QString>
|
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
struct KDbusImageStruct {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
QByteArray data;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef QVector<KDbusImageStruct> KDbusImageVector;
|
|
||||||
|
|
||||||
struct KDbusToolTipStruct {
|
|
||||||
QString icon;
|
|
||||||
KDbusImageVector image;
|
|
||||||
QString title;
|
|
||||||
QString subTitle;
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(KDbusImageStruct)
|
|
||||||
Q_DECLARE_METATYPE(KDbusImageVector)
|
|
||||||
Q_DECLARE_METATYPE(KDbusToolTipStruct)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,128 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include "systemtraytypes.h"
|
|
||||||
|
|
||||||
// Marshall the ImageStruct data into a D-BUS argument
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon)
|
|
||||||
{
|
|
||||||
argument.beginStructure();
|
|
||||||
argument << icon.width;
|
|
||||||
argument << icon.height;
|
|
||||||
argument << icon.data;
|
|
||||||
argument.endStructure();
|
|
||||||
return argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the ImageStruct data from the D-BUS argument
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon)
|
|
||||||
{
|
|
||||||
qint32 width = 0;
|
|
||||||
qint32 height = 0;
|
|
||||||
QByteArray data;
|
|
||||||
|
|
||||||
if (argument.currentType() == QDBusArgument::StructureType) {
|
|
||||||
argument.beginStructure();
|
|
||||||
// qCDebug(DATAENGINE_SNI)() << "begun structure";
|
|
||||||
argument >> width;
|
|
||||||
// qCDebug(DATAENGINE_SNI)() << width;
|
|
||||||
argument >> height;
|
|
||||||
// qCDebug(DATAENGINE_SNI)() << height;
|
|
||||||
argument >> data;
|
|
||||||
// qCDebug(DATAENGINE_SNI)() << data.size();
|
|
||||||
argument.endStructure();
|
|
||||||
}
|
|
||||||
|
|
||||||
icon.width = width;
|
|
||||||
icon.height = height;
|
|
||||||
icon.data = data;
|
|
||||||
|
|
||||||
return argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshall the ImageVector data into a D-BUS argument
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector)
|
|
||||||
{
|
|
||||||
argument.beginArray(qMetaTypeId<KDbusImageStruct>());
|
|
||||||
for (int i = 0; i < iconVector.size(); ++i) {
|
|
||||||
argument << iconVector[i];
|
|
||||||
}
|
|
||||||
argument.endArray();
|
|
||||||
return argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the ImageVector data from the D-BUS argument
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector)
|
|
||||||
{
|
|
||||||
iconVector.clear();
|
|
||||||
|
|
||||||
if (argument.currentType() == QDBusArgument::ArrayType) {
|
|
||||||
argument.beginArray();
|
|
||||||
|
|
||||||
while (!argument.atEnd()) {
|
|
||||||
KDbusImageStruct element;
|
|
||||||
argument >> element;
|
|
||||||
iconVector.append(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
argument.endArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshall the ToolTipStruct data into a D-BUS argument
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip)
|
|
||||||
{
|
|
||||||
argument.beginStructure();
|
|
||||||
argument << toolTip.icon;
|
|
||||||
argument << toolTip.image;
|
|
||||||
argument << toolTip.title;
|
|
||||||
argument << toolTip.subTitle;
|
|
||||||
argument.endStructure();
|
|
||||||
|
|
||||||
return argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the ToolTipStruct data from the D-BUS argument
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip)
|
|
||||||
{
|
|
||||||
QString icon;
|
|
||||||
KDbusImageVector image;
|
|
||||||
QString title;
|
|
||||||
QString subTitle;
|
|
||||||
|
|
||||||
if (argument.currentType() == QDBusArgument::StructureType) {
|
|
||||||
argument.beginStructure();
|
|
||||||
argument >> icon;
|
|
||||||
argument >> image;
|
|
||||||
argument >> title;
|
|
||||||
argument >> subTitle;
|
|
||||||
argument.endStructure();
|
|
||||||
}
|
|
||||||
|
|
||||||
toolTip.icon = icon;
|
|
||||||
toolTip.image = image;
|
|
||||||
toolTip.title = title;
|
|
||||||
toolTip.subTitle = subTitle;
|
|
||||||
|
|
||||||
return argument;
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef SYSTEMTRAYTYPES_H
|
|
||||||
#define SYSTEMTRAYTYPES_H
|
|
||||||
|
|
||||||
#include <QDBusArgument>
|
|
||||||
|
|
||||||
#include "systemtraytypedefs.h"
|
|
||||||
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageStruct &icon);
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageStruct &icon);
|
|
||||||
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusImageVector &iconVector);
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusImageVector &iconVector);
|
|
||||||
|
|
||||||
const QDBusArgument &operator<<(QDBusArgument &argument, const KDbusToolTipStruct &toolTip);
|
|
||||||
const QDBusArgument &operator>>(const QDBusArgument &argument, KDbusToolTipStruct &toolTip);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,151 +0,0 @@
|
||||||
#include "volumemanager.h"
|
|
||||||
|
|
||||||
#include <QDBusConnection>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
#include <QDBusReply>
|
|
||||||
#include <QDBusServiceWatcher>
|
|
||||||
#include <QDBusPendingCall>
|
|
||||||
|
|
||||||
static const QString Service = "org.cutefish.Settings";
|
|
||||||
static const QString ObjectPath = "/Audio";
|
|
||||||
static const QString Interface = "org.cutefish.Audio";
|
|
||||||
|
|
||||||
static VolumeManager *SELF = nullptr;
|
|
||||||
|
|
||||||
VolumeManager *VolumeManager::self()
|
|
||||||
{
|
|
||||||
if (!SELF)
|
|
||||||
SELF = new VolumeManager;
|
|
||||||
|
|
||||||
return SELF;
|
|
||||||
}
|
|
||||||
|
|
||||||
VolumeManager::VolumeManager(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_isValid(false)
|
|
||||||
, m_isMute(false)
|
|
||||||
, m_volume(0)
|
|
||||||
{
|
|
||||||
QDBusServiceWatcher *watcher = new QDBusServiceWatcher(this);
|
|
||||||
watcher->setConnection(QDBusConnection::sessionBus());
|
|
||||||
watcher->addWatchedService(Service);
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &VolumeManager::init);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VolumeManager::isValid() const
|
|
||||||
{
|
|
||||||
return m_isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::initStatus()
|
|
||||||
{
|
|
||||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
m_isValid = iface.isValid() && !iface.lastError().isValid();
|
|
||||||
|
|
||||||
if (m_isValid) {
|
|
||||||
int volume = iface.property("volume").toInt();
|
|
||||||
bool mute = iface.property("mute").toBool();
|
|
||||||
|
|
||||||
if (m_volume != volume) {
|
|
||||||
m_volume = volume;
|
|
||||||
emit volumeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_isMute != mute) {
|
|
||||||
m_isMute = mute;
|
|
||||||
emit muteChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit validChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::connectDBusSignals()
|
|
||||||
{
|
|
||||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
if (iface.isValid()) {
|
|
||||||
QDBusConnection::sessionBus().connect(Service, ObjectPath, Interface, "volumeChanged",
|
|
||||||
this, SLOT(onDBusVolumeChanged(int)));
|
|
||||||
QDBusConnection::sessionBus().connect(Service, ObjectPath, Interface, "muteChanged",
|
|
||||||
this, SLOT(onDBusMuteChanged(bool)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::onDBusVolumeChanged(int volume)
|
|
||||||
{
|
|
||||||
if (m_volume != volume) {
|
|
||||||
m_volume = volume;
|
|
||||||
emit volumeChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::onDBusMuteChanged(bool mute)
|
|
||||||
{
|
|
||||||
if (m_isMute != mute) {
|
|
||||||
m_isMute = mute;
|
|
||||||
emit muteChanged();
|
|
||||||
|
|
||||||
// Need to update the icon.
|
|
||||||
emit volumeChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int VolumeManager::volume() const
|
|
||||||
{
|
|
||||||
return m_volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString VolumeManager::iconName() const
|
|
||||||
{
|
|
||||||
if (m_volume <= 0 || m_isMute)
|
|
||||||
return QStringLiteral("audio-volume-muted-symbolic");
|
|
||||||
else if (m_volume <= 25)
|
|
||||||
return QStringLiteral("audio-volume-low-symbolic");
|
|
||||||
else if (m_volume <= 75)
|
|
||||||
return QStringLiteral("audio-volume-medium-symbolic");
|
|
||||||
else
|
|
||||||
return QStringLiteral("audio-volume-high-symbolic");
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::toggleMute()
|
|
||||||
{
|
|
||||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("toggleMute");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::setMute(bool mute)
|
|
||||||
{
|
|
||||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setMute", QVariant::fromValue(mute));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::setVolume(int value)
|
|
||||||
{
|
|
||||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
|
||||||
|
|
||||||
if (iface.isValid()) {
|
|
||||||
iface.call("setVolume", QVariant::fromValue(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VolumeManager::init()
|
|
||||||
{
|
|
||||||
initStatus();
|
|
||||||
connectDBusSignals();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VolumeManager::isMute() const
|
|
||||||
{
|
|
||||||
return m_isMute;
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
#ifndef VOLUMEMANAGER_H
|
|
||||||
#define VOLUMEMANAGER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class VolumeManager : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(bool isValid READ isValid NOTIFY validChanged)
|
|
||||||
Q_PROPERTY(bool isMute READ isMute NOTIFY muteChanged)
|
|
||||||
Q_PROPERTY(int volume READ volume NOTIFY volumeChanged)
|
|
||||||
Q_PROPERTY(QString iconName READ iconName NOTIFY volumeChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
static VolumeManager *self();
|
|
||||||
|
|
||||||
explicit VolumeManager(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
bool isMute() const;
|
|
||||||
int volume() const;
|
|
||||||
|
|
||||||
QString iconName() const;
|
|
||||||
|
|
||||||
Q_INVOKABLE void toggleMute();
|
|
||||||
Q_INVOKABLE void setMute(bool mute);
|
|
||||||
Q_INVOKABLE void setVolume(int value);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void validChanged();
|
|
||||||
void muteChanged();
|
|
||||||
void volumeChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void init();
|
|
||||||
void initStatus();
|
|
||||||
void connectDBusSignals();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onDBusVolumeChanged(int volume);
|
|
||||||
void onDBusMuteChanged(bool mute);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_isValid;
|
|
||||||
bool m_isMute;
|
|
||||||
int m_volume;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VOLUMEMANAGER_H
|
|
|
@ -143,30 +143,28 @@ bool XWindowInterface::isAcceptableWindow(quint64 wid)
|
||||||
return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
|
return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XWindowInterface::setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect, bool isMax)
|
void XWindowInterface::setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect)
|
||||||
{
|
{
|
||||||
NETExtendedStrut strut;
|
NETExtendedStrut strut;
|
||||||
|
|
||||||
const auto screen = view->screen();
|
const auto screen = view->screen();
|
||||||
|
|
||||||
const QRect currentScreen { screen->geometry() };
|
const QRect currentScreen {screen->geometry()};
|
||||||
const QRect wholeScreen { {0, 0}, screen->virtualSize() };
|
const QRect wholeScreen { {0, 0}, screen->virtualSize() };
|
||||||
|
|
||||||
bool roundedWindow = DockSettings::self()->roundedWindowEnabled();
|
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case DockSettings::Left: {
|
case DockSettings::Left: {
|
||||||
const int leftOffset = { screen->geometry().left() };
|
const int leftOffset = { screen->geometry().left() };
|
||||||
strut.left_width = rect.width() + leftOffset + (roundedWindow ? DockSettings::self()->edgeMargins() : 0);
|
strut.left_width = rect.width() + leftOffset + DockSettings::self()->edgeMargins();
|
||||||
strut.left_start = rect.y();
|
strut.left_start = rect.y();
|
||||||
strut.left_end = rect.y() + rect.height() - 1;
|
strut.left_end = rect.y() + rect.height() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DockSettings::Bottom: {
|
case DockSettings::Bottom: {
|
||||||
const int bottomOffset { wholeScreen.bottom() - currentScreen.bottom() };
|
const int bottomOffset { wholeScreen.bottom() - currentScreen.bottom() };
|
||||||
strut.bottom_width = rect.height() + bottomOffset + (roundedWindow ? DockSettings::self()->edgeMargins() : 0);
|
strut.bottom_width = rect.height() + bottomOffset + DockSettings::self()->edgeMargins();
|
||||||
strut.bottom_start = rect.x();
|
strut.bottom_start = rect.x();
|
||||||
strut.bottom_end = rect.x() + rect.width() - 1;
|
strut.bottom_end = rect.x() + rect.width();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
QString requestWindowClass(quint64 wid);
|
QString requestWindowClass(quint64 wid);
|
||||||
bool isAcceptableWindow(quint64 wid);
|
bool isAcceptableWindow(quint64 wid);
|
||||||
|
|
||||||
void setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect, bool isMax = false);
|
void setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect);
|
||||||
|
|
||||||
void startInitWindows();
|
void startInitWindows();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue