diff --git a/CMakeLists.txt b/CMakeLists.txt index 54d8387de..7bfd9f5ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,772 +1,775 @@ 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(QT_MIN_VERSION "5.14.0") set(KF5_MIN_VERSION "5.68.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" ) 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) +qt5_add_dbus_interface(effects_interface_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) +add_library(KWinEffectsInterface STATIC ${effects_interface_SRCS}) +target_link_libraries(KWinEffectsInterface Qt5::DBus) 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}) if (Libinput_VERSION_STRING VERSION_GREATER 1.14) target_compile_definitions(kwin PRIVATE -DLIBINPUT_HAS_TOTEM) endif () 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/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt index 433785a14..39b626150 100644 --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -1,89 +1,89 @@ add_subdirectory(helper) -add_library(KWinIntegrationTestFramework STATIC kwin_wayland_test.cpp test_helpers.cpp ${kwin_XWAYLAND_SRCS}) +add_library(KWinIntegrationTestFramework STATIC kwin_wayland_test.cpp test_helpers.cpp generic_scene_opengl_test.cpp ${kwin_XWAYLAND_SRCS}) target_link_libraries(KWinIntegrationTestFramework kwin Qt5::Test) function(integrationTest) set(optionArgs WAYLAND_ONLY) set(oneValueArgs NAME) set(multiValueArgs SRCS LIBS) cmake_parse_arguments(ARGS "${optionArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) add_executable(${ARGS_NAME} ${ARGS_SRCS}) target_link_libraries(${ARGS_NAME} KWinIntegrationTestFramework kwin Qt5::Test ${ARGS_LIBS}) add_test(NAME kwin-${ARGS_NAME} COMMAND dbus-run-session ${CMAKE_BINARY_DIR}/bin/${ARGS_NAME}) if (${ARGS_WAYLAND_ONLY}) add_executable(${ARGS_NAME}_waylandonly ${ARGS_SRCS}) set_target_properties(${ARGS_NAME}_waylandonly PROPERTIES COMPILE_DEFINITIONS "NO_XWAYLAND") target_link_libraries(${ARGS_NAME}_waylandonly KWinIntegrationTestFramework kwin Qt5::Test ${ARGS_LIBS}) add_test(NAME kwin-${ARGS_NAME}-waylandonly COMMAND dbus-run-session ${CMAKE_BINARY_DIR}/bin/${ARGS_NAME}_waylandonly) endif() endfunction() integrationTest(NAME testDontCrashGlxgears SRCS dont_crash_glxgears.cpp) integrationTest(NAME testLockScreen SRCS lockscreen.cpp) integrationTest(WAYLAND_ONLY NAME testDecorationInput SRCS decoration_input_test.cpp) integrationTest(WAYLAND_ONLY NAME testInternalWindow SRCS internal_window.cpp) integrationTest(WAYLAND_ONLY NAME testTouchInput SRCS touch_input_test.cpp) integrationTest(WAYLAND_ONLY NAME testInputStackingOrder SRCS input_stacking_order.cpp) integrationTest(NAME testPointerInput SRCS pointer_input.cpp) integrationTest(NAME testPlatformCursor SRCS platformcursor.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashCancelAnimation SRCS dont_crash_cancel_animation.cpp) integrationTest(WAYLAND_ONLY NAME testTransientPlacement SRCS transient_placement.cpp) integrationTest(NAME testDebugConsole SRCS debug_console_test.cpp) integrationTest(NAME testDontCrashEmptyDeco SRCS dont_crash_empty_deco.cpp) integrationTest(WAYLAND_ONLY NAME testPlasmaSurface SRCS plasma_surface_test.cpp) integrationTest(WAYLAND_ONLY NAME testMaximized SRCS maximize_test.cpp) integrationTest(WAYLAND_ONLY NAME testXdgShellClient SRCS xdgshellclient_test.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashNoBorder SRCS dont_crash_no_border.cpp) integrationTest(NAME testXwaylandSelections SRCS xwayland_selections_test.cpp) -integrationTest(WAYLAND_ONLY NAME testSceneOpenGL SRCS scene_opengl_test.cpp generic_scene_opengl_test.cpp) +integrationTest(WAYLAND_ONLY NAME testSceneOpenGL SRCS scene_opengl_test.cpp ) integrationTest(WAYLAND_ONLY NAME testSceneOpenGLShadow SRCS scene_opengl_shadow_test.cpp) -integrationTest(WAYLAND_ONLY NAME testSceneOpenGLES SRCS scene_opengl_es_test.cpp generic_scene_opengl_test.cpp) +integrationTest(WAYLAND_ONLY NAME testSceneOpenGLES SRCS scene_opengl_es_test.cpp ) integrationTest(WAYLAND_ONLY NAME testNoXdgRuntimeDir SRCS no_xdg_runtime_dir_test.cpp) integrationTest(WAYLAND_ONLY NAME testScreenChanges SRCS screen_changes_test.cpp) integrationTest(NAME testModiferOnlyShortcut SRCS modifier_only_shortcut_test.cpp) integrationTest(WAYLAND_ONLY NAME testTabBox SRCS tabbox_test.cpp) integrationTest(WAYLAND_ONLY NAME testWindowSelection SRCS window_selection_test.cpp) integrationTest(WAYLAND_ONLY NAME testPointerConstraints SRCS pointer_constraints_test.cpp) integrationTest(WAYLAND_ONLY NAME testKeyboardLayout SRCS keyboard_layout_test.cpp) integrationTest(WAYLAND_ONLY NAME testKeymapCreationFailure SRCS keymap_creation_failure_test.cpp) integrationTest(WAYLAND_ONLY NAME testShowingDesktop SRCS showing_desktop_test.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashUseractionsMenu SRCS dont_crash_useractions_menu.cpp) integrationTest(WAYLAND_ONLY NAME testKWinBindings SRCS kwinbindings_test.cpp) integrationTest(WAYLAND_ONLY NAME testVirtualDesktop SRCS virtual_desktop_test.cpp) integrationTest(WAYLAND_ONLY NAME testXdgShellClientRules SRCS xdgshellclient_rules_test.cpp) integrationTest(WAYLAND_ONLY NAME testIdleInhibition SRCS idle_inhibition_test.cpp) integrationTest(WAYLAND_ONLY NAME testColorCorrectNightColor SRCS colorcorrect_nightcolor_test.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont_crash_cursor_physical_size_empty.cpp) integrationTest(WAYLAND_ONLY NAME testDontCrashReinitializeCompositor SRCS dont_crash_reinitialize_compositor.cpp) integrationTest(WAYLAND_ONLY NAME testNoGlobalShortcuts SRCS no_global_shortcuts_test.cpp) -integrationTest(WAYLAND_ONLY NAME testBufferSizeChange SRCS buffer_size_change_test.cpp generic_scene_opengl_test.cpp) +integrationTest(WAYLAND_ONLY NAME testBufferSizeChange SRCS buffer_size_change_test.cpp ) integrationTest(WAYLAND_ONLY NAME testPlacement SRCS placement_test.cpp) integrationTest(WAYLAND_ONLY NAME testActivation SRCS activation_test.cpp) if (XCB_ICCCM_FOUND) integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testStruts SRCS struts_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testShade SRCS shade_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testDontCrashAuroraeDestroyDeco SRCS dont_crash_aurorae_destroy_deco.cpp LIBS XCB::ICCCM) integrationTest(NAME testPlasmaWindow SRCS plasmawindow_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testScreenEdgeClientShow SRCS screenedge_client_show_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testX11DesktopWindow SRCS desktop_window_x11_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testXwaylandInput SRCS xwayland_input_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testWindowRules SRCS window_rules_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testX11Client SRCS x11_client_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testQuickTiling SRCS quick_tiling_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testGlobalShortcuts SRCS globalshortcuts_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testSceneQPainter SRCS scene_qpainter_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testSceneQPainterShadow SRCS scene_qpainter_shadow_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testStackingOrder SRCS stacking_order_test.cpp LIBS XCB::ICCCM) integrationTest(NAME testDbusInterface SRCS dbus_interface_test.cpp LIBS XCB::ICCCM) if (KWIN_BUILD_ACTIVITIES) integrationTest(NAME testActivities SRCS activities_test.cpp LIBS XCB::ICCCM) endif() endif() add_subdirectory(scripting) add_subdirectory(effects) add_subdirectory(fakes) diff --git a/autotests/libinput/CMakeLists.txt b/autotests/libinput/CMakeLists.txt index 195ac2fdd..4ac4d2580 100644 --- a/autotests/libinput/CMakeLists.txt +++ b/autotests/libinput/CMakeLists.txt @@ -1,114 +1,85 @@ include_directories(${Libinput_INCLUDE_DIRS}) include_directories(${UDEV_INCLUDE_DIR}) + +add_library(LibInputTestObjects STATIC ../../libinput/device.cpp ../../libinput/events.cpp mock_libinput.cpp) +target_link_libraries(LibInputTestObjects Qt5::Test Qt5::Widgets Qt5::DBus Qt5::Gui KF5::ConfigCore) + ######################################################## # Test Devices ######################################################## -set(testLibinputDevice_SRCS device_test.cpp mock_libinput.cpp ../../libinput/device.cpp ) -add_executable(testLibinputDevice ${testLibinputDevice_SRCS}) -target_link_libraries(testLibinputDevice Qt5::Test Qt5::DBus Qt5::Gui KF5::ConfigCore) +add_executable(testLibinputDevice device_test.cpp) +target_link_libraries(testLibinputDevice Qt5::Test Qt5::DBus Qt5::Gui KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputDevice COMMAND testLibinputDevice) ecm_mark_as_test(testLibinputDevice) ######################################################## # Test Key Event ######################################################## -set(testLibinputKeyEvent_SRCS - ../../libinput/device.cpp - ../../libinput/events.cpp - key_event_test.cpp - mock_libinput.cpp -) -add_executable(testLibinputKeyEvent ${testLibinputKeyEvent_SRCS}) -target_link_libraries(testLibinputKeyEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_executable(testLibinputKeyEvent key_event_test.cpp) +target_link_libraries(testLibinputKeyEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputKeyEvent COMMAND testLibinputKeyEvent) ecm_mark_as_test(testLibinputKeyEvent) ######################################################## # Test Pointer Event ######################################################## -set(testLibinputPointerEvent_SRCS - ../../libinput/device.cpp - ../../libinput/events.cpp - mock_libinput.cpp - pointer_event_test.cpp -) -add_executable(testLibinputPointerEvent ${testLibinputPointerEvent_SRCS}) -target_link_libraries(testLibinputPointerEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_executable(testLibinputPointerEvent pointer_event_test.cpp) +target_link_libraries(testLibinputPointerEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputPointerEvent COMMAND testLibinputPointerEvent) ecm_mark_as_test(testLibinputPointerEvent) ######################################################## # Test Touch Event ######################################################## -set(testLibinputTouchEvent_SRCS - ../../libinput/device.cpp - ../../libinput/events.cpp - mock_libinput.cpp - touch_event_test.cpp -) -add_executable(testLibinputTouchEvent ${testLibinputTouchEvent_SRCS}) -target_link_libraries(testLibinputTouchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_executable(testLibinputTouchEvent touch_event_test.cpp) +target_link_libraries(testLibinputTouchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputTouchEvent COMMAND testLibinputTouchEvent) ecm_mark_as_test(testLibinputTouchEvent) ######################################################## # Test Gesture Event ######################################################## -set(testLibinputGestureEvent_SRCS - ../../libinput/device.cpp - ../../libinput/events.cpp - gesture_event_test.cpp - mock_libinput.cpp -) -add_executable(testLibinputGestureEvent ${testLibinputGestureEvent_SRCS}) -target_link_libraries(testLibinputGestureEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_executable(testLibinputGestureEvent gesture_event_test.cpp) +target_link_libraries(testLibinputGestureEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputGestureEvent COMMAND testLibinputGestureEvent) ecm_mark_as_test(testLibinputGestureEvent) ######################################################## # Test Switch Event ######################################################## -set(testLibinputSwitchEvent_SRCS - ../../libinput/device.cpp - ../../libinput/events.cpp - mock_libinput.cpp - switch_event_test.cpp -) -add_executable(testLibinputSwitchEvent ${testLibinputSwitchEvent_SRCS}) -target_link_libraries(testLibinputSwitchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_executable(testLibinputSwitchEvent switch_event_test.cpp) +target_link_libraries(testLibinputSwitchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testLibinputSwitchEvent COMMAND testLibinputSwitchEvent) ecm_mark_as_test(testLibinputSwitchEvent) ######################################################## # Test Context ######################################################## set(testLibinputContext_SRCS ../../libinput/context.cpp - ../../libinput/device.cpp - ../../libinput/events.cpp ../../libinput/libinput_logging.cpp ../../logind.cpp context_test.cpp - mock_libinput.cpp mock_udev.cpp ) add_executable(testLibinputContext ${testLibinputContext_SRCS}) target_link_libraries(testLibinputContext + LibInputTestObjects + Qt5::DBus Qt5::Test Qt5::Widgets KF5::ConfigCore KF5::WindowSystem ) add_test(NAME kwin-testLibinputContext COMMAND testLibinputContext) ecm_mark_as_test(testLibinputContext) ######################################################## # Test Input Events ######################################################## -set(testInputEvents_SRCS input_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../input_event.cpp) -add_executable(testInputEvents ${testInputEvents_SRCS}) -target_link_libraries(testInputEvents Qt5::Test Qt5::DBus Qt5::Gui Qt5::Widgets KF5::ConfigCore) +add_executable(testInputEvents input_event_test.cpp ../../input_event.cpp) +target_link_libraries(testInputEvents Qt5::Test Qt5::DBus Qt5::Gui Qt5::Widgets KF5::ConfigCore LibInputTestObjects) add_test(NAME kwin-testInputEvents COMMAND testInputEvents) ecm_mark_as_test(testInputEvents) diff --git a/effects/blur/CMakeLists.txt b/effects/blur/CMakeLists.txt index c1d9bd9a4..35db55d5d 100644 --- a/effects/blur/CMakeLists.txt +++ b/effects/blur/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_blur_config_SRCS blur_config.cpp) ki18n_wrap_ui(kwin_blur_config_SRCS blur_config.ui) -qt5_add_dbus_interface(kwin_blur_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_blur_config_SRCS blurconfig.kcfgc) add_library(kwin_blur_config MODULE ${kwin_blur_config_SRCS}) target_link_libraries(kwin_blur_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_blur_config blur_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_blur_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/coverswitch/CMakeLists.txt b/effects/coverswitch/CMakeLists.txt index 56b7a8190..f344a0efb 100644 --- a/effects/coverswitch/CMakeLists.txt +++ b/effects/coverswitch/CMakeLists.txt @@ -1,26 +1,26 @@ ####################################### # Effect ####################################### # Config set(kwin_coverswitch_config_SRCS coverswitch_config.cpp) ki18n_wrap_ui(kwin_coverswitch_config_SRCS coverswitch_config.ui) -qt5_add_dbus_interface(kwin_coverswitch_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_coverswitch_config_SRCS coverswitchconfig.kcfgc) add_library(kwin_coverswitch_config MODULE ${kwin_coverswitch_config_SRCS}) target_link_libraries(kwin_coverswitch_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_coverswitch_config coverswitch_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_coverswitch_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/cube/CMakeLists.txt b/effects/cube/CMakeLists.txt index c80b3e50a..c9d94605f 100644 --- a/effects/cube/CMakeLists.txt +++ b/effects/cube/CMakeLists.txt @@ -1,32 +1,32 @@ ####################################### # Effect # Data files install(FILES data/cubecap.png DESTINATION ${DATA_INSTALL_DIR}/kwin) ####################################### # Config set(kwin_cube_config_SRCS cube_config.cpp) ki18n_wrap_ui(kwin_cube_config_SRCS cube_config.ui) -qt5_add_dbus_interface(kwin_cube_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_cube_config_SRCS cubeconfig.kcfgc) add_library(kwin_cube_config MODULE ${kwin_cube_config_SRCS}) target_link_libraries(kwin_cube_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui KF5::KIOWidgets + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_cube_config cube_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_cube_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/cubeslide/CMakeLists.txt b/effects/cubeslide/CMakeLists.txt index 2836614bc..042ae92c0 100644 --- a/effects/cubeslide/CMakeLists.txt +++ b/effects/cubeslide/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_cubeslide_config_SRCS cubeslide_config.cpp) ki18n_wrap_ui(kwin_cubeslide_config_SRCS cubeslide_config.ui) -qt5_add_dbus_interface(kwin_cubeslide_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_cubeslide_config_SRCS cubeslideconfig.kcfgc) add_library(kwin_cubeslide_config MODULE ${kwin_cubeslide_config_SRCS}) target_link_libraries(kwin_cubeslide_config KF5::ConfigWidgets KF5::I18n kwineffects + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_cubeslide_config cubeslide_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_cubeslide_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/desktopgrid/CMakeLists.txt b/effects/desktopgrid/CMakeLists.txt index 807ff0e69..7fa4b7ace 100644 --- a/effects/desktopgrid/CMakeLists.txt +++ b/effects/desktopgrid/CMakeLists.txt @@ -1,31 +1,31 @@ ####################################### # Effect install(FILES main.qml DESTINATION ${DATA_INSTALL_DIR}/kwin/effects/desktopgrid/) ####################################### # Config set(kwin_desktopgrid_config_SRCS desktopgrid_config.cpp) ki18n_wrap_ui(kwin_desktopgrid_config_SRCS desktopgrid_config.ui) -qt5_add_dbus_interface(kwin_desktopgrid_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_desktopgrid_config_SRCS desktopgridconfig.kcfgc) add_library(kwin_desktopgrid_config MODULE ${kwin_desktopgrid_config_SRCS}) target_link_libraries(kwin_desktopgrid_config KF5::Completion KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui Qt5::Quick kwineffects + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_desktopgrid_config desktopgrid_config.desktop SERVICE_TYPES kcmodule.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_desktopgrid_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/diminactive/CMakeLists.txt b/effects/diminactive/CMakeLists.txt index 2aad1ea1b..5d6e7d3a1 100644 --- a/effects/diminactive/CMakeLists.txt +++ b/effects/diminactive/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_diminactive_config_SRCS diminactive_config.cpp) ki18n_wrap_ui(kwin_diminactive_config_SRCS diminactive_config.ui) -qt5_add_dbus_interface(kwin_diminactive_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_diminactive_config_SRCS diminactiveconfig.kcfgc) add_library(kwin_diminactive_config MODULE ${kwin_diminactive_config_SRCS}) target_link_libraries(kwin_diminactive_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_diminactive_config diminactive_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_diminactive_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/eyeonscreen/package/metadata.desktop b/effects/eyeonscreen/package/metadata.desktop index 7f11c282a..6bd5c54ae 100644 --- a/effects/eyeonscreen/package/metadata.desktop +++ b/effects/eyeonscreen/package/metadata.desktop @@ -1,56 +1,60 @@ [Desktop Entry] Name=Eye on Screen Name[ca]=Ull a la pantalla Name[cs]=Oko na obrazovce +Name[en_GB]=Eye on Screen Name[es]=Ojo a la pantalla Name[et]=Eye on Screen Name[eu]=Begirada pantailan Name[id]=Mata di Layar Name[it]=Eye On Screen Name[ko]=화면 위의 눈 Name[lt]=Akis ekrane Name[nl]=Oog op scherm Name[nn]=Auge på skjerm Name[pt]=Olho no Ecrã Name[pt_BR]=Olho na tela Name[ru]=Втягивание окон в центр экрана +Name[sl]=Oko na zaslonu Name[sv]=Ögat på skärmen Name[uk]=Око на екрані Name[x-test]=xxEye on Screenxx Name[zh_CN]=关注屏幕 Name[zh_TW]=螢幕之眼 Icon=preferences-system-windows-effect-eyeonscreen Comment=Suck windows into the desktop Comment[ca]=Enganxa les finestres a l'escriptori +Comment[en_GB]=Suck windows into the desktop Comment[es]=Aspirar las ventanas en el escritorio Comment[et]=Akende imemine töölauale Comment[eu]=Mahaigainak leihoak xurgatu Comment[id]=Sedot window ke desktop Comment[it]=Risucchia le finestre nel desktop Comment[ko]=창을 바탕 화면으로 흡수 Comment[lt]=Įtraukti langus į darbalaukį Comment[nl]=Zuig vensters in het bureaublad Comment[nn]=Sug vindauge inn i skrivebordet Comment[pt]=Aspira as janelas para o ecrã Comment[pt_BR]=Suga as janelas para a área de trabalho Comment[ru]=Втягивание окон в центр рабочего стола +Comment[sl]=Prisesa okna na namizje Comment[sv]=Sug in fönster i skrivbordet Comment[uk]=Засмоктування вікон до стільниці Comment[x-test]=xxSuck windows into the desktopxx Comment[zh_CN]=将窗口吸收到桌面 Comment[zh_TW]=將視窗吸進桌面 Type=Service X-Plasma-API=javascript X-Plasma-MainScript=code/main.js X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=Thomas Lübking X-KDE-PluginInfo-Email=thomas.luebking@gmail.com X-KDE-PluginInfo-Name=kwin4_effect_eyeonscreen X-KDE-PluginInfo-Version=0.1.0 X-KDE-PluginInfo-Category=Show Desktop Animation X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=false X-KDE-Ordering=50 X-KWin-Exclusive-Category=show-desktop diff --git a/effects/fadingpopups/package/metadata.desktop b/effects/fadingpopups/package/metadata.desktop index 05bbbe689..a42ae1df3 100644 --- a/effects/fadingpopups/package/metadata.desktop +++ b/effects/fadingpopups/package/metadata.desktop @@ -1,78 +1,80 @@ [Desktop Entry] Name=Fading Popups Name[ca]=Missatges emergents esvaïts Name[ca@valencia]=Missatges emergents que es fonen Name[cs]=Mizející vyskakovací okna Name[da]=Pop-op'er udtoner Name[de]=Überblendete Aufklappfenster Name[en_GB]=Fading Popups Name[es]=Desvanecer ventanas emergentes Name[et]=Hääbuvad hüpikdialoogid Name[eu]=Itzaleztatzen diren gainerakorrak Name[fi]=Hiipuvat ponnahdusikkunat Name[fr]=Fondu des boites de dialogue Name[gl]=Xanelas emerxentes que esvaen Name[hu]=Halványodó felugró ablakok Name[ia]=Popups dissolvente Name[id]=Sembulan Melesap Name[it]=Finestre a comparsa che si dissolvono Name[ko]=페이드 팝업 Name[lt]=Pamažu atsirandantys/išnykstantys iškylantieji langai Name[nl]=Vervagende pop-ups Name[nn]=Inn- og uttoning av sprettoppvindauge Name[pl]=Zanikanie okien wysuwnych Name[pt]=Mensagens Desvanecentes Name[pt_BR]=Desvanecer mensagens Name[ru]=Растворяющиеся всплывающие окна Name[sk]=Miznúce vyskakovacie okná +Name[sl]=Prehajajoča pojavna okna Name[sv]=Borttonande meddelanderutor Name[uk]=Інтерактивні контекстні панелі Name[x-test]=xxFading Popupsxx Name[zh_CN]=气泡通知渐隐渐现 Name[zh_TW]=淡化彈出視窗 Icon=preferences-system-windows-effect-fadingpopups Comment=Make popups smoothly fade in and out when they are shown or hidden Comment[ca]=Fa que els missatges emergents s'encenguin o s'apaguin de manera gradual quan es mostren o s'oculten Comment[ca@valencia]=Fa que els missatges emergents s'encenguen o s'apaguen de manera gradual quan es mostren o s'oculten Comment[cs]=Nechá vyskakovací okna plynule zmizet/objevit se, pokud jsou zobrazeny resp. skryty Comment[da]=Få pop-op'er til at tone ud og ind når de vises eller skjules Comment[de]=Blendet Aufklappfenster beim Öffnen/Schließen langsam ein bzw. aus Comment[en_GB]=Make popups smoothly fade in and out when they are shown or hidden Comment[es]=Hace que las ventanas emergentes aparezcan o se desvanezcan suavemente al mostrarlas u ocultarlas Comment[et]=Paneb hüpikaknad sujuvalt hääbuma või tugevnema, kui need peidetakse või nähtavale tuuakse Comment[eu]=Gainerakorrak emeki agertzen eta desagertzen ditu haiek erakustean edo ezkutatzean Comment[fi]=Ponnahdusikkunat tulevat näkyviin tai poistuvat näkyvistä pehmeästi häivyttäen Comment[fr]=Estompe ou fait apparaître en fondu les boites de dialogue lorsqu'elles sont affichées ou cachées Comment[gl]=Esvae e fai opacas as xanelas emerxentes con suavidade ao mostralas ou agochadas Comment[hu]=A felugró folyamatosan áttűnő módon lesznek elrejtve és megjelenítve Comment[ia]=Face que fenestras pote dulcemente pallidir intra e foras quando illos es monstrate o celate Comment[id]=Buat sembulan secara halus lesap-muncul dan lesap-hilang ketika ia ditampilkan atau disembunyikan Comment[it]=Fai dissolvere e comparire gradualmente le finestre a comparsa quando vengono mostrate o nascoste Comment[ko]=팝업이 보여지거나 감춰질 때 부드러운 페이드 인/아웃을 사용합니다 Comment[lt]=Sukuria efektą, kai iškylantieji langai, juos parodant ar paslepiant, glotniai pamažu atsiranda/išnyksta Comment[nl]=Laat pop-ups vloeiend opkomen/vervagen als ze worden weergegeven of verborgen Comment[nn]=Ton sprettoppvindauge gradvis inn og ut når dei vert viste eller gøymde Comment[pl]=Okna wysuwne gładko wyłaniają się przy otwieraniu i zanikają przy zamykaniu Comment[pt]=Fazer com que as janelas apareçam/desapareçam suavemente quando aparecem ou ficam escondidas Comment[pt_BR]=Faz as mensagens aparecerem/desaparecerem suavemente quando são exibidas ou ocultadas Comment[ru]=Всплывающие окна при закрытии будут становиться всё более прозрачными, а потом совсем исчезать Comment[sk]=Okná sa plynule objavia/zmiznú pri ich zobrazení alebo skrytí +Comment[sl]=Okna se pojavijo in izginejo postopoma, kadar se pokažejo ali skrijejo Comment[sv]=Gör att meddelanderutor mjukt tonas in eller ut när de visas eller döljs Comment[uk]=Поступова поява або зникнення контекстних вікон вікон при відкритті чи закритті Comment[x-test]=xxMake popups smoothly fade in and out when they are shown or hiddenxx Comment[zh_CN]=当弹窗被显示或者隐藏时,使窗口平滑地淡入淡出 Comment[zh_TW]=當彈出視窗出現或消失時,讓彈出視窗滑順的淡入和淡出 Type=Service X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=Vlad Zahorodnii X-KDE-PluginInfo-Email=vlad.zahorodnii@kde.org X-KDE-PluginInfo-Name=kwin4_effect_fadingpopups X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Category=Appearance X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-KDE-Ordering=60 X-Plasma-API=javascript X-Plasma-MainScript=code/main.js diff --git a/effects/flipswitch/CMakeLists.txt b/effects/flipswitch/CMakeLists.txt index b1160a027..6829ea590 100644 --- a/effects/flipswitch/CMakeLists.txt +++ b/effects/flipswitch/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_flipswitch_config_SRCS flipswitch_config.cpp) ki18n_wrap_ui(kwin_flipswitch_config_SRCS flipswitch_config.ui) -qt5_add_dbus_interface(kwin_flipswitch_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_flipswitch_config_SRCS flipswitchconfig.kcfgc) add_library(kwin_flipswitch_config MODULE ${kwin_flipswitch_config_SRCS}) target_link_libraries(kwin_flipswitch_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_flipswitch_config flipswitch_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_flipswitch_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/glide/CMakeLists.txt b/effects/glide/CMakeLists.txt index 7b7c3e17e..cd0a69cb4 100644 --- a/effects/glide/CMakeLists.txt +++ b/effects/glide/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_glide_config_SRCS glide_config.cpp) ki18n_wrap_ui(kwin_glide_config_SRCS glide_config.ui) -qt5_add_dbus_interface(kwin_glide_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_glide_config_SRCS glideconfig.kcfgc) add_library(kwin_glide_config MODULE ${kwin_glide_config_SRCS}) target_link_libraries(kwin_glide_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_glide_config glide_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_glide_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/invert/CMakeLists.txt b/effects/invert/CMakeLists.txt index d20368f13..09dac3fcf 100644 --- a/effects/invert/CMakeLists.txt +++ b/effects/invert/CMakeLists.txt @@ -1,25 +1,25 @@ ####################################### # Effect ####################################### # Config set(kwin_invert_config_SRCS invert_config.cpp) -qt5_add_dbus_interface(kwin_invert_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) add_library(kwin_invert_config MODULE ${kwin_invert_config_SRCS}) target_link_libraries(kwin_invert_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_invert_config invert_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_invert_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/logout/package/metadata.desktop b/effects/logout/package/metadata.desktop index 9f171a339..d224e117b 100644 --- a/effects/logout/package/metadata.desktop +++ b/effects/logout/package/metadata.desktop @@ -1,81 +1,83 @@ [Desktop Entry] Name=Logout Name[ast]=Zarru de sesión Name[ca]=Sortida Name[ca@valencia]=Eixida Name[cs]=Odhlášení Name[da]=Log ud Name[de]=Abmeldung Name[el]=Αποσύνδεση Name[en_GB]=Logout Name[es]=Cerrar la sesión Name[et]=Väljalogimine Name[eu]=Saio-ixtea Name[fi]=Kirjaudu ulos Name[fr]=Déconnexion Name[gl]=Saír Name[hu]=Kijelentkezés Name[ia]=Clausura de session Name[id]=Logout Name[it]=Uscita Name[ko]=로그아웃 Name[lt]=Atsijungimas Name[nl]=Afmelden Name[nn]=Logg ut Name[pl]=Wylogowywanie Name[pt]=Encerrar Name[pt_BR]=Encerrar sessão Name[ru]=Завершение работы Name[sk]=Odhlásiť sa +Name[sl]=Odjava Name[sv]=Logga ut Name[uk]=Вихід Name[x-test]=xxLogoutxx Name[zh_CN]=注销 Name[zh_TW]=登出 Icon=preferences-system-windows-effect-logout Comment=Smoothly fade to the logout screen Comment[ca]=Transició suau a la pantalla de sortida Comment[ca@valencia]=Transició suau a la pantalla d'eixida Comment[cs]=Plynule přejít na odhlašovací obrazovku Comment[da]=Toner blidt til log ud-skærmen Comment[de]=Blendet den Abmeldungsdialog langsam ein. Comment[el]=Ομαλή εμφάνιση της οθόνης αποσύνδεσης Comment[en_GB]=Smoothly fade to the logout screen Comment[es]=Desvanecer suavemente hasta la pantalla de cierre de sesión Comment[et]=Sujuv hääbumine sisselogimisekraani ilmumiseni Comment[eu]=Emeki desagertu saio-ixteko pantailarantz Comment[fi]=Häivytä pehmeästi kirjautumisikkunaan Comment[fr]=Effectue un dégradé progressif vers l'écran de déconnexion Comment[gl]=Suaviza a aparición da pantalla de saída Comment[hu]=Folyamatos átmenet a kijelentkező képernyőre Comment[ia]=Dulcemente pallidi al schermo de abandono (logout) Comment[id]=Melesap secara halus ke layar logout Comment[it]=Dissolvenza graduale alla schermata di uscita Comment[ko]=로그아웃 화면으로 부드럽게 전환합니다 Comment[lt]=Glotniai pamažu parodo atsijungimo ekraną Comment[nl]=Langzaam naar het afmeldscherm vervagen Comment[nn]=Ton ut til utloggingsbiletet Comment[pl]=Płynne zanikanie do ekranu wylogowywania Comment[pt]=Desvanecer suavemente para o ecrã de encerramento Comment[pt_BR]=Suaviza o desaparecimento para a tela de encerramento da sessão Comment[ru]=Плавное появление экрана завершения работы Comment[sk]=Plynule zobrazí plochu pri odhlásení +Comment[sl]=Postopoma okno zbledi v zaslon za odjavo Comment[sv]=Tona mjukt till utloggningsskärmen Comment[uk]=Плавний перехід до вікна виходу з системи Comment[x-test]=xxSmoothly fade to the logout screenxx Comment[zh_CN]=平滑地淡出到注销屏幕 Comment[zh_TW]=平順地淡入登出畫面 Type=Service X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=Lubos Lunak, Kai Uwe Broulik, Martin Gräßlin, Marco Martin X-KDE-PluginInfo-Email=l.lunak@kde.org, kde@privat.broulik.de, mgraesslin@kde.org, mart@kde.org X-KDE-PluginInfo-Name=kwin4_effect_logout X-KDE-PluginInfo-Version=0.2.0 X-KDE-PluginInfo-Category=Appearance X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-KDE-Ordering=40 X-Plasma-API=javascript X-Plasma-MainScript=code/main.js diff --git a/effects/lookingglass/CMakeLists.txt b/effects/lookingglass/CMakeLists.txt index 288d5f2c8..381a790b1 100644 --- a/effects/lookingglass/CMakeLists.txt +++ b/effects/lookingglass/CMakeLists.txt @@ -1,27 +1,27 @@ ####################################### # Effect ####################################### # Config set(kwin_lookingglass_config_SRCS lookingglass_config.cpp) ki18n_wrap_ui(kwin_lookingglass_config_SRCS lookingglass_config.ui) -qt5_add_dbus_interface(kwin_lookingglass_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_lookingglass_config_SRCS lookingglassconfig.kcfgc) add_library(kwin_lookingglass_config MODULE ${kwin_lookingglass_config_SRCS}) target_link_libraries(kwin_lookingglass_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_lookingglass_config lookingglass_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_lookingglass_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/magiclamp/CMakeLists.txt b/effects/magiclamp/CMakeLists.txt index ebeed364d..b1ea9c94a 100644 --- a/effects/magiclamp/CMakeLists.txt +++ b/effects/magiclamp/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_magiclamp_config_SRCS magiclamp_config.cpp) ki18n_wrap_ui(kwin_magiclamp_config_SRCS magiclamp_config.ui) -qt5_add_dbus_interface(kwin_magiclamp_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_magiclamp_config_SRCS magiclampconfig.kcfgc) add_library(kwin_magiclamp_config MODULE ${kwin_magiclamp_config_SRCS}) target_link_libraries(kwin_magiclamp_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_magiclamp_config magiclamp_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_magiclamp_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/magnifier/CMakeLists.txt b/effects/magnifier/CMakeLists.txt index 758a76463..cd3fe05be 100644 --- a/effects/magnifier/CMakeLists.txt +++ b/effects/magnifier/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_magnifier_config_SRCS magnifier_config.cpp) ki18n_wrap_ui(kwin_magnifier_config_SRCS magnifier_config.ui) -qt5_add_dbus_interface(kwin_magnifier_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_magnifier_config_SRCS magnifierconfig.kcfgc) add_library(kwin_magnifier_config MODULE ${kwin_magnifier_config_SRCS}) target_link_libraries(kwin_magnifier_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_magnifier_config magnifier_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_magnifier_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/magnifier/magnifier_config.desktop b/effects/magnifier/magnifier_config.desktop index 30e48bed8..b09413f94 100644 --- a/effects/magnifier/magnifier_config.desktop +++ b/effects/magnifier/magnifier_config.desktop @@ -1,89 +1,89 @@ [Desktop Entry] Type=Service X-KDE-ServiceTypes=KCModule X-KDE-Library=kwin_magnifier_config X-KDE-ParentComponents=magnifier Name=Magnifier Name[af]=Vergroter Name[ar]=المكبّر Name[be]=Павелічальная лупа Name[be@latin]=Lupa Name[bg]=Увеличител Name[bn]=ম্যাগনিফায়ার Name[bs]=Uveličavač Name[ca]=Lupa Name[ca@valencia]=Lupa Name[cs]=Lupa Name[csb]=Zwikszanié Name[da]=Forstørrelsesglas Name[de]=Lupe Name[el]=Μεγεθυντής Name[en_GB]=Magnifier Name[eo]=Pligrandigilo Name[es]=Lupa Name[et]=Suurendaja Name[eu]=Lupa Name[fa]=ذره‌بین Name[fi]=Suurennuslasi Name[fr]=Loupe Name[fy]=Fergrutter Name[ga]=Formhéadaitheoir Name[gl]=Lupa Name[gu]=મોટું કરનાર Name[he]=זכוכית מגדלת Name[hi]=आतिशी शीशा Name[hne]=आतिसी सीसा Name[hr]=Povećalo Name[hu]=Nagyító Name[ia]=Aggranditor Name[id]=Suryakanta Name[is]=Stækkunargler Name[it]=Lente d'ingrandimento Name[ja]=虫めがね Name[kk]=Ұлғайтқыш Name[km]=X Magnifier Name[kn]=ವರ್ಧಕ (ಮಸೂರ) Name[ko]=돋보기 Name[ku]=Mezinker Name[lt]=Didinamasis stiklas Name[lv]=Palielinātājs Name[mai]=आवर्धक Name[mk]=Лупа Name[ml]=ഭൂതകണ്ണാടി Name[mr]=वर्धक Name[nb]=Lupe Name[nds]=Kiekglas Name[ne]=परिमार्जक Name[nl]=Vergrootglas Name[nn]=Forstørr skjermdel Name[oc]=Lópia Name[pa]=ਵੱਡਦਰਸ਼ੀ Name[pl]=Powiększenie Name[pt]=Lupa Name[pt_BR]=Lente de aumento Name[ro]=Lupă Name[ru]=Лупа Name[se]=Stuorideaddji Name[si]=විශාලකය Name[sk]=Lupa -Name[sl]=Približevalnik +Name[sl]=Povečevalnik Name[sr]=Увеличавач Name[sr@ijekavian]=Увеличавач Name[sr@ijekavianlatin]=Uveličavač Name[sr@latin]=Uveličavač Name[sv]=Förstoringsglas Name[ta]=பெரிதாக்கி Name[te]=మాగ్నిఫైర్ Name[th]=แว่นขยาย Name[tr]=Büyüteç Name[ug]=چوڭايتقۇچ Name[uk]=Лупа Name[uz]=Kattalashtiruvchi Name[uz@cyrillic]=Катталаштирувчи Name[vi]=Kính lúp Name[wa]=Magnifieu Name[x-test]=xxMagnifierxx Name[zh_CN]=放大镜 Name[zh_TW]=放大鏡 diff --git a/effects/mouseclick/CMakeLists.txt b/effects/mouseclick/CMakeLists.txt index 92b0ae6b8..1b1834d62 100644 --- a/effects/mouseclick/CMakeLists.txt +++ b/effects/mouseclick/CMakeLists.txt @@ -1,25 +1,25 @@ ########################## ## configurtion dialog ########################## set(kwin_mouseclick_config_SRCS mouseclick_config.cpp) ki18n_wrap_ui(kwin_mouseclick_config_SRCS mouseclick_config.ui) -qt5_add_dbus_interface(kwin_mouseclick_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_mouseclick_config_SRCS mouseclickconfig.kcfgc) add_library(kwin_mouseclick_config MODULE ${kwin_mouseclick_config_SRCS}) target_link_libraries(kwin_mouseclick_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_mouseclick_config mouseclick_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_mouseclick_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/mousemark/CMakeLists.txt b/effects/mousemark/CMakeLists.txt index 1a8056e07..fd42575f1 100644 --- a/effects/mousemark/CMakeLists.txt +++ b/effects/mousemark/CMakeLists.txt @@ -1,25 +1,25 @@ ####################################### # Config set(kwin_mousemark_config_SRCS mousemark_config.cpp) ki18n_wrap_ui(kwin_mousemark_config_SRCS mousemark_config.ui) -qt5_add_dbus_interface(kwin_mousemark_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_mousemark_config_SRCS mousemarkconfig.kcfgc) add_library(kwin_mousemark_config MODULE ${kwin_mousemark_config_SRCS}) target_link_libraries(kwin_mousemark_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::TextWidgets KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_mousemark_config mousemark_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_mousemark_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/presentwindows/CMakeLists.txt b/effects/presentwindows/CMakeLists.txt index fc550ae31..9f86c0413 100644 --- a/effects/presentwindows/CMakeLists.txt +++ b/effects/presentwindows/CMakeLists.txt @@ -1,29 +1,29 @@ ####################################### # Effect install(FILES main.qml DESTINATION ${DATA_INSTALL_DIR}/kwin/effects/presentwindows/) ####################################### # Config set(kwin_presentwindows_config_SRCS presentwindows_config.cpp) ki18n_wrap_ui(kwin_presentwindows_config_SRCS presentwindows_config.ui) -qt5_add_dbus_interface(kwin_presentwindows_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_presentwindows_config_SRCS presentwindowsconfig.kcfgc) add_library(kwin_presentwindows_config MODULE ${kwin_presentwindows_config_SRCS}) target_link_libraries(kwin_presentwindows_config KF5::Completion KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_presentwindows_config presentwindows_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_presentwindows_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/resize/CMakeLists.txt b/effects/resize/CMakeLists.txt index 9b6293b86..5b4393533 100644 --- a/effects/resize/CMakeLists.txt +++ b/effects/resize/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_resize_config_SRCS resize_config.cpp) ki18n_wrap_ui(kwin_resize_config_SRCS resize_config.ui) -qt5_add_dbus_interface(kwin_resize_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_resize_config_SRCS resizeconfig.kcfgc) add_library(kwin_resize_config MODULE ${kwin_resize_config_SRCS}) target_link_libraries(kwin_resize_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_resize_config resize_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_resize_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/scale/package/metadata.desktop b/effects/scale/package/metadata.desktop index 5d8823a03..359085e3f 100644 --- a/effects/scale/package/metadata.desktop +++ b/effects/scale/package/metadata.desktop @@ -1,83 +1,85 @@ [Desktop Entry] Name=Scale Name[ca]=Escala Name[ca@valencia]=Escala Name[cs]=Měřítko Name[da]=Skalér Name[de]=Skalieren Name[el]=Κλιμάκωση Name[en_GB]=Scale Name[es]=Escalar Name[et]=Skaleerimine Name[eu]=Eskalatu Name[fi]=Skaalaa Name[fr]=Échelle Name[gl]=Cambiar as dimensións Name[hu]=Nagyítás Name[ia]=Scala Name[id]=Skala Name[it]=Scala Name[ko]=크기 조정 Name[lt]=Mastelio keitimas Name[nl]=Schalen Name[nn]=Skalering Name[pl]=Skalowanie Name[pt]=Escala Name[pt_BR]=Escala Name[ru]=Масштабирование Name[sk]=Škálovať +Name[sl]=Merilo Name[sv]=Skala Name[uk]=Масштабування Name[x-test]=xxScalexx Name[zh_CN]=比例 Name[zh_TW]=縮放 Icon=preferences-system-windows-effect-scale Comment=Make windows smoothly scale in and out when they are shown or hidden Comment[ca]=Fa que les finestres entrin o surtin volant quan es mostren o s'oculten Comment[ca@valencia]=Fa que les finestres entrin o isquen volant quan es mostren o s'oculten Comment[cs]=Nechá okna plynule zvětšit/zmenšit se, pokud jsou zobrazeny resp. skryty Comment[da]=Få vinduer til at skalere blidt ud og ind når de vises eller skjules Comment[de]=Ändert die Fenstergröße langsam beim Ein- oder Ausblenden Comment[en_GB]=Make windows smoothly scale in and out when they are shown or hidden Comment[es]=Hace que las ventanas se agranden o se encojan suavemente al mostrarlas u ocultarlas Comment[et]=Skaleerib aknaid sujuvalt, kui need peidetakse või nähtavale tuuakse Comment[eu]=Leihoak emeki eskalatu barrura eta kanpora haiek erakutsi edo ezkutatzean Comment[fi]=Ikkunat ilmestyvät näkyviin tai poistuvat näkyvistä hiljalleen Comment[fr]=Échelonne les fenêtres lorsqu'elles sont affichées ou cachées Comment[gl]=Facer que as xanelas crezan ou decrezan suavemente cando se mostran ou agochan Comment[ia]=Face que fenestras pote dulcemente scalar intra e foras quando illos es monstrate o celate Comment[id]=Buat window menskala besar atau kecil secara mulus ketika ia ditampilkan atau disembunyikan Comment[it]=Ridimensiona le finestre dolcemente quando sono mostrate o nascoste Comment[ko]=창이 보여지거나 감춰질 때 부드러운 크기 조정을 사용합니다 Comment[lt]=Glotniai didinti ar mažinti langų mastelį, juos parodant ar paslepiant Comment[nl]=Laat vensters vloeiend kleiner en groter schalen als ze worden getoond of verborgen Comment[nn]=Skaler vindauge jamt inn og ut når dei vert viste eller gøymde Comment[pl]=Okna gładko pomniejszają się przy otwieraniu i powiększają przy zamykaniu Comment[pt]=Fazer com que as janelas apareçam/desapareçam suavemente quando aparecem ou ficam escondidas Comment[pt_BR]=Faz com que as janelas aumentem ou reduzam o seu tamanho de forma suave ao serem exibidas ou ocultadas Comment[ru]=Плавное увеличение или уменьшение окон при их появлении и скрытии Comment[sk]=Okná sa plynule objavia/zmiznú pri ich zobrazení alebo skrytí +Comment[sl]=Okna se pojavijo in izginejo postopoma kadar se prikažejo ali skrijejo Comment[sv]=Gör att fönster mjukt skalas in eller ut när de visas eller döljs Comment[uk]=Плавне масштабування вікон при появі або приховуванні Comment[x-test]=xxMake windows smoothly scale in and out when they are shown or hiddenxx Comment[zh_CN]=窗口显示或隐藏时平滑缩放 Comment[zh_TW]=顯示或隱藏視窗時以平順的比例縮放方式呈現。 Type=Service X-KDE-ServiceTypes=KWin/Effect,KCModule X-KDE-PluginInfo-Author=Vlad Zahorodnii X-KDE-PluginInfo-Email=vlad.zahorodnii@kde.org X-KDE-PluginInfo-Name=kwin4_effect_scale X-KDE-PluginInfo-Version=1 X-KDE-PluginInfo-Category=Window Open/Close Animation X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=false X-KDE-Ordering=60 X-Plasma-API=javascript X-Plasma-MainScript=code/main.js X-KDE-PluginKeyword=kwin4_effect_scale X-KDE-Library=kcm_kwin4_genericscripted X-KDE-ParentComponents=kwin4_effect_scale X-KWin-Config-TranslationDomain=kwin_effects X-KWin-Exclusive-Category=toplevel-open-close-animation diff --git a/effects/sessionquit/package/metadata.desktop b/effects/sessionquit/package/metadata.desktop index 70a4eca6c..5dc800e84 100644 --- a/effects/sessionquit/package/metadata.desktop +++ b/effects/sessionquit/package/metadata.desktop @@ -1,69 +1,71 @@ [Desktop Entry] Name=Session Quit Name[ca]=Sortida de la sessió Name[cs]=Sezení bylo ukončeno Name[da]=Afslutning af session Name[en_GB]=Session Quit Name[es]=Cierre de sesión Name[et]=Seansist väljumine Name[eu]=Saiotik irtetea Name[fi]=Istunnon lopetus Name[gl]=Saída de sesión Name[ia]=Abandona session Name[id]=Sesi Berhenti Name[it]=Chiusura sessione Name[ko]=세션 종료 Name[lt]=Seanso baigimas Name[nl]=Afsluiten van sessie Name[nn]=Avslutt økt Name[pl]=Opuszczenie sesji Name[pt]=Saída da Sessão Name[pt_BR]=Saída da sessão Name[ru]=Завершение сеанса Name[sk]=Ukončenie sedenia +Name[sl]=Zapri sejo Name[sv]=Avsluta session Name[uk]=Вихід з сеансу Name[x-test]=xxSession Quitxx Name[zh_CN]=会话退出 Name[zh_TW]=離開工作階段 Icon=preferences-system-windows-effect-logout Comment=Keep the desktop background alive during logout until the end Comment[ca]=Manté viu el fons de l'escriptori durant la sortida de la sessió fins el final Comment[da]=Hold skrivebordsbaggrunden i live under log ud helt til sidst Comment[en_GB]=Keep the desktop background alive during logout until the end Comment[es]=Mantener el fondo del escritorio activo durante el cierre de sesión hasta el final Comment[et]=Töölaua taust hoitakse väljalogimisel alles kuni lõpuni Comment[eu]=Eutsi mahaigaineko atzeko-planoa bizirik saio-ixtean bukaera arte Comment[fi]=Pidä työpöydän tausta käynnissä aina uloskirjautumisen loppuun Comment[gl]=Manter vivo o fondo de escritorio durante a saída ata o final Comment[id]=Jaga latarbelakang desktop tetap nyala selama logout sampai akhir Comment[it]=Mantieni attivo lo sfondo del desktop durante la chiusura della sessione fino alla fine Comment[ko]=로그아웃이 끝날 때까지 데스크톱 배경 그림 유지 Comment[lt]=Atsijungiant, išlaikyti darbalaukio foną reaguojantį iki pat galo Comment[nl]=De achtergrond van het bureaublad tot het einde levend houden gedurende afmelden Comment[nn]=Hald skrivebordsbakgrunnen i live heilt til utlogginga er fullført Comment[pl]=Utrzymuj tło pulpitu podczas wylogowania, aż do końca Comment[pt]=Manter o fundo do ecrã activo durante a saída da sessão até ao fim Comment[pt_BR]=Mantém ativo o fundo da área de trabalho até o fim do fechamento da sessão Comment[ru]=Сохранение фона рабочего стола до окончания завершения сеанса Comment[sk]=Ponechať pozadie plochy aktívne počas odhlásenia do skončenia +Comment[sl]=Pusti ozadje namizja živo ob odjavi do konca Comment[sv]=Behåll skrivbordets bakgrund levande under utloggning till slutet Comment[uk]=Не вимикати тло стільниці до кінця процедури виходу із облікового запису Comment[x-test]=xxKeep the desktop background alive during logout until the endxx Comment[zh_CN]=注销时保持桌面背景,直到完全退出 Comment[zh_TW]=直到登出完成前皆保留桌面背景圖片 Type=Service X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=David Edmundson X-KDE-PluginInfo-Email=davidedmundson@kde.org X-KDE-PluginInfo-Name=kwin4_effect_sessionquit X-KDE-PluginInfo-Version=0.2.0 X-KDE-PluginInfo-Category=Appearance X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-KDE-Ordering=40 X-Plasma-API=javascript X-KWin-Internal=true X-Plasma-MainScript=code/main.js diff --git a/effects/showfps/CMakeLists.txt b/effects/showfps/CMakeLists.txt index a3418d9a3..e217e68fa 100644 --- a/effects/showfps/CMakeLists.txt +++ b/effects/showfps/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_showfps_config_SRCS showfps_config.cpp) ki18n_wrap_ui(kwin_showfps_config_SRCS showfps_config.ui) -qt5_add_dbus_interface(kwin_showfps_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_showfps_config_SRCS showfpsconfig.kcfgc) add_library(kwin_showfps_config MODULE ${kwin_showfps_config_SRCS}) target_link_libraries(kwin_showfps_config KF5::Completion KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_showfps_config showfps_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_showfps_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/showfps/showfps_config.desktop b/effects/showfps/showfps_config.desktop index eceea565f..765b1345d 100644 --- a/effects/showfps/showfps_config.desktop +++ b/effects/showfps/showfps_config.desktop @@ -1,85 +1,85 @@ [Desktop Entry] Type=Service X-KDE-ServiceTypes=KCModule X-KDE-Library=kwin_showfps_config X-KDE-ParentComponents=showfps Name=Show FPS Name[af]=Wys FPS Name[ar]=أظهر عدد الإطارات بالثانية Name[be@latin]=Vyjaŭleńnie „FPS” Name[bg]=Показване на кад/сек Name[bn_IN]=FPS প্রদর্শন করা হবে Name[bs]=Kadrovi/sekundi Name[ca]=Mostra els FPS Name[ca@valencia]=Mostra els FPS Name[cs]=Zobrazit FPS Name[csb]=Wëskrzëni FPS Name[da]=Vis FPS Name[de]=Bilder pro Sekunde anzeigen Name[el]=Εμφάνιση καρέ ανά δευτερόλεπτο Name[en_GB]=Show FPS Name[eo]=Montri FPS Name[es]=Muestra FPS Name[et]=FPS-i näitamine Name[eu]=Erakutsi FPS Name[fa]=نمایش FPS Name[fi]=FPS-näyttö Name[fr]=Afficher le nombre de trames par seconde Name[fy]=FPS sjen litte Name[ga]=Taispeáin FSS Name[gl]=Mostrar os FPS Name[gu]=FPS બતાવો Name[he]=הצג מספר תמונות לשנייה Name[hi]=एफ़पीएस दिखायें Name[hne]=एफपीएस देखाव Name[hr]=Prikaz FPS-a (broj okvira po sekundi) Name[hu]=Képkockaszámláló Name[ia]=Monstra FPS Name[id]=Tampilkan FPS Name[is]=Sýna FPS (rammar á sekúndu) Name[it]=Mostra fotogrammi al secondo Name[ja]=フレームレート (FPS) 表示 Name[kk]=FPS-ты көрсету Name[km]=បង្ហាញ FPS Name[kn]=FPS ತೋರಿಸು Name[ko]=FPS 표시 Name[ku]=FPS'ê nîşan bide Name[lt]=Rodyti kadr./sek. Name[lv]=Rādīt kadrus/sek. Name[mai]=एफपीएस देखाबू Name[mk]=Прикажи рамки/сек Name[ml]=എഫ്‌പിഎസ് കാണിക്കുക Name[mr]=एफपीएस दर्शवा Name[nb]=Vis FPS Name[nds]=Bps wiesen Name[ne]=एफपीएस देखाउनुहोस् Name[nl]=FPS tonen Name[nn]=Vis talet på bilete per sekund Name[pa]=FPS ਵੇਖੋ Name[pl]=Pokaż ilość klatek na sekundę Name[pt]=Mostrar as IPS Name[pt_BR]=Mostrar FPS Name[ro]=Afișează CPS Name[ru]=График производительности Name[se]=Čájet rámmaid sekunddas Name[si]=FPS පෙන්වන්න Name[sk]=Zobraziť FPS -Name[sl]=Sličice na sekundo +Name[sl]=Prikaži sličice na sekundo Name[sr]=Кадрови/секунди Name[sr@ijekavian]=Кадрови/секунди Name[sr@ijekavianlatin]=Kadrovi/sekundi Name[sr@latin]=Kadrovi/sekundi Name[sv]=Visa ramar/s Name[ta]=Show FPS Name[te]=FPS ను చూపుము Name[th]=แสดงอัตราเฟรมต่อวินาที Name[tr]=FPS Göster Name[ug]=FPS نى كۆرسەت Name[uk]=Показ частоти кадрів Name[vi]=Hiện FPS Name[wa]=Mostrer FPS Name[x-test]=xxShow FPSxx Name[zh_CN]=显示 FPS Name[zh_TW]=顯示 FPS 畫格數 diff --git a/effects/slide/CMakeLists.txt b/effects/slide/CMakeLists.txt index 718b903fb..a579bb630 100644 --- a/effects/slide/CMakeLists.txt +++ b/effects/slide/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_slide_config_SRCS slide_config.cpp) ki18n_wrap_ui(kwin_slide_config_SRCS slide_config.ui) -qt5_add_dbus_interface(kwin_slide_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_slide_config_SRCS slideconfig.kcfgc) add_library(kwin_slide_config MODULE ${kwin_slide_config_SRCS}) target_link_libraries(kwin_slide_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_slide_config slide_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_slide_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/squash/package/metadata.desktop b/effects/squash/package/metadata.desktop index c9e7f2b17..36ad7062e 100644 --- a/effects/squash/package/metadata.desktop +++ b/effects/squash/package/metadata.desktop @@ -1,77 +1,79 @@ [Desktop Entry] Comment=Squash windows when they are minimized Comment[ca]=Amuntega les finestres quan estan minimitzades Comment[ca@valencia]=Amuntega les finestres quan estan minimitzades Comment[da]=Mas vinduer når de minimeres Comment[de]=Quetscht Fenster beim Minimieren zusammen Comment[en_GB]=Squash windows when they are minimised Comment[es]=Aplastar las ventanas al minimizarlas Comment[et]=Minimeeritud akende taas üleshüpitamine Comment[eu]=Zanpatu leihoak haiek ikonotzean Comment[fi]=Litistä ikkunat, kun ne pienennetään Comment[fr]=Écrase les fenêtres lorsqu'elles sont minimisées Comment[gl]=Xuntar as xanelas cando estean minimizadas Comment[ia]=Deforma fenestras durante que illes es minimisate Comment[id]=Sesakkan window ketika mereka diminimalkan Comment[it]=Schiaccia le finestre quando vengono minimizzate Comment[ko]=창을 최소화할 때 압축시킵니다 Comment[lt]=Sutraiškyti langus, juos suskleidžiant Comment[nl]=Krimp vensters wanneer ze geminimaliseerd zijn Comment[nn]=Skvis vindauge når dei vert minimerte Comment[pl]=Ściąga okna przy ich minimalizacji Comment[pt]=Esmagar as janelas quando são minimizadas Comment[pt_BR]=Achatar as janelas quando são minimizadas Comment[ru]=Сжатие окна при сворачивании Comment[sk]=Deformuje okná pri ich minimalizovaní +Comment[sl]=Zmečkaj okna, ko jih strneš Comment[sv]=Kläm fönster när de minimeras Comment[uk]=Складує вікна, якщо їх мінімізовано Comment[x-test]=xxSquash windows when they are minimizedxx Comment[zh_CN]=最小化时压扁窗口 Comment[zh_TW]=壓縮最小化的視窗 Icon=preferences-system-windows-effect-squash Name=Squash Name[ca]=Amuntega Name[ca@valencia]=Amuntega Name[da]=Mas Name[de]=Quetschen Name[en_GB]=Squash Name[es]=Aplastar Name[et]=Üleshüpe Name[eu]=Zanpatu Name[fi]=Litistä Name[fr]=Écraser Name[gl]=Xuntar Name[ia]=Squash Name[id]=Sesakkan Name[it]=Schiaccia Name[ko]=압축 Name[lt]=Sutraiškymas Name[nl]=Krimpen Name[nn]=Skvis Name[pl]=Ściąganie Name[pt]=Esmagar Name[pt_BR]=Achatar Name[ru]=Сжатие Name[sk]=Rozpučiť +Name[sl]=Zmečkaj Name[sv]=Kläm Name[uk]=Складування Name[x-test]=xxSquashxx Name[zh_CN]=压扁 Name[zh_TW]=壓縮 Type=Service X-KDE-ParentApp= X-KDE-PluginInfo-Author=Rivo Laks, Vlad Zahorodnii X-KDE-PluginInfo-Category=Appearance X-KDE-PluginInfo-Email=rivolaks@hot.ee, vlad.zahorodnii@kde.org X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-Name=kwin4_effect_squash X-KDE-PluginInfo-Version=1 X-KDE-PluginInfo-Website= X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-EnabledByDefault=true X-KDE-Ordering=60 X-Plasma-API=javascript X-Plasma-MainScript=code/main.js X-KWin-Exclusive-Category=minimize X-KWin-Video-Url=https://files.kde.org/plasma/kwin/effect-videos/minimize.ogv diff --git a/effects/thumbnailaside/CMakeLists.txt b/effects/thumbnailaside/CMakeLists.txt index 6e5caf6c7..dacfb2a7e 100644 --- a/effects/thumbnailaside/CMakeLists.txt +++ b/effects/thumbnailaside/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_thumbnailaside_config_SRCS thumbnailaside_config.cpp) ki18n_wrap_ui(kwin_thumbnailaside_config_SRCS thumbnailaside_config.ui) -qt5_add_dbus_interface(kwin_thumbnailaside_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_thumbnailaside_config_SRCS thumbnailasideconfig.kcfgc) add_library(kwin_thumbnailaside_config MODULE ${kwin_thumbnailaside_config_SRCS}) target_link_libraries(kwin_thumbnailaside_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_thumbnailaside_config thumbnailaside_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_thumbnailaside_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/trackmouse/CMakeLists.txt b/effects/trackmouse/CMakeLists.txt index f467998fc..c44223a00 100644 --- a/effects/trackmouse/CMakeLists.txt +++ b/effects/trackmouse/CMakeLists.txt @@ -1,29 +1,29 @@ ####################################### # Effect # Data files install(FILES data/tm_inner.png data/tm_outer.png DESTINATION ${DATA_INSTALL_DIR}/kwin) ####################################### # Config set(kwin_trackmouse_config_SRCS trackmouse_config.cpp) ki18n_wrap_ui(kwin_trackmouse_config_SRCS trackmouse_config.ui) -qt5_add_dbus_interface(kwin_trackmouse_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_trackmouse_config_SRCS trackmouseconfig.kcfgc) add_library(kwin_trackmouse_config MODULE ${kwin_trackmouse_config_SRCS}) target_link_libraries(kwin_trackmouse_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_trackmouse_config trackmouse_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_trackmouse_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/windowaperture/package/metadata.desktop b/effects/windowaperture/package/metadata.desktop index 6a3d09e6d..fc8d13731 100644 --- a/effects/windowaperture/package/metadata.desktop +++ b/effects/windowaperture/package/metadata.desktop @@ -1,78 +1,80 @@ [Desktop Entry] Name=Window Aperture Name[ast]=Apertura de ventanes Name[ca]=Obertura de la finestra Name[ca@valencia]=Obertura de la finestra Name[cs]=Mřížka oken Name[da]=Vinduesblænding Name[de]=Fensteröffnung Name[el]=Διάφραγμα παραθύρου Name[en_GB]=Window Aperture Name[es]=Apertura de ventanas Name[et]=Aknaava Name[eu]=Leihoa irekitzea Name[fi]=Ikkunoiden siirto näytön kulmiin Name[fr]=Ouverture de la fenêtre Name[gl]=Apertura das xanelas Name[hu]=Ablakrekeszek Name[ia]=Aperturas de fenestra Name[id]=Window Melubang Name[it]=Apertura delle finestre Name[ko]=조리개 모양 배치 Name[lt]=Lango anga Name[nb]=Vindusåpning Name[nl]=Vensteropening Name[nn]=Vindaugsflukt Name[pl]=Przesłona okna Name[pt]=Aperto das Janelas Name[pt_BR]=Aperto das janelas Name[ro]=Diafragmă fereastră Name[ru]=Разбрасывание окон в стороны Name[sk]=Otvor okien Name[sl]=Zaslonka okna Name[sr]=Бленда прозора Name[sr@ijekavian]=Бленда прозора Name[sr@ijekavianlatin]=Blenda prozora Name[sr@latin]=Blenda prozora Name[sv]=Fönsteröppning Name[tr]=Pencere Açıklığı Name[uk]=Апертура вікна Name[x-test]=xxWindow Aperturexx Name[zh_CN]=窗口光圈 Name[zh_TW]=視窗光圈 Icon=preferences-system-windows-effect-windowaperture Comment=Move windows into screen corners Comment[ca]=Mou les finestres cap a les cantonades de la pantalla Comment[cs]=Přesunout okna do rohů obrazovky +Comment[en_GB]=Move windows into screen corners Comment[es]=Mover las ventanas a las esquinas de la pantalla Comment[et]=Akende liigutamine ekraani nurkadesse Comment[eu]=Eraman leihoak pantailako bazterretara Comment[id]=Pindahkan window ke sudut layar Comment[it]=Sposta le finestre negli angoli dello schermo Comment[ko]=창을 화면 꼭짓점으로 이동 Comment[lt]=Perkelti langus į kampus Comment[nl]=Verplaats vensters in de hoeken van het scherm Comment[nn]=Flytt vindauge til skjermhjørne Comment[pt]=Mover as janelas para os cantos do ecrã Comment[pt_BR]=Move as janelas para os cantos da tela Comment[ru]=Перемещение окон в углы экрана +Comment[sl]=Pomakne okna v kote zaslona Comment[sv]=Flytta fönster till skärmhörn Comment[uk]=Пересування вікон до кутів екрана Comment[x-test]=xxMove windows into screen cornersxx Comment[zh_CN]=将窗口移动到屏幕角 Comment[zh_TW]=將視窗移至螢幕角落 Type=Service X-Plasma-API=javascript X-Plasma-MainScript=code/main.js X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=Thomas Lübking X-KDE-PluginInfo-Email=thomas.luebking@gmail.com X-KDE-PluginInfo-Name=kwin4_effect_windowaperture X-KDE-PluginInfo-Version=0.1.0 X-KDE-PluginInfo-Category=Show Desktop Animation X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-KDE-Ordering=50 X-KWin-Exclusive-Category=show-desktop diff --git a/effects/windowgeometry/CMakeLists.txt b/effects/windowgeometry/CMakeLists.txt index 0d13c4fd6..4a460425d 100644 --- a/effects/windowgeometry/CMakeLists.txt +++ b/effects/windowgeometry/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_windowgeometry_config_SRCS windowgeometry_config.cpp) ki18n_wrap_ui(kwin_windowgeometry_config_SRCS windowgeometry_config.ui) -qt5_add_dbus_interface(kwin_windowgeometry_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_windowgeometry_config_SRCS windowgeometryconfig.kcfgc) add_library(kwin_windowgeometry_config MODULE ${kwin_windowgeometry_config_SRCS}) target_link_libraries(kwin_windowgeometry_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_windowgeometry_config windowgeometry_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_windowgeometry_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/wobblywindows/CMakeLists.txt b/effects/wobblywindows/CMakeLists.txt index da4b21c1b..fb2e038e9 100644 --- a/effects/wobblywindows/CMakeLists.txt +++ b/effects/wobblywindows/CMakeLists.txt @@ -1,23 +1,23 @@ ####################################### # Config set(kwin_wobblywindows_config_SRCS wobblywindows_config.cpp) ki18n_wrap_ui(kwin_wobblywindows_config_SRCS wobblywindows_config.ui) -qt5_add_dbus_interface(kwin_wobblywindows_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_wobblywindows_config_SRCS wobblywindowsconfig.kcfgc) add_library(kwin_wobblywindows_config MODULE ${kwin_wobblywindows_config_SRCS}) target_link_libraries(kwin_wobblywindows_config KF5::ConfigWidgets KF5::I18n Qt5::DBus + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_wobblywindows_config wobblywindows_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_wobblywindows_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/effects/zoom/CMakeLists.txt b/effects/zoom/CMakeLists.txt index 81f50a400..b6b47f241 100644 --- a/effects/zoom/CMakeLists.txt +++ b/effects/zoom/CMakeLists.txt @@ -1,24 +1,24 @@ ####################################### # Config set(kwin_zoom_config_SRCS zoom_config.cpp) ki18n_wrap_ui(kwin_zoom_config_SRCS zoom_config.ui) -qt5_add_dbus_interface(kwin_zoom_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) kconfig_add_kcfg_files(kwin_zoom_config_SRCS zoomconfig.kcfgc) add_library(kwin_zoom_config MODULE ${kwin_zoom_config_SRCS}) target_link_libraries(kwin_zoom_config KF5::ConfigWidgets KF5::GlobalAccel KF5::I18n KF5::XmlGui + KWinEffectsInterface ) kcoreaddons_desktop_to_json(kwin_zoom_config zoom_config.desktop SERVICE_TYPES kcmodule.desktop) install( TARGETS kwin_zoom_config DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ) diff --git a/input.cpp b/input.cpp index e2c5f09c6..c0879252f 100644 --- a/input.cpp +++ b/input.cpp @@ -1,2697 +1,2712 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Martin Gräßlin Copyright (C) 2018 Roman Gilg Copyright (C) 2019 Vlad Zahorodnii 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 "input.h" #include "effects.h" #include "gestures.h" #include "globalshortcuts.h" #include "input_event.h" #include "input_event_spy.h" #include "keyboard_input.h" #include "logind.h" #include "main.h" #include "pointer_input.h" #include "tablet_input.h" #include "touch_hide_cursor_spy.h" #include "touch_input.h" #include "x11client.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox/tabbox.h" #endif #include "internal_client.h" #include "libinput/connection.h" #include "libinput/device.h" #include "platform.h" #include "popup_input_filter.h" #include "screenedge.h" #include "screens.h" #include "unmanaged.h" #include "wayland_server.h" #include "workspace.h" #include "xdgshellclient.h" #include "xwl/xwayland_interface.h" #include "cursor.h" #include #include #include #include #include #include #include #include #include //screenlocker #include // Qt #include #include namespace KWin { InputEventFilter::InputEventFilter() = default; InputEventFilter::~InputEventFilter() { if (input()) { input()->uninstallInputEventFilter(this); } } bool InputEventFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton) { Q_UNUSED(event) Q_UNUSED(nativeButton) return false; } bool InputEventFilter::wheelEvent(QWheelEvent *event) { Q_UNUSED(event) return false; } bool InputEventFilter::keyEvent(QKeyEvent *event) { Q_UNUSED(event) return false; } bool InputEventFilter::touchDown(qint32 id, const QPointF &point, quint32 time) { Q_UNUSED(id) Q_UNUSED(point) Q_UNUSED(time) return false; } bool InputEventFilter::touchMotion(qint32 id, const QPointF &point, quint32 time) { Q_UNUSED(id) Q_UNUSED(point) Q_UNUSED(time) return false; } bool InputEventFilter::touchUp(qint32 id, quint32 time) { Q_UNUSED(id) Q_UNUSED(time) return false; } bool InputEventFilter::pinchGestureBegin(int fingerCount, quint32 time) { Q_UNUSED(fingerCount) Q_UNUSED(time) return false; } bool InputEventFilter::pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) { Q_UNUSED(scale) Q_UNUSED(angleDelta) Q_UNUSED(delta) Q_UNUSED(time) return false; } bool InputEventFilter::pinchGestureEnd(quint32 time) { Q_UNUSED(time) return false; } bool InputEventFilter::pinchGestureCancelled(quint32 time) { Q_UNUSED(time) return false; } bool InputEventFilter::swipeGestureBegin(int fingerCount, quint32 time) { Q_UNUSED(fingerCount) Q_UNUSED(time) return false; } bool InputEventFilter::swipeGestureUpdate(const QSizeF &delta, quint32 time) { Q_UNUSED(delta) Q_UNUSED(time) return false; } bool InputEventFilter::swipeGestureEnd(quint32 time) { Q_UNUSED(time) return false; } bool InputEventFilter::swipeGestureCancelled(quint32 time) { Q_UNUSED(time) return false; } bool InputEventFilter::switchEvent(SwitchEvent *event) { Q_UNUSED(event) return false; } bool InputEventFilter::tabletToolEvent(TabletEvent *event) { Q_UNUSED(event) return false; } bool InputEventFilter::tabletToolButtonEvent(const QSet &pressedButtons) { Q_UNUSED(pressedButtons) return false; } bool InputEventFilter::tabletPadButtonEvent(const QSet &pressedButtons) { Q_UNUSED(pressedButtons) return false; } bool InputEventFilter::tabletPadStripEvent(int number, int position, bool isFinger) { Q_UNUSED(number) Q_UNUSED(position) Q_UNUSED(isFinger) return false; } bool InputEventFilter::tabletPadRingEvent(int number, int position, bool isFinger) { Q_UNUSED(number) Q_UNUSED(position) Q_UNUSED(isFinger) return false; } void InputEventFilter::passToWaylandServer(QKeyEvent *event) { Q_ASSERT(waylandServer()); if (event->isAutoRepeat()) { return; } switch (event->type()) { case QEvent::KeyPress: waylandServer()->seat()->keyPressed(event->nativeScanCode()); break; case QEvent::KeyRelease: waylandServer()->seat()->keyReleased(event->nativeScanCode()); break; default: break; } } class VirtualTerminalFilter : public InputEventFilter { public: bool keyEvent(QKeyEvent *event) override { // really on press and not on release? X11 switches on press. if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) { const xkb_keysym_t keysym = event->nativeVirtualKey(); if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) { LogindIntegration::self()->switchVirtualTerminal(keysym - XKB_KEY_XF86Switch_VT_1 + 1); return true; } } return false; } }; class TerminateServerFilter : public InputEventFilter { public: bool keyEvent(QKeyEvent *event) override { if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) { if (event->nativeVirtualKey() == XKB_KEY_Terminate_Server) { qCWarning(KWIN_CORE) << "Request to terminate server"; QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); return true; } } return false; } }; class LockScreenFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { if (!waylandServer()->isScreenLocked()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(event->timestamp()); if (event->type() == QEvent::MouseMove) { if (pointerSurfaceAllowed()) { // TODO: should the pointer position always stay in sync, i.e. not do the check? seat->setPointerPos(event->screenPos().toPoint()); } } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) { if (pointerSurfaceAllowed()) { // TODO: can we leak presses/releases here when we move the mouse in between from an allowed surface to // disallowed one or vice versa? event->type() == QEvent::MouseButtonPress ? seat->pointerButtonPressed(nativeButton) : seat->pointerButtonReleased(nativeButton); } } return true; } bool wheelEvent(QWheelEvent *event) override { if (!waylandServer()->isScreenLocked()) { return false; } auto seat = waylandServer()->seat(); if (pointerSurfaceAllowed()) { seat->setTimestamp(event->timestamp()); const Qt::Orientation orientation = event->angleDelta().x() == 0 ? Qt::Vertical : Qt::Horizontal; seat->pointerAxis(orientation, orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y()); } return true; } bool keyEvent(QKeyEvent * event) override { if (!waylandServer()->isScreenLocked()) { return false; } if (event->isAutoRepeat()) { // wayland client takes care of it return true; } // send event to KSldApp for global accel // if event is set to accepted it means a whitelisted shortcut was triggered // in that case we filter it out and don't process it further event->setAccepted(false); QCoreApplication::sendEvent(ScreenLocker::KSldApp::self(), event); if (event->isAccepted()) { return true; } // continue normal processing input()->keyboard()->update(); auto seat = waylandServer()->seat(); seat->setTimestamp(event->timestamp()); if (!keyboardSurfaceAllowed()) { // don't pass event to seat return true; } switch (event->type()) { case QEvent::KeyPress: seat->keyPressed(event->nativeScanCode()); break; case QEvent::KeyRelease: seat->keyReleased(event->nativeScanCode()); break; default: break; } return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { if (!waylandServer()->isScreenLocked()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); if (touchSurfaceAllowed()) { input()->touch()->insertId(id, seat->touchDown(pos)); } return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { if (!waylandServer()->isScreenLocked()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); if (touchSurfaceAllowed()) { const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId != -1) { seat->touchMove(kwaylandId, pos); } } return true; } bool touchUp(qint32 id, quint32 time) override { if (!waylandServer()->isScreenLocked()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); if (touchSurfaceAllowed()) { const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId != -1) { seat->touchUp(kwaylandId); input()->touch()->removeId(id); } } return true; } bool pinchGestureBegin(int fingerCount, quint32 time) override { Q_UNUSED(fingerCount) Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) override { Q_UNUSED(scale) Q_UNUSED(angleDelta) Q_UNUSED(delta) Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool pinchGestureEnd(quint32 time) override { Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool pinchGestureCancelled(quint32 time) override { Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool swipeGestureBegin(int fingerCount, quint32 time) override { Q_UNUSED(fingerCount) Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override { Q_UNUSED(delta) Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool swipeGestureEnd(quint32 time) override { Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } bool swipeGestureCancelled(quint32 time) override { Q_UNUSED(time) // no touchpad multi-finger gestures on lock screen return waylandServer()->isScreenLocked(); } private: bool surfaceAllowed(KWayland::Server::SurfaceInterface *(KWayland::Server::SeatInterface::*method)() const) const { if (KWayland::Server::SurfaceInterface *s = (waylandServer()->seat()->*method)()) { if (Toplevel *t = waylandServer()->findClient(s)) { return t->isLockScreen() || t->isInputMethod(); } return false; } return true; } bool pointerSurfaceAllowed() const { return surfaceAllowed(&KWayland::Server::SeatInterface::focusedPointerSurface); } bool keyboardSurfaceAllowed() const { return surfaceAllowed(&KWayland::Server::SeatInterface::focusedKeyboardSurface); } bool touchSurfaceAllowed() const { return surfaceAllowed(&KWayland::Server::SeatInterface::focusedTouchSurface); } }; class EffectsFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) if (!effects) { return false; } return static_cast(effects)->checkInputWindowEvent(event); } bool wheelEvent(QWheelEvent *event) override { if (!effects) { return false; } return static_cast(effects)->checkInputWindowEvent(event); } bool keyEvent(QKeyEvent *event) override { if (!effects || !static_cast< EffectsHandlerImpl* >(effects)->hasKeyboardGrab()) { return false; } waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); passToWaylandServer(event); static_cast< EffectsHandlerImpl* >(effects)->grabbedKeyboardEvent(event); return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { if (!effects) { return false; } return static_cast< EffectsHandlerImpl* >(effects)->touchDown(id, pos, time); } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { if (!effects) { return false; } return static_cast< EffectsHandlerImpl* >(effects)->touchMotion(id, pos, time); } bool touchUp(qint32 id, quint32 time) override { if (!effects) { return false; } return static_cast< EffectsHandlerImpl* >(effects)->touchUp(id, time); } }; class MoveResizeFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) AbstractClient *c = workspace()->moveResizeClient(); if (!c) { return false; } switch (event->type()) { case QEvent::MouseMove: c->updateMoveResize(event->screenPos().toPoint()); break; case QEvent::MouseButtonRelease: if (event->buttons() == Qt::NoButton) { c->endMoveResize(); } break; default: break; } return true; } bool wheelEvent(QWheelEvent *event) override { Q_UNUSED(event) // filter out while moving a window return workspace()->moveResizeClient() != nullptr; } bool keyEvent(QKeyEvent *event) override { AbstractClient *c = workspace()->moveResizeClient(); if (!c) { return false; } if (event->type() == QEvent::KeyPress) { c->keyPressEvent(event->key() | event->modifiers()); if (c->isMove() || c->isResize()) { // only update if mode didn't end c->updateMoveResize(input()->globalPointer()); } } return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(id) Q_UNUSED(pos) Q_UNUSED(time) AbstractClient *c = workspace()->moveResizeClient(); if (!c) { return false; } return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) AbstractClient *c = workspace()->moveResizeClient(); if (!c) { return false; } if (!m_set) { m_id = id; m_set = true; } if (m_id == id) { c->updateMoveResize(pos.toPoint()); } return true; } bool touchUp(qint32 id, quint32 time) override { Q_UNUSED(time) AbstractClient *c = workspace()->moveResizeClient(); if (!c) { return false; } if (m_id == id || !m_set) { c->endMoveResize(); m_set = false; // pass through to update decoration filter later on return false; } m_set = false; return true; } private: qint32 m_id = 0; bool m_set = false; }; class WindowSelectorFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) if (!m_active) { return false; } switch (event->type()) { case QEvent::MouseButtonRelease: if (event->buttons() == Qt::NoButton) { if (event->button() == Qt::RightButton) { cancel(); } else { accept(event->globalPos()); } } break; default: break; } return true; } bool wheelEvent(QWheelEvent *event) override { Q_UNUSED(event) // filter out while selecting a window return m_active; } bool keyEvent(QKeyEvent *event) override { Q_UNUSED(event) if (!m_active) { return false; } waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); passToWaylandServer(event); if (event->type() == QEvent::KeyPress) { // x11 variant does this on key press, so do the same if (event->key() == Qt::Key_Escape) { cancel(); } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return || event->key() == Qt::Key_Space) { accept(input()->globalPointer()); } if (input()->supportsPointerWarping()) { int mx = 0; int my = 0; if (event->key() == Qt::Key_Left) { mx = -10; } if (event->key() == Qt::Key_Right) { mx = 10; } if (event->key() == Qt::Key_Up) { my = -10; } if (event->key() == Qt::Key_Down) { my = 10; } if (event->modifiers() & Qt::ControlModifier) { mx /= 10; my /= 10; } input()->warpPointer(input()->globalPointer() + QPointF(mx, my)); } } // filter out while selecting a window return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) if (!isActive()) { return false; } m_touchPoints.insert(id, pos); return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) if (!isActive()) { return false; } auto it = m_touchPoints.find(id); if (it != m_touchPoints.end()) { *it = pos; } return true; } bool touchUp(qint32 id, quint32 time) override { Q_UNUSED(time) if (!isActive()) { return false; } auto it = m_touchPoints.find(id); if (it != m_touchPoints.end()) { const auto pos = it.value(); m_touchPoints.erase(it); if (m_touchPoints.isEmpty()) { accept(pos); } } return true; } bool isActive() const { return m_active; } void start(std::function callback) { Q_ASSERT(!m_active); m_active = true; m_callback = callback; input()->keyboard()->update(); input()->cancelTouch(); } void start(std::function callback) { Q_ASSERT(!m_active); m_active = true; m_pointSelectionFallback = callback; input()->keyboard()->update(); input()->cancelTouch(); } private: void deactivate() { m_active = false; m_callback = std::function(); m_pointSelectionFallback = std::function(); input()->pointer()->removeWindowSelectionCursor(); input()->keyboard()->update(); m_touchPoints.clear(); } void cancel() { if (m_callback) { m_callback(nullptr); } if (m_pointSelectionFallback) { m_pointSelectionFallback(QPoint(-1, -1)); } deactivate(); } void accept(const QPoint &pos) { if (m_callback) { // TODO: this ignores shaped windows m_callback(input()->findToplevel(pos)); } if (m_pointSelectionFallback) { m_pointSelectionFallback(pos); } deactivate(); } void accept(const QPointF &pos) { accept(pos.toPoint()); } bool m_active = false; std::function m_callback; std::function m_pointSelectionFallback; QMap m_touchPoints; }; class GlobalShortcutFilter : public InputEventFilter { public: + GlobalShortcutFilter() { + m_powerDown = new QTimer; + m_powerDown->setSingleShot(true); + m_powerDown->setInterval(1000); + } + ~GlobalShortcutFilter() { + delete m_powerDown; + } + bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton); if (event->type() == QEvent::MouseButtonPress) { if (input()->shortcuts()->processPointerPressed(event->modifiers(), event->buttons())) { return true; } } return false; } bool wheelEvent(QWheelEvent *event) override { if (event->modifiers() == Qt::NoModifier) { return false; } PointerAxisDirection direction = PointerAxisUp; if (event->angleDelta().x() < 0) { direction = PointerAxisRight; } else if (event->angleDelta().x() > 0) { direction = PointerAxisLeft; } else if (event->angleDelta().y() < 0) { direction = PointerAxisDown; } else if (event->angleDelta().y() > 0) { direction = PointerAxisUp; } return input()->shortcuts()->processAxis(event->modifiers(), direction); } bool keyEvent(QKeyEvent *event) override { if (event->key() == Qt::Key_PowerOff) { - if (event->type() == QEvent::KeyPress) { - m_powerOffPress = event->timestamp(); + const auto modifiers = static_cast(event)->modifiersRelevantForGlobalShortcuts(); + if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) { + QObject::connect(m_powerDown, &QTimer::timeout, input()->shortcuts(), [this, modifiers] { + QObject::disconnect(m_powerDown, &QTimer::timeout, input()->shortcuts(), nullptr); + m_powerDown->stop(); + input()->shortcuts()->processKey(modifiers, Qt::Key_PowerDown); + }); + m_powerDown->start(); + return true; } else if (event->type() == QEvent::KeyRelease) { - const uint duration = (event->timestamp() - m_powerOffPress); - const Qt::Key key = duration > 1000 ? Qt::Key_PowerDown : Qt::Key_PowerOff; - const auto shortcuts = static_cast(event)->modifiersRelevantForGlobalShortcuts(); - return input()->shortcuts()->processKey(shortcuts, key | (event->key() & ~Qt::KeyboardModifierMask)); + const bool ret = !m_powerDown->isActive() || input()->shortcuts()->processKey(modifiers, event->key()); + m_powerDown->stop(); + return ret; } } else if (event->type() == QEvent::KeyPress) { return input()->shortcuts()->processKey(static_cast(event)->modifiersRelevantForGlobalShortcuts(), event->key()); } return false; } bool swipeGestureBegin(int fingerCount, quint32 time) override { Q_UNUSED(time) input()->shortcuts()->processSwipeStart(fingerCount); return false; } bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override { Q_UNUSED(time) input()->shortcuts()->processSwipeUpdate(delta); return false; } bool swipeGestureCancelled(quint32 time) override { Q_UNUSED(time) input()->shortcuts()->processSwipeCancel(); return false; } bool swipeGestureEnd(quint32 time) override { Q_UNUSED(time) input()->shortcuts()->processSwipeEnd(); return false; } private: - uint m_powerOffPress; + QTimer* m_powerDown = nullptr; }; namespace { enum class MouseAction { ModifierOnly, ModifierAndWindow }; std::pair performClientMouseAction(QMouseEvent *event, AbstractClient *client, MouseAction action = MouseAction::ModifierOnly) { Options::MouseCommand command = Options::MouseNothing; bool wasAction = false; if (static_cast(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) { if (!input()->pointer()->isConstrained() && !workspace()->globalShortcutsDisabled()) { wasAction = true; switch (event->button()) { case Qt::LeftButton: command = options->commandAll1(); break; case Qt::MiddleButton: command = options->commandAll2(); break; case Qt::RightButton: command = options->commandAll3(); break; default: // nothing break; } } } else { if (action == MouseAction::ModifierAndWindow) { command = client->getMouseCommand(event->button(), &wasAction); } } if (wasAction) { return std::make_pair(wasAction, !client->performMouseCommand(command, event->globalPos())); } return std::make_pair(wasAction, false); } std::pair performClientWheelAction(QWheelEvent *event, AbstractClient *c, MouseAction action = MouseAction::ModifierOnly) { bool wasAction = false; Options::MouseCommand command = Options::MouseNothing; if (static_cast(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) { if (!input()->pointer()->isConstrained() && !workspace()->globalShortcutsDisabled()) { wasAction = true; command = options->operationWindowMouseWheel(-1 * event->angleDelta().y()); } } else { if (action == MouseAction::ModifierAndWindow) { command = c->getWheelCommand(Qt::Vertical, &wasAction); } } if (wasAction) { return std::make_pair(wasAction, !c->performMouseCommand(command, event->globalPos())); } return std::make_pair(wasAction, false); } } class InternalWindowEventFilter : public InputEventFilter { bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) auto internal = input()->pointer()->internalWindow(); if (!internal) { return false; } // find client switch (event->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { auto s = qobject_cast(workspace()->findInternal(internal)); if (s && s->isDecorated()) { // only perform mouse commands on decorated internal windows const auto actionResult = performClientMouseAction(event, s); if (actionResult.first) { return actionResult.second; } } break; } default: break; } QMouseEvent e(event->type(), event->pos() - internal->position(), event->globalPos(), event->button(), event->buttons(), event->modifiers()); e.setAccepted(false); QCoreApplication::sendEvent(internal.data(), &e); return e.isAccepted(); } bool wheelEvent(QWheelEvent *event) override { auto internal = input()->pointer()->internalWindow(); if (!internal) { return false; } if (event->angleDelta().y() != 0) { auto s = qobject_cast(workspace()->findInternal(internal)); if (s && s->isDecorated()) { // client window action only on vertical scrolling const auto actionResult = performClientWheelAction(event, s); if (actionResult.first) { return actionResult.second; } } } const QPointF localPos = event->globalPosF() - QPointF(internal->x(), internal->y()); const Qt::Orientation orientation = (event->angleDelta().x() != 0) ? Qt::Horizontal : Qt::Vertical; const int delta = event->angleDelta().x() != 0 ? event->angleDelta().x() : event->angleDelta().y(); QWheelEvent e(localPos, event->globalPosF(), QPoint(), event->angleDelta() * -1, delta * -1, orientation, event->buttons(), event->modifiers()); e.setAccepted(false); QCoreApplication::sendEvent(internal.data(), &e); return e.isAccepted(); } bool keyEvent(QKeyEvent *event) override { const QList &internalClients = workspace()->internalClients(); if (internalClients.isEmpty()) { return false; } QWindow *found = nullptr; auto it = internalClients.end(); do { it--; if (QWindow *w = (*it)->internalWindow()) { if (!w->isVisible()) { continue; } if (!screens()->geometry().contains(w->geometry())) { continue; } if (w->property("_q_showWithoutActivating").toBool()) { continue; } if (w->property("outputOnly").toBool()) { continue; } if (w->flags().testFlag(Qt::ToolTip)) { continue; } found = w; break; } } while (it != internalClients.begin()); if (!found) { return false; } auto xkb = input()->keyboard()->xkb(); Qt::Key key = xkb->toQtKey(xkb->toKeysym(event->nativeScanCode())); if (key == Qt::Key_Super_L || key == Qt::Key_Super_R) { // workaround for QTBUG-62102 key = Qt::Key_Meta; } QKeyEvent internalEvent(event->type(), key, event->modifiers(), event->nativeScanCode(), event->nativeVirtualKey(), event->nativeModifiers(), event->text()); internalEvent.setAccepted(false); if (QCoreApplication::sendEvent(found, &internalEvent)) { waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); passToWaylandServer(event); return true; } return false; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { auto seat = waylandServer()->seat(); if (seat->isTouchSequence()) { // something else is getting the events return false; } auto touch = input()->touch(); if (touch->internalPressId() != -1) { // already on internal window, ignore further touch points, but filter out return true; } // a new touch point seat->setTimestamp(time); auto internal = touch->internalWindow(); if (!internal) { return false; } touch->setInternalPressId(id); // Qt's touch event API is rather complex, let's do fake mouse events instead m_lastGlobalTouchPos = pos; m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); QEnterEvent enterEvent(m_lastLocalTouchPos, m_lastLocalTouchPos, pos); QCoreApplication::sendEvent(internal.data(), &enterEvent); QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); e.setAccepted(false); QCoreApplication::sendEvent(internal.data(), &e); return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { auto touch = input()->touch(); auto internal = touch->internalWindow(); if (!internal) { return false; } if (touch->internalPressId() == -1) { return false; } waylandServer()->seat()->setTimestamp(time); if (touch->internalPressId() != qint32(id)) { // ignore, but filter out return true; } m_lastGlobalTouchPos = pos; m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y()); QMouseEvent e(QEvent::MouseMove, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); QCoreApplication::instance()->sendEvent(internal.data(), &e); return true; } bool touchUp(qint32 id, quint32 time) override { auto touch = input()->touch(); auto internal = touch->internalWindow(); if (!internal) { return false; } if (touch->internalPressId() == -1) { return false; } waylandServer()->seat()->setTimestamp(time); if (touch->internalPressId() != qint32(id)) { // ignore, but filter out return true; } // send mouse up QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); e.setAccepted(false); QCoreApplication::sendEvent(internal.data(), &e); QEvent leaveEvent(QEvent::Leave); QCoreApplication::sendEvent(internal.data(), &leaveEvent); m_lastGlobalTouchPos = QPointF(); m_lastLocalTouchPos = QPointF(); input()->touch()->setInternalPressId(-1); return true; } private: QPointF m_lastGlobalTouchPos; QPointF m_lastLocalTouchPos; }; class DecorationEventFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) auto decoration = input()->pointer()->decoration(); if (!decoration) { return false; } const QPointF p = event->globalPos() - decoration->client()->pos(); switch (event->type()) { case QEvent::MouseMove: { QHoverEvent e(QEvent::HoverMove, p, p); QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); decoration->client()->processDecorationMove(p.toPoint(), event->globalPos()); return true; } case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { const auto actionResult = performClientMouseAction(event, decoration->client()); if (actionResult.first) { return actionResult.second; } QMouseEvent e(event->type(), p, event->globalPos(), event->button(), event->buttons(), event->modifiers()); e.setAccepted(false); QCoreApplication::sendEvent(decoration->decoration(), &e); if (!e.isAccepted() && event->type() == QEvent::MouseButtonPress) { decoration->client()->processDecorationButtonPress(&e); } if (event->type() == QEvent::MouseButtonRelease) { decoration->client()->processDecorationButtonRelease(&e); } return true; } default: break; } return false; } bool wheelEvent(QWheelEvent *event) override { auto decoration = input()->pointer()->decoration(); if (!decoration) { return false; } if (event->angleDelta().y() != 0) { // client window action only on vertical scrolling const auto actionResult = performClientWheelAction(event, decoration->client()); if (actionResult.first) { return actionResult.second; } } const QPointF localPos = event->globalPosF() - decoration->client()->pos(); const Qt::Orientation orientation = (event->angleDelta().x() != 0) ? Qt::Horizontal : Qt::Vertical; const int delta = event->angleDelta().x() != 0 ? event->angleDelta().x() : event->angleDelta().y(); QWheelEvent e(localPos, event->globalPosF(), QPoint(), event->angleDelta(), delta, orientation, event->buttons(), event->modifiers()); e.setAccepted(false); QCoreApplication::sendEvent(decoration.data(), &e); if (e.isAccepted()) { return true; } if ((orientation == Qt::Vertical) && decoration->client()->titlebarPositionUnderMouse()) { decoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1), event->globalPosF().toPoint()); } return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { auto seat = waylandServer()->seat(); if (seat->isTouchSequence()) { return false; } if (input()->touch()->decorationPressId() != -1) { // already on a decoration, ignore further touch points, but filter out return true; } seat->setTimestamp(time); auto decoration = input()->touch()->decoration(); if (!decoration) { return false; } input()->touch()->setDecorationPressId(id); m_lastGlobalTouchPos = pos; m_lastLocalTouchPos = pos - decoration->client()->pos(); QHoverEvent hoverEvent(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos); QCoreApplication::sendEvent(decoration->decoration(), &hoverEvent); QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers()); e.setAccepted(false); QCoreApplication::sendEvent(decoration->decoration(), &e); if (!e.isAccepted()) { decoration->client()->processDecorationButtonPress(&e); } return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) auto decoration = input()->touch()->decoration(); if (!decoration) { return false; } if (input()->touch()->decorationPressId() == -1) { return false; } if (input()->touch()->decorationPressId() != qint32(id)) { // ignore, but filter out return true; } m_lastGlobalTouchPos = pos; m_lastLocalTouchPos = pos - decoration->client()->pos(); QHoverEvent e(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos); QCoreApplication::instance()->sendEvent(decoration->decoration(), &e); decoration->client()->processDecorationMove(m_lastLocalTouchPos.toPoint(), pos.toPoint()); return true; } bool touchUp(qint32 id, quint32 time) override { Q_UNUSED(time); auto decoration = input()->touch()->decoration(); if (!decoration) { return false; } if (input()->touch()->decorationPressId() == -1) { return false; } if (input()->touch()->decorationPressId() != qint32(id)) { // ignore, but filter out return true; } // send mouse up QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers()); e.setAccepted(false); QCoreApplication::sendEvent(decoration->decoration(), &e); decoration->client()->processDecorationButtonRelease(&e); QHoverEvent leaveEvent(QEvent::HoverLeave, QPointF(), QPointF()); QCoreApplication::sendEvent(decoration->decoration(), &leaveEvent); m_lastGlobalTouchPos = QPointF(); m_lastLocalTouchPos = QPointF(); input()->touch()->setDecorationPressId(-1); return true; } private: QPointF m_lastGlobalTouchPos; QPointF m_lastLocalTouchPos; }; #ifdef KWIN_BUILD_TABBOX class TabBoxInputFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 button) override { Q_UNUSED(button) if (!TabBox::TabBox::self() || !TabBox::TabBox::self()->isGrabbed()) { return false; } return TabBox::TabBox::self()->handleMouseEvent(event); } bool keyEvent(QKeyEvent *event) override { if (!TabBox::TabBox::self() || !TabBox::TabBox::self()->isGrabbed()) { return false; } auto seat = waylandServer()->seat(); seat->setFocusedKeyboardSurface(nullptr); input()->pointer()->setEnableConstraints(false); // pass the key event to the seat, so that it has a proper model of the currently hold keys // this is important for combinations like alt+shift to ensure that shift is not considered pressed passToWaylandServer(event); if (event->type() == QEvent::KeyPress) { TabBox::TabBox::self()->keyPress(event->modifiers() | event->key()); } else if (static_cast(event)->modifiersRelevantForGlobalShortcuts() == Qt::NoModifier) { TabBox::TabBox::self()->modifiersReleased(); } return true; } bool wheelEvent(QWheelEvent *event) override { if (!TabBox::TabBox::self() || !TabBox::TabBox::self()->isGrabbed()) { return false; } return TabBox::TabBox::self()->handleWheelEvent(event); } }; #endif class ScreenEdgeInputFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) ScreenEdges::self()->isEntered(event); // always forward return false; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) // TODO: better check whether a touch sequence is in progress if (m_touchInProgress || waylandServer()->seat()->isTouchSequence()) { // cancel existing touch ScreenEdges::self()->gestureRecognizer()->cancelSwipeGesture(); m_touchInProgress = false; m_id = 0; return false; } if (ScreenEdges::self()->gestureRecognizer()->startSwipeGesture(pos) > 0) { m_touchInProgress = true; m_id = id; m_lastPos = pos; return true; } return false; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(time) if (m_touchInProgress && m_id == id) { ScreenEdges::self()->gestureRecognizer()->updateSwipeGesture(QSizeF(pos.x() - m_lastPos.x(), pos.y() - m_lastPos.y())); m_lastPos = pos; return true; } return false; } bool touchUp(qint32 id, quint32 time) override { Q_UNUSED(time) if (m_touchInProgress && m_id == id) { ScreenEdges::self()->gestureRecognizer()->endSwipeGesture(); m_touchInProgress = false; return true; } return false; } private: bool m_touchInProgress = false; qint32 m_id = 0; QPointF m_lastPos; }; /** * This filter implements window actions. If the event should not be passed to the * current pointer window it will filter out the event */ class WindowActionInputFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { Q_UNUSED(nativeButton) if (event->type() != QEvent::MouseButtonPress) { return false; } AbstractClient *c = dynamic_cast(input()->pointer()->focus().data()); if (!c) { return false; } const auto actionResult = performClientMouseAction(event, c, MouseAction::ModifierAndWindow); if (actionResult.first) { return actionResult.second; } return false; } bool wheelEvent(QWheelEvent *event) override { if (event->angleDelta().y() == 0) { // only actions on vertical scroll return false; } AbstractClient *c = dynamic_cast(input()->pointer()->focus().data()); if (!c) { return false; } const auto actionResult = performClientWheelAction(event, c, MouseAction::ModifierAndWindow); if (actionResult.first) { return actionResult.second; } return false; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { Q_UNUSED(id) Q_UNUSED(time) auto seat = waylandServer()->seat(); if (seat->isTouchSequence()) { return false; } AbstractClient *c = dynamic_cast(input()->touch()->focus().data()); if (!c) { return false; } bool wasAction = false; const Options::MouseCommand command = c->getMouseCommand(Qt::LeftButton, &wasAction); if (wasAction) { return !c->performMouseCommand(command, pos.toPoint()); } return false; } }; /** * The remaining default input filter which forwards events to other windows */ class ForwardInputFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { auto seat = waylandServer()->seat(); seat->setTimestamp(event->timestamp()); switch (event->type()) { case QEvent::MouseMove: { seat->setPointerPos(event->globalPos()); MouseEvent *e = static_cast(event); if (e->delta() != QSizeF()) { seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestampMicroseconds()); } break; } case QEvent::MouseButtonPress: seat->pointerButtonPressed(nativeButton); break; case QEvent::MouseButtonRelease: seat->pointerButtonReleased(nativeButton); break; default: break; } return true; } bool wheelEvent(QWheelEvent *event) override { auto seat = waylandServer()->seat(); seat->setTimestamp(event->timestamp()); auto _event = static_cast(event); KWayland::Server::PointerAxisSource source; switch (_event->axisSource()) { case KWin::InputRedirection::PointerAxisSourceWheel: source = KWayland::Server::PointerAxisSource::Wheel; break; case KWin::InputRedirection::PointerAxisSourceFinger: source = KWayland::Server::PointerAxisSource::Finger; break; case KWin::InputRedirection::PointerAxisSourceContinuous: source = KWayland::Server::PointerAxisSource::Continuous; break; case KWin::InputRedirection::PointerAxisSourceWheelTilt: source = KWayland::Server::PointerAxisSource::WheelTilt; break; case KWin::InputRedirection::PointerAxisSourceUnknown: default: source = KWayland::Server::PointerAxisSource::Unknown; break; } seat->pointerAxisV5(_event->orientation(), _event->delta(), _event->discreteDelta(), source); return true; } bool keyEvent(QKeyEvent *event) override { if (!workspace()) { return false; } if (event->isAutoRepeat()) { // handled by Wayland client return false; } auto seat = waylandServer()->seat(); input()->keyboard()->update(); seat->setTimestamp(event->timestamp()); passToWaylandServer(event); return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); input()->touch()->insertId(id, seat->touchDown(pos)); return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId != -1) { seat->touchMove(kwaylandId, pos); } return true; } bool touchUp(qint32 id, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId != -1) { seat->touchUp(kwaylandId); input()->touch()->removeId(id); } return true; } bool pinchGestureBegin(int fingerCount, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->startPointerPinchGesture(fingerCount); return true; } bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->updatePointerPinchGesture(delta, scale, angleDelta); return true; } bool pinchGestureEnd(quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->endPointerPinchGesture(); return true; } bool pinchGestureCancelled(quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->cancelPointerPinchGesture(); return true; } bool swipeGestureBegin(int fingerCount, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->startPointerSwipeGesture(fingerCount); return true; } bool swipeGestureUpdate(const QSizeF &delta, quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->updatePointerSwipeGesture(delta); return true; } bool swipeGestureEnd(quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->endPointerSwipeGesture(); return true; } bool swipeGestureCancelled(quint32 time) override { if (!workspace()) { return false; } auto seat = waylandServer()->seat(); seat->setTimestamp(time); seat->cancelPointerSwipeGesture(); return true; } }; static KWayland::Server::SeatInterface *findSeat() { auto server = waylandServer(); if (!server) { return nullptr; } return server->seat(); } /** * Useful when there's no proper tablet support on the clients */ class TabletInputFilter : public QObject, public InputEventFilter { public: TabletInputFilter() { } static KWayland::Server::TabletSeatInterface *findTabletSeat() { auto server = waylandServer(); if (!server) { return nullptr; } KWayland::Server::TabletManagerInterface *manager = server->tabletManager(); return manager->seat(findSeat()); } void integrateDevice(LibInput::Device *device) { if (device->isTabletTool()) { KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat(); struct udev_device *const udev_device = libinput_device_get_udev_device(device->device()); const char *devnode = udev_device_get_devnode(udev_device); tabletSeat->addTablet(device->vendor(), device->product(), device->sysName(), device->name(), {QString::fromUtf8(devnode)}); } } void removeDevice(const QString &sysname) { KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat(); tabletSeat->removeTablet(sysname); } bool tabletToolEvent(TabletEvent *event) override { if (!workspace()) { return false; } KWayland::Server::TabletSeatInterface *tabletSeat = findTabletSeat(); auto tool = tabletSeat->toolByHardwareSerial(event->serialId()); if (!tool) { using namespace KWayland::Server; const QVector capabilities = event->capabilities(); const auto f = [](InputRedirection::Capability cap) { switch (cap) { case InputRedirection::Tilt: return TabletToolInterface::Tilt; case InputRedirection::Pressure: return TabletToolInterface::Pressure; case InputRedirection::Distance: return TabletToolInterface::Distance; case InputRedirection::Rotation: return TabletToolInterface::Rotation; case InputRedirection::Slider: return TabletToolInterface::Slider; case InputRedirection::Wheel: return TabletToolInterface::Wheel; } return TabletToolInterface::Wheel; }; QVector ifaceCapabilities; ifaceCapabilities.resize(capabilities.size()); std::transform(capabilities.constBegin(), capabilities.constEnd(), ifaceCapabilities.begin(), f); TabletToolInterface::Type toolType = TabletToolInterface::Type::Pen; switch (event->toolType()) { case InputRedirection::Pen: toolType = TabletToolInterface::Type::Pen; break; case InputRedirection::Eraser: toolType = TabletToolInterface::Type::Eraser; break; case InputRedirection::Brush: toolType = TabletToolInterface::Type::Brush; break; case InputRedirection::Pencil: toolType = TabletToolInterface::Type::Pencil; break; case InputRedirection::Airbrush: toolType = TabletToolInterface::Type::Airbrush; break; case InputRedirection::Finger: toolType = TabletToolInterface::Type::Finger; break; case InputRedirection::Mouse: toolType = TabletToolInterface::Type::Mouse; break; case InputRedirection::Lens: toolType = TabletToolInterface::Type::Lens; break; case InputRedirection::Totem: toolType = TabletToolInterface::Type::Totem; break; } tool = tabletSeat->addTool(toolType, event->serialId(), event->uniqueId(), ifaceCapabilities); } KWayland::Server::TabletInterface *tablet = tabletSeat->tabletByName(event->tabletSysName()); Toplevel *toplevel = input()->findToplevel(event->globalPos()); if (!toplevel || !toplevel->surface()) { return false; } KWayland::Server::SurfaceInterface *surface = toplevel->surface(); tool->setCurrentSurface(surface); if (!tool->isClientSupported() || !tablet->isSurfaceSupported(surface)) { return emulateTabletEvent(event); } switch (event->type()) { case QEvent::TabletMove: { const auto pos = event->globalPosF() - toplevel->pos(); tool->sendMotion(pos); break; } case QEvent::TabletEnterProximity: { tool->sendProximityIn(tablet); break; } case QEvent::TabletLeaveProximity: tool->sendProximityOut(); break; case QEvent::TabletPress: tool->sendDown(); break; case QEvent::TabletRelease: tool->sendUp(); break; default: qCWarning(KWIN_CORE) << "Unexpected tablet event type" << event; break; } const quint32 MAX_VAL = 65535; tool->sendPressure(MAX_VAL * event->pressure()); tool->sendFrame(event->timestamp()); waylandServer()->simulateUserActivity(); return true; } bool emulateTabletEvent(TabletEvent *event) { if (!workspace()) { return false; } switch (event->type()) { case QEvent::TabletMove: case QEvent::TabletEnterProximity: input()->pointer()->processMotion(event->globalPosF(), event->timestamp()); break; case QEvent::TabletPress: input()->pointer()->processButton(KWin::qtMouseButtonToButton(Qt::LeftButton), InputRedirection::PointerButtonPressed, event->timestamp()); break; case QEvent::TabletRelease: input()->pointer()->processButton(KWin::qtMouseButtonToButton(Qt::LeftButton), InputRedirection::PointerButtonReleased, event->timestamp()); break; case QEvent::TabletLeaveProximity: break; default: qCWarning(KWIN_CORE) << "Unexpected tablet event type" << event; break; } waylandServer()->simulateUserActivity(); return true; } }; class DragAndDropInputFilter : public InputEventFilter { public: bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override { auto seat = waylandServer()->seat(); if (!seat->isDragPointer()) { return false; } if (seat->isDragTouch()) { return true; } seat->setTimestamp(event->timestamp()); switch (event->type()) { case QEvent::MouseMove: { const auto pos = input()->globalPointer(); seat->setPointerPos(pos); const auto eventPos = event->globalPos(); // TODO: use InputDeviceHandler::at() here and check isClient()? Toplevel *t = input()->findManagedToplevel(eventPos); if (auto *xwl = xwayland()) { const auto ret = xwl->dragMoveFilter(t, eventPos); if (ret == Xwl::DragEventReply::Ignore) { return false; } else if (ret == Xwl::DragEventReply::Take) { break; } } if (t) { // TODO: consider decorations if (t->surface() != seat->dragSurface()) { if (AbstractClient *c = qobject_cast(t)) { workspace()->activateClient(c); } seat->setDragTarget(t->surface(), t->inputTransformation()); } } else { // no window at that place, if we have a surface we need to reset seat->setDragTarget(nullptr); } break; } case QEvent::MouseButtonPress: seat->pointerButtonPressed(nativeButton); break; case QEvent::MouseButtonRelease: seat->pointerButtonReleased(nativeButton); break; default: break; } // TODO: should we pass through effects? return true; } bool touchDown(qint32 id, const QPointF &pos, quint32 time) override { auto seat = waylandServer()->seat(); if (seat->isDragPointer()) { return true; } if (!seat->isDragTouch()) { return false; } if (m_touchId != id) { return true; } seat->setTimestamp(time); input()->touch()->insertId(id, seat->touchDown(pos)); return true; } bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override { auto seat = waylandServer()->seat(); if (seat->isDragPointer()) { return true; } if (!seat->isDragTouch()) { return false; } if (m_touchId < 0) { // We take for now the first id appearing as a move after a drag // started. We can optimize by specifying the id the drag is // associated with by implementing a key-value getter in KWayland. m_touchId = id; } if (m_touchId != id) { return true; } seat->setTimestamp(time); const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId == -1) { return true; } seat->touchMove(kwaylandId, pos); if (Toplevel *t = input()->findToplevel(pos.toPoint())) { // TODO: consider decorations if (t->surface() != seat->dragSurface()) { if (AbstractClient *c = qobject_cast(t)) { workspace()->activateClient(c); } seat->setDragTarget(t->surface(), pos, t->inputTransformation()); } } else { // no window at that place, if we have a surface we need to reset seat->setDragTarget(nullptr); } return true; } bool touchUp(qint32 id, quint32 time) override { auto seat = waylandServer()->seat(); if (!seat->isDragTouch()) { return false; } seat->setTimestamp(time); const qint32 kwaylandId = input()->touch()->mappedId(id); if (kwaylandId != -1) { seat->touchUp(kwaylandId); input()->touch()->removeId(id); } if (m_touchId == id) { m_touchId = -1; } return true; } private: qint32 m_touchId = -1; }; KWIN_SINGLETON_FACTORY(InputRedirection) static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad"); InputRedirection::InputRedirection(QObject *parent) : QObject(parent) , m_keyboard(new KeyboardInputRedirection(this)) , m_pointer(new PointerInputRedirection(this)) , m_tablet(new TabletInputRedirection(this)) , m_touch(new TouchInputRedirection(this)) , m_shortcuts(new GlobalShortcutsManager(this)) { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); if (Application::usesLibinput()) { if (LogindIntegration::self()->hasSessionControl()) { setupLibInput(); } else { LibInput::Connection::createThread(); if (LogindIntegration::self()->isConnected()) { LogindIntegration::self()->takeControl(); } else { connect(LogindIntegration::self(), &LogindIntegration::connectedChanged, LogindIntegration::self(), &LogindIntegration::takeControl); } connect(LogindIntegration::self(), &LogindIntegration::hasSessionControlChanged, this, [this] (bool sessionControl) { if (sessionControl) { setupLibInput(); } } ); } } connect(kwinApp(), &Application::workspaceCreated, this, &InputRedirection::setupWorkspace); reconfigure(); } InputRedirection::~InputRedirection() { s_self = nullptr; qDeleteAll(m_filters); qDeleteAll(m_spies); } void InputRedirection::installInputEventFilter(InputEventFilter *filter) { Q_ASSERT(!m_filters.contains(filter)); m_filters << filter; } void InputRedirection::prependInputEventFilter(InputEventFilter *filter) { Q_ASSERT(!m_filters.contains(filter)); m_filters.prepend(filter); } void InputRedirection::uninstallInputEventFilter(InputEventFilter *filter) { m_filters.removeOne(filter); } void InputRedirection::installInputEventSpy(InputEventSpy *spy) { m_spies << spy; } void InputRedirection::uninstallInputEventSpy(InputEventSpy *spy) { m_spies.removeOne(spy); } void InputRedirection::init() { m_shortcuts->init(); } void InputRedirection::setupWorkspace() { if (waylandServer()) { using namespace KWayland::Server; FakeInputInterface *fakeInput = waylandServer()->display()->createFakeInput(this); fakeInput->create(); connect(fakeInput, &FakeInputInterface::deviceCreated, this, [this] (FakeInputDevice *device) { connect(device, &FakeInputDevice::authenticationRequested, this, [device] (const QString &application, const QString &reason) { Q_UNUSED(application) Q_UNUSED(reason) // TODO: make secure device->setAuthentication(true); } ); connect(device, &FakeInputDevice::pointerMotionRequested, this, [this] (const QSizeF &delta) { // TODO: Fix time m_pointer->processMotion(globalPointer() + QPointF(delta.width(), delta.height()), 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::pointerMotionAbsoluteRequested, this, [this] (const QPointF &pos) { // TODO: Fix time m_pointer->processMotion(pos, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::pointerButtonPressRequested, this, [this] (quint32 button) { // TODO: Fix time m_pointer->processButton(button, InputRedirection::PointerButtonPressed, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::pointerButtonReleaseRequested, this, [this] (quint32 button) { // TODO: Fix time m_pointer->processButton(button, InputRedirection::PointerButtonReleased, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::pointerAxisRequested, this, [this] (Qt::Orientation orientation, qreal delta) { // TODO: Fix time InputRedirection::PointerAxis axis; switch (orientation) { case Qt::Horizontal: axis = InputRedirection::PointerAxisHorizontal; break; case Qt::Vertical: axis = InputRedirection::PointerAxisVertical; break; default: Q_UNREACHABLE(); break; } // TODO: Fix time m_pointer->processAxis(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::touchDownRequested, this, [this] (qint32 id, const QPointF &pos) { // TODO: Fix time m_touch->processDown(id, pos, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::touchMotionRequested, this, [this] (qint32 id, const QPointF &pos) { // TODO: Fix time m_touch->processMotion(id, pos, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::touchUpRequested, this, [this] (qint32 id) { // TODO: Fix time m_touch->processUp(id, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::touchCancelRequested, this, [this] () { m_touch->cancel(); } ); connect(device, &FakeInputDevice::touchFrameRequested, this, [this] () { m_touch->frame(); } ); connect(device, &FakeInputDevice::keyboardKeyPressRequested, this, [this] (quint32 button) { // TODO: Fix time m_keyboard->processKey(button, InputRedirection::KeyboardKeyPressed, 0); waylandServer()->simulateUserActivity(); } ); connect(device, &FakeInputDevice::keyboardKeyReleaseRequested, this, [this] (quint32 button) { // TODO: Fix time m_keyboard->processKey(button, InputRedirection::KeyboardKeyReleased, 0); waylandServer()->simulateUserActivity(); } ); } ); connect(workspace(), &Workspace::configChanged, this, &InputRedirection::reconfigure); m_keyboard->init(); m_pointer->init(); m_touch->init(); m_tablet->init(); } setupInputFilters(); } void InputRedirection::setupInputFilters() { const bool hasGlobalShortcutSupport = !waylandServer() || waylandServer()->hasGlobalShortcutSupport(); if (LogindIntegration::self()->hasSessionControl() && hasGlobalShortcutSupport) { installInputEventFilter(new VirtualTerminalFilter); } if (waylandServer()) { installInputEventSpy(new TouchHideCursorSpy); if (hasGlobalShortcutSupport) { installInputEventFilter(new TerminateServerFilter); } installInputEventFilter(new DragAndDropInputFilter); installInputEventFilter(new LockScreenFilter); installInputEventFilter(new PopupInputFilter); m_windowSelector = new WindowSelectorFilter; installInputEventFilter(m_windowSelector); } if (hasGlobalShortcutSupport) { installInputEventFilter(new ScreenEdgeInputFilter); } installInputEventFilter(new EffectsFilter); installInputEventFilter(new MoveResizeFilter); #ifdef KWIN_BUILD_TABBOX installInputEventFilter(new TabBoxInputFilter); #endif if (hasGlobalShortcutSupport) { installInputEventFilter(new GlobalShortcutFilter); } installInputEventFilter(new DecorationEventFilter); installInputEventFilter(new InternalWindowEventFilter); if (waylandServer()) { installInputEventFilter(new WindowActionInputFilter); installInputEventFilter(new ForwardInputFilter); if (m_libInput) { m_tabletSupport = new TabletInputFilter; for (LibInput::Device *dev : m_libInput->devices()) { m_tabletSupport->integrateDevice(dev); } connect(m_libInput, &LibInput::Connection::deviceAdded, m_tabletSupport, &TabletInputFilter::integrateDevice); connect(m_libInput, &LibInput::Connection::deviceRemovedSysName, m_tabletSupport, &TabletInputFilter::removeDevice); installInputEventFilter(m_tabletSupport); } } } void InputRedirection::reconfigure() { if (Application::usesLibinput()) { auto inputConfig = kwinApp()->inputConfig(); inputConfig->reparseConfiguration(); const auto config = inputConfig->group(QStringLiteral("Keyboard")); const int delay = config.readEntry("RepeatDelay", 660); const int rate = config.readEntry("RepeatRate", 25); const bool enabled = config.readEntry("KeyboardRepeating", 0) == 0; waylandServer()->seat()->setKeyRepeatInfo(enabled ? rate : 0, delay); } } void InputRedirection::setupLibInput() { if (!Application::usesLibinput()) { return; } if (m_libInput) { return; } LibInput::Connection *conn = LibInput::Connection::create(this); m_libInput = conn; if (conn) { if (waylandServer()) { // create relative pointer manager waylandServer()->display()->createRelativePointerManager(KWayland::Server::RelativePointerInterfaceVersion::UnstableV1, waylandServer()->display())->create(); } conn->setInputConfig(kwinApp()->inputConfig()); conn->updateLEDs(m_keyboard->xkb()->leds()); waylandServer()->updateKeyState(m_keyboard->xkb()->leds()); connect(m_keyboard, &KeyboardInputRedirection::ledsChanged, waylandServer(), &WaylandServer::updateKeyState); connect(m_keyboard, &KeyboardInputRedirection::ledsChanged, conn, &LibInput::Connection::updateLEDs); connect(conn, &LibInput::Connection::eventsRead, this, [this] { m_libInput->processEvents(); }, Qt::QueuedConnection ); conn->setup(); connect(conn, &LibInput::Connection::pointerButtonChanged, m_pointer, &PointerInputRedirection::processButton); connect(conn, &LibInput::Connection::pointerAxisChanged, m_pointer, &PointerInputRedirection::processAxis); connect(conn, &LibInput::Connection::pinchGestureBegin, m_pointer, &PointerInputRedirection::processPinchGestureBegin); connect(conn, &LibInput::Connection::pinchGestureUpdate, m_pointer, &PointerInputRedirection::processPinchGestureUpdate); connect(conn, &LibInput::Connection::pinchGestureEnd, m_pointer, &PointerInputRedirection::processPinchGestureEnd); connect(conn, &LibInput::Connection::pinchGestureCancelled, m_pointer, &PointerInputRedirection::processPinchGestureCancelled); connect(conn, &LibInput::Connection::swipeGestureBegin, m_pointer, &PointerInputRedirection::processSwipeGestureBegin); connect(conn, &LibInput::Connection::swipeGestureUpdate, m_pointer, &PointerInputRedirection::processSwipeGestureUpdate); connect(conn, &LibInput::Connection::swipeGestureEnd, m_pointer, &PointerInputRedirection::processSwipeGestureEnd); connect(conn, &LibInput::Connection::swipeGestureCancelled, m_pointer, &PointerInputRedirection::processSwipeGestureCancelled); connect(conn, &LibInput::Connection::keyChanged, m_keyboard, &KeyboardInputRedirection::processKey); connect(conn, &LibInput::Connection::pointerMotion, this, [this] (const QSizeF &delta, const QSizeF &deltaNonAccel, uint32_t time, quint64 timeMicroseconds, LibInput::Device *device) { m_pointer->processMotion(m_pointer->pos() + QPointF(delta.width(), delta.height()), delta, deltaNonAccel, time, timeMicroseconds, device); } ); connect(conn, &LibInput::Connection::pointerMotionAbsolute, this, [this] (QPointF orig, QPointF screen, uint32_t time, LibInput::Device *device) { Q_UNUSED(orig) m_pointer->processMotion(screen, time, device); } ); connect(conn, &LibInput::Connection::touchDown, m_touch, &TouchInputRedirection::processDown); connect(conn, &LibInput::Connection::touchUp, m_touch, &TouchInputRedirection::processUp); connect(conn, &LibInput::Connection::touchMotion, m_touch, &TouchInputRedirection::processMotion); connect(conn, &LibInput::Connection::touchCanceled, m_touch, &TouchInputRedirection::cancel); connect(conn, &LibInput::Connection::touchFrame, m_touch, &TouchInputRedirection::frame); auto handleSwitchEvent = [this] (SwitchEvent::State state, quint32 time, quint64 timeMicroseconds, LibInput::Device *device) { SwitchEvent event(state, time, timeMicroseconds, device); processSpies(std::bind(&InputEventSpy::switchEvent, std::placeholders::_1, &event)); processFilters(std::bind(&InputEventFilter::switchEvent, std::placeholders::_1, &event)); }; connect(conn, &LibInput::Connection::switchToggledOn, this, std::bind(handleSwitchEvent, SwitchEvent::State::On, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); connect(conn, &LibInput::Connection::switchToggledOff, this, std::bind(handleSwitchEvent, SwitchEvent::State::Off, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); connect(conn, &LibInput::Connection::tabletToolEvent, m_tablet, &TabletInputRedirection::tabletToolEvent); connect(conn, &LibInput::Connection::tabletToolButtonEvent, m_tablet, &TabletInputRedirection::tabletToolButtonEvent); connect(conn, &LibInput::Connection::tabletPadButtonEvent, m_tablet, &TabletInputRedirection::tabletPadButtonEvent); connect(conn, &LibInput::Connection::tabletPadRingEvent, m_tablet, &TabletInputRedirection::tabletPadRingEvent); connect(conn, &LibInput::Connection::tabletPadStripEvent, m_tablet, &TabletInputRedirection::tabletPadStripEvent); if (screens()) { setupLibInputWithScreens(); } else { connect(kwinApp(), &Application::screensCreated, this, &InputRedirection::setupLibInputWithScreens); } if (auto s = findSeat()) { // Workaround for QTBUG-54371: if there is no real keyboard Qt doesn't request virtual keyboard s->setHasKeyboard(true); s->setHasPointer(conn->hasPointer()); s->setHasTouch(conn->hasTouch()); connect(conn, &LibInput::Connection::hasAlphaNumericKeyboardChanged, this, [this] (bool set) { if (m_libInput->isSuspended()) { return; } // TODO: this should update the seat, only workaround for QTBUG-54371 emit hasAlphaNumericKeyboardChanged(set); } ); connect(conn, &LibInput::Connection::hasTabletModeSwitchChanged, this, [this] (bool set) { if (m_libInput->isSuspended()) { return; } emit hasTabletModeSwitchChanged(set); } ); connect(conn, &LibInput::Connection::hasPointerChanged, this, [this, s] (bool set) { if (m_libInput->isSuspended()) { return; } s->setHasPointer(set); } ); connect(conn, &LibInput::Connection::hasTouchChanged, this, [this, s] (bool set) { if (m_libInput->isSuspended()) { return; } s->setHasTouch(set); } ); } connect(LogindIntegration::self(), &LogindIntegration::sessionActiveChanged, m_libInput, [this] (bool active) { if (!active) { m_libInput->deactivate(); } } ); } setupTouchpadShortcuts(); } void InputRedirection::setupTouchpadShortcuts() { if (!m_libInput) { return; } QAction *touchpadToggleAction = new QAction(this); QAction *touchpadOnAction = new QAction(this); QAction *touchpadOffAction = new QAction(this); touchpadToggleAction->setObjectName(QStringLiteral("Toggle Touchpad")); touchpadToggleAction->setProperty("componentName", s_touchpadComponent); touchpadOnAction->setObjectName(QStringLiteral("Enable Touchpad")); touchpadOnAction->setProperty("componentName", s_touchpadComponent); touchpadOffAction->setObjectName(QStringLiteral("Disable Touchpad")); touchpadOffAction->setProperty("componentName", s_touchpadComponent); KGlobalAccel::self()->setDefaultShortcut(touchpadToggleAction, QList{Qt::Key_TouchpadToggle}); KGlobalAccel::self()->setShortcut(touchpadToggleAction, QList{Qt::Key_TouchpadToggle}); KGlobalAccel::self()->setDefaultShortcut(touchpadOnAction, QList{Qt::Key_TouchpadOn}); KGlobalAccel::self()->setShortcut(touchpadOnAction, QList{Qt::Key_TouchpadOn}); KGlobalAccel::self()->setDefaultShortcut(touchpadOffAction, QList{Qt::Key_TouchpadOff}); KGlobalAccel::self()->setShortcut(touchpadOffAction, QList{Qt::Key_TouchpadOff}); #ifndef KWIN_BUILD_TESTING registerShortcut(Qt::Key_TouchpadToggle, touchpadToggleAction); registerShortcut(Qt::Key_TouchpadOn, touchpadOnAction); registerShortcut(Qt::Key_TouchpadOff, touchpadOffAction); #endif connect(touchpadToggleAction, &QAction::triggered, m_libInput, &LibInput::Connection::toggleTouchpads); connect(touchpadOnAction, &QAction::triggered, m_libInput, &LibInput::Connection::enableTouchpads); connect(touchpadOffAction, &QAction::triggered, m_libInput, &LibInput::Connection::disableTouchpads); } bool InputRedirection::hasAlphaNumericKeyboard() { if (m_libInput) { return m_libInput->hasAlphaNumericKeyboard(); } return true; } bool InputRedirection::hasTabletModeSwitch() { if (m_libInput) { return m_libInput->hasTabletModeSwitch(); } return false; } void InputRedirection::setupLibInputWithScreens() { if (!screens() || !m_libInput) { return; } m_libInput->setScreenSize(screens()->size()); m_libInput->updateScreens(); connect(screens(), &Screens::sizeChanged, this, [this] { m_libInput->setScreenSize(screens()->size()); } ); connect(screens(), &Screens::changed, m_libInput, &LibInput::Connection::updateScreens); } void InputRedirection::processPointerMotion(const QPointF &pos, uint32_t time) { m_pointer->processMotion(pos, time); } void InputRedirection::processPointerButton(uint32_t button, InputRedirection::PointerButtonState state, uint32_t time) { m_pointer->processButton(button, state, time); } void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qreal delta, qint32 discreteDelta, PointerAxisSource source, uint32_t time) { m_pointer->processAxis(axis, delta, discreteDelta, source, time); } void InputRedirection::processKeyboardKey(uint32_t key, InputRedirection::KeyboardKeyState state, uint32_t time) { m_keyboard->processKey(key, state, time); } void InputRedirection::processKeyboardModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group) { m_keyboard->processModifiers(modsDepressed, modsLatched, modsLocked, group); } void InputRedirection::processKeymapChange(int fd, uint32_t size) { m_keyboard->processKeymapChange(fd, size); } void InputRedirection::processTouchDown(qint32 id, const QPointF &pos, quint32 time) { m_touch->processDown(id, pos, time); } void InputRedirection::processTouchUp(qint32 id, quint32 time) { m_touch->processUp(id, time); } void InputRedirection::processTouchMotion(qint32 id, const QPointF &pos, quint32 time) { m_touch->processMotion(id, pos, time); } void InputRedirection::cancelTouch() { m_touch->cancel(); } void InputRedirection::touchFrame() { m_touch->frame(); } Qt::MouseButtons InputRedirection::qtButtonStates() const { return m_pointer->buttons(); } static bool acceptsInput(Toplevel *t, const QPoint &pos) { const QRegion input = t->inputShape(); if (input.isEmpty()) { return true; } // TODO: What about sub-surfaces sticking outside the main surface? const QPoint localPoint = pos - t->bufferGeometry().topLeft(); return input.contains(localPoint); } Toplevel *InputRedirection::findToplevel(const QPoint &pos) { if (!Workspace::self()) { return nullptr; } const bool isScreenLocked = waylandServer() && waylandServer()->isScreenLocked(); // TODO: check whether the unmanaged wants input events at all if (!isScreenLocked) { // if an effect overrides the cursor we don't have a window to focus if (effects && static_cast(effects)->isMouseInterception()) { return nullptr; } const QList &unmanaged = Workspace::self()->unmanagedList(); foreach (Unmanaged *u, unmanaged) { if (u->inputGeometry().contains(pos) && acceptsInput(u, pos)) { return u; } } } return findManagedToplevel(pos); } Toplevel *InputRedirection::findManagedToplevel(const QPoint &pos) { if (!Workspace::self()) { return nullptr; } const bool isScreenLocked = waylandServer() && waylandServer()->isScreenLocked(); const QList &stacking = Workspace::self()->stackingOrder(); if (stacking.isEmpty()) { return nullptr; } auto it = stacking.end(); do { --it; Toplevel *t = (*it); if (t->isDeleted()) { // a deleted window doesn't get mouse events continue; } if (AbstractClient *c = dynamic_cast(t)) { if (!c->isOnCurrentActivity() || !c->isOnCurrentDesktop() || c->isMinimized() || c->isHiddenInternal()) { continue; } } if (!t->readyForPainting()) { continue; } if (isScreenLocked) { if (!t->isLockScreen() && !t->isInputMethod()) { continue; } } if (t->inputGeometry().contains(pos) && acceptsInput(t, pos)) { return t; } } while (it != stacking.begin()); return nullptr; } Qt::KeyboardModifiers InputRedirection::keyboardModifiers() const { return m_keyboard->modifiers(); } Qt::KeyboardModifiers InputRedirection::modifiersRelevantForGlobalShortcuts() const { return m_keyboard->modifiersRelevantForGlobalShortcuts(); } void InputRedirection::registerShortcut(const QKeySequence &shortcut, QAction *action) { Q_UNUSED(shortcut) kwinApp()->platform()->setupActionForGlobalAccel(action); } void InputRedirection::registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action) { m_shortcuts->registerPointerShortcut(action, modifiers, pointerButtons); } void InputRedirection::registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action) { m_shortcuts->registerAxisShortcut(action, modifiers, axis); } void InputRedirection::registerTouchpadSwipeShortcut(SwipeDirection direction, QAction *action) { m_shortcuts->registerTouchpadSwipe(action, direction); } void InputRedirection::registerGlobalAccel(KGlobalAccelInterface *interface) { m_shortcuts->setKGlobalAccelInterface(interface); } void InputRedirection::warpPointer(const QPointF &pos) { m_pointer->warp(pos); } bool InputRedirection::supportsPointerWarping() const { return m_pointer->supportsWarping(); } QPointF InputRedirection::globalPointer() const { return m_pointer->pos(); } void InputRedirection::startInteractiveWindowSelection(std::function callback, const QByteArray &cursorName) { if (!m_windowSelector || m_windowSelector->isActive()) { callback(nullptr); return; } m_windowSelector->start(callback); m_pointer->setWindowSelectionCursor(cursorName); } void InputRedirection::startInteractivePositionSelection(std::function callback) { if (!m_windowSelector || m_windowSelector->isActive()) { callback(QPoint(-1, -1)); return; } m_windowSelector->start(callback); m_pointer->setWindowSelectionCursor(QByteArray()); } bool InputRedirection::isSelectingWindow() const { return m_windowSelector ? m_windowSelector->isActive() : false; } InputDeviceHandler::InputDeviceHandler(InputRedirection *input) : QObject(input) { } InputDeviceHandler::~InputDeviceHandler() = default; void InputDeviceHandler::init() { connect(workspace(), &Workspace::stackingOrderChanged, this, &InputDeviceHandler::update); connect(workspace(), &Workspace::clientMinimizedChanged, this, &InputDeviceHandler::update); connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, this, &InputDeviceHandler::update); } bool InputDeviceHandler::setAt(Toplevel *toplevel) { if (m_at.at == toplevel) { return false; } auto old = m_at.at; disconnect(m_at.surfaceCreatedConnection); m_at.surfaceCreatedConnection = QMetaObject::Connection(); m_at.at = toplevel; emit atChanged(old, toplevel); return true; } void InputDeviceHandler::setFocus(Toplevel *toplevel) { m_focus.focus = toplevel; //TODO: call focusUpdate? } void InputDeviceHandler::setDecoration(QPointer decoration) { auto oldDeco = m_focus.decoration; m_focus.decoration = decoration; cleanupDecoration(oldDeco.data(), m_focus.decoration.data()); emit decorationChanged(); } void InputDeviceHandler::setInternalWindow(QWindow *window) { m_focus.internalWindow = window; //TODO: call internalWindowUpdate? } void InputDeviceHandler::updateFocus() { auto oldFocus = m_focus.focus; if (m_at.at && !m_at.at->surface()) { // The surface has not yet been created (special XWayland case). // Therefore listen for its creation. if (!m_at.surfaceCreatedConnection) { m_at.surfaceCreatedConnection = connect(m_at.at, &Toplevel::surfaceChanged, this, &InputDeviceHandler::update); } m_focus.focus = nullptr; } else { m_focus.focus = m_at.at; } focusUpdate(oldFocus, m_focus.focus); } bool InputDeviceHandler::updateDecoration() { const auto oldDeco = m_focus.decoration; m_focus.decoration = nullptr; auto *ac = qobject_cast(m_at.at); if (ac && ac->decoratedClient()) { const QRect clientRect = QRect(ac->clientPos(), ac->clientSize()).translated(ac->pos()); if (!clientRect.contains(position().toPoint())) { // input device above decoration m_focus.decoration = ac->decoratedClient(); } } if (m_focus.decoration == oldDeco) { // no change to decoration return false; } cleanupDecoration(oldDeco.data(), m_focus.decoration.data()); emit decorationChanged(); return true; } void InputDeviceHandler::updateInternalWindow(QWindow *window) { if (m_focus.internalWindow == window) { // no change return; } const auto oldInternal = m_focus.internalWindow; m_focus.internalWindow = window; cleanupInternalWindow(oldInternal, window); } void InputDeviceHandler::update() { if (!m_inited) { return; } Toplevel *toplevel = nullptr; QWindow *internalWindow = nullptr; if (!positionValid()) { const auto pos = position().toPoint(); internalWindow = findInternalWindow(pos); if (internalWindow) { toplevel = workspace()->findInternal(internalWindow); } else { toplevel = input()->findToplevel(pos); } } // Always set the toplevel at the position of the input device. setAt(toplevel); if (focusUpdatesBlocked()) { return; } if (internalWindow) { if (m_focus.internalWindow != internalWindow) { // changed internal window updateDecoration(); updateInternalWindow(internalWindow); updateFocus(); } else if (updateDecoration()) { // went onto or off from decoration, update focus updateFocus(); } return; } updateInternalWindow(nullptr); if (m_focus.focus != m_at.at) { // focus change updateDecoration(); updateFocus(); return; } // check if switched to/from decoration while staying on the same Toplevel if (updateDecoration()) { // went onto or off from decoration, update focus updateFocus(); } } QWindow* InputDeviceHandler::findInternalWindow(const QPoint &pos) const { if (waylandServer()->isScreenLocked()) { return nullptr; } const QList &internalClients = workspace()->internalClients(); if (internalClients.isEmpty()) { return nullptr; } auto it = internalClients.end(); do { --it; QWindow *w = (*it)->internalWindow(); if (!w || !w->isVisible()) { continue; } if (!(*it)->frameGeometry().contains(pos)) { continue; } // check input mask const QRegion mask = w->mask().translated(w->geometry().topLeft()); if (!mask.isEmpty() && !mask.contains(pos)) { continue; } if (w->property("outputOnly").toBool()) { continue; } return w; } while (it != internalClients.begin()); return nullptr; } } // namespace diff --git a/kcmkwin/common/effectsmodel.cpp b/kcmkwin/common/effectsmodel.cpp index 9584c05b4..60e733b5e 100644 --- a/kcmkwin/common/effectsmodel.cpp +++ b/kcmkwin/common/effectsmodel.cpp @@ -1,682 +1,682 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Antonis Tsiapaliokas Copyright (C) 2018 Vlad Zahorodnii 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 "effectsmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KWin { static QString translatedCategory(const QString &category) { static const QVector knownCategories = { QStringLiteral("Accessibility"), QStringLiteral("Appearance"), QStringLiteral("Focus"), QStringLiteral("Show Desktop Animation"), QStringLiteral("Tools"), QStringLiteral("Virtual Desktop Switching Animation"), QStringLiteral("Window Management"), QStringLiteral("Window Open/Close Animation") }; static const QVector translatedCategories = { i18nc("Category of Desktop Effects, used as section header", "Accessibility"), i18nc("Category of Desktop Effects, used as section header", "Appearance"), i18nc("Category of Desktop Effects, used as section header", "Focus"), i18nc("Category of Desktop Effects, used as section header", "Show Desktop Animation"), i18nc("Category of Desktop Effects, used as section header", "Tools"), i18nc("Category of Desktop Effects, used as section header", "Virtual Desktop Switching Animation"), i18nc("Category of Desktop Effects, used as section header", "Window Management"), i18nc("Category of Desktop Effects, used as section header", "Window Open/Close Animation") }; const int index = knownCategories.indexOf(category); if (index == -1) { qDebug() << "Unknown category '" << category << "' and thus not translated"; return category; } return translatedCategories[index]; } static EffectsModel::Status effectStatus(bool enabled) { return enabled ? EffectsModel::Status::Enabled : EffectsModel::Status::Disabled; } EffectsModel::EffectsModel(QObject *parent) : QAbstractItemModel(parent) { } QHash EffectsModel::roleNames() const { QHash roleNames; roleNames[NameRole] = "NameRole"; roleNames[DescriptionRole] = "DescriptionRole"; roleNames[AuthorNameRole] = "AuthorNameRole"; roleNames[AuthorEmailRole] = "AuthorEmailRole"; roleNames[LicenseRole] = "LicenseRole"; roleNames[VersionRole] = "VersionRole"; roleNames[CategoryRole] = "CategoryRole"; roleNames[ServiceNameRole] = "ServiceNameRole"; roleNames[IconNameRole] = "IconNameRole"; roleNames[StatusRole] = "StatusRole"; roleNames[VideoRole] = "VideoRole"; roleNames[WebsiteRole] = "WebsiteRole"; roleNames[SupportedRole] = "SupportedRole"; roleNames[ExclusiveRole] = "ExclusiveRole"; roleNames[ConfigurableRole] = "ConfigurableRole"; roleNames[ScriptedRole] = QByteArrayLiteral("ScriptedRole"); roleNames[EnabledByDefaultRole] = "EnabledByDefaultRole"; return roleNames; } QModelIndex EffectsModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effects.count()) { return {}; } return createIndex(row, column); } QModelIndex EffectsModel::parent(const QModelIndex &child) const { Q_UNUSED(child) return {}; } int EffectsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } int EffectsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_effects.count(); } QVariant EffectsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return {}; } const EffectData effect = m_effects.at(index.row()); switch (role) { case Qt::DisplayRole: case NameRole: return effect.name; case DescriptionRole: return effect.description; case AuthorNameRole: return effect.authorName; case AuthorEmailRole: return effect.authorEmail; case LicenseRole: return effect.license; case VersionRole: return effect.version; case CategoryRole: return effect.category; case ServiceNameRole: return effect.serviceName; case IconNameRole: return effect.iconName; case StatusRole: return static_cast(effect.status); case VideoRole: return effect.video; case WebsiteRole: return effect.website; case SupportedRole: return effect.supported; case ExclusiveRole: return effect.exclusiveGroup; case InternalRole: return effect.internal; case ConfigurableRole: return effect.configurable; case ScriptedRole: return effect.kind == Kind::Scripted; case EnabledByDefaultRole: return effect.enabledByDefault; default: return {}; } } bool EffectsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return QAbstractItemModel::setData(index, value, role); } if (role == StatusRole) { // note: whenever the StatusRole is modified (even to the same value) the entry // gets marked as changed and will get saved to the config file. This means the // config file could get polluted EffectData &data = m_effects[index.row()]; data.status = Status(value.toInt()); data.changed = data.status != data.originalStatus; emit dataChanged(index, index); if (data.status == Status::Enabled && !data.exclusiveGroup.isEmpty()) { // need to disable all other exclusive effects in the same category for (int i = 0; i < m_effects.size(); ++i) { if (i == index.row()) { continue; } EffectData &otherData = m_effects[i]; if (otherData.exclusiveGroup == data.exclusiveGroup) { otherData.status = Status::Disabled; otherData.changed = otherData.status != otherData.originalStatus; emit dataChanged(this->index(i, 0), this->index(i, 0)); } } } return true; } return QAbstractItemModel::setData(index, value, role); } void EffectsModel::loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { const auto builtins = BuiltInEffects::availableEffects(); for (auto builtin : builtins) { const BuiltInEffects::EffectData &data = BuiltInEffects::effectData(builtin); EffectData effect; effect.name = data.displayName; effect.description = data.comment; effect.authorName = i18n("KWin development team"); effect.authorEmail = QString(); // not used at all effect.license = QStringLiteral("GPL"); effect.version = QStringLiteral(KWIN_VERSION_STRING); effect.untranslatedCategory = data.category; effect.category = translatedCategory(data.category); effect.serviceName = data.name; effect.iconName = QStringLiteral("preferences-system-windows"); effect.enabledByDefault = data.enabled; effect.enabledByDefaultFunction = (data.enabledFunction != nullptr); const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (data.enabledFunction != nullptr) { effect.status = Status::EnabledUndeterminded; } else { effect.status = effectStatus(effect.enabledByDefault); } effect.originalStatus = effect.status; effect.video = data.video; effect.website = QUrl(); effect.supported = true; effect.exclusiveGroup = data.exclusiveCategory; effect.internal = data.internal; effect.kind = Kind::BuiltIn; effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [data](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; } ); if (shouldStore(effect)) { m_pendingEffects << effect; } } } void EffectsModel::loadJavascriptEffects(const KConfigGroup &kwinConfig) { const auto plugins = KPackage::PackageLoader::self()->listPackages( QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects") ); for (const KPluginMetaData &metaData : plugins) { KPluginInfo plugin(metaData); EffectData effect; effect.name = plugin.name(); effect.description = plugin.comment(); effect.authorName = plugin.author(); effect.authorEmail = plugin.email(); effect.license = plugin.license(); effect.version = plugin.version(); effect.untranslatedCategory = plugin.category(); effect.category = translatedCategory(plugin.category()); effect.serviceName = plugin.pluginName(); effect.iconName = plugin.icon(); effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", plugin.isPluginEnabledByDefault())); effect.originalStatus = effect.status; effect.enabledByDefault = plugin.isPluginEnabledByDefault(); effect.enabledByDefaultFunction = false; effect.video = plugin.property(QStringLiteral("X-KWin-Video-Url")).toUrl(); effect.website = QUrl(plugin.website()); effect.supported = true; effect.exclusiveGroup = plugin.property(QStringLiteral("X-KWin-Exclusive-Category")).toString(); effect.internal = plugin.property(QStringLiteral("X-KWin-Internal")).toBool(); effect.kind = Kind::Scripted; const QString pluginKeyword = plugin.property(QStringLiteral("X-KDE-PluginKeyword")).toString(); if (!pluginKeyword.isEmpty()) { // scripted effects have their pluginName() as the keyword effect.configurable = plugin.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginKeyword; } else { effect.configurable = false; } if (shouldStore(effect)) { m_pendingEffects << effect; } } } void EffectsModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { const auto pluginEffects = KPluginLoader::findPlugins( QStringLiteral("kwin/effects/plugins/"), [](const KPluginMetaData &data) { return data.serviceTypes().contains(QStringLiteral("KWin/Effect")); } ); for (const KPluginMetaData &pluginEffect : pluginEffects) { if (!pluginEffect.isValid()) { continue; } EffectData effect; effect.name = pluginEffect.name(); effect.description = pluginEffect.description(); effect.license = pluginEffect.license(); effect.version = pluginEffect.version(); effect.untranslatedCategory = pluginEffect.category(); effect.category = translatedCategory(pluginEffect.category()); effect.serviceName = pluginEffect.pluginId(); effect.iconName = pluginEffect.iconName(); effect.enabledByDefault = pluginEffect.isEnabledByDefault(); effect.supported = true; effect.enabledByDefaultFunction = false; effect.internal = false; effect.kind = Kind::Binary; for (int i = 0; i < pluginEffect.authors().count(); ++i) { effect.authorName.append(pluginEffect.authors().at(i).name()); effect.authorEmail.append(pluginEffect.authors().at(i).emailAddress()); if (i+1 < pluginEffect.authors().count()) { effect.authorName.append(", "); effect.authorEmail.append(", "); } } if (pluginEffect.rawData().contains("org.kde.kwin.effect")) { const QJsonObject d(pluginEffect.rawData().value("org.kde.kwin.effect").toObject()); effect.exclusiveGroup = d.value("exclusiveGroup").toString(); effect.video = QUrl::fromUserInput(d.value("video").toString()); effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool(); } effect.website = QUrl(pluginEffect.website()); const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (effect.enabledByDefaultFunction) { effect.status = Status::EnabledUndeterminded; } else { effect.status = effectStatus(effect.enabledByDefault); } effect.originalStatus = effect.status; effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [pluginEffect](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); } ); if (shouldStore(effect)) { m_pendingEffects << effect; } } } void EffectsModel::load(LoadOptions options) { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); m_pendingEffects.clear(); const KPluginInfo::List configs = KPluginTrader::self()->query(QStringLiteral("kwin/effects/configs/")); loadBuiltInEffects(kwinConfig, configs); loadJavascriptEffects(kwinConfig); loadPluginEffects(kwinConfig, configs); std::sort(m_pendingEffects.begin(), m_pendingEffects.end(), [](const EffectData &a, const EffectData &b) { if (a.category == b.category) { if (a.exclusiveGroup == b.exclusiveGroup) { return a.name < b.name; } return a.exclusiveGroup < b.exclusiveGroup; } return a.category < b.category; } ); auto commit = [this, options] { if (options == LoadOptions::KeepDirty) { for (const EffectData &oldEffect : m_effects) { if (!oldEffect.changed) { continue; } auto effectIt = std::find_if(m_pendingEffects.begin(), m_pendingEffects.end(), [oldEffect](const EffectData &data) { return data.serviceName == oldEffect.serviceName; } ); if (effectIt == m_pendingEffects.end()) { continue; } effectIt->status = oldEffect.status; effectIt->changed = effectIt->status != effectIt->originalStatus; } } beginResetModel(); m_effects = m_pendingEffects; m_pendingEffects.clear(); endResetModel(); emit loaded(); }; OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); if (interface.isValid()) { QStringList effectNames; effectNames.reserve(m_pendingEffects.count()); for (const EffectData &data : m_pendingEffects) { effectNames.append(data.serviceName); } const int serial = ++m_lastSerial; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(interface.areEffectsSupported(effectNames), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *self) { self->deleteLater(); if (m_lastSerial != serial) { return; } const QDBusPendingReply > reply = *self; if (reply.isError()) { commit(); return; } const QList supportedValues = reply.value(); if (supportedValues.count() != effectNames.count()) { return; } for (int i = 0; i < effectNames.size(); ++i) { const bool supported = supportedValues.at(i); const QString effectName = effectNames.at(i); auto it = std::find_if(m_pendingEffects.begin(), m_pendingEffects.end(), [effectName](const EffectData &data) { return data.serviceName == effectName; } ); if (it == m_pendingEffects.end()) { continue; } if ((*it).supported != supported) { (*it).supported = supported; } } commit(); } ); } else { commit(); } } void EffectsModel::updateEffectStatus(const QModelIndex &rowIndex, Status effectState) { setData(rowIndex, static_cast(effectState), StatusRole); } void EffectsModel::save() { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); QVector dirtyEffects; for (EffectData &effect : m_effects) { if (!effect.changed) { continue; } effect.changed = false; effect.originalStatus = effect.status; const QString key = effect.serviceName + QStringLiteral("Enabled"); const bool shouldEnable = (effect.status != Status::Disabled); const bool restoreToDefault = effect.enabledByDefaultFunction ? effect.status == Status::EnabledUndeterminded : shouldEnable == effect.enabledByDefault; if (restoreToDefault) { kwinConfig.deleteEntry(key); } else { kwinConfig.writeEntry(key, shouldEnable); } dirtyEffects.append(effect); } if (dirtyEffects.isEmpty()) { return; } kwinConfig.sync(); OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); if (!interface.isValid()) { return; } for (const EffectData &effect : dirtyEffects) { if (effect.status != Status::Disabled) { interface.loadEffect(effect.serviceName); } else { interface.unloadEffect(effect.serviceName); } } } void EffectsModel::defaults() { for (int i = 0; i < m_effects.count(); ++i) { const auto &effect = m_effects.at(i); if (effect.enabledByDefaultFunction && effect.status != Status::EnabledUndeterminded) { updateEffectStatus(index(i, 0), Status::EnabledUndeterminded); } else if (static_cast(effect.status) != effect.enabledByDefault) { updateEffectStatus(index(i, 0), effect.enabledByDefault ? Status::Enabled : Status::Disabled); } } } bool EffectsModel::isDefaults() const { return std::all_of(m_effects.constBegin(), m_effects.constEnd(), [](const EffectData &effect) { if (effect.enabledByDefaultFunction && effect.status != Status::EnabledUndeterminded) { return false; } if (static_cast(effect.status) != effect.enabledByDefault) { return false; } return true; }); } bool EffectsModel::needsSave() const { return std::any_of(m_effects.constBegin(), m_effects.constEnd(), [](const EffectData &data) { return data.changed; } ); } QModelIndex EffectsModel::findByPluginId(const QString &pluginId) const { auto it = std::find_if(m_effects.constBegin(), m_effects.constEnd(), [pluginId](const EffectData &data) { return data.serviceName == pluginId; } ); if (it == m_effects.constEnd()) { return {}; } return index(std::distance(m_effects.constBegin(), it), 0); } static KCModule *findBinaryConfig(const QString &pluginId, QObject *parent) { return KPluginTrader::createInstanceFromQuery( QStringLiteral("kwin/effects/configs/"), QString(), QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(pluginId), parent ); } static KCModule *findScriptedConfig(const QString &pluginId, QObject *parent) { const auto offers = KPluginTrader::self()->query( QStringLiteral("kwin/effects/configs/"), QString(), QStringLiteral("[X-KDE-Library] == 'kcm_kwin4_genericscripted'") ); if (offers.isEmpty()) { return nullptr; } const KPluginInfo &generic = offers.first(); KPluginLoader loader(generic.libraryPath()); KPluginFactory *factory = loader.factory(); if (!factory) { return nullptr; } return factory->create(pluginId, parent); } void EffectsModel::requestConfigure(const QModelIndex &index, QWindow *transientParent) { if (!index.isValid()) { return; } - QPointer dialog = new QDialog(); + auto dialog = new QDialog(); KCModule *module = index.data(ScriptedRole).toBool() ? findScriptedConfig(index.data(ServiceNameRole).toString(), dialog) : findBinaryConfig(index.data(ServiceNameRole).toString(), dialog); if (!module) { delete dialog; return; } dialog->setWindowTitle(index.data(NameRole).toString()); dialog->winId(); dialog->windowHandle()->setTransientParent(transientParent); auto buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults, dialog ); connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, module, &KCModule::defaults); connect(module, &KCModule::defaulted, this, [=](bool defaulted) { buttons->button(QDialogButtonBox::RestoreDefaults)->setEnabled(!defaulted); }); auto layout = new QVBoxLayout(dialog); layout->addWidget(module); layout->addWidget(buttons); - if (dialog->exec() == QDialog::Accepted) { - module->save(); - } + connect(dialog, &QDialog::accepted, module, &KCModule::save); - delete dialog; + dialog->setModal(true); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); } bool EffectsModel::shouldStore(const EffectData &data) const { Q_UNUSED(data) return true; } } diff --git a/kcmkwin/kwincompositing/CMakeLists.txt b/kcmkwin/kwincompositing/CMakeLists.txt index d759e202b..eb8c47d5a 100644 --- a/kcmkwin/kwincompositing/CMakeLists.txt +++ b/kcmkwin/kwincompositing/CMakeLists.txt @@ -1,35 +1,37 @@ ######################################################################### # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincompositing\") add_definitions(-DQT_NO_URL_CAST_FROM_STRING) remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY) ################# configure checks and create the configured files ################# -set(kwincomposing_SRC +set(kwincompositing_SRC main.cpp compositing.cpp ) -qt5_add_dbus_interface(kwincomposing_SRC +kconfig_add_kcfg_files(kwincompositing_SRC kwincompositing_setting.kcfgc GENERATE_MOC) + +qt5_add_dbus_interface(kwincompositing_SRC ${KWin_SOURCE_DIR}/org.kde.kwin.Compositing.xml kwin_compositing_interface ) -ki18n_wrap_ui(kwincomposing_SRC compositing.ui) +ki18n_wrap_ui(kwincompositing_SRC compositing.ui) -add_library(kwincompositing MODULE ${kwincomposing_SRC}) +add_library(kwincompositing MODULE ${kwincompositing_SRC}) target_link_libraries(kwincompositing Qt5::DBus Qt5::Widgets KF5::ConfigCore KF5::CoreAddons KF5::I18n KF5::KCMUtils ) install(TARGETS kwincompositing DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES kwincompositing.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/kcmkwin/kwincompositing/compositing.cpp b/kcmkwin/kwincompositing/compositing.cpp index b43f7cea2..e7042984d 100644 --- a/kcmkwin/kwincompositing/compositing.cpp +++ b/kcmkwin/kwincompositing/compositing.cpp @@ -1,546 +1,514 @@ /************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * Copyright (C) 2013 Martin Gräßlin * * * * 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 "compositing.h" #include #include #include #include #include #include #include #include #include +#include "kwincompositing_setting.h" + namespace KWin { namespace Compositing { Compositing::Compositing(QObject *parent) : QObject(parent) , m_animationSpeed(1.0) , m_windowThumbnail(0) , m_glScaleFilter(0) , m_xrScaleFilter(false) , m_glSwapStrategy(0) , m_compositingType(0) , m_compositingEnabled(true) - , m_changed(false) , m_openGLPlatformInterfaceModel(new OpenGLPlatformInterfaceModel(this)) , m_openGLPlatformInterface(0) , m_windowsBlockCompositing(true) , m_compositingInterface(new OrgKdeKwinCompositingInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus(), this)) - , m_config(KSharedConfig::openConfig("kwinrc")) -{ - reset(); - connect(this, &Compositing::animationSpeedChanged, this, &Compositing::changed); - connect(this, &Compositing::windowThumbnailChanged, this, &Compositing::changed); - connect(this, &Compositing::glScaleFilterChanged, this, &Compositing::changed); - connect(this, &Compositing::xrScaleFilterChanged, this, &Compositing::changed); - connect(this, &Compositing::glSwapStrategyChanged, this, &Compositing::changed); - connect(this, &Compositing::compositingTypeChanged, this, &Compositing::changed); - connect(this, &Compositing::compositingEnabledChanged, this, &Compositing::changed); - connect(this, &Compositing::openGLPlatformInterfaceChanged, this, &Compositing::changed); - connect(this, &Compositing::windowsBlockCompositingChanged, this, &Compositing::changed); - - connect(this, &Compositing::changed, [this]{ - m_changed = true; - }); + , m_settings(new KWinCompositingSetting(this)) +{ + load(); + connect(this, &Compositing::animationSpeedChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::windowThumbnailChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::glScaleFilterChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::xrScaleFilterChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::glSwapStrategyChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::compositingTypeChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::compositingEnabledChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::openGLPlatformInterfaceChanged, this, &Compositing::updateSettings); + connect(this, &Compositing::windowsBlockCompositingChanged, this, &Compositing::updateSettings); } -void Compositing::reset() +void Compositing::load() { - KConfigGroup globalConfig(m_config, QStringLiteral("KDE")); - setAnimationSpeed(globalConfig.readEntry("AnimationDurationFactor", 1.0)); + m_settings->load(); - KConfigGroup kwinConfig(m_config, QStringLiteral("Compositing")); - setWindowThumbnail(kwinConfig.readEntry("HiddenPreviews", 5) - 4); - setGlScaleFilter(kwinConfig.readEntry("GLTextureFilter", 2)); - setXrScaleFilter(kwinConfig.readEntry("XRenderSmoothScale", false)); - setCompositingEnabled(kwinConfig.readEntry("Enabled", true)); + applyValues(); - auto swapStrategy = [&kwinConfig]() { - const QString glSwapStrategyValue = kwinConfig.readEntry("GLPreferBufferSwap", "a"); + emit changed(false); + emit defaulted(m_settings->isDefaults()); +} - if (glSwapStrategyValue == "n") { - return 0; - } else if (glSwapStrategyValue == "a") { - return 1; - } else if (glSwapStrategyValue == "e") { - return 2; - } else if (glSwapStrategyValue == "p") { - return 3; - } else if (glSwapStrategyValue == "c") { - return 4; - } - return 0; - }; - setGlSwapStrategy(swapStrategy()); +void Compositing::applyValues() +{ + setAnimationSpeed(m_settings->animationDurationFactor()); + // from options.cpp Options::reloadCompositingSettings + // 4 - off, 5 - shown, 6 - always, other are old values + setWindowThumbnail(m_settings->hiddenPreviews() - 4); + setGlScaleFilter(m_settings->glTextureFilter()); + setXrScaleFilter(m_settings->xRenderSmoothScale()); + setCompositingEnabled(m_settings->enabled()); + setGlSwapStrategy(m_settings->glPreferBufferSwap()); - auto type = [&kwinConfig]{ - const QString backend = kwinConfig.readEntry("Backend", "OpenGL"); - const bool glCore = kwinConfig.readEntry("GLCore", false); + const auto type = [this]{ + const int backend = m_settings->backend(); + const bool glCore = m_settings->glCore(); - if (backend == QStringLiteral("OpenGL")) { + if (backend == KWinCompositingSetting::EnumBackend::OpenGL) { if (glCore) { return CompositingType::OPENGL31_INDEX; } else { return CompositingType::OPENGL20_INDEX; } } else { return CompositingType::XRENDER_INDEX; } }; setCompositingType(type()); - const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(kwinConfig.readEntry("GLPlatformInterface", "glx")); + const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(m_settings->glPlatformInterface()); setOpenGLPlatformInterface(index.isValid() ? index.row() : 0); - setWindowsBlockCompositing(kwinConfig.readEntry("WindowsBlockCompositing", true)); - - m_changed = false; + setWindowsBlockCompositing(m_settings->windowsBlockCompositing()); } void Compositing::defaults() { - setAnimationSpeed(1.0); - setWindowThumbnail(1); - setGlScaleFilter(2); - setXrScaleFilter(false); - setGlSwapStrategy(1); - setCompositingType(CompositingType::OPENGL20_INDEX); - const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(QStringLiteral("glx")); - setOpenGLPlatformInterface(index.isValid() ? index.row() : 0); - setWindowsBlockCompositing(true); - m_changed = true; + m_settings->setDefaults(); + + applyValues(); + + emit changed(m_settings->isSaveNeeded()); + emit defaulted(m_settings->isDefaults()); } bool Compositing::OpenGLIsUnsafe() const { - KConfigGroup kwinConfig(m_config, "Compositing"); - return kwinConfig.readEntry("OpenGLIsUnsafe", true); + return m_settings->openGLIsUnsafe(); } bool Compositing::OpenGLIsBroken() { - KConfigGroup kwinConfig(m_config, "Compositing"); - - QString oldBackend = kwinConfig.readEntry("Backend", "OpenGL"); - kwinConfig.writeEntry("Backend", "OpenGL"); - kwinConfig.sync(); + const int oldBackend = m_settings->backend(); + m_settings->setBackend(KWinCompositingSetting::EnumBackend::OpenGL); + m_settings->save(); if (m_compositingInterface->openGLIsBroken()) { - kwinConfig.writeEntry("Backend", oldBackend); - kwinConfig.sync(); + m_settings->setBackend(oldBackend); + m_settings->save(); return true; } - kwinConfig.writeEntry("OpenGLIsUnsafe", false); - kwinConfig.sync(); + m_settings->setOpenGLIsUnsafe(false); + m_settings->save(); return false; } void Compositing::reenableOpenGLDetection() { - KConfigGroup kwinConfig(m_config, "Compositing"); - kwinConfig.writeEntry("OpenGLIsUnsafe", false); - kwinConfig.sync(); + m_settings->setOpenGLIsUnsafe(false); + m_settings->save(); } qreal Compositing::animationSpeed() const { return m_animationSpeed; } int Compositing::windowThumbnail() const { return m_windowThumbnail; } int Compositing::glScaleFilter() const { return m_glScaleFilter; } bool Compositing::xrScaleFilter() const { return m_xrScaleFilter; } int Compositing::glSwapStrategy() const { return m_glSwapStrategy; } int Compositing::compositingType() const { return m_compositingType; } bool Compositing::compositingEnabled() const { return m_compositingEnabled; } void Compositing::setAnimationSpeed(qreal speed) { if (speed == m_animationSpeed) { return; } m_animationSpeed = speed; emit animationSpeedChanged(speed); } void Compositing::setGlScaleFilter(int index) { if (index == m_glScaleFilter) { return; } m_glScaleFilter = index; emit glScaleFilterChanged(index); } void Compositing::setGlSwapStrategy(int strategy) { if (strategy == m_glSwapStrategy) { return; } m_glSwapStrategy = strategy; emit glSwapStrategyChanged(strategy); } void Compositing::setWindowThumbnail(int index) { if (index == m_windowThumbnail) { return; } m_windowThumbnail = index; emit windowThumbnailChanged(index); } void Compositing::setXrScaleFilter(bool filter) { if (filter == m_xrScaleFilter) { return; } m_xrScaleFilter = filter; emit xrScaleFilterChanged(filter); } void Compositing::setCompositingType(int index) { if (index == m_compositingType) { return; } m_compositingType = index; emit compositingTypeChanged(index); } void Compositing::setCompositingEnabled(bool enabled) { if (compositingRequired()) { return; } if (enabled == m_compositingEnabled) { return; } m_compositingEnabled = enabled; emit compositingEnabledChanged(enabled); } -void Compositing::save() +void Compositing::updateSettings() { // this writes to the KDE group of the kwinrc, when loading we rely on kconfig cascading to // load a global value, or allow a kwin override - KConfigGroup generalConfig(m_config, "KDE"); if (!isRunningPlasma()) { - generalConfig.writeEntry("AnimationDurationFactor", animationSpeed()); + m_settings->setAnimationDurationFactor(animationSpeed()); } - KConfigGroup kwinConfig(m_config, "Compositing"); - kwinConfig.writeEntry("HiddenPreviews", windowThumbnail() + 4); - kwinConfig.writeEntry("GLTextureFilter", glScaleFilter()); - kwinConfig.writeEntry("XRenderSmoothScale", xrScaleFilter()); + m_settings->setHiddenPreviews(windowThumbnail() + 4); + m_settings->setGlTextureFilter(glScaleFilter()); + m_settings->setXRenderSmoothScale(xrScaleFilter()); if (!compositingRequired()) { - kwinConfig.writeEntry("Enabled", compositingEnabled()); + m_settings->setEnabled(compositingEnabled()); } - auto swapStrategy = [this] { - switch (glSwapStrategy()) { - case 0: - return QStringLiteral("n"); - case 2: - return QStringLiteral("e"); - case 3: - return QStringLiteral("p"); - case 4: - return QStringLiteral("c"); - case 1: - default: - return QStringLiteral("a"); - } - }; - kwinConfig.writeEntry("GLPreferBufferSwap", swapStrategy()); - QString backend; + m_settings->setGlPreferBufferSwap(glSwapStrategy()); + int backend = KWinCompositingSetting::EnumBackend::OpenGL; bool glCore = false; switch (compositingType()) { case CompositingType::OPENGL31_INDEX: - backend = "OpenGL"; + backend = KWinCompositingSetting::EnumBackend::OpenGL; glCore = true; break; case CompositingType::OPENGL20_INDEX: - backend = "OpenGL"; + backend = KWinCompositingSetting::EnumBackend::OpenGL; glCore = false; break; case CompositingType::XRENDER_INDEX: - backend = "XRender"; + backend = KWinCompositingSetting::EnumBackend::XRender; glCore = false; break; } - kwinConfig.writeEntry("Backend", backend); - kwinConfig.writeEntry("GLCore", glCore); + m_settings->setBackend(backend); + m_settings->setGlCore(glCore); if (!compositingRequired()) { - kwinConfig.writeEntry("WindowsBlockCompositing", windowsBlockCompositing()); + m_settings->setWindowsBlockCompositing(windowsBlockCompositing()); } - kwinConfig.sync(); - if (m_changed) { + emit changed(m_settings->isSaveNeeded()); + emit defaulted(m_settings->isDefaults()); +} + +void Compositing::save() +{ + if (m_settings->isSaveNeeded()) { + + m_settings->save(); + // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"), QStringLiteral("reinit")); QDBusConnection::sessionBus().send(message); - m_changed = false; } } OpenGLPlatformInterfaceModel *Compositing::openGLPlatformInterfaceModel() const { return m_openGLPlatformInterfaceModel; } int Compositing::openGLPlatformInterface() const { return m_openGLPlatformInterface; } void Compositing::setOpenGLPlatformInterface(int interface) { if (m_openGLPlatformInterface == interface) { return; } m_openGLPlatformInterface = interface; emit openGLPlatformInterfaceChanged(interface); } bool Compositing::windowsBlockCompositing() const { return m_windowsBlockCompositing; } void Compositing::setWindowsBlockCompositing(bool set) { if (compositingRequired()) { return; } if (m_windowsBlockCompositing == set) { return; } m_windowsBlockCompositing = set; emit windowsBlockCompositingChanged(set); } bool Compositing::compositingRequired() const { return m_compositingInterface->platformRequiresCompositing(); } bool Compositing::isRunningPlasma() { return qgetenv("XDG_CURRENT_DESKTOP") == "KDE"; } CompositingType::CompositingType(QObject *parent) : QAbstractItemModel(parent) { generateCompositing(); } void CompositingType::generateCompositing() { QHash compositingTypes; compositingTypes[i18n("OpenGL 3.1")] = CompositingType::OPENGL31_INDEX; compositingTypes[i18n("OpenGL 2.0")] = CompositingType::OPENGL20_INDEX; compositingTypes[i18n("XRender")] = CompositingType::XRENDER_INDEX; CompositingData data; beginResetModel(); auto it = compositingTypes.begin(); while (it != compositingTypes.end()) { data.name = it.key(); data.type = it.value(); m_compositingList << data; it++; } std::sort(m_compositingList.begin(), m_compositingList.end(), [](const CompositingData &a, const CompositingData &b) { - return a.type < b.type; + return a.type < b.type; }); endResetModel(); } QHash< int, QByteArray > CompositingType::roleNames() const { QHash roleNames; roleNames[NameRole] = "NameRole"; roleNames[TypeRole] = QByteArrayLiteral("type"); return roleNames; } QModelIndex CompositingType::index(int row, int column, const QModelIndex &parent) const { - -if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_compositingList.count()) { + if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_compositingList.count()) { return QModelIndex(); } return createIndex(row, column); } QModelIndex CompositingType::parent(const QModelIndex &child) const { Q_UNUSED(child) return QModelIndex(); } int CompositingType::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } int CompositingType::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_compositingList.count(); } QVariant CompositingType::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } switch (role) { case Qt::DisplayRole: case NameRole: return m_compositingList.at(index.row()).name; case TypeRole: return m_compositingList.at(index.row()).type; default: return QVariant(); } } int CompositingType::compositingTypeForIndex(int row) const { return index(row, 0).data(TypeRole).toInt(); } int CompositingType::indexForCompositingType(int type) const { for (int i = 0; i < m_compositingList.count(); ++i) { if (m_compositingList.at(i).type == type) { return i; } } return -1; } OpenGLPlatformInterfaceModel::OpenGLPlatformInterfaceModel(QObject *parent) : QAbstractListModel(parent) { beginResetModel(); OrgKdeKwinCompositingInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus()); m_keys << interface.supportedOpenGLPlatformInterfaces(); for (const QString &key : m_keys) { if (key == QStringLiteral("egl")) { m_names << i18nc("OpenGL Platform Interface", "EGL"); } else if (key == QStringLiteral("glx")) { m_names << i18nc("OpenGL Platform Interface", "GLX"); } else { m_names << key; } } endResetModel(); } OpenGLPlatformInterfaceModel::~OpenGLPlatformInterfaceModel() = default; int OpenGLPlatformInterfaceModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_keys.count(); } QHash< int, QByteArray > OpenGLPlatformInterfaceModel::roleNames() const { return QHash({ {Qt::DisplayRole, QByteArrayLiteral("display")}, {Qt::UserRole, QByteArrayLiteral("openglPlatformInterface")} }); } QVariant OpenGLPlatformInterfaceModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() < 0 || index.row() >= m_keys.size() || index.column() != 0) { return QVariant(); } switch (role) { case Qt::DisplayRole: return m_names.at(index.row()); case Qt::UserRole: return m_keys.at(index.row()); default: return QVariant(); } } QModelIndex OpenGLPlatformInterfaceModel::indexForKey(const QString &key) const { const int keyIndex = m_keys.indexOf(key); if (keyIndex < 0) { return QModelIndex(); } return createIndex(keyIndex, 0); } }//end namespace Compositing }//end namespace KWin diff --git a/kcmkwin/kwincompositing/compositing.h b/kcmkwin/kwincompositing/compositing.h index 0646288a6..0eba25282 100644 --- a/kcmkwin/kwincompositing/compositing.h +++ b/kcmkwin/kwincompositing/compositing.h @@ -1,185 +1,193 @@ /************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * * * 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 COMPOSITING_H #define COMPOSITING_H #include #include #include class OrgKdeKwinCompositingInterface; +class KWinCompositingSetting; + namespace KWin { namespace Compositing { class OpenGLPlatformInterfaceModel; class Compositing : public QObject { Q_OBJECT Q_PROPERTY(int animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged) Q_PROPERTY(int windowThumbnail READ windowThumbnail WRITE setWindowThumbnail NOTIFY windowThumbnailChanged) Q_PROPERTY(int glScaleFilter READ glScaleFilter WRITE setGlScaleFilter NOTIFY glScaleFilterChanged) Q_PROPERTY(bool xrScaleFilter READ xrScaleFilter WRITE setXrScaleFilter NOTIFY xrScaleFilterChanged) Q_PROPERTY(int glSwapStrategy READ glSwapStrategy WRITE setGlSwapStrategy NOTIFY glSwapStrategyChanged) Q_PROPERTY(int compositingType READ compositingType WRITE setCompositingType NOTIFY compositingTypeChanged) Q_PROPERTY(bool compositingEnabled READ compositingEnabled WRITE setCompositingEnabled NOTIFY compositingEnabledChanged) Q_PROPERTY(KWin::Compositing::OpenGLPlatformInterfaceModel *openGLPlatformInterfaceModel READ openGLPlatformInterfaceModel CONSTANT) Q_PROPERTY(int openGLPlatformInterface READ openGLPlatformInterface WRITE setOpenGLPlatformInterface NOTIFY openGLPlatformInterfaceChanged) Q_PROPERTY(bool windowsBlockCompositing READ windowsBlockCompositing WRITE setWindowsBlockCompositing NOTIFY windowsBlockCompositingChanged) Q_PROPERTY(bool compositingRequired READ compositingRequired CONSTANT) public: explicit Compositing(QObject *parent = nullptr); Q_INVOKABLE bool OpenGLIsUnsafe() const; Q_INVOKABLE bool OpenGLIsBroken(); Q_INVOKABLE void reenableOpenGLDetection(); qreal animationSpeed() const; int windowThumbnail() const; int glScaleFilter() const; bool xrScaleFilter() const; int glSwapStrategy() const; int compositingType() const; bool compositingEnabled() const; int openGLPlatformInterface() const; bool windowsBlockCompositing() const; bool compositingRequired() const; OpenGLPlatformInterfaceModel *openGLPlatformInterfaceModel() const; void setAnimationSpeed(qreal speed); void setWindowThumbnail(int index); void setGlScaleFilter(int index); void setXrScaleFilter(bool filter); void setGlSwapStrategy(int strategy); void setCompositingType(int index); void setCompositingEnabled(bool enalbed); void setOpenGLPlatformInterface(int interface); void setWindowsBlockCompositing(bool set); void save(); static bool isRunningPlasma(); public Q_SLOTS: - void reset(); + void load(); void defaults(); Q_SIGNALS: - void changed(); + void changed(bool changed); + void defaulted(bool defaulted); void animationSpeedChanged(qreal); void windowThumbnailChanged(int); void glScaleFilterChanged(int); void xrScaleFilterChanged(int); void glSwapStrategyChanged(int); void compositingTypeChanged(int); void compositingEnabledChanged(bool); void openGLPlatformInterfaceChanged(int); void windowsBlockCompositingChanged(bool); +private Q_SLOTS: + void updateSettings(); + private: + void applyValues(); + qreal m_animationSpeed; int m_windowThumbnail; int m_glScaleFilter; bool m_xrScaleFilter; int m_glSwapStrategy; int m_compositingType; bool m_compositingEnabled; - bool m_changed; OpenGLPlatformInterfaceModel *m_openGLPlatformInterfaceModel; int m_openGLPlatformInterface; bool m_windowsBlockCompositing; bool m_windowsBlockingCompositing; OrgKdeKwinCompositingInterface *m_compositingInterface; KSharedConfigPtr m_config; + KWinCompositingSetting *m_settings; }; struct CompositingData; class CompositingType : public QAbstractItemModel { Q_OBJECT Q_ENUMS(CompositingTypeIndex) public: enum CompositingTypeIndex { OPENGL31_INDEX = 0, OPENGL20_INDEX, XRENDER_INDEX }; enum CompositingTypeRoles { NameRole = Qt::UserRole +1, TypeRole = Qt::UserRole +2 }; explicit CompositingType(QObject *parent = nullptr); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QHash< int, QByteArray > roleNames() const override; Q_INVOKABLE int compositingTypeForIndex(int row) const; Q_INVOKABLE int indexForCompositingType(int type) const; private: void generateCompositing(); QList m_compositingList; }; struct CompositingData { QString name; CompositingType::CompositingTypeIndex type; }; class OpenGLPlatformInterfaceModel : public QAbstractListModel { Q_OBJECT public: explicit OpenGLPlatformInterfaceModel(QObject *parent = nullptr); ~OpenGLPlatformInterfaceModel() override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QModelIndex indexForKey(const QString &key) const; QHash< int, QByteArray > roleNames() const override; private: QStringList m_keys; QStringList m_names; }; }//end namespace Compositing }//end namespace KWin Q_DECLARE_METATYPE(KWin::Compositing::OpenGLPlatformInterfaceModel*) #endif diff --git a/kcmkwin/kwincompositing/compositing.ui b/kcmkwin/kwincompositing/compositing.ui index ec30fc32f..7d77f3496 100644 --- a/kcmkwin/kwincompositing/compositing.ui +++ b/kcmkwin/kwincompositing/compositing.ui @@ -1,307 +1,310 @@ CompositingForm 0 0 526 395 QFormLayout::AllNonFixedFieldsGrow + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + false OpenGL compositing (the default) has crashed KWin in the past. This was most likely due to a driver bug. If you think that you have meanwhile upgraded to a stable driver, you can reset this protection but be aware that this might result in an immediate crash! Alternatively, you might want to use the XRender backend instead. true false Scale method "Accurate" is not supported by all hardware and can cause performance regressions and rendering artifacts. true false true false Keeping the window thumbnail always interferes with the minimized state of windows. This can result in windows not suspending their work when minimized. true - - - - Enable compositor on startup - - - Animation speed: Scale method: Crisp Smooth Accurate Scale method: Crisp Smooth (slower) Qt::Horizontal Rendering backend: Qt::Horizontal Tearing prevention ("vsync"): Never Automatic Only when cheap Full screen repaints Re-use screen content Keep window thumbnails: Never Only for Shown Windows Always Applications can set a hint to block compositing when the window is open. This brings performance improvements for e.g. games. The setting can be overruled by window-specific rules. Allow applications to block compositing 0 0 0 0 Qt::Horizontal QSlider::TicksBelow 1 Very slow Qt::Horizontal 40 20 Instant + + + + Enable compositor on startup + + + KMessageWidget QFrame
kmessagewidget.h
1
diff --git a/kcmkwin/kwincompositing/kwincompositing.desktop b/kcmkwin/kwincompositing/kwincompositing.desktop index 4b699e843..d5c8a97b0 100644 --- a/kcmkwin/kwincompositing/kwincompositing.desktop +++ b/kcmkwin/kwincompositing/kwincompositing.desktop @@ -1,128 +1,130 @@ [Desktop Entry] Exec=kcmshell5 kwincompositing Icon=preferences-desktop Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=https://userbase.kde.org/Desktop_Effects_Performance#Advanced_Desktop_Effects_Settings X-KDE-Library=kwincompositing X-KDE-PluginKeyword=compositing X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=display X-KDE-Weight=60 Name=Compositor Name[ast]=Compositor Name[bs]=Compositor Name[ca]=Compositor Name[ca@valencia]=Compositor Name[cs]=Kompozitor Name[da]=Compositor Name[de]=Compositor Name[el]=Συνθέτης Name[en_GB]=Compositor Name[es]=Compositor Name[et]=Komposiitor Name[eu]=Konposatzailea Name[fi]=Koostin Name[fr]=Compositeur Name[gl]=Compositor Name[hu]=Kompozitor Name[ia]=Compositor Name[id]=Kompositor Name[it]=Compositore Name[ja]=コンポジタ Name[ko]=컴포지터 Name[lt]=Kompozitorius Name[nb]=Sammensetter Name[nds]=Tosamensetten Name[nl]=Compositor Name[nn]=Samansetjar Name[pa]=ਕੰਪੋਜੀਟਰ Name[pl]=Kompozytor Name[pt]=Compositor Name[pt_BR]=Compositor Name[ro]=Compozitor Name[ru]=Обеспечение эффектов Name[sk]=Kompozítor Name[sl]=Upravljalnik skladnje Name[sr]=Слагач Name[sr@ijekavian]=Слагач Name[sr@ijekavianlatin]=Slagač Name[sr@latin]=Slagač Name[sv]=Sammansättning Name[tr]=Dizgici Name[uk]=Засіб композиції Name[vi]=Compositor Name[x-test]=xxCompositorxx Name[zh_CN]=混成器 Name[zh_TW]=組合器 Comment=Compositor Settings for Desktop Effects Comment[bs]=Postavke Compositor-a za Desktop Efekte Comment[ca]=Arranjament del compositor per als efectes de l'escriptori Comment[ca@valencia]=Arranjament del compositor pels efectes d'escriptori Comment[cs]=Nastavení kompozitoru pro efekty pracovní plochy Comment[da]=Compositor-indstillinger til skrivebordseffekter Comment[de]=Compositor-Einstellungen für Arbeitsflächen-Effekte Comment[el]=Ρυθμίσεις συνθέτη για τα εφέ επιφάνειας εργασίας Comment[en_GB]=Compositor Settings for Desktop Effects Comment[es]=Configurar las preferencias del compositor para los efectos del escritorio Comment[et]=Komposiitori seadistused töölauaefektide tarbeks Comment[eu]=Konposatzailearen ezarpenak mahaigaineko efektuetarako Comment[fi]=Koostimen asetukset työpöytätehosteita varten Comment[fr]=Paramétrage du compositeur pour les effets de bureau Comment[gl]=Configuración do compositor para os efectos de escritorio Comment[hu]=A kompozitor beállításai az asztali effektusokhoz Comment[ia]=Preferentias de compositor pro le effectos de scriptorio Comment[id]=Pengaturan Kompositor untuk Efek Window Comment[it]=Impostazioni del compositore per gli effetti del desktop Comment[ja]=デスクトップ効果のためのコンポジタの設定 Comment[ko]=데스크톱 효과에 사용되는 컴포지터 설정 Comment[lt]=Darbalaukio efektų kompozitoriaus nuostatos Comment[nb]=Sammensetter-innstillinger for skrivebordseffekter Comment[nds]=Tosamensettoptschonen för de Schriefdischeffekten instellen Comment[nl]=Instellingen van compositor configureren voor bureaubladeffecten Comment[nn]=Samansetjarinnstillingar for skrivebordseffektar Comment[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ ਲਈ ਕੰਪੋਜੀਟਰ ਸੈਟਿੰਗਾਂ Comment[pl]=Ustawienia kompozytora dla efektów pulpitu Comment[pt]=Configuração do Compositor para os Efeitos do Ecrã Comment[pt_BR]=Definições do Compositor para os efeitos da área de trabalho Comment[ru]=Настройка движка эффектов рабочего стола Comment[sk]=Nastavenia kompozítora pre efekty plochy Comment[sl]=Nastavitve upravljalnika skladnje za učinke namizja Comment[sr]=Поставке слагача за ефекте површи Comment[sr@ijekavian]=Поставке слагача за ефекте површи Comment[sr@ijekavianlatin]=Postavke slagača za efekte površi Comment[sr@latin]=Postavke slagača za efekte površi Comment[sv]=Sammansättningsinställningar för skrivbordseffekter Comment[tr]=Masaüstü Efektleri için Dizgici Ayarları Comment[uk]=Параметри засобу композиції для ефектів стільниці Comment[vi]=Thiết lập Compositor cho hiệu ứng màn hình Comment[x-test]=xxCompositor Settings for Desktop Effectsxx Comment[zh_CN]=桌面特效混成器设置 Comment[zh_TW]=桌面效果使用的組合器設定 X-KDE-Keywords=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects X-KDE-Keywords[ca]=kwin,finestra,gestor,composició,efecte,efectes 3D,efectes 2D,OpenGL,XRender,arranjament de vídeo,efectes gràfics,efectes de l'escriptori X-KDE-Keywords[da]=kwin,vindue,håndtering,window,manager,compositing,effekt,3D effekter,2D effekter,OpenGL,XRender,video-indstillinger,grafiske effekter,skrivebordseffekter,desktop effects +X-KDE-Keywords[en_GB]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects X-KDE-Keywords[es]=kwin,ventana,gestor,composición,efecto,efectos 3D,efectos 2D,OpenGL,XRender,preferencias de vídeo,efectos gráficos,efectos del escritorio X-KDE-Keywords[et]=kwin,aken,haldur,komposiit,komposiitor,efekt,3D efektid,ruumilised efektid,2D efektid,OpenGL,XRender,videoseadistused,graafilised efektid,töölauaefektid X-KDE-Keywords[eu]=kwin,leihoa,kudeatzailea,konposatzailea,efektua,3Dtako efektuak,2Dtako efektuak,OpenGL,XRender,bideo ezarpenak,efektu grafikoak,mahaigaineko efektuak X-KDE-Keywords[fi]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,ikkunointiohjelma,ikkunaohjelma,ikkunanhallinta,tehoste,3D-tehosteet,2D-tehosteet,videoasetukset,graafiset tehosteet,työpöytätehosteet X-KDE-Keywords[fr]=Gestionnaire de fenêtres KWin, kwin,window,manager,compositeur, effet, effets 3D,effets 2D,OpenGL,XRender,paramétrage video,effets graphiques ,effects du bureau X-KDE-Keywords[ia]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects X-KDE-Keywords[id]=kwin,window,pengelola,kompositing,efek,efek 3D,efek 2D,OpenGL,XRender,pengaturan video,efek grafis,efek desktop X-KDE-Keywords[it]=kwin,finestra,gestore,composizione,effetto,effetti 3D,effetti 2D,OpenGL,XRender,impostazioni video,effetti grafici,effetti del desktop X-KDE-Keywords[ko]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,3D 효과,2D 효과,비디오 설정,그래픽 설정,그래픽 효과,데스크톱 효과 X-KDE-Keywords[lt]=kwin,langas,langai,tvarkytuvė,tvarkytuve,komponavimas,kompozicionavimas,efektas,efektai,3D efektai,2D efektai,trimačiai efektai,trimaciai efektai,dvimačiai efektai,dvimaciai efektai,OpenGL,XRender,vaizdo nustatymai,vaizdo nuostatos,video nustatymai,video nuostatos,grafiniai efektai,grafikos efektai,darbalaukio efektai,darbastalio efektai X-KDE-Keywords[nl]=kwin,window,manager,beheerder,compositing,effecten,3D-effecten,2D-effecten,OpenGL,XRender,video-instellingen,grafische effecten,bureaubladeffecten X-KDE-Keywords[nn]=kwin,vindauge,vindaugshandsamar,samansetjing,effekt,3D-effektar,2D-effektar,OpenGL,XRender,videoinnstillingar,grafiske effektar,skrivebordseffektar X-KDE-Keywords[pt]=kwin,janela,gestor,composição,efeito,efeitos 3D,efeitos 2D,OpenGL,XRender,configuração do vídeo,efeitos gráficos,efeitos do ecrã X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,composição,efeito,efeitos 3D,efeitos 2D,OpenGL,XRender,configurações de vídeo,efeitos gráficos,efeitos da área de trabalho X-KDE-Keywords[ru]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,композитинг,композитный диспетчер окон,эффекты рабочего стола,графические эффекты,рендеринг,параметры видео,настройка видео +X-KDE-Keywords[sl]=kwin,okna,upravljalnik,skladnja,učinek,3D učinki,2D učinki,OpenGL,XRender,nastavitve videa,video,grafični učinki,hitrost animacije,učinki namizja X-KDE-Keywords[sv]=kwin,fönster,hantering,sammansättning,effekt,3D effekter,2D effekter,OpenGL,XRender,videoinställningar,grafiska effekter,skrivbordseffekter X-KDE-Keywords[uk]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,вікно,керування,композитне,композиція,ефект,просторовий,ефекти,плоскі,параметри відео,графічні ефекти,ефекти стільниці X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxcompositingxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxOpenGLxx,xxXRenderxx,xxvideo settingsxx,xxgraphical effectsxx,xxdesktop effectsxx X-KDE-Keywords[zh_CN]=kwin,窗口,管理器,混成,特效,3D 特效,2D 特效,OpenGL,XRender,视频设置,图形特效,桌面特效 X-KDE-Keywords[zh_TW]=kwin,window,manager,compositing,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,桌面特效,圖形特效,視訊設定,特效,3D,2D,合成,視窗,管理器 diff --git a/kcmkwin/kwincompositing/kwincompositing_setting.kcfg b/kcmkwin/kwincompositing/kwincompositing_setting.kcfg new file mode 100644 index 000000000..31758a5e8 --- /dev/null +++ b/kcmkwin/kwincompositing/kwincompositing_setting.kcfg @@ -0,0 +1,73 @@ + + + + + + + 1.0 + + + + + + + 5 + + + + 2 + + + + false + + + + true + + + + true + + + + a + + + + + + + + + + + OpenGL + + + + + + + + false + + + + true + + + + glx + + + + + + + + + diff --git a/kcmkwin/kwincompositing/kwincompositing_setting.kcfgc b/kcmkwin/kwincompositing/kwincompositing_setting.kcfgc new file mode 100644 index 000000000..4b6ac5926 --- /dev/null +++ b/kcmkwin/kwincompositing/kwincompositing_setting.kcfgc @@ -0,0 +1,5 @@ +File=kwincompositing_setting.kcfg +ClassName=KWinCompositingSetting +Mutators=true +DefaultValueGetters=true +ParentInConstructor=true diff --git a/kcmkwin/kwincompositing/main.cpp b/kcmkwin/kwincompositing/main.cpp index 138cfe863..271559ab5 100644 --- a/kcmkwin/kwincompositing/main.cpp +++ b/kcmkwin/kwincompositing/main.cpp @@ -1,227 +1,228 @@ /************************************************************************** * KWin - the KDE window manager * * This file is part of the KDE project. * * * * Copyright (C) 2013 Antonis Tsiapaliokas * * Copyright (C) 2013 Martin Gräßlin * * * * 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 "compositing.h" #include "ui_compositing.h" #include #include #include #include #include #include #include -class KWinCompositingSettings : public KCModule +class KWinCompositingKCM : public KCModule { Q_OBJECT public: - explicit KWinCompositingSettings(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); + explicit KWinCompositingKCM(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); public Q_SLOTS: void load() override; void save() override; void defaults() override; private: void init(); KWin::Compositing::Compositing *m_compositing; Ui_CompositingForm m_form; }; static const QVector s_animationMultipliers = {8, 4, 2, 1, 0.5, 0.25, 0.125, 0}; -KWinCompositingSettings::KWinCompositingSettings(QWidget *parent, const QVariantList &args) +KWinCompositingKCM::KWinCompositingKCM(QWidget *parent, const QVariantList &args) : KCModule(parent, args) , m_compositing(new KWin::Compositing::Compositing(this)) { m_form.setupUi(this); m_form.glCrashedWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); QAction *reenableGLAction = new QAction(i18n("Re-enable OpenGL detection"), this); connect(reenableGLAction, &QAction::triggered, m_compositing, &KWin::Compositing::Compositing::reenableOpenGLDetection); connect(reenableGLAction, &QAction::triggered, m_form.glCrashedWarning, &KMessageWidget::animatedHide); m_form.glCrashedWarning->addAction(reenableGLAction); m_form.scaleWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.tearingWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.windowThumbnailWarning->setIcon(QIcon::fromTheme(QStringLiteral("dialog-warning"))); m_form.compositingEnabled->setVisible(!m_compositing->compositingRequired()); m_form.windowsBlockCompositing->setVisible(!m_compositing->compositingRequired()); init(); } -void KWinCompositingSettings::init() +void KWinCompositingKCM::init() { using namespace KWin::Compositing; auto currentIndexChangedSignal = static_cast(&QComboBox::currentIndexChanged); - connect(m_compositing, &Compositing::changed, this, &KWinCompositingSettings::markAsChanged); + connect(m_compositing, &Compositing::changed, this, qOverload(&KCModule::changed)); + connect(m_compositing, &Compositing::defaulted, this, qOverload(&KCModule::defaulted)); // enabled check box m_form.compositingEnabled->setChecked(m_compositing->compositingEnabled()); connect(m_compositing, &Compositing::compositingEnabledChanged, m_form.compositingEnabled, &QCheckBox::setChecked); connect(m_form.compositingEnabled, &QCheckBox::toggled, m_compositing, &Compositing::setCompositingEnabled); // animation speed m_form.animationSpeed->setMaximum(s_animationMultipliers.size() - 1); auto setSpeed = [this](const qreal multiplier) { auto const it = std::lower_bound(s_animationMultipliers.begin(), s_animationMultipliers.end(), multiplier, std::greater()); const int index = std::distance(s_animationMultipliers.begin(), it); m_form.animationSpeed->setValue(index); }; setSpeed(m_compositing->animationSpeed()); connect(m_compositing, &Compositing::animationSpeedChanged, m_form.animationSpeed, setSpeed); connect(m_form.animationSpeed, &QSlider::valueChanged, m_compositing, [this](int index) { m_compositing->setAnimationSpeed(s_animationMultipliers[index]); }); if (Compositing::isRunningPlasma()) { m_form.animationSpeedLabel->hide(); m_form.animationSpeedControls->hide(); } // gl scale filter m_form.glScaleFilter->setCurrentIndex(m_compositing->glScaleFilter()); connect(m_compositing, &Compositing::glScaleFilterChanged, m_form.glScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.glScaleFilter, currentIndexChangedSignal, m_compositing, &Compositing::setGlScaleFilter); connect(m_form.glScaleFilter, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.scaleWarning->animatedShow(); } else { m_form.scaleWarning->animatedHide(); } } ); // xrender scale filter m_form.xrScaleFilter->setCurrentIndex(m_compositing->xrScaleFilter()); connect(m_compositing, &Compositing::xrScaleFilterChanged, m_form.xrScaleFilter, &QComboBox::setCurrentIndex); connect(m_form.xrScaleFilter, currentIndexChangedSignal, [this](int index) { if (index == 0) { m_compositing->setXrScaleFilter(false); } else { m_compositing->setXrScaleFilter(true); } }); // tearing prevention m_form.tearingPrevention->setCurrentIndex(m_compositing->glSwapStrategy()); connect(m_compositing, &Compositing::glSwapStrategyChanged, m_form.tearingPrevention, &QComboBox::setCurrentIndex); connect(m_form.tearingPrevention, currentIndexChangedSignal, m_compositing, &Compositing::setGlSwapStrategy); connect(m_form.tearingPrevention, currentIndexChangedSignal, [this](int index) { if (index == 2) { // only when cheap - tearing m_form.tearingWarning->setText(i18n("\"Only when cheap\" only prevents tearing for full screen changes like a video.")); m_form.tearingWarning->animatedShow(); } else if (index == 3) { // full screen repaints m_form.tearingWarning->setText(i18n("\"Full screen repaints\" can cause performance problems.")); m_form.tearingWarning->animatedShow(); } else if (index == 4) { // re-use screen content m_form.tearingWarning->setText(i18n("\"Re-use screen content\" causes severe performance problems on MESA drivers.")); m_form.tearingWarning->animatedShow(); } else { m_form.tearingWarning->animatedHide(); } } ); // windowThumbnail m_form.windowThumbnail->setCurrentIndex(m_compositing->windowThumbnail()); connect(m_compositing, &Compositing::windowThumbnailChanged, m_form.windowThumbnail, &QComboBox::setCurrentIndex); connect(m_form.windowThumbnail, currentIndexChangedSignal, m_compositing, &Compositing::setWindowThumbnail); connect(m_form.windowThumbnail, currentIndexChangedSignal, [this](int index) { if (index == 2) { m_form.windowThumbnailWarning->animatedShow(); } else { m_form.windowThumbnailWarning->animatedHide(); } } ); // windows blocking compositing m_form.windowsBlockCompositing->setChecked(m_compositing->windowsBlockCompositing()); connect(m_compositing, &Compositing::windowsBlockCompositingChanged, m_form.windowsBlockCompositing, &QCheckBox::setChecked); connect(m_form.windowsBlockCompositing, &QCheckBox::toggled, m_compositing, &Compositing::setWindowsBlockCompositing); // compositing type CompositingType *type = new CompositingType(this); m_form.type->setModel(type); auto updateCompositingType = [this, type]() { m_form.type->setCurrentIndex(type->indexForCompositingType(m_compositing->compositingType())); }; updateCompositingType(); connect(m_compositing, &Compositing::compositingTypeChanged, [updateCompositingType]() { updateCompositingType(); } ); auto showHideBasedOnType = [this, type]() { const int currentType = type->compositingTypeForIndex(m_form.type->currentIndex()); m_form.glScaleFilter->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.glScaleFilterLabel->setVisible(currentType != CompositingType::XRENDER_INDEX); m_form.xrScaleFilter->setVisible(currentType == CompositingType::XRENDER_INDEX); m_form.xrScaleFilterLabel->setVisible(currentType == CompositingType::XRENDER_INDEX); }; showHideBasedOnType(); connect(m_form.type, currentIndexChangedSignal, [this, type, showHideBasedOnType]() { m_compositing->setCompositingType(type->compositingTypeForIndex(m_form.type->currentIndex())); showHideBasedOnType(); } ); if (m_compositing->OpenGLIsUnsafe()) { m_form.glCrashedWarning->animatedShow(); } } -void KWinCompositingSettings::load() +void KWinCompositingKCM::load() { KCModule::load(); - m_compositing->reset(); + m_compositing->load(); } -void KWinCompositingSettings::defaults() +void KWinCompositingKCM::defaults() { KCModule::defaults(); m_compositing->defaults(); } -void KWinCompositingSettings::save() +void KWinCompositingKCM::save() { KCModule::save(); m_compositing->save(); } K_PLUGIN_FACTORY(KWinCompositingConfigFactory, - registerPlugin("compositing"); + registerPlugin("compositing"); ) #include "main.moc" diff --git a/kcmkwin/kwindecoration/kwindecoration.desktop b/kcmkwin/kwindecoration/kwindecoration.desktop index b00a23332..597173654 100644 --- a/kcmkwin/kwindecoration/kwindecoration.desktop +++ b/kcmkwin/kwindecoration/kwindecoration.desktop @@ -1,150 +1,151 @@ [Desktop Entry] Icon=preferences-desktop-theme-windowdecorations Exec=kcmshell5 kwindecoration Categories=Qt;KDE;X-KDE-settings-looknfeel; Type=Service X-KDE-ServiceTypes=KCModule X-KDE-Library=kcm_kwindecoration X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=applicationstyle X-KDE-Weight=40 X-DocPath=kcontrol/kwindecoration/index.html X-KDE-FormFactors=desktop,tablet Name=Window Decorations Name[ar]=زخارف النوافذ Name[bg]=Декорации на прозорците Name[bs]=Dekoracije prozora Name[ca]=Decoració de les finestres Name[ca@valencia]=Decoració de les finestres Name[cs]=Dekorace oken Name[da]=Vinduesdekorationer Name[de]=Fensterdekoration Name[el]=Διακοσμήσεις παραθύρου Name[en_GB]=Window Decorations Name[es]=Decoración de ventanas Name[et]=Akna dekoratsioonid Name[eu]=Leiho-apaindurak Name[fi]=Ikkunakehykset Name[fr]=Décorations de fenêtres Name[ga]=Maisiúcháin Fhuinneog Name[gl]=Decoración da xanela Name[he]=מסגרת חלון Name[hi]=विंडो सजावट Name[hr]=Ukrasi prozora Name[hu]=Ablakdekorációk Name[ia]=Decorationes de fenestra Name[id]=Dekorasi Window Name[is]=Gluggaskreytingar Name[it]=Decorazioni delle finestre Name[ja]=ウィンドウの飾り Name[kk]=Терезенің безендірулері Name[km]=ការ​តុបតែង​បង្អួច Name[kn]=ವಿಂಡೋ ಅಲಂಕಾರಗಳು Name[ko]=창 장식 Name[lt]=Langų dekoracijos Name[lv]=Logu dekorācijas Name[mr]=चौकट सजावट Name[nb]=Vinduspynt Name[nds]=Finstern opfladusen Name[nl]=Vensterdecoraties Name[nn]=Vindaugspynt Name[pa]=ਵਿੰਡੋ ਸਜਾਵਟ Name[pl]=Wygląd okien Name[pt]=Decorações das Janelas Name[pt_BR]=Decorações da janela Name[ro]=Decorații fereastră Name[ru]=Оформление окон Name[si]=කවුළු සැරසිලි Name[sk]=Dekorácie okien Name[sl]=Okraski oken Name[sr]=Декорације прозора Name[sr@ijekavian]=Декорације прозора Name[sr@ijekavianlatin]=Dekoracije prozora Name[sr@latin]=Dekoracije prozora Name[sv]=Fönsterdekorationer Name[th]=ส่วนตกแต่งหน้าต่าง Name[tr]=Pencere Dekorasyonları Name[ug]=كۆزنەك بېزەكلىرى Name[uk]=Обрамлення вікон Name[wa]=Gåyotaedjes des fniesses Name[x-test]=xxWindow Decorationsxx Name[zh_CN]=窗口装饰 Name[zh_TW]=視窗裝飾 Comment=Configure window titlebars and borders Comment[ca]=Configura la barra de títol i les vores de les finestres Comment[ca@valencia]=Configura la barra de títol i les vores de les finestres Comment[da]=Indstil vinduets titellinjer og kanter Comment[de]=Titelleiste und Ränder von Fenstern einrichten Comment[en_GB]=Configure window titlebars and borders Comment[es]=Configurar barra de título y bordes de las ventanas Comment[et]=Akende tiitliriba ja raami seadistamine Comment[eu]=Konfiguratu leihoen titulu-barrak eta ertzak Comment[fi]=Ikkunan otsikkopalkkien ja reunojen asetukset Comment[fr]=Configure les barres de titre et les bordures de la fenêtre Comment[gl]=Configurar as barras de título e os bordos das xanelas Comment[ia]=Configura barras de titulo e margines Comment[id]=Konfigurasikan bingkai dan bilah-judul window Comment[it]=Configura la barra del titolo e i bordi delle finestre Comment[ko]=창 제목 표시줄과 경계선 설정 Comment[lt]=Konfigūruoti langų antraštės juostas ir rėmelius Comment[nl]=Titelbalken en randen van venster configureren Comment[nn]=Set opp tittellinjer og vindaugsrammer Comment[pl]=Ustawienia pasków tytułów i obramowań okien Comment[pt]=Configurar as barras de título e contornos das janelas Comment[pt_BR]=Configure as barras de títulos e bordas da janela Comment[ru]=Настройка заголовка и границ окон Comment[sk]=Nastaviť záhlavia a okraje okna +Comment[sl]=Nastavi naslovne vrstice in robove oken Comment[sv]=Anpassa namnlister och kanter för fönster Comment[uk]=Налаштовування смужок заголовків та рамок вікон Comment[x-test]=xxConfigure window titlebars and bordersxx Comment[zh_CN]=配置窗口标题栏和边框 Comment[zh_TW]=設定視窗的標題列和邊框 X-KDE-Keywords=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[bs]=kwin,prozor,upravitelj,granica,stil,tema,izgled,osjećati,izgled,dugme,držati,ivica,kwm,dekoracija X-KDE-Keywords[ca]=kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,gestió,vora,kwm,decoració X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,gestió,vora,kwm,decoració X-KDE-Keywords[cs]=kwin,okna,správce,okraj,styl,motiv,vzhled,pocit,rozvržení,tlačítko,madlo,okraj,kwm,dekorace X-KDE-Keywords[da]=kwin,vindueshåndtering,window,manager,kant,stil,tema,udseende,layout,knap,håndtag,kant,kwm,dekoration X-KDE-Keywords[de]=KWin,Kwm,Fenster,Manager,Rahmen,Design,Stile,Themes,Optik,Erscheinungsbild,Layout,Knöpfe,Ränder,Dekorationen X-KDE-Keywords[el]=kwin,παράθυρο,διαχειριστής,περίγραμμα,στιλ,θέμα,εμφάνιση,αίσθηση,διάταξη,κουμπί,χειρισμός,άκρη,kwm,διακόσμηση X-KDE-Keywords[en_GB]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[es]=kwin,ventana,gestor,borde,estilo,tema,aspecto,sensación,disposición,botón,asa,borde,kwm,decoración X-KDE-Keywords[et]=kwin,aken,haldur,piire,stiil,teema,välimus,paigutus,nupp,pide,serv,kwm,dekoratsioon X-KDE-Keywords[eu]=kwin,leiho,kudeatzaile,ertz,estilo,gai, itxura,izaera,diseinu,botoi,helduleku,kwm,dekorazio,apaindura,apainketa X-KDE-Keywords[fi]=kwin,ikkuna,hallinta,ikkunointiohjelma,kehys,reunus,tyyli,teema,ulkoasu,toiminta,asettelu,painike,kahva,kulma,reuna,kwm,koriste X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, composition, bordure, style, thème, apparence, comportement, disposition, bouton, prise en main, bord, kwm, décoration X-KDE-Keywords[ga]=kwin,fuinneog,bainisteoir,imlíne,stíl,téama,cuma,brath,leagan amach,cnaipe,hanla,ciumhais,kwm,maisiúchán X-KDE-Keywords[gl]=kwin,xanela,xestor,estilo,tema,aparencia,comportamento,aspecto,disposición, botón,asa,bordo,kwm,decoración X-KDE-Keywords[hu]=kwin,ablak,kezelő,szegély,stílus,téma,kinézet,megjelenés,elrendezés,gomb,kezel,szél,kwm,dekoráció X-KDE-Keywords[ia]=kwin,fenestra,gerente,margine,stilo,thema,aspecto,sentir,disposition,button,maneator,bordo,kwm,decoration X-KDE-Keywords[id]=kwin,window,pengelola,batas,gaya,tema,tampilan,rasa,tata letak,tombol,pegangan,bingkai,kwm,dekorasi X-KDE-Keywords[it]=kwin,gestore,finestre,bordo,stile,tema,aspetto,disposizione,pulsante,gestore,kwm,decorazione X-KDE-Keywords[kk]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[km]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[ko]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,창,관리자,테두리,스타일,테마,단추,핸들,경계 X-KDE-Keywords[lt]=kwin,langai,langas,langų,tvarkytuvė,tvarkytuve,rėmelis,remelis,stilius,apipavidalinimas,tema,išvaizda,isvaizda,turinys,išdėstymas,isdestymas,mygtukai,mygtukas,rankena,rankenėlė,rankenele,kraštas,krastas,kraštai,krastai,kwm,dekoracija,dekoracijos X-KDE-Keywords[nb]=kwin,vindu,behandler,ramme,stil,tema,lås,utforming,knapp,håndtak,kant,kwm X-KDE-Keywords[nds]=KWin,Finster,Pleger,Rahmen,Stil,Muster,Utsehn,Bedenen,Knoop,Greep,Kant,kwm,Dekoratschoon X-KDE-Keywords[nl]=kwin,venster,beheerder,grens,stijl,thema,look,feel,indeling,knop,handel,rand,kwm,decoratie X-KDE-Keywords[nn]=kwin,vindauge,handsamar,ramme,kantlinje,stil,tema,lås,utforming,knapp,handtak,kant,kwm,dekorasjon,pynt X-KDE-Keywords[pl]=kwin,okno,menadżer,obramowanie,styl,motyw,wygląd,odczucie,układ,przycisk, uchwyt,krawędź,kwm,dekoracja X-KDE-Keywords[pt]=kwin,gestor,janela,contorno,estilo,tema,aparência,comportamento,disposição,botão,pega,extremo,kwm,decoração X-KDE-Keywords[pt_BR]=kwin,gerenciador,janela,borda,estilo,tema,aparência,comportamento,layout,botão,canto,extremo,kwm,decoração X-KDE-Keywords[ru]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,окно,диспетчер,граница,стиль,тема,внешний вид,оформление,разметка,шаблон,кнопка,управление,край X-KDE-Keywords[sk]=kwin,okno,správca,rám,štýl,téma,vzhľad,cítenie,rozloženie,tlačidlo,spracovanie,okraj,kwm,dekorácia X-KDE-Keywords[sl]=kwin,okna,okenski upravljalnik,upravljalnik oken,rob,obroba,slog,tema,videz,obnašanje,občutek,razpored,gumbi,ročica,okraski,kwm X-KDE-Keywords[sr]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,К‑вин,прозор,менаџер,ивица,стила,тема,изглед,осећај,распоред,дугме,ручка,КВМ,декорација X-KDE-Keywords[sr@ijekavian]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,К‑вин,прозор,менаџер,ивица,стила,тема,изглед,осећај,распоред,дугме,ручка,КВМ,декорација X-KDE-Keywords[sr@ijekavianlatin]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,KWin,prozor,menadžer,ivica,stila,tema,izgled,osećaj,raspored,dugme,ručka,KWM,dekoracija X-KDE-Keywords[sr@latin]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,KWin,prozor,menadžer,ivica,stila,tema,izgled,osećaj,raspored,dugme,ručka,KWM,dekoracija X-KDE-Keywords[sv]=kwin,fönster,hantering,kant,stil,tema,utseende,känsla,layout,knapp,grepp,kant,kwm,dekoration X-KDE-Keywords[tr]=kwin,pencere,yönetici,kenarlık,biçim,tema,görünüm,şekil,düzen,düğme,kullanım,kenar,kwm,dekorasyon X-KDE-Keywords[uk]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,вікно,вікна,керування,менеджер,рамка,межа,стиль,тема,вигляд,поведінка,компонування,кнопка,елемент,край,декорації,обрамлення X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxborderxx,xxstylexx,xxthemexx,xxlookxx,xxfeelxx,xxlayoutxx,xxbuttonxx,xxhandlexx,xxedgexx,xxkwmxx,xxdecorationxx X-KDE-Keywords[zh_CN]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,窗口,管理,边框,样式,主题,外怪,布局,按钮,边界,装饰 X-KDE-Keywords[zh_TW]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration diff --git a/kcmkwin/kwindecoration/package/metadata.desktop b/kcmkwin/kwindecoration/package/metadata.desktop index 022703438..4755ca936 100644 --- a/kcmkwin/kwindecoration/package/metadata.desktop +++ b/kcmkwin/kwindecoration/package/metadata.desktop @@ -1,106 +1,107 @@ [Desktop Entry] Icon=preferences-system-windows-action Type=Service Keywords= X-KDE-ParentApp= X-KDE-System-Settings-Parent-Category=applicationstyle X-KDE-PluginInfo-Author=Valerio Pilo X-KDE-PluginInfo-Email=vpilo@coldshock.net X-KDE-PluginInfo-License=GPL-2.0+ X-KDE-PluginInfo-Name=kcm_kwindecoration X-KDE-PluginInfo-Version= X-KDE-PluginInfo-Website=https://www.kde.org/plasma-desktop X-KDE-ServiceTypes=Plasma/Generic X-Plasma-API=declarativeappletscript X-Plasma-MainScript=ui/main.qml X-KDE-FormFactors=desktop,tablet Name=Window Decorations Name[ar]=زخارف النوافذ Name[bg]=Декорации на прозорците Name[bs]=Dekoracije prozora Name[ca]=Decoració de les finestres Name[ca@valencia]=Decoració de les finestres Name[cs]=Dekorace oken Name[da]=Vinduesdekorationer Name[de]=Fensterdekoration Name[el]=Διακοσμήσεις παραθύρου Name[en_GB]=Window Decorations Name[es]=Decoración de ventanas Name[et]=Akna dekoratsioonid Name[eu]=Leiho-apaindurak Name[fi]=Ikkunakehykset Name[fr]=Décorations de fenêtres Name[ga]=Maisiúcháin Fhuinneog Name[gl]=Decoración da xanela Name[he]=מסגרת חלון Name[hi]=विंडो सजावट Name[hr]=Ukrasi prozora Name[hu]=Ablakdekorációk Name[ia]=Decorationes de fenestra Name[id]=Dekorasi Window Name[is]=Gluggaskreytingar Name[it]=Decorazioni delle finestre Name[ja]=ウィンドウの飾り Name[kk]=Терезенің безендірулері Name[km]=ការ​តុបតែង​បង្អួច Name[kn]=ವಿಂಡೋ ಅಲಂಕಾರಗಳು Name[ko]=창 장식 Name[lt]=Langų dekoracijos Name[lv]=Logu dekorācijas Name[mr]=चौकट सजावट Name[nb]=Vinduspynt Name[nds]=Finstern opfladusen Name[nl]=Vensterdecoraties Name[nn]=Vindaugspynt Name[pa]=ਵਿੰਡੋ ਸਜਾਵਟ Name[pl]=Wygląd okien Name[pt]=Decorações das Janelas Name[pt_BR]=Decorações da janela Name[ro]=Decorații fereastră Name[ru]=Оформление окон Name[si]=කවුළු සැරසිලි Name[sk]=Dekorácie okien Name[sl]=Okraski oken Name[sr]=Декорације прозора Name[sr@ijekavian]=Декорације прозора Name[sr@ijekavianlatin]=Dekoracije prozora Name[sr@latin]=Dekoracije prozora Name[sv]=Fönsterdekorationer Name[th]=ส่วนตกแต่งหน้าต่าง Name[tr]=Pencere Dekorasyonları Name[ug]=كۆزنەك بېزەكلىرى Name[uk]=Обрамлення вікон Name[wa]=Gåyotaedjes des fniesses Name[x-test]=xxWindow Decorationsxx Name[zh_CN]=窗口装饰 Name[zh_TW]=視窗裝飾 Comment=Configure window titlebars and borders Comment[ca]=Configura la barra de títol i les vores de les finestres Comment[ca@valencia]=Configura la barra de títol i les vores de les finestres Comment[da]=Indstil vinduets titellinjer og kanter Comment[de]=Titelleiste und Ränder von Fenstern einrichten Comment[en_GB]=Configure window titlebars and borders Comment[es]=Configurar barra de título y bordes de las ventanas Comment[et]=Akende tiitliriba ja raami seadistamine Comment[eu]=Konfiguratu leihoen titulu-barrak eta ertzak Comment[fi]=Ikkunan otsikkopalkkien ja reunojen asetukset Comment[fr]=Configure les barres de titre et les bordures de la fenêtre Comment[gl]=Configurar as barras de título e os bordos das xanelas Comment[ia]=Configura barras de titulo e margines Comment[id]=Konfigurasikan bingkai dan bilah-judul window Comment[it]=Configura la barra del titolo e i bordi delle finestre Comment[ko]=창 제목 표시줄과 경계선 설정 Comment[lt]=Konfigūruoti langų antraštės juostas ir rėmelius Comment[nl]=Titelbalken en randen van venster configureren Comment[nn]=Set opp tittellinjer og vindaugsrammer Comment[pl]=Ustawienia pasków tytułów i obramowań okien Comment[pt]=Configurar as barras de título e contornos das janelas Comment[pt_BR]=Configure as barras de títulos e bordas da janela Comment[ru]=Настройка заголовка и границ окон Comment[sk]=Nastaviť záhlavia a okraje okna +Comment[sl]=Nastavi naslovne vrstice in robove oken Comment[sv]=Anpassa namnlister och kanter för fönster Comment[uk]=Налаштовування смужок заголовків та рамок вікон Comment[x-test]=xxConfigure window titlebars and bordersxx Comment[zh_CN]=配置窗口标题栏和边框 Comment[zh_TW]=設定視窗的標題列和邊框 diff --git a/kcmkwin/kwindesktop/kcm_kwin_virtualdesktops.desktop b/kcmkwin/kwindesktop/kcm_kwin_virtualdesktops.desktop index 933905a5d..be78187d4 100644 --- a/kcmkwin/kwindesktop/kcm_kwin_virtualdesktops.desktop +++ b/kcmkwin/kwindesktop/kcm_kwin_virtualdesktops.desktop @@ -1,151 +1,152 @@ [Desktop Entry] Exec=kcmshell5 kcm_kwin_virtualdesktops Icon=preferences-desktop-virtual Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/kwin_virtualdesktops/index.html X-KDE-Library=kcm_kwin_virtualdesktops X-KDE-ParentApp=kcontrol X-KDE-FormFactors=desktop X-KDE-System-Settings-Parent-Category=desktopbehavior X-KDE-Weight=60 Name=Virtual Desktops Name[ar]=أسطح المكتب الافتراضية Name[ast]=Escritorios virtuales Name[bg]=Виртуални работни плотове Name[bs]=Virtuelne površi Name[ca]=Escriptoris virtuals Name[ca@valencia]=Escriptoris virtuals Name[cs]=Virtuální plochy Name[da]=Virtuelle skriveborde Name[de]=Virtuelle Arbeitsflächen Name[el]=Εικονικές επιφάνειες εργασίες Name[en_GB]=Virtual Desktops Name[es]=Escritorios virtuales Name[et]=Virtuaalsed töölauad Name[eu]=Alegiazko mahaigaina Name[fi]=Virtuaalityöpöydät Name[fr]=Bureaux virtuels Name[ga]=Deasca Fíorúla Name[gl]=Escritorios virtuais Name[gu]=વર્ચ્યુઅલ ડેસ્કટોપો Name[he]=שולחנות עבודה וירטואליים Name[hi]=आभासी डेस्कटॉप Name[hr]=Virtualne radne površine Name[hu]=Virtuális asztalok Name[ia]=Scriptorios virtual Name[id]=Desktop Virtual Name[is]=Sýndarskjáborð Name[it]=Desktop virtuali Name[ja]=仮想デスクトップ Name[kk]=Виртуалды Үстелдер Name[km]=ផ្ទៃតុ​និម្មិត Name[kn]=ವಾಸ್ತವಪ್ರಾಯ ಗಣಕತೆರೆಗಳು Name[ko]=가상 바탕 화면 Name[lt]=Virtualūs darbalaukiai Name[lv]=Virtuālās darbvirsmas Name[mr]=आभासी डेस्कटॉप Name[nb]=Virtuelle skrivebord Name[nds]=Mehr Schriefdischen Name[nl]=Virtuele bureaubladen Name[nn]=Virtuelle skrivebord Name[pa]=ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ Name[pl]=Pulpity wirtualne Name[pt]=Ecrãs Virtuais Name[pt_BR]=Áreas de trabalho virtuais Name[ro]=Birouri virtuale Name[ru]=Рабочие столы Name[si]=අත්ථ්‍ය වැඩතල Name[sk]=Virtuálne pracovné plochy Name[sl]=Navidezna namizja Name[sr]=Виртуелне површи Name[sr@ijekavian]=Виртуелне површи Name[sr@ijekavianlatin]=Virtuelne površi Name[sr@latin]=Virtuelne površi Name[sv]=Virtuella skrivbord Name[th]=พื้นที่ทำงานเสมือน Name[tr]=Sanal Masaüstleri Name[ug]=مەۋھۇم ئۈستەلئۈستى Name[uk]=Віртуальні стільниці Name[wa]=Forveyous scribannes Name[x-test]=xxVirtual Desktopsxx Name[zh_CN]=虚拟桌面 Name[zh_TW]=虛擬桌面 Comment=Configure navigation, number and layout of virtual desktops Comment[ca]=Configura la navegació, el nombre i la disposició dels escriptoris virtuals Comment[da]=Indstil navigation, antal og layout af virtuelle skriveborde Comment[de]=Navigation, Anzahl und Layout virtueller Arbeitsflächen einrichten Comment[en_GB]=Configure navigation, number and layout of virtual desktops Comment[es]=Configurar la navegación, número y disposición de los escritorios virtuales Comment[et]=Virtuaalsete töölaudade vahel liikumise, nende arvu ja paigutuse seadistamine Comment[eu]=Konfiguratu nabigatzea, alegiazko mahaigainen kopurua eta antolamendua Comment[fi]=Aseta virtuaalityöpöytien määrä, asettelu ja niiden välillä siirtyminen Comment[fr]=Configurer la navigation, le nombre et la disposition des bureaux virtuels Comment[gl]=Configurar a navegación, cantidade e disposición dos escritorios virtuais Comment[ia]=Configura navigation, numero e disposition de scriptorios virtual Comment[id]=Konfigurasikan navigasi, nomor dan tataletak desktop virtual Comment[it]=Configura navigazione, numero e disposizione dei desktop virtuali Comment[ko]=가상 바탕 화면 탐색, 개수, 레이아웃 설정 Comment[lt]=Konfigūruoti virtualių darbalaukių naršymą, skaičių ir išdėstymą Comment[nl]=Navigatie, aantal en indeling van virtuele bureaubladen configureren Comment[nn]=Set opp navigering, nummer og vising av virtuelle skrivebord Comment[pl]=Ustawienia poruszania się, liczby oraz układu wirtualnych klawiatur Comment[pt]=Configura a navegação, número e disposição dos ecrãs virtuais Comment[pt_BR]=Configura a navegação, quantidade e layout das áreas de trabalho virtuais Comment[ru]=Число, расположение и способ переключения рабочих столов Comment[sk]=Nastaviť navigáciu, počet a rozloženie virtuálnych plôch +Comment[sl]=Nastavi krmarjenje, število in razporeditev navideznih namizij Comment[sv]=Anpassa navigering, antal och layout av virtuella skrivbord Comment[uk]=Налаштовування навігації, кількості та компонування віртуальних стільниць Comment[x-test]=xxConfigure navigation, number and layout of virtual desktopsxx Comment[zh_CN]=配置虚拟桌面的导航,数目和布局 Comment[zh_TW]=設定虛擬桌面的導覽、數字與佈局 X-KDE-Keywords=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings X-KDE-Keywords[bs]=pozadina,pozadine,broj,virtuelna pozadina,višestruka pozadina,pejdžer,dodatak pejdžeru,aplet pejdžer,pejdžer postavke X-KDE-Keywords[ca]=escriptori,escriptoris,nombre,escriptori virtual,múltiples escriptoris,paginador,estri paginador,miniaplicació de paginació,arranjament del paginador X-KDE-Keywords[ca@valencia]=escriptori,escriptoris,nombre,escriptori virtual,escriptoris múltiples,paginador,estri paginador,miniaplicació de paginació,arranjament de paginador X-KDE-Keywords[da]=skrivebord,skriveborde,desktop,desktops,virtuelt skrivebord,flere skriveborde,spaces,pager,skrivebordsvælger,pager widget,pager applet X-KDE-Keywords[de]=Arbeitsfläche,Arbeitsflächen,Desktop,Anzahl,Virtuelle Arbeitsfläche,Mehrere Arbeitsflächen,Arbeitsflächenumschalter,Arbeitsflächenumschalter-Bedienelement,Arbeitsflächenumschalter-Miniprogramm,Arbeitsflächenumschalter-Einstellungen X-KDE-Keywords[el]=επιφάνεια εργασίας,επιφάνειες εργασίας,αριθμός,εικονική επιφάνεια εργασίας,πολλαπλές επιφάνειες εργασίας,χαρτί,γραφικό συστατικό χαρτιού,μικροεφαρμογή χαρτιού,ρυθμίσεις χαρτιού X-KDE-Keywords[en_GB]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings X-KDE-Keywords[es]=escritorio,escritorios,número,escritorio virtual,múltiples escritorios,paginador,control de paginación,miniaplicación del paginador,preferencias del paginador X-KDE-Keywords[et]=töölaud,töölauad,arv,virtuaalne töölaud,mitu töölauda,töölauavahetaja,töölaudade vahetaja,töölauavahetaja aplett,töölauavahetaja vidin,töölauavahetaja seadistused X-KDE-Keywords[eu]=mahaigain,mahaigainak,kopuru,mahaigain birtuala,alegiazko mahaigaina,hainbat mahaigain,bilagailu,bilagailuaren trepeta,bilagailuaren miniaplikazioa,bilagailuaren ezarpenak X-KDE-Keywords[fi]=työpöytä,työpöydät,lukumäärä,virtuaalityöpöytä,monta työpöytää,sivutin,sivutinsovelma,sivuttimen asetukset X-KDE-Keywords[fr]=bureau, bureaux, numéro, bureau virtuel, bureaux multiples, gestionnaire de bureau, composant graphique du gestionnaire de bureau, paramètres du gestionnaire de bureaux X-KDE-Keywords[gl]=escritorio,escritorios,número,escritorio virtual,escritorios múltiplos,paxinador, trebello paxinador, miniaplicativo paxinador,configuración do paxinador X-KDE-Keywords[hu]=asztal,asztalok,szám,virtuális asztal,több asztal,papír,papír felületi elem,papír kisalkalmazás,papírbeállítások X-KDE-Keywords[ia]=scriptorio,scriptorios,numero,scriptorio virtual,scriptorio multiple,pager, widget de pager, applet de pager, preferentias de pager X-KDE-Keywords[id]=desktop,desktop,jumlah,desktop virtual,banyak desktop,halaman,widget halaman,applet halaman,pengaturan halaman X-KDE-Keywords[it]=desktop,numero,desktop virtuali,desktop multipli,cambiadesktop,oggetto cambiadesktop,applet cambiadesktop,impostazioni del cambiadesktop X-KDE-Keywords[kk]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings X-KDE-Keywords[km]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings X-KDE-Keywords[ko]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,데스크톱,가상 데스크톱,다중 데스크톱,바탕 화면,가상 바탕 화면,다중 바탕 화면 X-KDE-Keywords[lt]=darbalaukis,darbastalis,darbalaukiai,darbastaliai,skaičius,numeris,numeriai,skaičiai,skaicius,skaiciai,virtualus darbalaukis,virtualūs darbalaukiai,virtualus darbalaukiai,keli darbalaukiai,keletas darbalaukių,keletas darbalaukiu,puslapiuotojas,perjungiklis,perjungiklio valdiklis,perjungiklio programėlė,perjungiklio programele,perjungiklio nuostatos,perjungiklio nustatymai X-KDE-Keywords[nb]=skrivebord,antall,virtuelt skrivebord,flere skrivebord,veksler,vekslerelement,veksler-miniprogram,vekslerinnstillinger X-KDE-Keywords[nds]=Schriefdisch,Schriefdischen,virtuell,mehr,Schriefdisch-Översicht,instellen X-KDE-Keywords[nl]=bureaublad,bureaubladen,aantal,virtueel bureaublad,meervoudige bureaubladen,pager,pager-widget,pager-applet,pagerinstellingen X-KDE-Keywords[nn]=skrivebord,mengd,tal,virtuelt skrivebord,fleire skrivebord,vekslar,vekslarelement,vekslarelement,vekslerinnstillinger,vekslaroppsett X-KDE-Keywords[pa]=ਡੈਸਕਟਾਪ,ਗਿਣਤੀ,ਨੰਬਰ,ਅੰਕ,ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ,ਕਈ ਡੈਸਕਟਾਪ,ਪੇਜ਼ਰ,ਪੇਜ਼ਰ ਵਿਜੈਟ,ਪੇਜ਼ਰ ਐਪਲਿਟ,ਪੇਜ਼ਰ ਸੈਟਿੰਗਾਂ X-KDE-Keywords[pl]=pulpit,pulpity,liczba,pulpity wirtualne,wiele pulpitów X-KDE-Keywords[pt]=ecrã,ecrãs,número,ecrã virtual,múltiplos ecrãs,paginador,elemento paginador,'applet' do paginador,configuração do paginador X-KDE-Keywords[pt_BR]=área de trabalho,áreas de trabalho,desktop,desktops,número,área de trabalho virtual,múltiplas áreas de trabalho,paginador,elemento paginador,miniaplicativo do paginador,configurações do paginador X-KDE-Keywords[ru]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,рабочий стол,рабочие столы,число,виртуальный рабочий стол,несколько рабочих столов,переключатель,переключение,виджет переключения,аплет переключения,параметры переключения,настройки переключения X-KDE-Keywords[sk]=plocha,plochy,číslo,virtuálna plocha,viac plôch,pager,widget pagera,applet pagera,nastavenia pagera X-KDE-Keywords[sl]=namizje,namizja,število namizij,navidezna namizja,več namizij,pozivnik X-KDE-Keywords[sr]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,површ,број,виртуелна површ,више површи,листач,виџет листача,аплет листача,поставке листача X-KDE-Keywords[sr@ijekavian]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,површ,број,виртуелна површ,више површи,листач,виџет листача,аплет листача,поставке листача X-KDE-Keywords[sr@ijekavianlatin]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,površ,broj,virtuelna površ,više površi,listač,vidžet listača,aplet listača,postavke listača X-KDE-Keywords[sr@latin]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,površ,broj,virtuelna površ,više površi,listač,vidžet listača,aplet listača,postavke listača X-KDE-Keywords[sv]=skrivbord,antal,virtuellt skrivbord,flera skrivbord,skrivbordsvisning,visningskomponent,visningsminiprogram,visningsinställningar X-KDE-Keywords[tr]=masaüstü,masaüstleri,sayı,sanal masaüstü,çoklu masaüstü,sayfalayıcı,sayfalayıcı gereci,sayfalayıcı gereci,sayfalayıcı ayarları X-KDE-Keywords[uk]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,стільниця,стільниці,кількість,віртуальна стільниця,перемикач,пейджер,віджет перемикача,віджет пейджера,аплет перемикання,аплет перемикача,параметри перемикання,параметри перемикача X-KDE-Keywords[x-test]=xxdesktopxx,xxdesktopsxx,xxnumberxx,xxvirtual desktopxx,xxmultiple desktopsxx,xxpagerxx,xxpager widgetxx,xxpager appletxx,xxpager settingsxx X-KDE-Keywords[zh_CN]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,桌面,虚拟桌面,多桌面,分页,分页器,分页器组件,分页器设置 X-KDE-Keywords[zh_TW]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings Categories=Qt;KDE;X-KDE-settings-translations; diff --git a/kcmkwin/kwindesktop/package/contents/ui/main.qml b/kcmkwin/kwindesktop/package/contents/ui/main.qml index 5e0f39b26..770bc22d6 100644 --- a/kcmkwin/kwindesktop/package/contents/ui/main.qml +++ b/kcmkwin/kwindesktop/package/contents/ui/main.qml @@ -1,276 +1,277 @@ /* * Copyright (C) 2018 Eike Hein * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ import QtQuick 2.5 import QtQuick.Controls 2.5 as QQC2 import QtQuick.Layouts 1.1 import org.kde.kcm 1.2 import org.kde.kirigami 2.10 as Kirigami import org.kde.plasma.core 2.1 as PlasmaCore ScrollViewKCM { id: root ConfigModule.quickHelp: i18n("This module lets you configure the navigation, number and layout of virtual desktops.") Connections { target: kcm.desktopsModel onReadyChanged: { rowsSpinBox.value = kcm.desktopsModel.rows; } onRowsChanged: { rowsSpinBox.value = kcm.desktopsModel.rows; } } implicitWidth: Kirigami.Units.gridUnit * 35 implicitHeight: Kirigami.Units.gridUnit * 30 Component { id: desktopsListItemComponent Kirigami.SwipeListItem { id: listItem contentItem: RowLayout { QQC2.TextField { id: nameField background: null leftPadding: Kirigami.Units.largeSpacing topPadding: 0 bottomPadding: 0 Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter text: model.display readOnly: true onEditingFinished: { readOnly = true; Qt.callLater(kcm.desktopsModel.setDesktopName, model.Id, text); } } } actions: [ Kirigami.Action { enabled: !model.IsMissing iconName: "edit-rename" tooltip: i18nc("@info:tooltip", "Rename") onTriggered: { nameField.readOnly = false; nameField.selectAll(); nameField.forceActiveFocus(); } }, Kirigami.Action { enabled: !model.IsMissing iconName: "edit-delete-remove" tooltip: i18nc("@info:tooltip", "Remove") onTriggered: kcm.desktopsModel.removeDesktop(model.Id) }] } } header: ColumnLayout { id: messagesLayout spacing: Kirigami.Units.largeSpacing Kirigami.InlineMessage { Layout.fillWidth: true type: Kirigami.MessageType.Error text: kcm.desktopsModel.error visible: kcm.desktopsModel.error != "" } Kirigami.InlineMessage { Layout.fillWidth: true type: Kirigami.MessageType.Information text: i18n("Virtual desktops have been changed outside this settings application. Saving now will overwrite the changes.") visible: kcm.desktopsModel.serverModified } } view: ListView { id: desktopsList model: kcm.desktopsModel.ready ? kcm.desktopsModel : null section.property: "DesktopRow" section.delegate: Kirigami.ListSectionHeader { width: desktopsList.width label: i18n("Row %1", section) } delegate: Kirigami.DelegateRecycler { width: desktopsList.width sourceComponent: desktopsListItemComponent } } footer: ColumnLayout { RowLayout { QQC2.Button { text: i18nc("@action:button", "Add") icon.name: "list-add" onClicked: kcm.desktopsModel.createDesktop(i18n("New Desktop")) } Item { // Spacer Layout.fillWidth: true } QQC2.SpinBox { id: rowsSpinBox from: 1 to: 20 editable: true textFromValue: function(value, locale) { return i18np("1 Row", "%1 Rows", value)} + valueFromText: function(text, locale) { return parseInt(text, 10); } onValueModified: kcm.desktopsModel.rows = value } } Kirigami.FormLayout { QQC2.CheckBox { id: navWraps Kirigami.FormData.label: i18n("Options:") text: i18n("Navigation wraps around") enabled: !kcm.virtualDesktopsSettings.isImmutable("rollOverDesktops") checked: kcm.virtualDesktopsSettings.rollOverDesktops onToggled: kcm.virtualDesktopsSettings.rollOverDesktops = checked } RowLayout { Layout.fillWidth: true QQC2.CheckBox { id: animationEnabled // Let it elide but don't make it push the ComboBox away from it Layout.fillWidth: true Layout.maximumWidth: implicitWidth text: i18n("Show animation when switching:") checked: kcm.animationsModel.enabled onToggled: kcm.animationsModel.enabled = checked } QQC2.ComboBox { enabled: animationEnabled.checked model: kcm.animationsModel textRole: "NameRole" currentIndex: kcm.animationsModel.currentIndex onActivated: kcm.animationsModel.currentIndex = currentIndex } QQC2.Button { enabled: animationEnabled.checked && kcm.animationsModel.currentConfigurable icon.name: "configure" onClicked: kcm.configureAnimation() } QQC2.Button { enabled: animationEnabled.checked icon.name: "dialog-information" onClicked: kcm.showAboutAnimation() } Item { Layout.fillWidth: true } } RowLayout { Layout.fillWidth: true QQC2.CheckBox { id: osdEnabled text: i18n("Show on-screen display when switching:") enabled: !kcm.virtualDesktopsSettings.isImmutable("desktopChangeOsdEnabled") checked: kcm.virtualDesktopsSettings.desktopChangeOsdEnabled onToggled: kcm.virtualDesktopsSettings.desktopChangeOsdEnabled = checked } QQC2.SpinBox { id: osdDuration enabled: osdEnabled.checked && !kcm.virtualDesktopsSettings.isImmutable("popupHideDelay") from: 0 to: 10000 stepSize: 100 textFromValue: function(value, locale) { return i18n("%1 ms", value)} value: kcm.virtualDesktopsSettings.popupHideDelay onValueModified: kcm.virtualDesktopsSettings.popupHideDelay = value } } RowLayout { Layout.fillWidth: true Item { width: units.largeSpacing } QQC2.CheckBox { id: osdTextOnly enabled: osdEnabled.checked && !kcm.virtualDesktopsSettings.isImmutable("textOnly") text: i18n("Show desktop layout indicators") checked: !kcm.virtualDesktopsSettings.textOnly onToggled: kcm.virtualDesktopsSettings.textOnly = !checked } } } } } diff --git a/kcmkwin/kwindesktop/package/metadata.desktop b/kcmkwin/kwindesktop/package/metadata.desktop index e7e3fc7d3..75f4c2c5c 100644 --- a/kcmkwin/kwindesktop/package/metadata.desktop +++ b/kcmkwin/kwindesktop/package/metadata.desktop @@ -1,102 +1,103 @@ [Desktop Entry] Name=Virtual Desktops Name[ar]=أسطح المكتب الافتراضية Name[ast]=Escritorios virtuales Name[bg]=Виртуални работни плотове Name[bs]=Virtuelne površi Name[ca]=Escriptoris virtuals Name[ca@valencia]=Escriptoris virtuals Name[cs]=Virtuální plochy Name[da]=Virtuelle skriveborde Name[de]=Virtuelle Arbeitsflächen Name[el]=Εικονικές επιφάνειες εργασίες Name[en_GB]=Virtual Desktops Name[es]=Escritorios virtuales Name[et]=Virtuaalsed töölauad Name[eu]=Alegiazko mahaigaina Name[fi]=Virtuaalityöpöydät Name[fr]=Bureaux virtuels Name[ga]=Deasca Fíorúla Name[gl]=Escritorios virtuais Name[gu]=વર્ચ્યુઅલ ડેસ્કટોપો Name[he]=שולחנות עבודה וירטואליים Name[hi]=आभासी डेस्कटॉप Name[hr]=Virtualne radne površine Name[hu]=Virtuális asztalok Name[ia]=Scriptorios virtual Name[id]=Desktop Virtual Name[is]=Sýndarskjáborð Name[it]=Desktop virtuali Name[ja]=仮想デスクトップ Name[kk]=Виртуалды Үстелдер Name[km]=ផ្ទៃតុ​និម្មិត Name[kn]=ವಾಸ್ತವಪ್ರಾಯ ಗಣಕತೆರೆಗಳು Name[ko]=가상 바탕 화면 Name[lt]=Virtualūs darbalaukiai Name[lv]=Virtuālās darbvirsmas Name[mr]=आभासी डेस्कटॉप Name[nb]=Virtuelle skrivebord Name[nds]=Mehr Schriefdischen Name[nl]=Virtuele bureaubladen Name[nn]=Virtuelle skrivebord Name[pa]=ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ Name[pl]=Pulpity wirtualne Name[pt]=Ecrãs Virtuais Name[pt_BR]=Áreas de trabalho virtuais Name[ro]=Birouri virtuale Name[ru]=Рабочие столы Name[si]=අත්ථ්‍ය වැඩතල Name[sk]=Virtuálne pracovné plochy Name[sl]=Navidezna namizja Name[sr]=Виртуелне површи Name[sr@ijekavian]=Виртуелне површи Name[sr@ijekavianlatin]=Virtuelne površi Name[sr@latin]=Virtuelne površi Name[sv]=Virtuella skrivbord Name[th]=พื้นที่ทำงานเสมือน Name[tr]=Sanal Masaüstleri Name[ug]=مەۋھۇم ئۈستەلئۈستى Name[uk]=Віртуальні стільниці Name[wa]=Forveyous scribannes Name[x-test]=xxVirtual Desktopsxx Name[zh_CN]=虚拟桌面 Name[zh_TW]=虛擬桌面 Comment=Configure navigation, number and layout of virtual desktops Comment[ca]=Configura la navegació, el nombre i la disposició dels escriptoris virtuals Comment[da]=Indstil navigation, antal og layout af virtuelle skriveborde Comment[de]=Navigation, Anzahl und Layout virtueller Arbeitsflächen einrichten Comment[en_GB]=Configure navigation, number and layout of virtual desktops Comment[es]=Configurar la navegación, número y disposición de los escritorios virtuales Comment[et]=Virtuaalsete töölaudade vahel liikumise, nende arvu ja paigutuse seadistamine Comment[eu]=Konfiguratu nabigatzea, alegiazko mahaigainen kopurua eta antolamendua Comment[fi]=Aseta virtuaalityöpöytien määrä, asettelu ja niiden välillä siirtyminen Comment[fr]=Configurer la navigation, le nombre et la disposition des bureaux virtuels Comment[gl]=Configurar a navegación, cantidade e disposición dos escritorios virtuais Comment[ia]=Configura navigation, numero e disposition de scriptorios virtual Comment[id]=Konfigurasikan navigasi, nomor dan tataletak desktop virtual Comment[it]=Configura navigazione, numero e disposizione dei desktop virtuali Comment[ko]=가상 바탕 화면 탐색, 개수, 레이아웃 설정 Comment[lt]=Konfigūruoti virtualių darbalaukių naršymą, skaičių ir išdėstymą Comment[nl]=Navigatie, aantal en indeling van virtuele bureaubladen configureren Comment[nn]=Set opp navigering, nummer og vising av virtuelle skrivebord Comment[pl]=Ustawienia poruszania się, liczby oraz układu wirtualnych klawiatur Comment[pt]=Configura a navegação, número e disposição dos ecrãs virtuais Comment[pt_BR]=Configura a navegação, quantidade e layout das áreas de trabalho virtuais Comment[ru]=Число, расположение и способ переключения рабочих столов Comment[sk]=Nastaviť navigáciu, počet a rozloženie virtuálnych plôch +Comment[sl]=Nastavi krmarjenje, število in razporeditev navideznih namizij Comment[sv]=Anpassa navigering, antal och layout av virtuella skrivbord Comment[uk]=Налаштовування навігації, кількості та компонування віртуальних стільниць Comment[x-test]=xxConfigure navigation, number and layout of virtual desktopsxx Comment[zh_CN]=配置虚拟桌面的导航,数目和布局 Comment[zh_TW]=設定虛擬桌面的導覽、數字與佈局 Icon=preferences-desktop Type=Service X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-Name=kcm_kwin_virtualdesktops X-KDE-ServiceTypes=Plasma/Generic X-Plasma-API=declarativeappletscript X-KDE-FormFactors=desktop X-Plasma-MainScript=ui/main.qml diff --git a/kcmkwin/kwineffects/kcm_kwin_effects.desktop b/kcmkwin/kwineffects/kcm_kwin_effects.desktop index ee78f454f..36804d58a 100644 --- a/kcmkwin/kwineffects/kcm_kwin_effects.desktop +++ b/kcmkwin/kwineffects/kcm_kwin_effects.desktop @@ -1,122 +1,124 @@ [Desktop Entry] Exec=kcmshell5 kcm_kwin_effects Icon=preferences-desktop-effects Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/kwineffects/index.html X-KDE-Library=kcm_kwin_effects X-KDE-PluginKeyword=effects X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=desktopbehavior X-KDE-Weight=50 X-KDE-FormFactors=desktop,tablet Name=Desktop Effects Name[bs]=Efekti površi Name[ca]=Efectes de l'escriptori Name[ca@valencia]=Efectes d'escriptori Name[cs]=Efekty na ploše Name[da]=Skrivebordseffekter Name[de]=Arbeitsflächen-Effekte Name[el]=Εφέ επιφάνειας εργασίας Name[en_GB]=Desktop Effects Name[es]=Efectos del escritorio Name[et]=Töölauaefektid Name[eu]=Mahaigaineko efektuak Name[fi]=Työpöytätehosteet Name[fr]=Effets de bureau Name[gl]=Efectos do escritorio Name[he]=הנפשות שולחן עבודה Name[hu]=Asztali effektusok Name[ia]=Effectos de scriptorio Name[id]=Efek Desktop Name[it]=Effetti del desktop Name[ja]=デスクトップ効果 Name[ko]=데스크톱 효과 Name[lt]=Darbalaukio efektai Name[nb]=Skrivebordseffekter Name[nds]=Schriefdischeffekten Name[nl]=Bureaubladeffecten Name[nn]=Skrivebords­effektar Name[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ Name[pl]=Efekty pulpitu Name[pt]=Efeitos do Ecrã Name[pt_BR]=Efeitos da área de trabalho Name[ro]=Efecte de birou Name[ru]=Эффекты Name[se]=Čállinbeavdeeffeavttat Name[sk]=Efekty plochy Name[sl]=Učinki namizja Name[sr]=Ефекти површи Name[sr@ijekavian]=Ефекти површи Name[sr@ijekavianlatin]=Efekti površi Name[sr@latin]=Efekti površi Name[sv]=Skrivbordseffekter Name[tg]=Таъсирҳои мизи корӣ Name[tr]=Masaüstü Efektleri Name[uk]=Ефекти стільниці Name[x-test]=xxDesktop Effectsxx Name[zh_CN]=桌面特效 Name[zh_TW]=桌面效果 Comment=Configure compositor settings for desktop effects Comment[ca]=Configura l'arranjament del compositor per als efectes de l'escriptori Comment[cs]=Nastavení kompozitoru pro efekty pracovní plochy Comment[da]=Compositor-indstillinger til skrivebordseffekter Comment[de]=Compositor-Einstellungen für Arbeitsflächen-Effekte einrichten Comment[en_GB]=Configure compositor settings for desktop effects Comment[es]=Configurar las preferencias del compositor para los efectos del escritorio Comment[et]=Komposiitori seadistamine töölauaefektide tarbeks Comment[eu]=Konfiguratu konposatzailearen ezarpenak mahaigaineko efektuetarako Comment[fi]=Koostimen asetukset työpöytätehosteille Comment[fr]=Configurer les paramètres du compositeur pour les effets de bureau Comment[gl]=Configurar o compositor para os efectos de escritorio Comment[ia]=Configura preferentias de compositor pro le effectos de scriptorio Comment[id]=Konfigurasikan pengaturan kompositor untuk efek desktop Comment[it]=Configura impostazioni del compositore per gli effetti del desktop Comment[ko]=데스크톱 효과에 사용되는 컴포지터 설정 Comment[lt]=Konfigūruoti darbalaukio efektų kompozitoriaus nuostatas Comment[nl]=Instellingen van compositor configureren voor bureaubladeffecten Comment[nn]=Samansetjarinnstillingar for skrivebordseffektar Comment[pl]=Ustawienia kompozytora dla efektów pulpitu Comment[pt]=Configuração do compositor para os efeitos do ecrã Comment[pt_BR]=Defina as configurações do compositor para os efeitos da área de trabalho Comment[ru]=Настройка движка эффектов рабочего стола Comment[sk]=Nastavenia kompozítora pre efekty plochy +Comment[sl]=Nastavitve upravljalnika skladnje za učinke namizja Comment[sv]=Anpassa sammansättningsinställningar för skrivbordseffekter Comment[uk]=Налаштовування параметрів засобу композиції для ефектів стільниці Comment[x-test]=xxConfigure compositor settings for desktop effectsxx Comment[zh_CN]=配置桌面特效混成器设置 Comment[zh_TW]=設定桌面特效的合成器設定 X-KDE-Keywords=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect X-KDE-Keywords[ca]=kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes d'escriptori,animacions,animacions diverses,efectes en la gestió de les finestres,efecte en el canvi de finestra,efecte en el canvi d'escriptori,animacions,animacions a l'escriptori,controladors,configuració dels controladors,renderització,render,efecte d'inversió,efecte d'aspecte de vidre,efecte de lupa,efecte ajudant del desplaçament,efecte de seguiment del ratolí,efecte de zoom,efecte de difuminat,efecte d'esvaïment,efecte d'esvaïment de l'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de la finestra,efecte en l'inici de la sessió,efecte en sortir de la sessió,efecte de làmpada màgica,efecte d'animació de la minimització,efecte de marca del ratolí,efecte d'apropament,efecte de captura de la pantalla,efecte de full,efecte de diapositiva,efecte de missatges emergents lliscants,efecte de miniatures laterals,translucidesa,efecte de translucidesa,transparència,efecte de geometria de la finestra,efecte de finestres sacsejades,efecte de confirmació d'engegada,efecte de diàleg principal,efecte d'enfosquiment en estar inactiu,efecte d'enfosquiment de la pantalla,efecte de diapositiva prèvia,decoració,efecte per a mostrar els FPS,efecte de mostrar el pintat,efecte de canvi de coberta,efecte de cub de l'escriptori,efecte d'animació del cub de l'escriptori,efecte de quadrícula de l'escriptori,efecte de canvi en roda,efecte de presentació de les finestres,efecte de redimensionat de la finestra,efecte de contrast del fons X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes d'escriptori,animacions,animacions diverses,efectes en la gestió de les finestres,efecte en el canvi de finestra,efecte en el canvi d'escriptori,animacions,animacions en l'escriptori,controladors,configuració dels controladors,renderització,render,efecte d'inversió,efecte d'aspecte de vidre,efecte de lupa,efecte ajudant del desplaçament,efecte de seguiment del ratolí,efecte de zoom,efecte de difuminat,efecte de fosa,efecte de fosa de l'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de la finestra,efecte en l'inici de la sessió,efecte en eixir de la sessió,efecte de làmpada màgica,efecte d'animació de la minimització,efecte de marca del ratolí,efecte d'apropament,efecte de captura de pantalla,efecte de full,efecte de diapositiva,efecte de missatges emergents lliscants,efecte de miniatures laterals,translucidesa,efecte de translucidesa,transparència,efecte de geometria de la finestra,efecte de finestres sacsejades,efecte de retroacció d'inici,efecte de diàleg principal,efecte d'enfosquiment en estar inactiu,efecte d'enfosquiment de la pantalla,efecte de diapositiva prèvia,decoració,efecte per a mostrar els FPS,efecte per a mostrar les zones pintades,efecte de canvi de coberta,efecte de cub de l'escriptori,efecte d'animació del cub de l'escriptori,efecte de graella de l'escriptori,efecte de canvi en roda,efecte de presentació de les finestres,efecte de redimensionat de la finestra,efecte de contrast del fons X-KDE-Keywords[da]=kwin,vindue,vindueshåndtering,effekter,3D-effekter,2D-effekter,grafiske effekter,skrivebordseffekter,animationer,diverse animationer,vindueshåndteringseffekter,effekt til skift af vinduer,effekt til skrivebordsskift,skrivebordsanimationer,drivere,driverindstillinger,rendering,render,invertereffect,kikkerteffekt,forstørrelsesglaseffekt,hægtehjælpereffekt,følg musen-effekt,zoomeffect,sløreffekt,fade-effect,svæve-effect,fremhæv vindue-effekt,login-effekt,log ud-effekt,magisk lampe-effekt,minimer-effekt,musemærke-effekt,skalerind-effekt,skærmbillede-effekt,glide-effekt,glidende pop-op-effekt,gennemsigtighed,transparens,ugennemsigtighed,vinduesgeometri-effekt,wobbly,blævrende vinduer,eye candy,øjeguf,vis FPS-effekt,cube,terning,gitter,baggrundskontrast-effekt X-KDE-Keywords[de]=KWin,Fenster,Verwaltung,Effekt,2D-Effekte,3D-Effekte,Grafische Effekte,Desktopeffekte,Arbeitsflächeneffekte,Animation,Fensterverwaltungs-Effekte,Fensterwechsel-Effekte,Desktop-Wechsel,Arbeitsflächenwechsel,Desktop-Animation,Arbeitsflächen-Animation,Treiber,Treibereinstellung,Rendering,Rendern,Invertierungseffekt,Bildschirmlupeneffekt,Vergrößerungseffekt,Einrasteffekt,Maus folgen,Zoomeffekt,Dashboard,Überblendungseffekt,Gleiteneffekt,Fensterhervorhebungs-Effekt,Anmeldungseffekt,Abmeldungseffekt,Animierter Minimierungseffekt,Mausmarkierungseffekt,Skalierungseffekt,Bildschirmeffekt,Blatteffekt,Folieneffekt,Vorschaueffekt,Durchsichtigkeit,Durchsichtigkeitseffekt,Fenstergeometrieffekt,Effekt Wabernde Fenster,Programmstartanzeigeneffekt,Inaktiveffekt,Bildschirmabdunkelungseffekt,FPS-Effekt,Zeichnungsbereicheffekt, 3D-Fenstergalerieeffekt,Desktopgittereffekt,3D-Fensterstapelumschalteffekt,Fensteranzeigeeffekt,Fenstergrößenänderungseffekt,Hintergrundkonstrasteffekt X-KDE-Keywords[en_GB]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect X-KDE-Keywords[es]=kwin,ventana,gestor,efecto,efectos 3D,efectos 2D,efectos gráficos,efectos del escritorio,animaciones,animaciones diversas,efectos de la gestión de ventanas,efecto de cambio de ventana,efecto de cambio de escritorio,animaciones,animaciones del escritorio,controladores,preferencias del controlador,renderización,renderizar,efecto de inversión,efecto de espejo,efecto de lupa,efecto auxiliar de instantánea,efecto de seguimiento del ratón,efecto de ampliación,efecto borroso,efecto de desvanecimiento,efecto de desvanecimiento del escritorio,efecto de romper en pedazos,efecto de planeo,efecto de resaltar ventanas,efecto de inicio de sesión,efecto de final de sesión,efecto de lámpara mágica,efecto de animación al minimizar,efecto de marcas del ratón,efecto de escalado,efecto de captura de pantalla,efecto de hoja,efecto de deslizamiento,efecto de ventanas emergentes deslizantes,efecto de miniaturas laterales,transparencia,efecto de transparencia,efecto de geometría de las ventanas, efecto de ventanas gelatinosas,efecto de notificación de inicio,efecto de padre de la ventana,efecto de oscurecer inactiva,efecto de oscurecer la pantalla,efecto atrás,efectos atractivos,efecto de mostrar FPS,efecto de mostrar pintura,efecto de selección de ventana en modo carátula,efecto de cubo del escritorio,efecto de animación del cubo del escritorio,efecto de rejilla del escritorio,efecto de selección de ventana en modo cascada,efecto de presentación de ventanas,efecto de cambiar tamaño de las ventanas,efecto de contraste del fondo X-KDE-Keywords[et]=kwin,aken,hakdur,efekt,3D efektid,ruumilised efektid,2D efektid,graafikaefektid,töölauaefektid,animatsioonid,eri animatsioonid,aknahaldusefektid,akna lülitamise efekt,töölaua lülitamise efekt,animatsioonid,töölauaanimatsioonid,draiverid,draiveri seadistused,renderdamine,renderdus,inverteerimisefekt,pikksilmaefekt,suurendusklaasiefekt,tõmbe abistaja efekt,hiire jälgimise efekt,suurendusefekt,vidinavaate efekt,plahvatuseefekt,hääbumisefekt,töölaua kadumise efekt,lagunemise efekt,liuglemisefekt,akna esiletõstmise efekt,sisselogimisefekt,väljalogimisefekt,maagilise laterna efekt,minimeerimisanimatsiooni efekt,hiirega tähistamise efekt,skaleerimisefekt,ekraanipildi efekt,leheefekt,slaidiefekt,liuglevate hüpikakende efekt,tegumiriba pisipiltide efekt,kõrvalasuvate pisipiltide efekt,läbipaistvus,läbipaistvuseefekt,akende geomeetria efekt,vonklevate akende efekt,käivitamise tagasiside efekt,dialoogi eellase efekt,tuhmi mitteaktiivse efekt,tuhmi ekraani efekt,tagasiliugumise efekt,silmarõõm,FPS-i näitamise efekt,joonistamise näitamise efekt,kastina lülitamise efekt,vaiplülitamise efekt,töölauakuubiku efekt, töölauakuubiku animatsiooni efekt,töölauavõrgustiku efekt,pööramisega lülitamise efekt,kontuuriefekt,aktiivsete akende efekt, akende suuruse muutmise efekt X-KDE-Keywords[eu]=kwin,leihoa,kudeatzailea,efektua,3D efektuak,2D efektuak,efektu grafikoak,mahaigaineko efektuak,animazioak,hainbat animazio,leiho kudeaketaren efektuak,leiho-aldatze efektuak,mahaigaina aldatzeko efektua,animazioak,mahaigaineko animazioak,gidariak,gidarien ezarpenak,errendatze,errendatu,alderantzikatu efektua,pantaila-lupa efektua,lupa efektua,atxikitze laguntzaile efektua,jarraitu saguari efektua,zoom efektua,lausotze efektua,desagertze efektua,mahaigain-desagertze efektua,puskatze efektua,irristatze efektua,leiho-nabarmentze efektua,saio-haste efektua,saio-ixte efektua,lanpara magiko efektua,minimizatze-animazio efektua, sagu-marka efektua,eskalatze efektua,pantaila-argazki efektua,orrialde efektua,diapositiba efektua,diapositiba gainerakor efektua,koadro txikiak alboan efektua,zeharrargitasuna,zeharrargitasun efektua,gardentasuna,leiho-geometria efektua,leiho dardartsuak efektua,abio berrelikadura efektua,guraso elkarrizketa-koadro efektua,itzaldu ez-aktiboa efektua,itzaldu pantaila efektua,diapositibak atzera efektua,ikusteko atsegina,atsegina,FPS erakuste efektua,erakutsi pintura efektua,azal aldaketa efektua,kubo-mahaigain efektua,kubo-mahaigain animazio efektua,mahaigain-sareta efektua,perspektiban pilatutako aldatze efektua,aurkeztu leihoak efektua,leihoaren neurri-aldatze efektua,atzealdeko kontraste efektua X-KDE-Keywords[fi]=kwin,ikkuna,hallinta,tehoste,3D-tehosteet,2D-tehosteet,graafiset tehosteet,työpöytätehosteet,animoinnit,eri animoinnit,ikkunanhallintatehosteet,ikkunanvaihtotehoste,työpöydänvaihtotehoste,animoinnit,työpöytäanimoinnit,ajurit,ajuriasetukset,hahmonnus,hahmonna,käänteistehoste,peilitehoste,suurennuslasitehoste,kiinnitysavustajatehoste,hiiren jäljitystehoste,suurennustehoste,sumennustehoste,häivytystehoste,työpöydän häivytystehoste,hajotustehoste,liukutehoste,ikkunan korostustehoste,kirjautumistehoste,uloskirjautumistehoste,taikalampputehoste,pienennyksen animointitehoste,hiiren jälki -tehoste,skaalaustehoste,ruudunkaappaustehoste,sheet effect,liukutehoste,liukuvat ponnahdusikkunat -tehoste,esikatselukuva reunalla -tehoste,läpikuultavuus,läpikuultavuustehoste,läpinäkyvyys,ikkunageometriatehoste,heiluvat ikkunat -tehoste,käynnistyspalautetehoste,kyselyikkunan isäntäikkuna -tehoste,himmennä passiivinen -tehoste,himmennä näyttö -tehoste,liuku taakse -tehoste,silmäkarkki,karkki,näytä FPS -tehoste,näytä näytönpiirto -tehoste,kansivaihtotehoste,työpöytäkuutiotehoste,työpöytäkuutioanimointitehoste,työpöytäruudukkotehoste,kääntövaihtotehoste,näytä ikkunat -tehoste,ikkunan koonmuuttamistehoste,taustakontrastitehoste X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, effet, effets 3D, effets 2D, effets graphiques, effets de bureau, animations, animations variés, effets de gestion des fenêtres, effets de changement de fenêtre, effets de changement de bureau, animations, animation du bureau, pilotes, paramètres du pilote, rendu, rendre, effet d'inversion, effet de verre, effet de loupe, effet d'aide au positionnement, effet de repérage de la souris, effet de zoom, effet de flou, effet de fondu, effet de fondu du bureau, effet d'effondrement, effet de glissement, effet de mise en valeur de la fenêtre, effet de connexion, effet de déconnexion, effet de lampe magique, effet de minimisation de l'application, effet de marque de la souris, effet de gradation, effet de capture d'écran, effet de feuille, effet de glisse, effet d'annotations glissantes, effet vignettes sur le coté, translucidité, effet de translucidité, transparence, effet de géométrie de la fenêtre, effet de fenêtre en gélatine, effet du témoin de démarrage, effet de dialogue parent, effet d'obscurcissement de fenêtre inactive, effet d'obscurcissement du bureau, effet de glissement en arrière, confort visuel, beauté, effet d'affichage du FPS, effet d'affichage des zones peintes, effet de défilement circulaire, effet de bureaux en cube, effet d'animation de cube de bureaux, effet de bureaux en grille, effet d'empilement en perspective, effet de présentation des fenêtres, effet de redimensionnement des fenêtres, effet de contraste du bureau X-KDE-Keywords[gl]=kwin,window,xanela,manager,xestor,effect,efecto,3D effects,efectos 3D,2D effects,efectos 2D,configuración de vídeo,graphical effects,efectos gráficos,efectos visuais,desktop effects,efectos de escritorio,animations,animacións,various animations,animacións diversas,varias animacións,animacións variadas,window management effects,efectos de xestión de xanelas,window switching effect,efecto de cambio de xanela,desktop switching effect,efecto de cambio de escritorio,animations,animacións,desktop animations,animacións de escritorio,animacións dos escritorios,animacións do escritorio,drivers,controlador,controladores,driver settings,configuración dos controladores,configuración do controlador,rendering,renderización,renderizado,renderizamento,render,renderizar,invert effect,inverter un efecto,inverter efecto,reverter un efecto,reverter efecto,looking glass effect,efecto de lupa,efecto lupa,magnifier effect,snap helper effect,track mouse effect,efecto de seguir o rato,efecto de seguimento do rato,zoom effect,efecto de ampliación,blur effect,efecto borroso,fade effect,efecto de esvaer,fade desktop effect,efecto de esvaer o escritorio,fall apart effect,efecto de destrución,glide effect,efecto de brillo,highlight window effect,efecto de realzar a xanela,efecto de resaltar a xanela,efecto de salientar a xanela,efecto de salientar a xanela,login effect,efecto de acceder,logout effect,efecto de saír,magic lamp effect,efecto de lámpada máxica,minimize animation effect,efecto de minimizar,mouse mark effect,efecto de marca co rato,scale in effect,efecto de achegar,efecto de cambia de escala,screenshot effect,efecto de captura,sheet effect,efecto de folla,slide effect,efecto de dispositiva,sliding popups effect,thumbnail aside effect,translucency,transparencia,translucidez,translucency effect,efecto de translucidez,efecto de transparencia,transparency,transparencia,window geometry effect,efecto de xeometría da xanela,efecto de xeometría das xanelas,wobbly windows effect,efecto de xanelas a tremer,startup feedback effect,dialog parent effect,efecto do pai do diálogo,dim inactive effect,dim screen effect,efecto de escurecer,slide back effect,eye candy,candy,show FPS effect,efecto de mostrar os FPS,show paint effect,cover switch effect,desktop cube effect,efecto de cubo de escritorio,efecto do cubo de escritorio,efecto de cubo do escritorio,desktop cube animation effect,desktop grid effect,efecto de grade de escritorios,efecto de grade de escritorios,flip switch effect,efecto de interruptor,efecto de contorno,present windows effect,resize window effect,efecto de cambio de tamaño das xanelas,efecto de contraste de fondo X-KDE-Keywords[hu]=kwin,ablak,kezelő,hatás,3D hatás,2D hatás,grafikai hatások,asztali hatások,animációk,különféle animációk,ablakkezelő hatások,ablakváltó hatások,asztalváltó hatások,animációk,asztali animációk,meghajtók,meghajtó beállítások,leképezés,renderelés,fordított hatás,tükörhatás,nagyító hatás,elkapás segítő hatás,egérkövetés hatás,nagyítás hatás,elmosás,elhalványulás hatás,asztal elhalványulása hatás,széteső hatás,csúszás hatás,ablak kiemelése hatás,belépés hatás,kilépés hatás,varázslámpa hatás,minimalizálás animáció hatás,egérjelölés hatás,méretezés hatás,képernyőkép hatás,munkalap hatás,dia hatás,csúszó felugrók hatás,,bélyegképek félre hatás, áttetszőség,áttetszőség hatás,átlátszóság,ablak geometria hatás,ingó ablak hatás,indulási visszajelzés hatás,párbeszédablak szülő hatás,dim inaktív hatás,dim kijelző hatás,dia vissza hatás,látványelem,édesség,FPS megjelenítése hatás,festék megjelenése hatás,eltakarás váltás hatás,asztal kocka hatás,asztal kockaanimáció hatás,asztal rács hatás,tükrözésváltás hatás,jelenlegi ablakok hatás,ablak átméretezése hatás,háttérkontraszt hatás X-KDE-Keywords[id]=kwin,window,pengelola,efek,efek 3D,efek 2D,efek grafik,efek desktop,animasi,beragam animasi,efek pengelola window,efek beralih window,efek beralih desktop,animasi,animasi desktop,driver,pengaturan driver,rendering,render,efek kebalikan,efek seperti gelas,efek kaca pembesar,efek penunjang jepret,efek lacak mouse,efek pembesaran,efek buram,efek lesap,efek desktop lesap,efek hancur,efek petak,efek window sorot,efek login,efek logout,efek lampu ajaib,efek animasi minimalkan,efek tanda mouse,efek skala,efek cuplikan layar,efek lembar,efek geser,efek sembul geser,efek gambar-mini disamping,translusensi,efek translusensi,transparan,efek geometri window,efek window goyang,efek feedback pemulaian,efek induk dialog,efek layar suram,efek geser mundur,eye candy,candy,efek tampilkan FPS,efek tampilkan lukisan,efek alih kotak,efek alih sampul,efek kubus desktop,efek animasi kubus desktop,efek kisi desktop,efek alih lipat,efek window hadir,efek ubah ukuran window,efek kontras latarbelakang X-KDE-Keywords[it]=kwin,finestra,gestore,effetto,effetti 3D,effetti 2D,effetti grafici,effetti del desktop,animazioni,animazioni varie, effetti del gestore delle finestre,effetto dello scambiafinestre,effetto dello scambiatore di desktop,animazioni,animazioni del desktop,driver,impostazioni driver,rendering,render,effetto invertito,effetto vetro,effetto lente,effetto snap helper,effetto traccia mouse,effetto ingrandimento, effetto sfocatura,effetto dissolvenza,effetto dissolvenza desktop,effetto caduta,effetto planatura,effetto evidenziazione finestra,effetto schermata di accesso, effetto disconnessione,effetto lampada magica,effetto animazione di minimizzazione,effetto marcatura mouse, effetto scalatura,effetto schermata,effetto foglio,effetto diapositiva,effetto scivolamento,effetto miniature nella barra delle applicazioni,effetto miniatura su un lato,translucenza,effetto translucenza, trasparenza,effetto geometria finestra,effetto finestre tremolanti,effetto segnale di avvio,effetto finestra madre,effetto oscura finestra inattiva,effetto oscura schermo,effetto scivola all'indietro,gradevole,effetto gradevole,effetto mostra FPS,effetto ridisegno,effetto scambio cubi,effetto scambio copertina,effetto cubi del desktop,effetto animazione cubi del desktop,effetto griglia desktop,effetto scambiatore con inversione,effetto riquadro,effetto finestra presente,effetto ridimensionamento finestra,effetto contrasto dello sfondo X-KDE-Keywords[ko]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,dashboard effect,explosion effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale in effect,screenshot effect,sheet effect,slide effect,sliding popups effect,taskbar thumbnails effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,box switch effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,outline effect,present windows effect,resize window effect,창,관리자,효과,3D 효과,2D 효과,그래픽 효과,데스크톱 효과,애니메이션,창 관리자,창 관리자 효과,데스크톱 전환,데스크톱 전환 효과,드라이버,드라이버 설정,렌더링,렌더링 설정,애니메이션 속도,투명 유리 효과,확대 축소 효과,흐림 효과,대시보드 효과,페이드 효과,로그인 효과,창 강조 효과,글라이드 효과,로그아웃 효과,램프 효과,시트 효과,최소화 효과,최대화 효과,팝업 효과 X-KDE-Keywords[lt]=kwin,langas,langai,langų,langu,tvarkytuvė,tvarkytuve,efektas,efektai,3D efektai,2D efektai,trimačiai efektai,trimaciai efektai,dvimačiai efektai,dvimaciai efektai,grafiniai efektai,grafikos efektai,darbalaukio efektai,darbastalio efektai,animacijos,įvairios animacijos,ivairios animacijos,langų tvarkymo efektai,langu tvarkymo efektai,langų valdymo efektai,langu valdymo efektai,langų perjungimo efektai,langu perjungimo efektai,langų perjungiklio efektai,langu perjungiklio efektai,darbalaukio perjungimo efektai,darbastalio perjungimo efektai,darbalaukio perjungiklio efektai,darbastalio perjungiklio efektai,animacijos,darbalaukio animacijos,darbastalio animacijos,tvarkyklės,tvarkykles,tvarkyklė,tvarkykle,tvarkyklės nustatymai,tvarkykles nustatymai,tvarkyklės nuostatos,tvarkykles nuostatos,vaizdavimas,atvaizdavimas,invertavimo efektas,invertavimas,didinamojo stiklo efektas,didinamasis stiklas,didintuvo efektas,didintuvas,pritraukimo pagelbiklio efektas,traukimo pagelbiklio efektas,pritraukimo pagelbiklis,traukimo pagelbiklis,sekti pelę,sekti pele,pelės sekimas,peles sekimas,didinimo efektas,didinimas,suliejimo efektas,suliejimas,išblukimo efektas,išblukimas,isblukimo efektas,isblukimas,atsiradimo efektas,atsiradimas,išnykimo efektas,isnykimo efektas,išnykimas,isnykimas,darbalaukio išblukimo efektas,darbalaukio isblukimo efektas,darbastalio išblukimo efektas,darbastalio isblukimo efektas,subyrėjimo efektas,subyrejimo efektas,subyrėjimas,subyrejimas,byrėjimas,byrejimas,sklandymo efektas,sklandymas,lango paryškinimo efektas,lango paryskinimo efektas,langų paryškinimo efektas,langu paryskinimo efektas,lango paryškinimas,lango paryskinimas,langų paryškinimas,langu paryskinimas,prisijungimo efektas,atsijungimo efektas,magiškos lempos efektas,magiskos lempos efektas,magiška lempa,magiska lempa,suskleidimo animacijos efektas,sumažinimo animacijos efektas,sumazinimo animacijos efektas,suskleidimas,sumažinimas,sumazinimas,žymėjimo pele efektas,zymejimo pele efektas,žymėjimas pele,zymejimas pele,mastelio keitimo efektas,mastelio keitimas,ekrano kopijos efektas,ekrano kopija,ekranvaizdžio efektas,ekranvaizdzio efektas,lapo efektas,lapas,slydimo efektas,slydimas,slidimas,slystančių iškylančiųjų langų efektas,slystanciu iskylanciuju langu efektas,slystantys iškylantieji langai,slystantys iskylantieji langai,miniatiūros šone efektas,miniatiuros sone efektas,dalinis permatomumas,dalinio permatomumo efektas,permatomumas,skaidrumas,lango geometrijos efektas,lango geometrija,svirduliuojančių langų efektas,svirduliuojanciu langu efektas,svirduliuojantys langai,paleidimo grįžtamojo ryšio efektas,paleidimo griztamojo rysio efektas,paleidimo grįžtamasis ryšys,paleidimo griztamasis rysys,paleisties grįžtamasis ryšys,paleisties griztamasis rysys,dialogo viršesnio efektas,dialogo virsesnio efektas,dialogo viršesnis,dialogo virsesnis,pasyviųjų pritemdymo efektas,pasyviuju pritemdymo efektas,pasyviųjų pritemdymas,pasyviuju pritemdymas,pasyvių pritemdymo efektas,pasyviu pritemdymo efektas,pasyvių pritemdymas,pasyviu pritemdymas,ekrano pritemdymo efektas,ekrano pritemdymas,slydimo atgal efektas,slydimas atgal,grožybės,grozybes,gražu,grazu,FPS rodymo efektas,FPS rodymas,kadr./sek.,kadr/sek,kadr./s,kadr/s,kadr./sek. rodymas,piešimo rodymo efektas,piesimo rodymo efektas,piešimo rodymas,piesimo rodymas,viršelių perjungiklio efektas,viršelio perjungiklio efektas,virseliu perjungiklio efektas,viršelių perjungiklis,virseliu perjungiklis,višelių perjungimas,virseliu perjungimas,darbalaukio kubo efektas,darbastalio kubo efektas,darbalaukio kubas,darbastalio kubas,darbalaukio kubo animacijos efektas,darbastalio kubo animacijos efektas,darbalaukio kubo animacija,darbastalio kubo animacija,darbalaukio tinklelio efektas,darbastalio tinklelio efektas,darbalaukio tinklelis,darbastalio tinklelis,kartotekos pavidalo langų perjungiklio efektas,kartotekos pavidalo langu perjungiklio efektas,kartotekos pavidalo langų perjungiklis,kartotekos pavidalo langu perjungiklis,langų pateikimo efektas,langu pateikimo efektas,langų pateikimas,langu pateikimas,langų dydžio keitimo efektas,lango dydžio keitimo efektas,langu dydzio keitimo efektas,lango dydzio keitimo efektas,fono kontrasto efektas,fono kontrastas X-KDE-Keywords[nl]=kwin,venster,beheerder,effect,3D effecten,2D effecten,grafische effecten,bureaubladeffecten,animaties,verrschillende animaties,vensterbeheereffecten,vensteromschakeleffect,bureaublad-omschakeleffect,animaties,bureaubladanimaties,stuurprogramma's,stuurprogramma-instellingen,rendering,render,inversieeffect,vergrootglaseffect,vergrotingseffect,snaphelpereffect,trackmuiseffect,zoomeffect,vervagingseffect,uitvaageffect,uitvaagbureaubladeffect,uiteenvaleffect,glijeffect,vensteraccentueringseffect,aanmeldeffect,afmeldeffect,magische lampeffect,animatie-effect minimaliseren,muismarkeringseffect,schaaleffect,schermafdrukeffect,bladeneffect,dia-effect,glijdende pop-upseffect,miniatuur-opzijeffect,doorzichtigheid,doorzichtigheidseffect,transparantie,vensterafmetingeneffect,wiebelende vensterseffect,opstartterugkoppeleffect,dialoogoudereffect,dim bij inactiviteitseffect,dim het schermeffect,schuif terugeffect,oogstrelend,snoepgoed,FPS toneneffect,verf toneneffect,vak deksel schakelaareffect,bureaublad kubuseffect,bureaublad kubus animatie-effect,bureaubladrastereffect,omschakeleffect,huidig venstereffect, wijzig grootte van venstereffect, achtergrondcontrasteffect X-KDE-Keywords[nn]=kwin,vindauge,handsamar,vindaugshandsamar,effekt,3D-effektar,2D-effektar,grafiske effektar,skrivebordeffektar,animasjonar,ymse animasjonar,vindaugsbyteeffektar,effektar ved skrivebordbyte,animasjonar,skrivebordsanimasjonar,drivarar,drivarinnstillingar,oppteikning,oppteiknar,inverteringseffekt,spegeleffekt,lupeeffekt,gripehjelpareffekt,musmerkeeffekt,forstørringseffekt,zoomeffekt,sløringseffekt,uklar-effekt,kontrollpulteffekt,uttoningseffekt,skrivebordtoningseffekt,gå-i-knas-effekt,glidareffekt,framhev vindauge-effekt,innloggingseffekt,utloggingsefffekt,magisk lampe-effekt,animasjonseffekt ved vindaugsminimering,musmerkeeffekt,skaleringseffekt,skjermdumpeffekt,ark-effekt,lysbileteffekt,glidande sprettopp-effekt,effekt for minibilete på sida,gjennomsiktseffekt,gjennomsikt,vindaugsgeometri-effekt,vaklande vindauge-effekt,effekt for oppstartsmelding,effekt for forelderdialog,effekt for mørk inaktiv,effekt for mørk skjerm,gli tilbake-effekt,augesnop,vis FPS-effekt,vis målingseffekt,omslagsbyteeffekt,skrivebordskube-effekt,effekt for animert skrivebordskube,effekt for skrivebordrutenett,effekt for flipp-byte,presenter vindauge-effekt,vindaugsskaleringseffekt,bakgrunnskontrast-effekt X-KDE-Keywords[pl]=kwin,okno,menadżer,efekt,efekty 3D,efekty 2D,efekty graficzne,efekty pulpitu,animacje,różne animacje,efekty zarządzania oknami,efekty przełączania okien,efekty przełączania pulpitów,animacje,animacje pulpitu,sterowniki,ustawienia sterowników,renderowania, efekt odwrócenia,szkło powiększające,efekt powiększenia,efekt pomocnika przyciągania, efekt śledzenia myszy,efekt przybliżenia,rozmycie,tablica,efekt eksplozji,efekt zanikania,efekt zanikania pulpitu,efekt rozpadania,efekt slajdu,efekt podświetlania okna, efekt logowania,efekt wylogowywania,efekt magicznej lampy,efekt animacji minimalizacji, efekt znacznika myszy,efekt skalowania,efekt zrzutu ekranu,efekt arkusza,efekt slajdu,efekt wysuwających się elementów wyskakujących,efekt prześwitywania,przezroczystość,efekt geometrii okna,efekt chwiejnych okien,efekt odczuć przy starcie,efekt okna rodzica,efekt przyciemniania nieaktywnych,efekt przyciemniania ekranu,efekt przesuwania do tył,efekt pokazania ilości klatek na sekundę X-KDE-Keywords[pt]=kwin,janela,gestor,composição,efeito,efeitos 3D,efeitos 2D,OpenGL,XRender,configuração do vídeo,efeitos gráficos,efeitos do ecrã,animações,animações diversas,efeitos de gestão das janelas,efeito de mudança de janelas,efeito de mudança de ecrãs,animações,velocidade da animação,animações do ecrã,controladores,configuração dos controladores,desenho,efeito de inversão,efeito de lupa,efeito de lente,efeito de ajuda no ajuste, efeito de seguimento do rato,efeito de ampliação,efeito de borrão,efeito de quadro,efeito de explosão,efeito de desvanecimento,efeito de desvanecimento do ecrã,efeito de destruição,efeito de deslizamento,efeito de realce da janela,efeito na autenticação,efeito do encerramento,efeito de lâmpada mágica,efeito de animação na minimização,efeito de marcação com rato,efeito de escala,efeito de captura do ecrã,efeito de folha,efeito de mensagens deslizantes,efeito de miniaturas na barra de tarefas,efeito de miniaturas laterais,efeito de janelas a tremer,efeito do arranque inicial,efeito da janela-mãe,efeito de escurecimento de janelas inactivas,efeito de deslize para trás,efeitos visuais,beleza,efeito de apresentação das IPS,efeito de pintura,efeito de mudança em caixa,efeito de mudança de capas, efeito de animação do cubo do ecrã,efeito de grelha do ecrã,efeito de mudança por viragem,efeito de destaque,efeito de apresentação das janelas,efeito de dimensionamento das janelas,efeito de contraste do fundo X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,efeito,efeitos 3D,efeitos 2D,efeitos gráficos,efeitos da área de trabalho,animações,animações diversas,efeitos do gerenciamento de janelas,efeito de mudança de janelas,efeito de mudança de área de trabalho,animações da área de trabalho,drivers,configuração dos drivers,desenho,renderização,efeito de inversão,efeito de lupa,efeito de lente,efeito de ajuda no ajuste,efeito de rastreamento do mouse,efeito de ampliação,efeito de borrão,efeito de escurecimento,efeito de escurecimento da área de trabalho,efeito de destruição,efeito de deslizamento,efeito de realce da janela,efeito na autenticação,efeito de encerramento de sessão,efeito de lâmpada mágica,efeito de animação na minimização,efeito de marcação com mouse,efeito em escala,efeito de captura de tela,efeito de folha,efeito de slide,efeito de mensagens deslizantes,efeito de miniaturas na barra de tarefas,transparência,efeito de transparência,efeito de geometria de janelas,efeito de janelas trêmulas,efeito do inicialização,efeito da janela-mãe,efeito de escurecimento de janelas inativas,efeito de deslize para trás,efeitos visuais,beleza,efeito de apresentação de FPS,efeito de pintura,efeito de mudança de capas,efeito de animação do cubo da área de trabalho,efeito de grade da área de trabalho,efeito de mudança em pilha,efeito de apresentação das janelas,efeito de dimensionamento das janelas,efeito de contraste de fundo X-KDE-Keywords[ru]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,эффекты рабочего стола,графические эффекты,рендеринг,параметры видео,настройка видео,трёхмерные эффекты,двумерные эффекты,эффекты управления окнами,эффекты диспетчера окон,анимация куба рабочих столов,плавная смена рабочих столов,прокрутка,анимация всплывающих окон,анимация появления окна,вход в систему,завершение сеанса,завершение работы,колышущиеся окна,болтающиеся окна,колыхание окон,край экрана,лист,анимация распахивания,анимация максимизации,максимизация окна,распахивание окна,миниатюры окон сбоку,миниатюры окон на краю экрана,полупрозрачность окон,размытие фона,размывание фона,распад закрывающихся окон,растворение закрывающихся окон,рисование на экране,рисование мышью на экране,скольжение окон,анимация сворачивания,сворачивание окон,волшебная лампа,график производительности,производительность эффектов,подсветка отрисовки,подсветка рендеринга,подсветка обновляемых частей экрана,анимация щелчка мышью,инверсия цветов,инвертирование цветов,поиск курсора мыши,разметка экрана,сетка на экране,линейки на экране,экранная разметка,экранная сетка,линза,искажение линзой,лупа,увеличение области экрана,масштаб рабочего стола,изменение масштаба рабочего стола,управление окнами,специальные возможности,инструменты,внешний вид,анимация переключения рабочих столов,все окна,просмотр всех окон,все рабочие столы,просмотр всех рабочих столов,изменение размера окна,масштабирование текстуры окна,куб с рабочими столами,перелистывание окон,управление фокусом,затемнение неактивных окон,затемнение основного окна,затемнение под диалогом,затемнение экрана при административной задаче,соскальзывание окон при смене фокуса,контрастность фона X-KDE-Keywords[sk]=kwin, okno, manažér, kompozícia, efekt, 3D efekty, 2D efekty, OpenGL, XRender,nastavenia obrazu, grafické efekty, desktop efekty, animácie, rôzneanimácie, efekty správa okien, okno prepínanie efektov, stolnýspínacie efekt, animácie, animácie rýchlosť, stolný animácie, ovládače,nastavenie ovládača, renderovanie, poskytnúť, invertný skutočnosti zrkadlá účinok,lupa efekt, snap pomocník efekt, trať myš efekt, zoom efekt, rozmazaniuúčinok, prístrojová doska efekt, výbuch efekt, fade efekt, fade stolný efekt,rozpadnúť účinok, zostupovej efekt, zvýraznenie okno efekt, efekt prihlásenie, odhlásenieúčinok, čarovnú lampu účinok, minimálny efekt animácie, myši značky efekt, mierkav skutočnosti, screenshot efekt, list efekt, snímka efekt, posuvné vyskakovacie okná účinok,miniatúry na hlavnom paneli efekt, náhľad stranou efekt, priesvitnosť, translucencieúčinok, transparentnosť, okno geometrie efekt, vratkú okná efekt, uvedenie do prevádzkyspätná väzba, dialóg rodič efekt, matný efekt neaktívny, stlmiť obrazovku efekt,posunutím zadnej efekt, pastva pre oči, cukrík zobraziť FPS efekt, zobrazovať farby efekt, boxprepínač efekt, kryt prepínače účinok, desktop, desktop cube efekt kocky animácieúčinok, Desktop Grid efekt, flip switch efekt, obrys účinok, súčasné okná účinok, zmena veľkosti okna efekt, kontrast pozadie efekt +X-KDE-Keywords[sl]=kwin,upravljalnik oken,učinek,učinki 3d,učinki 2d,grafični učinki,namizni učinki,animacije,upravljanje z okni,preklapljanje oken,preklapljanje namizij,namizne animacije,gonilniki,izrisovanje,upodabljanje,obrni,povečevalno steklo,pripenjalni pomagalnik,sledenje miški,približanje,zabriši,eksplozija,pojemanje,pojemanje namizja,razpad,drsenje,poudari okno,učinek prijave,učinek odjave,čarobna svetilka,animacija skrčenja,risanje,animirano pojavljanje,zaslonska slika,list,drsenje,drseča pojavna okna,sličice za opravilno vrstico,sličica ob strani,prosojnost,prozornost,geometrija okna,majava okna,odziv zagona,nadrejeno pogovorno okno,potemni nedejavno,potemni zaslon,zdrs v ozadje,vidni bonbončki,pokaži sličice na sekundo,izrisovanje,preklapljanje - škatla,preklapljanje - ovitki,kocka z namizji,animacija kocka z namizji,mreža namizij,preklapljanje - sklad,oris,predstavi okna,spreminjanje velikosti okna X-KDE-Keywords[sv]=kwin,fönster,hanterare,effekt,3D-effekter,grafiska effekter,skrivbordseffekter,animeringar,diverse animeringar,fönsterhanteringseffekter,fönsterbyteseffekt,skrivbordsbyteseffekt,skrivbordsanimeringar,drivrutiner,drivrutininställningar,återgivning,återge,inverteringseffekt,förstoringsglaseffekt,förstoringseffekt,låshjälpeffekt,musföljningseffekt,zoomeffekt,suddighetseffekt,explosionseffekt,borttoningseffekt,skrivbordsborttoningseffekt,sönderfallseffekt,glidningseffekt,fönstermarkeringseffekt,inloggningseffekt,utloggningseffekt,magisk lampeffekt,minimeringsanimeringseffekt,musmarkeringseffekt,inskalningseffekt,skärmbildseffekt,bladeffekt,skjuteffekt,glidande ruteffekt,miniatyrbilder i aktivitetsfältet,miniatyrbild vid sidan om,genomskinlighet,genomskinlighetseffekt,fönstergeometrieffekt,ostadiga fönstereffekt,startgensvarseffekt,dialogrutors ägareffekt,dämpa inaktiva effekt,dämpa skärmen effekt,glid tillbaka effekt,ögongodis,godis.visa ramar/s effekt, visa uppritningseffekt,byte med ruta effekt,skrivbordskubeffekt,animeringseffekt för skrivbordskub,skrivbordsrutnätseffekt,blädderbyteseffekt,befintliga fönstereffekt,ändra fönsterstorlekseffekt,bakgrundskontrasteffekt X-KDE-Keywords[uk]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale in effect,screenshot effect,sheet effect,slide effect,sliding popups effect,taskbar thumbnails effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,box switch effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,outline effect,present windows effect,resize window effect,вікно,керування вікнами,менеджер вікон,ефект,просторовий,плоский,параметри відео,графічні ефекти,анімації,анімація,перемикання вікон,драйвери,параметри драйверів,показ,відтворення,інвертування,інверсія,збільшувальне скло,збільшення,прилипання,шлейф за вказівником,шлейф,масштабування,масштаб,зміна розмірів,розмивання,панель,згасання,поява,ковзання,підсвічування,підсвічування вікон,вихід,магічна лампа,чарівна лампа,джин,аркуші,стос,знімок екрана,мініатюри панелі задач,мініатюри,прозорість,ефект прозорості,желе,желейні вікна,супровід запуску,стрибунець,притлумлення,сірість,прикраси,показ частоти,малювання,обкладинки,стрибання,контур,поточні вікна,зміна розмірів X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxgraphical effectsxx,xxdesktop effectsxx,xxanimationsxx,xxvarious animationsxx,xxwindow management effectsxx,xxwindow switching effectxx,xxdesktop switching effectxx,xxanimationsxx,xxdesktop animationsxx,xxdriversxx,xxdriver settingsxx,xxrenderingxx,xxrenderxx,xxinvert effectxx,xxlooking glass effectxx,xxmagnifier effectxx,xxsnap helper effectxx,xxtrack mouse effectxx,xxzoom effectxx,xxblur effectxx,xxfade effectxx,xxfade desktop effectxx,xxfall apart effectxx,xxglide effectxx,xxhighlight window effectxx,xxlogin effectxx,xxlogout effectxx,xxmagic lamp effectxx,xxminimize animation effectxx,xxmouse mark effectxx,xxscale effectxx,xxscreenshot effectxx,xxsheet effectxx,xxslide effectxx,xxsliding popups effectxx,xxthumbnail aside effectxx,xxtranslucencyxx,xxtranslucency effectxx,xxtransparencyxx,xxwindow geometry effectxx,xxwobbly windows effectxx,xxstartup feedback effectxx,xxdialog parent effectxx,xxdim inactive effectxx,xxdim screen effectxx,xxslide back effectxx,xxeye candyxx,xxcandyxx,xxshow FPS effectxx,xxshow paint effectxx,xxcover switch effectxx,xxdesktop cube effectxx,xxdesktop cube animation effectxx,xxdesktop grid effectxx,xxflip switch effectxx,xxpresent windows effectxx,xxresize window effectxx,xxbackground contrast effectxx X-KDE-Keywords[zh_CN]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,explosion effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,窗口,管理,特效,3D 特效,2D 特效,图形特效,桌面特效,动画,窗口管理特效,窗口切换特效,桌面切换特效,桌面动画,驱动,去掉设置,渲染,反色,放大镜特效,鼠标跟踪,缩放特效,模糊特效,渐变特效,破碎特效,滑动特效,高亮窗口,登录特效,注销特效,神灯特效,最小化动画,鼠标标记,截屏,飘落,滑动弹出窗口,缩略图置边,透明特效,摇摆窗口,启动反馈特效,黯淡对话框特效,黯淡屏幕特效,视觉效果,显示 FPS 特效,显示绘制区域特效,封面切换特效,桌面立方体特效,桌面立方体动画特效,翻转切换特效,展示窗口特效,调整窗口大小特效,背景对比特效 X-KDE-Keywords[zh_TW]=kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect diff --git a/kcmkwin/kwinoptions/focus.ui b/kcmkwin/kwinoptions/focus.ui index 735f81c05..d958008d4 100644 --- a/kcmkwin/kwinoptions/focus.ui +++ b/kcmkwin/kwinoptions/focus.ui @@ -1,265 +1,298 @@ KWinFocusConfigForm 0 0 600 500 Qt::AlignHCenter|Qt::AlignTop Window &activation policy: - windowFocusPolicyCombo + windowFocusPolicy - + With this option you can specify how and when windows will be focused. Click to focus Click to focus (mouse precedence) Focus follows mouse Focus follows mouse (mouse precedence) Focus under mouse Focus strictly under mouse &Delay focus by: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - delayFocus + kcfg_DelayFocusInterval - + This is the delay after which the window the mouse pointer is over will automatically receive focus. ms 0 3000 100 Focus &stealing prevention: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - focusStealing + kcfg_FocusStealingPreventionLevel - + <html><head/><body><p>This option specifies how much KWin will try to prevent unwanted focus stealing caused by unexpected activation of new windows. (Note: This feature does not work with the <span style=" font-style:italic;">Focus under mouse</span> or <span style=" font-style:italic;">Focus strictly under mouse</span> focus policies.) </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">None:</span> Prevention is turned off and new windows always become activated.</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Low:</span> Prevention is enabled; when some window does not have support for the underlying mechanism and KWin cannot reliably decide whether to activate the window or not, it will be activated. This setting may have both worse and better results than the medium level, depending on the applications.</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Medium:</span> Prevention is enabled.</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">High:</span> New windows get activated only if no window is currently active or if they belong to the currently active application. This setting is probably not really usable when not using mouse focus policy.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Extreme:</span> All windows must be explicitly activated by the user.</li></ul><p>Windows that are prevented from stealing focus are marked as demanding attention, which by default means their taskbar entry will be highlighted. This can be changed in the Notifications control module.</p></body></html> None Low Medium High Extreme Raising windows: - + When this option is enabled, the active window will be brought to the front when you click somewhere into the window contents. To change it for inactive windows, you need to change the settings in the Actions tab. &Click raises active window - + When this option is enabled, a window in the background will automatically come to the front when the mouse pointer has been over it for some time. &Raise on hover, delayed by: - + This is the delay after which the window that the mouse pointer is over will automatically come to the front. ms 0 3000 100 Multiscreen behavior: - + When this option is enabled, the active Xinerama screen (where new windows appear, for example) is the screen containing the mouse pointer. When disabled, the active Xinerama screen is the screen containing the focused window. By default this option is disabled for Click to focus and enabled for other focus policies. Active screen follows &mouse - + When this option is enabled, focus operations are limited only to the active Xinerama screen &Separate screen focus 280 0 Window activation policy description Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true Qt::Vertical 20 40 KComboBox QComboBox
kcombobox.h
- + + + kcfg_AutoRaise + toggled(bool) + kcfg_AutoRaiseInterval + setEnabled(bool) + + + 338 + 189 + + + 485 + 189 + + + + + kcfg_AutoRaise + toggled(bool) + kcfg_ClickRaise + setDisabled(bool) + + + 338 + 189 + + + 333 + 155 + + + +
diff --git a/kcmkwin/kwinoptions/kwinactions.desktop b/kcmkwin/kwinoptions/kwinactions.desktop index 163a54c20..3d515a348 100644 --- a/kcmkwin/kwinoptions/kwinactions.desktop +++ b/kcmkwin/kwinoptions/kwinactions.desktop @@ -1,114 +1,116 @@ [Desktop Entry] Icon=preferences-system-windows-action Type=Service X-KDE-ServiceTypes=KCModule Exec=kcmshell5 kwinactions X-DocPath=kcontrol/windowbehaviour/index.html#titlebar-actions Icon=preferences-system-windows-actions X-KDE-Library=kcm_kwinoptions X-KDE-PluginKeyword=kwinactions Name=Window Actions Name[ca]=Accions de la finestra Name[cs]=Činnosti oken Name[da]=Vindueshandlinger Name[de]=Fensteraktionen Name[en_GB]=Window Actions Name[es]=Acciones de ventanas Name[et]=Akna toimingud Name[eu]=Leihoetako ekintzak Name[fi]=Ikkunan toiminnot Name[fr]=Actions de la fenêtre Name[gl]=Accións da xanela Name[ia]=Actiones de fenestra Name[id]=Aksi Window Name[it]=Azioni delle finestre Name[ko]=창 동작 Name[lt]=Langų veiksmai Name[nl]=Vensteracties Name[nn]=Handlingar for vindauge Name[pl]=Zachowanie okien Name[pt]=Acções das Janelas Name[pt_BR]=Ações da janela Name[ru]=Действия с окнами Name[sk]=Akcie okna +Name[sl]=Dejavnosti oken Name[sv]=Fönsteråtgärder Name[uk]=Дії з вікнами Name[x-test]=xxWindow Actionsxx Name[zh_CN]=窗口动作 Name[zh_TW]=視窗動作 Comment=Configure mouse actions for windows and titlebars Comment[ca]=Configura les accions de ratolí per a les finestres i les barres de títol Comment[cs]=Nastavení činností myši na oknech a pruhu titulku Comment[da]=Indstil mushandlinger for vinduer og titellinjer Comment[de]=Mausaktionen für Fenster und Titelleisten einrichten Comment[en_GB]=Configure mouse actions for windows and titlebars Comment[es]=Configurar las acciones del ratón para las ventanas y las barras de títulos Comment[et]=Hiiretoimingute seadistamine akendes ja tiitliribadel Comment[eu]=Konfiguratu saguaren ekintzak leihoekin eta titulu-barrekin Comment[fi]=Ikkunoiden ja otsikkopalkkien hiiritoimintojen asetukset Comment[fr]=Configurer les actions de la souris pour les fenêtres et barres de titres Comment[gl]=Configurar as accións do rato para xanelas e barras de título Comment[ia]=Configura actiones de mus per fenestras e barras de titulo Comment[id]=Konfigurasikan aksi mouse untuk window dan bilah-judul Comment[it]=Configura azioni del mouse per finestre e barre del titolo Comment[ko]=창과 제목 표시줄 마우스 동작 설정 Comment[lt]=Konfigūruoti pelės veiksmus langams ir antraštės juostoms Comment[nl]=Muisacties voor vensters en titelbalken configureren Comment[nn]=Set opp musehandlingar for vindauge og tittellinjer Comment[pl]=Ustawienia działań myszy dla okien i pasków tytułu Comment[pt]=Configurar as acções do rato para as janelas e barras do título Comment[pt_BR]=Configura as ações do mouse para as janelas e barras de títulos Comment[ru]=Настройка действий для окон и их заголовков Comment[sk]=Nastavenie akcií myši pre okná a záhlavia +Comment[sl]=Nastavi aktivnosti miške za okna in naslovne vrstice Comment[sv]=Anpassa musåtgärder för fönster och namnlister Comment[uk]=Налаштовування керування мишею для вікон та смужок заголовків Comment[x-test]=xxConfigure mouse actions for windows and titlebarsxx Comment[zh_CN]=配置窗口和标题栏的鼠标动作 Comment[zh_TW]=設定視窗及標題列的滑鼠動作 X-KDE-Keywords=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize X-KDE-Keywords[bs]=sjena,povećali,povećala,smanjiti,umanjiti,sniziti,izbornik operacija,naslovnica,promjena veličine X-KDE-Keywords[ca]=ombra,maximitza,maximitza,minimitza,minimitza,abaixa,menú d'operacions,barra de títol,redimensiona X-KDE-Keywords[ca@valencia]=ombra,maximitza,maximitza,minimitza,minimitza,abaixa,menú d'operacions,barra de títol,redimensiona X-KDE-Keywords[da]=skyg,maksimer,minimer,nedre,operationsmenu,titellinje,ændr størrelse X-KDE-Keywords[de]=Fenstermenü,Fensterheber,Maximieren,Minimieren,Nach oben/unten,Titelleiste,Größe ändern X-KDE-Keywords[el]=σκιά,μεγιστοποίηση,μεγιστοποίηση,ελαχιστοποίηση,ελαχιστοποίηση, χαμηλότερα,μενού λειτουργιών,γραμμή τίτλου,αλλαγή μεγέθους X-KDE-Keywords[en_GB]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize X-KDE-Keywords[es]=sombra,maximizar,maximizar,minimizar,minimizar,inferior,menú de operaciones,barra de título,cambio de tamaño X-KDE-Keywords[et]=varjamine,peitmine,maksimeerimine,minimeerimine,allakerimine,üleskerimine,menüü,tiitliriba,suuruse muutmine X-KDE-Keywords[eu]=bildu,maximizatu,ikonotu,jaitsi,eragiketa-menua,titulu-barra,tamainaz aldatu X-KDE-Keywords[fi]=varjosta,rullaa,suurenna,pienennä,laske,toimintovalikko,otsikkopalkki,muuta kokoa X-KDE-Keywords[fr]=ombre, maximiser, maximise, minimiser, minimise, menu des opérations, barre de titre, redimensionner X-KDE-Keywords[ga]=scáth,scáthaigh,uasmhéadaigh,íosmhéadaigh,íoslaghdaigh,laghdaigh,roghchlár oibríochta,barra teidil,athraigh méid X-KDE-Keywords[gl]=sombra,sombrear,maximizar,minimizar,recoller,menú de operacións, barra de título, redimensionar X-KDE-Keywords[hu]=árnyék,maximalizálás,maximalizálás,minimalizálás,minimalizálás,alacsonyabb,műveletek menü,címsáv,átméretezés X-KDE-Keywords[ia]=tinta,maximisa,maximisa,minimisa,minimisa,plus basse,menu de operationes,barra de titulo, redimensionar X-KDE-Keywords[id]=bayangan,maksimalkan,maksimalkan,minimalkan,minimalkan,ke bawah,menu operasi,titlebar,ubah ukuran X-KDE-Keywords[it]=ombra,massimizza,minimizza,abbassa,menu operazioni,barra del titolo,ridimensiona X-KDE-Keywords[kk]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize X-KDE-Keywords[km]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize X-KDE-Keywords[ko]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,최대화,최소화,제목 표시줄,크기 조정 X-KDE-Keywords[lt]=pridengti,išskleisti,isskleisti,išdidinti,isdidinti,suskleisti,sumažinti,sumazinti,nuleisti į antrą planą,nuleisti i antra plana,operacijų meniu,operaciju meniu,antraštės juosta,antrastes juosta,keisti dydį,keisti dydi X-KDE-Keywords[nb]=rull,maksimer,minimer,senk,handlinger,meny,tittellinje,endre størrelse X-KDE-Keywords[nds]=Inrullen,maximeren,minimeren,na achtern,Akschonenmenü,Titelbalken,Finsternmenü,Grött ännern X-KDE-Keywords[nl]=verdonkeren,maximaliseren,minimaliseren,naar onderen,bedieningsmenu,titelbalk,grootte wijzigen X-KDE-Keywords[nn]=rull,fald saman,fald ut,samanfalding,maksimer,minimer,senk,handlingar,meny,tittellinje,storleiksendring X-KDE-Keywords[pl]=zwiń,maksymalizuj,minimalizuj,obniż,operacje na menu,pasek tytułu,zmień rozmiar X-KDE-Keywords[pt]=enrolar,maximizar,minimizar,baixar,menu de operações,barra de título,dimensionar X-KDE-Keywords[pt_BR]=enrolar,maximizar,minimizar,baixar,menu de operações,barra de título,redimensionar X-KDE-Keywords[ru]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,свернуть,распахнуть,убрать вниз,меню операций,меню действий,заголовок окна,заголовок,изменить размер X-KDE-Keywords[sk]=tieň,maximalizácia,maximalizovanie,minimalizácia,minimalizovanie,nižší,ponuka operácií,záhlavie,zmeniť veľkosť X-KDE-Keywords[sl]=zvij,povečaj,razpni,pomanjšaj,skrči,dvigni,spusti,naslovna vrstica,spremeni velikost,okenski meni,meni okna X-KDE-Keywords[sr]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,сенка,максимизуј,минимизуј,спусти,мени радњи,насловна трака,промени величину X-KDE-Keywords[sr@ijekavian]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,сенка,максимизуј,минимизуј,спусти,мени радњи,насловна трака,промени величину X-KDE-Keywords[sr@ijekavianlatin]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,senka,maksimizuj,minimizuj,spusti,meni radnji,naslovna traka,promeni veličinu X-KDE-Keywords[sr@latin]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,senka,maksimizuj,minimizuj,spusti,meni radnji,naslovna traka,promeni veličinu X-KDE-Keywords[sv]=skugga,maximera,minimera,åtgärdsmeny,namnlist,ändra storlek X-KDE-Keywords[tr]=geri yükle, gölgele,büyüt,küçült,aşağı al,işlemler menüsü,başlık çubuğu,yeniden boyutlandır X-KDE-Keywords[uk]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,тінь,максимізувати,розгорнути,згорнути,нижче,меню дій,заголовок,смужка заголовка,розмір,розміри,зміна розмірів X-KDE-Keywords[x-test]=xxshadexx,xxmaximisexx,xxmaximizexx,xxminimizexx,xxminimisexx,xxlowerxx,xxoperations menuxx,xxtitlebarxx,xxresizexx X-KDE-Keywords[zh_CN]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize,阴影,最大化,最小化,降低,动作,菜单,标题栏,更改大小 X-KDE-Keywords[zh_TW]=shade,maximise,maximize,minimize,minimise,lower,operations menu,titlebar,resize diff --git a/kcmkwin/kwinoptions/kwinadvanced.desktop b/kcmkwin/kwinoptions/kwinadvanced.desktop index 8cac4f583..988d019a2 100644 --- a/kcmkwin/kwinoptions/kwinadvanced.desktop +++ b/kcmkwin/kwinoptions/kwinadvanced.desktop @@ -1,95 +1,98 @@ [Desktop Entry] Icon=preferences-system-windows-actions Type=Service X-KDE-ServiceTypes=KCModule Exec=kcmshell5 kwinadvanced X-DocPath=kcontrol/windowbehaviour/index.html#action-advanced X-KDE-Library=kcm_kwinoptions X-KDE-PluginKeyword=kwinadvanced Name=Advanced Window Behavior Name[ca]=Comportament avançat de les finestres Name[cs]=Pokročilé chování oken Name[da]=Avanceret vinduesopførsel Name[de]=Erweitertes Fensterverhalten Name[en_GB]=Advanced Window Behaviour Name[es]=Comportamiento avanzado de las ventanas Name[et]=Täpsem akende käitumine Name[eu]=Leihoaren portaera aurreratua Name[fi]=Ikkunatoiminnan lisäasetukset Name[fr]=Comportement avancé des fenêtres Name[gl]=Comportamento avanzado das xanelas Name[ia]=Comportamento de fenestra avantiate Name[id]=Perilaku Window Tingkat-Lanjut Name[it]=Comportamento avanzato delle finestre Name[ko]=고급 창 행동 Name[lt]=Išplėstinė langų elgsena Name[nl]=Geavanceerd venstergedrag Name[nn]=Avansert vindaugsåtferd Name[pl]=Zaawansowane zachowania okien Name[pt]=Comportamento Avançado das Janelas Name[pt_BR]=Comportamento avançado das janelas Name[ru]=Расширенное поведение окон Name[sk]=Pokročilé správanie okien +Name[sl]=Napredno obnašanje oken Name[sv]=Avancerat fönsterbeteende Name[uk]=Додаткові параметри вікон Name[x-test]=xxAdvanced Window Behaviorxx Name[zh_CN]=高级窗口行为 Name[zh_TW]=進階視窗行為 Comment=Configure advanced window management options Comment[ca]=Configura les opcions avançades per a la gestió de les finestres Comment[cs]=Nastavení pokročilých voleb správce oken Comment[da]=Indstil avancerede vindueshåndteringsegenskaber Comment[de]=Einstellungen für erweiterte Fensterverwaltung einrichten Comment[en_GB]=Configure advanced window management options Comment[es]=Configurar las opciones avanzadas de la gestión de ventanas Comment[et]=Muude aknahalduse valikute seadistamine Comment[eu]=Konfiguratu leiho kudeaketa aukera aurreratuak Comment[fi]=Ikkunanhallinnan lisäasetukset Comment[fr]=Configurer les options de gestion avancée des fenêtres Comment[gl]=Configurar as funcionalidades avanzadas da xestión de xanelas Comment[ia]=Configura optiones avantiate de gestion de fenestra Comment[id]=Konfigurasikan opsi pengelolaan window tingkat-lanjut Comment[it]=Configura opzioni avanzate della gestione delle finestre Comment[ko]=고급 창 관리자 기능 설정 Comment[lt]=Konfigūruoti išplėstines langų tvarkymo parinktis Comment[nl]=Geavanceerde vensterbeheermogelijkheden configureren Comment[nn]=Set opp avanserte vindaugshandsamarinnstillingar Comment[pl]=Zaawansowane ustawienia zarządzania oknami Comment[pt]=Configurar as funcionalidades de gestão de janelas avançadas Comment[pt_BR]=Configure as opções avançadas de gerenciamento de janelas Comment[ru]=Настройка дополнительных возможностей управления окнами Comment[sk]=Nastaviť pokročilé možnosti správy okien +Comment[sl]=Nastavi napredne zmožnosti upravljanja oken Comment[sv]=Anpassa avancerade fönsterhanteringsalternativ Comment[uk]=Налаштовування додаткових параметрів керування вікнами Comment[x-test]=xxConfigure advanced window management optionsxx Comment[zh_CN]=配置高级窗口管理选项 Comment[zh_TW]=設定進階視窗管理選項 X-KDE-Keywords=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window,window tabbing,window grouping,window tiling,placement,window placement,placement of windows,window advanced behavior X-KDE-Keywords[ca]=desplega,desplegament,ombra,vora,passar per sobre,vores actives,mosaic,pestanyes,pestanyes de finestra,finestra,agrupació de les finestres,mosaic de les finestres,col·locació,col·locació de les finestres,comportament avançat de les finestres X-KDE-Keywords[da]=kant,hover,aktive kanter,tiling,faneblade,vinduesfaneblade,gruppering af vinduer,vinduesplacering,placering,placering af vinduer,avanceret vinduesopførsel X-KDE-Keywords[en_GB]=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window,window tabbing,window grouping,window tiling,placement,window placement,placement of windows,window advanced behaviour X-KDE-Keywords[es]=desplegar,extender,recoger,plegar,borde,pasada,bordes activos,mosaico,pestañas,páginas en pestañas,ventana,pestañas de páginas,agrupación de ventanas,ventanas en mosaico,posicionamiento,posicionamiento de ventanas,comportamiento avanzado de las ventanas X-KDE-Keywords[et]=varjamine,piire,kohalviibimine,aktiivsed piirded,paanimine,kaardid,aknad kaartidena,akende rühmitamine,akende paanimine,akende paigutus,akende täpne käitumine,aken,paigutus X-KDE-Keywords[eu]=zabaldu,zabaltzea,bildu,biltzea,gainetik pasatzea,ertz aktiboak,lauzatze,fitxak,leihoa,leihoen fitxak,leihoak lauza moduan,leihoen kokapena,leihoen jokabide aurreratua X-KDE-Keywords[fi]=rullauksen avaus,rullauksen avaaminen,rullaus,rullaaminen,kehys,leijunta,aktiiviset reunat,asettelu,välilehdet,ikkunavälilehdet,ikkunoiden ryhmittely,ikkunoiden asettelu,sijoittaminen,sijoittelu,ikkunoiden sijoittaminen,ikkunoiden sijoittelu,ikkunoiden lisäasetukset X-KDE-Keywords[gl]=dessombrar,dessombramento,sombra,bordo,beira,pasar,bordos activos,beiras activas,xanela,separadores,agrupar xanelas, situación das xanelas,colocación,colocación das xanelas,comportamento avanzado das xanelas X-KDE-Keywords[id]=tak berbayang,tak bayang,berbayang,batas,melayang,bingkai aktif,pengubinan,tab,pengetaban,window,pengetaban window,pengelompokan window,pengubinan window,penempatan,penempatan window,penempatan si window,perilaku tingkat-lanjut window X-KDE-Keywords[it]=arrotola,srotola,ombra,ombreggiatura,bordo,sovrapponi,bordi attivi,affiancamento,schede,navigazione a schede,finestre,finestre a schede,raggruppamento finestre,affiancamento finestre,posizionamento,posizionamento finestre,posizionamento delle finestre,comportamento avanzato delle finestre X-KDE-Keywords[ko]=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window,window tabbing,window grouping,window tiling,placement,window placement,placement of windows,window advanced behavior,그림자,경계선,호버,지나다니기,타일,탭,창 탭,창 그룹,창 타일,창 위치,말아 올리기,풀어 내리기,배치,창 X-KDE-Keywords[lt]=atidengti,atidengimas,pridengti,pridengimas,rėmelis,remelis,remas,rėmas,pelės užvedimas,peles uzvedimas,užvesti pelę,uzvesti pele,kortelės,korteles,langas,langai,langų kortelės,langu korteles,langų grupavimas,langu grupavimas,langų išklojimas,langu isklojimas,išdėstymas,isdestymas,padėjimas,padejimas,langų išdėstymas,langu isdestymas,langų padėjimas,langu padejimas,išplėstinė langų elgsena,isplestine langu elgsena,išplėstinė lango elgsena,isplestine lango elgsena,išplėstinis langų elgesys,isplestinis langu elgesys,išplėstinis lango elgesys,isplestinis lango elgesys X-KDE-Keywords[nl]=verhelderen,verheldering,schaduw,verduistering,rand,boven zweven,actieve randen,schuin achter elkaar,tabbladen,met tabbladen werken,venster,vensterwisseling,verstergroepering,vensters schuin achter elkaar,plaatsing,vensterplaatsing,plaatsing van vensters,geavanceerd gedrag van vensters X-KDE-Keywords[nn]=opprulling,kant,sveva,aktive kantar,flislegging,faner,vindaugsfaner,vindaugsgruppering,vindaugsflislegging,vindaugsplassering,plassering,plassering av vindauge,avansert vindaugsåtferd X-KDE-Keywords[pl]=rozwijanie,zwijanie,obramowanie,unoszenie,aktywne obramowania,kafelkowanie,karty,tworzenie kart,okno, umieszczanie okien w kartach,grupowanie okien,kafelkowanie okien,umieszczanie,umieszczanie okien, zaawansowane zachowania okien X-KDE-Keywords[pt]=sombra,contorno,passagem,contornos activos,lado-a-lado,páginas,páginas da janela,agrupamento de janelas,janelas lado-a-lado,colocação das janelas,comportamento avançado das janelas X-KDE-Keywords[pt_BR]=enrolar,desenrolar,desenrolando,sombra,contorno,passagem,contornos ativos, lado a lado,janela,páginas,páginas da janela,agrupamento de janelas,janelas lado a lado,colocação das janelas,colocação,comportamento avançado das janelas X-KDE-Keywords[ru]=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window,window tabbing,window grouping,window tiling,placement,window placement,placement of windows,window advanced behavior,затенение,сворачивание в заголовок,разворачивание из заголовка,граница,наведение,активные границы,мозаика,вкладки,окна во вкладках,группировка окон,мозаичный режим,окно,расположение окон,расширенное поведение окон X-KDE-Keywords[sk]=tieňovanie,okraj,prechod,aktívne okraje,dlaždicovanie,karty,kartovanie okien, zoskupovanie okien,dlaždicovanie okien,umiestnenie okna,poloha okien,pokročilé správanie okien +X-KDE-Keywords[sl]=osvetljevanje,senčenje,zvijanje,rob,obroba,robovi,obrobe,prehod,lebdenje,tlakovanje,zavihki,združevanje oken,tlakovanje oken,postavljanje oken,postavitev oken,napredno obnašanje oken X-KDE-Keywords[sv]=skugga,skuggning,kanter,hålla musen över,aktiva kanter,sida vid sida,flikar,fönster,fönsterflikar,fönstergruppering,fönster sida vid sida,placering,fönsterplacering,placering av fönster,avancerat fönsterbeteende X-KDE-Keywords[uk]=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window tabbing,window grouping,window tiling,placement?window placement,placement of windows,window advanced behavior,прибирання тіні,тінь,тіні,границі,межі,краї,активні краї,плитка,тайлінґ,вкладки,мозаїка,вікно з вкладками,групування вікон,розташування,розташування вікон, додаткові ефекти поведінки X-KDE-Keywords[x-test]=xxunshadexx,xxunshadingxx,xxshadexx,xxshadingxx,xxborderxx,xxhoverxx,xxactive bordersxx,xxtilingxx,xxtabsxx,xxtabbingxx,xxwindowxx,xxwindow tabbingxx,xxwindow groupingxx,xxwindow tilingxx,xxplacementxx,xxwindow placementxx,xxplacement of windowsxx,xxwindow advanced behaviorxx X-KDE-Keywords[zh_CN]=阴影,投影,边框,边界,悬停,激活边界,平铺,标签,窗口,窗口标签,窗口分组,平铺窗口,窗口位置,窗口高级行为 X-KDE-Keywords[zh_TW]=unshade,unshading,shade,shading,border,hover,active borders,tiling,tabs,tabbing,window,window tabbing,window grouping,window tiling,placement,window placement,placement of windows,window advanced behavior diff --git a/kcmkwin/kwinoptions/kwinfocus.desktop b/kcmkwin/kwinoptions/kwinfocus.desktop index 37c519f22..b62ce7aa3 100644 --- a/kcmkwin/kwinoptions/kwinfocus.desktop +++ b/kcmkwin/kwinoptions/kwinfocus.desktop @@ -1,94 +1,97 @@ [Desktop Entry] Icon=preferences-system-windows Type=Service X-KDE-ServiceTypes=KCModule Exec=kcmshell5 kwinfocus X-DocPath=kcontrol/windowbehaviour/index.html#action-focus X-KDE-Library=kcm_kwinoptions X-KDE-PluginKeyword=kwinfocus Name=Window Focus Behavior Name[ca]=Comportament del focus de les finestres Name[cs]=Chování při zaměření na okno Name[da]=Opførsel af vinduesfokus Name[en_GB]=Window Focus Behaviour Name[es]=Comportamiento del foco de las ventanas Name[et]=Akende fookuse käitumine Name[eu]=Leiho fokuaren portaera Name[fi]=Ikkunoiden kohdistuskäytäntö Name[fr]=Comportement de focus des fenêtres Name[gl]=Comportamento do foco das xanelas Name[ia]=Comportamento de foco de fenestra Name[id]=Perilaku Fokus Window Name[it]=Comportamento del fuoco delle finestre Name[ko]=창 초점 동작 Name[lt]=Langų fokusavimo elgsena Name[nl]=Focusgedrag venster Name[nn]=Fokus­åtferd for vindauge Name[pl]=Zachowanie uaktywnienia okien Name[pt]=Comportamento do Foco da Janela Name[pt_BR]=Comportamento do foco da janela Name[ru]=Фокус окон Name[sk]=Správanie zamerania okien +Name[sl]=Obnašanje oken pri osredotočanju Name[sv]=Fönsterfokusbeteende Name[uk]=Параметри фокусування вікон Name[x-test]=xxWindow Focus Behaviorxx Name[zh_CN]=窗口焦点行为 Name[zh_TW]=視窗焦點行為 Comment=Configure window activation policy Comment[ca]=Configura la política d'activació de les finestres Comment[cs]=Nastavení pravidel aktivování oken Comment[da]=Indstil vinduers aktiveringspolitik Comment[en_GB]=Configure window activation policy Comment[es]=Configurar la política de activación de ventanas Comment[et]=Akende aktiveerimise reeglite seadistamine Comment[eu]=Konfiguratu leihoa aktibatzeko gidalerroak Comment[fi]=Ikkunoiden aktivointikäytännön asetukset Comment[fr]=Configurer la politique d'activation des fenêtres Comment[gl]=Configurar a política de activación de xanelas Comment[ia]=Configura le politica de activation de fenestra Comment[id]=Konfigurasikan kebijakan pengaktifan window Comment[it]=Configura criteri di attivazione delle finestre Comment[ko]=창 활성화 정책 설정 Comment[lt]=Konfigūruoti langų aktyvavimo politiką Comment[nl]=Vensteractiveringsbeleid configureren Comment[nn]=Set opp praksisen for vindaugsaktivering Comment[pl]=Ustawienia uaktywniania okien Comment[pt]=Configurar a política de activação da janela Comment[pt_BR]=Configure a política de ativação de janela Comment[ru]=Настройка активации окон Comment[sk]=Nastavenie spôsobu aktivácie okien +Comment[sl]=Nastavi politiko aktiviranja okna Comment[sv]=Anpassa policy för fönsteraktivering Comment[uk]=Налаштовування правил активації вікон Comment[x-test]=xxConfigure window activation policyxx Comment[zh_CN]=配置窗口激活策略 Comment[zh_TW]=設定視窗啟用策略 X-KDE-Keywords=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior X-KDE-Keywords[ca]=focus,elevació automàtica,elevació,elevació en clic,teclat,CDE,alt-tab,tots els escriptoris,focus segueix el ratolí,prevenció del focus,robatori del focus,política del focus,comportament del focus de la finestra,comportament en pantalla de la finestra X-KDE-Keywords[da]=fokus,autohæv,hæv,klikhæv,tastatur,CDE,alt-tab,alle skriveborde,fokus følger mus,fokusforhindring,stjæler fokus,fokuspolitik,opførsel for vinduesfokus X-KDE-Keywords[en_GB]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behaviour,window screen behaviour X-KDE-Keywords[es]=foco,auto levantar,levantar,clic para levantar,teclado,CDE,alt-tab,todo el escritorio,el foco sigue al ratón,prevención de foco,robo del foco,política del foco,comportamiento del foco de las ventanas,comportamiento de la pantalla de ventanas X-KDE-Keywords[et]=fookus,asetus,automaatne esiletoomine,klõpsuga esiletoomine,klaviatuur,CDE,alt-tab,kõik töölauad,fookus järgib hiirt,fookuse vältimine,fookuse röövimine,fookuse reegel,akna fookuse käitumine X-KDE-Keywords[eu]=fokua,automatikoki igo,igo,egin klik igotzeko,teklatu,CDE,alt-tab,mahaigain guztiak,fokuak saguari jarraitzen dio,foku-prebentzioa,foku-lapurreta,fokuaren gidalerro,leihoen fokuaren portaera,leihoen pantailen portaera X-KDE-Keywords[fi]=kohdistus,sijoitus,automaattinen nosto,automaattinen nostaminen,nosta,nosta napsauttamalla,näppäimistö,alt-sarkain,kaikki työpöydät,kohdistus seuraa hiirtä,kohdistuksen esto,kohdistuksen varastaminen,kohdistustapa,ikkunoiden kohdistuksen toiminta,ikkunoiden näyttötoiminta X-KDE-Keywords[fr]=focus, agrandissement automatique, agrandissement, clic d'agrandissement, clavier, CDE, alt-tab, tous les bureaux, focus suivi par la souris, prise de focus, politique de focus, comportement du focus des fenêtres, comportement des fenêtres X-KDE-Keywords[gl]=foco,erguer automaticamente,erguer,erguer ao premer,teclado,CDE,alt-tab,todo o escritorio,foco que segue o rato,prevención do foco,roubar o foco,política de foco,comportamento de foco de xanela,comportamento de pantalla de xanela X-KDE-Keywords[id]=fokus,auto naik,naikkan,klik naikkan,keyboard,papan ketik,CDE,alt-tab,semua desktop,fokus mengikuti mouse,pencegahan fokus,pencurian fokus,kebijakan fokus,perilaku fokus window,perilaku layar window X-KDE-Keywords[it]=fuoco,avanzamento automatico,avanzamento,avanzamento con clic,tastiera,CDE,alt-tab,tutti i desktop,il fuoco segue il mouse,impedisci il fuoco,mantieni il fuoco,regole fuoco,comportamento fuoco finestra, comportamento schermo finestra X-KDE-Keywords[ko]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior,초점,키보드,모든 데스크톱,초점,초점 훔치기,초점 훔치기 방지,초점 정책,창 초점 행동,창 화면 행동 X-KDE-Keywords[lt]=fokusavimas,fokusas,automatinis iškėlimas,automatinis iskelimas,automatiškai iškelti į pirmą planą,automatiskai iskelti i pirma plana,iškelti į pirmą planą,iskelti i pirma plana,pakelti,pakėlimas,iškėlimas spustelėjus,iskelimas spustelejus,iškėlimas spustelėjant,iskelimas spustelejant,klaviatūra,klaviatura,CDE,alt-tab,visi darbalaukiai,visi darbastaliai,fokusas seka pelę,fokusas seka pele,fokusas seka paskui pelę,fokusas seka paskui pele,fokusavimas seka pelę,fokusavimas seka pele,fokusavimas seka paskui pelę,fokusavimas seka paskui pele,fokuso prevencija,fokusavimo prevencija,fokuso vogimas,fokusavimo vogimas,fokuso politika,fokusavimo politika,langų fokusavimo elgsena,langų fokuso elgsena,langų fokuso elgesys,lango fokuso elgsena,lango fokuso elgesys,langų fokusavimo elgesys,langų ekrano elgsena,langu ekrano elgsena,langų ekrano elgesys,langu ekrano elgesys,lango ekrano elgsena,lango ekrano elgesys X-KDE-Keywords[nl]=focus,automatisch omhoog komen,omhoog komen,omhoog komen bij klikken,toetsenbord,CDE,alt-tab,alle bureaubladen,focus volgt muis,voorkomen van focus,focus stelen,focusbeleid,focusgedrag in venster,gedrag van vensterscherm X-KDE-Keywords[nn]=fokus,autohev,hev,klikk-og-hev,tastatur,CDE,alt-tab,alle skrivebord,fokus følgjer mus,fokushindring,fokussteling,fokuspraksis,fokusåtferd for vindauge,vindaugsåtferd på skjerm X-KDE-Keywords[pl]=uaktywnienie,auto wznoszenie,wznoszenie,wznoszenie na kliknięcie,klawiatura,CDE,alt-tab,wszystkie pulpity X-KDE-Keywords[pt]=foco,colocação,elevação automática,elevar,elevar ao carregar,teclado,CDE,alt-tab,todos os ecrãs,foco segue o rato,prevenção do foco,roubo do foco,política de foco,comportamento do foco da janela,comportamento da janela no ecrã X-KDE-Keywords[pt_BR]=foco,elevação automática,elevar,elevar ao clicar,teclado,CDE,alt-tab,todas as áreas de trabalho,foco segue o mouse,prevenção do foco,captura do foco,política de foco,comportamento do foco da janela,comportamento da janela na tela X-KDE-Keywords[ru]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior,фокус,активация окон,автоматически,поднятие,поднимать,клавиатура,весь рабочий стол,фокус следует за мышью,фокус под мышью,похищение фокуса,предотвращение перехвата фокуса,поведение фокуса,окон,поведение экрана X-KDE-Keywords[sk]=zameranie,umiestnenie,automatické zdvihnutie,zdvihnutie,klik na zdvihnutie,klávesnica,CDE,alt-tab, všetky plochy,zameranie nasleduje mys,predchádzanie zameraniu,kradnutie zamerania,politika zamerania, správania zamerania okien,správania okien obrazovky +X-KDE-Keywords[sl]=fokus,žarišče,postavitev,postavljanje,samodejni dvig,samodejno dvigovanje,dvig,dvigovanje,dvig na klik,tipkovnica,cde,celotno namizje,fokus sledi miški,žarišče sledi miški,preprečevanje fokusa,preprečevanje žarišča,kraja fokusa,kraja žarišča,pravila osredotočanja,pravila za osredotočanje,obnašanje pri osredotočanju oken,obnašanje pri postavljanju oken v žarišče,obnašanje oken X-KDE-Keywords[sv]=fokus,fönsterbeteende,animering,höj,höj automatiskt,höj med klick,CDE,alt-tab,alla skrivbord,fokus följer musen,förhindra fokus,stjäla fokus,fokusprincip,fönsterfokusbeteende,fönsterskärmbeteende X-KDE-Keywords[uk]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior,фокус,фокусування,автопідняття,підняття,клацання,клавіатура,альт-таб,всі стільниці,фокус за мишею,запобігання,перехід фокуса,правила фокусування,поведінка вікон X-KDE-Keywords[x-test]=xxfocusxx,xxauto raisexx,xxraisexx,xxclick raisexx,xxkeyboardxx,xxCDExx,xxalt-tabxx,xxall desktopxx,xxfocus follows mousexx,xxfocus preventionxx,xxfocus stealingxx,xxfocus policyxx,xxwindow focus behaviorxx,xxwindow screen behaviorxx X-KDE-Keywords[zh_CN]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior,焦点,聚焦,自动升起,升起,点击升起,键盘,全部桌面,焦点跟随鼠标,偷取焦点,焦点策略,窗口焦点行为,窗口屏幕行为 X-KDE-Keywords[zh_TW]=focus,auto raise,raise,click raise,keyboard,CDE,alt-tab,all desktop,focus follows mouse,focus prevention,focus stealing,focus policy,window focus behavior,window screen behavior diff --git a/kcmkwin/kwinoptions/kwinmoving.desktop b/kcmkwin/kwinoptions/kwinmoving.desktop index 4806ff761..1938bbe52 100644 --- a/kcmkwin/kwinoptions/kwinmoving.desktop +++ b/kcmkwin/kwinoptions/kwinmoving.desktop @@ -1,111 +1,113 @@ [Desktop Entry] Icon=preferences-system-windows-movement Type=Service X-KDE-ServiceTypes=KCModule Exec=kcmshell5 kwinmoving X-DocPath=kcontrol/windowbehaviour/index.html#action-moving Icon=preferences-system-windows-move X-KDE-Library=kcm_kwinoptions X-KDE-PluginKeyword=kwinmoving Name=Window Movement Name[ca]=Moviment de les finestres Name[cs]=Pohyb oken Name[da]=Flytning af vinduer Name[en_GB]=Window Movement Name[es]=Movimiento de las ventanas Name[et]=Akna liigutamine Name[eu]=Leihoaren mugimendua Name[fi]=Ikkunoiden siirtäminen Name[fr]=Déplacement des fenêtres Name[gl]=Movemento das xanelas Name[ia]=Movimento de fenestra Name[id]=Pemindahan Window Name[it]=Spostamento delle finestre Name[ko]=창 이동 Name[lt]=Langų perkėlimas Name[nl]=Verplaatsen van vensters Name[nn]=Vidaugs­flytting Name[pl]=Przesuwanie okien Name[pt]=Movimentação das Janelas Name[pt_BR]=Movimento da janela Name[ru]=Перемещение окон Name[sk]=Presuny okien +Name[sl]=Premikanje oken Name[sv]=Fönsterförflyttning Name[uk]=Пересування вікон Name[x-test]=xxWindow Movementxx Name[zh_CN]=窗口移动 Name[zh_TW]=視窗移動 Comment=Configure window movement options Comment[ca]=Configura les opcions de moviment de les finestres Comment[cs]=Nastavit volby pohybu oken Comment[da]=Indstil flytning af vinduer Comment[en_GB]=Configure window movement options Comment[es]=Configurar las opciones del movimiento de las ventanas Comment[et]=Akende liigutamise seadistamine Comment[eu]=Konfiguratu leiho mugimenduaren aukerak Comment[fi]=Ikkunoiden siirtämisen asetukset Comment[fr]=Configurer les options de déplacement des fenêtres Comment[gl]=Configurar o movemento das xanelas Comment[ia]=Configura optiones de movimento de fenestra Comment[id]=Konfigurasikan opsi pemindahan window Comment[it]=Configura opzioni di spostamento delle finestre Comment[ko]=창 이동 옵션 설정 Comment[lt]=Konfigūruoti langų perkėlimo parinktis Comment[nl]=Opties voor vensterverplaatsing configureren Comment[nn]=Set opp vindaugsflytting Comment[pl]=Ustawienia opcji przesuwania okien Comment[pt]=Configurar as opções de movimentação das janelas Comment[pt_BR]=Configure as opções de movimento da janela Comment[ru]=Настройка поведения при перемещении окон Comment[sk]=Nastavenie spôsobu presunu okien +Comment[sl]=Nastavi možnosti premikanja okna Comment[sv]=Anpassa alternativ för fönsterförflyttning Comment[uk]=Налаштовування параметрів пересування вікон Comment[x-test]=xxConfigure window movement optionsxx Comment[zh_CN]=配置窗口移动选项 Comment[zh_TW]=設定視窗移動選項 X-KDE-Keywords=moving,smart,cascade,maximize,maximise,snap zone,snap,border X-KDE-Keywords[bs]=pomjeranje,pametno,kaskada,povećali,povećalo,namjestiti zonu,namjestiti,granica X-KDE-Keywords[ca]=moviment,intel·ligent,cascada,maximització,zona d'ajust,ajust,vora X-KDE-Keywords[ca@valencia]=moviment,intel·ligent,cascada,maximització,zona d'ajust,ajust,vora X-KDE-Keywords[da]=flytning,smart,kaskade,maksimer,hægtzone,hægt,kant X-KDE-Keywords[de]=Verschieben,Gestaffelt,Maximieren,Minimieren,Einrastzone,Ränder X-KDE-Keywords[el]=κίνηση,έξυπνη,διαδοχική,μεγιστοποίηση,ελαχιστοποίηση,snap zone,snap,περίγραμμα X-KDE-Keywords[en_GB]=moving,smart,cascade,maximize,maximise,snap zone,snap,border X-KDE-Keywords[es]=movimiento,inteligente,cascada,maximizar,maximizar,zona de instantánea,instantánea,borde X-KDE-Keywords[et]=liigutamine,nutikas,kaskaad,maksimeerimine,haardetsoon,haaramine,piire X-KDE-Keywords[eu]=lekuz aldatzea,adimendun,kaskada,maximizatu,atxikitze-eremu,atxikitu,ertz X-KDE-Keywords[fi]=siirtäminen,älykäs,porrastus,suurentaminen,tarttuminen,kiinnitysalue,tartunta,kiinnitys,kiinnittyminen,reuna X-KDE-Keywords[fr]=déplacement, intelligent, cascade, maximiser, maximise, zone de rupture, rupture, bordure X-KDE-Keywords[gl]=mover,intelixente,solapar,fervenza,maximizar,minimizar,zona de adherencia, adherencia,bordo,beira,bordo X-KDE-Keywords[hu]=mozgatás,intelligens,lépcsőzetes,maximalizálás,maximalizálás,vonzási távolság,szegély X-KDE-Keywords[ia]=movente,intelligente,cascada,maximisa,maximisa,zona de ruptura,ruptura,margine X-KDE-Keywords[id]=pemindahan,cerdas,kaskade,maksimalkan,maksimalkan,zona jepret,jepret,bingkai X-KDE-Keywords[it]=spostamento,intelligente,cascata,massimizza,zona di aggancio,agganciamento,bordo X-KDE-Keywords[kk]=moving,smart,cascade,maximize,maximise,snap zone,snap,border X-KDE-Keywords[km]=moving,smart,cascade,maximize,maximise,snap zone,snap,border X-KDE-Keywords[ko]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,이동,스마트,계단식,최대화,경계선 X-KDE-Keywords[lt]=perkėlimas,perkelti,perkelimas,išmanus,ismanus,mažiausias persidengimas,maziausias persidengimas,mažiausio persidengimo,maziausio persidengimo,pakopomis,kaskada,išskleisti,isskleisti,isdidinti,išdidinti,pritraukimo zona,traukimo zona,pritraukimas,traukimas,rėmelis,remelis,rėmas,remas X-KDE-Keywords[nb]=flytting,smart,kaskade,maksimer,gripesone,gripe,kant X-KDE-Keywords[nds]=Bewegen,klook,överenanner,maximeren,Andockrebeet,andocken,Rahmen,Kant X-KDE-Keywords[nl]=verplaatsen,smart,cascade,maximaliseren,zone vastzetten,vastzetten,grens X-KDE-Keywords[nn]=flytting,smart,kaskade,maksimering,gripesone,gripa,kant X-KDE-Keywords[pl]=przesuwanie,elegancki,kaskada,maksymalizuj,obszar przyciągania,przyciągaj,obramowanie X-KDE-Keywords[pt]=movimento,inteligente,cascata,maximizar,ajuste à zona,ajuste,contorno X-KDE-Keywords[pt_BR]=movimento,movimentação,inteligente,cascata,maximizar,ajuste à área,ajuste,borda X-KDE-Keywords[ru]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,перемещение,каскад,распахнуть,свернуть,захват,привязка,граница X-KDE-Keywords[sk]=presun,smart,kaskáda,maximalizácia,miinmalizácia,oblasť prichytenia,prichytenie,rám X-KDE-Keywords[sl]=premikanje,pametno premikanje,kaskada,povečaj,razpni,območje pripenjanja,pripenjanje,rob,robovi,obroba,obrobe X-KDE-Keywords[sr]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,померање,паметно,наслагано,максимизуј,зона лепљења,лепљење,ивица X-KDE-Keywords[sr@ijekavian]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,померање,паметно,наслагано,максимизуј,зона лепљења,лепљење,ивица X-KDE-Keywords[sr@ijekavianlatin]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,pomeranje,pametno,naslagano,maksimizuj,zona lepljenja,lepljenje,ivica X-KDE-Keywords[sr@latin]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,pomeranje,pametno,naslagano,maksimizuj,zona lepljenja,lepljenje,ivica X-KDE-Keywords[sv]=flytta,smart,kaskad,maximera,låszon,lås,kanter X-KDE-Keywords[tr]=taşıma,akıllı,döşeme,büyütme,en büyük,kopma alanı,kopma,kenarlık X-KDE-Keywords[uk]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,пересування,кмітливе,каскадом,максимізувати,розгорнути,прилипання,зона прилипання,межа X-KDE-Keywords[x-test]=xxmovingxx,xxsmartxx,xxcascadexx,xxmaximizexx,xxmaximisexx,xxsnap zonexx,xxsnapxx,xxborderxx X-KDE-Keywords[zh_CN]=moving,smart,cascade,maximize,maximise,snap zone,snap,border,移动,智能,最大化,级联,吸附区,吸附,边框 X-KDE-Keywords[zh_TW]=moving,smart,cascade,maximize,maximise,snap zone,snap,border diff --git a/kcmkwin/kwinoptions/kwinoptions.desktop b/kcmkwin/kwinoptions/kwinoptions.desktop index 69668445c..8185251ac 100644 --- a/kcmkwin/kwinoptions/kwinoptions.desktop +++ b/kcmkwin/kwinoptions/kwinoptions.desktop @@ -1,174 +1,175 @@ [Desktop Entry] Exec=kcmshell5 kwinoptions Icon=preferences-system-windows-actions Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/windowbehaviour/index.html X-KDE-Library=kcm_kwinoptions X-KDE-PluginKeyword=kwinoptions X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=windowmanagement X-KDE-Weight=40 Name=Window Behavior Name[af]=Venstergedrag Name[ar]=سلوك النوافذ Name[be]=Паводзіны вокнаў Name[be@latin]=Pavodziny akna Name[bg]=Поведение на прозорците Name[bn]=উইণ্ডো আচরণ Name[bn_IN]=উইন্ডোর আচরণ Name[br]=Emzalc'h ar prenester Name[bs]=Ponašanje prozora Name[ca]=Comportament de les finestres Name[ca@valencia]=Comportament de les finestres Name[cs]=Chování oken Name[csb]=Ùchòwanié òkna Name[cy]=Ymddygiad Ffenestri Name[da]=Vinduesopførsel Name[de]=Fensterverhalten Name[el]=Συμπεριφορά παραθύρων Name[en_GB]=Window Behaviour Name[eo]=Fenestrokonduto Name[es]=Comportamiento de las ventanas Name[et]=Akende käitumine Name[eu]=Leihoaren portaera Name[fa]=رفتار پنجره Name[fi]=Ikkunoiden toiminta Name[fr]=Comportement des fenêtres Name[fy]=Finstergedrach Name[ga]=Oibriú na bhFuinneog Name[gl]=Comportamento das xanelas Name[gu]=વિન્ડો વર્તણૂક Name[he]=התנהגות חלונות Name[hi]=विंडो व्यवहार Name[hne]=विंडो व्यवहार Name[hr]=Ponašanje prozora Name[hu]=Ablakműveletek Name[ia]=Comportamento de fenestra Name[id]=Perilaku Window Name[is]=Hegðun glugga Name[it]=Comportamento delle finestre Name[ja]=ウィンドウの挙動 Name[ka]=ფანჯრის ქცევა Name[kk]=Терезе қасиеттері Name[km]=ឥរិយាបថ​បង្អួច Name[kn]=ಕಿಟಕಿ ವರ್ತನೆ Name[ko]=창 동작 Name[ku]=Helwesta Paceyan Name[lt]=Langų elgsena Name[lv]=Logu izturēšanās Name[mai]=विंडो व्यवहार Name[mk]=Однесување на прозорци Name[ml]=ജാലകത്തിന്റെ വിശേഷത Name[mr]=चौकट वर्तन Name[nb]=Vindusoppførsel Name[nds]=Finsterbedregen Name[ne]=सञ्झ्याल व्यवहार Name[nl]=Venstergedrag Name[nn]=Vindaugs­åtferd Name[pa]=ਵਿੰਡੋ ਰਵੱਈਆ Name[pl]=Zachowania okien Name[pt]=Comportamento das Janelas Name[pt_BR]=Comportamento das janelas Name[ro]=Comportament fereastră Name[ru]=Поведение окон Name[se]=Láseláhtten Name[si]=කවුළු හැසිරීම Name[sk]=Správanie okien Name[sl]=Obnašanje oken Name[sr]=Понашање прозора Name[sr@ijekavian]=Понашање прозора Name[sr@ijekavianlatin]=Ponašanje prozora Name[sr@latin]=Ponašanje prozora Name[sv]=Fönsterbeteende Name[ta]=சாளர நடத்தை Name[te]=విండో ప్రవర్తన Name[th]=พฤติกรรมของหน้าต่าง Name[tr]=Pencere Davranışı Name[ug]=كۆزنەكنىڭ ئىش-ھەرىكەتلىرى Name[uk]=Поведінка вікон Name[uz]=Oynaning xususiyatlari Name[uz@cyrillic]=Ойнанинг хусусиятлари Name[vi]=Ứng xử của Cửa sổ Name[wa]=Dujhance des fniesses Name[xh]=Ukuziphatha kwe Window Name[x-test]=xxWindow Behaviorxx Name[zh_CN]=窗口行为 Name[zh_TW]=視窗行為 Comment=Configure window actions and behavior Comment[ca]=Configura les accions i comportament de les finestres Comment[cs]=Nastavte činností a chování oken Comment[da]=Indstil vindueshandlinger og -opførsel Comment[de]=Fenster-Aktionen und -verhalten einrichten Comment[en_GB]=Configure window actions and behaviour Comment[es]=Configurar las acciones y el comportamiento de las ventanas Comment[et]=Akende toimingute ja käitumise seadistamine Comment[eu]=Konfiguratu leihoaren ekintzak eta jokabidea Comment[fi]=Ikkunatoimintojen asetukset Comment[fr]=Configurer les actions et le comportement des fenêtres Comment[gl]=Configurar o comportamento e as accións das xanelas Comment[ia]=Cnfigura comportamento e actiones de fenestra Comment[id]=Konfigurasikan perilaku dan aksi window Comment[it]=Configura azioni e comportamento delle finestre Comment[ko]=창 동작과 행동 설정 Comment[lt]=Konfigūruoti langų veiksmus ir elgseną Comment[nl]=Vensteracties en gedrag configureren Comment[nn]=Set opp utsjånad og åtferd for vindauge Comment[pl]=Ustawienia działań i zachowań okien Comment[pt]=Configurar as acções e comportamento das janelas Comment[pt_BR]=Configure as ações e comportamento das janelas Comment[ru]=Настройка поведения окон Comment[sk]=Nastaviť akcie a správanie okien +Comment[sl]=Nastavi dejanja in obnašanje oken Comment[sv]=Anpassa fönsteråtgärder och beteende Comment[uk]=Налаштовування реакції та поведінки вікон Comment[x-test]=xxConfigure window actions and behaviorxx Comment[zh_CN]=配置窗口操作和行为 Comment[zh_TW]=設定視窗動作及行為 X-KDE-Keywords=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick X-KDE-Keywords[bs]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,fokus,pozicioniranje,ponašanje prozora,akcije prozora,animacija,podizanje,okvir,naslovna traka X-KDE-Keywords[ca]=focus,emplaçament,comportament de la finestra,accions de la finestra,animació,elevació,elevació automàtica,finestres,marc,barra de títol,clic doble X-KDE-Keywords[ca@valencia]=focus,emplaçament,comportament de la finestra,accions de la finestra,animació,elevació,elevació automàtica,finestres,marc,barra de títol,clic doble X-KDE-Keywords[da]=fokus,placering,vinduesopførsel,vindueshandlinger,animation,hæv,autohæv,vinduesramme,titelbjælke,dobbeltklik X-KDE-Keywords[de]=Aktivierung,Platzierung,Fensterverhalten,Fensteraktionen,Animation,Nach vorn/hinten, Fenster,Rahmen,Umrandung,Titelleiste,Doppelklick X-KDE-Keywords[el]=εστίαση,τοποθέτηση,συμπεριφορά παραθύρου,κίνηση εικόνας,αύξηση,αυτόματη αύξηση,παράθυρα,πλαίσιο,γραμμή τίτλου,διπλό κλικ X-KDE-Keywords[en_GB]=focus,placement,window behaviour,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick X-KDE-Keywords[es]=foco,posicionamiento,comportamiento de las ventanas,acciones de las ventanas,animación,elevación,autoelevación,ventanas,marco,barra de título,doble clic X-KDE-Keywords[et]=fookus,asetus,paigutus,akende käitumine,aknatoimingud,animeerimine,animatsioon,esiletoomine,automaatne esiletoomine,aknad,raam,tiitliriba,topeltklõps X-KDE-Keywords[eu]=foku,kokaleku,leihoen portaera,leiho-ekintzak,animazio,igo,automatikoki igo,leihoak,marko,titulu-barra,klik bikoitz X-KDE-Keywords[fi]=kohdistus,sijoittelu,sijoitus,ikkunoiden toiminta,ikkunoiden toiminnot,animaatio,nosta,automaattinen nosto,ikkunat,kehys,otsikkopalkki,kaksoisnapsautus,tuplanapsautus,kaksoisklikkaus,tuplaklikkaus X-KDE-Keywords[fr]=focus, placement, comportement de la fenêtre, actions sur les fenêtres, animation, agrandissement, agrandissement automatique, fenêtres, cadre, barre de titre, double clic X-KDE-Keywords[gl]=foco,posicionamento,comportamento das xanelas,accións das xanelas, animación,xanelas,moldura,barra de título,marco X-KDE-Keywords[hu]=fókusz,elhelyezés,ablakműködés,ablakműveletek,animáció,felemelés,automatikus felemelés,ablakok,keret,címsor,dupla kattintás X-KDE-Keywords[ia]=focus,placiamento,comportamento de fenestra,actiones de fenestra,animation,altiar,auto altiar,fenestras,quadro,barra de titulo,duple click X-KDE-Keywords[id]=fokus,penempatan,perilaku window,aksi window,animasi,naikkan,naikkan otomatis,window,bingkai,titlebar,klik ganda X-KDE-Keywords[it]=fuoco,posizionamento,comportamento della finestra,azioni delle finestre,animazione,sollevamento,sollevamento automatico,finestre,riquadro,barra del titolo,doppio clic X-KDE-Keywords[ko]=focus,placement,window behavior,animation,raise,auto raise,windows,frame,titlebar,doubleclick,초점,위치,창 행동,애니메이션,올리기,창,프레임,제목 표시줄 X-KDE-Keywords[lt]=fokusas,fokusavimas,išdėstymas,isdestymas,padėjimas,padejimas,lango elgsena,langų elgsena,langu elgsena,lango elgesys,langų elgsesys,langu elgesys,lango veiksmai,langų veiksmai,langu veiksmai,animacija,animacijos,iškelti į pirmą planą,iskelti i pirma plana,iškėlimas į pirmą planą,iskelimas i pirma plana,automatiškai iškelti į pirmą planą,automatiskai iskelti i pirma plana,automatinis iškėlimas į pirmą planą,automatinis iskelimas i pirma plana,langas,langai,rėmelis,remelis,rėmas,remas,antraštės juosta,antrastes juosta,pavadinimo juosta,dvikartis spustelėjimas,dvikartis spustelejimas,dvigubas spustelėjimas,dvigubas spustelejimas X-KDE-Keywords[nb]=fokus,plassering,vindusoppførsel,vindushandlinger,animering,hev,autohev,vinduer,ramme,tittellinje,dobbeltklikk X-KDE-Keywords[nds]=Fokus,Platzeren,Finsterbedregen,Finsterakschonen,Animeren,na vörn,automaatsch,Finstern,Rahmen,Titelbalken,Dubbelklick X-KDE-Keywords[nl]=focus,plaatsing,venstegedrag,vensteracties,animatie,omhoog,automatisch omhoog,vensters,frame,titelbalk,dubbelklik X-KDE-Keywords[nn]=fokus,plassering,vindaugsåtferd,vindaugshandlingar,animering,hev,autohev,vindauge,ramme,tittellinje,dobbeltklikk X-KDE-Keywords[pl]=uaktywnienie,umieszczenie,zachowanie okna,działania okien,animacja,wzniesienie,auto-wzniesienie, okna,ramka,pasek tytułu,podwójne kliknięcie X-KDE-Keywords[pt]=foco,colocação,comportamento da janela,acções das janelas,animação,elevar,elevar automaticamente,janelas,contorno,barra de título,duplo-click X-KDE-Keywords[pt_BR]=foco,colocação,comportamento da janela,ações da janela,animação,elevar,elevar automaticamente,janelas,contorno,barra de título,clique duplo X-KDE-Keywords[ru]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,фокус,местоположение,поведение окон,анимация,увеличение,автоувеличение,окна,рамка,заголовок,двойной щелчок,действия над окнами X-KDE-Keywords[sk]=zameranie,umiestnenie,správanie okien,animácia,zdvihnúť,automaticky zdvihnúť,okná,rám,záhlavie,dvojklik X-KDE-Keywords[sl]=fokus,žarišče,postavitev,postavljanje,obnašanje oken,dejanja oken,animacija,dvig,samodejni dvig,okna,okvir,naslovna vrstica,dvojni klik,dvoklik X-KDE-Keywords[sr]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,фокус,постављење,понашање прозора,радње над прозорима,анимација,подигни,аутоматско подизање,прозор,оквир,насловна трака,двоклик X-KDE-Keywords[sr@ijekavian]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,фокус,постављење,понашање прозора,радње над прозорима,анимација,подигни,аутоматско подизање,прозор,оквир,насловна трака,двоклик X-KDE-Keywords[sr@ijekavianlatin]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,fokus,postavljenje,ponašanje prozora,radnje nad prozorima,animacija,podigni,automatsko podizanje,prozor,okvir,naslovna traka,dvoklik X-KDE-Keywords[sr@latin]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,fokus,postavljenje,ponašanje prozora,radnje nad prozorima,animacija,podigni,automatsko podizanje,prozor,okvir,naslovna traka,dvoklik X-KDE-Keywords[sv]=fokus,placering,fönsterbeteende,animering,höj,höj automatiskt,fönster,ram,namnlist,dubbelklick X-KDE-Keywords[tr]=odak,yerleşim,pencere davranışı,pencere eylemleri,canlandırma,yükselt,otomatik yükselt,pencereler,çerçeve,başlık çubuğu,çift tıklama X-KDE-Keywords[uk]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,фокус,розташування,місце,вікно,поведінка,поведінка вікон,дії,реакція,дії з вікнами,реакція вікон,анімація,підняти,підняття,автоматична,автоматично,рамка,заголовок,смужка заголовка,клацання,подвійне X-KDE-Keywords[x-test]=xxfocusxx,xxplacementxx,xxwindow behaviorxx,xxwindow actionsxx,xxanimationxx,xxraisexx,xxauto raisexx,xxwindowsxx,xxframexx,xxtitlebarxx,xxdoubleclickxx X-KDE-Keywords[zh_CN]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,焦点,位置,窗口行为,窗口动作,动画,升起,自动升起,窗口,边框,标题栏,双击 X-KDE-Keywords[zh_TW]=focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick Categories=Qt;KDE;X-KDE-settings-looknfeel; diff --git a/kcmkwin/kwinoptions/kwinoptions_settings.kcfg b/kcmkwin/kwinoptions/kwinoptions_settings.kcfg index 5ad052b04..959c0dd6d 100644 --- a/kcmkwin/kwinoptions/kwinoptions_settings.kcfg +++ b/kcmkwin/kwinoptions/kwinoptions_settings.kcfg @@ -1,322 +1,368 @@ false 10 0 100 10 0 100 0 0 100 false false 250 0 0 true Maximize Maximize MaximizeVerticalOnly MaximizeVerticalOnly + + ClickToFocus + + + + + + + + + + false + + + + 750 + 0 + + + + 300 + 0 + + + + false + + + + true + + + + false + + + + true + + + + 1 + 0 + 4 + + Raise Nothing OperationsMenu Nothing ActivateAndRaise Nothing OperationsMenu ActivateRaisePassClick ActivatePassClick ActivatePassClick Scroll Alt Move ToggleRaiseAndLower Resize Nothing diff --git a/kcmkwin/kwinoptions/kwinoptions_settings.kcfgc b/kcmkwin/kwinoptions/kwinoptions_settings.kcfgc index 7135009fb..2deb14378 100644 --- a/kcmkwin/kwinoptions/kwinoptions_settings.kcfgc +++ b/kcmkwin/kwinoptions/kwinoptions_settings.kcfgc @@ -1,6 +1,5 @@ File=kwinoptions_settings.kcfg ClassName=KWinOptionsSettings Mutators=true DefaultValueGetters=true ParentInConstructor=true -Singleton=true diff --git a/kcmkwin/kwinoptions/main.cpp b/kcmkwin/kwinoptions/main.cpp index d056e5a62..2116567c7 100644 --- a/kcmkwin/kwinoptions/main.cpp +++ b/kcmkwin/kwinoptions/main.cpp @@ -1,244 +1,237 @@ /* * * Copyright (c) 2001 Waldo Bastian * * 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 "main.h" #include //Added by qt3to4: #include #include #include #include #include #include #include #include "mouse.h" #include "windows.h" +#include "kwinoptions_settings.h" K_PLUGIN_FACTORY_DECLARATION(KWinOptionsFactory) class KFocusConfigStandalone : public KFocusConfig { Q_OBJECT public: KFocusConfigStandalone(QWidget* parent, const QVariantList &) - : KFocusConfig(true, new KConfig("kwinrc"), parent) + : KFocusConfig(true, new KWinOptionsSettings(this), parent) {} }; class KMovingConfigStandalone : public KMovingConfig { Q_OBJECT public: KMovingConfigStandalone(QWidget* parent, const QVariantList &) - : KMovingConfig(true, parent) + : KMovingConfig(true, new KWinOptionsSettings(this), parent) {} }; class KAdvancedConfigStandalone : public KAdvancedConfig { Q_OBJECT public: KAdvancedConfigStandalone(QWidget* parent, const QVariantList &) - : KAdvancedConfig(true, parent) + : KAdvancedConfig(true, new KWinOptionsSettings(this), parent) {} }; KWinOptions::KWinOptions(QWidget *parent, const QVariantList &) : KCModule(parent) { - mConfig = new KConfig("kwinrc"); + mSettings = new KWinOptionsSettings(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); tab = new QTabWidget(this); layout->addWidget(tab); - mFocus = new KFocusConfig(false, mConfig, this); + mFocus = new KFocusConfig(false, mSettings, this); mFocus->setObjectName(QLatin1String("KWin Focus Config")); tab->addTab(mFocus, i18n("&Focus")); connect(mFocus, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); + connect(mFocus, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); - mTitleBarActions = new KTitleBarActionsConfig(false, this); + // Need to relay unmanagedWidgetDefaultState and unmanagedWidgetChangeState to wrapping KCModule + connect(mFocus, &KFocusConfig::unmanagedWidgetDefaulted, this, &KWinOptions::unmanagedWidgetDefaultState); + connect(mFocus, &KFocusConfig::unmanagedWidgetStateChanged, this, &KWinOptions::unmanagedWidgetChangeState); + + mTitleBarActions = new KTitleBarActionsConfig(false, mSettings, this); mTitleBarActions->setObjectName(QLatin1String("KWin TitleBar Actions")); tab->addTab(mTitleBarActions, i18n("Titlebar A&ctions")); connect(mTitleBarActions, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mTitleBarActions, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); - mWindowActions = new KWindowActionsConfig(false, this); + mWindowActions = new KWindowActionsConfig(false, mSettings, this); mWindowActions->setObjectName(QLatin1String("KWin Window Actions")); tab->addTab(mWindowActions, i18n("W&indow Actions")); connect(mWindowActions, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mWindowActions, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); - mMoving = new KMovingConfig(false, this); + mMoving = new KMovingConfig(false, mSettings, this); mMoving->setObjectName(QLatin1String("KWin Moving")); tab->addTab(mMoving, i18n("Mo&vement")); connect(mMoving, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mMoving, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); - mAdvanced = new KAdvancedConfig(false, this); + mAdvanced = new KAdvancedConfig(false, mSettings, this); mAdvanced->setObjectName(QLatin1String("KWin Advanced")); tab->addTab(mAdvanced, i18n("Adva&nced")); connect(mAdvanced, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mAdvanced, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); KAboutData *about = new KAboutData(QStringLiteral("kcmkwinoptions"), i18n("Window Behavior Configuration Module"), QString(), QString(), KAboutLicense::GPL, i18n("(c) 1997 - 2002 KWin and KControl Authors")); about->addAuthor(i18n("Matthias Ettrich"), QString(), "ettrich@kde.org"); about->addAuthor(i18n("Waldo Bastian"), QString(), "bastian@kde.org"); about->addAuthor(i18n("Cristian Tibirna"), QString(), "tibirna@kde.org"); about->addAuthor(i18n("Matthias Kalle Dalheimer"), QString(), "kalle@kde.org"); about->addAuthor(i18n("Daniel Molkentin"), QString(), "molkentin@kde.org"); about->addAuthor(i18n("Wynn Wilkes"), QString(), "wynnw@caldera.com"); about->addAuthor(i18n("Pat Dowler"), QString(), "dowler@pt1B1106.FSH.UVic.CA"); about->addAuthor(i18n("Bernd Wuebben"), QString(), "wuebben@kde.org"); about->addAuthor(i18n("Matthias Hoelzer-Kluepfel"), QString(), "hoelzer@kde.org"); setAboutData(about); } -KWinOptions::~KWinOptions() -{ - delete mConfig; -} - void KWinOptions::load() { - mConfig->reparseConfiguration(); - mFocus->load(); mTitleBarActions->load(); mWindowActions->load(); mMoving->load(); mAdvanced->load(); - emit KCModule::changed(false); + // mFocus is last because it may send unmanagedWidgetStateChanged + // that need to have the final word + mFocus->load(); } - void KWinOptions::save() { mFocus->save(); mTitleBarActions->save(); mWindowActions->save(); mMoving->save(); mAdvanced->save(); emit KCModule::changed(false); - // Send signal to kwin - mConfig->sync(); + // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } void KWinOptions::defaults() { - mFocus->defaults(); mTitleBarActions->defaults(); mWindowActions->defaults(); mMoving->defaults(); mAdvanced->defaults(); + // mFocus is last because it may send unmanagedWidgetDefaulted + // that need to have the final word + mFocus->defaults(); } QString KWinOptions::quickHelp() const { return i18n("

Window Behavior

Here you can customize the way windows behave when being" " moved, resized or clicked on. You can also specify a focus policy as well as a placement" " policy for new 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.

"); } KActionsOptions::KActionsOptions(QWidget *parent, const QVariantList &) : KCModule(parent) { - mConfig = new KConfig("kwinrc"); + mSettings = new KWinOptionsSettings(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); tab = new QTabWidget(this); layout->addWidget(tab); - mTitleBarActions = new KTitleBarActionsConfig(false, this); + mTitleBarActions = new KTitleBarActionsConfig(false, mSettings, this); mTitleBarActions->setObjectName(QLatin1String("KWin TitleBar Actions")); tab->addTab(mTitleBarActions, i18n("&Titlebar Actions")); connect(mTitleBarActions, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mTitleBarActions, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); - mWindowActions = new KWindowActionsConfig(false, this); + mWindowActions = new KWindowActionsConfig(false, mSettings, this); mWindowActions->setObjectName(QLatin1String("KWin Window Actions")); tab->addTab(mWindowActions, i18n("Window Actio&ns")); connect(mWindowActions, qOverload(&KCModule::changed), this, qOverload(&KCModule::changed)); connect(mWindowActions, qOverload(&KCModule::defaulted), this, qOverload(&KCModule::defaulted)); } -KActionsOptions::~KActionsOptions() -{ - delete mConfig; -} - void KActionsOptions::load() { mTitleBarActions->load(); mWindowActions->load(); } void KActionsOptions::save() { mTitleBarActions->save(); mWindowActions->save(); emit KCModule::changed(false); - // Send signal to kwin - mConfig->sync(); // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } void KActionsOptions::defaults() { mTitleBarActions->defaults(); mWindowActions->defaults(); } void KActionsOptions::moduleChanged(bool state) { emit KCModule::changed(state); } K_PLUGIN_FACTORY_DEFINITION(KWinOptionsFactory, registerPlugin("kwinactions"); registerPlugin("kwinfocus"); registerPlugin("kwinmoving"); registerPlugin("kwinadvanced"); registerPlugin("kwinoptions"); ) #include "main.moc" -#include "moc_main.cpp" diff --git a/kcmkwin/kwinoptions/main.h b/kcmkwin/kwinoptions/main.h index 50a8bcd8a..f85d61d5a 100644 --- a/kcmkwin/kwinoptions/main.h +++ b/kcmkwin/kwinoptions/main.h @@ -1,93 +1,90 @@ /* * main.h * * Copyright (c) 2001 Waldo Bastian * * Requires the Qt widget libraries, available at no cost at * https://www.qt.io/ * * 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 __MAIN_H__ #define __MAIN_H__ #include #include -class KConfig; +class KWinOptionsSettings; class KFocusConfig; class KTitleBarActionsConfig; class KWindowActionsConfig; class KAdvancedConfig; class KMovingConfig; class KWinOptions : public KCModule { Q_OBJECT public: KWinOptions(QWidget *parent, const QVariantList &args); - ~KWinOptions() override; void load() override; void save() override; void defaults() override; QString quickHelp() const override; private: QTabWidget *tab; KFocusConfig *mFocus; KTitleBarActionsConfig *mTitleBarActions; KWindowActionsConfig *mWindowActions; KMovingConfig *mMoving; KAdvancedConfig *mAdvanced; - KConfig *mConfig; + KWinOptionsSettings *mSettings; }; class KActionsOptions : public KCModule { Q_OBJECT public: KActionsOptions(QWidget *parent, const QVariantList &args); - ~KActionsOptions() override; void load() override; void save() override; void defaults() override; protected Q_SLOTS: void moduleChanged(bool state); - private: QTabWidget *tab; KTitleBarActionsConfig *mTitleBarActions; KWindowActionsConfig *mWindowActions; - KConfig *mConfig; + KWinOptionsSettings *mSettings; }; #endif diff --git a/kcmkwin/kwinoptions/mouse.cpp b/kcmkwin/kwinoptions/mouse.cpp index 8be4dc6ff..22c8a3031 100644 --- a/kcmkwin/kwinoptions/mouse.cpp +++ b/kcmkwin/kwinoptions/mouse.cpp @@ -1,223 +1,225 @@ /* * * Copyright (c) 1998 Matthias Ettrich * * 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 "mouse.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kwinoptions_settings.h" namespace { QPixmap maxButtonPixmaps[3]; void createMaxButtonPixmaps() { char const *maxButtonXpms[][3 + 13] = { { nullptr, nullptr, nullptr, "...............", ".......#.......", "......###......", ".....#####.....", "..#....#....#..", ".##....#....##.", "###############", ".##....#....##.", "..#....#....#..", ".....#####.....", "......###......", ".......#.......", "..............." }, { nullptr, nullptr, nullptr, "...............", ".......#.......", "......###......", ".....#####.....", ".......#.......", ".......#.......", ".......#.......", ".......#.......", ".......#.......", ".....#####.....", "......###......", ".......#.......", "..............." }, { nullptr, nullptr, nullptr, "...............", "...............", "...............", "...............", "..#.........#..", ".##.........##.", "###############", ".##.........##.", "..#.........#..", "...............", "...............", "...............", "..............." }, }; QByteArray baseColor(". c " + KColorScheme(QPalette::Active, KColorScheme::View).background().color().name().toLatin1()); QByteArray textColor("# c " + KColorScheme(QPalette::Active, KColorScheme::View).foreground().color().name().toLatin1()); for (int t = 0; t < 3; ++t) { maxButtonXpms[t][0] = "15 13 2 1"; maxButtonXpms[t][1] = baseColor.constData(); maxButtonXpms[t][2] = textColor.constData(); maxButtonPixmaps[t] = QPixmap(maxButtonXpms[t]); maxButtonPixmaps[t].setMask(maxButtonPixmaps[t].createHeuristicMask()); } } } // namespace KWinMouseConfigForm::KWinMouseConfigForm(QWidget *parent) : QWidget(parent) { setupUi(parent); } KWinActionsConfigForm::KWinActionsConfigForm(QWidget *parent) : QWidget(parent) { setupUi(parent); } void KTitleBarActionsConfig::paletteChanged() { createMaxButtonPixmaps(); for (int i=0; i<3; ++i) { m_ui->kcfg_MaximizeButtonLeftClickCommand->setItemIcon(i, maxButtonPixmaps[i]); m_ui->kcfg_MaximizeButtonMiddleClickCommand->setItemIcon(i, maxButtonPixmaps[i]); m_ui->kcfg_MaximizeButtonRightClickCommand->setItemIcon(i, maxButtonPixmaps[i]); } } -KTitleBarActionsConfig::KTitleBarActionsConfig(bool _standAlone, QWidget *parent) +KTitleBarActionsConfig::KTitleBarActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) : KCModule(parent), standAlone(_standAlone) , m_ui(new KWinMouseConfigForm(this)) + , m_settings(settings) { - addConfig(KWinOptionsSettings::self(), this); + addConfig(m_settings, this); // create the items for the maximize button actions createMaxButtonPixmaps(); for (int i=0; i<3; ++i) { m_ui->kcfg_MaximizeButtonLeftClickCommand->addItem(maxButtonPixmaps[i], QString()); m_ui->kcfg_MaximizeButtonMiddleClickCommand->addItem(maxButtonPixmaps[i], QString()); m_ui->kcfg_MaximizeButtonRightClickCommand->addItem(maxButtonPixmaps[i], QString()); } createMaximizeButtonTooltips(m_ui->kcfg_MaximizeButtonLeftClickCommand); createMaximizeButtonTooltips(m_ui->kcfg_MaximizeButtonMiddleClickCommand); createMaximizeButtonTooltips(m_ui->kcfg_MaximizeButtonRightClickCommand); load(); } void KTitleBarActionsConfig::createMaximizeButtonTooltips(KComboBox *combo) { combo->setItemData(0, i18n("Maximize"), Qt::ToolTipRole); combo->setItemData(1, i18n("Maximize (vertical only)"), Qt::ToolTipRole); combo->setItemData(2, i18n("Maximize (horizontal only)"), Qt::ToolTipRole); } void KTitleBarActionsConfig::showEvent(QShowEvent *ev) { if (!standAlone) { // Workaround KCModule::showEvent() calling load(), see bug 163817 QWidget::showEvent(ev); return; } KCModule::showEvent(ev); } void KTitleBarActionsConfig::changeEvent(QEvent *ev) { if (ev->type() == QEvent::PaletteChange) { paletteChanged(); } ev->accept(); } void KTitleBarActionsConfig::save() { KCModule::save(); if (standAlone) { // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } } -KWindowActionsConfig::KWindowActionsConfig(bool _standAlone, QWidget *parent) +KWindowActionsConfig::KWindowActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) : KCModule(parent), standAlone(_standAlone) , m_ui(new KWinActionsConfigForm(this)) + , m_settings(settings) { - addConfig(KWinOptionsSettings::self(), this); + addConfig(m_settings, this); load(); } void KWindowActionsConfig::showEvent(QShowEvent *ev) { if (!standAlone) { QWidget::showEvent(ev); return; } KCModule::showEvent(ev); } void KWindowActionsConfig::save() { KCModule::save(); if (standAlone) { // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } } diff --git a/kcmkwin/kwinoptions/mouse.h b/kcmkwin/kwinoptions/mouse.h index cbb5f4352..b6cf62a48 100644 --- a/kcmkwin/kwinoptions/mouse.h +++ b/kcmkwin/kwinoptions/mouse.h @@ -1,96 +1,100 @@ /* * mouse.h * * Copyright (c) 1998 Matthias Ettrich * * * 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 __KKWMMOUSECONFIG_H__ #define __KKWMMOUSECONFIG_H__ class KConfig; #include #include #include #include "ui_actions.h" #include "ui_mouse.h" +class KWinOptionsSettings; + class KWinMouseConfigForm : public QWidget, public Ui::KWinMouseConfigForm { Q_OBJECT public: explicit KWinMouseConfigForm(QWidget* parent); }; class KWinActionsConfigForm : public QWidget, public Ui::KWinActionsConfigForm { Q_OBJECT public: explicit KWinActionsConfigForm(QWidget* parent); }; class KTitleBarActionsConfig : public KCModule { Q_OBJECT public: - KTitleBarActionsConfig(bool _standAlone, QWidget *parent); + KTitleBarActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent); void save() override; protected: void showEvent(QShowEvent *ev) override; void changeEvent(QEvent *ev) override; private: bool standAlone; KWinMouseConfigForm *m_ui; + KWinOptionsSettings *m_settings; void createMaximizeButtonTooltips(KComboBox* combo); private Q_SLOTS: void paletteChanged(); }; class KWindowActionsConfig : public KCModule { Q_OBJECT public: - KWindowActionsConfig(bool _standAlone, QWidget *parent); + KWindowActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent); void save() override; protected: void showEvent(QShowEvent *ev) override; private: bool standAlone; KWinActionsConfigForm *m_ui; + KWinOptionsSettings *m_settings; }; #endif diff --git a/kcmkwin/kwinoptions/windows.cpp b/kcmkwin/kwinoptions/windows.cpp index a05015031..ecc81b653 100644 --- a/kcmkwin/kwinoptions/windows.cpp +++ b/kcmkwin/kwinoptions/windows.cpp @@ -1,442 +1,305 @@ /* * windows.cpp * * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca * Copyright (c) 2001 Waldo Bastian bastian@kde.org * * 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 #include #include #include #include +#include #include #include #include #include "windows.h" #include "kwinoptions_settings.h" #include #include -// kwin config keywords -#define KWIN_FOCUS "FocusPolicy" -#define KWIN_AUTORAISE_INTERVAL "AutoRaiseInterval" -#define KWIN_AUTORAISE "AutoRaise" -#define KWIN_DELAYFOCUS_INTERVAL "DelayFocusInterval" -#define KWIN_CLICKRAISE "ClickRaise" -#define KWIN_FOCUS_STEALING "FocusStealingPreventionLevel" -#define KWIN_INACTIVE_SKIP_TASKBAR "InactiveTabsSkipTaskbar" -#define KWIN_SEPARATE_SCREEN_FOCUS "SeparateScreenFocus" -#define KWIN_ACTIVE_MOUSE_SCREEN "ActiveMouseScreen" - -#define CLICK_TO_FOCUS 0 -#define FOCUS_FOLLOWS_MOUSE 2 -#define FOCUS_UNDER_MOUSE 4 -#define FOCUS_STRICTLY_UNDER_MOUSE 5 +#include "kwinoptions_settings.h" +#include - -KFocusConfig::~KFocusConfig() -{ - if (standAlone) - delete config; -} +#define CLICK_TO_FOCUS 0 +#define CLICK_TO_FOCUS_MOUSE_PRECEDENT 1 +#define FOCUS_FOLLOWS_MOUSE 2 +#define FOCUS_FOLLOWS_MOUSE_PRECEDENT 3 +#define FOCUS_UNDER_MOUSE 4 +#define FOCUS_STRICTLY_UNDER_MOUSE 5 KWinFocusConfigForm::KWinFocusConfigForm(QWidget* parent) : QWidget(parent) { setupUi(parent); } -// removed the LCD display over the slider - this is not good GUI design :) RNolden 051701 -KFocusConfig::KFocusConfig(bool _standAlone, KConfig *_config, QWidget * parent) - : KCModule(parent), config(_config), standAlone(_standAlone) +KFocusConfig::KFocusConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget * parent) + : KCModule(parent), standAlone(_standAlone) , m_ui(new KWinFocusConfigForm(this)) + , m_settings(settings) { - connect(m_ui->focusStealing, SIGNAL(activated(int)), SLOT(changed())); - connect(m_ui->windowFocusPolicyCombo, SIGNAL(currentIndexChanged(int)), SLOT(changed())); - connect(m_ui->windowFocusPolicyCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(focusPolicyChanged())); - connect(m_ui->windowFocusPolicyCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setDelayFocusEnabled())); - connect(m_ui->windowFocusPolicyCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActiveMouseScreen())); - connect(m_ui->autoRaiseOn, SIGNAL(clicked()), SLOT(changed())); - connect(m_ui->autoRaiseOn, SIGNAL(toggled(bool)), SLOT(autoRaiseOnTog(bool))); - connect(m_ui->clickRaiseOn, SIGNAL(clicked()), SLOT(changed())); - connect(m_ui->autoRaise, SIGNAL(valueChanged(int)), SLOT(changed())); - connect(m_ui->delayFocus, SIGNAL(valueChanged(int)), SLOT(changed())); - connect(m_ui->separateScreenFocus, SIGNAL(clicked()), SLOT(changed())); - connect(m_ui->activeMouseScreen, SIGNAL(clicked()), SLOT(changed())); - - connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), SLOT(updateMultiScreen())); + addConfig(m_settings, this); + + connect(m_ui->windowFocusPolicy, qOverload(&QComboBox::currentIndexChanged), this, &KFocusConfig::focusPolicyChanged); + + connect(qApp, &QGuiApplication::screenAdded, this, &KFocusConfig::updateMultiScreen); + connect(qApp, &QGuiApplication::screenRemoved, this, &KFocusConfig::updateMultiScreen); updateMultiScreen(); load(); } void KFocusConfig::updateMultiScreen() { m_ui->multiscreenBehaviorLabel->setVisible(QApplication::screens().count() > 1); - m_ui->activeMouseScreen->setVisible(QApplication::screens().count() > 1); - m_ui->separateScreenFocus->setVisible(QApplication::screens().count() > 1); -} - - -int KFocusConfig::getFocus() -{ - int policy = m_ui->windowFocusPolicyCombo->currentIndex(); - if (policy == 1 || policy == 3) - --policy; // fix the NextFocusPrefersMouse condition - return policy; -} - -void KFocusConfig::setFocus(int foc) -{ - m_ui->windowFocusPolicyCombo->setCurrentIndex(foc); - - // this will disable/hide the auto raise delay widget if focus==click - focusPolicyChanged(); -} - -void KFocusConfig::setAutoRaiseInterval(int tb) -{ - m_ui->autoRaise->setValue(tb); -} - -void KFocusConfig::setDelayFocusInterval(int tb) -{ - m_ui->delayFocus->setValue(tb); -} - -int KFocusConfig::getAutoRaiseInterval() -{ - return m_ui->autoRaise->value(); -} - -int KFocusConfig::getDelayFocusInterval() -{ - return m_ui->delayFocus->value(); -} - -void KFocusConfig::setAutoRaise(bool on) -{ - m_ui->autoRaiseOn->setChecked(on); -} - -void KFocusConfig::setClickRaise(bool on) -{ - m_ui->clickRaiseOn->setChecked(on); + m_ui->kcfg_ActiveMouseScreen->setVisible(QApplication::screens().count() > 1); + m_ui->kcfg_SeparateScreenFocus->setVisible(QApplication::screens().count() > 1); } void KFocusConfig::focusPolicyChanged() { - switch (m_ui->windowFocusPolicyCombo->currentIndex()) { - case 0: + int selectedFocusPolicy = 0; + bool selectedNextFocusPrefersMouseItem = false; + const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse(); + + int focusPolicy = m_ui->windowFocusPolicy->currentIndex(); + switch (focusPolicy) { + case CLICK_TO_FOCUS: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("Click to focus: A window becomes active when you click into it. This behavior is common on other operating systems and likely what you want.")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus; break; - case 1: + case CLICK_TO_FOCUS_MOUSE_PRECEDENT: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("Click to focus (mouse precedence): Mostly the same as Click to focus. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Unusual, but possible variant of Click to focus.")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus; + selectedNextFocusPrefersMouseItem = true; break; - case 2: + case FOCUS_FOLLOWS_MOUSE: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("Focus follows mouse: Moving the mouse onto a window will activate it. Eg. windows randomly appearing under the mouse will not gain the focus. Focus stealing prevention takes place as usual. Think as Click to focus just without having to actually click.")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse; break; - case 3: + case FOCUS_FOLLOWS_MOUSE_PRECEDENT: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("This is mostly the same as Focus follows mouse. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Choose this, if you want a hover controlled focus.")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse; + selectedNextFocusPrefersMouseItem = true; break; - case 4: + case FOCUS_UNDER_MOUSE: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("Focus under mouse: The focus always remains on the window under the mouse.
Warning: Focus stealing prevention and the tabbox ('Alt+Tab') contradict the activation policy and will not work. You very likely want to use Focus follows mouse (mouse precedence) instead!")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse; break; - case 5: + case FOCUS_STRICTLY_UNDER_MOUSE: m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("Focus strictly under mouse: The focus is always on the window under the mouse (in doubt nowhere) very much like the focus behavior in an unmanaged legacy X11 environment.
Warning: Focus stealing prevention and the tabbox ('Alt+Tab') contradict the activation policy and will not work. You very likely want to use Focus follows mouse (mouse precedence) instead!")); + selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse; break; } - int policyIndex = getFocus(); - - // the auto raise related widgets are: autoRaise - m_ui->autoRaiseOn->setEnabled(policyIndex != CLICK_TO_FOCUS); - autoRaiseOnTog(policyIndex != CLICK_TO_FOCUS && m_ui->autoRaiseOn->isChecked()); - - m_ui->focusStealing->setDisabled(policyIndex == FOCUS_UNDER_MOUSE || policyIndex == FOCUS_STRICTLY_UNDER_MOUSE); - m_ui->focusStealingLabel->setEnabled(m_ui->focusStealing->isEnabled()); + const bool changed = m_settings->focusPolicy() != selectedFocusPolicy || loadedNextFocusPrefersMouseItem != selectedNextFocusPrefersMouseItem; + unmanagedWidgetChangeState(changed); + emit unmanagedWidgetStateChanged(changed); - setDelayFocusEnabled(); + const bool isDefault = focusPolicy == CLICK_TO_FOCUS; + unmanagedWidgetDefaultState(isDefault); + emit unmanagedWidgetDefaulted(isDefault); -} + // the auto raise related widgets are: autoRaise + m_ui->kcfg_AutoRaise->setEnabled(focusPolicy != CLICK_TO_FOCUS && focusPolicy != CLICK_TO_FOCUS_MOUSE_PRECEDENT); -void KFocusConfig::setDelayFocusEnabled() -{ - int policyIndex = getFocus(); + m_ui->kcfg_FocusStealingPreventionLevel->setDisabled(focusPolicy == FOCUS_UNDER_MOUSE || focusPolicy == FOCUS_STRICTLY_UNDER_MOUSE); // the delayed focus related widgets are: delayFocus - m_ui->delayFocusOnLabel->setEnabled(policyIndex != CLICK_TO_FOCUS); - delayFocusOnTog(policyIndex != CLICK_TO_FOCUS); -} - -void KFocusConfig::autoRaiseOnTog(bool a) -{ - m_ui->autoRaise->setEnabled(a); - m_ui->clickRaiseOn->setEnabled(!a); -} - -void KFocusConfig::delayFocusOnTog(bool a) -{ - m_ui->delayFocus->setEnabled(a); -} + m_ui->delayFocusOnLabel->setEnabled(focusPolicy != CLICK_TO_FOCUS); + m_ui->kcfg_DelayFocusInterval->setEnabled(focusPolicy != CLICK_TO_FOCUS); -void KFocusConfig::setFocusStealing(int l) -{ - l = qMax(0, qMin(4, l)); - m_ui->focusStealing->setCurrentIndex(l); -} - -void KFocusConfig::setSeparateScreenFocus(bool s) -{ - m_ui->separateScreenFocus->setChecked(s); -} - -void KFocusConfig::setActiveMouseScreen(bool a) -{ - m_ui->activeMouseScreen->setChecked(a); -} - -void KFocusConfig::updateActiveMouseScreen() -{ // on by default for non click to focus policies - KConfigGroup cfg(config, "Windows"); - if (!cfg.hasKey(KWIN_ACTIVE_MOUSE_SCREEN)) - setActiveMouseScreen(getFocus() != 0); + if (m_settings->activeMouseScreen() == m_settings->defaultActiveMouseScreenValue()) { + m_ui->kcfg_ActiveMouseScreen->setChecked(focusPolicy != CLICK_TO_FOCUS && focusPolicy != CLICK_TO_FOCUS_MOUSE_PRECEDENT); + } } void KFocusConfig::showEvent(QShowEvent *ev) { if (!standAlone) { QWidget::showEvent(ev); return; } KCModule::showEvent(ev); } void KFocusConfig::load(void) { - QString key; - - KConfigGroup cg(config, "Windows"); - - const bool focusNextToMouse = cg.readEntry("NextFocusPrefersMouse", false); - - key = cg.readEntry(KWIN_FOCUS); - if (key == "ClickToFocus") - setFocus(CLICK_TO_FOCUS + focusNextToMouse); - else if (key == "FocusFollowsMouse") - setFocus(FOCUS_FOLLOWS_MOUSE + focusNextToMouse); - else if (key == "FocusUnderMouse") - setFocus(FOCUS_UNDER_MOUSE); - else if (key == "FocusStrictlyUnderMouse") - setFocus(FOCUS_STRICTLY_UNDER_MOUSE); + KCModule::load(); - int k = cg.readEntry(KWIN_AUTORAISE_INTERVAL, 750); - setAutoRaiseInterval(k); + const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse(); - k = cg.readEntry(KWIN_DELAYFOCUS_INTERVAL, 300); - setDelayFocusInterval(k); + int focusPolicy = m_settings->focusPolicy(); - setAutoRaise(cg.readEntry(KWIN_AUTORAISE, false)); - setClickRaise(cg.readEntry(KWIN_CLICKRAISE, true)); - focusPolicyChanged(); // this will disable/hide the auto raise delay widget if focus==click - - setSeparateScreenFocus(cg.readEntry(KWIN_SEPARATE_SCREEN_FOCUS, false)); - // on by default for non click to focus policies - setActiveMouseScreen(cg.readEntry(KWIN_ACTIVE_MOUSE_SCREEN, getFocus() != 0)); - -// setFocusStealing( cg.readEntry(KWIN_FOCUS_STEALING, 2 )); - // TODO default to low for now - setFocusStealing(cg.readEntry(KWIN_FOCUS_STEALING, 1)); - - - emit KCModule::changed(false); + switch (focusPolicy) { + // the ClickToFocus and FocusFollowsMouse have special values when + // NextFocusPrefersMouse is true + case KWinOptionsSettings::EnumFocusPolicy::ClickToFocus: + m_ui->windowFocusPolicy->setCurrentIndex(CLICK_TO_FOCUS + loadedNextFocusPrefersMouseItem); + break; + case KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse: + m_ui->windowFocusPolicy->setCurrentIndex(FOCUS_FOLLOWS_MOUSE + loadedNextFocusPrefersMouseItem); + break; + default: + // +2 to ignore the two special values + m_ui->windowFocusPolicy->setCurrentIndex(focusPolicy + 2); + break; + } } void KFocusConfig::save(void) { - int v; - - KConfigGroup cg(config, "Windows"); - - v = getFocus(); - if (v == CLICK_TO_FOCUS) - cg.writeEntry(KWIN_FOCUS, "ClickToFocus"); - else if (v == FOCUS_UNDER_MOUSE) - cg.writeEntry(KWIN_FOCUS, "FocusUnderMouse"); - else if (v == FOCUS_STRICTLY_UNDER_MOUSE) - cg.writeEntry(KWIN_FOCUS, "FocusStrictlyUnderMouse"); - else - cg.writeEntry(KWIN_FOCUS, "FocusFollowsMouse"); - - cg.writeEntry("NextFocusPrefersMouse", v != m_ui->windowFocusPolicyCombo->currentIndex()); - - v = getAutoRaiseInterval(); - if (v < 0) v = 0; - cg.writeEntry(KWIN_AUTORAISE_INTERVAL, v); - - v = getDelayFocusInterval(); - if (v < 0) v = 0; - cg.writeEntry(KWIN_DELAYFOCUS_INTERVAL, v); - - cg.writeEntry(KWIN_AUTORAISE, m_ui->autoRaiseOn->isChecked()); - - cg.writeEntry(KWIN_CLICKRAISE, m_ui->clickRaiseOn->isChecked()); - - cg.writeEntry(KWIN_SEPARATE_SCREEN_FOCUS, m_ui->separateScreenFocus->isChecked()); - cg.writeEntry(KWIN_ACTIVE_MOUSE_SCREEN, m_ui->activeMouseScreen->isChecked()); - - cg.writeEntry(KWIN_FOCUS_STEALING, m_ui->focusStealing->currentIndex()); + KCModule::save(); - cg.writeEntry(KWIN_SEPARATE_SCREEN_FOCUS, m_ui->separateScreenFocus->isChecked()); - cg.writeEntry(KWIN_ACTIVE_MOUSE_SCREEN, m_ui->activeMouseScreen->isChecked()); + int idxFocusPolicy = m_ui->windowFocusPolicy->currentIndex(); + switch (idxFocusPolicy) { + case CLICK_TO_FOCUS: + case CLICK_TO_FOCUS_MOUSE_PRECEDENT: + m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::ClickToFocus); + break; + case FOCUS_FOLLOWS_MOUSE: + case FOCUS_FOLLOWS_MOUSE_PRECEDENT: + // the ClickToFocus and FocusFollowsMouse have special values when + // NextFocusPrefersMouse is true + m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse); + break; + case FOCUS_UNDER_MOUSE: + m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse); + break; + case FOCUS_STRICTLY_UNDER_MOUSE: + m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse); + break; + } + m_settings->setNextFocusPrefersMouse(idxFocusPolicy == CLICK_TO_FOCUS_MOUSE_PRECEDENT || idxFocusPolicy == FOCUS_FOLLOWS_MOUSE_PRECEDENT); + m_settings->save(); if (standAlone) { - config->sync(); // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } emit KCModule::changed(false); } void KFocusConfig::defaults() { - setAutoRaiseInterval(0); - setDelayFocusInterval(0); - setFocus(CLICK_TO_FOCUS); - setAutoRaise(false); - setClickRaise(true); - setSeparateScreenFocus(false); - -// setFocusStealing(2); - // TODO default to low for now - setFocusStealing(1); - - // on by default for non click to focus policies - setActiveMouseScreen(getFocus() != 0); - setDelayFocusEnabled(); - emit KCModule::changed(true); + KCModule::defaults(); + m_ui->windowFocusPolicy->setCurrentIndex(CLICK_TO_FOCUS); } KWinAdvancedConfigForm::KWinAdvancedConfigForm(QWidget* parent) : QWidget(parent) { setupUi(parent); } -KAdvancedConfig::~KAdvancedConfig() -{ -} - -KAdvancedConfig::KAdvancedConfig(bool _standAlone, QWidget *parent) - : KCModule(parent), m_config(KWinOptionsSettings::self()), standAlone(_standAlone) +KAdvancedConfig::KAdvancedConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) + : KCModule(parent), standAlone(_standAlone) , m_ui(new KWinAdvancedConfigForm(this)) + , m_settings(settings) { - addConfig(m_config, this); + addConfig(m_settings, this); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Smart, "Smart"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Maximizing, "Maximizing"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Cascade, "Cascade"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Random, "Random"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Centered, "Centered"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::ZeroCornered, "ZeroCornered"); m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::UnderMouse, "UnderMouse"); load(); } void KAdvancedConfig::showEvent(QShowEvent *ev) { if (!standAlone) { QWidget::showEvent(ev); return; } KCModule::showEvent(ev); } void KAdvancedConfig::save(void) { KCModule::save(); if (standAlone) { // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } } KWinMovingConfigForm::KWinMovingConfigForm(QWidget* parent) : QWidget(parent) { setupUi(parent); } -KMovingConfig::~KMovingConfig() -{ -} - -KMovingConfig::KMovingConfig(bool _standAlone, QWidget *parent) - : KCModule(parent), m_config(KWinOptionsSettings::self()), standAlone(_standAlone) +KMovingConfig::KMovingConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent) + : KCModule(parent), m_config(settings), standAlone(_standAlone) , m_ui(new KWinMovingConfigForm(this)) { addConfig(m_config, this); load(); } void KMovingConfig::showEvent(QShowEvent *ev) { if (!standAlone) { QWidget::showEvent(ev); return; } KCModule::showEvent(ev); } void KMovingConfig::save(void) { - m_config->save(); + KCModule::save(); if (standAlone) { // Send signal to all kwin instances QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); } // and reconfigure the effect OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); if (m_config->geometryTip()) { interface.loadEffect(KWin::BuiltInEffects::nameForEffect(KWin::BuiltInEffect::WindowGeometry)); } else { interface.unloadEffect(KWin::BuiltInEffects::nameForEffect(KWin::BuiltInEffect::WindowGeometry)); } } diff --git a/kcmkwin/kwinoptions/windows.h b/kcmkwin/kwinoptions/windows.h index 80f6ac3d6..938411998 100644 --- a/kcmkwin/kwinoptions/windows.h +++ b/kcmkwin/kwinoptions/windows.h @@ -1,155 +1,134 @@ /* * windows.h * * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca * Copyright (c) 2001 Waldo Bastian bastian@kde.org * * 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 KKWMWINDOWS_H #define KKWMWINDOWS_H #include #include #include "ui_advanced.h" #include "ui_focus.h" #include "ui_moving.h" class QRadioButton; class QCheckBox; class QPushButton; class KComboBox; class QGroupBox; class QLabel; class QSlider; class QGroupBox; class QSpinBox; class KColorButton; class KWinOptionsSettings; class KWinFocusConfigForm : public QWidget, public Ui::KWinFocusConfigForm { Q_OBJECT public: explicit KWinFocusConfigForm(QWidget* parent); }; class KWinMovingConfigForm : public QWidget, public Ui::KWinMovingConfigForm { Q_OBJECT public: explicit KWinMovingConfigForm(QWidget* parent); }; class KWinAdvancedConfigForm : public QWidget, public Ui::KWinAdvancedConfigForm { Q_OBJECT public: explicit KWinAdvancedConfigForm(QWidget* parent); }; class KFocusConfig : public KCModule { Q_OBJECT public: - KFocusConfig(bool _standAlone, KConfig *_config, QWidget *parent); - ~KFocusConfig() override; + KFocusConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent); void load() override; void save() override; void defaults() override; +Q_SIGNALS: + void unmanagedWidgetDefaulted(bool defaulted); + void unmanagedWidgetStateChanged(bool changed); + protected: void showEvent(QShowEvent *ev) override; private Q_SLOTS: - void setDelayFocusEnabled(); void focusPolicyChanged(); - void autoRaiseOnTog(bool);//CT 23Oct1998 - void delayFocusOnTog(bool); - void updateActiveMouseScreen(); void updateMultiScreen(); - void changed() { - emit KCModule::changed(true); - } - private: - int getFocus(void); - int getAutoRaiseInterval(void); - int getDelayFocusInterval(void); - - void setFocus(int); - void setAutoRaiseInterval(int); - void setAutoRaise(bool); - void setDelayFocusInterval(int); - void setClickRaise(bool); - void setSeparateScreenFocus(bool); - void setActiveMouseScreen(bool); - - void setFocusStealing(int); - - KConfig *config; bool standAlone; KWinFocusConfigForm *m_ui; + KWinOptionsSettings *m_settings; }; class KMovingConfig : public KCModule { Q_OBJECT public: - KMovingConfig(bool _standAlone, QWidget *parent); - ~KMovingConfig() override; + KMovingConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent); void save() override; protected: void showEvent(QShowEvent *ev) override; private: KWinOptionsSettings *m_config; bool standAlone; KWinMovingConfigForm *m_ui; }; class KAdvancedConfig : public KCModule { Q_OBJECT public: - KAdvancedConfig(bool _standAlone, QWidget *parent); - ~KAdvancedConfig() override; + KAdvancedConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent); void save() override; protected: void showEvent(QShowEvent *ev) override; private: - KWinOptionsSettings *m_config; bool standAlone; KWinAdvancedConfigForm *m_ui; + KWinOptionsSettings *m_settings; }; #endif // KKWMWINDOWS_H diff --git a/kcmkwin/kwinrules/CMakeLists.txt b/kcmkwin/kwinrules/CMakeLists.txt index 406cffa66..1ccf777a6 100644 --- a/kcmkwin/kwinrules/CMakeLists.txt +++ b/kcmkwin/kwinrules/CMakeLists.txt @@ -1,77 +1,56 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwinrules\") add_definitions(-DKCMRULES) -########### next target ############### - include_directories(../../) -set(kwinrules_MOC_HDRS ../../cursor.h ../../plugins/platforms/x11/standalone/x11cursor.h) -qt5_wrap_cpp(kwinrules_MOC_SRCS ${kwinrules_MOC_HDRS}) set(kwinrules_SRCS ../../rulebooksettings.cpp + ../../cursor.cpp + ../../plugins/platforms/x11/standalone/x11cursor.cpp + ../../rules.cpp + ../../placement.cpp + ../../utils.cpp + kwinsrc.cpp optionsmodel.cpp ruleitem.cpp rulesmodel.cpp - rulesdialog.cpp - main.cpp - kwinsrc.cpp - ${kwinrules_MOC_SRCS} ) kconfig_add_kcfg_files(kwinrules_SRCS ../../rulesettings.kcfgc) kconfig_add_kcfg_files(kwinrules_SRCS ../../rulebooksettingsbase.kcfgc) -add_executable(kwin_rules_dialog ${kwinrules_SRCS}) +add_library(KWinRulesObjects STATIC ${kwinrules_SRCS}) set(kwin_kcm_rules_XCB_LIBS XCB::CURSOR XCB::XCB XCB::XFIXES ) set(kcm_libs + Qt5::Quick Qt5::QuickWidgets KF5::I18n + KF5::QuickAddons KF5::WindowSystem KF5::XmlGui ) if (KWIN_BUILD_ACTIVITIES) set(kcm_libs ${kcm_libs} KF5::Activities) endif() +target_link_libraries(KWinRulesObjects ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS}) -target_link_libraries(kwin_rules_dialog ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS}) - +add_executable(kwin_rules_dialog main.cpp rulesdialog.cpp) +target_link_libraries(kwin_rules_dialog KWinRulesObjects) install(TARGETS kwin_rules_dialog DESTINATION ${LIBEXEC_INSTALL_DIR}) -########### next target ############### - -set(kcmkwinrules_SRCS - kcmrules.cpp - ${kwinrules_SRCS} -) - -add_library(kcm_kwinrules MODULE ${kcmkwinrules_SRCS}) - -target_link_libraries(kcm_kwinrules - Qt5::Quick - - KF5::I18n - KF5::QuickAddons - - ${kcm_libs} - ${kwin_kcm_rules_XCB_LIBS} -) - +add_library(kcm_kwinrules MODULE kcmrules.cpp) +target_link_libraries(kcm_kwinrules KWinRulesObjects) kcoreaddons_desktop_to_json(kcm_kwinrules "kcm_kwinrules.desktop" SERVICE_TYPES kcmodule.desktop) -########### install files ############### - -# This desktop file is installed only for retrocompatibility with sycoca -install(TARGETS kcm_kwinrules DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) -install(FILES kcm_kwinrules.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) - +install(TARGETS kcm_kwinrules DESTINATION ${PLUGIN_INSTALL_DIR}/kcms) +install(FILES kcm_kwinrules.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kpackage_install_package(package kcm_kwinrules kcms) - diff --git a/kcmkwin/kwinrules/kwinsrc.cpp b/kcmkwin/kwinrules/kwinsrc.cpp index 4c4482d93..75173a0a3 100644 --- a/kcmkwin/kwinrules/kwinsrc.cpp +++ b/kcmkwin/kwinrules/kwinsrc.cpp @@ -1,53 +1,45 @@ /* * 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 "../../cursor.cpp" -#include "../../plugins/platforms/x11/standalone/x11cursor.cpp" -#include "../../rules.cpp" -#include "../../placement.cpp" -#include "../../options.cpp" -#include "../../utils.cpp" +#include 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/kwinscreenedges/kwinscreenedges.desktop b/kcmkwin/kwinscreenedges/kwinscreenedges.desktop index a85e52b25..b61adb2c4 100644 --- a/kcmkwin/kwinscreenedges/kwinscreenedges.desktop +++ b/kcmkwin/kwinscreenedges/kwinscreenedges.desktop @@ -1,152 +1,153 @@ [Desktop Entry] Exec=kcmshell5 kwinscreenedges Icon=preferences-desktop-gestures-screenedges Type=Service X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/kwinscreenedges/index.html X-KDE-Library=kcm_kwinscreenedges X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=desktopbehavior X-KDE-Weight=50 Name=Screen Edges Name[ar]=حواف الشاشة Name[bg]=Краища на екрана Name[bs]=Ivice ekrana Name[ca]=Vores de la pantalla Name[ca@valencia]=Vores de la pantalla Name[cs]=Hrany obrazovky Name[csb]=Nórtë ekranu Name[da]=Skærmkanter Name[de]=Bildschirmränder Name[el]=Άκρα οθόνης Name[en_GB]=Screen Edges Name[eo]=Ekrananguloj Name[es]=Bordes de pantalla Name[et]=Ekraani servad Name[eu]=Pantailaren ertzak Name[fi]=Näytön reunat Name[fr]=Bords de l'écran Name[fy]=Skerm rânen Name[ga]=Ciumhaiseanna Scáileáin Name[gl]=Bordos da pantalla Name[gu]=સ્ક્રિનનાં ખૂણાઓ Name[he]=קצוות מסך Name[hi]=स्क्रीन सीमाएँ Name[hr]=Rubovi ekrana Name[hu]=Képernyőszélek Name[ia]=Margines de schermo Name[id]=Tepian Layar Name[is]=Skjájaðrar Name[it]=Lati dello schermo Name[ja]=スクリーンエッジ Name[kk]=Экран жиектері Name[km]=គែម​អេក្រង់​ Name[kn]=ತೆರೆ ಅಂಚುಗಳು Name[ko]=화면 경계 Name[lt]=Ekrano kraštai Name[lv]=Ekrāna malas Name[mai]=स्क्रीन किनार Name[mk]=Рабови на екранот Name[ml]=സ്ക്രീന്‍ അതിരുകള്‍ Name[mr]=स्क्रीनच्या कडा Name[nb]=Skjermkanter Name[nds]=Schirmkanten Name[nl]=Schermranden Name[nn]=Skjerm­kantar Name[pa]=ਸਕਰੀਨ ਬਾਹੀਆਂ Name[pl]=Krawędzie ekranu Name[pt]=Extremos do Ecrã Name[pt_BR]=Contornos da tela Name[ro]=Muchiile ecranului Name[ru]=Края экрана Name[si]=තිර මුළු Name[sk]=Okraje obrazovky Name[sl]=Robovi zaslona Name[sr]=Ивице екрана Name[sr@ijekavian]=Ивице екрана Name[sr@ijekavianlatin]=Ivice ekrana Name[sr@latin]=Ivice ekrana Name[sv]=Skärmkanter Name[tg]=Канорҳои экран Name[th]=ขอบจอ Name[tr]=Ekran Kenarları Name[ug]=ئېكران گىرۋەكلىرى Name[uk]=Краї екрана Name[wa]=Boirds del waitroûle Name[x-test]=xxScreen Edgesxx Name[zh_CN]=屏幕边缘 Name[zh_TW]=螢幕邊緣 Comment=Configure active screen corners and edges Comment[ca]=Configura les cantonades i vores actives de la pantalla Comment[da]=Indstil aktive skærmhjørner- og kanter Comment[de]=Aktive Bildschirmränder und -ecken einrichten Comment[en_GB]=Configure active screen corners and edges Comment[es]=Configurar los bordes y las esquinas de pantalla activos Comment[et]=Aktiivsete ekraani nurkade ja servade seadistamine Comment[eu]=Konfiguratu pantailaren izkina eta ertz aktiboak Comment[fi]=Aseta näytön aktiiviset reunat ja kulmat Comment[fr]=Configurer les bords et les coins d'écran actifs Comment[gl]=Configurar os bordos e esquinas activos da pantalla Comment[hu]=Aktív képernyősarkok és szélek beállítása Comment[ia]=Configura margines e angulos de schermo active Comment[id]=Konfigurasikan tepian dan sudut layar aktif Comment[it]=Configura angoli e bordi attivi dello schermo Comment[ko]=활성 화면 경계와 꼭짓점 설정 Comment[lt]=Konfigūruoti aktyvaus ekrano kampus ir kraštus Comment[nl]=Actieve schermhoeken en -randen configureren Comment[nn]=Set opp aktive skjermhjørne og skjermkantar Comment[pl]=Ustawienia czułych narożników i krawędzi ekranu Comment[pt]=Configurar os cantos e extremos do ecrã activo Comment[pt_BR]=Configura os cantos e bordas da tela ativa Comment[ru]=Настройка действий для краёв и углов экрана Comment[sk]=Nastavenie aktívnych okrajov obrazovky a hrán +Comment[sl]=Nastavi dejavne kote in robove okna Comment[sv]=Anpassa aktiva skärmhörn och kanter Comment[uk]=Налаштовування активних кутів і країв екрана Comment[x-test]=xxConfigure active screen corners and edgesxx Comment[zh_CN]=配置活动屏幕的边角和边缘 Comment[zh_TW]=設定作用中螢幕角落與邊緣 X-KDE-Keywords=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners X-KDE-Keywords[bs]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners, prozor, menadćer, efekt, uigao, ivica, akcija, prebacivanje, desktop ivice, ivice ekrana, maksimitiranje prozora, ponašanje ekrana, virtualni desktop X-KDE-Keywords[ca]=kwin,finestra,gestor,efecte,cantonada,vora,acció,canvi,escriptori,vores de la pantalla del kwin,vores de l'escriptori,vores de la pantalla,maximitza les finestres,finestres en mosaic,costat de la pantalla,comportament de la pantalla,canvi d'escriptori,escriptori virtual,cantonades de la pantalla X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,efecte,cantó,vora,acció,canvi,escriptori,vores de pantalla de kwin,vores d'escriptori,vores de pantalla,maximitza finestres,mosaic de les finestres,costat de pantalla,comportament de pantalla,canvi d'escriptori,escriptori virtual,cantons de la pantalla X-KDE-Keywords[da]=kwin,vindue,håndtering,manager,effekt,hjørne,kant,handling,skift,skrivebord,kwin skærmkanter,skrivebordskanter,skærmkanter,maksimer vinduer,tile windows,fliser,felter,siden af skærmen,skærmens opførsel,skift skrivebord,virtuelle skriveborde,skærmhjørner,hjørner X-KDE-Keywords[de]=KWin,Fenster,Verwaltung,Effekt,Kante,Rand,Aktion,Wechseln,Desktop,Arbeitsfläche,KWin Bildschirmkanten,Desktopkanten,Bildschirmkanten,Fenster maximieren,Fenster kacheln,Bildschirmseite,Bildschirmverhalten,Desktop wechseln,Arbeitsfläche wechseln,Virtueller Desktop,Virtuelle Arbeitsfläche,Bildschirmecken X-KDE-Keywords[el]=kwin,παράθυρο,διαχειριστής,εφέ,άκρη,περίγραμμα,ενέργεια,εναλλαγή,επιφάνεια εργασίας,άκρες οθόνης kwin,άκρες επιφάνειας εργασίας,άκρες οθόνης,μεγιστοποίηση παραθύρων,παράθεση παραθύρων,πλευρά οθόνης,συμπεριφορά οθόνης,εναλλαγή επιφάνειας εργασίας,εικονική επιφάνεια εργασίας,γωνίες οθόνης X-KDE-Keywords[en_GB]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximise windows,tile windows,side of screen,screen behaviour,switch desktop,virtual desktop,screen corners X-KDE-Keywords[es]=kwin,ventana,gestor,efecto,esquina,borde,acción,cambiar,escritorio,bordes de pantalla de kwin,bordes del escritorio,bordes de la pantalla,maximizar ventanas,ventanas en mosaico,lado de la pantalla,comportamiento de la pantalla,cambiar escritorio,escritorio virtual,esquinas de la pantalla X-KDE-Keywords[et]=kwin,aken,haldur,efekt.nurk,serv,piire,toiming,lülitamine,töölaud,kwini ekraani servad,töölaua servad,ekraani servad,akende maksimeerimine,akende paanimine,ekraani äär,ekraani käitumine,töölaua lülitamine,virtuaalne töölaud,ekraani nurgad X-KDE-Keywords[eu]=kwin,leiho,kudeatzaile,efektu,izkin,ertz,ekintza,aldatu,mahaigain,kwin pantailaren ertzak,mahaigainaren ertzak,pantailen ertzak,maximizatu leihoak,lauzatu leihoak,leihoaren alboa,pantailaren portaera,aldatu mahaigaina,mahaigain birtuala,alegiazko mahaigaina,pantailaren izkinak X-KDE-Keywords[fi]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,ikkunamanageri,ikkunointiohjelma,tehoste,kulma,reuna,vaihda,vaihto,työpöytä,näytön reunat,työpöydän reunat,suurenna ikkuna,kasaa ikkunat,näytön toiminta,vaihda työpöytää,virtuaalityöpöytä,näytön reunat X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, effet, bord, coin, bordure, action, bascule, bureau, bords de l'écran kwin, bords du bureau, bords de l'écran, maximisation des fenêtres, mosaïque de fenêtres, cotés de l'écran, comportement de l'écran, changement de bureau, bureaux virtuels, coins de l'écran X-KDE-Keywords[gl]=kwin,xanela,xestor,efecto,esquina,beira,bordo,bordo,acción,trocar,escritorio,bordo do escritorio,maximizar xanelas,escritorio virtual,esquinas da pantalla X-KDE-Keywords[hu]=kwin,ablak,kezelő,effektus,sarok,szél,szegély,művelet,váltás,asztal,kwin képernyőszél,asztalszél,képernyőszél,ablakok maximalizálása,ablakcím,képernyőoldal,képernyő működése,asztalváltás,virtuális asztal,képernyősarkok X-KDE-Keywords[ia]=kwin,fenestra,gerente,effecto,bordo,margine,action,commuta,scriptorio,bordos de schermo de kwin,bordos de scriptorio,bordos de scriptorio,maximisa fenestras,tegula fenestras,parte de schermo, comportamento de schermo,commuta scriptorio,scriptorio virtual,angulos de schermo X-KDE-Keywords[id]=kwin,window,pengelola,efek,sudut,,tepi,bingkai,aksi,alihkan,desktop,tepian layar kwin,tepian desktop,tepian layar,maksimalkan window,ubinkan window,sisi layar,perilaku layar,alihkan desktop,virtualkan desktop,sudut layar X-KDE-Keywords[it]=kwin,finestra,gestore,effetto,angolo,bordo,azione,scambiatore,desktop,bordi schermo kwin,bordi desktop,bordi schermo,massimizza finestre,affianca finestre,lato dello schermo,comportamento schermo,scambia desktop,desktop virtuale,angoli dello schermo X-KDE-Keywords[ko]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,창,관리자,효과,경계,경계선,동작,액션,전환,kwin 화면 경계,화면 경계,창 최대화,최대화,바둑판식 배열,화면 행동,데스크톱 전환,가상 데스크톱,화면 모서리,꼭짓점,바탕 화면 전환,가상 바탕 화면 X-KDE-Keywords[lt]=kwin,langas,langų,lango,langu,tvarkytuvė,tvarkytuve,efektas,efektai,kampas,kampai,kraštas,krastas,veiksmas,veiksmai,perjungti,perjungiklis,darbalaukis,darbalaukio,kwin ekrano kraštai,kwin ekrano kraštas,kwin ekrano krastas,kwin ekrano krastai,darbalaukio kraštai,darbalaukio kraštas,darbalaukio krastas,darbalaukio krastai,ekrano kraštai,ekrano krastai,ekrano kraštas,ekrano krastas,išskleisti langus,isskleisti langus,langų išskleidimas,langu isskleidimas,lango išskleidimas,lango isskleidimas,išskleisti langą,isskleisti langa,iškloti langą,iškloti langus,iskloti langa,iskloti langus,ekrano šonas,ekrano sonas,ekrano pusė,ekrano puse,ekrano šonai,ekrano sonai,ekrano elgsena,ekrano elgesys,perjungti darbalaukį,perjungti darbalauki,darbalaukio perjungimas,virtualus darbalaukis,virtualūs darbalaukiai,virtualus darbalaukiai,ekrano kampas,ekrano kampai X-KDE-Keywords[nb]=kwin,vindu,behandler,effekt,kant,hjørne,ramme,handling,bytte,skrivebord,kwin skjermkanter,skrivebordkanter,skjermkanter,maksimere vinduer,flislegge vinduer,skjermside,skjermoppførsel,bytte skrivebord,virtuelt skrivebord,skjermhjørner X-KDE-Keywords[nds]=KWin,Finster,Pleger,Effekt,Hörn,Kant,Rahmen,Akschoon,wesseln,Schriefdisch,maximeren,kacheln,Schirmkant,Schirmbedregen,Schirmhuuk X-KDE-Keywords[nl]=kwin,venster,beheerder,effect,hoek,kant,rand,actie,omschakelen,bureaublad,schermranden van kwin,bureaubladkanten,schermkanten,vensters maximaliseren,venster schuin achter elkaar,zijkant van het scherm,schermgedrag,bureaublad omschakelen,virtueel bureaublad,schermhoeken X-KDE-Keywords[nn]=kwin,vindauge,handsamar,effekt,kant,hjørne,ramme,handling,byte,skrivebord,kwin skjermkantar,skrivebordskantar,skjermkantar,maksimera vindauge,flisleggja vindauge,skjermside,skjermåtferd,byte skrivebord,virtuelt skrivebord,skjermhjørne X-KDE-Keywords[pl]=kwin,okno,menadżer,efekt,narożnik,krawędź,obramowanie,działanie,przełącz,pulpit, krawędzie ekranu kwin,krawędzie pulpitu,krawędzie ekranu,maksymalizacja okien, kafelkowanie okien,strona ekranu,zachowanie ekranu,przełączanie pulpitu,wirtualny pulpit, krawędzie ekranu X-KDE-Keywords[pt]=kwin,janela,gestor,efeito,extremo,contorno,acção,mudar,ecrã,extremos do ecrã no kwin,extremos do ecrã,maximizar as janelas,janelas lado-a-lado,lado do ecrã,comportamento do ecrã,mudar de ecrã,ecrã virtual,cantos do ecrã X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,efeito,canto,contorno,borda,ação,mudar,área de trabalho,cantos da área de trabalho no kwin,cantos da área de trabalho,maximizar as janelas,janelas lado a lado,lado da tela,comportamento da tela,mudar de área de trabalho virtual,desktop,cantos da tela X-KDE-Keywords[ru]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,окно,окон,диспетчер,эффект,край,граница,действие,переключить,рабочий стол,края экрана kwin,края экрана,края рабочего стола,распахнуть окна,мозаика окон,край экрана,поведение экрана,переключить рабочий стол,виртуальный рабочий стол,углы рабочего стола,углы экрана X-KDE-Keywords[sk]=kwin,okno, správca,efekt,okraj,hrana,akcia,prepnúť,plocha,okraje obrazovky kwin, efekty plochy,okraje obrazovky,maximalizovať okná,dlaždicové okná,strana obrazovky, správanie obrazovky,prepnúť plochu,virtuálna plocha,okraje obrazovky X-KDE-Keywords[sl]=kwin,okno,upravljalnik oken,upravljanje oken,učinki,kot,rob,obroba,dejanje,preklopi,preklapljanje,robovi zaslona,robovi namizja,razpni okna,povečaj okna,tlakuj okna,rob zaslona,obnašanje zaslona,preklopi namizje,preklapljanje namizij,navidezno namizje,koti zaslona X-KDE-Keywords[sr]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,К‑вин,прозор,менаџер,ефекат,угао,ивица,радња,пребаци,површ,ивице екрана,ивице површи,максимизовање прозора,поплочавање прозора,странице прозора,понашање прозора,мењање површи,виртуелна површ,углови екрана X-KDE-Keywords[sr@ijekavian]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,К‑вин,прозор,менаџер,ефекат,угао,ивица,радња,пребаци,површ,ивице екрана,ивице површи,максимизовање прозора,поплочавање прозора,странице прозора,понашање прозора,мењање површи,виртуелна површ,углови екрана X-KDE-Keywords[sr@ijekavianlatin]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,KWin,prozor,menadžer,efekat,ugao,ivica,radnja,prebaci,površ,ivice ekrana,ivice površi,maksimizovanje prozora,popločavanje prozora,stranice prozora,ponašanje prozora,menjanje površi,virtuelna površ,uglovi ekrana X-KDE-Keywords[sr@latin]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,KWin,prozor,menadžer,efekat,ugao,ivica,radnja,prebaci,površ,ivice ekrana,ivice površi,maksimizovanje prozora,popločavanje prozora,stranice prozora,ponašanje prozora,menjanje površi,virtuelna površ,uglovi ekrana X-KDE-Keywords[sv]=kwin,fönster,hanterare,effekt,kant,gräns,åtgärd,byta,skrivbord,kwin skärmkanter,skrivbordskanter,maximera fönster,lägg fönster sida vid sida,skärmsidan, skärmbeteende,skrivbordsbyte,virtuellt skrivbord,skärmhörn X-KDE-Keywords[tr]=kwin,pencere,yönetici,efekt,kenar,kenarlık,eylem,seç,masaüstü,kwin ekran kenarlıkları,kenarlıklar,masaüstü kenarları,ekran kenarları,pencereleri büyüt,pencereleri döşe,ekranın kenarı,ekran davranışı,masaüstünü seç,sanal masaüstü,ekran köşeleri X-KDE-Keywords[uk]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,вікно,керування,край,кут,межа,сторона,бік,дія,перемикання,стільниця,краї екрана,максимізація,мозаїка,плитка,край екрана,поведінка екрана,перемикання стільниць,віртуальна стільниця X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxeffectxx,xxcornerxx,xxedgexx,xxborderxx,xxactionxx,xxswitchxx,xxdesktopxx,xxkwin screen edgesxx,xxdesktop edgesxx,xxscreen edgesxx,xxmaximize windowsxx,xxtile windowsxx,xxside of screenxx,xxscreen behaviorxx,xxswitch desktopxx,xxvirtual desktopxx,xxscreen cornersxx X-KDE-Keywords[zh_CN]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,窗口,管理,特效,角,边缘,动作,切换,桌面,kwin 屏幕边缘,屏幕边缘,桌面边缘,最大化窗口,平铺窗口,屏幕行为,桌面切换,虚拟桌面,屏幕角落 X-KDE-Keywords[zh_TW]= kwin,window,manager,effect,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners diff --git a/kcmkwin/kwinscreenedges/kwintouchscreen.desktop b/kcmkwin/kwinscreenedges/kwintouchscreen.desktop index 2099988fa..baa9e48af 100644 --- a/kcmkwin/kwinscreenedges/kwintouchscreen.desktop +++ b/kcmkwin/kwinscreenedges/kwintouchscreen.desktop @@ -1,118 +1,119 @@ [Desktop Entry] Exec=kcmshell5 kwintouchscreen Icon=preferences-desktop-gestures-touch Type=Service X-KDE-ServiceTypes=KCModule X-KDE-Library=kcm_kwintouchscreen X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=desktopbehavior X-KDE-Weight=50 Name=Touch Screen Name[ast]=Pantalla táutil Name[ca]=Pantalla tàctil Name[ca@valencia]=Pantalla tàctil Name[cs]=Dotyková obrazovka Name[da]=Touchskærm Name[de]=Touchscreen Name[el]=Οθόνη αφής Name[en_GB]=Touch Screen Name[es]=Pantalla táctil Name[et]=Puuteekraan Name[eu]=Ukimen-pantaila Name[fi]=Kosketusnäyttö Name[fr]=Écran tactile Name[gl]=Pantalla táctil Name[he]=מסך מגע Name[hu]=Érintőképernyő Name[ia]=Schermo a tacto Name[id]=Layar Sentuh Name[it]=Schermo a sfioramento Name[ko]=터치 스크린 Name[lt]=Jutiklinis ekranas Name[nl]=Aanraakscherm Name[nn]=Trykkskjerm Name[pa]=ਟੱਚ ਸਕਰੀਨ Name[pl]=Ekran dotykowy Name[pt]=Ecrã Táctil Name[pt_BR]=Touch Screen Name[ru]=Сенсорный экран Name[sk]=Dotyková obrazovka Name[sl]=Zaslon na dotik Name[sr]=Додирник Name[sr@ijekavian]=Додирник Name[sr@ijekavianlatin]=Dodirnik Name[sr@latin]=Dodirnik Name[sv]=Pekskärm Name[tr]=Dokunmatik Ekran Name[uk]=Сенсорна панель Name[x-test]=xxTouch Screenxx Name[zh_CN]=触摸屏 Name[zh_TW]=觸控螢幕 Comment=Configure touch screen swipe gestures Comment[ca]=Configura els gestos de lliscament en la pantalla tàctil Comment[da]=Indstil strygegestusser til touchskærme Comment[de]=Wischgesten für Touchscreens einrichten Comment[en_GB]=Configure touch screen swipe gestures Comment[es]=Configurar los gestos de deslizamiento en pantalla táctil Comment[et]=Puuteekraani žestide seadistamine Comment[eu]=Konfiguratu ukimen-pantailako kolpe arinen keinuak Comment[fi]=Aseta kosketusnäytön pyyhkäisyeleet Comment[fr]=Configurer les mouvements sur l'écran tactile Comment[gl]=Configurar os xestos de pantalla táctil Comment[hu]=Érintőképernyő-gesztusok beállítása Comment[id]=Konfigurasikan gestur usapan layar sentuh Comment[it]=Configura gesti dello schermo a sfioramento Comment[ko]=터치 스크린 밀기 제스처 설정 Comment[lt]=Konfigūruoti jutiklinio ekrano perbraukimų gestus Comment[nl]=Veeggebaren voor aanraakscherm configureren Comment[nn]=Set opp fingerrørsler på trykkskjerm Comment[pl]=Ustawienia gestów na ekranie dotykowym Comment[pt]=Configurar os gestos para deslizar o ecrã táctil Comment[pt_BR]=Configura os gestos na tela sensível ao toque Comment[ru]=Действия при проведении по сенсорному экрану Comment[sk]=Nastaviť ťahacie gestá dotykovej obrazovky +Comment[sl]=Nastavi kretnje vlečenja za zaslon na dotik Comment[sv]=Anpassa draggester för pekskärm Comment[uk]=Налаштовування жестів на сенсорній панелі Comment[x-test]=xxConfigure touch screen swipe gesturesxx Comment[zh_CN]=配置触摸屏滑动手势 Comment[zh_TW]=設定觸控螢幕滑動手勢 X-KDE-Keywords=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen X-KDE-Keywords[ca]=kwin,finestra,gestor,efecte,vora,frontera,acció,canvi,escriptori,vores de l'escriptori,vores de la pantalla,costat de la pantalla,comportament de la pantalla,pantalla tàctil X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,efecte,vora,borde,acció,canvi,escriptori,vores d'escriptori,vores de pantalla,costat de pantalla,comportament de la pantalla,pantalla tàctil X-KDE-Keywords[da]=kwin,vindue,håndtering,manager,effekt,hjørne,kant,handling,skift,skrivebord,kwin skærmkanter,skrivebordskanter,skærmkanter,maksimer vinduer,tile windows,fliser,felter,siden af skærmen,skærmens opførsel,touch,skift skrivebord,virtuelle skriveborde,skærmhjørner,hjørner X-KDE-Keywords[de]=KWin,Fenster,Verwaltung,Effekt,Kante,Rand,Aktion,Wechseln,Desktop,Arbeitsfläche,Bildschirmkanten,Desktopkanten,Bildschirmseite,Bildschirmverhalten,Touchscreen X-KDE-Keywords[el]=kwin,παράθυρο,διαχειριστής,εφέ,άκρη,περίγραμμα,ενέργεια,εναλλαγή,επιφάνεια εργασίας,άκρες επιφάνειας εργασίας,άκρες οθόνης,πλευρά οθόνης,συμπεριφορά οθόνης, οθόνη αφής X-KDE-Keywords[en_GB]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behaviour,touch screen X-KDE-Keywords[es]=kwin,ventana,gestor,efecto,esquina,borde,acción,cambiar,escritorio,bordes del escritorio,bordes de la pantalla,lado de la pantalla,comportamiento de la pantalla,pantalla táctil X-KDE-Keywords[et]=kwin,aken,haldur,efekt,nurk,serv,piire,toiming,lülitamine,töölaud,töölaua servad,ekraani servad,ekraani äär,ekraani käitumine,puuteekraan X-KDE-Keywords[eu]=kwin,leiho,kudeatzaile,efektu,izkin,ertz,ekintza,aldatu,mahaigain,mahaigainaren ertzak,pantailen ertzak,pantailaren aldea,pantailaren portaera,ukipen-pantaila X-KDE-Keywords[fi]=kwin,ikkuna,hallinta,tehoste,kulma,laita,reuna,toiminto,vaihda,työpöytä,työpöydän reunat,näytön reunat,näytön laita,näytön käyttäytyminen,kosketusnäyttö X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, effet, bord, bordure, action, bascule, bureau, bords du bureau, bords de l'écran, côté de l'écran, comportement de l'écran, écran tactile X-KDE-Keywords[gl]=kwin,window,xanela,manager,xestor,effect,efecto,edge,beira,bordo,contorno,esquina,border,action,acción,switch,cambiar,conmutar,trocar,desktop,escritorio,desktop edges,screen edges,pantalla,side of screen,screen behavior,comportamento,touch screen,táctil X-KDE-Keywords[hu]=kwin,ablak,kezelő,effektus,szél,szegély,művelet,váltás,asztal,asztalszél,képernyőszél,képernyőoldal,képernyő működése,érintőképernyő X-KDE-Keywords[id]=kwin,window,pengelola,efek,tepi,bingkai,aksi,alih,desktop,tepian desktop,tepian layar,sisi layar,perilaku layar,layar sentuh X-KDE-Keywords[it]=kwin,finestra,gestore,effetto,angolo,bordo,azione,scambiatore,desktop,bordi desktop,bordi schermo,lato dello schermo,comportamento schermo,schermo a sfioramento X-KDE-Keywords[ko]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,창,관리자,효과,경계,경계선,동작,액션,데스크톱,화면 경계,경계,터치,터치 스크린,터치스크린,바탕 화면 X-KDE-Keywords[lt]=kwin,lango,langų,langu,tvarkytuvė,tvarkytuve,efektas,efektai,kraštas,krastas,rėmelis,remelis,rėmas,remas,veiksmas,veiksmai,perjungti,perjugimo,perjungimas,darbalaukis,darbalaukio,darbalaukio kraštai,darbalaukio kraštas,darbalaukio krastai,darbalaukio krastas,ekrano kraštai,ekrano krastai,ekrano kraštas,ekrano krastas,ekrano šonas,ekrano sonas,ekrano pusė,ekrano puse,ekrano elgsena,ekrano elgsesys,jutiklinis ekranas,jutiminis ekranas,jautrusis ekranas,touchscreen,touch screen X-KDE-Keywords[nl]=kwin,venster,beheerder,effect,kant,rand,actie,omschakelen,bureaublad,bureaubladkanten,schermkanten,zijkant van het scherm,schermgedrag,aanraakscherm X-KDE-Keywords[nn]=kwin,vindauge,handsamar,effekt,kant,ramme,handling,byte,skrivebord,skrivebordkantar,skjermkantar,skjermside,skjermåtferd,trykkskjerm X-KDE-Keywords[pl]=kwin,okno,menadżer,efekt,krawędź,obramowanie,działanie,przełącz,pulpit,krawędzie pulpitu,krawędzie ekranu,strona ekranu,zachowanie ekranu,ekran dotykowy X-KDE-Keywords[pt]=kwin,janela,gestor,efeito,extremo,contorno,acção,mudar,ecrã,extremos do ecrã no kwin,extremos do ecrã,maximizar as janelas,janelas lado-a-lado,lado do ecrã,comportamento do ecrã,ecrã táctil X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,efeito,canto,contorno,borda,ação,mudar,área de trabalho,cantos da área de trabalho, desktop,lado da tela,comportamento da tela,touch screen X-KDE-Keywords[ru]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,окно,окон,диспетчер,эффект,край,граница,действие,переключить,рабочий стол,края экрана kwin,края экрана,края рабочего стола,распахнуть окна,мозаика окон,край экрана,поведение экрана,переключить рабочий стол,виртуальный рабочий стол,углы рабочего стола,углы экрана,тачскрин,сенсорный экран,touch screen X-KDE-Keywords[sk]=Kwin, okná, manažér, efekt, okraj, hranice, akcie, prepínač, desktop, okraje plochy,Okraje obrazovky, bočná strana obrazovky, správanie obrazovky, dotyková obrazovka X-KDE-Keywords[sl]=kwin,okno,upravljalnik oken,upravljanje oken,učinki,rob,obroba,dejanje,preklopi,preklapljanje,robovi namizja,robovi zaslona,rob zaslona,obnašanje zaslona,zaslon na dotik X-KDE-Keywords[sr]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,К‑вин,прозор,менаџер,ефекат,ивица,радња,пребаци,површ,ивице екрана,ивице површи,странице прозора,понашање прозора,додирник X-KDE-Keywords[sr@ijekavian]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,К‑вин,прозор,менаџер,ефекат,ивица,радња,пребаци,површ,ивице екрана,ивице површи,странице прозора,понашање прозора,додирник X-KDE-Keywords[sr@ijekavianlatin]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,KWin,prozor,menadžer,efekat,ivica,radnja,prebaci,površ,ivice ekrana,ivice površi,stranice prozora,ponašanje prozora,dodirnik X-KDE-Keywords[sr@latin]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,KWin,prozor,menadžer,efekat,ivica,radnja,prebaci,površ,ivice ekrana,ivice površi,stranice prozora,ponašanje prozora,dodirnik X-KDE-Keywords[sv]=kwin,fönster,hanterare,effekt,kant,gräns,åtgärd,byta,skrivbord,skrivbordskanter,skärmkanter,skärmsidan,skärmbeteende,pekskärm X-KDE-Keywords[tr]=kwin,pencere,yönetici,efekt,kenar,sınır,eylem,geçiş,masaüstü,masaüstü kenarları,ekran kenarları,ekranın yan tarafı,ekran davranışı,dokunmatik ekran X-KDE-Keywords[uk]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen,вікно,керування,край,кут,межа,сторона,бік,дія,перемикання,стільниця,плитка,край екрана,поведінка екрана,перемикання стільниць,віртуальна стільниця,сенсорна панель X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxeffectxx,xxedgexx,xxborderxx,xxactionxx,xxswitchxx,xxdesktopxx,xxdesktop edgesxx,xxscreen edgesxx,xxside of screenxx,xxscreen behaviorxx,xxtouch screenxx X-KDE-Keywords[zh_CN]=kwin,window,manager,effect,corner,edge,border,action,switch,desktop,kwin screen edges,desktop edges,screen edges,maximize windows,tile windows,side of screen,screen behavior,switch desktop,virtual desktop,screen corners,窗口,管理,特效,角,边缘,动作,切换,桌面,kwin 屏幕边缘,屏幕边缘,桌面边缘,最大化窗口,平铺窗口,屏幕行为,桌面切换,虚拟桌面,屏幕角落 X-KDE-Keywords[zh_TW]=kwin,window,manager,effect,edge,border,action,switch,desktop,desktop edges,screen edges,side of screen,screen behavior,touch screen diff --git a/kcmkwin/kwintabbox/CMakeLists.txt b/kcmkwin/kwintabbox/CMakeLists.txt index da71fdcf1..6a7fc3515 100644 --- a/kcmkwin/kwintabbox/CMakeLists.txt +++ b/kcmkwin/kwintabbox/CMakeLists.txt @@ -1,42 +1,43 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwintabbox\") include_directories(${KWin_SOURCE_DIR}/effects ${KWin_SOURCE_DIR}/tabbox ${KWin_SOURCE_DIR}) ########### next target ############### set(kcm_kwintabbox_PART_SRCS ${KWin_SOURCE_DIR}/tabbox/tabboxconfig.cpp layoutpreview.cpp main.cpp thumbnailitem.cpp + kwintabboxconfigform.cpp ) ki18n_wrap_ui(kcm_kwintabbox_PART_SRCS main.ui) qt5_add_dbus_interface(kcm_kwintabbox_PART_SRCS ${KWin_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface) kconfig_add_kcfg_files(kcm_kwintabbox_PART_SRCS kwintabboxsettings.kcfgc kwinswitcheffectsettings.kcfgc kwinpluginssettings.kcfgc) add_library(kcm_kwintabbox MODULE ${kcm_kwintabbox_PART_SRCS}) target_link_libraries(kcm_kwintabbox Qt5::Quick KF5::Completion KF5::GlobalAccel KF5::I18n KF5::KCMUtils KF5::NewStuff KF5::Package KF5::Service XCB::XCB kwin4_effect_builtins ) install(TARGETS kcm_kwintabbox DESTINATION ${PLUGIN_INSTALL_DIR} ) ########### install files ############### install(FILES kwintabbox.desktop DESTINATION ${SERVICES_INSTALL_DIR}) install(FILES thumbnails/konqueror.png thumbnails/kmail.png thumbnails/systemsettings.png thumbnails/dolphin.png DESTINATION ${DATA_INSTALL_DIR}/kwin/kcm_kwintabbox) install(FILES kwinswitcher.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR}) diff --git a/kcmkwin/kwintabbox/kwintabboxconfigform.cpp b/kcmkwin/kwintabbox/kwintabboxconfigform.cpp new file mode 100644 index 000000000..cdd6a4eb4 --- /dev/null +++ b/kcmkwin/kwintabbox/kwintabboxconfigform.cpp @@ -0,0 +1,353 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Martin Gräßlin +Copyright (C) 2020 Cyril Rossi + +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 "kwintabboxconfigform.h" +#include "ui_main.h" + +#include + +#include +#include +#include + + +namespace KWin +{ + +using namespace TabBox; + +KWinTabBoxConfigForm::KWinTabBoxConfigForm(TabboxType type, QWidget *parent) + : QWidget(parent) + , m_type(type) + , ui(new Ui::KWinTabBoxConfigForm) +{ + ui->setupUi(this); + + ui->effectConfigButton->setIcon(QIcon::fromTheme(QStringLiteral("view-preview"))); + + if (QApplication::screens().count() < 2) { + ui->filterScreens->hide(); + ui->screenFilter->hide(); + } + + connect(ui->effectConfigButton, &QPushButton::clicked, this, &KWinTabBoxConfigForm::effectConfigButtonClicked); + + connect(ui->kcfg_ShowTabBox, SIGNAL(clicked(bool)), SLOT(tabBoxToggled(bool))); + + connect(ui->filterScreens, SIGNAL(clicked(bool)), SLOT(onFilterScreen())); + connect(ui->currentScreen, SIGNAL(clicked(bool)), SLOT(onFilterScreen())); + connect(ui->otherScreens, SIGNAL(clicked(bool)), SLOT(onFilterScreen())); + + connect(ui->filterDesktops, SIGNAL(clicked(bool)), SLOT(onFilterDesktop())); + connect(ui->currentDesktop, SIGNAL(clicked(bool)), SLOT(onFilterDesktop())); + connect(ui->otherDesktops, SIGNAL(clicked(bool)), SLOT(onFilterDesktop())); + + connect(ui->filterActivities, SIGNAL(clicked(bool)), SLOT(onFilterActivites())); + connect(ui->currentActivity, SIGNAL(clicked(bool)), SLOT(onFilterActivites())); + connect(ui->otherActivities, SIGNAL(clicked(bool)), SLOT(onFilterActivites())); + + connect(ui->filterMinimization, SIGNAL(clicked(bool)), SLOT(onFilterMinimization())); + connect(ui->visibleWindows, SIGNAL(clicked(bool)), SLOT(onFilterMinimization())); + connect(ui->hiddenWindows, SIGNAL(clicked(bool)), SLOT(onFilterMinimization())); + + connect(ui->oneAppWindow, SIGNAL(clicked(bool)), SLOT(onApplicationMode())); + connect(ui->showDesktop, SIGNAL(clicked(bool)), SLOT(onShowDesktopMode())); + + connect(ui->switchingModeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onSwitchingMode())); + connect(ui->effectCombo, SIGNAL(currentIndexChanged(int)), SLOT(onEffectCombo())); + + auto addShortcut = [this](const char *name, KKeySequenceWidget *widget, const QKeySequence &sequence = QKeySequence()) { + QAction *a = m_actionCollection->addAction(name); + a->setProperty("isConfigurationAction", true); + widget->setProperty("shortcutAction", name); + a->setText(i18n(name)); + KGlobalAccel::self()->setShortcut(a, QList() << sequence); + connect(widget, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(shortcutChanged(QKeySequence))); + }; + + // Shortcut config. The shortcut belongs to the component "kwin"! + m_actionCollection = new KActionCollection(this, QStringLiteral("kwin")); + m_actionCollection->setComponentDisplayName(i18n("KWin")); + m_actionCollection->setConfigGroup("Navigation"); + m_actionCollection->setConfigGlobal(true); + + if (TabboxType::Main == m_type) { + addShortcut("Walk Through Windows", ui->scAll, Qt::ALT + Qt::Key_Tab); + addShortcut("Walk Through Windows (Reverse)", ui->scAllReverse, Qt::ALT + Qt::SHIFT + Qt::Key_Backtab); + addShortcut("Walk Through Windows of Current Application", ui->scCurrent, Qt::ALT + Qt::Key_QuoteLeft); + addShortcut("Walk Through Windows of Current Application (Reverse)", ui->scCurrentReverse, Qt::ALT + Qt::Key_AsciiTilde); + } else if (TabboxType::Alternative == m_type) { + addShortcut("Walk Through Windows Alternative", ui->scAll); + addShortcut("Walk Through Windows Alternative (Reverse)", ui->scAllReverse); + addShortcut("Walk Through Windows of Current Application Alternative", ui->scCurrent); + addShortcut("Walk Through Windows of Current Application Alternative (Reverse)", ui->scCurrentReverse); + } +} + +KWinTabBoxConfigForm::~KWinTabBoxConfigForm() +{ + delete ui; +} + +bool KWinTabBoxConfigForm::highlightWindows() const +{ + return ui->kcfg_HighlightWindows->isChecked(); +} + +bool KWinTabBoxConfigForm::showTabBox() const +{ + return ui->kcfg_ShowTabBox->isChecked(); +} + +int KWinTabBoxConfigForm::filterScreen() const +{ + if (ui->filterScreens->isChecked()) { + return ui->currentScreen->isChecked() ? TabBoxConfig::OnlyCurrentScreenClients : TabBoxConfig::ExcludeCurrentScreenClients; + } else { + return TabBoxConfig::IgnoreMultiScreen; + } +} + +int KWinTabBoxConfigForm::filterDesktop() const +{ + if (ui->filterDesktops->isChecked()) { + return ui->currentDesktop->isChecked() ? TabBoxConfig::OnlyCurrentDesktopClients : TabBoxConfig::ExcludeCurrentDesktopClients; + } else { + return TabBoxConfig::AllDesktopsClients; + } +} + +int KWinTabBoxConfigForm::filterActivities() const +{ + if (ui->filterActivities->isChecked()) { + return ui->currentActivity->isChecked() ? TabBoxConfig::OnlyCurrentActivityClients : TabBoxConfig::ExcludeCurrentActivityClients; + } else { + return TabBoxConfig::AllActivitiesClients; + } +} + +int KWinTabBoxConfigForm::filterMinimization() const +{ + if (ui->filterMinimization->isChecked()) { + return ui->visibleWindows->isChecked() ? TabBoxConfig::ExcludeMinimizedClients : TabBoxConfig::OnlyMinimizedClients; + } else { + return TabBoxConfig::IgnoreMinimizedStatus; + } +} + +int KWinTabBoxConfigForm::applicationMode() const +{ + return ui->oneAppWindow->isChecked() ? TabBoxConfig::OneWindowPerApplication : TabBoxConfig::AllWindowsAllApplications; +} + +int KWinTabBoxConfigForm::showDesktopMode() const +{ + return ui->showDesktop->isChecked() ? TabBoxConfig::ShowDesktopClient : TabBoxConfig::DoNotShowDesktopClient; +} + +int KWinTabBoxConfigForm::switchingMode() const +{ + return ui->switchingModeCombo->currentIndex(); +} + +QString KWinTabBoxConfigForm::layoutName() const +{ + return ui->effectCombo->currentData().toString(); +} + +void KWinTabBoxConfigForm::setFilterScreen(TabBox::TabBoxConfig::ClientMultiScreenMode mode) +{ + ui->filterScreens->setChecked(mode != TabBoxConfig::IgnoreMultiScreen); + ui->currentScreen->setChecked(mode == TabBoxConfig::OnlyCurrentScreenClients); + ui->otherScreens->setChecked(mode == TabBoxConfig::ExcludeCurrentScreenClients); +} + +void KWinTabBoxConfigForm::setFilterDesktop(TabBox::TabBoxConfig::ClientDesktopMode mode) +{ + ui->filterDesktops->setChecked(mode != TabBoxConfig::AllDesktopsClients); + ui->currentDesktop->setChecked(mode == TabBoxConfig::OnlyCurrentDesktopClients); + ui->otherDesktops->setChecked(mode == TabBoxConfig::ExcludeCurrentDesktopClients); +} + +void KWinTabBoxConfigForm::setFilterActivities(TabBox::TabBoxConfig::ClientActivitiesMode mode) +{ + ui->filterActivities->setChecked(mode != TabBoxConfig::AllActivitiesClients); + ui->currentActivity->setChecked(mode == TabBoxConfig::OnlyCurrentActivityClients); + ui->otherActivities->setChecked(mode == TabBoxConfig::ExcludeCurrentActivityClients); +} + +void KWinTabBoxConfigForm::setFilterMinimization(TabBox::TabBoxConfig::ClientMinimizedMode mode) +{ + ui->filterMinimization->setChecked(mode != TabBoxConfig::IgnoreMinimizedStatus); + ui->visibleWindows->setChecked(mode == TabBoxConfig::ExcludeMinimizedClients); + ui->hiddenWindows->setChecked(mode == TabBoxConfig::OnlyMinimizedClients); +} + +void KWinTabBoxConfigForm::setApplicationMode(TabBox::TabBoxConfig::ClientApplicationsMode mode) +{ + ui->oneAppWindow->setChecked(mode == TabBoxConfig::OneWindowPerApplication); +} + +void KWinTabBoxConfigForm::setShowDesktopMode(TabBox::TabBoxConfig::ShowDesktopMode mode) +{ + ui->showDesktop->setChecked(mode == TabBoxConfig::ShowDesktopClient); +} + +void KWinTabBoxConfigForm::setSwitchingModeChanged(TabBox::TabBoxConfig::ClientSwitchingMode mode) +{ + ui->switchingModeCombo->setCurrentIndex(mode); +} + +void KWinTabBoxConfigForm::setLayoutName(const QString &layoutName) +{ + ui->effectCombo->setCurrentIndex(ui->effectCombo->findData(layoutName)); +} + +void KWinTabBoxConfigForm::setEffectComboModel(QStandardItemModel *model) +{ + int index = ui->effectCombo->currentIndex(); + QVariant data = ui->effectCombo->itemData(index); + + ui->effectCombo->setModel(model); + + if (data.isValid()) { + ui->effectCombo->setCurrentIndex(ui->effectCombo->findData(data)); + } else if (index != -1) { + ui->effectCombo->setCurrentIndex(index); + } +} + +QVariant KWinTabBoxConfigForm::effectComboCurrentData(int role) const +{ + return ui->effectCombo->currentData(role); +} + +void KWinTabBoxConfigForm::loadShortcuts() +{ + auto loadShortcut = [this](KKeySequenceWidget *widget) { + QString actionName = widget->property("shortcutAction").toString(); + qDebug() << "load shortcut for " << actionName; + if (QAction *action = m_actionCollection->action(actionName)) { + auto shortcuts = KGlobalAccel::self()->shortcut(action); + if (!shortcuts.isEmpty()) { + widget->setKeySequence(shortcuts.first()); + } + } + }; + + loadShortcut(ui->scAll); + loadShortcut(ui->scAllReverse); + loadShortcut(ui->scCurrent); + loadShortcut(ui->scCurrentReverse); +} + +void KWinTabBoxConfigForm::resetShortcuts() +{ + QString action; + auto resetShortcut = [this](KKeySequenceWidget *widget, const QKeySequence &sequence = QKeySequence()) { + const QString action = widget->property("shortcutAction").toString(); + QAction *a = m_actionCollection->action(action); + KGlobalAccel::self()->setShortcut(a, QList() << sequence, KGlobalAccel::NoAutoloading); + }; + if (TabboxType::Main == m_type) { + resetShortcut(ui->scAll, Qt::ALT + Qt::Key_Tab); + resetShortcut(ui->scAllReverse, Qt::ALT + Qt::SHIFT + Qt::Key_Backtab); + resetShortcut(ui->scCurrent, Qt::ALT + Qt::Key_QuoteLeft); + resetShortcut(ui->scCurrentReverse, Qt::ALT + Qt::Key_AsciiTilde); + } else if (TabboxType::Alternative == m_type) { + resetShortcut(ui->scAll); + resetShortcut(ui->scAllReverse); + resetShortcut(ui->scCurrent); + resetShortcut(ui->scCurrentReverse); + } + m_actionCollection->writeSettings(); +} + +void KWinTabBoxConfigForm::tabBoxToggled(bool on) +{ + // Highlight Windows options is availabled if no TabBox effect is selected + // or if Tabbox is not builtin effet. + on = !on || ui->effectCombo->currentData(AddonEffect).toBool(); + ui->kcfg_HighlightWindows->setEnabled(on); +} + +void KWinTabBoxConfigForm::onFilterScreen() +{ + emit filterScreenChanged(filterScreen()); +} + +void KWinTabBoxConfigForm::onFilterDesktop() +{ + emit filterDesktopChanged(filterDesktop()); +} + +void KWinTabBoxConfigForm::onFilterActivites() +{ + emit filterActivitiesChanged(filterActivities()); +} + +void KWinTabBoxConfigForm::onFilterMinimization() +{ + emit filterMinimizationChanged(filterMinimization()); +} + +void KWin::KWinTabBoxConfigForm::onApplicationMode() +{ + emit applicationModeChanged(applicationMode()); +} + +void KWinTabBoxConfigForm::onShowDesktopMode() +{ + emit showDesktopModeChanged(showDesktopMode()); +} + +void KWinTabBoxConfigForm::onSwitchingMode() +{ + emit switchingModeChanged(switchingMode()); +} + +void KWinTabBoxConfigForm::onEffectCombo() +{ + const bool isAddonEffect = ui->effectCombo->currentData(AddonEffect).toBool(); + ui->effectConfigButton->setIcon(QIcon::fromTheme(isAddonEffect ? "view-preview" : "configure")); + if (!ui->kcfg_ShowTabBox->isChecked()) { + return; + } + ui->kcfg_HighlightWindows->setEnabled(isAddonEffect); + + emit layoutNameChanged(layoutName()); +} + +void KWinTabBoxConfigForm::shortcutChanged(const QKeySequence &seq) +{ + QString action; + if (sender()) { + action = sender()->property("shortcutAction").toString(); + } + if (action.isEmpty()) { + return; + } + QAction *a = m_actionCollection->action(action); + KGlobalAccel::self()->setShortcut(a, QList() << seq, KGlobalAccel::NoAutoloading); + m_actionCollection->writeSettings(); +} + +} // namespace diff --git a/kcmkwin/kwintabbox/kwintabboxconfigform.h b/kcmkwin/kwintabbox/kwintabboxconfigform.h new file mode 100644 index 000000000..08fabde5f --- /dev/null +++ b/kcmkwin/kwintabbox/kwintabboxconfigform.h @@ -0,0 +1,122 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Martin Gräßlin +Copyright (C) 2020 Cyril Rossi + +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 __KWINTABBOXCONFIGFORM_H__ +#define __KWINTABBOXCONFIGFORM_H__ + +#include +#include + +#include "tabboxconfig.h" + +class KShortcutsEditor; +class KActionCollection; + +namespace Ui +{ +class KWinTabBoxConfigForm; +} + +namespace KWin +{ + +class KWinTabBoxConfigForm : public QWidget +{ + Q_OBJECT + +public: + enum class TabboxType + { + Main, + Alternative, + }; + + + enum EffectComboRole + { + LayoutPath = Qt::UserRole + 1, + AddonEffect, // i.e not builtin effects + }; + + explicit KWinTabBoxConfigForm(TabboxType type, QWidget *parent = nullptr); + ~KWinTabBoxConfigForm() override; + + bool highlightWindows() const; + bool showTabBox() const; + int filterScreen() const; + int filterDesktop() const; + int filterActivities() const; + int filterMinimization() const; + int applicationMode() const; + int showDesktopMode() const; + int switchingMode() const; + QString layoutName() const; + + void setFilterScreen(TabBox::TabBoxConfig::ClientMultiScreenMode mode); + void setFilterDesktop(TabBox::TabBoxConfig::ClientDesktopMode mode); + void setFilterActivities(TabBox::TabBoxConfig::ClientActivitiesMode mode); + void setFilterMinimization(TabBox::TabBoxConfig::ClientMinimizedMode mode); + void setApplicationMode(TabBox::TabBoxConfig::ClientApplicationsMode mode); + void setShowDesktopMode(TabBox::TabBoxConfig::ShowDesktopMode mode); + void setSwitchingModeChanged(TabBox::TabBoxConfig::ClientSwitchingMode mode); + void setLayoutName(const QString &layoutName); + + // EffectCombo Data Model + void setEffectComboModel(QStandardItemModel *model); + QVariant effectComboCurrentData(int role = Qt::UserRole) const; + + void loadShortcuts(); + void resetShortcuts(); + +Q_SIGNALS: + void filterScreenChanged(int value); + void filterDesktopChanged(int value); + void filterActivitiesChanged(int value); + void filterMinimizationChanged(int value); + void applicationModeChanged(int value); + void showDesktopModeChanged(int value); + void switchingModeChanged(int value); + void layoutNameChanged(const QString &layoutName); + void effectConfigButtonClicked(); + +private Q_SLOTS: + void tabBoxToggled(bool on); + void onFilterScreen(); + void onFilterDesktop(); + void onFilterActivites(); + void onFilterMinimization(); + void onApplicationMode(); + void onShowDesktopMode(); + void onSwitchingMode(); + void onEffectCombo(); + void shortcutChanged(const QKeySequence &seq); + +private: + KActionCollection *m_actionCollection = nullptr; + KShortcutsEditor *m_editor = nullptr; + + TabboxType m_type; + Ui::KWinTabBoxConfigForm *ui; +}; + +} // namespace + +#endif diff --git a/kcmkwin/kwintabbox/main.cpp b/kcmkwin/kwintabbox/main.cpp index 551cabf0b..20897de92 100644 --- a/kcmkwin/kwintabbox/main.cpp +++ b/kcmkwin/kwintabbox/main.cpp @@ -1,565 +1,474 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 Martin Gräßlin Copyright (C) 2020 Cyril Rossi 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 "main.h" #include #include // Qt #include #include #include #include #include #include #include +#include #include #include +#include // KDE -#include #include -#include #include #include #include #include #include -#include #include // Plasma #include #include // own +#include "kwintabboxconfigform.h" #include "layoutpreview.h" #include "kwintabboxsettings.h" #include "kwinswitcheffectsettings.h" #include "kwinpluginssettings.h" K_PLUGIN_FACTORY(KWinTabBoxConfigFactory, registerPlugin();) namespace KWin { using namespace TabBox; -KWinTabBoxConfigForm::KWinTabBoxConfigForm(QWidget* parent) - : QWidget(parent) -{ - setupUi(this); -} KWinTabBoxConfig::KWinTabBoxConfig(QWidget* parent, const QVariantList& args) : KCModule(parent, args) , m_config(KSharedConfig::openConfig("kwinrc")) , m_tabBoxConfig(new TabBoxSettings(QStringLiteral("TabBox"), this)) , m_tabBoxAlternativeConfig(new TabBoxSettings(QStringLiteral("TabBoxAlternative"), this)) , m_coverSwitchConfig(new SwitchEffectSettings(QStringLiteral("Effect-CoverSwitch"), this)) , m_flipSwitchConfig(new SwitchEffectSettings(QStringLiteral("Effect-FlipSwitch"), this)) , m_pluginsConfig(new PluginsSettings(this)) { QTabWidget* tabWidget = new QTabWidget(this); - m_primaryTabBoxUi = new KWinTabBoxConfigForm(tabWidget); - m_alternativeTabBoxUi = new KWinTabBoxConfigForm(tabWidget); + m_primaryTabBoxUi = new KWinTabBoxConfigForm(KWinTabBoxConfigForm::TabboxType::Main, tabWidget); + m_alternativeTabBoxUi = new KWinTabBoxConfigForm(KWinTabBoxConfigForm::TabboxType::Alternative, tabWidget); tabWidget->addTab(m_primaryTabBoxUi, i18n("Main")); tabWidget->addTab(m_alternativeTabBoxUi, i18n("Alternative")); QPushButton* ghnsButton = new QPushButton(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Get New Task Switchers...")); connect(ghnsButton, SIGNAL(clicked(bool)), SLOT(slotGHNS())); QHBoxLayout* buttonBar = new QHBoxLayout(); QSpacerItem* buttonBarSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); buttonBar->addItem(buttonBarSpacer); buttonBar->addWidget(ghnsButton); QVBoxLayout* layout = new QVBoxLayout(this); KTitleWidget* infoLabel = new KTitleWidget(tabWidget); infoLabel->setText(i18n("Focus policy settings limit the functionality of navigating through windows."), KTitleWidget::InfoMessage); infoLabel->setPixmap(KTitleWidget::InfoMessage, KTitleWidget::ImageLeft); layout->addWidget(infoLabel,0); layout->addWidget(tabWidget,1); layout->addLayout(buttonBar); setLayout(layout); -#define ADD_SHORTCUT(_NAME_, _CUT_, _BTN_) \ - a = m_actionCollection->addAction(_NAME_);\ - a->setProperty("isConfigurationAction", true);\ - _BTN_->setProperty("shortcutAction", _NAME_);\ - a->setText(i18n(_NAME_));\ - KGlobalAccel::self()->setShortcut(a, QList() << _CUT_); \ - connect(_BTN_, SIGNAL(keySequenceChanged(QKeySequence)), SLOT(shortcutChanged(QKeySequence))) - - // Shortcut config. The shortcut belongs to the component "kwin"! - m_actionCollection = new KActionCollection(this, QStringLiteral("kwin")); - m_actionCollection->setComponentDisplayName(i18n("KWin")); - m_actionCollection->setConfigGroup("Navigation"); - m_actionCollection->setConfigGlobal(true); - QAction* a; - ADD_SHORTCUT("Walk Through Windows", Qt::ALT + Qt::Key_Tab, m_primaryTabBoxUi->scAll); - ADD_SHORTCUT("Walk Through Windows (Reverse)", Qt::ALT + Qt::SHIFT + Qt::Key_Backtab, - m_primaryTabBoxUi->scAllReverse); - ADD_SHORTCUT("Walk Through Windows Alternative", QKeySequence(), m_alternativeTabBoxUi->scAll); - ADD_SHORTCUT("Walk Through Windows Alternative (Reverse)", QKeySequence(), m_alternativeTabBoxUi->scAllReverse); - ADD_SHORTCUT("Walk Through Windows of Current Application", Qt::ALT + Qt::Key_QuoteLeft, - m_primaryTabBoxUi->scCurrent); - ADD_SHORTCUT("Walk Through Windows of Current Application (Reverse)", Qt::ALT + Qt::Key_AsciiTilde, - m_primaryTabBoxUi->scCurrentReverse); - ADD_SHORTCUT("Walk Through Windows of Current Application Alternative", QKeySequence(), m_alternativeTabBoxUi->scCurrent); - ADD_SHORTCUT("Walk Through Windows of Current Application Alternative (Reverse)", QKeySequence(), - m_alternativeTabBoxUi->scCurrentReverse); -#undef ADD_SHORTCUT + addConfig(m_tabBoxConfig, m_primaryTabBoxUi); + addConfig(m_tabBoxAlternativeConfig, m_alternativeTabBoxUi); - initLayoutLists(); - KWinTabBoxConfigForm *ui[2] = { m_primaryTabBoxUi, m_alternativeTabBoxUi }; - for (int i = 0; i < 2; ++i) { - ui[i]->effectConfigButton->setIcon(QIcon::fromTheme(QStringLiteral("view-preview"))); - - connect(ui[i]->highlightWindowCheck, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->showTabBox, SIGNAL(clicked(bool)), SLOT(tabBoxToggled(bool))); - connect(ui[i]->effectCombo, SIGNAL(currentIndexChanged(int)), SLOT(changed())); - connect(ui[i]->effectCombo, SIGNAL(currentIndexChanged(int)), SLOT(effectSelectionChanged(int))); - connect(ui[i]->effectConfigButton, SIGNAL(clicked(bool)), SLOT(configureEffectClicked())); - - connect(ui[i]->switchingModeCombo, SIGNAL(currentIndexChanged(int)), SLOT(changed())); - connect(ui[i]->showDesktop, SIGNAL(clicked(bool)), SLOT(changed())); - - connect(ui[i]->filterDesktops, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->currentDesktop, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->otherDesktops, SIGNAL(clicked(bool)), SLOT(changed())); - - connect(ui[i]->filterActivities, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->currentActivity, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->otherActivities, SIGNAL(clicked(bool)), SLOT(changed())); - - connect(ui[i]->filterScreens, SIGNAL(clicked(bool)), SLOT(changed())); - if (QApplication::screens().count() < 2) { - ui[i]->filterScreens->hide(); - ui[i]->screenFilter->hide(); - } else { - connect(ui[i]->currentScreen, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->otherScreens, SIGNAL(clicked(bool)), SLOT(changed())); - } + createConnections(m_primaryTabBoxUi, m_tabBoxConfig); + createConnections(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); - connect(ui[i]->oneAppWindow, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->filterMinimization, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->visibleWindows, SIGNAL(clicked(bool)), SLOT(changed())); - connect(ui[i]->hiddenWindows, SIGNAL(clicked(bool)), SLOT(changed())); - } + initLayoutLists(); // check focus policy - we don't offer configs for unreasonable focus policies KConfigGroup config(m_config, "Windows"); QString policy = config.readEntry("FocusPolicy", "ClickToFocus"); if ((policy == "FocusUnderMouse") || (policy == "FocusStrictlyUnderMouse")) { tabWidget->setEnabled(false); infoLabel->show(); } else { infoLabel->hide(); } } KWinTabBoxConfig::~KWinTabBoxConfig() { } - static QList availableLnFPackages() { QList packages; QStringList paths; const QStringList dataPaths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); for (const QString &path : dataPaths) { QDir dir(path + QLatin1String("/plasma/look-and-feel")); paths << dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); } const auto &p = paths; for (const QString &path : p) { KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); pkg.setPath(path); pkg.setFallbackPackage(KPackage::Package()); if (!pkg.filePath("defaults").isEmpty()) { KSharedConfigPtr conf = KSharedConfig::openConfig(pkg.filePath("defaults")); KConfigGroup cg = KConfigGroup(conf, "kwinrc"); cg = KConfigGroup(&cg, "WindowSwitcher"); if (!cg.readEntry("LayoutName", QString()).isEmpty()) { packages << pkg; } } } return packages; } void KWinTabBoxConfig::initLayoutLists() { // search the effect names - QString coverswitch = BuiltInEffects::effectData(BuiltInEffect::CoverSwitch).displayName; - QString flipswitch = BuiltInEffects::effectData(BuiltInEffect::FlipSwitch).displayName; + m_coverSwitch = BuiltInEffects::effectData(BuiltInEffect::CoverSwitch).name; + m_flipSwitch = BuiltInEffects::effectData(BuiltInEffect::FlipSwitch).name; QList offers = KPackage::PackageLoader::self()->listPackages("KWin/WindowSwitcher"); QStringList layoutNames, layoutPlugins, layoutPaths; const auto lnfPackages = availableLnFPackages(); for (const auto &package : lnfPackages) { const auto &metaData = package.metadata(); layoutNames << metaData.name(); layoutPlugins << metaData.pluginId(); layoutPaths << package.filePath("windowswitcher", QStringLiteral("WindowSwitcher.qml")); } for (const auto &offer : offers) { const QString pluginName = offer.pluginId(); if (offer.value("X-Plasma-API") != "declarativeappletscript") { continue; } //we don't have a proper servicetype if (offer.value("X-KWin-Exclude-Listing") == QStringLiteral("true")) { continue; } const QString scriptName = offer.value("X-Plasma-MainScript"); const QString scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kwin/tabbox/") + pluginName + QLatin1String("/contents/") + scriptName); if (scriptFile.isNull()) { continue; } layoutNames << offer.name(); layoutPlugins << pluginName; layoutPaths << scriptFile; } + KWinTabBoxConfigForm *ui[2] = { m_primaryTabBoxUi, m_alternativeTabBoxUi }; for (int i=0; i<2; ++i) { - int index = ui[i]->effectCombo->currentIndex(); - QVariant data = ui[i]->effectCombo->itemData(index); - ui[i]->effectCombo->clear(); - ui[i]->effectCombo->addItem(coverswitch); - ui[i]->effectCombo->addItem(flipswitch); + QStandardItemModel *model = new QStandardItemModel; + + QStandardItem *coverItem = new QStandardItem(BuiltInEffects::effectData(BuiltInEffect::CoverSwitch).displayName); + coverItem->setData(m_coverSwitch, Qt::UserRole); + coverItem->setData(false, KWinTabBoxConfigForm::AddonEffect); + model->appendRow(coverItem); + + QStandardItem *flipItem = new QStandardItem(BuiltInEffects::effectData(BuiltInEffect::FlipSwitch).displayName); + flipItem->setData(m_flipSwitch, Qt::UserRole); + flipItem->setData(false, KWinTabBoxConfigForm::AddonEffect); + model->appendRow(flipItem); + for (int j = 0; j < layoutNames.count(); ++j) { - ui[i]->effectCombo->addItem(layoutNames[j], layoutPlugins[j]); - ui[i]->effectCombo->setItemData(ui[i]->effectCombo->count() - 1, layoutPaths[j], Qt::UserRole+1); - } - if (data.isValid()) { - ui[i]->effectCombo->setCurrentIndex(ui[i]->effectCombo->findData(data)); - } else if (index != -1) { - ui[i]->effectCombo->setCurrentIndex(index); + QStandardItem *item = new QStandardItem(layoutNames[j]); + item->setData(layoutPlugins[j], Qt::UserRole); + item->setData(layoutPaths[j], KWinTabBoxConfigForm::LayoutPath); + item->setData(true, KWinTabBoxConfigForm::AddonEffect); + model->appendRow(item); } + model->sort(0); + ui[i]->setEffectComboModel(model); } } +void KWinTabBoxConfig::createConnections(KWinTabBoxConfigForm *form, TabBoxSettings *config) +{ + connect(form, SIGNAL(effectConfigButtonClicked()), this, SLOT(configureEffectClicked())); + + connect(form, SIGNAL(filterScreenChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(filterDesktopChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(filterActivitiesChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(filterMinimizationChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(applicationModeChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(showDesktopModeChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(switchingModeChanged(int)), this, SLOT(updateUnmanagedState())); + connect(form, SIGNAL(layoutNameChanged(QString)), this, SLOT(updateUnmanagedState())); +} + +void KWinTabBoxConfig::updateUnmanagedState() +{ + bool isNeedSave = false; + isNeedSave |= updateUnmanagedIsNeedSave(m_primaryTabBoxUi, m_tabBoxConfig); + isNeedSave |= updateUnmanagedIsNeedSave(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); + + unmanagedWidgetChangeState(isNeedSave); + + bool isDefault = true; + isDefault &= updateUnmanagedIsDefault(m_primaryTabBoxUi, m_tabBoxConfig); + isDefault &= updateUnmanagedIsDefault(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); + + unmanagedWidgetDefaultState(isDefault); +} + +bool KWinTabBoxConfig::updateUnmanagedIsNeedSave(const KWinTabBoxConfigForm *form, const TabBoxSettings *config) +{ + bool isNeedSave = false; + isNeedSave |= form->filterScreen() != config->multiScreenMode(); + isNeedSave |= form->filterDesktop() != config->desktopMode(); + isNeedSave |= form->filterActivities() != config->activitiesMode(); + isNeedSave |= form->filterMinimization() != config->minimizedMode(); + isNeedSave |= form->applicationMode() != config->applicationsMode(); + isNeedSave |= form->showDesktopMode() != config->showDesktopMode(); + isNeedSave |= form->switchingMode() != config->switchingMode(); + isNeedSave |= form->layoutName() != config->layoutName(); + + return isNeedSave; +} + +bool KWinTabBoxConfig::updateUnmanagedIsDefault(const KWinTabBoxConfigForm *form, const TabBoxSettings *config) +{ + bool isDefault = true; + isDefault &= form->filterScreen() == config->defaultMultiScreenModeValue(); + isDefault &= form->filterDesktop() == config->defaultDesktopModeValue(); + isDefault &= form->filterActivities() == config->defaultActivitiesModeValue(); + isDefault &= form->filterMinimization() == config->defaultMinimizedModeValue(); + isDefault &= form->applicationMode() == config->defaultApplicationsModeValue(); + isDefault &= form->showDesktopMode() == config->defaultShowDesktopModeValue(); + isDefault &= form->switchingMode() == config->defaultSwitchingModeValue(); + isDefault &= form->layoutName() == config->defaultLayoutNameValue(); + + return isDefault; +} + void KWinTabBoxConfig::load() { KCModule::load(); m_tabBoxConfig->load(); m_tabBoxAlternativeConfig->load(); + updateUiFromConfig(m_primaryTabBoxUi, m_tabBoxConfig); + updateUiFromConfig(m_alternativeTabBoxUi , m_tabBoxAlternativeConfig); + m_coverSwitchConfig->load(); m_flipSwitchConfig->load(); m_pluginsConfig->load(); - updateUiFromConfig(m_primaryTabBoxUi, m_tabBoxConfig); - updateUiFromConfig(m_alternativeTabBoxUi , m_tabBoxAlternativeConfig); - if (m_pluginsConfig->coverswitchEnabled()) { if (m_coverSwitchConfig->tabBox()) { - m_primaryTabBoxUi->effectCombo->setCurrentIndex(CoverSwitch); + m_primaryTabBoxUi->setLayoutName(m_coverSwitch); } if (m_coverSwitchConfig->tabBoxAlternative()) { - m_alternativeTabBoxUi->effectCombo->setCurrentIndex(CoverSwitch); + m_alternativeTabBoxUi->setLayoutName(m_coverSwitch); } } if (m_pluginsConfig->flipswitchEnabled()) { if (m_flipSwitchConfig->tabBox()) { - m_primaryTabBoxUi->effectCombo->setCurrentIndex(FlipSwitch); + m_primaryTabBoxUi->setLayoutName(m_flipSwitch); } if (m_flipSwitchConfig->tabBoxAlternative()) { - m_alternativeTabBoxUi->effectCombo->setCurrentIndex(FlipSwitch); + m_alternativeTabBoxUi->setLayoutName(m_flipSwitch); } } - KWinTabBoxConfigForm* ui[2] = { m_primaryTabBoxUi, m_alternativeTabBoxUi }; - for (int i = 0; i < 2; ++i) { - QString action; -#define LOAD_SHORTCUT(_BTN_)\ - action = ui[i]->_BTN_->property("shortcutAction").toString();\ - qDebug() << "load shortcut for " << action;\ - if (QAction *a = m_actionCollection->action(action)) { \ - auto shortcuts = KGlobalAccel::self()->shortcut(a); \ - if (!shortcuts.isEmpty()) \ - ui[i]->_BTN_->setKeySequence(shortcuts.first()); \ - } - LOAD_SHORTCUT(scAll); - LOAD_SHORTCUT(scAllReverse); - LOAD_SHORTCUT(scCurrent); - LOAD_SHORTCUT(scCurrentReverse); -#undef LOAD_SHORTCUT - } - emit changed(false); + m_primaryTabBoxUi->loadShortcuts(); + m_alternativeTabBoxUi->loadShortcuts(); + + updateUnmanagedState(); } void KWinTabBoxConfig::save() { - KCModule::save(); - - // sync ui to config - updateConfigFromUi(m_primaryTabBoxUi, m_tabBoxConfig); - updateConfigFromUi(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); - m_tabBoxConfig->save(); - m_tabBoxAlternativeConfig->save(); - // effects - bool highlightWindows = m_primaryTabBoxUi->highlightWindowCheck->isChecked() || - m_alternativeTabBoxUi->highlightWindowCheck->isChecked(); - const bool coverSwitch = m_primaryTabBoxUi->showTabBox->isChecked() && - m_primaryTabBoxUi->effectCombo->currentIndex() == CoverSwitch; - const bool flipSwitch = m_primaryTabBoxUi->showTabBox->isChecked() && - m_primaryTabBoxUi->effectCombo->currentIndex() == FlipSwitch; - const bool coverSwitchAlternative = m_alternativeTabBoxUi->showTabBox->isChecked() && - m_alternativeTabBoxUi->effectCombo->currentIndex() == CoverSwitch; - const bool flipSwitchAlternative = m_alternativeTabBoxUi->showTabBox->isChecked() && - m_alternativeTabBoxUi->effectCombo->currentIndex() == FlipSwitch; + const bool highlightWindows = m_primaryTabBoxUi->highlightWindows() || m_alternativeTabBoxUi->highlightWindows(); + const bool coverSwitch = m_primaryTabBoxUi->showTabBox() + && m_primaryTabBoxUi->effectComboCurrentData().toString() == m_coverSwitch; + const bool flipSwitch = m_primaryTabBoxUi->showTabBox() + && m_primaryTabBoxUi->effectComboCurrentData().toString() == m_flipSwitch; + const bool coverSwitchAlternative = m_alternativeTabBoxUi->showTabBox() + && m_alternativeTabBoxUi->effectComboCurrentData().toString() == m_coverSwitch; + const bool flipSwitchAlternative = m_alternativeTabBoxUi->showTabBox() + && m_alternativeTabBoxUi->effectComboCurrentData().toString() == m_flipSwitch; // activate effects if not active if (coverSwitch || coverSwitchAlternative) { m_pluginsConfig->setCoverswitchEnabled(true); } if (flipSwitch || flipSwitchAlternative) { m_pluginsConfig->setFlipswitchEnabled(true); } if (highlightWindows) { m_pluginsConfig->setHighlightwindowEnabled(true); } m_pluginsConfig->save(); m_coverSwitchConfig->setTabBox(coverSwitch); m_coverSwitchConfig->setTabBoxAlternative(coverSwitchAlternative); m_coverSwitchConfig->save(); m_flipSwitchConfig->setTabBox(flipSwitch); m_flipSwitchConfig->setTabBoxAlternative(flipSwitchAlternative); m_flipSwitchConfig->save(); + updateConfigFromUi(m_primaryTabBoxUi, m_tabBoxConfig); + updateConfigFromUi(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); + + m_tabBoxConfig->save(); + m_tabBoxAlternativeConfig->save(); + + KCModule::save(); + updateUnmanagedState(); + // Reload KWin. QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig"); QDBusConnection::sessionBus().send(message); // and reconfigure the effects OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::CoverSwitch)); interface.reconfigureEffect(BuiltInEffects::nameForEffect(BuiltInEffect::FlipSwitch)); - - emit changed(false); } void KWinTabBoxConfig::defaults() { - KCModule::defaults(); - - m_tabBoxConfig->setDefaults(); - m_tabBoxAlternativeConfig->setDefaults(); - - m_pluginsConfig->setDefaults(); m_coverSwitchConfig->setDefaults(); m_flipSwitchConfig->setDefaults(); - updateUiFromConfig(m_primaryTabBoxUi, m_tabBoxConfig); - updateUiFromConfig(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); - - QString action; - auto RESET_SHORTCUT = [this](KKeySequenceWidget *widget, const QKeySequence &sequence = QKeySequence()) { - const QString action = widget->property("shortcutAction").toString(); - QAction *a = m_actionCollection->action(action); - KGlobalAccel::self()->setShortcut(a, QList() << sequence, KGlobalAccel::NoAutoloading); - }; - RESET_SHORTCUT(m_primaryTabBoxUi->scAll, Qt::ALT + Qt::Key_Tab); - RESET_SHORTCUT(m_primaryTabBoxUi->scAllReverse, Qt::ALT + Qt::SHIFT + Qt::Key_Backtab); - RESET_SHORTCUT(m_alternativeTabBoxUi->scAll); - RESET_SHORTCUT(m_alternativeTabBoxUi->scAllReverse); - RESET_SHORTCUT(m_primaryTabBoxUi->scCurrent, Qt::ALT + Qt::Key_QuoteLeft); - RESET_SHORTCUT(m_primaryTabBoxUi->scCurrentReverse, Qt::ALT + Qt::Key_AsciiTilde); - RESET_SHORTCUT(m_alternativeTabBoxUi->scCurrent); - RESET_SHORTCUT(m_alternativeTabBoxUi->scCurrentReverse); - m_actionCollection->writeSettings(); - emit changed(true); -} + updateUiFromDefaultConfig(m_primaryTabBoxUi, m_tabBoxConfig); + updateUiFromDefaultConfig(m_alternativeTabBoxUi, m_tabBoxAlternativeConfig); -void KWinTabBoxConfig::updateUiFromConfig(KWinTabBoxConfigForm *ui, const KWin::TabBox::TabBoxSettings *config) -{ -#define CONFIGURE(SETTING, MODE, IS, VALUE) ui->SETTING->setChecked(config->MODE##Mode() IS TabBoxConfig::VALUE) - CONFIGURE(filterDesktops, desktop, !=, AllDesktopsClients); - CONFIGURE(currentDesktop, desktop, ==, OnlyCurrentDesktopClients); - CONFIGURE(otherDesktops, desktop, ==, ExcludeCurrentDesktopClients); - CONFIGURE(filterActivities, activities, !=, AllActivitiesClients); - CONFIGURE(currentActivity, activities, ==, OnlyCurrentActivityClients); - CONFIGURE(otherActivities, activities, ==, ExcludeCurrentActivityClients); - CONFIGURE(filterScreens, multiScreen, !=, IgnoreMultiScreen); - CONFIGURE(currentScreen, multiScreen, ==, OnlyCurrentScreenClients); - CONFIGURE(otherScreens, multiScreen, ==, ExcludeCurrentScreenClients); - CONFIGURE(oneAppWindow, applications, ==, OneWindowPerApplication); - CONFIGURE(filterMinimization, minimized, !=, IgnoreMinimizedStatus); - CONFIGURE(visibleWindows, minimized, ==, ExcludeMinimizedClients); - CONFIGURE(hiddenWindows, minimized, ==, OnlyMinimizedClients); - - ui->switchingModeCombo->setCurrentIndex(config->switchingMode()); - - // check boxes - ui->showTabBox->setChecked(config->showTabBox()); - ui->highlightWindowCheck->setChecked(config->highlightWindows()); - ui->effectCombo->setCurrentIndex(ui->effectCombo->findData(config->layoutName())); - CONFIGURE(showDesktop, showDesktop, ==, ShowDesktopClient); -#undef CONFIGURE + m_primaryTabBoxUi->resetShortcuts(); + m_alternativeTabBoxUi->resetShortcuts(); + + KCModule::defaults(); + updateUnmanagedState(); } -void KWinTabBoxConfig::updateConfigFromUi(const KWin::KWinTabBoxConfigForm *ui, TabBoxSettings *config) +void KWinTabBoxConfig::updateUiFromConfig(KWinTabBoxConfigForm *form, const KWin::TabBox::TabBoxSettings *config) { - if (ui->filterDesktops->isChecked()) { - config->setDesktopMode(ui->currentDesktop->isChecked() ? TabBoxConfig::OnlyCurrentDesktopClients : TabBoxConfig::ExcludeCurrentDesktopClients); - } else { - config->setDesktopMode(TabBoxConfig::AllDesktopsClients); - } - if (ui->filterActivities->isChecked()) { - config->setActivitiesMode(ui->currentActivity->isChecked() ? TabBoxConfig::OnlyCurrentActivityClients : TabBoxConfig::ExcludeCurrentActivityClients); - } else { - config->setActivitiesMode(TabBoxConfig::AllActivitiesClients); - } - if (ui->filterScreens->isChecked()) { - config->setMultiScreenMode(ui->currentScreen->isChecked() ? TabBoxConfig::OnlyCurrentScreenClients : TabBoxConfig::ExcludeCurrentScreenClients); - } else { - config->setMultiScreenMode(TabBoxConfig::IgnoreMultiScreen); - } - config->setApplicationsMode(ui->oneAppWindow->isChecked() ? TabBoxConfig::OneWindowPerApplication : TabBoxConfig::AllWindowsAllApplications); - if (ui->filterMinimization->isChecked()) { - config->setMinimizedMode(ui->visibleWindows->isChecked() ? TabBoxConfig::ExcludeMinimizedClients : TabBoxConfig::OnlyMinimizedClients); - } else { - config->setMinimizedMode(TabBoxConfig::IgnoreMinimizedStatus); - } - - config->setSwitchingMode(TabBoxConfig::ClientSwitchingMode(ui->switchingModeCombo->currentIndex())); - - config->setShowTabBox(ui->showTabBox->isChecked()); - config->setHighlightWindows(ui->highlightWindowCheck->isChecked()); - if (ui->effectCombo->currentIndex() >= Layout) { - config->setLayoutName(ui->effectCombo->itemData(ui->effectCombo->currentIndex()).toString()); - } - config->setShowDesktopMode(ui->showDesktop->isChecked() ? TabBoxConfig::ShowDesktopClient : TabBoxConfig::DoNotShowDesktopClient); + form->setFilterScreen(static_cast(config->multiScreenMode())); + form->setFilterDesktop(static_cast(config->desktopMode())); + form->setFilterActivities(static_cast(config->activitiesMode())); + form->setFilterMinimization(static_cast(config->minimizedMode())); + form->setApplicationMode(static_cast(config->applicationsMode())); + form->setShowDesktopMode(static_cast(config->showDesktopMode())); + form->setSwitchingModeChanged(static_cast(config->switchingMode())); + form->setLayoutName(config->layoutName()); } -#define CHECK_CURRENT_TABBOX_UI \ - Q_ASSERT(sender());\ - KWinTabBoxConfigForm *ui = nullptr;\ - QObject *dad = sender();\ - while (!ui && (dad = dad->parent()))\ - ui = qobject_cast(dad);\ - Q_ASSERT(ui); - -void KWinTabBoxConfig::effectSelectionChanged(int index) +void KWinTabBoxConfig::updateConfigFromUi(const KWinTabBoxConfigForm *form, TabBoxSettings *config) { - CHECK_CURRENT_TABBOX_UI - ui->effectConfigButton->setIcon(QIcon::fromTheme(index < Layout ? "configure" : "view-preview")); - if (!ui->showTabBox->isChecked()) - return; - ui->highlightWindowCheck->setEnabled(index >= Layout); + config->setMultiScreenMode(form->filterScreen()); + config->setDesktopMode(form->filterDesktop()); + config->setActivitiesMode(form->filterActivities()); + config->setMinimizedMode(form->filterMinimization()); + config->setApplicationsMode(form->applicationMode()); + config->setShowDesktopMode(form->showDesktopMode()); + config->setSwitchingMode(form->switchingMode()); + config->setLayoutName(form->layoutName()); } -void KWinTabBoxConfig::tabBoxToggled(bool on) +void KWinTabBoxConfig::updateUiFromDefaultConfig(KWinTabBoxConfigForm *form, const KWin::TabBox::TabBoxSettings *config) { - CHECK_CURRENT_TABBOX_UI - on = !on || ui->effectCombo->currentIndex() >= Layout; - ui->highlightWindowCheck->setEnabled(on); - markAsChanged(); + form->setFilterScreen(static_cast(config->defaultMultiScreenModeValue())); + form->setFilterDesktop(static_cast(config->defaultDesktopModeValue())); + form->setFilterActivities(static_cast(config->defaultActivitiesModeValue())); + form->setFilterMinimization(static_cast(config->defaultMinimizedModeValue())); + form->setApplicationMode(static_cast(config->defaultApplicationsModeValue())); + form->setShowDesktopMode(static_cast(config->defaultShowDesktopModeValue())); + form->setSwitchingModeChanged(static_cast(config->defaultSwitchingModeValue())); + form->setLayoutName(config->defaultLayoutNameValue()); } void KWinTabBoxConfig::configureEffectClicked() { - CHECK_CURRENT_TABBOX_UI + auto form = qobject_cast(sender()); + Q_ASSERT(form); - const int effect = ui->effectCombo->currentIndex(); - if (effect >= Layout) { - // TODO: here we need to show the preview - new LayoutPreview(ui->effectCombo->itemData(effect, Qt::UserRole+1).toString(), this); + if (form->effectComboCurrentData(KWinTabBoxConfigForm::AddonEffect).toBool()) { + // Show the preview for addon effect + new LayoutPreview(form->effectComboCurrentData(KWinTabBoxConfigForm::LayoutPath).toString(), this); } else { + // For builtin effect, display a configuration dialog QPointer configDialog = new QDialog(this); configDialog->setLayout(new QVBoxLayout); - configDialog->setWindowTitle(ui->effectCombo->currentText()); + configDialog->setWindowTitle(form->effectComboCurrentData(Qt::DisplayRole).toString()); QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults, configDialog); connect(buttonBox, SIGNAL(accepted()), configDialog, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), configDialog, SLOT(reject())); - const QString name = BuiltInEffects::nameForEffect(effect == CoverSwitch ? BuiltInEffect::CoverSwitch : BuiltInEffect::FlipSwitch); - + const QString name = form->effectComboCurrentData().toString(); KCModule *kcm = KPluginTrader::createInstanceFromQuery(QStringLiteral("kwin/effects/configs/"), QString(), QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(name), - configDialog); + configDialog); if (!kcm) { delete configDialog; return; } connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults); QWidget *showWidget = new QWidget(configDialog); QVBoxLayout *layout = new QVBoxLayout; showWidget->setLayout(layout); layout->addWidget(kcm); configDialog->layout()->addWidget(showWidget); configDialog->layout()->addWidget(buttonBox); if (configDialog->exec() == QDialog::Accepted) { kcm->save(); } else { kcm->load(); } delete configDialog; } } -void KWinTabBoxConfig::shortcutChanged(const QKeySequence &seq) -{ - QString action; - if (sender()) - action = sender()->property("shortcutAction").toString(); - if (action.isEmpty()) - return; - QAction *a = m_actionCollection->action(action); - KGlobalAccel::self()->setShortcut(a, QList() << seq, KGlobalAccel::NoAutoloading); - m_actionCollection->writeSettings(); -} - void KWinTabBoxConfig::slotGHNS() { QPointer downloadDialog = new KNS3::DownloadDialog("kwinswitcher.knsrc", this); if (downloadDialog->exec() == QDialog::Accepted) { if (!downloadDialog->changedEntries().isEmpty()) { initLayoutLists(); } } delete downloadDialog; } } // namespace #include "main.moc" diff --git a/kcmkwin/kwintabbox/main.h b/kcmkwin/kwintabbox/main.h index a6d962962..1cac4bc4b 100644 --- a/kcmkwin/kwintabbox/main.h +++ b/kcmkwin/kwintabbox/main.h @@ -1,98 +1,86 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 Martin Gräßlin Copyright (C) 2020 Cyril Rossi 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 __MAIN_H__ #define __MAIN_H__ #include #include - -#include "ui_main.h" - -class KShortcutsEditor; -class KActionCollection; +#include "tabboxconfig.h" namespace KWin { +class KWinTabBoxConfigForm; enum class BuiltInEffect; namespace TabBox { class TabBoxSettings; class SwitchEffectSettings; class PluginsSettings; } - -class KWinTabBoxConfigForm : public QWidget, public Ui::KWinTabBoxConfigForm -{ - Q_OBJECT - -public: - explicit KWinTabBoxConfigForm(QWidget* parent); -}; - class KWinTabBoxConfig : public KCModule { Q_OBJECT public: explicit KWinTabBoxConfig(QWidget* parent, const QVariantList& args); ~KWinTabBoxConfig() override; public Q_SLOTS: void save() override; void load() override; void defaults() override; private Q_SLOTS: - void effectSelectionChanged(int index); + void updateUnmanagedState(); void configureEffectClicked(); - void tabBoxToggled(bool on); - void shortcutChanged(const QKeySequence &seq); void slotGHNS(); + private: - void updateUiFromConfig(KWinTabBoxConfigForm *ui, const TabBox::TabBoxSettings *config); - void updateConfigFromUi(const KWinTabBoxConfigForm *ui, TabBox::TabBoxSettings *config); + void updateUiFromConfig(KWinTabBoxConfigForm *form, const TabBox::TabBoxSettings *config); + void updateConfigFromUi(const KWinTabBoxConfigForm *form, TabBox::TabBoxSettings *config); + void updateUiFromDefaultConfig(KWinTabBoxConfigForm *form, const TabBox::TabBoxSettings *config); void initLayoutLists(); + void createConnections(KWinTabBoxConfigForm *form, TabBox::TabBoxSettings *config); + bool updateUnmanagedIsNeedSave(const KWinTabBoxConfigForm *form, const TabBox::TabBoxSettings *config); + bool updateUnmanagedIsDefault(const KWinTabBoxConfigForm *form, const TabBox::TabBoxSettings *config); private: - enum Mode { - CoverSwitch = 0, - FlipSwitch = 1, - Layout = 2 - }; - KWinTabBoxConfigForm* m_primaryTabBoxUi; - KWinTabBoxConfigForm* m_alternativeTabBoxUi; + KWinTabBoxConfigForm *m_primaryTabBoxUi = nullptr; + KWinTabBoxConfigForm *m_alternativeTabBoxUi = nullptr; KSharedConfigPtr m_config; - KActionCollection* m_actionCollection; - KShortcutsEditor* m_editor; + TabBox::TabBoxSettings *m_tabBoxConfig; TabBox::TabBoxSettings *m_tabBoxAlternativeConfig; TabBox::SwitchEffectSettings *m_coverSwitchConfig; TabBox::SwitchEffectSettings *m_flipSwitchConfig; TabBox::PluginsSettings *m_pluginsConfig; + // Builtin effects' names + QString m_coverSwitch; + QString m_flipSwitch; }; } // namespace #endif diff --git a/kcmkwin/kwintabbox/main.ui b/kcmkwin/kwintabbox/main.ui index 9147dad94..e702e358b 100644 --- a/kcmkwin/kwintabbox/main.ui +++ b/kcmkwin/kwintabbox/main.ui @@ -1,699 +1,699 @@ KWinTabBoxConfigForm 0 0 658 418 Qt::Horizontal 40 20 Content true Include "Show Desktop" icon 0 0 Recently used Stacking order Only one window per application false Sort order: switchingModeCombo Qt::Horizontal 40 20 Filter windows by true Virtual desktops false false 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 24 20 Current desktop All other desktops Activities false false 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 24 20 Current activity All other activities Screens false false 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 24 20 Current screen All other screens Minimization false false 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 24 20 Visible windows Hidden windows Qt::Vertical 20 40 Qt::Vertical 20 40 Shortcuts true Forward Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 75 true All windows Qt::AlignCenter Reverse Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Forward Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Reverse Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 75 true Current application Qt::AlignCenter Visualization true 0 0 0 0 0 0 The effect to replace the list window when desktop effects are active. 0 0 - + true - + The currently selected window will be highlighted by fading out all other windows. This option requires desktop effects to be active. Show selected window Qt::Vertical Qt::Horizontal 40 20 KKeySequenceWidget QWidget
kkeysequencewidget.h
KComboBox QComboBox
kcombobox.h
- highlightWindowCheck - showTabBox + kcfg_HighlightWindows + kcfg_ShowTabBox effectCombo effectConfigButton switchingModeCombo showDesktop oneAppWindow filterDesktops currentDesktop otherDesktops filterActivities currentActivity otherActivities filterScreens currentScreen otherScreens filterMinimization visibleWindows hiddenWindows filterDesktops toggled(bool) desktopFilter setEnabled(bool) 541 172 701 197 filterActivities toggled(bool) activityFilter setEnabled(bool) 543 222 701 247 filterScreens toggled(bool) screenFilter setEnabled(bool) 555 272 701 297 filterMinimization toggled(bool) minimizationFilter setEnabled(bool) 558 322 701 347 - showTabBox + kcfg_ShowTabBox toggled(bool) widget_6 setEnabled(bool) 164 125 230 108
diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index 1101dbce3..abff491b9 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -1,4019 +1,4019 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006 Lubos Lunak Copyright (C) 2009 Lucas Murray Copyright (C) 2010, 2011 Martin Gräßlin Copyright (C) 2018 Vlad Zahorodnii 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 KWINEFFECTS_H #define KWINEFFECTS_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KConfigGroup; class QFont; class QGraphicsScale; class QKeyEvent; class QMatrix4x4; class QAction; /** * Logging category to be used inside the KWin effects. * Do not use in this library. */ Q_DECLARE_LOGGING_CATEGORY(KWINEFFECTS) namespace KWayland { namespace Server { class SurfaceInterface; class Display; } } namespace KWin { class PaintDataPrivate; class WindowPaintDataPrivate; class EffectWindow; class EffectWindowGroup; class EffectFrame; class EffectFramePrivate; class EffectQuickView; class Effect; class WindowQuad; class GLShader; class XRenderPicture; class WindowQuadList; class WindowPrePaintData; class WindowPaintData; class ScreenPrePaintData; class ScreenPaintData; typedef QPair< QString, Effect* > EffectPair; typedef QList< KWin::EffectWindow* > EffectWindowList; /** @defgroup kwineffects KWin effects library * KWin effects library contains necessary classes for creating new KWin * compositing effects. * * @section creating Creating new effects * This example will demonstrate the basics of creating an effect. We'll use * CoolEffect as the class name, cooleffect as internal name and * "Cool Effect" as user-visible name of the effect. * * This example doesn't demonstrate how to write the effect's code. For that, * see the documentation of the Effect class. * * @subsection creating-class CoolEffect class * First you need to create CoolEffect class which has to be a subclass of * @ref KWin::Effect. In that class you can reimplement various virtual * methods to control how and where the windows are drawn. * * @subsection creating-macro KWIN_EFFECT_FACTORY macro * This library provides a specialized KPluginFactory subclass and macros to * create a sub class. This subclass of KPluginFactory has to be used, otherwise * KWin won't load the plugin. Use the @ref KWIN_EFFECT_FACTORY macro to create the * plugin factory. * * @subsection creating-buildsystem Buildsystem * To build the effect, you can use the KWIN_ADD_EFFECT() cmake macro which * can be found in effects/CMakeLists.txt file in KWin's source. First * argument of the macro is the name of the library that will contain * your effect. Although not strictly required, it is usually a good idea to * use the same name as your effect's internal name there. Following arguments * to the macro are the files containing your effect's source. If our effect's * source is in cooleffect.cpp, we'd use following: * @code * KWIN_ADD_EFFECT(cooleffect cooleffect.cpp) * @endcode * * This macro takes care of compiling your effect. You'll also need to install * your effect's .desktop file, so the example CMakeLists.txt file would be * as follows: * @code * KWIN_ADD_EFFECT(cooleffect cooleffect.cpp) * install( FILES cooleffect.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kwin ) * @endcode * * @subsection creating-desktop Effect's .desktop file * You will also need to create .desktop file to set name, description, icon * and other properties of your effect. Important fields of the .desktop file * are: * @li Name User-visible name of your effect * @li Icon Name of the icon of the effect * @li Comment Short description of the effect * @li Type must be "Service" * @li X-KDE-ServiceTypes must be "KWin/Effect" * @li X-KDE-PluginInfo-Name effect's internal name as passed to the KWIN_EFFECT macro plus "kwin4_effect_" prefix * @li X-KDE-PluginInfo-Category effect's category. Should be one of Appearance, Accessibility, Window Management, Demos, Tests, Misc * @li X-KDE-PluginInfo-EnabledByDefault whether the effect should be enabled by default (use sparingly). Default is false * @li X-KDE-Library name of the library containing the effect. This is the first argument passed to the KWIN_ADD_EFFECT macro in cmake file plus "kwin4_effect_" prefix. * * Example cooleffect.desktop file follows: * @code [Desktop Entry] Name=Cool Effect Comment=The coolest effect you've ever seen Icon=preferences-system-windows-effect-cooleffect Type=Service X-KDE-ServiceTypes=KWin/Effect X-KDE-PluginInfo-Author=My Name X-KDE-PluginInfo-Email=my@email.here X-KDE-PluginInfo-Name=kwin4_effect_cooleffect X-KDE-PluginInfo-Category=Misc X-KDE-Library=kwin4_effect_cooleffect * @endcode * * * @section accessing Accessing windows and workspace * Effects can gain access to the properties of windows and workspace via * EffectWindow and EffectsHandler classes. * * There is one global EffectsHandler object which you can access using the * @ref effects pointer. * For each window, there is an EffectWindow object which can be used to read * window properties such as position and also to change them. * * For more information about this, see the documentation of the corresponding * classes. * * @{ */ #define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor )) #define KWIN_EFFECT_API_VERSION_MAJOR 0 -#define KWIN_EFFECT_API_VERSION_MINOR 229 +#define KWIN_EFFECT_API_VERSION_MINOR 230 #define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \ KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR ) enum WindowQuadType { WindowQuadError, // for the stupid default ctor WindowQuadContents, WindowQuadDecoration, // Shadow Quad types WindowQuadShadow, // OpenGL only. The other shadow types are only used by Xrender WindowQuadShadowTop, WindowQuadShadowTopRight, WindowQuadShadowRight, WindowQuadShadowBottomRight, WindowQuadShadowBottom, WindowQuadShadowBottomLeft, WindowQuadShadowLeft, WindowQuadShadowTopLeft, EFFECT_QUAD_TYPE_START = 100 ///< @internal }; /** * EffectWindow::setData() and EffectWindow::data() global roles. * All values between 0 and 999 are reserved for global roles. */ enum DataRole { // Grab roles are used to force all other animations to ignore the window. // The value of the data is set to the Effect's `this` value. WindowAddedGrabRole = 1, WindowClosedGrabRole, WindowMinimizedGrabRole, WindowUnminimizedGrabRole, WindowForceBlurRole, ///< For fullscreen effects to enforce blurring of windows, WindowBlurBehindRole, ///< For single windows to blur behind WindowForceBackgroundContrastRole, ///< For fullscreen effects to enforce the background contrast, WindowBackgroundContrastRole, ///< For single windows to enable Background contrast LanczosCacheRole }; /** * Style types used by @ref EffectFrame. * @since 4.6 */ enum EffectFrameStyle { EffectFrameNone, ///< Displays no frame around the contents. EffectFrameUnstyled, ///< Displays a basic box around the contents. EffectFrameStyled ///< Displays a Plasma-styled frame around the contents. }; /** * Infinite region (i.e. a special region type saying that everything needs to be painted). */ KWINEFFECTS_EXPORT inline QRect infiniteRegion() { // INT_MIN / 2 because width/height is used (INT_MIN+INT_MAX==-1) return QRect(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX); } /** * @short Base class for all KWin effects * * This is the base class for all effects. By reimplementing virtual methods * of this class, you can customize how the windows are painted. * * The virtual methods are used for painting and need to be implemented for * custom painting. * * In order to react to state changes (e.g. a window gets closed) the effect * should provide slots for the signals emitted by the EffectsHandler. * * @section Chaining * Most methods of this class are called in chain style. This means that when * effects A and B area active then first e.g. A::paintWindow() is called and * then from within that method B::paintWindow() is called (although * indirectly). To achieve this, you need to make sure to call corresponding * method in EffectsHandler class from each such method (using @ref effects * pointer): * @code * void MyEffect::postPaintScreen() * { * // Do your own processing here * ... * // Call corresponding EffectsHandler method * effects->postPaintScreen(); * } * @endcode * * @section Effectsptr Effects pointer * @ref effects pointer points to the global EffectsHandler object that you can * use to interact with the windows. * * @section painting Painting stages * Painting of windows is done in three stages: * @li First, the prepaint pass.
* Here you can specify how the windows will be painted, e.g. that they will * be translucent and transformed. * @li Second, the paint pass.
* Here the actual painting takes place. You can change attributes such as * opacity of windows as well as apply transformations to them. You can also * paint something onto the screen yourself. * @li Finally, the postpaint pass.
* Here you can mark windows, part of windows or even the entire screen for * repainting to create animations. * * For each stage there are *Screen() and *Window() methods. The window method * is called for every window which the screen method is usually called just * once. * * @section OpenGL * Effects can use OpenGL if EffectsHandler::isOpenGLCompositing() returns @c true. * The OpenGL context may not always be current when code inside the effect is * executed. The framework ensures that the OpenGL context is current when the Effect * gets created, destroyed or reconfigured and during the painting stages. All virtual * methods which have the OpenGL context current are documented. * * If OpenGL code is going to be executed outside the painting stages, e.g. in reaction * to a global shortcut, it is the task of the Effect to make the OpenGL context current: * @code * effects->makeOpenGLContextCurrent(); * @endcode * * There is in general no need to call the matching doneCurrent method. */ class KWINEFFECTS_EXPORT Effect : public QObject { Q_OBJECT public: /** Flags controlling how painting is done. */ // TODO: is that ok here? enum { /** * Window (or at least part of it) will be painted opaque. */ PAINT_WINDOW_OPAQUE = 1 << 0, /** * Window (or at least part of it) will be painted translucent. */ PAINT_WINDOW_TRANSLUCENT = 1 << 1, /** * Window will be painted with transformed geometry. */ PAINT_WINDOW_TRANSFORMED = 1 << 2, /** * Paint only a region of the screen (can be optimized, cannot * be used together with TRANSFORMED flags). */ PAINT_SCREEN_REGION = 1 << 3, /** * The whole screen will be painted with transformed geometry. * Forces the entire screen to be painted. */ PAINT_SCREEN_TRANSFORMED = 1 << 4, /** * At least one window will be painted with transformed geometry. * Forces the entire screen to be painted. */ PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS = 1 << 5, /** * Clear whole background as the very first step, without optimizing it */ PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6, // PAINT_DECORATION_ONLY = 1 << 7 has been deprecated /** * Window will be painted with a lanczos filter. */ PAINT_WINDOW_LANCZOS = 1 << 8 // PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS = 1 << 9 has been removed }; enum Feature { Nothing = 0, Resize, GeometryTip, Outline, /**< @deprecated */ ScreenInversion, Blur, Contrast, HighlightWindows }; /** * Constructs new Effect object. * * In OpenGL based compositing, the frameworks ensures that the context is current * when the Effect is constructed. */ Effect(); /** * Destructs the Effect object. * * In OpenGL based compositing, the frameworks ensures that the context is current * when the Effect is destroyed. */ ~Effect() override; /** * Flags describing which parts of configuration have changed. */ enum ReconfigureFlag { ReconfigureAll = 1 << 0 /// Everything needs to be reconfigured. }; Q_DECLARE_FLAGS(ReconfigureFlags, ReconfigureFlag) /** * Called when configuration changes (either the effect's or KWin's global). * * In OpenGL based compositing, the frameworks ensures that the context is current * when the Effect is reconfigured. If this method is called from within the Effect it is * required to ensure that the context is current if the implementation does OpenGL calls. */ virtual void reconfigure(ReconfigureFlags flags); /** * Called when another effect requests the proxy for this effect. */ virtual void* proxy(); /** * Called before starting to paint the screen. * In this method you can: * @li set whether the windows or the entire screen will be transformed * @li change the region of the screen that will be painted * @li do various housekeeping tasks such as initing your effect's variables for the upcoming paint pass or updating animation's progress * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void prePaintScreen(ScreenPrePaintData& data, int time); /** * In this method you can: * @li paint something on top of the windows (by painting after calling * effects->paintScreen()) * @li paint multiple desktops and/or multiple copies of the same desktop * by calling effects->paintScreen() multiple times * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data); /** * Called after all the painting has been finished. * In this method you can: * @li schedule next repaint in case of animations * You shouldn't paint anything here. * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void postPaintScreen(); /** * Called for every window before the actual paint pass * In this method you can: * @li enable or disable painting of the window (e.g. enable paiting of minimized window) * @li set window to be painted with translucency * @li set window to be transformed * @li request the window to be divided into multiple parts * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time); /** * This is the main method for painting windows. * In this method you can: * @li do various transformations * @li change opacity of the window * @li change brightness and/or saturation, if it's supported * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data); /** * Called for every window after all painting has been finished. * In this method you can: * @li schedule next repaint for individual window(s) in case of animations * You shouldn't paint anything here. * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void postPaintWindow(EffectWindow* w); /** * This method is called directly before painting an @ref EffectFrame. * You can implement this method if you need to bind a shader or perform * other operations before the frame is rendered. * @param frame The EffectFrame which will be rendered * @param region Region to restrict painting to * @param opacity Opacity of text/icon * @param frameOpacity Opacity of background * @since 4.6 * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void paintEffectFrame(EffectFrame* frame, const QRegion ®ion, double opacity, double frameOpacity); /** * Called on Transparent resizes. * return true if your effect substitutes questioned feature */ virtual bool provides(Feature); /** * Performs the @p feature with the @p arguments. * * This allows to have specific protocols between KWin core and an Effect. * * The method is supposed to return @c true if it performed the features, * @c false otherwise. * * The default implementation returns @c false. * @since 5.8 */ virtual bool perform(Feature feature, const QVariantList &arguments); /** * Can be called to draw multiple copies (e.g. thumbnails) of a window. * You can change window's opacity/brightness/etc here, but you can't * do any transformations. * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. */ virtual void drawWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data); /** * Define new window quads so that they can be transformed by other effects. * It's up to the effect to keep track of them. */ virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList); virtual void windowInputMouseEvent(QEvent* e); virtual void grabbedKeyboardEvent(QKeyEvent* e); /** * Overwrite this method to indicate whether your effect will be doing something in * the next frame to be rendered. If the method returns @c false the effect will be * excluded from the chained methods in the next rendered frame. * * This method is called always directly before the paint loop begins. So it is totally * fine to e.g. react on a window event, issue a repaint to trigger an animation and * change a flag to indicate that this method returns @c true. * * As the method is called each frame, you should not perform complex calculations. * Best use just a boolean flag. * * The default implementation of this method returns @c true. * @since 4.8 */ virtual bool isActive() const; /** * Reimplement this method to provide online debugging. * This could be as trivial as printing specific detail information about the effect state * but could also be used to move the effect in and out of a special debug modes, clear bogus * data, etc. * Notice that the functions is const by intent! Whenever you alter the state of the object * due to random user input, you should do so with greatest care, hence const_cast<> your * object - signalling "let me alone, i know what i'm doing" * @param parameter A freeform string user input for your effect to interpret. * @since 4.11 */ virtual QString debug(const QString ¶meter) const; /** * Reimplement this method to indicate where in the Effect chain the Effect should be placed. * * A low number indicates early chain position, thus before other Effects got called, a high * number indicates a late position. The returned number should be in the interval [0, 100]. * The default value is 0. * * In KWin4 this information was provided in the Effect's desktop file as property * X-KDE-Ordering. In the case of Scripted Effects this property is still used. * * @since 5.0 */ virtual int requestedEffectChainPosition() const; /** * A touch point was pressed. * * If the effect wants to exclusively use the touch event it should return @c true. * If @c false is returned the touch event is passed to further effects. * * In general an Effect should only return @c true if it is the exclusive effect getting * input events. E.g. has grabbed mouse events. * * Default implementation returns @c false. * * @param id The unique id of the touch point * @param pos The position of the touch point in global coordinates * @param time Timestamp * * @see touchMotion * @see touchUp * @since 5.8 */ virtual bool touchDown(qint32 id, const QPointF &pos, quint32 time); /** * A touch point moved. * * If the effect wants to exclusively use the touch event it should return @c true. * If @c false is returned the touch event is passed to further effects. * * In general an Effect should only return @c true if it is the exclusive effect getting * input events. E.g. has grabbed mouse events. * * Default implementation returns @c false. * * @param id The unique id of the touch point * @param pos The position of the touch point in global coordinates * @param time Timestamp * * @see touchDown * @see touchUp * @since 5.8 */ virtual bool touchMotion(qint32 id, const QPointF &pos, quint32 time); /** * A touch point was released. * * If the effect wants to exclusively use the touch event it should return @c true. * If @c false is returned the touch event is passed to further effects. * * In general an Effect should only return @c true if it is the exclusive effect getting * input events. E.g. has grabbed mouse events. * * Default implementation returns @c false. * * @param id The unique id of the touch point * @param time Timestamp * * @see touchDown * @see touchMotion * @since 5.8 */ virtual bool touchUp(qint32 id, quint32 time); static QPoint cursorPos(); /** * Read animation time from the configuration and possibly adjust using animationTimeFactor(). * The configuration value in the effect should also have special value 'default' (set using * QSpinBox::setSpecialValueText()) with the value 0. This special value is adjusted * using the global animation speed, otherwise the exact time configured is returned. * @param cfg configuration group to read value from * @param key configuration key to read value from * @param defaultTime default animation time in milliseconds */ // return type is intentionally double so that one can divide using it without losing data static double animationTime(const KConfigGroup& cfg, const QString& key, int defaultTime); /** * @overload Use this variant if the animation time is hardcoded and not configurable * in the effect itself. */ static double animationTime(int defaultTime); /** * @overload Use this variant if animation time is provided through a KConfigXT generated class * having a property called "duration". */ template int animationTime(int defaultDuration); /** * Linearly interpolates between @p x and @p y. * * Returns @p x when @p a = 0; returns @p y when @p a = 1. */ static double interpolate(double x, double y, double a) { return x * (1 - a) + y * a; } /** Helper to set WindowPaintData and QRegion to necessary transformations so that * a following drawWindow() would put the window at the requested geometry (useful for thumbnails) */ static void setPositionTransformations(WindowPaintData& data, QRect& region, EffectWindow* w, const QRect& r, Qt::AspectRatioMode aspect); public Q_SLOTS: virtual bool borderActivated(ElectricBorder border); protected: xcb_connection_t *xcbConnection() const; xcb_window_t x11RootWindow() const; /** * An implementing class can call this with it's kconfig compiled singleton class. * This method will perform the instance on the class. * @since 5.9 */ template void initConfig(); }; /** * Prefer the KWIN_EFFECT_FACTORY macros. */ class KWINEFFECTS_EXPORT EffectPluginFactory : public KPluginFactory { Q_OBJECT public: EffectPluginFactory(); ~EffectPluginFactory() override; /** * Returns whether the Effect is supported. * * An Effect can implement this method to determine at runtime whether the Effect is supported. * * If the current compositing backend is not supported it should return @c false. * * This method is optional, by default @c true is returned. */ virtual bool isSupported() const; /** * Returns whether the Effect should get enabled by default. * * This function provides a way for an effect to override the default at runtime, * e.g. based on the capabilities of the hardware. * * This method is optional; the effect doesn't have to provide it. * * Note that this function is only called if the supported() function returns true, * and if X-KDE-PluginInfo-EnabledByDefault is set to true in the .desktop file. * * This method is optional, by default @c true is returned. */ virtual bool enabledByDefault() const; /** * This method returns the created Effect. */ virtual KWin::Effect *createEffect() const = 0; }; /** * Defines an EffectPluginFactory sub class with customized isSupported and enabledByDefault methods. * * If the Effect to be created does not need the isSupported or enabledByDefault methods prefer * the simplified KWIN_EFFECT_FACTORY, KWIN_EFFECT_FACTORY_SUPPORTED or KWIN_EFFECT_FACTORY_ENABLED * macros which create an EffectPluginFactory with a useable default value. * * The macro also adds a useable K_EXPORT_PLUGIN_VERSION to the definition. KWin will not load * any Effect with a non-matching plugin version. This API is not providing binary compatibility * and thus the effect plugin must be compiled against the same kwineffects library version as * KWin. * * @param factoryName The name to be used for the EffectPluginFactory * @param className The class name of the Effect sub class which is to be created by the factory * @param jsonFile Name of the json file to be compiled into the plugin as metadata * @param supported Source code to go into the isSupported() method, must return a boolean * @param enabled Source code to go into the enabledByDefault() method, must return a boolean */ #define KWIN_EFFECT_FACTORY_SUPPORTED_ENABLED( factoryName, className, jsonFile, supported, enabled ) \ class factoryName : public KWin::EffectPluginFactory \ { \ Q_OBJECT \ Q_PLUGIN_METADATA(IID KPluginFactory_iid FILE jsonFile) \ Q_INTERFACES(KPluginFactory) \ public: \ explicit factoryName() {} \ ~factoryName() {} \ bool isSupported() const override { \ supported \ } \ bool enabledByDefault() const override { \ enabled \ } \ KWin::Effect *createEffect() const override { \ return new className(); \ } \ }; \ K_EXPORT_PLUGIN_VERSION(quint32(KWIN_EFFECT_API_VERSION)) #define KWIN_EFFECT_FACTORY_ENABLED( factoryName, className, jsonFile, enabled ) \ KWIN_EFFECT_FACTORY_SUPPORTED_ENABLED( factoryName, className, jsonFile, return true;, enabled ) #define KWIN_EFFECT_FACTORY_SUPPORTED( factoryName, classname, jsonFile, supported ) \ KWIN_EFFECT_FACTORY_SUPPORTED_ENABLED( factoryName, className, jsonFile, supported, return true; ) #define KWIN_EFFECT_FACTORY( factoryName, classname, jsonFile ) \ KWIN_EFFECT_FACTORY_SUPPORTED_ENABLED( factoryName, className, jsonFile, return true;, return true; ) /** * @short Manager class that handles all the effects. * * This class creates Effect objects and calls it's appropriate methods. * * Effect objects can call methods of this class to interact with the * workspace, e.g. to activate or move a specific window, change current * desktop or create a special input window to receive mouse and keyboard * events. */ class KWINEFFECTS_EXPORT EffectsHandler : public QObject { Q_OBJECT Q_PROPERTY(int currentDesktop READ currentDesktop WRITE setCurrentDesktop NOTIFY desktopChanged) Q_PROPERTY(QString currentActivity READ currentActivity NOTIFY currentActivityChanged) Q_PROPERTY(KWin::EffectWindow *activeWindow READ activeWindow WRITE activateWindow NOTIFY windowActivated) Q_PROPERTY(QSize desktopGridSize READ desktopGridSize) Q_PROPERTY(int desktopGridWidth READ desktopGridWidth) Q_PROPERTY(int desktopGridHeight READ desktopGridHeight) Q_PROPERTY(int workspaceWidth READ workspaceWidth) Q_PROPERTY(int workspaceHeight READ workspaceHeight) /** * The number of desktops currently used. Minimum number of desktops is 1, maximum 20. */ Q_PROPERTY(int desktops READ numberOfDesktops WRITE setNumberOfDesktops NOTIFY numberDesktopsChanged) Q_PROPERTY(bool optionRollOverDesktops READ optionRollOverDesktops) Q_PROPERTY(int activeScreen READ activeScreen) Q_PROPERTY(int numScreens READ numScreens NOTIFY numberScreensChanged) /** * Factor by which animation speed in the effect should be modified (multiplied). * If configurable in the effect itself, the option should have also 'default' * animation speed. The actual value should be determined using animationTime(). * Note: The factor can be also 0, so make sure your code can cope with 0ms time * if used manually. */ Q_PROPERTY(qreal animationTimeFactor READ animationTimeFactor) Q_PROPERTY(QList< KWin::EffectWindow* > stackingOrder READ stackingOrder) /** * Whether window decorations use the alpha channel. */ Q_PROPERTY(bool decorationsHaveAlpha READ decorationsHaveAlpha) /** * Whether the window decorations support blurring behind the decoration. */ Q_PROPERTY(bool decorationSupportsBlurBehind READ decorationSupportsBlurBehind) Q_PROPERTY(CompositingType compositingType READ compositingType CONSTANT) Q_PROPERTY(QPoint cursorPos READ cursorPos) Q_PROPERTY(QSize virtualScreenSize READ virtualScreenSize NOTIFY virtualScreenSizeChanged) Q_PROPERTY(QRect virtualScreenGeometry READ virtualScreenGeometry NOTIFY virtualScreenGeometryChanged) Q_PROPERTY(bool hasActiveFullScreenEffect READ hasActiveFullScreenEffect NOTIFY hasActiveFullScreenEffectChanged) /** * The status of the session i.e if the user is logging out * @since 5.18 */ Q_PROPERTY(KWin::SessionState sessionState READ sessionState NOTIFY sessionStateChanged) friend class Effect; public: explicit EffectsHandler(CompositingType type); ~EffectsHandler() override; // for use by effects virtual void prePaintScreen(ScreenPrePaintData& data, int time) = 0; virtual void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) = 0; virtual void postPaintScreen() = 0; virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) = 0; virtual void paintWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data) = 0; virtual void postPaintWindow(EffectWindow* w) = 0; virtual void paintEffectFrame(EffectFrame* frame, const QRegion ®ion, double opacity, double frameOpacity) = 0; virtual void drawWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data) = 0; virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList) = 0; virtual QVariant kwinOption(KWinOption kwopt) = 0; /** * Sets the cursor while the mouse is intercepted. * @see startMouseInterception * @since 4.11 */ virtual void defineCursor(Qt::CursorShape shape) = 0; virtual QPoint cursorPos() const = 0; virtual bool grabKeyboard(Effect* effect) = 0; virtual void ungrabKeyboard() = 0; /** * Ensures that all mouse events are sent to the @p effect. * No window will get the mouse events. Only fullscreen effects providing a custom user interface should * be using this method. The input events are delivered to Effect::windowInputMouseEvent. * * @note This method does not perform an X11 mouse grab. On X11 a fullscreen input window is raised above * all other windows, but no grab is performed. * * @param effect The effect * @param shape Sets the cursor to be used while the mouse is intercepted * @see stopMouseInterception * @see Effect::windowInputMouseEvent * @since 4.11 */ virtual void startMouseInterception(Effect *effect, Qt::CursorShape shape) = 0; /** * Releases the hold mouse interception for @p effect * @see startMouseInterception * @since 4.11 */ virtual void stopMouseInterception(Effect *effect) = 0; /** * @brief Registers a global shortcut with the provided @p action. * * @param shortcut The global shortcut which should trigger the action * @param action The action which gets triggered when the shortcut matches */ virtual void registerGlobalShortcut(const QKeySequence &shortcut, QAction *action) = 0; /** * @brief Registers a global pointer shortcut with the provided @p action. * * @param modifiers The keyboard modifiers which need to be holded * @param pointerButtons The pointer buttons which need to be pressed * @param action The action which gets triggered when the shortcut matches */ virtual void registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action) = 0; /** * @brief Registers a global axis shortcut with the provided @p action. * * @param modifiers The keyboard modifiers which need to be holded * @param axis The direction in which the axis needs to be moved * @param action The action which gets triggered when the shortcut matches */ virtual void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action) = 0; /** * @brief Registers a global touchpad swipe gesture shortcut with the provided @p action. * * @param direction The direction for the swipe * @param action The action which gets triggered when the gesture triggers * @since 5.10 */ virtual void registerTouchpadSwipeShortcut(SwipeDirection direction, QAction *action) = 0; /** * Retrieve the proxy class for an effect if it has one. Will return NULL if * the effect isn't loaded or doesn't have a proxy class. */ virtual void* getProxy(QString name) = 0; // Mouse polling virtual void startMousePolling() = 0; virtual void stopMousePolling() = 0; virtual void reserveElectricBorder(ElectricBorder border, Effect *effect) = 0; virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect) = 0; /** * Registers the given @p action for the given @p border to be activated through * a touch swipe gesture. * * If the @p border gets triggered through a touch swipe gesture the QAction::triggered * signal gets invoked. * * To unregister the touch screen action either delete the @p action or * invoke unregisterTouchBorder. * * @see unregisterTouchBorder * @since 5.10 */ virtual void registerTouchBorder(ElectricBorder border, QAction *action) = 0; /** * Unregisters the given @p action for the given touch @p border. * * @see registerTouchBorder * @since 5.10 */ virtual void unregisterTouchBorder(ElectricBorder border, QAction *action) = 0; // functions that allow controlling windows/desktop virtual void activateWindow(KWin::EffectWindow* c) = 0; virtual KWin::EffectWindow* activeWindow() const = 0 ; Q_SCRIPTABLE virtual void moveWindow(KWin::EffectWindow* w, const QPoint& pos, bool snap = false, double snapAdjust = 1.0) = 0; /** * Moves the window to the specific desktop * Setting desktop to NET::OnAllDesktops will set the window on all desktops */ Q_SCRIPTABLE virtual void windowToDesktop(KWin::EffectWindow* w, int desktop) = 0; /** * Moves a window to the given desktops * On X11, the window will end up on the last window in the list * Setting this to an empty list will set the window on all desktops * * @arg desktopIds a list of desktops the window should be placed on. NET::OnAllDesktops is not a valid desktop X11Id */ Q_SCRIPTABLE virtual void windowToDesktops(KWin::EffectWindow* w, const QVector &desktopIds) = 0; Q_SCRIPTABLE virtual void windowToScreen(KWin::EffectWindow* w, int screen) = 0; virtual void setShowingDesktop(bool showing) = 0; // Activities /** * @returns The ID of the current activity. */ virtual QString currentActivity() const = 0; // Desktops /** * @returns The ID of the current desktop. */ virtual int currentDesktop() const = 0; /** * @returns Total number of desktops currently in existence. */ virtual int numberOfDesktops() const = 0; /** * Set the current desktop to @a desktop. */ virtual void setCurrentDesktop(int desktop) = 0; /** * Sets the total number of desktops to @a desktops. */ virtual void setNumberOfDesktops(int desktops) = 0; /** * @returns The size of desktop layout in grid units. */ virtual QSize desktopGridSize() const = 0; /** * @returns The width of desktop layout in grid units. */ virtual int desktopGridWidth() const = 0; /** * @returns The height of desktop layout in grid units. */ virtual int desktopGridHeight() const = 0; /** * @returns The width of desktop layout in pixels. */ virtual int workspaceWidth() const = 0; /** * @returns The height of desktop layout in pixels. */ virtual int workspaceHeight() const = 0; /** * @returns The ID of the desktop at the point @a coords or 0 if no desktop exists at that * point. @a coords is to be in grid units. */ virtual int desktopAtCoords(QPoint coords) const = 0; /** * @returns The coords of desktop @a id in grid units. */ virtual QPoint desktopGridCoords(int id) const = 0; /** * @returns The coords of the top-left corner of desktop @a id in pixels. */ virtual QPoint desktopCoords(int id) const = 0; /** * @returns The ID of the desktop above desktop @a id. Wraps around to the bottom of * the layout if @a wrap is set. If @a id is not set use the current one. */ Q_SCRIPTABLE virtual int desktopAbove(int desktop = 0, bool wrap = true) const = 0; /** * @returns The ID of the desktop to the right of desktop @a id. Wraps around to the * left of the layout if @a wrap is set. If @a id is not set use the current one. */ Q_SCRIPTABLE virtual int desktopToRight(int desktop = 0, bool wrap = true) const = 0; /** * @returns The ID of the desktop below desktop @a id. Wraps around to the top of the * layout if @a wrap is set. If @a id is not set use the current one. */ Q_SCRIPTABLE virtual int desktopBelow(int desktop = 0, bool wrap = true) const = 0; /** * @returns The ID of the desktop to the left of desktop @a id. Wraps around to the * right of the layout if @a wrap is set. If @a id is not set use the current one. */ Q_SCRIPTABLE virtual int desktopToLeft(int desktop = 0, bool wrap = true) const = 0; Q_SCRIPTABLE virtual QString desktopName(int desktop) const = 0; virtual bool optionRollOverDesktops() const = 0; virtual int activeScreen() const = 0; // Xinerama virtual int numScreens() const = 0; // Xinerama Q_SCRIPTABLE virtual int screenNumber(const QPoint& pos) const = 0; // Xinerama virtual QRect clientArea(clientAreaOption, int screen, int desktop) const = 0; virtual QRect clientArea(clientAreaOption, const EffectWindow* c) const = 0; virtual QRect clientArea(clientAreaOption, const QPoint& p, int desktop) const = 0; /** * The bounding size of all screens combined. Overlapping areas * are not counted multiple times. * * @see virtualScreenGeometry() * @see virtualScreenSizeChanged() * @since 5.0 */ virtual QSize virtualScreenSize() const = 0; /** * The bounding geometry of all outputs combined. Always starts at (0,0) and has * virtualScreenSize as it's size. * * @see virtualScreenSize() * @see virtualScreenGeometryChanged() * @since 5.0 */ virtual QRect virtualScreenGeometry() const = 0; /** * Factor by which animation speed in the effect should be modified (multiplied). * If configurable in the effect itself, the option should have also 'default' * animation speed. The actual value should be determined using animationTime(). * Note: The factor can be also 0, so make sure your code can cope with 0ms time * if used manually. */ virtual double animationTimeFactor() const = 0; virtual WindowQuadType newWindowQuadType() = 0; Q_SCRIPTABLE virtual KWin::EffectWindow* findWindow(WId id) const = 0; Q_SCRIPTABLE virtual KWin::EffectWindow* findWindow(KWayland::Server::SurfaceInterface *surf) const = 0; /** * Finds the EffectWindow for the internal window @p w. * If there is no such window @c null is returned. * * On Wayland this returns the internal window. On X11 it returns an Unamanged with the * window id matching that of the provided window @p w. * * @since 5.16 */ Q_SCRIPTABLE virtual KWin::EffectWindow *findWindow(QWindow *w) const = 0; /** * Finds the EffectWindow for the Toplevel with KWin internal @p id. * If there is no such window @c null is returned. * * @since 5.16 */ Q_SCRIPTABLE virtual KWin::EffectWindow *findWindow(const QUuid &id) const = 0; virtual EffectWindowList stackingOrder() const = 0; // window will be temporarily painted as if being at the top of the stack Q_SCRIPTABLE virtual void setElevatedWindow(KWin::EffectWindow* w, bool set) = 0; virtual void setTabBoxWindow(EffectWindow*) = 0; virtual void setTabBoxDesktop(int) = 0; virtual EffectWindowList currentTabBoxWindowList() const = 0; virtual void refTabBox() = 0; virtual void unrefTabBox() = 0; virtual void closeTabBox() = 0; virtual QList< int > currentTabBoxDesktopList() const = 0; virtual int currentTabBoxDesktop() const = 0; virtual EffectWindow* currentTabBoxWindow() const = 0; virtual void setActiveFullScreenEffect(Effect* e) = 0; virtual Effect* activeFullScreenEffect() const = 0; /** * Schedules the entire workspace to be repainted next time. * If you call it during painting (including prepaint) then it does not * affect the current painting. */ Q_SCRIPTABLE virtual void addRepaintFull() = 0; Q_SCRIPTABLE virtual void addRepaint(const QRect& r) = 0; Q_SCRIPTABLE virtual void addRepaint(const QRegion& r) = 0; Q_SCRIPTABLE virtual void addRepaint(int x, int y, int w, int h) = 0; CompositingType compositingType() const; /** * @brief Whether the Compositor is OpenGL based (either GL 1 or 2). * * @return bool @c true in case of OpenGL based Compositor, @c false otherwise */ bool isOpenGLCompositing() const; virtual unsigned long xrenderBufferPicture() = 0; /** * @brief Provides access to the QPainter which is rendering to the back buffer. * * Only relevant for CompositingType QPainterCompositing. For all other compositing types * @c null is returned. * * @return QPainter* The Scene's QPainter or @c null. */ virtual QPainter *scenePainter() = 0; virtual void reconfigure() = 0; virtual QByteArray readRootProperty(long atom, long type, int format) const = 0; /** * @brief Announces support for the feature with the given name. If no other Effect * has announced support for this feature yet, an X11 property will be installed on * the root window. * * The Effect will be notified for events through the signal propertyNotify(). * * To remove the support again use removeSupportProperty. When an Effect is * destroyed it is automatically taken care of removing the support. It is not * required to call removeSupportProperty in the Effect's cleanup handling. * * @param propertyName The name of the property to announce support for * @param effect The effect which announces support * @return xcb_atom_t The created X11 atom * @see removeSupportProperty * @since 4.11 */ virtual xcb_atom_t announceSupportProperty(const QByteArray &propertyName, Effect *effect) = 0; /** * @brief Removes support for the feature with the given name. If there is no other Effect left * which has announced support for the given property, the property will be removed from the * root window. * * In case the Effect had not registered support, calling this function does not change anything. * * @param propertyName The name of the property to remove support for * @param effect The effect which had registered the property. * @see announceSupportProperty * @since 4.11 */ virtual void removeSupportProperty(const QByteArray &propertyName, Effect *effect) = 0; /** * Returns @a true if the active window decoration has shadow API hooks. */ virtual bool hasDecorationShadows() const = 0; /** * Returns @a true if the window decorations use the alpha channel, and @a false otherwise. * @since 4.5 */ virtual bool decorationsHaveAlpha() const = 0; /** * Returns @a true if the window decorations support blurring behind the decoration, and @a false otherwise * @since 4.6 */ virtual bool decorationSupportsBlurBehind() const = 0; /** * Creates a new frame object. If the frame does not have a static size * then it will be located at @a position with @a alignment. A * non-static frame will automatically adjust its size to fit the contents. * @returns A new @ref EffectFrame. It is the responsibility of the caller to delete the * EffectFrame. * @since 4.6 */ virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize = true, const QPoint& position = QPoint(-1, -1), Qt::Alignment alignment = Qt::AlignCenter) const = 0; /** * Allows an effect to trigger a reload of itself. * This can be used by an effect which needs to be reloaded when screen geometry changes. * It is possible that the effect cannot be loaded again as it's supported method does no longer * hold. * @param effect The effect to reload * @since 4.8 */ virtual void reloadEffect(Effect *effect) = 0; /** * Whether the screen is currently considered as locked. * Note for technical reasons this is not always possible to detect. The screen will only * be considered as locked if the screen locking process implements the * org.freedesktop.ScreenSaver interface. * * @returns @c true if the screen is currently locked, @c false otherwise * @see screenLockingChanged * @since 4.11 */ virtual bool isScreenLocked() const = 0; /** * @brief Makes the OpenGL compositing context current. * * If the compositing backend is not using OpenGL, this method returns @c false. * * @return bool @c true if the context became current, @c false otherwise. */ virtual bool makeOpenGLContextCurrent() = 0; /** * @brief Makes a null OpenGL context current resulting in no context * being current. * * If the compositing backend is not OpenGL based, this method is a noop. * * There is normally no reason for an Effect to call this method. */ virtual void doneOpenGLContextCurrent() = 0; virtual xcb_connection_t *xcbConnection() const = 0; virtual xcb_window_t x11RootWindow() const = 0; /** * Interface to the Wayland display: this is relevant only * on Wayland, on X11 it will be nullptr * @since 5.5 */ virtual KWayland::Server::Display *waylandDisplay() const = 0; /** * Whether animations are supported by the Scene. * If this method returns @c false Effects are supposed to not * animate transitions. * * @returns Whether the Scene can drive animations * @since 5.8 */ virtual bool animationsSupported() const = 0; /** * The current cursor image of the Platform. * @see cursorPos * @since 5.9 */ virtual PlatformCursorImage cursorImage() const = 0; /** * The cursor image should be hidden. * @see showCursor * @since 5.9 */ virtual void hideCursor() = 0; /** * The cursor image should be shown again after having been hidden. * @see hideCursor * @since 5.9 */ virtual void showCursor() = 0; /** * Starts an interactive window selection process. * * Once the user selected a window the @p callback is invoked with the selected EffectWindow as * argument. In case the user cancels the interactive window selection or selecting a window is currently * not possible (e.g. screen locked) the @p callback is invoked with a @c nullptr argument. * * During the interactive window selection the cursor is turned into a crosshair cursor. * * @param callback The function to invoke once the interactive window selection ends * @since 5.9 */ virtual void startInteractiveWindowSelection(std::function callback) = 0; /** * Starts an interactive position selection process. * * Once the user selected a position on the screen the @p callback is invoked with * the selected point as argument. In case the user cancels the interactive position selection * or selecting a position is currently not possible (e.g. screen locked) the @p callback * is invoked with a point at @c -1 as x and y argument. * * During the interactive window selection the cursor is turned into a crosshair cursor. * * @param callback The function to invoke once the interactive position selection ends * @since 5.9 */ virtual void startInteractivePositionSelection(std::function callback) = 0; /** * Shows an on-screen-message. To hide it again use hideOnScreenMessage. * * @param message The message to show * @param iconName The optional themed icon name * @see hideOnScreenMessage * @since 5.9 */ virtual void showOnScreenMessage(const QString &message, const QString &iconName = QString()) = 0; /** * Flags for how to hide a shown on-screen-message * @see hideOnScreenMessage * @since 5.9 */ enum class OnScreenMessageHideFlag { /** * The on-screen-message should skip the close window animation. * @see EffectWindow::skipsCloseAnimation */ SkipsCloseAnimation = 1 }; Q_DECLARE_FLAGS(OnScreenMessageHideFlags, OnScreenMessageHideFlag) /** * Hides a previously shown on-screen-message again. * @param flags The flags for how to hide the message * @see showOnScreenMessage * @since 5.9 */ virtual void hideOnScreenMessage(OnScreenMessageHideFlags flags = OnScreenMessageHideFlags()) = 0; /* * @returns The configuration used by the EffectsHandler. * @since 5.10 */ virtual KSharedConfigPtr config() const = 0; /** * @returns The global input configuration (kcminputrc) * @since 5.10 */ virtual KSharedConfigPtr inputConfig() const = 0; /** * Returns if activeFullScreenEffect is set */ virtual bool hasActiveFullScreenEffect() const = 0; /** * Render the supplied EffectQuickView onto the scene * It can be called at any point during the scene rendering * @since 5.18 */ virtual void renderEffectQuickView(EffectQuickView *effectQuickView) const = 0; /** * The status of the session i.e if the user is logging out * @since 5.18 */ virtual SessionState sessionState() const = 0; Q_SIGNALS: /** * Signal emitted when the current desktop changed. * @param oldDesktop The previously current desktop * @param newDesktop The new current desktop * @param with The window which is taken over to the new desktop, can be NULL * @since 4.9 */ void desktopChanged(int oldDesktop, int newDesktop, KWin::EffectWindow *with); /** * @since 4.7 * @deprecated */ void desktopChanged(int oldDesktop, int newDesktop); /** * Signal emitted when a window moved to another desktop * NOTICE that this does NOT imply that the desktop has changed * The @param window which is moved to the new desktop * @param oldDesktop The previous desktop of the window * @param newDesktop The new desktop of the window * @since 4.11.4 */ void desktopPresenceChanged(KWin::EffectWindow *window, int oldDesktop, int newDesktop); /** * Signal emitted when the number of currently existing desktops is changed. * @param old The previous number of desktops in used. * @see EffectsHandler::numberOfDesktops. * @since 4.7 */ void numberDesktopsChanged(uint old); /** * Signal emitted when the number of screens changed. * @since 5.0 */ void numberScreensChanged(); /** * Signal emitted when the desktop showing ("dashboard") state changed * The desktop is risen to the keepAbove layer, you may want to elevate * windows or such. * @since 5.3 */ void showingDesktopChanged(bool); /** * Signal emitted when a new window has been added to the Workspace. * @param w The added window * @since 4.7 */ void windowAdded(KWin::EffectWindow *w); /** * Signal emitted when a window is being removed from the Workspace. * An effect which wants to animate the window closing should connect * to this signal and reference the window by using * refWindow * @param w The window which is being closed * @since 4.7 */ void windowClosed(KWin::EffectWindow *w); /** * Signal emitted when a window get's activated. * @param w The new active window, or @c NULL if there is no active window. * @since 4.7 */ void windowActivated(KWin::EffectWindow *w); /** * Signal emitted when a window is deleted. * This means that a closed window is not referenced any more. * An effect bookkeeping the closed windows should connect to this * signal to clean up the internal references. * @param w The window which is going to be deleted. * @see EffectWindow::refWindow * @see EffectWindow::unrefWindow * @see windowClosed * @since 4.7 */ void windowDeleted(KWin::EffectWindow *w); /** * Signal emitted when a user begins a window move or resize operation. * To figure out whether the user resizes or moves the window use * isUserMove or isUserResize. * Whenever the geometry is updated the signal @ref windowStepUserMovedResized * is emitted with the current geometry. * The move/resize operation ends with the signal @ref windowFinishUserMovedResized. * Only one window can be moved/resized by the user at the same time! * @param w The window which is being moved/resized * @see windowStepUserMovedResized * @see windowFinishUserMovedResized * @see EffectWindow::isUserMove * @see EffectWindow::isUserResize * @since 4.7 */ void windowStartUserMovedResized(KWin::EffectWindow *w); /** * Signal emitted during a move/resize operation when the user changed the geometry. * Please note: KWin supports two operation modes. In one mode all changes are applied * instantly. This means the window's geometry matches the passed in @p geometry. In the * other mode the geometry is changed after the user ended the move/resize mode. * The @p geometry differs from the window's geometry. Also the window's pixmap still has * the same size as before. Depending what the effect wants to do it would be recommended * to scale/translate the window. * @param w The window which is being moved/resized * @param geometry The geometry of the window in the current move/resize step. * @see windowStartUserMovedResized * @see windowFinishUserMovedResized * @see EffectWindow::isUserMove * @see EffectWindow::isUserResize * @since 4.7 */ void windowStepUserMovedResized(KWin::EffectWindow *w, const QRect &geometry); /** * Signal emitted when the user finishes move/resize of window @p w. * @param w The window which has been moved/resized * @see windowStartUserMovedResized * @see windowFinishUserMovedResized * @since 4.7 */ void windowFinishUserMovedResized(KWin::EffectWindow *w); /** * Signal emitted when the maximized state of the window @p w changed. * A window can be in one of four states: * @li restored: both @p horizontal and @p vertical are @c false * @li horizontally maximized: @p horizontal is @c true and @p vertical is @c false * @li vertically maximized: @p horizontal is @c false and @p vertical is @c true * @li completely maximized: both @p horizontal and @p vertical are @c true * @param w The window whose maximized state changed * @param horizontal If @c true maximized horizontally * @param vertical If @c true maximized vertically * @since 4.7 */ void windowMaximizedStateChanged(KWin::EffectWindow *w, bool horizontal, bool vertical); /** * Signal emitted when the geometry or shape of a window changed. * This is caused if the window changes geometry without user interaction. * E.g. the decoration is changed. This is in opposite to windowUserMovedResized * which is caused by direct user interaction. * @param w The window whose geometry changed * @param old The previous geometry * @see windowUserMovedResized * @since 4.7 */ void windowGeometryShapeChanged(KWin::EffectWindow *w, const QRect &old); /** * This signal is emitted when the frame geometry of a window changed. * @param window The window whose geometry changed * @param oldGeometry The previous geometry * @since 5.19 */ void windowFrameGeometryChanged(KWin::EffectWindow *window, const QRect &oldGeometry); /** * Signal emitted when the padding of a window changed. (eg. shadow size) * @param w The window whose geometry changed * @param old The previous expandedGeometry() * @since 4.9 */ void windowPaddingChanged(KWin::EffectWindow *w, const QRect &old); /** * Signal emitted when the windows opacity is changed. * @param w The window whose opacity level is changed. * @param oldOpacity The previous opacity level * @param newOpacity The new opacity level * @since 4.7 */ void windowOpacityChanged(KWin::EffectWindow *w, qreal oldOpacity, qreal newOpacity); /** * Signal emitted when a window got minimized. * @param w The window which was minimized * @since 4.7 */ void windowMinimized(KWin::EffectWindow *w); /** * Signal emitted when a window got unminimized. * @param w The window which was unminimized * @since 4.7 */ void windowUnminimized(KWin::EffectWindow *w); /** * Signal emitted when a window either becomes modal (ie. blocking for its main client) or looses that state. * @param w The window which was unminimized * @since 4.11 */ void windowModalityChanged(KWin::EffectWindow *w); /** * Signal emitted when a window either became unresponsive (eg. app froze or crashed) * or respoonsive * @param w The window that became (un)responsive * @param unresponsive Whether the window is responsive or unresponsive * @since 5.10 */ void windowUnresponsiveChanged(KWin::EffectWindow *w, bool unresponsive); /** * Signal emitted when an area of a window is scheduled for repainting. * Use this signal in an effect if another area needs to be synced as well. * @param w The window which is scheduled for repainting * @param r Always empty. * @since 4.7 */ void windowDamaged(KWin::EffectWindow *w, const QRect &r); /** * Signal emitted when a tabbox is added. * An effect who wants to replace the tabbox with itself should use refTabBox. * @param mode The TabBoxMode. * @see refTabBox * @see tabBoxClosed * @see tabBoxUpdated * @see tabBoxKeyEvent * @since 4.7 */ void tabBoxAdded(int mode); /** * Signal emitted when the TabBox was closed by KWin core. * An effect which referenced the TabBox should use unrefTabBox to unref again. * @see unrefTabBox * @see tabBoxAdded * @since 4.7 */ void tabBoxClosed(); /** * Signal emitted when the selected TabBox window changed or the TabBox List changed. * An effect should only response to this signal if it referenced the TabBox with refTabBox. * @see refTabBox * @see currentTabBoxWindowList * @see currentTabBoxDesktopList * @see currentTabBoxWindow * @see currentTabBoxDesktop * @since 4.7 */ void tabBoxUpdated(); /** * Signal emitted when a key event, which is not handled by TabBox directly is, happens while * TabBox is active. An effect might use the key event to e.g. change the selected window. * An effect should only response to this signal if it referenced the TabBox with refTabBox. * @param event The key event not handled by TabBox directly * @see refTabBox * @since 4.7 */ void tabBoxKeyEvent(QKeyEvent* event); void currentTabAboutToChange(KWin::EffectWindow* from, KWin::EffectWindow* to); void tabAdded(KWin::EffectWindow* from, KWin::EffectWindow* to); // from merged with to void tabRemoved(KWin::EffectWindow* c, KWin::EffectWindow* group); // c removed from group /** * Signal emitted when mouse changed. * If an effect needs to get updated mouse positions, it needs to first call startMousePolling. * For a fullscreen effect it is better to use an input window and react on windowInputMouseEvent. * @param pos The new mouse position * @param oldpos The previously mouse position * @param buttons The pressed mouse buttons * @param oldbuttons The previously pressed mouse buttons * @param modifiers Pressed keyboard modifiers * @param oldmodifiers Previously pressed keyboard modifiers. * @see startMousePolling * @since 4.7 */ void mouseChanged(const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); /** * Signal emitted when the cursor shape changed. * You'll likely want to query the current cursor as reaction: xcb_xfixes_get_cursor_image_unchecked * Connection to this signal is tracked, so if you don't need it anymore, disconnect from it to stop cursor event filtering */ void cursorShapeChanged(); /** * Receives events registered for using registerPropertyType. * Use readProperty() to get the property data. * Note that the property may be already set on the window, so doing the same * processing from windowAdded() (e.g. simply calling propertyNotify() from it) * is usually needed. * @param w The window whose property changed, is @c null if it is a root window property * @param atom The property * @since 4.7 */ void propertyNotify(KWin::EffectWindow* w, long atom); /** * Signal emitted after the screen geometry changed (e.g. add of a monitor). * Effects using displayWidth()/displayHeight() to cache information should * react on this signal and update the caches. * @param size The new screen size * @since 4.8 */ void screenGeometryChanged(const QSize &size); /** * This signal is emitted when the global * activity is changed * @param id id of the new current activity * @since 4.9 */ void currentActivityChanged(const QString &id); /** * This signal is emitted when a new activity is added * @param id id of the new activity * @since 4.9 */ void activityAdded(const QString &id); /** * This signal is emitted when the activity * is removed * @param id id of the removed activity * @since 4.9 */ void activityRemoved(const QString &id); /** * This signal is emitted when the screen got locked or unlocked. * @param locked @c true if the screen is now locked, @c false if it is now unlocked * @since 4.11 */ void screenLockingChanged(bool locked); /** * This signal is emitted just before the screen locker tries to grab keys and lock the screen * Effects should release any grabs immediately * @since 5.17 */ void screenAboutToLock(); /** * This signels is emitted when ever the stacking order is change, ie. a window is risen * or lowered * @since 4.10 */ void stackingOrderChanged(); /** * This signal is emitted when the user starts to approach the @p border with the mouse. * The @p factor describes how far away the mouse is in a relative mean. The values are in * [0.0, 1.0] with 0.0 being emitted when first entered and on leaving. The value 1.0 means that * the @p border is reached with the mouse. So the values are well suited for animations. * The signal is always emitted when the mouse cursor position changes. * @param border The screen edge which is being approached * @param factor Value in range [0.0,1.0] to describe how close the mouse is to the border * @param geometry The geometry of the edge which is being approached * @since 4.11 */ void screenEdgeApproaching(ElectricBorder border, qreal factor, const QRect &geometry); /** * Emitted whenever the virtualScreenSize changes. * @see virtualScreenSize() * @since 5.0 */ void virtualScreenSizeChanged(); /** * Emitted whenever the virtualScreenGeometry changes. * @see virtualScreenGeometry() * @since 5.0 */ void virtualScreenGeometryChanged(); /** * The window @p w gets shown again. The window was previously * initially shown with windowAdded and hidden with windowHidden. * * @see windowHidden * @see windowAdded * @since 5.8 */ void windowShown(KWin::EffectWindow *w); /** * The window @p w got hidden but not yet closed. * This can happen when a window is still being used and is supposed to be shown again * with windowShown. On X11 an example is autohiding panels. On Wayland every * window first goes through the window hidden state and might get shown again, or might * get closed the normal way. * * @see windowShown * @see windowClosed * @since 5.8 */ void windowHidden(KWin::EffectWindow *w); /** * This signal gets emitted when the data on EffectWindow @p w for @p role changed. * * An Effect can connect to this signal to read the new value and react on it. * E.g. an Effect which does not operate on windows grabbed by another Effect wants * to cancel the already scheduled animation if another Effect adds a grab. * * @param w The EffectWindow for which the data changed * @param role The data role which changed * @see EffectWindow::setData * @see EffectWindow::data * @since 5.8.4 */ void windowDataChanged(KWin::EffectWindow *w, int role); /** * The xcb connection changed, either a new xcbConnection got created or the existing one * got destroyed. * Effects can use this to refetch the properties they want to set. * * When the xcbConnection changes also the x11RootWindow becomes invalid. * @see xcbConnection * @see x11RootWindow * @since 5.11 */ void xcbConnectionChanged(); /** * This signal is emitted when active fullscreen effect changed. * * @see activeFullScreenEffect * @see setActiveFullScreenEffect * @since 5.14 */ void activeFullScreenEffectChanged(); /** * This signal is emitted when active fullscreen effect changed to being * set or unset * * @see activeFullScreenEffect * @see setActiveFullScreenEffect * @since 5.15 */ void hasActiveFullScreenEffectChanged(); /** * This signal is emitted when the keep above state of @p w was changed. * * @param w The window whose the keep above state was changed. * @since 5.15 */ void windowKeepAboveChanged(KWin::EffectWindow *w); /** * This signal is emitted when the keep below state of @p was changed. * * @param w The window whose the keep below state was changed. * @since 5.15 */ void windowKeepBelowChanged(KWin::EffectWindow *w); /** * This signal is emitted when the full screen state of @p w was changed. * * @param w The window whose the full screen state was changed. * @since 5.15 */ void windowFullScreenChanged(KWin::EffectWindow *w); /** * This signal is emitted when the session state was changed * @since 5.18 */ void sessionStateChanged(); protected: QVector< EffectPair > loaded_effects; //QHash< QString, EffectFactory* > effect_factories; CompositingType compositing_type; }; /** * @short Representation of a window used by/for Effect classes. * * The purpose is to hide internal data and also to serve as a single * representation for the case when Client/Unmanaged becomes Deleted. */ class KWINEFFECTS_EXPORT EffectWindow : public QObject { Q_OBJECT Q_PROPERTY(bool alpha READ hasAlpha CONSTANT) Q_PROPERTY(QRect geometry READ geometry) Q_PROPERTY(QRect expandedGeometry READ expandedGeometry) Q_PROPERTY(int height READ height) Q_PROPERTY(qreal opacity READ opacity) Q_PROPERTY(QPoint pos READ pos) Q_PROPERTY(int screen READ screen) Q_PROPERTY(QSize size READ size) Q_PROPERTY(int width READ width) Q_PROPERTY(int x READ x) Q_PROPERTY(int y READ y) Q_PROPERTY(int desktop READ desktop) Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops) Q_PROPERTY(bool onCurrentDesktop READ isOnCurrentDesktop) Q_PROPERTY(QRect rect READ rect) Q_PROPERTY(QString windowClass READ windowClass) Q_PROPERTY(QString windowRole READ windowRole) /** * Returns whether the window is a desktop background window (the one with wallpaper). * See _NET_WM_WINDOW_TYPE_DESKTOP at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool desktopWindow READ isDesktop) /** * Returns whether the window is a dock (i.e. a panel). * See _NET_WM_WINDOW_TYPE_DOCK at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool dock READ isDock) /** * Returns whether the window is a standalone (detached) toolbar window. * See _NET_WM_WINDOW_TYPE_TOOLBAR at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool toolbar READ isToolbar) /** * Returns whether the window is a torn-off menu. * See _NET_WM_WINDOW_TYPE_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool menu READ isMenu) /** * Returns whether the window is a "normal" window, i.e. an application or any other window * for which none of the specialized window types fit. * See _NET_WM_WINDOW_TYPE_NORMAL at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool normalWindow READ isNormalWindow) /** * Returns whether the window is a dialog window. * See _NET_WM_WINDOW_TYPE_DIALOG at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool dialog READ isDialog) /** * Returns whether the window is a splashscreen. Note that many (especially older) applications * do not support marking their splash windows with this type. * See _NET_WM_WINDOW_TYPE_SPLASH at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool splash READ isSplash) /** * Returns whether the window is a utility window, such as a tool window. * See _NET_WM_WINDOW_TYPE_UTILITY at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool utility READ isUtility) /** * Returns whether the window is a dropdown menu (i.e. a popup directly or indirectly open * from the applications menubar). * See _NET_WM_WINDOW_TYPE_DROPDOWN_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool dropdownMenu READ isDropdownMenu) /** * Returns whether the window is a popup menu (that is not a torn-off or dropdown menu). * See _NET_WM_WINDOW_TYPE_POPUP_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool popupMenu READ isPopupMenu) /** * Returns whether the window is a tooltip. * See _NET_WM_WINDOW_TYPE_TOOLTIP at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool tooltip READ isTooltip) /** * Returns whether the window is a window with a notification. * See _NET_WM_WINDOW_TYPE_NOTIFICATION at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool notification READ isNotification) /** * Returns whether the window is a window with a critical notification. * using the non-standard _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION */ Q_PROPERTY(bool criticalNotification READ isCriticalNotification) /** * Returns whether the window is an on screen display window * using the non-standard _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY */ Q_PROPERTY(bool onScreenDisplay READ isOnScreenDisplay) /** * Returns whether the window is a combobox popup. * See _NET_WM_WINDOW_TYPE_COMBO at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool comboBox READ isComboBox) /** * Returns whether the window is a Drag&Drop icon. * See _NET_WM_WINDOW_TYPE_DND at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(bool dndIcon READ isDNDIcon) /** * Returns the NETWM window type * See https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(int windowType READ windowType) /** * Whether this EffectWindow is managed by KWin (it has control over its placement and other * aspects, as opposed to override-redirect windows that are entirely handled by the application). */ Q_PROPERTY(bool managed READ isManaged) /** * Whether this EffectWindow represents an already deleted window and only kept for the compositor for animations. */ Q_PROPERTY(bool deleted READ isDeleted) /** * Whether the window has an own shape */ Q_PROPERTY(bool shaped READ hasOwnShape) /** * The Window's shape */ Q_PROPERTY(QRegion shape READ shape) /** * The Caption of the window. Read from WM_NAME property together with a suffix for hostname and shortcut. */ Q_PROPERTY(QString caption READ caption) /** * Whether the window is set to be kept above other windows. */ Q_PROPERTY(bool keepAbove READ keepAbove) /** * Whether the window is set to be kept below other windows. */ Q_PROPERTY(bool keepBelow READ keepBelow) /** * Whether the window is minimized. */ Q_PROPERTY(bool minimized READ isMinimized WRITE setMinimized) /** * Whether the window represents a modal window. */ Q_PROPERTY(bool modal READ isModal) /** * Whether the window is moveable. Even if it is not moveable, it might be possible to move * it to another screen. * @see moveableAcrossScreens */ Q_PROPERTY(bool moveable READ isMovable) /** * Whether the window can be moved to another screen. * @see moveable */ Q_PROPERTY(bool moveableAcrossScreens READ isMovableAcrossScreens) /** * By how much the window wishes to grow/shrink at least. Usually QSize(1,1). * MAY BE DISOBEYED BY THE WM! It's only for information, do NOT rely on it at all. */ Q_PROPERTY(QSize basicUnit READ basicUnit) /** * Whether the window is currently being moved by the user. */ Q_PROPERTY(bool move READ isUserMove) /** * Whether the window is currently being resized by the user. */ Q_PROPERTY(bool resize READ isUserResize) /** * The optional geometry representing the minimized Client in e.g a taskbar. * See _NET_WM_ICON_GEOMETRY at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ Q_PROPERTY(QRect iconGeometry READ iconGeometry) /** * Returns whether the window is any of special windows types (desktop, dock, splash, ...), * i.e. window types that usually don't have a window frame and the user does not use window * management (moving, raising,...) on them. */ Q_PROPERTY(bool specialWindow READ isSpecialWindow) Q_PROPERTY(QIcon icon READ icon) /** * Whether the window should be excluded from window switching effects. */ Q_PROPERTY(bool skipSwitcher READ isSkipSwitcher) /** * Geometry of the actual window contents inside the whole (including decorations) window. */ Q_PROPERTY(QRect contentsRect READ contentsRect) /** * Geometry of the transparent rect in the decoration. * May be different from contentsRect if the decoration is extended into the client area. */ Q_PROPERTY(QRect decorationInnerRect READ decorationInnerRect) Q_PROPERTY(bool hasDecoration READ hasDecoration) Q_PROPERTY(QStringList activities READ activities) Q_PROPERTY(bool onCurrentActivity READ isOnCurrentActivity) Q_PROPERTY(bool onAllActivities READ isOnAllActivities) /** * Whether the decoration currently uses an alpha channel. * @since 4.10 */ Q_PROPERTY(bool decorationHasAlpha READ decorationHasAlpha) /** * Whether the window is currently visible to the user, that is: *
    *
  • Not minimized
  • *
  • On current desktop
  • *
  • On current activity
  • *
* @since 4.11 */ Q_PROPERTY(bool visible READ isVisible) /** * Whether the window does not want to be animated on window close. * In case this property is @c true it is not useful to start an animation on window close. * The window will not be visible, but the animation hooks are executed. * @since 5.0 */ Q_PROPERTY(bool skipsCloseAnimation READ skipsCloseAnimation) /** * Interface to the corresponding wayland surface. * relevant only in Wayland, on X11 it will be nullptr */ Q_PROPERTY(KWayland::Server::SurfaceInterface *surface READ surface) /** * Whether the window is fullscreen. * @since 5.6 */ Q_PROPERTY(bool fullScreen READ isFullScreen) /** * Whether this client is unresponsive. * * When an application failed to react on a ping request in time, it is * considered unresponsive. This usually indicates that the application froze or crashed. * * @since 5.10 */ Q_PROPERTY(bool unresponsive READ isUnresponsive) /** * Whether this is a Wayland client. * @since 5.15 */ Q_PROPERTY(bool waylandClient READ isWaylandClient CONSTANT) /** * Whether this is an X11 client. * @since 5.15 */ Q_PROPERTY(bool x11Client READ isX11Client CONSTANT) /** * Whether the window is a popup. * * A popup is a window that can be used to implement tooltips, combo box popups, * popup menus and other similar user interface concepts. * * @since 5.15 */ Q_PROPERTY(bool popupWindow READ isPopupWindow CONSTANT) /** * KWin internal window. Specific to Wayland platform. * * If the EffectWindow does not reference an internal window, this property is @c null. * @since 5.16 */ Q_PROPERTY(QWindow *internalWindow READ internalWindow CONSTANT) /** * Whether this EffectWindow represents the outline. * * When compositing is turned on, the outline is an actual window. * * @since 5.16 */ Q_PROPERTY(bool outline READ isOutline CONSTANT) /** * The PID of the application this window belongs to. * * @since 5.18 */ Q_PROPERTY(bool outline READ isOutline CONSTANT) public: /** Flags explaining why painting should be disabled */ enum { /** Window will not be painted */ PAINT_DISABLED = 1 << 0, /** Window will not be painted because it is deleted */ PAINT_DISABLED_BY_DELETE = 1 << 1, /** Window will not be painted because of which desktop it's on */ PAINT_DISABLED_BY_DESKTOP = 1 << 2, /** Window will not be painted because it is minimized */ PAINT_DISABLED_BY_MINIMIZE = 1 << 3, /** Deprecated, tab groups have been removed: Window will not be painted because it is not the active window in a client group */ PAINT_DISABLED_BY_TAB_GROUP = 1 << 4, /** Window will not be painted because it's not on the current activity */ PAINT_DISABLED_BY_ACTIVITY = 1 << 5 }; explicit EffectWindow(QObject *parent = nullptr); ~EffectWindow() override; virtual void enablePainting(int reason) = 0; virtual void disablePainting(int reason) = 0; virtual bool isPaintingEnabled() = 0; Q_SCRIPTABLE virtual void addRepaint(const QRect &r) = 0; Q_SCRIPTABLE virtual void addRepaint(int x, int y, int w, int h) = 0; Q_SCRIPTABLE virtual void addRepaintFull() = 0; Q_SCRIPTABLE virtual void addLayerRepaint(const QRect &r) = 0; Q_SCRIPTABLE virtual void addLayerRepaint(int x, int y, int w, int h) = 0; virtual void refWindow() = 0; virtual void unrefWindow() = 0; virtual bool isDeleted() const = 0; virtual bool isMinimized() const = 0; virtual double opacity() const = 0; virtual bool hasAlpha() const = 0; bool isOnCurrentActivity() const; Q_SCRIPTABLE bool isOnActivity(const QString &id) const; bool isOnAllActivities() const; virtual QStringList activities() const = 0; Q_SCRIPTABLE bool isOnDesktop(int d) const; bool isOnCurrentDesktop() const; bool isOnAllDesktops() const; /** * The desktop this window is in. This makes sense only on X11 * where desktops are mutually exclusive, on Wayland it's the last * desktop the window has been added to. * use desktops() instead. * @see desktops() * @deprecated */ #ifndef KWIN_NO_DEPRECATED virtual int KWIN_DEPRECATED desktop() const = 0; // prefer isOnXXX() #endif /** * All the desktops by number that the window is in. On X11 this list will always have * a length of 1, on Wayland can be any subset. * If the list is empty it means the window is on all desktops */ virtual QVector desktops() const = 0; virtual int x() const = 0; virtual int y() const = 0; virtual int width() const = 0; virtual int height() const = 0; /** * By how much the window wishes to grow/shrink at least. Usually QSize(1,1). * MAY BE DISOBEYED BY THE WM! It's only for information, do NOT rely on it at all. */ virtual QSize basicUnit() const = 0; /** * @deprecated Use frameGeometry() instead. */ virtual QRect geometry() const = 0; /** * Returns the geometry of the window excluding server-side and client-side * drop-shadows. * * @since 5.18 */ virtual QRect frameGeometry() const = 0; /** * Returns the geometry of the pixmap or buffer attached to this window. * * For X11 clients, this method returns server-side geometry of the Toplevel. * * For Wayland clients, this method returns rectangle that the main surface * occupies on the screen, in global screen coordinates. * * @since 5.18 */ virtual QRect bufferGeometry() const = 0; /** * Geometry of the window including decoration and potentially shadows. * May be different from geometry() if the window has a shadow. * @since 4.9 */ virtual QRect expandedGeometry() const = 0; virtual QRegion shape() const = 0; virtual int screen() const = 0; /** @internal Do not use */ virtual bool hasOwnShape() const = 0; // only for shadow effect, for now virtual QPoint pos() const = 0; virtual QSize size() const = 0; virtual QRect rect() const = 0; virtual bool isMovable() const = 0; virtual bool isMovableAcrossScreens() const = 0; virtual bool isUserMove() const = 0; virtual bool isUserResize() const = 0; virtual QRect iconGeometry() const = 0; /** * Geometry of the actual window contents inside the whole (including decorations) window. */ virtual QRect contentsRect() const = 0; /** * Geometry of the transparent rect in the decoration. * May be different from contentsRect() if the decoration is extended into the client area. * @since 4.5 */ virtual QRect decorationInnerRect() const = 0; bool hasDecoration() const; virtual bool decorationHasAlpha() const = 0; virtual QByteArray readProperty(long atom, long type, int format) const = 0; virtual void deleteProperty(long atom) const = 0; virtual QString caption() const = 0; virtual QIcon icon() const = 0; virtual QString windowClass() const = 0; virtual QString windowRole() const = 0; virtual const EffectWindowGroup* group() const = 0; /** * Returns whether the window is a desktop background window (the one with wallpaper). * See _NET_WM_WINDOW_TYPE_DESKTOP at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isDesktop() const = 0; /** * Returns whether the window is a dock (i.e. a panel). * See _NET_WM_WINDOW_TYPE_DOCK at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isDock() const = 0; /** * Returns whether the window is a standalone (detached) toolbar window. * See _NET_WM_WINDOW_TYPE_TOOLBAR at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isToolbar() const = 0; /** * Returns whether the window is a torn-off menu. * See _NET_WM_WINDOW_TYPE_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isMenu() const = 0; /** * Returns whether the window is a "normal" window, i.e. an application or any other window * for which none of the specialized window types fit. * See _NET_WM_WINDOW_TYPE_NORMAL at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isNormalWindow() const = 0; // normal as in 'NET::Normal or NET::Unknown non-transient' /** * Returns whether the window is any of special windows types (desktop, dock, splash, ...), * i.e. window types that usually don't have a window frame and the user does not use window * management (moving, raising,...) on them. */ virtual bool isSpecialWindow() const = 0; /** * Returns whether the window is a dialog window. * See _NET_WM_WINDOW_TYPE_DIALOG at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isDialog() const = 0; /** * Returns whether the window is a splashscreen. Note that many (especially older) applications * do not support marking their splash windows with this type. * See _NET_WM_WINDOW_TYPE_SPLASH at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isSplash() const = 0; /** * Returns whether the window is a utility window, such as a tool window. * See _NET_WM_WINDOW_TYPE_UTILITY at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isUtility() const = 0; /** * Returns whether the window is a dropdown menu (i.e. a popup directly or indirectly open * from the applications menubar). * See _NET_WM_WINDOW_TYPE_DROPDOWN_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isDropdownMenu() const = 0; /** * Returns whether the window is a popup menu (that is not a torn-off or dropdown menu). * See _NET_WM_WINDOW_TYPE_POPUP_MENU at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isPopupMenu() const = 0; // a context popup, not dropdown, not torn-off /** * Returns whether the window is a tooltip. * See _NET_WM_WINDOW_TYPE_TOOLTIP at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isTooltip() const = 0; /** * Returns whether the window is a window with a notification. * See _NET_WM_WINDOW_TYPE_NOTIFICATION at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isNotification() const = 0; /** * Returns whether the window is a window with a critical notification. * using the non-standard _KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION */ virtual bool isCriticalNotification() const = 0; /** * Returns whether the window is an on screen display window * using the non-standard _KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY */ virtual bool isOnScreenDisplay() const = 0; /** * Returns whether the window is a combobox popup. * See _NET_WM_WINDOW_TYPE_COMBO at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isComboBox() const = 0; /** * Returns whether the window is a Drag&Drop icon. * See _NET_WM_WINDOW_TYPE_DND at https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual bool isDNDIcon() const = 0; /** * Returns the NETWM window type * See https://standards.freedesktop.org/wm-spec/wm-spec-latest.html . */ virtual NET::WindowType windowType() const = 0; /** * Returns whether the window is managed by KWin (it has control over its placement and other * aspects, as opposed to override-redirect windows that are entirely handled by the application). */ virtual bool isManaged() const = 0; // whether it's managed or override-redirect /** * Returns whether or not the window can accept keyboard focus. */ virtual bool acceptsFocus() const = 0; /** * Returns whether or not the window is kept above all other windows. */ virtual bool keepAbove() const = 0; /** * Returns whether the window is kept below all other windows. */ virtual bool keepBelow() const = 0; virtual bool isModal() const = 0; Q_SCRIPTABLE virtual KWin::EffectWindow* findModal() = 0; Q_SCRIPTABLE virtual QList mainWindows() const = 0; /** * Returns whether the window should be excluded from window switching effects. * @since 4.5 */ virtual bool isSkipSwitcher() const = 0; /** * Returns the unmodified window quad list. Can also be used to force rebuilding. */ virtual WindowQuadList buildQuads(bool force = false) const = 0; void setMinimized(bool minimize); virtual void minimize() = 0; virtual void unminimize() = 0; Q_SCRIPTABLE virtual void closeWindow() = 0; /// deprecated virtual bool isCurrentTab() const = 0; /** * @since 4.11 */ bool isVisible() const; /** * @since 5.0 */ virtual bool skipsCloseAnimation() const = 0; /** * @since 5.5 */ virtual KWayland::Server::SurfaceInterface *surface() const = 0; /** * @since 5.6 */ virtual bool isFullScreen() const = 0; /** * @since 5.10 */ virtual bool isUnresponsive() const = 0; /** * @since 5.15 */ virtual bool isWaylandClient() const = 0; /** * @since 5.15 */ virtual bool isX11Client() const = 0; /** * @since 5.15 */ virtual bool isPopupWindow() const = 0; /** * @since 5.16 */ virtual QWindow *internalWindow() const = 0; /** * @since 5.16 */ virtual bool isOutline() const = 0; /** * @since 5.18 */ virtual pid_t pid() const = 0; /** * Can be used to by effects to store arbitrary data in the EffectWindow. * * Invoking this method will emit the signal EffectsHandler::windowDataChanged. * @see EffectsHandler::windowDataChanged */ Q_SCRIPTABLE virtual void setData(int role, const QVariant &data) = 0; Q_SCRIPTABLE virtual QVariant data(int role) const = 0; /** * @brief References the previous window pixmap to prevent discarding. * * This method allows to reference the previous window pixmap in case that a window changed * its size, which requires a new window pixmap. By referencing the previous (and then outdated) * window pixmap an effect can for example cross fade the current window pixmap with the previous * one. This allows for smoother transitions for window geometry changes. * * If an effect calls this method on a window it also needs to call unreferencePreviousWindowPixmap * once it does no longer need the previous window pixmap. * * Note: the window pixmap is not kept forever even when referenced. If the geometry changes again, so that * a new window pixmap is created, the previous window pixmap will be exchanged with the current one. This * means it's still possible to have rendering glitches. An effect is supposed to track for itself the changes * to the window's geometry and decide how the transition should continue in such a situation. * * @see unreferencePreviousWindowPixmap * @since 4.11 */ virtual void referencePreviousWindowPixmap() = 0; /** * @brief Unreferences the previous window pixmap. Only relevant after referencePreviousWindowPixmap had * been called. * * @see referencePreviousWindowPixmap * @since 4.11 */ virtual void unreferencePreviousWindowPixmap() = 0; private: class Private; QScopedPointer d; }; class KWINEFFECTS_EXPORT EffectWindowGroup { public: virtual ~EffectWindowGroup(); virtual EffectWindowList members() const = 0; }; struct GLVertex2D { QVector2D position; QVector2D texcoord; }; struct GLVertex3D { QVector3D position; QVector2D texcoord; }; /** * @short Vertex class * * A vertex is one position in a window. WindowQuad consists of four WindowVertex objects * and represents one part of a window. */ class KWINEFFECTS_EXPORT WindowVertex { public: WindowVertex(); WindowVertex(const QPointF &position, const QPointF &textureCoordinate); WindowVertex(double x, double y, double tx, double ty); double x() const { return px; } double y() const { return py; } double u() const { return tx; } double v() const { return ty; } double originalX() const { return ox; } double originalY() const { return oy; } double textureX() const { return tx; } double textureY() const { return ty; } void move(double x, double y); void setX(double x); void setY(double y); private: friend class WindowQuad; friend class WindowQuadList; double px, py; // position double ox, oy; // origional position double tx, ty; // texture coords }; /** * @short Class representing one area of a window. * * WindowQuads consists of four WindowVertex objects and represents one part of a window. */ // NOTE: This class expects the (original) vertices to be in the clockwise order starting from topleft. class KWINEFFECTS_EXPORT WindowQuad { public: explicit WindowQuad(WindowQuadType type, int id = -1); WindowQuad makeSubQuad(double x1, double y1, double x2, double y2) const; WindowVertex& operator[](int index); const WindowVertex& operator[](int index) const; WindowQuadType type() const; void setUVAxisSwapped(bool value) { uvSwapped = value; } bool uvAxisSwapped() const { return uvSwapped; } int id() const; bool decoration() const; bool effect() const; double left() const; double right() const; double top() const; double bottom() const; double originalLeft() const; double originalRight() const; double originalTop() const; double originalBottom() const; bool smoothNeeded() const; bool isTransformed() const; private: friend class WindowQuadList; WindowVertex verts[ 4 ]; WindowQuadType quadType; // 0 - contents, 1 - decoration bool uvSwapped; int quadID; }; class KWINEFFECTS_EXPORT WindowQuadList : public QList< WindowQuad > { public: WindowQuadList splitAtX(double x) const; WindowQuadList splitAtY(double y) const; WindowQuadList makeGrid(int maxquadsize) const; WindowQuadList makeRegularGrid(int xSubdivisions, int ySubdivisions) const; WindowQuadList select(WindowQuadType type) const; WindowQuadList filterOut(WindowQuadType type) const; bool smoothNeeded() const; void makeInterleavedArrays(unsigned int type, GLVertex2D *vertices, const QMatrix4x4 &matrix) const; void makeArrays(float** vertices, float** texcoords, const QSizeF &size, bool yInverted) const; bool isTransformed() const; }; class KWINEFFECTS_EXPORT WindowPrePaintData { public: int mask; /** * Region that will be painted, in screen coordinates. */ QRegion paint; /** * The clip region will be subtracted from paint region of following windows. * I.e. window will definitely cover it's clip region */ QRegion clip; WindowQuadList quads; /** * Simple helper that sets data to say the window will be painted as non-opaque. * Takes also care of changing the regions. */ void setTranslucent(); /** * Helper to mark that this window will be transformed */ void setTransformed(); }; class KWINEFFECTS_EXPORT PaintData { public: virtual ~PaintData(); /** * @returns scale factor in X direction. * @since 4.10 */ qreal xScale() const; /** * @returns scale factor in Y direction. * @since 4.10 */ qreal yScale() const; /** * @returns scale factor in Z direction. * @since 4.10 */ qreal zScale() const; /** * Sets the scale factor in X direction to @p scale * @param scale The scale factor in X direction * @since 4.10 */ void setXScale(qreal scale); /** * Sets the scale factor in Y direction to @p scale * @param scale The scale factor in Y direction * @since 4.10 */ void setYScale(qreal scale); /** * Sets the scale factor in Z direction to @p scale * @param scale The scale factor in Z direction * @since 4.10 */ void setZScale(qreal scale); /** * Sets the scale factor in X and Y direction. * @param scale The scale factor for X and Y direction * @since 4.10 */ void setScale(const QVector2D &scale); /** * Sets the scale factor in X, Y and Z direction * @param scale The scale factor for X, Y and Z direction * @since 4.10 */ void setScale(const QVector3D &scale); const QGraphicsScale &scale() const; const QVector3D &translation() const; /** * @returns the translation in X direction. * @since 4.10 */ qreal xTranslation() const; /** * @returns the translation in Y direction. * @since 4.10 */ qreal yTranslation() const; /** * @returns the translation in Z direction. * @since 4.10 */ qreal zTranslation() const; /** * Sets the translation in X direction to @p translate. * @since 4.10 */ void setXTranslation(qreal translate); /** * Sets the translation in Y direction to @p translate. * @since 4.10 */ void setYTranslation(qreal translate); /** * Sets the translation in Z direction to @p translate. * @since 4.10 */ void setZTranslation(qreal translate); /** * Performs a translation by adding the values component wise. * @param x Translation in X direction * @param y Translation in Y direction * @param z Translation in Z direction * @since 4.10 */ void translate(qreal x, qreal y = 0.0, qreal z = 0.0); /** * Performs a translation by adding the values component wise. * Overloaded method for convenience. * @param translate The translation * @since 4.10 */ void translate(const QVector3D &translate); /** * Sets the rotation angle. * @param angle The new rotation angle. * @since 4.10 * @see rotationAngle() */ void setRotationAngle(qreal angle); /** * Returns the rotation angle. * Initially 0.0. * @returns The current rotation angle. * @since 4.10 * @see setRotationAngle */ qreal rotationAngle() const; /** * Sets the rotation origin. * @param origin The new rotation origin. * @since 4.10 * @see rotationOrigin() */ void setRotationOrigin(const QVector3D &origin); /** * Returns the rotation origin. That is the point in space which is fixed during the rotation. * Initially this is 0/0/0. * @returns The rotation's origin * @since 4.10 * @see setRotationOrigin() */ QVector3D rotationOrigin() const; /** * Sets the rotation axis. * Set a component to 1.0 to rotate around this axis and to 0.0 to disable rotation around the * axis. * @param axis A vector holding information on which axis to rotate * @since 4.10 * @see rotationAxis() */ void setRotationAxis(const QVector3D &axis); /** * Sets the rotation axis. * Overloaded method for convenience. * @param axis The axis around which should be rotated. * @since 4.10 * @see rotationAxis() */ void setRotationAxis(Qt::Axis axis); /** * The current rotation axis. * By default the rotation is (0/0/1) which means a rotation around the z axis. * @returns The current rotation axis. * @since 4.10 * @see setRotationAxis */ QVector3D rotationAxis() const; protected: PaintData(); PaintData(const PaintData &other); private: PaintDataPrivate * const d; }; class KWINEFFECTS_EXPORT WindowPaintData : public PaintData { public: explicit WindowPaintData(EffectWindow* w); explicit WindowPaintData(EffectWindow* w, const QMatrix4x4 &screenProjectionMatrix); WindowPaintData(const WindowPaintData &other); ~WindowPaintData() override; /** * Scales the window by @p scale factor. * Multiplies all three components by the given factor. * @since 4.10 */ WindowPaintData& operator*=(qreal scale); /** * Scales the window by @p scale factor. * Performs a component wise multiplication on x and y components. * @since 4.10 */ WindowPaintData& operator*=(const QVector2D &scale); /** * Scales the window by @p scale factor. * Performs a component wise multiplication. * @since 4.10 */ WindowPaintData& operator*=(const QVector3D &scale); /** * Translates the window by the given @p translation and returns a reference to the ScreenPaintData. * @since 4.10 */ WindowPaintData& operator+=(const QPointF &translation); /** * Translates the window by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ WindowPaintData& operator+=(const QPoint &translation); /** * Translates the window by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ WindowPaintData& operator+=(const QVector2D &translation); /** * Translates the window by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ WindowPaintData& operator+=(const QVector3D &translation); /** * Window opacity, in range 0 = transparent to 1 = fully opaque * @see setOpacity * @since 4.10 */ qreal opacity() const; /** * Sets the window opacity to the new @p opacity. * If you want to modify the existing opacity level consider using multiplyOpacity. * @param opacity The new opacity level * @since 4.10 */ void setOpacity(qreal opacity); /** * Multiplies the current opacity with the @p factor. * @param factor Factor with which the opacity should be multiplied * @return New opacity level * @since 4.10 */ qreal multiplyOpacity(qreal factor); /** * Saturation of the window, in range [0; 1] * 1 means that the window is unchanged, 0 means that it's completely * unsaturated (greyscale). 0.5 would make the colors less intense, * but not completely grey * Use EffectsHandler::saturationSupported() to find out whether saturation * is supported by the system, otherwise this value has no effect. * @return The current saturation * @see setSaturation() * @since 4.10 */ qreal saturation() const; /** * Sets the window saturation level to @p saturation. * If you want to modify the existing saturation level consider using multiplySaturation. * @param saturation The new saturation level * @since 4.10 */ void setSaturation(qreal saturation) const; /** * Multiplies the current saturation with @p factor. * @param factor with which the saturation should be multiplied * @return New saturation level * @since 4.10 */ qreal multiplySaturation(qreal factor); /** * Brightness of the window, in range [0; 1] * 1 means that the window is unchanged, 0 means that it's completely * black. 0.5 would make it 50% darker than usual */ qreal brightness() const; /** * Sets the window brightness level to @p brightness. * If you want to modify the existing brightness level consider using multiplyBrightness. * @param brightness The new brightness level */ void setBrightness(qreal brightness); /** * Multiplies the current brightness level with @p factor. * @param factor with which the brightness should be multiplied. * @return New brightness level * @since 4.10 */ qreal multiplyBrightness(qreal factor); /** * The screen number for which the painting should be done. * This affects color correction (different screens may need different * color correction lookup tables because they have different ICC profiles). * @return screen for which painting should be done */ int screen() const; /** * @param screen New screen number * A value less than 0 will indicate that a default profile should be done. */ void setScreen(int screen) const; /** * @brief Sets the cross fading @p factor to fade over with previously sized window. * If @c 1.0 only the current window is used, if @c 0.0 only the previous window is used. * * By default only the current window is used. This factor can only make any visual difference * if the previous window get referenced. * * @param factor The cross fade factor between @c 0.0 (previous window) and @c 1.0 (current window) * @see crossFadeProgress */ void setCrossFadeProgress(qreal factor); /** * @see setCrossFadeProgress */ qreal crossFadeProgress() const; /** * Sets the projection matrix that will be used when painting the window. * * The default projection matrix can be overridden by setting this matrix * to a non-identity matrix. */ void setProjectionMatrix(const QMatrix4x4 &matrix); /** * Returns the current projection matrix. * * The default value for this matrix is the identity matrix. */ QMatrix4x4 projectionMatrix() const; /** * Returns a reference to the projection matrix. */ QMatrix4x4 &rprojectionMatrix(); /** * Sets the model-view matrix that will be used when painting the window. * * The default model-view matrix can be overridden by setting this matrix * to a non-identity matrix. */ void setModelViewMatrix(const QMatrix4x4 &matrix); /** * Returns the current model-view matrix. * * The default value for this matrix is the identity matrix. */ QMatrix4x4 modelViewMatrix() const; /** * Returns a reference to the model-view matrix. */ QMatrix4x4 &rmodelViewMatrix(); /** * Returns The projection matrix as used by the current screen painting pass * including screen transformations. * * @since 5.6 */ QMatrix4x4 screenProjectionMatrix() const; WindowQuadList quads; /** * Shader to be used for rendering, if any. */ GLShader* shader; private: WindowPaintDataPrivate * const d; }; class KWINEFFECTS_EXPORT ScreenPaintData : public PaintData { public: ScreenPaintData(); ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry = QRect()); ScreenPaintData(const ScreenPaintData &other); ~ScreenPaintData() override; /** * Scales the screen by @p scale factor. * Multiplies all three components by the given factor. * @since 4.10 */ ScreenPaintData& operator*=(qreal scale); /** * Scales the screen by @p scale factor. * Performs a component wise multiplication on x and y components. * @since 4.10 */ ScreenPaintData& operator*=(const QVector2D &scale); /** * Scales the screen by @p scale factor. * Performs a component wise multiplication. * @since 4.10 */ ScreenPaintData& operator*=(const QVector3D &scale); /** * Translates the screen by the given @p translation and returns a reference to the ScreenPaintData. * @since 4.10 */ ScreenPaintData& operator+=(const QPointF &translation); /** * Translates the screen by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ ScreenPaintData& operator+=(const QPoint &translation); /** * Translates the screen by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ ScreenPaintData& operator+=(const QVector2D &translation); /** * Translates the screen by the given @p translation and returns a reference to the ScreenPaintData. * Overloaded method for convenience. * @since 4.10 */ ScreenPaintData& operator+=(const QVector3D &translation); ScreenPaintData& operator=(const ScreenPaintData &rhs); /** * The projection matrix used by the scene for the current rendering pass. * On non-OpenGL compositors it's set to Identity matrix. * @since 5.6 */ QMatrix4x4 projectionMatrix() const; /** * The geometry of the currently rendered output. * Only set for per-output rendering (e.g. Wayland). * * This geometry can be used as a hint about the native window the OpenGL context * is bound. OpenGL calls need to be translated to this geometry. * @since 5.9 */ QRect outputGeometry() const; private: class Private; QScopedPointer d; }; class KWINEFFECTS_EXPORT ScreenPrePaintData { public: int mask; QRegion paint; }; /** * @short Helper class for restricting painting area only to allowed area. * * This helper class helps specifying areas that should be painted, clipping * out the rest. The simplest usage is creating an object on the stack * and giving it the area that is allowed to be painted to. When the object * is destroyed, the restriction will be removed. * Note that all painting code must use paintArea() to actually perform the clipping. */ class KWINEFFECTS_EXPORT PaintClipper { public: /** * Calls push(). */ explicit PaintClipper(const QRegion& allowed_area); /** * Calls pop(). */ ~PaintClipper(); /** * Allows painting only in the given area. When areas have been already * specified, painting is allowed only in the intersection of all areas. */ static void push(const QRegion& allowed_area); /** * Removes the given area. It must match the top item in the stack. */ static void pop(const QRegion& allowed_area); /** * Returns true if any clipping should be performed. */ static bool clip(); /** * If clip() returns true, this function gives the resulting area in which * painting is allowed. It is usually simpler to use the helper Iterator class. */ static QRegion paintArea(); /** * Helper class to perform the clipped painting. The usage is: * @code * for ( PaintClipper::Iterator iterator; * !iterator.isDone(); * iterator.next()) * { // do the painting, possibly use iterator.boundingRect() * } * @endcode */ class KWINEFFECTS_EXPORT Iterator { public: Iterator(); ~Iterator(); bool isDone(); void next(); QRect boundingRect() const; private: struct Data; Data* data; }; private: QRegion area; static QStack< QRegion >* areas; }; /** * @internal */ template class KWINEFFECTS_EXPORT Motion { public: /** * Creates a new motion object. "Strength" is the amount of * acceleration that is applied to the object when the target * changes and "smoothness" relates to how fast the object * can change its direction and speed. */ explicit Motion(T initial, double strength, double smoothness); /** * Creates an exact copy of another motion object, including * position, target and velocity. */ Motion(const Motion &other); ~Motion(); inline T value() const { return m_value; } inline void setValue(const T value) { m_value = value; } inline T target() const { return m_target; } inline void setTarget(const T target) { m_start = m_value; m_target = target; } inline T velocity() const { return m_velocity; } inline void setVelocity(const T velocity) { m_velocity = velocity; } inline double strength() const { return m_strength; } inline void setStrength(const double strength) { m_strength = strength; } inline double smoothness() const { return m_smoothness; } inline void setSmoothness(const double smoothness) { m_smoothness = smoothness; } inline T startValue() { return m_start; } /** * The distance between the current position and the target. */ inline T distance() const { return m_target - m_value; } /** * Calculates the new position if not at the target. Called * once per frame only. */ void calculate(const int msec); /** * Place the object on top of the target immediately, * bypassing all movement calculation. */ void finish(); private: T m_value; T m_start; T m_target; T m_velocity; double m_strength; double m_smoothness; }; /** * @short A single 1D motion dynamics object. * * This class represents a single object that can be moved around a * 1D space. Although it can be used directly by itself it is * recommended to use a motion manager instead. */ class KWINEFFECTS_EXPORT Motion1D : public Motion { public: explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0); Motion1D(const Motion1D &other); ~Motion1D(); }; /** * @short A single 2D motion dynamics object. * * This class represents a single object that can be moved around a * 2D space. Although it can be used directly by itself it is * recommended to use a motion manager instead. */ class KWINEFFECTS_EXPORT Motion2D : public Motion { public: explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0); Motion2D(const Motion2D &other); ~Motion2D(); }; /** * @short Helper class for motion dynamics in KWin effects. * * This motion manager class is intended to help KWin effect authors * move windows across the screen smoothly and naturally. Once * windows are registered by the manager the effect can issue move * commands with the moveWindow() methods. The position of any * managed window can be determined in realtime by the * transformedGeometry() method. As the manager knows if any windows * are moving at any given time it can also be used as a notifier as * to see whether the effect is active or not. */ class KWINEFFECTS_EXPORT WindowMotionManager { public: /** * Creates a new window manager object. */ explicit WindowMotionManager(bool useGlobalAnimationModifier = true); ~WindowMotionManager(); /** * Register a window for managing. */ void manage(EffectWindow *w); /** * Register a list of windows for managing. */ inline void manage(const EffectWindowList &list) { for (int i = 0; i < list.size(); i++) manage(list.at(i)); } /** * Deregister a window. All transformations applied to the * window will be permanently removed and cannot be recovered. */ void unmanage(EffectWindow *w); /** * Deregister all windows, returning the manager to its * originally initiated state. */ void unmanageAll(); /** * Determine the new positions for windows that have not * reached their target. Called once per frame, usually in * prePaintScreen(). Remember to set the * Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag. */ void calculate(int time); /** * Modify a registered window's paint data to make it appear * at its real location on the screen. Usually called in * paintWindow(). Remember to flag the window as having been * transformed in prePaintWindow() by calling * WindowPrePaintData::setTransformed() */ void apply(EffectWindow *w, WindowPaintData &data); /** * Set all motion targets and values back to where the * windows were before transformations. The same as * unmanaging then remanaging all windows. */ void reset(); /** * Resets the motion target and current value of a single * window. */ void reset(EffectWindow *w); /** * Ask the manager to move the window to the target position * with the specified scale. If `yScale` is not provided or * set to 0.0, `scale` will be used as the scale in the * vertical direction as well as in the horizontal direction. */ void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0); /** * This is an overloaded method, provided for convenience. * * Ask the manager to move the window to the target rectangle. * Automatically determines scale. */ inline void moveWindow(EffectWindow *w, QRect target) { // TODO: Scale might be slightly different in the comparison due to rounding moveWindow(w, target.topLeft(), target.width() / double(w->width()), target.height() / double(w->height())); } /** * Retrieve the current tranformed geometry of a registered * window. */ QRectF transformedGeometry(EffectWindow *w) const; /** * Sets the current transformed geometry of a registered window to the given geometry. * @see transformedGeometry * @since 4.5 */ void setTransformedGeometry(EffectWindow *w, const QRectF &geometry); /** * Retrieve the current target geometry of a registered * window. */ QRectF targetGeometry(EffectWindow *w) const; /** * Return the window that has its transformed geometry under * the specified point. It is recommended to use the stacking * order as it's what the user sees, but it is slightly * slower to process. */ EffectWindow* windowAtPoint(QPoint point, bool useStackingOrder = true) const; /** * Return a list of all currently registered windows. */ inline EffectWindowList managedWindows() const { return m_managedWindows.keys(); } /** * Returns whether or not a specified window is being managed * by this manager object. */ inline bool isManaging(EffectWindow *w) const { return m_managedWindows.contains(w); } /** * Returns whether or not this manager object is actually * managing any windows or not. */ inline bool managingWindows() const { return !m_managedWindows.empty(); } /** * Returns whether all windows have reached their targets yet * or not. Can be used to see if an effect should be * processed and displayed or not. */ inline bool areWindowsMoving() const { return !m_movingWindowsSet.isEmpty(); } /** * Returns whether a window has reached its targets yet * or not. */ inline bool isWindowMoving(EffectWindow *w) const { return m_movingWindowsSet.contains(w); } private: bool m_useGlobalAnimationModifier; struct WindowMotion { // TODO: Rotation, etc? Motion2D translation; // Absolute position Motion2D scale; // xScale and yScale }; QHash m_managedWindows; QSet m_movingWindowsSet; }; /** * @short Helper class for displaying text and icons in frames. * * Paints text and/or and icon with an optional frame around them. The * available frames includes one that follows the default Plasma theme and * another that doesn't. * It is recommended to use this class whenever displaying text. */ class KWINEFFECTS_EXPORT EffectFrame { public: EffectFrame(); virtual ~EffectFrame(); /** * Delete any existing textures to free up graphics memory. They will * be automatically recreated the next time they are required. */ virtual void free() = 0; /** * Render the frame. */ virtual void render(const QRegion ®ion = infiniteRegion(), double opacity = 1.0, double frameOpacity = 1.0) = 0; virtual void setPosition(const QPoint& point) = 0; /** * Set the text alignment for static frames and the position alignment * for non-static. */ virtual void setAlignment(Qt::Alignment alignment) = 0; virtual Qt::Alignment alignment() const = 0; virtual void setGeometry(const QRect& geometry, bool force = false) = 0; virtual const QRect& geometry() const = 0; virtual void setText(const QString& text) = 0; virtual const QString& text() const = 0; virtual void setFont(const QFont& font) = 0; virtual const QFont& font() const = 0; /** * Set the icon that will appear on the left-hand size of the frame. */ virtual void setIcon(const QIcon& icon) = 0; virtual const QIcon& icon() const = 0; virtual void setIconSize(const QSize& size) = 0; virtual const QSize& iconSize() const = 0; /** * Sets the geometry of a selection. * To remove the selection set a null rect. * @param selection The geometry of the selection in screen coordinates. */ virtual void setSelection(const QRect& selection) = 0; /** * @param shader The GLShader for rendering. */ virtual void setShader(GLShader* shader) = 0; /** * @returns The GLShader used for rendering or null if none. */ virtual GLShader* shader() const = 0; /** * @returns The style of this EffectFrame. */ virtual EffectFrameStyle style() const = 0; /** * If @p enable is @c true cross fading between icons and text is enabled * By default disabled. Use setCrossFadeProgress to cross fade. * Cross Fading is currently only available if OpenGL is used. * @param enable @c true enables cross fading, @c false disables it again * @see isCrossFade * @see setCrossFadeProgress * @since 4.6 */ void enableCrossFade(bool enable); /** * @returns @c true if cross fading is enabled, @c false otherwise * @see enableCrossFade * @since 4.6 */ bool isCrossFade() const; /** * Sets the current progress for cross fading the last used icon/text * with current icon/text to @p progress. * A value of 0.0 means completely old icon/text, a value of 1.0 means * completely current icon/text. * Default value is 1.0. You have to enable cross fade before using it. * Cross Fading is currently only available if OpenGL is used. * @see enableCrossFade * @see isCrossFade * @see crossFadeProgress * @since 4.6 */ void setCrossFadeProgress(qreal progress); /** * @returns The current progress for cross fading * @see setCrossFadeProgress * @see enableCrossFade * @see isCrossFade * @since 4.6 */ qreal crossFadeProgress() const; /** * Returns The projection matrix as used by the current screen painting pass * including screen transformations. * * This matrix is only valid during a rendering pass started by render. * * @since 5.6 * @see render * @see EffectsHandler::paintEffectFrame * @see Effect::paintEffectFrame */ QMatrix4x4 screenProjectionMatrix() const; protected: void setScreenProjectionMatrix(const QMatrix4x4 &projection); private: EffectFramePrivate* const d; }; /** * The TimeLine class is a helper for controlling animations. */ class KWINEFFECTS_EXPORT TimeLine { public: /** * Direction of the timeline. * * When the direction of the timeline is Forward, the progress * value will go from 0.0 to 1.0. * * When the direction of the timeline is Backward, the progress * value will go from 1.0 to 0.0. */ enum Direction { Forward, Backward }; /** * Constructs a new instance of TimeLine. * * @param duration Duration of the timeline, in milliseconds * @param direction Direction of the timeline * @since 5.14 */ explicit TimeLine(std::chrono::milliseconds duration = std::chrono::milliseconds(1000), Direction direction = Forward); TimeLine(const TimeLine &other); ~TimeLine(); /** * Returns the current value of the timeline. * * @since 5.14 */ qreal value() const; /** * Updates the progress of the timeline. * * @note The delta value should be a non-negative number, i.e. it * should be greater or equal to 0. * * @param delta The number milliseconds passed since last frame * @since 5.14 */ void update(std::chrono::milliseconds delta); /** * Returns the number of elapsed milliseconds. * * @see setElapsed * @since 5.14 */ std::chrono::milliseconds elapsed() const; /** * Sets the number of elapsed milliseconds. * * This method overwrites previous value of elapsed milliseconds. * If the new value of elapsed milliseconds is greater or equal * to duration of the timeline, the timeline will be finished, i.e. * proceeding TimeLine::done method calls will return @c true. * Please don't use it. Instead, use TimeLine::update. * * @note The new number of elapsed milliseconds should be a non-negative * number, i.e. it should be greater or equal to 0. * * @param elapsed The new number of elapsed milliseconds * @see elapsed * @since 5.14 */ void setElapsed(std::chrono::milliseconds elapsed); /** * Returns the duration of the timeline. * * @returns Duration of the timeline, in milliseconds * @see setDuration * @since 5.14 */ std::chrono::milliseconds duration() const; /** * Sets the duration of the timeline. * * In addition to setting new value of duration, the timeline will * try to retarget the number of elapsed milliseconds to match * as close as possible old progress value. If the new duration * is much smaller than old duration, there is a big chance that * the timeline will be finished after setting new duration. * * @note The new duration should be a positive number, i.e. it * should be greater or equal to 1. * * @param duration The new duration of the timeline, in milliseconds * @see duration * @since 5.14 */ void setDuration(std::chrono::milliseconds duration); /** * Returns the direction of the timeline. * * @returns Direction of the timeline(TimeLine::Forward or TimeLine::Backward) * @see setDirection * @see toggleDirection * @since 5.14 */ Direction direction() const; /** * Sets the direction of the timeline. * * @param direction The new direction of the timeline * @see direction * @see toggleDirection * @since 5.14 */ void setDirection(Direction direction); /** * Toggles the direction of the timeline. * * If the direction of the timeline was TimeLine::Forward, it becomes * TimeLine::Backward, and vice verca. * * @see direction * @see setDirection * @since 5.14 */ void toggleDirection(); /** * Returns the easing curve of the timeline. * * @see setEasingCurve * @since 5.14 */ QEasingCurve easingCurve() const; /** * Sets new easing curve. * * @param easingCurve An easing curve to be set * @see easingCurve * @since 5.14 */ void setEasingCurve(const QEasingCurve &easingCurve); /** * Sets new easing curve by providing its type. * * @param type Type of the easing curve(e.g. QEasingCurve::InCubic, etc) * @see easingCurve * @since 5.14 */ void setEasingCurve(QEasingCurve::Type type); /** * Returns whether the timeline is currently in progress. * * @see done * @since 5.14 */ bool running() const; /** * Returns whether the timeline is finished. * * @see reset * @since 5.14 */ bool done() const; /** * Resets the timeline to initial state. * * @since 5.14 */ void reset(); enum class RedirectMode { Strict, Relaxed }; /** * Returns the redirect mode for the source position. * * The redirect mode controls behavior of the timeline when its direction is * changed at the source position, e.g. what should we do when the timeline * initially goes forward and we change its direction to go backward. * * In the strict mode, the timeline will stop. * * In the relaxed mode, the timeline will go in the new direction. For example, * if the timeline goes forward(from 0 to 1), then with the new direction it * will go backward(from 1 to 0). * * The default is RedirectMode::Relaxed. * * @see targetRedirectMode * @since 5.15 */ RedirectMode sourceRedirectMode() const; /** * Sets the redirect mode for the source position. * * @param mode The new mode. * @since 5.15 */ void setSourceRedirectMode(RedirectMode mode); /** * Returns the redirect mode for the target position. * * The redirect mode controls behavior of the timeline when its direction is * changed at the target position. * * In the strict mode, subsequent update calls won't have any effect on the * current value of the timeline. * * In the relaxed mode, the timeline will go in the new direction. * * The default is RedirectMode::Strict. * * @see sourceRedirectMode * @since 5.15 */ RedirectMode targetRedirectMode() const; /** * Sets the redirect mode for the target position. * * @param mode The new mode. * @since 5.15 */ void setTargetRedirectMode(RedirectMode mode); TimeLine &operator=(const TimeLine &other); private: qreal progress() const; private: class Data; QSharedDataPointer d; }; /** * Pointer to the global EffectsHandler object. */ extern KWINEFFECTS_EXPORT EffectsHandler* effects; /*************************************************************** WindowVertex ***************************************************************/ inline WindowVertex::WindowVertex() : px(0), py(0), ox(0), oy(0), tx(0), ty(0) { } inline WindowVertex::WindowVertex(double _x, double _y, double _tx, double _ty) : px(_x), py(_y), ox(_x), oy(_y), tx(_tx), ty(_ty) { } inline WindowVertex::WindowVertex(const QPointF &position, const QPointF &texturePosition) : px(position.x()), py(position.y()), ox(position.x()), oy(position.y()), tx(texturePosition.x()), ty(texturePosition.y()) { } inline void WindowVertex::move(double x, double y) { px = x; py = y; } inline void WindowVertex::setX(double x) { px = x; } inline void WindowVertex::setY(double y) { py = y; } /*************************************************************** WindowQuad ***************************************************************/ inline WindowQuad::WindowQuad(WindowQuadType t, int id) : quadType(t) , uvSwapped(false) , quadID(id) { } inline WindowVertex& WindowQuad::operator[](int index) { Q_ASSERT(index >= 0 && index < 4); return verts[ index ]; } inline const WindowVertex& WindowQuad::operator[](int index) const { Q_ASSERT(index >= 0 && index < 4); return verts[ index ]; } inline WindowQuadType WindowQuad::type() const { Q_ASSERT(quadType != WindowQuadError); return quadType; } inline int WindowQuad::id() const { return quadID; } inline bool WindowQuad::decoration() const { Q_ASSERT(quadType != WindowQuadError); return quadType == WindowQuadDecoration; } inline bool WindowQuad::effect() const { Q_ASSERT(quadType != WindowQuadError); return quadType >= EFFECT_QUAD_TYPE_START; } inline bool WindowQuad::isTransformed() const { return !(verts[ 0 ].px == verts[ 0 ].ox && verts[ 0 ].py == verts[ 0 ].oy && verts[ 1 ].px == verts[ 1 ].ox && verts[ 1 ].py == verts[ 1 ].oy && verts[ 2 ].px == verts[ 2 ].ox && verts[ 2 ].py == verts[ 2 ].oy && verts[ 3 ].px == verts[ 3 ].ox && verts[ 3 ].py == verts[ 3 ].oy); } inline double WindowQuad::left() const { return qMin(verts[ 0 ].px, qMin(verts[ 1 ].px, qMin(verts[ 2 ].px, verts[ 3 ].px))); } inline double WindowQuad::right() const { return qMax(verts[ 0 ].px, qMax(verts[ 1 ].px, qMax(verts[ 2 ].px, verts[ 3 ].px))); } inline double WindowQuad::top() const { return qMin(verts[ 0 ].py, qMin(verts[ 1 ].py, qMin(verts[ 2 ].py, verts[ 3 ].py))); } inline double WindowQuad::bottom() const { return qMax(verts[ 0 ].py, qMax(verts[ 1 ].py, qMax(verts[ 2 ].py, verts[ 3 ].py))); } inline double WindowQuad::originalLeft() const { return verts[ 0 ].ox; } inline double WindowQuad::originalRight() const { return verts[ 2 ].ox; } inline double WindowQuad::originalTop() const { return verts[ 0 ].oy; } inline double WindowQuad::originalBottom() const { return verts[ 2 ].oy; } /*************************************************************** Motion ***************************************************************/ template Motion::Motion(T initial, double strength, double smoothness) : m_value(initial) , m_start(initial) , m_target(initial) , m_velocity() , m_strength(strength) , m_smoothness(smoothness) { } template Motion::Motion(const Motion &other) : m_value(other.value()) , m_start(other.target()) , m_target(other.target()) , m_velocity(other.velocity()) , m_strength(other.strength()) , m_smoothness(other.smoothness()) { } template Motion::~Motion() { } template void Motion::calculate(const int msec) { if (m_value == m_target && m_velocity == T()) // At target and not moving return; // Poor man's time independent calculation int steps = qMax(1, msec / 5); for (int i = 0; i < steps; i++) { T diff = m_target - m_value; T strength = diff * m_strength; m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0); m_value += m_velocity; } } template void Motion::finish() { m_value = m_target; m_velocity = T(); } /*************************************************************** Effect ***************************************************************/ template int Effect::animationTime(int defaultDuration) { return animationTime(T::duration() != 0 ? T::duration() : defaultDuration); } template void Effect::initConfig() { T::instance(effects->config()); } } // namespace Q_DECLARE_METATYPE(KWin::EffectWindow*) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(KWin::TimeLine) Q_DECLARE_METATYPE(KWin::TimeLine::Direction) /** @} */ #endif // KWINEFFECTS_H diff --git a/libkwineffects/kwinglplatform.cpp b/libkwineffects/kwinglplatform.cpp index 6e8e37732..3373f9cdb 100644 --- a/libkwineffects/kwinglplatform.cpp +++ b/libkwineffects/kwinglplatform.cpp @@ -1,1280 +1,1279 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2010 Fredrik Höglund 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 "kwinglplatform.h" // include kwinglutils_funcs.h to avoid the redeclaration issues // between qopengl.h and epoxy/gl.h #include "kwinglutils_funcs.h" #include -#include +#include #include #include #include #include #include #include #include namespace KWin { GLPlatform *GLPlatform::s_platform = nullptr; static qint64 parseVersionString(const QByteArray &version) { // Skip any leading non digit int start = 0; while (start < version.length() && !QChar::fromLatin1(version[start]).isDigit()) start++; // Strip any non digit, non '.' characters from the end int end = start; while (end < version.length() && (version[end] == '.' || QChar::fromLatin1(version[end]).isDigit())) end++; const QByteArray result = version.mid(start, end-start); const QList tokens = result.split('.'); const qint64 major = tokens.at(0).toInt(); const qint64 minor = tokens.count() > 1 ? tokens.at(1).toInt() : 0; const qint64 patch = tokens.count() > 2 ? tokens.at(2).toInt() : 0; return kVersionNumber(major, minor, patch); } static qint64 getXServerVersion() { qint64 major, minor, patch; major = 0; minor = 0; patch = 0; if (xcb_connection_t *c = connection()) { auto setup = xcb_get_setup(c); const QByteArray vendorName(xcb_setup_vendor(setup), xcb_setup_vendor_length(setup)); if (vendorName.contains("X.Org")) { const int release = setup->release_number; major = (release / 10000000); minor = (release / 100000) % 100; patch = (release / 1000) % 100; } } return kVersionNumber(major, minor, patch); } static qint64 getKernelVersion() { struct utsname name; uname(&name); if (qstrcmp(name.sysname, "Linux") == 0) return parseVersionString(name.release); return 0; } // Extracts the portion of a string that matches a regular expression -static QString extract(const QString &string, const QString &match, int offset = 0) +static QString extract(const QString &text, const QString &pattern) { - QString result; - QRegExp rx(match); - int pos = rx.indexIn(string, offset); - if (pos != -1) - result = string.mid(pos, rx.matchedLength()); - return result; + const QRegularExpression regexp(pattern); + const QRegularExpressionMatch match = regexp.match(text); + if (!match.hasMatch()) + return QString(); + return match.captured(); } static ChipClass detectRadeonClass(const QByteArray &chipset) { if (chipset.isEmpty()) return UnknownRadeon; if (chipset.contains("R100") || chipset.contains("RV100") || chipset.contains("RS100")) return R100; if (chipset.contains("RV200") || chipset.contains("RS200") || chipset.contains("R200") || chipset.contains("RV250") || chipset.contains("RS300") || chipset.contains("RV280")) return R200; if (chipset.contains("R300") || chipset.contains("R350") || chipset.contains("R360") || chipset.contains("RV350") || chipset.contains("RV370") || chipset.contains("RV380")) return R300; if (chipset.contains("R420") || chipset.contains("R423") || chipset.contains("R430") || chipset.contains("R480") || chipset.contains("R481") || chipset.contains("RV410") || chipset.contains("RS400") || chipset.contains("RC410") || chipset.contains("RS480") || chipset.contains("RS482") || chipset.contains("RS600") || chipset.contains("RS690") || chipset.contains("RS740")) return R400; if (chipset.contains("RV515") || chipset.contains("R520") || chipset.contains("RV530") || chipset.contains("R580") || chipset.contains("RV560") || chipset.contains("RV570")) return R500; if (chipset.contains("R600") || chipset.contains("RV610") || chipset.contains("RV630") || chipset.contains("RV670") || chipset.contains("RV620") || chipset.contains("RV635") || chipset.contains("RS780") || chipset.contains("RS880")) return R600; if (chipset.contains("R700") || chipset.contains("RV770") || chipset.contains("RV730") || chipset.contains("RV710") || chipset.contains("RV740")) return R700; if (chipset.contains("EVERGREEN") || // Not an actual chipset, but returned by R600G in 7.9 chipset.contains("CEDAR") || chipset.contains("REDWOOD") || chipset.contains("JUNIPER") || chipset.contains("CYPRESS") || chipset.contains("HEMLOCK") || chipset.contains("PALM")) return Evergreen; if (chipset.contains("SUMO") || chipset.contains("SUMO2") || chipset.contains("BARTS") || chipset.contains("TURKS") || chipset.contains("CAICOS") || chipset.contains("CAYMAN")) return NorthernIslands; if (chipset.contains("TAHITI") || chipset.contains("PITCAIRN") || chipset.contains("VERDE") || chipset.contains("OLAND") || chipset.contains("HAINAN")) { return SouthernIslands; } if (chipset.contains("BONAIRE") || chipset.contains("KAVERI") || chipset.contains("KABINI") || chipset.contains("HAWAII") || chipset.contains("MULLINS")) { return SeaIslands; } if (chipset.contains("TONGA") || chipset.contains("TOPAZ") || chipset.contains("FIJI") || chipset.contains("CARRIZO") || chipset.contains("STONEY")) { return VolcanicIslands; } if (chipset.contains("POLARIS10") || chipset.contains("POLARIS11") || chipset.contains("POLARIS12") || chipset.contains("VEGAM")) { return ArcticIslands; } if (chipset.contains("VEGA10") || chipset.contains("VEGA12") || chipset.contains("VEGA20") || chipset.contains("RAVEN") || chipset.contains("RAVEN2") || chipset.contains("RENOIR") || chipset.contains("ARCTURUS")) { return Vega; } if (chipset.contains("NAVI10") || chipset.contains("NAVI12") || chipset.contains("NAVI14")) { return Navi; } const QString chipset16 = QString::fromLatin1(chipset); QString name = extract(chipset16, QStringLiteral("HD [0-9]{4}")); // HD followed by a space and 4 digits if (!name.isEmpty()) { const int id = name.rightRef(4).toInt(); if (id == 6250 || id == 6310) // Palm return Evergreen; if (id >= 6000 && id < 7000) return NorthernIslands; // HD 6xxx if (id >= 5000 && id < 6000) return Evergreen; // HD 5xxx if (id >= 4000 && id < 5000) return R700; // HD 4xxx if (id >= 2000 && id < 4000) // HD 2xxx/3xxx return R600; return UnknownRadeon; } name = extract(chipset16, QStringLiteral("X[0-9]{3,4}")); // X followed by 3-4 digits if (!name.isEmpty()) { const int id = name.midRef(1, -1).toInt(); // X1xxx if (id >= 1300) return R500; // X7xx, X8xx, X12xx, 2100 if ((id >= 700 && id < 1000) || id >= 1200) return R400; // X200, X3xx, X5xx, X6xx, X10xx, X11xx if ((id >= 300 && id < 700) || (id >= 1000 && id < 1200)) return R300; return UnknownRadeon; } name = extract(chipset16, QStringLiteral("\\b[0-9]{4}\\b")); // A group of 4 digits if (!name.isEmpty()) { const int id = name.toInt(); // 7xxx if (id >= 7000 && id < 8000) return R100; // 8xxx, 9xxx if (id >= 8000 && id < 9500) return R200; // 9xxx if (id >= 9500) return R300; if (id == 2100) return R400; } return UnknownRadeon; } static ChipClass detectNVidiaClass(const QString &chipset) { QString name = extract(chipset, QStringLiteral("\\bNV[0-9,A-F]{2}\\b")); // NV followed by two hexadecimal digits if (!name.isEmpty()) { const int id = chipset.midRef(2, -1).toInt(nullptr, 16); // Strip the 'NV' from the id switch(id & 0xf0) { case 0x00: case 0x10: return NV10; case 0x20: return NV20; case 0x30: return NV30; case 0x40: case 0x60: return NV40; case 0x50: case 0x80: case 0x90: case 0xA0: return G80; default: return UnknownNVidia; } } if (chipset.contains(QLatin1String("GeForce2")) || chipset.contains(QLatin1String("GeForce 256"))) return NV10; if (chipset.contains(QLatin1String("GeForce3"))) return NV20; if (chipset.contains(QLatin1String("GeForce4"))) { if (chipset.contains(QLatin1String("MX 420")) || chipset.contains(QLatin1String("MX 440")) || // including MX 440SE chipset.contains(QLatin1String("MX 460")) || chipset.contains(QLatin1String("MX 4000")) || chipset.contains(QLatin1String("PCX 4300"))) return NV10; return NV20; } // GeForce 5,6,7,8,9 name = extract(chipset, QStringLiteral("GeForce (FX |PCX |Go )?\\d{4}(M|\\b)")).trimmed(); if (!name.isEmpty()) { if (!name[name.length() - 1].isDigit()) name.chop(1); const int id = name.rightRef(4).toInt(); if (id < 6000) return NV30; if (id >= 6000 && id < 8000) return NV40; if (id >= 8000) return G80; return UnknownNVidia; } // GeForce 100/200/300/400/500 name = extract(chipset, QStringLiteral("GeForce (G |GT |GTX |GTS )?\\d{3}(M|\\b)")).trimmed(); if (!name.isEmpty()) { if (!name[name.length() - 1].isDigit()) name.chop(1); const int id = name.rightRef(3).toInt(); if (id >= 100 && id < 600) { if (id >= 400) return GF100; return G80; } return UnknownNVidia; } return UnknownNVidia; } static inline ChipClass detectNVidiaClass(const QByteArray &chipset) { return detectNVidiaClass(QString::fromLatin1(chipset)); } static ChipClass detectIntelClass(const QByteArray &chipset) { // see mesa repository: src/mesa/drivers/dri/intel/intel_context.c // GL 1.3, DX8? SM ? if (chipset.contains("845G") || chipset.contains("830M") || chipset.contains("852GM/855GM") || chipset.contains("865G")) return I8XX; // GL 1.4, DX 9.0, SM 2.0 if (chipset.contains("915G") || chipset.contains("E7221G") || chipset.contains("915GM") || chipset.contains("945G") || // DX 9.0c chipset.contains("945GM") || chipset.contains("945GME") || chipset.contains("Q33") || // GL1.5 chipset.contains("Q35") || chipset.contains("G33") || chipset.contains("965Q") || // GMA 3000, but apparently considered gen 4 by the driver chipset.contains("946GZ") || // GMA 3000, but apparently considered gen 4 by the driver chipset.contains("IGD")) return I915; // GL 2.0, DX 9.0c, SM 3.0 if (chipset.contains("965G") || chipset.contains("G45/G43") || // SM 4.0 chipset.contains("965GM") || // GL 2.1 chipset.contains("965GME/GLE") || chipset.contains("GM45") || chipset.contains("Q45/Q43") || chipset.contains("G41") || chipset.contains("B43") || chipset.contains("Ironlake")) return I965; // GL 3.1, CL 1.1, DX 10.1 if (chipset.contains("Sandybridge")) { return SandyBridge; } // GL4.0, CL1.1, DX11, SM 5.0 if (chipset.contains("Ivybridge")) { return IvyBridge; } // GL4.0, CL1.2, DX11.1, SM 5.0 if (chipset.contains("Haswell")) { return Haswell; } return UnknownIntel; } static ChipClass detectQualcommClass(const QByteArray &chipClass) { if (!chipClass.contains("Adreno")) { return UnknownChipClass; } const auto parts = chipClass.split(' '); if (parts.count() < 3) { return UnknownAdreno; } bool ok = false; const int value = parts.at(2).toInt(&ok); if (ok) { if (value >= 100 && value < 200) { return Adreno1XX; } if (value >= 200 && value < 300) { return Adreno2XX; } if (value >= 300 && value < 400) { return Adreno3XX; } if (value >= 400 && value < 500) { return Adreno4XX; } if (value >= 500 && value < 600) { return Adreno5XX; } } return UnknownAdreno; } QString GLPlatform::versionToString(qint64 version) { return QString::fromLatin1(versionToString8(version)); } QByteArray GLPlatform::versionToString8(qint64 version) { int major = (version >> 32); int minor = (version >> 16) & 0xffff; int patch = version & 0xffff; QByteArray string = QByteArray::number(major) + '.' + QByteArray::number(minor); if (patch != 0) string += '.' + QByteArray::number(patch); return string; } QString GLPlatform::driverToString(Driver driver) { return QString::fromLatin1(driverToString8(driver)); } QByteArray GLPlatform::driverToString8(Driver driver) { switch(driver) { case Driver_R100: return QByteArrayLiteral("Radeon"); case Driver_R200: return QByteArrayLiteral("R200"); case Driver_R300C: return QByteArrayLiteral("R300C"); case Driver_R300G: return QByteArrayLiteral("R300G"); case Driver_R600C: return QByteArrayLiteral("R600C"); case Driver_R600G: return QByteArrayLiteral("R600G"); case Driver_RadeonSI: return QByteArrayLiteral("RadeonSI"); case Driver_Nouveau: return QByteArrayLiteral("Nouveau"); case Driver_Intel: return QByteArrayLiteral("Intel"); case Driver_NVidia: return QByteArrayLiteral("NVIDIA"); case Driver_Catalyst: return QByteArrayLiteral("Catalyst"); case Driver_Swrast: return QByteArrayLiteral("Software rasterizer"); case Driver_Softpipe: return QByteArrayLiteral("softpipe"); case Driver_Llvmpipe: return QByteArrayLiteral("LLVMpipe"); case Driver_VirtualBox: return QByteArrayLiteral("VirtualBox (Chromium)"); case Driver_VMware: return QByteArrayLiteral("VMware (SVGA3D)"); case Driver_Qualcomm: return QByteArrayLiteral("Qualcomm"); case Driver_Virgl: return QByteArrayLiteral("Virgl (virtio-gpu, Qemu/KVM guest)"); default: return QByteArrayLiteral("Unknown"); } } QString GLPlatform::chipClassToString(ChipClass chipClass) { return QString::fromLatin1(chipClassToString8(chipClass)); } QByteArray GLPlatform::chipClassToString8(ChipClass chipClass) { switch(chipClass) { case R100: return QByteArrayLiteral("R100"); case R200: return QByteArrayLiteral("R200"); case R300: return QByteArrayLiteral("R300"); case R400: return QByteArrayLiteral("R400"); case R500: return QByteArrayLiteral("R500"); case R600: return QByteArrayLiteral("R600"); case R700: return QByteArrayLiteral("R700"); case Evergreen: return QByteArrayLiteral("EVERGREEN"); case NorthernIslands: return QByteArrayLiteral("Northern Islands"); case SouthernIslands: return QByteArrayLiteral("Southern Islands"); case SeaIslands: return QByteArrayLiteral("Sea Islands"); case VolcanicIslands: return QByteArrayLiteral("Volcanic Islands"); case ArcticIslands: return QByteArrayLiteral("Arctic Islands"); case Vega: return QByteArrayLiteral("Vega"); case Navi: return QByteArrayLiteral("Navi"); case NV10: return QByteArrayLiteral("NV10"); case NV20: return QByteArrayLiteral("NV20"); case NV30: return QByteArrayLiteral("NV30"); case NV40: return QByteArrayLiteral("NV40/G70"); case G80: return QByteArrayLiteral("G80/G90"); case GF100: return QByteArrayLiteral("GF100"); case I8XX: return QByteArrayLiteral("i830/i835"); case I915: return QByteArrayLiteral("i915/i945"); case I965: return QByteArrayLiteral("i965"); case SandyBridge: return QByteArrayLiteral("SandyBridge"); case IvyBridge: return QByteArrayLiteral("IvyBridge"); case Haswell: return QByteArrayLiteral("Haswell"); case Adreno1XX: return QByteArrayLiteral("Adreno 1xx series"); case Adreno2XX: return QByteArrayLiteral("Adreno 2xx series"); case Adreno3XX: return QByteArrayLiteral("Adreno 3xx series"); case Adreno4XX: return QByteArrayLiteral("Adreno 4xx series"); case Adreno5XX: return QByteArrayLiteral("Adreno 5xx series"); default: return QByteArrayLiteral("Unknown"); } } // ------- GLPlatform::GLPlatform() : m_driver(Driver_Unknown), m_chipClass(UnknownChipClass), m_recommendedCompositor(XRenderCompositing), m_glVersion(0), m_glslVersion(0), m_mesaVersion(0), m_driverVersion(0), m_galliumVersion(0), m_serverVersion(0), m_kernelVersion(0), m_looseBinding(false), m_supportsGLSL(false), m_limitedGLSL(false), m_textureNPOT(false), m_limitedNPOT(false), m_virtualMachine(false), m_preferBufferSubData(false), m_platformInterface(NoOpenGLPlatformInterface), m_gles(false) { } GLPlatform::~GLPlatform() { } void GLPlatform::detect(OpenGLPlatformInterface platformInterface) { m_platformInterface = platformInterface; m_vendor = (const char*)glGetString(GL_VENDOR); m_renderer = (const char*)glGetString(GL_RENDERER); m_version = (const char*)glGetString(GL_VERSION); // Parse the OpenGL version const QList versionTokens = m_version.split(' '); if (versionTokens.count() > 0) { const QByteArray version = QByteArray(m_version); m_glVersion = parseVersionString(version); if (platformInterface == EglPlatformInterface) { // only EGL can have OpenGLES, GLX is OpenGL only if (version.startsWith("OpenGL ES")) { // from GLES 2: "Returns a version or release number of the form OpenGLES." // from GLES 3: "Returns a version or release number." and "The version number uses one of these forms: major_number.minor_number major_number.minor_number.release_number" m_gles = true; } } } if (!isGLES() && m_glVersion >= kVersionNumber(3, 0)) { int count; glGetIntegerv(GL_NUM_EXTENSIONS, &count); for (int i = 0; i < count; i++) { const char *name = (const char *) glGetStringi(GL_EXTENSIONS, i); m_extensions.insert(name); } } else { const QByteArray extensions = (const char *) glGetString(GL_EXTENSIONS); #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) const QList extensionsList = extensions.split(' '); m_extensions = {extensionsList.constBegin(), extensionsList.constEnd()}; #else m_extensions = extensions.split(' ').toSet(); #endif } // Parse the Mesa version const int mesaIndex = versionTokens.indexOf("Mesa"); if (mesaIndex != -1) { const QByteArray &version = versionTokens.at(mesaIndex + 1); m_mesaVersion = parseVersionString(version); } if (isGLES()) { m_supportsGLSL = true; m_textureNPOT = true; } else { m_supportsGLSL = m_extensions.contains("GL_ARB_shader_objects") && m_extensions.contains("GL_ARB_fragment_shader") && m_extensions.contains("GL_ARB_vertex_shader"); m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two"); } m_serverVersion = getXServerVersion(); m_kernelVersion = getKernelVersion(); m_glslVersion = 0; m_glsl_version.clear(); if (m_supportsGLSL) { // Parse the GLSL version m_glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); m_glslVersion = parseVersionString(m_glsl_version); } m_chipset = QByteArrayLiteral("Unknown"); m_preferBufferSubData = false; // Mesa classic drivers // ==================================================== // Radeon if (m_renderer.startsWith("Mesa DRI R")) { // Sample renderer string: Mesa DRI R600 (RV740 94B3) 20090101 x86/MMX/SSE2 TCL DRI2 const QList tokens = m_renderer.split(' '); const QByteArray &chipClass = tokens.at(2); m_chipset = tokens.at(3).mid(1, -1); // Strip the leading '(' if (chipClass == "R100") // Vendor: Tungsten Graphics, Inc. m_driver = Driver_R100; else if (chipClass == "R200") // Vendor: Tungsten Graphics, Inc. m_driver = Driver_R200; else if (chipClass == "R300") // Vendor: DRI R300 Project m_driver = Driver_R300C; else if (chipClass == "R600") // Vendor: Advanced Micro Devices, Inc. m_driver = Driver_R600C; m_chipClass = detectRadeonClass(m_chipset); } // Intel else if (m_renderer.contains("Intel")) { // Vendor: Tungsten Graphics, Inc. // Sample renderer string: Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100328 2010Q1 QByteArray chipset; if (m_renderer.startsWith("Intel(R) Integrated Graphics Device")) chipset = "IGD"; else chipset = m_renderer; m_driver = Driver_Intel; m_chipClass = detectIntelClass(chipset); } // Properietary drivers // ==================================================== else if (m_vendor == "ATI Technologies Inc.") { m_chipClass = detectRadeonClass(m_renderer); m_driver = Driver_Catalyst; if (versionTokens.count() > 1 && versionTokens.at(2)[0] == '(') m_driverVersion = parseVersionString(versionTokens.at(1)); else if (versionTokens.count() > 0) m_driverVersion = parseVersionString(versionTokens.at(0)); else m_driverVersion = 0; } else if (m_vendor == "NVIDIA Corporation") { m_chipClass = detectNVidiaClass(m_renderer); m_driver = Driver_NVidia; int index = versionTokens.indexOf("NVIDIA"); if (versionTokens.count() > index) m_driverVersion = parseVersionString(versionTokens.at(index + 1)); else m_driverVersion = 0; } else if (m_vendor == "Qualcomm") { m_driver = Driver_Qualcomm; m_chipClass = detectQualcommClass(m_renderer); } else if (m_renderer == "Software Rasterizer") { m_driver = Driver_Swrast; } // Virtual Hardware // ==================================================== else if (m_vendor == "Humper" && m_renderer == "Chromium") { // Virtual Box m_driver = Driver_VirtualBox; const int index = versionTokens.indexOf("Chromium"); if (versionTokens.count() > index) m_driverVersion = parseVersionString(versionTokens.at(index + 1)); else m_driverVersion = 0; } // Gallium drivers // ==================================================== else { const QList tokens = m_renderer.split(' '); if (m_renderer.contains("Gallium")) { // Sample renderer string: Gallium 0.4 on AMD RV740 m_galliumVersion = parseVersionString(tokens.at(1)); m_chipset = (tokens.at(3) == "AMD" || tokens.at(3) == "ATI") ? tokens.at(4) : tokens.at(3); } else { // The renderer string does not contain "Gallium" anymore. m_chipset = tokens.at(0); // We don't know the actual version anymore, but it's at least 0.4. m_galliumVersion = kVersionNumber(0, 4, 0); } // R300G if (m_vendor == QByteArrayLiteral("X.Org R300 Project")) { m_chipClass = detectRadeonClass(m_chipset); m_driver = Driver_R300G; } // R600G else if (m_vendor == "X.Org" && (m_renderer.contains("R6") || m_renderer.contains("R7") || m_renderer.contains("RV6") || m_renderer.contains("RV7") || m_renderer.contains("RS780") || m_renderer.contains("RS880") || m_renderer.contains("CEDAR") || m_renderer.contains("REDWOOD") || m_renderer.contains("JUNIPER") || m_renderer.contains("CYPRESS") || m_renderer.contains("HEMLOCK") || m_renderer.contains("PALM") || m_renderer.contains("EVERGREEN") || m_renderer.contains("SUMO") || m_renderer.contains("SUMO2") || m_renderer.contains("BARTS") || m_renderer.contains("TURKS") || m_renderer.contains("CAICOS") || m_renderer.contains("CAYMAN"))) { m_chipClass = detectRadeonClass(m_chipset); m_driver = Driver_R600G; } // RadeonSI else if (m_vendor == "X.Org" && (m_renderer.contains("TAHITI") || m_renderer.contains("PITCAIRN") || m_renderer.contains("VERDE") || m_renderer.contains("OLAND") || m_renderer.contains("HAINAN") || m_renderer.contains("BONAIRE") || m_renderer.contains("KAVERI") || m_renderer.contains("KABINI") || m_renderer.contains("HAWAII") || m_renderer.contains("MULLINS") || m_renderer.contains("TOPAZ") || m_renderer.contains("TONGA") || m_renderer.contains("FIJI") || m_renderer.contains("CARRIZO") || m_renderer.contains("STONEY") || m_renderer.contains("POLARIS10") || m_renderer.contains("POLARIS11") || m_renderer.contains("POLARIS12") || m_renderer.contains("VEGAM") || m_renderer.contains("VEGA10") || m_renderer.contains("VEGA12") || m_renderer.contains("VEGA20") || m_renderer.contains("RAVEN") || m_renderer.contains("RAVEN2") || m_renderer.contains("RENOIR") || m_renderer.contains("ARCTURUS") || m_renderer.contains("NAVI10") || m_renderer.contains("NAVI12") || m_renderer.contains("NAVI14"))) { m_chipClass = detectRadeonClass(m_renderer); m_driver = Driver_RadeonSI; } // Nouveau else if (m_vendor == "nouveau") { m_chipClass = detectNVidiaClass(m_chipset); m_driver = Driver_Nouveau; } // softpipe else if (m_vendor == "VMware, Inc." && m_chipset == "softpipe" ) { m_driver = Driver_Softpipe; } // llvmpipe else if (m_vendor == "VMware, Inc." && m_chipset == "llvmpipe") { m_driver = Driver_Llvmpipe; } // SVGA3D else if (m_vendor == "VMware, Inc." && m_chipset.contains("SVGA3D")) { m_driver = Driver_VMware; } // virgl else if (m_renderer == "virgl") { m_driver = Driver_Virgl; } } // Driver/GPU specific features // ==================================================== if (isRadeon()) { // R200 technically has a programmable pipeline, but since it's SM 1.4, // it's too limited to to be of any practical value to us. if (m_chipClass < R300) m_supportsGLSL = false; m_limitedGLSL = false; m_limitedNPOT = false; if (m_chipClass < R600) { if (driver() == Driver_Catalyst) m_textureNPOT = m_limitedNPOT = false; // Software fallback else if (driver() == Driver_R300G) m_limitedNPOT = m_textureNPOT; m_limitedGLSL = m_supportsGLSL; } if (m_chipClass < R300) { // fallback to XRender for R100 and R200 m_recommendedCompositor = XRenderCompositing; } else if (m_chipClass < R600) { // XRender due to NPOT limitations not supported by KWin's shaders m_recommendedCompositor = XRenderCompositing; } else { m_recommendedCompositor = OpenGL2Compositing; } if (driver() == Driver_R600G || (driver() == Driver_R600C && m_renderer.contains("DRI2"))) { m_looseBinding = true; } } if (isNvidia()) { if (m_driver == Driver_NVidia && m_chipClass < NV40) m_supportsGLSL = false; // High likelihood of software emulation if (m_driver == Driver_NVidia) { m_looseBinding = true; m_preferBufferSubData = true; } if (m_chipClass < NV40) { m_recommendedCompositor = XRenderCompositing; } else { m_recommendedCompositor = OpenGL2Compositing; } m_limitedNPOT = m_textureNPOT && m_chipClass < NV40; m_limitedGLSL = m_supportsGLSL && m_chipClass < G80; } if (isIntel()) { if (m_chipClass < I915) m_supportsGLSL = false; m_limitedGLSL = m_supportsGLSL && m_chipClass < I965; // see https://bugs.freedesktop.org/show_bug.cgi?id=80349#c1 m_looseBinding = false; if (m_chipClass < I915) { m_recommendedCompositor = XRenderCompositing; } else { m_recommendedCompositor = OpenGL2Compositing; } } if (isMesaDriver() && platformInterface == EglPlatformInterface) { // According to the reference implementation in // mesa/demos/src/egl/opengles1/texture_from_pixmap // the mesa egl implementation does not require a strict binding (so far). m_looseBinding = true; } if (isSoftwareEmulation()) { if (m_driver < Driver_Llvmpipe) { // we recommend XRender m_recommendedCompositor = XRenderCompositing; // Software emulation does not provide GLSL m_limitedGLSL = m_supportsGLSL = false; } else { // llvmpipe does support GLSL m_recommendedCompositor = OpenGL2Compositing; m_limitedGLSL = false; m_supportsGLSL = true; } } if (m_driver == Driver_Qualcomm) { if (m_chipClass == Adreno1XX) { m_recommendedCompositor = NoCompositing; } else { // all other drivers support at least GLES 2 m_recommendedCompositor = OpenGL2Compositing; } } if (m_chipClass == UnknownChipClass && m_driver == Driver_Unknown) { // we don't know the hardware. Let's be optimistic and assume OpenGL compatible hardware m_recommendedCompositor = OpenGL2Compositing; m_supportsGLSL = true; } if (isVirtualBox()) { m_virtualMachine = true; m_recommendedCompositor = OpenGL2Compositing; } if (isVMware()) { m_virtualMachine = true; m_recommendedCompositor = OpenGL2Compositing; } if (m_driver == Driver_Virgl) { m_virtualMachine = true; m_recommendedCompositor = OpenGL2Compositing; } // and force back to shader supported on gles, we wouldn't have got a context if not supported if (isGLES()) { m_supportsGLSL = true; m_limitedGLSL = false; } } static void print(const QByteArray &label, const QByteArray &setting) { std::cout << std::setw(40) << std::left << label.data() << setting.data() << std::endl; } void GLPlatform::printResults() const { print(QByteArrayLiteral("OpenGL vendor string:"), m_vendor); print(QByteArrayLiteral("OpenGL renderer string:"), m_renderer); print(QByteArrayLiteral("OpenGL version string:"), m_version); if (m_supportsGLSL) print(QByteArrayLiteral("OpenGL shading language version string:"), m_glsl_version); print(QByteArrayLiteral("Driver:"), driverToString8(m_driver)); if (!isMesaDriver()) print(QByteArrayLiteral("Driver version:"), versionToString8(m_driverVersion)); print(QByteArrayLiteral("GPU class:"), chipClassToString8(m_chipClass)); print(QByteArrayLiteral("OpenGL version:"), versionToString8(m_glVersion)); if (m_supportsGLSL) print(QByteArrayLiteral("GLSL version:"), versionToString8(m_glslVersion)); if (isMesaDriver()) print(QByteArrayLiteral("Mesa version:"), versionToString8(mesaVersion())); //if (galliumVersion() > 0) // print("Gallium version:", versionToString(m_galliumVersion)); if (serverVersion() > 0) print(QByteArrayLiteral("X server version:"), versionToString8(m_serverVersion)); if (kernelVersion() > 0) print(QByteArrayLiteral("Linux kernel version:"), versionToString8(m_kernelVersion)); print(QByteArrayLiteral("Requires strict binding:"), !m_looseBinding ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); print(QByteArrayLiteral("GLSL shaders:"), m_supportsGLSL ? (m_limitedGLSL ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); print(QByteArrayLiteral("Texture NPOT support:"), m_textureNPOT ? (m_limitedNPOT ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); } bool GLPlatform::supports(GLFeature feature) const { switch(feature) { case LooseBinding: return m_looseBinding; case GLSL: return m_supportsGLSL; case LimitedGLSL: return m_limitedGLSL; case TextureNPOT: return m_textureNPOT; case LimitedNPOT: return m_limitedNPOT; default: return false; } } qint64 GLPlatform::glVersion() const { return m_glVersion; } qint64 GLPlatform::glslVersion() const { return m_glslVersion; } qint64 GLPlatform::mesaVersion() const { return m_mesaVersion; } qint64 GLPlatform::galliumVersion() const { return m_galliumVersion; } qint64 GLPlatform::serverVersion() const { return m_serverVersion; } qint64 GLPlatform::kernelVersion() const { return m_kernelVersion; } qint64 GLPlatform::driverVersion() const { if (isMesaDriver()) return mesaVersion(); return m_driverVersion; } Driver GLPlatform::driver() const { return m_driver; } ChipClass GLPlatform::chipClass() const { return m_chipClass; } bool GLPlatform::isMesaDriver() const { return mesaVersion() > 0; } bool GLPlatform::isGalliumDriver() const { return galliumVersion() > 0; } bool GLPlatform::isRadeon() const { return m_chipClass >= R100 && m_chipClass <= UnknownRadeon; } bool GLPlatform::isNvidia() const { return m_chipClass >= NV10 && m_chipClass <= UnknownNVidia; } bool GLPlatform::isIntel() const { return m_chipClass >= I8XX && m_chipClass <= UnknownIntel; } bool GLPlatform::isVirtualBox() const { return m_driver == Driver_VirtualBox; } bool GLPlatform::isVMware() const { return m_driver == Driver_VMware; } bool GLPlatform::isVirgl() const { return m_driver == Driver_Virgl; } bool GLPlatform::isSoftwareEmulation() const { return m_driver == Driver_Softpipe || m_driver == Driver_Swrast || m_driver == Driver_Llvmpipe; } bool GLPlatform::isAdreno() const { return m_chipClass >= Adreno1XX && m_chipClass <= UnknownAdreno; } const QByteArray &GLPlatform::glRendererString() const { return m_renderer; } const QByteArray &GLPlatform::glVendorString() const { return m_vendor; } const QByteArray &GLPlatform::glVersionString() const { return m_version; } const QByteArray &GLPlatform::glShadingLanguageVersionString() const { return m_glsl_version; } bool GLPlatform::isLooseBinding() const { return m_looseBinding; } bool GLPlatform::isVirtualMachine() const { return m_virtualMachine; } CompositingType GLPlatform::recommendedCompositor() const { return m_recommendedCompositor; } bool GLPlatform::preferBufferSubData() const { return m_preferBufferSubData; } OpenGLPlatformInterface GLPlatform::platformInterface() const { return m_platformInterface; } bool GLPlatform::isGLES() const { return m_gles; } void GLPlatform::cleanup() { delete s_platform; s_platform = nullptr; } } // namespace KWin diff --git a/libkwineffects/kwinglutils.cpp b/libkwineffects/kwinglutils.cpp index 413b04460..c5e00f06e 100644 --- a/libkwineffects/kwinglutils.cpp +++ b/libkwineffects/kwinglutils.cpp @@ -1,2329 +1,2319 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin 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 "kwinglutils.h" // need to call GLTexturePrivate::initStatic() #include "kwingltexture_p.h" #include "kwineffects.h" #include "kwinglplatform.h" #include "logging_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG_GLRENDERTARGET 0 #ifdef __GNUC__ # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) #else # define likely(x) (x) # define unlikely(x) (x) #endif namespace KWin { // Variables // List of all supported GL extensions static QList glExtensions; // Functions void initGL(const std::function &resolveFunction) { // Get list of supported OpenGL extensions if (hasGLVersion(3, 0)) { int count; glGetIntegerv(GL_NUM_EXTENSIONS, &count); for (int i = 0; i < count; i++) { const QByteArray name = (const char *) glGetStringi(GL_EXTENSIONS, i); glExtensions << name; } } else glExtensions = QByteArray((const char*)glGetString(GL_EXTENSIONS)).split(' '); // handle OpenGL extensions functions glResolveFunctions(resolveFunction); GLTexturePrivate::initStatic(); GLRenderTarget::initStatic(); GLVertexBuffer::initStatic(); } void cleanupGL() { ShaderManager::cleanup(); GLTexturePrivate::cleanup(); GLRenderTarget::cleanup(); GLVertexBuffer::cleanup(); GLPlatform::cleanup(); glExtensions.clear(); } bool hasGLVersion(int major, int minor, int release) { return GLPlatform::instance()->glVersion() >= kVersionNumber(major, minor, release); } bool hasGLExtension(const QByteArray &extension) { return glExtensions.contains(extension); } QList openGLExtensions() { return glExtensions; } static QString formatGLError(GLenum err) { switch(err) { case GL_NO_ERROR: return QStringLiteral("GL_NO_ERROR"); case GL_INVALID_ENUM: return QStringLiteral("GL_INVALID_ENUM"); case GL_INVALID_VALUE: return QStringLiteral("GL_INVALID_VALUE"); case GL_INVALID_OPERATION: return QStringLiteral("GL_INVALID_OPERATION"); case GL_STACK_OVERFLOW: return QStringLiteral("GL_STACK_OVERFLOW"); case GL_STACK_UNDERFLOW: return QStringLiteral("GL_STACK_UNDERFLOW"); case GL_OUT_OF_MEMORY: return QStringLiteral("GL_OUT_OF_MEMORY"); default: return QLatin1String("0x") + QString::number(err, 16); } } bool checkGLError(const char* txt) { GLenum err = glGetError(); if (err == GL_CONTEXT_LOST) { qCWarning(LIBKWINGLUTILS) << "GL error: context lost"; return true; } bool hasError = false; while (err != GL_NO_ERROR) { qCWarning(LIBKWINGLUTILS) << "GL error (" << txt << "): " << formatGLError(err); hasError = true; err = glGetError(); if (err == GL_CONTEXT_LOST) { qCWarning(LIBKWINGLUTILS) << "GL error: context lost"; break; } } return hasError; } //**************************************** // GLShader //**************************************** GLShader::GLShader(unsigned int flags) : mValid(false) , mLocationsResolved(false) , mExplicitLinking(flags & ExplicitLinking) { mProgram = glCreateProgram(); } GLShader::GLShader(const QString& vertexfile, const QString& fragmentfile, unsigned int flags) : mValid(false) , mLocationsResolved(false) , mExplicitLinking(flags & ExplicitLinking) { mProgram = glCreateProgram(); loadFromFiles(vertexfile, fragmentfile); } GLShader::~GLShader() { if (mProgram) { glDeleteProgram(mProgram); } } bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentFile) { QFile vf(vertexFile); if (!vf.open(QIODevice::ReadOnly)) { qCCritical(LIBKWINGLUTILS) << "Couldn't open" << vertexFile << "for reading!"; return false; } const QByteArray vertexSource = vf.readAll(); QFile ff(fragmentFile); if (!ff.open(QIODevice::ReadOnly)) { qCCritical(LIBKWINGLUTILS) << "Couldn't open" << fragmentFile << "for reading!"; return false; } const QByteArray fragmentSource = ff.readAll(); return load(vertexSource, fragmentSource); } bool GLShader::link() { // Be optimistic mValid = true; glLinkProgram(mProgram); // Get the program info log int maxLength, length; glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &maxLength); QByteArray log(maxLength, 0); glGetProgramInfoLog(mProgram, maxLength, &length, log.data()); // Make sure the program linked successfully int status; glGetProgramiv(mProgram, GL_LINK_STATUS, &status); if (status == 0) { qCCritical(LIBKWINGLUTILS) << "Failed to link shader:" << "\n" << log; mValid = false; } else if (length > 0) { qCDebug(LIBKWINGLUTILS) << "Shader link log:" << log; } return mValid; } const QByteArray GLShader::prepareSource(GLenum shaderType, const QByteArray &source) const { Q_UNUSED(shaderType) // Prepare the source code QByteArray ba; if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() < kVersionNumber(3, 0)) { ba.append("precision highp float;\n"); } - if (ShaderManager::instance()->isShaderDebug()) { - ba.append("#define KWIN_SHADER_DEBUG 1\n"); - } ba.append(source); if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0)) { ba.replace("#version 140", "#version 300 es\n\nprecision highp float;\n"); } return ba; } bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const { GLuint shader = glCreateShader(shaderType); QByteArray preparedSource = prepareSource(shaderType, source); const char* src = preparedSource.constData(); glShaderSource(shader, 1, &src, nullptr); // Compile the shader glCompileShader(shader); // Get the shader info log int maxLength, length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); QByteArray log(maxLength, 0); glGetShaderInfoLog(shader, maxLength, &length, log.data()); // Check the status int status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status == 0) { const char *typeName = (shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment"); qCCritical(LIBKWINGLUTILS) << "Failed to compile" << typeName << "shader:" << "\n" << log; } else if (length > 0) qCDebug(LIBKWINGLUTILS) << "Shader compile log:" << log; if (status != 0) glAttachShader(program, shader); glDeleteShader(shader); return status != 0; } bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource) { // Make sure shaders are actually supported if (!(GLPlatform::instance()->supports(GLSL) && // we lack shader branching for Texture2DRectangle everywhere - and it's probably not worth it GLPlatform::instance()->supports(TextureNPOT))) { qCCritical(LIBKWINGLUTILS) << "Shaders are not supported"; return false; } mValid = false; // Compile the vertex shader if (!vertexSource.isEmpty()) { bool success = compile(mProgram, GL_VERTEX_SHADER, vertexSource); if (!success) return false; } // Compile the fragment shader if (!fragmentSource.isEmpty()) { bool success = compile(mProgram, GL_FRAGMENT_SHADER, fragmentSource); if (!success) return false; } if (mExplicitLinking) return true; // link() sets mValid return link(); } void GLShader::bindAttributeLocation(const char *name, int index) { glBindAttribLocation(mProgram, index, name); } void GLShader::bindFragDataLocation(const char *name, int index) { if (!GLPlatform::instance()->isGLES() && (hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_gpu_shader4")))) glBindFragDataLocation(mProgram, index, name); } void GLShader::bind() { glUseProgram(mProgram); } void GLShader::unbind() { glUseProgram(0); } void GLShader::resolveLocations() { if (mLocationsResolved) return; mMatrixLocation[TextureMatrix] = uniformLocation("textureMatrix"); mMatrixLocation[ProjectionMatrix] = uniformLocation("projection"); mMatrixLocation[ModelViewMatrix] = uniformLocation("modelview"); mMatrixLocation[ModelViewProjectionMatrix] = uniformLocation("modelViewProjectionMatrix"); mMatrixLocation[WindowTransformation] = uniformLocation("windowTransformation"); mMatrixLocation[ScreenTransformation] = uniformLocation("screenTransformation"); mVec2Location[Offset] = uniformLocation("offset"); mVec4Location[ModulationConstant] = uniformLocation("modulation"); mFloatLocation[Saturation] = uniformLocation("saturation"); mColorLocation[Color] = uniformLocation("geometryColor"); mVec4Location[TextureClamp] = uniformLocation("textureClamp"); mLocationsResolved = true; } int GLShader::uniformLocation(const char *name) { const int location = glGetUniformLocation(mProgram, name); return location; } bool GLShader::setUniform(GLShader::MatrixUniform uniform, const QMatrix4x4 &matrix) { resolveLocations(); return setUniform(mMatrixLocation[uniform], matrix); } bool GLShader::setUniform(GLShader::Vec2Uniform uniform, const QVector2D &value) { resolveLocations(); return setUniform(mVec2Location[uniform], value); } bool GLShader::setUniform(GLShader::Vec4Uniform uniform, const QVector4D &value) { resolveLocations(); return setUniform(mVec4Location[uniform], value); } bool GLShader::setUniform(GLShader::FloatUniform uniform, float value) { resolveLocations(); return setUniform(mFloatLocation[uniform], value); } bool GLShader::setUniform(GLShader::IntUniform uniform, int value) { resolveLocations(); return setUniform(mIntLocation[uniform], value); } bool GLShader::setUniform(GLShader::ColorUniform uniform, const QVector4D &value) { resolveLocations(); return setUniform(mColorLocation[uniform], value); } bool GLShader::setUniform(GLShader::ColorUniform uniform, const QColor &value) { resolveLocations(); return setUniform(mColorLocation[uniform], value); } bool GLShader::setUniform(const char *name, float value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, int value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, const QVector2D& value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, const QVector3D& value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, const QVector4D& value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, const QMatrix4x4& value) { const int location = uniformLocation(name); return setUniform(location, value); } bool GLShader::setUniform(const char *name, const QColor& color) { const int location = uniformLocation(name); return setUniform(location, color); } bool GLShader::setUniform(int location, float value) { if (location >= 0) { glUniform1f(location, value); } return (location >= 0); } bool GLShader::setUniform(int location, int value) { if (location >= 0) { glUniform1i(location, value); } return (location >= 0); } bool GLShader::setUniform(int location, const QVector2D &value) { if (location >= 0) { glUniform2fv(location, 1, (const GLfloat*)&value); } return (location >= 0); } bool GLShader::setUniform(int location, const QVector3D &value) { if (location >= 0) { glUniform3fv(location, 1, (const GLfloat*)&value); } return (location >= 0); } bool GLShader::setUniform(int location, const QVector4D &value) { if (location >= 0) { glUniform4fv(location, 1, (const GLfloat*)&value); } return (location >= 0); } bool GLShader::setUniform(int location, const QMatrix4x4 &value) { if (location >= 0) { GLfloat m[16]; const auto *data = value.constData(); // i is column, j is row for m for (int i = 0; i < 16; ++i) { m[i] = data[i]; } glUniformMatrix4fv(location, 1, GL_FALSE, m); } return (location >= 0); } bool GLShader::setUniform(int location, const QColor &color) { if (location >= 0) { glUniform4f(location, color.redF(), color.greenF(), color.blueF(), color.alphaF()); } return (location >= 0); } int GLShader::attributeLocation(const char* name) { int location = glGetAttribLocation(mProgram, name); return location; } bool GLShader::setAttribute(const char* name, float value) { int location = attributeLocation(name); if (location >= 0) { glVertexAttrib1f(location, value); } return (location >= 0); } QMatrix4x4 GLShader::getUniformMatrix4x4(const char* name) { int location = uniformLocation(name); if (location >= 0) { GLfloat m[16]; glGetnUniformfv(mProgram, location, sizeof(m), m); QMatrix4x4 matrix(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]); matrix.optimize(); return matrix; } else { return QMatrix4x4(); } } //**************************************** // ShaderManager //**************************************** ShaderManager *ShaderManager::s_shaderManager = nullptr; ShaderManager *ShaderManager::instance() { if (!s_shaderManager) { s_shaderManager = new ShaderManager(); } return s_shaderManager; } void ShaderManager::cleanup() { delete s_shaderManager; s_shaderManager = nullptr; } ShaderManager::ShaderManager() { - m_debug = qstrcmp(qgetenv("KWIN_GL_DEBUG"), "1") == 0; - const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40); if (GLPlatform::instance()->glslVersion() >= coreVersionNumber) { m_resourcePath = QStringLiteral(":/effect-shaders-1.40/"); } else { m_resourcePath = QStringLiteral(":/effect-shaders-1.10/"); } } ShaderManager::~ShaderManager() { while (!m_boundShaders.isEmpty()) { popShader(); } qDeleteAll(m_shaderHash); m_shaderHash.clear(); } static bool fuzzyCompare(const QVector4D &lhs, const QVector4D &rhs) { const float epsilon = 1.0f / 255.0f; return lhs[0] >= rhs[0] - epsilon && lhs[0] <= rhs[0] + epsilon && lhs[1] >= rhs[1] - epsilon && lhs[1] <= rhs[1] + epsilon && lhs[2] >= rhs[2] - epsilon && lhs[2] <= rhs[2] + epsilon && lhs[3] >= rhs[3] - epsilon && lhs[3] <= rhs[3] + epsilon; } static bool checkPixel(int x, int y, const QVector4D &expected, const char *file, int line) { uint8_t data[4]; glReadnPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 4, data); const QVector4D pixel{data[0] / 255.f, data[1] / 255.f, data[2] / 255.f, data[3] / 255.f}; if (fuzzyCompare(pixel, expected)) return true; QMessageLogger(file, line, nullptr).warning() << "Pixel was" << pixel << "expected" << expected; return false; } #define CHECK_PIXEL(x, y, expected) \ checkPixel(x, y, expected, __FILE__, __LINE__) static QVector4D adjustSaturation(const QVector4D &color, float saturation) { const float gray = QVector3D::dotProduct(color.toVector3D(), {0.2126, 0.7152, 0.0722}); return QVector4D{gray, gray, gray, color.w()} * (1.0f - saturation) + color * saturation; } bool ShaderManager::selfTest() { bool pass = true; if (!GLRenderTarget::supported()) { qCWarning(LIBKWINGLUTILS) << "Framebuffer objects not supported - skipping shader tests"; return true; } if (GLPlatform::instance()->isNvidia() && GLPlatform::instance()->glRendererString().contains("Quadro")) { qCWarning(LIBKWINGLUTILS) << "Skipping self test as it is reported to return false positive results on Quadro hardware"; return true; } if (GLPlatform::instance()->isMesaDriver() && GLPlatform::instance()->mesaVersion() >= kVersionNumber(17, 0)) { qCWarning(LIBKWINGLUTILS) << "Skipping self test as it is reported to return false positive results on Mesa drivers"; return true; } // Create the source texture QImage image(2, 2, QImage::Format_ARGB32_Premultiplied); image.setPixel(0, 0, 0xffff0000); // Red image.setPixel(1, 0, 0xff00ff00); // Green image.setPixel(0, 1, 0xff0000ff); // Blue image.setPixel(1, 1, 0xffffffff); // White GLTexture src(image); src.setFilter(GL_NEAREST); // Create the render target GLTexture dst(GL_RGBA8, 32, 32); GLRenderTarget fbo(dst); GLRenderTarget::pushRenderTarget(&fbo); // Set up the vertex buffer GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); const GLVertexAttrib attribs[] { { VA_Position, 2, GL_FLOAT, offsetof(GLVertex2D, position) }, { VA_TexCoord, 2, GL_FLOAT, offsetof(GLVertex2D, texcoord) }, }; vbo->setAttribLayout(attribs, 2, sizeof(GLVertex2D)); GLVertex2D *verts = (GLVertex2D*) vbo->map(6 * sizeof(GLVertex2D)); verts[0] = GLVertex2D{{0, 0}, {0, 0}}; // Top left verts[1] = GLVertex2D{{0, 32}, {0, 1}}; // Bottom left verts[2] = GLVertex2D{{32, 0}, {1, 0}}; // Top right verts[3] = GLVertex2D{{32, 0}, {1, 0}}; // Top right verts[4] = GLVertex2D{{0, 32}, {0, 1}}; // Bottom left verts[5] = GLVertex2D{{32, 32}, {1, 1}}; // Bottom right vbo->unmap(); vbo->bindArrays(); glViewport(0, 0, 32, 32); glClearColor(0, 0, 0, 0); // Set up the projection matrix QMatrix4x4 matrix; matrix.ortho(QRect(0, 0, 32, 32)); // Bind the source texture src.bind(); const QVector4D red {1.0f, 0.0f, 0.0f, 1.0f}; const QVector4D green {0.0f, 1.0f, 0.0f, 1.0f}; const QVector4D blue {0.0f, 0.0f, 1.0f, 1.0f}; const QVector4D white {1.0f, 1.0f, 1.0f, 1.0f}; // Note: To see the line number in error messages, set // QT_MESSAGE_PATTERN="%{message} (%{file}:%{line})" // Test solid color GLShader *shader = pushShader(ShaderTrait::UniformColor); if (shader->isValid()) { glClear(GL_COLOR_BUFFER_BIT); shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); shader->setUniform(GLShader::Color, green); vbo->draw(GL_TRIANGLES, 0, 6); pass = CHECK_PIXEL(8, 24, green) && pass; pass = CHECK_PIXEL(24, 24, green) && pass; pass = CHECK_PIXEL(8, 8, green) && pass; pass = CHECK_PIXEL(24, 8, green) && pass; } else { pass = false; } popShader(); // Test texture mapping shader = pushShader(ShaderTrait::MapTexture); if (shader->isValid()) { glClear(GL_COLOR_BUFFER_BIT); shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); vbo->draw(GL_TRIANGLES, 0, 6); pass = CHECK_PIXEL(8, 24, red) && pass; pass = CHECK_PIXEL(24, 24, green) && pass; pass = CHECK_PIXEL(8, 8, blue) && pass; pass = CHECK_PIXEL(24, 8, white) && pass; } else { pass = false; } popShader(); // Test saturation filter shader = pushShader(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation); if (shader->isValid()) { glClear(GL_COLOR_BUFFER_BIT); const float saturation = .3; shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); shader->setUniform(GLShader::Saturation, saturation); vbo->draw(GL_TRIANGLES, 0, 6); pass = CHECK_PIXEL(8, 24, adjustSaturation(red, saturation)) && pass; pass = CHECK_PIXEL(24, 24, adjustSaturation(green, saturation)) && pass; pass = CHECK_PIXEL(8, 8, adjustSaturation(blue, saturation)) && pass; pass = CHECK_PIXEL(24, 8, adjustSaturation(white, saturation)) && pass; } else { pass = false; } popShader(); // Test modulation filter shader = pushShader(ShaderTrait::MapTexture | ShaderTrait::Modulate); if (shader->isValid()) { glClear(GL_COLOR_BUFFER_BIT); const QVector4D modulation{.3f, .4f, .5f, .6f}; shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); shader->setUniform(GLShader::ModulationConstant, modulation); vbo->draw(GL_TRIANGLES, 0, 6); pass = CHECK_PIXEL(8, 24, red * modulation) && pass; pass = CHECK_PIXEL(24, 24, green * modulation) && pass; pass = CHECK_PIXEL(8, 8, blue * modulation) && pass; pass = CHECK_PIXEL(24, 8, white * modulation) && pass; } else { pass = false; } popShader(); // Test saturation + modulation shader = pushShader(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate); if (shader->isValid()) { glClear(GL_COLOR_BUFFER_BIT); const QVector4D modulation{.3f, .4f, .5f, .6f}; const float saturation = .3; shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); shader->setUniform(GLShader::ModulationConstant, modulation); shader->setUniform(GLShader::Saturation, saturation); vbo->draw(GL_TRIANGLES, 0, 6); pass = CHECK_PIXEL(8, 24, adjustSaturation(red * modulation, saturation)) && pass; pass = CHECK_PIXEL(24, 24, adjustSaturation(green * modulation, saturation)) && pass; pass = CHECK_PIXEL(8, 8, adjustSaturation(blue * modulation, saturation)) && pass; pass = CHECK_PIXEL(24, 8, adjustSaturation(white * modulation, saturation)) && pass; } else { pass = false; } popShader(); vbo->unbindArrays(); GLRenderTarget::popRenderTarget(); return pass; } QByteArray ShaderManager::generateVertexSource(ShaderTraits traits) const { QByteArray source; QTextStream stream(&source); GLPlatform * const gl = GLPlatform::instance(); QByteArray attribute, varying; if (!gl->isGLES()) { const bool glsl_140 = gl->glslVersion() >= kVersionNumber(1, 40); attribute = glsl_140 ? QByteArrayLiteral("in") : QByteArrayLiteral("attribute"); varying = glsl_140 ? QByteArrayLiteral("out") : QByteArrayLiteral("varying"); if (glsl_140) stream << "#version 140\n\n"; } else { const bool glsl_es_300 = gl->glslVersion() >= kVersionNumber(3, 0); attribute = glsl_es_300 ? QByteArrayLiteral("in") : QByteArrayLiteral("attribute"); varying = glsl_es_300 ? QByteArrayLiteral("out") : QByteArrayLiteral("varying"); if (glsl_es_300) stream << "#version 300 es\n\n"; } stream << attribute << " vec4 position;\n"; if (traits & ShaderTrait::MapTexture) { stream << attribute << " vec4 texcoord;\n\n"; stream << varying << " vec2 texcoord0;\n\n"; } else stream << "\n"; stream << "uniform mat4 modelViewProjectionMatrix;\n\n"; stream << "void main()\n{\n"; if (traits & ShaderTrait::MapTexture) stream << " texcoord0 = texcoord.st;\n"; stream << " gl_Position = modelViewProjectionMatrix * position;\n"; stream << "}\n"; stream.flush(); return source; } QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const { QByteArray source; QTextStream stream(&source); GLPlatform * const gl = GLPlatform::instance(); QByteArray varying, output, textureLookup; if (!gl->isGLES()) { const bool glsl_140 = gl->glslVersion() >= kVersionNumber(1, 40); if (glsl_140) stream << "#version 140\n\n"; varying = glsl_140 ? QByteArrayLiteral("in") : QByteArrayLiteral("varying"); textureLookup = glsl_140 ? QByteArrayLiteral("texture") : QByteArrayLiteral("texture2D"); output = glsl_140 ? QByteArrayLiteral("fragColor") : QByteArrayLiteral("gl_FragColor"); } else { const bool glsl_es_300 = GLPlatform::instance()->glslVersion() >= kVersionNumber(3, 0); if (glsl_es_300) stream << "#version 300 es\n\n"; // From the GLSL ES specification: // // "The fragment language has no default precision qualifier for floating point types." stream << "precision highp float;\n\n"; varying = glsl_es_300 ? QByteArrayLiteral("in") : QByteArrayLiteral("varying"); textureLookup = glsl_es_300 ? QByteArrayLiteral("texture") : QByteArrayLiteral("texture2D"); output = glsl_es_300 ? QByteArrayLiteral("fragColor") : QByteArrayLiteral("gl_FragColor"); } if (traits & ShaderTrait::MapTexture) { stream << "uniform sampler2D sampler;\n"; if (traits & ShaderTrait::Modulate) stream << "uniform vec4 modulation;\n"; if (traits & ShaderTrait::AdjustSaturation) stream << "uniform float saturation;\n"; stream << "\n" << varying << " vec2 texcoord0;\n"; } else if (traits & ShaderTrait::UniformColor) stream << "uniform vec4 geometryColor;\n"; if (traits & ShaderTrait::ClampTexture) { stream << "uniform vec4 textureClamp;\n"; } if (output != QByteArrayLiteral("gl_FragColor")) stream << "\nout vec4 " << output << ";\n"; stream << "\nvoid main(void)\n{\n"; if (traits & ShaderTrait::MapTexture) { stream << "vec2 texcoordC = texcoord0;\n"; if (traits & ShaderTrait::ClampTexture) { stream << "texcoordC.x = clamp(texcoordC.x, textureClamp.x, textureClamp.z);\n"; stream << "texcoordC.y = clamp(texcoordC.y, textureClamp.y, textureClamp.w);\n"; } if (traits & (ShaderTrait::Modulate | ShaderTrait::AdjustSaturation)) { stream << " vec4 texel = " << textureLookup << "(sampler, texcoordC);\n"; if (traits & ShaderTrait::Modulate) stream << " texel *= modulation;\n"; if (traits & ShaderTrait::AdjustSaturation) stream << " texel.rgb = mix(vec3(dot(texel.rgb, vec3(0.2126, 0.7152, 0.0722))), texel.rgb, saturation);\n"; stream << " " << output << " = texel;\n"; } else { stream << " " << output << " = " << textureLookup << "(sampler, texcoordC);\n"; } } else if (traits & ShaderTrait::UniformColor) stream << " " << output << " = geometryColor;\n"; stream << "}"; stream.flush(); return source; } GLShader *ShaderManager::generateShader(ShaderTraits traits) { return generateCustomShader(traits); } GLShader *ShaderManager::generateCustomShader(ShaderTraits traits, const QByteArray &vertexSource, const QByteArray &fragmentSource) { const QByteArray vertex = vertexSource.isEmpty() ? generateVertexSource(traits) : vertexSource; const QByteArray fragment = fragmentSource.isEmpty() ? generateFragmentSource(traits) : fragmentSource; #if 0 qCDebug(LIBKWINGLUTILS) << "**************"; qCDebug(LIBKWINGLUTILS) << vertex; qCDebug(LIBKWINGLUTILS) << "**************"; qCDebug(LIBKWINGLUTILS) << fragment; qCDebug(LIBKWINGLUTILS) << "**************"; #endif GLShader *shader = new GLShader(GLShader::ExplicitLinking); shader->load(vertex, fragment); shader->bindAttributeLocation("position", VA_Position); shader->bindAttributeLocation("texcoord", VA_TexCoord); shader->bindFragDataLocation("fragColor", 0); shader->link(); return shader; } GLShader *ShaderManager::generateShaderFromResources(ShaderTraits traits, const QString &vertexFile, const QString &fragmentFile) { auto loadShaderFile = [this] (const QString &fileName) { QFile file(m_resourcePath + fileName); if (file.open(QIODevice::ReadOnly)) { return file.readAll(); } qCCritical(LIBKWINGLUTILS) << "Failed to read shader " << fileName; return QByteArray(); }; QByteArray vertexSource; QByteArray fragmentSource; if (!vertexFile.isEmpty()) { vertexSource = loadShaderFile(vertexFile); if (vertexSource.isEmpty()) { return new GLShader(); } } if (!fragmentFile.isEmpty()) { fragmentSource = loadShaderFile(fragmentFile); if (fragmentSource.isEmpty()) { return new GLShader(); } } return generateCustomShader(traits, vertexSource, fragmentSource); } GLShader *ShaderManager::shader(ShaderTraits traits) { GLShader *shader = m_shaderHash.value(traits); if (!shader) { shader = generateShader(traits); m_shaderHash.insert(traits, shader); } return shader; } GLShader *ShaderManager::getBoundShader() const { if (m_boundShaders.isEmpty()) { return nullptr; } else { return m_boundShaders.top(); } } bool ShaderManager::isShaderBound() const { return !m_boundShaders.isEmpty(); } -bool ShaderManager::isShaderDebug() const -{ - return m_debug; -} - GLShader *ShaderManager::pushShader(ShaderTraits traits) { GLShader *shader = this->shader(traits); pushShader(shader); return shader; } void ShaderManager::pushShader(GLShader *shader) { // only bind shader if it is not already bound if (shader != getBoundShader()) { shader->bind(); } m_boundShaders.push(shader); } void ShaderManager::popShader() { if (m_boundShaders.isEmpty()) { return; } GLShader *shader = m_boundShaders.pop(); if (m_boundShaders.isEmpty()) { // no more shader bound - unbind shader->unbind(); } else if (shader != m_boundShaders.top()) { // only rebind if a different shader is on top of stack m_boundShaders.top()->bind(); } } void ShaderManager::bindFragDataLocations(GLShader *shader) { shader->bindFragDataLocation("fragColor", 0); } void ShaderManager::bindAttributeLocations(GLShader *shader) const { shader->bindAttributeLocation("vertex", VA_Position); shader->bindAttributeLocation("texCoord", VA_TexCoord); } GLShader *ShaderManager::loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource) { GLShader *shader = new GLShader(GLShader::ExplicitLinking); shader->load(vertexSource, fragmentSource); bindAttributeLocations(shader); bindFragDataLocations(shader); shader->link(); return shader; } /*** GLRenderTarget ***/ bool GLRenderTarget::sSupported = false; bool GLRenderTarget::s_blitSupported = false; QStack GLRenderTarget::s_renderTargets = QStack(); QSize GLRenderTarget::s_virtualScreenSize; QRect GLRenderTarget::s_virtualScreenGeometry; qreal GLRenderTarget::s_virtualScreenScale = 1.0; GLint GLRenderTarget::s_virtualScreenViewport[4]; GLuint GLRenderTarget::s_kwinFramebuffer = 0; void GLRenderTarget::initStatic() { if (GLPlatform::instance()->isGLES()) { sSupported = true; s_blitSupported = hasGLVersion(3, 0); } else { sSupported = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_ARB_framebuffer_object")) || hasGLExtension(QByteArrayLiteral("GL_EXT_framebuffer_object")); s_blitSupported = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_ARB_framebuffer_object")) || hasGLExtension(QByteArrayLiteral("GL_EXT_framebuffer_blit")); } } void GLRenderTarget::cleanup() { Q_ASSERT(s_renderTargets.isEmpty()); sSupported = false; s_blitSupported = false; } bool GLRenderTarget::isRenderTargetBound() { return !s_renderTargets.isEmpty(); } bool GLRenderTarget::blitSupported() { return s_blitSupported; } void GLRenderTarget::pushRenderTarget(GLRenderTarget* target) { if (s_renderTargets.isEmpty()) { glGetIntegerv(GL_VIEWPORT, s_virtualScreenViewport); } target->enable(); s_renderTargets.push(target); } void GLRenderTarget::pushRenderTargets(QStack targets) { if (s_renderTargets.isEmpty()) { glGetIntegerv(GL_VIEWPORT, s_virtualScreenViewport); } targets.top()->enable(); s_renderTargets.append(targets); } GLRenderTarget* GLRenderTarget::popRenderTarget() { GLRenderTarget* ret = s_renderTargets.pop(); ret->setTextureDirty(); if (!s_renderTargets.isEmpty()) { s_renderTargets.top()->enable(); } else { ret->disable(); glViewport (s_virtualScreenViewport[0], s_virtualScreenViewport[1], s_virtualScreenViewport[2], s_virtualScreenViewport[3]); } return ret; } GLRenderTarget::GLRenderTarget() { // Reset variables mValid = false; mTexture = GLTexture(); } GLRenderTarget::GLRenderTarget(const GLTexture& color) { // Reset variables mValid = false; mTexture = color; // Make sure FBO is supported if (sSupported && !mTexture.isNull()) { initFBO(); } else qCCritical(LIBKWINGLUTILS) << "Render targets aren't supported!"; } GLRenderTarget::~GLRenderTarget() { if (mValid) { glDeleteFramebuffers(1, &mFramebuffer); } } bool GLRenderTarget::enable() { if (!mValid) { initFBO(); } if (!valid()) { qCCritical(LIBKWINGLUTILS) << "Can't enable invalid render target!"; return false; } glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); glViewport(0, 0, mTexture.width(), mTexture.height()); mTexture.setDirty(); return true; } bool GLRenderTarget::disable() { if (!mValid) { initFBO(); } if (!valid()) { qCCritical(LIBKWINGLUTILS) << "Can't disable invalid render target!"; return false; } glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); mTexture.setDirty(); return true; } static QString formatFramebufferStatus(GLenum status) { switch(status) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: // An attachment is the wrong type / is invalid / has 0 width or height return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: // There are no images attached to the framebuffer return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); case GL_FRAMEBUFFER_UNSUPPORTED: // A format or the combination of formats of the attachments is unsupported return QStringLiteral("GL_FRAMEBUFFER_UNSUPPORTED"); case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: // Not all attached images have the same width and height return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT"); case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: // The color attachments don't have the same format return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT"); case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: // The attachments don't have the same number of samples return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"); case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: // The draw buffer is missing return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"); case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: // The read buffer is missing return QStringLiteral("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"); default: return QStringLiteral("Unknown (0x") + QString::number(status, 16) + QStringLiteral(")"); } } void GLRenderTarget::initFBO() { #if DEBUG_GLRENDERTARGET GLenum err = glGetError(); if (err != GL_NO_ERROR) qCCritical(LIBKWINGLUTILS) << "Error status when entering GLRenderTarget::initFBO: " << formatGLError(err); #endif glGenFramebuffers(1, &mFramebuffer); #if DEBUG_GLRENDERTARGET if ((err = glGetError()) != GL_NO_ERROR) { qCCritical(LIBKWINGLUTILS) << "glGenFramebuffers failed: " << formatGLError(err); return; } #endif glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); #if DEBUG_GLRENDERTARGET if ((err = glGetError()) != GL_NO_ERROR) { qCCritical(LIBKWINGLUTILS) << "glBindFramebuffer failed: " << formatGLError(err); glDeleteFramebuffers(1, &mFramebuffer); return; } #endif glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture.target(), mTexture.texture(), 0); #if DEBUG_GLRENDERTARGET if ((err = glGetError()) != GL_NO_ERROR) { qCCritical(LIBKWINGLUTILS) << "glFramebufferTexture2D failed: " << formatGLError(err); glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); glDeleteFramebuffers(1, &mFramebuffer); return; } #endif const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); if (status != GL_FRAMEBUFFER_COMPLETE) { // We have an incomplete framebuffer, consider it invalid if (status == 0) qCCritical(LIBKWINGLUTILS) << "glCheckFramebufferStatus failed: " << formatGLError(glGetError()); else qCCritical(LIBKWINGLUTILS) << "Invalid framebuffer status: " << formatFramebufferStatus(status); glDeleteFramebuffers(1, &mFramebuffer); return; } mValid = true; } void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &destination, GLenum filter) { if (!GLRenderTarget::blitSupported()) { return; } if (!mValid) { initFBO(); } GLRenderTarget::pushRenderTarget(this); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, s_kwinFramebuffer); const QRect s = source.isNull() ? s_virtualScreenGeometry : source; const QRect d = destination.isNull() ? QRect(0, 0, mTexture.width(), mTexture.height()) : destination; glBlitFramebuffer((s.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y() + s.height())) * s_virtualScreenScale, (s.x() - s_virtualScreenGeometry.x() + s.width()) * s_virtualScreenScale, (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y())) * s_virtualScreenScale, d.x(), mTexture.height() - d.y() - d.height(), d.x() + d.width(), mTexture.height() - d.y(), GL_COLOR_BUFFER_BIT, filter); GLRenderTarget::popRenderTarget(); } void GLRenderTarget::attachTexture(const GLTexture& target) { if (!mValid) { initFBO(); } if (mTexture.texture() == target.texture()) { return; } pushRenderTarget(this); mTexture = target; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture.target(), mTexture.texture(), 0); popRenderTarget(); } void GLRenderTarget::detachTexture() { if (mTexture.isNull()) { return; } pushRenderTarget(this); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture.target(), 0, 0); popRenderTarget(); } // ------------------------------------------------------------------ static const uint16_t indices[] = { 1, 0, 3, 3, 2, 1, 5, 4, 7, 7, 6, 5, 9, 8, 11, 11, 10, 9, 13, 12, 15, 15, 14, 13, 17, 16, 19, 19, 18, 17, 21, 20, 23, 23, 22, 21, 25, 24, 27, 27, 26, 25, 29, 28, 31, 31, 30, 29, 33, 32, 35, 35, 34, 33, 37, 36, 39, 39, 38, 37, 41, 40, 43, 43, 42, 41, 45, 44, 47, 47, 46, 45, 49, 48, 51, 51, 50, 49, 53, 52, 55, 55, 54, 53, 57, 56, 59, 59, 58, 57, 61, 60, 63, 63, 62, 61, 65, 64, 67, 67, 66, 65, 69, 68, 71, 71, 70, 69, 73, 72, 75, 75, 74, 73, 77, 76, 79, 79, 78, 77, 81, 80, 83, 83, 82, 81, 85, 84, 87, 87, 86, 85, 89, 88, 91, 91, 90, 89, 93, 92, 95, 95, 94, 93, 97, 96, 99, 99, 98, 97, 101, 100, 103, 103, 102, 101, 105, 104, 107, 107, 106, 105, 109, 108, 111, 111, 110, 109, 113, 112, 115, 115, 114, 113, 117, 116, 119, 119, 118, 117, 121, 120, 123, 123, 122, 121, 125, 124, 127, 127, 126, 125, 129, 128, 131, 131, 130, 129, 133, 132, 135, 135, 134, 133, 137, 136, 139, 139, 138, 137, 141, 140, 143, 143, 142, 141, 145, 144, 147, 147, 146, 145, 149, 148, 151, 151, 150, 149, 153, 152, 155, 155, 154, 153, 157, 156, 159, 159, 158, 157, 161, 160, 163, 163, 162, 161, 165, 164, 167, 167, 166, 165, 169, 168, 171, 171, 170, 169, 173, 172, 175, 175, 174, 173, 177, 176, 179, 179, 178, 177, 181, 180, 183, 183, 182, 181, 185, 184, 187, 187, 186, 185, 189, 188, 191, 191, 190, 189, 193, 192, 195, 195, 194, 193, 197, 196, 199, 199, 198, 197, 201, 200, 203, 203, 202, 201, 205, 204, 207, 207, 206, 205, 209, 208, 211, 211, 210, 209, 213, 212, 215, 215, 214, 213, 217, 216, 219, 219, 218, 217, 221, 220, 223, 223, 222, 221, 225, 224, 227, 227, 226, 225, 229, 228, 231, 231, 230, 229, 233, 232, 235, 235, 234, 233, 237, 236, 239, 239, 238, 237, 241, 240, 243, 243, 242, 241, 245, 244, 247, 247, 246, 245, 249, 248, 251, 251, 250, 249, 253, 252, 255, 255, 254, 253, 257, 256, 259, 259, 258, 257, 261, 260, 263, 263, 262, 261, 265, 264, 267, 267, 266, 265, 269, 268, 271, 271, 270, 269, 273, 272, 275, 275, 274, 273, 277, 276, 279, 279, 278, 277, 281, 280, 283, 283, 282, 281, 285, 284, 287, 287, 286, 285, 289, 288, 291, 291, 290, 289, 293, 292, 295, 295, 294, 293, 297, 296, 299, 299, 298, 297, 301, 300, 303, 303, 302, 301, 305, 304, 307, 307, 306, 305, 309, 308, 311, 311, 310, 309, 313, 312, 315, 315, 314, 313, 317, 316, 319, 319, 318, 317, 321, 320, 323, 323, 322, 321, 325, 324, 327, 327, 326, 325, 329, 328, 331, 331, 330, 329, 333, 332, 335, 335, 334, 333, 337, 336, 339, 339, 338, 337, 341, 340, 343, 343, 342, 341, 345, 344, 347, 347, 346, 345, 349, 348, 351, 351, 350, 349, 353, 352, 355, 355, 354, 353, 357, 356, 359, 359, 358, 357, 361, 360, 363, 363, 362, 361, 365, 364, 367, 367, 366, 365, 369, 368, 371, 371, 370, 369, 373, 372, 375, 375, 374, 373, 377, 376, 379, 379, 378, 377, 381, 380, 383, 383, 382, 381, 385, 384, 387, 387, 386, 385, 389, 388, 391, 391, 390, 389, 393, 392, 395, 395, 394, 393, 397, 396, 399, 399, 398, 397, 401, 400, 403, 403, 402, 401, 405, 404, 407, 407, 406, 405, 409, 408, 411, 411, 410, 409, 413, 412, 415, 415, 414, 413, 417, 416, 419, 419, 418, 417, 421, 420, 423, 423, 422, 421, 425, 424, 427, 427, 426, 425, 429, 428, 431, 431, 430, 429, 433, 432, 435, 435, 434, 433, 437, 436, 439, 439, 438, 437, 441, 440, 443, 443, 442, 441, 445, 444, 447, 447, 446, 445, 449, 448, 451, 451, 450, 449, 453, 452, 455, 455, 454, 453, 457, 456, 459, 459, 458, 457, 461, 460, 463, 463, 462, 461, 465, 464, 467, 467, 466, 465, 469, 468, 471, 471, 470, 469, 473, 472, 475, 475, 474, 473, 477, 476, 479, 479, 478, 477, 481, 480, 483, 483, 482, 481, 485, 484, 487, 487, 486, 485, 489, 488, 491, 491, 490, 489, 493, 492, 495, 495, 494, 493, 497, 496, 499, 499, 498, 497, 501, 500, 503, 503, 502, 501, 505, 504, 507, 507, 506, 505, 509, 508, 511, 511, 510, 509, 513, 512, 515, 515, 514, 513, 517, 516, 519, 519, 518, 517, 521, 520, 523, 523, 522, 521, 525, 524, 527, 527, 526, 525, 529, 528, 531, 531, 530, 529, 533, 532, 535, 535, 534, 533, 537, 536, 539, 539, 538, 537, 541, 540, 543, 543, 542, 541, 545, 544, 547, 547, 546, 545, 549, 548, 551, 551, 550, 549, 553, 552, 555, 555, 554, 553, 557, 556, 559, 559, 558, 557, 561, 560, 563, 563, 562, 561, 565, 564, 567, 567, 566, 565, 569, 568, 571, 571, 570, 569, 573, 572, 575, 575, 574, 573, 577, 576, 579, 579, 578, 577, 581, 580, 583, 583, 582, 581, 585, 584, 587, 587, 586, 585, 589, 588, 591, 591, 590, 589, 593, 592, 595, 595, 594, 593, 597, 596, 599, 599, 598, 597, 601, 600, 603, 603, 602, 601, 605, 604, 607, 607, 606, 605, 609, 608, 611, 611, 610, 609, 613, 612, 615, 615, 614, 613, 617, 616, 619, 619, 618, 617, 621, 620, 623, 623, 622, 621, 625, 624, 627, 627, 626, 625, 629, 628, 631, 631, 630, 629, 633, 632, 635, 635, 634, 633, 637, 636, 639, 639, 638, 637, 641, 640, 643, 643, 642, 641, 645, 644, 647, 647, 646, 645, 649, 648, 651, 651, 650, 649, 653, 652, 655, 655, 654, 653, 657, 656, 659, 659, 658, 657, 661, 660, 663, 663, 662, 661, 665, 664, 667, 667, 666, 665, 669, 668, 671, 671, 670, 669, 673, 672, 675, 675, 674, 673, 677, 676, 679, 679, 678, 677, 681, 680, 683, 683, 682, 681, 685, 684, 687, 687, 686, 685, 689, 688, 691, 691, 690, 689, 693, 692, 695, 695, 694, 693, 697, 696, 699, 699, 698, 697, 701, 700, 703, 703, 702, 701, 705, 704, 707, 707, 706, 705, 709, 708, 711, 711, 710, 709, 713, 712, 715, 715, 714, 713, 717, 716, 719, 719, 718, 717, 721, 720, 723, 723, 722, 721, 725, 724, 727, 727, 726, 725, 729, 728, 731, 731, 730, 729, 733, 732, 735, 735, 734, 733, 737, 736, 739, 739, 738, 737, 741, 740, 743, 743, 742, 741, 745, 744, 747, 747, 746, 745, 749, 748, 751, 751, 750, 749, 753, 752, 755, 755, 754, 753, 757, 756, 759, 759, 758, 757, 761, 760, 763, 763, 762, 761, 765, 764, 767, 767, 766, 765, 769, 768, 771, 771, 770, 769, 773, 772, 775, 775, 774, 773, 777, 776, 779, 779, 778, 777, 781, 780, 783, 783, 782, 781, 785, 784, 787, 787, 786, 785, 789, 788, 791, 791, 790, 789, 793, 792, 795, 795, 794, 793, 797, 796, 799, 799, 798, 797, 801, 800, 803, 803, 802, 801, 805, 804, 807, 807, 806, 805, 809, 808, 811, 811, 810, 809, 813, 812, 815, 815, 814, 813, 817, 816, 819, 819, 818, 817, 821, 820, 823, 823, 822, 821, 825, 824, 827, 827, 826, 825, 829, 828, 831, 831, 830, 829, 833, 832, 835, 835, 834, 833, 837, 836, 839, 839, 838, 837, 841, 840, 843, 843, 842, 841, 845, 844, 847, 847, 846, 845, 849, 848, 851, 851, 850, 849, 853, 852, 855, 855, 854, 853, 857, 856, 859, 859, 858, 857, 861, 860, 863, 863, 862, 861, 865, 864, 867, 867, 866, 865, 869, 868, 871, 871, 870, 869, 873, 872, 875, 875, 874, 873, 877, 876, 879, 879, 878, 877, 881, 880, 883, 883, 882, 881, 885, 884, 887, 887, 886, 885, 889, 888, 891, 891, 890, 889, 893, 892, 895, 895, 894, 893, 897, 896, 899, 899, 898, 897, 901, 900, 903, 903, 902, 901, 905, 904, 907, 907, 906, 905, 909, 908, 911, 911, 910, 909, 913, 912, 915, 915, 914, 913, 917, 916, 919, 919, 918, 917, 921, 920, 923, 923, 922, 921, 925, 924, 927, 927, 926, 925, 929, 928, 931, 931, 930, 929, 933, 932, 935, 935, 934, 933, 937, 936, 939, 939, 938, 937, 941, 940, 943, 943, 942, 941, 945, 944, 947, 947, 946, 945, 949, 948, 951, 951, 950, 949, 953, 952, 955, 955, 954, 953, 957, 956, 959, 959, 958, 957, 961, 960, 963, 963, 962, 961, 965, 964, 967, 967, 966, 965, 969, 968, 971, 971, 970, 969, 973, 972, 975, 975, 974, 973, 977, 976, 979, 979, 978, 977, 981, 980, 983, 983, 982, 981, 985, 984, 987, 987, 986, 985, 989, 988, 991, 991, 990, 989, 993, 992, 995, 995, 994, 993, 997, 996, 999, 999, 998, 997, 1001, 1000, 1003, 1003, 1002, 1001, 1005, 1004, 1007, 1007, 1006, 1005, 1009, 1008, 1011, 1011, 1010, 1009, 1013, 1012, 1015, 1015, 1014, 1013, 1017, 1016, 1019, 1019, 1018, 1017, 1021, 1020, 1023, 1023, 1022, 1021, 1025, 1024, 1027, 1027, 1026, 1025, 1029, 1028, 1031, 1031, 1030, 1029, 1033, 1032, 1035, 1035, 1034, 1033, 1037, 1036, 1039, 1039, 1038, 1037, 1041, 1040, 1043, 1043, 1042, 1041, 1045, 1044, 1047, 1047, 1046, 1045, 1049, 1048, 1051, 1051, 1050, 1049, 1053, 1052, 1055, 1055, 1054, 1053, 1057, 1056, 1059, 1059, 1058, 1057, 1061, 1060, 1063, 1063, 1062, 1061, 1065, 1064, 1067, 1067, 1066, 1065, 1069, 1068, 1071, 1071, 1070, 1069, 1073, 1072, 1075, 1075, 1074, 1073, 1077, 1076, 1079, 1079, 1078, 1077, 1081, 1080, 1083, 1083, 1082, 1081, 1085, 1084, 1087, 1087, 1086, 1085, 1089, 1088, 1091, 1091, 1090, 1089, 1093, 1092, 1095, 1095, 1094, 1093, 1097, 1096, 1099, 1099, 1098, 1097, 1101, 1100, 1103, 1103, 1102, 1101, 1105, 1104, 1107, 1107, 1106, 1105, 1109, 1108, 1111, 1111, 1110, 1109, 1113, 1112, 1115, 1115, 1114, 1113, 1117, 1116, 1119, 1119, 1118, 1117, 1121, 1120, 1123, 1123, 1122, 1121, 1125, 1124, 1127, 1127, 1126, 1125, 1129, 1128, 1131, 1131, 1130, 1129, 1133, 1132, 1135, 1135, 1134, 1133, 1137, 1136, 1139, 1139, 1138, 1137, 1141, 1140, 1143, 1143, 1142, 1141, 1145, 1144, 1147, 1147, 1146, 1145, 1149, 1148, 1151, 1151, 1150, 1149, 1153, 1152, 1155, 1155, 1154, 1153, 1157, 1156, 1159, 1159, 1158, 1157, 1161, 1160, 1163, 1163, 1162, 1161, 1165, 1164, 1167, 1167, 1166, 1165, 1169, 1168, 1171, 1171, 1170, 1169, 1173, 1172, 1175, 1175, 1174, 1173, 1177, 1176, 1179, 1179, 1178, 1177, 1181, 1180, 1183, 1183, 1182, 1181, 1185, 1184, 1187, 1187, 1186, 1185, 1189, 1188, 1191, 1191, 1190, 1189, 1193, 1192, 1195, 1195, 1194, 1193, 1197, 1196, 1199, 1199, 1198, 1197, 1201, 1200, 1203, 1203, 1202, 1201, 1205, 1204, 1207, 1207, 1206, 1205, 1209, 1208, 1211, 1211, 1210, 1209, 1213, 1212, 1215, 1215, 1214, 1213, 1217, 1216, 1219, 1219, 1218, 1217, 1221, 1220, 1223, 1223, 1222, 1221, 1225, 1224, 1227, 1227, 1226, 1225, 1229, 1228, 1231, 1231, 1230, 1229, 1233, 1232, 1235, 1235, 1234, 1233, 1237, 1236, 1239, 1239, 1238, 1237, 1241, 1240, 1243, 1243, 1242, 1241, 1245, 1244, 1247, 1247, 1246, 1245, 1249, 1248, 1251, 1251, 1250, 1249, 1253, 1252, 1255, 1255, 1254, 1253, 1257, 1256, 1259, 1259, 1258, 1257, 1261, 1260, 1263, 1263, 1262, 1261, 1265, 1264, 1267, 1267, 1266, 1265, 1269, 1268, 1271, 1271, 1270, 1269, 1273, 1272, 1275, 1275, 1274, 1273, 1277, 1276, 1279, 1279, 1278, 1277, 1281, 1280, 1283, 1283, 1282, 1281, 1285, 1284, 1287, 1287, 1286, 1285, 1289, 1288, 1291, 1291, 1290, 1289, 1293, 1292, 1295, 1295, 1294, 1293, 1297, 1296, 1299, 1299, 1298, 1297, 1301, 1300, 1303, 1303, 1302, 1301, 1305, 1304, 1307, 1307, 1306, 1305, 1309, 1308, 1311, 1311, 1310, 1309, 1313, 1312, 1315, 1315, 1314, 1313, 1317, 1316, 1319, 1319, 1318, 1317, 1321, 1320, 1323, 1323, 1322, 1321, 1325, 1324, 1327, 1327, 1326, 1325, 1329, 1328, 1331, 1331, 1330, 1329, 1333, 1332, 1335, 1335, 1334, 1333, 1337, 1336, 1339, 1339, 1338, 1337, 1341, 1340, 1343, 1343, 1342, 1341, 1345, 1344, 1347, 1347, 1346, 1345, 1349, 1348, 1351, 1351, 1350, 1349, 1353, 1352, 1355, 1355, 1354, 1353, 1357, 1356, 1359, 1359, 1358, 1357, 1361, 1360, 1363, 1363, 1362, 1361, 1365, 1364, 1367, 1367, 1366, 1365, 1369, 1368, 1371, 1371, 1370, 1369, 1373, 1372, 1375, 1375, 1374, 1373, 1377, 1376, 1379, 1379, 1378, 1377, 1381, 1380, 1383, 1383, 1382, 1381, 1385, 1384, 1387, 1387, 1386, 1385, 1389, 1388, 1391, 1391, 1390, 1389, 1393, 1392, 1395, 1395, 1394, 1393, 1397, 1396, 1399, 1399, 1398, 1397, 1401, 1400, 1403, 1403, 1402, 1401, 1405, 1404, 1407, 1407, 1406, 1405, 1409, 1408, 1411, 1411, 1410, 1409, 1413, 1412, 1415, 1415, 1414, 1413, 1417, 1416, 1419, 1419, 1418, 1417, 1421, 1420, 1423, 1423, 1422, 1421, 1425, 1424, 1427, 1427, 1426, 1425, 1429, 1428, 1431, 1431, 1430, 1429, 1433, 1432, 1435, 1435, 1434, 1433, 1437, 1436, 1439, 1439, 1438, 1437, 1441, 1440, 1443, 1443, 1442, 1441, 1445, 1444, 1447, 1447, 1446, 1445, 1449, 1448, 1451, 1451, 1450, 1449, 1453, 1452, 1455, 1455, 1454, 1453, 1457, 1456, 1459, 1459, 1458, 1457, 1461, 1460, 1463, 1463, 1462, 1461, 1465, 1464, 1467, 1467, 1466, 1465, 1469, 1468, 1471, 1471, 1470, 1469, 1473, 1472, 1475, 1475, 1474, 1473, 1477, 1476, 1479, 1479, 1478, 1477, 1481, 1480, 1483, 1483, 1482, 1481, 1485, 1484, 1487, 1487, 1486, 1485, 1489, 1488, 1491, 1491, 1490, 1489, 1493, 1492, 1495, 1495, 1494, 1493, 1497, 1496, 1499, 1499, 1498, 1497, 1501, 1500, 1503, 1503, 1502, 1501, 1505, 1504, 1507, 1507, 1506, 1505, 1509, 1508, 1511, 1511, 1510, 1509, 1513, 1512, 1515, 1515, 1514, 1513, 1517, 1516, 1519, 1519, 1518, 1517, 1521, 1520, 1523, 1523, 1522, 1521, 1525, 1524, 1527, 1527, 1526, 1525, 1529, 1528, 1531, 1531, 1530, 1529, 1533, 1532, 1535, 1535, 1534, 1533, 1537, 1536, 1539, 1539, 1538, 1537, 1541, 1540, 1543, 1543, 1542, 1541, 1545, 1544, 1547, 1547, 1546, 1545, 1549, 1548, 1551, 1551, 1550, 1549, 1553, 1552, 1555, 1555, 1554, 1553, 1557, 1556, 1559, 1559, 1558, 1557, 1561, 1560, 1563, 1563, 1562, 1561, 1565, 1564, 1567, 1567, 1566, 1565, 1569, 1568, 1571, 1571, 1570, 1569, 1573, 1572, 1575, 1575, 1574, 1573, 1577, 1576, 1579, 1579, 1578, 1577, 1581, 1580, 1583, 1583, 1582, 1581, 1585, 1584, 1587, 1587, 1586, 1585, 1589, 1588, 1591, 1591, 1590, 1589, 1593, 1592, 1595, 1595, 1594, 1593, 1597, 1596, 1599, 1599, 1598, 1597, 1601, 1600, 1603, 1603, 1602, 1601, 1605, 1604, 1607, 1607, 1606, 1605, 1609, 1608, 1611, 1611, 1610, 1609, 1613, 1612, 1615, 1615, 1614, 1613, 1617, 1616, 1619, 1619, 1618, 1617, 1621, 1620, 1623, 1623, 1622, 1621, 1625, 1624, 1627, 1627, 1626, 1625, 1629, 1628, 1631, 1631, 1630, 1629, 1633, 1632, 1635, 1635, 1634, 1633, 1637, 1636, 1639, 1639, 1638, 1637, 1641, 1640, 1643, 1643, 1642, 1641, 1645, 1644, 1647, 1647, 1646, 1645, 1649, 1648, 1651, 1651, 1650, 1649, 1653, 1652, 1655, 1655, 1654, 1653, 1657, 1656, 1659, 1659, 1658, 1657, 1661, 1660, 1663, 1663, 1662, 1661, 1665, 1664, 1667, 1667, 1666, 1665, 1669, 1668, 1671, 1671, 1670, 1669, 1673, 1672, 1675, 1675, 1674, 1673, 1677, 1676, 1679, 1679, 1678, 1677, 1681, 1680, 1683, 1683, 1682, 1681, 1685, 1684, 1687, 1687, 1686, 1685, 1689, 1688, 1691, 1691, 1690, 1689, 1693, 1692, 1695, 1695, 1694, 1693, 1697, 1696, 1699, 1699, 1698, 1697, 1701, 1700, 1703, 1703, 1702, 1701, 1705, 1704, 1707, 1707, 1706, 1705, 1709, 1708, 1711, 1711, 1710, 1709, 1713, 1712, 1715, 1715, 1714, 1713, 1717, 1716, 1719, 1719, 1718, 1717, 1721, 1720, 1723, 1723, 1722, 1721, 1725, 1724, 1727, 1727, 1726, 1725, 1729, 1728, 1731, 1731, 1730, 1729, 1733, 1732, 1735, 1735, 1734, 1733, 1737, 1736, 1739, 1739, 1738, 1737, 1741, 1740, 1743, 1743, 1742, 1741, 1745, 1744, 1747, 1747, 1746, 1745, 1749, 1748, 1751, 1751, 1750, 1749, 1753, 1752, 1755, 1755, 1754, 1753, 1757, 1756, 1759, 1759, 1758, 1757, 1761, 1760, 1763, 1763, 1762, 1761, 1765, 1764, 1767, 1767, 1766, 1765, 1769, 1768, 1771, 1771, 1770, 1769, 1773, 1772, 1775, 1775, 1774, 1773, 1777, 1776, 1779, 1779, 1778, 1777, 1781, 1780, 1783, 1783, 1782, 1781, 1785, 1784, 1787, 1787, 1786, 1785, 1789, 1788, 1791, 1791, 1790, 1789, 1793, 1792, 1795, 1795, 1794, 1793, 1797, 1796, 1799, 1799, 1798, 1797, 1801, 1800, 1803, 1803, 1802, 1801, 1805, 1804, 1807, 1807, 1806, 1805, 1809, 1808, 1811, 1811, 1810, 1809, 1813, 1812, 1815, 1815, 1814, 1813, 1817, 1816, 1819, 1819, 1818, 1817, 1821, 1820, 1823, 1823, 1822, 1821, 1825, 1824, 1827, 1827, 1826, 1825, 1829, 1828, 1831, 1831, 1830, 1829, 1833, 1832, 1835, 1835, 1834, 1833, 1837, 1836, 1839, 1839, 1838, 1837, 1841, 1840, 1843, 1843, 1842, 1841, 1845, 1844, 1847, 1847, 1846, 1845, 1849, 1848, 1851, 1851, 1850, 1849, 1853, 1852, 1855, 1855, 1854, 1853, 1857, 1856, 1859, 1859, 1858, 1857, 1861, 1860, 1863, 1863, 1862, 1861, 1865, 1864, 1867, 1867, 1866, 1865, 1869, 1868, 1871, 1871, 1870, 1869, 1873, 1872, 1875, 1875, 1874, 1873, 1877, 1876, 1879, 1879, 1878, 1877, 1881, 1880, 1883, 1883, 1882, 1881, 1885, 1884, 1887, 1887, 1886, 1885, 1889, 1888, 1891, 1891, 1890, 1889, 1893, 1892, 1895, 1895, 1894, 1893, 1897, 1896, 1899, 1899, 1898, 1897, 1901, 1900, 1903, 1903, 1902, 1901, 1905, 1904, 1907, 1907, 1906, 1905, 1909, 1908, 1911, 1911, 1910, 1909, 1913, 1912, 1915, 1915, 1914, 1913, 1917, 1916, 1919, 1919, 1918, 1917, 1921, 1920, 1923, 1923, 1922, 1921, 1925, 1924, 1927, 1927, 1926, 1925, 1929, 1928, 1931, 1931, 1930, 1929, 1933, 1932, 1935, 1935, 1934, 1933, 1937, 1936, 1939, 1939, 1938, 1937, 1941, 1940, 1943, 1943, 1942, 1941, 1945, 1944, 1947, 1947, 1946, 1945, 1949, 1948, 1951, 1951, 1950, 1949, 1953, 1952, 1955, 1955, 1954, 1953, 1957, 1956, 1959, 1959, 1958, 1957, 1961, 1960, 1963, 1963, 1962, 1961, 1965, 1964, 1967, 1967, 1966, 1965, 1969, 1968, 1971, 1971, 1970, 1969, 1973, 1972, 1975, 1975, 1974, 1973, 1977, 1976, 1979, 1979, 1978, 1977, 1981, 1980, 1983, 1983, 1982, 1981, 1985, 1984, 1987, 1987, 1986, 1985, 1989, 1988, 1991, 1991, 1990, 1989, 1993, 1992, 1995, 1995, 1994, 1993, 1997, 1996, 1999, 1999, 1998, 1997, 2001, 2000, 2003, 2003, 2002, 2001, 2005, 2004, 2007, 2007, 2006, 2005, 2009, 2008, 2011, 2011, 2010, 2009, 2013, 2012, 2015, 2015, 2014, 2013, 2017, 2016, 2019, 2019, 2018, 2017, 2021, 2020, 2023, 2023, 2022, 2021, 2025, 2024, 2027, 2027, 2026, 2025, 2029, 2028, 2031, 2031, 2030, 2029, 2033, 2032, 2035, 2035, 2034, 2033, 2037, 2036, 2039, 2039, 2038, 2037, 2041, 2040, 2043, 2043, 2042, 2041, 2045, 2044, 2047, 2047, 2046, 2045 }; template T align(T value, int bytes) { return (value + bytes - 1) & ~T(bytes - 1); } class IndexBuffer { public: IndexBuffer(); ~IndexBuffer(); void accommodate(int count); void bind(); private: GLuint m_buffer; size_t m_size; int m_count; }; IndexBuffer::IndexBuffer() { // The maximum number of quads we can render with 16 bit indices is 16,384. // But we start with 512 and grow the buffer as needed. m_size = sizeof(indices); m_count = m_size / (6 * sizeof(uint16_t)); glGenBuffers(1, &m_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); } IndexBuffer::~IndexBuffer() { glDeleteBuffers(1, &m_buffer); } void IndexBuffer::accommodate(int count) { // Check if we need to grow the buffer. if (count <= m_count) return; count = align(count, 128); size_t size = 6 * sizeof(uint16_t) * count; // Create a new buffer object GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW); // Use the GPU to copy the data from the old object to the new object, glBindBuffer(GL_COPY_READ_BUFFER, m_buffer); glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ELEMENT_ARRAY_BUFFER, 0, 0, m_size); glDeleteBuffers(1, &m_buffer); glFlush(); // Needed to work around what appears to be a CP DMA issue in r600g // Map the new object and fill in the uninitialized section const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_RANGE_BIT; uint16_t *map = (uint16_t *) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, m_size, size - m_size, access); const uint16_t index[] = { 1, 0, 3, 3, 2, 1 }; for (int i = m_count; i < count; i++) { for (int j = 0; j < 6; j++) *(map++) = i * 4 + index[j]; } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); m_buffer = buffer; m_count = count; m_size = size; } void IndexBuffer::bind() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); } // ------------------------------------------------------------------ class BitRef { public: BitRef(uint32_t &bitfield, int bit) : m_bitfield(bitfield), m_mask(1 << bit) {} void operator = (bool val) { if (val) m_bitfield |= m_mask; else m_bitfield &= ~m_mask; } operator bool () const { return m_bitfield & m_mask; } private: uint32_t &m_bitfield; int const m_mask; }; // ------------------------------------------------------------------ class Bitfield { public: Bitfield() : m_bitfield(0) {} Bitfield(uint32_t bits) : m_bitfield(bits) {} void set(int i) { m_bitfield |= (1 << i); } void clear(int i) { m_bitfield &= ~(1 << i); } BitRef operator [] (int i) { return BitRef(m_bitfield, i); } operator uint32_t () const { return m_bitfield; } private: uint32_t m_bitfield; }; // ------------------------------------------------------------------ class BitfieldIterator { public: BitfieldIterator(uint32_t bitfield) : m_bitfield(bitfield) {} bool hasNext() const { return m_bitfield != 0; } int next() { const int bit = ffs(m_bitfield) - 1; m_bitfield ^= (1 << bit); return bit; } private: uint32_t m_bitfield; }; // ------------------------------------------------------------------ struct VertexAttrib { int size; GLenum type; int offset; }; // ------------------------------------------------------------------ struct BufferFence { GLsync sync; intptr_t nextEnd; bool signaled() const { GLint value; glGetSynciv(sync, GL_SYNC_STATUS, 1, nullptr, &value); return value == GL_SIGNALED; } }; static void deleteAll(std::deque &fences) { for (const BufferFence &fence : fences) glDeleteSync(fence.sync); fences.clear(); } // ------------------------------------------------------------------ template struct FrameSizesArray { public: FrameSizesArray() { m_array.fill(0); } void push(size_t size) { m_array[m_index] = size; m_index = (m_index + 1) % Count; } size_t average() const { size_t sum = 0; for (size_t size : m_array) sum += size; return sum / Count; } private: std::array m_array; int m_index = 0; }; //********************************* // GLVertexBufferPrivate //********************************* class GLVertexBufferPrivate { public: GLVertexBufferPrivate(GLVertexBuffer::UsageHint usageHint) : vertexCount(0) , persistent(false) , useColor(false) , color(0, 0, 0, 255) , bufferSize(0) , bufferEnd(0) , mappedSize(0) , frameSize(0) , nextOffset(0) , baseAddress(0) , map(nullptr) { glGenBuffers(1, &buffer); switch(usageHint) { case GLVertexBuffer::Dynamic: usage = GL_DYNAMIC_DRAW; break; case GLVertexBuffer::Static: usage = GL_STATIC_DRAW; break; default: usage = GL_STREAM_DRAW; break; } } ~GLVertexBufferPrivate() { deleteAll(fences); if (buffer != 0) { glDeleteBuffers(1, &buffer); map = nullptr; } } void interleaveArrays(float *array, int dim, const float *vertices, const float *texcoords, int count); void bindArrays(); void unbindArrays(); void reallocateBuffer(size_t size); GLvoid *mapNextFreeRange(size_t size); void reallocatePersistentBuffer(size_t size); bool awaitFence(intptr_t offset); GLvoid *getIdleRange(size_t size); GLuint buffer; GLenum usage; int stride; int vertexCount; static GLVertexBuffer *streamingBuffer; static bool haveBufferStorage; static bool haveSyncFences; static bool hasMapBufferRange; static bool supportsIndexedQuads; QByteArray dataStore; bool persistent; bool useColor; QVector4D color; size_t bufferSize; intptr_t bufferEnd; size_t mappedSize; size_t frameSize; intptr_t nextOffset; intptr_t baseAddress; uint8_t *map; std::deque fences; FrameSizesArray<4> frameSizes; VertexAttrib attrib[VertexAttributeCount]; Bitfield enabledArrays; static IndexBuffer *s_indexBuffer; }; bool GLVertexBufferPrivate::hasMapBufferRange = false; bool GLVertexBufferPrivate::supportsIndexedQuads = false; GLVertexBuffer *GLVertexBufferPrivate::streamingBuffer = nullptr; bool GLVertexBufferPrivate::haveBufferStorage = false; bool GLVertexBufferPrivate::haveSyncFences = false; IndexBuffer *GLVertexBufferPrivate::s_indexBuffer = nullptr; void GLVertexBufferPrivate::interleaveArrays(float *dst, int dim, const float *vertices, const float *texcoords, int count) { if (!texcoords) { memcpy((void *) dst, vertices, dim * sizeof(float) * count); return; } switch (dim) { case 2: for (int i = 0; i < count; i++) { *(dst++) = *(vertices++); *(dst++) = *(vertices++); *(dst++) = *(texcoords++); *(dst++) = *(texcoords++); } break; case 3: for (int i = 0; i < count; i++) { *(dst++) = *(vertices++); *(dst++) = *(vertices++); *(dst++) = *(vertices++); *(dst++) = *(texcoords++); *(dst++) = *(texcoords++); } break; default: for (int i = 0; i < count; i++) { for (int j = 0; j < dim; j++) *(dst++) = *(vertices++); *(dst++) = *(texcoords++); *(dst++) = *(texcoords++); } } } void GLVertexBufferPrivate::bindArrays() { if (useColor) { GLShader *shader = ShaderManager::instance()->getBoundShader(); shader->setUniform(GLShader::Color, color); } glBindBuffer(GL_ARRAY_BUFFER, buffer); BitfieldIterator it(enabledArrays); while (it.hasNext()) { const int index = it.next(); glVertexAttribPointer(index, attrib[index].size, attrib[index].type, GL_FALSE, stride, (const GLvoid *) (baseAddress + attrib[index].offset)); glEnableVertexAttribArray(index); } } void GLVertexBufferPrivate::unbindArrays() { BitfieldIterator it(enabledArrays); while (it.hasNext()) glDisableVertexAttribArray(it.next()); } void GLVertexBufferPrivate::reallocatePersistentBuffer(size_t size) { if (buffer != 0) { // This also unmaps and unbinds the buffer glDeleteBuffers(1, &buffer); buffer = 0; deleteAll(fences); } if (buffer == 0) glGenBuffers(1, &buffer); // Round the size up to 64 kb size_t minSize = qMax(frameSizes.average() * 3, 128 * 1024); bufferSize = align(qMax(size, minSize), 64 * 1024); const GLbitfield storage = GL_DYNAMIC_STORAGE_BIT; const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferStorage(GL_ARRAY_BUFFER, bufferSize, nullptr, storage | access); map = (uint8_t *) glMapBufferRange(GL_ARRAY_BUFFER, 0, bufferSize, access); nextOffset = 0; bufferEnd = bufferSize; } bool GLVertexBufferPrivate::awaitFence(intptr_t end) { // Skip fences until we reach the end offset while (!fences.empty() && fences.front().nextEnd < end) { glDeleteSync(fences.front().sync); fences.pop_front(); } Q_ASSERT(!fences.empty()); // Wait on the next fence const BufferFence &fence = fences.front(); if (!fence.signaled()) { qCDebug(LIBKWINGLUTILS) << "Stalling on VBO fence"; const GLenum ret = glClientWaitSync(fence.sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000); if (ret == GL_TIMEOUT_EXPIRED || ret == GL_WAIT_FAILED) { qCCritical(LIBKWINGLUTILS) << "Wait failed"; return false; } } glDeleteSync(fence.sync); // Update the end pointer bufferEnd = fence.nextEnd; fences.pop_front(); return true; } GLvoid *GLVertexBufferPrivate::getIdleRange(size_t size) { if (unlikely(size > bufferSize)) reallocatePersistentBuffer(size * 2); // Handle wrap-around if (unlikely(nextOffset + size > bufferSize)) { nextOffset = 0; bufferEnd -= bufferSize; for (BufferFence &fence : fences) fence.nextEnd -= bufferSize; // Emit a fence now BufferFence fence; fence.sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); fence.nextEnd = bufferSize; fences.emplace_back(fence); } if (unlikely(nextOffset + intptr_t(size) > bufferEnd)) { if (!awaitFence(nextOffset + size)) return nullptr; } return map + nextOffset; } void GLVertexBufferPrivate::reallocateBuffer(size_t size) { // Round the size up to 4 Kb for streaming/dynamic buffers. const size_t minSize = 32768; // Minimum size for streaming buffers const size_t alloc = usage != GL_STATIC_DRAW ? align(qMax(size, minSize), 4096) : size; glBufferData(GL_ARRAY_BUFFER, alloc, nullptr, usage); bufferSize = alloc; } GLvoid *GLVertexBufferPrivate::mapNextFreeRange(size_t size) { GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; if ((nextOffset + size) > bufferSize) { // Reallocate the data store if it's too small. if (size > bufferSize) { reallocateBuffer(size); } else { access |= GL_MAP_INVALIDATE_BUFFER_BIT; access ^= GL_MAP_UNSYNCHRONIZED_BIT; } nextOffset = 0; } return glMapBufferRange(GL_ARRAY_BUFFER, nextOffset, size, access); } //********************************* // GLVertexBuffer //********************************* QRect GLVertexBuffer::s_virtualScreenGeometry; qreal GLVertexBuffer::s_virtualScreenScale; GLVertexBuffer::GLVertexBuffer(UsageHint hint) : d(new GLVertexBufferPrivate(hint)) { } GLVertexBuffer::~GLVertexBuffer() { delete d; } void GLVertexBuffer::setData(const void *data, size_t size) { GLvoid *ptr = map(size); memcpy(ptr, data, size); unmap(); } void GLVertexBuffer::setData(int vertexCount, int dim, const float* vertices, const float* texcoords) { const GLVertexAttrib layout[] = { { VA_Position, dim, GL_FLOAT, 0 }, { VA_TexCoord, 2, GL_FLOAT, int(dim * sizeof(float)) } }; int stride = (texcoords ? dim + 2 : dim) * sizeof(float); int attribCount = texcoords ? 2 : 1; setAttribLayout(layout, attribCount, stride); setVertexCount(vertexCount); GLvoid *ptr = map(vertexCount * stride); d->interleaveArrays((float *) ptr, dim, vertices, texcoords, vertexCount); unmap(); } GLvoid *GLVertexBuffer::map(size_t size) { d->mappedSize = size; d->frameSize += size; if (d->persistent) return d->getIdleRange(size); glBindBuffer(GL_ARRAY_BUFFER, d->buffer); bool preferBufferSubData = GLPlatform::instance()->preferBufferSubData(); if (GLVertexBufferPrivate::hasMapBufferRange && !preferBufferSubData) return (GLvoid *) d->mapNextFreeRange(size); // If we can't map the buffer we allocate local memory to hold the // buffer data and return a pointer to it. The data will be submitted // to the actual buffer object when the user calls unmap(). if (size_t(d->dataStore.size()) < size) d->dataStore.resize(size); return (GLvoid *) d->dataStore.data(); } void GLVertexBuffer::unmap() { if (d->persistent) { d->baseAddress = d->nextOffset; d->nextOffset += align(d->mappedSize, 16); // Align to 16 bytes for SSE d->mappedSize = 0; return; } bool preferBufferSubData = GLPlatform::instance()->preferBufferSubData(); if (GLVertexBufferPrivate::hasMapBufferRange && !preferBufferSubData) { glUnmapBuffer(GL_ARRAY_BUFFER); d->baseAddress = d->nextOffset; d->nextOffset += align(d->mappedSize, 16); // Align to 16 bytes for SSE } else { // Upload the data from local memory to the buffer object if (preferBufferSubData) { if ((d->nextOffset + d->mappedSize) > d->bufferSize) { d->reallocateBuffer(d->mappedSize); d->nextOffset = 0; } glBufferSubData(GL_ARRAY_BUFFER, d->nextOffset, d->mappedSize, d->dataStore.constData()); d->baseAddress = d->nextOffset; d->nextOffset += align(d->mappedSize, 16); // Align to 16 bytes for SSE } else { glBufferData(GL_ARRAY_BUFFER, d->mappedSize, d->dataStore.data(), d->usage); d->baseAddress = 0; } // Free the local memory buffer if it's unlikely to be used again if (d->usage == GL_STATIC_DRAW) d->dataStore = QByteArray(); } d->mappedSize = 0; } void GLVertexBuffer::setVertexCount(int count) { d->vertexCount = count; } void GLVertexBuffer::setAttribLayout(const GLVertexAttrib *attribs, int count, int stride) { // Start by disabling all arrays d->enabledArrays = 0; for (int i = 0; i < count; i++) { const int index = attribs[i].index; Q_ASSERT(index >= 0 && index < VertexAttributeCount); Q_ASSERT(!d->enabledArrays[index]); d->attrib[index].size = attribs[i].size; d->attrib[index].type = attribs[i].type; d->attrib[index].offset = attribs[i].relativeOffset; d->enabledArrays[index] = true; } d->stride = stride; } void GLVertexBuffer::render(GLenum primitiveMode) { render(infiniteRegion(), primitiveMode, false); } void GLVertexBuffer::render(const QRegion& region, GLenum primitiveMode, bool hardwareClipping) { d->bindArrays(); draw(region, primitiveMode, 0, d->vertexCount, hardwareClipping); d->unbindArrays(); } void GLVertexBuffer::bindArrays() { d->bindArrays(); } void GLVertexBuffer::unbindArrays() { d->unbindArrays(); } void GLVertexBuffer::draw(GLenum primitiveMode, int first, int count) { draw(infiniteRegion(), primitiveMode, first, count, false); } void GLVertexBuffer::draw(const QRegion ®ion, GLenum primitiveMode, int first, int count, bool hardwareClipping) { if (primitiveMode == GL_QUADS) { IndexBuffer *&indexBuffer = GLVertexBufferPrivate::s_indexBuffer; if (!indexBuffer) indexBuffer = new IndexBuffer; indexBuffer->bind(); indexBuffer->accommodate(count / 4); count = count * 6 / 4; if (!hardwareClipping) { glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr, first); } else { // Clip using scissoring for (const QRect &r : region) { glScissor((r.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, (s_virtualScreenGeometry.height() + s_virtualScreenGeometry.y() - r.y() - r.height()) * s_virtualScreenScale, r.width() * s_virtualScreenScale, r.height() * s_virtualScreenScale); glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr, first); } } return; } if (!hardwareClipping) { glDrawArrays(primitiveMode, first, count); } else { // Clip using scissoring for (const QRect &r : region) { glScissor((r.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, (s_virtualScreenGeometry.height() + s_virtualScreenGeometry.y() - r.y() - r.height()) * s_virtualScreenScale, r.width() * s_virtualScreenScale, r.height() * s_virtualScreenScale); glDrawArrays(primitiveMode, first, count); } } } bool GLVertexBuffer::supportsIndexedQuads() { return GLVertexBufferPrivate::supportsIndexedQuads; } bool GLVertexBuffer::isUseColor() const { return d->useColor; } void GLVertexBuffer::setUseColor(bool enable) { d->useColor = enable; } void GLVertexBuffer::setColor(const QColor& color, bool enable) { d->useColor = enable; d->color = QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF()); } void GLVertexBuffer::reset() { d->useColor = false; d->color = QVector4D(0, 0, 0, 1); d->vertexCount = 0; } void GLVertexBuffer::endOfFrame() { if (!d->persistent) return; // Emit a fence if we have uploaded data if (d->frameSize > 0) { d->frameSizes.push(d->frameSize); d->frameSize = 0; // Force the buffer to be reallocated at the beginning of the next frame // if the average frame size is greater than half the size of the buffer if (unlikely(d->frameSizes.average() > d->bufferSize / 2)) { deleteAll(d->fences); glDeleteBuffers(1, &d->buffer); d->buffer = 0; d->bufferSize = 0; d->nextOffset = 0; d->map = nullptr; } else { BufferFence fence; fence.sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); fence.nextEnd = d->nextOffset + d->bufferSize; d->fences.emplace_back(fence); } } } void GLVertexBuffer::framePosted() { if (!d->persistent) return; // Remove finished fences from the list and update the bufferEnd offset while (d->fences.size() > 1 && d->fences.front().signaled()) { const BufferFence &fence = d->fences.front(); glDeleteSync(fence.sync); d->bufferEnd = fence.nextEnd; d->fences.pop_front(); } } void GLVertexBuffer::initStatic() { if (GLPlatform::instance()->isGLES()) { bool haveBaseVertex = hasGLExtension(QByteArrayLiteral("GL_OES_draw_elements_base_vertex")); bool haveCopyBuffer = hasGLVersion(3, 0); bool haveMapBufferRange = hasGLExtension(QByteArrayLiteral("GL_EXT_map_buffer_range")); GLVertexBufferPrivate::hasMapBufferRange = haveMapBufferRange; GLVertexBufferPrivate::supportsIndexedQuads = haveBaseVertex && haveCopyBuffer && haveMapBufferRange; GLVertexBufferPrivate::haveBufferStorage = hasGLExtension("GL_EXT_buffer_storage"); GLVertexBufferPrivate::haveSyncFences = hasGLVersion(3, 0); } else { bool haveBaseVertex = hasGLVersion(3, 2) || hasGLExtension(QByteArrayLiteral("GL_ARB_draw_elements_base_vertex")); bool haveCopyBuffer = hasGLVersion(3, 1) || hasGLExtension(QByteArrayLiteral("GL_ARB_copy_buffer")); bool haveMapBufferRange = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_ARB_map_buffer_range")); GLVertexBufferPrivate::hasMapBufferRange = haveMapBufferRange; GLVertexBufferPrivate::supportsIndexedQuads = haveBaseVertex && haveCopyBuffer && haveMapBufferRange; GLVertexBufferPrivate::haveBufferStorage = hasGLVersion(4, 4) || hasGLExtension("GL_ARB_buffer_storage"); GLVertexBufferPrivate::haveSyncFences = hasGLVersion(3, 2) || hasGLExtension("GL_ARB_sync"); } GLVertexBufferPrivate::s_indexBuffer = nullptr; GLVertexBufferPrivate::streamingBuffer = new GLVertexBuffer(GLVertexBuffer::Stream); if (GLVertexBufferPrivate::haveBufferStorage && GLVertexBufferPrivate::haveSyncFences) { if (qgetenv("KWIN_PERSISTENT_VBO") != QByteArrayLiteral("0")) { GLVertexBufferPrivate::streamingBuffer->d->persistent = true; } } } void GLVertexBuffer::cleanup() { delete GLVertexBufferPrivate::s_indexBuffer; GLVertexBufferPrivate::s_indexBuffer = nullptr; GLVertexBufferPrivate::hasMapBufferRange = false; GLVertexBufferPrivate::supportsIndexedQuads = false; delete GLVertexBufferPrivate::streamingBuffer; GLVertexBufferPrivate::streamingBuffer = nullptr; } GLVertexBuffer *GLVertexBuffer::streamingBuffer() { return GLVertexBufferPrivate::streamingBuffer; } } // namespace diff --git a/libkwineffects/kwinglutils.h b/libkwineffects/kwinglutils.h index cea03f39d..39f0a780c 100644 --- a/libkwineffects/kwinglutils.h +++ b/libkwineffects/kwinglutils.h @@ -1,837 +1,829 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin 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_GLUTILS_H #define KWIN_GLUTILS_H // kwin #include #include "kwinglutils_funcs.h" #include "kwingltexture.h" // Qt #include #include /** @addtogroup kwineffects */ /** @{ */ class QVector2D; class QVector3D; class QVector4D; class QMatrix4x4; template< class K, class V > class QHash; namespace KWin { class GLVertexBuffer; class GLVertexBufferPrivate; // Initializes OpenGL stuff. This includes resolving function pointers as // well as checking for GL version and extensions // Note that GL context has to be created by the time this function is called typedef void (*resolveFuncPtr)(); void KWINGLUTILS_EXPORT initGL(const std::function &resolveFunction); // Cleans up all resources hold by the GL Context void KWINGLUTILS_EXPORT cleanupGL(); bool KWINGLUTILS_EXPORT hasGLVersion(int major, int minor, int release = 0); // use for both OpenGL and GLX extensions bool KWINGLUTILS_EXPORT hasGLExtension(const QByteArray &extension); // detect OpenGL error (add to various places in code to pinpoint the place) bool KWINGLUTILS_EXPORT checkGLError(const char* txt); QList KWINGLUTILS_EXPORT openGLExtensions(); class KWINGLUTILS_EXPORT GLShader { public: enum Flags { NoFlags = 0, ExplicitLinking = (1 << 0) }; GLShader(const QString &vertexfile, const QString &fragmentfile, unsigned int flags = NoFlags); ~GLShader(); bool isValid() const { return mValid; } void bindAttributeLocation(const char *name, int index); void bindFragDataLocation(const char *name, int index); bool link(); int uniformLocation(const char* name); bool setUniform(const char* name, float value); bool setUniform(const char* name, int value); bool setUniform(const char* name, const QVector2D& value); bool setUniform(const char* name, const QVector3D& value); bool setUniform(const char* name, const QVector4D& value); bool setUniform(const char* name, const QMatrix4x4& value); bool setUniform(const char* name, const QColor& color); bool setUniform(int location, float value); bool setUniform(int location, int value); bool setUniform(int location, const QVector2D &value); bool setUniform(int location, const QVector3D &value); bool setUniform(int location, const QVector4D &value); bool setUniform(int location, const QMatrix4x4 &value); bool setUniform(int location, const QColor &value); int attributeLocation(const char* name); bool setAttribute(const char* name, float value); /** * @return The value of the uniform as a matrix * @since 4.7 */ QMatrix4x4 getUniformMatrix4x4(const char* name); enum MatrixUniform { TextureMatrix = 0, ProjectionMatrix, ModelViewMatrix, ModelViewProjectionMatrix, WindowTransformation, ScreenTransformation, MatrixCount }; enum Vec2Uniform { Offset, Vec2UniformCount }; enum Vec4Uniform { ModulationConstant, TextureClamp, Vec4UniformCount }; enum FloatUniform { Saturation, FloatUniformCount }; enum IntUniform { AlphaToOne, ///< @deprecated no longer used IntUniformCount }; enum ColorUniform { Color, ColorUniformCount }; bool setUniform(MatrixUniform uniform, const QMatrix4x4 &matrix); bool setUniform(Vec2Uniform uniform, const QVector2D &value); bool setUniform(Vec4Uniform uniform, const QVector4D &value); bool setUniform(FloatUniform uniform, float value); bool setUniform(IntUniform uniform, int value); bool setUniform(ColorUniform uniform, const QVector4D &value); bool setUniform(ColorUniform uniform, const QColor &value); protected: GLShader(unsigned int flags = NoFlags); bool loadFromFiles(const QString& vertexfile, const QString& fragmentfile); bool load(const QByteArray &vertexSource, const QByteArray &fragmentSource); const QByteArray prepareSource(GLenum shaderType, const QByteArray &sourceCode) const; bool compile(GLuint program, GLenum shaderType, const QByteArray &sourceCode) const; void bind(); void unbind(); void resolveLocations(); private: unsigned int mProgram; bool mValid:1; bool mLocationsResolved:1; bool mExplicitLinking:1; int mMatrixLocation[MatrixCount]; int mVec2Location[Vec2UniformCount]; int mVec4Location[Vec4UniformCount]; int mFloatLocation[FloatUniformCount]; int mIntLocation[IntUniformCount]; int mColorLocation[ColorUniformCount]; friend class ShaderManager; }; enum class ShaderTrait { MapTexture = (1 << 0), UniformColor = (1 << 1), Modulate = (1 << 2), AdjustSaturation = (1 << 3), ClampTexture = (1 << 4), }; Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait) /** * @short Manager for Shaders. * * This class provides some built-in shaders to be used by both compositing scene and effects. * The ShaderManager provides methods to bind a built-in or a custom shader and keeps track of * the shaders which have been bound. When a shader is unbound the previously bound shader * will be rebound. * * @author Martin Gräßlin * @since 4.7 */ class KWINGLUTILS_EXPORT ShaderManager { public: /** * Returns a shader with the given traits, creating it if necessary. */ GLShader *shader(ShaderTraits traits); /** * @return The currently bound shader or @c null if no shader is bound. */ GLShader *getBoundShader() const; /** * @return @c true if a shader is bound, @c false otherwise */ bool isShaderBound() const; - /** - * Is @c true if the environment variable KWIN_GL_DEBUG is set to 1. - * In that case shaders are compiled with KWIN_SHADER_DEBUG defined. - * @returns @c true if shaders are compiled with debug information - * @since 4.8 - */ - bool isShaderDebug() const; /** * Pushes the current shader onto the stack and binds a shader * with the given traits. */ GLShader *pushShader(ShaderTraits traits); /** * Binds the @p shader. * To unbind the shader use popShader. A previous bound shader will be rebound. * To bind a built-in shader use the more specific method. * @param shader The shader to be bound * @see popShader */ void pushShader(GLShader *shader); /** * Unbinds the currently bound shader and rebinds a previous stored shader. * If there is no previous shader, no shader will be rebound. * It is not safe to call this method if there is no bound shader. * @see pushShader * @see getBoundShader */ void popShader(); /** * Creates a GLShader with the specified sources. * The difference to GLShader is that it does not need to be loaded from files. * @param vertexSource The source code of the vertex shader * @param fragmentSource The source code of the fragment shader. * @return The created shader */ GLShader *loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource); /** * Creates a custom shader with the given @p traits and custom @p vertexSource and or @p fragmentSource. * If the @p vertexSource is empty a vertex shader with the given @p traits is generated. * If it is not empty the @p vertexSource is used as the source for the vertex shader. * * The same applies for argument @p fragmentSource just for the fragment shader. * * So if both @p vertesSource and @p fragmentSource are provided the @p traits are ignored. * If neither are provided a new shader following the @p traits is generated. * * @param traits The shader traits for generating the shader * @param vertexSource optional vertex shader source code to be used instead of shader traits * @param fragmentSource optional fragment shader source code to be used instead of shader traits * @return new generated shader * @since 5.6 */ GLShader *generateCustomShader(ShaderTraits traits, const QByteArray &vertexSource = QByteArray(), const QByteArray &fragmentSource = QByteArray()); /** * Creates a custom shader with the given @p traits and custom @p vertexFile and or @p fragmentFile. * The file names specified in @p vertexFile and @p fragmentFile are relative paths to the shaders * resource file shipped together with KWin. This means this method can only be used for built-in * effects, for 3rd party effects generateCustomShader should be used. * * If the @p vertexFile is empty a vertex shader with the given @p traits is generated. * If it is not empty the @p vertexFile is used as the source for the vertex shader. * * The same applies for argument @p fragmentFile just for the fragment shader. * * So if both @p vertexFile and @p fragmentFile are provided the @p traits are ignored. * If neither are provided a new shader following the @p traits is generated. * * @param traits The shader traits for generating the shader * @param vertexFile optional vertex shader source code to be used instead of shader traits * @param fragmentFile optional fragment shader source code to be used instead of shader traits * @return new generated shader * @see generateCustomShader * @since 5.6 */ GLShader *generateShaderFromResources(ShaderTraits traits, const QString &vertexFile = QString(), const QString &fragmentFile = QString()); /** * Compiles and tests the dynamically generated shaders. * Returns true if successful and false otherwise. */ bool selfTest(); /** * @return a pointer to the ShaderManager instance */ static ShaderManager *instance(); /** * @internal */ static void cleanup(); private: ShaderManager(); ~ShaderManager(); void bindFragDataLocations(GLShader *shader); void bindAttributeLocations(GLShader *shader) const; QByteArray generateVertexSource(ShaderTraits traits) const; QByteArray generateFragmentSource(ShaderTraits traits) const; GLShader *generateShader(ShaderTraits traits); QStack m_boundShaders; QHash m_shaderHash; - bool m_debug; QString m_resourcePath; static ShaderManager *s_shaderManager; }; /** * An helper class to push a Shader on to ShaderManager's stack and ensuring that the Shader * gets popped again from the stack automatically once the object goes out of life. * * How to use: * @code * { * GLShader *myCustomShaderIWantToPush; * ShaderBinder binder(myCustomShaderIWantToPush); * // do stuff with the shader being pushed on the stack * } * // here the Shader is automatically popped as helper does no longer exist. * @endcode * * @since 4.10 */ class KWINGLUTILS_EXPORT ShaderBinder { public: /** * @brief Pushes the given @p shader to the ShaderManager's stack. * * @param shader The Shader to push on the stack * @see ShaderManager::pushShader */ explicit ShaderBinder(GLShader *shader); /** * @brief Pushes the Shader with the given @p traits to the ShaderManager's stack. * * @param traits The traits describing the shader * @see ShaderManager::pushShader * @since 5.6 */ explicit ShaderBinder(ShaderTraits traits); ~ShaderBinder(); /** * @return The Shader pushed to the Stack. */ GLShader *shader(); private: GLShader *m_shader; }; inline ShaderBinder::ShaderBinder(GLShader *shader) : m_shader(shader) { ShaderManager::instance()->pushShader(shader); } inline ShaderBinder::ShaderBinder(ShaderTraits traits) : m_shader(nullptr) { m_shader = ShaderManager::instance()->pushShader(traits); } inline ShaderBinder::~ShaderBinder() { ShaderManager::instance()->popShader(); } inline GLShader* ShaderBinder::shader() { return m_shader; } /** * @short Render target object * * Render target object enables you to render onto a texture. This texture can * later be used to e.g. do post-processing of the scene. * * @author Rivo Laks */ class KWINGLUTILS_EXPORT GLRenderTarget { public: /** * Constructs a GLRenderTarget * @since 5.13 */ explicit GLRenderTarget(); /** * Constructs a GLRenderTarget * @param color texture where the scene will be rendered onto */ explicit GLRenderTarget(const GLTexture& color); ~GLRenderTarget(); /** * Enables this render target. * All OpenGL commands from now on affect this render target until the * @ref disable method is called */ bool enable(); /** * Disables this render target, activating whichever target was active * when @ref enable was called. */ bool disable(); /** * Sets the target texture * @param target texture where the scene will be rendered on * @since 4.8 */ void attachTexture(const GLTexture& target); /** * Detaches the texture that is currently attached to this framebuffer object. * @since 5.13 */ void detachTexture(); bool valid() const { return mValid; } void setTextureDirty() { mTexture.setDirty(); } static void initStatic(); static bool supported() { return sSupported; } /** * Pushes the render target stack of the input parameter in reverse order. * @param targets The stack of GLRenderTargets * @since 5.13 */ static void pushRenderTargets(QStack targets); static void pushRenderTarget(GLRenderTarget *target); static GLRenderTarget *popRenderTarget(); static bool isRenderTargetBound(); /** * Whether the GL_EXT_framebuffer_blit extension is supported. * This functionality is not available in OpenGL ES 2.0. * * @returns whether framebuffer blitting is supported. * @since 4.8 */ static bool blitSupported(); /** * Blits the content of the current draw framebuffer into the texture attached to this FBO. * * Be aware that framebuffer blitting may not be supported on all hardware. Use blitSupported to check whether * it is supported. * @param source Geometry in screen coordinates which should be blitted, if not specified complete framebuffer is used * @param destination Geometry in attached texture, if not specified complete texture is used as destination * @param filter The filter to use if blitted content needs to be scaled. * @see blitSupported * @since 4.8 */ void blitFromFramebuffer(const QRect &source = QRect(), const QRect &destination = QRect(), GLenum filter = GL_LINEAR); /** * Sets the virtual screen size to @p s. * @since 5.2 */ static void setVirtualScreenSize(const QSize &s) { s_virtualScreenSize = s; } /** * Sets the virtual screen geometry to @p g. * This is the geometry of the OpenGL window currently being rendered to * in the virtual geometry space the rendering geometries use. * @see virtualScreenGeometry * @since 5.9 */ static void setVirtualScreenGeometry(const QRect &g) { s_virtualScreenGeometry = g; } /** * The geometry of the OpenGL window currently being rendered to * in the virtual geometry space the rendering system uses. * @see setVirtualScreenGeometry * @since 5.9 */ static QRect virtualScreenGeometry() { return s_virtualScreenGeometry; } /** * The scale of the OpenGL window currently being rendered to * * @returns the ratio between the virtual geometry space the rendering * system uses and the target * @since 5.10 */ static void setVirtualScreenScale(qreal scale) { s_virtualScreenScale = scale; } static qreal virtualScreenScale() { return s_virtualScreenScale; } /** * The framebuffer of KWin's OpenGL window or other object currently being rendered to * * @since 5.18 */ static void setKWinFramebuffer(GLuint fb) { s_kwinFramebuffer = fb; } protected: void initFBO(); private: friend void KWin::cleanupGL(); static void cleanup(); static bool sSupported; static bool s_blitSupported; static QStack s_renderTargets; static QSize s_virtualScreenSize; static QRect s_virtualScreenGeometry; static qreal s_virtualScreenScale; static GLint s_virtualScreenViewport[4]; static GLuint s_kwinFramebuffer; GLTexture mTexture; bool mValid; GLuint mFramebuffer; }; enum VertexAttributeType { VA_Position = 0, VA_TexCoord = 1, VertexAttributeCount = 2 }; /** * Describes the format of a vertex attribute stored in a buffer object. * * The attribute format consists of the attribute index, the number of * vector components, the data type, and the offset of the first element * relative to the start of the vertex data. */ struct GLVertexAttrib { int index; /** The attribute index */ int size; /** The number of components [1..4] */ GLenum type; /** The type (e.g. GL_FLOAT) */ int relativeOffset; /** The relative offset of the attribute */ }; /** * @short Vertex Buffer Object * * This is a short helper class to use vertex buffer objects (VBO). A VBO can be used to buffer * vertex data and to store them on graphics memory. It is the only allowed way to pass vertex * data to the GPU in OpenGL ES 2 and OpenGL 3 with forward compatible mode. * * If VBOs are not supported on the used OpenGL profile this class falls back to legacy * rendering using client arrays. Therefore this class should always be used for rendering geometries. * * @author Martin Gräßlin * @since 4.6 */ class KWINGLUTILS_EXPORT GLVertexBuffer { public: /** * Enum to define how often the vertex data in the buffer object changes. */ enum UsageHint { Dynamic, ///< frequent changes, but used several times for rendering Static, ///< No changes to data Stream ///< Data only used once for rendering, updated very frequently }; explicit GLVertexBuffer(UsageHint hint); ~GLVertexBuffer(); /** * Specifies how interleaved vertex attributes are laid out in * the buffer object. * * Note that the attributes and the stride should be 32 bit aligned * or a performance penalty may be incurred. * * For some hardware the optimal stride is a multiple of 32 bytes. * * Example: * * struct Vertex { * QVector3D position; * QVector2D texcoord; * }; * * const GLVertexAttrib attribs[] = { * { VA_Position, 3, GL_FLOAT, offsetof(Vertex, position) }, * { VA_TexCoord, 2, GL_FLOAT, offsetof(Vertex, texcoord) } * }; * * Vertex vertices[6]; * vbo->setAttribLayout(attribs, 2, sizeof(Vertex)); * vbo->setData(vertices, sizeof(vertices)); */ void setAttribLayout(const GLVertexAttrib *attribs, int count, int stride); /** * Uploads data into the buffer object's data store. */ void setData(const void *data, size_t sizeInBytes); /** * Sets the number of vertices that will be drawn by the render() method. */ void setVertexCount(int count); /** * Sets the vertex data. * @param numberVertices The number of vertices in the arrays * @param dim The dimension of the vertices: 2 for x/y, 3 for x/y/z * @param vertices The vertices, size must equal @a numberVertices * @a dim * @param texcoords The texture coordinates for each vertex. * Size must equal 2 * @a numberVertices. */ void setData(int numberVertices, int dim, const float* vertices, const float* texcoords); /** * Maps an unused range of the data store into the client's address space. * * The data store will be reallocated if it is smaller than the given size. * * The buffer object is mapped for writing, not reading. Attempts to read from * the mapped buffer range may result in system errors, including program * termination. The data in the mapped region is undefined until it has been * written to. If subsequent GL calls access unwritten memory, the results are * undefined and system errors, including program termination, may occur. * * No GL calls that access the buffer object must be made while the buffer * object is mapped. The returned pointer must not be passed as a parameter * value to any GL function. * * It is assumed that the GL_ARRAY_BUFFER_BINDING will not be changed while * the buffer object is mapped. */ GLvoid *map(size_t size); /** * Flushes the mapped buffer range and unmaps the buffer. */ void unmap(); /** * Binds the vertex arrays to the context. */ void bindArrays(); /** * Disables the vertex arrays. */ void unbindArrays(); /** * Draws count vertices beginning with first. */ void draw(GLenum primitiveMode, int first, int count); /** * Draws count vertices beginning with first. */ void draw(const QRegion ®ion, GLenum primitiveMode, int first, int count, bool hardwareClipping = false); /** * Renders the vertex data in given @a primitiveMode. * Please refer to OpenGL documentation of glDrawArrays or glDrawElements for allowed * values for @a primitiveMode. Best is to use GL_TRIANGLES or similar to be future * compatible. */ void render(GLenum primitiveMode); /** * Same as above restricting painting to @a region if @a hardwareClipping is true. * It's within the caller's responsibility to enable GL_SCISSOR_TEST. */ void render(const QRegion& region, GLenum primitiveMode, bool hardwareClipping = false); /** * Sets the color the geometry will be rendered with. * For legacy rendering glColor is used before rendering the geometry. * For core shader a uniform "geometryColor" is expected and is set. * @param color The color to render the geometry * @param enableColor Whether the geometry should be rendered with a color or not * @see setUseColor * @see isUseColor * @since 4.7 */ void setColor(const QColor& color, bool enableColor = true); /** * @return @c true if geometry will be painted with a color, @c false otherwise * @see setUseColor * @see setColor * @since 4.7 */ bool isUseColor() const; /** * Enables/Disables rendering the geometry with a color. * If no color is set an opaque, black color is used. * @param enable Enable/Disable rendering with color * @see isUseColor * @see setColor * @since 4.7 */ void setUseColor(bool enable); /** * Resets the instance to default values. * Useful for shared buffers. * @since 4.7 */ void reset(); /** * Notifies the vertex buffer that we are done painting the frame. * * @internal */ void endOfFrame(); /** * Notifies the vertex buffer that we have posted the frame. * * @internal */ void framePosted(); /** * @internal */ static void initStatic(); /** * @internal */ static void cleanup(); /** * Returns true if indexed quad mode is supported, and false otherwise. */ static bool supportsIndexedQuads(); /** * @return A shared VBO for streaming data * @since 4.7 */ static GLVertexBuffer *streamingBuffer(); /** * Sets the virtual screen geometry to @p g. * This is the geometry of the OpenGL window currently being rendered to * in the virtual geometry space the rendering geometries use. * @since 5.9 */ static void setVirtualScreenGeometry(const QRect &g) { s_virtualScreenGeometry = g; } /** * The scale of the OpenGL window currently being rendered to * * @returns the ratio between the virtual geometry space the rendering * system uses and the target * @since 5.11.3 */ static void setVirtualScreenScale(qreal s) { s_virtualScreenScale = s; } private: GLVertexBufferPrivate* const d; static QRect s_virtualScreenGeometry; static qreal s_virtualScreenScale; }; } // namespace Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::ShaderTraits) /** @} */ #endif diff --git a/plugins/kdecorations/aurorae/themes/plastik/code/plastikplugin.cpp b/plugins/kdecorations/aurorae/themes/plastik/code/plastikplugin.cpp index 25d11251f..e121d6d94 100644 --- a/plugins/kdecorations/aurorae/themes/plastik/code/plastikplugin.cpp +++ b/plugins/kdecorations/aurorae/themes/plastik/code/plastikplugin.cpp @@ -1,33 +1,31 @@ /******************************************************************** Copyright (C) 2012 Martin Gräßlin 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 "plastikplugin.h" #include "plastikbutton.h" #include void PlastikPlugin::registerTypes(const char *uri) { Q_UNUSED(uri) } void PlastikPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.kwin.decorations.plastik")); engine->addImageProvider(QLatin1String("plastik"), new KWin::PlastikButtonProvider()); QQmlExtensionPlugin::initializeEngine(engine, uri); } - -#include "moc_plastikplugin.cpp" diff --git a/plugins/kpackage/effect/kwin-packagestructure-effect.desktop b/plugins/kpackage/effect/kwin-packagestructure-effect.desktop index 439d4a9d9..b7b8c007b 100644 --- a/plugins/kpackage/effect/kwin-packagestructure-effect.desktop +++ b/plugins/kpackage/effect/kwin-packagestructure-effect.desktop @@ -1,41 +1,42 @@ [Desktop Entry] Name=KWin Effect Name[ca]=Efecte del KWin Name[ca@valencia]=Efecte de KWin Name[cs]=Efekt KWinu Name[da]=KWin-effekt Name[de]=KWin-Effekt Name[el]=Εφέ KWin Name[en_GB]=KWin Effect Name[es]=Efecto de KWin Name[et]=KWini efekt Name[eu]=KWin efektua Name[fi]=KWin-tehoste Name[fr]=Effet KWin Name[gl]=Efecto de KWin Name[hu]=KWin effektus Name[ia]=Effecto de KWin Name[id]=Efek KWin Name[it]=Effetto di KWin Name[ko]=KWin 효과 Name[lt]=KWin efektas Name[nl]=KWin-effect Name[nn]=KWin-effekt Name[pl]=Efekt KWin Name[pt]=Efeito do KWin Name[pt_BR]=Efeito do KWin Name[ru]=Эффект диспетчера окон Name[sk]=Efekty KWin +Name[sl]=Učinek KWin Name[sv]=Kwin-effekt Name[uk]=Ефект KWin Name[x-test]=xxKWin Effectxx Name[zh_CN]=KWin 效果 Name[zh_TW]=KWin 效果 Type=Service X-KDE-ServiceTypes=KPackage/PackageStructure X-KDE-Library=kwin_packagestructure_effect X-KDE-PluginInfo-Author=Vlad Zahorodnii X-KDE-PluginInfo-Email=vlad.zahorodnii@kde.org X-KDE-PluginInfo-Name=KWin/Effect X-KDE-PluginInfo-Version=1 diff --git a/plugins/platforms/wayland/wayland_backend.cpp b/plugins/platforms/wayland/wayland_backend.cpp index c88d08871..2a6bde797 100644 --- a/plugins/platforms/wayland/wayland_backend.cpp +++ b/plugins/platforms/wayland/wayland_backend.cpp @@ -1,840 +1,840 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright 2019 Roman Gilg Copyright 2013 Martin Gräßlin 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 "wayland_backend.h" #if HAVE_WAYLAND_EGL #include "egl_wayland_backend.h" #endif #include "logging.h" #include "scene_qpainter_wayland_backend.h" #include "wayland_output.h" #include "composite.h" #include "cursor.h" #include "input.h" #include "main.h" #include "outputscreens.h" #include "pointer_input.h" #include "screens.h" #include "wayland_cursor_theme.h" #include "wayland_server.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KWin { namespace Wayland { using namespace KWayland::Client; WaylandCursor::WaylandCursor(WaylandBackend *backend) : QObject(backend) , m_backend(backend) { resetSurface(); } void WaylandCursor::resetSurface() { delete m_surface; m_surface = backend()->compositor()->createSurface(this); } void WaylandCursor::init() { installImage(); } WaylandCursor::~WaylandCursor() { delete m_surface; } void WaylandCursor::installImage() { const QImage image = m_backend->softwareCursor(); if (image.isNull() || image.size().isEmpty()) { doInstallImage(nullptr, QSize()); return; } auto buffer = m_backend->shmPool()->createBuffer(image).toStrongRef(); wl_buffer *imageBuffer = *buffer.data(); doInstallImage(imageBuffer, image.size()); } void WaylandCursor::doInstallImage(wl_buffer *image, const QSize &size) { auto *pointer = m_backend->seat()->pointer(); if (!pointer || !pointer->isValid()) { return; } pointer->setCursor(m_surface, image ? m_backend->softwareCursorHotspot() : QPoint()); drawSurface(image, size); } void WaylandCursor::drawSurface(wl_buffer *image, const QSize &size) { m_surface->attachBuffer(image); m_surface->damage(QRect(QPoint(0,0), size)); m_surface->commit(Surface::CommitFlag::None); m_backend->flush(); } WaylandSubSurfaceCursor::WaylandSubSurfaceCursor(WaylandBackend *backend) : WaylandCursor(backend) { } void WaylandSubSurfaceCursor::init() { if (auto *pointer = backend()->seat()->pointer()) { pointer->hideCursor(); } } WaylandSubSurfaceCursor::~WaylandSubSurfaceCursor() { delete m_subSurface; } void WaylandSubSurfaceCursor::changeOutput(WaylandOutput *output) { delete m_subSurface; m_subSurface = nullptr; m_output = output; if (!output) { return; } createSubSurface(); surface()->commit(); } void WaylandSubSurfaceCursor::createSubSurface() { if (m_subSurface) { return; } if (!m_output) { return; } resetSurface(); m_subSurface = backend()->subCompositor()->createSubSurface(surface(), m_output->surface(), this); m_subSurface->setMode(SubSurface::Mode::Desynchronized); } void WaylandSubSurfaceCursor::doInstallImage(wl_buffer *image, const QSize &size) { if (!image) { delete m_subSurface; m_subSurface = nullptr; return; } createSubSurface(); // cursor position might have changed due to different cursor hot spot move(input()->pointer()->pos()); drawSurface(image, size); } QPointF WaylandSubSurfaceCursor::absoluteToRelativePosition(const QPointF &position) { auto ret = position - m_output->geometry().topLeft() - backend()->softwareCursorHotspot(); return ret; } void WaylandSubSurfaceCursor::move(const QPointF &globalPosition) { auto *output = backend()->getOutputAt(globalPosition.toPoint()); if (!m_output || (output && m_output != output)) { changeOutput(output); if (!m_output) { // cursor might be off the grid return; } installImage(); return; } if (!m_subSurface) { return; } // place the sub-surface relative to the output it is on and factor in the hotspot const auto relativePosition = globalPosition.toPoint() - backend()->softwareCursorHotspot() - m_output->geometry().topLeft(); m_subSurface->setPosition(relativePosition); Compositor::self()->addRepaintFull(); } WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend) : QObject(nullptr) , m_seat(new Seat(this)) , m_pointer(nullptr) , m_keyboard(nullptr) , m_touch(nullptr) , m_enteredSerial(0) , m_backend(backend) { m_seat->setup(seat); connect(m_seat, &Seat::hasKeyboardChanged, this, [this](bool hasKeyboard) { if (hasKeyboard) { m_keyboard = m_seat->createKeyboard(this); connect(m_keyboard, &Keyboard::keyChanged, this, [this](quint32 key, Keyboard::KeyState state, quint32 time) { switch (state) { case Keyboard::KeyState::Pressed: if (key == KEY_RIGHTCTRL) { m_backend->togglePointerLock(); } m_backend->keyboardKeyPressed(key, time); break; case Keyboard::KeyState::Released: m_backend->keyboardKeyReleased(key, time); break; default: Q_UNREACHABLE(); } } ); connect(m_keyboard, &Keyboard::modifiersChanged, this, [this](quint32 depressed, quint32 latched, quint32 locked, quint32 group) { m_backend->keyboardModifiers(depressed, latched, locked, group); } ); connect(m_keyboard, &Keyboard::keymapChanged, this, [this](int fd, quint32 size) { m_backend->keymapChange(fd, size); } ); } else { destroyKeyboard(); } } ); connect(m_seat, &Seat::hasPointerChanged, this, [this](bool hasPointer) { if (hasPointer && !m_pointer) { m_pointer = m_seat->createPointer(this); setupPointerGestures(); connect(m_pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) { Q_UNUSED(relativeToSurface) m_enteredSerial = serial; } ); connect(m_pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) { m_backend->pointerMotionRelativeToOutput(relativeToSurface, time); } ); connect(m_pointer, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState state) { Q_UNUSED(serial) switch (state) { case Pointer::ButtonState::Pressed: m_backend->pointerButtonPressed(button, time); break; case Pointer::ButtonState::Released: m_backend->pointerButtonReleased(button, time); break; default: Q_UNREACHABLE(); } } ); // TODO: Send discreteDelta and source as well. connect(m_pointer, &Pointer::axisChanged, this, [this](quint32 time, Pointer::Axis axis, qreal delta) { switch (axis) { case Pointer::Axis::Horizontal: m_backend->pointerAxisHorizontal(delta, time); break; case Pointer::Axis::Vertical: m_backend->pointerAxisVertical(delta, time); break; default: Q_UNREACHABLE(); } } ); } else { destroyPointer(); } } ); connect(m_seat, &Seat::hasTouchChanged, [this] (bool hasTouch) { if (hasTouch && !m_touch) { m_touch = m_seat->createTouch(this); connect(m_touch, &Touch::sequenceCanceled, m_backend, &Platform::touchCancel); connect(m_touch, &Touch::frameEnded, m_backend, &Platform::touchFrame); connect(m_touch, &Touch::sequenceStarted, this, [this] (TouchPoint *tp) { m_backend->touchDown(tp->id(), tp->position(), tp->time()); } ); connect(m_touch, &Touch::pointAdded, this, [this] (TouchPoint *tp) { m_backend->touchDown(tp->id(), tp->position(), tp->time()); } ); connect(m_touch, &Touch::pointRemoved, this, [this] (TouchPoint *tp) { m_backend->touchUp(tp->id(), tp->time()); } ); connect(m_touch, &Touch::pointMoved, this, [this] (TouchPoint *tp) { m_backend->touchMotion(tp->id(), tp->position(), tp->time()); } ); } else { destroyTouch(); } } ); WaylandServer *server = waylandServer(); if (server) { using namespace KWayland::Server; SeatInterface *si = server->seat(); connect(m_seat, &Seat::hasKeyboardChanged, si, &SeatInterface::setHasKeyboard); connect(m_seat, &Seat::hasPointerChanged, si, &SeatInterface::setHasPointer); connect(m_seat, &Seat::hasTouchChanged, si, &SeatInterface::setHasTouch); connect(m_seat, &Seat::nameChanged, si, &SeatInterface::setName); } } void WaylandBackend::pointerMotionRelativeToOutput(const QPointF &position, quint32 time) { auto outputIt = std::find_if(m_outputs.begin(), m_outputs.end(), [this](WaylandOutput *wo) { return wo->surface() == m_seat->pointer()->enteredSurface(); }); Q_ASSERT(outputIt != m_outputs.end()); const QPointF outputPosition = (*outputIt)->geometry().topLeft() + position; Platform::pointerMotion(outputPosition, time); } WaylandSeat::~WaylandSeat() { destroyPointer(); destroyKeyboard(); destroyTouch(); } void WaylandSeat::destroyPointer() { delete m_pinchGesture; m_pinchGesture = nullptr; delete m_swipeGesture; m_swipeGesture = nullptr; delete m_pointer; m_pointer = nullptr; } void WaylandSeat::destroyKeyboard() { delete m_keyboard; m_keyboard = nullptr; } void WaylandSeat::destroyTouch() { delete m_touch; m_touch = nullptr; } void WaylandSeat::setupPointerGestures() { if (!m_pointer || !m_gesturesInterface) { return; } if (m_pinchGesture || m_swipeGesture) { return; } m_pinchGesture = m_gesturesInterface->createPinchGesture(m_pointer, this); m_swipeGesture = m_gesturesInterface->createSwipeGesture(m_pointer, this); connect(m_pinchGesture, &PointerPinchGesture::started, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial); m_backend->processPinchGestureBegin(m_pinchGesture->fingerCount(), time); } ); connect(m_pinchGesture, &PointerPinchGesture::updated, m_backend, [this] (const QSizeF &delta, qreal scale, qreal rotation, quint32 time) { m_backend->processPinchGestureUpdate(scale, rotation, delta, time); } ); connect(m_pinchGesture, &PointerPinchGesture::ended, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial) m_backend->processPinchGestureEnd(time); } ); connect(m_pinchGesture, &PointerPinchGesture::cancelled, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial) m_backend->processPinchGestureCancelled(time); } ); connect(m_swipeGesture, &PointerSwipeGesture::started, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial) m_backend->processSwipeGestureBegin(m_swipeGesture->fingerCount(), time); } ); connect(m_swipeGesture, &PointerSwipeGesture::updated, m_backend, &Platform::processSwipeGestureUpdate); connect(m_swipeGesture, &PointerSwipeGesture::ended, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial) m_backend->processSwipeGestureEnd(time); } ); connect(m_swipeGesture, &PointerSwipeGesture::cancelled, m_backend, [this] (quint32 serial, quint32 time) { Q_UNUSED(serial) m_backend->processSwipeGestureCancelled(time); } ); } WaylandBackend::WaylandBackend(QObject *parent) : Platform(parent) , m_display(nullptr) , m_eventQueue(new EventQueue(this)) , m_registry(new Registry(this)) , m_compositor(new KWayland::Client::Compositor(this)) , m_subCompositor(new KWayland::Client::SubCompositor(this)) , m_shm(new ShmPool(this)) , m_connectionThreadObject(new ConnectionThread(nullptr)) , m_connectionThread(nullptr) { connect(this, &WaylandBackend::connectionFailed, this, &WaylandBackend::initFailed); } WaylandBackend::~WaylandBackend() { if (m_pointerConstraints) { m_pointerConstraints->release(); } delete m_waylandCursor; + m_eventQueue->release(); qDeleteAll(m_outputs); if (m_xdgShell) { m_xdgShell->release(); } m_subCompositor->release(); m_compositor->release(); m_registry->release(); delete m_seat; m_shm->release(); - m_eventQueue->release(); - m_connectionThreadObject->deleteLater(); m_connectionThread->quit(); m_connectionThread->wait(); + m_connectionThreadObject->deleteLater(); qCDebug(KWIN_WAYLAND_BACKEND) << "Destroyed Wayland display"; } void WaylandBackend::init() { connect(m_registry, &Registry::compositorAnnounced, this, [this](quint32 name) { m_compositor->setup(m_registry->bindCompositor(name, 1)); } ); connect(m_registry, &Registry::subCompositorAnnounced, this, [this](quint32 name) { m_subCompositor->setup(m_registry->bindSubCompositor(name, 1)); } ); connect(m_registry, &Registry::seatAnnounced, this, [this](quint32 name) { if (Application::usesLibinput()) { return; } m_seat = new WaylandSeat(m_registry->bindSeat(name, 2), this); } ); connect(m_registry, &Registry::shmAnnounced, this, [this](quint32 name) { m_shm->setup(m_registry->bindShm(name, 1)); } ); connect(m_registry, &Registry::relativePointerManagerUnstableV1Announced, this, [this](quint32 name, quint32 version) { if (m_relativePointerManager) { return; } m_relativePointerManager = m_registry->createRelativePointerManager(name, version, this); if (m_pointerConstraints) { emit pointerLockSupportedChanged(); } } ); connect(m_registry, &Registry::pointerConstraintsUnstableV1Announced, this, [this](quint32 name, quint32 version) { if (m_pointerConstraints) { return; } m_pointerConstraints = m_registry->createPointerConstraints(name, version, this); if (m_relativePointerManager) { emit pointerLockSupportedChanged(); } } ); connect(m_registry, &Registry::interfacesAnnounced, this, &WaylandBackend::createOutputs); connect(m_registry, &Registry::interfacesAnnounced, this, [this] { if (!m_seat) { return; } const auto gi = m_registry->interface(Registry::Interface::PointerGesturesUnstableV1); if (gi.name == 0) { return; } auto gesturesInterface = m_registry->createPointerGestures(gi.name, gi.version, m_seat); m_seat->installGesturesInterface(gesturesInterface); m_waylandCursor = new WaylandCursor(this); } ); if (!deviceIdentifier().isEmpty()) { m_connectionThreadObject->setSocketName(deviceIdentifier()); } connect(this, &WaylandBackend::cursorChanged, this, [this] { if (!m_seat) { return; } m_waylandCursor->installImage(); markCursorAsRendered(); } ); connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) { delete m_waylandCursor; if (locked) { Q_ASSERT(!m_relativePointer); m_waylandCursor = new WaylandSubSurfaceCursor(this); m_waylandCursor->move(input()->pointer()->pos()); m_relativePointer = m_relativePointerManager->createRelativePointer(m_seat->pointer(), this); if (!m_relativePointer->isValid()) { return; } connect(m_relativePointer, &RelativePointer::relativeMotion, this, &WaylandBackend::relativeMotionHandler); } else { delete m_relativePointer; m_relativePointer = nullptr; m_waylandCursor = new WaylandCursor(this); } m_waylandCursor->init(); }); initConnection(); } void WaylandBackend::relativeMotionHandler(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp) { Q_UNUSED(deltaNonAccelerated) Q_ASSERT(m_waylandCursor); const auto oldGlobalPos = input()->pointer()->pos(); const QPointF newPos = oldGlobalPos + QPointF(delta.width(), delta.height()); m_waylandCursor->move(newPos); Platform::pointerMotion(newPos, timestamp); } void WaylandBackend::initConnection() { connect(m_connectionThreadObject, &ConnectionThread::connected, this, [this]() { // create the event queue for the main gui thread m_display = m_connectionThreadObject->display(); m_eventQueue->setup(m_connectionThreadObject); m_registry->setEventQueue(m_eventQueue); // setup registry m_registry->create(m_display); m_registry->setup(); }, Qt::QueuedConnection); connect(m_connectionThreadObject, &ConnectionThread::connectionDied, this, [this]() { setReady(false); emit systemCompositorDied(); delete m_seat; m_shm->destroy(); qDeleteAll(m_outputs); m_outputs.clear(); if (m_xdgShell) { m_xdgShell->destroy(); } m_subCompositor->destroy(); m_compositor->destroy(); m_registry->destroy(); m_eventQueue->destroy(); if (m_display) { m_display = nullptr; } }, Qt::QueuedConnection); connect(m_connectionThreadObject, &ConnectionThread::failed, this, &WaylandBackend::connectionFailed, Qt::QueuedConnection); m_connectionThread = new QThread(this); m_connectionThreadObject->moveToThread(m_connectionThread); m_connectionThread->start(); m_connectionThreadObject->initConnection(); } void WaylandBackend::updateScreenSize(WaylandOutput *output) { auto it = std::find(m_outputs.begin(), m_outputs.end(), output); int nextLogicalPosition = output->geometry().topRight().x(); while (++it != m_outputs.end()) { const QRect geo = (*it)->geometry(); (*it)->setGeometry(QPoint(nextLogicalPosition, 0), geo.size()); nextLogicalPosition = geo.topRight().x(); } } void WaylandBackend::createOutputs() { using namespace KWayland::Client; const auto ssdManagerIface = m_registry->interface(Registry::Interface::ServerSideDecorationManager); ServerSideDecorationManager *ssdManager = ssdManagerIface.name == 0 ? nullptr : m_registry->createServerSideDecorationManager(ssdManagerIface.name, ssdManagerIface.version, this); const auto xdgIface = m_registry->interface(Registry::Interface::XdgShellStable); if (xdgIface.name != 0) { m_xdgShell = m_registry->createXdgShell(xdgIface.name, xdgIface.version, this); } // we need to multiply the initial window size with the scale in order to // create an output window of this size in the end const int pixelWidth = initialWindowSize().width() * initialOutputScale() + 0.5; const int pixelHeight = initialWindowSize().height() * initialOutputScale() + 0.5; const int logicalWidth = initialWindowSize().width(); int logicalWidthSum = 0; for (int i = 0; i < initialOutputCount(); i++) { auto surface = m_compositor->createSurface(this); if (!surface || !surface->isValid()) { qCCritical(KWIN_WAYLAND_BACKEND) << "Creating Wayland Surface failed"; return; } if (ssdManager) { auto decoration = ssdManager->create(surface, this); connect(decoration, &ServerSideDecoration::modeChanged, this, [decoration] { if (decoration->mode() != ServerSideDecoration::Mode::Server) { decoration->requestMode(ServerSideDecoration::Mode::Server); } } ); } WaylandOutput *waylandOutput = nullptr; if (m_xdgShell && m_xdgShell->isValid()) { waylandOutput = new XdgShellOutput(surface, m_xdgShell, this, i+1); } if (!waylandOutput) { qCCritical(KWIN_WAYLAND_BACKEND) << "Binding to all shell interfaces failed for output" << i; return; } waylandOutput->init(QPoint(logicalWidthSum, 0), QSize(pixelWidth, pixelHeight)); connect(waylandOutput, &WaylandOutput::sizeChanged, this, [this, waylandOutput](const QSize &size) { Q_UNUSED(size) updateScreenSize(waylandOutput); Compositor::self()->addRepaintFull(); }); connect(waylandOutput, &WaylandOutput::frameRendered, this, &WaylandBackend::checkBufferSwap); logicalWidthSum += logicalWidth; m_outputs << waylandOutput; } setReady(true); emit screensQueried(); } Screens *WaylandBackend::createScreens(QObject *parent) { return new OutputScreens(this, parent); } OpenGLBackend *WaylandBackend::createOpenGLBackend() { #if HAVE_WAYLAND_EGL return new EglWaylandBackend(this); #else return nullptr; #endif } QPainterBackend *WaylandBackend::createQPainterBackend() { return new WaylandQPainterBackend(this); } void WaylandBackend::checkBufferSwap() { const bool allRendered = std::all_of(m_outputs.begin(), m_outputs.end(), [](WaylandOutput *o) { return o->rendered(); }); if (!allRendered) { // need to wait more // TODO: what if one does not need to be rendered (no damage)? return; } for (auto *output : m_outputs) { if (!output->rendered()) { return; } } Compositor::self()->bufferSwapComplete(); for (auto *output : m_outputs) { output->resetRendered(); } } void WaylandBackend::flush() { if (m_connectionThreadObject) { m_connectionThreadObject->flush(); } } WaylandOutput* WaylandBackend::getOutputAt(const QPointF globalPosition) { const auto pos = globalPosition.toPoint(); auto checkPosition = [pos](WaylandOutput *output) { return output->geometry().contains(pos); }; auto it = std::find_if(m_outputs.begin(), m_outputs.end(), checkPosition); return it == m_outputs.end() ? nullptr : *it; } bool WaylandBackend::supportsPointerLock() { return m_pointerConstraints && m_relativePointerManager; } void WaylandBackend::togglePointerLock() { if (!m_pointerConstraints) { return; } if (!m_relativePointerManager) { return; } if (!m_seat) { return; } auto pointer = m_seat->pointer(); if (!pointer) { return; } if (m_outputs.isEmpty()) { return; } for (auto output : m_outputs) { output->lockPointer(m_seat->pointer(), !m_pointerLockRequested); } m_pointerLockRequested = !m_pointerLockRequested; flush(); } bool WaylandBackend::pointerIsLocked() { for (auto *output : m_outputs) { if (output->pointerIsLocked()) { return true; } } return false; } QVector WaylandBackend::supportedCompositors() const { if (selectedCompositor() != NoCompositing) { return {selectedCompositor()}; } #if HAVE_WAYLAND_EGL return QVector{OpenGLCompositing, QPainterCompositing}; #else return QVector{QPainterCompositing}; #endif } Outputs WaylandBackend::outputs() const { return m_outputs; } Outputs WaylandBackend::enabledOutputs() const { // all outputs are enabled return m_outputs; } } } // KWin diff --git a/utils.cpp b/utils.cpp index 53864a34d..6323e248d 100644 --- a/utils.cpp +++ b/utils.cpp @@ -1,206 +1,206 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 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 . *********************************************************************/ /* This file is for (very) small utility functions/classes. */ #include "utils.h" #include #include #ifndef KCMRULES #include #include #include "atoms.h" #include "platform.h" #include "workspace.h" #include #include #endif Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core", QtCriticalMsg) Q_LOGGING_CATEGORY(KWIN_VIRTUALKEYBOARD, "kwin_virtualkeyboard", QtCriticalMsg) namespace KWin { #ifndef KCMRULES //************************************ // StrutRect //************************************ StrutRect::StrutRect(QRect rect, StrutArea area) : QRect(rect) , m_area(area) { } StrutRect::StrutRect(const StrutRect& other) : QRect(other) , m_area(other.area()) { } StrutRect &StrutRect::operator=(const StrutRect &other) { if (this != &other) { QRect::operator=(other); m_area = other.area(); } return *this; } #endif +Process::Process(QObject *parent) + : QProcess(parent) +{ +} + +Process::~Process() = default; + #ifndef KCMRULES void updateXTime() { kwinApp()->platform()->updateXTime(); } static int server_grab_count = 0; void grabXServer() { if (++server_grab_count == 1) xcb_grab_server(connection()); } void ungrabXServer() { Q_ASSERT(server_grab_count > 0); if (--server_grab_count == 0) { xcb_ungrab_server(connection()); xcb_flush(connection()); } } static bool keyboard_grabbed = false; bool grabXKeyboard(xcb_window_t w) { if (QWidget::keyboardGrabber() != nullptr) return false; if (keyboard_grabbed) return false; if (qApp->activePopupWidget() != nullptr) return false; if (w == XCB_WINDOW_NONE) w = rootWindow(); const xcb_grab_keyboard_cookie_t c = xcb_grab_keyboard_unchecked(connection(), false, w, xTime(), XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); ScopedCPointer grab(xcb_grab_keyboard_reply(connection(), c, nullptr)); if (grab.isNull()) { return false; } if (grab->status != XCB_GRAB_STATUS_SUCCESS) { return false; } keyboard_grabbed = true; return true; } void ungrabXKeyboard() { if (!keyboard_grabbed) { // grabXKeyboard() may fail sometimes, so don't fail, but at least warn anyway qCDebug(KWIN_CORE) << "ungrabXKeyboard() called but keyboard not grabbed!"; } keyboard_grabbed = false; xcb_ungrab_keyboard(connection(), XCB_TIME_CURRENT_TIME); } -Process::Process(QObject *parent) - : QProcess(parent) -{ -} - -Process::~Process() = default; - void Process::setupChildProcess() { sigset_t userSiganls; sigemptyset(&userSiganls); sigaddset(&userSiganls, SIGUSR1); sigaddset(&userSiganls, SIGUSR2); pthread_sigmask(SIG_UNBLOCK, &userSiganls, nullptr); } #endif // converting between X11 mouse/keyboard state mask and Qt button/keyboard states Qt::MouseButton x11ToQtMouseButton(int button) { if (button == XCB_BUTTON_INDEX_1) return Qt::LeftButton; if (button == XCB_BUTTON_INDEX_2) return Qt::MidButton; if (button == XCB_BUTTON_INDEX_3) return Qt::RightButton; if (button == XCB_BUTTON_INDEX_4) return Qt::XButton1; if (button == XCB_BUTTON_INDEX_5) return Qt::XButton2; return Qt::NoButton; } Qt::MouseButtons x11ToQtMouseButtons(int state) { Qt::MouseButtons ret = {}; if (state & XCB_KEY_BUT_MASK_BUTTON_1) ret |= Qt::LeftButton; if (state & XCB_KEY_BUT_MASK_BUTTON_2) ret |= Qt::MidButton; if (state & XCB_KEY_BUT_MASK_BUTTON_3) ret |= Qt::RightButton; if (state & XCB_KEY_BUT_MASK_BUTTON_4) ret |= Qt::XButton1; if (state & XCB_KEY_BUT_MASK_BUTTON_5) ret |= Qt::XButton2; return ret; } Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state) { Qt::KeyboardModifiers ret = {}; if (state & XCB_KEY_BUT_MASK_SHIFT) ret |= Qt::ShiftModifier; if (state & XCB_KEY_BUT_MASK_CONTROL) ret |= Qt::ControlModifier; if (state & KKeyServer::modXAlt()) ret |= Qt::AltModifier; if (state & KKeyServer::modXMeta()) ret |= Qt::MetaModifier; return ret; } } // namespace #ifndef KCMRULES #endif diff --git a/utils.h b/utils.h index 0271967ce..a0b36d413 100644 --- a/utils.h +++ b/utils.h @@ -1,207 +1,209 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 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_UTILS_H #define KWIN_UTILS_H // cmake stuff #include #include // kwin #include // Qt #include #include #include #include #include #include // system #include Q_DECLARE_LOGGING_CATEGORY(KWIN_CORE) Q_DECLARE_LOGGING_CATEGORY(KWIN_VIRTUALKEYBOARD) namespace KWin { const QPoint invalidPoint(INT_MIN, INT_MIN); enum Layer { UnknownLayer = -1, FirstLayer = 0, DesktopLayer = FirstLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer, NotificationLayer, // layer for windows of type notification ActiveLayer, // active fullscreen, or active dialog CriticalNotificationLayer, // layer for notifications that should be shown even on top of fullscreen OnScreenDisplayLayer, // layer for On Screen Display windows such as volume feedback UnmanagedLayer, // layer for override redirect windows. NumLayers // number of layers, must be last }; enum StrutArea { StrutAreaInvalid = 0, // Null StrutAreaTop = 1 << 0, StrutAreaRight = 1 << 1, StrutAreaBottom = 1 << 2, StrutAreaLeft = 1 << 3, StrutAreaAll = StrutAreaTop | StrutAreaRight | StrutAreaBottom | StrutAreaLeft }; Q_DECLARE_FLAGS(StrutAreas, StrutArea) class StrutRect : public QRect { public: explicit StrutRect(QRect rect = QRect(), StrutArea area = StrutAreaInvalid); StrutRect(const StrutRect& other); StrutRect &operator=(const StrutRect& other); inline StrutArea area() const { return m_area; } private: StrutArea m_area; }; typedef QVector StrutRects; enum ShadeMode { ShadeNone, // not shaded ShadeNormal, // normally shaded - isShade() is true only here ShadeHover, // "shaded", but visible due to hover unshade ShadeActivated // "shaded", but visible due to alt+tab to the window }; /** * Maximize mode. These values specify how a window is maximized. * * @note these values are written to session files, don't change the order */ enum MaximizeMode { MaximizeRestore = 0, ///< The window is not maximized in any direction. MaximizeVertical = 1, ///< The window is maximized vertically. MaximizeHorizontal = 2, ///< The window is maximized horizontally. /// Equal to @p MaximizeVertical | @p MaximizeHorizontal MaximizeFull = MaximizeVertical | MaximizeHorizontal }; inline MaximizeMode operator^(MaximizeMode m1, MaximizeMode m2) { return MaximizeMode(int(m1) ^ int(m2)); } enum class QuickTileFlag { None = 0, Left = 1 << 0, Right = 1 << 1, Top = 1 << 2, Bottom = 1 << 3, Horizontal = Left | Right, Vertical = Top | Bottom, Maximize = Left | Right | Top | Bottom, }; Q_DECLARE_FLAGS(QuickTileMode, QuickTileFlag) template using ScopedCPointer = QScopedPointer; void KWIN_EXPORT updateXTime(); void KWIN_EXPORT grabXServer(); void KWIN_EXPORT ungrabXServer(); bool KWIN_EXPORT grabXKeyboard(xcb_window_t w = XCB_WINDOW_NONE); void KWIN_EXPORT ungrabXKeyboard(); /** * Small helper class which performs grabXServer in the ctor and * ungrabXServer in the dtor. Use this class to ensure that grab and * ungrab are matched. */ class XServerGrabber { public: XServerGrabber() { grabXServer(); } ~XServerGrabber() { ungrabXServer(); } }; // the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint #ifndef UrgencyHint #define UrgencyHint XUrgencyHint #endif // converting between X11 mouse/keyboard state mask and Qt button/keyboard states Qt::MouseButton x11ToQtMouseButton(int button); Qt::MouseButton KWIN_EXPORT x11ToQtMouseButton(int button); Qt::MouseButtons KWIN_EXPORT x11ToQtMouseButtons(int state); Qt::KeyboardModifiers KWIN_EXPORT x11ToQtKeyboardModifiers(int state); /** * Separate the concept of an unet QPoint and 0,0 */ class ClearablePoint { public: inline bool isValid() const { return m_valid; } inline void clear(){ m_valid = false; } inline void setPoint(const QPoint &point) { m_point = point; m_valid = true; } inline QPoint point() const { return m_point; } private: QPoint m_point; bool m_valid = false; }; /** * QProcess subclass which unblocks SIGUSR in the child process. */ class KWIN_EXPORT Process : public QProcess { Q_OBJECT public: explicit Process(QObject *parent = nullptr); ~Process() override; +#ifndef KCMRULES protected: void setupChildProcess() override; +#endif }; } // namespace // Must be outside namespace Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::StrutAreas) Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::QuickTileMode) #endif diff --git a/wayland_server.cpp b/wayland_server.cpp index 0814396a0..a84abcce1 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -1,791 +1,826 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2015 Martin Gräßlin 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 "wayland_server.h" #include "x11client.h" #include "platform.h" #include "composite.h" #include "idle_inhibition.h" #include "screens.h" #include "xdgshellclient.h" #include "workspace.h" // Client #include #include #include #include #include #include #include #include // Server #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KF #include // Qt #include #include #include #include #include // system #include #include #include //screenlocker #include using namespace KWayland::Server; namespace KWin { KWIN_SINGLETON_FACTORY(WaylandServer) WaylandServer::WaylandServer(QObject *parent) : QObject(parent) { qRegisterMetaType(); } WaylandServer::~WaylandServer() { destroyInputMethodConnection(); } void WaylandServer::destroyInternalConnection() { emit terminatingInternalClientConnection(); if (m_internalConnection.client) { // delete all connections hold by plugins like e.g. widget style const auto connections = KWayland::Client::ConnectionThread::connections(); for (auto c : connections) { if (c == m_internalConnection.client) { continue; } emit c->connectionDied(); } delete m_internalConnection.registry; delete m_internalConnection.compositor; delete m_internalConnection.seat; delete m_internalConnection.ddm; delete m_internalConnection.shm; dispatch(); m_internalConnection.client->deleteLater(); m_internalConnection.clientThread->quit(); m_internalConnection.clientThread->wait(); delete m_internalConnection.clientThread; m_internalConnection.client = nullptr; m_internalConnection.server->destroy(); m_internalConnection.server = nullptr; } } void WaylandServer::terminateClientConnections() { destroyInternalConnection(); destroyInputMethodConnection(); if (m_display) { const auto connections = m_display->connections(); for (auto it = connections.begin(); it != connections.end(); ++it) { (*it)->destroy(); } } } template void WaylandServer::createSurface(T *surface) { if (!Workspace::self()) { // it's possible that a Surface gets created before Workspace is created return; } if (surface->client() == m_xwayland.client) { // skip Xwayland clients, those are created using standard X11 way return; } if (surface->client() == m_screenLockerClientConnection) { ScreenLocker::KSldApp::self()->lockScreenShown(); } XdgShellClient *client = new XdgShellClient(surface); if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) { client->installServerSideDecoration(deco); } auto it = std::find_if(m_plasmaShellSurfaces.begin(), m_plasmaShellSurfaces.end(), [client] (PlasmaShellSurfaceInterface *surface) { return client->surface() == surface->surface(); } ); if (it != m_plasmaShellSurfaces.end()) { client->installPlasmaShellSurface(*it); m_plasmaShellSurfaces.erase(it); } if (auto menu = m_appMenuManager->appMenuForSurface(surface->surface())) { client->installAppMenu(menu); } if (auto palette = m_paletteManager->paletteForSurface(surface->surface())) { client->installPalette(palette); } m_clients << client; if (client->readyForPainting()) { emit shellClientAdded(client); } else { connect(client, &XdgShellClient::windowShown, this, &WaylandServer::shellClientShown); } //not directly connected as the connection is tied to client instead of this connect(m_XdgForeign, &KWayland::Server::XdgForeignInterface::transientChanged, client, [this](KWayland::Server::SurfaceInterface *child) { emit foreignTransientChanged(child); }); } class KWinDisplay : public KWayland::Server::FilteredDisplay { public: KWinDisplay(QObject *parent) : KWayland::Server::FilteredDisplay(parent) {} static QByteArray sha256(const QString &fileName) { QFile f(fileName); if (f.open(QFile::ReadOnly)) { QCryptographicHash hash(QCryptographicHash::Sha256); if (hash.addData(&f)) { return hash.result(); } } return QByteArray(); } bool isTrustedOrigin(KWayland::Server::ClientConnection *client) const { const auto fullPathSha = sha256(client->executablePath()); const auto localSha = sha256(QLatin1String("/proc/") + QString::number(client->processId()) + QLatin1String("/exe")); const bool trusted = !localSha.isEmpty() && fullPathSha == localSha; if (!trusted) { qCWarning(KWIN_CORE) << "Could not trust" << client->executablePath() << "sha" << localSha << fullPathSha; } return trusted; } QStringList fetchRequestedInterfaces(KWayland::Server::ClientConnection *client) const { const auto serviceQuery = QStringLiteral("exist Exec and exist [X-KDE-Wayland-Interfaces] and '%1' =~ Exec").arg(client->executablePath()); const auto servicesFound = KServiceTypeTrader::self()->query(QStringLiteral("Application"), serviceQuery); if (servicesFound.isEmpty()) { qCDebug(KWIN_CORE) << "Could not find the desktop file for" << client->executablePath(); return {}; } const auto interfaces = servicesFound.first()->property("X-KDE-Wayland-Interfaces").toStringList(); qCDebug(KWIN_CORE) << "Interfaces for" << client->executablePath() << interfaces; return interfaces; } QSet interfacesBlackList = {"org_kde_kwin_remote_access_manager", "org_kde_plasma_window_management", "org_kde_kwin_fake_input", "org_kde_kwin_keystate"}; bool allowInterface(KWayland::Server::ClientConnection *client, const QByteArray &interfaceName) override { if (client->processId() == getpid()) { return true; } if (!interfacesBlackList.contains(interfaceName)) { return true; } if (client->executablePath().isEmpty()) { qCWarning(KWIN_CORE) << "Could not identify process with pid" << client->processId(); return false; } { auto requestedInterfaces = client->property("requestedInterfaces"); if (requestedInterfaces.isNull()) { requestedInterfaces = fetchRequestedInterfaces(client); client->setProperty("requestedInterfaces", requestedInterfaces); } if (!requestedInterfaces.toStringList().contains(QString::fromUtf8(interfaceName))) { qCWarning(KWIN_CORE) << "Did not grant the interface" << interfaceName << "to" << client->executablePath() << ". Please request it under X-KDE-Wayland-Interfaces"; return false; } } { auto trustedOrigin = client->property("isPrivileged"); if (trustedOrigin.isNull()) { trustedOrigin = isTrustedOrigin(client); client->setProperty("isPrivileged", trustedOrigin); } if (!trustedOrigin.toBool()) { return false; } } qCDebug(KWIN_CORE) << "authorized" << client->executablePath() << interfaceName; return true; } }; bool WaylandServer::init(const QByteArray &socketName, InitializationFlags flags) { m_initFlags = flags; m_display = new KWinDisplay(this); if (!socketName.isNull() && !socketName.isEmpty()) { m_display->setSocketName(QString::fromUtf8(socketName)); } else { m_display->setAutomaticSocketNaming(true); } m_display->start(); if (!m_display->isRunning()) { return false; } m_compositor = m_display->createCompositor(m_display); m_compositor->create(); connect(m_compositor, &CompositorInterface::surfaceCreated, this, [this] (SurfaceInterface *surface) { // check whether we have a Toplevel with the Surface's id Workspace *ws = Workspace::self(); if (!ws) { // it's possible that a Surface gets created before Workspace is created return; } if (surface->client() != xWaylandConnection()) { // setting surface is only relevat for Xwayland clients return; } auto check = [surface] (const Toplevel *t) { return t->surfaceId() == surface->id(); }; if (Toplevel *t = ws->findToplevel(check)) { t->setSurface(surface); } } ); m_tabletManager = m_display->createTabletManagerInterface(m_display); m_xdgShell = m_display->createXdgShell(XdgShellInterfaceVersion::Stable, m_display); m_xdgShell->create(); connect(m_xdgShell, &XdgShellInterface::surfaceCreated, this, &WaylandServer::createSurface); connect(m_xdgShell, &XdgShellInterface::xdgPopupCreated, this, &WaylandServer::createSurface); m_xdgDecorationManager = m_display->createXdgDecorationManager(m_xdgShell, m_display); m_xdgDecorationManager->create(); connect(m_xdgDecorationManager, &XdgDecorationManagerInterface::xdgDecorationInterfaceCreated, this, [this] (XdgDecorationInterface *deco) { if (XdgShellClient *client = findXdgShellClient(deco->surface()->surface())) { client->installXdgDecoration(deco); } }); m_display->createShm(); m_seat = m_display->createSeat(m_display); m_seat->create(); m_display->createPointerGestures(PointerGesturesInterfaceVersion::UnstableV1, m_display)->create(); m_display->createPointerConstraints(PointerConstraintsInterfaceVersion::UnstableV1, m_display)->create(); m_dataDeviceManager = m_display->createDataDeviceManager(m_display); m_dataDeviceManager->create(); m_idle = m_display->createIdle(m_display); m_idle->create(); auto idleInhibition = new IdleInhibition(m_idle); connect(this, &WaylandServer::shellClientAdded, idleInhibition, &IdleInhibition::registerClient); m_display->createIdleInhibitManager(IdleInhibitManagerInterfaceVersion::UnstableV1, m_display)->create(); m_plasmaShell = m_display->createPlasmaShell(m_display); m_plasmaShell->create(); connect(m_plasmaShell, &PlasmaShellInterface::surfaceCreated, [this] (PlasmaShellSurfaceInterface *surface) { if (XdgShellClient *client = findXdgShellClient(surface->surface())) { client->installPlasmaShellSurface(surface); } else { m_plasmaShellSurfaces << surface; connect(surface, &QObject::destroyed, this, [this, surface] { m_plasmaShellSurfaces.removeOne(surface); } ); } } ); m_appMenuManager = m_display->createAppMenuManagerInterface(m_display); m_appMenuManager->create(); connect(m_appMenuManager, &AppMenuManagerInterface::appMenuCreated, [this] (AppMenuInterface *appMenu) { if (XdgShellClient *client = findXdgShellClient(appMenu->surface())) { client->installAppMenu(appMenu); } } ); m_paletteManager = m_display->createServerSideDecorationPaletteManager(m_display); m_paletteManager->create(); connect(m_paletteManager, &ServerSideDecorationPaletteManagerInterface::paletteCreated, [this] (ServerSideDecorationPaletteInterface *palette) { if (XdgShellClient *client = findXdgShellClient(palette->surface())) { client->installPalette(palette); } } ); m_windowManagement = m_display->createPlasmaWindowManagement(m_display); m_windowManagement->create(); m_windowManagement->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Disabled); connect(m_windowManagement, &PlasmaWindowManagementInterface::requestChangeShowingDesktop, this, [] (PlasmaWindowManagementInterface::ShowingDesktopState state) { if (!workspace()) { return; } bool set = false; switch (state) { case PlasmaWindowManagementInterface::ShowingDesktopState::Disabled: set = false; break; case PlasmaWindowManagementInterface::ShowingDesktopState::Enabled: set = true; break; default: Q_UNREACHABLE(); break; } if (set == workspace()->showingDesktop()) { return; } workspace()->setShowingDesktop(set); } ); m_virtualDesktopManagement = m_display->createPlasmaVirtualDesktopManagement(m_display); m_virtualDesktopManagement->create(); m_windowManagement->setPlasmaVirtualDesktopManagementInterface(m_virtualDesktopManagement); auto shadowManager = m_display->createShadowManager(m_display); shadowManager->create(); m_display->createDpmsManager(m_display)->create(); m_decorationManager = m_display->createServerSideDecorationManager(m_display); connect(m_decorationManager, &ServerSideDecorationManagerInterface::decorationCreated, this, [this] (ServerSideDecorationInterface *deco) { if (XdgShellClient *c = findXdgShellClient(deco->surface())) { c->installServerSideDecoration(deco); } connect(deco, &ServerSideDecorationInterface::modeRequested, this, [deco] (ServerSideDecorationManagerInterface::Mode mode) { // always acknowledge the requested mode deco->setMode(mode); } ); } ); m_decorationManager->create(); m_outputManagement = m_display->createOutputManagement(m_display); connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested, this, [](KWayland::Server::OutputConfigurationInterface *config) { kwinApp()->platform()->requestOutputsChange(config); }); m_outputManagement->create(); m_xdgOutputManager = m_display->createXdgOutputManager(m_display); m_xdgOutputManager->create(); m_display->createSubCompositor(m_display)->create(); m_XdgForeign = m_display->createXdgForeignInterface(m_display); m_XdgForeign->create(); m_keyState = m_display->createKeyStateInterface(m_display); m_keyState->create(); return true; } KWayland::Server::LinuxDmabufUnstableV1Interface *WaylandServer::linuxDmabuf() { if (!m_linuxDmabuf) { m_linuxDmabuf = m_display->createLinuxDmabufInterface(m_display); m_linuxDmabuf->create(); } return m_linuxDmabuf; } SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface *surface) { return m_XdgForeign->transientFor(surface); } void WaylandServer::shellClientShown(Toplevel *t) { XdgShellClient *c = dynamic_cast(t); if (!c) { qCWarning(KWIN_CORE) << "Failed to cast a Toplevel which is supposed to be a XdgShellClient to XdgShellClient"; return; } disconnect(c, &XdgShellClient::windowShown, this, &WaylandServer::shellClientShown); emit shellClientAdded(c); } void WaylandServer::initWorkspace() { VirtualDesktopManager::self()->setVirtualDesktopManagement(m_virtualDesktopManagement); if (m_windowManagement) { connect(workspace(), &Workspace::showingDesktopChanged, this, [this] (bool set) { using namespace KWayland::Server; m_windowManagement->setShowingDesktopState(set ? PlasmaWindowManagementInterface::ShowingDesktopState::Enabled : PlasmaWindowManagementInterface::ShowingDesktopState::Disabled ); } ); } if (hasScreenLockerIntegration()) { if (m_internalConnection.interfacesAnnounced) { initScreenLocker(); } else { connect(m_internalConnection.registry, &KWayland::Client::Registry::interfacesAnnounced, this, &WaylandServer::initScreenLocker); } } else { emit initialized(); } } void WaylandServer::initScreenLocker() { - ScreenLocker::KSldApp::self(); - ScreenLocker::KSldApp::self()->setWaylandDisplay(m_display); + auto *screenLockerApp = ScreenLocker::KSldApp::self(); + ScreenLocker::KSldApp::self()->setGreeterEnvironment(kwinApp()->processStartupEnvironment()); ScreenLocker::KSldApp::self()->initialize(); - connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::greeterClientConnectionChanged, this, - [this] () { - m_screenLockerClientConnection = ScreenLocker::KSldApp::self()->greeterClientConnection(); + connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::aboutToLock, this, + [this, screenLockerApp] () { + if (m_screenLockerClientConnection) { + // Already sent data to KScreenLocker. + return; + } + int clientFd = createScreenLockerConnection(); + if (clientFd < 0) { + return; + } + ScreenLocker::KSldApp::self()->setWaylandFd(clientFd); + + for (auto *seat : m_display->seats()) { + connect(seat, &KWayland::Server::SeatInterface::timestampChanged, + screenLockerApp, &ScreenLocker::KSldApp::userActivity); + } } ); connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::unlocked, this, - [this] () { - m_screenLockerClientConnection = nullptr; + [this, screenLockerApp] () { + if (m_screenLockerClientConnection) { + m_screenLockerClientConnection->destroy(); + delete m_screenLockerClientConnection; + m_screenLockerClientConnection = nullptr; + } + + for (auto *seat : m_display->seats()) { + disconnect(seat, &KWayland::Server::SeatInterface::timestampChanged, + screenLockerApp, &ScreenLocker::KSldApp::userActivity); + } + ScreenLocker::KSldApp::self()->setWaylandFd(-1); } ); if (m_initFlags.testFlag(InitializationFlag::LockScreen)) { ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate); } emit initialized(); } WaylandServer::SocketPairConnection WaylandServer::createConnection() { SocketPairConnection ret; int sx[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) { qCWarning(KWIN_CORE) << "Could not create socket"; return ret; } ret.connection = m_display->createClient(sx[0]); ret.fd = sx[1]; return ret; } +int WaylandServer::createScreenLockerConnection() +{ + const auto socket = createConnection(); + if (!socket.connection) { + return -1; + } + m_screenLockerClientConnection = socket.connection; + connect(m_screenLockerClientConnection, &KWayland::Server::ClientConnection::disconnected, + this, [this] { m_screenLockerClientConnection = nullptr; }); + return socket.fd; +} + int WaylandServer::createXWaylandConnection() { const auto socket = createConnection(); if (!socket.connection) { return -1; } m_xwayland.client = socket.connection; m_xwayland.destroyConnection = connect(m_xwayland.client, &KWayland::Server::ClientConnection::disconnected, this, [] { qFatal("Xwayland Connection died"); } ); return socket.fd; } void WaylandServer::destroyXWaylandConnection() { if (!m_xwayland.client) { return; } disconnect(m_xwayland.destroyConnection); m_xwayland.client->destroy(); m_xwayland.client = nullptr; } int WaylandServer::createInputMethodConnection() { const auto socket = createConnection(); if (!socket.connection) { return -1; } m_inputMethodServerConnection = socket.connection; return socket.fd; } void WaylandServer::destroyInputMethodConnection() { if (!m_inputMethodServerConnection) { return; } m_inputMethodServerConnection->destroy(); m_inputMethodServerConnection = nullptr; } void WaylandServer::createInternalConnection() { const auto socket = createConnection(); if (!socket.connection) { return; } m_internalConnection.server = socket.connection; using namespace KWayland::Client; m_internalConnection.client = new ConnectionThread(); m_internalConnection.client->setSocketFd(socket.fd); m_internalConnection.clientThread = new QThread; m_internalConnection.client->moveToThread(m_internalConnection.clientThread); m_internalConnection.clientThread->start(); connect(m_internalConnection.client, &ConnectionThread::connected, this, [this] { Registry *registry = new Registry(this); EventQueue *eventQueue = new EventQueue(this); eventQueue->setup(m_internalConnection.client); registry->setEventQueue(eventQueue); registry->create(m_internalConnection.client); m_internalConnection.registry = registry; connect(registry, &Registry::shmAnnounced, this, [this] (quint32 name, quint32 version) { m_internalConnection.shm = m_internalConnection.registry->createShmPool(name, version, this); } ); connect(registry, &Registry::interfacesAnnounced, this, [this, registry] { m_internalConnection.interfacesAnnounced = true; const auto compInterface = registry->interface(Registry::Interface::Compositor); if (compInterface.name != 0) { m_internalConnection.compositor = registry->createCompositor(compInterface.name, compInterface.version, this); } const auto seatInterface = registry->interface(Registry::Interface::Seat); if (seatInterface.name != 0) { m_internalConnection.seat = registry->createSeat(seatInterface.name, seatInterface.version, this); } const auto ddmInterface = registry->interface(Registry::Interface::DataDeviceManager); if (ddmInterface.name != 0) { m_internalConnection.ddm = registry->createDataDeviceManager(ddmInterface.name, ddmInterface.version, this); } } ); registry->setup(); } ); m_internalConnection.client->initConnection(); } void WaylandServer::removeClient(AbstractClient *c) { m_clients.removeAll(c); emit shellClientRemoved(c); } void WaylandServer::dispatch() { if (!m_display) { return; } if (m_internalConnection.server) { m_internalConnection.server->flush(); } m_display->dispatchEvents(0); } static AbstractClient *findClientInList(const QList &clients, quint32 id) { auto it = std::find_if(clients.begin(), clients.end(), [id] (AbstractClient *c) { return c->windowId() == id; } ); if (it == clients.end()) { return nullptr; } return *it; } static AbstractClient *findClientInList(const QList &clients, KWayland::Server::SurfaceInterface *surface) { auto it = std::find_if(clients.begin(), clients.end(), [surface] (AbstractClient *c) { return c->surface() == surface; } ); if (it == clients.end()) { return nullptr; } return *it; } AbstractClient *WaylandServer::findClient(quint32 id) const { if (id == 0) { return nullptr; } if (AbstractClient *c = findClientInList(m_clients, id)) { return c; } return nullptr; } AbstractClient *WaylandServer::findClient(SurfaceInterface *surface) const { if (!surface) { return nullptr; } if (AbstractClient *c = findClientInList(m_clients, surface)) { return c; } return nullptr; } XdgShellClient *WaylandServer::findXdgShellClient(SurfaceInterface *surface) const { return qobject_cast(findClient(surface)); } quint32 WaylandServer::createWindowId(SurfaceInterface *surface) { auto it = m_clientIds.constFind(surface->client()); quint16 clientId = 0; if (it != m_clientIds.constEnd()) { clientId = it.value(); } else { clientId = createClientId(surface->client()); } Q_ASSERT(clientId != 0); quint32 id = clientId; // TODO: this does not prevent that two surfaces of same client get same id id = (id << 16) | (surface->id() & 0xFFFF); if (findClient(id)) { qCWarning(KWIN_CORE) << "Invalid client windowId generated:" << id; return 0; } return id; } quint16 WaylandServer::createClientId(ClientConnection *c) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) const QSet ids(m_clientIds.constBegin(), m_clientIds.constEnd()); #else const auto ids = m_clientIds.values().toSet(); #endif quint16 id = 1; if (!ids.isEmpty()) { for (quint16 i = ids.count() + 1; i >= 1 ; i--) { if (!ids.contains(i)) { id = i; break; } } } Q_ASSERT(!ids.contains(id)); m_clientIds.insert(c, id); connect(c, &ClientConnection::disconnected, this, [this] (ClientConnection *c) { m_clientIds.remove(c); } ); return id; } bool WaylandServer::isScreenLocked() const { if (!hasScreenLockerIntegration()) { return false; } return ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::Locked || ScreenLocker::KSldApp::self()->lockState() == ScreenLocker::KSldApp::AcquiringLock; } bool WaylandServer::hasScreenLockerIntegration() const { return !m_initFlags.testFlag(InitializationFlag::NoLockScreenIntegration); } bool WaylandServer::hasGlobalShortcutSupport() const { return !m_initFlags.testFlag(InitializationFlag::NoGlobalShortcuts); } void WaylandServer::simulateUserActivity() { if (m_idle) { m_idle->simulateUserActivity(); } } void WaylandServer::updateKeyState(KWin::Xkb::LEDs leds) { if (!m_keyState) return; m_keyState->setState(KeyStateInterface::Key::CapsLock, leds & KWin::Xkb::LED::CapsLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked); m_keyState->setState(KeyStateInterface::Key::NumLock, leds & KWin::Xkb::LED::NumLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked); m_keyState->setState(KeyStateInterface::Key::ScrollLock, leds & KWin::Xkb::LED::ScrollLock ? KeyStateInterface::State::Locked : KeyStateInterface::State::Unlocked); } } diff --git a/wayland_server.h b/wayland_server.h index d90e0119e..b2f1c77c5 100644 --- a/wayland_server.h +++ b/wayland_server.h @@ -1,304 +1,305 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2015 Martin Gräßlin 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_WAYLAND_SERVER_H #define KWIN_WAYLAND_SERVER_H #include #include "keyboard_input.h" #include class QThread; class QProcess; class QWindow; namespace KWayland { namespace Client { class ConnectionThread; class Registry; class Compositor; class Seat; class DataDeviceManager; class ShmPool; class Surface; } namespace Server { class AppMenuManagerInterface; class ClientConnection; class CompositorInterface; class Display; class DataDeviceInterface; class IdleInterface; class SeatInterface; class DataDeviceManagerInterface; class ServerSideDecorationManagerInterface; class ServerSideDecorationPaletteManagerInterface; class SurfaceInterface; class OutputInterface; class PlasmaShellInterface; class PlasmaShellSurfaceInterface; class PlasmaVirtualDesktopManagementInterface; class PlasmaWindowManagementInterface; class QtSurfaceExtensionInterface; class OutputManagementInterface; class OutputConfigurationInterface; class XdgDecorationManagerInterface; class XdgShellInterface; class XdgForeignInterface; class XdgOutputManagerInterface; class KeyStateInterface; class LinuxDmabufUnstableV1Interface; class LinuxDmabufUnstableV1Buffer; class TabletManagerInterface; } } namespace KWin { class XdgShellClient; class AbstractClient; class Toplevel; class KWIN_EXPORT WaylandServer : public QObject { Q_OBJECT public: enum class InitializationFlag { NoOptions = 0x0, LockScreen = 0x1, NoLockScreenIntegration = 0x2, NoGlobalShortcuts = 0x4 }; Q_DECLARE_FLAGS(InitializationFlags, InitializationFlag) ~WaylandServer() override; bool init(const QByteArray &socketName = QByteArray(), InitializationFlags flags = InitializationFlag::NoOptions); void terminateClientConnections(); KWayland::Server::Display *display() { return m_display; } KWayland::Server::CompositorInterface *compositor() { return m_compositor; } KWayland::Server::SeatInterface *seat() { return m_seat; } KWayland::Server::TabletManagerInterface *tabletManager() { return m_tabletManager; } KWayland::Server::DataDeviceManagerInterface *dataDeviceManager() { return m_dataDeviceManager; } KWayland::Server::PlasmaVirtualDesktopManagementInterface *virtualDesktopManagement() { return m_virtualDesktopManagement; } KWayland::Server::PlasmaWindowManagementInterface *windowManagement() { return m_windowManagement; } KWayland::Server::ServerSideDecorationManagerInterface *decorationManager() const { return m_decorationManager; } KWayland::Server::XdgOutputManagerInterface *xdgOutputManager() const { return m_xdgOutputManager; } KWayland::Server::LinuxDmabufUnstableV1Interface *linuxDmabuf(); QList clients() const { return m_clients; } void removeClient(AbstractClient *c); AbstractClient *findClient(quint32 id) const; AbstractClient *findClient(KWayland::Server::SurfaceInterface *surface) const; XdgShellClient *findXdgShellClient(KWayland::Server::SurfaceInterface *surface) const; /** * @returns a transient parent of a surface imported with the foreign protocol, if any */ KWayland::Server::SurfaceInterface *findForeignTransientForSurface(KWayland::Server::SurfaceInterface *surface); /** * @returns file descriptor for Xwayland to connect to. */ int createXWaylandConnection(); void destroyXWaylandConnection(); /** * @returns file descriptor to the input method server's socket. */ int createInputMethodConnection(); void destroyInputMethodConnection(); /** * @returns true if screen is locked. */ bool isScreenLocked() const; /** * @returns whether integration with KScreenLocker is available. */ bool hasScreenLockerIntegration() const; /** * @returns whether any kind of global shortcuts are supported. */ bool hasGlobalShortcutSupport() const; void createInternalConnection(); void initWorkspace(); KWayland::Server::ClientConnection *xWaylandConnection() const { return m_xwayland.client; } KWayland::Server::ClientConnection *inputMethodConnection() const { return m_inputMethodServerConnection; } KWayland::Server::ClientConnection *internalConnection() const { return m_internalConnection.server; } KWayland::Server::ClientConnection *screenLockerClientConnection() const { return m_screenLockerClientConnection; } KWayland::Client::Compositor *internalCompositor() { return m_internalConnection.compositor; } KWayland::Client::Seat *internalSeat() { return m_internalConnection.seat; } KWayland::Client::DataDeviceManager *internalDataDeviceManager() { return m_internalConnection.ddm; } KWayland::Client::ShmPool *internalShmPool() { return m_internalConnection.shm; } KWayland::Client::ConnectionThread *internalClientConection() { return m_internalConnection.client; } KWayland::Client::Registry *internalClientRegistry() { return m_internalConnection.registry; } void dispatch(); quint32 createWindowId(KWayland::Server::SurfaceInterface *surface); /** * Struct containing information for a created Wayland connection through a * socketpair. */ struct SocketPairConnection { /** * ServerSide Connection */ KWayland::Server::ClientConnection *connection = nullptr; /** * client-side file descriptor for the socket */ int fd = -1; }; /** * Creates a Wayland connection using a socket pair. */ SocketPairConnection createConnection(); void simulateUserActivity(); void updateKeyState(KWin::Xkb::LEDs leds); QSet linuxDmabufBuffers() const { return m_linuxDmabufBuffers; } void addLinuxDmabufBuffer(KWayland::Server::LinuxDmabufUnstableV1Buffer *buffer) { m_linuxDmabufBuffers << buffer; } void removeLinuxDmabufBuffer(KWayland::Server::LinuxDmabufUnstableV1Buffer *buffer) { m_linuxDmabufBuffers.remove(buffer); } Q_SIGNALS: void shellClientAdded(KWin::AbstractClient *); void shellClientRemoved(KWin::AbstractClient *); void terminatingInternalClientConnection(); void initialized(); void foreignTransientChanged(KWayland::Server::SurfaceInterface *child); private: + int createScreenLockerConnection(); void shellClientShown(Toplevel *t); quint16 createClientId(KWayland::Server::ClientConnection *c); void destroyInternalConnection(); template void createSurface(T *surface); void initScreenLocker(); KWayland::Server::Display *m_display = nullptr; KWayland::Server::CompositorInterface *m_compositor = nullptr; KWayland::Server::SeatInterface *m_seat = nullptr; KWayland::Server::TabletManagerInterface *m_tabletManager = nullptr; KWayland::Server::DataDeviceManagerInterface *m_dataDeviceManager = nullptr; KWayland::Server::XdgShellInterface *m_xdgShell = nullptr; KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr; KWayland::Server::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr; KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr; KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr; KWayland::Server::AppMenuManagerInterface *m_appMenuManager = nullptr; KWayland::Server::ServerSideDecorationPaletteManagerInterface *m_paletteManager = nullptr; KWayland::Server::IdleInterface *m_idle = nullptr; KWayland::Server::XdgOutputManagerInterface *m_xdgOutputManager = nullptr; KWayland::Server::XdgDecorationManagerInterface *m_xdgDecorationManager = nullptr; KWayland::Server::LinuxDmabufUnstableV1Interface *m_linuxDmabuf = nullptr; QSet m_linuxDmabufBuffers; struct { KWayland::Server::ClientConnection *client = nullptr; QMetaObject::Connection destroyConnection; } m_xwayland; KWayland::Server::ClientConnection *m_inputMethodServerConnection = nullptr; KWayland::Server::ClientConnection *m_screenLockerClientConnection = nullptr; struct { KWayland::Server::ClientConnection *server = nullptr; KWayland::Client::ConnectionThread *client = nullptr; QThread *clientThread = nullptr; KWayland::Client::Registry *registry = nullptr; KWayland::Client::Compositor *compositor = nullptr; KWayland::Client::Seat *seat = nullptr; KWayland::Client::DataDeviceManager *ddm = nullptr; KWayland::Client::ShmPool *shm = nullptr; bool interfacesAnnounced = false; } m_internalConnection; KWayland::Server::XdgForeignInterface *m_XdgForeign = nullptr; KWayland::Server::KeyStateInterface *m_keyState = nullptr; QList m_clients; QHash m_clientIds; InitializationFlags m_initFlags; QVector m_plasmaShellSurfaces; KWIN_SINGLETON(WaylandServer) }; inline WaylandServer *waylandServer() { return WaylandServer::self(); } } // namespace KWin #endif diff --git a/workspace.cpp b/workspace.cpp index 66818ee62..273c5a36a 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -1,2780 +1,2779 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak Copyright (C) 2019 Vlad Zahorodnii 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 . *********************************************************************/ // own #include "workspace.h" // kwin libs #include // kwin #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif #include "appmenu.h" #include "atoms.h" #include "x11client.h" #include "composite.h" #include "cursor.h" #include "dbusinterface.h" #include "deleted.h" #include "effects.h" #include "focuschain.h" #include "group.h" #include "input.h" #include "internal_client.h" #include "logind.h" #include "moving_client_x11_filter.h" #include "killwindow.h" #include "netinfo.h" #include "outline.h" #include "placement.h" #include "rules.h" #include "screenedge.h" #include "screens.h" #include "platform.h" #include "scripting/scripting.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox.h" #endif #include "unmanaged.h" #include "useractions.h" #include "virtualdesktops.h" #include "was_user_interaction_x11_filter.h" #include "wayland_server.h" #include "xcbutils.h" #include "main.h" #include "decorations/decorationbridge.h" // KDE #include #include #include #include // Qt #include namespace KWin { extern int screen_number; extern bool is_multihead; ColorMapper::ColorMapper(QObject *parent) : QObject(parent) , m_default(defaultScreen()->default_colormap) , m_installed(defaultScreen()->default_colormap) { } ColorMapper::~ColorMapper() { } void ColorMapper::update() { xcb_colormap_t cmap = m_default; if (X11Client *c = dynamic_cast(Workspace::self()->activeClient())) { if (c->colormap() != XCB_COLORMAP_NONE) { cmap = c->colormap(); } } if (cmap != m_installed) { xcb_install_colormap(connection(), cmap); m_installed = cmap; } } Workspace* Workspace::_self = nullptr; Workspace::Workspace(const QString &sessionKey) : QObject(nullptr) , m_compositor(nullptr) // Unsorted , active_popup(nullptr) , active_popup_client(nullptr) , m_initialDesktop(1) , active_client(nullptr) , last_active_client(nullptr) , most_recently_raised(nullptr) , movingClient(nullptr) , delayfocus_client(nullptr) , force_restacking(false) , showing_desktop(false) , was_user_interaction(false) , block_focus(0) , m_userActionsMenu(new UserActionsMenu(this)) , client_keys_dialog(nullptr) , client_keys_client(nullptr) , global_shortcuts_disabled_for_client(false) , workspaceInit(true) , startup(nullptr) , set_active_client_recursion(0) , block_stacking_updates(0) , m_sessionManager(new SessionManager(this)) { // If KWin was already running it saved its configuration after loosing the selection -> Reread QFuture reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration); ApplicationMenu::create(this); _self = this; #ifdef KWIN_BUILD_ACTIVITIES Activities *activities = nullptr; if (kwinApp()->usesKActivities()) { activities = Activities::create(this); } if (activities) { connect(activities, SIGNAL(currentChanged(QString)), SLOT(updateCurrentActivity(QString))); } #endif // PluginMgr needs access to the config file, so we need to wait for it for finishing reparseConfigFuture.waitForFinished(); options->loadConfig(); options->loadCompositingConfig(false); delayFocusTimer = nullptr; if (!sessionKey.isEmpty()) loadSessionInfo(sessionKey); connect(qApp, &QGuiApplication::saveStateRequest, this, &Workspace::saveState); RuleBook::create(this)->load(); kwinApp()->createScreens(); ScreenEdges::create(this); // VirtualDesktopManager needs to be created prior to init shortcuts // and prior to TabBox, due to TabBox connecting to signals // actual initialization happens in init() VirtualDesktopManager::create(this); //dbus interface new VirtualDesktopManagerDBusInterface(VirtualDesktopManager::self()); #ifdef KWIN_BUILD_TABBOX // need to create the tabbox before compositing scene is setup TabBox::TabBox::create(this); #endif if (Compositor::self()) { m_compositor = Compositor::self(); } else { Q_ASSERT(kwinApp()->operationMode() == Application::OperationMode::OperationModeX11); m_compositor = X11Compositor::create(this); } connect(this, &Workspace::currentDesktopChanged, m_compositor, &Compositor::addRepaintFull); connect(m_compositor, &QObject::destroyed, this, [this] { m_compositor = nullptr; }); auto decorationBridge = Decoration::DecorationBridge::create(this); decorationBridge->init(); connect(this, &Workspace::configChanged, decorationBridge, &Decoration::DecorationBridge::reconfigure); new DBusInterface(this); Outline::create(this); initShortcuts(); init(); } void Workspace::init() { KSharedConfigPtr config = kwinApp()->config(); Screens *screens = Screens::self(); // get screen support connect(screens, SIGNAL(changed()), SLOT(desktopResized())); screens->setConfig(config); screens->reconfigure(); connect(options, SIGNAL(configChanged()), screens, SLOT(reconfigure())); ScreenEdges *screenEdges = ScreenEdges::self(); screenEdges->setConfig(config); screenEdges->init(); connect(options, SIGNAL(configChanged()), screenEdges, SLOT(reconfigure())); connect(VirtualDesktopManager::self(), SIGNAL(layoutChanged(int,int)), screenEdges, SLOT(updateLayout())); connect(this, &Workspace::clientActivated, screenEdges, &ScreenEdges::checkBlocking); FocusChain *focusChain = FocusChain::create(this); connect(this, &Workspace::clientRemoved, focusChain, &FocusChain::remove); connect(this, &Workspace::clientActivated, focusChain, &FocusChain::setActiveClient); connect(VirtualDesktopManager::self(), SIGNAL(countChanged(uint,uint)), focusChain, SLOT(resize(uint,uint))); connect(VirtualDesktopManager::self(), SIGNAL(currentChanged(uint,uint)), focusChain, SLOT(setCurrentDesktop(uint,uint))); connect(options, SIGNAL(separateScreenFocusChanged(bool)), focusChain, SLOT(setSeparateScreenFocus(bool))); focusChain->setSeparateScreenFocus(options->isSeparateScreenFocus()); // create VirtualDesktopManager and perform dependency injection VirtualDesktopManager *vds = VirtualDesktopManager::self(); connect(vds, &VirtualDesktopManager::desktopRemoved, this, [this](KWin::VirtualDesktop *desktop) { //Wayland if (kwinApp()->operationMode() == Application::OperationModeWaylandOnly || kwinApp()->operationMode() == Application::OperationModeXwayland) { for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { if (!(*it)->desktops().contains(desktop)) { continue; } if ((*it)->desktops().count() > 1) { (*it)->leaveDesktop(desktop); } else { sendClientToDesktop(*it, qMin(desktop->x11DesktopNumber(), VirtualDesktopManager::self()->count()), true); } } //X11 } else { for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { if (!(*it)->isOnAllDesktops() && ((*it)->desktop() > static_cast(VirtualDesktopManager::self()->count()))) { sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true); } } } } ); connect(vds, SIGNAL(countChanged(uint,uint)), SLOT(slotDesktopCountChanged(uint,uint))); connect(vds, SIGNAL(currentChanged(uint,uint)), SLOT(slotCurrentDesktopChanged(uint,uint))); vds->setNavigationWrappingAround(options->isRollOverDesktops()); connect(options, SIGNAL(rollOverDesktopsChanged(bool)), vds, SLOT(setNavigationWrappingAround(bool))); vds->setConfig(config); // Now we know how many desktops we'll have, thus we initialize the positioning object Placement::create(this); // positioning object needs to be created before the virtual desktops are loaded. vds->load(); vds->updateLayout(); //makes sure any autogenerated id is saved, necessary as in case of xwayland, load will be called 2 times // load is needed to be called again when starting xwayalnd to sync to RootInfo, see BUG 385260 vds->save(); if (!VirtualDesktopManager::self()->setCurrent(m_initialDesktop)) VirtualDesktopManager::self()->setCurrent(1); reconfigureTimer.setSingleShot(true); updateToolWindowsTimer.setSingleShot(true); connect(&reconfigureTimer, SIGNAL(timeout()), this, SLOT(slotReconfigure())); connect(&updateToolWindowsTimer, SIGNAL(timeout()), this, SLOT(slotUpdateToolWindows())); // TODO: do we really need to reconfigure everything when fonts change? // maybe just reconfigure the decorations? Move this into libkdecoration? QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KDEPlatformTheme"), QStringLiteral("org.kde.KDEPlatformTheme"), QStringLiteral("refreshFonts"), this, SLOT(reconfigure())); active_client = nullptr; initWithX11(); Scripting::create(this); if (auto server = waylandServer()) { connect(server, &WaylandServer::shellClientAdded, this, &Workspace::addShellClient); connect(server, &WaylandServer::shellClientRemoved, this, &Workspace::removeShellClient); } // SELI TODO: This won't work with unreasonable focus policies, // and maybe in rare cases also if the selected client doesn't // want focus workspaceInit = false; // broadcast that Workspace is ready, but first process all events. QMetaObject::invokeMethod(this, "workspaceInitialized", Qt::QueuedConnection); // TODO: ungrabXServer() } void Workspace::initWithX11() { if (!kwinApp()->x11Connection()) { connect(kwinApp(), &Application::x11ConnectionChanged, this, &Workspace::initWithX11, Qt::UniqueConnection); return; } disconnect(kwinApp(), &Application::x11ConnectionChanged, this, &Workspace::initWithX11); atoms->retrieveHelpers(); // first initialize the extensions Xcb::Extensions::self(); ColorMapper *colormaps = new ColorMapper(this); connect(this, &Workspace::clientActivated, colormaps, &ColorMapper::update); // Call this before XSelectInput() on the root window startup = new KStartupInfo( KStartupInfo::DisableKWinModule | KStartupInfo::AnnounceSilenceChanges, this); // Select windowmanager privileges selectWmInputEventMask(); // Compatibility int32_t data = 1; xcb_change_property(connection(), XCB_PROP_MODE_APPEND, rootWindow(), atoms->kwin_running, atoms->kwin_running, 32, 1, &data); if (kwinApp()->operationMode() == Application::OperationModeX11) { m_wasUserInteractionFilter.reset(new WasUserInteractionX11Filter); m_movingClientFilter.reset(new MovingClientX11Filter); } updateXTime(); // Needed for proper initialization of user_time in Client ctor const uint32_t nullFocusValues[] = {true}; m_nullFocus.reset(new Xcb::Window(QRect(-1, -1, 1, 1), XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, nullFocusValues)); m_nullFocus->map(); RootInfo *rootInfo = RootInfo::create(); const auto vds = VirtualDesktopManager::self(); vds->setRootInfo(rootInfo); // load again to sync to RootInfo, see BUG 385260 vds->load(); vds->updateRootInfo(); rootInfo->setCurrentDesktop(vds->currentDesktop()->x11DesktopNumber()); // TODO: only in X11 mode // Extra NETRootInfo instance in Client mode is needed to get the values of the properties NETRootInfo client_info(connection(), NET::ActiveWindow | NET::CurrentDesktop); if (!qApp->isSessionRestored()) { m_initialDesktop = client_info.currentDesktop(); vds->setCurrent(m_initialDesktop); } // TODO: better value rootInfo->setActiveWindow(None); focusToNull(); if (!qApp->isSessionRestored()) ++block_focus; // Because it will be set below { // Begin updates blocker block StackingUpdatesBlocker blocker(this); Xcb::Tree tree(rootWindow()); xcb_window_t *wins = xcb_query_tree_children(tree.data()); QVector windowAttributes(tree->children_len); QVector windowGeometries(tree->children_len); // Request the attributes and geometries of all toplevel windows for (int i = 0; i < tree->children_len; i++) { windowAttributes[i] = Xcb::WindowAttributes(wins[i]); windowGeometries[i] = Xcb::WindowGeometry(wins[i]); } // Get the replies for (int i = 0; i < tree->children_len; i++) { Xcb::WindowAttributes attr(windowAttributes.at(i)); if (attr.isNull()) { continue; } if (attr->override_redirect) { if (attr->map_state == XCB_MAP_STATE_VIEWABLE && attr->_class != XCB_WINDOW_CLASS_INPUT_ONLY) // ### This will request the attributes again createUnmanaged(wins[i]); } else if (attr->map_state != XCB_MAP_STATE_UNMAPPED) { if (Application::wasCrash()) { fixPositionAfterCrash(wins[i], windowGeometries.at(i).data()); } // ### This will request the attributes again createClient(wins[i], true); } } // Propagate clients, will really happen at the end of the updates blocker block updateStackingOrder(true); saveOldScreenSizes(); updateClientArea(); // NETWM spec says we have to set it to (0,0) if we don't support it NETPoint* viewports = new NETPoint[VirtualDesktopManager::self()->count()]; rootInfo->setDesktopViewport(VirtualDesktopManager::self()->count(), *viewports); delete[] viewports; QRect geom; for (int i = 0; i < screens()->count(); i++) { geom |= screens()->geometry(i); } NETSize desktop_geometry; desktop_geometry.width = geom.width(); desktop_geometry.height = geom.height(); rootInfo->setDesktopGeometry(desktop_geometry); setShowingDesktop(false); } // End updates blocker block // TODO: only on X11? AbstractClient* new_active_client = nullptr; if (!qApp->isSessionRestored()) { --block_focus; new_active_client = findClient(Predicate::WindowMatch, client_info.activeWindow()); } if (new_active_client == nullptr && activeClient() == nullptr && should_get_focus.count() == 0) { // No client activated in manage() if (new_active_client == nullptr) new_active_client = topClientOnDesktop(VirtualDesktopManager::self()->current(), -1); if (new_active_client == nullptr && !desktops.isEmpty()) new_active_client = findDesktop(true, VirtualDesktopManager::self()->current()); } if (new_active_client != nullptr) activateClient(new_active_client); } Workspace::~Workspace() { blockStackingUpdates(true); // TODO: grabXServer(); // Use stacking_order, so that kwin --replace keeps stacking order const QList stack = stacking_order; // "mutex" the stackingorder, since anything trying to access it from now on will find // many dangeling pointers and crash stacking_order.clear(); for (auto it = stack.constBegin(), end = stack.constEnd(); it != end; ++it) { X11Client *c = qobject_cast(const_cast(*it)); if (!c) { continue; } // Only release the window c->releaseWindow(true); // No removeClient() is called, it does more than just removing. // However, remove from some lists to e.g. prevent performTransiencyCheck() // from crashing. clients.removeAll(c); m_allClients.removeAll(c); desktops.removeAll(c); } X11Client::cleanupX11(); if (waylandServer()) { const QList shellClients = waylandServer()->clients(); for (AbstractClient *client : shellClients) { client->destroyClient(); } } for (auto it = unmanaged.begin(), end = unmanaged.end(); it != end; ++it) (*it)->release(ReleaseReason::KWinShutsDown); for (InternalClient *client : m_internalClients) { client->destroyClient(); } if (auto c = kwinApp()->x11Connection()) { xcb_delete_property(c, kwinApp()->x11RootWindow(), atoms->kwin_running); } for (auto it = deleted.begin(); it != deleted.end();) { emit deletedRemoved(*it); it = deleted.erase(it); } delete RuleBook::self(); kwinApp()->config()->sync(); RootInfo::destroy(); delete startup; delete Placement::self(); delete client_keys_dialog; - foreach (SessionInfo * s, session) - delete s; + qDeleteAll(session); // TODO: ungrabXServer(); Xcb::Extensions::destroy(); _self = nullptr; } void Workspace::setupClientConnections(AbstractClient *c) { connect(c, &Toplevel::needsRepaint, m_compositor, &Compositor::scheduleRepaint); connect(c, &AbstractClient::desktopPresenceChanged, this, &Workspace::desktopPresenceChanged); connect(c, &AbstractClient::minimizedChanged, this, std::bind(&Workspace::clientMinimizedChanged, this, c)); } X11Client *Workspace::createClient(xcb_window_t w, bool is_mapped) { StackingUpdatesBlocker blocker(this); X11Client *c = new X11Client(); setupClientConnections(c); if (X11Compositor *compositor = X11Compositor::self()) { connect(c, &X11Client::blockingCompositingChanged, compositor, &X11Compositor::updateClientCompositeBlocking); } connect(c, SIGNAL(clientFullScreenSet(KWin::X11Client *,bool,bool)), ScreenEdges::self(), SIGNAL(checkBlocking())); if (!c->manage(w, is_mapped)) { X11Client::deleteClient(c); return nullptr; } addClient(c); return c; } Unmanaged* Workspace::createUnmanaged(xcb_window_t w) { if (X11Compositor *compositor = X11Compositor::self()) { if (compositor->checkForOverlayWindow(w)) { return nullptr; } } Unmanaged* c = new Unmanaged(); if (!c->track(w)) { Unmanaged::deleteUnmanaged(c); return nullptr; } connect(c, &Unmanaged::needsRepaint, m_compositor, &Compositor::scheduleRepaint); addUnmanaged(c); emit unmanagedAdded(c); return c; } void Workspace::addClient(X11Client *c) { Group* grp = findGroup(c->window()); emit clientAdded(c); if (grp != nullptr) grp->gotLeader(c); if (c->isDesktop()) { desktops.append(c); if (active_client == nullptr && should_get_focus.isEmpty() && c->isOnCurrentDesktop()) requestFocus(c); // TODO: Make sure desktop is active after startup if there's no other window active } else { FocusChain::self()->update(c, FocusChain::Update); clients.append(c); m_allClients.append(c); } if (!unconstrained_stacking_order.contains(c)) unconstrained_stacking_order.append(c); // Raise if it hasn't got any stacking position yet if (!stacking_order.contains(c)) // It'll be updated later, and updateToolWindows() requires stacking_order.append(c); // c to be in stacking_order markXStackingOrderAsDirty(); updateClientArea(); // This cannot be in manage(), because the client got added only now updateClientLayer(c); if (c->isDesktop()) { raiseClient(c); // If there's no active client, make this desktop the active one if (activeClient() == nullptr && should_get_focus.count() == 0) activateClient(findDesktop(true, VirtualDesktopManager::self()->current())); } c->checkActiveModal(); checkTransients(c->window()); // SELI TODO: Does this really belong here? updateStackingOrder(true); // Propagate new client if (c->isUtility() || c->isMenu() || c->isToolbar()) updateToolWindows(true); updateTabbox(); } void Workspace::addUnmanaged(Unmanaged* c) { unmanaged.append(c); markXStackingOrderAsDirty(); } /** * Destroys the client \a c */ void Workspace::removeClient(X11Client *c) { if (c == active_popup_client) closeActivePopup(); if (m_userActionsMenu->isMenuClient(c)) { m_userActionsMenu->close(); } if (client_keys_client == c) setupWindowShortcutDone(false); if (!c->shortcut().isEmpty()) { c->setShortcut(QString()); // Remove from client_keys clientShortcutUpdated(c); // Needed, since this is otherwise delayed by setShortcut() and wouldn't run } Q_ASSERT(clients.contains(c) || desktops.contains(c)); // TODO: if marked client is removed, notify the marked list clients.removeAll(c); m_allClients.removeAll(c); desktops.removeAll(c); markXStackingOrderAsDirty(); attention_chain.removeAll(c); Group* group = findGroup(c->window()); if (group != nullptr) group->lostLeader(); if (c == most_recently_raised) most_recently_raised = nullptr; should_get_focus.removeAll(c); Q_ASSERT(c != active_client); if (c == last_active_client) last_active_client = nullptr; if (c == delayfocus_client) cancelDelayFocus(); emit clientRemoved(c); updateStackingOrder(true); updateClientArea(); updateTabbox(); } void Workspace::removeUnmanaged(Unmanaged* c) { Q_ASSERT(unmanaged.contains(c)); unmanaged.removeAll(c); emit unmanagedRemoved(c); markXStackingOrderAsDirty(); } void Workspace::addDeleted(Deleted* c, Toplevel *orig) { Q_ASSERT(!deleted.contains(c)); deleted.append(c); const int unconstraintedIndex = unconstrained_stacking_order.indexOf(orig); if (unconstraintedIndex != -1) { unconstrained_stacking_order.replace(unconstraintedIndex, c); } else { unconstrained_stacking_order.append(c); } const int index = stacking_order.indexOf(orig); if (index != -1) { stacking_order.replace(index, c); } else { stacking_order.append(c); } markXStackingOrderAsDirty(); connect(c, &Deleted::needsRepaint, m_compositor, &Compositor::scheduleRepaint); } void Workspace::removeDeleted(Deleted* c) { Q_ASSERT(deleted.contains(c)); emit deletedRemoved(c); deleted.removeAll(c); unconstrained_stacking_order.removeAll(c); stacking_order.removeAll(c); markXStackingOrderAsDirty(); if (!c->wasClient()) { return; } if (X11Compositor *compositor = X11Compositor::self()) { compositor->updateClientCompositeBlocking(); } } void Workspace::addShellClient(AbstractClient *client) { setupClientConnections(client); client->updateDecoration(false); updateClientLayer(client); const QRect area = clientArea(PlacementArea, Screens::self()->current(), client->desktop()); bool placementDone = false; if (client->isInitialPositionSet()) { placementDone = true; } if (client->isFullScreen()) { placementDone = true; } if (client->maximizeMode() == MaximizeMode::MaximizeFull) { placementDone = true; } if (client->rules()->checkPosition(invalidPoint, true) != invalidPoint) { placementDone = true; } if (!placementDone) { client->placeIn(area); } m_allClients.append(client); if (!unconstrained_stacking_order.contains(client)) { unconstrained_stacking_order.append(client); // Raise if it hasn't got any stacking position yet } if (!stacking_order.contains(client)) { // It'll be updated later, and updateToolWindows() requires stacking_order.append(client); // client to be in stacking_order } markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); if (client->wantsInput() && !client->isMinimized()) { activateClient(client); } updateTabbox(); connect(client, &AbstractClient::windowShown, this, [this, client] { updateClientLayer(client); // TODO: when else should we send the client through placement? if (client->hasTransientPlacementHint()) { const QRect area = clientArea(PlacementArea, Screens::self()->current(), client->desktop()); client->placeIn(area); } markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); if (client->wantsInput()) { activateClient(client); } }); connect(client, &AbstractClient::windowHidden, this, [this] { // TODO: update tabbox if it's displayed markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); }); } void Workspace::removeShellClient(AbstractClient *client) { m_allClients.removeAll(client); if (client == most_recently_raised) { most_recently_raised = nullptr; } if (client == delayfocus_client) { cancelDelayFocus(); } if (client == last_active_client) { last_active_client = nullptr; } if (client_keys_client == client) { setupWindowShortcutDone(false); } if (!client->shortcut().isEmpty()) { client->setShortcut(QString()); // Remove from client_keys } clientHidden(client); emit clientRemoved(client); markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); updateTabbox(); } void Workspace::updateToolWindows(bool also_hide) { // TODO: What if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?) if (!options->isHideUtilityWindowsForInactive()) { for (auto it = clients.constBegin(); it != clients.constEnd(); ++it) (*it)->hideClient(false); return; } const Group* group = nullptr; auto client = active_client; // Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow // will be shown; if a group transient is group, all tools in the group will be shown while (client != nullptr) { if (!client->isTransient()) break; if (client->groupTransient()) { group = client->group(); break; } client = client->transientFor(); } // Use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0, // I.e. if it's not up to date // SELI TODO: But maybe it should - what if a new client has been added that's not in stacking order yet? QVector to_show, to_hide; for (auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { auto c = qobject_cast(*it); if (!c) { continue; } if (c->isUtility() || c->isMenu() || c->isToolbar()) { bool show = true; if (!c->isTransient()) { if (!c->group() || c->group()->members().count() == 1) // Has its own group, keep always visible show = true; else if (client != nullptr && c->group() == client->group()) show = true; else show = false; } else { if (group != nullptr && c->group() == group) show = true; else if (client != nullptr && client->hasTransient(c, true)) show = true; else show = false; } if (!show && also_hide) { const auto mainclients = c->mainClients(); // Don't hide utility windows which are standalone(?) or // have e.g. kicker as mainwindow if (mainclients.isEmpty()) show = true; for (auto it2 = mainclients.constBegin(); it2 != mainclients.constEnd(); ++it2) { if ((*it2)->isSpecialWindow()) show = true; } if (!show) to_hide.append(c); } if (show) to_show.append(c); } } // First show new ones, then hide for (int i = to_show.size() - 1; i >= 0; --i) // From topmost // TODO: Since this is in stacking order, the order of taskbar entries changes :( to_show.at(i)->hideClient(false); if (also_hide) { for (auto it = to_hide.constBegin(); it != to_hide.constEnd(); ++it) // From bottommost (*it)->hideClient(true); updateToolWindowsTimer.stop(); } else // setActiveClient() is after called with NULL client, quickly followed // by setting a new client, which would result in flickering resetUpdateToolWindowsTimer(); } void Workspace::resetUpdateToolWindowsTimer() { updateToolWindowsTimer.start(200); } void Workspace::slotUpdateToolWindows() { updateToolWindows(true); } void Workspace::slotReloadConfig() { reconfigure(); } void Workspace::reconfigure() { reconfigureTimer.start(200); } /** * Reread settings */ void Workspace::slotReconfigure() { qCDebug(KWIN_CORE) << "Workspace::slotReconfigure()"; reconfigureTimer.stop(); bool borderlessMaximizedWindows = options->borderlessMaximizedWindows(); kwinApp()->config()->reparseConfiguration(); options->updateSettings(); emit configChanged(); m_userActionsMenu->discard(); updateToolWindows(true); RuleBook::self()->load(); for (auto it = m_allClients.begin(); it != m_allClients.end(); ++it) { (*it)->setupWindowRules(true); (*it)->applyWindowRules(); RuleBook::self()->discardUsed(*it, false); } if (borderlessMaximizedWindows != options->borderlessMaximizedWindows() && !options->borderlessMaximizedWindows()) { // in case borderless maximized windows option changed and new option // is to have borders, we need to unset the borders for all maximized windows for (auto it = m_allClients.begin(); it != m_allClients.end(); ++it) { if ((*it)->maximizeMode() == MaximizeFull) (*it)->checkNoBorder(); } } } void Workspace::slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop) { closeActivePopup(); ++block_focus; StackingUpdatesBlocker blocker(this); updateClientVisibilityOnDesktopChange(newDesktop); // Restore the focus on this desktop --block_focus; activateClientOnNewDesktop(newDesktop); emit currentDesktopChanged(oldDesktop, movingClient); } void Workspace::updateClientVisibilityOnDesktopChange(uint newDesktop) { for (auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { X11Client *c = qobject_cast(*it); if (!c) { continue; } if (!c->isOnDesktop(newDesktop) && c != movingClient && c->isOnCurrentActivity()) { (c)->updateVisibility(); } } // Now propagate the change, after hiding, before showing if (rootInfo()) { rootInfo()->setCurrentDesktop(VirtualDesktopManager::self()->current()); } if (movingClient && !movingClient->isOnDesktop(newDesktop)) { movingClient->setDesktop(newDesktop); } for (int i = stacking_order.size() - 1; i >= 0 ; --i) { X11Client *c = qobject_cast(stacking_order.at(i)); if (!c) { continue; } if (c->isOnDesktop(newDesktop) && c->isOnCurrentActivity()) c->updateVisibility(); } if (showingDesktop()) // Do this only after desktop change to avoid flicker setShowingDesktop(false); } void Workspace::activateClientOnNewDesktop(uint desktop) { AbstractClient* c = nullptr; if (options->focusPolicyIsReasonable()) { c = findClientToActivateOnDesktop(desktop); } // If "unreasonable focus policy" and active_client is on_all_desktops and // under mouse (Hence == old_active_client), conserve focus. // (Thanks to Volker Schatz ) else if (active_client && active_client->isShown(true) && active_client->isOnCurrentDesktop()) c = active_client; if (c == nullptr && !desktops.isEmpty()) c = findDesktop(true, desktop); if (c != active_client) setActiveClient(nullptr); if (c) requestFocus(c); else if (!desktops.isEmpty()) requestFocus(findDesktop(true, desktop)); else focusToNull(); } AbstractClient *Workspace::findClientToActivateOnDesktop(uint desktop) { if (movingClient != nullptr && active_client == movingClient && FocusChain::self()->contains(active_client, desktop) && active_client->isShown(true) && active_client->isOnCurrentDesktop()) { // A requestFocus call will fail, as the client is already active return active_client; } // from actiavtion.cpp if (options->isNextFocusPrefersMouse()) { auto it = stackingOrder().constEnd(); while (it != stackingOrder().constBegin()) { X11Client *client = qobject_cast(*(--it)); if (!client) { continue; } if (!(client->isShown(false) && client->isOnDesktop(desktop) && client->isOnCurrentActivity() && client->isOnActiveScreen())) continue; if (client->frameGeometry().contains(Cursor::pos())) { if (!client->isDesktop()) return client; break; // unconditional break - we do not pass the focus to some client below an unusable one } } } return FocusChain::self()->getForActivation(desktop); } /** * Updates the current activity when it changes * do *not* call this directly; it does not set the activity. * * Shows/Hides windows according to the stacking order */ void Workspace::updateCurrentActivity(const QString &new_activity) { #ifdef KWIN_BUILD_ACTIVITIES if (!Activities::self()) { return; } //closeActivePopup(); ++block_focus; // TODO: Q_ASSERT( block_stacking_updates == 0 ); // Make sure stacking_order is up to date StackingUpdatesBlocker blocker(this); // Optimized Desktop switching: unmapping done from back to front // mapping done from front to back => less exposure events //Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop)); for (auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { X11Client *c = qobject_cast(*it); if (!c) { continue; } if (!c->isOnActivity(new_activity) && c != movingClient && c->isOnCurrentDesktop()) { c->updateVisibility(); } } // Now propagate the change, after hiding, before showing //rootInfo->setCurrentDesktop( currentDesktop() ); /* TODO someday enable dragging windows to other activities if ( movingClient && !movingClient->isOnDesktop( new_desktop )) { movingClient->setDesktop( new_desktop ); */ for (int i = stacking_order.size() - 1; i >= 0 ; --i) { X11Client *c = qobject_cast(stacking_order.at(i)); if (!c) { continue; } if (c->isOnActivity(new_activity)) c->updateVisibility(); } //FIXME not sure if I should do this either if (showingDesktop()) // Do this only after desktop change to avoid flicker setShowingDesktop(false); // Restore the focus on this desktop --block_focus; AbstractClient* c = nullptr; //FIXME below here is a lot of focuschain stuff, probably all wrong now if (options->focusPolicyIsReasonable()) { // Search in focus chain c = FocusChain::self()->getForActivation(VirtualDesktopManager::self()->current()); } // If "unreasonable focus policy" and active_client is on_all_desktops and // under mouse (Hence == old_active_client), conserve focus. // (Thanks to Volker Schatz ) else if (active_client && active_client->isShown(true) && active_client->isOnCurrentDesktop() && active_client->isOnCurrentActivity()) c = active_client; if (c == nullptr && !desktops.isEmpty()) c = findDesktop(true, VirtualDesktopManager::self()->current()); if (c != active_client) setActiveClient(nullptr); if (c) requestFocus(c); else if (!desktops.isEmpty()) requestFocus(findDesktop(true, VirtualDesktopManager::self()->current())); else focusToNull(); // Not for the very first time, only if something changed and there are more than 1 desktops //if ( effects != NULL && old_desktop != 0 && old_desktop != new_desktop ) // static_cast( effects )->desktopChanged( old_desktop ); if (compositing() && m_compositor) m_compositor->addRepaintFull(); #else Q_UNUSED(new_activity) #endif } void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount) { Q_UNUSED(previousCount) Placement::self()->reinitCascading(0); resetClientAreas(newCount); } void Workspace::resetClientAreas(uint desktopCount) { // Make it +1, so that it can be accessed as [1..numberofdesktops] workarea.clear(); workarea.resize(desktopCount + 1); restrictedmovearea.clear(); restrictedmovearea.resize(desktopCount + 1); screenarea.clear(); updateClientArea(true); } void Workspace::selectWmInputEventMask() { uint32_t presentMask = 0; Xcb::WindowAttributes attr(rootWindow()); if (!attr.isNull()) { presentMask = attr->your_event_mask; } Xcb::selectInput(rootWindow(), presentMask | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_COLOR_MAP_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | // For NotifyDetailNone XCB_EVENT_MASK_EXPOSURE ); } /** * Sends client \a c to desktop \a desk. * * Takes care of transients as well. */ void Workspace::sendClientToDesktop(AbstractClient* c, int desk, bool dont_activate) { if ((desk < 1 && desk != NET::OnAllDesktops) || desk > static_cast(VirtualDesktopManager::self()->count())) return; int old_desktop = c->desktop(); bool was_on_desktop = c->isOnDesktop(desk) || c->isOnAllDesktops(); c->setDesktop(desk); if (c->desktop() != desk) // No change or desktop forced return; desk = c->desktop(); // Client did range checking if (c->isOnDesktop(VirtualDesktopManager::self()->current())) { if (c->wantsTabFocus() && options->focusPolicyIsReasonable() && !was_on_desktop && // for stickyness changes !dont_activate) requestFocus(c); else restackClientUnderActive(c); } else raiseClient(c); c->checkWorkspacePosition( QRect(), old_desktop ); auto transients_stacking_order = ensureStackingOrder(c->transients()); for (auto it = transients_stacking_order.constBegin(); it != transients_stacking_order.constEnd(); ++it) sendClientToDesktop(*it, desk, dont_activate); updateClientArea(); } /** * checks whether the X Window with the input focus is on our X11 screen * if the window cannot be determined or inspected, resturn depends on whether there's actually * more than one screen * * this is NOT in any way related to XRandR multiscreen * */ extern bool is_multihead; // main.cpp bool Workspace::isOnCurrentHead() { if (!is_multihead) { return true; } Xcb::CurrentInput currentInput; if (currentInput.window() == XCB_WINDOW_NONE) { return !is_multihead; } Xcb::WindowGeometry geometry(currentInput.window()); if (geometry.isNull()) { // should not happen return !is_multihead; } return rootWindow() == geometry->root; } void Workspace::sendClientToScreen(AbstractClient* c, int screen) { c->sendToScreen(screen); } void Workspace::sendPingToWindow(xcb_window_t window, xcb_timestamp_t timestamp) { if (rootInfo()) { rootInfo()->sendPing(window, timestamp); } } /** * Delayed focus functions */ void Workspace::delayFocus() { requestFocus(delayfocus_client); cancelDelayFocus(); } void Workspace::requestDelayFocus(AbstractClient* c) { delayfocus_client = c; delete delayFocusTimer; delayFocusTimer = new QTimer(this); connect(delayFocusTimer, SIGNAL(timeout()), this, SLOT(delayFocus())); delayFocusTimer->setSingleShot(true); delayFocusTimer->start(options->delayFocusInterval()); } void Workspace::cancelDelayFocus() { delete delayFocusTimer; delayFocusTimer = nullptr; } bool Workspace::checkStartupNotification(xcb_window_t w, KStartupInfoId &id, KStartupInfoData &data) { return startup->checkStartup(w, id, data) == KStartupInfo::Match; } /** * Puts the focus on a dummy window * Just using XSetInputFocus() with None would block keyboard input */ void Workspace::focusToNull() { if (m_nullFocus) { m_nullFocus->focus(); } } void Workspace::setShowingDesktop(bool showing) { const bool changed = showing != showing_desktop; if (rootInfo() && changed) { rootInfo()->setShowingDesktop(showing); } showing_desktop = showing; AbstractClient *topDesk = nullptr; { // for the blocker RAII StackingUpdatesBlocker blocker(this); // updateLayer & lowerClient would invalidate stacking_order for (int i = stacking_order.count() - 1; i > -1; --i) { AbstractClient *c = qobject_cast(stacking_order.at(i)); if (c && c->isOnCurrentDesktop()) { if (c->isDock()) { c->updateLayer(); } else if (c->isDesktop() && c->isShown(true)) { c->updateLayer(); lowerClient(c); if (!topDesk) topDesk = c; if (auto group = c->group()) { foreach (X11Client *cm, group->members()) { cm->updateLayer(); } } } } } } // ~StackingUpdatesBlocker if (showing_desktop && topDesk) { requestFocus(topDesk); } else if (!showing_desktop && changed) { const auto client = FocusChain::self()->getForActivation(VirtualDesktopManager::self()->current()); if (client) { activateClient(client); } } if (changed) emit showingDesktopChanged(showing); } void Workspace::disableGlobalShortcutsForClient(bool disable) { if (global_shortcuts_disabled_for_client == disable) return; QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), QStringLiteral("org.kde.KGlobalAccel"), QStringLiteral("blockGlobalShortcuts")); message.setArguments(QList() << disable); QDBusConnection::sessionBus().asyncCall(message); global_shortcuts_disabled_for_client = disable; // Update also Alt+LMB actions etc. for (auto it = clients.constBegin(); it != clients.constEnd(); ++it) (*it)->updateMouseGrab(); } QString Workspace::supportInformation() const { QString support; const QString yes = QStringLiteral("yes\n"); const QString no = QStringLiteral("no\n"); support.append(ki18nc("Introductory text shown in the support information.", "KWin Support Information:\n" "The following information should be used when requesting support on e.g. https://forum.kde.org.\n" "It provides information about the currently running instance, which options are used,\n" "what OpenGL driver and which effects are running.\n" "Please post the information provided underneath this introductory text to a paste bin service\n" "like https://paste.kde.org instead of pasting into support threads.\n").toString()); support.append(QStringLiteral("\n==========================\n\n")); // all following strings are intended for support. They need to be pasted to e.g forums.kde.org // it is expected that the support will happen in English language or that the people providing // help understand English. Because of that all texts are not translated support.append(QStringLiteral("Version\n")); support.append(QStringLiteral("=======\n")); support.append(QStringLiteral("KWin version: ")); support.append(QStringLiteral(KWIN_VERSION_STRING)); support.append(QStringLiteral("\n")); support.append(QStringLiteral("Qt Version: ")); support.append(QString::fromUtf8(qVersion())); support.append(QStringLiteral("\n")); support.append(QStringLiteral("Qt compile version: %1\n").arg(QStringLiteral(QT_VERSION_STR))); support.append(QStringLiteral("XCB compile version: %1\n\n").arg(QStringLiteral(XCB_VERSION_STRING))); support.append(QStringLiteral("Operation Mode: ")); switch (kwinApp()->operationMode()) { case Application::OperationModeX11: support.append(QStringLiteral("X11 only")); break; case Application::OperationModeWaylandOnly: support.append(QStringLiteral("Wayland Only")); break; case Application::OperationModeXwayland: support.append(QStringLiteral("Xwayland")); break; } support.append(QStringLiteral("\n\n")); support.append(QStringLiteral("Build Options\n")); support.append(QStringLiteral("=============\n")); support.append(QStringLiteral("KWIN_BUILD_DECORATIONS: ")); #ifdef KWIN_BUILD_DECORATIONS support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("KWIN_BUILD_TABBOX: ")); #ifdef KWIN_BUILD_TABBOX support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("KWIN_BUILD_ACTIVITIES: ")); #ifdef KWIN_BUILD_ACTIVITIES support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_DRM: ")); #if HAVE_DRM support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_GBM: ")); #if HAVE_GBM support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_EGL_STREAMS: ")); #if HAVE_EGL_STREAMS support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_X11_XCB: ")); #if HAVE_X11_XCB support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_EPOXY_GLX: ")); #if HAVE_EPOXY_GLX support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("HAVE_WAYLAND_EGL: ")); #if HAVE_WAYLAND_EGL support.append(yes); #else support.append(no); #endif support.append(QStringLiteral("\n")); if (auto c = kwinApp()->x11Connection()) { support.append(QStringLiteral("X11\n")); support.append(QStringLiteral("===\n")); auto x11setup = xcb_get_setup(c); support.append(QStringLiteral("Vendor: %1\n").arg(QString::fromUtf8(QByteArray::fromRawData(xcb_setup_vendor(x11setup), xcb_setup_vendor_length(x11setup))))); support.append(QStringLiteral("Vendor Release: %1\n").arg(x11setup->release_number)); support.append(QStringLiteral("Protocol Version/Revision: %1/%2\n").arg(x11setup->protocol_major_version).arg(x11setup->protocol_minor_version)); const auto extensions = Xcb::Extensions::self()->extensions(); for (const auto &e : extensions) { support.append(QStringLiteral("%1: %2; Version: 0x%3\n").arg(QString::fromUtf8(e.name)) .arg(e.present ? yes.trimmed() : no.trimmed()) .arg(QString::number(e.version, 16))); } support.append(QStringLiteral("\n")); } if (auto bridge = Decoration::DecorationBridge::self()) { support.append(QStringLiteral("Decoration\n")); support.append(QStringLiteral("==========\n")); support.append(bridge->supportInformation()); support.append(QStringLiteral("\n")); } support.append(QStringLiteral("Platform\n")); support.append(QStringLiteral("==========\n")); support.append(kwinApp()->platform()->supportInformation()); support.append(QStringLiteral("\n")); support.append(QStringLiteral("Options\n")); support.append(QStringLiteral("=======\n")); const QMetaObject *metaOptions = options->metaObject(); auto printProperty = [] (const QVariant &variant) { if (variant.type() == QVariant::Size) { const QSize &s = variant.toSize(); return QStringLiteral("%1x%2").arg(QString::number(s.width())).arg(QString::number(s.height())); } if (QLatin1String(variant.typeName()) == QLatin1String("KWin::OpenGLPlatformInterface") || QLatin1String(variant.typeName()) == QLatin1String("KWin::Options::WindowOperation")) { return QString::number(variant.toInt()); } return variant.toString(); }; for (int i=0; ipropertyCount(); ++i) { const QMetaProperty property = metaOptions->property(i); if (QLatin1String(property.name()) == QLatin1String("objectName")) { continue; } support.append(QStringLiteral("%1: %2\n").arg(property.name()).arg(printProperty(options->property(property.name())))); } support.append(QStringLiteral("\nScreen Edges\n")); support.append(QStringLiteral( "============\n")); const QMetaObject *metaScreenEdges = ScreenEdges::self()->metaObject(); for (int i=0; ipropertyCount(); ++i) { const QMetaProperty property = metaScreenEdges->property(i); if (QLatin1String(property.name()) == QLatin1String("objectName")) { continue; } support.append(QStringLiteral("%1: %2\n").arg(property.name()).arg(printProperty(ScreenEdges::self()->property(property.name())))); } support.append(QStringLiteral("\nScreens\n")); support.append(QStringLiteral( "=======\n")); support.append(QStringLiteral("Multi-Head: ")); if (is_multihead) { support.append(QStringLiteral("yes\n")); support.append(QStringLiteral("Head: %1\n").arg(screen_number)); } else { support.append(QStringLiteral("no\n")); } support.append(QStringLiteral("Active screen follows mouse: ")); if (screens()->isCurrentFollowsMouse()) support.append(QStringLiteral(" yes\n")); else support.append(QStringLiteral(" no\n")); support.append(QStringLiteral("Number of Screens: %1\n\n").arg(screens()->count())); for (int i=0; icount(); ++i) { const QRect geo = screens()->geometry(i); support.append(QStringLiteral("Screen %1:\n").arg(i)); support.append(QStringLiteral("---------\n")); support.append(QStringLiteral("Name: %1\n").arg(screens()->name(i))); support.append(QStringLiteral("Geometry: %1,%2,%3x%4\n") .arg(geo.x()) .arg(geo.y()) .arg(geo.width()) .arg(geo.height())); support.append(QStringLiteral("Scale: %1\n").arg(screens()->scale(i))); support.append(QStringLiteral("Refresh Rate: %1\n\n").arg(screens()->refreshRate(i))); } support.append(QStringLiteral("\nCompositing\n")); support.append(QStringLiteral( "===========\n")); if (effects) { support.append(QStringLiteral("Compositing is active\n")); switch (effects->compositingType()) { case OpenGL2Compositing: case OpenGLCompositing: { GLPlatform *platform = GLPlatform::instance(); if (platform->isGLES()) { support.append(QStringLiteral("Compositing Type: OpenGL ES 2.0\n")); } else { support.append(QStringLiteral("Compositing Type: OpenGL\n")); } support.append(QStringLiteral("OpenGL vendor string: ") + QString::fromUtf8(platform->glVendorString()) + QStringLiteral("\n")); support.append(QStringLiteral("OpenGL renderer string: ") + QString::fromUtf8(platform->glRendererString()) + QStringLiteral("\n")); support.append(QStringLiteral("OpenGL version string: ") + QString::fromUtf8(platform->glVersionString()) + QStringLiteral("\n")); support.append(QStringLiteral("OpenGL platform interface: ")); switch (platform->platformInterface()) { case GlxPlatformInterface: support.append(QStringLiteral("GLX")); break; case EglPlatformInterface: support.append(QStringLiteral("EGL")); break; default: support.append(QStringLiteral("UNKNOWN")); } support.append(QStringLiteral("\n")); if (platform->supports(LimitedGLSL) || platform->supports(GLSL)) support.append(QStringLiteral("OpenGL shading language version string: ") + QString::fromUtf8(platform->glShadingLanguageVersionString()) + QStringLiteral("\n")); support.append(QStringLiteral("Driver: ") + GLPlatform::driverToString(platform->driver()) + QStringLiteral("\n")); if (!platform->isMesaDriver()) support.append(QStringLiteral("Driver version: ") + GLPlatform::versionToString(platform->driverVersion()) + QStringLiteral("\n")); support.append(QStringLiteral("GPU class: ") + GLPlatform::chipClassToString(platform->chipClass()) + QStringLiteral("\n")); support.append(QStringLiteral("OpenGL version: ") + GLPlatform::versionToString(platform->glVersion()) + QStringLiteral("\n")); if (platform->supports(LimitedGLSL) || platform->supports(GLSL)) support.append(QStringLiteral("GLSL version: ") + GLPlatform::versionToString(platform->glslVersion()) + QStringLiteral("\n")); if (platform->isMesaDriver()) support.append(QStringLiteral("Mesa version: ") + GLPlatform::versionToString(platform->mesaVersion()) + QStringLiteral("\n")); if (platform->serverVersion() > 0) support.append(QStringLiteral("X server version: ") + GLPlatform::versionToString(platform->serverVersion()) + QStringLiteral("\n")); if (platform->kernelVersion() > 0) support.append(QStringLiteral("Linux kernel version: ") + GLPlatform::versionToString(platform->kernelVersion()) + QStringLiteral("\n")); support.append(QStringLiteral("Direct rendering: ")); support.append(QStringLiteral("Requires strict binding: ")); if (!platform->isLooseBinding()) { support.append(QStringLiteral("yes\n")); } else { support.append(QStringLiteral("no\n")); } support.append(QStringLiteral("GLSL shaders: ")); if (platform->supports(GLSL)) { if (platform->supports(LimitedGLSL)) { support.append(QStringLiteral(" limited\n")); } else { support.append(QStringLiteral(" yes\n")); } } else { support.append(QStringLiteral(" no\n")); } support.append(QStringLiteral("Texture NPOT support: ")); if (platform->supports(TextureNPOT)) { if (platform->supports(LimitedNPOT)) { support.append(QStringLiteral(" limited\n")); } else { support.append(QStringLiteral(" yes\n")); } } else { support.append(QStringLiteral(" no\n")); } support.append(QStringLiteral("Virtual Machine: ")); if (platform->isVirtualMachine()) { support.append(QStringLiteral(" yes\n")); } else { support.append(QStringLiteral(" no\n")); } support.append(QStringLiteral("OpenGL 2 Shaders are used\n")); support.append(QStringLiteral("Painting blocks for vertical retrace: ")); if (m_compositor->scene()->blocksForRetrace()) support.append(QStringLiteral(" yes\n")); else support.append(QStringLiteral(" no\n")); break; } case XRenderCompositing: support.append(QStringLiteral("Compositing Type: XRender\n")); break; case QPainterCompositing: support.append("Compositing Type: QPainter\n"); break; case NoCompositing: default: support.append(QStringLiteral("Something is really broken, neither OpenGL nor XRender is used")); } support.append(QStringLiteral("\nLoaded Effects:\n")); support.append(QStringLiteral( "---------------\n")); foreach (const QString &effect, static_cast(effects)->loadedEffects()) { support.append(effect + QStringLiteral("\n")); } support.append(QStringLiteral("\nCurrently Active Effects:\n")); support.append(QStringLiteral( "-------------------------\n")); foreach (const QString &effect, static_cast(effects)->activeEffects()) { support.append(effect + QStringLiteral("\n")); } support.append(QStringLiteral("\nEffect Settings:\n")); support.append(QStringLiteral( "----------------\n")); foreach (const QString &effect, static_cast(effects)->loadedEffects()) { support.append(static_cast(effects)->supportInformation(effect)); support.append(QStringLiteral("\n")); } } else { support.append(QStringLiteral("Compositing is not active\n")); } return support; } X11Client *Workspace::findClient(std::function func) const { if (X11Client *ret = Toplevel::findInList(clients, func)) { return ret; } if (X11Client *ret = Toplevel::findInList(desktops, func)) { return ret; } return nullptr; } AbstractClient *Workspace::findAbstractClient(std::function func) const { if (AbstractClient *ret = Toplevel::findInList(m_allClients, func)) { return ret; } if (X11Client *ret = Toplevel::findInList(desktops, func)) { return ret; } if (InternalClient *ret = Toplevel::findInList(m_internalClients, func)) { return ret; } return nullptr; } Unmanaged *Workspace::findUnmanaged(std::function func) const { return Toplevel::findInList(unmanaged, func); } Unmanaged *Workspace::findUnmanaged(xcb_window_t w) const { return findUnmanaged([w](const Unmanaged *u) { return u->window() == w; }); } X11Client *Workspace::findClient(Predicate predicate, xcb_window_t w) const { switch (predicate) { case Predicate::WindowMatch: return findClient([w](const X11Client *c) { return c->window() == w; }); case Predicate::WrapperIdMatch: return findClient([w](const X11Client *c) { return c->wrapperId() == w; }); case Predicate::FrameIdMatch: return findClient([w](const X11Client *c) { return c->frameId() == w; }); case Predicate::InputIdMatch: return findClient([w](const X11Client *c) { return c->inputId() == w; }); } return nullptr; } Toplevel *Workspace::findToplevel(std::function func) const { if (X11Client *ret = Toplevel::findInList(clients, func)) { return ret; } if (X11Client *ret = Toplevel::findInList(desktops, func)) { return ret; } if (Unmanaged *ret = Toplevel::findInList(unmanaged, func)) { return ret; } if (InternalClient *ret = Toplevel::findInList(m_internalClients, func)) { return ret; } return nullptr; } void Workspace::forEachToplevel(std::function func) { std::for_each(m_allClients.constBegin(), m_allClients.constEnd(), func); std::for_each(desktops.constBegin(), desktops.constEnd(), func); std::for_each(deleted.constBegin(), deleted.constEnd(), func); std::for_each(unmanaged.constBegin(), unmanaged.constEnd(), func); std::for_each(m_internalClients.constBegin(), m_internalClients.constEnd(), func); } bool Workspace::hasClient(const AbstractClient *c) { if (auto cc = dynamic_cast(c)) { return hasClient(cc); } else { return findAbstractClient([c](const AbstractClient *test) { return test == c; }) != nullptr; } return false; } void Workspace::forEachAbstractClient(std::function< void (AbstractClient*) > func) { std::for_each(m_allClients.constBegin(), m_allClients.constEnd(), func); std::for_each(desktops.constBegin(), desktops.constEnd(), func); std::for_each(m_internalClients.constBegin(), m_internalClients.constEnd(), func); } Toplevel *Workspace::findInternal(QWindow *w) const { if (!w) { return nullptr; } if (kwinApp()->operationMode() == Application::OperationModeX11) { return findUnmanaged(w->winId()); } for (InternalClient *client : m_internalClients) { if (client->internalWindow() == w) { return client; } } return nullptr; } bool Workspace::compositing() const { return m_compositor && m_compositor->scene(); } void Workspace::markXStackingOrderAsDirty() { m_xStackingDirty = true; if (kwinApp()->x11Connection()) { m_xStackingQueryTree.reset(new Xcb::Tree(kwinApp()->x11RootWindow())); } } void Workspace::setWasUserInteraction() { if (was_user_interaction) { return; } was_user_interaction = true; // might be called from within the filter, so delay till we now the filter returned QTimer::singleShot(0, this, [this] { m_wasUserInteractionFilter.reset(); } ); } void Workspace::updateTabbox() { #ifdef KWIN_BUILD_TABBOX TabBox::TabBox *tabBox = TabBox::TabBox::self(); if (tabBox->isDisplayed()) { tabBox->reset(true); } #endif } void Workspace::addInternalClient(InternalClient *client) { m_internalClients.append(client); setupClientConnections(client); client->updateLayer(); if (client->isDecorated()) { client->keepInArea(clientArea(FullScreenArea, client)); } markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); emit internalClientAdded(client); } void Workspace::removeInternalClient(InternalClient *client) { m_internalClients.removeOne(client); markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); emit internalClientRemoved(client); } Group* Workspace::findGroup(xcb_window_t leader) const { Q_ASSERT(leader != XCB_WINDOW_NONE); for (auto it = groups.constBegin(); it != groups.constEnd(); ++it) if ((*it)->leader() == leader) return *it; return nullptr; } // Client is group transient, but has no group set. Try to find // group with windows with the same client leader. Group* Workspace::findClientLeaderGroup(const X11Client *c) const { Group* ret = nullptr; for (auto it = clients.constBegin(); it != clients.constEnd(); ++it) { if (*it == c) continue; if ((*it)->wmClientLeader() == c->wmClientLeader()) { if (ret == nullptr || ret == (*it)->group()) ret = (*it)->group(); else { // There are already two groups with the same client leader. // This most probably means the app uses group transients without // setting group for its windows. Merging the two groups is a bad // hack, but there's no really good solution for this case. QList old_group = (*it)->group()->members(); // old_group autodeletes when being empty for (int pos = 0; pos < old_group.count(); ++pos) { X11Client *tmp = old_group[ pos ]; if (tmp != c) tmp->changeClientLeaderGroup(ret); } } } } return ret; } void Workspace::updateMinimizedOfTransients(AbstractClient* c) { // if mainwindow is minimized or shaded, minimize transients too if (c->isMinimized()) { for (auto it = c->transients().constBegin(); it != c->transients().constEnd(); ++it) { if ((*it)->isModal()) continue; // there's no reason to hide modal dialogs with the main client // but to keep them to eg. watch progress or whatever if (!(*it)->isMinimized()) { (*it)->minimize(); updateMinimizedOfTransients((*it)); } } if (c->isModal()) { // if a modal dialog is minimized, minimize its mainwindow too foreach (AbstractClient * c2, c->mainClients()) c2->minimize(); } } else { // else unmiminize the transients for (auto it = c->transients().constBegin(); it != c->transients().constEnd(); ++it) { if ((*it)->isMinimized()) { (*it)->unminimize(); updateMinimizedOfTransients((*it)); } } if (c->isModal()) { foreach (AbstractClient * c2, c->mainClients()) c2->unminimize(); } } } /** * Sets the client \a c's transient windows' on_all_desktops property to \a on_all_desktops. */ void Workspace::updateOnAllDesktopsOfTransients(AbstractClient* c) { for (auto it = c->transients().constBegin(); it != c->transients().constEnd(); ++it) { if ((*it)->isOnAllDesktops() != c->isOnAllDesktops()) (*it)->setOnAllDesktops(c->isOnAllDesktops()); } } // A new window has been mapped. Check if it's not a mainwindow for some already existing transient window. void Workspace::checkTransients(xcb_window_t w) { for (auto it = clients.constBegin(); it != clients.constEnd(); ++it) (*it)->checkTransient(w); } /** * Resizes the workspace after an XRANDR screen size change */ void Workspace::desktopResized() { QRect geom = screens()->geometry(); if (rootInfo()) { NETSize desktop_geometry; desktop_geometry.width = geom.width(); desktop_geometry.height = geom.height(); rootInfo()->setDesktopGeometry(desktop_geometry); } updateClientArea(); saveOldScreenSizes(); // after updateClientArea(), so that one still uses the previous one // TODO: emit a signal instead and remove the deep function calls into edges and effects ScreenEdges::self()->recreateEdges(); if (effects) { static_cast(effects)->desktopResized(geom.size()); } } void Workspace::saveOldScreenSizes() { olddisplaysize = screens()->displaySize(); oldscreensizes.clear(); for( int i = 0; i < screens()->count(); ++i ) oldscreensizes.append( screens()->geometry( i )); } /** * Updates the current client areas according to the current clients. * * If the area changes or force is @c true, the new areas are propagated to the world. * * The client area is the area that is available for clients (that * which is not taken by windows like panels, the top-of-screen menu * etc). * * @see clientArea() */ void Workspace::updateClientArea(bool force) { const Screens *s = Screens::self(); int nscreens = s->count(); const int numberOfDesktops = VirtualDesktopManager::self()->count(); QVector< QRect > new_wareas(numberOfDesktops + 1); QVector< StrutRects > new_rmoveareas(numberOfDesktops + 1); QVector< QVector< QRect > > new_sareas(numberOfDesktops + 1); QVector< QRect > screens(nscreens); QRect desktopArea; for (int i = 0; i < nscreens; i++) { desktopArea |= s->geometry(i); } for (int iS = 0; iS < nscreens; iS ++) { screens [iS] = s->geometry(iS); } for (int i = 1; i <= numberOfDesktops; ++i) { new_wareas[ i ] = desktopArea; new_sareas[ i ].resize(nscreens); for (int iS = 0; iS < nscreens; iS ++) new_sareas[ i ][ iS ] = screens[ iS ]; } for (auto it = clients.constBegin(); it != clients.constEnd(); ++it) { if (!(*it)->hasStrut()) continue; QRect r = (*it)->adjustedClientArea(desktopArea, desktopArea); // sanity check that a strut doesn't exclude a complete screen geometry // this is a violation to EWMH, as KWin just ignores the strut for (int i = 0; i < Screens::self()->count(); i++) { if (!r.intersects(Screens::self()->geometry(i))) { qCDebug(KWIN_CORE) << "Adjusted client area would exclude a complete screen, ignore"; r = desktopArea; break; } } StrutRects strutRegion = (*it)->strutRects(); const QRect clientsScreenRect = KWin::screens()->geometry((*it)->screen()); for (auto strut = strutRegion.begin(); strut != strutRegion.end(); strut++) { *strut = StrutRect((*strut).intersected(clientsScreenRect), (*strut).area()); } // Ignore offscreen xinerama struts. These interfere with the larger monitors on the setup // and should be ignored so that applications that use the work area to work out where // windows can go can use the entire visible area of the larger monitors. // This goes against the EWMH description of the work area but it is a toss up between // having unusable sections of the screen (Which can be quite large with newer monitors) // or having some content appear offscreen (Relatively rare compared to other). bool hasOffscreenXineramaStrut = (*it)->hasOffscreenXineramaStrut(); if ((*it)->isOnAllDesktops()) { for (int i = 1; i <= numberOfDesktops; ++i) { if (!hasOffscreenXineramaStrut) new_wareas[ i ] = new_wareas[ i ].intersected(r); new_rmoveareas[ i ] += strutRegion; for (int iS = 0; iS < nscreens; iS ++) { const auto geo = new_sareas[ i ][ iS ].intersected( (*it)->adjustedClientArea(desktopArea, screens[ iS ])); // ignore the geometry if it results in the screen getting removed completely if (!geo.isEmpty()) { new_sareas[ i ][ iS ] = geo; } } } } else { if (!hasOffscreenXineramaStrut) new_wareas[(*it)->desktop()] = new_wareas[(*it)->desktop()].intersected(r); new_rmoveareas[(*it)->desktop()] += strutRegion; for (int iS = 0; iS < nscreens; iS ++) { // qDebug() << "adjusting new_sarea: " << screens[ iS ]; const auto geo = new_sareas[(*it)->desktop()][ iS ].intersected( (*it)->adjustedClientArea(desktopArea, screens[ iS ])); // ignore the geometry if it results in the screen getting removed completely if (!geo.isEmpty()) { new_sareas[(*it)->desktop()][ iS ] = geo; } } } } if (waylandServer()) { auto updateStrutsForWaylandClient = [&] (AbstractClient *c) { // assuming that only docks have "struts" and that all docks have a strut if (!c->hasStrut()) { return; } auto margins = [c] (const QRect &geometry) { QMargins margins; if (!geometry.intersects(c->frameGeometry())) { return margins; } // figure out which areas of the overall screen setup it borders const bool left = c->frameGeometry().left() == geometry.left(); const bool right = c->frameGeometry().right() == geometry.right(); const bool top = c->frameGeometry().top() == geometry.top(); const bool bottom = c->frameGeometry().bottom() == geometry.bottom(); const bool horizontal = c->frameGeometry().width() >= c->frameGeometry().height(); if (left && ((!top && !bottom) || !horizontal)) { margins.setLeft(c->frameGeometry().width()); } if (right && ((!top && !bottom) || !horizontal)) { margins.setRight(c->frameGeometry().width()); } if (top && ((!left && !right) || horizontal)) { margins.setTop(c->frameGeometry().height()); } if (bottom && ((!left && !right) || horizontal)) { margins.setBottom(c->frameGeometry().height()); } return margins; }; auto marginsToStrutArea = [] (const QMargins &margins) { if (margins.left() != 0) { return StrutAreaLeft; } if (margins.right() != 0) { return StrutAreaRight; } if (margins.top() != 0) { return StrutAreaTop; } if (margins.bottom() != 0) { return StrutAreaBottom; } return StrutAreaInvalid; }; const auto strut = margins(KWin::screens()->geometry(c->screen())); const StrutRects strutRegion = StrutRects{StrutRect(c->frameGeometry(), marginsToStrutArea(strut))}; QRect r = desktopArea - margins(KWin::screens()->geometry()); if (c->isOnAllDesktops()) { for (int i = 1; i <= numberOfDesktops; ++i) { new_wareas[ i ] = new_wareas[ i ].intersected(r); for (int iS = 0; iS < nscreens; ++iS) { new_sareas[ i ][ iS ] = new_sareas[ i ][ iS ].intersected(screens[iS] - margins(screens[iS])); } new_rmoveareas[ i ] += strutRegion; } } else { new_wareas[c->desktop()] = new_wareas[c->desktop()].intersected(r); for (int iS = 0; iS < nscreens; iS++) { new_sareas[c->desktop()][ iS ] = new_sareas[c->desktop()][ iS ].intersected(screens[iS] - margins(screens[iS])); } new_rmoveareas[ c->desktop() ] += strutRegion; } }; const auto clients = waylandServer()->clients(); for (auto c : clients) { updateStrutsForWaylandClient(c); } } #if 0 for (int i = 1; i <= numberOfDesktops(); ++i) { for (int iS = 0; iS < nscreens; iS ++) qCDebug(KWIN_CORE) << "new_sarea: " << new_sareas[ i ][ iS ]; } #endif bool changed = force; if (screenarea.isEmpty()) changed = true; for (int i = 1; !changed && i <= numberOfDesktops; ++i) { if (workarea[ i ] != new_wareas[ i ]) changed = true; if (restrictedmovearea[ i ] != new_rmoveareas[ i ]) changed = true; if (screenarea[ i ].size() != new_sareas[ i ].size()) changed = true; for (int iS = 0; !changed && iS < nscreens; iS ++) if (new_sareas[ i ][ iS ] != screenarea [ i ][ iS ]) changed = true; } if (changed) { workarea = new_wareas; oldrestrictedmovearea = restrictedmovearea; restrictedmovearea = new_rmoveareas; screenarea = new_sareas; if (rootInfo()) { NETRect r; for (int i = 1; i <= numberOfDesktops; i++) { r.pos.x = workarea[ i ].x(); r.pos.y = workarea[ i ].y(); r.size.width = workarea[ i ].width(); r.size.height = workarea[ i ].height(); rootInfo()->setWorkArea(i, r); } } for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) (*it)->checkWorkspacePosition(); oldrestrictedmovearea.clear(); // reset, no longer valid or needed } } void Workspace::updateClientArea() { updateClientArea(false); } /** * Returns the area available for clients. This is the desktop * geometry minus windows on the dock. Placement algorithms should * refer to this rather than Screens::geometry. */ QRect Workspace::clientArea(clientAreaOption opt, int screen, int desktop) const { if (desktop == NETWinInfo::OnAllDesktops || desktop == 0) desktop = VirtualDesktopManager::self()->current(); if (screen == -1) screen = screens()->current(); const QSize displaySize = screens()->displaySize(); QRect sarea, warea; if (is_multihead) { sarea = (!screenarea.isEmpty() && screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes ? screenarea[ desktop ][ screen_number ] : screens()->geometry(screen_number); warea = workarea[ desktop ].isNull() ? screens()->geometry(screen_number) : workarea[ desktop ]; } else { sarea = (!screenarea.isEmpty() && screen < screenarea[ desktop ].size()) // screens may be missing during KWin initialization or screen config changes ? screenarea[ desktop ][ screen ] : screens()->geometry(screen); warea = workarea[ desktop ].isNull() ? QRect(0, 0, displaySize.width(), displaySize.height()) : workarea[ desktop ]; } switch(opt) { case MaximizeArea: case PlacementArea: return sarea; case MaximizeFullArea: case FullScreenArea: case MovementArea: case ScreenArea: if (is_multihead) return screens()->geometry(screen_number); else return screens()->geometry(screen); case WorkArea: if (is_multihead) return sarea; else return warea; case FullArea: return QRect(0, 0, displaySize.width(), displaySize.height()); } abort(); } QRect Workspace::clientArea(clientAreaOption opt, const QPoint& p, int desktop) const { return clientArea(opt, screens()->number(p), desktop); } QRect Workspace::clientArea(clientAreaOption opt, const AbstractClient* c) const { return clientArea(opt, c->frameGeometry().center(), c->desktop()); } QRegion Workspace::restrictedMoveArea(int desktop, StrutAreas areas) const { if (desktop == NETWinInfo::OnAllDesktops || desktop == 0) desktop = VirtualDesktopManager::self()->current(); QRegion region; foreach (const StrutRect & rect, restrictedmovearea[desktop]) if (areas & rect.area()) region += rect; return region; } bool Workspace::inUpdateClientArea() const { return !oldrestrictedmovearea.isEmpty(); } QRegion Workspace::previousRestrictedMoveArea(int desktop, StrutAreas areas) const { if (desktop == NETWinInfo::OnAllDesktops || desktop == 0) desktop = VirtualDesktopManager::self()->current(); QRegion region; foreach (const StrutRect & rect, oldrestrictedmovearea.at(desktop)) if (areas & rect.area()) region += rect; return region; } QVector< QRect > Workspace::previousScreenSizes() const { return oldscreensizes; } int Workspace::oldDisplayWidth() const { return olddisplaysize.width(); } int Workspace::oldDisplayHeight() const { return olddisplaysize.height(); } /** * Client \a c is moved around to position \a pos. This gives the * workspace the opportunity to interveniate and to implement * snap-to-windows functionality. * * The parameter \a snapAdjust is a multiplier used to calculate the * effective snap zones. When 1.0, it means that the snap zones will be * used without change. */ QPoint Workspace::adjustClientPosition(AbstractClient* c, QPoint pos, bool unrestricted, double snapAdjust) { QSize borderSnapZone(options->borderSnapZone(), options->borderSnapZone()); QRect maxRect; int guideMaximized = MaximizeRestore; if (c->maximizeMode() != MaximizeRestore) { maxRect = clientArea(MaximizeArea, pos + c->rect().center(), c->desktop()); QRect geo = c->frameGeometry(); if (c->maximizeMode() & MaximizeHorizontal && (geo.x() == maxRect.left() || geo.right() == maxRect.right())) { guideMaximized |= MaximizeHorizontal; borderSnapZone.setWidth(qMax(borderSnapZone.width() + 2, maxRect.width() / 16)); } if (c->maximizeMode() & MaximizeVertical && (geo.y() == maxRect.top() || geo.bottom() == maxRect.bottom())) { guideMaximized |= MaximizeVertical; borderSnapZone.setHeight(qMax(borderSnapZone.height() + 2, maxRect.height() / 16)); } } if (options->windowSnapZone() || !borderSnapZone.isNull() || options->centerSnapZone()) { const bool sOWO = options->isSnapOnlyWhenOverlapping(); const int screen = screens()->number(pos + c->rect().center()); if (maxRect.isNull()) maxRect = clientArea(MovementArea, screen, c->desktop()); const int xmin = maxRect.left(); const int xmax = maxRect.right() + 1; //desk size const int ymin = maxRect.top(); const int ymax = maxRect.bottom() + 1; const int cx(pos.x()); const int cy(pos.y()); const int cw(c->width()); const int ch(c->height()); const int rx(cx + cw); const int ry(cy + ch); //these don't change int nx(cx), ny(cy); //buffers int deltaX(xmax); int deltaY(ymax); //minimum distance to other clients int lx, ly, lrx, lry; //coords and size for the comparison client, l // border snap const int snapX = borderSnapZone.width() * snapAdjust; //snap trigger const int snapY = borderSnapZone.height() * snapAdjust; if (snapX || snapY) { QRect geo = c->frameGeometry(); QMargins frameMargins = c->frameMargins(); // snap to titlebar / snap to window borders on inner screen edges AbstractClient::Position titlePos = c->titlebarPosition(); if (frameMargins.left() && (titlePos == AbstractClient::PositionLeft || (c->maximizeMode() & MaximizeHorizontal) || screens()->intersecting(geo.translated(maxRect.x() - (frameMargins.left() + geo.x()), 0)) > 1)) { frameMargins.setLeft(0); } if (frameMargins.right() && (titlePos == AbstractClient::PositionRight || (c->maximizeMode() & MaximizeHorizontal) || screens()->intersecting(geo.translated(maxRect.right() + frameMargins.right() - geo.right(), 0)) > 1)) { frameMargins.setRight(0); } if (frameMargins.top() && (titlePos == AbstractClient::PositionTop || (c->maximizeMode() & MaximizeVertical) || screens()->intersecting(geo.translated(0, maxRect.y() - (frameMargins.top() + geo.y()))) > 1)) { frameMargins.setTop(0); } if (frameMargins.bottom() && (titlePos == AbstractClient::PositionBottom || (c->maximizeMode() & MaximizeVertical) || screens()->intersecting(geo.translated(0, maxRect.bottom() + frameMargins.bottom() - geo.bottom())) > 1)) { frameMargins.setBottom(0); } if ((sOWO ? (cx < xmin) : true) && (qAbs(xmin - cx) < snapX)) { deltaX = xmin - cx; nx = xmin - frameMargins.left(); } if ((sOWO ? (rx > xmax) : true) && (qAbs(rx - xmax) < snapX) && (qAbs(xmax - rx) < deltaX)) { deltaX = rx - xmax; nx = xmax - cw + frameMargins.right(); } if ((sOWO ? (cy < ymin) : true) && (qAbs(ymin - cy) < snapY)) { deltaY = ymin - cy; ny = ymin - frameMargins.top(); } if ((sOWO ? (ry > ymax) : true) && (qAbs(ry - ymax) < snapY) && (qAbs(ymax - ry) < deltaY)) { deltaY = ry - ymax; ny = ymax - ch + frameMargins.bottom(); } } // windows snap int snap = options->windowSnapZone() * snapAdjust; if (snap) { for (auto l = m_allClients.constBegin(); l != m_allClients.constEnd(); ++l) { if ((*l) == c) continue; if ((*l)->isMinimized()) continue; // is minimized if (!(*l)->isShown(false)) continue; if (!((*l)->isOnDesktop(c->desktop()) || c->isOnDesktop((*l)->desktop()))) continue; // wrong virtual desktop if (!(*l)->isOnCurrentActivity()) continue; // wrong activity if ((*l)->isDesktop() || (*l)->isSplash()) continue; lx = (*l)->x(); ly = (*l)->y(); lrx = lx + (*l)->width(); lry = ly + (*l)->height(); if (!(guideMaximized & MaximizeHorizontal) && (((cy <= lry) && (cy >= ly)) || ((ry >= ly) && (ry <= lry)) || ((cy <= ly) && (ry >= lry)))) { if ((sOWO ? (cx < lrx) : true) && (qAbs(lrx - cx) < snap) && (qAbs(lrx - cx) < deltaX)) { deltaX = qAbs(lrx - cx); nx = lrx; } if ((sOWO ? (rx > lx) : true) && (qAbs(rx - lx) < snap) && (qAbs(rx - lx) < deltaX)) { deltaX = qAbs(rx - lx); nx = lx - cw; } } if (!(guideMaximized & MaximizeVertical) && (((cx <= lrx) && (cx >= lx)) || ((rx >= lx) && (rx <= lrx)) || ((cx <= lx) && (rx >= lrx)))) { if ((sOWO ? (cy < lry) : true) && (qAbs(lry - cy) < snap) && (qAbs(lry - cy) < deltaY)) { deltaY = qAbs(lry - cy); ny = lry; } //if ( (qAbs( ry-ly ) < snap) && (qAbs( ry - ly ) < deltaY )) if ((sOWO ? (ry > ly) : true) && (qAbs(ry - ly) < snap) && (qAbs(ry - ly) < deltaY)) { deltaY = qAbs(ry - ly); ny = ly - ch; } } // Corner snapping if (!(guideMaximized & MaximizeVertical) && (nx == lrx || nx + cw == lx)) { if ((sOWO ? (ry > lry) : true) && (qAbs(lry - ry) < snap) && (qAbs(lry - ry) < deltaY)) { deltaY = qAbs(lry - ry); ny = lry - ch; } if ((sOWO ? (cy < ly) : true) && (qAbs(cy - ly) < snap) && (qAbs(cy - ly) < deltaY)) { deltaY = qAbs(cy - ly); ny = ly; } } if (!(guideMaximized & MaximizeHorizontal) && (ny == lry || ny + ch == ly)) { if ((sOWO ? (rx > lrx) : true) && (qAbs(lrx - rx) < snap) && (qAbs(lrx - rx) < deltaX)) { deltaX = qAbs(lrx - rx); nx = lrx - cw; } if ((sOWO ? (cx < lx) : true) && (qAbs(cx - lx) < snap) && (qAbs(cx - lx) < deltaX)) { deltaX = qAbs(cx - lx); nx = lx; } } } } // center snap snap = options->centerSnapZone() * snapAdjust; //snap trigger if (snap) { int diffX = qAbs((xmin + xmax) / 2 - (cx + cw / 2)); int diffY = qAbs((ymin + ymax) / 2 - (cy + ch / 2)); if (diffX < snap && diffY < snap && diffX < deltaX && diffY < deltaY) { // Snap to center of screen nx = (xmin + xmax) / 2 - cw / 2; ny = (ymin + ymax) / 2 - ch / 2; } else if (options->borderSnapZone()) { // Enhance border snap if ((nx == xmin || nx == xmax - cw) && diffY < snap && diffY < deltaY) { // Snap to vertical center on screen edge ny = (ymin + ymax) / 2 - ch / 2; } else if (((unrestricted ? ny == ymin : ny <= ymin) || ny == ymax - ch) && diffX < snap && diffX < deltaX) { // Snap to horizontal center on screen edge nx = (xmin + xmax) / 2 - cw / 2; } } } pos = QPoint(nx, ny); } return pos; } QRect Workspace::adjustClientSize(AbstractClient* c, QRect moveResizeGeom, int mode) { //adapted from adjustClientPosition on 29May2004 //this function is called when resizing a window and will modify //the new dimensions to snap to other windows/borders if appropriate if (options->windowSnapZone() || options->borderSnapZone()) { // || options->centerSnapZone ) const bool sOWO = options->isSnapOnlyWhenOverlapping(); const QRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop()); const int xmin = maxRect.left(); const int xmax = maxRect.right(); //desk size const int ymin = maxRect.top(); const int ymax = maxRect.bottom(); const int cx(moveResizeGeom.left()); const int cy(moveResizeGeom.top()); const int rx(moveResizeGeom.right()); const int ry(moveResizeGeom.bottom()); int newcx(cx), newcy(cy); //buffers int newrx(rx), newry(ry); int deltaX(xmax); int deltaY(ymax); //minimum distance to other clients int lx, ly, lrx, lry; //coords and size for the comparison client, l // border snap int snap = options->borderSnapZone(); //snap trigger if (snap) { deltaX = int(snap); deltaY = int(snap); #define SNAP_BORDER_TOP \ if ((sOWO?(newcyymax):true) && (qAbs(ymax-newry)xmax):true) && (qAbs(xmax-newrx)windowSnapZone(); if (snap) { deltaX = int(snap); deltaY = int(snap); for (auto l = m_allClients.constBegin(); l != m_allClients.constEnd(); ++l) { if ((*l)->isOnDesktop(VirtualDesktopManager::self()->current()) && !(*l)->isMinimized() && (*l) != c) { lx = (*l)->x() - 1; ly = (*l)->y() - 1; lrx = (*l)->x() + (*l)->width(); lry = (*l)->y() + (*l)->height(); #define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy >= ly )) || \ (( newry >= ly ) && ( newry <= lry )) || \ (( newcy <= ly ) && ( newry >= lry )) ) #define WITHIN_WIDTH ( (( cx <= lrx ) && ( cx >= lx )) || \ (( rx >= lx ) && ( rx <= lrx )) || \ (( cx <= lx ) && ( rx >= lrx )) ) #define SNAP_WINDOW_TOP if ( (sOWO?(newcyly):true) \ && WITHIN_WIDTH \ && (qAbs( ly - newry ) < deltaY) ) { \ deltaY = qAbs( ly - newry ); \ newry=ly; \ } #define SNAP_WINDOW_LEFT if ( (sOWO?(newcxlx):true) \ && WITHIN_HEIGHT \ && (qAbs( lx - newrx ) < deltaX)) \ { \ deltaX = qAbs( lx - newrx ); \ newrx=lx; \ } #define SNAP_WINDOW_C_TOP if ( (sOWO?(newcylry):true) \ && (newcx == lrx || newrx == lx) \ && qAbs(lry-newry) < deltaY ) { \ deltaY = qAbs( lry - newry - 1 ); \ newry = lry - 1; \ } #define SNAP_WINDOW_C_LEFT if ( (sOWO?(newcxlrx):true) \ && (newcy == lry || newry == ly) \ && qAbs(lrx-newrx) < deltaX ) { \ deltaX = qAbs( lrx - newrx - 1 ); \ newrx = lrx - 1; \ } switch(mode) { case AbstractClient::PositionBottomRight: SNAP_WINDOW_BOTTOM SNAP_WINDOW_RIGHT SNAP_WINDOW_C_BOTTOM SNAP_WINDOW_C_RIGHT break; case AbstractClient::PositionRight: SNAP_WINDOW_RIGHT SNAP_WINDOW_C_RIGHT break; case AbstractClient::PositionBottom: SNAP_WINDOW_BOTTOM SNAP_WINDOW_C_BOTTOM break; case AbstractClient::PositionTopLeft: SNAP_WINDOW_TOP SNAP_WINDOW_LEFT SNAP_WINDOW_C_TOP SNAP_WINDOW_C_LEFT break; case AbstractClient::PositionLeft: SNAP_WINDOW_LEFT SNAP_WINDOW_C_LEFT break; case AbstractClient::PositionTop: SNAP_WINDOW_TOP SNAP_WINDOW_C_TOP break; case AbstractClient::PositionTopRight: SNAP_WINDOW_TOP SNAP_WINDOW_RIGHT SNAP_WINDOW_C_TOP SNAP_WINDOW_C_RIGHT break; case AbstractClient::PositionBottomLeft: SNAP_WINDOW_BOTTOM SNAP_WINDOW_LEFT SNAP_WINDOW_C_BOTTOM SNAP_WINDOW_C_LEFT break; default: abort(); break; } } } } // center snap //snap = options->centerSnapZone; //if (snap) // { // // Don't resize snap to center as it interferes too much // // There are two ways of implementing this if wanted: // // 1) Snap only to the same points that the move snap does, and // // 2) Snap to the horizontal and vertical center lines of the screen // } moveResizeGeom = QRect(QPoint(newcx, newcy), QPoint(newrx, newry)); } return moveResizeGeom; } /** * Marks the client as being moved or resized by the user. */ void Workspace::setMoveResizeClient(AbstractClient *c) { Q_ASSERT(!c || !movingClient); // Catch attempts to move a second // window while still moving the first one. movingClient = c; if (movingClient) ++block_focus; else --block_focus; } // When kwin crashes, windows will not be gravitated back to their original position // and will remain offset by the size of the decoration. So when restarting, fix this // (the property with the size of the frame remains on the window after the crash). void Workspace::fixPositionAfterCrash(xcb_window_t w, const xcb_get_geometry_reply_t *geometry) { NETWinInfo i(connection(), w, rootWindow(), NET::WMFrameExtents, NET::Properties2()); NETStrut frame = i.frameExtents(); if (frame.left != 0 || frame.top != 0) { // left and top needed due to narrowing conversations restrictions in C++11 const uint32_t left = frame.left; const uint32_t top = frame.top; const uint32_t values[] = { geometry->x - left, geometry->y - top }; xcb_configure_window(connection(), w, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); } } } // namespace diff --git a/xdgshellclient.cpp b/xdgshellclient.cpp index 5d487b66e..5cee6ac34 100644 --- a/xdgshellclient.cpp +++ b/xdgshellclient.cpp @@ -1,2023 +1,2024 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2015 Martin Gräßlin Copyright (C) 2018 David Edmundson Copyright (C) 2019 Vlad Zahorodnii 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 "xdgshellclient.h" #include "cursor.h" #include "decorations/decoratedclient.h" #include "decorations/decorationbridge.h" #include "deleted.h" #include "placement.h" #include "screenedge.h" #include "screens.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox.h" #endif #include "virtualdesktops.h" #include "wayland_server.h" #include "workspace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(NET::WindowType) using namespace KWayland::Server; namespace KWin { XdgShellClient::XdgShellClient(XdgShellSurfaceInterface *surface) : AbstractClient() , m_xdgShellToplevel(surface) , m_xdgShellPopup(nullptr) { setSurface(surface->surface()); init(); } XdgShellClient::XdgShellClient(XdgShellPopupInterface *surface) : AbstractClient() , m_xdgShellToplevel(nullptr) , m_xdgShellPopup(surface) { setSurface(surface->surface()); init(); } XdgShellClient::~XdgShellClient() = default; void XdgShellClient::init() { m_requestGeometryBlockCounter++; connect(this, &XdgShellClient::desktopFileNameChanged, this, &XdgShellClient::updateIcon); createWindowId(); setupCompositing(); updateIcon(); // TODO: Initialize with null rect. m_frameGeometry = QRect(0, 0, -1, -1); m_windowGeometry = QRect(0, 0, -1, -1); if (waylandServer()->inputMethodConnection() == surface()->client()) { m_windowType = NET::OnScreenDisplay; } connect(surface(), &SurfaceInterface::unmapped, this, &XdgShellClient::unmap); connect(surface(), &SurfaceInterface::unbound, this, &XdgShellClient::destroyClient); connect(surface(), &SurfaceInterface::destroyed, this, &XdgShellClient::destroyClient); if (m_xdgShellToplevel) { connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::destroyed, this, &XdgShellClient::destroyClient); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::configureAcknowledged, this, &XdgShellClient::handleConfigureAcknowledged); m_caption = m_xdgShellToplevel->title().simplified(); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::titleChanged, this, &XdgShellClient::handleWindowTitleChanged); QTimer::singleShot(0, this, &XdgShellClient::updateCaption); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::moveRequested, this, &XdgShellClient::handleMoveRequested); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::resizeRequested, this, &XdgShellClient::handleResizeRequested); // Determine the resource name, this is inspired from ICCCM 4.1.2.5 // the binary name of the invoked client. QFileInfo info{m_xdgShellToplevel->client()->executablePath()}; QByteArray resourceName; if (info.exists()) { resourceName = info.fileName().toUtf8(); } setResourceClass(resourceName, m_xdgShellToplevel->windowClass()); setDesktopFileName(m_xdgShellToplevel->windowClass()); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::windowClassChanged, this, &XdgShellClient::handleWindowClassChanged); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::minimizeRequested, this, &XdgShellClient::handleMinimizeRequested); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::maximizedChanged, this, &XdgShellClient::handleMaximizeRequested); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::fullscreenChanged, this, &XdgShellClient::handleFullScreenRequested); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::windowMenuRequested, this, &XdgShellClient::handleWindowMenuRequested); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::transientForChanged, this, &XdgShellClient::handleTransientForChanged); connect(m_xdgShellToplevel, &XdgShellSurfaceInterface::windowGeometryChanged, this, &XdgShellClient::handleWindowGeometryChanged); auto global = static_cast(m_xdgShellToplevel->global()); connect(global, &XdgShellInterface::pingDelayed, this, &XdgShellClient::handlePingDelayed); connect(global, &XdgShellInterface::pingTimeout, this, &XdgShellClient::handlePingTimeout); connect(global, &XdgShellInterface::pongReceived, this, &XdgShellClient::handlePongReceived); auto configure = [this] { if (m_closing) { return; } if (m_requestGeometryBlockCounter != 0 || areGeometryUpdatesBlocked()) { return; } m_xdgShellToplevel->configure(xdgSurfaceStates(), m_requestedClientSize); }; connect(this, &AbstractClient::activeChanged, this, configure); connect(this, &AbstractClient::clientStartUserMovedResized, this, configure); connect(this, &AbstractClient::clientFinishUserMovedResized, this, configure); connect(this, &XdgShellClient::frameGeometryChanged, this, &XdgShellClient::updateClientOutputs); connect(screens(), &Screens::changed, this, &XdgShellClient::updateClientOutputs); } else if (m_xdgShellPopup) { connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, &XdgShellClient::handleConfigureAcknowledged); connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, &XdgShellClient::handleGrabRequested); connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &XdgShellClient::destroyClient); connect(m_xdgShellPopup, &XdgShellPopupInterface::windowGeometryChanged, this, &XdgShellClient::handleWindowGeometryChanged); } // set initial desktop setDesktop(VirtualDesktopManager::self()->current()); // setup shadow integration updateShadow(); connect(surface(), &SurfaceInterface::shadowChanged, this, &Toplevel::updateShadow); connect(waylandServer(), &WaylandServer::foreignTransientChanged, this, [this](KWayland::Server::SurfaceInterface *child) { if (child == surface()) { handleTransientForChanged(); } }); handleTransientForChanged(); AbstractClient::updateColorScheme(QString()); connect(surface(), &SurfaceInterface::committed, this, &XdgShellClient::finishInit); } void XdgShellClient::finishInit() { disconnect(surface(), &SurfaceInterface::committed, this, &XdgShellClient::finishInit); connect(surface(), &SurfaceInterface::committed, this, &XdgShellClient::handleCommitted); bool needsPlacement = !isInitialPositionSet(); if (supportsWindowRules()) { setupWindowRules(false); const QRect originalGeometry = frameGeometry(); const QRect ruledGeometry = rules()->checkGeometry(originalGeometry, true); if (originalGeometry != ruledGeometry) { setFrameGeometry(ruledGeometry); } maximize(rules()->checkMaximize(maximizeMode(), true)); setDesktop(rules()->checkDesktop(desktop(), true)); setDesktopFileName(rules()->checkDesktopFile(desktopFileName(), true).toUtf8()); if (rules()->checkMinimize(isMinimized(), true)) { minimize(true); // No animation. } setSkipTaskbar(rules()->checkSkipTaskbar(skipTaskbar(), true)); setSkipPager(rules()->checkSkipPager(skipPager(), true)); setSkipSwitcher(rules()->checkSkipSwitcher(skipSwitcher(), true)); setKeepAbove(rules()->checkKeepAbove(keepAbove(), true)); setKeepBelow(rules()->checkKeepBelow(keepBelow(), true)); setShortcut(rules()->checkShortcut(shortcut().toString(), true)); updateColorScheme(); // Don't place the client if its position is set by a rule. if (rules()->checkPosition(invalidPoint, true) != invalidPoint) { needsPlacement = false; } // Don't place the client if the maximize state is set by a rule. if (requestedMaximizeMode() != MaximizeRestore) { needsPlacement = false; } discardTemporaryRules(); RuleBook::self()->discardUsed(this, false); // Remove Apply Now rules. updateWindowRules(Rules::All); } if (isFullScreen()) { needsPlacement = false; } if (needsPlacement) { const QRect area = workspace()->clientArea(PlacementArea, Screens::self()->current(), desktop()); placeIn(area); } m_requestGeometryBlockCounter--; if (m_requestGeometryBlockCounter == 0) { requestGeometry(m_blockedRequestGeometry); } m_isInitialized = true; } void XdgShellClient::destroyClient() { m_closing = true; #ifdef KWIN_BUILD_TABBOX TabBox::TabBox *tabBox = TabBox::TabBox::self(); if (tabBox->isDisplayed() && tabBox->currentClient() == this) { tabBox->nextPrev(true); } #endif if (isMoveResize()) { leaveMoveResize(); } // Replace ShellClient with an instance of Deleted in the stacking order. Deleted *deleted = Deleted::create(this); emit windowClosed(this, deleted); // Remove Force Temporarily rules. RuleBook::self()->discardUsed(this, true); destroyWindowManagementInterface(); destroyDecoration(); StackingUpdatesBlocker blocker(workspace()); if (transientFor()) { transientFor()->removeTransient(this); } for (auto it = transients().constBegin(); it != transients().constEnd();) { if ((*it)->transientFor() == this) { removeTransient(*it); it = transients().constBegin(); // restart, just in case something more has changed with the list } else { ++it; } } waylandServer()->removeClient(this); deleted->unrefWindow(); m_xdgShellToplevel = nullptr; m_xdgShellPopup = nullptr; deleteClient(this); } void XdgShellClient::deleteClient(XdgShellClient *c) { delete c; } QRect XdgShellClient::inputGeometry() const { if (isDecorated()) { return AbstractClient::inputGeometry(); } // TODO: What about sub-surfaces sticking outside the main surface? return m_bufferGeometry; } QRect XdgShellClient::bufferGeometry() const { return m_bufferGeometry; } QStringList XdgShellClient::activities() const { // TODO: implement return QStringList(); } QPoint XdgShellClient::clientContentPos() const { return -1 * clientPos(); } QSize XdgShellClient::clientSize() const { const QRect boundingRect = surface()->boundingRect(); return m_windowGeometry.size().boundedTo(boundingRect.size()); } QSize XdgShellClient::minSize() const { if (m_xdgShellToplevel) { return rules()->checkMinSize(m_xdgShellToplevel->minimumSize()); } return QSize(0, 0); } QSize XdgShellClient::maxSize() const { if (m_xdgShellToplevel) { return rules()->checkMaxSize(m_xdgShellToplevel->maximumSize()); } return QSize(INT_MAX, INT_MAX); } void XdgShellClient::debug(QDebug &stream) const { stream.nospace(); stream << "\'XdgShellClient:" << surface() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'"; } bool XdgShellClient::belongsToDesktop() const { const auto clients = waylandServer()->clients(); return std::any_of(clients.constBegin(), clients.constEnd(), [this](const AbstractClient *client) { if (belongsToSameApplication(client, SameApplicationChecks())) { return client->isDesktop(); } return false; } ); } Layer XdgShellClient::layerForDock() const { if (m_plasmaShellSurface) { switch (m_plasmaShellSurface->panelBehavior()) { case PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover: return NormalLayer; case PlasmaShellSurfaceInterface::PanelBehavior::AutoHide: return AboveLayer; case PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow: case PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible: return DockLayer; default: Q_UNREACHABLE(); break; } } return AbstractClient::layerForDock(); } QRect XdgShellClient::transparentRect() const { // TODO: implement return QRect(); } NET::WindowType XdgShellClient::windowType(bool direct, int supported_types) const { // TODO: implement Q_UNUSED(direct) Q_UNUSED(supported_types) return m_windowType; } double XdgShellClient::opacity() const { return m_opacity; } void XdgShellClient::setOpacity(double opacity) { const qreal newOpacity = qBound(0.0, opacity, 1.0); if (newOpacity == m_opacity) { return; } const qreal oldOpacity = m_opacity; m_opacity = newOpacity; addRepaintFull(); emit opacityChanged(this, oldOpacity); } void XdgShellClient::addDamage(const QRegion &damage) { const int offsetX = m_bufferGeometry.x() - frameGeometry().x(); const int offsetY = m_bufferGeometry.y() - frameGeometry().y(); repaints_region += damage.translated(offsetX, offsetY); Toplevel::addDamage(damage); } void XdgShellClient::markAsMapped() { if (!m_unmapped) { return; } m_unmapped = false; if (!ready_for_painting) { setReadyForPainting(); } else { addRepaintFull(); emit windowShown(this); } if (shouldExposeToWindowManagement()) { setupWindowManagementInterface(); } updateShowOnScreenEdge(); } void XdgShellClient::updateDecoration(bool check_workspace_pos, bool force) { if (!force && ((!isDecorated() && noBorder()) || (isDecorated() && !noBorder()))) return; QRect oldgeom = frameGeometry(); QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom()); blockGeometryUpdates(true); if (force) destroyDecoration(); if (!noBorder()) { createDecoration(oldgeom); } else destroyDecoration(); if (m_serverDecoration && isDecorated()) { m_serverDecoration->setMode(KWayland::Server::ServerSideDecorationManagerInterface::Mode::Server); } if (m_xdgDecoration) { auto mode = isDecorated() || m_userNoBorder ? XdgDecorationInterface::Mode::ServerSide: XdgDecorationInterface::Mode::ClientSide; m_xdgDecoration->configure(mode); if (m_requestGeometryBlockCounter == 0) { m_xdgShellToplevel->configure(xdgSurfaceStates(), m_requestedClientSize); } } updateShadow(); if (check_workspace_pos) checkWorkspacePosition(oldgeom, -2, oldClientGeom); blockGeometryUpdates(false); } void XdgShellClient::setFrameGeometry(const QRect &rect, ForceGeometry_t force) { const QRect newGeometry = rules()->checkGeometry(rect); if (areGeometryUpdatesBlocked()) { // when the GeometryUpdateBlocker exits the current geom is passed to setGeometry // thus we need to set it here. m_frameGeometry = newGeometry; if (pendingGeometryUpdate() == PendingGeometryForced) { // maximum, nothing needed } else if (force == ForceGeometrySet) { setPendingGeometryUpdate(PendingGeometryForced); } else { setPendingGeometryUpdate(PendingGeometryNormal); } return; } if (pendingGeometryUpdate() != PendingGeometryNone) { // reset geometry to the one before blocking, so that we can compare properly m_frameGeometry = frameGeometryBeforeUpdateBlocking(); } const QSize requestedClientSize = newGeometry.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()); if (requestedClientSize == m_windowGeometry.size() && (m_requestedClientSize.isEmpty() || requestedClientSize == m_requestedClientSize)) { // size didn't change, and we don't need to explicitly request a new size doSetGeometry(newGeometry); updateMaximizeMode(m_requestedMaximizeMode); } else { // size did change, Client needs to provide a new buffer requestGeometry(newGeometry); } } QRect XdgShellClient::determineBufferGeometry() const { // Offset of the main surface relative to the frame rect. const int offsetX = borderLeft() - m_windowGeometry.left(); const int offsetY = borderTop() - m_windowGeometry.top(); QRect bufferGeometry; bufferGeometry.setX(x() + offsetX); bufferGeometry.setY(y() + offsetY); bufferGeometry.setSize(surface()->size()); return bufferGeometry; } void XdgShellClient::doSetGeometry(const QRect &rect) { bool frameGeometryIsChanged = false; bool bufferGeometryIsChanged = false; if (m_frameGeometry != rect) { m_frameGeometry = rect; frameGeometryIsChanged = true; } const QRect bufferGeometry = determineBufferGeometry(); if (m_bufferGeometry != bufferGeometry) { m_bufferGeometry = bufferGeometry; bufferGeometryIsChanged = true; } if (!frameGeometryIsChanged && !bufferGeometryIsChanged) { return; } if (m_unmapped && geometryRestore().isEmpty() && !m_frameGeometry.isEmpty()) { // use first valid geometry as restore geometry setGeometryRestore(m_frameGeometry); } if (frameGeometryIsChanged) { if (hasStrut()) { workspace()->updateClientArea(); } updateWindowRules(Rules::Position | Rules::Size); emit frameGeometryChanged(this, frameGeometryBeforeUpdateBlocking()); } emit geometryShapeChanged(this, frameGeometryBeforeUpdateBlocking()); addRepaintDuringGeometryUpdates(); updateGeometryBeforeUpdateBlocking(); if (isResize()) { performMoveResize(); } } void XdgShellClient::doMove(int x, int y) { Q_UNUSED(x) Q_UNUSED(y) m_bufferGeometry = determineBufferGeometry(); } QByteArray XdgShellClient::windowRole() const { return QByteArray(); } bool XdgShellClient::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const { if (checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) { if (other->desktopFileName() == desktopFileName()) { return true; } } if (auto s = other->surface()) { return s->client() == surface()->client(); } return false; } void XdgShellClient::blockActivityUpdates(bool b) { Q_UNUSED(b) } QString XdgShellClient::captionNormal() const { return m_caption; } QString XdgShellClient::captionSuffix() const { return m_captionSuffix; } void XdgShellClient::updateCaption() { const QString oldSuffix = m_captionSuffix; const auto shortcut = shortcutCaptionSuffix(); m_captionSuffix = shortcut; if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()) { int i = 2; do { m_captionSuffix = shortcut + QLatin1String(" <") + QString::number(i) + QLatin1Char('>'); i++; } while (findClientWithSameCaption()); } if (m_captionSuffix != oldSuffix) { emit captionChanged(); } } void XdgShellClient::closeWindow() { if (m_xdgShellToplevel && isCloseable()) { m_xdgShellToplevel->close(); ping(PingReason::CloseWindow); } } AbstractClient *XdgShellClient::findModal(bool allow_itself) { Q_UNUSED(allow_itself) return nullptr; } bool XdgShellClient::isCloseable() const { if (m_windowType == NET::Desktop || m_windowType == NET::Dock) { return false; } if (m_xdgShellToplevel) { return true; } return false; } bool XdgShellClient::isFullScreen() const { return m_fullScreen; } bool XdgShellClient::isMaximizable() const { if (!isResizable()) { return false; } if (rules()->checkMaximize(MaximizeRestore) != MaximizeRestore || rules()->checkMaximize(MaximizeFull) != MaximizeFull) { return false; } return true; } bool XdgShellClient::isMinimizable() const { if (!rules()->checkMinimize(true)) { return false; } return (!m_plasmaShellSurface || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal); } bool XdgShellClient::isMovable() const { if (isFullScreen()) { return false; } if (rules()->checkPosition(invalidPoint) != invalidPoint) { return false; } if (m_plasmaShellSurface) { return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; } if (m_xdgShellPopup) { return false; } return true; } bool XdgShellClient::isMovableAcrossScreens() const { if (rules()->checkPosition(invalidPoint) != invalidPoint) { return false; } if (m_plasmaShellSurface) { return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; } if (m_xdgShellPopup) { return false; } return true; } bool XdgShellClient::isResizable() const { if (isFullScreen()) { return false; } if (rules()->checkSize(QSize()).isValid()) { return false; } if (m_plasmaShellSurface) { return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal; } if (m_xdgShellPopup) { return false; } return true; } bool XdgShellClient::isShown(bool shaded_is_shown) const { Q_UNUSED(shaded_is_shown) return !m_closing && !m_unmapped && !isMinimized() && !m_hidden; } bool XdgShellClient::isHiddenInternal() const { return m_unmapped || m_hidden; } void XdgShellClient::hideClient(bool hide) { if (m_hidden == hide) { return; } m_hidden = hide; if (hide) { addWorkspaceRepaint(visibleRect()); workspace()->clientHidden(this); emit windowHidden(this); } else { emit windowShown(this); } } static bool changeMaximizeRecursion = false; void XdgShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust) { if (changeMaximizeRecursion) { return; } if (!isResizable()) { return; } const QRect clientArea = isElectricBorderMaximizing() ? workspace()->clientArea(MaximizeArea, Cursor::pos(), desktop()) : workspace()->clientArea(MaximizeArea, this); const MaximizeMode oldMode = m_requestedMaximizeMode; const QRect oldGeometry = frameGeometry(); // 'adjust == true' means to update the size only, e.g. after changing workspace size if (!adjust) { if (vertical) m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeVertical); if (horizontal) m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeHorizontal); } m_requestedMaximizeMode = rules()->checkMaximize(m_requestedMaximizeMode); if (!adjust && m_requestedMaximizeMode == oldMode) { return; } StackingUpdatesBlocker blocker(workspace()); RequestGeometryBlocker geometryBlocker(this); // call into decoration update borders if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_requestedMaximizeMode == KWin::MaximizeFull)) { changeMaximizeRecursion = true; - const auto c = decoration()->client().data(); + const auto c = decoration()->client().toStrongRef(); if ((m_requestedMaximizeMode & MaximizeVertical) != (oldMode & MaximizeVertical)) { emit c->maximizedVerticallyChanged(m_requestedMaximizeMode & MaximizeVertical); } if ((m_requestedMaximizeMode & MaximizeHorizontal) != (oldMode & MaximizeHorizontal)) { emit c->maximizedHorizontallyChanged(m_requestedMaximizeMode & MaximizeHorizontal); } if ((m_requestedMaximizeMode == MaximizeFull) != (oldMode == MaximizeFull)) { emit c->maximizedChanged(m_requestedMaximizeMode & MaximizeFull); } changeMaximizeRecursion = false; } if (options->borderlessMaximizedWindows()) { // triggers a maximize change. // The next setNoBorder interation will exit since there's no change but the first recursion pullutes the restore geometry changeMaximizeRecursion = true; setNoBorder(rules()->checkNoBorder(m_requestedMaximizeMode == MaximizeFull)); changeMaximizeRecursion = false; } // Conditional quick tiling exit points const auto oldQuickTileMode = quickTileMode(); if (quickTileMode() != QuickTileMode(QuickTileFlag::None)) { if (oldMode == MaximizeFull && !clientArea.contains(geometryRestore().center())) { // Not restoring on the same screen // TODO: The following doesn't work for some reason //quick_tile_mode = QuickTileNone; // And exit quick tile mode manually } else if ((oldMode == MaximizeVertical && m_requestedMaximizeMode == MaximizeRestore) || (oldMode == MaximizeFull && m_requestedMaximizeMode == MaximizeHorizontal)) { // Modifying geometry of a tiled window updateQuickTileMode(QuickTileFlag::None); // Exit quick tile mode without restoring geometry } } if (m_requestedMaximizeMode == MaximizeFull) { setGeometryRestore(oldGeometry); // TODO: Client has more checks if (options->electricBorderMaximize()) { updateQuickTileMode(QuickTileFlag::Maximize); } else { updateQuickTileMode(QuickTileFlag::None); } if (quickTileMode() != oldQuickTileMode) { emit quickTileModeChanged(); } setFrameGeometry(workspace()->clientArea(MaximizeArea, this)); workspace()->raiseClient(this); } else { if (m_requestedMaximizeMode == MaximizeRestore) { updateQuickTileMode(QuickTileFlag::None); } if (quickTileMode() != oldQuickTileMode) { emit quickTileModeChanged(); } if (geometryRestore().isValid()) { setFrameGeometry(geometryRestore()); } else { setFrameGeometry(workspace()->clientArea(PlacementArea, this)); } } } MaximizeMode XdgShellClient::maximizeMode() const { return m_maximizeMode; } MaximizeMode XdgShellClient::requestedMaximizeMode() const { return m_requestedMaximizeMode; } bool XdgShellClient::noBorder() const { if (m_serverDecoration) { if (m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) { return m_userNoBorder || isFullScreen(); } } if (m_xdgDecoration && m_xdgDecoration->requestedMode() != XdgDecorationInterface::Mode::ClientSide) { return m_userNoBorder || isFullScreen(); } return true; } bool XdgShellClient::isFullScreenable() const { if (!rules()->checkFullScreen(true)) { return false; } return !isSpecialWindow(); } void XdgShellClient::setFullScreen(bool set, bool user) { set = rules()->checkFullScreen(set); const bool wasFullscreen = isFullScreen(); if (wasFullscreen == set) { return; } if (isSpecialWindow()) { return; } if (user && !userCanSetFullScreen()) { return; } if (wasFullscreen) { workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event } else { m_geomFsRestore = frameGeometry(); } m_fullScreen = set; if (set) { workspace()->raiseClient(this); } RequestGeometryBlocker requestBlocker(this); StackingUpdatesBlocker blocker1(workspace()); GeometryUpdatesBlocker blocker2(this); workspace()->updateClientLayer(this); // active fullscreens get different layer updateDecoration(false, false); if (set) { setFrameGeometry(workspace()->clientArea(FullScreenArea, this)); } else { if (m_geomFsRestore.isValid()) { int currentScreen = screen(); setFrameGeometry(QRect(m_geomFsRestore.topLeft(), constrainFrameSize(m_geomFsRestore.size()))); if( currentScreen != screen()) workspace()->sendClientToScreen( this, currentScreen ); } else { // this can happen when the window was first shown already fullscreen, // so let the client set the size by itself setFrameGeometry(QRect(workspace()->clientArea(PlacementArea, this).topLeft(), QSize(0, 0))); } } updateWindowRules(Rules::Fullscreen|Rules::Position|Rules::Size); emit fullScreenChanged(); } void XdgShellClient::setNoBorder(bool set) { if (!userCanSetNoBorder()) { return; } set = rules()->checkNoBorder(set); if (m_userNoBorder == set) { return; } m_userNoBorder = set; updateDecoration(true, false); updateWindowRules(Rules::NoBorder); } void XdgShellClient::setOnAllActivities(bool set) { Q_UNUSED(set) } void XdgShellClient::takeFocus() { if (rules()->checkAcceptFocus(wantsInput())) { if (m_xdgShellToplevel) { ping(PingReason::FocusWindow); } setActive(true); } if (!keepAbove() && !isOnScreenDisplay() && !belongsToDesktop()) { workspace()->setShowingDesktop(false); } } void XdgShellClient::doSetActive() { if (!isActive()) { return; } StackingUpdatesBlocker blocker(workspace()); workspace()->focusToNull(); } bool XdgShellClient::userCanSetFullScreen() const { if (m_xdgShellToplevel) { return true; } return false; } bool XdgShellClient::userCanSetNoBorder() const { if (m_serverDecoration && m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) { return !isFullScreen() && !isShade(); } if (m_xdgDecoration && m_xdgDecoration->requestedMode() != XdgDecorationInterface::Mode::ClientSide) { return !isFullScreen() && !isShade(); } return false; } bool XdgShellClient::wantsInput() const { return rules()->checkAcceptFocus(acceptsFocus()); } bool XdgShellClient::acceptsFocus() const { if (waylandServer()->inputMethodConnection() == surface()->client()) { return false; } if (m_plasmaShellSurface) { if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::OnScreenDisplay || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::ToolTip) { return false; } if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Notification || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::CriticalNotification) { return m_plasmaShellSurface->panelTakesFocus(); } } if (m_closing) { // a closing window does not accept focus return false; } if (m_unmapped) { // an unmapped window does not accept focus return false; } if (m_xdgShellToplevel) { // TODO: proper return true; } return false; } void XdgShellClient::createWindowId() { m_windowId = waylandServer()->createWindowId(surface()); } pid_t XdgShellClient::pid() const { return surface()->client()->processId(); } bool XdgShellClient::isLockScreen() const { return surface()->client() == waylandServer()->screenLockerClientConnection(); } bool XdgShellClient::isInputMethod() const { return surface()->client() == waylandServer()->inputMethodConnection(); } void XdgShellClient::requestGeometry(const QRect &rect) { if (m_requestGeometryBlockCounter != 0) { m_blockedRequestGeometry = rect; return; } QSize size; if (rect.isValid()) { size = rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()); } else { size = QSize(0, 0); } m_requestedClientSize = size; quint64 serialId = 0; if (m_xdgShellToplevel) { serialId = m_xdgShellToplevel->configure(xdgSurfaceStates(), size); } if (m_xdgShellPopup) { auto parent = transientFor(); if (parent) { const QPoint globalClientContentPos = parent->frameGeometry().topLeft() + parent->clientPos(); const QPoint relativeOffset = rect.topLeft() - globalClientContentPos; serialId = m_xdgShellPopup->configure(QRect(relativeOffset, size)); } } if (rect.isValid()) { //if there's no requested size, then there's implicity no positional information worth using PendingConfigureRequest configureRequest; configureRequest.serialId = serialId; configureRequest.positionAfterResize = rect.topLeft(); configureRequest.maximizeMode = m_requestedMaximizeMode; m_pendingConfigureRequests.append(configureRequest); } m_blockedRequestGeometry = QRect(); } void XdgShellClient::updatePendingGeometry() { QPoint position = pos(); MaximizeMode maximizeMode = m_maximizeMode; for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) { if (it->serialId > m_lastAckedConfigureRequest) { //this serial is not acked yet, therefore we know all future serials are not break; } if (it->serialId == m_lastAckedConfigureRequest) { if (position != it->positionAfterResize) { addLayerRepaint(frameGeometry()); } position = it->positionAfterResize; maximizeMode = it->maximizeMode; m_pendingConfigureRequests.erase(m_pendingConfigureRequests.begin(), ++it); break; } //else serialId < m_lastAckedConfigureRequest and the state is now irrelevant and can be ignored } QRect geometry = QRect(position, adjustedSize()); if (isMove()) { geometry = adjustMoveGeometry(geometry); } if (isResize()) { geometry = adjustResizeGeometry(geometry); } doSetGeometry(geometry); updateMaximizeMode(maximizeMode); } void XdgShellClient::handleConfigureAcknowledged(quint32 serial) { m_lastAckedConfigureRequest = serial; } void XdgShellClient::handleTransientForChanged() { SurfaceInterface *transientSurface = nullptr; if (m_xdgShellToplevel) { if (auto transient = m_xdgShellToplevel->transientFor().data()) { transientSurface = transient->surface(); } } if (m_xdgShellPopup) { transientSurface = m_xdgShellPopup->transientFor().data(); } if (!transientSurface) { transientSurface = waylandServer()->findForeignTransientForSurface(surface()); } AbstractClient *transientClient = waylandServer()->findClient(transientSurface); if (transientClient != transientFor()) { // Remove from main client. if (transientFor()) { transientFor()->removeTransient(this); } setTransientFor(transientClient); if (transientClient) { transientClient->addTransient(this); } } m_transient = (transientSurface != nullptr); } void XdgShellClient::handleWindowClassChanged(const QByteArray &windowClass) { setResourceClass(resourceName(), windowClass); if (m_isInitialized && supportsWindowRules()) { setupWindowRules(true); applyWindowRules(); } setDesktopFileName(windowClass); } void XdgShellClient::handleWindowGeometryChanged(const QRect &windowGeometry) { m_windowGeometry = windowGeometry; m_hasWindowGeometry = true; } void XdgShellClient::handleWindowTitleChanged(const QString &title) { const QString oldSuffix = m_captionSuffix; m_caption = title.simplified(); updateCaption(); if (m_captionSuffix == oldSuffix) { // Don't emit caption change twice it already got emitted by the changing suffix. emit captionChanged(); } } void XdgShellClient::handleMoveRequested(SeatInterface *seat, quint32 serial) { // FIXME: Check the seat and serial. Q_UNUSED(seat) Q_UNUSED(serial) performMouseCommand(Options::MouseMove, Cursor::pos()); } void XdgShellClient::handleResizeRequested(SeatInterface *seat, quint32 serial, Qt::Edges edges) { // FIXME: Check the seat and serial. Q_UNUSED(seat) Q_UNUSED(serial) if (!isResizable() || isShade()) { return; } if (isMoveResize()) { finishMoveResize(false); } setMoveResizePointerButtonDown(true); setMoveOffset(Cursor::pos() - pos()); // map from global setInvertedMoveOffset(rect().bottomRight() - moveOffset()); setUnrestrictedMoveResize(false); auto toPosition = [edges] { Position position = PositionCenter; if (edges.testFlag(Qt::TopEdge)) { position = PositionTop; } else if (edges.testFlag(Qt::BottomEdge)) { position = PositionBottom; } if (edges.testFlag(Qt::LeftEdge)) { position = Position(position | PositionLeft); } else if (edges.testFlag(Qt::RightEdge)) { position = Position(position | PositionRight); } return position; }; setMoveResizePointerMode(toPosition()); if (!startMoveResize()) { setMoveResizePointerButtonDown(false); } updateCursor(); } void XdgShellClient::handleMinimizeRequested() { performMouseCommand(Options::MouseMinimize, Cursor::pos()); } void XdgShellClient::handleMaximizeRequested(bool maximized) { // If the maximized state of the client hasn't been changed due to a window // rule or because the requested state is the same as the current, then the // compositor still has to send a configure event. RequestGeometryBlocker blocker(this); maximize(maximized ? MaximizeFull : MaximizeRestore); } void XdgShellClient::handleFullScreenRequested(bool fullScreen, OutputInterface *output) { // FIXME: Consider output as well. Q_UNUSED(output); setFullScreen(fullScreen, false); } void XdgShellClient::handleWindowMenuRequested(SeatInterface *seat, quint32 serial, const QPoint &surfacePos) { // FIXME: Check the seat and serial. Q_UNUSED(seat) Q_UNUSED(serial) performMouseCommand(Options::MouseOperationsMenu, pos() + surfacePos); } void XdgShellClient::handleGrabRequested(SeatInterface *seat, quint32 serial) { // FIXME: Check the seat and serial as well whether the parent had focus. Q_UNUSED(seat) Q_UNUSED(serial) m_hasPopupGrab = true; } void XdgShellClient::handlePingDelayed(quint32 serial) { auto it = m_pingSerials.find(serial); if (it != m_pingSerials.end()) { qCDebug(KWIN_CORE) << "First ping timeout:" << caption(); setUnresponsive(true); } } void XdgShellClient::handlePingTimeout(quint32 serial) { auto it = m_pingSerials.find(serial); if (it != m_pingSerials.end()) { if (it.value() == PingReason::CloseWindow) { qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption(); //for internal windows, killing the window will delete this QPointer guard(this); killWindow(); if (!guard) { return; } } m_pingSerials.erase(it); } } void XdgShellClient::handlePongReceived(quint32 serial) { auto it = m_pingSerials.find(serial); if (it != m_pingSerials.end()) { setUnresponsive(false); m_pingSerials.erase(it); } } void XdgShellClient::handleCommitted() { if (!surface()->buffer()) { return; } if (!m_hasWindowGeometry) { m_windowGeometry = surface()->boundingRect(); } updatePendingGeometry(); setDepth((surface()->buffer()->hasAlphaChannel() && !isDesktop()) ? 32 : 24); markAsMapped(); } void XdgShellClient::resizeWithChecks(const QSize &size, ForceGeometry_t force) { // don't allow growing larger than workarea const QRect area = workspace()->clientArea(WorkArea, this); setFrameGeometry(QRect{pos(), size.boundedTo(area.size())}, force); } void XdgShellClient::unmap() { m_unmapped = true; if (isMoveResize()) { leaveMoveResize(); } m_requestedClientSize = QSize(0, 0); destroyWindowManagementInterface(); if (Workspace::self()) { addWorkspaceRepaint(visibleRect()); workspace()->clientHidden(this); } emit windowHidden(this); } void XdgShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface) { m_plasmaShellSurface = surface; auto updatePosition = [this, surface] { // That's a mis-use of doSetGeometry method. One should instead use move method. QRect rect = QRect(surface->position(), size()); doSetGeometry(rect); }; auto updateRole = [this, surface] { NET::WindowType type = NET::Unknown; switch (surface->role()) { case PlasmaShellSurfaceInterface::Role::Desktop: type = NET::Desktop; break; case PlasmaShellSurfaceInterface::Role::Panel: type = NET::Dock; break; case PlasmaShellSurfaceInterface::Role::OnScreenDisplay: type = NET::OnScreenDisplay; break; case PlasmaShellSurfaceInterface::Role::Notification: type = NET::Notification; break; case PlasmaShellSurfaceInterface::Role::ToolTip: type = NET::Tooltip; break; case PlasmaShellSurfaceInterface::Role::CriticalNotification: type = NET::CriticalNotification; break; case PlasmaShellSurfaceInterface::Role::Normal: default: type = NET::Normal; break; } if (type != m_windowType) { m_windowType = type; if (m_windowType == NET::Desktop || type == NET::Dock || type == NET::OnScreenDisplay || type == NET::Notification || type == NET::Tooltip || type == NET::CriticalNotification) { setOnAllDesktops(true); } workspace()->updateClientArea(); } }; connect(surface, &PlasmaShellSurfaceInterface::panelTakesFocusChanged , this, [this, surface]() { if (surface->panelTakesFocus()) { workspace()->activateClient(this); } }); connect(surface, &PlasmaShellSurfaceInterface::positionChanged, this, updatePosition); connect(surface, &PlasmaShellSurfaceInterface::roleChanged, this, updateRole); connect(surface, &PlasmaShellSurfaceInterface::panelBehaviorChanged, this, [this] { updateShowOnScreenEdge(); workspace()->updateClientArea(); } ); connect(surface, &PlasmaShellSurfaceInterface::panelAutoHideHideRequested, this, [this] { hideClient(true); m_plasmaShellSurface->hideAutoHidingPanel(); updateShowOnScreenEdge(); } ); connect(surface, &PlasmaShellSurfaceInterface::panelAutoHideShowRequested, this, [this] { hideClient(false); ScreenEdges::self()->reserve(this, ElectricNone); m_plasmaShellSurface->showAutoHidingPanel(); } ); - updatePosition(); + if (surface->isPositionSet()) + updatePosition(); updateRole(); updateShowOnScreenEdge(); connect(this, &XdgShellClient::frameGeometryChanged, this, &XdgShellClient::updateShowOnScreenEdge); setSkipTaskbar(surface->skipTaskbar()); connect(surface, &PlasmaShellSurfaceInterface::skipTaskbarChanged, this, [this] { setSkipTaskbar(m_plasmaShellSurface->skipTaskbar()); }); setSkipSwitcher(surface->skipSwitcher()); connect(surface, &PlasmaShellSurfaceInterface::skipSwitcherChanged, this, [this] { setSkipSwitcher(m_plasmaShellSurface->skipSwitcher()); }); } void XdgShellClient::updateShowOnScreenEdge() { if (!ScreenEdges::self()) { return; } if (m_unmapped || !m_plasmaShellSurface || m_plasmaShellSurface->role() != PlasmaShellSurfaceInterface::Role::Panel) { ScreenEdges::self()->reserve(this, ElectricNone); return; } if ((m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AutoHide && m_hidden) || m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover) { // screen edge API requires an edge, thus we need to figure out which edge the window borders const QRect clientGeometry = frameGeometry(); Qt::Edges edges; for (int i = 0; i < screens()->count(); i++) { const QRect screenGeometry = screens()->geometry(i); if (screenGeometry.left() == clientGeometry.left()) { edges |= Qt::LeftEdge; } if (screenGeometry.right() == clientGeometry.right()) { edges |= Qt::RightEdge; } if (screenGeometry.top() == clientGeometry.top()) { edges |= Qt::TopEdge; } if (screenGeometry.bottom() == clientGeometry.bottom()) { edges |= Qt::BottomEdge; } } // a panel might border multiple screen edges. E.g. a horizontal panel at the bottom will // also border the left and right edge // let's remove such cases if (edges.testFlag(Qt::LeftEdge) && edges.testFlag(Qt::RightEdge)) { edges = edges & (~(Qt::LeftEdge | Qt::RightEdge)); } if (edges.testFlag(Qt::TopEdge) && edges.testFlag(Qt::BottomEdge)) { edges = edges & (~(Qt::TopEdge | Qt::BottomEdge)); } // it's still possible that a panel borders two edges, e.g. bottom and left // in that case the one which is sharing more with the edge wins auto check = [clientGeometry](Qt::Edges edges, Qt::Edge horiz, Qt::Edge vert) { if (edges.testFlag(horiz) && edges.testFlag(vert)) { if (clientGeometry.width() >= clientGeometry.height()) { return edges & ~horiz; } else { return edges & ~vert; } } return edges; }; edges = check(edges, Qt::LeftEdge, Qt::TopEdge); edges = check(edges, Qt::LeftEdge, Qt::BottomEdge); edges = check(edges, Qt::RightEdge, Qt::TopEdge); edges = check(edges, Qt::RightEdge, Qt::BottomEdge); ElectricBorder border = ElectricNone; if (edges.testFlag(Qt::LeftEdge)) { border = ElectricLeft; } if (edges.testFlag(Qt::RightEdge)) { border = ElectricRight; } if (edges.testFlag(Qt::TopEdge)) { border = ElectricTop; } if (edges.testFlag(Qt::BottomEdge)) { border = ElectricBottom; } ScreenEdges::self()->reserve(this, border); } else { ScreenEdges::self()->reserve(this, ElectricNone); } } bool XdgShellClient::isInitialPositionSet() const { if (m_plasmaShellSurface) { return m_plasmaShellSurface->isPositionSet(); } return false; } void XdgShellClient::installAppMenu(AppMenuInterface *menu) { m_appMenuInterface = menu; auto updateMenu = [this](AppMenuInterface::InterfaceAddress address) { updateApplicationMenuServiceName(address.serviceName); updateApplicationMenuObjectPath(address.objectPath); }; connect(m_appMenuInterface, &AppMenuInterface::addressChanged, this, [=](AppMenuInterface::InterfaceAddress address) { updateMenu(address); }); updateMenu(menu->address()); } void XdgShellClient::installPalette(ServerSideDecorationPaletteInterface *palette) { m_paletteInterface = palette; auto updatePalette = [this](const QString &palette) { AbstractClient::updateColorScheme(rules()->checkDecoColor(palette)); }; connect(m_paletteInterface, &ServerSideDecorationPaletteInterface::paletteChanged, this, [=](const QString &palette) { updatePalette(palette); }); connect(m_paletteInterface, &QObject::destroyed, this, [=]() { updatePalette(QString()); }); updatePalette(palette->palette()); } void XdgShellClient::updateColorScheme() { if (m_paletteInterface) { AbstractClient::updateColorScheme(rules()->checkDecoColor(m_paletteInterface->palette())); } else { AbstractClient::updateColorScheme(rules()->checkDecoColor(QString())); } } void XdgShellClient::updateMaximizeMode(MaximizeMode maximizeMode) { if (maximizeMode == m_maximizeMode) { return; } m_maximizeMode = maximizeMode; updateWindowRules(Rules::MaximizeHoriz | Rules::MaximizeVert | Rules::Position | Rules::Size); emit clientMaximizedStateChanged(this, m_maximizeMode); emit clientMaximizedStateChanged(this, m_maximizeMode & MaximizeHorizontal, m_maximizeMode & MaximizeVertical); } bool XdgShellClient::hasStrut() const { if (!isShown(true)) { return false; } if (!m_plasmaShellSurface) { return false; } if (m_plasmaShellSurface->role() != PlasmaShellSurfaceInterface::Role::Panel) { return false; } return m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible; } quint32 XdgShellClient::windowId() const { return m_windowId; } void XdgShellClient::updateIcon() { const QString waylandIconName = QStringLiteral("wayland"); const QString dfIconName = iconFromDesktopFile(); const QString iconName = dfIconName.isEmpty() ? waylandIconName : dfIconName; if (iconName == icon().name()) { return; } setIcon(QIcon::fromTheme(iconName)); } bool XdgShellClient::isTransient() const { return m_transient; } bool XdgShellClient::hasTransientPlacementHint() const { return isTransient() && transientFor() && m_xdgShellPopup; } QRect XdgShellClient::transientPlacement(const QRect &bounds) const { Q_ASSERT(m_xdgShellPopup); QRect anchorRect; Qt::Edges anchorEdge; Qt::Edges gravity; QPoint offset; PositionerConstraints constraintAdjustments; QSize size = frameGeometry().size(); const QPoint parentClientPos = transientFor()->pos() + transientFor()->clientPos(); // returns if a target is within the supplied bounds, optional edges argument states which side to check auto inBounds = [bounds](const QRect &target, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::TopEdge | Qt::BottomEdge) -> bool { if (edges & Qt::LeftEdge && target.left() < bounds.left()) { return false; } if (edges & Qt::TopEdge && target.top() < bounds.top()) { return false; } if (edges & Qt::RightEdge && target.right() > bounds.right()) { //normal QRect::right issue cancels out return false; } if (edges & Qt::BottomEdge && target.bottom() > bounds.bottom()) { return false; } return true; }; anchorRect = m_xdgShellPopup->anchorRect(); anchorEdge = m_xdgShellPopup->anchorEdge(); gravity = m_xdgShellPopup->gravity(); offset = m_xdgShellPopup->anchorOffset(); constraintAdjustments = m_xdgShellPopup->constraintAdjustments(); if (!size.isValid()) { size = m_xdgShellPopup->initialSize(); } QRect popupRect(popupOffset(anchorRect, anchorEdge, gravity, size) + offset + parentClientPos, size); //if that fits, we don't need to do anything if (inBounds(popupRect)) { return popupRect; } //otherwise apply constraint adjustment per axis in order XDG Shell Popup states if (constraintAdjustments & PositionerConstraint::FlipX) { if (!inBounds(popupRect, Qt::LeftEdge | Qt::RightEdge)) { //flip both edges (if either bit is set, XOR both) auto flippedAnchorEdge = anchorEdge; if (flippedAnchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { flippedAnchorEdge ^= (Qt::LeftEdge | Qt::RightEdge); } auto flippedGravity = gravity; if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) { flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge); } auto flippedPopupRect = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size); //if it still doesn't fit we should continue with the unflipped version if (inBounds(flippedPopupRect, Qt::LeftEdge | Qt::RightEdge)) { popupRect.moveLeft(flippedPopupRect.left()); } } } if (constraintAdjustments & PositionerConstraint::SlideX) { if (!inBounds(popupRect, Qt::LeftEdge)) { popupRect.moveLeft(bounds.left()); } if (!inBounds(popupRect, Qt::RightEdge)) { popupRect.moveRight(bounds.right()); } } if (constraintAdjustments & PositionerConstraint::ResizeX) { QRect unconstrainedRect = popupRect; if (!inBounds(unconstrainedRect, Qt::LeftEdge)) { unconstrainedRect.setLeft(bounds.left()); } if (!inBounds(unconstrainedRect, Qt::RightEdge)) { unconstrainedRect.setRight(bounds.right()); } if (unconstrainedRect.isValid()) { popupRect = unconstrainedRect; } } if (constraintAdjustments & PositionerConstraint::FlipY) { if (!inBounds(popupRect, Qt::TopEdge | Qt::BottomEdge)) { //flip both edges (if either bit is set, XOR both) auto flippedAnchorEdge = anchorEdge; if (flippedAnchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { flippedAnchorEdge ^= (Qt::TopEdge | Qt::BottomEdge); } auto flippedGravity = gravity; if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) { flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge); } auto flippedPopupRect = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size); //if it still doesn't fit we should continue with the unflipped version if (inBounds(flippedPopupRect, Qt::TopEdge | Qt::BottomEdge)) { popupRect.moveTop(flippedPopupRect.top()); } } } if (constraintAdjustments & PositionerConstraint::SlideY) { if (!inBounds(popupRect, Qt::TopEdge)) { popupRect.moveTop(bounds.top()); } if (!inBounds(popupRect, Qt::BottomEdge)) { popupRect.moveBottom(bounds.bottom()); } } if (constraintAdjustments & PositionerConstraint::ResizeY) { QRect unconstrainedRect = popupRect; if (!inBounds(unconstrainedRect, Qt::TopEdge)) { unconstrainedRect.setTop(bounds.top()); } if (!inBounds(unconstrainedRect, Qt::BottomEdge)) { unconstrainedRect.setBottom(bounds.bottom()); } if (unconstrainedRect.isValid()) { popupRect = unconstrainedRect; } } return popupRect; } QPoint XdgShellClient::popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) const { QPoint anchorPoint; switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { case Qt::LeftEdge: anchorPoint.setX(anchorRect.x()); break; case Qt::RightEdge: anchorPoint.setX(anchorRect.x() + anchorRect.width()); break; default: anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0)); } switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { case Qt::TopEdge: anchorPoint.setY(anchorRect.y()); break; case Qt::BottomEdge: anchorPoint.setY(anchorRect.y() + anchorRect.height()); break; default: anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0)); } // calculate where the top left point of the popup will end up with the applied gravity // gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge // will next to the anchor point QPoint popupPosAdjust; switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) { case Qt::LeftEdge: popupPosAdjust.setX(-popupSize.width()); break; case Qt::RightEdge: popupPosAdjust.setX(0); break; default: popupPosAdjust.setX(qRound(-popupSize.width() / 2.0)); } switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) { case Qt::TopEdge: popupPosAdjust.setY(-popupSize.height()); break; case Qt::BottomEdge: popupPosAdjust.setY(0); break; default: popupPosAdjust.setY(qRound(-popupSize.height() / 2.0)); } return anchorPoint + popupPosAdjust; } void XdgShellClient::doResizeSync() { requestGeometry(moveResizeGeometry()); } QMatrix4x4 XdgShellClient::inputTransformation() const { QMatrix4x4 matrix; matrix.translate(-m_bufferGeometry.x(), -m_bufferGeometry.y()); return matrix; } void XdgShellClient::installServerSideDecoration(KWayland::Server::ServerSideDecorationInterface *deco) { if (m_serverDecoration == deco) { return; } m_serverDecoration = deco; connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this, [this] { m_serverDecoration = nullptr; if (m_closing || !Workspace::self()) { return; } if (!m_unmapped) { // maybe delay to next event cycle in case the XdgShellClient is getting destroyed, too updateDecoration(true); } } ); if (!m_unmapped) { updateDecoration(true); } connect(m_serverDecoration, &ServerSideDecorationInterface::modeRequested, this, [this] (ServerSideDecorationManagerInterface::Mode mode) { const bool changed = mode != m_serverDecoration->mode(); if (changed && !m_unmapped) { updateDecoration(false); } } ); } void XdgShellClient::installXdgDecoration(XdgDecorationInterface *deco) { Q_ASSERT(m_xdgShellToplevel); m_xdgDecoration = deco; connect(m_xdgDecoration, &QObject::destroyed, this, [this] { m_xdgDecoration = nullptr; if (m_closing || !Workspace::self()) { return; } updateDecoration(true); } ); connect(m_xdgDecoration, &XdgDecorationInterface::modeRequested, this, [this] () { //force is true as we must send a new configure response updateDecoration(false, true); }); } bool XdgShellClient::shouldExposeToWindowManagement() { if (isLockScreen()) { return false; } if (m_xdgShellPopup) { return false; } return true; } KWayland::Server::XdgShellSurfaceInterface::States XdgShellClient::xdgSurfaceStates() const { XdgShellSurfaceInterface::States states; if (isActive()) { states |= XdgShellSurfaceInterface::State::Activated; } if (isFullScreen()) { states |= XdgShellSurfaceInterface::State::Fullscreen; } if (m_requestedMaximizeMode == MaximizeMode::MaximizeFull) { states |= XdgShellSurfaceInterface::State::Maximized; } if (isResize()) { states |= XdgShellSurfaceInterface::State::Resizing; } return states; } void XdgShellClient::doMinimize() { if (isMinimized()) { workspace()->clientHidden(this); } else { emit windowShown(this); } workspace()->updateMinimizedOfTransients(this); } void XdgShellClient::showOnScreenEdge() { if (!m_plasmaShellSurface || m_unmapped) { return; } hideClient(false); workspace()->raiseClient(this); if (m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AutoHide) { m_plasmaShellSurface->showAutoHidingPanel(); } } bool XdgShellClient::dockWantsInput() const { if (m_plasmaShellSurface) { if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Panel) { return m_plasmaShellSurface->panelTakesFocus(); } } return false; } void XdgShellClient::killWindow() { if (!surface()) { return; } auto c = surface()->client(); if (c->processId() == getpid() || c->processId() == 0) { c->destroy(); return; } ::kill(c->processId(), SIGTERM); // give it time to terminate and only if terminate fails, try destroy Wayland connection QTimer::singleShot(5000, c, &ClientConnection::destroy); } bool XdgShellClient::isLocalhost() const { return true; } bool XdgShellClient::hasPopupGrab() const { return m_hasPopupGrab; } void XdgShellClient::popupDone() { if (m_xdgShellPopup) { m_xdgShellPopup->popupDone(); } } void XdgShellClient::updateClientOutputs() { QVector clientOutputs; const auto outputs = waylandServer()->display()->outputs(); for (OutputInterface *output : outputs) { const QRect outputGeometry(output->globalPosition(), output->pixelSize() / output->scale()); if (frameGeometry().intersects(outputGeometry)) { clientOutputs << output; } } surface()->setOutputs(clientOutputs); } bool XdgShellClient::isPopupWindow() const { if (Toplevel::isPopupWindow()) { return true; } if (m_xdgShellPopup != nullptr) { return true; } return false; } bool XdgShellClient::supportsWindowRules() const { if (m_plasmaShellSurface) { return false; } return m_xdgShellToplevel; } QRect XdgShellClient::adjustMoveGeometry(const QRect &rect) const { QRect geometry = rect; geometry.moveTopLeft(moveResizeGeometry().topLeft()); return geometry; } QRect XdgShellClient::adjustResizeGeometry(const QRect &rect) const { QRect geometry = rect; // We need to adjust frame geometry because configure events carry the maximum window geometry // size. A client that has aspect ratio can attach a buffer with smaller size than the one in // a configure event. switch (moveResizePointerMode()) { case PositionTopLeft: geometry.moveRight(moveResizeGeometry().right()); geometry.moveBottom(moveResizeGeometry().bottom()); break; case PositionTop: case PositionTopRight: geometry.moveLeft(moveResizeGeometry().left()); geometry.moveBottom(moveResizeGeometry().bottom()); break; case PositionRight: case PositionBottomRight: case PositionBottom: geometry.moveLeft(moveResizeGeometry().left()); geometry.moveTop(moveResizeGeometry().top()); break; case PositionBottomLeft: case PositionLeft: geometry.moveRight(moveResizeGeometry().right()); geometry.moveTop(moveResizeGeometry().top()); break; case PositionCenter: Q_UNREACHABLE(); } return geometry; } void XdgShellClient::ping(PingReason reason) { Q_ASSERT(m_xdgShellToplevel); XdgShellInterface *shell = static_cast(m_xdgShellToplevel->global()); const quint32 serial = shell->ping(m_xdgShellToplevel); m_pingSerials.insert(serial, reason); } }