From 68a6fc25e6ef9d7d13f54db739eab96ec870dfe0 Mon Sep 17 00:00:00 2001 From: Yoq To Date: Wed, 6 Jan 2021 13:49:26 +0100 Subject: [PATCH] Provide kwin-5.20.5 --- kde-plasma/kwin/Manifest | 1 + .../kwin/files/kwin-lowlatency-5.20.5.patch | 2982 +++++++++++++++++ kde-plasma/kwin/kwin-5.20.5.ebuild | 119 + 3 files changed, 3102 insertions(+) create mode 100644 kde-plasma/kwin/files/kwin-lowlatency-5.20.5.patch create mode 100644 kde-plasma/kwin/kwin-5.20.5.ebuild diff --git a/kde-plasma/kwin/Manifest b/kde-plasma/kwin/Manifest index ba4eadd..c7d4fd0 100644 --- a/kde-plasma/kwin/Manifest +++ b/kde-plasma/kwin/Manifest @@ -1,3 +1,4 @@ DIST kwin-5.19.5.tar.xz 6260188 BLAKE2B bcf3c8afc00af0df8cddeb49396bd23df6178e379ac4c3ba3c547a2c602d309202a72136b69b83f729434fc5691ba24699cf3f44d47b2c033623bca5d551bdb1 SHA512 97ad0096066d99b4bba3089416a6d3744b6f83d82a004caa8762b420cad34cac4221b3535678d4c6f1bcb43c4d97db56be5ac68c4ac501dc168f4472a6c0dad5 DIST kwin-5.20.3.tar.xz 6329376 BLAKE2B 11dfb77c147f9033850fa4592ec3e4baec425a32c377869c427591aae8239ce86452660063dbf1fbfa7ec311b73fcece8e2512fc8ae5bb84bcf169d5f4452965 SHA512 a156ef06fad48402a98e13dbaeeddf0f84e74b969198be631a3519fd36216968914ff4dca90e74b9d7a15b2ee7479791822006e13046e6ad4f1463faeac759e1 DIST kwin-5.20.4.tar.xz 6328068 BLAKE2B af249815add959b337a7b08a3a15fdbbf6949595d27653611954f90dc12d697ca062ea46c8b00775f3e284b3e4ae12bd3dce11de7eb1234ec1bfcdb59de9a9be SHA512 b402ce6fea79d4c41d10b76d48f5737c10321ca5ab4a2b188646d8fe2b8ea346813091412a7dbd1246eb70ea3f4cd6961d577c19c325a9b5d94083961e0ed512 +DIST kwin-5.20.5.tar.xz 6329444 BLAKE2B e80890c1a353b3b8a15659ea3f88e08b84f29ee863aa41ed99758e93008def940450abc2ad66bc2f5d4c9cd391a3d6ddb21eb2ab79d3696b7373f8ae0fdb6d89 SHA512 e9186dc71e3e9b913314a83fe9413b956d61d633f0e8418fd47d82178c6f50eb75b03299c00495af351b0951df23057500ef28123123583c291a0c29ea3414f1 diff --git a/kde-plasma/kwin/files/kwin-lowlatency-5.20.5.patch b/kde-plasma/kwin/files/kwin-lowlatency-5.20.5.patch new file mode 100644 index 0000000..4e13782 --- /dev/null +++ b/kde-plasma/kwin/files/kwin-lowlatency-5.20.5.patch @@ -0,0 +1,2982 @@ +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/autotests/CMakeLists.txt kwin/autotests/CMakeLists.txt +--- kwin-5.20.5/autotests/CMakeLists.txt 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/autotests/CMakeLists.txt 2020-11-15 03:17:53.481629532 -0500 +@@ -181,6 +181,7 @@ + kconfig_add_kcfg_files(testScriptedEffectLoader_SRCS ../settings.kcfgc) + add_executable(testScriptedEffectLoader ${testScriptedEffectLoader_SRCS}) + ++target_compile_definitions(testScriptedEffectLoader PUBLIC KWINLL_NO_OPTIONS) + target_link_libraries(testScriptedEffectLoader + Qt5::Concurrent + Qt5::Qml +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/colorcorrection/clockskewnotifierengine_linux.cpp kwin/colorcorrection/clockskewnotifierengine_linux.cpp +--- kwin-5.20.5/colorcorrection/clockskewnotifierengine_linux.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/colorcorrection/clockskewnotifierengine_linux.cpp 2020-11-20 19:36:33.983428353 -0500 +@@ -8,6 +8,7 @@ + + #include + ++#include + #include + #include + #include +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/composite.cpp kwin/composite.cpp +--- kwin-5.20.5/composite.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/composite.cpp 2020-11-20 19:36:34.010095021 -0500 +@@ -50,6 +50,7 @@ + #include + + #include ++#include + + Q_DECLARE_METATYPE(KWin::X11Compositor::SuspendReason) + +@@ -113,6 +114,7 @@ + , m_selectionOwner(nullptr) + , vBlankInterval(0) + , fpsInterval(0) ++ , forceUnredirectCheck(false) + , m_timeSinceLastVBlank(0) + , m_scene(nullptr) + , m_bufferSwapPending(false) +@@ -121,6 +123,10 @@ + connect(options, &Options::configChanged, this, &Compositor::configChanged); + connect(options, &Options::animationSpeedChanged, this, &Compositor::configChanged); + ++ connect(&unredirectTimer, &QTimer::timeout, this, &Compositor::delayedCheckUnredirect); ++ connect(options, &Options::unredirectFullscreenChanged, this, &Compositor::delayedCheckUnredirect); ++ unredirectTimer.setSingleShot(true); ++ + m_monotonicClock.start(); + + // 2 sec which should be enough to restart the compositor. +@@ -721,7 +727,23 @@ + if (m_bufferSwapPending && m_scene->syncsToVBlank()) { + m_composeAtSwapCompletion = true; + } else { +- scheduleRepaint(); ++ if (m_bufferSwapPending && m_scene->syncsToVBlank()) { ++ m_composeAtSwapCompletion = true; ++ } else { ++ if (m_idle) { ++ m_idle=false; ++ m_totalSkips--; ++ if (m_totalSkips<0) m_totalSkips=0; ++ // TODO: improve this thing ++ m_lastPaintFree=2000; ++ } ++ if (m_scene->syncsToVBlank()) { ++ usleep(m_lastPaintFree); ++ } else { ++ usleep(6000); ++ } ++ scheduleRepaint(); ++ } + } + } + +@@ -834,6 +856,57 @@ + } + } + // Force 4fps minimum: ++ if (waitTime<4) waitTime=4; ++ m_totalSkips-=0.004; ++ if (m_totalSkips<0) { ++ m_totalSkips=0; ++ } ++ if ((signed)(m_lastPaintFree-2000)>(signed)((waitTime*1000)-4000)) { ++ m_totalSkips++; ++ switch (options->latencyControl()) { ++ case 0: // favor responsive ++ m_lastPaintFree=(waitTime*1000)-4000; ++ break; ++ case 2: // favor low-latency ++ m_lastPaintFree-=500; ++ break; ++ case 3: // aggressive ++ m_lastPaintFree-=300; ++ break; ++ case 1: default: // balanced ++ m_lastPaintFree-=500; ++ break; ++ } ++ //printf("\x1b[1;31mstutter\x1b[m\n"); ++ } else { ++ switch (options->latencyControl()) { ++ case 0: // favor responsive ++ m_lastPaintFree=fmin((waitTime*1000)-4000,m_lastPaintFree+(50-m_totalSkips*5)); ++ break; ++ case 2: // favor low-latency ++ m_lastPaintFree=fmin((waitTime*1000)-4000,m_lastPaintFree+(500-m_totalSkips*30)); ++ break; ++ case 3: // aggressive ++ m_lastPaintFree=fmin((waitTime*1000)-4000,m_lastPaintFree+(1000-m_totalSkips*30)); ++ break; ++ case 1: default: // balanced ++ m_lastPaintFree=fmin((waitTime*1000)-4000,m_lastPaintFree+(200-m_totalSkips*20)); ++ break; ++ } ++ } ++ if (m_lastPaintFreeminLatency()*1000) { ++ m_lastPaintFree=options->minLatency()*1000; ++ } ++ if (m_lastPaintFree<1) { ++ m_lastPaintFree=1; ++ } ++ if (m_lastPaintFree>options->maxLatency()*1000) { ++ m_lastPaintFree=options->maxLatency()*1000; ++ } ++ if (m_totalSkips>10) { ++ m_totalSkips=10; ++ } ++ waitTime=0; + compositeTimer.start(qMin(waitTime, 250u), this); + } + +@@ -842,6 +915,54 @@ + return m_state == State::On; + } + ++void Compositor::checkUnredirect() ++{ ++ checkUnredirect(false); ++} ++ ++// force is needed when the list of windows changes (e.g. a window goes away) ++void Compositor::checkUnredirect(bool force) ++{ ++ if (!isActive() || !m_scene->overlayWindow() || m_scene->overlayWindow()->window() == None || !options->isUnredirectFullscreen()) ++ return; ++ if (force) ++ forceUnredirectCheck = true; ++ if (!unredirectTimer.isActive()) ++ unredirectTimer.start(0); ++} ++ ++void Compositor::delayedCheckUnredirect() ++{ ++ if (!isActive() || !m_scene->overlayWindow() || m_scene->overlayWindow()->window() == None || !(options->isUnredirectFullscreen() || sender() == options)) ++ return; ++ QList list; ++ bool changed = forceUnredirectCheck; ++ foreach (X11Client * c, Workspace::self()->clientList()) ++ list.append(c); ++ foreach (Unmanaged * c, Workspace::self()->unmanagedList()) ++ list.append(c); ++ foreach (Toplevel * c, list) { ++ if (c->updateUnredirectedState()) { ++ changed = true; ++ break; ++ } ++ } ++ // no desktops, no Deleted ones ++ if (!changed) ++ return; ++ forceUnredirectCheck = false; ++ // Cut out parts from the overlay window where unredirected windows are, ++ // so that they are actually visible. ++ const QSize &s = screens()->size(); ++ QRegion reg(0, 0, s.width(), s.height()); ++ foreach (Toplevel * c, list) { ++ if (c->unredirected()) ++ reg -= c->frameGeometry(); ++ } ++ m_scene->overlayWindow()->setShape(reg); ++ addRepaint(reg); ++} ++ + WaylandCompositor::WaylandCompositor(QObject *parent) + : Compositor(parent) + { +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/composite.h kwin/composite.h +--- kwin-5.20.5/composite.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/composite.h 2020-11-20 19:36:34.010095021 -0500 +@@ -48,6 +48,13 @@ + * Schedules a new repaint if no repaint is currently scheduled. + */ + void scheduleRepaint(); ++ ++ /** ++ * Checks for possibly unredirectable windows. ++ */ ++ void checkUnredirect(); ++ void checkUnredirect(bool force); ++ void delayedCheckUnredirect(); + + /** + * Notifies the compositor that SwapBuffers() is about to be called. +@@ -149,6 +156,9 @@ + qint64 vBlankInterval, fpsInterval; + QRegion repaints_region; + ++ QTimer unredirectTimer; ++ bool forceUnredirectCheck; ++ + qint64 m_timeSinceLastVBlank; + + Scene *m_scene; +@@ -158,6 +168,11 @@ + + int m_framesToTestForSafety = 3; + QElapsedTimer m_monotonicClock; ++ ++ // low-latency stuff ++ int m_lastPaintFree=8000; ++ float m_totalSkips=0; ++ bool m_idle; + }; + + class KWIN_EXPORT WaylandCompositor : public Compositor +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/deleted.cpp kwin/deleted.cpp +--- kwin-5.20.5/deleted.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/deleted.cpp 2020-11-20 19:36:34.040095020 -0500 +@@ -297,5 +297,10 @@ + m_transientFor.removeAll(parent); + } + ++bool Deleted::shouldUnredirect() const ++{ ++ return false; ++} ++ + } // namespace + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/deleted.h kwin/deleted.h +--- kwin-5.20.5/deleted.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/deleted.h 2020-11-20 19:36:34.040095020 -0500 +@@ -170,6 +170,8 @@ + bool isOutline() const override { + return m_wasOutline; + } ++protected: ++ bool shouldUnredirect() const override; + + private Q_SLOTS: + void mainClientClosed(KWin::Toplevel *client); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/CMakeLists.txt kwin/effects/CMakeLists.txt +--- kwin-5.20.5/effects/CMakeLists.txt 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects/CMakeLists.txt 2020-11-20 19:36:34.040095020 -0500 +@@ -99,6 +99,7 @@ + magnifier/magnifier.cpp + mouseclick/mouseclick.cpp + mousemark/mousemark.cpp ++ mousepos/mousepos.cpp + presentwindows/presentwindows.cpp + presentwindows/presentwindows_proxy.cpp + resize/resize.cpp +@@ -138,6 +139,7 @@ + magnifier/magnifierconfig.kcfgc + mouseclick/mouseclickconfig.kcfgc + mousemark/mousemarkconfig.kcfgc ++ mousepos/mouseposconfig.kcfgc + presentwindows/presentwindowsconfig.kcfgc + resize/resizeconfig.kcfgc + showfps/showfpsconfig.kcfgc +@@ -210,6 +212,7 @@ + add_subdirectory(magnifier) + add_subdirectory(mouseclick) + add_subdirectory(mousemark) ++add_subdirectory(mousepos) + include(screenshot/CMakeLists.txt) + include(sheet/CMakeLists.txt) + include(snaphelper/CMakeLists.txt) +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/effect_builtins.cpp kwin/effects/effect_builtins.cpp +--- kwin-5.20.5/effects/effect_builtins.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects/effect_builtins.cpp 2020-11-20 19:36:34.043428354 -0500 +@@ -43,6 +43,7 @@ + #include "magnifier/magnifier.h" + #include "mouseclick/mouseclick.h" + #include "mousemark/mousemark.h" ++#include "mousepos/mousepos.h" + #include "sheet/sheet.h" + #include "snaphelper/snaphelper.h" + #include "startupfeedback/startupfeedback.h" +@@ -370,6 +371,21 @@ + nullptr, + nullptr + #endif ++EFFECT_FALLBACK ++ }, { ++ QStringLiteral("mousepos"), ++ i18ndc("kwin_effects", "Name of a KWin Effect", "Paint cursor"), ++ i18ndc("kwin_effects", "Comment describing the KWin Effect", "Redraw the mouse cursor for capturing the display using kmsgrab in FFmpeg"), ++ QStringLiteral("Tools"), ++ QString(), ++ QUrl(), ++ false, ++ false, ++#ifdef EFFECT_BUILTINS ++ &createHelper, ++ nullptr, ++ nullptr ++#endif + EFFECT_FALLBACK + }, { + QStringLiteral("presentwindows"), +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/effect_builtins.h kwin/effects/effect_builtins.h +--- kwin-5.20.5/effects/effect_builtins.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects/effect_builtins.h 2020-11-20 19:36:34.043428354 -0500 +@@ -42,6 +42,7 @@ + Magnifier, + MouseClick, + MouseMark, ++ MousePos, + PresentWindows, + Resize, + ScreenEdge, +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/CMakeLists.txt kwin/effects/mousepos/CMakeLists.txt +--- kwin-5.20.5/effects/mousepos/CMakeLists.txt 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/CMakeLists.txt 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,25 @@ ++####################################### ++# Config ++set(kwin_mousepos_config_SRCS mousepos_config.cpp) ++ki18n_wrap_ui(kwin_mousepos_config_SRCS mousepos_config.ui) ++qt5_add_dbus_interface(kwin_mousepos_config_SRCS ${kwin_effects_dbus_xml} kwineffects_interface) ++kconfig_add_kcfg_files(kwin_mousepos_config_SRCS mouseposconfig.kcfgc) ++ ++add_library(kwin_mousepos_config MODULE ${kwin_mousepos_config_SRCS}) ++ ++target_link_libraries(kwin_mousepos_config ++ KF5::ConfigWidgets ++ KF5::GlobalAccel ++ KF5::I18n ++ KF5::Service ++ KF5::XmlGui ++) ++ ++kcoreaddons_desktop_to_json(kwin_mousepos_config mousepos_config.desktop SERVICE_TYPES kcmodule.desktop) ++ ++install( ++ TARGETS ++ kwin_mousepos_config ++ DESTINATION ++ ${PLUGIN_INSTALL_DIR}/kwin/effects/configs ++) +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/data/1.10/motion.frag kwin/effects/mousepos/data/1.10/motion.frag +--- kwin-5.20.5/effects/mousepos/data/1.10/motion.frag 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/data/1.10/motion.frag 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,43 @@ ++#version 140 ++ ++// thanks Steven Lu ++ ++uniform sampler2D sampler; ++in vec2 f_sceneCoord; // this should be pretransformed texcoord to scene tex ++// it is also appropriate to use as a "this pixel" position ++// (in relation to center, etc) ++varying float f_alpha; ++varying vec2 f_center; ++in vec3 f_vel; ++in float samples; ++varying mat2 rot_per_sample; ++ ++out vec4 fragColor; ++ ++void main (void) { ++vec2 original_center = f_center - f_vel.xy; ++// vel.xy is actually just the dist ++vec4 accum = vec4(0,0,0,0); ++mat2 cumulativeRotation; ++// set identity rotation matrix ++cumulativeRotation[0] = vec2(1,0); cumulativeRotation[1] = vec2(0, ++1); ++float samples_i = ceil(samples); ++for(int i=0;i1.0f || pos.x<0.0f || pos.y>1.0f || pos.y<0.0f) continue; ++vec4 col = texture2D(sampler, pos); ++//col=vec4(0.0f,0.0f,0.0f,0.0f); ++// 1: translate to orig ctr 2: rotate by i*rot ++// 3: translate back to origctr+(curctr-origctr)*i ++if (col.a>0.01f) { accum = accum + vec4(col.rgba); } ++cumulativeRotation = cumulativeRotation * rot_per_sample; ++} ++if (accum.a < 1.0/1024.) discard; // prevent divide by zero ++fragColor = vec4(accum.rgb*(1.0/accum.a),accum.a/samples_i); ++//fragColor=vec4(texture2D(sampler, f_sceneCoord)); ++//fragColor=vec4(1.0f,1.0f,1.0f,1.0f); ++// This should be a non-premultiplied alpha value for use with ++// saturate blending. ++} +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/data/1.10/motion.vert kwin/effects/mousepos/data/1.10/motion.vert +--- kwin-5.20.5/effects/mousepos/data/1.10/motion.vert 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/data/1.10/motion.vert 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,61 @@ ++#version 140 ++ ++// thanks Steven Lu ++ ++// KWin ++uniform mat4 projection; ++uniform mat4 modelview; ++uniform mat4 modelViewProjectionMatrix; ++uniform mat4 textureMatrix; ++ ++in vec4 position; ++in vec4 texcoord; ++ ++uniform mat4 mvm; ++uniform vec2 viewport; ++uniform vec2 in_pos; ++// this is vertex position ++uniform vec2 in_center; ++uniform vec4 in_vel; ++uniform vec2 in_sizes; ++// those were the per-object velocity related quantities ++// I pack omega*dt into in_vel.z, and in_vel.w is max-displacement ++// for calculating samples ++uniform float in_alpha; ++varying float f_alpha; ++varying vec2 f_center; ++out vec3 f_vel; ++out float samples; // # of samples to blur ++varying mat2 rot_per_sample; // A special scale-rotate matrix ++out vec2 f_sceneCoord; // NDC to tex coord ++varying mat4 f_scale; ++void main (void) { ++mat4 proj_modelview_mat = projection * modelview; ++f_scale[0]=vec4(1.0+abs(in_vel.x),0.0,0.0,-abs(in_vel.x)*(in_pos.x+((sign(in_vel.x)>0.5)?in_sizes.x:0.0))); ++f_scale[1]=vec4(0.0,1.0+abs(in_vel.y),0.0,-abs(in_vel.y)*(in_pos.y+((sign(in_vel.y)>0.5)?in_sizes.y:0.0))); ++f_scale[2]=vec4(0.0,0.0,1.0,0.0); ++f_scale[3]=vec4(0.0,0.0,0.0,1.0); ++/*f_scale[0]=vec4(1.0,0.0,0.0,0.0); ++f_scale[1]=vec4(0.0,1.0,0.0,0.0); ++f_scale[2]=vec4(0.0,0.0,1.0,0.0); ++f_scale[3]=vec4(0.0,0.0,0.0,1.0);*/ ++gl_Position = modelViewProjectionMatrix * vec4(position.xyzw*f_scale); ++f_sceneCoord = vec2( texcoord)*(1+abs(in_vel.xy))-max(vec2(0.0,0.0),in_vel.xy); ++f_center = ((modelViewProjectionMatrix * vec4(in_center,0.0,1.0)).xy +++ vec2(1.0,1.0))*0.5; // transform the center to clip space ++f_vel.xy=in_vel.xy; ++//f_vel.xy = (proj_modelview_mat * vec4(in_vel.xy,0.0,0.0)).xy * 0.5; ++// velocity also need to be in clip space ++// careful! We don't shift this one, only scale ++f_vel.z = in_vel.z; // Store omega in z-comp in radians ++samples = min(50,(modelViewProjectionMatrix * vec4(in_vel.w,0,0,0)).x ++* viewport.x * 2 + 1); ++// w here is not omega it is the max disp value from CPU ++float theta = in_vel.z/(samples); ++float cost = cos(theta); float sint = sin(theta); ++float aspect = viewport.x/viewport.y; ++rot_per_sample[0] = vec2(cost,sint*aspect); rot_per_sample[1] = vec2(-sint/aspect,cost); ++// the rotation matrix is actually a scale and rotate matrix. ++// the rotation must be correct in world space but is manipulated by the ++// fragment shader in NDC which requires aspect correction. ++} +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/data/1.40/motion.frag kwin/effects/mousepos/data/1.40/motion.frag +--- kwin-5.20.5/effects/mousepos/data/1.40/motion.frag 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/data/1.40/motion.frag 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,43 @@ ++#version 140 ++ ++// thanks Steven Lu ++ ++uniform sampler2D sampler; ++in vec2 f_sceneCoord; // this should be pretransformed texcoord to scene tex ++// it is also appropriate to use as a "this pixel" position ++// (in relation to center, etc) ++varying float f_alpha; ++varying vec2 f_center; ++in vec3 f_vel; ++in float samples; ++varying mat2 rot_per_sample; ++ ++out vec4 fragColor; ++ ++void main (void) { ++vec2 original_center = f_center - f_vel.xy; ++// vel.xy is actually just the dist ++vec4 accum = vec4(0,0,0,0); ++mat2 cumulativeRotation; ++// set identity rotation matrix ++cumulativeRotation[0] = vec2(1,0); cumulativeRotation[1] = vec2(0, ++1); ++float samples_i = ceil(samples); ++for(int i=0;i1.0f || pos.x<0.0f || pos.y>1.0f || pos.y<0.0f) continue; ++vec4 col = texture2D(sampler, pos); ++//col=vec4(0.0f,0.0f,0.0f,0.0f); ++// 1: translate to orig ctr 2: rotate by i*rot ++// 3: translate back to origctr+(curctr-origctr)*i ++if (col.a>0.01f) { accum = accum + vec4(col.rgba); } ++cumulativeRotation = cumulativeRotation * rot_per_sample; ++} ++if (accum.a < 1.0/1024.) discard; // prevent divide by zero ++fragColor = vec4(accum.rgb*(1.0/accum.a),accum.a/samples_i); ++//fragColor=vec4(texture2D(sampler, f_sceneCoord)); ++//fragColor=vec4(1.0f,1.0f,1.0f,1.0f); ++// This should be a non-premultiplied alpha value for use with ++// saturate blending. ++} +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/data/1.40/motion.vert kwin/effects/mousepos/data/1.40/motion.vert +--- kwin-5.20.5/effects/mousepos/data/1.40/motion.vert 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/data/1.40/motion.vert 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,61 @@ ++#version 140 ++ ++// thanks Steven Lu ++ ++// KWin ++uniform mat4 projection; ++uniform mat4 modelview; ++uniform mat4 modelViewProjectionMatrix; ++uniform mat4 textureMatrix; ++ ++in vec4 position; ++in vec4 texcoord; ++ ++uniform mat4 mvm; ++uniform vec2 viewport; ++uniform vec2 in_pos; ++// this is vertex position ++uniform vec2 in_center; ++uniform vec4 in_vel; ++uniform vec2 in_sizes; ++// those were the per-object velocity related quantities ++// I pack omega*dt into in_vel.z, and in_vel.w is max-displacement ++// for calculating samples ++uniform float in_alpha; ++varying float f_alpha; ++varying vec2 f_center; ++out vec3 f_vel; ++out float samples; // # of samples to blur ++varying mat2 rot_per_sample; // A special scale-rotate matrix ++out vec2 f_sceneCoord; // NDC to tex coord ++varying mat4 f_scale; ++void main (void) { ++mat4 proj_modelview_mat = projection * modelview; ++f_scale[0]=vec4(1.0+abs(in_vel.x),0.0,0.0,-abs(in_vel.x)*(in_pos.x+((sign(in_vel.x)>0.5)?in_sizes.x:0.0))); ++f_scale[1]=vec4(0.0,1.0+abs(in_vel.y),0.0,-abs(in_vel.y)*(in_pos.y+((sign(in_vel.y)>0.5)?in_sizes.y:0.0))); ++f_scale[2]=vec4(0.0,0.0,1.0,0.0); ++f_scale[3]=vec4(0.0,0.0,0.0,1.0); ++/*f_scale[0]=vec4(1.0,0.0,0.0,0.0); ++f_scale[1]=vec4(0.0,1.0,0.0,0.0); ++f_scale[2]=vec4(0.0,0.0,1.0,0.0); ++f_scale[3]=vec4(0.0,0.0,0.0,1.0);*/ ++gl_Position = modelViewProjectionMatrix * vec4(position.xyzw*f_scale); ++f_sceneCoord = vec2( texcoord)*(1+abs(in_vel.xy))-max(vec2(0.0,0.0),in_vel.xy); ++f_center = ((modelViewProjectionMatrix * vec4(in_center,0.0,1.0)).xy +++ vec2(1.0,1.0))*0.5; // transform the center to clip space ++f_vel.xy=in_vel.xy; ++//f_vel.xy = (proj_modelview_mat * vec4(in_vel.xy,0.0,0.0)).xy * 0.5; ++// velocity also need to be in clip space ++// careful! We don't shift this one, only scale ++f_vel.z = in_vel.z; // Store omega in z-comp in radians ++samples = min(50,(modelViewProjectionMatrix * vec4(in_vel.w,0,0,0)).x ++* viewport.x * 2 + 1); ++// w here is not omega it is the max disp value from CPU ++float theta = in_vel.z/(samples); ++float cost = cos(theta); float sint = sin(theta); ++float aspect = viewport.x/viewport.y; ++rot_per_sample[0] = vec2(cost,sint*aspect); rot_per_sample[1] = vec2(-sint/aspect,cost); ++// the rotation matrix is actually a scale and rotate matrix. ++// the rotation must be correct in world space but is manipulated by the ++// fragment shader in NDC which requires aspect correction. ++} +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos_config.cpp kwin/effects/mousepos/mousepos_config.cpp +--- kwin-5.20.5/effects/mousepos/mousepos_config.cpp 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos_config.cpp 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,123 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2007 Rivo Laks ++Copyright (C) 2010 Jorge Mata ++ ++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 ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "mousepos_config.h" ++ ++// KConfigSkeleton ++#include "mouseposconfig.h" ++ ++K_PLUGIN_FACTORY_WITH_JSON(MousePosEffectConfigFactory, ++ "mousepos_config.json", ++ registerPlugin();) ++ ++namespace KWin ++{ ++ ++MousePosEffectConfigForm::MousePosEffectConfigForm(QWidget* parent) : QWidget(parent) ++{ ++ setupUi(this); ++} ++ ++MousePosEffectConfig::MousePosEffectConfig(QWidget* parent, const QVariantList& args) : ++ KCModule(KAboutData::pluginData(QStringLiteral("mousepos")), parent, args) ++{ ++ MousePosConfig::instance(KWIN_CONFIG); ++ m_ui = new MousePosEffectConfigForm(this); ++ QVBoxLayout* layout = new QVBoxLayout(this); ++ layout->addWidget(m_ui); ++ ++ addConfig(MousePosConfig::self(), m_ui); ++ ++ m_actionCollection = new KActionCollection(this, QStringLiteral("kwin")); ++ m_actionCollection->setComponentDisplayName(i18n("KWin")); ++ m_actionCollection->setConfigGroup(QStringLiteral("MousePos")); ++ m_actionCollection->setConfigGlobal(true); ++ ++ QAction *a = m_actionCollection->addAction(QStringLiteral("MousePos")); ++ a->setText(i18n("Paint cursor")); ++ a->setProperty("isConfigurationAction", true); ++ ++ KGlobalAccel::self()->setDefaultShortcut(a, QList()); ++ KGlobalAccel::self()->setShortcut(a, QList()); ++ ++ connect(m_ui->kcfg_mpMotionBlur, SIGNAL(keySequenceChanged(QKeySequence)), ++ SLOT(shortcutChanged(QKeySequence))); ++ ++ load(); ++} ++ ++MousePosEffectConfig::~MousePosEffectConfig() ++{ ++} ++ ++void MousePosEffectConfig::checkModifiers() ++{ ++} ++ ++void MousePosEffectConfig::load() ++{ ++ KCModule::load(); ++ ++ checkModifiers(); ++ emit changed(false); ++} ++ ++void MousePosEffectConfig::save() ++{ ++ KCModule::save(); ++ m_actionCollection->writeSettings(); ++ OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), ++ QStringLiteral("/Effects"), ++ QDBusConnection::sessionBus()); ++ interface.reconfigureEffect(QStringLiteral("mousepos")); ++} ++ ++void MousePosEffectConfig::defaults() ++{ ++ KCModule::defaults(); ++ checkModifiers(); ++} ++ ++void MousePosEffectConfig::shortcutChanged(const QKeySequence &seq) ++{ ++ /*if (QAction *a = m_actionCollection->action(QStringLiteral("MousePos"))) { ++ KGlobalAccel::self()->setShortcut(a, QList() << seq, KGlobalAccel::NoAutoloading); ++ }*/ ++// m_actionCollection->writeSettings(); ++ emit changed(true); ++} ++ ++} // namespace ++ ++#include "mousepos_config.moc" +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos_config.desktop kwin/effects/mousepos/mousepos_config.desktop +--- kwin-5.20.5/effects/mousepos/mousepos_config.desktop 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos_config.desktop 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,10 @@ ++[Desktop Entry] ++Type=Service ++X-KDE-ServiceTypes=KCModule ++ ++X-KDE-Library=kwin_mousepos_config ++X-KDE-ParentComponents=mousepos ++ ++Name=Paint cursor ++Name[es]=Pintar cursor ++Name[x-test]=xxPaint Cursorxx +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos_config.h kwin/effects/mousepos/mousepos_config.h +--- kwin-5.20.5/effects/mousepos/mousepos_config.h 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos_config.h 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,62 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2007 Rivo Laks ++Copyright (C) 2010 Jorge Mata ++ ++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_MOUSEPOS_CONFIG_H ++#define KWIN_MOUSEPOS_CONFIG_H ++ ++#include ++ ++#include "ui_mousepos_config.h" ++ ++class KActionCollection; ++ ++namespace KWin ++{ ++ ++class MousePosEffectConfigForm : public QWidget, public Ui::MousePosEffectConfigForm ++{ ++ Q_OBJECT ++public: ++ explicit MousePosEffectConfigForm(QWidget* parent); ++}; ++ ++class MousePosEffectConfig : public KCModule ++{ ++ Q_OBJECT ++public: ++ explicit MousePosEffectConfig(QWidget* parent = 0, const QVariantList& args = QVariantList()); ++ ~MousePosEffectConfig(); ++ ++public Q_SLOTS: ++ virtual void save(); ++ virtual void load(); ++ virtual void defaults(); ++private Q_SLOTS: ++ void shortcutChanged(const QKeySequence &seq); ++private: ++ void checkModifiers(); ++ MousePosEffectConfigForm* m_ui; ++ KActionCollection* m_actionCollection; ++}; ++ ++} // namespace ++ ++#endif +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mouseposconfig.kcfgc kwin/effects/mousepos/mouseposconfig.kcfgc +--- kwin-5.20.5/effects/mousepos/mouseposconfig.kcfgc 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mouseposconfig.kcfgc 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,5 @@ ++File=mousepos.kcfg ++ClassName=MousePosConfig ++NameSpace=KWin ++Singleton=true ++Mutators=true +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos_config.ui kwin/effects/mousepos/mousepos_config.ui +--- kwin-5.20.5/effects/mousepos/mousepos_config.ui 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos_config.ui 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,25 @@ ++ ++ ++ KWin::MousePosEffectConfigForm ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 36 ++ ++ ++ ++ ++ ++ ++ Motion blur ++ ++ ++ ++ ++ ++ ++ ++ +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos.cpp kwin/effects/mousepos/mousepos.cpp +--- kwin-5.20.5/effects/mousepos/mousepos.cpp 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos.cpp 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,236 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2006 Lubos Lunak ++Copyright (C) 2010 Jorge Mata ++ ++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 "mousepos.h" ++ ++// KConfigSkeleton ++#include "mouseposconfig.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++namespace KWin ++{ ++ ++MousePosEffect::MousePosEffect() ++ : m_active(false) ++ , m_inited(false) ++ , m_valid(true) ++{ ++ initConfig(); ++ m_mousePolling = false; ++ ++ m_action = new QAction(this); ++ m_action->setObjectName(QStringLiteral("MousePos")); ++ m_action->setText(i18n("Paint cursor")); ++ //KGlobalAccel::self()->setDefaultShortcut(m_action, QList()); ++ //KGlobalAccel::self()->setShortcut(m_action, QList()); ++ //effects->registerGlobalShortcut(QKeySequence(), m_action); ++ ++ connect(m_action, SIGNAL(triggered(bool)), this, SLOT(toggle())); ++ ++ connect(effects, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)), ++ SLOT(slotMouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers))); ++ reconfigure(ReconfigureAll); ++ if (!m_mousePolling) { ++ effects->startMousePolling(); ++ m_mousePolling = true; ++ } ++} ++ ++MousePosEffect::~MousePosEffect() ++{ ++ if (m_mousePolling) ++ effects->stopMousePolling(); ++} ++ ++void MousePosEffect::reconfigure(ReconfigureFlags) ++{ ++ MousePosConfig::self()->read(); ++} ++ ++void MousePosEffect::prePaintScreen(ScreenPrePaintData& data, int time) ++{ ++ if (m_active) { ++ QTime t = QTime::currentTime(); ++ //m_lastRect[0].moveCenter(cursorPos()); ++ //m_lastRect[1].moveCenter(cursorPos()); ++ m_union=m_lastRect[0].united(m_lastRect[1]); ++ data.paint |= m_union.adjusted(-1,-1,1,1); ++ } ++ effects->prePaintScreen(data, time); ++} ++ ++bool MousePosEffect::loadData() ++{ ++ m_inited = true; ++ printf("load data!\n"); ++ ++ m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString("motion.vert"), QStringLiteral("motion.frag")); ++ if (!m_shader->isValid()) { ++ printf("failure.\n"); ++ qCCritical(KWINEFFECTS) << "The shader failed to load!"; ++ return false; ++ } ++ printf("shader loaded.\n"); ++ return true; ++} ++ ++void MousePosEffect::paintScreen(int mask, const QRegion& region, ScreenPaintData& data) ++{ ++ effects->paintScreen(mask, region, data); // paint normal screen ++ if (!m_active) ++ return; ++ auto c = xcbConnection(); ++ ++ if (m_valid && !m_inited) ++ m_valid = loadData(); ++ ++ if ( effects->isOpenGLCompositing()) { ++ QScopedPointer cursor( ++ xcb_xfixes_get_cursor_image_reply(c, ++ xcb_xfixes_get_cursor_image_unchecked(c), ++ nullptr)); ++ if (cursor.isNull()) { ++ return; ++ } ++ QImage img = QImage((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height, ++ QImage::Format_ARGB32_Premultiplied); ++ ++ if (img.isNull()) { ++ return; ++ } ++ m_cursorTexture.reset(new GLTexture(img)); ++ // get cursor position in projection coordinates ++ if (!m_cursorTexture) { ++ return; ++ } ++ const QRect cursorRect(0, 0, m_cursorTexture->width(), m_cursorTexture->height()); ++ QMatrix4x4 mvp = data.projectionMatrix(); ++ mvp.translate(cursor->x-cursor->xhot, cursor->y-cursor->yhot); ++ ++ // handle transparence ++ glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ ++ // paint texture in cursor offset ++ if (MousePosConfig::motionBlur()) { ++ m_cursorTexture->bind(); ++ ShaderBinder binder(m_shader); ++ binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); ++ binder.shader()->setUniform("viewport",QVector2D(3840,2160)); ++ binder.shader()->setUniform("in_center",QVector2D(0.0f,0.0f)); ++ binder.shader()->setUniform("in_vel",QVector4D(((float)(cursor->x-cursor->xhot)-m_prevX)/(float)cursorRect.width() ++ ,((float)(cursor->y-cursor->yhot)-m_prevY)/(float)cursorRect.height() ++ ,0.0f,32.0f)); ++ //binder.shader()->setUniform("in_pos",QVector2D(cursor->x-cursor->xhot+16, cursor->y-cursor->yhot)); ++ binder.shader()->setUniform("in_pos",QVector2D(0,0)); ++ binder.shader()->setUniform("in_sizes",QVector2D(cursorRect.width(),cursorRect.height())); ++ m_cursorTexture->render(QRegion(cursorRect), cursorRect); ++ m_cursorTexture->unbind(); ++ } else { ++ m_cursorTexture->bind(); ++ ShaderBinder obinder(ShaderTrait::MapTexture); ++ obinder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); ++ m_cursorTexture->render(QRegion(cursorRect), cursorRect); ++ m_cursorTexture->unbind(); ++ } ++ ++ glDisable(GL_BLEND); ++ m_cursorTexture.reset(NULL); ++ ++ m_prevX=cursor->x-cursor->xhot; ++ m_prevY=cursor->y-cursor->yhot; ++ m_lastRect[1]=m_lastRect[0]; ++ m_lastRect[0]=cursorRect; ++ m_lastRect[0].moveTo(m_prevX,m_prevY); ++ } ++} ++ ++void MousePosEffect::postPaintScreen() ++{ ++ if (m_lastRect[0]!=m_lastRect[1]) { ++ effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); ++ } ++ effects->postPaintScreen(); ++} ++ ++bool MousePosEffect::init() ++{ ++ effects->makeOpenGLContextCurrent(); ++ m_lastRect[0].moveCenter(cursorPos()); ++ m_lastRect[1].moveCenter(cursorPos()); ++ m_active = true; ++ printf("init...\n"); ++ return true; ++} ++ ++void MousePosEffect::toggle() ++{ ++ m_mousePolling=true; ++ m_active=true; ++ printf("toggle\n"); ++/* ++ if (m_mousePolling) ++ return; ++ ++ if (m_active) { ++ m_active = false; ++ } else if (!init()) { ++ return; ++ }*/ ++ effects->addRepaint(m_lastRect[0].adjusted(-1,-1,1,1)); ++} ++ ++void MousePosEffect::slotMouseChanged(const QPoint&, const QPoint&, ++ Qt::MouseButtons, Qt::MouseButtons, ++ Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers) ++{ ++ if (!m_mousePolling) // we didn't ask for it but maybe someone else did... ++ return; ++ if (!m_active && !init()) { ++ return; ++ } ++ m_union=m_lastRect[0].united(m_lastRect[1]); ++ effects->addRepaint(m_lastRect[1].adjusted(-1,-1,1,1)); ++} ++ ++void MousePosEffect::loadTexture() ++{ ++} ++ ++bool MousePosEffect::isActive() const ++{ ++ return m_active; ++} ++ ++} // namespace +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos.h kwin/effects/mousepos/mousepos.h +--- kwin-5.20.5/effects/mousepos/mousepos.h 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos.h 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,80 @@ ++/******************************************************************** ++ KWin - the KDE window manager ++ This file is part of the KDE project. ++ ++Copyright (C) 2006 Lubos Lunak ++Copyright (C) 2010 Jorge Mata ++ ++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_MOUSEPOS_H ++#define KWIN_MOUSEPOS_H ++ ++#include ++ ++class QAction; ++ ++namespace KWin ++{ ++class GLTexture; ++ ++class MousePosEffect ++ : public Effect ++{ ++ Q_OBJECT ++ Q_PROPERTY(bool mousePolling READ isMousePolling) ++public: ++ MousePosEffect(); ++ virtual ~MousePosEffect(); ++ virtual void prePaintScreen(ScreenPrePaintData& data, int time); ++ virtual void paintScreen(int mask, const QRegion& region, ScreenPaintData& data); ++ virtual void postPaintScreen(); ++ virtual void reconfigure(ReconfigureFlags); ++ virtual bool isActive() const; ++ ++ // for properties ++ bool isMousePolling() const { ++ return m_mousePolling; ++ } ++protected: ++ bool loadData(); ++private Q_SLOTS: ++ void toggle(); ++ void slotMouseChanged(const QPoint& pos, const QPoint& old, ++ Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, ++ Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); ++private: ++ bool init(); ++ void loadTexture(); ++ QRect m_lastRect[2]; ++ QRect m_union; ++ bool m_active, m_mousePolling; ++ float m_angle; ++ float m_angleBase; ++#ifdef KWIN_HAVE_XRENDER_COMPOSITING ++ QSize m_size[2]; ++#endif ++ QAction* m_action; ++ QScopedPointer m_cursorTexture; ++ Qt::KeyboardModifiers m_modifiers; ++ bool m_inited; ++ bool m_valid; ++ GLShader* m_shader; ++ float m_prevX, m_prevY; ++}; ++ ++} // namespace ++ ++#endif +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/mousepos/mousepos.kcfg kwin/effects/mousepos/mousepos.kcfg +--- kwin-5.20.5/effects/mousepos/mousepos.kcfg 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/effects/mousepos/mousepos.kcfg 2020-09-25 11:49:59.149565231 -0500 +@@ -0,0 +1,12 @@ ++ ++ ++ ++ ++ ++ false ++ ++ ++ +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/presentwindows/presentwindows_config.ui kwin/effects/presentwindows/presentwindows_config.ui +--- kwin-5.20.5/effects/presentwindows/presentwindows_config.ui 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects/presentwindows/presentwindows_config.ui 2020-09-25 11:49:59.149565231 -0500 +@@ -164,6 +164,11 @@ + (Un-)Minimize window + + ++ ++ ++ Close window ++ ++ + + + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects/shaders.qrc kwin/effects/shaders.qrc +--- kwin-5.20.5/effects/shaders.qrc 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects/shaders.qrc 2020-09-25 11:49:59.149565231 -0500 +@@ -6,6 +6,8 @@ + cube/data/1.10/cylinder.vert + cube/data/1.10/sphere.vert + invert/data/1.10/invert.frag ++ mousepos/data/1.10/motion.vert ++ mousepos/data/1.10/motion.frag + lookingglass/data/1.10/lookingglass.frag + startupfeedback/data/1.10/blinking-startup-fragment.glsl + +@@ -16,6 +18,8 @@ + cube/data/1.40/cylinder.vert + cube/data/1.40/sphere.vert + invert/data/1.40/invert.frag ++ mousepos/data/1.40/motion.vert ++ mousepos/data/1.40/motion.frag + lookingglass/data/1.40/lookingglass.frag + startupfeedback/data/1.40/blinking-startup-fragment.glsl + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/effects.cpp kwin/effects.cpp +--- kwin-5.20.5/effects.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/effects.cpp 2020-11-20 19:36:34.040095020 -0500 +@@ -632,6 +632,7 @@ + } + const bool activeChanged = (e == nullptr || fullscreen_effect == nullptr); + fullscreen_effect = e; ++ m_compositor->checkUnredirect(); + emit activeFullScreenEffectChanged(); + if (activeChanged) { + emit hasActiveFullScreenEffectChanged(); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/HACKING.md kwin/HACKING.md +--- kwin-5.20.5/HACKING.md 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/HACKING.md 2020-11-15 03:17:53.461629533 -0500 +@@ -21,13 +21,16 @@ + + To start a nested KWin Wayland use: + +- cd build +- cd bin +- QT_PLUGIN_PATH=`pwd` dbus-run-session ./kwin_wayland --xwayland --socket=wayland-1 ++``` ++cd build ++QT_PLUGIN_PATH="$PWD/bin" dbus-run-session ./bin/kwin_wayland --xwayland --socket=wayland-1 ++``` + + The socket option is not required if KWin is started from an X11 session. On Wayland of course a socket not matching the session's socket must be chosen. To show windows in the nested KWin adjust the environment variables DISPLAY (for X11 windows) and WAYLAND_DISPLAY (for Wayland windows). Alternatively it's possible to pass applications to launch as command line arguments to kwin_wayland command. E.g. + +- QT_PLUGIN_PATH=`pwd` dbus-run-session ./kwin_wayland --xwayland --socket=wayland-1 konsole ++``` ++QT_PLUGIN_PATH="$PWD/bin" dbus-run-session ./bin/kwin_wayland --xwayland --socket=wayland-1 konsole ++``` + + Will start a konsole in the nested KWin. + +@@ -47,9 +50,10 @@ + + KWin for the X11 windowing system cannot be tested with a nested Wayland setup. Instead the common way is to run KWin and replace the existing window manager of the X session: + +- cd build +- cd bin +- QT_PLUGIN_PATH=`pwd` ./kwin_x11 --replace ++``` ++cd build ++QT_PLUGIN_PATH="$PWD/bin" ./bin/kwin_x11 --replace ++``` + + In this case also the current DBus session should be used and dbus-run-session should not be used. Of course it's only possible to start kwin_x11 in an X session. On Wayland kwin_x11 will refuse to start. + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/inputpanelv1client.h kwin/inputpanelv1client.h +--- kwin-5.20.5/inputpanelv1client.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/inputpanelv1client.h 2020-11-20 19:36:34.090095021 -0500 +@@ -35,6 +35,7 @@ + bool isResizable() const override { return false; } + bool isMovable() const override { return false; } + bool isMovableAcrossScreens() const override { return false; } ++ bool shouldUnredirect() const override { return false; } + bool acceptsFocus() const override { return false; } + void closeWindow() override {} + bool takeFocus() override { return false; } +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/internal_client.cpp kwin/internal_client.cpp +--- kwin-5.20.5/internal_client.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/internal_client.cpp 2020-11-20 19:36:34.110095021 -0500 +@@ -560,4 +560,9 @@ + commitGeometry(clientRectToFrameRect(m_internalWindow->geometry())); + } + ++bool InternalClient::shouldUnredirect() const ++{ ++ return false; ++} ++ + } +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/internal_client.h kwin/internal_client.h +--- kwin-5.20.5/internal_client.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/internal_client.h 2020-11-20 19:36:34.110095021 -0500 +@@ -33,6 +33,7 @@ + QPoint clientContentPos() const override; + QSize minSize() const override; + QSize maxSize() const override; ++ bool shouldUnredirect() const override; + QRect transparentRect() const override; + NET::WindowType windowType(bool direct = false, int supported_types = 0) const override; + double opacity() const override; +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/kcmkwin/kwincompositing/compositing.ui kwin/kcmkwin/kwincompositing/compositing.ui +--- kwin-5.20.5/kcmkwin/kwincompositing/compositing.ui 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/kcmkwin/kwincompositing/compositing.ui 2020-11-15 03:17:53.618296195 -0500 +@@ -6,8 +6,8 @@ + + 0 + 0 +- 526 +- 395 ++ 628 ++ 581 + + + +@@ -292,6 +292,159 @@ + + + ++ ++ ++ ++ Applications do not have to set any hint to suspend compositing when the window is full-screen. ++ This delivers lower latency and has no delay when compared to the other option. ++ Some people have reported crashes under Intel, but I am not sure if this is the case. ++ ++ ++ Suspend compositor for full-screen windows ++ ++ ++ ++ ++ ++ ++ Animation curve: ++ ++ ++ ++ ++ ++ ++ ++ Linear ++ ++ ++ ++ ++ Quadratic ++ ++ ++ ++ ++ Sine ++ ++ ++ ++ ++ Cubic ++ ++ ++ ++ ++ Quartic ++ ++ ++ ++ ++ ++ ++ ++ Latency/stutter control: ++ ++ ++ ++ ++ ++ ++ ++ Less stutter ++ ++ ++ ++ ++ Balanced ++ ++ ++ ++ ++ Lower latency ++ ++ ++ ++ ++ Even lower latency ++ ++ ++ ++ ++ ++ ++ ++ Maximum latency reduction: ++ ++ ++ ++ ++ ++ ++ 8 ++ ++ ++ ++ ++ ++ ++ Minimum latency reduction: ++ ++ ++ ++ ++ ++ ++ 8 ++ ++ ++ ++ ++ ++ ++ (units in milliseconds) ++ ++ ++ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter ++ ++ ++ ++ ++ ++ ++ ++ Automatic ++ ++ ++ ++ ++ None and just hope for the best (NVIDIA 435.17+) ++ ++ ++ ++ ++ SGI video sync (NVIDIA pre-435, recent Mesa/X versions may hang) ++ ++ ++ ++ ++ glFinish (Mesa hang workaround for AMD, maybe works on NVIDIA too) ++ ++ ++ ++ ++ SGI video sync with horrible hack (Mesa hang workaround for Intel) ++ ++ ++ ++ ++ ++ ++ ++ VSync mechanism: ++ ++ ++ + + + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/kcmkwin/kwincompositing/kwincompositing_setting.kcfg kwin/kcmkwin/kwincompositing/kwincompositing_setting.kcfg +--- kwin-5.20.5/kcmkwin/kwincompositing/kwincompositing_setting.kcfg 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/kcmkwin/kwincompositing/kwincompositing_setting.kcfg 2020-11-15 03:17:53.618296195 -0500 +@@ -69,6 +69,43 @@ + true + + ++ ++ true ++ ++ ++ ++ 2 ++ ++ ++ ++ Balance ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Automatic ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 8 ++ ++ ++ ++ 8 ++ ++ + + + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/kcmkwin/kwincompositing/main.cpp kwin/kcmkwin/kwincompositing/main.cpp +--- kwin-5.20.5/kcmkwin/kwincompositing/main.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/kcmkwin/kwincompositing/main.cpp 2020-11-20 19:36:34.110095021 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -100,6 +101,7 @@ + void KWinCompositingKCM::init() + { + auto currentIndexChangedSignal = static_cast(&QComboBox::currentIndexChanged); ++ auto valueChangedSignal = static_cast(&QSpinBox::valueChanged); + + // animation speed + m_form.animationDurationFactor->setMaximum(s_animationMultipliers.size() - 1); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/kwin.kcfg kwin/kwin.kcfg +--- kwin-5.20.5/kwin.kcfg 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/kwin.kcfg 2020-11-20 19:36:34.173428355 -0500 +@@ -248,12 +248,40 @@ + 4 + 6 + ++ ++ false ++ + + glx + + + true + ++ ++ 2 ++ 0 ++ 4 ++ ++ ++ 1 ++ 0 ++ 3 ++ ++ ++ 8 ++ 0 ++ 8 ++ ++ ++ 0 ++ 0 ++ 8 ++ ++ ++ 0 ++ 0 ++ 4 ++ + + + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/kwin.kdev4 kwin/kwin.kdev4 +--- kwin-5.20.5/kwin.kdev4 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/kwin.kdev4 2019-01-29 16:00:48.440970608 -0500 +@@ -0,0 +1,4 @@ ++[Project] ++CreatedFrom=CMakeLists.txt ++Manager=KDevCMakeManager ++Name=kwin +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/layers.cpp kwin/layers.cpp +--- kwin-5.20.5/layers.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/layers.cpp 2020-11-20 19:36:34.193428355 -0500 +@@ -715,6 +715,9 @@ + if (m_xStackingDirty) { + const_cast(this)->updateXStackingOrder(); + } ++ if (m_compositor) { ++ const_cast(this)->m_compositor->checkUnredirect(); ++ } + return x_stacking; + } + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/layershellv1client.h kwin/layershellv1client.h +--- kwin-5.20.5/layershellv1client.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/layershellv1client.h 2020-11-20 19:36:34.193428355 -0500 +@@ -48,6 +48,7 @@ + protected: + Layer belongsToLayer() const override; + bool acceptsFocus() const override; ++ bool shouldUnredirect() const override { return false; } + void requestGeometry(const QRect &rect) override; + void addDamage(const QRegion ®ion) override; + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/main_x11.cpp kwin/main_x11.cpp +--- kwin-5.20.5/main_x11.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/main_x11.cpp 2020-11-20 19:36:34.200095021 -0500 +@@ -344,6 +344,7 @@ + { + KWin::Application::setupMalloc(); + KWin::Application::setupLocalizedString(); ++ KCrash::setDrKonqiEnabled(false); + + int primaryScreen = 0; + xcb_connection_t *c = xcb_connect(nullptr, &primaryScreen); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/options.cpp kwin/options.cpp +--- kwin-5.20.5/options.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/options.cpp 2020-11-20 19:36:34.200095021 -0500 +@@ -59,12 +59,17 @@ + } + } + } ++ // wait who in the heck said "50Hz BS"?! ++ // hey come on I still play Turrican or some other Amiga/C64 stuff! ++ // yeah I have not in a while but COME ON THERE IS **NO** REASON to ++ // attack the PAL territory! + rate = qRound(Screens::self()->refreshRate(syncScreen)); // TODO forward float precision? + } + + // 0Hz or less is invalid, so we fallback to a default rate ++ // I play Turrican. ok? so I need my 50Hz back! + if (rate <= 0) +- rate = 60; // and not shitty 50Hz for sure! *grrr* ++ rate = 300; // and not shitty insults to my 50Hz for sure! *grrr* + + // QTimer gives us 1msec (1000Hz) at best, so we ignore anything higher; + // however, additional throttling prevents very high rates from taking place anyway +@@ -100,6 +105,7 @@ + , m_compositingMode(Options::defaultCompositingMode()) + , m_useCompositing(Options::defaultUseCompositing()) + , m_hiddenPreviews(Options::defaultHiddenPreviews()) ++ , m_unredirectFullscreen(Options::defaultUnredirectFullscreen()) + , m_glSmoothScale(Options::defaultGlSmoothScale()) + , m_xrenderSmoothScale(Options::defaultXrenderSmoothScale()) + , m_maxFpsInterval(Options::defaultMaxFpsInterval()) +@@ -111,6 +117,11 @@ + , m_glPreferBufferSwap(Options::defaultGlPreferBufferSwap()) + , m_glPlatformInterface(Options::defaultGlPlatformInterface()) + , m_windowsBlockCompositing(true) ++ , m_animationCurve(Options::defaultAnimationCurve()) ++ , m_latencyControl(Options::defaultLatencyControl()) ++ , m_maxLatency(Options::defaultMaxLatency()) ++ , m_minLatency(Options::defaultMinLatency()) ++ , m_vsyncMechanism(Options::defaultVsyncMechanism()) + , OpTitlebarDblClick(Options::defaultOperationTitlebarDblClick()) + , CmdActiveTitlebar1(Options::defaultCommandActiveTitlebar1()) + , CmdActiveTitlebar2(Options::defaultCommandActiveTitlebar2()) +@@ -598,6 +609,20 @@ + emit hiddenPreviewsChanged(); + } + ++void Options::setUnredirectFullscreen(bool unredirectFullscreen) ++{ ++ //if (GLPlatform::instance()->driver() == Driver_Intel) ++ //unredirectFullscreen = false; // bug #252817 ++ if (m_unredirectFullscreen == unredirectFullscreen) { ++ return; ++ } ++ //if (GLPlatform::instance()->driver() == Driver_Intel) { // write back the value ++ //KConfigGroup(m_settings->config(), "Compositing").writeEntry("UnredirectFullscreen", false); ++ //} ++ m_unredirectFullscreen = unredirectFullscreen; ++ emit unredirectFullscreenChanged(); ++} ++ + void Options::setGlSmoothScale(int glSmoothScale) + { + if (m_glSmoothScale == glSmoothScale) { +@@ -679,6 +704,46 @@ + emit windowsBlockCompositingChanged(); + } + ++void Options::setAnimationCurve(int val) { ++ if (m_animationCurve == val) { ++ return; ++ } ++ m_animationCurve = val; ++ emit animationCurveChanged(); ++} ++ ++void Options::setLatencyControl(int val) { ++ if (m_latencyControl == val) { ++ return; ++ } ++ m_latencyControl = val; ++ emit latencyControlChanged(); ++} ++ ++void Options::setMaxLatency(int val) { ++ if (m_maxLatency == val) { ++ return; ++ } ++ m_maxLatency = val; ++ emit maxLatencyChanged(); ++} ++ ++void Options::setMinLatency(int val) { ++ if (m_minLatency == val) { ++ return; ++ } ++ m_minLatency = val; ++ emit minLatencyChanged(); ++} ++ ++void Options::setVsyncMechanism(int val) { ++ if (m_vsyncMechanism == val) { ++ return; ++ } ++ m_vsyncMechanism = val; ++ emit vsyncMechanismChanged(); ++} ++ + void Options::setGlPreferBufferSwap(char glPreferBufferSwap) + { + if (glPreferBufferSwap == 'a') { +@@ -850,6 +915,11 @@ + setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio()); + setWindowsBlockCompositing(m_settings->windowsBlockCompositing()); + ++ setAnimationCurve(m_settings->animationCurve()); ++ setLatencyControl(m_settings->latencyControl()); ++ setMaxLatency(m_settings->maxLatency()); ++ setMinLatency(m_settings->minLatency()); ++ setVsyncMechanism(m_settings->vSyncMechanism()); + } + + bool Options::loadCompositingConfig (bool force) +@@ -949,6 +1019,8 @@ + else if (hps == 6) + previews = HiddenPreviewsAlways; + setHiddenPreviews(previews); ++ ++ setUnredirectFullscreen(config.readEntry("UnredirectFullscreen",Options::defaultUnredirectFullscreen())); + + auto interfaceToKey = [](OpenGLPlatformInterface interface) { + switch (interface) { +@@ -1100,4 +1172,9 @@ + return m_useCompositing || kwinApp()->platform()->requiresCompositing(); + } + ++bool Options::isUnredirectFullscreen() const ++{ ++ return m_unredirectFullscreen && !kwinApp()->platform()->requiresCompositing(); ++} ++ + } // namespace +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/options.h kwin/options.h +--- kwin-5.20.5/options.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/options.h 2020-11-20 19:36:34.200095021 -0500 +@@ -163,6 +163,7 @@ + Q_PROPERTY(int compositingMode READ compositingMode WRITE setCompositingMode NOTIFY compositingModeChanged) + Q_PROPERTY(bool useCompositing READ isUseCompositing WRITE setUseCompositing NOTIFY useCompositingChanged) + Q_PROPERTY(int hiddenPreviews READ hiddenPreviews WRITE setHiddenPreviews NOTIFY hiddenPreviewsChanged) ++ Q_PROPERTY(bool unredirectFullscreen READ isUnredirectFullscreen WRITE setUnredirectFullscreen NOTIFY unredirectFullscreenChanged) + /** + * 0 = no, 1 = yes when transformed, + * 2 = try trilinear when transformed; else 1, +@@ -545,6 +546,7 @@ + HiddenPreviews hiddenPreviews() const { + return m_hiddenPreviews; + } ++ bool isUnredirectFullscreen() const; + // OpenGL + // 0 = no, 1 = yes when transformed, + // 2 = try trilinear when transformed; else 1, +@@ -589,6 +591,23 @@ + { + return m_windowsBlockCompositing; + } ++ ++ int animationCurve() const { ++ return m_animationCurve; ++ } ++ int latencyControl() const { ++ return m_latencyControl; ++ } ++ int maxLatency() const { ++ return m_maxLatency; ++ } ++ int minLatency() const { ++ return m_minLatency; ++ } ++ int vsyncMechanism() const { ++ return m_vsyncMechanism; ++ } ++ + + QStringList modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const; + +@@ -640,6 +659,7 @@ + void setCompositingMode(int compositingMode); + void setUseCompositing(bool useCompositing); + void setHiddenPreviews(int hiddenPreviews); ++ void setUnredirectFullscreen(bool unredirectFullscreen); + void setGlSmoothScale(int glSmoothScale); + void setXrenderSmoothScale(bool xrenderSmoothScale); + void setMaxFpsInterval(qint64 maxFpsInterval); +@@ -651,6 +671,11 @@ + void setGlPreferBufferSwap(char glPreferBufferSwap); + void setGlPlatformInterface(OpenGLPlatformInterface interface); + void setWindowsBlockCompositing(bool set); ++ void setAnimationCurve(int curve); ++ void setLatencyControl(int index); ++ void setMaxLatency(int val); ++ void setMinLatency(int val); ++ void setVsyncMechanism(int val); + + // default values + static WindowOperation defaultOperationTitlebarDblClick() { +@@ -722,6 +747,9 @@ + static HiddenPreviews defaultHiddenPreviews() { + return HiddenPreviewsShown; + } ++ static bool defaultUnredirectFullscreen() { ++ return true; ++ } + static int defaultGlSmoothScale() { + return 2; + } +@@ -761,6 +789,21 @@ + static int defaultXwaylandMaxCrashCount() { + return 3; + } ++ static int defaultAnimationCurve() { ++ return 2; ++ } ++ static int defaultLatencyControl() { ++ return 1; ++ } ++ static int defaultMaxLatency() { ++ return 8; ++ } ++ static int defaultMinLatency() { ++ return 0; ++ } ++ static int defaultVsyncMechanism() { ++ return 0; ++ } + /** + * Performs loading all settings except compositing related. + */ +@@ -824,6 +867,7 @@ + void compositingModeChanged(); + void useCompositingChanged(); + void hiddenPreviewsChanged(); ++ void unredirectFullscreenChanged(); + void glSmoothScaleChanged(); + void xrenderSmoothScaleChanged(); + void maxFpsIntervalChanged(); +@@ -836,6 +880,11 @@ + void glPlatformInterfaceChanged(); + void windowsBlockCompositingChanged(); + void animationSpeedChanged(); ++ void animationCurveChanged(); ++ void latencyControlChanged(); ++ void maxLatencyChanged(); ++ void minLatencyChanged(); ++ void vsyncMechanismChanged(); + + void configChanged(); + +@@ -869,6 +918,7 @@ + CompositingType m_compositingMode; + bool m_useCompositing; + HiddenPreviews m_hiddenPreviews; ++ bool m_unredirectFullscreen; + int m_glSmoothScale; + bool m_xrenderSmoothScale; + qint64 m_maxFpsInterval; +@@ -881,6 +931,11 @@ + GlSwapStrategy m_glPreferBufferSwap; + OpenGLPlatformInterface m_glPlatformInterface; + bool m_windowsBlockCompositing; ++ int m_animationCurve; ++ int m_latencyControl; ++ int m_maxLatency; ++ int m_minLatency; ++ int m_vsyncMechanism; + + WindowOperation OpTitlebarDblClick; + WindowOperation opMaxButtonRightClick = defaultOperationMaxButtonRightClick(); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/patch.sh kwin/patch.sh +--- kwin-5.20.5/patch.sh 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/patch.sh 2020-11-20 19:36:34.200095021 -0500 +@@ -0,0 +1,25 @@ ++#!/bin/bash ++ ++klpath=${PWD##*/} ++minorVer=1 ++tinyPatch=0 ++version=$(sed -rn "s/^set\(PROJECT_VERSION \"([0-9.]+)\"\)$/\1/p" CMakeLists.txt) ++ ++if [ $tinyPatch -gt 0 ]; then ++ downversion=$version"."$tinyPatch ++else ++ downversion=$version ++fi ++ ++cd .. ++if [ ! -e kwin-$downversion.tar.xz ] ++ then wget https://download.kde.org/stable/plasma/$version/kwin-$downversion.tar.xz || exit 1 ++fi ++ ++tar -xf kwin-$downversion.tar.xz ++ ++if [ $minorVer -eq 1 ] ++ then filename="kwin-lowlatency-$version.patch" ++ else filename="kwin-lowlatency-$version-$minorVer.patch" ++fi ++diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-$downversion $klpath > $filename +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/plugins/platforms/x11/standalone/glxbackend.cpp kwin/plugins/platforms/x11/standalone/glxbackend.cpp +--- kwin-5.20.5/plugins/platforms/x11/standalone/glxbackend.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/plugins/platforms/x11/standalone/glxbackend.cpp 2020-11-20 19:36:34.253428355 -0500 +@@ -197,6 +197,61 @@ + // Initialize OpenGL + GLPlatform *glPlatform = GLPlatform::instance(); + glPlatform->detect(GlxPlatformInterface); ++ ++ //if (GLPlatform::instance()->driver() == Driver_Intel) ++ //options->setUnredirectFullscreen(false); // bug #252817 ++ // HACK! please replace with a better solution soon ++ if (GLPlatform::instance()->driver() == Driver_Intel) { ++ useHorribleHack=true; // issue #13 ++ } ++ // NVIDIA doesn't freeze on that wait sync function ++ if (GLPlatform::instance()->driver() == Driver_NVidia) { ++ int nvidiaVerMaj=0; ++ int nvidiaVerMin=0; ++ // version 435 blocks without having to wait for sync, issues #36, #39 ++ // if the latency increases (it hasn't been the case so far), please open ++ // another bug report. thanks. ++ sscanf(GLPlatform::instance()->glVersionString().data(),"%*s NVIDIA %d.%d",&nvidiaVerMaj,&nvidiaVerMin); ++ if (nvidiaVerMaj>=435) { ++ // we don't need to wait for sync anymore. whoop! ++ useWaitSync=false; ++ hopeBest=true; ++ } else { ++ // for old or unknown NVIDIA driver ++ useWaitSync=true; // issue #17 ++ } ++ } ++ // AMDGPU-PRO/Catalyst. SGI VBlank thingy. ++ if (GLPlatform::instance()->driver() == Driver_Catalyst) { ++ useWaitSync=true; ++ hopeBest=false; ++ } ++ // force VSync mechanism code ++ switch (options->vsyncMechanism()) { ++ case 1: ++ useWaitSync=false; ++ hopeBest=true; ++ useHorribleHack=false; ++ break; ++ case 2: ++ useWaitSync=true; ++ hopeBest=false; ++ useHorribleHack=false; ++ break; ++ case 3: ++ useWaitSync=false; ++ hopeBest=false; ++ useHorribleHack=false; ++ break; ++ case 4: ++ useWaitSync=true; ++ hopeBest=false; ++ useHorribleHack=true; ++ break; ++ default: ++ break; ++ } ++ + options->setGlPreferBufferSwap(options->glPreferBufferSwap()); // resolve autosetting + if (options->glPreferBufferSwap() == Options::AutoSwapStrategy) + options->setGlPreferBufferSwap('e'); // for unknown drivers - should not happen +@@ -236,24 +291,21 @@ + const bool wantSync = options->glPreferBufferSwap() != Options::NoSwapEncourage; + if (wantSync && glXIsDirect(display(), ctx)) { + if (haveSwapInterval) { // glXSwapInterval is preferred being more reliable +- setSwapInterval(1); +- setSyncsToVBlank(true); +- const QByteArray tripleBuffer = qgetenv("KWIN_TRIPLE_BUFFER"); +- if (!tripleBuffer.isEmpty()) { +- setBlocksForRetrace(qstrcmp(tripleBuffer, "0") == 0); +- gs_tripleBufferUndetected = false; +- } +- gs_tripleBufferNeedsDetection = gs_tripleBufferUndetected; +- } else if (hasExtension(QByteArrayLiteral("GLX_SGI_video_sync"))) { ++ setSwapInterval(1); // but adds latency. see below ++ } else { ++ qCWarning(KWIN_X11STANDALONE) << "TEARING ALERT! unable to set swap interval"; ++ } ++ if (hasExtension(QByteArrayLiteral("GLX_SGI_video_sync"))) { ++ // we still need this extension for lowering latency. + unsigned int sync; + if (glXGetVideoSyncSGI(&sync) == 0 && glXWaitVideoSyncSGI(1, 0, &sync) == 0) { + setSyncsToVBlank(true); + setBlocksForRetrace(true); + haveWaitSync = true; + } else +- qCWarning(KWIN_X11STANDALONE) << "NO VSYNC! glXSwapInterval is not supported, glXWaitVideoSync is supported but broken"; ++ qCWarning(KWIN_X11STANDALONE) << "HIGH LATENCY ALERT! glXWaitVideoSync is supported but broken"; + } else +- qCWarning(KWIN_X11STANDALONE) << "NO VSYNC! neither glSwapInterval nor glXWaitVideoSync are supported"; ++ qCWarning(KWIN_X11STANDALONE) << "HIGH LATENCY ALERT! glXWaitVideoSync is not supported"; + } else { + // disable v-sync (if possible) + setSwapInterval(0); +@@ -738,7 +790,6 @@ + } + } + } else { +- waitSync(); + glXSwapBuffers(display(), glxWindow); + } + if (supportsBufferAge()) { +@@ -755,7 +806,27 @@ + copyPixels(lastDamage()); + glDrawBuffer(GL_BACK); + } +- ++ ++ if (useHorribleHack) { ++ // HACK HACK HACK! please replace with a better solution soon ++ unsigned int oldSync, sync; ++ glXGetVideoSyncSGI(&sync); ++ oldSync=sync; ++ while (1) { ++ glXGetVideoSyncSGI(&sync); ++ if (sync!=oldSync) break; ++ usleep(1000); ++ } ++ } else { ++ if (useWaitSync) { ++ waitSync(); ++ } else { ++ if (!hopeBest) { ++ glFinish(); ++ } ++ } ++ } ++ + setLastDamage(QRegion()); + if (!supportsBufferAge()) { + glXWaitGL(); +@@ -828,15 +899,9 @@ + + setLastDamage(renderedRegion); + +- if (!blocksForRetrace()) { +- // This also sets lastDamage to empty which prevents the frame from +- // being posted again when prepareRenderingFrame() is called. +- present(); +- } else { +- // Make sure that the GPU begins processing the command stream +- // now and not the next time prepareRenderingFrame() is called. +- glFlush(); +- } ++ // just present. this is the culprit. ++ // come on Roman Gilg at least acknowledge me for the discovery ++ present(); + + if (overlayWindow()->window()) // show the window only after the first pass, + overlayWindow()->show(); // since that pass may take long +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/plugins/platforms/x11/standalone/glxbackend.h kwin/plugins/platforms/x11/standalone/glxbackend.h +--- kwin-5.20.5/plugins/platforms/x11/standalone/glxbackend.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/plugins/platforms/x11/standalone/glxbackend.h 2020-11-20 19:36:34.253428355 -0500 +@@ -107,6 +107,9 @@ + bool m_haveINTELSwapEvent = false; + bool haveSwapInterval = false; + bool haveWaitSync = false; ++ bool useHorribleHack = false; ++ bool useWaitSync = false; ++ bool hopeBest = false; + Display *m_x11Display; + SwapProfiler m_swapProfiler; + friend class GlxTexture; +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/plugins/scenes/opengl/scene_opengl.cpp kwin/plugins/scenes/opengl/scene_opengl.cpp +--- kwin-5.20.5/plugins/scenes/opengl/scene_opengl.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/plugins/scenes/opengl/scene_opengl.cpp 2021-01-05 11:59:47.283171773 -0500 +@@ -2125,9 +2125,15 @@ + return s_instance; + } + ++// the crash is here but I am not sure what causes it. + DecorationShadowTextureCache::~DecorationShadowTextureCache() + { +- Q_ASSERT(m_cache.isEmpty()); ++ // why should we assert anything? why not just empty the cache here? ++ //Q_ASSERT(m_cache.isEmpty()); ++ if (!m_cache.isEmpty()) { ++ qWarning() << "the DecorationShadowTextureCache is not empty. clearing it out. hope this doesn't crash :<"; ++ m_cache.clear(); ++ } + } + + void DecorationShadowTextureCache::unregister(SceneOpenGLShadow *shadow) +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/po.sh kwin/po.sh +--- kwin-5.20.5/po.sh 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/po.sh 2020-10-13 11:58:36.525885497 -0500 +@@ -0,0 +1,16 @@ ++#!/bin/bash ++# make po ++ ++klpath=${PWD##*/} ++version=$(sed -rn "s/^set\(PROJECT_VERSION \"([0-9.]+)\"\)$/\1/p" CMakeLists.txt) ++ ++rm -r po ++ ++cd .. ++if [ ! -e kwin-$version.tar.xz ] ++ then wget https://download.kde.org/stable/plasma/$version/kwin-$version.tar.xz || exit 1 ++fi ++ ++tar -xf kwin-$version.tar.xz ++ ++cp -r kwin-$version/po $klpath/po +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/README.md kwin/README.md +--- kwin-5.20.5/README.md 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/README.md 2021-01-05 12:04:27.993163431 -0500 +@@ -1,48 +1,263 @@ +-# KWin ++# KWin-lowlatency + +-KWin is an easy to use, but flexible, composited Window Manager for Xorg windowing systems (Wayland, X11) on Linux. Its primary usage is in conjunction with a Desktop Shell (e.g. KDE Plasma Desktop). KWin is designed to go out of the way; users should not notice that they use a window manager at all. Nevertheless KWin provides a steep learning curve for advanced features, which are available, if they do not conflict with the primary mission. KWin does not have a dedicated targeted user group, but follows the targeted user group of the Desktop Shell using KWin as it's window manager. ++KWin-lowlatency is my attempt to reduce latency and stuttering in the popular KWin compositor used in KDE. + +-## KWin is not... ++## old background + +- * a standalone window manager (c.f. openbox, i3) and does not provide any functionality belonging to a Desktop Shell. +- * a replacement for window managers designed for use with a specific Desktop Shell (e.g. GNOME Shell) +- * a minimalistic window manager +- * designed for use without compositing or for X11 network transparency, though both are possible. ++stock KWin has a major issue regarding stuttering. it stutters heavily, and if you don't want that, then you have the latency problem (of up to 50ms!). + +-# Contacting KWin development team ++the rationale for such a problem is that KWin uses a weird method to paint the screen. ++instead of simply sync'ing to vblank, it uses a timer. yeah, a **timer** that is off-sync with the vblank interval. ++you can prove this by disabling VSync in the system settings. you'll see just 1 line of tearing in your screen, and well, that's the time it swaps due to the timer. ++ ++in order to "fix" this under vanilla KWin, a typical solution is to insert this in kwinrc: ++ ++``` ++MaxFPS=200 ++RefreshRate=200 ++``` ++ ++effectively making the timer faster than the actual screen's rate, forcing VSync at some point. ++ ++however, this introduces additional output lag, which varies depending on your driver, but usually it's 50ms (still too high). ++you can prove this by moving a window. you'll see the cursor being ahead of the title bar, or at least so under X. ++ ++so, how to fix this? let's ditch the timer and let us access the VBlank interval directly. ++ ++but how do we do that? there are several approaches, but they vary between drivers. ++ ++1. by using glFinish. ++ - this is a much, **much** better solution over glXWaitVideoSyncSGI for Mesa, as it achieves the same effect and doesn't have a chance of freezing. ++2. by using glXWaitVideoSyncSGI. ++ - this solution works on Catalyst/AMDGPU-PRO. it was used before for Mesa too, but not anymore after Mesa exhibited freezes. ++3. by doing nothing at all. ++ - NVIDIA doesn't require anything in particular for this to work. the buffer swap function seems to wait for VBlank. ++4. by polling the current VBlank interval and waiting until the next one. ++ - sadly, Mesa (Intel) does not obey glFinish correctly. this is a hack, but it works. ++ ++now, by doing this, we have a proper desktop without stuttering, but the lag persists... ++ ++after digging deep into the code, i found this piece of code in particular, which is pretty much the culprit: ++ ++``` ++if (!blocksForRetrace()) { ++ // This also sets lastDamage to empty which prevents the frame from ++ // being posted again when prepareRenderingFrame() is called. ++ present(); ++} else { ++ // Make sure that the GPU begins processing the command stream ++ // now and not the next time prepareRenderingFrame() is called. ++ glFlush(); ++} ++``` ++ ++by removing this code and simply presenting as soon as possible (we're blocking for retrace anyway due to the wait-for-vblank thingy), we cut off 1 whole frame of lag! ++ ++but hey, can we go further? yes, of course! ++ ++now, by sleeping for a very few milliseconds (up to 8 in high-end systems) the compositor has more time for user input before rendering, which further reduces latency. ++ ++the reason why only up to 8ms is because any further would leave little room for rendering, and that will actually produce more stuttering than fix it. ++ ++## KWin-lowlatency is not... ++ ++- perfect. it tries its best to deliver low-latency no-stutter video, but I can't promise this is always the case. ++ - as an example, it will stutter if you select another window, or if you have too many windows open. ++- truly designed for low-end systems. if you use KWin-lowlatency in one of them, you may experience stuttering. ++ ++# installation ++ ++## Arch Linux ++ ++[kwin-lowlatency is available in the AUR](https://aur.archlinux.org/packages/kwin-lowlatency). ++ ++## Fedora ++ ++ZaWertun provides pre-compiled packages [in the Copr](https://copr.fedorainfracloud.org/coprs/zawertun/kde/package/kwin-lowlatency/). ++ ++## Gentoo ++ ++[an overlay](https://github.com/agates/kwin-lowlatency-overlay) is available, courtesy of agates. ++ ++## Manjaro ++ ++use the Arch Linux instructions. Manjaro has updated to Plasma 5.20. ++ ++## NixOS ++ ++check out pasqui23's [kwin-ll](https://github.com/pasqui23/nixpkgs/tree/kwin-ll) branch. ++ ++please note that this is an old version. ++ ++## openSUSE Leap and Tumbleweed ++ ++kwin-lowlatency can be found at [home:DarkWav:kwin-lowlatency](https://software.opensuse.org/download.html?project=home%3ADarkWav%3Akwin-lowlatency&package=kwin-lowlatency) (OBS). ++ ++## Ubuntu ++ ++[kwin-lowlatency PPA](https://launchpad.net/~maxiberta/+archive/ubuntu/kwin-lowlatency). thanks maxiberta! ++ ++## other distributions/manual method ++ ++you can compile/install this yourself if your distro isn't listed here, or if you merely want to. ++ ++### installing dependencies ++ ++you may need to install specific dependencies before compiling. [here](https://community.kde.org/Guidelines_and_HOWTOs/Build_from_source/Install_the_dependencies) you can find a list. ++ ++### acquiring the source ++ ++you can get the source code by using any of the following 2 methods: ++ ++#### git repo clone ++ ++``` ++$ git clone https://github.com/tildearrow/kwin-lowlatency.git ++$ cd kwin-lowlatency ++``` ++ ++if you are not using the latest major version of Plasma (you can check by doing `kwin_x11 --version`), you may want to check out the branch for your version, e.g.: ++ ++``` ++$ git checkout Plasma/5.20 ++``` ++ ++you may want to check the current stable version out: ++ ++``` ++$ git checkout v5.20.5 ++``` ++ ++#### patch format ++ ++download stock KWin source and patch file: ++ ++``` ++$ wget https://download.kde.org/stable/plasma/5.20.5/kwin-5.20.5.tar.xz ++$ wget https://tildearrow.org/storage/kwin-lowlatency/kwin-lowlatency-5.20.5.patch ++``` ++ ++extract: ++ ++``` ++$ tar -xvf kwin-5.20.5.tar.xz ++``` ++ ++patch: ++ ++``` ++$ cd kwin-5.20.5 ++$ patch -p1 < ../kwin-lowlatency-5.20.5.patch ++``` ++ ++### building ++ ++#### Ubuntu ++ ++Ubuntu uses a different library path, which means you'll have to tweak the library dir: ++ ++``` ++$ mkdir build ++$ cd build ++$ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu -DCMAKE_INSTALL_LIBEXECDIR=lib/x86_64-linux-gnu -DBUILD_TESTING=OFF .. ++$ make ++``` ++ ++#### other distros ++ ++``` ++$ mkdir build ++$ cd build ++$ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_LIBEXECDIR=lib -DBUILD_TESTING=OFF .. ++$ make ++``` ++ ++### installing ++ ++``` ++$ sudo make install ++``` ++ ++# contacting original KWin development team + + * mailing list: [kwin@kde.org](https://mail.kde.org/mailman/listinfo/kwin) + * IRC: #kwin on freenode + +-# Support +-## Application Developer +-If you are an application developer having questions regarding windowing systems (either X11 or Wayland) please do not hesitate to contact us. Preferable through our mailing list. Ideally subscribe to the mailing list, so that your mail doesn't get stuck in the moderation queue. ++# additional options menu + +-## End user +-Please contact the support channels of your Linux distribution for user support. The KWin development team does not provide end user support. ++KWin-lowlatency introduces few extra options in System Settings > Display and Monitor > Compositor. these are: + +-# Reporting bugs ++- animation curve: allows you to make animations look smoother. I have a gripe with linear animations, hence this option. the following options are available: ++ - Linear: default and only option in stock KWin. ugly. ++ - Quadratic: smooth curve. may cause a nuisance if your animation speed is high. ++ - Sine: smooth curve. default in KWin-lowlatency. ++ - Cubic: smooth curve. may cause an annoyance if your animation speed is high. ++ - Quartic: smoothest curve. you definitely need to lower the animation speed for this one, though. ++- latency/stutter control: use if you have a high-end system and want lower latency, or if you're having stuttering and want to reduce it. ++- minimum/maximum latency reduction: allows you to configure the latency reduction window. examples (min/max): 0/8 default, 0/0 disable latency reduction, and 8/8 lowest latency possible. this is limited to 8ms, since any further would cause major stuttering and slowdowns. ++- VSync mechanism: **use this if you have latency problems or frame rate halving.** allows you to set the mechanism used to detect VSync. the following options are available: ++ - Automatic: auto-detect the VSync mechanism. **default, and recommended.** ++ - None and just hope for the best: ++ - NVIDIA drivers since version 435 wait for VSync on glXSwapBuffers if `__GL_MaxFramesAllowed` is set to 1. ++ - **other drivers may cause latency problems.** ++ - SGI video sync: use `GLX_SGI_video_sync` to wait for VBlank. ++ - default for AMDGPU-PRO. ++ - not recommended on recent Mesa drivers. I've had hangs using it. ++ - not recommended on NVIDIA drivers 435+. causes frame rate halving. see above. ++ - glFinish: use `glFinish` to force waiting for VBlank. ++ - according to this [bug report](https://github.com/tildearrow/kwin-lowlatency/issues/17) this may actually increase latency on NVIDIA cards. ++ - this is more of a workaround to the Mesa hang problem. ++ - SGI video sync with horrible hack: use `GLX_SGI_video_sync` to partially busy-wait for VBlank. ++ - for some reason glFinish doesn't work on Intel cards, and is just skipped without any VBlank waiting. ++ - hence I had to write this dirty hack for such systems because SGI video sync hangs there too. ++ - uses around ~10-20% CPU in my laptop when playing games or some other render activity because it has to poll the current frame number 10-20 times a second. ++ - if none of these options solve any problems, please open a bug report. thanks. + +-Please use [KDE's bugtracker](https://bugs.kde.org) and report for [product KWin](https://bugs.kde.org/enter_bug.cgi?product=kwin). ++# misc/FAQ + +-# Developing on KWin +-Please refer to [hacking documentation](HACKING.md) for how to build and start KWin. Further information about KWin's test suite can be found in [TESTING.md](TESTING.md). ++> I can't build it and it fails on the class ScreenLocker::KSldApp has no member named 'setWaylandFd' ++ ++update Plasma to 5.19 before building. ++this might include going back to vanilla KWin for the purpose of building the package. ++ ++> what's this "Paint cursor" effect in Desktop Effects? ++ ++it's an effect I wrote back in 2018 when experimenting with kmsgrab for some private recordings. ++it basically redraws the cursor. this may seem redundant, but actually is helpful for recording with kmsgrab (since it doesn't draw the hardware sprite). ++ ++the following applications may benefit from the usage of this effect: + +-## Guidelines for new features ++- FFmpeg (kmsgrab input device) ++- darmstadt ++- w23's drmtoy/linux-libdrm-grab OBS plugin + +-A new Feature can only be added to KWin if: ++> will this work under Wayland? + +- * it does not violate the primary missions as stated at the start of this document +- * it does not introduce instabilities +- * it is maintained, that is bugs are fixed in a timely manner (second next minor release) if it is not a corner case. +- * it works together with all existing features +- * it supports both single and multi screen (xrandr) +- * it adds a significant advantage +- * it is feature complete, that is supports at least all useful features from competitive implementations +- * it is not a special case for a small user group +- * it does not increase code complexity significantly +- * it does not affect KWin's license (GPLv2+) ++no, it won't, but I am working on it. so far using DRM VBlank only showed negative results, with applications running at half speed. now i'm trying again with glFinish and friends... + +-All new added features are under probation, that is if any of the non-functional requirements as listed above do not hold true in the next two feature releases, the added feature will be removed again. ++> do you have any plans to upstream this? ++ ++some. Daniel gets a chance to improve the GNOME side in mainline and reduce lag so I must fight to get our beloved KDE on par with GNOME! however: ++ ++- i still can't ensure this will work everywhere (but it should). ++- this patchset brings full-screen unredirection back, which is a feature the KDE devs definitely [don't want to see in upstream](https://blog.martin-graesslin.com/blog/2016/08/opengl-changes-in-kwin-compositing/) since they have another "approach" (allow apps to block compositing). ++ - the problem with their approach is that it means every app must support it in order to work, which is something not every app does. on the other hand, unredirection works for most apps, and doesn't require developers to change their code for it to work. ++ - another problem is that instead of suspending compositing, it **disables** compositing. this means you get to see a few frames of an ugly desktop when the app quits. this doesn't happen with unredirection. ++ - I can try to upstream just the glFinish/notimer/something bits, and have this project for the rest of features. ++- furthermore, this also brings back "close" option in Present Windows, which once again the KDE devs despise. ++ - apparently they officially brought the feature back in Plasma 5.17, but not for left click :( ++- Roman Gilg took my idea away. ++ ++> unredirection is not working. ++ ++please see [unredirect.md](https://github.com/tildearrow/kwin-lowlatency/blob/Plasma/5.15/unredirect.md) for known issues. you may file a bug report as well. ++ ++# Support (bugs?) ++ ++use the issues section at the top. **but wait!** before reporting an issue, first test it again on [the official KWin](https://cgit.kde.org/kwin.git/) to determine whether this is really a KWin-lowlatency-only bug. ++ ++if the bug also reproduces in official KWin, please file a bug on [their bug tracker](https://bugs.kde.org/enter_bug.cgi?product=kwin) instead. ++ ++# Developing on KWin + +-The same non functional requirements hold true for any kind of plugins (effects, scripts, etc.). It is suggested to use scripted plugins and distribute them separately. +\ No newline at end of file ++the [hacking documentation](HACKING.md) has information on how to build and start KWin. +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/rules.cpp kwin/rules.cpp +--- kwin-5.20.5/rules.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/rules.cpp 2020-11-20 19:36:35.460095031 -0500 +@@ -64,6 +64,7 @@ + , noborderrule(UnusedSetRule) + , decocolorrule(UnusedForceRule) + , blockcompositingrule(UnusedForceRule) ++ , allowunredirectrule(UnusedForceRule) + , fsplevelrule(UnusedForceRule) + , fpplevelrule(UnusedForceRule) + , acceptfocusrule(UnusedForceRule) +@@ -162,6 +163,7 @@ + decocolorrule = UnusedForceRule; + + READ_FORCE_RULE(blockcompositing,); ++ READ_FORCE_RULE(allowunredirect,); + READ_FORCE_RULE(fsplevel,); + READ_FORCE_RULE(fpplevel,); + READ_FORCE_RULE(acceptfocus,); +@@ -243,6 +245,7 @@ + }; + WRITE_FORCE_RULE(decocolor, Decocolor, colorToString); + WRITE_FORCE_RULE(blockcompositing, Blockcompositing,); ++ WRITE_FORCE_RULE(allowunredirect, Allowunredirect,); + WRITE_FORCE_RULE(fsplevel, Fsplevel,); + WRITE_FORCE_RULE(fpplevel, Fpplevel,); + WRITE_FORCE_RULE(acceptfocus, Acceptfocus,); +@@ -288,6 +291,7 @@ + && noborderrule == UnusedSetRule + && decocolorrule == UnusedForceRule + && blockcompositingrule == UnusedForceRule ++ && allowunredirectrule == UnusedForceRule + && fsplevelrule == UnusedForceRule + && fpplevelrule == UnusedForceRule + && acceptfocusrule == UnusedForceRule +@@ -604,6 +608,7 @@ + APPLY_RULE(noborder, NoBorder, bool) + APPLY_FORCE_RULE(decocolor, DecoColor, QString) + APPLY_FORCE_RULE(blockcompositing, BlockCompositing, bool) ++APPLY_FORCE_RULE(allowunredirect, AllowUnredirect, bool) + APPLY_FORCE_RULE(fsplevel, FSP, int) + APPLY_FORCE_RULE(fpplevel, FPP, int) + APPLY_FORCE_RULE(acceptfocus, AcceptFocus, bool) +@@ -679,6 +684,7 @@ + DISCARD_USED_SET_RULE(noborder); + DISCARD_USED_FORCE_RULE(decocolor); + DISCARD_USED_FORCE_RULE(blockcompositing); ++ DISCARD_USED_FORCE_RULE(allowunredirect); + DISCARD_USED_FORCE_RULE(fsplevel); + DISCARD_USED_FORCE_RULE(fpplevel); + DISCARD_USED_FORCE_RULE(acceptfocus); +@@ -816,6 +822,7 @@ + CHECK_RULE(NoBorder, bool) + CHECK_FORCE_RULE(DecoColor, QString) + CHECK_FORCE_RULE(BlockCompositing, bool) ++CHECK_FORCE_RULE(AllowUnredirect, bool) + CHECK_FORCE_RULE(FSP, int) + CHECK_FORCE_RULE(FPP, int) + CHECK_FORCE_RULE(AcceptFocus, bool) +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/rulesettings.kcfg kwin/rulesettings.kcfg +--- kwin-5.20.5/rulesettings.kcfg 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/rulesettings.kcfg 2020-11-15 03:17:54.741629495 -0500 +@@ -328,6 +328,15 @@ + Rules::UnusedForceRule + + ++ ++ ++ false ++ ++ ++ ++ Rules::UnusedForceRule ++ ++ + + + 0 +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/rules.h kwin/rules.h +--- kwin-5.20.5/rules.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/rules.h 2020-11-20 19:36:35.460095031 -0500 +@@ -67,6 +67,7 @@ + bool checkNoBorder(bool noborder, bool init = false) const; + QString checkDecoColor(QString schemeFile) const; + bool checkBlockCompositing(bool block) const; ++ bool checkAllowUnredirect(bool allow) const; + int checkFSP(int fsp) const; + int checkFPP(int fpp) const; + bool checkAcceptFocus(bool focus) const; +@@ -162,6 +163,7 @@ + bool applyNoBorder(bool& noborder, bool init) const; + bool applyDecoColor(QString &schemeFile) const; + bool applyBlockCompositing(bool& block) const; ++ bool applyAllowUnredirect(bool& allow) const; + bool applyFSP(int& fsp) const; + bool applyFPP(int& fpp) const; + bool applyAcceptFocus(bool& focus) const; +@@ -251,6 +253,8 @@ + ForceRule decocolorrule; + bool blockcompositing; + ForceRule blockcompositingrule; ++ bool allowunredirect; ++ ForceRule allowunredirectrule; + int fsplevel; + int fpplevel; + ForceRule fsplevelrule; +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/scripting/scriptedeffect.cpp kwin/scripting/scriptedeffect.cpp +--- kwin-5.20.5/scripting/scriptedeffect.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/scripting/scriptedeffect.cpp 2020-11-20 19:36:35.490095030 -0500 +@@ -11,6 +11,9 @@ + #include "meta.h" + #include "scriptingutils.h" + #include "workspace_wrapper.h" ++#ifndef KWINLL_NO_OPTIONS ++#include "../options.h" ++#endif + #include "../screens.h" + #include "../screenedge.h" + #include "scripting_logging.h" +@@ -142,7 +145,27 @@ + settings.curve = static_cast(curve.toInt32()); + settings.set |= AnimationSettings::Curve; + } else { +- settings.curve = QEasingCurve::Linear; ++#ifndef KWINLL_NO_OPTIONS ++ switch (options->animationCurve()) { ++ case 1: ++ settings.curve = QEasingCurve::InOutQuad; ++ break; ++ case 2: ++ settings.curve = QEasingCurve::InOutSine; ++ break; ++ case 3: ++ settings.curve = QEasingCurve::InOutCubic; ++ break; ++ case 4: ++ settings.curve = QEasingCurve::InOutQuart; ++ break; ++ default: ++ settings.curve = QEasingCurve::Linear; ++ break; ++ } ++#else ++ settings.curve = QEasingCurve::InOutSine; ++#endif + } + + QScriptValue type = object.property(QStringLiteral("type")); +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/toplevel.cpp kwin/toplevel.cpp +--- kwin-5.20.5/toplevel.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/toplevel.cpp 2020-11-20 19:36:35.606761698 -0500 +@@ -25,6 +25,8 @@ + + #include + ++#include ++ + namespace KWin + { + +@@ -292,6 +294,7 @@ + effect_window = new EffectWindowImpl(this); + + Compositor::self()->scene()->addToplevel(this); ++ Compositor::self()->checkUnredirect(true); + + return true; + } +@@ -300,6 +303,7 @@ + { + if (kwinApp()->operationMode() == Application::OperationModeX11 && damage_handle == XCB_NONE) + return; ++ Compositor::self()->checkUnredirect(true); + if (effect_window->window() == this) { // otherwise it's already passed to Deleted, don't free data + discardWindowPixmap(); + delete effect_window; +@@ -826,5 +830,45 @@ + return QMargins(); + } + ++bool Toplevel::updateUnredirectedState() ++{ ++ assert(compositing()); ++ bool should = options->isUnredirectFullscreen() && shouldUnredirect() && !unredirectSuspend && ++ !shape() && !hasAlpha() && opacity() == 1.0 && ++ !static_cast(effects)->activeFullScreenEffect(); ++ if (should) { ++ if (Screens::self()->count()<2) { ++ usleep(50000); ++ } ++ } ++ if (should == unredirect) ++ return false; ++ static QElapsedTimer lastUnredirect; ++ static const qint64 msecRedirectInterval = 100; ++ if (!lastUnredirect.hasExpired(msecRedirectInterval)) { ++ QTimer::singleShot(msecRedirectInterval, Compositor::self(), static_cast(&Compositor::checkUnredirect)); ++ return false; ++ } ++ lastUnredirect.start(); ++ unredirect = should; ++ if (unredirect) { ++ qCDebug(KWIN_CORE) << "Unredirecting:" << this; ++ xcb_composite_unredirect_window(connection(), frameId(), XCB_COMPOSITE_REDIRECT_MANUAL); ++ } else { ++ qCDebug(KWIN_CORE) << "Redirecting:" << this; ++ xcb_composite_redirect_window(connection(), frameId(), XCB_COMPOSITE_REDIRECT_MANUAL); ++ discardWindowPixmap(); ++ } ++ return true; ++} ++ ++void Toplevel::suspendUnredirect(bool suspend) ++{ ++ if (unredirectSuspend == suspend) ++ return; ++ unredirectSuspend = suspend; ++ Compositor::self()->checkUnredirect(); ++} ++ + } // namespace + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/toplevel.h kwin/toplevel.h +--- kwin-5.20.5/toplevel.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/toplevel.h 2020-11-20 19:36:35.613428365 -0500 +@@ -444,6 +444,9 @@ + bool hasAlpha() const; + virtual bool setupCompositing(); + virtual void finishCompositing(ReleaseReason releaseReason = ReleaseReason::Release); ++ bool updateUnredirectedState(); ++ bool unredirected() const; ++ void suspendUnredirect(bool suspend); + Q_INVOKABLE void addRepaint(const QRect& r); + Q_INVOKABLE void addRepaint(const QRegion& r); + Q_INVOKABLE void addRepaint(int x, int y, int w, int h); +@@ -711,6 +714,7 @@ + void copyToDeleted(Toplevel* c); + void disownDataPassedToDeleted(); + void deleteEffectWindow(); ++ virtual bool shouldUnredirect() const = 0; + void setDepth(int depth); + QRect m_frameGeometry; + QRect m_clientGeometry; +@@ -741,6 +745,8 @@ + QByteArray resource_class; + ClientMachine *m_clientMachine; + xcb_window_t m_wmClientLeader; ++ bool unredirect; ++ bool unredirectSuspend; // when unredirected, but pixmap is needed temporarily + bool m_damageReplyPending; + QRegion opaque_region; + xcb_xfixes_fetch_region_cookie_t m_regionCookie; +@@ -1004,6 +1010,11 @@ + return resource_class; // it is always lowercase + } + ++inline bool Toplevel::unredirected() const ++{ ++ return unredirect; ++} ++ + inline const ClientMachine *Toplevel::clientMachine() const + { + return m_clientMachine; +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/tva.md kwin/tva.md +--- kwin-5.20.5/tva.md 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/tva.md 2020-09-25 11:49:59.152898564 -0500 +@@ -0,0 +1,65 @@ ++# Tilde van Arrow ++ ++the ultimate project to optimize KWin and cut the rough edges. ++the compositor should do nothing more than render windows in the exact time. ++it is unknown why do some things take too long to render, such as moving between desktop, using present windows or even switching windows. ++those are detrimental to smoothness and cause stutter. ++ ++this document is incomplete. ++ ++# possibilities ++ ++- too much processing when switching windows ++- the need to recreate every single texture ++- Qt is too high-level ++ ++# solutions ++ ++## window switch stutter ++ ++even after using the most basic theme, switching windows causes stutter. ++maybe the toplevel is doing too much, or some effect... ++ ++## texture recreation ++ ++certain heavier themes cause more lag spikes. come on why can't we have a cache so we don't have to re-render everything? ++decoration rendering is done in software so yeah... ++ ++## Qt is too high-level ++ ++...we could replace certain unneeded Qt parts by our own ones, and perhaps improve performance... ++ ++## kwin-lowerlatencyandlowpower ++ ++what about we go single-buffer, somehow make the card always wait for VBlank (or near-VBlank) and let that be it? ++ ++what about we use an hybrid setup? ++ ++- single-buffering when the compositor is not doing anything fancy ++- double-buffering when it is ++- clients that want VSync will have a big wait before present ++- clients that don't, will be redrawn immediately (this may cause tearing), Quartz-style ++ ++## let's learn OpenGL ++ ++because this could allow for further optimizations on lower-end systems. ++ ++I just do not think KWin is optimized enough... for them... ++ ++## come on let's catch up already ++ ++if we do not do anything about this soon, the other guy working at Mutter will destroy KWin in performance. ++ ++sadly I think we already lost the race, because GNOME is beginning to run on Pi, and... KDE still does not :< ++ ++come on they will defeat us and team uid will get a chance to achieve World Domination!! like this ++ ++> Qt is there because Canonical used it to validate their own CLA. Basically “We are happy to sign Qt’s CLA so you should be happy to sign our CLA”. Fortunately that failed as well. ++ ++oh come on 144Hz you are SO annoying! ++ ++# frequently asked questions ++ ++> KDE is a downstream, Qt has CLA and C++ is an unwise choice. GNOME is the Standard- ++ ++144Hz. [look here](https://www.youtube.com/watch?v=VZlWCBhoCns&t=56s). +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/unmanaged.cpp kwin/unmanaged.cpp +--- kwin-5.20.5/unmanaged.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/unmanaged.cpp 2020-11-20 19:36:35.613428365 -0500 +@@ -195,5 +195,35 @@ + return true; + } + ++bool Unmanaged::shouldUnredirect() const ++{ ++ // the pixmap is needed for the login effect, a nicer solution would be the login effect increasing ++ // refcount for the window pixmap (which would prevent unredirect), avoiding this hack ++ if (resourceClass() == "ksplashx" ++ || resourceClass() == "ksplashsimple" ++ || resourceClass() == "ksplashqml" ++ ) ++ return false; ++ // it must cover whole display or one xinerama screen, and be the topmost there ++ const int desktop = VirtualDesktopManager::self()->current(); ++ // TODO: this mess o-o ++ if (frameGeometry() == workspace()->clientArea(FullArea, frameGeometry().center(), desktop) ++ || frameGeometry() == workspace()->clientArea(ScreenArea, frameGeometry().center(), desktop)) { ++ QList stacking = workspace()->xStackingOrder(); ++ for (int pos = stacking.count() - 1; ++ pos >= 0; ++ --pos) { ++ Toplevel* c = stacking.at(pos); ++ if (c == this) // is not covered by any other window, ok to unredirect ++ return true; ++ // TODO: check if this works ++ if (c->frameGeometry().intersects(bufferGeometry())) ++ return false; ++ } ++ abort(); ++ } ++ return false; ++} ++ + } // namespace + +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/unmanaged.h kwin/unmanaged.h +--- kwin-5.20.5/unmanaged.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/unmanaged.h 2020-11-20 19:36:35.613428365 -0500 +@@ -43,6 +43,7 @@ + public Q_SLOTS: + void release(ReleaseReason releaseReason = ReleaseReason::Release); + protected: ++ bool shouldUnredirect() const override; + void addDamage(const QRegion &damage) override; + private: + ~Unmanaged() override; // use release() +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/unredirect.md kwin/unredirect.md +--- kwin-5.20.5/unredirect.md 1969-12-31 19:00:00.000000000 -0500 ++++ kwin/unredirect.md 2020-09-25 11:49:59.152898564 -0500 +@@ -0,0 +1,30 @@ ++# fullscreen unredirection ++ ++this version of the compositor brings back the ability to unredirect fullscreen windows, which has been originally removed by the KDE developers because they thought their "block compositing" approach would be the future. ++ ++their "block compositing" approach has 3 flaws: ++ ++- it actually fully disables the compositor (which means it will take a while for it to re-enable) ++- it can get annoying (especially with SDL apps. SDL requests KWin to disable compositing, even if not in fullscreen!) ++- every application must be coded to support it. with unredirection it works on most apps without giving the developers extra burden. ++ ++however, fullscreen unredirection also has its flaws: ++ ++- in some setups it may crash, according to KDE developers ++- some applications may interfere and prevent it from working ++ ++# non-working/crashing setups ++ ++none so far. please contact me if your setup causes KWin to crash with unredirection. ++ ++# known issues ++ ++the following applications prevent unredirection from working: ++ ++- applications using the old tray mechanism (e.g. calfjackhost or Battle.net). they create a 32x32 invisible window at the top left corner, which becomes visible when you aren't using Plasma or some other desktop that doesn't support this mechanism. ++ - however, a workaround has been applied as of v5.16.2-2 but I am not sure whether it works well or not. ++- [latte-dock](https://github.com/tildearrow/kwin-lowlatency/issues/1#issuecomment-483403493) (sometimes) ++ ++the following applications may misbehave when unredirection is enabled: ++ ++- some Wine applications. after switching windows [they may turn black and hang](https://github.com/tildearrow/kwin-lowlatency/issues/25). +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/workspace.cpp kwin/workspace.cpp +--- kwin-5.20.5/workspace.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/workspace.cpp 2020-11-20 19:36:35.626761699 -0500 +@@ -554,6 +554,11 @@ + connect(c, &X11Client::blockingCompositingChanged, compositor, &X11Compositor::updateClientCompositeBlocking); + } + connect(c, SIGNAL(clientFullScreenSet(KWin::X11Client *,bool,bool)), ScreenEdges::self(), SIGNAL(checkBlocking())); ++ connect(c, &X11Client::activeChanged, m_compositor, static_cast(&Compositor::checkUnredirect)); ++ // THIS ONE PLEASE ++ connect(c, &X11Client::fullScreenChanged, m_compositor, static_cast(&Compositor::checkUnredirect)); ++ connect(c, &X11Client::geometryChanged, m_compositor, static_cast(&Compositor::checkUnredirect)); ++ connect(c, &X11Client::geometryShapeChanged, m_compositor, static_cast(&Compositor::checkUnredirect)); + if (!c->manage(w, is_mapped)) { + X11Client::deleteClient(c); + return nullptr; +@@ -1972,6 +1977,9 @@ + if (effects) { + static_cast(effects)->desktopResized(geom.size()); + } ++ ++ // best guess. ++ m_compositor->checkUnredirect(true); + } + + void Workspace::saveOldScreenSizes() +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/x11client.cpp kwin/x11client.cpp +--- kwin-5.20.5/x11client.cpp 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/x11client.cpp 2020-11-20 19:36:35.650095031 -0500 +@@ -1590,6 +1590,9 @@ + m_decoInputExtent.map(); + updateHiddenPreview(); + } ++ if (Compositor::self()->isActive()) { ++ Compositor::self()->checkUnredirect(); ++ } + emit windowShown(this); + } + +@@ -1605,6 +1608,9 @@ + updateHiddenPreview(); + addWorkspaceRepaint(visibleRect()); + workspace()->clientHidden(this); ++ if (Compositor::self()->isActive()) { ++ Compositor::self()->checkUnredirect(); ++ } + emit windowHidden(this); + } + +@@ -1623,6 +1629,9 @@ + updateHiddenPreview(); + addWorkspaceRepaint(visibleRect()); + workspace()->clientHidden(this); ++ if (Compositor::self()->isActive()) { ++ Compositor::self()->checkUnredirect(); ++ } + } + + /** +@@ -2893,6 +2902,10 @@ + updateGeometryBeforeUpdateBlocking(); + screens()->setCurrent(this); + workspace()->updateStackingOrder(); ++ if (Compositor::self()->isActive()) { ++ // TODO: there was a todo here but I don't know ++ Compositor::self()->checkUnredirect(); ++ } + // client itself is not damaged + if (oldBufferGeometry != bufferGeometry()) { + emit bufferGeometryChanged(this, oldBufferGeometry); +@@ -4778,10 +4791,11 @@ + if (m_syncRequest.counter != XCB_NONE) { + m_syncRequest.timeout->start(250); + sendSyncRequest(); +- } else { // for clients not supporting the XSYNC protocol, we +- m_syncRequest.isPending = true; // limit the resizes to 30Hz to take pointless load from X11 +- m_syncRequest.timeout->start(33); // and the client, the mouse is still moved at full speed +- } // and no human can control faster resizes anyway ++ } else { ++ m_syncRequest.isPending = true; // 30Hz resizes are so old and it makes the compositor ++ m_syncRequest.timeout->start(5); // look horrible. zero excuses. ++ } ++ + const QRect moveResizeClientGeometry = frameRectToClientRect(moveResizeGeometry()); + const QRect moveResizeBufferGeometry = frameRectToBufferRect(moveResizeGeometry()); + +@@ -4917,4 +4931,35 @@ + } + } + ++// TODO THIS ++bool X11Client::shouldUnredirect() const ++{ ++ if (isActiveFullScreen()) { ++ if (!rules()->checkAllowUnredirect(true)) return false; ++ QList stacking = workspace()->xStackingOrder(); ++ for (int pos = stacking.count() - 1; ++ pos >= 0; ++ --pos) { ++ Toplevel* c = stacking.at(pos); ++ if (c == this) { // is not covered by any other window, ok to unredirect ++ //printf("yes.\n"); ++ return true; ++ } ++ if (c->frameGeometry().intersects(frameGeometry())) { ++ // check whether this is an invisible floating icon at the top left corner ++ if (c->frameGeometry()==QRect(0,0,32,32)) { ++ //printf("yes via hack.\n"); ++ return true; ++ } ++ //printf("no. this: %d %d %d %d. other: %d %d %d %d.\n",geometry().x(),geometry().y(),geometry().width(),geometry().height(),c->geometry().x(),c->geometry().y(),c->geometry().width(),c->geometry().height()); ++ return false; ++ } ++ } ++ //printf("ABORT\n"); ++ abort(); ++ } ++ return false; ++} ++ ++ + } // namespace +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/x11client.h kwin/x11client.h +--- kwin-5.20.5/x11client.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/x11client.h 2020-11-20 19:36:35.650095031 -0500 +@@ -320,6 +320,7 @@ + bool motionNotifyEvent(xcb_window_t w, int state, int x, int y, int x_root, int y_root); + + protected: ++ bool shouldUnredirect() const override; + void addDamage(const QRegion &damage) override; + bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const override; + void doSetActive() override; +diff -ruNx .git -x build -x .clang-format -x .kdev4 -x po kwin-5.20.5/xdgshellclient.h kwin/xdgshellclient.h +--- kwin-5.20.5/xdgshellclient.h 2021-01-05 07:08:52.000000000 -0500 ++++ kwin/xdgshellclient.h 2020-11-20 19:36:35.653428365 -0500 +@@ -63,6 +63,7 @@ + virtual void installPlasmaShellSurface(KWaylandServer::PlasmaShellSurfaceInterface *shellSurface) = 0; + + protected: ++ bool shouldUnredirect() const override { return false; } + void requestGeometry(const QRect &rect) override; + void addDamage(const QRegion &damage) override; + diff --git a/kde-plasma/kwin/kwin-5.20.5.ebuild b/kde-plasma/kwin/kwin-5.20.5.ebuild new file mode 100644 index 0000000..4addb7e --- /dev/null +++ b/kde-plasma/kwin/kwin-5.20.5.ebuild @@ -0,0 +1,119 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +ECM_HANDBOOK="optional" +ECM_TEST="optional" +KFMIN=5.74.0 +PVCUT=$(ver_cut 1-3) +QTMIN=5.15.1 +VIRTUALX_REQUIRED="test" +inherit ecm kde.org + +DESCRIPTION="Flexible, composited Window Manager for windowing systems on Linux" + +LICENSE="GPL-2+" +SLOT="5" +KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86" +IUSE="accessibility caps gles2-only lowlatency multimedia screencast" + +COMMON_DEPEND=" + >=dev-libs/libinput-1.14 + >=dev-libs/wayland-1.2 + >=dev-qt/qtdbus-${QTMIN}:5 + >=dev-qt/qtdeclarative-${QTMIN}:5 + >=dev-qt/qtgui-${QTMIN}:5=[gles2-only=] + >=dev-qt/qtscript-${QTMIN}:5 + >=dev-qt/qtsensors-${QTMIN}:5 + >=dev-qt/qtwidgets-${QTMIN}:5 + >=dev-qt/qtx11extras-${QTMIN}:5 + >=kde-frameworks/kactivities-${KFMIN}:5 + >=kde-frameworks/kauth-${KFMIN}:5 + >=kde-frameworks/kcmutils-${KFMIN}:5 + >=kde-frameworks/kcompletion-${KFMIN}:5 + >=kde-frameworks/kconfig-${KFMIN}:5 + >=kde-frameworks/kconfigwidgets-${KFMIN}:5 + >=kde-frameworks/kcoreaddons-${KFMIN}:5 + >=kde-frameworks/kcrash-${KFMIN}:5 + >=kde-frameworks/kdeclarative-${KFMIN}:5 + >=kde-frameworks/kglobalaccel-${KFMIN}:5= + >=kde-frameworks/ki18n-${KFMIN}:5 + >=kde-frameworks/kiconthemes-${KFMIN}:5 + >=kde-frameworks/kidletime-${KFMIN}:5= + >=kde-frameworks/kio-${KFMIN}:5 + >=kde-frameworks/knewstuff-${KFMIN}:5 + >=kde-frameworks/knotifications-${KFMIN}:5 + >=kde-frameworks/kpackage-${KFMIN}:5 + >=kde-frameworks/kservice-${KFMIN}:5 + >=kde-frameworks/ktextwidgets-${KFMIN}:5 + >=kde-frameworks/kwayland-${KFMIN}:5 + >=kde-frameworks/kwidgetsaddons-${KFMIN}:5 + >=kde-frameworks/kwindowsystem-${KFMIN}:5[X] + >=kde-frameworks/kxmlgui-${KFMIN}:5 + >=kde-frameworks/plasma-${KFMIN}:5 + >=kde-plasma/breeze-${PVCUT}:5 + >=kde-plasma/kdecoration-${PVCUT}:5 + >=kde-plasma/kscreenlocker-${PVCUT}:5 + >=kde-plasma/kwayland-server-${PVCUT}:5 + media-libs/fontconfig + media-libs/freetype + media-libs/libepoxy + media-libs/mesa[egl,gbm,wayland,X(+)] + virtual/libudev:= + x11-libs/libICE + x11-libs/libSM + x11-libs/libX11 + x11-libs/libXi + x11-libs/libdrm + >=x11-libs/libxcb-1.10 + >=x11-libs/libxkbcommon-0.7.0 + x11-libs/xcb-util-cursor + x11-libs/xcb-util-image + x11-libs/xcb-util-keysyms + x11-libs/xcb-util-wm + accessibility? ( media-libs/libqaccessibilityclient:5 ) + caps? ( sys-libs/libcap ) + gles2-only? ( media-libs/mesa[gles2] ) + screencast? ( >=media-video/pipewire-0.3:= ) +" +# TODO: sys-apps/hwdata? not packaged yet; commit 33a1777a, Gentoo-bug 717216 +RDEPEND="${COMMON_DEPEND} + >=dev-qt/qtquickcontrols-${QTMIN}:5 + >=dev-qt/qtquickcontrols2-${QTMIN}:5 + >=dev-qt/qtvirtualkeyboard-${QTMIN}:5 + >=kde-frameworks/kirigami-${KFMIN}:5 + >=kde-frameworks/kitemmodels-${KFMIN}:5[qml] + multimedia? ( >=dev-qt/qtmultimedia-${QTMIN}:5[gstreamer,qml] ) +" +DEPEND="${COMMON_DEPEND} + >=dev-qt/designer-${QTMIN}:5 + >=dev-qt/qtconcurrent-${QTMIN}:5 + x11-base/xorg-proto +" +PDEPEND=" + >=kde-plasma/kde-cli-tools-${PVCUT}:5 +" + +RESTRICT+=" test" + +src_prepare() { + use lowlatency && eapply "${FILESDIR}/${PN}-lowlatency-5.20.5.patch" + ecm_src_prepare + use multimedia || eapply "${FILESDIR}/${PN}-5.16.80-gstreamer-optional.patch" + + # TODO: try to get a build switch upstreamed + if ! use screencast; then + sed -e "s/^pkg_check_modules.*PipeWire/#&/" \ + -i CMakeLists.txt || die + fi +} + +src_configure() { + local mycmakeargs=( + $(cmake_use_find_package accessibility QAccessibilityClient) + $(cmake_use_find_package caps Libcap) + ) + + ecm_src_configure +}