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