diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1d83e9e44..70a3ff73f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,767 +1,770 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(KWin)
set(PROJECT_VERSION "5.18.80")
set(PROJECT_VERSION_MAJOR 5)
set(QT_MIN_VERSION "5.12.0")
set(KF5_MIN_VERSION "5.66.0")
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
find_package(ECM 5.38 REQUIRED NO_MODULE)
include(FeatureSummary)
include(WriteBasicConfigVersionFile)
include(GenerateExportHeader)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Concurrent
Core
DBus
Quick
QuickWidgets
Script
Sensors
UiTools
Widgets
X11Extras
)
find_package(Qt5Test ${QT_MIN_VERSION} CONFIG QUIET)
set_package_properties(Qt5Test PROPERTIES
PURPOSE "Required for tests"
TYPE OPTIONAL
)
add_feature_info("Qt5Test" Qt5Test_FOUND "Required for building tests")
if (NOT Qt5Test_FOUND)
set(BUILD_TESTING OFF CACHE BOOL "Build the testing tree.")
endif()
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(KDEClangFormat)
include(ECMInstallIcons)
include(ECMOptionalAddSubdirectory)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0 -DQT_USE_QSTRINGBUILDER -DQT_NO_URL_CAST_FROM_STRING)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5Multimedia QUIET)
set_package_properties(Qt5Multimedia PROPERTIES
PURPOSE "Runtime-only dependency for effect video playback"
TYPE RUNTIME
)
# required frameworks by Core
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
Config
ConfigWidgets
CoreAddons
Crash
GlobalAccel
I18n
IconThemes
IdleTime
Notifications
Package
Plasma
Wayland
WidgetsAddons
WindowSystem
)
# required frameworks by config modules
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
Completion
Declarative
KCMUtils
KIO
NewStuff
Service
TextWidgets
XmlGui
)
find_package(Threads)
set_package_properties(Threads PROPERTIES
PURPOSE "Needed for VirtualTerminal support in KWin Wayland"
TYPE REQUIRED
)
# optional frameworks
find_package(KF5Activities ${KF5_MIN_VERSION} CONFIG)
set_package_properties(KF5Activities PROPERTIES
PURPOSE "Enable building of KWin with kactivities support"
TYPE OPTIONAL
)
add_feature_info("KF5Activities" KF5Activities_FOUND "Enable building of KWin with kactivities support")
find_package(KF5DocTools ${KF5_MIN_VERSION} CONFIG)
set_package_properties(KF5DocTools PROPERTIES
PURPOSE "Enable building documentation"
TYPE OPTIONAL
)
add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation")
find_package(KF5Kirigami2 ${KF5_MIN_VERSION} CONFIG)
set_package_properties(KF5Kirigami2 PROPERTIES
DESCRIPTION "A QtQuick based components set"
PURPOSE "Required at runtime for Virtual desktop KCM and the virtual keyboard"
TYPE RUNTIME
)
find_package(KDecoration2 5.18.0 CONFIG REQUIRED)
find_package(KScreenLocker CONFIG REQUIRED)
set_package_properties(KScreenLocker PROPERTIES
TYPE REQUIRED
PURPOSE "For screenlocker integration in kwin_wayland"
)
find_package(Breeze 5.9.0 CONFIG)
set_package_properties(Breeze PROPERTIES
TYPE OPTIONAL
PURPOSE "For setting the default window decoration plugin"
)
if (${Breeze_FOUND})
if (${BREEZE_WITH_KDECORATION})
set(HAVE_BREEZE_DECO true)
else()
set(HAVE_BREEZE_DECO FALSE)
endif()
else()
set(HAVE_BREEZE_DECO FALSE)
endif()
add_feature_info("Breeze-Decoration" HAVE_BREEZE_DECO "Default decoration plugin Breeze")
find_package(EGL)
set_package_properties(EGL PROPERTIES
TYPE RUNTIME
PURPOSE "Required to build KWin with EGL support"
)
find_package(epoxy)
set_package_properties(epoxy PROPERTIES
DESCRIPTION "libepoxy"
URL "https://github.com/anholt/libepoxy"
TYPE REQUIRED
PURPOSE "OpenGL dispatch library"
)
set(HAVE_DL_LIBRARY FALSE)
if (epoxy_HAS_GLX)
find_library(DL_LIBRARY dl)
if (DL_LIBRARY)
set(HAVE_DL_LIBRARY TRUE)
endif()
endif()
find_package(Wayland 1.2 REQUIRED COMPONENTS Cursor OPTIONAL_COMPONENTS Egl)
set_package_properties(Wayland PROPERTIES
TYPE REQUIRED
PURPOSE "Required for building KWin with Wayland support"
)
add_feature_info("Wayland::EGL" Wayland_Egl_FOUND "Enable building of Wayland backend and QPA with EGL support.")
set(HAVE_WAYLAND_EGL FALSE)
if (Wayland_Egl_FOUND)
set(HAVE_WAYLAND_EGL TRUE)
endif()
find_package(XKB 0.7.0)
set_package_properties(XKB PROPERTIES
TYPE REQUIRED
PURPOSE "Required for building KWin with Wayland support"
)
find_package(Libinput 1.9)
set_package_properties(Libinput PROPERTIES TYPE REQUIRED PURPOSE "Required for input handling on Wayland.")
find_package(UDev)
set_package_properties(UDev PROPERTIES
URL "https://www.freedesktop.org/wiki/Software/systemd/"
DESCRIPTION "Linux device library."
TYPE REQUIRED
PURPOSE "Required for input handling on Wayland."
)
find_package(Libdrm 2.4.62)
set_package_properties(Libdrm PROPERTIES TYPE OPTIONAL PURPOSE "Required for drm output on Wayland.")
set(HAVE_DRM FALSE)
if (Libdrm_FOUND)
set(HAVE_DRM TRUE)
endif()
find_package(gbm)
set_package_properties(gbm PROPERTIES TYPE OPTIONAL PURPOSE "Required for egl output of drm backend.")
set(HAVE_GBM FALSE)
if (HAVE_DRM AND gbm_FOUND)
set(HAVE_GBM TRUE)
endif()
option(KWIN_BUILD_EGL_STREAM_BACKEND "Enable building of EGLStream based DRM backend" ON)
if (HAVE_DRM AND KWIN_BUILD_EGL_STREAM_BACKEND)
set(HAVE_EGL_STREAMS TRUE)
endif()
find_package(libhybris)
set_package_properties(libhybris PROPERTIES TYPE OPTIONAL PURPOSE "Required for libhybris backend")
set(HAVE_LIBHYBRIS ${libhybris_FOUND})
find_package(X11)
set_package_properties(X11 PROPERTIES
DESCRIPTION "X11 libraries"
URL "https://www.x.org"
TYPE REQUIRED
)
add_feature_info("XInput" X11_Xinput_FOUND "Required for poll-free mouse cursor updates")
set(HAVE_X11_XINPUT ${X11_Xinput_FOUND})
# All the required XCB components
find_package(XCB 1.10 REQUIRED COMPONENTS
COMPOSITE
CURSOR
DAMAGE
GLX
ICCCM
IMAGE
KEYSYMS
RANDR
RENDER
SHAPE
SHM
SYNC
XCB
XFIXES
)
set_package_properties(XCB PROPERTIES TYPE REQUIRED)
# and the optional XCB dependencies
if (XCB_ICCCM_VERSION VERSION_LESS "0.4")
set(XCB_ICCCM_FOUND FALSE)
endif()
add_feature_info("XCB-ICCCM" XCB_ICCCM_FOUND "Required for building test applications for KWin")
find_package(X11_XCB)
set_package_properties(X11_XCB PROPERTIES
PURPOSE "Required for building X11 windowed backend of kwin_wayland"
TYPE OPTIONAL
)
# dependencies for QPA plugin
find_package(Qt5FontDatabaseSupport REQUIRED)
find_package(Qt5ThemeSupport REQUIRED)
find_package(Qt5EventDispatcherSupport REQUIRED)
find_package(Freetype REQUIRED)
set_package_properties(Freetype PROPERTIES
DESCRIPTION "A font rendering engine"
URL "https://www.freetype.org"
TYPE REQUIRED
PURPOSE "Needed for KWin's QPA plugin."
)
find_package(Fontconfig REQUIRED)
set_package_properties(Fontconfig PROPERTIES
TYPE REQUIRED
PURPOSE "Needed for KWin's QPA plugin."
)
find_package(Xwayland)
set_package_properties(Xwayland PROPERTIES
URL "https://x.org"
DESCRIPTION "Xwayland X server"
TYPE RUNTIME
PURPOSE "Needed for running kwin_wayland"
)
find_package(Libcap)
set_package_properties(Libcap PROPERTIES
TYPE OPTIONAL
PURPOSE "Needed for running kwin_wayland with real-time scheduling policy"
)
set(HAVE_LIBCAP ${Libcap_FOUND})
find_package(hwdata)
set_package_properties(hwdata PROPERTIES
TYPE RUNTIME
PURPOSE "Runtime-only dependency needed for mapping monitor hardware vendor IDs to full names"
URL "https://github.com/vcrhonek/hwdata"
)
set(HAVE_HWDATA ${hwdata_FOUND})
include(ECMQMLModules)
ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 1.2)
ecm_find_qmlmodule(QtQuick.Layouts 1.3)
ecm_find_qmlmodule(QtQuick.VirtualKeyboard 2.1)
ecm_find_qmlmodule(QtQuick.Window 2.1)
ecm_find_qmlmodule(QtMultimedia 5.0)
ecm_find_qmlmodule(org.kde.kquickcontrolsaddons 2.0)
ecm_find_qmlmodule(org.kde.plasma.core 2.0)
ecm_find_qmlmodule(org.kde.plasma.components 2.0)
########### configure tests ###############
include(CMakeDependentOption)
option(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON)
option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON)
option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON)
option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON)
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF)
# Binary name of KWin
set(KWIN_NAME "kwin")
set(KWIN_INTERNAL_NAME_X11 "kwin_x11")
set(KWIN_INTERNAL_NAME_WAYLAND "kwin_wayland")
# KWIN_HAVE_XRENDER_COMPOSITING - whether XRender-based compositing support is available: may be disabled
if (KWIN_BUILD_XRENDER_COMPOSITING)
set(KWIN_HAVE_XRENDER_COMPOSITING 1)
endif()
include_directories(${XKB_INCLUDE_DIR})
include_directories(${epoxy_INCLUDE_DIR})
set(HAVE_EPOXY_GLX ${epoxy_HAS_GLX})
# for things that are also used by kwin libraries
configure_file(libkwineffects/kwinconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/libkwineffects/kwinconfig.h )
# for kwin internal things
set(HAVE_X11_XCB ${X11_XCB_FOUND})
include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckSymbolExists)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(malloc.h HAVE_MALLOC_H)
check_include_file("sys/prctl.h" HAVE_SYS_PRCTL_H)
check_symbol_exists(PR_SET_DUMPABLE "sys/prctl.h" HAVE_PR_SET_DUMPABLE)
check_symbol_exists(PR_SET_PDEATHSIG "sys/prctl.h" HAVE_PR_SET_PDEATHSIG)
check_include_file("sys/procctl.h" HAVE_SYS_PROCCTL_H)
check_symbol_exists(PROC_TRACE_CTL "sys/procctl.h" HAVE_PROC_TRACE_CTL)
if (HAVE_PR_SET_DUMPABLE OR HAVE_PROC_TRACE_CTL)
set(CAN_DISABLE_PTRACE TRUE)
endif()
add_feature_info("prctl/procctl tracing control"
CAN_DISABLE_PTRACE
"Required for disallowing ptrace on kwin_wayland process")
check_include_file("sys/sysmacros.h" HAVE_SYS_SYSMACROS_H)
check_include_file("linux/vt.h" HAVE_LINUX_VT_H)
add_feature_info("linux/vt.h"
HAVE_LINUX_VT_H
"Required for virtual terminal support under wayland")
check_include_file("linux/fb.h" HAVE_LINUX_FB_H)
add_feature_info("linux/fb.h"
HAVE_LINUX_FB_H
"Required for the fbdev backend")
check_symbol_exists(SCHED_RESET_ON_FORK "sched.h" HAVE_SCHED_RESET_ON_FORK)
add_feature_info("SCHED_RESET_ON_FORK"
HAVE_SCHED_RESET_ON_FORK
"Required for running kwin_wayland with real-time scheduling")
configure_file(config-kwin.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwin.h)
########### global ###############
set(kwin_effects_dbus_xml ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.kwin.Effects.xml)
include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/libkwineffects
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libkwineffects
${CMAKE_CURRENT_SOURCE_DIR}/effects
${CMAKE_CURRENT_SOURCE_DIR}/tabbox
${CMAKE_CURRENT_SOURCE_DIR}/platformsupport
)
add_subdirectory(libkwineffects)
if (KWIN_BUILD_KCMS)
add_subdirectory(kcmkwin)
endif()
add_subdirectory(data)
add_subdirectory(effects)
add_subdirectory(scripts)
add_subdirectory(tabbox)
add_subdirectory(scripting)
add_subdirectory(helpers)
########### next target ###############
set(kwin_SRCS
abstract_client.cpp
abstract_opengl_context_attribute_builder.cpp
abstract_output.cpp
abstract_wayland_output.cpp
activation.cpp
appmenu.cpp
atoms.cpp
client_machine.cpp
colorcorrection/clockskewnotifier.cpp
colorcorrection/clockskewnotifierengine.cpp
colorcorrection/colorcorrectdbusinterface.cpp
colorcorrection/manager.cpp
colorcorrection/suncalc.cpp
composite.cpp
cursor.cpp
dbusinterface.cpp
debug_console.cpp
decorations/decoratedclient.cpp
decorations/decorationbridge.cpp
decorations/decorationpalette.cpp
decorations/decorationrenderer.cpp
decorations/decorations_logging.cpp
decorations/settings.cpp
deleted.cpp
effectloader.cpp
effects.cpp
egl_context_attribute_builder.cpp
events.cpp
focuschain.cpp
geometrytip.cpp
gestures.cpp
globalshortcuts.cpp
group.cpp
idle_inhibition.cpp
input.cpp
input_event.cpp
input_event_spy.cpp
internal_client.cpp
keyboard_input.cpp
keyboard_layout.cpp
keyboard_layout_switching.cpp
keyboard_repeat.cpp
killwindow.cpp
layers.cpp
libinput/connection.cpp
libinput/context.cpp
libinput/device.cpp
libinput/events.cpp
libinput/libinput_logging.cpp
linux_dmabuf.cpp
logind.cpp
main.cpp
modifier_only_shortcuts.cpp
moving_client_x11_filter.cpp
netinfo.cpp
onscreennotification.cpp
options.cpp
osd.cpp
outline.cpp
outputscreens.cpp
overlaywindow.cpp
placement.cpp
platform.cpp
pointer_input.cpp
popup_input_filter.cpp
rootinfo_filter.cpp
rules.cpp
+ rulebooksettings.cpp
scene.cpp
screenedge.cpp
screenlockerwatcher.cpp
screens.cpp
scripting/dbuscall.cpp
scripting/meta.cpp
scripting/screenedgeitem.cpp
scripting/scriptedeffect.cpp
scripting/scripting.cpp
scripting/scripting_logging.cpp
scripting/scripting_model.cpp
scripting/scriptingutils.cpp
scripting/timer.cpp
scripting/workspace_wrapper.cpp
shadow.cpp
sm.cpp
thumbnailitem.cpp
toplevel.cpp
touch_hide_cursor_spy.cpp
tablet_input.cpp
touch_input.cpp
udev.cpp
unmanaged.cpp
useractions.cpp
utils.cpp
virtualdesktops.cpp
virtualdesktopsdbustypes.cpp
virtualkeyboard.cpp
virtualkeyboard_dbus.cpp
was_user_interaction_x11_filter.cpp
wayland_cursor_theme.cpp
wayland_server.cpp
window_property_notify_x11_filter.cpp
workspace.cpp
x11client.cpp
x11eventfilter.cpp
xcbutils.cpp
xdgshellclient.cpp
xkb.cpp
xwl/xwayland_interface.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(kwin_SRCS
${kwin_SRCS}
colorcorrection/clockskewnotifierengine_linux.cpp
)
endif()
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(kwin_SRCS
HEADER
colorcorrect_logging.h
IDENTIFIER
KWIN_COLORCORRECTION
CATEGORY_NAME
kwin_colorcorrection
DEFAULT_SEVERITY
Critical
)
if (KWIN_BUILD_TABBOX)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
set(kwin_SRCS ${kwin_SRCS}
tabbox/clientmodel.cpp
tabbox/desktopchain.cpp
tabbox/desktopmodel.cpp
tabbox/switcheritem.cpp
tabbox/tabbox.cpp
tabbox/tabbox_logging.cpp
tabbox/tabboxconfig.cpp
tabbox/tabboxhandler.cpp
tabbox/x11_filter.cpp
)
endif()
if (KWIN_BUILD_ACTIVITIES)
set(kwin_SRCS ${kwin_SRCS}
activities.cpp
)
endif()
if (HAVE_LINUX_VT_H)
set(kwin_SRCS ${kwin_SRCS}
virtual_terminal.cpp
)
endif()
kconfig_add_kcfg_files(kwin_SRCS settings.kcfgc)
kconfig_add_kcfg_files(kwin_SRCS colorcorrection/colorcorrect_settings.kcfgc)
+kconfig_add_kcfg_files(kwin_SRCS rulesettings.kcfgc)
+kconfig_add_kcfg_files(kwin_SRCS rulebooksettingsbase.kcfgc)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.KWin.xml dbusinterface.h KWin::DBusInterface)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.kwin.Compositing.xml dbusinterface.h KWin::CompositorDBusInterface)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.kwin.ColorCorrect.xml colorcorrection/colorcorrectdbusinterface.h KWin::ColorCorrect::ColorCorrectDBusInterface)
qt5_add_dbus_adaptor(kwin_SRCS ${kwin_effects_dbus_xml} effects.h KWin::EffectsHandlerImpl)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.KWin.VirtualDesktopManager.xml dbusinterface.h KWin::VirtualDesktopManagerDBusInterface)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.KWin.Session.xml sm.h KWin::SessionManager)
qt5_add_dbus_interface(kwin_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/kf5_org.freedesktop.ScreenSaver.xml screenlocker_interface)
qt5_add_dbus_interface(kwin_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/org.kde.screensaver.xml kscreenlocker_interface)
qt5_add_dbus_interface(kwin_SRCS org.kde.kappmenu.xml appmenu_interface)
ki18n_wrap_ui(kwin_SRCS
debug_console.ui
shortcutdialog.ui
)
########### target link libraries ###############
set(kwin_OWN_LIBS
kwineffects
kwin4_effect_builtins
)
set(kwin_QT_LIBS
Qt5::Concurrent
Qt5::DBus
Qt5::Quick
Qt5::Script
Qt5::Sensors
)
set(kwin_KDE_LIBS
KF5::ConfigCore
KF5::ConfigWidgets
KF5::CoreAddons
KF5::GlobalAccel
KF5::GlobalAccelPrivate
KF5::I18n
KF5::Notifications
KF5::Package
KF5::Plasma
KF5::QuickAddons
KF5::WindowSystem
KDecoration2::KDecoration
KDecoration2::KDecoration2Private
PW::KScreenLocker
)
set(kwin_XLIB_LIBS
${X11_ICE_LIB}
${X11_SM_LIB}
${X11_X11_LIB}
)
set(kwin_XCB_LIBS
XCB::COMPOSITE
XCB::DAMAGE
XCB::GLX
XCB::ICCCM
XCB::KEYSYMS
XCB::RANDR
XCB::RENDER
XCB::SHAPE
XCB::SHM
XCB::SYNC
XCB::XCB
XCB::XFIXES
)
set(kwin_WAYLAND_LIBS
KF5::WaylandClient
KF5::WaylandServer
Wayland::Cursor
XKB::XKB
${CMAKE_THREAD_LIBS_INIT}
)
if (KWIN_BUILD_ACTIVITIES)
set(kwin_KDE_LIBS ${kwin_KDE_LIBS} KF5::Activities)
endif()
set(kwinLibs
${kwin_OWN_LIBS}
${kwin_QT_LIBS}
${kwin_KDE_LIBS}
${kwin_XLIB_LIBS}
${kwin_XCB_LIBS}
${kwin_WAYLAND_LIBS}
${UDEV_LIBS}
Libinput::Libinput
)
add_library(kwin SHARED ${kwin_SRCS})
set_target_properties(kwin PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
target_link_libraries(kwin ${kwinLibs})
generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h)
target_link_libraries(kwin kwinglutils ${epoxy_LIBRARY})
add_executable(kwin_x11 main_x11.cpp)
target_link_libraries(kwin_x11 kwin KF5::Crash Qt5::X11Extras)
install(TARGETS kwin ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
install(TARGETS kwin_x11 ${INSTALL_TARGETS_DEFAULT_ARGS})
set(kwin_XWAYLAND_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/xwl/clipboard.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/databridge.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/dnd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/drag.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/drag_wl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/drag_x.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/selection.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/selection_source.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/transfer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/xwl/xwayland.cpp
)
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(kwin_XWAYLAND_SRCS
HEADER
xwayland_logging.h
IDENTIFIER
KWIN_XWL
CATEGORY_NAME
kwin_xwl
DEFAULT_SEVERITY
Critical
)
set(kwin_WAYLAND_SRCS
main_wayland.cpp
tabletmodemanager.cpp
)
add_executable(kwin_wayland ${kwin_WAYLAND_SRCS} ${kwin_XWAYLAND_SRCS})
target_link_libraries(kwin_wayland kwin KF5::Crash)
if (HAVE_LIBCAP)
target_link_libraries(kwin_wayland ${Libcap_LIBRARIES})
endif()
install(TARGETS kwin_wayland ${INSTALL_TARGETS_DEFAULT_ARGS})
if (HAVE_LIBCAP)
install(
CODE "execute_process(
COMMAND
${SETCAP_EXECUTABLE}
CAP_SYS_NICE=+ep
\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/kwin_wayland)"
)
endif()
add_subdirectory(platformsupport)
add_subdirectory(plugins)
########### install files ###############
install(FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} RENAME ${KWIN_NAME}.kcfg)
install(FILES colorcorrection/colorcorrect_settings.kcfg DESTINATION ${KCFG_INSTALL_DIR} RENAME ${KWIN_NAME}_colorcorrect.kcfg)
install(FILES kwin.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR} RENAME ${KWIN_NAME}.notifyrc)
install(
FILES
org.kde.KWin.VirtualDesktopManager.xml
org.kde.KWin.xml
org.kde.kwin.ColorCorrect.xml
org.kde.kwin.Compositing.xml
org.kde.kwin.Effects.xml
DESTINATION
${KDE_INSTALL_DBUSINTERFACEDIR}
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kwin_export.h DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel)
# Install the KWin/Script service type
install(FILES scripting/kwinscript.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
add_subdirectory(qml)
if (BUILD_TESTING)
add_subdirectory(autotests)
add_subdirectory(tests)
endif()
if (KF5DocTools_FOUND)
add_subdirectory(doc)
endif()
add_subdirectory(kconf_update)
# add clang-format target for all our real source files
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
include(CMakePackageConfigHelpers)
set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KWinDBusInterface")
configure_package_config_file(KWinDBusInterfaceConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/KWinDBusInterfaceConfig.cmake"
PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KWinDBusInterfaceConfig.cmake
DESTINATION ${CMAKECONFIG_INSTALL_DIR})
diff --git a/kcmkwin/kwinrules/CMakeLists.txt b/kcmkwin/kwinrules/CMakeLists.txt
index bee3e2ee2..f25e7ff46 100644
--- a/kcmkwin/kwinrules/CMakeLists.txt
+++ b/kcmkwin/kwinrules/CMakeLists.txt
@@ -1,53 +1,56 @@
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwinrules\")
add_definitions(-DKCMRULES)
########### next target ###############
include_directories(../../)
set(kwinrules_MOC_HDRS yesnobox.h ../../cursor.h ../../plugins/platforms/x11/standalone/x11cursor.h)
qt5_wrap_cpp(kwinrules_MOC_SRCS ${kwinrules_MOC_HDRS})
-set(kwinrules_SRCS ruleswidget.cpp ruleslist.cpp kwinsrc.cpp detectwidget.cpp main.cpp ${kwinrules_MOC_SRCS})
+set(kwinrules_SRCS ../../rulebooksettings.cpp ruleswidget.cpp ruleslist.cpp kwinsrc.cpp detectwidget.cpp main.cpp ${kwinrules_MOC_SRCS})
ki18n_wrap_ui(kwinrules_SRCS ruleslist.ui detectwidget.ui editshortcut.ui ruleswidgetbase.ui)
+kconfig_add_kcfg_files(kwinrules_SRCS ../../rulesettings.kcfgc)
+kconfig_add_kcfg_files(kwinrules_SRCS ../../rulebooksettingsbase.kcfgc)
+
add_executable(kwin_rules_dialog ${kwinrules_SRCS})
set(kwin_kcm_rules_XCB_LIBS
XCB::CURSOR
XCB::XCB
XCB::XFIXES
)
set(kcm_libs
Qt5::Concurrent
Qt5::X11Extras
KF5::Completion
KF5::ConfigWidgets
KF5::I18n
KF5::Service
KF5::WindowSystem
KF5::XmlGui
)
if (KWIN_BUILD_ACTIVITIES)
set(kcm_libs ${kcm_libs} KF5::Activities)
endif()
target_link_libraries(kwin_rules_dialog ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS})
install(TARGETS kwin_rules_dialog DESTINATION ${LIBEXEC_INSTALL_DIR})
########### next target ###############
set(kcm_kwinrules_PART_SRCS kcm.cpp ${kwinrules_SRCS})
add_library(kcm_kwinrules MODULE ${kcm_kwinrules_PART_SRCS})
target_link_libraries(kcm_kwinrules ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS})
install(TARGETS kcm_kwinrules DESTINATION ${PLUGIN_INSTALL_DIR})
########### install files ###############
install(FILES kwinrules.desktop DESTINATION ${SERVICES_INSTALL_DIR})
diff --git a/kcmkwin/kwinrules/kcm.cpp b/kcmkwin/kwinrules/kcm.cpp
index 9dca089a9..a18a188da 100644
--- a/kcmkwin/kwinrules/kcm.cpp
+++ b/kcmkwin/kwinrules/kcm.cpp
@@ -1,106 +1,102 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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 "kcm.h"
#include
//Added by qt3to4:
#include
#include
#include
#include
#include
#include "ruleslist.h"
#include
#include
K_PLUGIN_FACTORY(KCMRulesFactory,
registerPlugin();
)
namespace KWin
{
KCMRules::KCMRules(QWidget *parent, const QVariantList &)
: KCModule(parent)
- , config("kwinrulesrc", KConfig::NoGlobals)
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
widget = new KCMRulesList(this);
layout->addWidget(widget);
connect(widget, SIGNAL(changed(bool)), SLOT(moduleChanged(bool)));
KAboutData *about = new KAboutData(QStringLiteral("kcmkwinrules"),
i18n("Window-Specific Settings Configuration Module"),
QString(), QString(), KAboutLicense::GPL, i18n("(c) 2004 KWin and KControl Authors"));
about->addAuthor(i18n("Lubos Lunak"), QString(), "l.lunak@kde.org");
setAboutData(about);
}
void KCMRules::load()
{
- config.reparseConfiguration();
widget->load();
emit KCModule::changed(false);
}
void KCMRules::save()
{
widget->save();
emit KCModule::changed(false);
- // Send signal to kwin
- config.sync();
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
void KCMRules::defaults()
{
widget->defaults();
}
QString KCMRules::quickHelp() const
{
return i18n("
Window-specific Settings
Here you can customize window settings specifically only"
" for some windows.
"
"
Please note that this configuration will not take effect if you do not use"
" KWin as your window manager. If you do use a different window manager, please refer to its documentation"
" for how to customize window behavior.
");
}
void KCMRules::moduleChanged(bool state)
{
emit KCModule::changed(state);
}
}
// i18n freeze :-/
#if 0
I18N_NOOP("Remember settings separately for every window")
I18N_NOOP("Show internal settings for remembering")
I18N_NOOP("Internal setting for remembering")
#endif
#include "kcm.moc"
diff --git a/kcmkwin/kwinrules/kcm.h b/kcmkwin/kwinrules/kcm.h
index cb1f48dd8..7d0c462c9 100644
--- a/kcmkwin/kwinrules/kcm.h
+++ b/kcmkwin/kwinrules/kcm.h
@@ -1,52 +1,51 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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 __KCM_H__
#define __KCM_H__
#include
#include
class KConfig;
namespace KWin
{
class KCMRulesList;
class KCMRules
: public KCModule
{
Q_OBJECT
public:
KCMRules(QWidget *parent, const QVariantList &args);
void load() override;
void save() override;
void defaults() override;
QString quickHelp() const override;
protected Q_SLOTS:
void moduleChanged(bool state);
private:
KCMRulesList* widget;
- KConfig config;
};
} // namespace
#endif
diff --git a/kcmkwin/kwinrules/kwinsrc.cpp b/kcmkwin/kwinrules/kwinsrc.cpp
index 24a67f85d..4c4482d93 100644
--- a/kcmkwin/kwinrules/kwinsrc.cpp
+++ b/kcmkwin/kwinrules/kwinsrc.cpp
@@ -1,54 +1,53 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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 some code from kwin core in order to avoid
// double implementation.
-#include "ruleslist.h"
#include "../../cursor.cpp"
#include "../../plugins/platforms/x11/standalone/x11cursor.cpp"
#include "../../rules.cpp"
#include "../../placement.cpp"
#include "../../options.cpp"
#include "../../utils.cpp"
KWin::InputRedirection *KWin::InputRedirection::s_self = nullptr;
Qt::MouseButtons KWin::InputRedirection::qtButtonStates() const
{
return Qt::NoButton;
}
Qt::KeyboardModifiers KWin::InputRedirection::keyboardModifiers() const
{
return Qt::NoModifier;
}
void KWin::InputRedirection::warpPointer(const QPointF&)
{
}
bool KWin::InputRedirection::supportsPointerWarping() const
{
return false;
}
QPointF KWin::InputRedirection::globalPointer() const
{
return QPointF();
}
diff --git a/kcmkwin/kwinrules/main.cpp b/kcmkwin/kwinrules/main.cpp
index f27a85633..a738442c6 100644
--- a/kcmkwin/kwinrules/main.cpp
+++ b/kcmkwin/kwinrules/main.cpp
@@ -1,284 +1,250 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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
#include
#include
#include
#include
#include "ruleswidget.h"
+#include "rulebooksettings.h"
#include "../../rules.h"
#include
#include
#include
#include
#include
#include
Q_DECLARE_METATYPE(NET::WindowType)
namespace KWin
{
-static void loadRules(QList< Rules* >& rules)
-{
- KConfig _cfg("kwinrulesrc", KConfig::NoGlobals);
- KConfigGroup cfg(&_cfg, "General");
- int count = cfg.readEntry("count", 0);
- for (int i = 1;
- i <= count;
- ++i) {
- cfg = KConfigGroup(&_cfg, QString::number(i));
- Rules* rule = new Rules(cfg);
- rules.append(rule);
- }
-}
-
-static void saveRules(const QList< Rules* >& rules)
-{
- KConfig cfg("kwinrulesrc", KConfig::NoGlobals);
- QStringList groups = cfg.groupList();
- for (QStringList::ConstIterator it = groups.constBegin();
- it != groups.constEnd();
- ++it)
- cfg.deleteGroup(*it);
- cfg.group("General").writeEntry("count", rules.count());
- int i = 1;
- for (QList< Rules* >::ConstIterator it = rules.constBegin();
- it != rules.constEnd();
- ++it) {
- KConfigGroup cg(&cfg, QString::number(i));
- (*it)->write(cg);
- ++i;
- }
-}
-
-static Rules* findRule(const QList< Rules* >& rules, const QVariantMap &data, bool whole_app)
+static Rules *findRule(const QVector &rules, const QVariantMap &data, bool whole_app)
{
QByteArray wmclass_class = data.value("resourceClass").toByteArray().toLower();
QByteArray wmclass_name = data.value("resourceName").toByteArray().toLower();
QByteArray role = data.value("role").toByteArray().toLower();
NET::WindowType type = data.value("type").value();
QString title = data.value("caption").toString();
QByteArray machine = data.value("clientMachine").toByteArray();
Rules* best_match = nullptr;
int match_quality = 0;
- for (QList< Rules* >::ConstIterator it = rules.constBegin();
- it != rules.constEnd();
- ++it) {
+ for (const auto rule : rules) {
// try to find an exact match, i.e. not a generic rule
- Rules* rule = *it;
int quality = 0;
bool generic = true;
if (rule->wmclassmatch != Rules::ExactMatch)
continue; // too generic
if (!rule->matchWMClass(wmclass_class, wmclass_name))
continue;
// from now on, it matches the app - now try to match for a specific window
if (rule->wmclasscomplete) {
quality += 1;
generic = false; // this can be considered specific enough (old X apps)
}
if (!whole_app) {
if (rule->windowrolematch != Rules::UnimportantMatch) {
quality += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
generic = false;
}
if (rule->titlematch != Rules::UnimportantMatch) {
quality += rule->titlematch == Rules::ExactMatch ? 3 : 1;
generic = false;
}
if (rule->types != NET::AllTypesMask) {
int bits = 0;
for (unsigned int bit = 1;
bit < 1U << 31;
bit <<= 1)
if (rule->types & bit)
++bits;
if (bits == 1)
quality += 2;
}
if (generic) // ignore generic rules, use only the ones that are for this window
continue;
} else {
if (rule->types == NET::AllTypesMask)
quality += 2;
}
if (!rule->matchType(type)
|| !rule->matchRole(role)
|| !rule->matchTitle(title)
|| !rule->matchClientMachine(machine, data.value("localhost").toBool()))
continue;
if (quality > match_quality) {
best_match = rule;
match_quality = quality;
}
}
if (best_match != nullptr)
return best_match;
Rules* ret = new Rules;
if (whole_app) {
ret->description = i18n("Application settings for %1", QString::fromLatin1(wmclass_class));
// TODO maybe exclude some types? If yes, then also exclude them above
// when searching.
ret->types = NET::AllTypesMask;
ret->titlematch = Rules::UnimportantMatch;
ret->clientmachine = machine; // set, but make unimportant
ret->clientmachinematch = Rules::UnimportantMatch;
ret->windowrolematch = Rules::UnimportantMatch;
if (wmclass_name == wmclass_class) {
ret->wmclasscomplete = false;
ret->wmclass = wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
} else {
// WM_CLASS components differ - perhaps the app got -name argument
ret->wmclasscomplete = true;
ret->wmclass = wmclass_name + ' ' + wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
}
return ret;
}
ret->description = i18n("Window settings for %1", QString::fromLatin1(wmclass_class));
if (type == NET::Unknown)
ret->types = NET::NormalMask;
else
ret->types = NET::WindowTypeMask( 1 << type); // convert type to its mask
ret->title = title; // set, but make unimportant
ret->titlematch = Rules::UnimportantMatch;
ret->clientmachine = machine; // set, but make unimportant
ret->clientmachinematch = Rules::UnimportantMatch;
if (!role.isEmpty()
&& role != "unknown" && role != "unnamed") { // Qt sets this if not specified
ret->windowrole = role;
ret->windowrolematch = Rules::ExactMatch;
if (wmclass_name == wmclass_class) {
ret->wmclasscomplete = false;
ret->wmclass = wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
} else {
// WM_CLASS components differ - perhaps the app got -name argument
ret->wmclasscomplete = true;
ret->wmclass = wmclass_name + ' ' + wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
}
} else { // no role set
if (wmclass_name != wmclass_class) {
ret->wmclasscomplete = true;
ret->wmclass = wmclass_name + ' ' + wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
} else {
// This is a window that has no role set, and both components of WM_CLASS
// match (possibly only differing in case), which most likely means either
// the application doesn't give a damn about distinguishing its various
// windows, or it's an app that uses role for that, but this window
// lacks it for some reason. Use non-complete WM_CLASS matching, also
// include window title in the matching, and pray it causes many more positive
// matches than negative matches.
ret->titlematch = Rules::ExactMatch;
ret->wmclasscomplete = false;
ret->wmclass = wmclass_class;
ret->wmclassmatch = Rules::ExactMatch;
}
}
return ret;
}
static void edit(const QVariantMap &data, bool whole_app)
{
- QList< Rules* > rules;
- loadRules(rules);
- Rules* orig_rule = findRule(rules, data, whole_app);
+ RuleBookSettings settings(KConfig::NoGlobals);
+ QVector rules = settings.rules();
+ Rules *orig_rule = findRule(rules, data, whole_app);
RulesDialog dlg;
if (whole_app)
dlg.setWindowTitle(i18nc("Window caption for the application wide rules dialog", "Edit Application-Specific Settings"));
// dlg.edit() creates new Rules instance if edited
Rules* edited_rule = dlg.edit(orig_rule, data, true);
if (edited_rule == nullptr || edited_rule->isEmpty()) {
rules.removeAll(orig_rule);
delete orig_rule;
if (orig_rule != edited_rule)
delete edited_rule;
} else if (edited_rule != orig_rule) {
int pos = rules.indexOf(orig_rule);
if (pos != -1)
rules[ pos ] = edited_rule;
else
rules.prepend(edited_rule);
delete orig_rule;
}
- saveRules(rules);
+ settings.setRules(rules);
+ settings.save();
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
qApp->quit();
}
} // namespace
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
app.setApplicationDisplayName(i18n("KWin"));
app.setApplicationName("kwin_rules_dialog");
app.setApplicationVersion("1.0");
bool whole_app = false;
QUuid uuid;
{
QCommandLineParser parser;
parser.setApplicationDescription(i18n("KWin helper utility"));
parser.addOption(QCommandLineOption("uuid", i18n("KWin id of the window for special window settings."), "uuid"));
parser.addOption(QCommandLineOption("whole-app", i18n("Whether the settings should affect all windows of the application.")));
parser.process(app);
uuid = QUuid::fromString(parser.value("uuid"));
whole_app = parser.isSet("whole-app");
}
if (uuid.isNull()) {
printf("%s\n", qPrintable(i18n("This helper utility is not supposed to be called directly.")));
return 1;
}
QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"),
QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("getWindowInfo"));
message.setArguments({uuid.toString()});
QDBusPendingReply async = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, &app);
QObject::connect(callWatcher, &QDBusPendingCallWatcher::finished, &app,
[&whole_app] (QDBusPendingCallWatcher *self) {
QDBusPendingReply reply = *self;
self->deleteLater();
if (!reply.isValid() || reply.value().isEmpty()) {
qApp->quit();
return;
}
KWin::edit(reply.value(), whole_app);
}
);
return app.exec();
}
diff --git a/kcmkwin/kwinrules/ruleslist.cpp b/kcmkwin/kwinrules/ruleslist.cpp
index f6180d7ab..e2550f9b6 100644
--- a/kcmkwin/kwinrules/ruleslist.cpp
+++ b/kcmkwin/kwinrules/ruleslist.cpp
@@ -1,263 +1,238 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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 "ruleslist.h"
#include
#include
#include
+#include "../../rules.h"
+#include "rulesettings.h"
#include "ruleswidget.h"
namespace KWin
{
KCMRulesList::KCMRulesList(QWidget* parent)
: QWidget(parent)
{
setupUi(this);
// connect both current/selected, so that current==selected (stupid QListBox :( )
connect(rules_listbox, SIGNAL(itemChanged(QListWidgetItem*)),
SLOT(activeChanged()));
connect(rules_listbox, SIGNAL(itemSelectionChanged()),
SLOT(activeChanged()));
connect(new_button, SIGNAL(clicked()),
SLOT(newClicked()));
connect(modify_button, SIGNAL(clicked()),
SLOT(modifyClicked()));
connect(delete_button, SIGNAL(clicked()),
SLOT(deleteClicked()));
connect(moveup_button, SIGNAL(clicked()),
SLOT(moveupClicked()));
connect(movedown_button, SIGNAL(clicked()),
SLOT(movedownClicked()));
connect(export_button, SIGNAL(clicked()),
SLOT(exportClicked()));
connect(import_button, SIGNAL(clicked()),
SLOT(importClicked()));
connect(rules_listbox, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
SLOT(modifyClicked()));
load();
}
KCMRulesList::~KCMRulesList()
{
- for (QVector< Rules* >::Iterator it = rules.begin();
- it != rules.end();
- ++it)
- delete *it;
- rules.clear();
+ qDeleteAll(m_rules);
+ m_rules.clear();
}
void KCMRulesList::activeChanged()
{
QListWidgetItem *item = rules_listbox->currentItem();
int itemRow = rules_listbox->row(item);
if (item != nullptr) // make current==selected
rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
modify_button->setEnabled(item != nullptr);
delete_button->setEnabled(item != nullptr);
export_button->setEnabled(item != nullptr);
moveup_button->setEnabled(item != nullptr && itemRow > 0);
movedown_button->setEnabled(item != nullptr && itemRow < (rules_listbox->count() - 1));
}
void KCMRulesList::newClicked()
{
RulesDialog dlg(this);
Rules* rule = dlg.edit(nullptr, {}, false);
if (rule == nullptr)
return;
int pos = rules_listbox->currentRow() + 1;
rules_listbox->insertItem(pos , rule->description);
rules_listbox->setCurrentRow(pos, QItemSelectionModel::ClearAndSelect);
- rules.insert(rules.begin() + pos, rule);
+ m_rules.insert(m_rules.begin() + pos, rule);
emit changed(true);
}
void KCMRulesList::modifyClicked()
{
int pos = rules_listbox->currentRow();
if (pos == -1)
return;
RulesDialog dlg(this);
- Rules* rule = dlg.edit(rules[ pos ], {}, false);
- if (rule == rules[ pos ])
+ Rules *rule = dlg.edit(m_rules[pos], {}, false);
+ if (rule == m_rules[pos])
return;
- delete rules[ pos ];
- rules[ pos ] = rule;
+ delete m_rules[pos];
+ m_rules[pos] = rule;
rules_listbox->item(pos)->setText(rule->description);
emit changed(true);
}
void KCMRulesList::deleteClicked()
{
int pos = rules_listbox->currentRow();
Q_ASSERT(pos != -1);
delete rules_listbox->takeItem(pos);
- rules.erase(rules.begin() + pos);
+ m_rules.erase(m_rules.begin() + pos);
emit changed(true);
}
void KCMRulesList::moveupClicked()
{
int pos = rules_listbox->currentRow();
Q_ASSERT(pos != -1);
if (pos > 0) {
QListWidgetItem * item = rules_listbox->takeItem(pos);
rules_listbox->insertItem(pos - 1 , item);
rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
- Rules* rule = rules[ pos ];
- rules[ pos ] = rules[ pos - 1 ];
- rules[ pos - 1 ] = rule;
+ Rules *rule = m_rules[pos];
+ m_rules[pos] = m_rules[pos - 1];
+ m_rules[pos - 1] = rule;
}
emit changed(true);
}
void KCMRulesList::movedownClicked()
{
int pos = rules_listbox->currentRow();
Q_ASSERT(pos != -1);
if (pos < int(rules_listbox->count()) - 1) {
QListWidgetItem * item = rules_listbox->takeItem(pos);
rules_listbox->insertItem(pos + 1 , item);
rules_listbox->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
- Rules* rule = rules[ pos ];
- rules[ pos ] = rules[ pos + 1 ];
- rules[ pos + 1 ] = rule;
+ Rules *rule = m_rules[pos];
+ m_rules[pos] = m_rules[pos + 1];
+ m_rules[pos + 1] = rule;
}
emit changed(true);
}
void KCMRulesList::exportClicked()
{
int pos = rules_listbox->currentRow();
Q_ASSERT(pos != -1);
QString path = QFileDialog::getSaveFileName(this, i18n("Export Rules"), QDir::home().absolutePath(),
i18n("KWin Rules (*.kwinrule)"));
if (path.isEmpty())
return;
- KConfig config(path, KConfig::SimpleConfig);
- KConfigGroup group(&config, rules[pos]->description);
- group.deleteGroup();
- rules[pos]->write(group);
+ const auto cfg = KSharedConfig::openConfig(path, KConfig::SimpleConfig);
+ RuleSettings settings(cfg, m_rules[pos]->description);
+ settings.setDefaults();
+ m_rules[pos]->write(&settings);
+ settings.save();
}
void KCMRulesList::importClicked()
{
QString path = QFileDialog::getOpenFileName(this, i18n("Import Rules"), QDir::home().absolutePath(),
i18n("KWin Rules (*.kwinrule)"));
if (path.isEmpty())
return;
- KConfig config(path, KConfig::SimpleConfig);
- QStringList groups = config.groupList();
+ const auto config = KSharedConfig::openConfig(path, KConfig::SimpleConfig);
+ QStringList groups = config->groupList();
if (groups.isEmpty())
return;
int pos = qMax(0, rules_listbox->currentRow());
- foreach (const QString &group, groups) {
- KConfigGroup grp(&config, group);
- const bool remove = grp.readEntry("DeleteRule", false);
- Rules* new_rule = new Rules(grp);
+ for (const QString &group : groups) {
+ RuleSettings settings(config, group);
+ const bool remove = settings.deleteRule();
+ Rules *new_rule = new Rules(&settings);
// try to replace existing rule first
- for (int i = 0; i < rules.count(); ++i) {
- if (rules[i]->description == new_rule->description) {
- delete rules[i];
+ for (int i = 0; i < m_rules.count(); ++i) {
+ if (m_rules[i]->description == new_rule->description) {
+ delete m_rules[i];
if (remove) {
- rules.remove(i);
+ m_rules.remove(i);
delete rules_listbox->takeItem(i);
delete new_rule;
pos = qMax(0, rules_listbox->currentRow()); // might have changed!
- }
- else
- rules[i] = new_rule;
+ } else
+ m_rules[i] = new_rule;
new_rule = nullptr;
break;
}
}
// don't add "to be deleted" if not present
if (remove) {
delete new_rule;
new_rule = nullptr;
}
// plain insertion
if (new_rule) {
- rules.insert(pos, new_rule);
+ m_rules.insert(pos, new_rule);
rules_listbox->insertItem(pos++, new_rule->description);
}
}
emit changed(true);
}
void KCMRulesList::load()
{
rules_listbox->clear();
- for (QVector< Rules* >::Iterator it = rules.begin();
- it != rules.end();
- ++it)
- delete *it;
- rules.clear();
- KConfig _cfg("kwinrulesrc");
- KConfigGroup cfg(&_cfg, "General");
- int count = cfg.readEntry("count", 0);
- rules.reserve(count);
- for (int i = 1;
- i <= count;
- ++i) {
- cfg = KConfigGroup(&_cfg, QString::number(i));
- Rules* rule = new Rules(cfg);
- rules.append(rule);
+ m_settings.load();
+ m_rules = m_settings.rules();
+ for (const auto rule : qAsConst(m_rules)) {
rules_listbox->addItem(rule->description);
}
- if (rules.count() > 0)
+
+ if (m_rules.count() > 0)
rules_listbox->setCurrentItem(rules_listbox->item(0));
else
rules_listbox->setCurrentItem(nullptr);
activeChanged();
}
void KCMRulesList::save()
{
- KConfig cfg(QLatin1String("kwinrulesrc"));
- QStringList groups = cfg.groupList();
- for (QStringList::ConstIterator it = groups.constBegin();
- it != groups.constEnd();
- ++it)
- cfg.deleteGroup(*it);
- cfg.group("General").writeEntry("count", rules.count());
- int i = 1;
- for (QVector< Rules* >::ConstIterator it = rules.constBegin();
- it != rules.constEnd();
- ++it) {
- KConfigGroup cg(&cfg, QString::number(i));
- (*it)->write(cg);
- ++i;
- }
+ m_settings.setRules(m_rules);
+ m_settings.save();
}
void KCMRulesList::defaults()
{
load();
}
} // namespace
diff --git a/kcmkwin/kwinrules/ruleslist.h b/kcmkwin/kwinrules/ruleslist.h
index c480d1081..81e846777 100644
--- a/kcmkwin/kwinrules/ruleslist.h
+++ b/kcmkwin/kwinrules/ruleslist.h
@@ -1,57 +1,58 @@
/*
* Copyright (c) 2004 Lubos Lunak
*
* 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 __RULESLIST_H__
#define __RULESLIST_H__
-#include "../../rules.h"
-
#include "ui_ruleslist.h"
+#include "rulebooksettings.h"
namespace KWin
{
+class Rules;
class KCMRulesList
: public QWidget, Ui_KCMRulesList
{
Q_OBJECT
public:
explicit KCMRulesList(QWidget* parent = nullptr);
~KCMRulesList() override;
void load();
void save();
void defaults();
Q_SIGNALS:
void changed(bool);
private Q_SLOTS:
void newClicked();
void modifyClicked();
void deleteClicked();
void moveupClicked();
void movedownClicked();
void exportClicked();
void importClicked();
void activeChanged();
private:
- QVector< Rules* > rules;
+ QVector m_rules;
+ RuleBookSettings m_settings;
};
} // namespace
#endif
diff --git a/rulebooksettings.cpp b/rulebooksettings.cpp
new file mode 100644
index 000000000..b3cba6d2f
--- /dev/null
+++ b/rulebooksettings.cpp
@@ -0,0 +1,108 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2020 Henri Chain
+
+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, see .
+*********************************************************************/
+
+#include "rulebooksettings.h"
+#include "rulesettings.h"
+
+namespace KWin
+{
+RuleBookSettings::RuleBookSettings(KSharedConfig::Ptr config, QObject *parent)
+ : RuleBookSettingsBase(config, parent)
+{
+ for (int i = 1; i <= count(); i++) {
+ m_list.append(new RuleSettings(config, QString::number(i), this));
+ }
+}
+
+RuleBookSettings::RuleBookSettings(const QString &configname, KConfig::OpenFlags flags, QObject *parent)
+ : RuleBookSettings(KSharedConfig::openConfig(configname, flags), parent)
+{
+}
+
+RuleBookSettings::RuleBookSettings(KConfig::OpenFlags flags, QObject *parent)
+ : RuleBookSettings(QStringLiteral("kwinrulesrc"), flags, parent)
+{
+}
+
+RuleBookSettings::RuleBookSettings(QObject *parent)
+ : RuleBookSettings(KConfig::FullConfig, parent)
+{
+}
+
+void RuleBookSettings::setRules(const QVector &rules)
+{
+ int i = 1;
+ const int list_length = m_list.length();
+ for (const auto &rule : rules) {
+ RuleSettings *settings;
+ if (i <= list_length) {
+ settings = m_list[i - 1];
+ settings->setDefaults();
+ } else {
+ // If there are more rules than in cache
+ settings = new RuleSettings(this->sharedConfig(), QString::number(i), this);
+ m_list.append(settings);
+ }
+ rule->write(settings);
+ i++;
+ }
+
+ setCount(rules.length());
+}
+
+QVector RuleBookSettings::rules()
+{
+ QVector result;
+ result.reserve(mCount);
+ // mCount is always <= m_list.length()
+ for (int i = 0; i < mCount; i++) {
+ result.append(new Rules(m_list[i]));
+ }
+ return result;
+}
+
+bool RuleBookSettings::usrSave()
+{
+ bool result = true;
+ for (const auto &settings : qAsConst(m_list)) {
+ result &= settings->save();
+ }
+ int nRuleGroups = sharedConfig()->groupList().length() - 1;
+ // Remove any extra groups currently in config
+ for (int i = mCount + 1; i <= nRuleGroups; i++) {
+ sharedConfig()->deleteGroup(QString::number(i));
+ }
+ return result;
+}
+
+void RuleBookSettings::usrRead()
+{
+ const int list_length = m_list.length();
+ for (int i = 1; i <= mCount; i++) {
+ if (i <= list_length) {
+ m_list[i - 1]->load();
+ } else {
+ // If there are more groups than in cache
+ m_list.append(new RuleSettings(sharedConfig(), QString::number(i), this));
+ }
+ }
+}
+
+}
diff --git a/rulebooksettings.h b/rulebooksettings.h
new file mode 100644
index 000000000..5b7579b58
--- /dev/null
+++ b/rulebooksettings.h
@@ -0,0 +1,50 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2020 Henri Chain
+
+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, see .
+*********************************************************************/
+
+#ifndef RULEBOOKSETTINGS_H
+#define RULEBOOKSETTINGS_H
+
+#include "rulebooksettingsbase.h"
+#include
+
+namespace KWin
+{
+class Rules;
+class RuleSettings;
+
+class RuleBookSettings : public RuleBookSettingsBase
+{
+public:
+ RuleBookSettings(KSharedConfig::Ptr config, QObject *parent = nullptr);
+ RuleBookSettings(const QString &configname, KConfig::OpenFlags, QObject *parent = nullptr);
+ RuleBookSettings(KConfig::OpenFlags, QObject *parent = nullptr);
+ RuleBookSettings(QObject *parent = nullptr);
+ void setRules(const QVector &);
+ QVector rules();
+ bool usrSave() override;
+ void usrRead() override;
+
+private:
+ QVector m_list;
+};
+
+}
+
+#endif // RULEBOOKSETTINGS_H
diff --git a/rulebooksettingsbase.kcfg b/rulebooksettingsbase.kcfg
new file mode 100644
index 000000000..4a64810f3
--- /dev/null
+++ b/rulebooksettingsbase.kcfg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ 0
+
+
+
diff --git a/rulebooksettingsbase.kcfgc b/rulebooksettingsbase.kcfgc
new file mode 100644
index 000000000..d2a5b8277
--- /dev/null
+++ b/rulebooksettingsbase.kcfgc
@@ -0,0 +1,5 @@
+File=rulebooksettingsbase.kcfg
+NameSpace=KWin
+ClassName=RuleBookSettingsBase
+Mutators=true
+ParentInConstructor=true
diff --git a/rules.cpp b/rules.cpp
index 135f1060b..ed7484114 100644
--- a/rules.cpp
+++ b/rules.cpp
@@ -1,1178 +1,1117 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2004 Lubos Lunak
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, see .
*********************************************************************/
#include "rules.h"
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef KCMRULES
#include "x11client.h"
#include "client_machine.h"
#include "screens.h"
#include "workspace.h"
#endif
+#include "rulesettings.h"
+#include "rulebooksettings.h"
+
namespace KWin
{
Rules::Rules()
: temporary_state(0)
, wmclassmatch(UnimportantMatch)
, wmclasscomplete(UnimportantMatch)
, windowrolematch(UnimportantMatch)
, titlematch(UnimportantMatch)
, clientmachinematch(UnimportantMatch)
, types(NET::AllTypesMask)
, placementrule(UnusedForceRule)
, positionrule(UnusedSetRule)
, sizerule(UnusedSetRule)
, minsizerule(UnusedForceRule)
, maxsizerule(UnusedForceRule)
, opacityactiverule(UnusedForceRule)
, opacityinactiverule(UnusedForceRule)
, ignoregeometryrule(UnusedSetRule)
, desktoprule(UnusedSetRule)
, screenrule(UnusedSetRule)
, activityrule(UnusedSetRule)
, typerule(UnusedForceRule)
, maximizevertrule(UnusedSetRule)
, maximizehorizrule(UnusedSetRule)
, minimizerule(UnusedSetRule)
, shaderule(UnusedSetRule)
, skiptaskbarrule(UnusedSetRule)
, skippagerrule(UnusedSetRule)
, skipswitcherrule(UnusedSetRule)
, aboverule(UnusedSetRule)
, belowrule(UnusedSetRule)
, fullscreenrule(UnusedSetRule)
, noborderrule(UnusedSetRule)
, decocolorrule(UnusedForceRule)
, blockcompositingrule(UnusedForceRule)
, fsplevelrule(UnusedForceRule)
, fpplevelrule(UnusedForceRule)
, acceptfocusrule(UnusedForceRule)
, closeablerule(UnusedForceRule)
, autogrouprule(UnusedForceRule)
, autogroupfgrule(UnusedForceRule)
, autogroupidrule(UnusedForceRule)
, strictgeometryrule(UnusedForceRule)
, shortcutrule(UnusedSetRule)
, disableglobalshortcutsrule(UnusedForceRule)
, desktopfilerule(UnusedSetRule)
{
}
Rules::Rules(const QString& str, bool temporary)
: temporary_state(temporary ? 2 : 0)
{
QTemporaryFile file;
if (file.open()) {
QByteArray s = str.toUtf8();
file.write(s.data(), s.length());
}
file.flush();
- KConfig cfg(file.fileName(), KConfig::SimpleConfig);
- readFromCfg(cfg.group(QString()));
+ auto cfg = KSharedConfig::openConfig(file.fileName(), KConfig::SimpleConfig);
+ RuleSettings settings(cfg, QString());
+ readFromSettings(&settings);
if (description.isEmpty())
description = QStringLiteral("temporary");
}
-#define READ_MATCH_STRING( var, func ) \
- var = cfg.readEntry( #var ) func; \
- var##match = (StringMatch) qMax( FirstStringMatch, \
- qMin( LastStringMatch, static_cast< StringMatch >( cfg.readEntry( #var "match",0 ))));
-
-#define READ_SET_RULE( var, func, def ) \
- var = func ( cfg.readEntry( #var, def)); \
- var##rule = readSetRule( cfg, QStringLiteral( #var "rule" ) );
-
-#define READ_SET_RULE_DEF( var , func, def ) \
- var = func ( cfg.readEntry( #var, def )); \
- var##rule = readSetRule( cfg, QStringLiteral( #var "rule" ) );
-
-#define READ_FORCE_RULE( var, func, def) \
- var = func ( cfg.readEntry( #var, def)); \
- var##rule = readForceRule( cfg, QStringLiteral( #var "rule" ) );
+#define READ_MATCH_STRING(var, func) \
+ var = settings->var() func; \
+ var##match = static_cast(settings->var##match())
-#define READ_FORCE_RULE2( var, def, func, funcarg ) \
- var = func ( cfg.readEntry( #var, def),funcarg ); \
- var##rule = readForceRule( cfg, QStringLiteral( #var "rule" ) );
+#define READ_SET_RULE(var) \
+ var = settings->var(); \
+ var##rule = static_cast(settings->var##rule())
+#define READ_FORCE_RULE(var, func) \
+ var = func(settings->var()); \
+ var##rule = convertForceRule(settings->var##rule())
-Rules::Rules(const KConfigGroup& cfg)
+Rules::Rules(const RuleSettings *settings)
: temporary_state(0)
{
- readFromCfg(cfg);
-}
-
-static int limit0to4(int i)
-{
- return qMax(0, qMin(4, i));
+ readFromSettings(settings);
}
-void Rules::readFromCfg(const KConfigGroup& cfg)
+void Rules::readFromSettings(const RuleSettings *settings)
{
- description = cfg.readEntry("Description");
- if (description.isEmpty()) // capitalized first, lowercase for backwards compatibility
- description = cfg.readEntry("description");
+ description = settings->description();
+ if (description.isEmpty()) {
+ description = settings->descriptionLegacy();
+ }
READ_MATCH_STRING(wmclass, .toLower().toLatin1());
- wmclasscomplete = cfg.readEntry("wmclasscomplete" , false);
+ wmclasscomplete = settings->wmclasscomplete();
READ_MATCH_STRING(windowrole, .toLower().toLatin1());
READ_MATCH_STRING(title,);
READ_MATCH_STRING(clientmachine, .toLower().toLatin1());
- types = NET::WindowTypeMask(cfg.readEntry("types", NET::AllTypesMask));
- READ_FORCE_RULE2(placement, QString(), Placement::policyFromString, false);
- READ_SET_RULE_DEF(position, , invalidPoint);
- READ_SET_RULE(size, , QSize());
- if (size.isEmpty() && sizerule != (SetRule)Remember)
+ types = NET::WindowTypeMask(settings->types());
+ READ_FORCE_RULE(placement,);
+ READ_SET_RULE(position);
+ READ_SET_RULE(size);
+ if (size.isEmpty() && sizerule != static_cast(Remember))
sizerule = UnusedSetRule;
- READ_FORCE_RULE(minsize, , QSize());
+ READ_FORCE_RULE(minsize,);
if (!minsize.isValid())
minsize = QSize(1, 1);
- READ_FORCE_RULE(maxsize, , QSize());
+ READ_FORCE_RULE(maxsize,);
if (maxsize.isEmpty())
maxsize = QSize(32767, 32767);
- READ_FORCE_RULE(opacityactive, , 0);
- if (opacityactive < 0 || opacityactive > 100)
- opacityactive = 100;
- READ_FORCE_RULE(opacityinactive, , 0);
- if (opacityinactive < 0 || opacityinactive > 100)
- opacityinactive = 100;
- READ_SET_RULE(ignoregeometry, , false);
- READ_SET_RULE(desktop, , 0);
- READ_SET_RULE(screen, , 0);
- READ_SET_RULE(activity, , QString());
- type = readType(cfg, QStringLiteral("type"));
- typerule = type != NET::Unknown ? readForceRule(cfg, QStringLiteral("typerule")) : UnusedForceRule;
- READ_SET_RULE(maximizevert, , false);
- READ_SET_RULE(maximizehoriz, , false);
- READ_SET_RULE(minimize, , false);
- READ_SET_RULE(shade, , false);
- READ_SET_RULE(skiptaskbar, , false);
- READ_SET_RULE(skippager, , false);
- READ_SET_RULE(skipswitcher, , false);
- READ_SET_RULE(above, , false);
- READ_SET_RULE(below, , false);
- READ_SET_RULE(fullscreen, , false);
- READ_SET_RULE(noborder, , false);
- decocolor = readDecoColor(cfg);
- decocolorrule = decocolor.isEmpty() ? UnusedForceRule : readForceRule(cfg, QStringLiteral("decocolorrule"));
- READ_FORCE_RULE(blockcompositing, , false);
- READ_FORCE_RULE(fsplevel, limit0to4, 0); // fsp is 0-4
- READ_FORCE_RULE(fpplevel, limit0to4, 0); // fpp is 0-4
- READ_FORCE_RULE(acceptfocus, , false);
- READ_FORCE_RULE(closeable, , false);
- READ_FORCE_RULE(autogroup, , false);
- READ_FORCE_RULE(autogroupfg, , true);
- READ_FORCE_RULE(autogroupid, , QString());
- READ_FORCE_RULE(strictgeometry, , false);
- READ_SET_RULE(shortcut, , QString());
- READ_FORCE_RULE(disableglobalshortcuts, , false);
- READ_SET_RULE(desktopfile, , QString());
+ READ_FORCE_RULE(opacityactive,);
+ READ_FORCE_RULE(opacityinactive,);
+ READ_SET_RULE(ignoregeometry);
+ READ_SET_RULE(desktop);
+ READ_SET_RULE(screen);
+ READ_SET_RULE(activity);
+ READ_FORCE_RULE(type, static_cast);
+ if (type == NET::Unknown)
+ typerule = UnusedForceRule;
+ READ_SET_RULE(maximizevert);
+ READ_SET_RULE(maximizehoriz);
+ READ_SET_RULE(minimize);
+ READ_SET_RULE(shade);
+ READ_SET_RULE(skiptaskbar);
+ READ_SET_RULE(skippager);
+ READ_SET_RULE(skipswitcher);
+ READ_SET_RULE(above);
+ READ_SET_RULE(below);
+ READ_SET_RULE(fullscreen);
+ READ_SET_RULE(noborder);
+
+ READ_FORCE_RULE(decocolor, getDecoColor);
+ if (decocolor.isEmpty())
+ decocolorrule = UnusedForceRule;
+
+ READ_FORCE_RULE(blockcompositing,);
+ READ_FORCE_RULE(fsplevel,);
+ READ_FORCE_RULE(fpplevel,);
+ READ_FORCE_RULE(acceptfocus,);
+ READ_FORCE_RULE(closeable,);
+ READ_FORCE_RULE(autogroup,);
+ READ_FORCE_RULE(autogroupfg,);
+ READ_FORCE_RULE(autogroupid,);
+ READ_FORCE_RULE(strictgeometry,);
+ READ_SET_RULE(shortcut);
+ READ_FORCE_RULE(disableglobalshortcuts,);
+ READ_SET_RULE(desktopfile);
}
#undef READ_MATCH_STRING
#undef READ_SET_RULE
#undef READ_FORCE_RULE
#undef READ_FORCE_RULE2
-#define WRITE_MATCH_STRING( var, force ) \
- if ( !var.isEmpty() || force ) \
- { \
- cfg.writeEntry( #var, var ); \
- cfg.writeEntry( #var "match", (int)var##match ); \
- } \
- else \
+#define WRITE_MATCH_STRING(var, capital, force) \
+ settings->set##capital##match(var##match); \
+ if (!var.isEmpty() || force) \
{ \
- cfg.deleteEntry( #var ); \
- cfg.deleteEntry( #var "match" ); \
+ settings->set##capital(var); \
}
-#define WRITE_SET_RULE( var, func ) \
- if ( var##rule != UnusedSetRule ) \
- { \
- cfg.writeEntry( #var, func ( var )); \
- cfg.writeEntry( #var "rule", (int)var##rule ); \
- } \
- else \
+#define WRITE_SET_RULE(var, capital, func) \
+ settings->set##capital##rule(var##rule); \
+ if (var##rule != UnusedSetRule) \
{ \
- cfg.deleteEntry( #var ); \
- cfg.deleteEntry( #var "rule" ); \
+ settings->set##capital(func(var)); \
}
-#define WRITE_FORCE_RULE( var, func ) \
+#define WRITE_FORCE_RULE(var, capital, func) \
+ settings->set##capital##rule(var##rule); \
if ( var##rule != UnusedForceRule ) \
{ \
- cfg.writeEntry( #var, func ( var )); \
- cfg.writeEntry( #var "rule", (int)var##rule ); \
- } \
- else \
- { \
- cfg.deleteEntry( #var ); \
- cfg.deleteEntry( #var "rule" ); \
+ settings->set##capital(func(var)); \
}
-void Rules::write(KConfigGroup& cfg) const
+void Rules::write(RuleSettings *settings) const
{
- cfg.writeEntry("Description", description);
+ settings->setDescription(description);
// always write wmclass
- WRITE_MATCH_STRING(wmclass, true);
- cfg.writeEntry("wmclasscomplete", wmclasscomplete);
- WRITE_MATCH_STRING(windowrole, false);
- WRITE_MATCH_STRING(title, false);
- WRITE_MATCH_STRING(clientmachine, false);
- if (types != NET::AllTypesMask)
- cfg.writeEntry("types", uint(types));
- else
- cfg.deleteEntry("types");
- WRITE_FORCE_RULE(placement, Placement::policyToString);
- WRITE_SET_RULE(position,);
- WRITE_SET_RULE(size,);
- WRITE_FORCE_RULE(minsize,);
- WRITE_FORCE_RULE(maxsize,);
- WRITE_FORCE_RULE(opacityactive,);
- WRITE_FORCE_RULE(opacityinactive,);
- WRITE_SET_RULE(ignoregeometry,);
- WRITE_SET_RULE(desktop,);
- WRITE_SET_RULE(screen,);
- WRITE_SET_RULE(activity,);
- WRITE_FORCE_RULE(type, int);
- WRITE_SET_RULE(maximizevert,);
- WRITE_SET_RULE(maximizehoriz,);
- WRITE_SET_RULE(minimize,);
- WRITE_SET_RULE(shade,);
- WRITE_SET_RULE(skiptaskbar,);
- WRITE_SET_RULE(skippager,);
- WRITE_SET_RULE(skipswitcher,);
- WRITE_SET_RULE(above,);
- WRITE_SET_RULE(below,);
- WRITE_SET_RULE(fullscreen,);
- WRITE_SET_RULE(noborder,);
+ WRITE_MATCH_STRING(wmclass, Wmclass, true);
+ settings->setWmclasscomplete(wmclasscomplete);
+ WRITE_MATCH_STRING(windowrole, Windowrole, false);
+ WRITE_MATCH_STRING(title, Title, false);
+ WRITE_MATCH_STRING(clientmachine, Clientmachine, false);
+ settings->setTypes(types);
+ WRITE_FORCE_RULE(placement, Placement,);
+ WRITE_SET_RULE(position, Position,);
+ WRITE_SET_RULE(size, Size,);
+ WRITE_FORCE_RULE(minsize, Minsize,);
+ WRITE_FORCE_RULE(maxsize, Maxsize,);
+ WRITE_FORCE_RULE(opacityactive, Opacityactive,);
+ WRITE_FORCE_RULE(opacityinactive, Opacityinactive,);
+ WRITE_SET_RULE(ignoregeometry, Ignoregeometry,);
+ WRITE_SET_RULE(desktop, Desktop,);
+ WRITE_SET_RULE(screen, Screen,);
+ WRITE_SET_RULE(activity, Activity,);
+ WRITE_FORCE_RULE(type, Type,);
+ WRITE_SET_RULE(maximizevert, Maximizevert,);
+ WRITE_SET_RULE(maximizehoriz, Maximizehoriz,);
+ WRITE_SET_RULE(minimize, Minimize,);
+ WRITE_SET_RULE(shade, Shade,);
+ WRITE_SET_RULE(skiptaskbar, Skiptaskbar,);
+ WRITE_SET_RULE(skippager, Skippager,);
+ WRITE_SET_RULE(skipswitcher, Skipswitcher,);
+ WRITE_SET_RULE(above, Above,);
+ WRITE_SET_RULE(below, Below,);
+ WRITE_SET_RULE(fullscreen, Fullscreen,);
+ WRITE_SET_RULE(noborder, Noborder,);
auto colorToString = [](const QString &value) -> QString {
if (value.endsWith(QLatin1String(".colors"))) {
return QFileInfo(value).baseName();
} else {
return value;
}
};
- WRITE_FORCE_RULE(decocolor, colorToString);
- WRITE_FORCE_RULE(blockcompositing,);
- WRITE_FORCE_RULE(fsplevel,);
- WRITE_FORCE_RULE(fpplevel,);
- WRITE_FORCE_RULE(acceptfocus,);
- WRITE_FORCE_RULE(closeable,);
- WRITE_FORCE_RULE(autogroup,);
- WRITE_FORCE_RULE(autogroupfg,);
- WRITE_FORCE_RULE(autogroupid,);
- WRITE_FORCE_RULE(strictgeometry,);
- WRITE_SET_RULE(shortcut,);
- WRITE_FORCE_RULE(disableglobalshortcuts,);
- WRITE_SET_RULE(desktopfile,);
+ WRITE_FORCE_RULE(decocolor, Decocolor, colorToString);
+ WRITE_FORCE_RULE(blockcompositing, Blockcompositing,);
+ WRITE_FORCE_RULE(fsplevel, Fsplevel,);
+ WRITE_FORCE_RULE(fpplevel, Fpplevel,);
+ WRITE_FORCE_RULE(acceptfocus, Acceptfocus,);
+ WRITE_FORCE_RULE(closeable, Closeable,);
+ WRITE_FORCE_RULE(autogroup, Autogroup,);
+ WRITE_FORCE_RULE(autogroupfg, Autogroupfg,);
+ WRITE_FORCE_RULE(autogroupid, Autogroupid,);
+ WRITE_FORCE_RULE(strictgeometry, Strictgeometry,);
+ WRITE_SET_RULE(shortcut, Shortcut,);
+ WRITE_FORCE_RULE(disableglobalshortcuts, Disableglobalshortcuts,);
+ WRITE_SET_RULE(desktopfile, Desktopfile,);
}
#undef WRITE_MATCH_STRING
#undef WRITE_SET_RULE
#undef WRITE_FORCE_RULE
// returns true if it doesn't affect anything
bool Rules::isEmpty() const
{
return(placementrule == UnusedForceRule
&& positionrule == UnusedSetRule
&& sizerule == UnusedSetRule
&& minsizerule == UnusedForceRule
&& maxsizerule == UnusedForceRule
&& opacityactiverule == UnusedForceRule
&& opacityinactiverule == UnusedForceRule
&& ignoregeometryrule == UnusedSetRule
&& desktoprule == UnusedSetRule
&& screenrule == UnusedSetRule
&& activityrule == UnusedSetRule
&& typerule == UnusedForceRule
&& maximizevertrule == UnusedSetRule
&& maximizehorizrule == UnusedSetRule
&& minimizerule == UnusedSetRule
&& shaderule == UnusedSetRule
&& skiptaskbarrule == UnusedSetRule
&& skippagerrule == UnusedSetRule
&& skipswitcherrule == UnusedSetRule
&& aboverule == UnusedSetRule
&& belowrule == UnusedSetRule
&& fullscreenrule == UnusedSetRule
&& noborderrule == UnusedSetRule
&& decocolorrule == UnusedForceRule
&& blockcompositingrule == UnusedForceRule
&& fsplevelrule == UnusedForceRule
&& fpplevelrule == UnusedForceRule
&& acceptfocusrule == UnusedForceRule
&& closeablerule == UnusedForceRule
&& autogrouprule == UnusedForceRule
&& autogroupfgrule == UnusedForceRule
&& autogroupidrule == UnusedForceRule
&& strictgeometryrule == UnusedForceRule
&& shortcutrule == UnusedSetRule
&& disableglobalshortcutsrule == UnusedForceRule
&& desktopfilerule == UnusedSetRule);
}
-Rules::SetRule Rules::readSetRule(const KConfigGroup& cfg, const QString& key)
+Rules::ForceRule Rules::convertForceRule(int v)
{
- int v = cfg.readEntry(key, 0);
- if (v >= DontAffect && v <= ForceTemporarily)
- return static_cast< SetRule >(v);
- return UnusedSetRule;
-}
-
-Rules::ForceRule Rules::readForceRule(const KConfigGroup& cfg, const QString& key)
-{
- int v = cfg.readEntry(key, 0);
if (v == DontAffect || v == Force || v == ForceTemporarily)
- return static_cast< ForceRule >(v);
+ return static_cast(v);
return UnusedForceRule;
}
-NET::WindowType Rules::readType(const KConfigGroup& cfg, const QString& key)
-{
- int v = cfg.readEntry(key, 0);
- if (v >= NET::Normal && v <= NET::Splash)
- return static_cast< NET::WindowType >(v);
- return NET::Unknown;
-}
-
-QString Rules::readDecoColor(const KConfigGroup &cfg)
+QString Rules::getDecoColor(const QString &themeName)
{
- QString themeName = cfg.readEntry("decocolor", QString());
if (themeName.isEmpty()) {
return QString();
}
// find the actual scheme file
return QStandardPaths::locate(QStandardPaths::GenericDataLocation,
QLatin1String("color-schemes/") + themeName + QLatin1String(".colors"));
}
bool Rules::matchType(NET::WindowType match_type) const
{
if (types != NET::AllTypesMask) {
if (match_type == NET::Unknown)
match_type = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
if (!NET::typeMatchesMask(match_type, types))
return false;
}
return true;
}
bool Rules::matchWMClass(const QByteArray& match_class, const QByteArray& match_name) const
{
if (wmclassmatch != UnimportantMatch) {
// TODO optimize?
QByteArray cwmclass = wmclasscomplete
? match_name + ' ' + match_class : match_class;
if (wmclassmatch == RegExpMatch && QRegExp(QString::fromUtf8(wmclass)).indexIn(QString::fromUtf8(cwmclass)) == -1)
return false;
if (wmclassmatch == ExactMatch && wmclass != cwmclass)
return false;
if (wmclassmatch == SubstringMatch && !cwmclass.contains(wmclass))
return false;
}
return true;
}
bool Rules::matchRole(const QByteArray& match_role) const
{
if (windowrolematch != UnimportantMatch) {
if (windowrolematch == RegExpMatch && QRegExp(QString::fromUtf8(windowrole)).indexIn(QString::fromUtf8(match_role)) == -1)
return false;
if (windowrolematch == ExactMatch && windowrole != match_role)
return false;
if (windowrolematch == SubstringMatch && !match_role.contains(windowrole))
return false;
}
return true;
}
bool Rules::matchTitle(const QString& match_title) const
{
if (titlematch != UnimportantMatch) {
if (titlematch == RegExpMatch && QRegExp(title).indexIn(match_title) == -1)
return false;
if (titlematch == ExactMatch && title != match_title)
return false;
if (titlematch == SubstringMatch && !match_title.contains(title))
return false;
}
return true;
}
bool Rules::matchClientMachine(const QByteArray& match_machine, bool local) const
{
if (clientmachinematch != UnimportantMatch) {
// if it's localhost, check also "localhost" before checking hostname
if (match_machine != "localhost" && local
&& matchClientMachine("localhost", true))
return true;
if (clientmachinematch == RegExpMatch
&& QRegExp(QString::fromUtf8(clientmachine)).indexIn(QString::fromUtf8(match_machine)) == -1)
return false;
if (clientmachinematch == ExactMatch
&& clientmachine != match_machine)
return false;
if (clientmachinematch == SubstringMatch
&& !match_machine.contains(clientmachine))
return false;
}
return true;
}
#ifndef KCMRULES
bool Rules::match(const AbstractClient* c) const
{
if (!matchType(c->windowType(true)))
return false;
if (!matchWMClass(c->resourceClass(), c->resourceName()))
return false;
if (!matchRole(c->windowRole().toLower()))
return false;
if (!matchClientMachine(c->clientMachine()->hostName(), c->clientMachine()->isLocal()))
return false;
if (titlematch != UnimportantMatch) // track title changes to rematch rules
QObject::connect(c, &AbstractClient::captionChanged, c, &AbstractClient::evaluateWindowRules,
// QueuedConnection, because title may change before
// the client is ready (could segfault!)
static_cast(Qt::QueuedConnection|Qt::UniqueConnection));
if (!matchTitle(c->captionNormal()))
return false;
return true;
}
#define NOW_REMEMBER(_T_, _V_) ((selection & _T_) && (_V_##rule == (SetRule)Remember))
bool Rules::update(AbstractClient* c, int selection)
{
// TODO check this setting is for this client ?
bool updated = false;
if NOW_REMEMBER(Position, position) {
if (!c->isFullScreen()) {
QPoint new_pos = position;
// don't use the position in the direction which is maximized
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
new_pos.setX(c->pos().x());
if ((c->maximizeMode() & MaximizeVertical) == 0)
new_pos.setY(c->pos().y());
updated = updated || position != new_pos;
position = new_pos;
}
}
if NOW_REMEMBER(Size, size) {
if (!c->isFullScreen()) {
QSize new_size = size;
// don't use the position in the direction which is maximized
if ((c->maximizeMode() & MaximizeHorizontal) == 0)
new_size.setWidth(c->size().width());
if ((c->maximizeMode() & MaximizeVertical) == 0)
new_size.setHeight(c->size().height());
updated = updated || size != new_size;
size = new_size;
}
}
if NOW_REMEMBER(Desktop, desktop) {
updated = updated || desktop != c->desktop();
desktop = c->desktop();
}
if NOW_REMEMBER(Screen, screen) {
updated = updated || screen != c->screen();
screen = c->screen();
}
if NOW_REMEMBER(Activity, activity) {
// TODO: ivan - multiple activities support
const QString & joinedActivities = c->activities().join(QStringLiteral(","));
updated = updated || activity != joinedActivities;
activity = joinedActivities;
}
if NOW_REMEMBER(MaximizeVert, maximizevert) {
updated = updated || maximizevert != bool(c->maximizeMode() & MaximizeVertical);
maximizevert = c->maximizeMode() & MaximizeVertical;
}
if NOW_REMEMBER(MaximizeHoriz, maximizehoriz) {
updated = updated || maximizehoriz != bool(c->maximizeMode() & MaximizeHorizontal);
maximizehoriz = c->maximizeMode() & MaximizeHorizontal;
}
if NOW_REMEMBER(Minimize, minimize) {
updated = updated || minimize != c->isMinimized();
minimize = c->isMinimized();
}
if NOW_REMEMBER(Shade, shade) {
updated = updated || (shade != (c->shadeMode() != ShadeNone));
shade = c->shadeMode() != ShadeNone;
}
if NOW_REMEMBER(SkipTaskbar, skiptaskbar) {
updated = updated || skiptaskbar != c->skipTaskbar();
skiptaskbar = c->skipTaskbar();
}
if NOW_REMEMBER(SkipPager, skippager) {
updated = updated || skippager != c->skipPager();
skippager = c->skipPager();
}
if NOW_REMEMBER(SkipSwitcher, skipswitcher) {
updated = updated || skipswitcher != c->skipSwitcher();
skipswitcher = c->skipSwitcher();
}
if NOW_REMEMBER(Above, above) {
updated = updated || above != c->keepAbove();
above = c->keepAbove();
}
if NOW_REMEMBER(Below, below) {
updated = updated || below != c->keepBelow();
below = c->keepBelow();
}
if NOW_REMEMBER(Fullscreen, fullscreen) {
updated = updated || fullscreen != c->isFullScreen();
fullscreen = c->isFullScreen();
}
if NOW_REMEMBER(NoBorder, noborder) {
updated = updated || noborder != c->noBorder();
noborder = c->noBorder();
}
if NOW_REMEMBER(DesktopFile, desktopfile) {
updated = updated || desktopfile != c->desktopFileName();
desktopfile = c->desktopFileName();
}
return updated;
}
#undef NOW_REMEMBER
#define APPLY_RULE( var, name, type ) \
bool Rules::apply##name( type& arg, bool init ) const \
{ \
if ( checkSetRule( var##rule, init )) \
arg = this->var; \
return checkSetStop( var##rule ); \
}
#define APPLY_FORCE_RULE( var, name, type ) \
bool Rules::apply##name( type& arg ) const \
{ \
if ( checkForceRule( var##rule )) \
arg = this->var; \
return checkForceStop( var##rule ); \
}
APPLY_FORCE_RULE(placement, Placement, Placement::Policy)
bool Rules::applyGeometry(QRect& rect, bool init) const
{
QPoint p = rect.topLeft();
QSize s = rect.size();
bool ret = false; // no short-circuiting
if (applyPosition(p, init)) {
rect.moveTopLeft(p);
ret = true;
}
if (applySize(s, init)) {
rect.setSize(s);
ret = true;
}
return ret;
}
bool Rules::applyPosition(QPoint& pos, bool init) const
{
if (this->position != invalidPoint && checkSetRule(positionrule, init))
pos = this->position;
return checkSetStop(positionrule);
}
bool Rules::applySize(QSize& s, bool init) const
{
if (this->size.isValid() && checkSetRule(sizerule, init))
s = this->size;
return checkSetStop(sizerule);
}
APPLY_FORCE_RULE(minsize, MinSize, QSize)
APPLY_FORCE_RULE(maxsize, MaxSize, QSize)
APPLY_FORCE_RULE(opacityactive, OpacityActive, int)
APPLY_FORCE_RULE(opacityinactive, OpacityInactive, int)
APPLY_RULE(ignoregeometry, IgnoreGeometry, bool)
APPLY_RULE(desktop, Desktop, int)
APPLY_RULE(screen, Screen, int)
APPLY_RULE(activity, Activity, QString)
APPLY_FORCE_RULE(type, Type, NET::WindowType)
bool Rules::applyMaximizeHoriz(MaximizeMode& mode, bool init) const
{
if (checkSetRule(maximizehorizrule, init))
mode = static_cast< MaximizeMode >((maximizehoriz ? MaximizeHorizontal : 0) | (mode & MaximizeVertical));
return checkSetStop(maximizehorizrule);
}
bool Rules::applyMaximizeVert(MaximizeMode& mode, bool init) const
{
if (checkSetRule(maximizevertrule, init))
mode = static_cast< MaximizeMode >((maximizevert ? MaximizeVertical : 0) | (mode & MaximizeHorizontal));
return checkSetStop(maximizevertrule);
}
APPLY_RULE(minimize, Minimize, bool)
bool Rules::applyShade(ShadeMode& sh, bool init) const
{
if (checkSetRule(shaderule, init)) {
if (!this->shade)
sh = ShadeNone;
if (this->shade && sh == ShadeNone)
sh = ShadeNormal;
}
return checkSetStop(shaderule);
}
APPLY_RULE(skiptaskbar, SkipTaskbar, bool)
APPLY_RULE(skippager, SkipPager, bool)
APPLY_RULE(skipswitcher, SkipSwitcher, bool)
APPLY_RULE(above, KeepAbove, bool)
APPLY_RULE(below, KeepBelow, bool)
APPLY_RULE(fullscreen, FullScreen, bool)
APPLY_RULE(noborder, NoBorder, bool)
APPLY_FORCE_RULE(decocolor, DecoColor, QString)
APPLY_FORCE_RULE(blockcompositing, BlockCompositing, bool)
APPLY_FORCE_RULE(fsplevel, FSP, int)
APPLY_FORCE_RULE(fpplevel, FPP, int)
APPLY_FORCE_RULE(acceptfocus, AcceptFocus, bool)
APPLY_FORCE_RULE(closeable, Closeable, bool)
APPLY_FORCE_RULE(autogroup, Autogrouping, bool)
APPLY_FORCE_RULE(autogroupfg, AutogroupInForeground, bool)
APPLY_FORCE_RULE(autogroupid, AutogroupById, QString)
APPLY_FORCE_RULE(strictgeometry, StrictGeometry, bool)
APPLY_RULE(shortcut, Shortcut, QString)
APPLY_FORCE_RULE(disableglobalshortcuts, DisableGlobalShortcuts, bool)
APPLY_RULE(desktopfile, DesktopFile, QString)
#undef APPLY_RULE
#undef APPLY_FORCE_RULE
bool Rules::isTemporary() const
{
return temporary_state > 0;
}
bool Rules::discardTemporary(bool force)
{
if (temporary_state == 0) // not temporary
return false;
if (force || --temporary_state == 0) { // too old
delete this;
return true;
}
return false;
}
#define DISCARD_USED_SET_RULE( var ) \
do { \
if ( var##rule == ( SetRule ) ApplyNow || ( withdrawn && var##rule == ( SetRule ) ForceTemporarily )) { \
var##rule = UnusedSetRule; \
changed = true; \
} \
} while ( false )
#define DISCARD_USED_FORCE_RULE( var ) \
do { \
if ( withdrawn && var##rule == ( ForceRule ) ForceTemporarily ) { \
var##rule = UnusedForceRule; \
changed = true; \
} \
} while ( false )
bool Rules::discardUsed(bool withdrawn)
{
bool changed = false;
DISCARD_USED_FORCE_RULE(placement);
DISCARD_USED_SET_RULE(position);
DISCARD_USED_SET_RULE(size);
DISCARD_USED_FORCE_RULE(minsize);
DISCARD_USED_FORCE_RULE(maxsize);
DISCARD_USED_FORCE_RULE(opacityactive);
DISCARD_USED_FORCE_RULE(opacityinactive);
DISCARD_USED_SET_RULE(ignoregeometry);
DISCARD_USED_SET_RULE(desktop);
DISCARD_USED_SET_RULE(screen);
DISCARD_USED_SET_RULE(activity);
DISCARD_USED_FORCE_RULE(type);
DISCARD_USED_SET_RULE(maximizevert);
DISCARD_USED_SET_RULE(maximizehoriz);
DISCARD_USED_SET_RULE(minimize);
DISCARD_USED_SET_RULE(shade);
DISCARD_USED_SET_RULE(skiptaskbar);
DISCARD_USED_SET_RULE(skippager);
DISCARD_USED_SET_RULE(skipswitcher);
DISCARD_USED_SET_RULE(above);
DISCARD_USED_SET_RULE(below);
DISCARD_USED_SET_RULE(fullscreen);
DISCARD_USED_SET_RULE(noborder);
DISCARD_USED_FORCE_RULE(decocolor);
DISCARD_USED_FORCE_RULE(blockcompositing);
DISCARD_USED_FORCE_RULE(fsplevel);
DISCARD_USED_FORCE_RULE(fpplevel);
DISCARD_USED_FORCE_RULE(acceptfocus);
DISCARD_USED_FORCE_RULE(closeable);
DISCARD_USED_FORCE_RULE(autogroup);
DISCARD_USED_FORCE_RULE(autogroupfg);
DISCARD_USED_FORCE_RULE(autogroupid);
DISCARD_USED_FORCE_RULE(strictgeometry);
DISCARD_USED_SET_RULE(shortcut);
DISCARD_USED_FORCE_RULE(disableglobalshortcuts);
DISCARD_USED_SET_RULE(desktopfile);
return changed;
}
#undef DISCARD_USED_SET_RULE
#undef DISCARD_USED_FORCE_RULE
#endif
QDebug& operator<<(QDebug& stream, const Rules* r)
{
return stream << "[" << r->description << ":" << r->wmclass << "]" ;
}
#ifndef KCMRULES
void WindowRules::discardTemporary()
{
QVector< Rules* >::Iterator it2 = rules.begin();
for (QVector< Rules* >::Iterator it = rules.begin();
it != rules.end();
) {
if ((*it)->discardTemporary(true))
++it;
else {
*it2++ = *it++;
}
}
rules.erase(it2, rules.end());
}
void WindowRules::update(AbstractClient* c, int selection)
{
bool updated = false;
for (QVector< Rules* >::ConstIterator it = rules.constBegin();
it != rules.constEnd();
++it)
if ((*it)->update(c, selection)) // no short-circuiting here
updated = true;
if (updated)
RuleBook::self()->requestDiskStorage();
}
#define CHECK_RULE( rule, type ) \
type WindowRules::check##rule( type arg, bool init ) const \
{ \
if ( rules.count() == 0 ) \
return arg; \
type ret = arg; \
for ( QVector< Rules* >::ConstIterator it = rules.constBegin(); \
it != rules.constEnd(); \
++it ) \
{ \
if ( (*it)->apply##rule( ret, init )) \
break; \
} \
return ret; \
}
#define CHECK_FORCE_RULE( rule, type ) \
type WindowRules::check##rule( type arg ) const \
{ \
if ( rules.count() == 0 ) \
return arg; \
type ret = arg; \
for ( QVector< Rules* >::ConstIterator it = rules.begin(); \
it != rules.end(); \
++it ) \
{ \
if ( (*it)->apply##rule( ret )) \
break; \
} \
return ret; \
}
CHECK_FORCE_RULE(Placement, Placement::Policy)
QRect WindowRules::checkGeometry(QRect rect, bool init) const
{
return QRect(checkPosition(rect.topLeft(), init), checkSize(rect.size(), init));
}
CHECK_RULE(Position, QPoint)
CHECK_RULE(Size, QSize)
CHECK_FORCE_RULE(MinSize, QSize)
CHECK_FORCE_RULE(MaxSize, QSize)
CHECK_FORCE_RULE(OpacityActive, int)
CHECK_FORCE_RULE(OpacityInactive, int)
CHECK_RULE(IgnoreGeometry, bool)
CHECK_RULE(Desktop, int)
CHECK_RULE(Activity, QString)
CHECK_FORCE_RULE(Type, NET::WindowType)
CHECK_RULE(MaximizeVert, MaximizeMode)
CHECK_RULE(MaximizeHoriz, MaximizeMode)
MaximizeMode WindowRules::checkMaximize(MaximizeMode mode, bool init) const
{
bool vert = checkMaximizeVert(mode, init) & MaximizeVertical;
bool horiz = checkMaximizeHoriz(mode, init) & MaximizeHorizontal;
return static_cast< MaximizeMode >((vert ? MaximizeVertical : 0) | (horiz ? MaximizeHorizontal : 0));
}
int WindowRules::checkScreen(int screen, bool init) const
{
if ( rules.count() == 0 )
return screen;
int ret = screen;
for ( QVector< Rules* >::ConstIterator it = rules.constBegin(); it != rules.constEnd(); ++it ) {
if ( (*it)->applyScreen( ret, init ))
break;
}
if (ret >= Screens::self()->count())
ret = screen;
return ret;
}
CHECK_RULE(Minimize, bool)
CHECK_RULE(Shade, ShadeMode)
CHECK_RULE(SkipTaskbar, bool)
CHECK_RULE(SkipPager, bool)
CHECK_RULE(SkipSwitcher, bool)
CHECK_RULE(KeepAbove, bool)
CHECK_RULE(KeepBelow, bool)
CHECK_RULE(FullScreen, bool)
CHECK_RULE(NoBorder, bool)
CHECK_FORCE_RULE(DecoColor, QString)
CHECK_FORCE_RULE(BlockCompositing, bool)
CHECK_FORCE_RULE(FSP, int)
CHECK_FORCE_RULE(FPP, int)
CHECK_FORCE_RULE(AcceptFocus, bool)
CHECK_FORCE_RULE(Closeable, bool)
CHECK_FORCE_RULE(Autogrouping, bool)
CHECK_FORCE_RULE(AutogroupInForeground, bool)
CHECK_FORCE_RULE(AutogroupById, QString)
CHECK_FORCE_RULE(StrictGeometry, bool)
CHECK_RULE(Shortcut, QString)
CHECK_FORCE_RULE(DisableGlobalShortcuts, bool)
CHECK_RULE(DesktopFile, QString)
#undef CHECK_RULE
#undef CHECK_FORCE_RULE
// Client
void AbstractClient::setupWindowRules(bool ignore_temporary)
{
disconnect(this, &AbstractClient::captionChanged, this, &AbstractClient::evaluateWindowRules);
m_rules = RuleBook::self()->find(this, ignore_temporary);
// check only after getting the rules, because there may be a rule forcing window type
}
// Applies Force, ForceTemporarily and ApplyNow rules
// Used e.g. after the rules have been modified using the kcm.
void AbstractClient::applyWindowRules()
{
// apply force rules
// Placement - does need explicit update, just like some others below
// Geometry : setGeometry() doesn't check rules
auto client_rules = rules();
QRect orig_geom = QRect(pos(), adjustedSize()); // handle shading
QRect geom = client_rules->checkGeometry(orig_geom);
if (geom != orig_geom)
setFrameGeometry(geom);
// MinSize, MaxSize handled by Geometry
// IgnoreGeometry
setDesktop(desktop());
workspace()->sendClientToScreen(this, screen());
setOnActivities(activities());
// Type
maximize(maximizeMode());
// Minimize : functions don't check, and there are two functions
if (client_rules->checkMinimize(isMinimized()))
minimize();
else
unminimize();
setShade(shadeMode());
setOriginalSkipTaskbar(skipTaskbar());
setSkipPager(skipPager());
setSkipSwitcher(skipSwitcher());
setKeepAbove(keepAbove());
setKeepBelow(keepBelow());
setFullScreen(isFullScreen(), true);
setNoBorder(noBorder());
updateColorScheme();
// FSP
// AcceptFocus :
if (workspace()->mostRecentlyActivatedClient() == this
&& !client_rules->checkAcceptFocus(true))
workspace()->activateNextClient(this);
// Closeable
QSize s = adjustedSize();
if (s != size() && s.isValid())
resizeWithChecks(s);
// Autogrouping : Only checked on window manage
// AutogroupInForeground : Only checked on window manage
// AutogroupById : Only checked on window manage
// StrictGeometry
setShortcut(rules()->checkShortcut(shortcut().toString()));
// see also X11Client::setActive()
if (isActive()) {
setOpacity(rules()->checkOpacityActive(qRound(opacity() * 100.0)) / 100.0);
workspace()->disableGlobalShortcutsForClient(rules()->checkDisableGlobalShortcuts(false));
} else
setOpacity(rules()->checkOpacityInactive(qRound(opacity() * 100.0)) / 100.0);
setDesktopFileName(rules()->checkDesktopFile(desktopFileName()).toUtf8());
}
void X11Client::updateWindowRules(Rules::Types selection)
{
if (!isManaged()) // not fully setup yet
return;
AbstractClient::updateWindowRules(selection);
}
void AbstractClient::updateWindowRules(Rules::Types selection)
{
if (RuleBook::self()->areUpdatesDisabled())
return;
m_rules.update(this, selection);
}
void AbstractClient::finishWindowRules()
{
updateWindowRules(Rules::All);
m_rules = WindowRules();
}
// Workspace
KWIN_SINGLETON_FACTORY(RuleBook)
RuleBook::RuleBook(QObject *parent)
: QObject(parent)
, m_updateTimer(new QTimer(this))
, m_updatesDisabled(false)
, m_temporaryRulesMessages()
{
initWithX11();
connect(kwinApp(), &Application::x11ConnectionChanged, this, &RuleBook::initWithX11);
connect(m_updateTimer, SIGNAL(timeout()), SLOT(save()));
m_updateTimer->setInterval(1000);
m_updateTimer->setSingleShot(true);
}
RuleBook::~RuleBook()
{
save();
deleteAll();
}
void RuleBook::initWithX11()
{
auto c = kwinApp()->x11Connection();
if (!c) {
m_temporaryRulesMessages.reset();
return;
}
m_temporaryRulesMessages.reset(new KXMessages(c, kwinApp()->x11RootWindow(), "_KDE_NET_WM_TEMPORARY_RULES", nullptr));
connect(m_temporaryRulesMessages.data(), SIGNAL(gotMessage(QString)), SLOT(temporaryRulesMessage(QString)));
}
void RuleBook::deleteAll()
{
qDeleteAll(m_rules);
m_rules.clear();
}
WindowRules RuleBook::find(const AbstractClient* c, bool ignore_temporary)
{
QVector< Rules* > ret;
for (QList< Rules* >::Iterator it = m_rules.begin();
it != m_rules.end();
) {
if (ignore_temporary && (*it)->isTemporary()) {
++it;
continue;
}
if ((*it)->match(c)) {
Rules* rule = *it;
qCDebug(KWIN_CORE) << "Rule found:" << rule << ":" << c;
if (rule->isTemporary())
it = m_rules.erase(it);
else
++it;
ret.append(rule);
continue;
}
++it;
}
return WindowRules(ret);
}
void RuleBook::edit(AbstractClient* c, bool whole_app)
{
save();
QStringList args;
args << QStringLiteral("--uuid") << c->internalId().toString();
if (whole_app)
args << QStringLiteral("--whole-app");
QProcess *p = new Process(this);
p->setArguments(args);
p->setProcessEnvironment(kwinApp()->processStartupEnvironment());
const QFileInfo buildDirBinary{QDir{QCoreApplication::applicationDirPath()}, QStringLiteral("kwin_rules_dialog")};
p->setProgram(buildDirBinary.exists() ? buildDirBinary.absoluteFilePath() : QStringLiteral(KWIN_RULES_DIALOG_BIN));
p->setProcessChannelMode(QProcess::MergedChannels);
connect(p, static_cast(&QProcess::finished), p, &QProcess::deleteLater);
connect(p, &QProcess::errorOccurred, this, [p](QProcess::ProcessError e) {
if (e == QProcess::FailedToStart) {
qCDebug(KWIN_CORE) << "Failed to start" << p->program();
}
});
p->start();
}
void RuleBook::load()
{
deleteAll();
if (!m_config) {
m_config = KSharedConfig::openConfig(QStringLiteral(KWIN_NAME "rulesrc"), KConfig::NoGlobals);
} else {
m_config->reparseConfiguration();
}
- int count = m_config->group("General").readEntry("count", 0);
- for (int i = 1;
- i <= count;
- ++i) {
- KConfigGroup cg(m_config, QString::number(i));
- Rules* rule = new Rules(cg);
- m_rules.append(rule);
- }
+ m_rules = RuleBookSettings(m_config).rules().toList();
}
void RuleBook::save()
{
m_updateTimer->stop();
if (!m_config) {
qCWarning(KWIN_CORE) << "RuleBook::save invoked without prior invocation of RuleBook::load";
return;
}
- QStringList groups = m_config->groupList();
- for (QStringList::ConstIterator it = groups.constBegin();
- it != groups.constEnd();
- ++it)
- m_config->deleteGroup(*it);
- m_config->group("General").writeEntry("count", m_rules.count());
- int i = 1;
- for (QList< Rules* >::ConstIterator it = m_rules.constBegin();
- it != m_rules.constEnd();
- ++it) {
- if ((*it)->isTemporary())
- continue;
- KConfigGroup cg(m_config, QString::number(i));
- (*it)->write(cg);
- ++i;
+ QVector filteredRules;
+ for (const auto &rule : qAsConst(m_rules)) {
+ if (!rule->isTemporary()) {
+ filteredRules.append(rule);
+ }
}
- m_config->sync();
+ RuleBookSettings settings(m_config);
+ settings.setRules(filteredRules);
+ settings.save();
}
void RuleBook::temporaryRulesMessage(const QString& message)
{
bool was_temporary = false;
for (QList< Rules* >::ConstIterator it = m_rules.constBegin();
it != m_rules.constEnd();
++it)
if ((*it)->isTemporary())
was_temporary = true;
Rules* rule = new Rules(message, true);
m_rules.prepend(rule); // highest priority first
if (!was_temporary)
QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules()));
}
void RuleBook::cleanupTemporaryRules()
{
bool has_temporary = false;
for (QList< Rules* >::Iterator it = m_rules.begin();
it != m_rules.end();
) {
if ((*it)->discardTemporary(false)) { // deletes (*it)
it = m_rules.erase(it);
} else {
if ((*it)->isTemporary())
has_temporary = true;
++it;
}
}
if (has_temporary)
QTimer::singleShot(60000, this, SLOT(cleanupTemporaryRules()));
}
void RuleBook::discardUsed(AbstractClient* c, bool withdrawn)
{
bool updated = false;
for (QList< Rules* >::Iterator it = m_rules.begin();
it != m_rules.end();
) {
if (c->rules()->contains(*it)) {
if ((*it)->discardUsed(withdrawn)) {
updated = true;
}
if ((*it)->isEmpty()) {
c->removeRule(*it);
Rules* r = *it;
it = m_rules.erase(it);
delete r;
continue;
}
}
++it;
}
if (updated)
requestDiskStorage();
}
void RuleBook::requestDiskStorage()
{
m_updateTimer->start();
}
void RuleBook::setUpdatesDisabled(bool disable)
{
m_updatesDisabled = disable;
if (!disable) {
foreach (X11Client *c, Workspace::self()->clientList())
c->updateWindowRules(Rules::All);
}
}
#endif
} // namespace
diff --git a/rules.h b/rules.h
index 035efeadd..c6f6061db 100644
--- a/rules.h
+++ b/rules.h
@@ -1,393 +1,391 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2004 Lubos Lunak
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, see .
*********************************************************************/
#ifndef KWIN_RULES_H
#define KWIN_RULES_H
#include
#include
#include
-#include
#include "placement.h"
#include "options.h"
#include "utils.h"
class QDebug;
class KConfig;
class KXMessages;
namespace KWin
{
class AbstractClient;
class Rules;
+class RuleSettings;
#ifndef KCMRULES // only for kwin core
class WindowRules
{
public:
explicit WindowRules(const QVector< Rules* >& rules);
WindowRules();
void update(AbstractClient*, int selection);
void discardTemporary();
bool contains(const Rules* rule) const;
void remove(Rules* rule);
Placement::Policy checkPlacement(Placement::Policy placement) const;
QRect checkGeometry(QRect rect, bool init = false) const;
// use 'invalidPoint' with checkPosition, unlike QSize() and QRect(), QPoint() is a valid point
QPoint checkPosition(QPoint pos, bool init = false) const;
QSize checkSize(QSize s, bool init = false) const;
QSize checkMinSize(QSize s) const;
QSize checkMaxSize(QSize s) const;
int checkOpacityActive(int s) const;
int checkOpacityInactive(int s) const;
bool checkIgnoreGeometry(bool ignore, bool init = false) const;
int checkDesktop(int desktop, bool init = false) const;
int checkScreen(int screen, bool init = false) const;
QString checkActivity(QString activity, bool init = false) const;
NET::WindowType checkType(NET::WindowType type) const;
MaximizeMode checkMaximize(MaximizeMode mode, bool init = false) const;
bool checkMinimize(bool minimized, bool init = false) const;
ShadeMode checkShade(ShadeMode shade, bool init = false) const;
bool checkSkipTaskbar(bool skip, bool init = false) const;
bool checkSkipPager(bool skip, bool init = false) const;
bool checkSkipSwitcher(bool skip, bool init = false) const;
bool checkKeepAbove(bool above, bool init = false) const;
bool checkKeepBelow(bool below, bool init = false) const;
bool checkFullScreen(bool fs, bool init = false) const;
bool checkNoBorder(bool noborder, bool init = false) const;
QString checkDecoColor(QString schemeFile) const;
bool checkBlockCompositing(bool block) const;
int checkFSP(int fsp) const;
int checkFPP(int fpp) const;
bool checkAcceptFocus(bool focus) const;
bool checkCloseable(bool closeable) const;
bool checkAutogrouping(bool autogroup) const;
bool checkAutogroupInForeground(bool fg) const;
QString checkAutogroupById(QString id) const;
bool checkStrictGeometry(bool strict) const;
QString checkShortcut(QString s, bool init = false) const;
bool checkDisableGlobalShortcuts(bool disable) const;
QString checkDesktopFile(QString desktopFile, bool init = false) const;
private:
MaximizeMode checkMaximizeVert(MaximizeMode mode, bool init) const;
MaximizeMode checkMaximizeHoriz(MaximizeMode mode, bool init) const;
QVector< Rules* > rules;
};
#endif
class Rules
{
public:
Rules();
- explicit Rules(const KConfigGroup&);
+ explicit Rules(const RuleSettings*);
Rules(const QString&, bool temporary);
enum Type {
Position = 1<<0, Size = 1<<1, Desktop = 1<<2,
MaximizeVert = 1<<3, MaximizeHoriz = 1<<4, Minimize = 1<<5,
Shade = 1<<6, SkipTaskbar = 1<<7, SkipPager = 1<<8,
SkipSwitcher = 1<<9, Above = 1<<10, Below = 1<<11, Fullscreen = 1<<12,
NoBorder = 1<<13, OpacityActive = 1<<14, OpacityInactive = 1<<15,
Activity = 1<<16, Screen = 1<<17, DesktopFile = 1 << 18, All = 0xffffffff
};
Q_DECLARE_FLAGS(Types, Type)
// All these values are saved to the cfg file, and are also used in kstart!
enum {
Unused = 0,
DontAffect, // use the default value
Force, // force the given value
Apply, // apply only after initial mapping
Remember, // like apply, and remember the value when the window is withdrawn
ApplyNow, // apply immediatelly, then forget the setting
ForceTemporarily // apply and force until the window is withdrawn
};
enum StringMatch {
FirstStringMatch,
UnimportantMatch = FirstStringMatch,
ExactMatch,
SubstringMatch,
RegExpMatch,
LastStringMatch = RegExpMatch
};
- void write(KConfigGroup&) const;
+ enum SetRule {
+ UnusedSetRule = Unused,
+ SetRuleDummy = 256 // so that it's at least short int
+ };
+ enum ForceRule {
+ UnusedForceRule = Unused,
+ ForceRuleDummy = 256 // so that it's at least short int
+ };
+ void write(RuleSettings*) const;
bool isEmpty() const;
#ifndef KCMRULES
bool discardUsed(bool withdrawn);
bool match(const AbstractClient* c) const;
bool update(AbstractClient*, int selection);
bool isTemporary() const;
bool discardTemporary(bool force); // removes if temporary and forced or too old
bool applyPlacement(Placement::Policy& placement) const;
bool applyGeometry(QRect& rect, bool init) const;
// use 'invalidPoint' with applyPosition, unlike QSize() and QRect(), QPoint() is a valid point
bool applyPosition(QPoint& pos, bool init) const;
bool applySize(QSize& s, bool init) const;
bool applyMinSize(QSize& s) const;
bool applyMaxSize(QSize& s) const;
bool applyOpacityActive(int& s) const;
bool applyOpacityInactive(int& s) const;
bool applyIgnoreGeometry(bool& ignore, bool init) const;
bool applyDesktop(int& desktop, bool init) const;
bool applyScreen(int& desktop, bool init) const;
bool applyActivity(QString& activity, bool init) const;
bool applyType(NET::WindowType& type) const;
bool applyMaximizeVert(MaximizeMode& mode, bool init) const;
bool applyMaximizeHoriz(MaximizeMode& mode, bool init) const;
bool applyMinimize(bool& minimized, bool init) const;
bool applyShade(ShadeMode& shade, bool init) const;
bool applySkipTaskbar(bool& skip, bool init) const;
bool applySkipPager(bool& skip, bool init) const;
bool applySkipSwitcher(bool& skip, bool init) const;
bool applyKeepAbove(bool& above, bool init) const;
bool applyKeepBelow(bool& below, bool init) const;
bool applyFullScreen(bool& fs, bool init) const;
bool applyNoBorder(bool& noborder, bool init) const;
bool applyDecoColor(QString &schemeFile) const;
bool applyBlockCompositing(bool& block) const;
bool applyFSP(int& fsp) const;
bool applyFPP(int& fpp) const;
bool applyAcceptFocus(bool& focus) const;
bool applyCloseable(bool& closeable) const;
bool applyAutogrouping(bool& autogroup) const;
bool applyAutogroupInForeground(bool& fg) const;
bool applyAutogroupById(QString& id) const;
bool applyStrictGeometry(bool& strict) const;
bool applyShortcut(QString& shortcut, bool init) const;
bool applyDisableGlobalShortcuts(bool& disable) const;
bool applyDesktopFile(QString &desktopFile, bool init) const;
private:
#endif
bool matchType(NET::WindowType match_type) const;
bool matchWMClass(const QByteArray& match_class, const QByteArray& match_name) const;
bool matchRole(const QByteArray& match_role) const;
bool matchTitle(const QString& match_title) const;
bool matchClientMachine(const QByteArray& match_machine, bool local) const;
- enum SetRule {
- UnusedSetRule = Unused,
- SetRuleDummy = 256 // so that it's at least short int
- };
- enum ForceRule {
- UnusedForceRule = Unused,
- ForceRuleDummy = 256 // so that it's at least short int
- };
- void readFromCfg(const KConfigGroup& cfg);
- static SetRule readSetRule(const KConfigGroup&, const QString& key);
- static ForceRule readForceRule(const KConfigGroup&, const QString& key);
- static NET::WindowType readType(const KConfigGroup&, const QString& key);
- static QString readDecoColor(const KConfigGroup &cfg);
+ void readFromSettings(const RuleSettings *settings);
+ static ForceRule convertForceRule(int v);
+ static QString getDecoColor(const QString &themeName);
#ifndef KCMRULES
static bool checkSetRule(SetRule rule, bool init);
static bool checkForceRule(ForceRule rule);
static bool checkSetStop(SetRule rule);
static bool checkForceStop(ForceRule rule);
#endif
int temporary_state; // e.g. for kstart
QString description;
QByteArray wmclass;
StringMatch wmclassmatch;
bool wmclasscomplete;
QByteArray windowrole;
StringMatch windowrolematch;
QString title;
StringMatch titlematch;
QByteArray clientmachine;
StringMatch clientmachinematch;
NET::WindowTypes types; // types for matching
Placement::Policy placement;
ForceRule placementrule;
QPoint position;
SetRule positionrule;
QSize size;
SetRule sizerule;
QSize minsize;
ForceRule minsizerule;
QSize maxsize;
ForceRule maxsizerule;
int opacityactive;
ForceRule opacityactiverule;
int opacityinactive;
ForceRule opacityinactiverule;
bool ignoregeometry;
SetRule ignoregeometryrule;
int desktop;
SetRule desktoprule;
int screen;
SetRule screenrule;
QString activity;
SetRule activityrule;
NET::WindowType type; // type for setting
ForceRule typerule;
bool maximizevert;
SetRule maximizevertrule;
bool maximizehoriz;
SetRule maximizehorizrule;
bool minimize;
SetRule minimizerule;
bool shade;
SetRule shaderule;
bool skiptaskbar;
SetRule skiptaskbarrule;
bool skippager;
SetRule skippagerrule;
bool skipswitcher;
SetRule skipswitcherrule;
bool above;
SetRule aboverule;
bool below;
SetRule belowrule;
bool fullscreen;
SetRule fullscreenrule;
bool noborder;
SetRule noborderrule;
QString decocolor;
ForceRule decocolorrule;
bool blockcompositing;
ForceRule blockcompositingrule;
int fsplevel;
int fpplevel;
ForceRule fsplevelrule;
ForceRule fpplevelrule;
bool acceptfocus;
ForceRule acceptfocusrule;
bool closeable;
ForceRule closeablerule;
bool autogroup;
ForceRule autogrouprule;
bool autogroupfg;
ForceRule autogroupfgrule;
QString autogroupid;
ForceRule autogroupidrule;
bool strictgeometry;
ForceRule strictgeometryrule;
QString shortcut;
SetRule shortcutrule;
bool disableglobalshortcuts;
ForceRule disableglobalshortcutsrule;
QString desktopfile;
SetRule desktopfilerule;
friend QDebug& operator<<(QDebug& stream, const Rules*);
};
#ifndef KCMRULES
class KWIN_EXPORT RuleBook : public QObject
{
Q_OBJECT
public:
~RuleBook() override;
WindowRules find(const AbstractClient*, bool);
void discardUsed(AbstractClient* c, bool withdraw);
void setUpdatesDisabled(bool disable);
bool areUpdatesDisabled() const;
void load();
void edit(AbstractClient* c, bool whole_app);
void requestDiskStorage();
void setConfig(const KSharedConfig::Ptr &config) {
m_config = config;
}
private Q_SLOTS:
void temporaryRulesMessage(const QString&);
void cleanupTemporaryRules();
void save();
private:
void deleteAll();
void initWithX11();
QTimer *m_updateTimer;
bool m_updatesDisabled;
QList m_rules;
QScopedPointer m_temporaryRulesMessages;
KSharedConfig::Ptr m_config;
KWIN_SINGLETON(RuleBook)
};
inline
bool RuleBook::areUpdatesDisabled() const
{
return m_updatesDisabled;
}
inline
bool Rules::checkSetRule(SetRule rule, bool init)
{
if (rule > (SetRule)DontAffect) { // Unused or DontAffect
if (rule == (SetRule)Force || rule == (SetRule) ApplyNow
|| rule == (SetRule) ForceTemporarily || init)
return true;
}
return false;
}
inline
bool Rules::checkForceRule(ForceRule rule)
{
return rule == (ForceRule)Force || rule == (ForceRule) ForceTemporarily;
}
inline
bool Rules::checkSetStop(SetRule rule)
{
return rule != UnusedSetRule;
}
inline
bool Rules::checkForceStop(ForceRule rule)
{
return rule != UnusedForceRule;
}
inline
WindowRules::WindowRules(const QVector< Rules* >& r)
: rules(r)
{
}
inline
WindowRules::WindowRules()
{
}
inline
bool WindowRules::contains(const Rules* rule) const
{
return rules.contains(const_cast(rule));
}
inline
void WindowRules::remove(Rules* rule)
{
rules.removeOne(rule);
}
#endif
QDebug& operator<<(QDebug& stream, const Rules*);
} // namespace
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::Rules::Types)
#endif
diff --git a/rulesettings.kcfg b/rulesettings.kcfg
new file mode 100644
index 000000000..b80b1c87b
--- /dev/null
+++ b/rulesettings.kcfg
@@ -0,0 +1,435 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+ Rules::UnimportantMatch
+ Rules::FirstStringMatch
+ Rules::LastStringMatch
+
+
+
+ Rules::UnimportantMatch
+
+
+
+
+
+
+
+ Rules::UnimportantMatch
+ Rules::FirstStringMatch
+ Rules::LastStringMatch
+
+
+
+
+
+
+
+ Rules::UnimportantMatch
+ Rules::FirstStringMatch
+ Rules::LastStringMatch
+
+
+
+
+
+
+
+ Rules::UnimportantMatch
+ Rules::FirstStringMatch
+ Rules::LastStringMatch
+
+
+
+
+ NET::AllTypesMask
+
+
+
+
+
+ Placement::Smart
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ invalidPoint
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ 0
+ 100
+ 0
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ 0
+ 100
+ 0
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ 0
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ 0
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ NET::Normal
+ NET::Splash
+ NET::Unknown
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ 0
+ 0
+ 4
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ 0
+ 0
+ 4
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ true
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
+
+ false
+
+
+
+ Rules::UnusedForceRule
+
+
+
+
+
+
+
+ Rules::UnusedSetRule
+ static_cast<Rules::SetRule>(Rules::ForceTemporarily)
+ Rules::UnusedSetRule
+
+
+
diff --git a/rulesettings.kcfgc b/rulesettings.kcfgc
new file mode 100644
index 000000000..d244e9860
--- /dev/null
+++ b/rulesettings.kcfgc
@@ -0,0 +1,7 @@
+File=rulesettings.kcfg
+IncludeFiles=\"rules.h\",\"placement.h\",netwm_def.h
+NameSpace=KWin
+ClassName=RuleSettings
+UseEnumTypes=true
+Mutators=true
+ParentInConstructor=true