Compare commits

...

1059 Commits

Author SHA1 Message Date
Xaver Hugl f1a867ea12 color management: map reference luminance of source and target content to each other
This ensures that different content on the screen matches with the user configured
reference / SDR luminance, and both simplifies SDR<->HDR mapping by removing the need
for special casing that situation and significantly improves the mapping in some cases.
As we don't get any reference luminance values for HDR content (yet), this commit
assumes that HDR content is prepared for the reference luminance of the preferred
color description.
2024-06-28 13:16:02 +00:00
Xaver Hugl 15589c9997 color management: change brightness information names to be shorter and more correct
Brightness is a loose word for how bright we perceive things to be, but the
values we're using are about objective measurements, about luminance instead.
2024-06-28 13:16:02 +00:00
Xaver Hugl 280594354c plugins/qpa: set deprecated functions option correctly
If a context is forward compatible, that means the deprecated functions are not
available, and if the QSurfaceFormat::DeprecatedFunctions option is set, that means
they are available.
Wrongly setting QSurfaceFormat::DeprecatedFunctions thus causes Qt to use OpenGL in
a way the context doesn't actually support.

CCBUG: 486460
2024-06-28 12:50:50 +00:00
Vlad Zahorodnii a9377db1a9 plugins/kdecoration: Fix MenuButton not accepting button press events
If two mouse areas are stacked on top of each other and a button press
event is sent so one of them accepts it, QMouseEvent::isAccepted() will
still return false. It's a QtQuick bug, see the associated upstream bug
report https://bugreports.qt.io/browse/QTBUG-126733.

On the other hand, given that the MenuButton implements its own input
handling, we can port it away from DecorationButton to mitigate the issue.

BUG: 488993
2024-06-28 12:38:04 +00:00
Xaver Hugl 8f35a9ea8d plugins/colorcorrection: simplify the effect, merge the shader files and support color management 2024-06-28 12:23:48 +00:00
Vlad Zahorodnii cfe5bf2073 opengl: Reset OpenGlContext::currentContext() if it's destroyed
GlxContext destructor doesn't reset s_currentContext.

BUG: 488830
2024-06-28 11:24:58 +00:00
l10n daemon script 09b45a9937 GIT_SILENT Sync po/docbooks with svn 2024-06-28 01:36:56 +00:00
l10n daemon script d7ad0083a5 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-28 01:24:07 +00:00
David Edmundson d2c648f6cc input method: Drop unused member variable
The preedit struct holds values that need to be effectively double
buffered till the preedit string is set. There is no need to store the
text in this struct as it is reset at the end of setPreeditString
2024-06-27 22:05:41 +00:00
Andrew Shark 13b2c43b2b Add Colorblindness Correction effect keywords
This allows to easily reach this effect when searching in system settings.

BUG: 489329
2024-06-27 20:57:48 +00:00
Vlad Zahorodnii 3fd9026a01 Make X11Window::{update,discard}WindowPixmap noop on Wayland
These are relevant only to X11 session.
2024-06-27 20:34:42 +00:00
Vlad Zahorodnii 11d3f27e97 Remove the surfaces tab in the debug console
It's usefulness is doubtful, the current visuals poorly map to the
wayland abstractions, and it's partially incomplete because surface
previews are only shown for surfaces that have wl_shm buffers attached.
Tree hierarchy changes are also handled very poorly.
2024-06-27 20:54:42 +03:00
Xaver Hugl 8314cdf89d window: adhere to window rules in checkWorkspacePosition
BUG: 489117
2024-06-27 11:56:07 +00:00
Jonathan Riddell 6f2cab89d9 use separation dep_version to build against, updated by release scripts 2024-06-27 12:42:45 +01:00
Xaver Hugl ad8c947134 plugins/hidecursor: show the cursor on tablet events
BUG: 489009
2024-06-27 12:38:14 +02:00
l10n daemon script e597a37429 GIT_SILENT Sync po/docbooks with svn 2024-06-27 01:30:48 +00:00
l10n daemon script 240af64c82 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-27 01:19:12 +00:00
Vlad Zahorodnii 585dd069f7 plugins/hidecursor: Change the defaults
It's more likely that this plugin will be enabled because of hiding
cursor when typing so let's use that by default.

CCBUG: 488971
2024-06-26 22:02:29 +03:00
Vlad Zahorodnii 4c8544c44f plugins/hidecursor: Allow disabling hiding cursor on inactivity
BUG: 488971
2024-06-26 22:02:03 +03:00
Vlad Zahorodnii a41fac2d75 Switch to Xcb::Window geometry where it makes sense
There are a couple of reasons why it's worthwhile doing:

The first is that it makes the logic in the updateServerGeometry()
function reusable for the interactive code path. As of now, when the
window is being interactively resized, doInteractiveResizeSync() will
issue some xcb_configure_window() calls but then it also implicitly
assumes that updateServerGeometry() will call updateShape() and
updateInputWindow() but skip m_frame.setGeometry() later. That is
confusing, and error prone. For example, if somebody drops
m_lastFrameGeometry in favor of m_frame.geometry() (which is an
absolutely reasonable thing to do btw!!), a regression will be
introduced: things would appear to work at first, but then eventually
bug reports about input working weirdly would start piling up.

The second is hidpi scaling of wayland clients. toXNative(a + b + c)
is not the same as toXNative(a) + toXNative(b) + toXNative(c). By
switching to the device geometry, we leave less space for making an
error.

The third is that lets us clean up some geometry manipulation code.
When dealing with window hierarchies, it's more convenient to have
m_window.position() rather than a dedicated property in the X11Window
class such as wrapperPos().
2024-06-26 17:53:31 +00:00
Vlad Zahorodnii 02d43147b5 utils: Add convenience geometry getters in Xcb::Window 2024-06-26 17:53:31 +00:00
Akseli Lahtinen 07dcede820 WindowHeapDelegate: Label text background
Give label text background color to make it easier to distinct from the background.


BUG:483016
2024-06-26 16:00:54 +00:00
Vlad Zahorodnii 4c86653cd5 utils/xcbutils: Use window geometry in device pixels
If the logical geometry changes, the X11Window still needs to verify
whether the currently applied native geometry differs from it. In order
to do that, the X11Window needs to map the logical geometry to the device
pixels. Given that X11Window already maps the logical pixels to the
device pixels, the Xcb::Window doesn't need to map the geometry again.

Also, the way different coordinate spaces are handled now is inconsistent.
Some things (Xcb::Window) work only with the logical pixels, while other
(e.g. client messages) require the user manually mapping the geometry
between the different coordinate spaces. With this change, it would be
more consistent.

Regarding the porting process, it was performed in a single step because
all the code that changes or reads Xcb::Window geometry is neatly
encapsulated in the X11Window class in a couple of functions.
2024-06-26 18:06:06 +03:00
Xaver Hugl eb7b04e320 core/colorspace: make max brightness values optional
Zero is already optional, but it's easy to make mistakes that way
2024-06-26 15:41:38 +02:00
Xaver Hugl bdc24ff8c7 core/colorspace: add mastering display colorimetry
The mastering display colorimetry describes what part of the colorspace
is actually used, which is important when we're sending desired metadata
about a screen using the rec.2020 container colorspace, or when the client
uses an "infinite" / extended colorspace like scRGB
2024-06-26 15:41:38 +02:00
Xaver Hugl b35edf8d30 plugins/backgroundcontrast,blur: correct support checks
On Xorg, the effects need support for OpenGL blits, but on Wayland, the
screen texture can be used instead
2024-06-26 14:52:38 +02:00
Xaver Hugl 60a483471c opengl/glframebuffer: handle missing support for blits on Wayland
If OpenGL blits aren't supported, we can still copy the area by sampling the
texture for the screen on Wayland

BUG: 484193
2024-06-26 14:52:38 +02:00
Xaver Hugl 0773db0710 opengl: glBufferStorage is not supported on GL ES by default
CCBUG: 484193
2024-06-26 14:52:33 +02:00
Vlad Zahorodnii 9e57469c2f kcms/effects: Remove shake cursor keywords
It's confusing when the Desktop Effects shows up in the search results
while looking for "shake cursor".

BUG: 488850
2024-06-26 09:02:41 +03:00
l10n daemon script f0fad81963 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-26 01:19:45 +00:00
Vlad Zahorodnii 7590c6d386 wayland: Bump default max buffer size to 1 MiB
This is to prevent disconnecting clients that sometimes struggle with
keeping up with the events that the compositor sends. 1 MiB was eyeballed.

Wayland's wire protocol consists of a stream of messages. Every message
consists of a header (2 words: 1 word for object id, the other word
specifies the message size + event/request opcode) and the arguments.

Considering the compositor sending motion events generated by a mouse
with 1000Hz polling rate, we have

- wl_pointer.motion event size: (4 bytes for serial + 4 bytes for x +
  4 bytes for y + 8 bytes for header) = 20 bytes
- wl_pointer.frame event size: 8 bytes for header

So in total, if the client freezes for a second, the client buffer size
should be at least (20 + 8) * 1000 / 1024 = 27 KiB. 1 MiB corresponds to
the client not processing the motion events for approximately 30 seconds.
2024-06-25 20:19:59 +03:00
Xaver Hugl 5a0ecdba33 opengl/eglcontext: bail out early if we can't use complex shaders
Some old hardware is very limited in the amount of instructions it can support.
In order to not have KWin fail to composite, reject using hardware acceleration
in this case and fall back to llvmpipe or QPainter

BUG: 482868
2024-06-25 13:49:01 +00:00
Xaver Hugl c5fb21fd8b core/renderloop: assume high render times if the last frame has been a while ago
This helps avoid some frame drops after the GPU may have went into a lower power
state. While this isn't generally noticeable, avoiding this makes noticing and
debugging actually relevant frame drops easier

CCBUG: 488843
2024-06-25 13:07:36 +00:00
Aleix Pol Gonzalez 2601d06f5b Fix !KWIN_BUILD_GLOBALSHORTCUTS builds
Makes it so the GlobalShortucts object gets built and its KGlobalAccelD
parts get disabled.

Addresses the TODO in GestureHandler.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-25 11:21:56 +02:00
Aleix Pol Gonzalez a7470f4b4a core/renderjournal: Make sure we include std::span 2024-06-25 11:13:59 +02:00
Vlad Zahorodnii 44ea9ee959 scripting: Add a temporary workaround to fix build without global shortcuts 2024-06-25 07:29:48 +00:00
Vlad Zahorodnii 059f66af9a scripting: Port gesture handlers to native gesture apis
If a SwipeGesture or a PinchGesture is cancelled, the associated QAction
is going to be triggered. It is against the expectations of the gesture
handlers.

In order to address that, this ports the gesture handlers to the native
gesture apis, which expose whether the gesture has been started or cancelled
better.
2024-06-25 07:29:48 +00:00
Vlad Zahorodnii c958a75e2b scene: Drop ItemRendererOpenGL::RenderNode::scale
It's unused.
2024-06-25 06:56:56 +00:00
Alik Aslanyan 47ee47dcc8 tiling: Add fallback path for the first Polonium tile
After  a new code path was triggered during Workspace::rearrange call.
When first Polonium window opens on any screen, there is no active tile yet.
This forces geometry calculation in Window::checkWorkspacePosition -> Window::ensureSpecialStateGeometry
To return empty QRect, which depending on the screen arrangement will move window to the other screen.

This confuses Polonium plugin, as it receives wrong outputChanged signal in scripting API.

BUG: 488898
Signed-off-by: Alik Aslanyan <inline0@pm.me>
2024-06-25 05:59:11 +00:00
Vlad Zahorodnii a97c748d1c plugins/shakecursor: Harden cursor theme loading logic
The currently used cursor theme can be different from the configured one.
For example, if the configured theme cannot be used.

In order to ensure that that case is handled well, this change makes the
shake cursor plugin uses the same cursor theme as PointerInputRedirection.
2024-06-25 05:38:59 +00:00
Vlad Zahorodnii 1384a8d3fd utils: Fix XCURSOR_PATH envvar parsing
The XCURSOR_PATH environment variable can contain "~/.icons". Unfortunately,
QDir does not expand the tilda, we need to do it ourselves.
2024-06-25 05:38:59 +00:00
Vlad Zahorodnii d6b3baec8f plugins/shakecursor: Include high resolution breeze cursor themes 2024-06-25 05:38:59 +00:00
Vlad Zahorodnii 53221fd43f utils: Allow specifying XCursor theme search paths 2024-06-25 05:38:59 +00:00
Vlad Zahorodnii 28b396f44c plugins/shakecursor: Display default cursor shape
At the moment, the shake cursor respects the current cursor shape. But
there are couple of drawbacks behind doing it: the first is that it's
very likely that the cursor pixmap has low resolution, the second is
the cursor can be hidden client-side.

This change makes the shake cursor plugin load the Xcursor theme with
a high enough size and display the default cursor shape regardless of
what the client has set in order to address the two aforementioned issues.
2024-06-25 05:38:59 +00:00
Vlad Zahorodnii 6a2bc79dae Make FocusChain ignore closed windows
At the moment, the FocusChain has Q_ASSERT()s to prevent inserting closed
windows back into the focus chain. It makes sense on paper. But, there
are code paths that could still hypothetically call FocusChain::update(),
they are harmless except the logic in the FocusChain.

So instead this change makes the FocusChain ignore closed windows, i.e.
take a more defensive approach. There are a few reasons why it's
worthwhile doing: the first is that it would prevent inserting closed
windows back into the focus chain in release builds and potentially even
back into the stack, debugging such crashes is absolutely no fun; the
second is that it would be preferred to avoid sprinkling random
isDeleted() checks in the Window code here and there and thus making
the code harder to follow.
2024-06-25 05:23:40 +00:00
Xaver Hugl 03eb688818 core/renderloop: also log the predicted render time
It can be used to better judge why a frame was dropped
2024-06-24 20:59:14 +02:00
Xaver Hugl 92ceb00b37 autotests/drm: add test for vrr capability changing without a hotunplug 2024-06-24 18:47:00 +02:00
Xaver Hugl 4453ce7eef backends/drm: update output properties after they're created too
Otherwise we might miss some changes that come without a hotplug event,
like adaptive sync becoming available after the output has been initialized

BUG: 486149
2024-06-24 18:47:00 +02:00
Xaver Hugl 3b3c75a8e9 core/renderjournal: remove unnecessary includes 2024-06-24 15:05:32 +00:00
Vlad Zahorodnii ad4e27f5ef opengl: Remove code that prints gl platform details
It's printed whenever any opengl context is created, which can flood the
logs. On the other hand, this information is also included in the support
information, which we often ask in the bug reports.

BUG: 489000
2024-06-24 15:03:11 +00:00
Xaver Hugl 21a0ae31b7 plugins/screencast: test creating a dmabuf with the real modifier list
The test isn't useful if it tests different parameters than we're actually using
2024-06-24 16:43:09 +03:00
Xaver Hugl a169114fee core/renderloop: log frame statistics into a file
Data like target vs. actual pageflip time, and render times is often needed for
debugging or optimizing render time predictions, so this commit makes KWin print
that information to a file in the home directory whenever KWIN_LOG_PERFORMANCE_DATA
is set.

CCBUG: 488843
2024-06-24 15:26:18 +02:00
Aleix Pol 0eb02c8b2c plugins/slidingpopups: adopt input panels from when they're added
Now that they will be shown and hidden in the proper state, we can set
up the input panel slide as the window gets added and ignore the
geometry changes that it will have in its lifetime.
2024-06-24 12:48:05 +00:00
Aleix Pol b1bd3ff630 inputpanelv1window: polish window states
Do not markAsMapped an unpositioned panel, it would confuse the sliding
popups effect and force it to figure out its state in creative ways.
Mark the panel window as hidden as it gets destroyed.
2024-06-24 12:48:05 +00:00
Vlad Zahorodnii 1dbef2d5ed backends/drm: Fix DrmCrtc::queryCurrentMode() accidentally resetting m_crtc to null
Otherwise kwin will likely crash.
2024-06-24 12:32:24 +03:00
l10n daemon script 1ee3062e45 GIT_SILENT Sync po/docbooks with svn 2024-06-24 01:23:58 +00:00
Vlad Zahorodnii 944be3d55a Drop WaylandServer initialization flags
These flags affect kwin in general so WaylandServer is not the best place
for them to live in. For such things, we typically add properties in the
Application object, which is what this change does.
2024-06-23 17:53:17 +00:00
Yifan Zhu c6ac6d3caa scene: install all the headers 2024-06-23 01:59:43 +00:00
l10n daemon script 6540112bf3 GIT_SILENT Sync po/docbooks with svn 2024-06-23 01:30:03 +00:00
l10n daemon script 7d486ddce7 GIT_SILENT Sync po/docbooks with svn 2024-06-22 01:34:31 +00:00
l10n daemon script 85badd901d SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-22 01:20:29 +00:00
Vlad Zahorodnii 7eb9f75af2 plugins/glide: Subdivide window quad grid
The way the glide effect works is that it takes 2D geometry and applies
the perspective projection to it on the CPU side. The reason we do it is
that the scene is 2D.

However, this leaves us with the well known problem where a texture
that's mapped to a trapezoid won't be correctly interpolated along the
diagonal.

It can addressed by performing a perspective division in the fragment
shader, but given the way the effect is structured, it's off the table. So
instead subdivide the window grid.

BUG: 488840
2024-06-21 12:46:28 +00:00
Xaver Hugl b745f83339 x11window: remove unused variable 2024-06-21 12:34:35 +00:00
Xaver Hugl 9293df2681 plugins/zoom: do colorspace conversions between the screen textures
Otherwise colors and especially brightness levels can be quite wrong when
the textures are used on a different screen

BUG: 488839
2024-06-21 14:26:12 +02:00
Vlad Zahorodnii 2fb485d67d plugins/screencast: Unset only cursor id when the cursor is invisible
We are doing half a job of resetting spa_meta_cursor, the actual cursor
content is still left as is. On the other hand, it should plenty enough
to simply reset the cursor id. The clients are expected to call
spa_meta_cursor_is_valid().
2024-06-21 05:54:25 +00:00
Vlad Zahorodnii 16f6473f56 Add closed window guards in X11Window::doSetXYZ() methods
It won't hurt to have them.
2024-06-21 05:35:13 +00:00
l10n daemon script 9bcba5334c GIT_SILENT Sync po/docbooks with svn 2024-06-21 01:27:47 +00:00
l10n daemon script 268d066f4f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-21 01:18:41 +00:00
Vlad Zahorodnii 9276d28b3d plugins/shakecursor: Ignore animation speed
From the user perspective, shaking cursor is not perceived as an
animation, so let's ignore the global animation speed factor.

BUG: 488813
2024-06-20 22:28:49 +03:00
l10n daemon script 2db79aaca8 GIT_SILENT Sync po/docbooks with svn 2024-06-20 01:32:04 +00:00
David Redondo 1a916293dc plugins/eis: Make input capture activation ids unsigned
The portal API is specified with unsigned ids. Let's make them
unsigned all the way through.
2024-06-19 11:49:31 +00:00
Xaver Hugl 92f1fabe5b wayland_server: create a new screen locker connection when the greeter gets restarted
Otherwise, Wayland objects and protocol errors can cause the new instance to not start
2024-06-19 11:09:10 +00:00
Xaver Hugl b107295c03 windowheap: don't animate the position of windows that get hidden
The target position is zero, so they just move into the top left corner,
which looks weird. With this commit, they just fade away without moving
2024-06-19 10:17:53 +00:00
Vlad Zahorodnii e316694675 backends/x11: Move the contents of common/ to standalone/
It's used only there.
2024-06-19 08:56:12 +00:00
Vlad Zahorodnii 8a5bae0f86 backends/x11: Port away from XRenderPicture 2024-06-19 08:56:12 +00:00
Vlad Zahorodnii ad31fd6b18 plugins/nightlight: Fix dbus property types
currentTemperature, targetTemperature, and mode properties have "u" type.
But there is a mismatch between the property types declared in the
Q_PROPERTY macro and the org.freedesktop.DBus.Properties.PropertiesChanged
signal.

This change makes the property types consistent and match the types
declared in the xml file.
2024-06-19 05:29:11 +00:00
l10n daemon script 18e9adf5b7 GIT_SILENT Sync po/docbooks with svn 2024-06-19 01:28:15 +00:00
Vlad Zahorodnii 1dee66a36c plugins/nightlight: De-duplicate dbus code 2024-06-18 18:14:07 +00:00
David Redondo 1b1af29de9 Sync xwayland eavesdropping default in kwin.kcfg
Amends a136a159f9 which changed the value in the kcfg file that the kcm reads, KWin uses options.kcfg
4f322e24d3 changed the in code default but this will be later overriden when loading the options.
2024-06-18 07:39:22 +00:00
l10n daemon script 940215b624 GIT_SILENT Sync po/docbooks with svn 2024-06-18 01:33:57 +00:00
Aleix Pol Gonzalez 559b0cccf5 shm: support textures of 3 bytes-per-color
Adds support for BGR888 and RGB888.
Some clients use it and we just fail to render them, making devs
thinking that kwin is broken.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-17 22:24:16 +00:00
Vlad Zahorodnii 7fca508619 Remove code that updates the focus chain in Window::setSkipTaskbar()
skipsTaskbar() doesn't influence whether the window wants input.
2024-06-17 20:04:11 +00:00
Vlad Zahorodnii 0fc6c6800e Get rid of extra string allocations in src/inputmethod.cpp 2024-06-17 19:01:12 +00:00
Xaver Hugl c761571a43 workspace: don't use an empty list as "don't update"
It's confusing and caused the xwayland scale to not be updated in all situations
where it should be updated
2024-06-17 20:49:52 +02:00
Xaver Hugl e16069ae77 autotests: add Xwayland scale changes to the output changes test
CCBUG: 487409
2024-06-17 20:41:58 +02:00
Xaver Hugl 4f5fce8b7a workspace: also update xwayland scale when not changing the output order 2024-06-17 20:41:58 +02:00
Alessandro Astone 170b138026 wayland: Allow configuring locale1 mode from kwinrc
KWin already supports following org.freedesktop.locale1 for the
keyboard keymap, but only by passing a command-line option. This is
typically used in SDDM when running the greeter in kwin_wayland.

We want to use locale1 mode in livesys environments too, so that
environment-agnostic installers can configure the keyboard and also
immediatly apply the same configuration to the running desktop.
When KWin is started through `startplasma` we cannot easily supply
an extra command-line option, so we need to make this configurable
from the external environment, in the form of a KConfig.

The command-line option will keep precedence over the KConfig.
2024-06-17 17:52:29 +00:00
Xaver Hugl 7e2d650c8f plugins/nightlight: remove unnecessary commitGammaRamps 2024-06-17 16:17:24 +00:00
Vlad Zahorodnii af16c9b243 wayland: Make org_kde_kwin_shadow use GraphicsBufferRef
It makes the graphics buffer referencing less error prone.
2024-06-17 11:48:06 +00:00
Vlad Zahorodnii 1a7c94b692 wayland: Fix buffer ref'ing in org_kde_kwin_shadow.commit
In case the current state and the pending state have the same buffer for
a particular side or a corner, that buffer can be prematurely released
because the buffer in the current state is unreferenced first.

The ref/unref order should be vice versa to ensure that the GraphicsBuffer
is not released prematurely.
2024-06-17 11:48:06 +00:00
Marius P ba599a2aa0 Prefer en_US, "centre" -> "center" 2024-06-17 05:29:59 +00:00
Vlad Zahorodnii 64bbbde249 cmake: Group together code that tests compiler features and platform features 2024-06-17 05:09:13 +00:00
Vlad Zahorodnii f89a1f9766 cmake: Remove invalid comments 2024-06-17 05:09:13 +00:00
Vlad Zahorodnii a1443cb43e cmake: Move find_package() around to keep them all close 2024-06-17 05:09:13 +00:00
Vlad Zahorodnii 2d4bbe917c cmake: Group option()s 2024-06-17 05:09:13 +00:00
l10n daemon script 8c067c77f4 GIT_SILENT Sync po/docbooks with svn 2024-06-17 01:31:03 +00:00
Nate Graham 68b7448847 plugins/showpaint: set default shortcut
This effects is off by default, which means to instruct someone how to
use it for debugging purposes, you need to both tell them to enable it,
and then also teach them how to assign a shortcut for it.

Since it's off by default, there's no harm in setting a shortcut, which
simplifies the enablement instructions. I've chosen Meta+Ctrl+Alt+P,
which uses so many modifiers that it won't conflict with anything.
2024-06-16 11:01:40 -06:00
Xaver Hugl 178d49093c backends/drm: don't do direct scanout when HDR brightness isn't 1
Otherwise the brightness multiplier doesn't get applied
2024-06-16 17:11:43 +02:00
l10n daemon script 979ac5bd50 GIT_SILENT Sync po/docbooks with svn 2024-06-16 01:27:32 +00:00
Vlad Zahorodnii 29a5541ccf wayland: Reset dnd state when the target surface is about to be destroyed
Use the SurfaceInterface::aboutToBeDestroyed() for the consistency sake
with other code that performs cleanup when the wl_surface is destroyed.
2024-06-15 15:11:53 +00:00
Vlad Zahorodnii e1192a6934 plugins/nightlight: Drop NightLightManager::self()
It's unused.
2024-06-15 12:06:06 +03:00
Vlad Zahorodnii d00d00c7fc plugins/nightlight: Tidy header include directives 2024-06-15 12:03:39 +03:00
Vlad Zahorodnii 6b4ef4170c plugins/nightlight: Shuffle some code
Keep things that are related spatially close, in this case, the
initialization of the timer that will start the next transition.
2024-06-15 11:37:26 +03:00
Vlad Zahorodnii d595b8f8aa plugins/nightlight: Rename FALLBACK_SLOW_UPDATE_TIME 2024-06-15 07:58:15 +00:00
Vlad Zahorodnii 55dc891190 plugins/nightlight: Store transition duration in milliseconds
This allows us to make the code that computes transition timings more
cleaner, and other time constants are in milliseconds, so it makes sense
to make m_transitionDuration store milliseconds too.
2024-06-15 07:58:15 +00:00
l10n daemon script 5c6e51d75e GIT_SILENT Sync po/docbooks with svn 2024-06-15 01:28:00 +00:00
l10n daemon script 927fb42abc SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-15 01:19:16 +00:00
Vlad Zahorodnii 3461d5bc3a plugins/nightlight: Unobfuscate code that reads geocoordinates
The current code is unreadable:

- it creates a lambda that captures two local variables for latitude and longitude
- then it copies values from the config to those local variables
- calls the lambda
- and finally copies the data from the local variables to the NightLightManager fields

That code can be simplified by simply calling checkLocation() directly
and using an if statement.
2024-06-15 01:29:59 +03:00
Vlad Zahorodnii e5528e9317 plugins/nightlight: Rename variables and functions to adhere to the KDE coding conventions
The variables and functions should be fully spelled out, with temporary
variables being an exception.
2024-06-14 18:24:06 +03:00
Vlad Zahorodnii 786b3ffbae plugins/nightlight: Guard against invalid timings in the config
Morning and evening timings should be ordered correctly. When computing
the daylight duration, that ternary operator should not be needed and it
hides other bugs.
2024-06-14 18:00:53 +03:00
Vlad Zahorodnii 07f266e7c7 plugins/nightlight: Remove premature optimization in updateTransitionTimings()
There are a couple of reasons why it's worth removing it:

- it's error prone. If one forgets to pass correct "force" flag, night
  light will break
- it contributes some complexity
- updateTransitionTimings() is not called in any hot path and the code
  that calculates the position of the Sun is not resource intensive
2024-06-14 14:26:35 +00:00
Vlad Zahorodnii 5fe9e9c756 plugins/screencast: Check compositing type
Screencasting only works with OpenGL compositing at the moment.
2024-06-14 12:50:46 +00:00
Vlad Zahorodnii 8256f8e14c Reorder some function calls in X11Window::updateServerGeometry()
The main motivation is to improve code aesthetics. The relative
order in which various window properties are configured shouldn't
matter.
2024-06-14 12:37:56 +00:00
Vlad Zahorodnii 5d03d58dc1 Drop X11Window::resizeDecoration()
We can call updateInputWindow() directly.
2024-06-14 12:37:56 +00:00
Vlad Zahorodnii a7c4175099 Don't call triggerDecorationRepaint() when resizing an X11Window
Wayland windows have no such code path and they have been good so far.
If the borders change, KDecoration will trigger a repaint.
2024-06-14 12:37:56 +00:00
Vlad Zahorodnii fef2bfb93f plugins/nightlight: Make Night Light more robust to QTimer firing slightly earlier
Currently, resetSlowUpdateTimers() will start a timer that will pass
m_next.first as the current time to resetSlowUpdateTimers(). This kind
of works, but there are more code paths where updateTransitionTimings()
can be called.

This change hardens updateTransitionTimings() against the current time
being very close to the start of the next transition by introducing a
time fudge factor.

If we are currently 1 second away from the start of the next transition,
then it is assumed that that transition has been reached, and we need
to calculate the timings of a transition after that.
2024-06-14 12:06:34 +00:00
Vlad Zahorodnii ad98069618 Make Window::closeWindow() noop if the window is already closed
The surface handle can be dropped by that time. Also, there is no point
to ask the client to close the window again if it's already closed.
2024-06-14 11:16:41 +00:00
Vlad Zahorodnii ec86640f44 plugins/nightlight: Tidy temperature lerp code
This change simplifies the color temperature interpolation code by doing
the following:

- compute a progress value so 0 corresponds to target1, i.e. the beginning
  of the transition, and 1 corresponds to target2, the end of the
  transition, instead of vice versa
- and use std::lerp() function

Rounding to a multiple of ten is not needed, it is for nicer digits in
the applet, but if the applet really cares about it, it could perform
such rounding on its own. In the night light manager, it's better to avoid
rounding the interpolated values because that can result in the final
temperature getting outside of the [target1, target2] interval.
2024-06-14 07:22:03 +00:00
David Redondo c2141dc4ef Also wake up screens on tablet interactions
BUG:451359
FIXED-IN:6.1.1
2024-06-14 06:54:42 +00:00
Vlad Zahorodnii f46174453d plugins/nightlight: Ensure the target temperature remains within reasonable bounds
The interpolated temperature can get out of the bounds of [target1, target2]
if the current time is slightly earlier than m_prev.first, which can be
unexpected. This change addresses that by adding a relevant guard.
2024-06-13 15:58:01 +03:00
Vlad Zahorodnii 21a45c2700 Avoid sending X11 sync request if new logical geometry doesn't change the device geometry
There are two mechanisms to throttle ConfigureNotify events during
interactive resize:

- either using XSync
- or by a dummy QTimer

The QTimer approach is pretty straightforward: the wm configures the
window, blocks the interactive resize operation and arms a timer to
unblock it some time later in the future.

With the xsync approach, the wm sends an xsync request, makes a
call to XConfigureWindow(), and blocks interactive resize until
the xsync request is acked by the client. When the client sees the
ConfigureNotify event, it is going to repaint and ack the xsync request.
When the xsync request is acked, the wm will apply new geometry and
unblock interactive resize.

After the scaling changes, the logical geometry can have some fractional
part, which gets rounded when configuring the X windows. Due to that,
it's possible to encounter the case where the logical geometry changes,
but the native/device geometry does not due to std::round(). In that
case, the wm should not send an xsync request because the client won't
ack it because the device geometry has not changed.

BUG: 488223
2024-06-13 08:34:30 +00:00
Vlad Zahorodnii 4db2742e96 autotests: Add a missing mock definition of Xcb::toXNative(QRectF) 2024-06-13 08:34:30 +00:00
l10n daemon script 312f88872b GIT_SILENT Sync po/docbooks with svn 2024-06-13 01:25:35 +00:00
Xaver Hugl ad6700dd88 workspace: initialize the output config store earlier
It needs to be created before the outputs are queried the first time,
as that uses the config store
2024-06-12 19:32:36 +02:00
Xaver Hugl 6543ab3caa workspace: only load output configs on Wayland
They don't need to be loaded, or on exit saved again on X11

BUG: 488229
2024-06-12 17:46:31 +02:00
Vlad Zahorodnii c2ca1cc33d wayland: Remove unnecessary wl_surface resource check
The lifetime of SurfaceInterface matches the lifetime of the corresponding
wl_resource.
2024-06-12 13:43:00 +00:00
Vlad Zahorodnii 8fb3348600 wayland: Clean up action matching connections when the target dnd surface dies 2024-06-12 13:43:00 +00:00
Vlad Zahorodnii 877d220bfe wayland: Fix a crash in dnd action matching
In order to match dnd actions, we need both a data source and a data
offer. If the preferred actions of either change, then a new dnd
must be chosen.

The code that sets up the monitoring of the preferred actions of the
data offer sets the correct receiver context object (data source).

But the code that sets up the monitoring of the preferred actions of
the data source uses the data source as the receiver context object,
however we would like to break the matchOffers connection when either
the data source or the data offer is destroyed.
2024-06-12 13:43:00 +00:00
Vlad Zahorodnii f37c15b0a2 Enable drkonqi
Enable dr konqi for kwin so sentry crash reports are more useful.
2024-06-12 12:45:47 +00:00
Vlad Zahorodnii 6be238e622 Fix registering touch screen edge actions after the screen edge has been reserved
After the screen edge is reserved, the touch screen gestures will be
registered or unregistered when the Edge::activatesForTouchGesture()
signal is emitted.

On the other hand, Edge::reserveTouch() lacks code to emit that signal,
which results in touch screen gesture not working if the same screen
edge is reserved both for pointer and touch input.

BUG: 451349
2024-06-12 12:33:52 +00:00
Xaver Hugl 35a7e30952 backends/drm: set scaling mode to full aspect with generated modes on internal displays
While the scaling mode has caused some issues with external displays, we've had several
reports that using "unify outputs" has caused the internal display to no longer show
anything, as it changes to an unsupported mode. This sets the scaling mode so that the
driver handles the scaling internally, instead of leaving it up to the panel, and it only
does so on internal displays with generated modes, to minimize the risk of further breakage.

BUG: 488111
2024-06-12 11:50:57 +00:00
Jie Liu 131c5399b3 x11window: enable startSystemMove/Resize which is triggered from touch events
Signed-off-by: Jie Liu <liujie01@kylinos.cn>
2024-06-12 02:19:02 +00:00
l10n daemon script d65bc400e9 GIT_SILENT Sync po/docbooks with svn 2024-06-12 01:31:01 +00:00
l10n daemon script 1c3b4cc548 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-12 01:19:49 +00:00
David Edmundson d6360cc4ce effects: Drop morphing popups effect
The effect does not work very well for two main reasons:
Some clients will make a new popup rather than move an existing one, so
whether it does anything is highly unpredictable as a user.

Popups can be of massively different sizes with different amounts of
text. This means the text in the smaller popup gets resized which
doesn't look like a natural in-between state of the two popups. This
defeats the objective of looking smoother.

On top of that, it's rather glitchy.
This effect was purely visual, no functionality changes.

BUG: 473411
BUG: 466638
BUG: 416048
BUG: 461501
BUG: 466637
2024-06-11 19:58:50 +00:00
Vlad Zahorodnii 64b02cf464 plugins/screencast: Preserve modifier order
The SPA_FORMAT_VIDEO_modifier property has the following format:

    preferred_value,alternative1,alternative2,...

The preferred value is usually the same as the first alternative value.
It can also happen that the modifier list the compositor has supplied is
not good either and it contains duplicate entries, specifically
`DRM_FORMAT_MOD_INVALID` to indicate that modifier-less buffers are
supported.

In order to deal with that, the screencast plugin removes the
duplicates by sorting the modifier list and then using std::unique().

That is not good, there is no written rule that the order of the
modifiers passed to the graphics buffer allocator matters but it
typically does, some drivers in mesa assume that the modifiers are
sorted in the preference order. The graphics buffer allocator might be
also very lazy and just look at the first supplied modifier instead of
wisely choosing the best modifier.

This change makes the ScreenCastStream remove the duplicate modifiers
in a more conservative fashion preserving the relative order of the
modifiers. It also removes an extra `{DRM_FORMAT_MOD_INVALID}` because
this kind of thing should be dictated by the render backend.
2024-06-11 10:39:19 +03:00
l10n daemon script 6c69f0a4d1 GIT_SILENT Sync po/docbooks with svn 2024-06-11 01:32:20 +00:00
Aleix Pol Gonzalez f9b9149ba4 plugins/showfps: Allow showfps to work without kirigami and quickcharts
showfps is a handy plugin when deploying to a new platform because it
will render something that says "I am here".
Since both kirigami and quickcharts are quite high level, we add a
variant that just depends on QtQuick and shows the fps which is what we
promise anyway.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-10 17:32:28 +02:00
Aleix Pol Gonzalez b202ecf711 aaaa 2024-06-10 17:32:28 +02:00
Aleix Pol Gonzalez 3c857a3375 scripting: Do not crash when calling workspace.clientArea() without an output
Just set a default one, one way less a script can crash kwin.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-10 17:23:43 +02:00
Aleix Pol Gonzalez 68d1e2f42a wayland: Log an entry when an unsupported buffer was submitted
It's fine to be conservative about what kind of buffers we support, but
failing silently only makes it hard on such cases.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-10 17:23:43 +02:00
Aleix Pol Gonzalez 70231f2431 backends/drm: Complain when we are issuing an invalid drm property
The alternative is silent failures and KWin rendering nothing. The
kernel will only be telling us that something went wrong which makes it
hard to debug.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-10 17:23:42 +02:00
Vlad Zahorodnii cd2d5b07d5 Prevent potentially adding closed windows to the attention chain
CCBUG: 486693
2024-06-10 16:21:16 +03:00
Vlad Zahorodnii cfbee55c2a wayland: Initialize xdg-toplevel size hints to 0,0
QSize() initializes the width and the height to -1x-1 by default.
2024-06-10 15:29:49 +03:00
Vlad Zahorodnii 61332caa20 wayland: Fix one dimensional size constraints
QSize::isEmpty() will return true if either dimension is 0. On the other
hand, given the current language in the spec, it seems like the client
is allowed to set size constraints per dimension.

BUG: 488260
2024-06-10 15:29:49 +03:00
Xaver Hugl 0c5ee47892 core/renderbackend: check for the renderloop being deleted
Output frames can outlive the output they were created for, so the render loop
might also be deleted by the time the output frame is destroyed or presented

BUG: 487701
2024-06-10 13:46:33 +02:00
David Edmundson 4b58f6c207 wayland: Drop unused global from interface blacklist
This was deleted when we added pipewire support
2024-06-10 07:46:33 +00:00
l10n daemon script 57d8bd6856 GIT_SILENT Sync po/docbooks with svn 2024-06-10 01:43:24 +00:00
l10n daemon script 57f862eb4d GIT_SILENT Sync po/docbooks with svn 2024-06-09 01:27:11 +00:00
l10n daemon script fa5b3e920b GIT_SILENT Sync po/docbooks with svn 2024-06-08 01:31:30 +00:00
l10n daemon script cfca23f9b3 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-08 01:20:05 +00:00
Xaver Hugl 65b4968c80 remove the HideUtilityWindowsForInactive option
It caused bugs and doesn't seem to work anymore, with no complaints about it
not working or an obvious reason for it to exist, so it almost certainly
isn't needed at all.
2024-06-07 21:14:41 +02:00
Xaver Hugl a6a85466cd workspace: restrict showing windows because HideUtilityWindowsForInactive=false to actual utility windows
BUG: 413549
2024-06-07 21:05:52 +02:00
Xaver Hugl f6540283d5 placement: if a window can't be placed maximized, place it centered
It's closer to what maximized does than minimal overlapping

BUG: 438572
2024-06-07 19:59:49 +02:00
Vlad Zahorodnii 83502e29a9 plugins/nightlight: Fix current time changing after updating transitions
When the slow update timer fires, it's going to pass m_next.first as the
current time in order to calculate the next transition timings. After
the timings have been calculated, the slow update timer will be started
with an interval of "todayNow.msecsTo(m_next.first)". Since todayNow
is a reference to m_next.first, the time diff will be 0, which will
throw off the night light manager. To fix that, make a copy of m_next.first
and then pass the copy as the current date time to resetSlowUpdateTimers().

BUG: 487901
2024-06-07 15:16:48 +00:00
Xaver Hugl b2ff465490 workspace,window: don't elevate windows during electric border tiling / maximizing
Instead, move the outline below the window, so that the visual order of things stays the
same. This also fixes a visual glitch, where the outline is visible for a moment after
maximization, and is above the no-longer-elevated window

BUG: 436466
BUG: 354741
2024-06-07 14:46:10 +02:00
Xaver Hugl bffae41983 remove Workspace::sendWindowToOutput
It just calls Window::sendToOutput...

BUG: 329980
2024-06-07 00:44:24 +00:00
Xaver Hugl 3bf97e87e5 backends/x11/standalone: add a nullptr check in the vblank handler
It can be called without a previous presentation in some cases

BUG: 488112
2024-06-06 16:54:16 +00:00
Xaver Hugl 0cd6f5cd06 window: use the correct output when electric border quick tiling
BUG: 487844
2024-06-06 16:54:16 +02:00
l10n daemon script 6166060f9b GIT_SILENT Sync po/docbooks with svn 2024-06-06 01:30:28 +00:00
Xaver Hugl 76739f1f2f core/renderloop: don't do triple buffering with vrr or tearing
While in theory it could be useful with both, I'm not sure that it makes sense
in practice, and the current triple buffering logic doesn't support it.

BUG: 487605
2024-06-05 19:24:09 +00:00
Vlad Zahorodnii 54473f03ba Re-enable hardware cursor on intel devices
My recent testing has shown that screen freezes when moving the cursor
cannot be observed anymore. Maybe the issue has been fixed upstream by
some unrelated change. Either way, let's re-enable the hardware cursor
to gather some feedback.
2024-06-05 18:08:51 +00:00
Xaver Hugl ecb6460277 backends/drm: re-enable buffer readability checks on i915
We're checking the egl fence fd now, instead of the dmabuf directly, which shouldn't
be affected by the same issue
2024-06-05 15:08:11 +00:00
Xaver Hugl a167657214 backends/drm: enable pipelines for VR headsets
Otherwise, the pipeline state from an earlier hotplug scenario can leave
the pipeline disabled and without a CRTC, which means leasing the output
will fail

BUG: 487938
FIXED-IN: 6.1.0
2024-06-05 13:12:56 +00:00
Xaver Hugl 47d873db94 autotests/drm: disable testModeset
It only works with the assumption that outputs are enabled by default, which
is not the case anymore
2024-06-05 13:12:56 +00:00
l10n daemon script 3f48b22f1a GIT_SILENT Sync po/docbooks with svn 2024-06-05 01:43:49 +00:00
Xaver Hugl 8c25784070 outputconfigurationstore: split user configured and automatically set modes
If the mode the user has previously set through KScreen isn't available, this falls
back to a different mode without overwriting the user preference. If on the next
hotplug, the desired mode is available again, it then gets chosen instead of the
fallback

BUG: 484037
2024-06-04 13:52:54 +00:00
Xaver Hugl c9627dc60f backends/drm: reset edid if the property is zero
Otherwise, a display without any EDID might be recognized as a display
that was previously connected to the same connector
2024-06-04 12:08:56 +00:00
Niccolò Venerandi a56b16e2ff Remove orphan shortcuts for desktop grid and expose effects
BUG:487974
2024-06-04 10:09:08 +00:00
Vlad Zahorodnii eea79bddd8 backends/libinput: Destroy Connection in correct thread 2024-06-04 10:00:17 +00:00
Vlad Zahorodnii 7622921de6 Explicitly destroy WaylandServer in ApplicationWayland destructor
Otherwise the WaylandServer will be destroyed when QCoreAppplication is
gone, which is too late.
2024-06-04 10:00:17 +00:00
Vlad Zahorodnii b4822389c3 Create WaylandServer after backends
Move WaylandServer after backends so it's less tempting to use WaylandServer
in low level components.
2024-06-04 10:00:17 +00:00
David Edmundson 8c149bb6b7 effects: Do not call RHI QQuickRenderControl methods when using software rendering
As per the docs:
Note: This function does not need to be, and must not be, called when
using the software adaptation of Qt Quick.

This sets up RHI on the render control, which in turn sets RHI on the
window, which shouldn't exist when using software rendering.

BUG: 482663
BUG: 486078
2024-06-04 08:33:19 +00:00
l10n daemon script fd746b46e5 GIT_SILENT Sync po/docbooks with svn 2024-06-04 01:24:29 +00:00
Vlad Zahorodnii cadf16b12e Improve handling of closed windows
A layer shell window can request a screen edge without having a chance
to map the surface. In that case, no Workspace::windowRemoved() signal
is not going to be emitted because no surface has been mapped. Perhaps
it needs some re-wiring, but on the other hand, it is also more reasonable
to monitor Window::closed() signal.

With this change, the ScreenEdges manager will reject any request to
reserve a screen edge for a closed window. And in addition to that,
the ScreenEdges will unreserve screen edges when the window is closed
rather than when the window is unmapped.

CCBUG: 485318
2024-06-03 14:54:40 +00:00
Vlad Zahorodnii 01a9eb2327 plugins/screencast: Stop frame rate throttling timer when stream is paused
Hypothetically, m_pendingFrame can be armed when the stream is paused.
It is undesired to call recordFrame() in that case.
2024-06-03 12:54:39 +00:00
Vlad Zahorodnii d048f9aad8 autotests: Destroy WaylandServer before Application 2024-06-03 11:22:13 +00:00
Vlad Zahorodnii 79238b06cf core: Check that GraphicsBuffer references change on the main thread 2024-06-03 11:22:13 +00:00
David Edmundson 79ef1be57b xwayland: Avoid crash if processing keys after xwayland is disconnected
Whilst the XWayland input filter only runs whilst XWayland is running
there is hypothetical window between the wayland connection to xwayland
being disconnected and handleXwaylandFinished, the process exiting. This
should be guarded correctly.

BUG: 480925
2024-06-03 10:23:57 +00:00
Vlad Zahorodnii 8b843e647c xwayland: Initiate x-to-wayland dnd only if the seat permits it
This is mainly to avoid creating lingering m_currentDrag object if
SeatInterface::startDrag() refuses to start a dnd session.
2024-06-03 09:54:32 +00:00
Vlad Zahorodnii ee4cf67371 wayland: Refuse starting dnd if there's another dnd session in progress
If a new drag and drop session is started while there is already one
existing, it's possible to end up in a situation where the
SeatInterface::dragEnded signal is emitted the second time when one of
the data sources is destroyed.

CCBUG: 460374
2024-06-03 09:54:32 +00:00
David Edmundson 1c3a987d74 wayland: Only load HiddenPreviews options in X11
HiddenPreviews was a hack to not inform X11 that windows were minimised,
so that their previews kept working.

On wayland the user facing setting is not visible but the value is
loaded which is a bad combination.

CCBUG: 415286
2024-06-03 08:36:53 +00:00
Aleix Pol Gonzalez 26d9361695 core,backends/drm: Improve error logging
Write something into the logs when a call goes awry, it can save some
time to the next person porting kwin to a dysfunctional driver.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-06-03 08:14:32 +00:00
Sam James 31a3961c4c
watchdog: add includes for geteuid
05a3e2bad9 added `geteuid` use but didn't
add the needed headers. This works by chance on libstdc++ systems via
transitive includes, but it doesn't work on libc++ systems, as reported
downstream in Gentoo at https://bugs.gentoo.org/933120.
2024-06-02 00:25:26 +01:00
l10n daemon script a1f30edaf6 GIT_SILENT Sync po/docbooks with svn 2024-06-01 01:25:57 +00:00
l10n daemon script e84ca82c9a SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-06-01 01:18:54 +00:00
David Edmundson f700de56f8 core: Disable Qt RHI pipeline cache
The Qt pipeline cache causes a disk sync on every load and save of a
QQuickWindow. This causes a stutter under high disk usage.

The gains from this cache are minimal on our simple scenes on PC
hardware. Especially given mesa has it's own cache, profiling on my
personal laptop showed the pipeline as being 0ms.

There is an upstream patch at
https://codereview.qt-project.org/c/qt/qtdeclarative/+/564411 .
QSaveFile still has a sync, but that should only be hit for the first
non-cached run. I'm also adding a flag to QSaveFile to fix the QML cache
and first run case. 

Tested via running kwin with `strace -e
inject=fdatasync:delay_enter=10000000` to simulate a slow flush.

BUG: 487043
2024-05-31 15:28:09 +00:00
Vlad Zahorodnii 40839e3347 plugins/startupfeedback: Don't show bouncing cursor if cursor is invisible
BUG: 482566
2024-05-31 15:00:10 +00:00
Vlad Zahorodnii 2ca81bbe32 kcms/decoration: Use "grab" and "grabbing" cursor to communicate dnd state 2024-05-31 14:24:51 +00:00
Vlad Zahorodnii d7772031b1 Use "grabbing" cursor during interactive move
BUG: 483305
2024-05-31 14:24:51 +00:00
Xaver Hugl 1195936a68 opengl/openglcontext: correct the check for glMapBufferRange support
It's also supported with OpenGL ES 3.0
2024-05-31 12:11:39 +00:00
Xaver Hugl f4f0660dbb opengl/openglcontext: correct the check for buffer storage support
BUG: 487777
2024-05-31 12:11:39 +00:00
l10n daemon script 4ab679f2fd GIT_SILENT Sync po/docbooks with svn 2024-05-31 01:37:59 +00:00
David Edmundson 5d90f232bd effects: Disable showing desktop when starting any fullscreen effect
Fullscreen effects typically will show all the windows, when the effect
ends having the windows disappear doesn't really work.
From a user point of view any full screen effect is a new task, we want
to cancel any preivous task.

BUG: 487299
2024-05-30 08:06:56 +00:00
l10n daemon script 0ce7a40850 GIT_SILENT Sync po/docbooks with svn 2024-05-30 01:30:05 +00:00
Xaver Hugl 2cf36e640f core/renderloop: honor repaint scheduling requests from effects with vrr
Until effects are converted to schedule repaints on the item they're modifying,
we need to allow repaint scheduling from nullptr items, and handle repaints on
the (cursor) render layers to still be filtered out

BUG: 487480
2024-05-29 12:46:26 +00:00
David Redondo cefcdf7db5 Unset suspended state of windows that are marked for offscreen rendering
Otherwise some clients will not render anything even though we are
sending frame callbacks.
BUG:487702
FIXED-IN:6.1
2024-05-29 12:02:01 +00:00
Vlad Zahorodnii 64ddeff3bd Forbid activating override redirect windows
BUG: 486026
2024-05-29 10:51:23 +00:00
Łukasz Patron ce57af62ec scripting: Filter out windows with isClient=false in WindowModel
These windows render as empty boxes and opening them crashes the KWin.
Also, the same check is present in TabBox.

BUG: 486182
2024-05-29 10:45:14 +00:00
David Redondo ba7b23c41d autotests/test_xkb: Do not expect fail in fixed Qt versions 2024-05-29 12:12:42 +02:00
l10n daemon script 59f1f7ee9f GIT_SILENT Sync po/docbooks with svn 2024-05-29 01:44:10 +00:00
l10n daemon script c164ff467c SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-29 01:17:54 +00:00
David Redondo ec1ebb6fb8 Use di_info_get_serial to fetch the serial number from EDID
This will also look at the "product serial string" in addition
to the actual serial number. The former is what we use elsewhere
in Plasma like the kscreen kcm.
BUG:485015
FIXED-IN:6.1
2024-05-28 13:19:59 +00:00
Vlad Zahorodnii 1d05f98e4b qpa: Guard against failing to get a swapchain in platform opengl context
QOpenGLContextPrivate::setCurrentContext() was dropped because the
platform opengl context no longer uses QOpenGLFramebufferObject, which
needed QOpenGLContext::currentContext().
2024-05-28 12:51:10 +00:00
l10n daemon script 6a59c4defc GIT_SILENT Sync po/docbooks with svn 2024-05-28 01:26:54 +00:00
Xaver Hugl 804ecb0e22 core/renderloop: make repaint scheduling more robust against wrong render time estimations
When the render time estimation is much higher than the real render time, and triple buffering is
enabled, the previous logic would schedule frames multiple vblanks in advance, which could drop the
effective refresh rate by more than is necessary. This commit limits it to the second vblank after
the current time, which ensures that we hit the full refresh rate even when render time prediction
is wrong
2024-05-28 01:23:11 +02:00
Xaver Hugl 97c1d335e5 backends/drm: delay atomic commits until the time they're meant for
Otherwise, if render time prediction and actual render time are very different,
a lot of frames get dropped and in some cases more frames than is useful are
rendered, creating stutter instead of only unnecessary latency

BUG: 487605
2024-05-28 01:23:11 +02:00
Yifan Zhu 09d4f3fda3 xkb: support converting Qt keys to keysyms
QXkbCommon::toKeysym doesn't correctly handle the case where a single Qt
key map to multiple keysyms.

BUG: 482847
2024-05-27 18:27:33 +00:00
Vlad Zahorodnii b0ccacc983 Avoid using QMouseEvent in processDecorationButtonPress()
BUG: 480864
2024-05-27 17:32:14 +00:00
Vlad Zahorodnii fa351403ef Ignore button release events when double clicking
One could check that the double click timer is still active.
2024-05-27 17:32:14 +00:00
Vlad Zahorodnii a76ae07ee1 Revert "effects: Use unique device for replaying events to QQuickView"
It broke overview.

This reverts commit 862dae455a.
2024-05-27 17:32:14 +00:00
Vlad Zahorodnii 447994581b xwayland: Fix dnd position with hidpi 2024-05-27 16:21:01 +00:00
Xaver Hugl 5e122cb6c0 wayland/linuxdrmsyncobjv1: don't emit a protocol error for unmapping a surface 2024-05-27 15:14:27 +02:00
Alois Wohlschlager ae376766ef window: consistently use normal keyboard modifiers for tiling
A bad rebase in commit 43e5f17547 inadvertedly
reverted half of the fix from 1f1c54ca6c. As a
result, custom tiling would appear broken again for keyboard layouts where caps
lock is achieved by pressing both shift keys at the same time. Reapply the half
of the fix that went missing.
2024-05-27 09:56:31 +00:00
David Edmundson 862dae455a effects: Use unique device for replaying events to QQuickView
When a new mouse event is made it updates the global position of that
device. This causes issues if a mouse event is forwarded with an
adjusted position then used afterwards.

`QPointingDevice::primaryPointingDevice` creates a new pointer device
internally if the seat name does not exist. It is then shared between
future usages.

BUG: 480864
2024-05-27 08:55:27 +00:00
l10n daemon script d0e07ba3e8 GIT_SILENT Sync po/docbooks with svn 2024-05-27 01:29:46 +00:00
l10n daemon script 669e90325c GIT_SILENT Sync po/docbooks with svn 2024-05-26 01:26:01 +00:00
l10n daemon script 9e3db94718 GIT_SILENT Sync po/docbooks with svn 2024-05-25 01:29:28 +00:00
l10n daemon script 2099409189 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-25 01:18:37 +00:00
Xaver Hugl 3f0627172d cmake: bump required plasma-wayland-protocols version 2024-05-24 20:53:02 +00:00
David Edmundson 73425b13a4 autotests: Improve autotests for window scaling 2024-05-24 18:23:05 +00:00
Vlad Zahorodnii cc031839db Properly update move resize output when the move resize geometry changes
setMoveResizeGeometry() should be used so the preferred buffer scale and
transform are updated.
2024-05-24 21:10:21 +03:00
Vlad Zahorodnii e678ebef29 3rdparty: Reformat xcursor.{h,c} 2024-05-24 16:21:36 +00:00
Vlad Zahorodnii 586a775d5b utils: Load Xcursor themes using QFile
This improves the integration of the XcursorTheme class with the rest of
the Qt ecosystem, for example it should be possible to load cursor themes
from Qt resources.
2024-05-24 16:21:36 +00:00
Vlad Zahorodnii d655b5a994 3rdparty: Drop xcursor write hook
It's unused.
2024-05-24 16:21:36 +00:00
Xaver Hugl 40a9f08dd3 backends/drm: allow up to two composited frames to be pending at the same time
This should improve responsiveness on setups where rendering each frame takes longer
than the refresh cycle of the display.

BUG: 452119
CCBUG: 454098
2024-05-24 17:32:20 +02:00
Xaver Hugl 1e3d50e3ff core/renderloop: support triple buffering
When rendering a frame takes longer than a refresh period, allow rendering to
happen before the previous frame is presented. This way the effective refresh
rate is increased, without increasing latency or impacting frame pacing more
than necessary
2024-05-24 17:32:20 +02:00
Xaver Hugl 0c4f46739d backends/drm: store OutputFrames in the commit objects
That way, multiple frames in flight can be tracked correctly
2024-05-24 17:32:20 +02:00
Xaver Hugl df9b0bd8f0 backends: move output refresh duration to compositor 2024-05-24 17:32:20 +02:00
Jonathan Riddell 3ebbe28b64 update version for new release 2024-05-24 16:14:01 +01:00
David Edmundson 5362105f27 plugins/desktopchangeosd: Port to simpler PlasmaWindow
Plasma::Dialog contains logic that we don't want for a kwin window and
is considered deprecated. Dialog uses the width of the main item which
results in an unavoidable binding loop.

PlasmaWindow allows us to propagate implicit sizes upwards correctly.

BUG: 420757
2024-05-24 12:51:46 +00:00
Jonathan Riddell 572e07b130 Update Qt version requirement to 6.6.0
GIT_SILENT
2024-05-24 13:11:44 +01:00
Jonathan Riddell 01d3f22633 update version for new release 2024-05-24 12:32:27 +01:00
Jonathan Riddell 5e79956933 Update Qt version requirement to 6.7.0
GIT_SILENT
2024-05-24 11:22:28 +01:00
Jonathan Riddell 1ab1a5f297 Update Frameworks version requirement to 6.2.0
GIT_SILENT
2024-05-24 11:22:28 +01:00
l10n daemon script 14bbe38b31 GIT_SILENT Sync po/docbooks with svn 2024-05-24 01:31:11 +00:00
Vlad Zahorodnii 7b547bf61d Apply 1 suggestion(s) to 1 file(s) 2024-05-23 15:01:42 +00:00
David Edmundson e7e6dee79b xwayland: Update Qt key enums 2024-05-23 15:01:37 +00:00
Vlad Zahorodnii dd36387c1f Pass all key events to kglobalacceld
kglobalacceld needs to process all key events to detect whether
a modifier only shortcut has been triggered.

On the other hand, when using Meta+Space keyboard layout switching
shortcut, we will get the following key syms (not native scan codes)

- press meta: Meta_L
- press spacebar: Super_L
- release meta: Meta_L
- release spacebar: Space

The fact that xkb reports Super_L when the spacebar is pressed trips
modifier only shortcut detection in kglobalacceld, and it's likely
that kickoff will open after pressing Meta+Space to switch the keyboard
layout.

In order to prevent that, kglobalacceld needs to see all key events
even with invalid key codes. As an alternative, we could explore the
possibility of using native scan codes instead of mapping keysyms to
key codes, but that needs thorough analysis, which we have no time
for.

The check was introduced in 4403e86acc.
After that check is removed, the test still passes.
2024-05-23 10:58:16 +00:00
David Redondo d737d1dbcb Add support for input capturing for the portal
This is the backend that will be used by the portal to enable
the functionality of the input capture portal.
When the cursor tries to move out of the workarea across a barrier
that the portal registered all input events are filtered out
and forwarded via eis.
2024-05-23 09:17:14 +00:00
David Edmundson 84633badc7 effects: Support dynamic delegate changes whilst running
The cube effect has a placeholder which can update the delegate at
runtime. There's an "add desktop" button which then might give us 3
virtual desktops. As a general rule any setter exposed via a declarative
API should always perform the setting.

Reloading has to be delayed because otherwise we unload the caller.

BUG: 486839
2024-05-23 12:00:56 +03:00
Vlad Zahorodnii 29122f1df6 Improve integration of preferred buffer scale with xdg shell configure events
With this change the preferred buffer scale, transform and color
description properties will be latched to xdg shell configure events.

This should ensure that the clients are told the preferred buffer
scale before the first configure events.
2024-05-23 08:15:29 +00:00
l10n daemon script 0e934273bb GIT_SILENT Sync po/docbooks with svn 2024-05-23 01:28:27 +00:00
Xaver Hugl b232e80319 backends/drm: don't update outputs from within DrmGpu
DrmBackend::updateOutputs may delete DrmGpu objects, so calling it from within
a DrmGpu method can cause problems

BUG: 483008
FIXED-IN: 6.1.0
2024-05-22 20:33:51 +00:00
Xaver Hugl 1866e70fe3 core/renderjournal: tweak render time prediction to reduce latency slower
This makes it a bit more conservative for reducing latency, which decreases the
amount of dropped frames in desktop usage a lot (by 13x on my desktop, 2x on my laptop)
2024-05-22 17:18:11 +02:00
David Edmundson c65f01e5dc xwayland: Avoid forwarding spurious mouse events
pointerEvents contain all motion events, the xwayland filter is only
concerned with forwarding clicks. Right now we would update an invalid
button state constantly. It did nothing harmful but was still a bit
silly.
2024-05-22 07:32:36 +00:00
l10n daemon script 7ba6c08fa7 GIT_SILENT Sync po/docbooks with svn 2024-05-22 01:30:43 +00:00
Xaver Hugl 2e9e6893bb wayland: port linux drm syncobj from RenderBackend to DrmDevice 2024-05-22 00:26:14 +02:00
Xaver Hugl 0f41239515 waylandserver: set render backend for linuxdrmsyncobj directly
The code would previously never set the render backend, causing the use of explicit sync
to fail

BUG: 486391
2024-05-22 00:26:14 +02:00
Xaver Hugl 3465ecac16 wayland: implement plasma window management v17
This fixes plasmashell crashing because of the stacking order string exceeding
the size of a Wayland message

CCBUG: 479492
2024-05-21 17:48:55 +02:00
Jakub Piecuch 7bf40c3501 utils/edid: use detailed timings to compute physical screen size
An EDID can contain zero or more detailed timing definitions, which can contain
more precise physical dimensions of the screen (in millimeters, as opposed to
centimeters).

The Xorg server has similar logic for determining the physical screen size from
the EDID: pick the first sane size from the detailed timing definitions, and
fall back to the screen size given in the "Basic Display Parameters & Features"
section.

BUG: 486585
2024-05-21 11:22:51 +00:00
l10n daemon script 79357db409 GIT_SILENT Sync po/docbooks with svn 2024-05-21 01:33:01 +00:00
Nate Graham dcd2f7b15a plugins/tileseditor: clarify wording in "split the view" buttons
Apparently people have differing ideas of what "vertically" and
"horizontally" mean, and some feel that this wording contradicts the
icon.

That's not accurate, but the wording is admittedly a little a bit
ambiguous. We can clarify this by using super duper explicit
terminology that always matches the icon.

BUG: 475103
FIXED-IN: 6.1
2024-05-20 15:58:01 +00:00
Volodymyr Zolotopupov 202356ba89 plugins/screenshot: Snap pixel grid for rectangular screenshots
To prevent blurring with fractional scaling
2024-05-20 14:23:38 +00:00
Volodymyr Zolotopupov f4232bc391 plugins/screenshot: Round texture size
To prevent window screenshot blurring with fractional scaling
2024-05-20 14:23:38 +00:00
Vlad Zahorodnii 1ca7524853 plugins/nightlight: Correct time check in currentTargetTemp() 2024-05-20 14:09:15 +00:00
Vlad Zahorodnii bc52189e20 plugins/nightlight: Remove unused typedef 2024-05-20 14:09:15 +00:00
Vlad Zahorodnii 1d9824d0a2 plugins/nightlight: Clean up the slow update code path 2024-05-20 14:09:15 +00:00
Vlad Zahorodnii 7880f879a3 plugins/nightlight: Make the slow transition more robust to fuzzy time values
If the slow transition is scheduled slightly earlier before m_next.first,
don't skip the "m_prev.first <= todayNow && todayNow <= m_prev.second" branch.

Also explicitly handle the case when resetSlowUpdateTimers() gets called
after m_prev.second, i.e. the previous transition has finished running.
2024-05-20 14:09:15 +00:00
Xaver Hugl bbf4f46b28 compositor_wayland: properly handle moving the cursor plane failing
On test failure, the plane has to be disabled or future atomic tests fail

BUG: 487037
2024-05-20 11:14:01 +00:00
l10n daemon script f5ac8968d8 GIT_SILENT Sync po/docbooks with svn 2024-05-20 01:28:06 +00:00
l10n daemon script aae9eb9c65 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-20 01:18:51 +00:00
l10n daemon script c919c91063 GIT_SILENT Sync po/docbooks with svn 2024-05-19 01:29:43 +00:00
Xaver Hugl 35ce8a6208 outputconfigurationstore: increase the default SDR brightness
200 nits is a bit dark in most situations, so this switches the default SDR
brightness to up to 500 nits (depending on what the screen supports)
2024-05-18 20:37:07 +00:00
l10n daemon script 22dffa4714 GIT_SILENT Sync po/docbooks with svn 2024-05-18 01:28:37 +00:00
Vlad Zahorodnii ebe6f58d9a backends/wayland: Avoid attaching null buffer
Otherwise the window will be unmapped.
2024-05-17 11:20:35 +00:00
Ambareesh Balaji 0b2596b604 plugins/nightlight: handle imprecise timers
Due to QTimer sometimes firing a tad bit early, transitions get skipped, or we
end up in the "Error in time calculation" branch. This commit improves timer
handling to avoid this.
2024-05-17 09:46:34 +00:00
Niccolò Venerandi b59ba5b9b7 Do not snap to windows of the Dock type
We do not snap to docks (i.e. panels) since the ones we
actually want to snap to (i.e. always visible ones) will
restrict the workspace area, and the window will snap to
that, effectively snapping to the panel too. Explicitedly
avoiding panel snapping solves any possible issue of
floating panels, since they change their size when a window
gets near them.
2024-05-17 09:17:24 +00:00
l10n daemon script de88370577 GIT_SILENT Sync po/docbooks with svn 2024-05-17 01:28:13 +00:00
Vlad Zahorodnii fa895828de plugins/screencast: Cleanup buildFormats()
The fixate branch makes sense only in case dmabuf is available.
2024-05-16 13:01:14 +00:00
Vlad Zahorodnii 9af15a979d backends/wayland: Check whether it's possible to create a swapchain with the given format+modifier
BUG: 485496
2024-05-16 12:44:21 +00:00
David Edmundson df60eef0db wayland: Send dnd_cancelled to source before data_device.leave to target
Otherwise it is harder for clients to detect an actual cancellation when
dragging to itself.
2024-05-16 10:55:43 +00:00
Vlad Zahorodnii 856925bcc3 wayland: Print error code if accept fails for security context's listen fd 2024-05-16 10:32:38 +00:00
Vlad Zahorodnii de15b87ea7 wayland: Fix security context failing to create a client
wl_client_create() can fail.
2024-05-16 09:44:56 +00:00
Vlad Zahorodnii 982a2e3a37 wayland: Lower severity of a log message about unknown uuid
The communication between the compositor and plasmashell is asynchronous.
It's possible that plasma can call get_window_by_uuid before it is notified
that the window has been closed. There's no any way around with the
current design of the protocol. So printing a warning message is
unjustified. This fixes kwin's logs being full of "could not find window"
warning messages.
2024-05-16 08:54:01 +00:00
David Edmundson 711c5bb43f wayland: send dndFinished to source if target fails to do so
After receiving a drop a client should call data_offer.finish
to tell the source it's done using the drop.

A client could delete an offer after drop before calling finish.

This can happen with misbehaving/buggy or malicious Wayland clients.
A real case was found in the wild with Chromium, as described in the
linked bug.

In this situation we should let the source know the dnd is finished
as there are no other transfers than can take place.

We don't want to universally send this in all data offer destructors
only, offers that are deleted post drop so the flag on the source is
exposed.

BUG: 482142
2024-05-16 08:23:00 +00:00
Vlad Zahorodnii 7710b44f1d plugins/screencast: Specify the effective drm format
Currently, the dmabuf format is hardcoded to DRM_FORMAT_ARGB8888, but
testCreateDmabuf() uses m_drmFormat.

Furthermore, if the shm buffers are used, it's preferred to use a buffer
format that's friendly to QImage and OpenGL, which is DRM_FORMAT_ARGB8888.
2024-05-16 10:59:35 +03:00
Vlad Zahorodnii 54f7079100 plugins/screencast: Use buffer format and modifier as specified in spa_video_info_raw
It appears like pipewire can ask kwin to allocate a drm buffer even
though m_dmabufParams has been reset. It's underspecified when pipewire
will start requesting new buffers after changing the stream params. So
use the last reported video info to allocate buffers. If even it is wrong,
then it's an issue somewhere in pipewire.
2024-05-16 07:38:38 +00:00
l10n daemon script 47484bb141 GIT_SILENT Sync po/docbooks with svn 2024-05-16 01:44:30 +00:00
Pau López 96c0d800b8 docs/contributing: Update windowswitchers location 2024-05-15 18:36:46 +02:00
Nate Graham 29a93a2e57 plugins/slidingpopups: use standard duration values
Right now the opening duration is 150ms, and the closing duration is
250ms. Neither are standard durations we use elsewhere, and it's also a
bit odd to be slower to close than to open--at least from a visual
perspective.

The average of these value happens to be 200ms, which happily is the
exact value of Kirigami.Units.longDuration.

As such, use that value instead, in the interests of visual consistency.
2024-05-15 09:06:05 -06:00
Vlad Zahorodnii 77794e1333 plugins/screencast: Call pw_deinit()
The constructor has a pw_init() function call, but the destructor lacks
the matching pw_deinit().
2024-05-15 12:16:40 +00:00
David Redondo 805435d157 xwayland: Enable xtest libei integration
Enabling this feature makes Xwayland send xtest events via
the remote desktop portal and libei.
XWayland will create a new session for each X client (it keeps
contexts around and reuses them if the cmdline matches, so not
every xdotool invocation produces a new portal prompt).
2024-05-15 09:31:53 +00:00
Vlad Zahorodnii 4ebb21e8c3 plugins/screencast: Refuse creating a dmabuf buffer if n_datas is wrong
n_datas must match the plane count in the graphics buffer. But apparently
pw buffers with wrong n_datas can still slip through somehow. It makes
the screen cast stream crash when filling in buffer data.

The crash is hard to reproduce, but on the other hand, according to
sentry, a substantial number of users is affected by this issue.

Taking the defensive approach is not great, there will likely be other
issues with screencasting, but it seems like the only feasible option
so far. Broken streams is better than kwin crashing. It also wouldn't
hurt to add some warning messages, that will be done in a follow up MR.
2024-05-15 08:58:27 +00:00
Vlad Zahorodnii 886f0e852b Disconnect Workspace::outputsChanged from InputPanelV1Window when it's closed
Otherwise the input panel window can be repositioned after it's closed,
which will crash.
2024-05-15 08:51:00 +00:00
l10n daemon script 0ce58c7cbf GIT_SILENT Sync po/docbooks with svn 2024-05-15 01:28:14 +00:00
Xaver Hugl 9fef6380d4 backends/drm: adapt the color factors to the target colorspace
Otherwise the effect of night color is much bigger in larger colorspaces.
This is mostly a workaround, but the better solution (adapting the color
temperature of the colorspace instead) will have to wait for 6.1

BUG: 483801
FIXED-IN: 6.0.5
2024-05-14 14:47:12 +02:00
Xaver Hugl e04ec0ce29 opengl: make GLRenderTimeQuery::query non-destructive 2024-05-14 12:33:08 +00:00
Xaver Hugl b167d1f56a core/renderbackend: improve handling of multiple render time queries
With multiple OpenGL render time queries, you can't just add the render
times together, because the GPUs execute commands asynchronously and you
may get a far too big result this way. Instead, this converts all timestamps
to steady_clock and correctly calculates the actual total time spent rendering
with the first and last timestamp.
2024-05-14 12:33:08 +00:00
Xaver Hugl 8d5ebb5e15 backends/drm: relax direct scanout rules for color management
The GL renderer currently doesn't apply any transformations except clipping,
so allowing direct scanout is okay as long as colorimetry and transfer
function match.
2024-05-14 08:08:08 +00:00
Xaver Hugl 22d0631b1b backends/drm: add support for an HDR brightness setting 2024-05-14 09:51:59 +02:00
l10n daemon script 589479c24a GIT_SILENT Sync po/docbooks with svn 2024-05-14 01:30:06 +00:00
Fushan Wen 7a2e6bb58e Constify Qt containers passed to ranges
This constifies a few mutable Qt containers passed to std::ranges to improve the efficiency.
2024-05-13 19:50:25 +00:00
Ismael Asensio d2d92cdfd2 rules/RuleBook: Optimize saving discarded rules to config
After porting to KConfigXT settings some time ago, there was still an
inefficient and error-prone codepath between the `RuleBook` (which keeps
the runtime list of `Rules`) and the `RuleBookSettings` (responsible for
config reads and saves), in the form of the `setRules()` method.

We can eliminate the `setRules()` codepath, reducing unnecessary
runtime process and file access operations, and instead:
- Keep track of the config `id` in the `Rules` objects
- Keep a single `RuleBookSettings` object as a member
- Modify or delete the discarded rules settings directly
- Save when necessary

This also fixes two bugs/pitfalls of the previous solution:
- the config group id for each rule is now preserved instead of creating
  new ones
- no leftovers on the config file for the discarded groups and entries

Setting custom configs for the integration tests still works unchanged.

BUG: 446381
FIXED-IN: 6.1
2024-05-13 20:18:09 +02:00
Xaver Hugl a3c763b8ef backends/drm: ensure that ctm and gamma_lut are always unset with color management
Otherwise night color will be applied twice
2024-05-13 08:32:03 +00:00
Xaver Hugl dcda15e5e3 core/renderlayer: don't implicitly truncate width and height of the geometry
Otherwise, repaint regions will be limited to a pixel less than it should be
in some cases

BUG: 482987
FIXED-IN: 6.0.5
2024-05-13 08:07:38 +00:00
Jan Grulich 653938e456 plugins/screencast: fix damage region position
Damage reported from the output is output-local and therefore doesn't
need to be translated.

I tested this with Chromium, where the damage region on my 3-monitor
setup was always -4k something on the right screen, -2k on the middle
one and correct on the left screen. With this change I can confirm that
the position is now correctly reported for the right screen.
2024-05-13 09:52:27 +02:00
l10n daemon script 26a0038d0c GIT_SILENT Sync po/docbooks with svn 2024-05-13 01:31:07 +00:00
Ismael Asensio b1ed2bb3e7 kcms/rules: Handle Escape key to exit Export mode
This avoids unexpectedly exiting the whole KCM when just trying
to cancel the Export mode (based on a true story)
2024-05-12 23:38:49 +02:00
l10n daemon script 200e46bec6 GIT_SILENT Sync po/docbooks with svn 2024-05-12 01:36:34 +00:00
l10n daemon script 325daecace SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-12 01:20:22 +00:00
Nate Graham 43c21c390b kcms/desktop: re-add separator line between scrollview and controls
The extraFooterTopPadding property used to do this is now somewhat
incoherent, but we're stuck with it until KF7.
2024-05-11 14:19:57 -06:00
David Edmundson 013e69988f Reconnect Pipewire on Failure
Our connection to pipewire can go down if the pipewire service restarts, it's on us to tear down and reconnect.
To ensure Streams can tear down on their own properly, this patch leaves existing streams with a defunct connection
and creates a new connection for new streams, sharing the connection between them.

This also implicitly fixes the case for distributions without working socket activation.

BUG: 483137
2024-05-10 14:35:11 +00:00
Kai Uwe Broulik ba8c52564e workspace: Don't activate desktop window when it gets added
Unless there is no focus window. Matches X11 behavior.

Otherwise (re)starting plasmashell would pull focus away from
whatever window is currently focussed.
2024-05-10 09:51:56 +02:00
l10n daemon script ef41fa8e8f GIT_SILENT Sync po/docbooks with svn 2024-05-10 01:27:48 +00:00
l10n daemon script 4c144958c7 GIT_SILENT Sync po/docbooks with svn 2024-05-09 01:33:27 +00:00
l10n daemon script 2dd71603dd SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-09 01:18:28 +00:00
l10n daemon script b2e1ede6e5 GIT_SILENT Sync po/docbooks with svn 2024-05-08 01:33:48 +00:00
l10n daemon script ea5b79dbf6 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-05-08 01:18:43 +00:00
Xaver Hugl 01f3f185d8 backends/drm: allow using the EDID primaries and whitepoint as the color profile
They're usually close enough, so this allows users with wide color gamut screens to
get non-oversaturated colors without having to profile the screen
2024-05-07 13:52:35 +00:00
Pau López c41315564c effect: Fix clip region in AnimationEffect 2024-05-07 10:45:00 +00:00
l10n daemon script 46f5951820 GIT_SILENT Sync po/docbooks with svn 2024-05-07 01:27:36 +00:00
Natalie Clarius 6ec7e919fb plugins/nightlight: clarify strings for inhibition
To clarify that the toggle action merely temporarily disables the blue light filter, rather than turning the schedule off permanently like the "Disbaled" setting in the KCM does, use "suspend/resume" terminology instead of "off/on" in the keyboard shortcut and OSD.

Follow-up on plasma-workspace!4262

CCBUG: 486647
2024-05-07 01:14:30 +02:00
Aleix Pol Gonzalez 24807dfa50 backends/drm: Also get the range for signed range properties
Otherwise these default to -1 which isn't helpful

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-05-06 16:06:32 +00:00
Aleix Pol Gonzalez d55fa39ebf backends/drm: Add a check for ranged properties
Include a warning if we are ever setting an invalid value, this can save
some of us quite some time in the future, since failing to fall in the
range makes the whole pipeline become rejected.
2024-05-06 08:47:41 +00:00
Aleix Pol Gonzalez 0db46e3966 backends/drm: Make sure we respect the alpha property range
This is in part a workaround for an issue in Qualcomm drivers where the
range for alpha is 0-UINT8_MAX (255). We were setting a value too big
and this would make the whole pipeline fail.

Instead set the top of the property range which is what we were doing
after all, resulting in more explicit code to what we were trying to
achieve.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-05-06 08:47:41 +00:00
l10n daemon script b3f7924539 GIT_SILENT Sync po/docbooks with svn 2024-05-06 01:28:47 +00:00
l10n daemon script cac430fdbb GIT_SILENT Sync po/docbooks with svn 2024-05-04 01:37:13 +00:00
Vyacheslav Mayorov 4e01d2c8b7 workspace: fix syncing the stacking order with Xorg
Deleted windows have frameId zero, which makes Xorg stack other windows
below the bottom-most window instead of the correct one. To avoid that,
filter out deleted windows in Workspace::propagateWindows.

BUG: 478556
2024-05-03 20:00:19 +03:00
Xaver Hugl 33fe211471 placementtracker: fix restoring of windows in custom tiles
There were two problems preventing it from working:
1. The placement tracker didn't handle them correctly; now it sets the custom tile mode
after moving the window to its location
2. The window code used `output()` instead of `moveResizeOutput()`, which means when KWin
just moved the window to a different screen and immediately changes the tile mode
afterwards, it would tile the window on the wrong output
2024-05-03 16:47:47 +02:00
Xaver Hugl 14c08422ca placementtracker: fix quick tiled windows not being restored correctly
There were two problems:
1. Workspace interacted with the tile mode of windows before inhibiting
the placement tracker, so the wrong window state was stored in the placement
tracker
2. Window::setQuickTileMode is unintuitive and has some undesired side effects,
meant to handle quick tiling with keyboard shortcuts and by dragging the
window with a mouse specifically. This commit just works around that by
un-setting the tile mode first

BUG: 461886
2024-05-03 15:58:17 +02:00
Xaver Hugl df9f8f8346 fix vertically maximized windows sometimes being moved out of the screen
...and add a test for it

BUG: 476037
2024-05-03 13:45:18 +00:00
Xaver Hugl fb28d75ad8 placementtracker: fix vertically maximized windows being misplaced
...and extend the autotest to cover that situation.

CCBUG: 476037
2024-05-03 13:45:18 +00:00
l10n daemon script 6a44cce527 GIT_SILENT Sync po/docbooks with svn 2024-05-03 01:26:34 +00:00
Xaver Hugl 219f110093 backends: move render time queries into OutputFrame
This way, multiple OutputFrames can be pending at the same time, without
interfering in each other's render time queries
2024-05-02 13:03:27 +00:00
Vlad Zahorodnii 4470e82baa xwayland: Prevent kwin crashing when an xwayland socket cannot be created
If the X11 socket directory has wrong permissions, XwaylandSocket will
refuse to create sockets. Crashing in that case is undesired, just continue
executing without X.
2024-05-02 12:55:47 +00:00
David Redondo c8de1aa677 Revert "Disable freebsd ci"
This reverts commit 57a79608da.
2024-05-02 09:39:13 +00:00
l10n daemon script 11cd27c793 GIT_SILENT Sync po/docbooks with svn 2024-05-01 01:24:50 +00:00
Arsen Arsenović 5980945ee4
dpmsinputeventfilter: Don't wake screens up on warp events
As pointer warps are not user interactions, they should not wake screens
up.

BUG: 480026
2024-04-30 19:01:15 +02:00
Arsen Arsenović 38c4980b0d
backends/drm: Prevent "recently disconnected" screen wakeup more aggressively
It seems that, on some systems (such as on mine), 1s is not long enough
for a spurious disconnect and reconnect to happen.  2s seems enough,
however, while still likely not being long enough to cause user
confusion.

BUG: 480026
2024-04-30 19:01:11 +02:00
Vlad Zahorodnii 6acc652487 Rework how geometry updates blocking is handled in X11Window
Process the geometry update as usual but just avoid confuguring the x
windows. It simplifies the implementation of the move resize function
and makes it more refactorable.
2024-04-30 14:28:27 +00:00
Vlad Zahorodnii 801fecf821 Port some X11Window code away from GeometryUpdatesBlocker
GeometryUpdatesBlocker is unnecessary. One could just compute the
final geometry on a side and then issue one moveResize() rather than
call move(); resize(); moveResize() and so on in a sequence. The
advantage of the former approach over the latter is that the code
can be a bit more straightforward.
2024-04-30 14:20:59 +00:00
Vlad Zahorodnii 8f0425d91c Remove geometry updates blockers in X11Window teardown code
When a window is closed, its geometry should not change, so the geometry
updates blockers are not needed. There's also no code that could potentially
change the geometry in destroyWindow() or releaseWindow().
2024-04-30 14:06:49 +00:00
Xaver Hugl 93d810aaad backends/drm: unify primary and cursor plane layers
Drm planes aren't specialized enough to need completely separate code paths to
handle them, and having one class for all layers makes it easier to add support
for overlay planes
2024-04-30 13:43:36 +00:00
Xaver Hugl a7e26a5770 backends/wayland: remove m_output member
It's in the base class now
2024-04-30 11:45:57 +00:00
Xaver Hugl b976c274fd workspace: don't touch output configs on Xorg
It sets some output properties that don't match what Xorg knows about the outputs,
which may cause problems

CCBUG: 477268
2024-04-30 11:38:27 +00:00
l10n daemon script aabadcee6d GIT_SILENT Sync po/docbooks with svn 2024-04-30 01:26:46 +00:00
Aleix Pol Gonzalez 04643fa3d8 Workspace: only calculate the clientArea for the wayland window when necessary
No need to calculate it just to discard it.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-04-29 21:41:49 +00:00
Aleix Pol Gonzalez 7916352f5b wayland: skip the outputs refresh if they didn't change
We have a bunch of logic in there that is effectively no-op if the
values don't change. We might as well skip it altogether and save some
code from being run to do nothing.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-04-29 21:41:49 +00:00
Vlad Zahorodnii cdbe119789 Make GeometryUpdatesBlocker X11-specific
It's used only by X11Window so move it there.
2024-04-29 17:58:05 +03:00
Vlad Zahorodnii b2193f370d Drop the remaining geometry updates blockers in Window
While these geometry updates blockers are used in functions that can
call moveResize() several times in a row, it's not critical.

On the other hand, by removing these blockers, no other core code is
going to rely on GeometryUpdatesBlocker, which opens us the future
opportunitinies to drop it and make geometry manipulation code simpler.
2024-04-29 14:40:16 +00:00
Xaver Hugl e4e5c52300 autotests/integration: clean up remnants of "active output follows mouse" setting in screenstest 2024-04-29 14:13:32 +00:00
Xaver Hugl 55e5d50074 autotests/integration: fix xdg shell test
It made now-invalid assumptions about how the active output is decided
2024-04-29 14:13:32 +00:00
Xaver Hugl 354a71855e workspace: unify active screen modes
Instead of the active screen being purely defined by the mouse position,
or purely defined by the active window and keyboard shortcuts, this changes
it to make the active screen all about the last user interaction. This should
work for most workflows without needing a setting to choose between two flawed
approaches.

BUG: 482865
BUG: 484902
BUG: 484902
2024-04-29 14:13:32 +00:00
Xaver Hugl 336b2fd2f6 backends/x11/standalone: remove the code that runs on return to the event loop
It's unclear why it would be needed
2024-04-29 14:13:32 +00:00
Xaver Hugl 26b15feb61 backends/x11/standalone: remove on-demand mouse polling
Instead, rely on XInput if available, and fall back to polling every 50ms if not
2024-04-29 14:13:32 +00:00
Xaver Hugl 20d5f9bc6e backends/drm: work around amdgpu bugs with DCC modifiers
See https://gitlab.freedesktop.org/mesa/mesa/-/issues/10875 for details. The workaround
can be disabled again with the KWIN_DRM_NO_DCC_WORKAROUND=1 environment variable
2024-04-29 13:16:20 +00:00
Xaver Hugl 445567f54e backends: move more things from output layers to kwin core 2024-04-29 15:02:33 +02:00
Xaver Hugl 3232a63ac1 backends: put damage into OutputFrame, instead of passing it into the direct scanout function
This way, damage tracking for screen casting is a bit more decoupled from the output layers, and
can actually work for direct scanout
2024-04-29 15:00:12 +02:00
Xaver Hugl 06ba20cc2e compositor: move the composite method into X11 and Wayland implementations
There's a bunch of differences between them, like direct scanout, adaptive sync, content type
and the actually painted output in the Wayland session but not on Xorg, so keeping them in one
method doesn't really make sense
2024-04-29 14:56:20 +02:00
l10n daemon script 6b5571b023 GIT_SILENT Sync po/docbooks with svn 2024-04-29 01:27:07 +00:00
Vlad Zahorodnii 55cccf3779 plugins/screencast: Rename "_damagedRegion" parameter 2024-04-28 18:40:21 +03:00
Vlad Zahorodnii ce9531d549 plugins/screencast: Throttle cursor updates 2024-04-28 18:40:21 +03:00
Vlad Zahorodnii 4e4186aa48 plugins/screencast: Negotiate a stream with new resolution right after enqueueing a buffer
This simplifies how the stream resolution is updated and removes a couple
more of failure points. This also appears to fix window screencasts freezing
in obs when those windows are resized.
2024-04-28 15:30:52 +00:00
Vlad Zahorodnii a2185d0836 plugins/screencast: Remove SPA_ID_INVALID check
This should be unnecessary or pipewire is broken beyond repair.
2024-04-28 15:23:14 +00:00
Vlad Zahorodnii 5c93c4251b Fix scanout device information when running nested kwin
Without it, there are issues with running Xwayland.
2024-04-28 15:15:20 +00:00
Justin Gatzen 75ab5b8353 backends/drm: fix udev event KWIN_DRM_DEVICES check
The existing check incorrectly compares the directory path only. This
allows unintended GPUs to be added when events occur for them, such
as with "udevadm trigger".

Update the check to use the full path.
2024-04-28 00:49:09 -04:00
l10n daemon script eb331a5df4 GIT_SILENT Sync po/docbooks with svn 2024-04-28 01:22:23 +00:00
Xaver Hugl 77cf49aa72 backends: refactor direct scanout and dmabuf feedback
This moves some of the responsbilities up in the stack, which simplifies
the backends and opens up some future possibilities like making direct scanout
work for non-surface items
2024-04-27 18:39:23 +00:00
l10n daemon script f5120e570b GIT_SILENT Sync po/docbooks with svn 2024-04-27 01:21:46 +00:00
Xaver Hugl 4037f093db plugins/qpa: support recovering from GPU resets
When the context experienced a GPU reset, the context and all swapchains need
to be recreated or there will be glitches
2024-04-26 14:27:07 +00:00
Vlad Zahorodnii e2611d710f plugins/screencast: Avoid resetting m_dmabufParams when resizing the stream
ScreenCastStream::onStreamAddBuffer() can be called before the stream
params are updated. This is problematic because that function expects a
valid m_dmabufParams.

The reason why m_dmabufParams is reset is to force the onStreamParamChanged()
function to check whether dmabufs can be still allocated with the new size.
2024-04-26 13:31:17 +00:00
Vlad Zahorodnii 31f80d18f2 wayland: Use xdg-dialog-v1 basename 2024-04-26 11:31:34 +00:00
David Redondo 2e92fca017 plugins/zoom: Center cursor on active screen on shortcut
BUG:435108
2024-04-26 10:41:49 +00:00
Vlad Zahorodnii 69b8c91655 Drop more (unnecessary) geometry updates blockers 2024-04-26 08:01:21 +00:00
Jakob Petsovits 351f613ef4 kcms/desktop: Expand button label from "Add" to "Add Desktop"
Also pull "Rows" out of the SpinBox into a dedicated label.

Both to address concerns "Add" about being misinterpreted as
"Add Row", given that the button to add a new virtual desktop
now sits right next to the row count spinner.
2024-04-26 00:00:11 -04:00
l10n daemon script e804b45d86 GIT_SILENT Sync po/docbooks with svn 2024-04-26 01:21:46 +00:00
Xaver Hugl 4dffc09aaa input: fix warning about nodiscard
std::any_of is used here in a way it was never meant to be used...
Instead just write out the loop
2024-04-25 19:24:19 +02:00
Vlad Zahorodnii 4a70793e2b Apply 1 suggestion(s) to 1 file(s) 2024-04-25 11:59:52 +00:00
Vlad Zahorodnii c404c76a8b plugins/screencast: Use steady clock to generate last sent timestamps
The steady clock is more preferred for generating timestamps because it
ensures that timestamps increase monotonically.

This fixes screencasts freezing in obs after changing the system time.
2024-04-25 14:52:30 +03:00
Vlad Zahorodnii 5ff705a124 plugins/screencast: Make frame throttling less strict
If the max framerate is 60Hz, currently, the frameInterval is going to
be 16.6ms. On the other hand, lastSentAgo is likely to be just 16ms. So
the frame throttling timer will be started just to wait less than a
millisecond.
2024-04-25 11:26:36 +00:00
Vlad Zahorodnii 24f4e268a9 plugins/screencast: Reset last sent timestamp when the stream resumes
Hypothetically, if the stream is paused and restarted in a short burst,
the frame throttling logic can be mis-triggered.
2024-04-25 11:16:59 +00:00
l10n daemon script 529ccbbd18 GIT_SILENT Sync po/docbooks with svn 2024-04-25 01:24:03 +00:00
Vlad Zahorodnii 068f1c2b54 Drop support for geometry updates blocking in wayland windows
Geometry updates are very asynchronous on wayland, the update blockers
should be redudant.
2024-04-24 14:39:09 +00:00
Vlad Zahorodnii 1470cfc790 Drop Window::keepInArea() overload with hidden moveResize()
Hidden moveResize() calls stand in the way of making geometry code
reusable or more refactorable. They also usually require one using
geometry update blockers, which are just a horrible concept because
they make geometry code unnecessarily more complex and add more failure
points.
2024-04-24 14:19:42 +00:00
Vlad Zahorodnii bc29e09d88 plugins/screenshot: Fix monitor screenshots on x11
After some refactoring changes, m_paintedScreen is always the first
output on x11, so it's no longer possible to take screenshots of other
outputs.
2024-04-24 14:01:12 +00:00
l10n daemon script 98aa044508 GIT_SILENT Sync po/docbooks with svn 2024-04-24 01:35:03 +00:00
Xaver Hugl 7949032411 outputconfigurationstore: don't overwrite output settings with kscreen configs
The existing code overwrites all per-output data with the config from KScreen
every time an output config is found that isn't in the KWin data base yet.
That causes problems like the scale being reset to 1.0 if the user logged
into Xorg before, or resetting it to whatever scale KScreen had saved on
Wayland, which isn't much better.

Instead of doing that, use the KScreen config as inspiration for some specific
output settings, instead of copying it outright. It's not ideal, but it's
better than overwriting settings the user has explicitly set up

BUG: 485353
2024-04-23 11:41:40 +00:00
l10n daemon script 38694bbe1a GIT_SILENT Sync po/docbooks with svn 2024-04-23 01:34:47 +00:00
Xaver Hugl c14c61f745 backends/drm: use dumb buffers for the cursor on virtual machines
Apparently not all VM drivers handle dmabufs on the cursor plane correctly

BUG: 485827
2024-04-22 12:33:42 +00:00
Vlad Zahorodnii 1f32171ac9 ci: Switch to suse_tumbleweed_qt67 2024-04-22 15:26:22 +03:00
l10n daemon script 1da8b61864 GIT_SILENT Sync po/docbooks with svn 2024-04-22 01:34:05 +00:00
Xaver Hugl fba948b39f scene/workspacescene: don't check direct scanout candidates for a pixmap
We don't need a pixmap for direct scanout, and the drm backend destroys the pixmap
when direct scanout is successful... so this check created a loop of direct scanout
working and not working, and worse, the client reallocating its buffers each time.

BUG: 485639
BUG: 485730
BUG: 485712
CCBUG: 477016
2024-04-19 23:06:56 +02:00
Xaver Hugl 48197a4f5b backends: don't duplicate file descriptors as often
Instead, move them when possible
2024-04-19 19:32:43 +00:00
l10n daemon script 7bd6b92110 GIT_SILENT Sync po/docbooks with svn 2024-04-19 01:29:00 +00:00
Xaver Hugl eed7943939 wayland/surface: fix the change signal for release points not being emitted 2024-04-17 13:59:43 +02:00
l10n daemon script 09b32a1e68 GIT_SILENT Sync po/docbooks with svn 2024-04-17 01:29:07 +00:00
Erik Kurzinger 9ca7b9b1cf core/syncobjtimeline: import release fence at correct timeline point
SyncTimeline::moveInto imports the provided fence to the syncobj by
calling drmSyncobjImportSyncFile. However, that function assumes the
syncobj a binary syncobj, meaning the fence will be imported at timeline
point 0, not at the intended timeline point.

Since there is no timeline equivalent of drmSyncobjImportSyncFile, to
achieve the correct behavior we create a temporary binary syncobj,
import the fence into that, and then use drmSyncobjTransfer to transfer
the fence to the desired timeline point on the destination syncobj.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2024-04-16 14:45:48 -07:00
Xaver Hugl 26afbfb6fa wayland_server: guard against DRM_IOCTL_SYNCOBJ_EVENTFD being broken
...either because it's not implemented, or because it's buggy.
2024-04-16 13:51:42 +02:00
Fabian Vogt 01d224fa22 Fall back to breeze_cursors if neither configured nor default can be loaded
Try harder to get some cursor theme loaded, otherwise the cursor is
invisible, which also makes it hard to fix the configuration.

Also add some warnings instead of failing silently.
2024-04-16 11:50:48 +02:00
l10n daemon script 98747246cd GIT_SILENT Sync po/docbooks with svn 2024-04-16 01:31:06 +00:00
David Edmundson 3ed535dd67 Remove superfluous wake in dpmsinputeventfilter destruction
Workspace already makes sure to only dynamically delete the
dpmsinputeventfilter if all screens are currently on. This line to wake
all screens is therefore redundant.

It's problematic as it can cause a crash on final teardown when
workspace is destroyed.

BUG: 484861
2024-04-15 22:03:51 +00:00
David Redondo bca99d0b4c Add missing license header
Amends 499d006e3a
GIT_SILENT
2024-04-15 16:13:00 +02:00
David Redondo 499d006e3a Add a libeis input backend plugin
This adds a libeis backend via plugin which supports clients sending
emulated input events. No public listening socket is exposed,
clients are expected to go through the RemoteDesktop portal.
In order to restrict the device types available to clients
according to what was approved via the portal a separate eis
context per portal request is created. The communication with
the portal happens through a simple dbus interface where cookies
are  handed out for each eis context so the portal can inform KWin
when the portal session is closed/should end.
2024-04-15 13:05:15 +00:00
David Redondo 2120e18729 Make InputRedirection::addInputBackend public
This allows plugins to register additional input backends.
2024-04-15 13:05:15 +00:00
David Redondo 9ba95ecd5d Export KeyboardLayout 2024-04-15 13:05:15 +00:00
Marco Martin 52b92904de Quick tiling double buffereing
The quicktileMode member now is just for the requested tile mode, base the "real" mode only on m_tile.

The requested tile mode is used for double buffering, to look and behave just like requestedMAximizeMode() which is updated immediately, but needs to acknowledge the configure request and render for quickTileMode() (and the right tile() instanced to be associated) to be updated accordingly
2024-04-15 12:18:09 +00:00
Xaver Hugl 36001e5ee0 increase minimum libdrm version to 2.4.116
It's required for drmSyncobjEventfd
2024-04-15 09:22:00 +00:00
Aleix Pol 1ab5453a90 EffectLoader: Warn about trying to load an invalid effect
If the metadata of the effect is invalid, loadEffect will complain
rather than failing silently, making debugging issues a bit harder and
it's something that we are already checking for and shouldn't
realistically be happening.
2024-04-15 00:47:33 +02:00
l10n daemon script 5e94f5429a GIT_SILENT Sync po/docbooks with svn 2024-04-14 01:22:41 +00:00
l10n daemon script f7a36a43d9 GIT_SILENT Sync po/docbooks with svn 2024-04-13 01:28:05 +00:00
ivan tkachenko 344e56dd77
plugins/dialogparent: Disable darkening while picking colors
Integrate with colorpicker effect to disable window darkening while
color picker effect is active. Unfortunately, this solution has couple
of limitations:
- active state of effects is not an observable property, so a new
  property had to be added to the effects singleton;
- consequently, list of active effects is not an observable property, so
  the whole thing could not be implemented in pure QML in the dialog
  parent effects;
- actual isActive() state of the color picker for whatever reason
  required that m_scheduledPosition is not an invalid point,
  effectively making it always inactive except for a brief moment
  between addRepaintFull() call and paintScreen() callback. That check
  had to be removed.
- QColorDialog windows are still modal and darkened by default;
- QColorDialog on X11 does not use portals/KWin, so this trick does not
  apply at all;
- effects->isScreenLocked() which isActive() depends on is not an
  observable property either.

BUG: 172921
2024-04-12 22:39:01 +06:00
Nate Graham 99324c12fd plugins/overview: remove middle click to close virtual desktop
This is a hidden destructive action[1] in a context where users are not
primed to expect it. It's also largely unnecessary since the delegates
already show a delete button on hover, and deleting virtual desktops
isn't such a common task that it benefits from an accelerator. Let's
remove it for safety.

[1] It's destructive because user-created state on the deleted virtual
desktop is lost--with no confirmation or undo, to boot.

BUG: 484999
FIXED-IN: 6.1
2024-04-12 13:25:58 +00:00
Xaver Hugl 64e0b693c7 core/output: remove direct scanout inhibition
It's not used anywhere
2024-04-12 12:58:55 +00:00
Carl Schwan b2f181fe80 Update kirigami target
Since kf6, FindKirigami2Config is deprecated in favor of
FindKirigamiConfig
2024-04-12 10:22:48 +00:00
l10n daemon script 89b6a67232 GIT_SILENT Sync po/docbooks with svn 2024-04-12 01:26:17 +00:00
Xaver Hugl 749b80ab49 backends/wayland: rename framePending to setPendingFrame
It's more clear about what the method does
2024-04-11 22:36:59 +00:00
Aleix Pol Gonzalez 881858f8dd Remove a number of unused forward declarations of gbm_* structs
Found this while debugging something else, seems like it's a good
cleanup.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-04-11 22:05:21 +00:00
Yifan Zhu 1a4606d990 scripting/windowmodel: match screen closest to center for filter
When filtering windows by screen, match the screen closest to the window
center, instead of testing whether the window is visible on the current
screen. The new method guarantees that when filtering by screen, the
window appears for exactly one screen. Previously windows spanning
multiple screens appear on all of them, and off-screen windows are not
shown in any screen.

BUG: 480028
BUG: 485337

FIXED-IN: 6.0.4
2024-04-11 09:36:26 -07:00
Vlad Zahorodnii bf4c5241a0 backends/x11: Use correct allocator when using software rendering
The drm device will be null when using software rendering.
2024-04-11 16:36:46 +03:00
Vlad Zahorodnii ab1350b6a6 wayland: Send data offer source actions only for dnd
It makes sense only with dnd and sending the source_actions events for
selections and primary selections tricks gtk into thinking that there
are drag motion events.

BUG: 464196
2024-04-11 08:21:06 +00:00
Yifan Zhu 9ca69cf50c screenedge: reset timer when pointer leaves edge
Currently the edge erroneously triggers when the pointer repeatedly
enters and leaves the edge in short durations. Send all events to edges,
and reset the timer when pointer leaves edge. Add corresponding test.

BUG: 441892
FIXED-IN: 6.0.4
2024-04-10 20:55:29 +00:00
Xaver Hugl 4c6000b3e1 core/syncobjtimeline: make explicit sync use SYNC_IOC_MERGE instead of waiting on the CPU side
This brings some performance benefits, because the application can potentially reuse
the buffer earlier, and it simplifies the code a bit
2024-04-10 19:06:01 +02:00
Xaver Hugl 32addf4d59 wayland: implement linux-drm-syncobj-v1
linux-drm-syncobj-v1 allows drivers and apps to synchronize KWin's buffer access
to their rendering, and synchronize their rendering to KWin's buffer release. This
fixes severe glitches with the proprietary NVidia driver and allows for some
performance improvements with Mesa too.
2024-04-10 19:06:00 +02:00
Natalie Clarius 672b662dd2 plugins/nightlight: add todo comment to rename config group key 2024-04-10 14:37:22 +00:00
David Redondo 1573d04b5a Mark windows for offsceen rendering in WindowThumbnailSource
This way if an effect wants to show such  window  that is for example
on a different virtual desktop it is updated live.
BUG:456280
FIXED-IN:6.0.4
2024-04-10 13:50:57 +00:00
Xaver Hugl 485769ddd9 plugins/zoom: limit the maximum zoom value to 100
Accidental changes in zoom can become very time consuming to undo otherwise.
With a value of 100, you can still zoom in far enough to only see a few pixels
on the screen, so it shouldn't break any actual use cases

BUG: 485192
2024-04-10 13:26:20 +02:00
l10n daemon script cfe001df6f GIT_SILENT Sync po/docbooks with svn 2024-04-10 01:28:24 +00:00
Vlad Zahorodnii 2014f9a382 plugins/screencast: Remove irrelevant code
testCreateDmaBuf() is going to use the GbmGraphicsBufferAllocator under
the hood.

The GbmGraphicsBufferAllocator works as follows: if you pass it the
DRM_FORMAT_MOD_INVALID modifier, the resulting GraphicsBuffer is going
to have the invalid modifier as well. So the receivedModifiers check
is unnecessary.
2024-04-09 08:54:11 +00:00
Vlad Zahorodnii 00c1e9850b plugins/screencast: Clean up cursor metadata
Every caller of sendCursorData() is required to retrieve the
spa_meta_cursor object. But there's no good reason to do it, this can
be done by the sendCursorData() function.

Also, sendCursorData() is not a good name, it doesn't send anything.
Instead, it adds cursor metadata to the buffer.
2024-04-09 08:40:49 +00:00
l10n daemon script f9e746dff6 GIT_SILENT Sync po/docbooks with svn 2024-04-09 01:28:17 +00:00
Vlad Zahorodnii 7d557784a1 plugins/screencast: Fix sizeof() of SPA_META_Header
At the moment, the sizeof the pointer is passed, but the size of the
struct must be passed instead.
2024-04-08 22:28:32 +00:00
Zack Rusin 15e23b825e backends/drm: Force software cursor on vmwgfx
The hardware cursor on vmware virtual machines is missing. This is
likely related to issues with importing DRM dumb buffers through
prime on vmwgfx.
Force software cursor on vmwgfx to make sure cursor is visible and
working properly until the hardware cursor is fixed.
2024-04-08 21:07:39 +00:00
Zack Rusin 17029cd54f backends/drm: Fix redraw issues on vmwgfx
Disable the readability checks when running on vmwgfx. The DMABuf syncs
seem broken on vmwgfx and until they're fixed disable the readablity
checks to actually let KDE propertly redraw when running on vmwgfx.
2024-04-08 21:07:39 +00:00
Zack Rusin d20d84cfa3 backends/drm: Fix the closefb ioctl
The DRM_IOCTL_MODE_CLOSEFB ioctl takes a struct drm_mode_closefb as
argument and not the framebuffer id as integer.

That distinction is important because the kernel side explicitly
checks whether the padding in drm_mode_closefb has been correctly
initialized to zero:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_framebuffer.c#n494

Use drm_mode_closefb and thus make sure the kernel side is not reading
garbage when testing the padding.
2024-04-08 21:07:39 +00:00
Nate Graham 61ca42cd2c Round all the things consistently
Now that we have Kirigami.Units.cornerRadius, there's a central source
of truth for corner radius so don't have to use random numbers for
these anymore.

Part of https://invent.kde.org/teams/vdg/issues/-/issues/45.
2024-04-08 16:56:50 +00:00
Xaver Hugl c26101a9fe backends/drm: use a swapchain instead of an OpenGL texture for the shadow buffer(s)
This seems to have better performance on Intel GPUs, and allows us to implement damage
tracking for the shadow "buffer" in the future

CCBUG: 477223
2024-04-08 17:19:01 +02:00
l10n daemon script 786dc09704 GIT_SILENT Sync po/docbooks with svn 2024-04-08 01:27:19 +00:00
Jakob Petsovits d9d733924c kcms/desktop: Move "Add" button and row count to header actions
I swapped the order of "Add" and row count because (in LTR layouts)
row captions are on the left and an "Add" button on the right sits
right on top of the "Remove" buttons in the list view.
2024-04-07 11:44:13 -04:00
l10n daemon script 9cd067e4fd GIT_SILENT Sync po/docbooks with svn 2024-04-07 01:26:27 +00:00
Xaver Hugl b29b3db26d plugins/colorpicker: fix interaction with SDR brightness
Right now both source and target color descriptions have SDR brightness values,
and the target one gets used; in this case however the source brightness needs
to be used instead.

BUG: 484497
2024-04-06 13:28:08 +00:00
l10n daemon script 2dbf2dd995 GIT_SILENT Sync po/docbooks with svn 2024-04-06 01:26:54 +00:00
Yifan Zhu c05a26f5c4 remove modifier only shortcuts
This is now implemented in kglobalacceld

BUG: 371560
2024-04-05 07:35:58 -07:00
Vlad Zahorodnii 693603d87a plugins/screencast: Unset spa_data::data for memfd buffers
The data pointer should be set mainly for SPA_DATA_MemPtr.
2024-04-05 12:06:42 +00:00
Vlad Zahorodnii 17c857ce66 plugins/screencast: Drop ScreenCastSource::hasAlphaChannel()
It's mainly unused.
2024-04-05 12:06:42 +00:00
Vlad Zahorodnii c3c3b903b1 plugins/screencast: Refactor buffer management
Use GraphicsBuffers both for dmabuf and memfd code paths.
2024-04-05 12:06:42 +00:00
l10n daemon script 608cc0e7f8 GIT_SILENT Sync po/docbooks with svn 2024-04-05 01:24:39 +00:00
Ian Forbes bd2728fac1 backend/drm: fix cursor hotspot enablement for virtualized drivers
DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT can only be set after DRM_CLIENT_CAP_ATOMIC
has been enabled.
2024-04-04 21:28:41 +00:00
David Redondo 9a74d70ba4 Fix build with newer QtWaylandScanner
Because of a shortcoming in upstream qtwaylandscanner and the cmake
macro we defered to the ecm macro which renames the output files
acoording to what qtwaylandscanner expects. However since this
was corrected in newer Qt this doesn't build anymore since
the tool now expects correctly named files.
2024-04-04 16:08:58 +00:00
Xaver Hugl d9ee6d98ae backends/drm: support cropping with direct scanout 2024-04-04 15:28:53 +00:00
Xaver Hugl 4448e23363 backends/drm: remove amd cursor-only commit workaround
The workaround prevents cropping with direct scanout, and it's no longer necessary
because we force a software cursor with adaptive sync on AMD to work around a related
problem
2024-04-04 15:28:53 +00:00
Xaver Hugl 9c2035ca63 scene/workspacescene: fix direct scanout checks with subsurfaces
The check ignored that subsurfaces could be not visible, not mapped, and also below
the parent surface
2024-04-04 15:07:22 +00:00
Xaver Hugl da34191115 backends/drm: actually prefer alpha formats again
The drm formats will never be the same, the intention was to check for bits
per color and bits per pixel
2024-04-04 13:51:05 +00:00
Aleix Pol Gonzalez 2b0b04235c wayland_server: Only check if there's an executable when we check permissions
There's not much point checking that we can convert an executable into a
file if we are not going to use that file.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-04-04 13:09:01 +00:00
Weng Xuetian 8c6ebee318
Fix inconsistent default keyboard delay value used in kwin.
plasma-desktop/keyboard/keyboardmiscsettings.kcfg has the default value
600. When default value (600) is set from kcm, kwin will wrongly use its
own default value in the code (660, which is most likely due to a typo when the
code is initially written).
2024-04-03 15:47:03 -07:00
Xaver Hugl 38e2bf34cf backends/drm: signal dmabuf feedback if an unsupported modifier is used
Otherwise the per-surface feedback never gets updated, and direct scanout fails
2024-04-03 15:13:37 +00:00
David Redondo cbab4b46c1 Implement xdg-dialog-v1 2024-04-03 14:34:53 +00:00
Vlad Zahorodnii baaa1db5d1 Guard against negative screen indices in Workspace::xineramaIndexToOutput() 2024-04-03 13:59:08 +00:00
Vlad Zahorodnii 883acb1f58 scene: Update surface texture in preprocess()
If two items display image data, the item renderer needs to special case
each item. It's not an extensible design, and my long term goal is to
introduce a separate tree specifically to solve this problem and also
help with computing the repaint damage automatically, instead of issuing
scheduleRepaint()s manually.

The first step is to refactor the item renderer so it merely takes the
input data and renders it. At the moment, it's not exactly the case
because surface textures are updated while painting the items, which
inherently requires special casing. This change moves surface texture
update code to the surface item so it's easier to refactor rendering code
in the item renderer.
2024-04-03 11:45:28 +00:00
Nate Graham fdd338f02b Mark risky KNS content
By design, these categories of content can run arbitrary code on the
system. This makes them security-sensitive and risky, so we need to
inform the user about it.

Depends on https://invent.kde.org/frameworks/knewstuff/-/merge_requests/309
2024-04-03 10:45:57 +00:00
David Redondo 3d5e10e9bb Stop vendoring xdg-toplevel-drag 2024-04-03 09:27:46 +00:00
David Redondo 7f20621b25 Bump wayland-protocols to 1.34 2024-04-03 09:27:46 +00:00
Vlad Zahorodnii 57a79608da Disable freebsd ci
It's broken and it blocks normal workflow.
2024-04-03 11:02:54 +03:00
l10n daemon script 7c3a27fb43 GIT_SILENT Sync po/docbooks with svn 2024-04-03 01:28:26 +00:00
Ser Freeman 298a8ca8c5 XdgSurfaceWindow: Always update move resize geometry
Since interactive move resize logic has changed, there is
no need to guard maybeUpdateMoveResizeGeometry anymore.

BUG: 483309
2024-04-02 16:42:38 +00:00
Vlad Zahorodnii 7bb250826e wayland: Emit closed signal immediately after marking the window as closed
The main motivation is to give users a chance to perform their cleanup.
2024-04-02 15:34:15 +03:00
Vlad Zahorodnii 28d6b5230a Unset Window::tile() when the window is closed
If a window is closed, its geometry should not change. The window has to
leave its assigned tile so it's not possibly moved or resized.
2024-04-02 15:34:15 +03:00
Yifan Zhu 5272c24301 plugins/mousemark: clear drawing when no modifiers are pressed
Previously when drawing has length 1, it is not cleared. So the
remaining point in drawing can connect with the new point when the user
represses the modifiers, leading to a unexpected mark.

This ammends commit 46807b1a72.

BUG: 482297
2024-04-02 08:52:45 +00:00
Yifan Zhu b4e15b28b6 plugins/mousemark: correct reserve size.
verts is now QVector<QVector2D>. So don't reserve 2x the size.

This ammends commit 617f3b9000.
2024-04-02 08:52:45 +00:00
Vlad Zahorodnii 4c384d1e9f plugins/screencast: Destroy renegotiate event
If I'm not mistaken, the renegotiate event is leaked. Also, its handler
function can be hypothetically called after thhe ScreenCastStream object
is destroyed.
2024-04-02 08:21:40 +00:00
Vlad Zahorodnii 0c49ae5360 plugins/screencast: Corrupt header to indicate that buffer has no data
SPA_META_HEADER_FLAG_CORRUPTED indicates that the buffer contains
absolutely no any data.

SPA_CHUNK_FLAG_CORRUPTED indicates that the buffer has no frame contents
but it can contain other data, for example cursor metadata.
2024-04-01 11:41:22 +03:00
l10n daemon script a4be9859b7 GIT_SILENT Sync po/docbooks with svn 2024-04-01 01:19:43 +00:00
l10n daemon script 4d72263b31 GIT_SILENT Sync po/docbooks with svn 2024-03-31 01:38:05 +00:00
l10n daemon script 20960c2fea SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-31 01:14:02 +00:00
l10n daemon script b5c127519f GIT_SILENT Sync po/docbooks with svn 2024-03-30 01:19:32 +00:00
l10n daemon script 7ac61516b2 GIT_SILENT Sync po/docbooks with svn 2024-03-29 01:38:23 +00:00
l10n daemon script 9165ba3b20 GIT_SILENT Sync po/docbooks with svn 2024-03-28 01:45:49 +00:00
Vlad Zahorodnii 5c2314a6bd plugins/screencast: Handle failing to import dmabuf 2024-03-27 15:41:54 +00:00
Nicolas Fella 9e9da67fc0 kcm/decoration: Port to ecm_add_qml_module and declarative type registration
This makes the types visible to QML tooling
2024-03-27 10:26:24 +00:00
Niccolò Venerandi c8e0568022 Fix oversights on shortcut handling within Overview/Grid effect
BUG:482931
2024-03-27 10:01:15 +00:00
l10n daemon script 4be92db483 GIT_SILENT Sync po/docbooks with svn 2024-03-27 09:55:36 +00:00
l10n daemon script bd84f1606d GIT_SILENT Sync po/docbooks with svn 2024-03-27 01:39:29 +00:00
Vlad Zahorodnii 8d3c06a178 plugins/screencast: Simplify damage calculation in region screen cast source
Whether the output is rotated should be irrelevant. The region screen
cast source handles scrapping fairly well blitting from rotated outputs.
2024-03-27 02:00:57 +02:00
Vlad Zahorodnii d1fdb69946 plugins/screencast: Drop "stream" in ScreenCastStream::streamReady
The word "stream" is redundant.
2024-03-27 02:00:57 +02:00
Vlad Zahorodnii cd2a4de82f plugins/screencast: Rename ScreenCastStream::stop() to close()
This is to help disambiguating between the code that shuts down the
stream completely and one that pauses/resumes the stream.
2024-03-27 02:00:57 +02:00
Vlad Zahorodnii 7894db7504 plugins/screencast: Pause/resume source when stream is paused/resumed 2024-03-27 02:00:55 +02:00
Vlad Zahorodnii 9d3e87bd9d tiles: Evacuate windows in CustomTile::remove() 2024-03-26 23:23:59 +00:00
Vlad Zahorodnii ea9691a2f5 tiles: Use deleteLater() in CustomTile::remove()
Otherwise it seems that QQmlEngine can segfault.
2024-03-26 23:23:59 +00:00
Kevin Ottens 0bcb9a0ddd plugins/screencast: Indicate which stream is considered in debug logs
We can easily have several streams manipulated at the same time, this
helps to distinguish between them.
2024-03-26 23:09:25 +00:00
Kevin Ottens 399a955eb2 plugins/screencast: Add more debug about the format negociation with PW 2024-03-26 23:09:25 +00:00
Kevin Ottens c310ba782a utils: drop the prefix param from drmFormatName 2024-03-26 23:09:25 +00:00
Xaver Hugl d59451adcf effects/quickeffect: render qtquick scenes in the normal render pass
If they're rendered in prePaintScreen, the time needed to render them is not
accounted for in compositing scheduling, which may make KWin miss vblank

CCBUG: 482861
CCBUG: 452119
CCBUG: 482034
2024-03-26 17:06:07 +01:00
Xaver Hugl 5101579eb8 opengl: introduce makeCurrent and doneCurrent in OpenGlContext
... instead of them being specific to EglContext and GlxContext
2024-03-26 16:06:01 +01:00
l10n daemon script 8c8c5b9b0e GIT_SILENT Sync po/docbooks with svn 2024-03-26 01:39:06 +00:00
Vlad Zahorodnii 8428b4603c plugins/screencast: Neutralize stopped streams
Streams are deleted with QObject::deleteLater(), it's still possible to
process some events before the stream is actually destroyed, which can
cause problems.
2024-03-25 19:56:08 +00:00
Xaver Hugl c6c99c1740 backends/wayland: don't clear the format map on tranche_done
It's not per tranche, it's global. Clearing the map means we ignore formats
from non-preferred tranches entirely
2024-03-25 13:19:01 +00:00
Xaver Hugl 686ea6374b backends/x11/standalone: port the egl backend away from AbstractEglBackend
This reduces the requirement on AbstractEglBackend to accomodate for X11
2024-03-25 12:52:31 +00:00
l10n daemon script 866afcb94b GIT_SILENT Sync po/docbooks with svn 2024-03-25 01:39:13 +00:00
Bart Ribbers d71243aa07 Add missing include on sys/types.h to fix build on Musl libc
I guess sys/types.h is implicitely included on glibc but that's definitely
not the case on Musl libc. The include is however necessary to define
dev_t introduced in 3c82d5a919
2024-03-24 20:09:22 +01:00
Nate Graham a2cccf0d75 Port to Kirigami version of ContextualHelpButton
It's been added there after starting life in kcmutils. Depends on
https://invent.kde.org/frameworks/kirigami/-/merge_requests/1488.
2024-03-24 15:56:00 +00:00
l10n daemon script 9b5ee76683 GIT_SILENT Sync po/docbooks with svn 2024-03-23 01:22:35 +00:00
Nicolas Fella 0fef229587 kcms/decoration: Fix crash when preview cannot be generated
m_bridge->createDecoration() can return nullptr. Most codepaths
already guard against that, but not all of them

BUG: 456531
2024-03-22 13:42:47 +01:00
Xaver Hugl 6a4a68dea4 backends: expose the DrmDevice instead of an allocator 2024-03-22 12:07:29 +01:00
Xaver Hugl 221c6aaf2b backends/virtual: use DrmDevice 2024-03-22 12:07:29 +01:00
Xaver Hugl 08439957d0 backends/x11/windowed: use DrmDevice 2024-03-22 12:07:29 +01:00
Xaver Hugl fb19774730 backends/wayland: use DrmDevice 2024-03-22 12:07:29 +01:00
Xaver Hugl d0b69f3503 backends/drm: use DrmDevice 2024-03-22 12:07:29 +01:00
Xaver Hugl 3c82d5a919 core: introduce DrmDevice 2024-03-22 12:07:29 +01:00
Vlad Zahorodnii 831ca28f93 plugins/screencast: Prefer allocating 3 buffers per stream by default
The current default 16 is way too many. For example, when screencasting
a 4K output, about 500MB will be wasted.
2024-03-22 08:30:47 +00:00
l10n daemon script 5777b3c257 GIT_SILENT Sync po/docbooks with svn 2024-03-22 01:21:31 +00:00
Vlad Zahorodnii 8bf1f9203b plugins/screenshot: Fix a crash in ScreenShotSource2::marshal()
There are behavior differences between QFutureInterface and QPromise.
The QFutureWatcher::finished() signal will be emitted in both cases
when the promise reports results or it is canceled.
2024-03-21 12:35:46 +00:00
Vlad Zahorodnii 489cd31ee9 Disable placeholder output when removing it
The current assumption is that Output::enabledChanged(false) always comes
before Output::destroyed.
2024-03-21 12:19:20 +02:00
David Edmundson 4f322e24d3 xwayland: Sync X11 keyboard tracking options between kcfg file and code
amends: a136a159f9
2024-03-21 08:16:15 +00:00
l10n daemon script 232984ebd5 GIT_SILENT Sync po/docbooks with svn 2024-03-21 01:24:14 +00:00
Yifan Zhu 111657ad04 x11window: round border size to integral XNative units
Both frameSize and clientSize are rounded to integral XNative units.
So their difference must also be rounded to integral XNative units.
Otherwise we get cycles of rounding that can cause growing window sizes.

BUG: 481460
2024-03-20 21:24:37 +00:00
Yifan Zhu 5c16cdd4ed globalshortcuts: send mouse events to kglobalacceld
This is needed so that kglobalacceld can correctly handle modifier-only
shortcuts.
2024-03-20 20:22:45 +00:00
Vlad Zahorodnii 012c64b054 Fix warning about nullptr sender in QObject::connect()
When one sets "no border" property, the decoration can be null.
2024-03-20 14:17:33 +00:00
Vlad Zahorodnii 236baa63df backends/drm: Handle failing to reopen drm node
Otherwise the drm backend will crash.
2024-03-20 14:07:33 +00:00
Vlad Zahorodnii 8934a31dad Add more guards for closed windows 2024-03-20 13:55:24 +00:00
Vlad Zahorodnii 442648edc0 wayland: Remove zombie ClientConnection from Display later
Otherwise it's theoretically possible to create a new ClientConnection
object for the zombie wl_client when its resources are being destroyed.
For example

- process early wl_client destroy notification
- the ClientConnection objects gets removed from the client list in Display
- process wl_resource objects getting destroyed
- if some code calls display->getConnection(zombie_client), it's going to
  reintroduce the client in the client list
- process late wl_client destroy notification, it's going to destroy the
  original and the clone ClientConnection object

This change prevents reintoducing a clone client object, by keeping the
original for a bit longer until it's actually destroyed. In the future though,
it would be great to kill the client lists in Display and ClientConnection,
and just use `static_cast<ClientConnection *>(wl_client_get_user_data())`.
2024-03-20 13:41:59 +00:00
Vlad Zahorodnii 44b72823c2 Don't trigger screen edge if the pointer is constrained
If the pointer is constrained, the screen edge may push the cursor back,
which will work not as expected. It's also undesired to trigger the screen
edge while the pointer is constrained by some surface, in general.
2024-03-20 13:46:00 +02:00
Vlad Zahorodnii 6412fd2c34 autotests: Add WM_TRANSIENT_FOR tests 2024-03-20 08:12:54 +00:00
l10n daemon script b4b9a28b6f GIT_SILENT Sync po/docbooks with svn 2024-03-20 01:24:48 +00:00
Vlad Zahorodnii a7e7923d6b plugins/screencast: Enqueue buffers immediately
There's still a crash in pw_stream_queue_buffer().
2024-03-19 20:32:46 +00:00
Xaver Hugl 630ba5fab4 pointer input: handle warp events differently from absolute motion events
As Wayland doesn't have a warp event yet, before this commit, warps were
dealt with like normal absolute motion events. This trips up games though,
which don't deal with actual absolute motion events well. As a solution
to that, until an actual warp event is a thing, we send a motion event with
a position + a relative motion event with no motion

BUG: 458233
CCBUG: 482476
2024-03-19 20:13:11 +01:00
Kristen McWilliam 246824aa61 autotests: add test for global keyboard shortcut
Adds an integration test that verifies the screen locks when the global keyboard shortcut is invoked.
2024-03-19 18:00:12 +00:00
Vlad Zahorodnii 60d36c0753 Move X11Window::findModal() to Window and remove boolean trap 2024-03-19 12:47:59 +00:00
Vlad Zahorodnii fb6ce3707a autotests: Add _NET_WM_STATE_MODAL tests 2024-03-19 12:47:59 +00:00
Vlad Zahorodnii 3ebe34bc3f plugins/screencast: Improve code readability 2024-03-19 12:25:33 +00:00
Vlad Zahorodnii 75f94c7cd0 plugins/screencast: Guard against having no dmabuf data for particular buffer 2024-03-19 12:25:33 +00:00
Vlad Zahorodnii afbb878fca plugins/screencast: Properly mark pw buffers as corrupted 2024-03-19 12:25:33 +00:00
Vlad Zahorodnii 01fa6c0af0 plugins/screencast: Clean up how pw_buffer is initialized
The offset and the stride of dmabuf can be set during the pw_buffer
initialization.
2024-03-19 12:25:33 +00:00
Vlad Zahorodnii 7bfb4a93e2 plugins/kpackage: Fix mainscript for declarative effects 2024-03-19 12:04:40 +02:00
Yifan Zhu 701f914081 window: fix interactiveMove exit condition
Previously the <= 1.0 test always succeeds in the first try, causing the
loop to exit prematurely.

BUG:  481610
2024-03-19 03:33:06 +00:00
l10n daemon script c1a2355d71 GIT_SILENT Sync po/docbooks with svn 2024-03-19 01:24:42 +00:00
Vlad Zahorodnii 6b1e2f24f4 autotests: Add _NET_WM_MOVERESIZE tests 2024-03-18 20:54:10 +00:00
Vlad Zahorodnii 8892b16626 autotests: Add tests to check unmaximizing X11Window by dragging it 2024-03-18 18:23:33 +00:00
Vlad Zahorodnii bf6727b384 Fix the titlebar visibility check for small windows
Consider a window with the size of 50x100 and the titlebar height of 36px.
The maximum number of visible titlebar pixels is 1800, but the
titleBarRect() function reports 3600 instead, which is completely wrong.

Since the reported number of required visible pixels is wrong, the window
geometry constraining logic is mistriggered and it's possible to move the
window only by 1px.
2024-03-18 17:27:07 +00:00
Yifan Zhu b6d315705b pointer_input: make edgeBarrier behavior consistent on corners
The pointer should cross a corner as soon as the movement in the barrier
zone exceeds barrierWidth. Previously horizontal and vertical movements
were separately considered, which made corners harder to cross compared
to edges even when the separate corner barrier was disabled.

CCBUG: 483651
2024-03-18 16:19:05 +00:00
Vlad Zahorodnii 29135f188f plugins/screencast: Add missing Q_OBJECT 2024-03-18 14:58:13 +00:00
Vlad Zahorodnii fb7dd07076 plugins/screencast: Avoid closing dmabuf fds twice
dmabuf fds are owned by the GraphicsBuffer, which will be destroyed when
`m_dmabufDataForPwBuffer.remove(buffer);` is executed.
2024-03-18 14:42:13 +00:00
Xaver Hugl 0897dbff75 clang-format: change the indentation of lambdas
Instead of indenting lambdas to the start of the lambda, always indent them to the
start of the line, which is more consistent and easier to read
2024-03-18 14:04:33 +00:00
David Edmundson e13a30f00f effects: Do not take ownership of QuickEffect::delegate
QuickEffect::setDelegate is exposed QML API.

The lifespan of assigned objects is therefore managed by the QML engine,
and we should be watching for deletion not actually deleting it.
2024-03-18 12:55:51 +00:00
David Edmundson b2a48d09e7 xwayland: Allow pushing to the clipboard without focus
X11 did not have a requirement that apps needed keyboard focus to update
a clipboard. Apps could copy things on click. With context menus and
grabs there can be no active window at this point.

Kwin tried to retrofit a requirement, which doesn't work in all cases.

Whilst there are security implications of reading a clipboard there are
no security issues about pushing a new clipboard. Gnome also allows X11
apps to push to the clipboard at any point.
2024-03-18 12:40:29 +00:00
Vlad Zahorodnii 22ef6d9ddf autotests: Stabilize X11WindowTest
Make a roundtrip to the x server to ensure that WM_STATE changes have
been propagated. xcb_flush() is not good enough, there's still a race
condition between the wm flushing its connection and the client reading
window properties.
2024-03-18 08:46:11 +00:00
l10n daemon script 0bc3fc18aa GIT_SILENT Sync po/docbooks with svn 2024-03-18 01:39:04 +00:00
Xaver Hugl 5fd96620ed backends: use explicit sync for reusing graphics buffers with EGL
Otherwise there can be glitches on NVidia, and this also makes some future
code changes around multi gpu copies and shadow buffers easier
2024-03-17 18:47:21 +01:00
Xaver Hugl af3bf939c5 platformsupport/scenes/opengl: don't access std::nullopt 2024-03-17 18:08:36 +01:00
Xaver Hugl 2a13a33040 platformsupport/scenes/opengl: advertise formats unnknown to KWin too
While KWin may not have information about the formats, that doesn't mean KWin
should filter them out - EGL can still import them, so allow clients to use them
2024-03-17 03:01:09 +00:00
l10n daemon script e5805fbd62 GIT_SILENT Sync po/docbooks with svn 2024-03-17 01:37:21 +00:00
Martin Rys 6b25d95f77 Optimize all PNGs losslessly, sans /po, saves 360KB~
*Second in series after https://invent.kde.org/plasma/plasma-workspace-wallpapers/-/merge_requests/17*

Another patch will follow from the translations SVN, after I figure out how to work with it.  

In kwin repo alone, there's another 4MB in savings with funny files like those:

```
kwin/po/ru/docs/kcontrol/windowspecific/tbird-reminder-info.png
  [oxipng] Reduced by 768.94 KB (-96.42%) from 797.52 KB
```
2024-03-16 23:53:12 +00:00
Vlad Zahorodnii 8cae7f7186 Port more stuff away from Cursor::pos() to interactiveMoveResizeAnchor()
The main benefit from doing this is that kwin is going to handle
maximizing the window by dragging it on touchscreen correctly if the
pointer focus point and touch focus point are on different screens.
2024-03-16 10:52:30 +00:00
Vlad Zahorodnii e8ae03d799 Make some Window::updateInteractiveMoveResize() code less misleading
The "!isMovable()" code path is needed to handle moving fullscreen windows.
Maximized windows are movable and their geometry is computed in
Window::nextInteractiveMoveGeometry().
2024-03-16 10:38:58 +00:00
Vlad Zahorodnii f563bade46 autotests: Add desktop tests in X11WindowTest 2024-03-16 10:25:32 +00:00
l10n daemon script 0780c0d96b GIT_SILENT Sync po/docbooks with svn 2024-03-16 01:42:05 +00:00
Harald Sitter 645db7fc90 keyboard_layout: always expose dbus interface
our plasmoid only listens to signals when the interface was found.
also when switching from 2 to 1 layout we'd emit a signal that the
layouts changed but then we'd throw away our interface leaving
the client wondering what happened to us (and consequently
printing warnings because our service wasn't found)

this specifically resulted in the plasmoid not getting layout event
changes when switching from 1 to >1

BUG: 449531
2024-03-15 22:21:08 +00:00
Vlad Zahorodnii 2663756ebf Move code to initiate interactive move by dragging the decoration outside Window::handleInteractiveMoveResize()
The main motivation behind this change is to make the code in
Window::handleInteractiveMoveResize() more reasonable. Almost all of the
code in it will be called after startInteractiveMoveResize(), except
when one drags the decoration to initiate an interactive move operation.

This change moves that code to the places where it makes more sense to
ensure that handleInteractiveMoveResize() has no any hidden pitfalls.
2024-03-15 23:01:30 +02:00
Vlad Zahorodnii 7db47ac2fd autotests: Add a test case for _NET_WM_WINDOW_OPACITY 2024-03-15 21:23:31 +02:00
Vlad Zahorodnii 78e2c123c3 Simplify Window::handleInteractiveMoveResize()
The lambda is not needed, its content can be embedded in the function.
2024-03-15 20:25:31 +02:00
Vlad Zahorodnii 11a5513e78 Avoid moving the window while it's maximized
Unlike X11, on Wayland, the window won't change its maximize mode until
it renders a new buffer. This creates a problem for interactive move
because if it's not careful and moves the window while it's still effectively
maximized, it will look as if the window has leaked to other screens.

This change fixes the problem by making Window::handleInteractiveMoveResize()
avoid move() if the window needs to be unmaximized.

As a bonus, it also allows to unmaximize the windows that are maximized
along only one dimension by dragging them.

Unfortunately, tiling stuff still suffers from the same issue. In order
to fix it, Window::tile() has to be part of double buffered state, like
Window::maximizeMode().

BUG: 449105
BUG: 459218
CCBUG: 482085
2024-03-15 18:00:52 +00:00
Vlad Zahorodnii 3e4c2b3ec8 Introduce Window::interactiveMoveResizeAnchor
This provides the grab point that controls the interactive move resize
operation. It can be used outside Window::handleInteractiveMoveResize()
to position XdgToplevelWindow when a configure event is acked.
2024-03-15 18:00:52 +00:00
Vlad Zahorodnii 5d313fdd7b Document Window::interactiveMoveOffset() 2024-03-15 18:00:52 +00:00
Vlad Zahorodnii 2d5a69b1d2 autotests: Add skip switcher/pager/taskbar tests in X11WindowTest 2024-03-15 17:16:27 +00:00
Méven Car aa465efa51 wayland: DrmLeaseDevice, use Q_OBJECT macro
BUG: 483008
2024-03-15 17:31:25 +01:00
l10n daemon script 1655d6bbc7 GIT_SILENT Sync po/docbooks with svn 2024-03-15 01:38:30 +00:00
Yifan Zhu e68ac506af plugins/shakecursor: reset detector on mouse press
A sequence of mouse moves shouldn't trigger the effect if the user
presses any mouse button during the mouse moves.
2024-03-14 21:49:33 +00:00
Aleix Pol ac9b9a6772 buttonrebinds: Introduce tests
Should help make sure the rebind feature stays working.
2024-03-14 14:39:00 -07:00
Yifan Zhu b8a59d0bd9 plugins/buttonrebinds: choose keysym based on KeypadModifier status
Use keysyms from the keypad if and only if KeypadModifier is set.
2024-03-14 14:37:19 -07:00
Yifan Zhu 6c4551ff46 plugins/buttonrebinds: remove modifiers before keysym conversion
QXkbCommon::toKeysym can't handle modifiers in key.

CCBUG: 482847
2024-03-14 14:37:19 -07:00
Vlad Zahorodnii 0b4c6f8b3b autotests: Reduce amount of boilerplate code in X11 window test 2024-03-14 21:27:05 +00:00
Xaver Hugl c7b9376ccc backends/drm: support hardware rotation with direct scanout
This improves latency and power use for fullscreen windows when the output
is rotated
2024-03-14 21:36:16 +01:00
Xaver Hugl d6ad0bcc20 backends/drm: remove remnants of hardware rotation with compositing 2024-03-14 21:36:16 +01:00
Vlad Zahorodnii acb4945cd3 autotests: Add more basic X11 window tests 2024-03-14 18:36:41 +00:00
Vlad Zahorodnii 9ee6b57d69 plugins/shakecursor: Fix blocking direct scanout
Effects are active by default.
2024-03-14 01:50:22 +00:00
l10n daemon script 9a0471a6d5 GIT_SILENT Sync po/docbooks with svn 2024-03-14 01:39:36 +00:00
Natalie Clarius a28676666a doc/windowbehavior: Remove removed "Active screen follows mouse" option
Leftover from commit e7d6e8b2
2024-03-12 23:54:17 +01:00
Vlad Zahorodnii fa4635e570 x11: Fix interactive move offset
Only the y component has to be divided by height(), not the whole QPointF()
expression.
2024-03-12 23:56:26 +02:00
Xaver Hugl b2babac3d0 dpmsinputfilter: don't wake up the screen on media or volume key events
It's pretty unexpected that the key press would be ignored and instead the screen
wakes up
2024-03-12 16:11:33 +01:00
l10n daemon script 09049954b9 GIT_SILENT Sync po/docbooks with svn 2024-03-12 01:21:12 +00:00
Xaver Hugl 3a55351211 plugins/screencast: fix the cursor being offset after changing the scale
When the scale of a screen is changed, the cursor parameters have to be
adjusted or the client will render it offset to the actual cursor
2024-03-11 23:46:51 +01:00
Vlad Zahorodnii 2c7301b3ee Make Window::interactiveMoveOffset() relative
Window::interactiveMoveOffset() stores the move offset in pixels, but it
is somewhat annoying to deal with when the window size changes, for example
when the window is unmaximized.

This change makes Window::interactiveMoveOffset() store a ratio where
the move offset can be found. This simplifies the code a bit and fixes
the cursor jumping to the topleft window corner. Although there are other
glitches.

CCBUG: 449105
2024-03-11 20:16:10 +00:00
Xaver Hugl 656313455b backends/drm: work around amdgpu vrr cursor bug differently
Instead of not-delaying cursor updates with adaptive sync, this forces a
software cursor instead. That way, the functionality works the same on all
the vendors.

For testing potential driver fixes, the environment variable
KWIN_DRM_DONT_FORCE_AMD_SW_CURSOR=1 can be used to disable this workaround
2024-03-11 19:56:43 +00:00
Yifan Zhu 380795423d xkb: always update keysym
Previously m_keysym was only updated on key press. This caused issues
when multiple keys are pressed at the same time. E.g., if the user
presses A, presses B, releases A, releases B, the actual events sent by
kwin was A pressed;  B pressed; B released; B released.

Also call xkb_state_update_key after xkb_state_key_get_one_sym, as
recommended by the libxkbcommon documentation
2024-03-11 15:29:02 +00:00
Yifan Zhu 92d29ed7f0 kcms/screenedges: add keywords for edge/corner barriers 2024-03-11 15:11:06 +00:00
Yifan Zhu 681752ada1 xkb: fix testing if on keypad
XKB_KEY_KP_9 is 0xffb9 while XKB_KEY_KP_Equal is 0xffbd and XKB_KEY_F1
is 0xffbe. So XKB_KEY_KP_Equal, instead of XKB_KEY_KP_9, has the maximum
keysym for keypad keys.
2024-03-11 07:47:58 -07:00
Marco Martin 609833e880 Properly intersect the shape with clipRect
That for loop in the end didn't have any effect,
actually compute the final region and return that one
2024-03-11 11:56:21 +00:00
David Edmundson 9302e84b95 wayland: Revert send pointer leave on drag
This was changed to match the behaviour of other compositors.
However what kwin did before is more sensible.

Sending a leave event breaks cursor updates by design. See
https://gitlab.freedesktop.org/wayland/wayland/-/issues/444
2024-03-11 11:32:35 +00:00
David Edmundson 044c9f0154 wayland: Only send artificial mouse up events for xwayland drags
Seat has to handle two types of drags; ones where clients are updated
through data device, and xwayland version where the drag target has
mouse events sents as pointer events. A mechanism to treat them
differently was introduced, but this former xwayland hack was not
included. We also don't need to send frame events when in datadevice
mode.

This reset of pointer state breaks electron.
2024-03-11 11:06:35 +00:00
Vlad Zahorodnii 4d659998d4 autotests: Make cursor-shape-device-v1 factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii 46f3c8509c autotests: Make auto-hide-screen-edge-v1 factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii a887b737ef autotests: Make idle-inhibitor-v1 factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii 2922b8d0a7 autotests: Make xdg-toplevel-decoration-v1 factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii b4e2241ded autotests: Make factional-scale-v1 factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii 8a11dde6f2 autotests: Make input panel surface factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii 98f0af0bc1 autotests: Make wl-subsurface factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
Vlad Zahorodnii f723b11a9a autotests: Make layer shell surface factory function return a std::unique_ptr 2024-03-11 08:52:10 +00:00
l10n daemon script ad747daf4f GIT_SILENT Sync po/docbooks with svn 2024-03-11 01:20:58 +00:00
Vlad Zahorodnii 670c71f11e Don't block interactive moves by sync requests
The compositor doesn't need to synchronize with the client when moving
windows, except cases like unmaximizing the window. It's needed only
when resizing to avoid overwhelming the client with configure notify events.
2024-03-10 19:07:02 +00:00
Vlad Zahorodnii 93326f3e50 Revert "plugins/zoom: Port to CursorItem"
This reverts commit e40f632c9b.

It broke non default mouse tracking modes. There are just too many
options, so revert the change instead.
2024-03-10 17:44:25 +00:00
Vlad Zahorodnii af7388c8a3 autotests: Port xdg-shell factory functions to unique_ptr 2024-03-10 17:25:52 +00:00
Vlad Zahorodnii 3f6a4eb1ea plugins/shakecursor: Mark it as internal
The accessibility kcm can be used to enable/disable the shake cursor
plugin and change its other parameters, so hide it in the desktop
effects kcm by default.
2024-03-10 17:12:55 +00:00
Vlad Zahorodnii 47829e6ac3 Remove isWaitingForInteractiveMoveResizeSync() check when interactively moving a window
There's already a check at the start of the function. Although interactive
moves don't need to be synchronized with the client, in general.
2024-03-10 10:43:03 +00:00
l10n daemon script 6435adc9d8 GIT_SILENT Sync po/docbooks with svn 2024-03-10 01:38:05 +00:00
Kristen McWilliam 0bfe7e150a scripting/workspace_wrapper: improve readability
Adds whitespace between documented members of the header file.

Currently the members are all bunched together, making it difficult to
read as one flows directly into the next. This change adds a newline
between each member, making it easier to read.
2024-03-10 01:17:17 +00:00
l10n daemon script 422b6c4f0d SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-10 01:13:49 +00:00
Xaver Hugl 0360ce38e2 core/colorspace: fix ColorDescription comparisons
They used the sdr gamut wideness (which should've been removed) instead of
the sdr colorimetry

BUG: 482809
2024-03-09 15:57:36 +01:00
Vlad Zahorodnii 277701e99f scene: Inherit scene from the parent item
It makes Item API more ergonomic.
2024-03-09 11:18:21 +00:00
l10n daemon script c1311abfc1 GIT_SILENT Sync po/docbooks with svn 2024-03-09 01:26:57 +00:00
l10n daemon script 05dc255048 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-09 01:15:34 +00:00
Yifan Zhu 2e5d3253d4 screenedge: allow creation between screens on wayland
Allow the creation of screen edges bordering two screens. This allows
panels in auto-hide/dodge-windows mode to work when the panel is
positioned between two edges.

Don't change the X11 behavior since edge barrier is not supported on
X11, without which it is virtually impossible to exactly position the
cursor on the pixel to activate the edge.

BUG: 351175
2024-03-08 12:03:28 -08:00
Yifan Zhu ad13765348 pointer_input: implement edge barrier between screens
Allow users to configure a virtual edge barrier between screens.
The pointer will only cross over to the other screen after the distance
travelled surpasses edgeBarrier.

Reduce the speed during interactive moveresize, at edges that trigger,
and at the corner.

Only supports wayland. Doesn't have X11 support since it is far too
complicated there.

BUG: 416570
BUG: 451744
2024-03-08 12:03:28 -08:00
Yifan Zhu ea4fa87bc6 utils/xcbutils: Don't call toXNative with unsigned integer
Instead use signed integers, to prevent the implicit cast from unsigned
integers to qreal.

BUG: 482687
2024-03-08 19:25:39 +00:00
Xaver Hugl b19426879f opengl/openglcontext: fix capitalization of isOpenGLES 2024-03-08 17:26:54 +00:00
Xaver Hugl 2f3b05e733 opengl: move "isOpenGLES" from eglutils to eglcontext and rename it
It's named in a confusing way and only used in eglcontext
2024-03-08 17:26:54 +00:00
Xaver Hugl 179af074eb opengl/glframebuffer: move s_fbos to OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl 493797ff31 opengl: move extension function resolving and debug output into OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl 7618be3697 opengl/glplatform: remove dependency on OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl 605401dcfc opengl: move glsl version to OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl c5cd8d1318 port most uses of GLPlatform::isGLES to use OpenGlContext directly 2024-03-08 17:26:54 +00:00
Xaver Hugl 5aa2606f04 opengl/glplatform: remove GLPlatform::supports method
There's only one "feature" left, so the method for it can be used instead
2024-03-08 17:26:54 +00:00
Xaver Hugl c41da588f6 opengl: move timer query detection to OpenGLContext 2024-03-08 17:26:54 +00:00
Xaver Hugl 568da29fbf opengl: move pack invert detection to OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl a8b9e8d262 opengl: remove most of glutils 2024-03-08 17:26:54 +00:00
Xaver Hugl bb0d1fc45e opengl: move static vertex buffer variables to OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl f98477e05b opengl/glframebuffer: move static variables to OpenGlContext 2024-03-08 17:26:54 +00:00
Xaver Hugl 1b4a9abbe3 opengl/gltexture: remove all the static things
The static fbo is removed, and the rest is moved to OpenGlContext
2024-03-08 17:26:54 +00:00
Xaver Hugl feeacf37db opengl: require support for fbos
It's effectively required already, as they're used everywhere
2024-03-08 17:26:54 +00:00
Xaver Hugl e763cd9eec opengl: remove the global shadermanager instance 2024-03-08 17:26:54 +00:00
Xaver Hugl 1b21b08130 opengl: move shader manager getter to OpenGlContext 2024-03-08 17:26:54 +00:00
Nate Graham 7ff51ba47c Raise target mobile device DPI
A target mobile DPI of 135 is rather low and results in excessively
large scale factors, so everything is too big.. Let's raise it a
little bit to improve the default level of information density on
these devices that are designed to be held close to the face.

This has the effect of changing the calculated default scale factor for
the following devices:

| Device     | Device DPI | Old scale factor | New scale factor |
| ---------- | ---------- | ---------------- | ---------------- |
| Steam Deck | 204        | 1.5              | 1.25             |
| PinePhone  | 268        | 2.0              | 1.75             |
| OnePlus    | 388        | 3.0              | 2.5              |

Devices are taken from the autotest data found at
https://invent.kde.org/plasma/kscreen/-/blob/master/tests/kded/configs/AutogeneratedMobileScreenScales.json
2024-03-08 17:14:16 +00:00
Xaver Hugl f3d9e5c90c backends/drm: handle dumb buffer target correctly
It's independent of the multi gpu import mode

BUG: 482859
2024-03-08 16:19:58 +00:00
Vlad Zahorodnii 9bf7c294a8 plugins/fadingpopups: Fix autohidden panels blinking when plasmashell launches
The autohidden panels "blink" because this effect animates their opacity.

The dock windows are animated because, as the comment says, the old effect
animated almost every window.

Conceptually, animating docks doesn't align with the purpose of this effect.
2024-03-08 16:07:36 +00:00
Nate Graham a136a159f9 Allow harmless XWayland key snooping by default
Wayland has a design philosophy of prohibiting keyloggers, which is
sane. However X11 did not, and a lot of X11 apps were developed with the
expectation of being able to sniff keyboard events to handle global
shortcuts. When such apps are run in a Wayland session under XWayland,
these features break.

Historically we have prohibited this in the name of security. In Plasma
5.27, we gave users a KCM they can use to choose their preferred balance
of security and unbreaking XWayland apps with global shortcuts. But we
still defaulted to total 100% security, at the expense of breaking these
apps by default.

However today we have a compromise that unbreaks them 99% of the time
while not meaningfully reducing security: we can have KWin only prohibit
XWayland apps from reading alphanumeric key events that don't have a
modifier key pressed at the same time. This still prevents those apps
from acting as keyloggers and reading your password or all the text you
type, but does allow those apps that have a legitimate need to read key
events for global shortcuts do so, because global shortcuts will involve
modifier keys being held down.

Due to the way the security modes work, making this change will also
allow XWayland apps to read non-alphanumeric keystrokes without any
modifiers being held down, but that's also fine for security since you
can't use any of those keys to type text or passwords.
2024-03-08 15:51:41 +00:00
Łukasz Patron f5cb109a87 xwayland: Disconnect xwaylandEavesdropsMouseChanged signal on finish
It appears that this was missed in 183637502d.
2024-03-08 11:57:10 +00:00
Vlad Zahorodnii e2cbed7060 Port IdleDetector to QBasicTimer
QBasicTimer is lighter and it properly handles timeout values bigger
than INT32_MAX.

CCBUG: 482077
2024-03-08 13:12:09 +02:00
Vlad Zahorodnii 18e414443e Add timeout assert in IdleDetector
CCBUG: 482077
2024-03-08 11:09:42 +02:00
Patrik Fábián 40b8637ab8 xdgshellwindow: Always update window position and size along all axes when fully miximizing window
BUG: 482086
2024-03-08 08:33:56 +00:00
Nicolas Fella 7078f4e3af Fix sending window to all desktops
NET::OnAllDesktops is a special desktop number (-1), desktopForX11Id will not return a desktop for it

When all desktops are requested pass an empty desktop list, the following code will handle it appropriately

BUG: 482670
2024-03-08 08:21:29 +00:00
l10n daemon script 2103eb8d16 GIT_SILENT Sync po/docbooks with svn 2024-03-08 01:20:07 +00:00
Nate Graham 7992d01fbd kcms/effects: add keywords for newly-introduced cursor effects
BUG: 482607
FIXED-IN: 6.1
2024-03-07 10:35:25 -07:00
Vlad Zahorodnii b674b458df Rename Workspace::updateClientArea as Workspace::rearrange
We need to re-arrange layer shell surfaces, compute new struts and adjust
the windows in a single step.

Workspace::updateClientArea() is the best candidate for that, so this change
repurposes that function from computing work areas to a generic relayouting
function.

CCBUG: 482361
2024-03-07 13:41:02 +02:00
Vlad Zahorodnii a489bfa12c wayland: Fix windows shrinking when output layout changes
When the output layout changes, the Workspace is going to update the
struts and then go through every window and see whether it should be
moved or resized.

On the other hand, the layer shell windows react to output changes on
a timer. Furthermore, it's not synchronized with the workspace rearranging
the managed windows. It means that when Workspace::desktopResized() runs,
the panel struts can be slightly outdated, i.e.

- An output layout change occurs
- Workspace::desktopResized() is called but the struts can be wrong
- some time later, LayerShellV1Integration::rearrange is called, it
  fixes layer shell window geometries and struts
- after the layer shell integration has finished rearranging the
  layer shell windows, it calls Workspace::desktopResized(), but the
  damage had already been caused

With the proposed change, the Workspace and the LayerShellV1Integration
will rearrange the windows in sync.

CCBUG: 482361
2024-03-07 13:41:01 +02:00
Mouse Zhang 9ca738ffec Add .directory to .gitignore 2024-03-07 17:20:53 +08:00
Mouse Zhang 769c63c834 plugins/backgroundcontrast: remove dolphin directory file 2024-03-07 17:17:36 +08:00
l10n daemon script 5401d6c213 GIT_SILENT Sync po/docbooks with svn 2024-03-07 01:19:27 +00:00
l10n daemon script 34545553b2 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-07 01:13:03 +00:00
Xaver Hugl e4349536a3 backends/drm: also set legacy gamma after VT switches
Just like with modes, the gamma state is unknown after VT switches, and has
to be explicitly set again to ensure it's correct
2024-03-07 01:50:43 +01:00
Xaver Hugl d1bc39a6ea backends/drm: don't set gamma with legacy unless really necessary
It seems to have a pretty large performance impact
2024-03-07 01:50:43 +01:00
Xaver Hugl 568f9fb666 backends/drm: ignore ctm support on legacy
BUG: 482143
2024-03-07 01:50:20 +01:00
Xaver Hugl 4a42829841 backends/drm: move tracking of legacy direct scanout presentation to DrmPipeline
The behavior between direct scanout and normal presentation being different is an
implementation detail of DrmPipeline, the output layers shouldn't need to care
2024-03-06 21:42:26 +01:00
Aleix Pol 1d57c9a5af effects: Use chrono to specify the animation times
Makes both the API and its uses explicit in terms of what unit the times
are on.
2024-03-06 10:19:55 +00:00
Vlad Zahorodnii f82542790c plugins/shakecursor: Enable by default
Multi monitor setups with 4K screens are not uncommon and one of the
annoyances associated with such setups is that you lose the track
of the cursor sometimes. It's natural to shake the cursor in such
occasions.

This change enables the shake cursor effect to improve the desktop
experience. One potential risk associated with doing so is that the cursor
can be magnified in some undesired situations. It is true. But we took a
great precaution of that and added some heuristics to avoid triggering the
effect in such cases given all the data we have available.
2024-03-05 21:32:35 +00:00
Vlad Zahorodnii dcd20922d9 plugins/shakedetector: Optimize ShakeDetector
Only store one history item for movement in the same direction.
With this optimization I measure m_history.size() <= 15 for all kinds of
movements, including back and forth, and circular.
2024-03-05 18:30:51 +00:00
Vlad Zahorodnii 0bc60023f5 plugins/shakecursor: Prefer operator[] over at()
Bounds checks are redundant. Plus kwin is built with exceptions disabled.
2024-03-05 17:38:14 +00:00
Vlad Zahorodnii 2ad896c71d plugins/shakecursor: Make the cursor big enough upon the first shake
The current behavior is that the cursor size follows how hard or fast
the cursor is shaken. While this looks fancy, given the purpose of this
plugin, it should be possible to magnify the cursor as easy as possible
without interfering or false triggering.

This change implements a sort of a compromise. When the cursor is shaken
for the first time, the cursor is magnified by some certain scale factor.
Then every next shake magnifies the cursor further by a smaller amount.
2024-03-05 18:34:30 +02:00
Vlad Zahorodnii 8736e44e1a effect: Fix EffectWindow::contentsRect()
It should specify the client rect inside the frame.

2556378dfa incorrectly assumed that the
buffer geometry includes the decoration.

BUG: 482294
2024-03-05 13:34:35 +00:00
Vlad Zahorodnii bfd755aee9 Fix confined pointer being able to escape the surface
When using fractional scaling, an xwayland window's client geometry can
have some fractional part. When that's the case, .toRect() can shrink the
client geometry or extruding the decoration borders inside the surface.

On the other hand, the pointer is going to be confined as long as the
wl_surface is focused. If the focus jumps to the decoration, the pointer
constraint is going to be broken. Unfortunately, the focus can shift to
the decoration even though the wl_surface is still focused because of the
pesky .toRect().

BUG: 482448
CCBUG: 477124
2024-03-05 13:23:59 +00:00
Vlad Zahorodnii 0c8b3251e5 examples: Fix License metadata 2024-03-05 11:02:37 +00:00
l10n daemon script 2b8b53a105 GIT_SILENT Sync po/docbooks with svn 2024-03-05 01:20:02 +00:00
l10n daemon script a33fe84f57 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-05 01:14:33 +00:00
Dominique Hummel d0a6bd3404 effects/windowview: use correct enum value for `PointerDevice`
BUG: 482191
2024-03-04 23:14:55 +00:00
Ser Freeman 43e5f17547 Window: Rearrange handleInteractiveMoveResize
Calculate the next geometry without actually moving a window.
This prevents one of the visual issues when restoring a maximized
window by dragging.
2024-03-04 14:57:59 +00:00
Xaver Hugl 599020d8da backends/drm: don't work around pageflips timing out
It doesn't seem to (always) work, and it has caused at least one crash. If the workaround
is needed, it'll have to be implemented in a different way
2024-03-04 13:44:35 +00:00
Xaver Hugl 1b10dde569 opengl: assume a minimum of 2ms of render time
When GPUs are barely loaded, render times can spike randomly, likely because it goes
to a lower power state and has to ramp up again when KWin renders. To ensure this
doesn't make KWin drop frames, assume rendering always takes at least 2 milliseconds
2024-03-04 13:07:15 +00:00
Xaver Hugl da80dd4c84 backends/drm: fix vblank calculation
Due to some misinterpretation of mode timings, the old method calculated vsync, not vblank,
so the resulting duration was much shorter, which caused frame drops on some systems.

BUG: 482064
2024-03-04 13:34:16 +01:00
Vlad Zahorodnii 9e77e5038f wayland: Fix a crash in DrmLeaseDeviceV1Interface::setDrmMaster()
The case when a resource is destroyed before kwin becomes the drm master
again is not handled. It can leave dangling pointers in m_pendingFds.
2024-03-04 10:59:40 +00:00
Xaver Hugl 3b28788592 wayland/surface: don't update preferred color description unless it changed
This avoids clients doing unnecessary work
2024-03-03 18:10:26 +00:00
David Edmundson 918ac8b27e xwayland: Use correct key for key release events
When a key is pressed the string that should be used in the key event
changes depending on the xkb updated state for composed keys.

The key itself should be not be affected.
2024-03-03 12:41:15 +00:00
David Edmundson b650f55d60 xwayland: Add unit test for XWayland key tracking 2024-03-03 12:41:15 +00:00
David Edmundson 2025bf4c6b xwayland: Send to xwayland even when no window is focussed
In the codepath to keep xwayland notified of key presses we have to
check the focussed window is not already an xwayland client. To avoid a
null dereference a guard is added that the focussed window is not null,
however the current code incorrectly returns early intead of skipping
just the relevant check.

BUG: 478705
2024-03-03 12:41:15 +00:00
Sam James 53a61dfac0 Fix ODR violation with MouseClick plugin
```
/var/tmp/portage/kde-plasma/kwin-6.0.49.9999/work/kwin-6.0.49.9999/src/input_event.h:21:7: error: type ‘struct MouseEvent’ violates the C++ One Definition Rule [-Werror=odr]
   21 | class MouseEvent : public QMouseEvent
      |       ^
/var/tmp/portage/kde-plasma/kwin-6.0.49.9999/work/kwin-6.0.49.9999/src/plugins/mouseclick/mouseclick.h:27:7: note: a type with different bases is defined in another translation unit
   27 | class MouseEvent
      |       ^
lto1: some warnings being treated as errors
```

Bug: https://bugs.gentoo.org/921558
Signed-off-by: Sam James <sam@gentoo.org>
2024-03-03 10:46:03 +00:00
l10n daemon script 956390005b GIT_SILENT Sync po/docbooks with svn 2024-03-03 01:26:45 +00:00
l10n daemon script 282d221ee1 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-03 01:16:28 +00:00
l10n daemon script 96139b8af5 GIT_SILENT Sync po/docbooks with svn 2024-03-02 01:21:33 +00:00
l10n daemon script fdb8d49946 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-02 01:13:21 +00:00
Vlad Zahorodnii 2491fb1b2b Ignore size hints when maximizing X11 windows
This is to help to fix maximized xwayland windows not covering the whole
work area. Size hints are obeyed only when restoring the window.

According to the net wm spec, the window manager should not obey size
hints when maximizing a window and some other window managers already ignore
them when maximizing windows.

CCBUG: 459373
2024-03-01 14:50:38 +00:00
Vlad Zahorodnii 47317a9fc7 examples/quick-effect: Revamp CMakeLists.txt 2024-03-01 14:31:42 +00:00
Vlad Zahorodnii f0b3964c1a examples: Add quick script example 2024-03-01 14:31:42 +00:00
Akseli Lahtinen 181ce590a9 plugins/overview: Adds a border around hovered and selected desktop in desktopGrid
Currently desktop grid view is missing the selection rectangle when hovered over a desktop.
This adds the selection rectangle on hover, since it used to be there before three-state design.

Currently selected desktop has thinner and different colored border.


![image](/uploads/ad1f2f7acbe602fb7b9479ce859026b7/image.png)

![image](/uploads/9fa50bac4b81958da0b8926f8d2518ba/image.png)

![image](/uploads/3e46c1f5a740c40bbf18a5d887f31d39/image.png)

BUG:481812
2024-03-01 12:05:14 +00:00
l10n daemon script f6813258ce GIT_SILENT Sync po/docbooks with svn 2024-03-01 01:39:10 +00:00
l10n daemon script 49852cc096 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-01 01:15:05 +00:00
Vlad Zahorodnii 0dc3f4906f opengl: Harden GLRenderTimeQuery against opengl providing bad timestamps
The end render timestamp can be slightly in the past before the start
render timestamp. This results in negative render times, which can make
kwin wait way more than just one vblank interval before starting the
next frame.

It appears that there is no way to detect if the gpu has performed a
disjoint operation in OpenGL. It's available only in GLES. As a way
around, this change makes the GLRenderTimeQuery insert two probes: one
queries gl timestamps when starting rendering and ending rendering;
another one just queries std::steady_clock before and after painting.
This hardens the GLRenderTimeQuery against OpenGL providing nonsensical
results sometimes.

BUG: 481721
2024-02-29 17:58:17 +00:00
Vlad Zahorodnii 79b7545840 backends/x11: Make SwapEventFilter report presentation feedback to OutputFrame 2024-02-29 16:46:05 +02:00
Vlad Zahorodnii 64dc01c640 effect: Drop WindowPaintData::screen
It's unused.
2024-02-29 13:33:52 +00:00
Marco Martin 86ede0ecf2 Remove invalid tabbox configs from defaults
We know that org.kde.breeze.desktop is invalid as LayoutName for the
tabbox, it will break the default button in the tabbox kcm.
Also the DesktopListLayout and DesktopLayout aren't valid anymore

BUG:481640
2024-02-29 11:14:31 +00:00
Fushan Wen d377b5cdab plugins/outputlocator: show physical size in output locator
Make sure the effect shows the same sizes as the KScreen KCM.
2024-02-29 09:29:51 +00:00
l10n daemon script bd88801de4 GIT_SILENT Sync po/docbooks with svn 2024-02-29 01:22:07 +00:00
Shubham Arora e89bd802a2 kwin/rules: update placeholder text and add icon 2024-02-28 21:58:15 +00:00
Shubham Arora 52349491af kcm/rules: move kcm actions to top 2024-02-28 21:58:15 +00:00
Aleix Pol Gonzalez bf1ce85474 Make it possible to build KWin without libxcb
Now that we have Wayland around, there's a whole branch of dependencies
that shouldn't be necessary anymore.
This allows to build KWin without all of it, allowing us to have a much
more compact alignment for cases where all the legacy software isn't
necessary anymore.

Bundle KWindowSystem X11-specific headers into it too, since it's part
of the same process.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-02-28 16:03:50 +00:00
Aleix Pol Gonzalez 94121c2a42 Unify the format for #include "config.h" 2024-02-28 16:03:50 +00:00
Nate Graham 26a7af5e5f {kcms,plugins}: Use real ellipsis character for user-facing translated strings
This is better for screen readers.
2024-02-28 08:58:37 -07:00
Vlad Zahorodnii e84d5bb666 examples: Add binary plugin example 2024-02-28 15:38:05 +00:00
Vlad Zahorodnii 38fae969a9 examples/quick-effect: Clean up metadata 2024-02-28 15:27:50 +00:00
Jin Liu 7d7344a983 plugins: add a "hidecursor" effect
This hides the mouse cursor on inactivity or keypress (configurable in the KCM).

BUG: 465119
2024-02-28 11:23:21 +00:00
l10n daemon script 494daab3d5 GIT_SILENT Sync po/docbooks with svn 2024-02-28 01:20:33 +00:00
l10n daemon script 6004ffe228 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-28 01:14:13 +00:00
Vlad Zahorodnii d8e8f952a2 Allow maximizing the window by double clicking borders
It's a more intuitive way to maximize a window either horizontally or
vertically.

BUG: 480848
2024-02-27 23:27:22 +02:00
Vlad Zahorodnii bc62e7e094 Drop Window::{windowShown,windowHidden}
They serve the same purpose as Window::hiddenChanged, so drop these
signals instead of having multiple signals to indicate the same thing.
2024-02-27 20:58:52 +00:00
Vlad Zahorodnii a8a53c651b Port away the remaining users of windowShown/windowHidden to hiddenChanged 2024-02-27 20:58:52 +00:00
Vlad Zahorodnii 5a32f012c3 Drop Workspace::windowHidden
Its name is misleading. Use activateNextWindow(), it's more readable.
2024-02-27 20:58:52 +00:00
Vlad Zahorodnii 2ed54ee10f wayland: Port "show under cursor" to Window::readyForPaintingChanged 2024-02-27 20:58:52 +00:00
Vlad Zahorodnii 6fb8eac890 plugins/{nightcolor -> nightlight} 2024-02-27 22:35:50 +02:00
Vlad Zahorodnii 0dd2012d4f plugins/screenedge: Port to ImageItem 2024-02-27 20:14:05 +00:00
Vlad Zahorodnii e40f632c9b plugins/zoom: Port to CursorItem 2024-02-27 20:14:05 +00:00
Vlad Zahorodnii fe45c99e99 plugins/trackmouse: Port to ImageItem
It reduces the amount of manual OpenGL code, and it's better to use
ImageItem because that way the ItemRenderer will take care of snapping
to the pixel grid or colorspaces.
2024-02-27 20:14:05 +00:00
Vlad Zahorodnii 191b0e7b6d plugins/shakecursor: Port to CursorItem
It reduces the amount of manual OpenGL code, and it's better to use
ImageItem because that way the ItemRenderer will take care of snapping
to the pixel grid or colorspaces.
2024-02-27 20:14:05 +00:00
Vlad Zahorodnii bcba59a7f5 scene: Use hardware clipping when painting overlay items
It's needed to properly render transformed overlay items. Ideally, the
ItemRenderer would split items that can be rendered with and without the
scissor test on its own. But we are not there yet, so pass the
PAINT_SCREEN_TRANSFORMED flag to force the ItemRendererOpenGL to use
hardware clipping.
2024-02-27 20:14:05 +00:00
Vlad Zahorodnii 916710ea01 scene: Export CursorItem 2024-02-27 20:14:05 +00:00
Vlad Zahorodnii 207bc1d9e6 scene: Introduce WorkspaceScene::overlayItem
The overlay item is the parent for all overlay contents above windows.
2024-02-27 20:14:05 +00:00
Vlad Zahorodnii c153fc719a scene: Make top left corner of CursorItem match the hotspot
It's more convenient if one wants to paint cursor at the specified
location. For example, when drawing the cursor on your own.
2024-02-27 20:14:05 +00:00
Vlad Zahorodnii f6b605daf2 scene: Add support for item transformations 2024-02-27 20:14:05 +00:00
Xaver Hugl 9e70c2a21c backends/drm: always prefer 10bpc buffers when supported
The environment variable is primarily meant as a workaround for displays
and drivers that misbehave when more than 8 bits per color is used. To simplify
the code, this commit makes the environment variable only control the bpc
used for displays, instead of also controlling which buffer formats get
used.
2024-02-27 21:01:28 +01:00
Vlad Zahorodnii 33e971cc09 wayland: Move popupOffset() back to xdgshell.cpp
The InputPanelV1Window doesn't actually need popupOffset(). Its popup
positioning is not data driven like xdg-positioner. It will be simpler
and more readable to compute the desired popup geometry explicitly.
2024-02-27 18:28:46 +00:00
Vlad Zahorodnii 693cd16b12 effect: Drop WindowPaintData::projectionMatrix() 2024-02-27 17:47:39 +00:00
Vlad Zahorodnii 18628131df plugins/sheet: Port to OffscreenEffect 2024-02-27 17:47:39 +00:00
Vlad Zahorodnii 5f043f2d61 plugins/glide: Port to OffscreenEffect
The main motivation behind this change is to make the glide effect stop
setting a custom projection matrix in order to assist with making the scene
2d only.
2024-02-27 17:47:39 +00:00
Xaver Hugl 36f6f2fb2d compositor: only set content type if window is on the current output 2024-02-27 16:13:23 +00:00
Patrik Fábián c11eeabc86 plugins/overview: Search bar can be clicked without closing effect 2024-02-27 15:32:45 +00:00
Xaver Hugl 765cd82613 autotests/test_colorspaces: add an autotest for non-normalized primaries 2024-02-27 15:14:20 +00:00
Xaver Hugl dd53576fe2 core/colorspace: normalize XYZ values before using them in calculations
Otherwise ICC profiles where the primaries are normalized to different values than what
KWin needs may cause too dark or bright results.

BUG: 481034
2024-02-27 15:14:20 +00:00
Xaver Hugl af4e12c5fc comopsitor: only activate VRR if the active window is on the current screen
BUG: 481750
2024-02-27 14:20:32 +00:00
Xaver Hugl d55f012537 backends/drm: support HDR content while an ICC profile is set better
The brightness of the screen is read from the luminance tag, and through
the color management protocol(s) passed to apps, so that they can adjust
their content accordingly
2024-02-27 13:50:36 +00:00
Oliver Beard 183637502d xwayland: Add option to additionally eavesdrop on mouse buttons
BUG: 466448
2024-02-27 13:34:14 +00:00
Vlad Zahorodnii d13b6db706 x11: Refuse starting move/resize operation with no pressed buttons
If the client is slow, kwin can receive _NET_WM_MOVERESIZE requests
after user has released mouse buttons. Ideally, the window manager
should refuse starting an interactive move/resize operation in such a
case so it's still possible to finish moving or resizing the window
by releasing mouse buttons.
2024-02-27 12:12:32 +02:00
l10n daemon script 677ce4014a GIT_SILENT Sync po/docbooks with svn 2024-02-27 01:21:41 +00:00
l10n daemon script deb17ded8a SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-27 01:14:32 +00:00
Vlad Zahorodnii 4d6f6223bc plugins/overview: Provide a way to reserve a screen edge for grid mode
BUG: 478137
2024-02-26 14:12:26 +00:00
Vlad Zahorodnii 329c5de451 xwayland: Ignore somebody else claiming WM_S0 selection
If somebody else claims the selection, it's unclear what we should do.
kwin can't give up its selection as it's the one who is responsible for
window management and compositing. If anything, Xwayland should ensure
that no client can claim WM_S0.
2024-02-26 15:58:13 +02:00
Vlad Zahorodnii 13c092d671 Fix a crash in eglDestroyImageKHR()
Apparently, libepoxy requires a current EGL display in order to resolve
EGL functions. This is unexpected as most of the EGL functions require no
current opengl context.

This change makes kwin bypass libepoxy for problematic cases.

BUG: 470980
2024-02-26 15:31:30 +02:00
Ser Freeman 192ec437df Window: Don't reset quick tile mode on interactive move start
Quick tile mode reset should be done in the interactive move handler,
where the new move offset is set. Only reset it on resize to unsnap
the window from the tile.

BUG: 472366
2024-02-26 11:11:53 +00:00
Łukasz Patron 083318dddd
x11window: Skip strict geometry checks in isFullScreenable()
This addresses an issue where mpv window with keep aspect ratio enabled
cannot be fullscreened due to constrainClientSize() returning size that
doesn't fit full screen area.

NOTE: This has been tested with 3440x1440 display and 1920x1080 video in
      mpv.
2024-02-26 11:33:18 +01:00
David Edmundson 32be54b19d x11window: Disable strict geometry placement by default in wayland
Strict geometry disables certain user activites; full screen requests
and only sending configure events at sizes the client claims to support.

This was added as a workaround for xterm in 19 years ago. It's a client
side bug as applications can still choose to ignore the configure event,
so kwin shouldn't have to sanitise them in advance. xterm seems to have
fixed it's bug, and pragmatically we know not all window managers
perform these checks so most clients should not be relying on it.

On Wayland this additional check is proving problematic, the handling of
scaling especially fractional scaling is hitting cases where it's better
to always ask the client to do what kwin wants.

Tests that refer to sizeIncrements are dropped as they are only used in
the strict geometry passes which is being obsoleted. Resizing in general
is still tested.

BUG: 481456
2024-02-26 10:32:49 +00:00
Akseli Lahtinen 024db60ccd tileseditor: Don't allow tiles to move tiles already at minimum size
Previously a tile could intersect with the tile next to it when resizing tiles in tiles-editor.

This checks that the tile next to the resized one is not at minimum size already, and stops
resizing if it is.

Do note that any current setups that may get broken if there is tiles that intersect each other,
so they may have to remake the tile setup.

BUG: 465721
FIXED-IN: 6.0.1
2024-02-26 10:16:55 +00:00
l10n daemon script fb36af09cd GIT_SILENT Sync po/docbooks with svn 2024-02-26 01:22:57 +00:00
l10n daemon script 4d5195bf8b SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-26 01:14:57 +00:00
Aleix Pol Gonzalez 7468465393 wayland: Install the clientconnection.h header file
Together with the rest of files that effects might use.

Signed-off-by: Falko Becker <falko.becker@mbition.io>
2024-02-25 19:18:19 +00:00
l10n daemon script d649eab88a GIT_SILENT Sync po/docbooks with svn 2024-02-25 01:27:05 +00:00
l10n daemon script a8af40ecf7 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-25 01:15:42 +00:00
l10n daemon script 8029c5c7ac GIT_SILENT Sync po/docbooks with svn 2024-02-24 01:19:16 +00:00
Ser Freeman 9cf424993f Window: Extract next interactive move geometry code to the separate function
This will allow code reuse.
2024-02-23 19:40:00 +00:00
Ser Freeman 4449315e39 Window: Extract next interactive resize geometry code to the separate function
This will allow code reuse.
2024-02-23 19:40:00 +00:00
Ser Freeman 10e41fc948 Window: Extract title bar rect code to the separate function
This will allow code reuse.
2024-02-23 19:40:00 +00:00
Vlad Zahorodnii 56d3c797cc plugins/showpaint: Add support for color management
It makes the show paint plugin work when color management is enabled.
2024-02-23 18:42:12 +02:00
Vlad Zahorodnii 7c0a88f34b plugins/glide: Fix rotation order when applying render target transformation
The perspective projection matrix has its y axis flipped vertically. It
should be undone when applying the render target transformation, otherwise
the rotation order will be wrong.

BUG: 481664
2024-02-23 13:57:16 +00:00
Marco Martin 9da0b8543f Send tablet input to active screen
Try to send the tablet input to the configured screen for the tablet if any,
otherwise always send it to the active screen, not the screen of the active window
which is very confusing

BUG:479713
2024-02-23 09:01:15 +00:00
l10n daemon script 493a4f7280 GIT_SILENT Sync po/docbooks with svn 2024-02-23 01:20:21 +00:00
Xaver Hugl d51b69d6ac useractions: don't interact with deleted windows
BUG: 481688
2024-02-22 23:53:57 +01:00
Aleix Pol Gonzalez 05a3e2bad9 systemd: Set up a watchdog
Allows to notify systemd whether kwin is still running and possibly
restart the service if it stops responding.

Use Type=notify-reload to watch the kwin service. This will make it so
we receive SIGHUP rather than SIGTERM on the wrapper which we can handle
gracefully and stop the kwin process and restart as expected.

https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-02-22 16:47:35 +00:00
Xaver Hugl 4f008c0231 backends: port most algorithm calls to ranges 2024-02-22 16:12:15 +00:00
Vlad Zahorodnii ff4cfe279a backends/x11: Avoid calling doneCurrent() if GLX context has not been created
BUG: 477854
2024-02-22 15:43:52 +00:00
Vlad Zahorodnii bb354de90e backends/wayland: Guard against failing to create EGLSwapchain
BUG: 478864
2024-02-22 17:12:58 +02:00
Xaver Hugl d33ab542db backends/drm: only enable HDR if both display and driver are capable of it
The config may have HDR or WCG enabled, and the driver or display settings changed
since then to make it impossible to actually enable either.
The config values stay unchanged when this happens, so reconnecting the display with
HDR support will automatically turn it on again.

BUG: 481518
2024-02-22 13:01:30 +00:00
zoro wk 904c33556b xcbutils: arm x apps can't be dragged to a negative position on the screen
the behavior of converting negative floating-point numbers to unsigned
integers is undefined. It is necessary to keep the conversion behavior
consistent between ARM and x86 platforms.

through the above conversions, all become the two's complement of
negative numbers.

Signed-off-by: zorowk <near.kingzero@gmail.com>
2024-02-22 10:27:19 +00:00
Vlad Zahorodnii 648cfcd66c wayland: Avoid rearranging layer surfaces when wl_surface size changes
wl_surface size is not used when re-arranging surfaces. It also results in
excessive configure events.

Note that it can be useful for updating strut rects, but we could use the
next geometry, which is even preferrable over the frame geometry as the
Workspace would use proper struts earlier.
2024-02-22 10:03:09 +00:00
l10n daemon script 602095ec52 GIT_SILENT Sync po/docbooks with svn 2024-02-22 01:22:16 +00:00
l10n daemon script b7bdd4f3ff SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-22 01:15:21 +00:00
Xaver Hugl 8c3332f619 opengl/eglcontext: tell Qt when the OpenGL context gets changed
Otherwise, Qt thinks the old context is still current and will do things like
destroying VAOs with KWin's context, which ends up destroying the VAO of the
context and breaks rendering.

BUG: 479094
2024-02-21 20:58:09 +01:00
Xaver Hugl 564bfafb57 backends/drm: delay cursor updates with VRR by default for non-AMD GPUs 2024-02-21 16:28:50 +01:00
Xaver Hugl 039fd39e34 backends/drm: delay cursor updates with adaptive sync
While the primary plane delivers a high enough refresh rate for the cursor to be
at least usable, delay cursor updates to be in sync with the primary plane. This
avoids stutter of the content being shown on the primary plane.

Because amdgpu doesn't handle this correctly at the moment, this feature is guarded
behind the KWIN_DRM_DELAY_VRR_CURSOR_UPDATES environment variable.
See https://gitlab.freedesktop.org/drm/amd/-/issues/2186 for more details on that.
2024-02-21 14:35:12 +00:00
Xaver Hugl 080d28b3f9 backends/drm: move committing logic into a separate method
This makes the code a bit more readable
2024-02-21 14:35:12 +00:00
Jonathan Esk-Riddell 5306823435 Update Frameworks version requirement to 6.0.0
GIT_SILENT
2024-02-21 14:33:28 +00:00
Vlad Zahorodnii c5c25a66f7 Remove legacy virtual desktop id from "Move to" action 2024-02-21 14:30:40 +02:00
Vlad Zahorodnii 2c445ebf3c Remove all legacy virtual desktop ids
Amends 0bd65de375.
2024-02-21 14:28:15 +02:00
Aleix Pol Gonzalez ade5d72c3a qpa: Don't build SPI support if Qt wasn't build with it
Signed-off-by: Falko Becker <falko.becker@mbition.io>
2024-02-21 12:25:09 +00:00
Jin Liu c2c19fe91f plugins/contrast: fix: effect not clipped to region
Introduced in:
7732f0e56b
2024-02-21 19:00:47 +08:00
Xaver Hugl 0bd65de375 useractions: remove legacy virtual desktop number from the menu
In almost all cases it's duplicated in the name, and if the user manually
changes the name, the custom name should be shown without additional numbers

CCBUG: 481576
2024-02-21 09:07:19 +00:00
Vlad Zahorodnii f77f5b2342 plugins/overview: Make screen edge toggle overview rather than cycle between modes
The user may have no usecase for the grid view mode, i.e. they may want
to activate overview, do their thing, and then return back to normal
desktop. However, with the current behavior, there's one extra step
(switch to grid mode) in order to go back to desktop.

In hindsight, we should have added different screen edge actions for
overview and grid modes. This can be done in 6.1.

BUG: 481335
2024-02-21 08:44:10 +00:00
l10n daemon script be3823e826 GIT_SILENT Sync po/docbooks with svn 2024-02-21 01:21:51 +00:00
l10n daemon script af7fa6a040 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-21 01:14:15 +00:00
Vlad Zahorodnii bb8b51a3ab Fix disappearing software cursor in overview and zoom effect
The overview and the zoom effect repaint the whole screen every frame.
But the problem is that there are cases when there's nothing to repaint.
I'm not quite sure why it happens. Maybe overview and other effects
should honor the repaint region, but on the other hand, they don't need
to because of the fullscreen effect api promises.

This change forces overview and zoom effect to use "generic paint" code
path in the workspace scene to force infiniteRegion() repaint regions.

BUG: 481523
2024-02-21 01:01:59 +02:00
Vlad Zahorodnii b2450cfe14 plugins/wobblywindows: Ignore PAINT_SCREEN_TRANSFORMED
Screen transform apis have been dropped, so the wobbly windows should be
safe to ignore screen transformations.
2024-02-21 01:01:59 +02:00
Michael VanOverbeek 86f0d9914e Fix zoom push mouse tracking on multi-monitor workspaces
Zoom push tracking now considers the layout of the user's monitors, accounting for situations where the monitor layout doesn't form a perfect rectangle. These changes help prevent the zoom area from being unable to reach certain areas of the workspace depending on which edge of which screen the user pushes against.

One known issue is that, if the mouse moves too quickly, the zoom area can sometimes imperfectly track the movement. It will look the same as the original bug (areas of the screen will appear to be cut off/unreachable), but moving the mouse in the opposite direction a tiny bit snaps the zoom area back to where it should be. 

BUG: 467182

@teams/qa Heads-up that I'm very blind, and this is the first time I've ever contributed to a KDE project. I've tested the changes on my system and they fix the bug, but I want to make sure I didn't break anything in the process.
2024-02-20 20:23:35 +00:00
Jakob Petsovits 9e3e567592 backends/drm: Undo fade-out effect upon unsuccessful DPMS Off
DrmOutput::setDrmDpmsMode() already takes care of reverting any
pending output pipeline changes, but the aboutToTurnOff signal from
setDpmsMode() needs an explicit wakeUp signal to cancel it out.

BUG: 477916
CCBUG: 481520
2024-02-20 14:29:32 -05:00
Aleix Pol Gonzalez 79dd34b3f9 Do not rely on NETWM for the main Window class
NETWM forces a weird X11 dependency on KWin that doesn't necessarily
match what we want to do. Instead we decouple such a central class in
KWin like it's Window from KWindowSystem X11 support.

Signed-off-by: Falko Becker <falko.becker@mbition.io>
2024-02-20 18:04:06 +00:00
Nicolas Fella afa450b97a Set componentDisplayName for shortcut migration
Otherwise the binary name is used as display name, causing all kwin
shortcuts to be registered under kwin-6.0-delete-desktop-switching-shortcuts
2024-02-20 11:22:11 +00:00
l10n daemon script 4045b3b389 GIT_SILENT Sync po/docbooks with svn 2024-02-20 01:23:39 +00:00
l10n daemon script 6dc908908c SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-20 01:15:26 +00:00
Xaver Hugl 8fa782f1a8 autotests/integration/outputchanges: add geometry restore test 2024-02-19 17:18:28 +01:00
Xaver Hugl 2c280b1bb0 placementtracker: save geometry restores more explicitly
Geometry restores were only saved when maximize or fullscreen changed, which is
not the only time the geometry restores change. This adds a signal to Window for
that, which fixes a few bugs with windows being moved between screens while
maximized or fullscreened
2024-02-19 17:18:28 +01:00
Xaver Hugl 86db3b4336 placementtracker: don't set geometry to geometry restores
It can cause problems when the geometry restore value is invalid

BUG: 473602
2024-02-19 17:18:28 +01:00
David Edmundson 3ede995b27 overview: Only handled input events in on-screen desktops
kwin does not support true multiscreen drag and drops. Events are sent
to an offscreen location of the screen initiating the drag. Therefore it
is important that off-screen items do not process drop events

BUG: 481331
2024-02-19 15:28:25 +00:00
Vlad Zahorodnii 64e701fdaf Synchronize input transformation regardless of interactive move resize status
This check is old and I'm not sure why it even exists. It should not be
needed in general.

The problem with this check is that when interactive move/resize
operation finishes, the seat input transformation is not synchronized.
2024-02-19 15:21:19 +00:00
Yifan Zhu c3cda8b62a effects/overview: implement new layout algorithm
Replace old "closest" and "natural" layout algorithms with new layout
algorithm. The new layout algorithm tries to
- use screen space efficiently, given diverse geometries of windows
- be aesthetically pleasing
- and minimize movement of windows from initial positions.

More concretely, find a layered layout, where each layer, or strip, is a
row or column. Ensure that different strips have similar widths, and use
binary search to find a packing with similar aspect ratio to the layout
area. Within each strip, minimize horizontal movement (for rows) or
vertical movement (for columns) of windows.

Run time is O(n) (up to log factors), where n is the number of windows.

CCBUG: 453749
BUG: 450263
BUG: 477833
BUG: 478097
BUG: 477830
2024-02-19 11:46:28 +00:00
Niccolò Venerandi 7732f0e56b Ensure that translations never change the size of a contrast effect / blur regions
BUG:480434
2024-02-19 11:11:01 +00:00
l10n daemon script f349d8e132 GIT_SILENT Sync po/docbooks with svn 2024-02-19 01:24:42 +00:00
l10n daemon script dfa1cbda4f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-19 01:14:19 +00:00
l10n daemon script 86540cd344 GIT_SILENT Sync po/docbooks with svn 2024-02-18 01:23:34 +00:00
l10n daemon script b3b2bcb369 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-18 01:15:04 +00:00
l10n daemon script a1ae401240 GIT_SILENT Sync po/docbooks with svn 2024-02-17 01:22:53 +00:00
Xaver Hugl 742268bfa1 backends/drm: don't advertise support for wide color gamut on Intel
i915 doesn't implement the Colorspace property correctly, so exposing this
feature makes it look like our HDR implementation is broken. This hides the
HDR checkbox in system settings until Intel fixes their driver

For testing purposes, users can still opt into this with the environment
variable KWIN_DRM_ALLOW_INTEL_COLORSPACE.
2024-02-16 11:41:13 +00:00
Xaver Hugl 9ea6f311ea backends/drm: force a modeset when connectors are unplugged
And turn off unused CRTCs with legacy

BUG: 478476
2024-02-16 11:20:02 +00:00
Xaver Hugl d69331d186 backends/drm: fix HDR with legacy modesetting
The properties were entirely ignored before
2024-02-16 11:09:56 +00:00
Vlad Zahorodnii fc92544cb3 plugins/overview: Allow switching between modes using shortcuts while already active
Overview and Grid modes have shortcuts assigned to them. While they
provide a way to toggle the overview effect between on and off state, in
other words overview <-> off or grid <-> off, it's not possible to move
between the modes by pressing those shortcuts, e.g. off -> overview ->
grid -> overview -> grid -> ... -> off.

The culprit seems to be that EffectTogglableState has two "inactive"
states - Inactive and Stopped. It's counter-intuitive and needs a further
cleanup.

To make switching between overview modes work, this change makes
EffectTogglableState::toggle() toggle the state based on the Active state.
There's only one active state.

CCBUG: 481335
2024-02-16 08:59:06 +00:00
Ismael Asensio 0991cded05 kcms/rules: Fix section header and info button sizing
The section header being now a QQC2.ItemDelegate needs to explicitly
set the width to be visible.

The ContextualHelpButton size was getting constrained by the parent
layout's being adjusted to just the label height.
2024-02-16 08:36:16 +00:00
l10n daemon script f364f3a923 GIT_SILENT Sync po/docbooks with svn 2024-02-16 01:23:20 +00:00
l10n daemon script ac9d470ab8 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-16 01:15:32 +00:00
Vlad Zahorodnii 7297e62283 plugins/screencast: Make grabTexture() more nicer to memfd code path
OutputTransform::Normal is handled by doGrabTexture().

If the texture transform is neither normal nor flip-y, the GPU is going
to be used to transform the texture, however since it doesn't flip the y
axis, doGrabTexture() will flip the y axis on the cpu side. To fix that,
make the contents of backingTexture mirrored vertically.
2024-02-15 14:25:01 +00:00
Vlad Zahorodnii af12a103ae plugins/screencast: Make region screen cast nicer to memfd
Set the FlipY flag so when the memfd code grabs the texture contents, it
doesn't need to flip the texture on the cpu side.
2024-02-15 13:54:56 +00:00
Vlad Zahorodnii 3388b7643c plugins/screencast: Fix window screencasts being vertically mirrored with memfd
WindowScreenCastSource::render(GLFramebuffer) renders windows with the y
axis flipped, but the offscreen has no FlipY flag set.

BUG: 478223
2024-02-15 13:54:56 +00:00
Xaver Hugl 3a8ae60f87 wayland/textinput_v2: copy the data instead of assuming ownership
The life time of the wl_array is limited to the callback, afterwards it's
a dangling pointer

BUG: 481239
2024-02-15 12:07:04 +00:00
Vlad Zahorodnii 5d787a4083 opengl: Invalidate cached vbo when content transform is different
When output rotation changes, the texture size stays the same, but the
texture coordinates are no longer valid and have to be recomputed.
2024-02-15 11:18:58 +00:00
David Edmundson c6a3d76b92 decorations: Avoid opaque areas of decorations being larger than the rendered contents
Opaque is a QRegion in logical pixels, using .toRect will round to the
nearest integer in either direction. This can mean an area is considered
opaque outside the rendered area, leading to glitchy contents on
shadows.

This is most noticable on on X11 windows when fractional scaling is
used.

Long term I hope to move Item::opaque to QList<QRectF> and
WindowPrePaintData::opaque to device pixels.
2024-02-15 11:10:19 +00:00
David Edmundson b36894884e wayland: Dispatch mouse events to internal windows via QWindowSystemInterface
QWindowSystemInterface goes via QGuiApplication which updates some
internal properties. Most notably QGuiApplication::lastCursorPosition
which is used by advanced menu closing behaviour.

BUG: 478061
2024-02-15 10:44:00 +00:00
Marco Martin 5244f9f406 Only show otherScreenThumbnail if we are actually dragging
otherScreenThumbnail is used to fake a window thumbnail being dragged
half in the old screen, half in the "new" one (or even more than two)

right now the condition to use it is purely the "real" thumbnail x
or y change, but sometimes especially when the item has just been created
and is being laid out it might trigger an itemDraggedOutOfScreen
when no-one was dragging.

We should never make otherScreenThumbnail visible when we aren't dragging
a thumbnail, so check for Drag being active in the source item.

the item will be kept visible even if drag becomes inactive as before,
as it still needs to be visible for the reset animation

BUG:480564
2024-02-15 09:58:35 +00:00
l10n daemon script 1b14b7b2f1 GIT_SILENT Sync po/docbooks with svn 2024-02-15 01:19:45 +00:00
l10n daemon script 46ca22f480 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-15 01:13:26 +00:00
Xaver Hugl b7e5d3f232 wayland: slightly simplify idle inhibit implementation 2024-02-14 20:59:32 +01:00
Fushan Wen f303ba4b59
plugins/colorblindnesscorrection: set translation domain in config ui
By default the translation domain of KQuickManagedConfigModule is the
unique identifier within the namespace of the plugin, but those i18n
strings belong to kwin.po.
2024-02-15 00:17:33 +08:00
Fushan Wen f650ebe2fc
plugins/colorblindnesscorrection: support adjusting intensity
Though there are 3 common CVD types, each individual can have different
color perception level, and the default intensity might not be suitable
for everyone, so add an intensity slider to select how much the filter
affects the display.
2024-02-14 23:47:18 +08:00
Xaver Hugl 1f1c54ca6c window: use normal keyboard modifiers for triggering custom tiling
Modifiers for global shortcuts are handled differently from normal shortcuts,
because they need to consider modifiers that are consumed by xkb for keyboard
layout transitions and similar. This restriction is not relevant for custom
tiling.

BUG: 465858
2024-02-14 14:25:03 +00:00
Xaver Hugl a917d1885e input_event: remove modifiersRelevantForTabBox
It was only needed because the normal modifiers path considered caps lock
as shift lock
2024-02-14 14:25:03 +00:00
Xaver Hugl 8c543dbe7c xkb: caps lock is not shift lock
Caps lock only locks capitalization of letters, making it artificially also
trigger shift in the context of KWin only causes problems
2024-02-14 14:25:03 +00:00
Aleix Pol Gonzalez c5305820d4 Reduce needed dependencies
For many components KConfigWidgets isn't necessary, just KColorScheme.

Signed-off-by: Falko Becker <falko.becker@mbition.io>
2024-02-14 14:45:24 +01:00
David Edmundson 5386360928 wayland: Send wl_pointer leave before data_device enter
SeatInterface currently has a separation of kwin's focus scope to
pointer input with early return guards in notifyPointerEnter and
notifyPointerLeave where clients don't get pointer events.

However we don't update the initial state when a drag is started, this
patch notifies sends a pointer leave to the new drag target before the
data_device enter so things are consistent.

This also brings it in line with Weston and Mutter.

notifyPointerLeave has it's early return removed as for wayland windows
as we know nothing will have pointer focus.
2024-02-14 12:39:32 +00:00
Vlad Zahorodnii 8a9cb06b41 Adapt to NETRootInfo::moveResize() changes 2024-02-14 10:43:00 +00:00
David Edmundson eab90b6a0a overview: Explicitly reset parent on teradown
Instantiators create objects when they're added to a model, and
deference when when they're removed from the model.

When we explicitly set a parent in onObjectAdded we're creating a second
reference. This does get cleaned up later, but not in the same frame.

This brings us in line to what QQmlRepeater (which works with items)
does internally for items being added and removed.

BUG: 478777
2024-02-14 09:19:28 +00:00
l10n daemon script b480297913 GIT_SILENT Sync po/docbooks with svn 2024-02-14 01:23:06 +00:00
l10n daemon script 1230c5ef92 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-14 01:14:48 +00:00
Xaver Hugl c6be2b51a9 backends/wayland: support direct scanout
This allows for (mostly) overhead-less pass-through of fullscreen content
to the host compositor
2024-02-13 15:45:26 +00:00
Yifan Zhu 2f4db693e3 screenedge: don't reduce approachGeometry
Reducing approachGeometry is not needed.

During edge creation, createHorizontalEdge and createVerticalEdge
already substract the needed cornerOffset, and edges reserved by client
windows shouldn't be reduced in geometry.
In addition, during display, ScreenEdgeEffect confines the painted area
to approachGeometry. So approachGeometry shouldn't be reduced in
advance.

BUG: 481282
2024-02-13 15:30:22 +00:00
Vlad Zahorodnii 55ef69645c Fix a warning about null sender in QObject::connect()
The original assumption was that once PointerInputRedirection starts
pushing cursor sources to cursors, they cannot be null. In many cases,
it is true, but the tests are a bit special as many of them lack
wl_pointer.set_cursor requests, so it's possible to set a null source.
As an example, when the pointer moves from the decoration to the
surface. On the other hand, it also does make sense to allow having
no source connected.
2024-02-13 13:36:52 +02:00
Ismael Asensio f6447ad188 tabbox/thumbnail-grid: Activate on thumbnail click when selected
While tabbox switching is usually a keyboard operation, we offer also
a mouse-friendly way to launch it via screen edges, and should allow
to switch directly on mouse click.

BUG: 481267
FIXED-IN: 6.0
2024-02-13 09:10:21 +00:00
l10n daemon script 62b55d0463 GIT_SILENT Sync po/docbooks with svn 2024-02-13 01:24:18 +00:00
l10n daemon script 77f3046ae0 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-13 01:14:57 +00:00
Xaver Hugl 8f27ee0cb8 input: remove hasAlphaNumericKeyboard method
It's completely unreliable
2024-02-12 18:19:23 +01:00
Vlad Zahorodnii 9abf7a9d61 plugins/blur: Fix blurred region sticking outside panel popups
The blur geometry is scaled in the global coordinate space, while it
works fine with integer scale factors, it's not okay with fractional
scale factors as it doesn't match how the ItemRenderer snaps quads to
the pixel grid.

Note that blur behind apps can be still off by one pixel, but it
should be harder to notice it. In order to fix it, it would be great
to apply effects behind Items, which is on my todo list.
2024-02-12 14:22:55 +00:00
Xaver Hugl 2ca1d3fd4c kscreenintegration: fix rotation not being preserved from Plasma 5 2024-02-12 13:38:14 +00:00
Vlad Zahorodnii 857766eb74 scene: Fix DecorationItem reacting to new geometry
Window::layoutDecorationRects() uses KDecoration2::Decoration::rect() to
get the bounding decoration rect.

While Decoration::rect() should normally match Window::rect(), they can
diverge for a brief moment during async geometry updates. The worst
possible case is that the cached item quads may not be invalidated when
the geometry updates saddle.

To fix that, make DecorationItem monitor decorated client size changes
instead of window frame geometry changes. The reason for that is that
Decoration::size() is effectively decorated client size with added border
margins.
2024-02-12 13:16:58 +00:00
Pedro Nishiyama a0d437163d Add Adaptive Sync window rule 2024-02-12 12:05:52 +00:00
Vlad Zahorodnii b02190bf23 plugins/overview: Fix a warning about incorrect anchor
The mouse area is no longer a sibling of the window heap, which produces
a warning.

BUG: 481106
2024-02-12 11:09:19 +00:00
l10n daemon script 956451111c GIT_SILENT Sync po/docbooks with svn 2024-02-12 01:20:51 +00:00
l10n daemon script 4585cec7a1 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-12 01:13:13 +00:00
Jin Liu daec969720 effects/outputlocator: add name and description metadata
Otherwise it's shown as a confusing empty item when "show
builtin" is on.
2024-02-11 01:28:20 +00:00
l10n daemon script 349f9c1fb6 GIT_SILENT Sync po/docbooks with svn 2024-02-11 01:23:44 +00:00
l10n daemon script 9187fe80f4 GIT_SILENT Sync po/docbooks with svn 2024-02-10 01:32:30 +00:00
l10n daemon script ea8dd5f32c SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-10 01:17:39 +00:00
Vlad Zahorodnii 4e8f1bdfda Bring back decoration spacer buttons
They were lost during KDecoration 1 -> KDecoration 2 transition.

CCBUG: 348393
CCBUG: 438719
2024-02-09 18:20:33 +00:00
Vlad Zahorodnii 13e7cac019 Handle wl_surface destruction in SurfaceCursorSource
Wine/Wayland hides the cursor as follows:

[ 853107.473]  -> wl_pointer@15.set_cursor(172832, wl_surface@38, 0, 0)
...
[ 858989.757]  -> wl_surface@38.destroy()
[ 858989.759]  -> wl_pointer@15.set_cursor(172832, nil, 0, 0)

i.e. it destroys the cursor surface, then calls wl_pointer.set_cursor().

SurfaceCursorSource stores the wl_surface in a QPointer, furthermore it
is going to emit the changed signal, which is needed to force the
CursorItem to update its content, only if either a new hotspot or a
surface has been passed to SurfaceCursorSource::update(). So what happens
is the following:

- The SurfaceInterface object is destroyed and the QPointer resets its
  value to nullptr
- SurfaceCursorSource::update(nullptr, QPointF(0, 0)) gets called in
  response to wl_pointer@15.set_cursor(nil, 0, 0)
- but since m_surface has been implicitly reset to nullptr, no changed
  signal is going to be emitted

This change addresses the issue by making the SurfaceCursorSource track
the SurfaceInterface's destroyed signal.

BUG: 480582
2024-02-09 13:53:04 +02:00
David Edmundson 95d4671a10 quickeffect: Avoid double delete of QQuickViews
Views are owned by the C++ backend, but also retrievable by invokables
to get neighbouring screens from JS space. By default Qt then transfers
ownership of the view to the QML collector. This results in double
ownership.

BUG: 480788
2024-02-09 09:12:17 +00:00
l10n daemon script 914aeb32ec GIT_SILENT Sync po/docbooks with svn 2024-02-09 01:25:27 +00:00
Ismael Asensio 7c8b5be55a kcms/rules: Fix import/export FileDialog type
They were just missing the alias qualifier.

Add also explicit parameters to the signal handlers.

BUG: 481082
FIXED-IN: 6.0
2024-02-08 22:24:44 +01:00
Xaver Hugl 31ebdb73a0 scene/surfaceitem: change refresh rate estimation to frame time estimation
This is both more direct and avoids divisions by durations that can potentially
be zero

BUG: 480971
2024-02-08 19:36:15 +01:00
Vlad Zahorodnii 06db626fc4 Reorder code in VirtualDesktopManager::setPlasmaVirtualDesktopManagement()
The code that initializes the initial state is buried between connect()s,
but there is no reason to do it and it is less organized.
2024-02-08 14:56:15 +00:00
Vlad Zahorodnii 764f0102fd Drop save() in VirtualDesktopManager::setVirtualDesktopManagement()
Changing the virtual desktop configuration when creating the plasma
virtual desktop global is wrong and it doesn't look like it happens.
2024-02-08 14:56:15 +00:00
Vlad Zahorodnii d78dcc6140 Fix initialization of virtual desktop row count in plasma virtual desktop global 2024-02-08 14:56:15 +00:00
Vlad Zahorodnii e974c07001 wayland: Schedule a configure event when borders change
Window::checkWorkspacePosition() before the window is mapped is still
problematic and should be avoided as it can produce undesired constrained
client size (1x1).

Given that XdgToplevelWindow tries to maintain the same frame geometry
size, it should be enough to schedule another configure event instead.
It is going to be in line with the other decoration logic in the
XdgToplevelWindow and it's a better way to handle async geometry updates.

BUG: 480910
2024-02-08 14:46:23 +00:00
Vlad Zahorodnii 5ad63f21e0 plugins/nightcolor: Rename d-bus interface 2024-02-08 14:24:51 +00:00
Xaver Hugl a5726e19fd wayland: update xx-color-management to v2 2024-02-08 14:01:43 +00:00
Vlad Zahorodnii cd43199e70 plugins/overview: Revoke Meta+Tab and Meta+Shift+Tab shortcuts
These shortcuts make more sense to be used with Meta+Tab and Meta+Shift+Tab.
Let's keep them reserved for the task switcher. Cycling between overview
modes is not something that requires Meta+Tab to be assigned to it by default.
2024-02-08 13:48:42 +00:00
Vlad Zahorodnii 540dff30e7 kconf_update: Drop kwin-6.0-overview-activities-shortcuts script
There are a few issues:

- it's incompatible with Version 6 format
- activity shortcuts cannot be changed in kwin
- overview shortcuts don't need to be touched

BUG: 480758
2024-02-08 13:48:42 +00:00
David Redondo 6b4018014c Guard against render time query failing
glGetQuery can fail (for example because of a context loss) in this
case the buffer stays unmodified. In this case this is zero resulting
in GLRenderTimeQuery::result() returning a negative value. Down the
line this leads to a negative duration in the RenderJournal and
RenderLoopPrivate::scheduleRepaint starting a timer with an amount
of milliseconds bigger than what an int can hold. This will not
actually start a timer but QTimer::isActive returns true resulting
in no futher repaints being scheduled.
BUG: 475605
FIXED-IN: 6.0
2024-02-08 13:29:05 +00:00
Marco Martin 51fb56773b Don't scale WindowHeap in overview mode
when in overview mode, don't scale down WindowHeap, as this
will cause ugly glitches, but resize it down instead.
Still use transforms when it goes in desktop grid mode, at least for now

probably future further refactor can still help things

Before:

![image](/uploads/7ca83e7e9292bd8489faaf76d4c12693/image.png)

After:

![image](/uploads/27b970d056c89486661d6695d09813ff/image.png)

CCBUG:475682
2024-02-08 13:01:27 +00:00
l10n daemon script 7c4bde3a32 GIT_SILENT Sync po/docbooks with svn 2024-02-08 01:22:46 +00:00
l10n daemon script 6cd615e4df SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-08 01:14:14 +00:00
Xaver Hugl 83fe158a16 backends/drm: fix night light updates after dpms
BUG: 480911
FIXED-IN: 6.0
2024-02-07 20:49:58 +01:00
Vlad Zahorodnii 4b7874391d kcms/tabbox: Update layout name in response to user input
The current index can change when populating the combobox.
2024-02-07 15:40:44 +00:00
Xaver Hugl d3a2e07002 backends/drm: fix multi gpu transfers with mixed modifiers and implicit modifiers usage
BUG: 478921
2024-02-07 14:35:50 +00:00
Xaver Hugl 1583b2c717 backends/drm: fix EglGbmLayerSurface::doesSurfaceFit with multi gpu
CCBUG: 478921
2024-02-07 14:35:50 +00:00
Vlad Zahorodnii 6d0f1fedc0 plugins/backgroundcontrast: Correct texture transform
The y axis should be mirrored as the last step, otherwise it's going to
change the winding order in rotation transforms in the render target
transform.

BUG: 479934
2024-02-07 13:53:20 +00:00
Vlad Zahorodnii f75fb70ddc Move alternative cursor shape resolver from Cursor to CursorShape
This code is more related to CursorShape than Cursor, so move it there.
2024-02-07 08:46:20 +00:00
Vlad Zahorodnii b1908949d0 autotests: Use ShapeCursorSource to load reference cursor images in testPointerInput 2024-02-07 08:46:20 +00:00
Vlad Zahorodnii a472c90327 Prefer up-arrow cursor shape
That's what breeze only has.
2024-02-07 08:35:52 +00:00
Vlad Zahorodnii c9c84b6859 Prefer cursor shape names from the CSS W3C specification
There is a mix of cursor shape names from the CSS W3C specification and
non-spec ones, which is confusing when deciding what cursor shapes need
aliases in Cursor::cursorAlternativeNames().
2024-02-07 08:35:52 +00:00
Columbariu S 7c2cf9c953 plugins/screencast: Announce size and stride only for SHM buffers
DmaBufs don't have a welldefined size or stride. Clients and PipeWire
shouldn't rely on those values. Therefore we better omit them.
2024-02-07 08:27:53 +00:00
Columbariu S cb398ce6fe plugins/screencast: Reset dmabufParams if SHM buffers are negotiated
m_dmabufParams is initialised after a format with modifiers is
suggested. Should the negotiation process fallback to SHM buffers, we
should reset it, so it can be used to determine if the negotiated format
is of type DmaBuf or not.
2024-02-07 08:27:53 +00:00
l10n daemon script b432c22e76 GIT_SILENT Sync po/docbooks with svn 2024-02-07 01:18:29 +00:00
Vlad Zahorodnii b560ad56b6 tabbox: Add a placeholder message in the thumbnails grid switcher
It improves the visuals of the switcher when there are no entries to display.
2024-02-06 21:50:14 +02:00
Vlad Zahorodnii 3714dcc337 tabbox: Prevent including "show desktop" entry if there are no other windows
BUG: 419408
2024-02-06 16:28:29 +00:00
Vlad Zahorodnii 8086707d1c Revert "tabbox: Show window switcher only when there are two or more windows"
This reverts commit b31baaf0cd.

It's still a good idea to show the task switcher even if there's only
one window in order to provide the user feedback about their action.
Since the task switcher is not shown when there's only one window, it
can be confusing and lead to thinking that the task switcher is broken.
It also fixes a regression which prevents alt-tabbing to the only
remaining minimized window.

BUG: 480940
CCBUG: 419408
2024-02-06 15:59:14 +00:00
Vlad Zahorodnii 2556378dfa Fix X11Window wrapper window geometry
This amends 66a491bda6.

There are a few more cases that had been overlooked in the original patch.
2024-02-06 12:13:54 +00:00
l10n daemon script 9c0947ae15 GIT_SILENT Sync po/docbooks with svn 2024-02-06 01:37:43 +00:00
Xaver Hugl 3d21e41bc9 backends/drm: add workaround for an amdgpu adaptive sync cursor bug
See https://gitlab.freedesktop.org/drm/amd/-/issues/3034 for details
2024-02-05 23:00:46 +00:00
Xaver Hugl 14749e91e9 backends/drm: try to handle page flips timing out
While this should really never happen in the first place, if the kernel still accepts
atomic commits, this is better than the screen(s) freezing and never recovering.

BUG: 480895
2024-02-05 23:51:14 +01:00
Xaver Hugl 1c8bd1be62 backends/drm: use explicit sync where possible
Instead of calling glFinish, which blocks until it's done and has high CPU
usage on NVidia, use EGL_ANDROID_native_fence_fd to get an explicit sync
fd, which the commit thread automatically waits on before committing the
buffer to KMS.

CCBUG: 452219
2024-02-05 22:46:04 +01:00
Alexander Wilms 3118ba5982 Task Switcher KCM: Change `Include "Show Desktop" icon` to `Include "Show Desktop" entry`
Not all task switchers use icons, so "entry" is more fitting.
2024-02-05 21:01:34 +02:00
Vlad Zahorodnii e7d6e8b217 kcms/options: Hide "active mouse screen" option
In the late Plasma 5 times we agreed that it would be better to drop
"active mouse screen" option and stick with last interacted screen
approach instead. However, it was forgotten and nobody has pursued this
goal, so let's hide the option in the system settings ui at least.

The option is not completely removed because some parts of kwin would
need adjustments.
2024-02-05 20:23:50 +02:00
Vlad Zahorodnii 8f7f97148c plugins/desktopchangeosd: Fix previous desktop indicator
BUG: 480630
2024-02-05 17:17:20 +00:00
Vlad Zahorodnii 63c1363ca1 Fix syncing Xwayland::Scale config option
The new scale value is written but it's not flushed to the disk so
when kcm_fonts_init and kcm_style_init run, they use the old scale
value.

CCBUG: 480792
2024-02-05 16:51:34 +00:00
Xaver Hugl 41aeecbb2a scene/surfaceitem: prevent division by zero
If the steady_clock's resolution is very limited, now - m_lastDamage might be zero,
so enforce a minimum time of 10us (or 100'000 fps)
2024-02-05 16:32:04 +00:00
Vlad Zahorodnii e97b6032c2 effect: Allow ref'ing normal windows
It can be used to simplify state tracking in some effects. The
restriction exists because there used to be separation between normal
and closed windows (Toplevel and Deleted), and one could reference
only Deleted windows. So it was easier just to forbid referencing still
alive windows.
2024-02-05 15:06:13 +00:00
Vlad Zahorodnii 0c03e7ccfc plugins/slidingpopups: Always ref window when sliding it offscreen
Imagine the following case:

- the window is hidden, slideOut() is called but no deleted reference is
  created because the window is not deleted
- the window is closed, slideOut() won't be called because the window is
  hidden and SlidingPopupsEffect::slotWindowClosed() ignores closed windows
  that are already hidden
- the window is deleted in meanwhile
- the sliding popups effects attempt to delete m_animations[w] entry,
  but since "w" is a dangling pointer at this point, visibleRef is going
  to access released memory

To fix that, make slideOut() always ref the window.
2024-02-05 15:06:13 +00:00
Vlad Zahorodnii 69f344a439 plugins/screenshot: Cache screenshot attributes
When a QPromise reports results, it's not necessary that the
QFutureWatcher is going to report it immediately. That can happen at
some point in the future, which is okay according to the QFuture api
contract.

Due to that, we cannot assume that the stored Output and EffectWindow
objects pointers are valid when the QFutureWatcher::finished is emitted.
2024-02-05 16:24:48 +02:00
Vlad Zahorodnii 50fae55821 Revert "systemd: Set up a watchdog"
kwin_wayland has become unstable. Sometimes it works fine, sometimes it
is randomly killed. Things are quite bad after kwin_wayland --replace.

This reverts commit 71ade59f4b.
2024-02-05 12:54:47 +02:00
Xaver Hugl 6e4b5839ce Revert "opengl/openglcontext: require support for RGBA16F framebuffers"
This reverts commit a89d1f8058. Apparently lima does not
support the extension :|
2024-02-05 10:11:26 +00:00
Kai Uwe Broulik 68f1684031 killer: Initialize Xdg Importer in its constructor
Avoids having to do asynchronous code further down.
2024-02-05 10:04:12 +00:00
Vlad Zahorodnii fec39141b5 Decouple updateLayout() from updateRootInfo()
It makes code more intuitive, updating X11 specific stuff should not be
needed to update the grid layout. Another advantage that this change
brings is that it should be possible to decouple X11 bits from the
virtual desktop manager completely, might be useful for running multiple
xwayland instances.
2024-02-05 11:52:36 +02:00
Vlad Zahorodnii 8b29f07dbe Make NETRootInfo initialization reasonable
The documentation of NETRootInfo::activate() says that it should be
called after creating the NETRootInfo object to read properties.

However, it's called in two places: VirtualDesktopManager::setRows()
and Workspace::initializeX11(). At quick glance, there's no justifying
reason to call activate() in setRows(), it doesn't fit the purpose
of setRows().

This change re-arranges NETRootInfo initialization code so it makes
more sense.
2024-02-05 09:45:22 +00:00
Vlad Zahorodnii 993f110d59 Don't overwrite current virtual desktop when restarting Xwayland 2024-02-05 09:36:57 +00:00
Aleix Pol Gonzalez 71ade59f4b systemd: Set up a watchdog
Allows to notify systemd whether kwin is still running and possibly
restart the service if it stops responding.

Use Type=notify-reload to watch the kwin service. This will make it so
we receive SIGHUP rather than SIGTERM on the wrapper which we can handle
gracefully and stop the kwin process and restart as expected.

https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2024-02-05 09:25:08 +00:00
Vlad Zahorodnii aac5d562fb Drop "<N>" window caption suffix
The current implementation of the `<N>` suffix is still buggy and its
benefits are doubtful. One could argue that visual aids such as window
thumbnails or highlighting the windows are better. On its own, these
numbers don't have strong connections to the windows and can change on
a whim.
2024-02-05 11:10:53 +02:00
Vlad Zahorodnii 3f2b49be5d Stop emitting windowShown signal when XdgToplevelWindow is unminimized
Minimized state has no connection to the hidden state.
2024-02-05 08:44:14 +00:00
Vlad Zahorodnii 66a491bda6 wayland: Remove extra space around the wrapper window in X11 windows
This way no extra buffer space is going to be wasted for a decoration
that isn't there, and it might be nicer for fractional scaling as kwin
won't need to deal with border size voodoo cases.
2024-02-05 08:30:40 +00:00
l10n daemon script ba37d18ab9 GIT_SILENT Sync po/docbooks with svn 2024-02-05 01:32:52 +00:00
l10n daemon script 909d83419c GIT_SILENT Sync po/docbooks with svn 2024-02-04 01:20:54 +00:00
l10n daemon script 94e1d6de3e GIT_SILENT Sync po/docbooks with svn 2024-02-03 01:23:52 +00:00
l10n daemon script 7c9fb68b14 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-02-03 01:15:33 +00:00
Vlad Zahorodnii cc2e6fc96c Add fallback cursor shape for "default" shape
Some cursor themes don't have "default" shape, so fallback to "left_ptr"
with such themes.

BUG: 477476
2024-02-02 17:17:38 +02:00
David Redondo ee782c8a91 Update to merged version of xdg-toplevel-drag 2024-02-02 14:44:23 +01:00
David Redondo 4d0cd42aef Revert "Use qt prefix variant of toplevel drag protocol"
The protocol has been merged upstream and Qt is now using it.

This reverts commit 216a268a43.
2024-02-02 14:44:23 +01:00
Niccolò Venerandi 79a61deb25 Register touch action to activate Overview instead of toggling it
This is because the Overview will activate itself at the end of a 1:1 gesture,
and a toggle action might actually deactivate it rather than activate it.
2024-02-02 14:42:06 +01:00
Vlad Zahorodnii e58451fc01 wayland: Truncate virtual desktop names
Virtual desktop names are user defined strings so they can exceed
the maximum size of a wayland message size.

BUG: 480614
2024-02-02 12:03:33 +02:00
l10n daemon script 92f4a95bb5 GIT_SILENT Sync po/docbooks with svn 2024-02-02 01:19:44 +00:00
Vlad Zahorodnii 5896bab86f Activate next window when an X11 window is minimized
It matches the behavior of XdgToplevelWindow.

BUG: 479388
2024-02-02 02:01:39 +01:00
Xaver Hugl 880ce92fb2 xwayland/xwaylandlauncher: don't enable WAYLAND_DEBUG with KWIN_XWAYLAND_DEBUG=0 2024-02-02 02:01:13 +01:00
Vlad Zahorodnii c733e7a7b6 backends/virtual: Fix OutputFrame 2024-02-02 02:00:51 +01:00
Xaver Hugl c2749e3acf x11window: explicitly resize when the Xwayland scale changes
With how Xwayland scaling works, KWin assumes the window already uses the
new coordinate system - but that doesn't happen until Xwayland and the client
know about the new size as well.

BUG: 480642
2024-02-02 02:00:27 +01:00
Vlad Zahorodnii 93b9fdd391 effect: Fix initialization of QEvent::isAccepted() in cloned events in OffscreenQuickView
QEvent::isAccepted() is initialized to true by default.

BUG: 480538
2024-02-02 02:00:07 +01:00
Xaver Hugl 67b1a88466 autotests/integration: re-enable lid closed output changes test
KWin is handling the lid switch now
2024-02-02 01:59:36 +01:00
Xaver Hugl cc72778d5e plugins/nightcolor: clamp preview color temperature to be somewhat sane
BUG: 480700
2024-02-02 01:59:06 +01:00
Yifan Zhu ae7fb3885b inputmethod&plugins/buttonrebinds: use new KKeyServer API
To correctly handle Qt::Key_Calculator corresponding to both
XF86Calculator and XF86Calculater.
2024-02-01 23:11:32 +00:00
Vlad Zahorodnii 795b619704 Take surface idle inhibitors into account only after window is added to the workspace
This helps to reduce having N sources for the same information.
2024-02-01 10:49:39 +02:00
Marco Martin 19970bd639 plugins/wobblywindows: Use snapping when the window isn't moving
disable pixel snapping when the window is moving with some velocity/acceleration,
reenable it when is (alsmost) stopped
2024-02-01 10:47:45 +02:00
Jay Paul 5ae170f1d6 plugins/screencast: set frame timer to one shot
BUG: 469777
2024-02-01 10:27:15 +02:00
Xaver Hugl 896a57d3be opengl/glshader: make uniform enums type safe 2024-01-31 13:24:48 +01:00
Xaver Hugl a649be64db backends/drm: use the correct uniform type 2024-01-31 13:24:48 +01:00
Xaver Hugl 6db05aaef1 backends/drm: merge all commits and try again if atomic commits fail
The failure might be from the commit reordering going wrong in some way.
The total accumulated state might still work even if an individual commit
does not though, so before considering the whole frame lost, merge all the
commits and try again
2024-01-31 13:24:24 +01:00
Xaver Hugl 9c0085f5a9 colorspace: make sdr colorimetry not be about rec.2020 anymore
This was just done because of the wrong assumption that displays needed that
to show the full native gamut. That turned out to be an amdgpu bug though; with
that fixed, most of the 0-100% range is wildly oversaturated.
To make the slider more intuitive, this changes the sdr gamut wideness to instead
interpolate to the native display primaries as indicated by the EDID.
2024-01-31 13:23:03 +01:00
Xaver Hugl 8d44ece874 input: increase raise timeout for drag and drop to 1s
This should be long enough to not happen accidentally, but short enough to not be
annoying and discoverable.

BUG: 480511
2024-01-31 10:41:03 +02:00
Vlad Zahorodnii 3a1b9414ed plugins/screencast: Fix hidden cursors
The screencast plugin doesn't take into account the hidden status of
the cursor, which results in the cursor being visible when screencasting
even though it's hidden.
2024-01-31 10:38:56 +02:00
l10n daemon script 120e36da2a GIT_SILENT Sync po/docbooks with svn 2024-01-31 01:25:39 +00:00
l10n daemon script 788f42ddd4 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-31 01:13:52 +00:00
Vlad Zahorodnii def3a50558 Ignore external updates of _NET_DESKTOP_LAYOUT and _NET_DESKTOP_NAMES
At the moment, the desktop layout in _NET_DESKTOP_LAYOUT overwrites new
desktop layout with outdated information. This happens because kwin tries
to honor the desktop layout set by the pager. However, kwin itself
already acts as the pager. The pager applet in plasma doesn't attempt to
maintain _NET_DESKTOP_LAYOUT with proper values.

On the other hand, kwin trying to both update and also sync its state to
_NET_DESKTOP_LAYOUT and _NET_DESKTOP_NAMES has created a series of
issues, like lockups or rendering glitches.

Given that the window manager can ignore these properties, and the fact
that kwin already does act like a pager, this patch makes kwin ignore
external updates to _NET_DESKTOP_LAYOUT and _NET_DESKTOP_NAMES.

In order to modify the desktop layout on X11, use the dbus api. On
Wayland, either the dbus api or the virtual desktop wayland protocol.

BUG: 422319
BUG: 480371
2024-01-30 14:14:09 +02:00
l10n daemon script 98dcf82ada GIT_SILENT Sync po/docbooks with svn 2024-01-30 01:22:09 +00:00
Xaver Hugl b1414033ef colorimetry: use 4x4 matrices for colorimetry transforms
This is so that offsets can be represented in the matrices and not just
scaled and rotated coordinate systems
2024-01-29 22:15:21 +00:00
Xaver Hugl 4dd1e91bda wayland: implement experimental tag of the upstream color management protocol
Support is hidden by an environment variable to prevent accidental standardization
on this experimental version. It allows app devs to already implement and
test it though, and easily switch to the proper protocol later
2024-01-29 23:07:38 +01:00
Vlad Zahorodnii a64c86b73f wayland: Install headers generated by qtwaylandscanner 2024-01-29 22:32:57 +02:00
Vlad Zahorodnii e23cb52a16 wayland: Add windows when readyForPainting changes
A window is added to the workspace when it's mapped. It's assumed that
the first Window::windowShown signal indicates that. But it's not
entirely true. For example, if setHidden(false); setHidden(true); are
called in succession, the window will be marked as ready for painting
even though it isn't.

The Window::readyForPaintingChanged() signal fixes that. It's emitted
when the window is actually mapped.
2024-01-29 12:35:10 +02:00
Xaver Hugl b05fa94d32 backends/drm: don't set the content type drm property
We haven't seen any benefit from passing it through from apps and apparently
it can make atomic commits fail in some cases.

BUG: 480454
2024-01-29 11:55:50 +02:00
Akseli Lahtinen 91974b7794 Set correct opaqueRegion for Xwayland apps 2024-01-29 09:34:57 +00:00
Vlad Zahorodnii d9e96223f4 plugins/slidingpopups: Avoid sliding already hidden popups 2024-01-29 11:14:15 +02:00
Vlad Zahorodnii 341067d4d7 Port ScreenEdges::recreateEdges() to std::span 2024-01-29 11:14:15 +02:00
Vlad Zahorodnii 16aaf92782 Reserve a screen edge on the same output as the window
This makes the association between the window's output and the screen
edge's output more robust.
2024-01-29 11:14:15 +02:00
Vlad Zahorodnii 2d399e93f0 Relax constraints for screen edges reserved by windows
At the moment, if the workspace extends or shrinks by an output, the
hidden panel will be shown. It doesn't make sense in all cases.

Furthermore, no screen edge will be reserved if the layer surface has
some margins.

To address that, allow "floating" panels reserve screen edges and also
make kwin try harder to preserve window edges if the output layout
changes.

CCBUG: 448420
2024-01-29 11:14:15 +02:00
Vlad Zahorodnii aaa35d455c plugins/shakecursor: Ignore pointer motion events when the pointer is constrained
The main motivation is to prevent the shake cursor from triggering in
video games. It's not a bullet-proof solution though.
2024-01-29 11:05:15 +02:00
Vlad Zahorodnii 1eb95982dc autotests: Disable outline in breeze
Some our tests assume that with "none" border size, the decoration has
no borders. When breeze paints an outline, that's not the case.
2024-01-29 11:04:05 +02:00
Vlad Zahorodnii b21229e59a wayland: Implement closeable window rule
BUG: 443129
2024-01-29 10:57:29 +02:00
Vlad Zahorodnii 35572904fc effect: Overwrite the output in OffscreenQuickView::setGeometry()
It seems like QWindow::setGeometry() won't update the associated output
if no platform window has been created, which is the case when running
overview or any other qml effect.

It's not clear whether this is a Qt bug or intended behavior.
qwindow.cpp contains comments assuming that the window is on the primary
output if no platform window exists.
2024-01-29 10:51:54 +02:00
Vlad Zahorodnii 601d33f294 effect: Allocate an offscreen fbo with correct scale in OffscreenQuickView
QQuickWindow::effectiveDevicePixelRatio() uses the device pixel ratio
of the attached QQuickRenderTarget. Instead, the scale factor of the
output should be used, which is what QWindow::devicePixelRatio() returns.
2024-01-29 10:51:54 +02:00
Fushan Wen 75b08a8fd9 tabbox/switchers/thumbnail_grid: use FocusScope as main item
By default the focus item in a tabbox is always the main item, so if the
main item is not a focus scope, the inner item will not get focused.

BUG: 477286
FIXED-IN: 6.0
2024-01-29 10:36:14 +02:00
l10n daemon script ab631c2147 GIT_SILENT Sync po/docbooks with svn 2024-01-29 01:18:52 +00:00
l10n daemon script 53fa2bfbd6 GIT_SILENT Sync po/docbooks with svn 2024-01-28 01:22:25 +00:00
l10n daemon script 0300c17441 GIT_SILENT Sync po/docbooks with svn 2024-01-27 01:19:51 +00:00
Vlad Zahorodnii 1b6aa65ee5 autotests: Add layer_surface_v1.set_exclusive_edge test cases 2024-01-26 13:55:13 +02:00
Marco Martin fe8fe42ea9 wayland: Add support for layer_surface_v1.set_exclusive_edge
This can be used to disambiguate the exclusive edge when the anchors are
on a corner (so there would be 2 candidates)

it's quite quick and dirty mostly to understand if we do want to push for
something along the lines (it should at least do a protocol error when
the requested edge is not within the anchors)
2024-01-26 13:34:48 +02:00
l10n daemon script 2d2ee710c8 GIT_SILENT Sync po/docbooks with svn 2024-01-26 01:22:02 +00:00
l10n daemon script 5876269f66 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-26 01:13:56 +00:00
Vlad Zahorodnii 91ae3d907e plugins/zoom: Unset PAINT_SCREEN_TRANSFORMED
It's not needed because of the offscreen texture.

BUG: 480216
2024-01-25 15:10:18 +02:00
Vlad Zahorodnii 2505fd03f1 kconf_update: Add script to drop old desktop switching shortcuts
BUG: 479984
2024-01-25 10:52:19 +02:00
Xaver Hugl bbc833baa6 core/renderloop: take the output of the active window into account for vrr scheduling
If the active window is on a different output than the one the renderloop is for,
the scheduling logic would otherwise never schedule a repaint while adaptive sync
is active.

BUG: 480252
2024-01-25 10:29:57 +02:00
Xaver Hugl bb2391133d plugins/screencast: hardcode DRM_FORMAT_ARGB8888 for screencasts
It's universally supported, and our format negotiation code needs improvements to
properly handle the receiving application not suporting the actual output format
2024-01-25 10:19:15 +02:00
Nicolas Fella 06230e43d6 Remove wrong handling of Qt::KeypadModifier
Qt::KeypadModifier doesn't actually map to any XKB modifier

The XKB_MOD_NAME_NUM modifier is (semi-)unrelated
2024-01-25 10:10:11 +02:00
l10n daemon script 957e73a889 GIT_SILENT Sync po/docbooks with svn 2024-01-25 01:18:34 +00:00
l10n daemon script daad3b9d7c SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-25 01:12:07 +00:00
Vlad Zahorodnii 9cdf19c657 autotests: Add keypad global shortcuts test 2024-01-24 13:20:58 +00:00
Nicolas Fella 296d3f31be Consider Qt::KeypadModifier relevant for global shortcuts
Otherwise kglobalaccel can't distinguish between numbers on the num block and other numbers

BUG: 453423

BUG: 446389
2024-01-24 13:20:58 +00:00
Vlad Zahorodnii 25150633ed kconf_update: Update Version
kconf_expects version 6.
2024-01-24 12:16:22 +02:00
Vlad Zahorodnii 3bce89553c Prefer QRegion::operator+=
`QRegion::operator|=` has some optimizations but it basically boils
down to

  QRegion result(*this);
  result.detach(); // it will make a copy because this is shared
  result.d->append(rect);
  return result;

On the other hand, `QRegion::operator+=` tries to add the new rect
in-place.
2024-01-24 10:26:02 +02:00
Vlad Zahorodnii f44484137e plugins/blur: Fix blur behind decoration
Currently, if only blur behind decoration is enabled, no m_windows entry
is going to be created and so the blur effect won't blur the background.

BUG: 479893
2024-01-24 10:24:57 +02:00
Vlad Zahorodnii e01116149b tests: Fix constraint region in pointerconstraints example 2024-01-24 10:23:45 +02:00
l10n daemon script a1b47dfa08 GIT_SILENT Sync po/docbooks with svn 2024-01-24 01:19:44 +00:00
l10n daemon script f065ee6d06 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-24 01:12:23 +00:00
Vlad Zahorodnii 3663e1ec13 Apply "Accepts focus" window rule to WM_TAKE_FOCUS messages as well
Currently the window rule is not 100% effective because the "take focus"
message is not guarded. So depending on the input model of the X11
window, kwin can still activate a window even if it has a window rule
to force no focus.

workspace()->setShouldGetFocus() should be guarded too to help the focus
stealing prevention logic.

Technically though, forcing XSetInputFocus() or WM_TAKE_FOCUS if the
client doesn't advertise supporting them is finiky. But on the other
hand, the window rules are an advanced feature, so its assumed that the
user knows what they do.
2024-01-23 22:11:16 +02:00
Vlad Zahorodnii bbb40a9a84 Fix lingering dpms input event filter after cancelling scheduled dpms mode change
The output goes through the following stages when it changes its dpms
mode:

- Output::aboutToTurnOff()]
- some time later, Output::dpmsModeChanged() to indicate that it's off
- Output::dpmsModeChanged() to indicate that it's back on
- Output::wakeUp()

The Output::dpmsModeChanged() signals in the middle are optional. They
may not be emitted after Output::aboutToTurnOff() if the user quickly
cancels the dpms mode transition.

The Workspace should monitor the Output::wakeUp() signal instead.
Alternatively, create the dpms input event filter only after the dpms
mode has changed. While the screen won't be turned back on immediately,
it's still going to produce acceptable visuals. Either solution is fine.
This patch makes the Workspace monitor the wakeUp signal because it
takes fewer lines of code.

BUG: 479659
2024-01-23 22:05:25 +02:00
Yifan Zhu adc076322b plugins/fallapart: use InCubic easing
This visual effect corresponds to visible to invisible. So use InCubic
easing for opacity and speed.
2024-01-23 22:00:14 +02:00
Vlad Zahorodnii d0a49a6b77 helpers/wayland_wrapper: Bump the buffer size for display_name
The compiler prints the following warning at the moment:

    wl-socket.c:143:9: note: ‘snprintf’ output between 10 and 20 bytes into a destination of size 16
2024-01-23 21:55:19 +02:00
Xaver Hugl 8db8dd24bf move vao from WorkspaceSceneOpenGL to GlxContext
EglContext already had a vao, and it makes more sense for the context to
take care of this than the scene
2024-01-23 19:40:30 +00:00
Xaver Hugl 7e095412aa outputconfigurationstore: add a fallback for when edid parsing fails
When edid parsing fails, KWin will base output settings on the connector, which
isn't great on its own, but at least works in many cases. When the edid can be
parsed later though, the display settings will reset because now the edid identifier
is used to exclude the old config (in which the latter is missing).
To work around that, this commit adds output identification based on the edid hash,
which is also not ideal, but can be safely matched with in case no output config
with a matching edid identifier exists.
2024-01-23 19:34:06 +00:00
Xaver Hugl 3cafc20981 backensd/drm: directly try presentation with changed properties
This optimizes out an unnecessary atomic test - instead of testing the new state and
then attempting to present with that new state, this just directly tries to present the
full state. If that commit fails, the backend just tries again with the safer presentation
mode.
2024-01-23 19:25:05 +00:00
Xaver Hugl 7a2d95ddc8 outputconfigurationstore: take rotation into account for the position
Otherwise outputs may overlap
2024-01-23 19:19:49 +00:00
Vlad Zahorodnii 575ff68e5b plugins/qpa: Fix a warning about unused variable 2024-01-23 21:10:56 +02:00
Vlad Zahorodnii 01818f683c wayland: Add missing wp_security_context_manager_v1.destroy implementation 2024-01-23 21:00:15 +02:00
Yifan Zhu 8774a0114c plugins/private/Windowheap: Use InOutCubic easing
All transitions correspond to visible to visible changes, and should
have InOutCubic easing as per HIG.
2024-01-23 20:59:04 +02:00
l10n daemon script acb0dc4c24 GIT_SILENT Sync po/docbooks with svn 2024-01-23 01:21:22 +00:00
l10n daemon script 015a8452cd SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-23 01:13:11 +00:00
l10n daemon script 9fa5f7547f GIT_SILENT Sync po/docbooks with svn 2024-01-22 01:36:03 +00:00
Ismael Asensio efde6c8e9e kcms/tabbox: Use higher resolution thumbnails for previews
Replace the hardcoded thumbnails which have a low resolution for
current screen standards (~300x200), with higher resolution ones
(~1200x800).

Also set the new 6.0 wallpaper as the fallback desktop thumbnail

BUG: 446765
FIXED-IN: 5.93.0
2024-01-21 12:47:25 +01:00
Aleix Pol fd7a67d92e screencasting_test: Declaring the metatype is unnecessary now 2024-01-21 11:17:49 +00:00
l10n daemon script daa8785e34 GIT_SILENT Sync po/docbooks with svn 2024-01-21 01:19:39 +00:00
l10n daemon script 2b684146c7 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-21 01:12:31 +00:00
Tino Lorenz adbf69aab4 plugins/buttonrebinds: Support rebinding to modifier keys
Allow rebinding buttons to send modifier keys (Control, Alt, Meta,
Shift) without any other key.
This is part of restoring the functionality kcm-wacomtablet had under
X11 for wayland.
CCBUG: 461259
2024-01-20 15:49:42 +00:00
l10n daemon script 39a5489bde GIT_SILENT Sync po/docbooks with svn 2024-01-20 01:19:39 +00:00
Aki Sakurai ab41bcf3ad Accepting the tablet serial for the xdg_toplevel move/resize function 2024-01-19 20:06:49 +00:00
Xaver Hugl 9822e75fbf core/renderjournal: improve render time heuristics
Instead of giving the rolling average for render times a special case for
when render time suddenly increases, detect how stable render times are.
If they're volatile and increase a lot, increase the predicated render time
beyond the spike, as more render time spikes are likely to follow.

CCBUG: 477959
2024-01-19 20:26:20 +01:00
Vlad Zahorodnii 7ba7ddfee8 opengl: Let OpenGL implementation handle if preprocessor directive
It's less error prone and handles cases like if/elif/else better, etc.

CCBUG: 479279
2024-01-19 16:57:50 +02:00
Vlad Zahorodnii 0284610eff opengl: Fix parsing of the else branch
`it` points to `#else`. We need to move to the next line.

BUG: 479279
2024-01-19 14:44:39 +00:00
Vlad Zahorodnii 7e8230a596 plugins/colorblindnesscorrection: Ensure that error and correction are fully initialized
vec3() will complain if the vector is not fully initialized. Also if the
type of these variables is changed to vec4 and some miss alpha values,
the glsl compiler will complain again.
2024-01-19 14:23:57 +00:00
Vlad Zahorodnii 4cc94e9462 plugins/colorblindnesscorrection: Fix screen becoming white on intel machines
correction.a is uninitialized. It creates problems on intel machines.

BUG: 479749
2024-01-19 14:23:57 +00:00
Aleix Pol 0ce01ac30f screencasting: Fix CI
It seems on the CI the dataFrame is null at times
2024-01-19 14:05:51 +00:00
Stefan Hoffmeister d563bc6c86 Fix mishandling of output configuration if output monitor EDID is missing
This functionally fixes
* duplication of output configuration in ~/.config/kwinoutputconfig.json
* _wrong_ ouput configuration - in particular the scale - being restored (i.e. scale would never be restored)
2024-01-19 13:52:28 +00:00
Vlad Zahorodnii cffacc514d opengl: Correct order of transforms in GLTexturePrivate::updateMatrix
The textureToTransformMatrix should be applied first, otherwise the scale
transform is going to change the winding order of rotations.

In practice though, it shouldn't matter because these matrices are used
to downscale or upscale uv coordinates.
2024-01-19 07:43:30 +00:00
l10n daemon script 428758d33a GIT_SILENT Sync po/docbooks with svn 2024-01-19 01:22:42 +00:00
Aleix Pol 0b36919b7c screencasting_test: Adapt to KPipeWire change 2024-01-19 01:41:47 +01:00
Xaver Hugl 36bec2d941 colors/colordevice: make channel factors linear
The redshift table is in gamma 2.2 encoding and not linear, which means
that it only yields correct results with 1.0 pixel values. It also means
that when it's being applied in linear space in the color management shaders,
the result is quite wrong.

To fix that, this commit makes the channel factors linear and the backend
calculates the nonlinear factors where needed.
2024-01-18 21:51:40 +01:00
Vlad Zahorodnii 788c186701 plugins/shakecursor: Ensure that cursor is magnificated for at least certain amount of time
If the cursor is magnificated and it's slightly moved so the shake
detector returns std::nullopt, the cursor scale will be set back to 1.0
as soon as possible. This is not ideal. Immediately resetting doesn't
help with locating the cursor.

Also the cursor scale reset delay has been increased to two seconds to
provide more time to see the cursor.
2024-01-18 18:03:15 +00:00
Vlad Zahorodnii f6d9b8a0b4 plugins/screenshot: Use SmoothPixmapTransform when stitching area screenshots
CCBUG: 478426
2024-01-18 14:56:33 +00:00
Vlad Zahorodnii f23e0ef05b opengl: Correct transformation order in GLTexture::render()
First, the texture-to-buffer transform has to be applied, then the y
axis should be flipped. Doing it vice versa changes the winding order
of rotation transforms.

Also the screenshot plugin uses incorrect render transform. Since
convertFromGLImage() undoes the render target's transform, the color
space transformation pass should use the same transform, not the
inverted one.

BUG: 479934
2024-01-18 14:15:28 +00:00
Niccolò Venerandi 69f8bee0b1 kcms/screenedges: Hardcode the Overview as an option in the touchscreen KCM
You can now select "Overview" in the touch KCM to use it as a touch edge gesture again!
2024-01-18 14:08:34 +00:00
Xaver Hugl d5ca429627 wayland: consider every commit a "content update" for presentation time
The protocol doesn't have a definition of what it means, but damage is a
flawed interpretation. Color management changes are arguably content updates,
so are viewporter changes, so are blur changes and so on.

Also see https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/36
for an upstream discussion of this
2024-01-18 13:45:18 +00:00
Vlad Zahorodnii da4f4d7e69 Rename UnmanagedLayer to OverlayLayer
The UnmanagedLayer layer is used for placing overlay content so
rename it to match how it's used in practice.
2024-01-18 13:13:55 +00:00
l10n daemon script 9f10d5d79f GIT_SILENT Sync po/docbooks with svn 2024-01-18 01:20:12 +00:00
Fushan Wen f79886765d plugins/colorblindnesscorrection: remove duplicate definition in Tritanopia shader 2024-01-17 23:42:58 +00:00
Vlad Zahorodnii 176ae6e692 Drop window type rule
Practically all code assumes that the window type is static and fixing
it would bring extra complexity, which may not be worth given that there
are window rules to control position, focus, layer, etc.

BUG: 466016
2024-01-17 23:05:53 +00:00
Vlad Zahorodnii 5c4acbdddd Introduce layer window rule
The new window rule allows to overwrite the stack layer. It can be
useful on wayland to force picture-in-picture surfaces (which are
xdg-toplevels at the moment) to be placed above fullscreen windows.
Keep above flag is unsuitable because fullscreen windows are placed
higher "above" windows.

CCBUG: 466016
2024-01-17 23:05:53 +00:00
Vlad Zahorodnii 74a193d383 plugins/shakecursor: Use std::deque to store history
It's more suitable for the task. The ShakeDetector constantly adds new
items at the end of the list and pops old items at the front.
2024-01-17 22:00:30 +02:00
Yifan Zhu 597753047d window: use QRect to calculate visiblePixels
If QRectF is used, the exact comparison several lines down will fail.
2024-01-17 18:05:54 +00:00
Yifan Zhu 2dba3d30af window: don't use exact comparison for QRectFs
With fractional geometries, we can only guarantee that
nextMoveResizeGeom eventually is within one unit of
currentMoveResizeGeom.

BUG: 479786
FIXED-IN: 6.0
2024-01-17 18:05:54 +00:00
Nate Graham e963ae09cc screenedge: reduce default activation delay
Currently there is a 150ms delay before screen edge actions and
hotcorners are triggered; the cursor has to spend that much time there
before they'll activate. This is good for preventing accidental
activations, but also prevents and delays deliberate activations, which
are likely to be more annoying for the user.

To alleviate this, the delay is reduced to 75ms, which still prevents
most of the accidental activations in my testing, while making
deliberate activations faster and easier.
2024-01-17 14:52:05 +00:00
Xaver Hugl 7007599b3f backends/drm: ensure commits are done before vblank
If a commit is applied during vblank, the kernel delays it to the next vblank,
for X11 reasons. To ensure that doesn't happen with KWin, read how long
vblank is for the current mode and adjust the safety margin accordingly.

CCBUG: 477959
2024-01-17 13:47:58 +00:00
David Edmundson 42c61dc6a3 plugins/screencast: Don't recreate the core every stream
Loading pipewire is noticably slow with libpipewire loading a bunch of
internals.

Change from a singleton pattern to being managed by the
ScreencastManager

This is still unloaded if the plugin is explicitly stopped.
2024-01-17 13:27:00 +00:00
Vlad Zahorodnii 9c2f12f98f backends/drm: Provide a way to force color management
It can be handy if kwin runs on a setup not capable of HDR or without an
ICC profile. The output management protocol has not been touched because
the long term goal is to have color management enabled by default. This
is rather for testing purposes.
2024-01-17 13:23:15 +02:00
Xaver Hugl e9db9cd7d3 plugins/fullscreen: retarget the animation instead of restarting it
BUG: 474488
FIXED-IN: 6.0
2024-01-17 11:18:35 +01:00
Jie Liu 1a1eaee13f Only precompute the geometry restore when m_interactiveMoveResize.initialQuickTileMode is None
If the user wants to move a tiled window but changes their mind and tiles the window back to the previous
position, quickTileGeometryRestore() will return an error value beacause m_electricMaximizing is true and
the m_electricGeometryRestore is the same as the geometry of the window in the last tiled mode.

Now the geometry restore of the tiled window is true when starting interactive move, so we no longer need
to precompute it.

Changes for testQuickTilingPointerMove:

We need to attach a new image after the tiling window, so that updateElectricGeometryRestore can obtain
the same framegeometry as the framegeometry obtained during actual runtime.

Now testQuickTilingPointerMove can detect the error:If the user wants to move a tiled window but changes
their mind and tiles the window back to the previous position, quickTileGeometryRestore() will return an
error value beacause m_electricMaximizing is true and the m_electricGeometryRestore is the same as the
geometry of the window in the last tiled mode.

Signed-off-by: Jie Liu <liujie01@kylinos.cn>
2024-01-17 01:03:27 +00:00
Xaver Hugl fd2e77317f wayland/surface: store subsurface transaction in a unique_ptr 2024-01-17 00:12:38 +00:00
Xaver Hugl 6ab8f179a7 backends/drm: apply the ICC profile without premultiplication
As a side effect, this ensures that when alpha is zero, rgb is zero as well.
This is needed because the ICC profile may contain transformations where zero
brightness gets mapped to a non-zero value.

BUG: 479380
2024-01-16 19:42:12 +01:00
Xaver Hugl ed339de953 opengl/glshadermanager: add missing newline
BUG: 479279
2024-01-16 14:42:27 +01:00
David Redondo 203c4998bc Make sure window thumbnails and Qt Quick resources are destroyed properly
Drops the doneCurrent as it was preventing proper cleanUp
because no context was current when textures were deleted.
Also avoid manipulating the context when Qt has the current
one, as various Qt classes have guards around their cleanup
handlers which rely on a current Qt context.
Despite the comment the order of render control and view destruction
needs to be switched as the QQuickWindow destructor calls into
the render control to notify if of window destruction.
BUG:478770
BUG:479846
FIXED-IN:6.0
2024-01-16 13:45:52 +01:00
l10n daemon script 3dd18a543b GIT_SILENT Sync po/docbooks with svn 2024-01-16 01:21:56 +00:00
Xaver Hugl 4433fb48dc backends/drm: make icc profiles work with OpenGL ES
OpenGL doesn't support 1D textures, and has some special requirements in
the shaders, like no implicit conversion from int to float
2024-01-15 18:56:54 +00:00
Joshua Goins c3d3d83b56 Add missing find_dependency for epoxy
This is required by the KWin target, but was missing a find_dependency
call. If any downstream project tried to link to the KWin::kwin target,
it would fail because epoxy couldn't be found.
2024-01-15 18:02:44 +00:00
David Edmundson 2e6619f3d0 screencasting: Resume streams after buffer renegotiation
When we start renegotiation the stream is pasused. This is not restarted
when the format has been renegotiated.

This occurred when a streaming window was resized
2024-01-15 16:53:01 +00:00
Vlad Zahorodnii f665dda192 scene: Remove warning message about older presentation timestamps
Outputs present frames at different pace, some can present new content
later, some sooner. If the scene gets a slightly older presentation
timestamp, it's okay.
2024-01-15 15:55:06 +00:00
Vlad Zahorodnii af39179446 Break show desktop mode if a new window is added
BUG: 479424
2024-01-15 15:41:57 +00:00
Vlad Zahorodnii 359f36d6ab autotests: Add a test to verify that show desktop mode quits after activating a window 2024-01-15 15:41:57 +00:00
Vlad Zahorodnii 3b67edf20d backends/drm: Fix a crash in VirtualEglGbmLayer::texture()
If nothing has been rendered yet, m_currentSlot will be null.

BUG: 475296
BUG: 479558
2024-01-15 15:07:39 +00:00
Vlad Zahorodnii 72c391ebc8 effect: Remove const refs in EffectFrame
It's a micro optimization.
2024-01-15 14:42:27 +00:00
Vlad Zahorodnii 09f97c8037 plugins/mouseclick: Fix glitches
Effect frame geometry is not properly synchronized with the quick
scene geometry.

BUG: 477892
2024-01-15 14:42:27 +00:00
Vlad Zahorodnii b98607c689 Fix cleanup of forced window shortcuts
XdgToplevelWindow doesn't call finishWindowRules(). It creates a problem
for Workspace::removeWindow() because it calls setShortcut() to release
the window shortcut.

While one way to fix the bug would be to add a finishWindowRules() call
in XdgToplevelWindow, it would perhaps be not the best one because it
would change the appearance of decoration when the window is closed.

Instead, this change makes the workspace release the shortcut when the
window is closed. It has a couple of advantages: the appearance of the
decoration won't change, shortcut cleanup is better encapsulated.

BUG: 478647
2024-01-15 14:24:59 +00:00
Vlad Zahorodnii 4f8c941bff scripting: Fix a crash in useGlThumbnails() when compositing is off
BUG: 479791
2024-01-15 14:07:51 +00:00
Vlad Zahorodnii 2d71d7cada plugins: Hide "Drag Down to Close" when using a pointing device
BUG: 479802
2024-01-15 15:35:03 +02:00
Vlad Zahorodnii 0ddcc85f68 plugins/shakecursor: Ignore motion events with at least one pressed button
It reduces the chances of false triggering the plugin, for example if
the user presses a mouse button and chaotically moves the pointer
because they navigate in 3D space and what not.
2024-01-15 08:24:29 +00:00
Yifan Zhu 1f74e9a5c5 scene/cursordelegate_opengl: undo ortho() flip y
Flip y axis before and after applying renderTarget.transform to undo
ortho() flipping the y axis. Otherwise the cursor is invisible on
rotated screen.

BUG: 479764
FIXED-IN: 6.0
2024-01-14 20:48:58 -08:00
Joshua Goins e00a26d72d Fix link to Frameworks Coding Style in CONTRIBUTING
The double parenthesis may trip up certain markdown viewers, and the
location of the wiki page has changed too.
2024-01-14 21:15:26 +00:00
Weng Xuetian 1fd5a6555e
inputmethod: Ensure InputPanelV1Window is always within the screen
Currently when input panel is using overlay mode and the cursor rectangle
is below or above the screen area, the input panel may be placed off the
screen. The change ensure it is always placed within the screen area
using similar math like xdg_popup's slide_y constrain.
2024-01-13 22:39:15 -08:00
l10n daemon script 4f512c6571 GIT_SILENT Sync po/docbooks with svn 2024-01-14 01:37:02 +00:00
Yifan Zhu faab23e914 kcms/options: port to KCModule methods
Remove code that duplicates functionality of KCModule.

Previously the various config items were not fully ported to using
KCModule methods, and kept custom versions of isSaveNeeded and
isDefault. When called from KWinOptions::updateUnmanagedState, these
methods incorrectly reports that there are still changes to be saved.
This patch set ports all configs in window behavior to methods provided
by KCModule, solving the problem.

BUG: 477940
2024-01-13 10:04:52 -08:00
Ismael Asensio 3353ed87ef kcms/tabbox: Mock-up closeable role for previews
Fixes a qml warning and wrong representation when trying to
access this model property
2024-01-13 15:26:13 +01:00
Ismael Asensio 3572e6f0e7 kcms/tabbox: Add mock-up object for KWin.DesktopBackground
The window switcher previews don't use the actual quick components
the KWin plugin provides, but mock-up objects of those.

Add a mock-up component for `KWin.DesktopBackground`, which is just
a thumbnail of the desktop default image but stretched to cover the
whole parent size.

This fixes the previews for flip&cover window switchers.

BUG: 479552
FIXED-IN: 5.93.0
2024-01-13 15:26:13 +01:00
Xaver Hugl c1e09f65c9 opengl/glshader: use gamma 2.2 for sRGB render targets
The sRGB global colordescription uses gamma 2.2, so this function also has to do
it, or the shader will end up doing a colorspace conversion where there shouldn't
be one.
This also meams that HDR content will be wrongly encoded, but fixing that while
also dealing with sRGB content correctly requires a lot more invasive changes, in
KWin and in the screenshot and screencast APIs.

BUG: 478967
2024-01-13 13:28:03 +00:00
Ismael Asensio 20bee00681 kcms/tabbox: Fix preview for show desktop option
Use the correct config option to decide whether to show the desktop
thumbnail on preview. "DesktopMode" refers to filter by desktop.
2024-01-13 13:32:50 +01:00
Alexander Lohnau 7d1db53f6b Remove unneeded includes from headers and cpp files 2024-01-13 11:34:45 +01:00
Alexander Lohnau d8012cf00c decorationbridge: Slight code cleanup 2024-01-13 10:59:17 +01:00
l10n daemon script 24168aebdb GIT_SILENT Sync po/docbooks with svn 2024-01-13 01:27:27 +00:00
l10n daemon script 2a07aa238f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-01-13 01:15:23 +00:00
Ismael Asensio b08a4a1896 kcms/tabbox: Fix tabbox preview not getting dismissed
On X11 we would dismiss the tabbox preview when clicking outside
of the switcher. This doesn't work on Wayland because the popup
cannot globally grab the mouse and doesn't get notified.

Use `QEvent::FocusOut` instead which works on both platforms.

We also get rid of a warning message.

BUG: 374971
FIXED-IN: 5.93.0
2024-01-12 23:10:06 +01:00
Xaver Hugl 427ce522a2 opengl/glshader: print the shader source if compilation fails
The shader log is almost entirely useless without the source

CCBUG: 479279
2024-01-12 20:42:05 +00:00
Xaver Hugl d4a3d6689e backends/drm: wait for the pageflip to be done with the condition variable
...instead of busy looping, which is causing several percent CPU usage in some cases

BUG: 479126
2024-01-12 19:15:25 +01:00
Xaver Hugl 56fc8f83ac backends/drm: don't call QThread::currentThread in a loop
We're always in the same thread, so there's no need to check it
2024-01-12 17:00:01 +01:00
Xaver Hugl a89d1f8058 opengl/openglcontext: require support for RGBA16F framebuffers
It's effectively already required, this just checks it earlier
2024-01-12 15:19:25 +01:00
Vlad Zahorodnii c59f385996 wayland: Fix handling of unminimization for not fully initialized xdg-toplevels
If setMinimized(false) is called for a not fully initialized
XdgToplevelWindow, we don't want to emit the windowShown signal.

BUG: 479234
2024-01-12 12:29:33 +00:00
Vlad Zahorodnii 1c15a6dd88 Fix software cursor stucking on old monitor
When the software cursor leaves an output, its RenderLayer is marked
as invisible and the area corresponding to the layer is scheduled to
be repainted in the output layer. However, the composite function only
checks whether the root RenderLayer needs a repaint, not the output
layer too.

BUG: 479668
2024-01-12 14:14:53 +02:00
Xaver Hugl 260bc0a61d input: remove the terminate server shortcut
Accidentally pressing any shortcut shouldn't take down the whole session.
If KWin isn't reponsive but can still process shortcuts for some reason,
you can still switch to a different virtual terminal to explicitly kill
it from there
2024-01-11 23:21:22 +00:00
Xaver Hugl 451b878bb9 backends/drm: don't allow implicit modifiers for multi gpu transfers
As we translate DRM_FORMAT_MOD_LINEAR to implicit modifiers + linear flag, the
egl import path should still work without implicit modifiers too.

BUG: 478921
2024-01-11 19:07:51 +00:00
Vlad Zahorodnii 36222adb25 scene: Fix software cursor clip region
The dirty region is in the output local coordinate space.

BUG: 479583
2024-01-11 18:10:04 +00:00
Vlad Zahorodnii 571e4026ac core: Add Output::rectF 2024-01-11 18:10:04 +00:00
Vlad Zahorodnii c314705d53 core: Rename Output::fractionalGeometry()
In Qt, if an overloaded function returns QRectF/QSizeF/QPointF, it
usually has F suffix. Do the same in kwin for the consistency sake.
2024-01-11 18:10:04 +00:00
Xaver Hugl bc58d13ee8 opengl: don't crash in GLTexture::toImage with OpenGL ES
OpenGL ES 2 doesn't support glGetTexImage
2024-01-11 16:58:04 +00:00
Bart Ribbers a879c59a08 Fix building of tests on Musl by making sure to include sys/select.h
Required for access to fd_set
2024-01-11 17:00:09 +01:00
Vlad Zahorodnii bc30ca64dc Fix evaluating window rules for closed windows
gedit changes its caption from "Untitled document - gedit" to "gedit"
when it closes. This schedules Window::evaluateWindowRules() to be
called when the window is already marked as deleted. kwin then crashes.

In order to prevent that, a direct connection can be used instead. But
then the caption must be initialized extra carefully because if the
window rule changes the window type, "<N>" can be lost.
2024-01-11 14:17:31 +00:00
Vlad Zahorodnii 4ab504c994 Add Window::captionNormalChanged()
This signal notifies when the client specified caption changes, not when
kwin changes it because it changed the suffix, etc.
2024-01-11 14:17:31 +00:00
Vlad Zahorodnii 68f1570d45 scene: Fix alpha channel of offscreen cursor texture
When running with 10bpc, the alpha channel has only 2 bits for it, which
is too low for the cursor.

BUG: 479637
2024-01-11 13:44:36 +00:00
Vlad Zahorodnii 3a5ba58a45 effect: Install xcb.h
BUG: 479584
2024-01-11 09:10:06 +00:00
Jin Liu 18ba622c40 Update keyboard focus when exiting from a keyboard-grabbing effect
BUG: 479628
2024-01-11 16:40:44 +08:00
Jie Liu e427ad73aa update keyboard focus when window switcher is closed.
BUG:477885

Signed-off-by: Jie Liu <liujie01@kylinos.cn>
2024-01-11 01:28:52 +00:00
l10n daemon script 4d3779f061 GIT_SILENT Sync po/docbooks with svn 2024-01-11 01:19:25 +00:00
Xaver Hugl a05a6d8727 effect/offscreenquickview: always use GL_RGBA8
GL_RGB8 isn't supported by OpenGL ES

BUG: 479055
2024-01-10 20:56:15 +01:00
Vlad Zahorodnii 66b1462cf8 xwayland: Make xinerama index -> Output mapping more robust with fractional scaling
xdg-output-v1 uses the fractional geometry, so also use it when mapping
a xinerama screen index to an Output.
2024-01-10 15:18:48 +00:00
Jonathan Esk-Riddell 61699e9ed3 Update version number for 6.0.80
GIT_SILENT
2024-01-10 14:03:49 +00:00
Vlad Zahorodnii 3f1e57de1c xwayland: Fix primary output identification
Output::geometry() returns a logical geometry, while the crtc rect is in
the device pixels.
2024-01-10 12:41:31 +00:00
1735 changed files with 102760 additions and 81751 deletions

View File

@ -81,3 +81,6 @@ AllowShortLambdasOnASingleLine: Empty
# We do not want clang-format to put all arguments on a new line
AllowAllArgumentsOnNextLine: false
# Indent lambdas to the start of the line, not to the start of the lambda
LambdaBodyIndentation: OuterScope

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ CMakeLists.txt.user*
.idea
/cmake-build*
.cache
.directory

View File

@ -7,8 +7,8 @@ include:
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/freebsd-qt6.yml
suse_tumbleweed_qt66_reduced_featureset:
extends: suse_tumbleweed_qt66
suse_tumbleweed_qt67_reduced_featureset:
extends: suse_tumbleweed_qt67
script:
- git config --global --add safe.directory $CI_PROJECT_DIR
- python3 -u ci-utilities/run-ci-build.py --project $CI_PROJECT_NAME --branch $CI_COMMIT_REF_NAME --platform Linux --extra-cmake-args="-DKWIN_BUILD_KCMS=OFF -DKWIN_BUILD_SCREENLOCKER=OFF -DKWIN_BUILD_TABBOX=OFF -DKWIN_BUILD_ACTIVITIES=OFF -DKWIN_BUILD_RUNNERS=OFF -DKWIN_BUILD_NOTIFICATIONS=OFF -DKWIN_BUILD_GLOBALSHORTCUTS=OFF" --skip-publishing
- python3 -u ci-utilities/run-ci-build.py --project $CI_PROJECT_NAME --branch $CI_COMMIT_REF_NAME --platform Linux --extra-cmake-args="-DKWIN_BUILD_KCMS=OFF -DKWIN_BUILD_SCREENLOCKER=OFF -DKWIN_BUILD_TABBOX=OFF -DKWIN_BUILD_ACTIVITIES=OFF -DKWIN_BUILD_RUNNERS=OFF -DKWIN_BUILD_NOTIFICATIONS=OFF -DKWIN_BUILD_GLOBALSHORTCUTS=OFF -DKWIN_BUILD_X11=OFF -DKWIN_BUILD_EIS=OFF" --skip-publishing

View File

@ -1,14 +1,15 @@
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VERSION "5.92.0") # Handled by release scripts
set(PROJECT_VERSION "6.1.80") # Handled by release scripts
project(KWin VERSION ${PROJECT_VERSION})
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJECT_DEP_VERSION "6.1.1")
set(QT_MIN_VERSION "6.6.0")
set(KF6_MIN_VERSION "5.240.0")
set(KF6_MIN_VERSION "6.2.0")
set(KDE_COMPILERSETTINGS_LEVEL "5.82")
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
@ -47,6 +48,9 @@ option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON)
option(KWIN_BUILD_NOTIFICATIONS "Enable building of KWin with knotifications support" ON)
option(KWIN_BUILD_SCREENLOCKER "Enable building of KWin lockscreen functionality" ON)
option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON)
option(KWIN_BUILD_X11 "Enable building kwin_x11 and Xwayland support" ON)
option(KWIN_BUILD_GLOBALSHORTCUTS "Enable building of KWin with global shortcuts support" ON)
option(KWIN_BUILD_RUNNERS "Enable building of KWin with krunner support" ON)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Concurrent
@ -77,6 +81,7 @@ endif()
# required frameworks by Core
find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
Auth
ColorScheme
Config
ConfigWidgets
CoreAddons
@ -109,14 +114,14 @@ set_package_properties(Threads PROPERTIES
TYPE REQUIRED
)
find_package(KWayland ${PROJECT_VERSION} CONFIG)
find_package(KWayland ${PROJECT_DEP_VERSION} CONFIG)
set_package_properties(KWayland PROPERTIES
PURPOSE "Required to build wayland platform plugin and tests"
TYPE REQUIRED
)
# optional frameworks
find_package(PlasmaActivities ${PROJECT_VERSION} CONFIG)
find_package(PlasmaActivities ${PROJECT_DEP_VERSION} CONFIG)
set_package_properties(PlasmaActivities PROPERTIES
PURPOSE "Enable building of KWin with kactivities support"
TYPE OPTIONAL
@ -130,20 +135,20 @@ set_package_properties(KF6DocTools PROPERTIES
)
add_feature_info("KF6DocTools" KF6DocTools_FOUND "Enable building documentation")
find_package(KF6Kirigami2 ${KF6_MIN_VERSION} CONFIG)
set_package_properties(KF6Kirigami2 PROPERTIES
find_package(KF6Kirigami ${KF6_MIN_VERSION} CONFIG)
set_package_properties(KF6Kirigami PROPERTIES
DESCRIPTION "A QtQuick based components set"
PURPOSE "Required at runtime for several QML effects"
TYPE RUNTIME
)
find_package(Plasma ${PROJECT_VERSION} CONFIG)
find_package(Plasma ${PROJECT_DEP_VERSION} CONFIG)
set_package_properties(Plasma PROPERTIES
DESCRIPTION "A QtQuick based components set"
PURPOSE "Required at runtime for several QML effects"
TYPE RUNTIME
)
find_package(KDecoration2 ${PROJECT_VERSION} CONFIG)
find_package(KDecoration2 ${PROJECT_DEP_VERSION} CONFIG)
set_package_properties(KDecoration2 PROPERTIES
TYPE REQUIRED
PURPOSE "Required for server side decoration support"
@ -187,33 +192,25 @@ if (epoxy_HAS_GLX)
endif()
endif()
check_cxx_source_compiles("
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
int main() {
const int size = 10;
int fd = memfd_create(\"test\", MFD_CLOEXEC | MFD_ALLOW_SEALING);
ftruncate(fd, size);
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
mmap(nullptr, size, PROT_WRITE, MAP_SHARED, fd, 0);
}" HAVE_MEMFD)
find_package(Wayland 1.22)
set_package_properties(Wayland PROPERTIES
TYPE REQUIRED
PURPOSE "Required for building KWin with Wayland support"
)
if (Wayland_VERSION VERSION_GREATER_EQUAL 1.23)
set(HAVE_WL_DISPLAY_SET_DEFAULT_MAX_BUFFER_SIZE 1)
else()
set(HAVE_WL_DISPLAY_SET_DEFAULT_MAX_BUFFER_SIZE 0)
endif()
find_package(WaylandProtocols 1.32)
find_package(WaylandProtocols 1.34)
set_package_properties(WaylandProtocols PROPERTIES
TYPE REQUIRED
PURPOSE "Collection of Wayland protocols that add functionality not available in the Wayland core protocol"
URL "https://gitlab.freedesktop.org/wayland/wayland-protocols/"
)
find_package(PlasmaWaylandProtocols 1.9.0 CONFIG)
find_package(PlasmaWaylandProtocols 1.13.0 CONFIG)
set_package_properties(PlasmaWaylandProtocols PROPERTIES
TYPE REQUIRED
PURPOSE "Collection of Plasma-specific Wayland protocols"
@ -231,12 +228,67 @@ else()
set(HAVE_XKBCOMMON_NO_SECURE_GETENV 0)
endif()
pkg_check_modules(XKBX11 IMPORTED_TARGET xkbcommon-x11 REQUIRED)
add_feature_info(XKBX11 XKBX11_FOUND "Required for handling keyboard events in X11 backend")
if (KWIN_BUILD_X11)
pkg_check_modules(XKBX11 IMPORTED_TARGET xkbcommon-x11 REQUIRED)
add_feature_info(XKBX11 XKBX11_FOUND "Required for handling keyboard events in X11 backend")
# All the required XCB components
find_package(XCB 1.10 REQUIRED COMPONENTS
COMPOSITE
CURSOR
DAMAGE
DRI3
GLX
ICCCM
IMAGE
KEYSYMS
PRESENT
RANDR
RENDER
SHAPE
SHM
SYNC
XCB
XFIXES
XKB
XINERAMA
XINPUT
)
set_package_properties(XCB PROPERTIES TYPE REQUIRED)
find_package(X11_XCB)
set_package_properties(X11_XCB PROPERTIES
PURPOSE "Required for building X11 windowed backend of kwin_wayland"
TYPE OPTIONAL
)
find_package(Xwayland)
set_package_properties(Xwayland PROPERTIES
URL "https://x.org"
DESCRIPTION "Xwayland X server"
TYPE RUNTIME
PURPOSE "Needed for running kwin_wayland"
)
set(HAVE_XWAYLAND_LISTENFD ${Xwayland_HAVE_LISTENFD})
set(HAVE_XWAYLAND_ENABLE_EI_PORTAL ${Xwayland_HAVE_ENABLE_EI_PORTAL})
set(HAVE_GLX ${epoxy_HAS_GLX})
get_target_property(QT_DISABLED_FEATURES Qt6::Gui QT_DISABLED_PUBLIC_FEATURES)
if("xcb_glx_plugin" IN_LIST QT_DISABLED_FEATURES)
message(STATUS "Disable GLX because Qt6::Gui was built without xcb_glx_plugin")
set(HAVE_GLX false)
endif()
# for kwin internal things
set(HAVE_X11_XCB ${X11_XCB_FOUND})
endif()
find_package(Libinput 1.19)
set_package_properties(Libinput PROPERTIES TYPE REQUIRED PURPOSE "Required for input handling on Wayland.")
find_package(Libeis-1.0)
set_package_properties(Libeis PROPERTIES TYPE OPTIONAL PURPOSE "Required for emulated input handling.")
find_package(UDev)
set_package_properties(UDev PROPERTIES
URL "https://www.freedesktop.org/wiki/Software/systemd/"
@ -245,7 +297,7 @@ set_package_properties(UDev PROPERTIES
PURPOSE "Required for input handling on Wayland."
)
find_package(Libdrm 2.4.112)
find_package(Libdrm 2.4.116)
set_package_properties(Libdrm PROPERTIES TYPE REQUIRED PURPOSE "Required for drm output on Wayland.")
find_package(gbm)
@ -281,35 +333,6 @@ set_package_properties(lcms2 PROPERTIES
PURPOSE "Required for the color management system"
)
# All the required XCB components
find_package(XCB 1.10 REQUIRED COMPONENTS
COMPOSITE
CURSOR
DAMAGE
DRI3
GLX
ICCCM
IMAGE
KEYSYMS
PRESENT
RANDR
RENDER
SHAPE
SHM
SYNC
XCB
XFIXES
XKB
XINERAMA
)
set_package_properties(XCB PROPERTIES TYPE REQUIRED)
find_package(X11_XCB)
set_package_properties(X11_XCB PROPERTIES
PURPOSE "Required for building X11 windowed backend of kwin_wayland"
TYPE OPTIONAL
)
find_package(Freetype)
set_package_properties(Freetype PROPERTIES
DESCRIPTION "A font rendering engine"
@ -323,15 +346,6 @@ set_package_properties(Fontconfig PROPERTIES
PURPOSE "Needed for KWin's QPA plugin."
)
find_package(Xwayland)
set_package_properties(Xwayland PROPERTIES
URL "https://x.org"
DESCRIPTION "Xwayland X server"
TYPE RUNTIME
PURPOSE "Needed for running kwin_wayland"
)
set(HAVE_XWAYLAND_LISTENFD ${Xwayland_HAVE_LISTENFD})
find_package(Libcap)
set_package_properties(Libcap PROPERTIES
TYPE OPTIONAL
@ -355,45 +369,19 @@ set_package_properties(QAccessibilityClient6 PROPERTIES
)
set(HAVE_ACCESSIBILITY ${QAccessibilityClient6_FOUND})
option(KWIN_BUILD_GLOBALSHORTCUTS "Enable building of KWin with global shortcuts support" ON)
pkg_check_modules(libsystemd IMPORTED_TARGET libsystemd)
add_feature_info(libsystemd libsystemd_FOUND "Required for setting up the service watchdog")
if(KWIN_BUILD_GLOBALSHORTCUTS)
find_package(KGlobalAccelD REQUIRED)
endif()
pkg_check_modules(libdisplayinfo IMPORTED_TARGET display-info)
if (NOT libdisplayinfo_FOUND)
pkg_check_modules(libdisplayinfo REQUIRED IMPORTED_TARGET libdisplay-info)
endif()
add_feature_info(libdisplayinfo libdisplayinfo_FOUND "EDID and DisplayID library: https://gitlab.freedesktop.org/emersion/libdisplay-info")
ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 2.15)
ecm_find_qmlmodule(QtQuick.Layouts 1.3)
ecm_find_qmlmodule(QtQuick.Window 2.1)
ecm_find_qmlmodule(QtMultimedia 5.0)
ecm_find_qmlmodule(org.kde.kquickcontrolsaddons 2.0)
ecm_find_qmlmodule(org.kde.plasma.core 2.0)
ecm_find_qmlmodule(org.kde.plasma.components 2.0)
########### configure tests ###############
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "PlasmaActivities_FOUND" OFF)
option(KWIN_BUILD_RUNNERS "Enable building of KWin with krunner support" ON)
set(HAVE_GLX ${epoxy_HAS_GLX})
get_target_property(QT_DISABLED_FEATURES Qt6::Gui QT_DISABLED_PUBLIC_FEATURES)
if("xcb_glx_plugin" IN_LIST QT_DISABLED_FEATURES)
message(STATUS "Disable GLX because Qt6::Gui was built without xcb_glx_plugin")
set(HAVE_GLX false)
endif()
# for kwin internal things
set(HAVE_X11_XCB ${X11_XCB_FOUND})
check_symbol_exists(SCHED_RESET_ON_FORK "sched.h" HAVE_SCHED_RESET_ON_FORK)
add_feature_info("SCHED_RESET_ON_FORK"
HAVE_SCHED_RESET_ON_FORK
"Required for running kwin_wayland with real-time scheduling")
pkg_check_modules(PipeWire IMPORTED_TARGET libpipewire-0.3>=0.3.29)
add_feature_info(PipeWire PipeWire_FOUND "Required for Wayland screencasting")
@ -409,7 +397,17 @@ if (KWIN_BUILD_SCREENLOCKER)
)
endif()
########### global ###############
ecm_find_qmlmodule(QtQuick 2.3)
ecm_find_qmlmodule(QtQuick.Controls 2.15)
ecm_find_qmlmodule(QtQuick.Layouts 1.3)
ecm_find_qmlmodule(QtQuick.Window 2.1)
ecm_find_qmlmodule(QtMultimedia 5.0)
ecm_find_qmlmodule(org.kde.kquickcontrolsaddons 2.0)
ecm_find_qmlmodule(org.kde.plasma.core 2.0)
ecm_find_qmlmodule(org.kde.plasma.components 2.0)
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "PlasmaActivities_FOUND" OFF)
cmake_dependent_option(KWIN_BUILD_EIS "Enable building KWin with libeis support" ON "Libeis-1.0_FOUND" OFF)
include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/src/wayland
@ -417,6 +415,24 @@ include_directories(BEFORE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
check_symbol_exists(SCHED_RESET_ON_FORK "sched.h" HAVE_SCHED_RESET_ON_FORK)
add_feature_info("SCHED_RESET_ON_FORK"
HAVE_SCHED_RESET_ON_FORK
"Required for running kwin_wayland with real-time scheduling")
check_cxx_source_compiles("
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
int main() {
const int size = 10;
int fd = memfd_create(\"test\", MFD_CLOEXEC | MFD_ALLOW_SEALING);
ftruncate(fd, size);
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
mmap(nullptr, size, PROT_WRITE, MAP_SHARED, fd, 0);
}" HAVE_MEMFD)
check_cxx_compiler_flag(-Wno-unused-parameter COMPILER_UNUSED_PARAMETER_SUPPORTED)
if (COMPILER_UNUSED_PARAMETER_SUPPORTED)
add_compile_options(-Wno-unused-parameter)

View File

@ -27,9 +27,9 @@ The Breeze decorations theme is not located in the KWin repository, and is in fa
### Tab Switcher
The default visual appearance of the tab switcher is not located in the KWin repository, and is in fact part of [Plasma Workspace](https://invent.kde.org/plasma/plasma-workspace), located at `lookandfeel/contents/windowswitcher`.
The default visual appearance of the tab switcher is located in `src/tabbox/switchers`.
Other window switchers usually shipped by default are located in [Plasma Addons](https://invent.kde.org/plasma/kdeplasma-addons), located in the `windowswitchers` directory.
Other window switchers usually shipped by default are located in [Plasma Addons](https://invent.kde.org/plasma/kdeplasma-addons), located in the `kwin/windowswitchers` directory.
### Window Management
@ -53,7 +53,7 @@ Other scripting stuff is located in `src/scripting`.
KWin's coding conventions are located [here](doc/coding-conventions.md).
KWin additionally follows [KDE's Frameworks Coding Style]((https://techbase.kde.org/Policies/Frameworks_Coding_Style)).
KWin additionally follows [KDE's Frameworks Coding Style](https://community.kde.org/Policies/Frameworks_Coding_Style).
### Commits

View File

@ -6,5 +6,5 @@ set(KWIN_EFFECTS_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.kwin.
set(KWIN_VIRTUALKEYBOARD_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.kwin.VirtualKeyboard.xml")
set(KWIN_TABLETMODE_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.KWin.TabletModeManager.xml")
set(KWIN_INPUTDEVICE_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.kwin.InputDevice.xml")
set(KWIN_COLORCORRECT_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.kwin.ColorCorrect.xml")
set(KWIN_NIGHTLIGHT_INTERFACE "@PACKAGE_KDE_INSTALL_DBUSINTERFACEDIR@/org.kde.KWin.NightLight.xml")
set(KWIN_WAYLAND_BIN_PATH "@CMAKE_INSTALL_FULL_BINDIR@/kwin_wayland")

View File

@ -45,82 +45,97 @@ ecm_mark_as_test(testVirtualDesktops)
########################################################
# Test ClientMachine
########################################################
set(testClientMachine_SRCS
../src/client_machine.cpp
test_client_machine.cpp
xcb_scaling_mock.cpp
)
add_executable(testClientMachine ${testClientMachine_SRCS})
set_target_properties(testClientMachine PROPERTIES COMPILE_DEFINITIONS "NO_NONE_WINDOW")
if(KWIN_BUILD_X11)
set(testClientMachine_SRCS
../src/client_machine.cpp
test_client_machine.cpp
xcb_scaling_mock.cpp
)
add_executable(testClientMachine ${testClientMachine_SRCS})
set_target_properties(testClientMachine PROPERTIES COMPILE_DEFINITIONS "NO_NONE_WINDOW")
target_link_libraries(testClientMachine
Qt::Concurrent
Qt::GuiPrivate
Qt::Test
Qt::Widgets
target_link_libraries(testClientMachine
Qt::Concurrent
Qt::GuiPrivate
Qt::Test
Qt::Widgets
KF6::ConfigCore
KF6::WindowSystem
KF6::ConfigCore
KF6::WindowSystem
XCB::XCB
XCB::XFIXES
XCB::XCB
XCB::XFIXES
${X11_X11_LIB} # to make jenkins happy
)
add_test(NAME kwin-testClientMachine COMMAND testClientMachine)
ecm_mark_as_test(testClientMachine)
${X11_X11_LIB} # to make jenkins happy
)
add_test(NAME kwin-testClientMachine COMMAND testClientMachine)
ecm_mark_as_test(testClientMachine)
########################################################
# Test XcbWrapper
########################################################
add_executable(testXcbWrapper test_xcb_wrapper.cpp xcb_scaling_mock.cpp)
########################################################
# Test XcbWrapper
########################################################
add_executable(testXcbWrapper test_xcb_wrapper.cpp xcb_scaling_mock.cpp)
target_link_libraries(testXcbWrapper
Qt::GuiPrivate
Qt::Test
Qt::Widgets
target_link_libraries(testXcbWrapper
Qt::GuiPrivate
Qt::Test
Qt::Widgets
KF6::ConfigCore
KF6::WindowSystem
KF6::ConfigCore
KF6::WindowSystem
XCB::XCB
)
add_test(NAME kwin-testXcbWrapper COMMAND testXcbWrapper)
ecm_mark_as_test(testXcbWrapper)
XCB::XCB
)
add_test(NAME kwin-testXcbWrapper COMMAND testXcbWrapper)
ecm_mark_as_test(testXcbWrapper)
add_executable(testXcbSizeHints test_xcb_size_hints.cpp xcb_scaling_mock.cpp)
set_target_properties(testXcbSizeHints PROPERTIES COMPILE_DEFINITIONS "NO_NONE_WINDOW")
target_link_libraries(testXcbSizeHints
Qt::GuiPrivate
Qt::Test
Qt::Widgets
add_executable(testXcbSizeHints test_xcb_size_hints.cpp xcb_scaling_mock.cpp)
set_target_properties(testXcbSizeHints PROPERTIES COMPILE_DEFINITIONS "NO_NONE_WINDOW")
target_link_libraries(testXcbSizeHints
Qt::GuiPrivate
Qt::Test
Qt::Widgets
KF6::ConfigCore
KF6::WindowSystem
KF6::ConfigCore
KF6::WindowSystem
XCB::ICCCM
XCB::XCB
)
add_test(NAME kwin-testXcbSizeHints COMMAND testXcbSizeHints)
ecm_mark_as_test(testXcbSizeHints)
XCB::ICCCM
XCB::XCB
)
add_test(NAME kwin-testXcbSizeHints COMMAND testXcbSizeHints)
ecm_mark_as_test(testXcbSizeHints)
########################################################
# Test XcbWindow
########################################################
add_executable(testXcbWindow test_xcb_window.cpp xcb_scaling_mock.cpp)
########################################################
# Test XcbWindow
########################################################
add_executable(testXcbWindow test_xcb_window.cpp xcb_scaling_mock.cpp)
target_link_libraries(testXcbWindow
Qt::GuiPrivate
Qt::Test
Qt::Widgets
target_link_libraries(testXcbWindow
Qt::GuiPrivate
Qt::Test
Qt::Widgets
KF6::ConfigCore
KF6::WindowSystem
KF6::ConfigCore
KF6::WindowSystem
XCB::XCB
)
add_test(NAME kwin-testXcbWindow COMMAND testXcbWindow)
ecm_mark_as_test(testXcbWindow)
XCB::XCB
)
add_test(NAME kwin-testXcbWindow COMMAND testXcbWindow)
ecm_mark_as_test(testXcbWindow)
########################################################
# Test X11 TimestampUpdate
########################################################
add_executable(testX11TimestampUpdate test_x11_timestamp_update.cpp)
target_link_libraries(testX11TimestampUpdate
KF6::CoreAddons
Qt::Test
Qt::GuiPrivate
kwin
)
add_test(NAME kwin-testX11TimestampUpdate COMMAND testX11TimestampUpdate)
ecm_mark_as_test(testX11TimestampUpdate)
endif()
########################################################
# Test OnScreenNotification
@ -161,19 +176,6 @@ target_link_libraries(testGestures
add_test(NAME kwin-testGestures COMMAND testGestures)
ecm_mark_as_test(testGestures)
########################################################
# Test X11 TimestampUpdate
########################################################
add_executable(testX11TimestampUpdate test_x11_timestamp_update.cpp)
target_link_libraries(testX11TimestampUpdate
KF6::CoreAddons
Qt::Test
Qt::GuiPrivate
kwin
)
add_test(NAME kwin-testX11TimestampUpdate COMMAND testX11TimestampUpdate)
ecm_mark_as_test(testX11TimestampUpdate)
set(testOpenGLContextAttributeBuilder_SRCS
../src/opengl/abstract_opengl_context_attribute_builder.cpp
../src/opengl/egl_context_attribute_builder.cpp

View File

@ -8,9 +8,7 @@ set(mockDRM_SRCS
../../src/backends/drm/drm_commit_thread.cpp
../../src/backends/drm/drm_connector.cpp
../../src/backends/drm/drm_crtc.cpp
../../src/backends/drm/drm_dmabuf_feedback.cpp
../../src/backends/drm/drm_egl_backend.cpp
../../src/backends/drm/drm_egl_cursor_layer.cpp
../../src/backends/drm/drm_egl_layer.cpp
../../src/backends/drm/drm_egl_layer_surface.cpp
../../src/backends/drm/drm_gpu.cpp
@ -39,7 +37,6 @@ target_link_libraries(LibDrmTest
KF6::WindowSystem
KF6::CoreAddons
KF6::I18n
XCB::XCB
PkgConfig::Libxcvt
gbm::gbm
Libdrm::Libdrm

View File

@ -7,6 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QSignalSpy>
#include <QSize>
#include <QTest>
@ -70,6 +71,7 @@ private Q_SLOTS:
void testConnectorLifetime();
void testModeset_data();
void testModeset();
void testVrrChange();
};
static void verifyCleanup(MockGpu *mockGpu)
@ -93,7 +95,7 @@ void DrmTest::testAmsDetection()
// gpu without planes should use legacy mode
{
const auto mockGpu = findPrimaryDevice(0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(!gpu->atomicModeSetting());
}
@ -101,8 +103,8 @@ void DrmTest::testAmsDetection()
{
const auto mockGpu = findPrimaryDevice(0);
mockGpu->planes << std::make_shared<MockPlane>(mockGpu.get(), PlaneType::Primary, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(gpu->atomicModeSetting());
}
@ -110,7 +112,7 @@ void DrmTest::testAmsDetection()
{
const auto mockGpu = findPrimaryDevice(0);
mockGpu->deviceCaps[MOCKDRM_DEVICE_CAP_ATOMIC] = 0;
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(!gpu->atomicModeSetting());
gpu.reset();
verifyCleanup(mockGpu.get());
@ -131,7 +133,7 @@ void DrmTest::testOutputDetection()
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(gpu->updateOutputs());
// 3 outputs should be detected, one of them non-desktop
@ -178,7 +180,7 @@ void DrmTest::testZeroModesHandling()
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
// connector with zero modes should be ignored
conn->modes.clear();
@ -295,7 +297,7 @@ void DrmTest::testModeGeneration()
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QFETCH(QSize, nativeMode);
QFETCH(QList<QSize>, expectedModes);
@ -338,7 +340,7 @@ void DrmTest::testConnectorLifetime()
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(gpu->updateOutputs());
QCOMPARE(gpu->drmOutputs().size(), 1);
@ -364,6 +366,8 @@ void DrmTest::testModeset_data()
void DrmTest::testModeset()
{
// to reenable, make this part of an integration test, so that kwinApp() isn't nullptr
QSKIP("this test needs output pipelines to be enabled by default, which is no longer the case");
// test if doing a modeset would succeed
QFETCH(int, AMS);
const auto mockGpu = findPrimaryDevice(5);
@ -375,7 +379,7 @@ void DrmTest::testModeset()
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->devNode, mockGpu->fd, 0);
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(gpu->updateOutputs());
QCOMPARE(gpu->drmOutputs().size(), 1);
@ -384,12 +388,40 @@ void DrmTest::testModeset()
layer->beginFrame();
output->renderLoop()->prepareNewFrame();
output->renderLoop()->beginPaint();
layer->endFrame(infiniteRegion(), infiniteRegion());
QVERIFY(output->present(std::make_shared<OutputFrame>(output->renderLoop())));
const auto frame = std::make_shared<OutputFrame>(output->renderLoop(), std::chrono::nanoseconds(1'000'000'000'000 / output->refreshRate()));
layer->endFrame(infiniteRegion(), infiniteRegion(), frame.get());
QVERIFY(output->present(frame));
gpu.reset();
verifyCleanup(mockGpu.get());
}
void DrmTest::testVrrChange()
{
const auto mockGpu = findPrimaryDevice(5);
mockGpu->deviceCaps[MOCKDRM_DEVICE_CAP_ATOMIC] = 1;
const auto conn = std::make_shared<MockConnector>(mockGpu.get());
conn->setVrrCapable(false);
mockGpu->connectors.push_back(conn);
const auto session = Session::create(Session::Type::Noop);
const auto backend = std::make_unique<DrmBackend>(session.get());
const auto renderBackend = backend->createQPainterBackend();
auto gpu = std::make_unique<DrmGpu>(backend.get(), mockGpu->fd, DrmDevice::open(mockGpu->devNode));
QVERIFY(gpu->updateOutputs());
const auto output = gpu->drmOutputs().front();
QVERIFY(!(output->capabilities() & Output::Capability::Vrr));
QSignalSpy capsChanged(output, &Output::capabilitiesChanged);
conn->setVrrCapable(true);
QVERIFY(gpu->updateOutputs());
QCOMPARE(gpu->drmOutputs().front(), output);
QCOMPARE(capsChanged.count(), 1);
QVERIFY(output->capabilities() & Output::Capability::Vrr);
}
QTEST_GUILESS_MAIN(DrmTest)
#include "drmTest.moc"

View File

@ -212,6 +212,14 @@ void MockConnector::addMode(uint32_t width, uint32_t height, float refreshRate,
free(modeInfo);
}
void MockConnector::setVrrCapable(bool cap)
{
auto &prop = *std::ranges::find_if(props, [](const auto &prop) {
return prop.name == "vrr_capable";
});
prop.value = cap ? 1 : 0;
}
//
MockCrtc::MockCrtc(MockGpu *gpu, const std::shared_ptr<MockPlane> &legacyPlane, int pipeIndex, int gamma_size)

View File

@ -71,6 +71,7 @@ public:
~MockConnector() = default;
void addMode(uint32_t width, uint32_t height, float refreshRate, bool preferred = false);
void setVrrCapable(bool cap);
drmModeConnection connection;
uint32_t type;

View File

@ -14,7 +14,7 @@ kwineffects_unit_tests(
timelinetest
)
add_executable(kwinglplatformtest kwinglplatformtest.cpp mock_gl.cpp ../../src/opengl/glplatform.cpp ../../src/opengl/openglcontext.cpp ../../src/utils/version.cpp)
add_executable(kwinglplatformtest kwinglplatformtest.cpp ../../src/opengl/glplatform.cpp ../../src/utils/version.cpp)
add_test(NAME kwineffects-kwinglplatformtest COMMAND kwinglplatformtest)
target_link_libraries(kwinglplatformtest Qt::Test Qt::Gui KF6::ConfigCore XCB::XCB)
target_link_libraries(kwinglplatformtest Qt::Test Qt::Gui KF6::ConfigCore)
ecm_mark_as_test(kwinglplatformtest)

View File

@ -6,7 +6,6 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mock_gl.h"
#include "opengl/glplatform.h"
#include <QTest>
@ -18,33 +17,18 @@ Q_DECLARE_METATYPE(KWin::ChipClass)
using namespace KWin;
void KWin::cleanupGL()
{
GLPlatform::cleanup();
}
class GLPlatformTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void cleanup();
void testDriverToString_data();
void testDriverToString();
void testChipClassToString_data();
void testChipClassToString();
void testPriorDetect();
void testDetect_data();
void testDetect();
};
void GLPlatformTest::cleanup()
{
cleanupGL();
delete s_gl;
s_gl = nullptr;
}
void GLPlatformTest::testDriverToString_data()
{
QTest::addColumn<Driver>("driver");
@ -142,47 +126,6 @@ void GLPlatformTest::testChipClassToString()
QTEST(GLPlatform::chipClassToString(chipClass), "expected");
}
void GLPlatformTest::testPriorDetect()
{
auto *gl = GLPlatform::instance();
QVERIFY(gl);
QCOMPARE(gl->supports(GLFeature::LooseBinding), false);
QCOMPARE(gl->glVersion(), Version());
QCOMPARE(gl->glslVersion(), Version());
QCOMPARE(gl->mesaVersion(), Version());
QCOMPARE(gl->driverVersion(), Version());
QCOMPARE(gl->driver(), Driver_Unknown);
QCOMPARE(gl->chipClass(), UnknownChipClass);
QCOMPARE(gl->isMesaDriver(), false);
QCOMPARE(gl->isRadeon(), false);
QCOMPARE(gl->isNvidia(), false);
QCOMPARE(gl->isIntel(), false);
QCOMPARE(gl->isPanfrost(), false);
QCOMPARE(gl->isLima(), false);
QCOMPARE(gl->isVideoCore4(), false);
QCOMPARE(gl->isVideoCore3D(), false);
QCOMPARE(gl->isVirtualBox(), false);
QCOMPARE(gl->isVMware(), false);
QCOMPARE(gl->isSoftwareEmulation(), false);
QCOMPARE(gl->isVirtualMachine(), false);
QCOMPARE(gl->glVersionString(), QByteArray());
QCOMPARE(gl->glRendererString(), QByteArray());
QCOMPARE(gl->glVendorString(), QByteArray());
QCOMPARE(gl->glShadingLanguageVersionString(), QByteArray());
QCOMPARE(gl->isLooseBinding(), false);
QCOMPARE(gl->isGLES(), false);
QCOMPARE(gl->recommendedCompositor(), QPainterCompositing);
QCOMPARE(gl->preferBufferSubData(), false);
QCOMPARE(gl->platformInterface(), NoOpenGLPlatformInterface);
}
void GLPlatformTest::testDetect_data()
{
QTest::addColumn<QString>("configFile");
@ -222,60 +165,50 @@ void GLPlatformTest::testDetect()
QFETCH(QString, configFile);
KConfig config(configFile);
const KConfigGroup driverGroup = config.group(QStringLiteral("Driver"));
s_gl = new MockGL;
s_gl->getString.vendor = driverGroup.readEntry("Vendor").toUtf8();
s_gl->getString.renderer = driverGroup.readEntry("Renderer").toUtf8();
s_gl->getString.version = driverGroup.readEntry("Version").toUtf8();
s_gl->getString.shadingLanguageVersion = driverGroup.readEntry("ShadingLanguageVersion").toUtf8();
s_gl->getString.extensions = QList<QByteArray>{QByteArrayLiteral("GL_ARB_shader_objects"),
QByteArrayLiteral("GL_ARB_fragment_shader"),
QByteArrayLiteral("GL_ARB_vertex_shader"),
QByteArrayLiteral("GL_ARB_texture_non_power_of_two")};
s_gl->getString.extensionsString = QByteArray();
auto *gl = GLPlatform::instance();
QVERIFY(gl);
gl->detect(EglPlatformInterface);
QCOMPARE(gl->platformInterface(), EglPlatformInterface);
const auto version = driverGroup.readEntry("Version").toUtf8();
const auto glslVersion = driverGroup.readEntry("ShadingLanguageVersion").toUtf8();
const auto renderer = driverGroup.readEntry("Renderer").toUtf8();
const auto vendor = driverGroup.readEntry("Vendor").toUtf8();
GLPlatform gl(EglPlatformInterface, version, glslVersion, renderer, vendor);
QCOMPARE(gl.platformInterface(), EglPlatformInterface);
const KConfigGroup settingsGroup = config.group(QStringLiteral("Settings"));
QCOMPARE(gl->supports(GLFeature::LooseBinding), settingsGroup.readEntry("LooseBinding", false));
QCOMPARE(gl.isLooseBinding(), settingsGroup.readEntry("LooseBinding", false));
QCOMPARE(gl->glVersion(), readVersion(settingsGroup, "GLVersion"));
QCOMPARE(gl->glslVersion(), readVersion(settingsGroup, "GLSLVersion"));
QCOMPARE(gl->mesaVersion(), readVersion(settingsGroup, "MesaVersion"));
QCOMPARE(gl.glVersion(), readVersion(settingsGroup, "GLVersion"));
QCOMPARE(gl.glslVersion(), readVersion(settingsGroup, "GLSLVersion"));
QCOMPARE(gl.mesaVersion(), readVersion(settingsGroup, "MesaVersion"));
QEXPECT_FAIL("amd-catalyst-radeonhd-7700M-3.1.13399", "Detects GL version instead of driver version", Continue);
QCOMPARE(gl->driverVersion(), readVersion(settingsGroup, "DriverVersion"));
QCOMPARE(gl.driverVersion(), readVersion(settingsGroup, "DriverVersion"));
QCOMPARE(gl->driver(), Driver(settingsGroup.readEntry("Driver", int(Driver_Unknown))));
QCOMPARE(gl->chipClass(), ChipClass(settingsGroup.readEntry("ChipClass", int(UnknownChipClass))));
QCOMPARE(gl.driver(), Driver(settingsGroup.readEntry("Driver", int(Driver_Unknown))));
QCOMPARE(gl.chipClass(), ChipClass(settingsGroup.readEntry("ChipClass", int(UnknownChipClass))));
QCOMPARE(gl->isMesaDriver(), settingsGroup.readEntry("Mesa", false));
QCOMPARE(gl->isRadeon(), settingsGroup.readEntry("Radeon", false));
QCOMPARE(gl->isNvidia(), settingsGroup.readEntry("Nvidia", false));
QCOMPARE(gl->isIntel(), settingsGroup.readEntry("Intel", false));
QCOMPARE(gl->isVirtualBox(), settingsGroup.readEntry("VirtualBox", false));
QCOMPARE(gl->isVMware(), settingsGroup.readEntry("VMware", false));
QCOMPARE(gl->isAdreno(), settingsGroup.readEntry("Adreno", false));
QCOMPARE(gl->isPanfrost(), settingsGroup.readEntry("Panfrost", false));
QCOMPARE(gl->isLima(), settingsGroup.readEntry("Lima", false));
QCOMPARE(gl->isVideoCore4(), settingsGroup.readEntry("VC4", false));
QCOMPARE(gl->isVideoCore3D(), settingsGroup.readEntry("V3D", false));
QCOMPARE(gl->isVirgl(), settingsGroup.readEntry("Virgl", false));
QCOMPARE(gl.isMesaDriver(), settingsGroup.readEntry("Mesa", false));
QCOMPARE(gl.isRadeon(), settingsGroup.readEntry("Radeon", false));
QCOMPARE(gl.isNvidia(), settingsGroup.readEntry("Nvidia", false));
QCOMPARE(gl.isIntel(), settingsGroup.readEntry("Intel", false));
QCOMPARE(gl.isVirtualBox(), settingsGroup.readEntry("VirtualBox", false));
QCOMPARE(gl.isVMware(), settingsGroup.readEntry("VMware", false));
QCOMPARE(gl.isAdreno(), settingsGroup.readEntry("Adreno", false));
QCOMPARE(gl.isPanfrost(), settingsGroup.readEntry("Panfrost", false));
QCOMPARE(gl.isLima(), settingsGroup.readEntry("Lima", false));
QCOMPARE(gl.isVideoCore4(), settingsGroup.readEntry("VC4", false));
QCOMPARE(gl.isVideoCore3D(), settingsGroup.readEntry("V3D", false));
QCOMPARE(gl.isVirgl(), settingsGroup.readEntry("Virgl", false));
QCOMPARE(gl->isSoftwareEmulation(), settingsGroup.readEntry("SoftwareEmulation", false));
QCOMPARE(gl->isVirtualMachine(), settingsGroup.readEntry("VirtualMachine", false));
QCOMPARE(gl.isVirtualMachine(), settingsGroup.readEntry("VirtualMachine", false));
QCOMPARE(gl->glVersionString(), s_gl->getString.version);
QCOMPARE(gl->glRendererString(), s_gl->getString.renderer);
QCOMPARE(gl->glVendorString(), s_gl->getString.vendor);
QCOMPARE(gl->glShadingLanguageVersionString(), s_gl->getString.shadingLanguageVersion);
QCOMPARE(gl.glVersionString(), version);
QCOMPARE(gl.glRendererString(), renderer);
QCOMPARE(gl.glVendorString(), vendor);
QCOMPARE(gl.glShadingLanguageVersionString(), glslVersion);
QCOMPARE(gl->isLooseBinding(), settingsGroup.readEntry("LooseBinding", false));
QCOMPARE(gl->isGLES(), settingsGroup.readEntry("GLES", false));
QCOMPARE(gl->recommendedCompositor(), CompositingType(settingsGroup.readEntry("Compositor", int(NoCompositing))));
QCOMPARE(gl->preferBufferSubData(), settingsGroup.readEntry("PreferBufferSubData", false));
QCOMPARE(gl.isLooseBinding(), settingsGroup.readEntry("LooseBinding", false));
QCOMPARE(gl.recommendedCompositor(), CompositingType(settingsGroup.readEntry("Compositor", int(NoCompositing))));
QCOMPARE(gl.preferBufferSubData(), settingsGroup.readEntry("PreferBufferSubData", false));
}
QTEST_GUILESS_MAIN(GLPlatformTest)

View File

@ -1,57 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mock_gl.h"
#include <epoxy/gl.h>
MockGL *s_gl = nullptr;
static const GLubyte *mock_glGetString(GLenum name)
{
if (!s_gl) {
return nullptr;
}
switch (name) {
case GL_VENDOR:
return (const GLubyte *)s_gl->getString.vendor.constData();
case GL_RENDERER:
return (const GLubyte *)s_gl->getString.renderer.constData();
case GL_VERSION:
return (const GLubyte *)s_gl->getString.version.constData();
case GL_EXTENSIONS:
return (const GLubyte *)s_gl->getString.extensionsString.constData();
case GL_SHADING_LANGUAGE_VERSION:
return (const GLubyte *)s_gl->getString.shadingLanguageVersion.constData();
default:
return nullptr;
}
}
static const GLubyte *mock_glGetStringi(GLenum name, GLuint index)
{
if (!s_gl) {
return nullptr;
}
if (name == GL_EXTENSIONS && index < uint(s_gl->getString.extensions.count())) {
return (const GLubyte *)s_gl->getString.extensions.at(index).constData();
}
return nullptr;
}
static void mock_glGetIntegerv(GLenum pname, GLint *data)
{
if (pname == GL_NUM_EXTENSIONS) {
if (data && s_gl) {
*data = s_gl->getString.extensions.count();
}
}
}
PFNGLGETSTRINGPROC epoxy_glGetString = mock_glGetString;
PFNGLGETSTRINGIPROC epoxy_glGetStringi = mock_glGetStringi;
PFNGLGETINTEGERVPROC epoxy_glGetIntegerv = mock_glGetIntegerv;

View File

@ -1,30 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef MOCK_GL_H
#define MOCK_GL_H
#include <QByteArray>
#include <QList>
struct MockGL
{
struct
{
QByteArray vendor;
QByteArray renderer;
QByteArray version;
QList<QByteArray> extensions;
QByteArray extensionsString;
QByteArray shadingLanguageVersion;
} getString;
};
extern MockGL *s_gl;
#endif

View File

@ -25,6 +25,36 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
${PLASMA_WAYLAND_PROTOCOLS_DIR}/fake-input.xml
)
if (Qt6_VERSION VERSION_LESS "6.7.1")
# the qtwaylandscanner macro cannot handle the mismatched file name and <protocol name=""
find_package(QtWaylandScanner REQUIRED)
if (WaylandProtocols_VERSION VERSION_LESS 1.36)
ecm_add_qtwayland_client_protocol(KWinIntegrationTestFramework
PROTOCOL ${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
BASENAME dialog-v1
)
target_compile_definitions(KWinIntegrationTestFramework PUBLIC
-DHAVE_XDG_DIALOG_V1_HEADER=0
)
else()
ecm_add_qtwayland_client_protocol(KWinIntegrationTestFramework
PROTOCOL ${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
BASENAME xdg-dialog-v1
)
target_compile_definitions(KWinIntegrationTestFramework PUBLIC
-DHAVE_XDG_DIALOG_V1_HEADER=1
)
endif()
else()
qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
FILES
${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
)
target_compile_definitions(KWinIntegrationTestFramework PUBLIC
-DHAVE_XDG_DIALOG_V1_HEADER=1
)
endif()
target_sources(KWinIntegrationTestFramework PRIVATE
generic_scene_opengl_test.cpp
kwin_wayland_test.cpp
@ -33,20 +63,21 @@ target_sources(KWinIntegrationTestFramework PRIVATE
target_link_libraries(KWinIntegrationTestFramework
PUBLIC
Qt::Test
Qt::Concurrent
Plasma::KWaylandClient
Wayland::Client
Libdrm::Libdrm
kwin
PRIVATE
# Own libraries
KWinXwaylandServerModule
# Static plugins
KWinQpaPlugin
KF6WindowSystemKWinPlugin
KF6IdleTimeKWinPlugin
)
if(KWIN_BUILD_X11)
target_link_libraries(KWinIntegrationTestFramework PRIVATE KWinXwaylandServerModule)
endif()
if(TARGET KF6GlobalAccelKWinPlugin)
target_link_libraries(KWinIntegrationTestFramework PUBLIC KF6GlobalAccelKWinPlugin)
endif()
@ -60,6 +91,9 @@ function(integrationTest)
set(oneValueArgs NAME)
set(multiValueArgs SRCS LIBS)
cmake_parse_arguments(ARGS "${optionArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT KWIN_BUILD_X11 AND ARGS_LIBS MATCHES XCB::)
return()
endif()
add_executable(${ARGS_NAME} ${ARGS_SRCS})
target_link_libraries(${ARGS_NAME} KWinIntegrationTestFramework Qt::Test ${ARGS_LIBS})
if(${ARGS_BUILTIN_EFFECTS})
@ -67,12 +101,14 @@ function(integrationTest)
endif()
add_test(NAME kwin-${ARGS_NAME} COMMAND dbus-run-session ${CMAKE_BINARY_DIR}/bin/${ARGS_NAME})
endfunction()
integrationTest(NAME testDontCrashGlxgears SRCS dont_crash_glxgears.cpp LIBS KF6::I18n KDecoration2::KDecoration)
if(KWIN_BUILD_X11)
integrationTest(NAME testDontCrashGlxgears SRCS dont_crash_glxgears.cpp LIBS KF6::I18n KDecoration2::KDecoration)
endif()
if (KWIN_BUILD_SCREENLOCKER)
integrationTest(NAME testLockScreen SRCS lockscreen.cpp LIBS KF6::GlobalAccel)
endif()
integrationTest(NAME testBounceKeys SRCS bounce_keys_test.cpp)
integrationTest(NAME testButtonRebind SRCS buttonrebind_test.cpp)
integrationTest(NAME testDecorationInput SRCS decoration_input_test.cpp LIBS KDecoration2::KDecoration KDecoration2::KDecoration2Private)
integrationTest(NAME testInternalWindow SRCS internal_window.cpp)
integrationTest(NAME testTouchInput SRCS touch_input_test.cpp)
@ -82,15 +118,12 @@ integrationTest(NAME testPlatformCursor SRCS platformcursor.cpp)
integrationTest(NAME testDontCrashCancelAnimation SRCS dont_crash_cancel_animation.cpp LIBS KDecoration2::KDecoration)
integrationTest(NAME testTransientPlacement SRCS transient_placement.cpp)
integrationTest(NAME testDebugConsole SRCS debug_console_test.cpp)
integrationTest(NAME testDontCrashEmptyDeco SRCS dont_crash_empty_deco.cpp LIBS KDecoration2::KDecoration)
integrationTest(NAME testPlasmaSurface SRCS plasma_surface_test.cpp)
integrationTest(NAME testMaximized SRCS maximize_test.cpp LIBS KDecoration2::KDecoration KF6::Package)
integrationTest(NAME testXdgShellWindow SRCS xdgshellwindow_test.cpp LIBS KDecoration2::KDecoration)
integrationTest(NAME testXwaylandSelections SRCS xwayland_selections_test.cpp)
integrationTest(NAME testSceneOpenGL SRCS scene_opengl_test.cpp )
integrationTest(NAME testSceneOpenGLES SRCS scene_opengl_es_test.cpp )
integrationTest(NAME testScreenChanges SRCS screen_changes_test.cpp)
integrationTest(NAME testModiferOnlyShortcut SRCS modifier_only_shortcut_test.cpp LIBS XKB::XKB)
if (KWIN_BUILD_TABBOX)
integrationTest(NAME testTabBox SRCS tabbox_test.cpp)
endif()
@ -111,7 +144,7 @@ integrationTest(NAME testActivation SRCS activation_test.cpp)
integrationTest(NAME testInputMethod SRCS inputmethod_test.cpp LIBS XKB::XKB)
integrationTest(NAME testScreens SRCS screens_test.cpp)
integrationTest(NAME testScreenEdges SRCS screenedges_test.cpp LIBS XCB::ICCCM)
integrationTest(NAME testOutputChanges SRCS outputchanges_test.cpp)
integrationTest(NAME testOutputChanges SRCS outputchanges_test.cpp LIBS XCB::ICCCM)
integrationTest(NAME testTiles SRCS tiles_test.cpp)
integrationTest(NAME testFractionalScaling SRCS fractional_scaling_test.cpp)
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)
@ -131,6 +164,12 @@ integrationTest(NAME testXwaylandServerRestart SRCS xwaylandserver_restart_test.
integrationTest(NAME testFakeInput SRCS fakeinput_test.cpp)
integrationTest(NAME testSecurityContext SRCS security_context_test.cpp)
integrationTest(NAME testStickyKeys SRCS sticky_keys_test.cpp)
if(KWIN_BUILD_X11)
integrationTest(NAME testDontCrashEmptyDeco SRCS dont_crash_empty_deco.cpp LIBS KDecoration2::KDecoration)
integrationTest(NAME testXwaylandSelections SRCS xwayland_selections_test.cpp)
integrationTest(NAME testXinerama SRCS xinerama_test.cpp)
integrationTest(NAME testX11KeyRead SRCS x11keyread.cpp LIBS XCB::XINPUT)
endif()
qt_add_dbus_interfaces(DBUS_SRCS ${CMAKE_BINARY_DIR}/src/org.kde.kwin.VirtualKeyboard.xml)
integrationTest(NAME testVirtualKeyboardDBus SRCS test_virtualkeyboard_dbus.cpp ${DBUS_SRCS})

View File

@ -0,0 +1,108 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2024 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "pointer_input.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KWayland/Client/keyboard.h>
#include <KWayland/Client/seat.h>
#include <linux/input-event-codes.h>
using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_buttonrebind-0");
class TestButtonRebind : public QObject
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void initTestCase();
void testKey_data();
void testKey();
private:
quint32 timestamp = 1;
};
void TestButtonRebind::init()
{
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat));
QVERIFY(Test::waitForWaylandKeyboard());
}
void TestButtonRebind::cleanup()
{
Test::destroyWaylandConnection();
QVERIFY(QFile::remove(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("kcminputrc"))));
}
void TestButtonRebind::initTestCase()
{
qRegisterMetaType<KWin::Window *>();
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
}
void TestButtonRebind::testKey_data()
{
QTest::addColumn<QKeySequence>("boundKeys");
QTest::addColumn<QList<quint32>>("expectedKeys");
QTest::newRow("single key") << QKeySequence(Qt::Key_A) << QList<quint32>{KEY_A};
QTest::newRow("single modifier") << QKeySequence(Qt::Key_Control) << QList<quint32>{KEY_LEFTCTRL};
QTest::newRow("single modifier plus key") << QKeySequence(Qt::ControlModifier | Qt::Key_N) << QList<quint32>{KEY_LEFTCTRL, KEY_N};
QTest::newRow("multiple modifiers plus key") << QKeySequence(Qt::ControlModifier | Qt::MetaModifier | Qt::Key_Y) << QList<quint32>{KEY_LEFTCTRL, KEY_LEFTMETA, KEY_Y};
QTest::newRow("delete") << QKeySequence(Qt::Key_Delete) << QList<quint32>{KEY_DELETE};
QTest::newRow("keypad delete") << QKeySequence(Qt::KeypadModifier | Qt::Key_Delete) << QList<quint32>{KEY_KPDOT};
QTest::newRow("keypad enter") << QKeySequence(Qt::KeypadModifier | Qt::Key_Enter) << QList<quint32>{KEY_KPENTER};
}
void TestButtonRebind::testKey()
{
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
QFETCH(QKeySequence, boundKeys);
buttonGroup.writeEntry("ExtraButton7", QStringList{"Key", boundKeys.toString(QKeySequence::PortableText)}, KConfig::Notify);
buttonGroup.sync();
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
QVERIFY(enteredSpy.wait());
// 0x119 is Qt::ExtraButton7
Test::pointerButtonPressed(0x119, timestamp++);
QVERIFY(keyChangedSpy.wait());
QFETCH(QList<quint32>, expectedKeys);
QCOMPARE(keyChangedSpy.count(), expectedKeys.count());
for (int i = 0; i < keyChangedSpy.count(); i++) {
QCOMPARE(keyChangedSpy.at(i).at(0).value<quint32>(), expectedKeys.at(i));
QCOMPARE(keyChangedSpy.at(i).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed);
}
Test::pointerButtonReleased(0x119, timestamp++);
}
WAYLANDTEST_MAIN(TestButtonRebind)
#include "buttonrebind_test.moc"

View File

@ -140,6 +140,7 @@ void TestDbusInterface::testGetWindowInfoXdgShellClient()
#if KWIN_BUILD_ACTIVITIES
{QStringLiteral("activities"), QStringList()},
#endif
{QStringLiteral("layer"), NormalLayer},
};
// let's get the window info
@ -276,6 +277,7 @@ void TestDbusInterface::testGetWindowInfoX11Client()
#if KWIN_BUILD_ACTIVITIES
{QStringLiteral("activities"), QStringList()},
#endif
{QStringLiteral("layer"), NormalLayer},
};
// let's get the window info

View File

@ -11,11 +11,14 @@
#include "core/output.h"
#include "debug_console.h"
#include "internalwindow.h"
#include "utils/xcbutils.h"
#include "wayland_server.h"
#include "window.h"
#include "workspace.h"
#if KWIN_BUILD_X11
#include "utils/xcbutils.h"
#endif
#include <KWayland/Client/compositor.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/shm_pool.h>
@ -38,8 +41,10 @@ private Q_SLOTS:
void cleanup();
void topLevelTest_data();
void topLevelTest();
#if KWIN_BUILD_X11
void testX11Window();
void testX11Unmanaged();
#endif
void testWaylandClient();
void testInternalWindow();
void testClosingDebugConsole();
@ -109,6 +114,7 @@ void DebugConsoleTest::topLevelTest()
}
}
#if KWIN_BUILD_X11
void DebugConsoleTest::testX11Window()
{
DebugConsoleModel model;
@ -281,6 +287,7 @@ void DebugConsoleTest::testX11Unmanaged()
QVERIFY(!model.hasChildren(unmanagedTopLevelIndex));
QVERIFY(!model2.hasChildren(model2.index(1, 0, QModelIndex())));
}
#endif
void DebugConsoleTest::testWaylandClient()
{

View File

@ -52,10 +52,8 @@ private Q_SLOTS:
void cleanup();
void testAxis_data();
void testAxis();
void testDoubleClickOnAllDesktops_data();
void testDoubleClickOnAllDesktops();
void testDoubleClickClose();
void testDoubleTap_data();
void testDoubleTap();
void testHover();
void testPressToMove_data();
@ -72,7 +70,7 @@ private Q_SLOTS:
void testTooltipDoesntEatKeyEvents();
private:
std::tuple<Window *, std::unique_ptr<KWayland::Client::Surface>, Test::XdgToplevel *> showWindow();
std::tuple<Window *, std::unique_ptr<KWayland::Client::Surface>, std::unique_ptr<Test::XdgToplevel>, std::unique_ptr<Test::XdgToplevelDecorationV1>> showWindow();
};
#define MOTION(target) Test::pointerMotion(target, timestamp++)
@ -81,23 +79,23 @@ private:
#define RELEASE Test::pointerButtonReleased(BTN_LEFT, timestamp++)
std::tuple<Window *, std::unique_ptr<KWayland::Client::Surface>, Test::XdgToplevel *> DecorationInputTest::showWindow()
std::tuple<Window *, std::unique_ptr<KWayland::Client::Surface>, std::unique_ptr<Test::XdgToplevel>, std::unique_ptr<Test::XdgToplevelDecorationV1>> DecorationInputTest::showWindow()
{
#define VERIFY(statement) \
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
return {nullptr, nullptr, nullptr};
return {nullptr, nullptr, nullptr, nullptr};
#define COMPARE(actual, expected) \
if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
return {nullptr, nullptr, nullptr};
return {nullptr, nullptr, nullptr, nullptr};
std::unique_ptr<KWayland::Client::Surface> surface{Test::createSurface()};
VERIFY(surface.get());
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
VERIFY(shellSurface);
Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(shellSurface, shellSurface);
VERIFY(decoration);
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly);
VERIFY(shellSurface.get());
std::unique_ptr<Test::XdgToplevelDecorationV1> decoration = Test::createXdgToplevelDecorationV1(shellSurface.get());
VERIFY(decoration.get());
QSignalSpy decorationConfigureRequestedSpy(decoration, &Test::XdgToplevelDecorationV1::configureRequested);
QSignalSpy decorationConfigureRequestedSpy(decoration.get(), &Test::XdgToplevelDecorationV1::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
@ -114,7 +112,7 @@ std::tuple<Window *, std::unique_ptr<KWayland::Client::Surface>, Test::XdgToplev
#undef VERIFY
#undef COMPARE
return {window, std::move(surface), shellSurface};
return {window, std::move(surface), std::move(shellSurface), std::move(decoration)};
}
void DecorationInputTest::initTestCase()
@ -174,7 +172,7 @@ void DecorationInputTest::testAxis()
{
static constexpr double oneTick = 15;
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -211,16 +209,6 @@ void DecorationInputTest::testAxis()
QVERIFY(!window->keepAbove());
}
void DecorationInputTest::testDoubleClickOnAllDesktops_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("expectedSection");
QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection;
QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection;
QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection;
}
void KWin::DecorationInputTest::testDoubleClickOnAllDesktops()
{
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
@ -228,7 +216,7 @@ void KWin::DecorationInputTest::testDoubleClickOnAllDesktops()
group.sync();
workspace()->slotReconfigure();
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -249,21 +237,6 @@ void KWin::DecorationInputTest::testDoubleClickOnAllDesktops()
PRESS;
RELEASE;
QVERIFY(!window->isOnAllDesktops());
// test top most deco pixel, BUG: 362860
window->move(QPoint(0, 0));
QFETCH(QPoint, decoPoint);
MOTION(decoPoint);
QVERIFY(input()->pointer()->decoration());
QCOMPARE(input()->pointer()->decoration()->window(), window);
QTEST(input()->pointer()->decoration()->decoration()->sectionUnderMouse(), "expectedSection");
// double click
PRESS;
RELEASE;
QVERIFY(!window->isOnAllDesktops());
PRESS;
RELEASE;
QVERIFY(window->isOnAllDesktops());
}
void DecorationInputTest::testDoubleClickClose()
@ -274,13 +247,13 @@ void DecorationInputTest::testDoubleClickClose()
group.sync();
workspace()->slotReconfigure();
auto [window, surface, shellSurface] = showWindow();
auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
quint32 timestamp = 1;
MOTION(QPoint(window->frameGeometry().center().x(), window->frameMargins().top() / 2.0));
connect(shellSurface, &Test::XdgToplevel::closeRequested, this, [&surface = surface]() {
connect(shellSurface.get(), &Test::XdgToplevel::closeRequested, this, [&surface = surface]() {
surface.reset();
});
@ -297,16 +270,6 @@ void DecorationInputTest::testDoubleClickClose()
window->unref();
}
void DecorationInputTest::testDoubleTap_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("expectedSection");
QTest::newRow("topLeft") << QPoint(10, 10) << Qt::TopLeftSection;
QTest::newRow("top") << QPoint(260, 10) << Qt::TopSection;
QTest::newRow("topRight") << QPoint(509, 10) << Qt::TopRightSection;
}
void KWin::DecorationInputTest::testDoubleTap()
{
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
@ -314,7 +277,7 @@ void KWin::DecorationInputTest::testDoubleTap()
group.sync();
workspace()->slotReconfigure();
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -335,28 +298,11 @@ void KWin::DecorationInputTest::testDoubleTap()
Test::touchDown(0, tapPoint, timestamp++);
Test::touchUp(0, timestamp++);
QVERIFY(!window->isOnAllDesktops());
// test top most deco pixel, BUG: 362860
//
// Not directly at (0, 0), otherwise ScreenEdgeInputFilter catches
// event before DecorationEventFilter.
window->move(QPoint(10, 10));
QFETCH(QPoint, decoPoint);
// double click
Test::touchDown(0, decoPoint, timestamp++);
QVERIFY(input()->touch()->decoration());
QCOMPARE(input()->touch()->decoration()->window(), window);
QTEST(input()->touch()->decoration()->decoration()->sectionUnderMouse(), "expectedSection");
Test::touchUp(0, timestamp++);
QVERIFY(!window->isOnAllDesktops());
Test::touchDown(0, decoPoint, timestamp++);
Test::touchUp(0, timestamp++);
QVERIFY(window->isOnAllDesktops());
}
void DecorationInputTest::testHover()
{
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -415,7 +361,7 @@ void DecorationInputTest::testPressToMove_data()
void DecorationInputTest::testPressToMove()
{
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -472,7 +418,7 @@ void DecorationInputTest::testTapToMove_data()
void DecorationInputTest::testTapToMove()
{
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -536,7 +482,7 @@ void DecorationInputTest::testResizeOutsideWindow()
workspace()->slotReconfigure();
// now create window
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -630,7 +576,7 @@ void DecorationInputTest::testModifierClickUnrestrictedMove()
QCOMPARE(options->commandAll3(), Options::MouseUnrestrictedMove);
// create a window
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -692,7 +638,7 @@ void DecorationInputTest::testModifierScrollOpacity()
group.sync();
workspace()->slotReconfigure();
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -750,7 +696,7 @@ void DecorationInputTest::testTouchEvents()
{
// this test verifies that the decoration gets a hover leave event on touch release
// see BUG 386231
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());
@ -796,7 +742,7 @@ void DecorationInputTest::testTooltipDoesntEatKeyEvents()
QVERIFY(keyboard);
QSignalSpy enteredSpy(keyboard, &KWayland::Client::Keyboard::entered);
const auto [window, surface, shellSurface] = showWindow();
const auto [window, surface, shellSurface, decoration] = showWindow();
QVERIFY(window);
QVERIFY(window->isDecorated());
QVERIFY(!window->noBorder());

View File

@ -131,7 +131,7 @@ void X11DesktopWindowTest::testDesktopWindow()
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(!window->isDecorated());
QCOMPARE(window->windowType(), NET::Desktop);
QCOMPARE(window->windowType(), WindowType::Desktop);
QCOMPARE(window->frameGeometry(), windowGeometry);
QVERIFY(window->isDesktop());
QCOMPARE(window->depth(), 24);

View File

@ -15,7 +15,9 @@
#include "wayland_server.h"
#include "window.h"
#include "workspace.h"
#if KWIN_BUILD_X11
#include "x11window.h"
#endif
#include <KDecoration2/Decoration>
@ -85,7 +87,7 @@ void DontCrashCancelAnimationFromAnimationEndedTest::testScript()
// create a window
std::unique_ptr<KWayland::Client::Surface> surface{Test::createSurface()};
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
// let's render
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);

View File

@ -182,7 +182,7 @@ void ScriptedEffectsTest::testEffectsHandler()
// create a window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
auto *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
shellSurface->set_title("WindowA");
auto *c = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
@ -265,7 +265,7 @@ void ScriptedEffectsTest::testAnimations()
// animated after window added connect
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
auto *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
shellSurface->set_title("Window 1");
auto *c = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
@ -371,7 +371,7 @@ void ScriptedEffectsTest::testFullScreenEffect()
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
auto *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
shellSurface->set_title("Window 1");
auto *c = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
@ -433,7 +433,7 @@ void ScriptedEffectsTest::testKeepAlive()
// create a window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
auto *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
auto *c = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(c);
@ -479,7 +479,7 @@ void ScriptedEffectsTest::testGrab()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
@ -509,7 +509,7 @@ void ScriptedEffectsTest::testGrabAlreadyGrabbedWindow()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
@ -543,7 +543,7 @@ void ScriptedEffectsTest::testGrabAlreadyGrabbedWindowForced()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
@ -572,7 +572,7 @@ void ScriptedEffectsTest::testUngrab()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
@ -614,7 +614,7 @@ void ScriptedEffectsTest::testRedirect()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
@ -690,7 +690,7 @@ void ScriptedEffectsTest::testComplete()
// create test window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);

View File

@ -119,8 +119,8 @@ void WobblyWindowsShadeTest::testShadeMove()
QVERIFY(!window->isShade());
QVERIFY(window->isActive());
QSignalSpy windowShownSpy(window, &Window::windowShown);
QVERIFY(windowShownSpy.wait());
QSignalSpy readyForPaintingChangedSpy(window, &Window::readyForPaintingChanged);
QVERIFY(readyForPaintingChangedSpy.wait());
// now shade the window
workspace()->slotWindowShade();

View File

@ -42,7 +42,8 @@ private Q_SLOTS:
void init();
void cleanup();
void testShow();
void testToplevel();
void testPopup();
};
void TestFractionalScale::initTestCase()
@ -87,20 +88,73 @@ void TestFractionalScale::cleanup()
Test::destroyWaylandConnection();
}
void TestFractionalScale::testShow()
void TestFractionalScale::testToplevel()
{
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::FractionalScaleV1> fractionalScale(Test::createFractionalScaleV1(surface.get()));
QSignalSpy fractionalScaleChanged(fractionalScale.get(), &Test::FractionalScaleV1::preferredScaleChanged);
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
// above call commits the surface and blocks for the configure event. We should have received the scale already
// We are sent the value in 120ths
QCOMPARE(fractionalScale->preferredScale(), 1.25 * 120);
QCOMPARE(fractionalScaleChanged.count(), 1);
QCOMPARE(fractionalScale->preferredScale(), std::round(1.25 * 120));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
QCOMPARE(fractionalScaleChanged.count(), 1);
QCOMPARE(fractionalScale->preferredScale(), std::round(1.25 * 120));
QCOMPARE(fractionalScale->preferredScale(), 1.25 * 120);
// move to screen 2
window->move(QPoint(1280, 0));
QVERIFY(Test::waylandSync());
QCOMPARE(fractionalScaleChanged.count(), 2);
QCOMPARE(fractionalScale->preferredScale(), std::round(2.0 * 120));
}
void TestFractionalScale::testPopup()
{
std::unique_ptr<KWayland::Client::Surface> toplevelSurface(Test::createSurface());
std::unique_ptr<Test::FractionalScaleV1> toplevelFractionalScale(Test::createFractionalScaleV1(toplevelSurface.get()));
QSignalSpy toplevelFractionalScaleChanged(toplevelFractionalScale.get(), &Test::FractionalScaleV1::preferredScaleChanged);
std::unique_ptr<Test::XdgToplevel> toplevel(Test::createXdgToplevelSurface(toplevelSurface.get()));
// above call commits the surface and blocks for the configure event. We should have received the scale already
// We are sent the value in 120ths
QCOMPARE(toplevelFractionalScaleChanged.count(), 1);
QCOMPARE(toplevelFractionalScale->preferredScale(), std::round(1.25 * 120));
auto toplevelWindow = Test::renderAndWaitForShown(toplevelSurface.get(), QSize(100, 50), Qt::blue);
QVERIFY(toplevelWindow);
QCOMPARE(toplevelFractionalScaleChanged.count(), 1);
QCOMPARE(toplevelFractionalScale->preferredScale(), std::round(1.25 * 120));
std::unique_ptr<KWayland::Client::Surface> popupSurface(Test::createSurface());
std::unique_ptr<Test::FractionalScaleV1> popupFractionalScale(Test::createFractionalScaleV1(popupSurface.get()));
QSignalSpy popupFractionalScaleChanged(popupFractionalScale.get(), &Test::FractionalScaleV1::preferredScaleChanged);
std::unique_ptr<Test::XdgPositioner> positioner(Test::createXdgPositioner());
positioner->set_size(10, 10);
positioner->set_anchor_rect(10, 10, 10, 10);
std::unique_ptr<Test::XdgPopup> popup(Test::createXdgPopupSurface(popupSurface.get(), toplevel->xdgSurface(), positioner.get()));
// above call commits the surface and blocks for the configure event. We should have received the scale already
// We are sent the value in 120ths
QCOMPARE(popupFractionalScaleChanged.count(), 1);
QCOMPARE(popupFractionalScale->preferredScale(), std::round(1.25 * 120));
auto popupWindow = Test::renderAndWaitForShown(popupSurface.get(), QSize(10, 10), Qt::cyan);
QVERIFY(popupWindow);
QCOMPARE(popupFractionalScaleChanged.count(), 1);
QCOMPARE(popupFractionalScale->preferredScale(), std::round(1.25 * 120));
// move the parent to screen 2
toplevelWindow->move(QPoint(1280, 0));
QVERIFY(Test::waylandSync());
QCOMPARE(toplevelFractionalScaleChanged.count(), 2);
QCOMPARE(toplevelFractionalScale->preferredScale(), std::round(2.0 * 120));
QCOMPARE(popupFractionalScaleChanged.count(), 2);
QCOMPARE(popupFractionalScale->preferredScale(), std::round(2.0 * 120));
}
WAYLANDTEST_MAIN(TestFractionalScale)

View File

@ -49,6 +49,7 @@ private Q_SLOTS:
void testUserActionsMenu();
void testMetaShiftW();
void testComponseKey();
void testKeypad();
void testX11WindowShortcut();
void testWaylandWindowShortcut();
void testSetupWindowShortcut();
@ -275,6 +276,44 @@ void GlobalShortcutsTest::testComponseKey()
QTRY_COMPARE(triggeredSpy.count(), 0);
}
void GlobalShortcutsTest::testKeypad()
{
auto zeroAction = std::make_unique<QAction>();
zeroAction->setProperty("componentName", QStringLiteral("kwin"));
zeroAction->setObjectName(QStringLiteral("globalshortcuts-test-keypad-0"));
QSignalSpy zeroActionTriggeredSpy(zeroAction.get(), &QAction::triggered);
KGlobalAccel::self()->setShortcut(zeroAction.get(), QList<QKeySequence>{Qt::MetaModifier | Qt::KeypadModifier | Qt::Key_0}, KGlobalAccel::NoAutoloading);
auto insertAction = std::make_unique<QAction>();
insertAction->setProperty("componentName", QStringLiteral("kwin"));
insertAction->setObjectName(QStringLiteral("globalshortcuts-test-keypad-ins"));
QSignalSpy insertActionTriggeredSpy(insertAction.get(), &QAction::triggered);
KGlobalAccel::self()->setShortcut(insertAction.get(), QList<QKeySequence>{Qt::MetaModifier | Qt::KeypadModifier | Qt::Key_Insert}, KGlobalAccel::NoAutoloading);
// Turn on numlock
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
Test::keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
Test::keyboardKeyPressed(KEY_KP0, timestamp++);
Test::keyboardKeyReleased(KEY_KP0, timestamp++);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QTRY_COMPARE(zeroActionTriggeredSpy.count(), 1);
QCOMPARE(insertActionTriggeredSpy.count(), 0);
// Turn off numlock
Test::keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
Test::keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
Test::keyboardKeyPressed(KEY_KP0, timestamp++);
Test::keyboardKeyReleased(KEY_KP0, timestamp++);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QTRY_COMPARE(insertActionTriggeredSpy.count(), 1);
QCOMPARE(zeroActionTriggeredSpy.count(), 1);
}
void GlobalShortcutsTest::testX11WindowShortcut()
{
// create an X11 window

View File

@ -101,7 +101,7 @@ void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
std::unique_ptr<Test::XdgToplevel> shellSurface1 = Test::createXdgToplevelSurface(surface1.get());
QVERIFY(shellSurface1);
render(surface1.get());
QVERIFY(windowAddedSpy.wait());
@ -110,7 +110,7 @@ void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
std::unique_ptr<Test::XdgToplevel> shellSurface2 = Test::createXdgToplevelSurface(surface2.get());
QVERIFY(shellSurface2);
render(surface2.get());
QVERIFY(windowAddedSpy.wait());

View File

@ -10,6 +10,7 @@
#include "core/output.h"
#include "inputmethod.h"
#include "inputpanelv1window.h"
#include "keyboard_input.h"
#include "pointer_input.h"
#include "qwayland-input-method-unstable-v1.h"
@ -63,6 +64,8 @@ private Q_SLOTS:
void testDisableShowInputPanel();
void testModifierForwarding();
void testFakeEventFallback();
void testOverlayPositioning_data();
void testOverlayPositioning();
private:
void touchNow()
@ -210,12 +213,12 @@ void InputMethodTest::testEnableDisableV3()
kwinApp()->inputMethod()->hide();
QVERIFY(!keyboardClient->isShown());
QSignalSpy windowShownSpy(keyboardClient, &Window::windowShown);
QSignalSpy hiddenChangedSpy(keyboardClient, &Window::hiddenChanged);
// Force enable the text input object. This is what's done by Gtk.
textInputV3->enable();
textInputV3->commit();
windowShownSpy.wait();
hiddenChangedSpy.wait();
QVERIFY(keyboardClient->isShown());
// disable text input and ensure that it is not hiding input panel without commit
@ -358,7 +361,7 @@ void InputMethodTest::testSwitchFocusedSurfaces()
QList<Window *> windows;
std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
QList<Test::XdgToplevel *> toplevels;
std::vector<std::unique_ptr<Test::XdgToplevel>> toplevels;
// We create 3 surfaces
for (int i = 0; i < 3; ++i) {
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
@ -366,7 +369,7 @@ void InputMethodTest::testSwitchFocusedSurfaces()
windows += Test::renderAndWaitForShown(surface.get(), QSize(1280, 1024), Qt::red);
QCOMPARE(workspace()->activeWindow(), windows.constLast());
surfaces.push_back(std::move(surface));
toplevels += shellSurface;
toplevels.push_back(std::move(shellSurface));
}
QCOMPARE(windowAddedSpy.count(), 3);
waylandServer()->seat()->setFocusedTextInputSurface(windows.constFirst()->surface());
@ -385,12 +388,6 @@ void InputMethodTest::testSwitchFocusedSurfaces()
waylandServer()->seat()->setFocusedTextInputSurface(windows.first()->surface());
QVERIFY(activateSpy.count() || activateSpy.wait());
QVERIFY(!kwinApp()->inputMethod()->isActive());
// Destroy the test window.
for (int i = 0; i < windows.count(); ++i) {
delete toplevels[i];
QVERIFY(Test::waitForWindowClosed(windows[i]));
}
}
void InputMethodTest::testV2V3SameClient()
@ -552,6 +549,10 @@ void InputMethodTest::testV3Styling()
// Merged range should be [1,6).
QCOMPARE(textInputPreeditSpy.last().at(1), 1);
QCOMPARE(textInputPreeditSpy.last().at(2), 6);
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
QVERIFY(!kwinApp()->inputMethod()->isActive());
}
void InputMethodTest::testDisableShowInputPanel()
@ -584,6 +585,9 @@ void InputMethodTest::testDisableShowInputPanel()
textInputV2->showInputPanel();
QVERIFY(requestShowInputPanelSpy.count() || requestShowInputPanelSpy.wait());
QVERIFY(!kwinApp()->inputMethod()->isActive());
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
}
void InputMethodTest::testModifierForwarding()
@ -655,6 +659,10 @@ void InputMethodTest::testModifierForwarding()
QVERIFY(modifierSpy.count() == 3 || modifierSpy.wait());
disconnect(keyChangedConnection);
disconnect(modifiersChangedConnection);
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
QVERIFY(!kwinApp()->inputMethod()->isActive());
}
void InputMethodTest::testFakeEventFallback()
@ -726,6 +734,71 @@ void InputMethodTest::testFakeEventFallback()
compare(keySpy.at(0), KEY_ENTER, KWayland::Client::Keyboard::KeyState::Pressed);
compare(keySpy.at(1), KEY_ENTER, KWayland::Client::Keyboard::KeyState::Released);
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
kwinApp()->inputMethod()->setActive(false);
QVERIFY(!kwinApp()->inputMethod()->isActive());
}
void InputMethodTest::testOverlayPositioning_data()
{
QTest::addColumn<QRect>("cursorRectangle");
QTest::addColumn<QRect>("result");
QTest::newRow("regular") << QRect(10, 20, 30, 40) << QRect(60, 160, 200, 50);
QTest::newRow("offscreen-left") << QRect(-200, 40, 30, 40) << QRect(0, 180, 200, 50);
QTest::newRow("offscreen-right") << QRect(1200, 40, 30, 40) << QRect(1080, 180, 200, 50);
QTest::newRow("offscreen-top") << QRect(1200, -400, 30, 40) << QRect(1080, 0, 200, 50);
// Check it is flipped near the bottom of screen (anchor point 844 + 100 + 40 = 1024 - 40)
QTest::newRow("offscreen-bottom-flip") << QRect(1200, 844, 30, 40) << QRect(1080, 894, 200, 50);
// Top is (screen height 1024 - window height 50) = 984
QTest::newRow("offscreen-bottom-slide") << QRect(1200, 1200, 30, 40) << QRect(1080, 974, 200, 50);
}
void InputMethodTest::testOverlayPositioning()
{
QFETCH(QRect, cursorRectangle);
QFETCH(QRect, result);
Test::inputMethod()->setMode(Test::MockInputMethod::Mode::Overlay);
QVERIFY(!kwinApp()->inputMethod()->isActive());
touchNow();
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
QSignalSpy windowRemovedSpy(workspace(), &Workspace::windowRemoved);
QSignalSpy activateSpy(kwinApp()->inputMethod(), &InputMethod::activeChanged);
std::unique_ptr<KWayland::Client::TextInput> textInput(Test::waylandTextInputManager()->createTextInput(Test::waylandSeat()));
// Create an xdg_toplevel surface and wait for the compositor to catch up.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
// Make the window smaller than the screen and move it.
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(1080, 824), Qt::red);
window->move(QPointF(50, 100));
waylandServer()->seat()->setFocusedTextInputSurface(window->surface());
textInput->setCursorRectangle(cursorRectangle);
textInput->enable(surface.get());
// Overlay is shown upon activate
QVERIFY(windowAddedSpy.wait());
QCOMPARE(workspace()->activeWindow(), window);
QCOMPARE(windowAddedSpy.count(), 2);
QVERIFY(activateSpy.count() || activateSpy.wait());
QVERIFY(kwinApp()->inputMethod()->isActive());
auto keyboardWindow = kwinApp()->inputMethod()->panel();
QVERIFY(keyboardWindow);
// Check the overlay window is placed with cursor rectangle + window position.
QCOMPARE(keyboardWindow->frameGeometry(), result);
// Destroy the test window.
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
Test::inputMethod()->setMode(Test::MockInputMethod::Mode::TopLevel);
}
WAYLANDTEST_MAIN(InputMethodTest)

View File

@ -500,16 +500,6 @@ void InternalWindowTest::testMove()
internalWindow->move(QPoint(10, 20));
QCOMPARE(internalWindow->frameGeometry(), QRect(10, 20, 100, 100));
QTRY_COMPARE(win.geometry(), QRect(10, 20, 100, 100));
// now move with a Geometry update blocker
{
GeometryUpdatesBlocker blocker(internalWindow);
internalWindow->move(QPoint(5, 10));
// not synced!
QCOMPARE(win.geometry(), QRect(10, 20, 100, 100));
}
// after destroying the blocker it should be synced
QTRY_COMPARE(win.geometry(), QRect(5, 10, 100, 100));
}
void InternalWindowTest::testSkipCloseAnimation_data()

View File

@ -58,7 +58,6 @@ private Q_SLOTS:
void testReconfigure();
void testChangeLayoutThroughDBus();
void testPerLayoutShortcut();
void testDBusServiceExport();
void testVirtualDesktopPolicy();
void testWindowPolicy();
void testApplicationPolicy();
@ -307,36 +306,6 @@ void KeyboardLayoutTest::testPerLayoutShortcut()
Test::keyboardKeyReleased(KEY_LEFTCTRL, timestamp++);
}
void KeyboardLayoutTest::testDBusServiceExport()
{
// verifies that the dbus service is only exported if there are at least two layouts
// first configure layouts, with just one layout
layoutGroup.writeEntry("LayoutList", QStringLiteral("us"));
layoutGroup.sync();
reconfigureLayouts();
auto xkb = input()->keyboard()->xkb();
QCOMPARE(xkb->numberOfLayouts(), 1u);
// default layout is English
QCOMPARE(xkb->layoutName(), QStringLiteral("English (US)"));
// with one layout we should not have the dbus interface
QVERIFY(!QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.keyboard")).value());
// reconfigure to two layouts
layoutGroup.writeEntry("LayoutList", QStringLiteral("us,de"));
layoutGroup.sync();
reconfigureLayouts();
QCOMPARE(xkb->numberOfLayouts(), 2u);
QVERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.keyboard")).value());
// and back to one layout
layoutGroup.writeEntry("LayoutList", QStringLiteral("us"));
layoutGroup.sync();
reconfigureLayouts();
QCOMPARE(xkb->numberOfLayouts(), 1u);
QVERIFY(!QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.keyboard")).value());
}
void KeyboardLayoutTest::testVirtualDesktopPolicy()
{
layoutGroup.writeEntry("LayoutList", QStringLiteral("us,de,de(neo)"));

View File

@ -15,11 +15,14 @@
#include "inputmethod.h"
#include "placement.h"
#include "pluginmanager.h"
#include "utils/xcbutils.h"
#include "wayland_server.h"
#include "workspace.h"
#if KWIN_BUILD_X11
#include "utils/xcbutils.h"
#include "xwayland/xwayland.h"
#include "xwayland/xwaylandlauncher.h"
#endif
#include <KPluginMetaData>
@ -52,6 +55,7 @@ WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, ch
const QStringList configs{
QStringLiteral("kaccessrc"),
QStringLiteral("kglobalshortcutsrc"),
QStringLiteral("kcminputrc"),
};
for (const QString &config : configs) {
if (const QString &fileName = QStandardPaths::locate(QStandardPaths::ConfigLocation, config); !fileName.isEmpty()) {
@ -71,10 +75,18 @@ WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, ch
qunsetenv("XKB_DEFAULT_VARIANT");
qunsetenv("XKB_DEFAULT_OPTIONS");
auto breezerc = KSharedConfig::openConfig(QStringLiteral("breezerc"));
breezerc->group(QStringLiteral("Common")).writeEntry(QStringLiteral("OutlineIntensity"), QStringLiteral("OutlineOff"));
breezerc->sync();
auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
KConfigGroup windowsGroup = config->group(QStringLiteral("Windows"));
windowsGroup.writeEntry("Placement", Placement::policyToString(PlacementSmart));
windowsGroup.sync();
KConfigGroup edgeBarrierGroup = config->group(QStringLiteral("EdgeBarrier"));
edgeBarrierGroup.writeEntry("EdgeBarrier", 0);
edgeBarrierGroup.writeEntry("CornerBarrier", false);
edgeBarrierGroup.sync();
setConfig(config);
const auto ownPath = libraryPaths().last();
@ -83,7 +95,7 @@ WaylandTestApplication::WaylandTestApplication(OperationMode mode, int &argc, ch
setSession(Session::create(Session::Type::Noop));
setOutputBackend(std::make_unique<VirtualBackend>());
WaylandServer::create(this);
m_waylandServer.reset(WaylandServer::create());
setProcessStartupEnvironment(QProcessEnvironment::systemEnvironment());
}
@ -95,13 +107,16 @@ WaylandTestApplication::~WaylandTestApplication()
if (effects) {
effects->unloadAllEffects();
}
#if KWIN_BUILD_X11
m_xwayland.reset();
#endif
destroyVirtualInputDevices();
destroyColorManager();
destroyWorkspace();
destroyInputMethod();
destroyCompositor();
destroyInput();
m_waylandServer.reset();
}
void WaylandTestApplication::createVirtualInputDevices()
@ -175,10 +190,12 @@ void WaylandTestApplication::continueStartupWithScene()
qFatal("Failed to initialize the Wayland server, exiting now");
}
#if KWIN_BUILD_X11
if (operationMode() == OperationModeXwayland) {
m_xwayland = std::make_unique<Xwl::Xwayland>(this);
m_xwayland->init();
}
#endif
notifyStarted();
}
@ -198,10 +215,12 @@ Test::VirtualInputDevice *WaylandTestApplication::virtualTouch() const
return m_virtualTouch.get();
}
#if KWIN_BUILD_X11
XwaylandInterface *WaylandTestApplication::xwayland() const
{
return m_xwayland.get();
}
#endif
Test::FractionalScaleManagerV1::~FractionalScaleManagerV1()
{
@ -220,7 +239,11 @@ int Test::FractionalScaleV1::preferredScale()
void Test::FractionalScaleV1::wp_fractional_scale_v1_preferred_scale(uint32_t scale)
{
if (m_preferredScale == scale) {
return;
}
m_preferredScale = scale;
Q_EMIT preferredScaleChanged();
}
void Test::setOutputConfig(const QList<QRect> &geometries)

View File

@ -34,6 +34,11 @@
#include "qwayland-xdg-decoration-unstable-v1.h"
#include "qwayland-xdg-shell.h"
#include "qwayland-zkde-screencast-unstable-v1.h"
#if HAVE_XDG_DIALOG_V1_HEADER
#include "qwayland-xdg-dialog-v1.h"
#else
#include "qwayland-dialog-v1.h"
#endif
namespace KWayland
{
@ -68,10 +73,15 @@ class ScreencastingV1;
namespace KWin
{
class WaylandServer;
#if KWIN_BUILD_X11
namespace Xwl
{
class Xwayland;
}
#endif
namespace Test
{
@ -93,7 +103,9 @@ public:
Test::VirtualInputDevice *virtualPointer() const;
Test::VirtualInputDevice *virtualKeyboard() const;
Test::VirtualInputDevice *virtualTouch() const;
#if KWIN_BUILD_X11
XwaylandInterface *xwayland() const override;
#endif
protected:
void performStartup() override;
@ -105,7 +117,10 @@ private:
void createVirtualInputDevices();
void destroyVirtualInputDevices();
std::unique_ptr<WaylandServer> m_waylandServer;
#if KWIN_BUILD_X11
std::unique_ptr<Xwl::Xwayland> m_xwayland;
#endif
QString m_inputMethodServerToStart;
std::unique_ptr<Test::VirtualInputDevice> m_virtualPointer;
@ -446,6 +461,11 @@ class MockInputMethod : public QObject, QtWayland::zwp_input_method_v1
{
Q_OBJECT
public:
enum class Mode {
TopLevel,
Overlay,
};
MockInputMethod(struct wl_registry *registry, int id, int version);
~MockInputMethod();
@ -458,6 +478,8 @@ public:
return m_context;
}
void setMode(Mode mode);
Q_SIGNALS:
void activate();
@ -467,8 +489,9 @@ protected:
private:
std::unique_ptr<KWayland::Client::Surface> m_inputSurface;
QtWayland::zwp_input_panel_surface_v1 *m_inputMethodSurface = nullptr;
std::unique_ptr<QtWayland::zwp_input_panel_surface_v1> m_inputMethodSurface;
struct ::zwp_input_method_context_v1 *m_context = nullptr;
Mode m_mode = Mode::TopLevel;
};
class FractionalScaleManagerV1 : public QObject, public QtWayland::wp_fractional_scale_manager_v1
@ -488,8 +511,11 @@ public:
protected:
void wp_fractional_scale_v1_preferred_scale(uint32_t scale) override;
Q_SIGNALS:
void preferredScaleChanged();
private:
int m_preferredScale = 120;
uint m_preferredScale = 120;
};
class ScreenEdgeManagerV1 : public QObject, public QtWayland::kde_screen_edge_manager_v1
@ -534,6 +560,19 @@ public:
~SecurityContextManagerV1() override;
};
class XdgWmDialogV1 : public QtWayland::xdg_wm_dialog_v1
{
public:
~XdgWmDialogV1() override;
};
class XdgDialogV1 : public QtWayland::xdg_dialog_v1
{
public:
XdgDialogV1(XdgWmDialogV1 *wm, XdgToplevel *toplevel);
~XdgDialogV1() override;
};
enum class AdditionalWaylandInterface {
Seat = 1 << 0,
PlasmaShell = 1 << 2,
@ -555,6 +594,7 @@ enum class AdditionalWaylandInterface {
CursorShapeV1 = 1 << 18,
FakeInput = 1 << 19,
SecurityContextManagerV1 = 1 << 20,
XdgDialogV1 = 1 << 21,
};
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
@ -581,7 +621,6 @@ public:
void setLeds(LEDs leds) override;
bool isKeyboard() const override;
bool isAlphaNumericKeyboard() const override;
bool isPointer() const override;
bool isTouchpad() const override;
bool isTouch() const override;
@ -667,13 +706,13 @@ void flushWaylandConnection();
bool waylandSync();
std::unique_ptr<KWayland::Client::Surface> createSurface();
KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface,
KWayland::Client::Surface *parentSurface, QObject *parent = nullptr);
std::unique_ptr<KWayland::Client::SubSurface> createSubSurface(KWayland::Client::Surface *surface,
KWayland::Client::Surface *parentSurface);
LayerSurfaceV1 *createLayerSurfaceV1(KWayland::Client::Surface *surface,
const QString &scope,
KWayland::Client::Output *output = nullptr,
LayerShellV1::layer layer = LayerShellV1::layer_top);
std::unique_ptr<LayerSurfaceV1> createLayerSurfaceV1(KWayland::Client::Surface *surface,
const QString &scope,
KWayland::Client::Output *output = nullptr,
LayerShellV1::layer layer = LayerShellV1::layer_top);
TextInputManagerV3 *waylandTextInputManagerV3();
@ -682,27 +721,27 @@ enum class CreationSetup {
CreateAndConfigure, /// commit and wait for the configure event, making this surface ready to commit buffers
};
QtWayland::zwp_input_panel_surface_v1 *createInputPanelSurfaceV1(KWayland::Client::Surface *surface,
KWayland::Client::Output *output);
std::unique_ptr<QtWayland::zwp_input_panel_surface_v1> createInputPanelSurfaceV1(KWayland::Client::Surface *surface,
KWayland::Client::Output *output,
MockInputMethod::Mode mode);
FractionalScaleV1 *createFractionalScaleV1(KWayland::Client::Surface *surface);
std::unique_ptr<FractionalScaleV1> createFractionalScaleV1(KWayland::Client::Surface *surface);
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent = nullptr);
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface,
CreationSetup configureMode,
QObject *parent = nullptr);
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface);
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface, CreationSetup configureMode);
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface, std::function<void(XdgToplevel *toplevel)> setup);
XdgPositioner *createXdgPositioner();
std::unique_ptr<XdgPositioner> createXdgPositioner();
XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface,
XdgPositioner *positioner,
CreationSetup configureMode = CreationSetup::CreateAndConfigure,
QObject *parent = nullptr);
std::unique_ptr<XdgPopup> createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface,
XdgPositioner *positioner,
CreationSetup configureMode = CreationSetup::CreateAndConfigure);
XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent = nullptr);
IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface);
AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
std::unique_ptr<XdgToplevelDecorationV1> createXdgToplevelDecorationV1(XdgToplevel *toplevel);
std::unique_ptr<IdleInhibitorV1> createIdleInhibitorV1(KWayland::Client::Surface *surface);
std::unique_ptr<AutoHideScreenEdgeV1> createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
std::unique_ptr<XdgDialogV1> createXdgDialogV1(XdgToplevel *toplevel);
/**
* Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface.
@ -758,13 +797,14 @@ bool renderNodeAvailable();
* with X on demand
*/
#if KWIN_BUILD_X11
struct XcbConnectionDeleter
{
void operator()(xcb_connection_t *pointer);
};
typedef std::unique_ptr<xcb_connection_t, XcbConnectionDeleter> XcbConnectionPtr;
XcbConnectionPtr createX11Connection();
#endif
MockInputMethod *inputMethod();
KWayland::Client::Surface *inputPanelSurface();

View File

@ -7,6 +7,7 @@
#include "kwin_wayland_test.h"
#include "core/output.h"
#include "core/outputconfiguration.h"
#include "main.h"
#include "pointer_input.h"
#include "screenedge.h"
@ -44,6 +45,7 @@ private Q_SLOTS:
void testChangeLayer();
void testPlacementArea_data();
void testPlacementArea();
void testPlacementAreaAfterOutputLayoutChange();
void testFill_data();
void testFill();
void testStack();
@ -52,6 +54,7 @@ private Q_SLOTS:
void testActivate_data();
void testActivate();
void testUnmap();
void testScreenEdge_data();
void testScreenEdge();
};
@ -263,7 +266,7 @@ void LayerShellV1WindowTest::testLayer_data()
QTest::addColumn<int>("protocolLayer");
QTest::addColumn<Layer>("compositorLayer");
QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << UnmanagedLayer;
QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << OverlayLayer;
QTest::addRow("top") << int(Test::LayerShellV1::layer_top) << AboveLayer;
QTest::addRow("bottom") << int(Test::LayerShellV1::layer_bottom) << BelowLayer;
QTest::addRow("background") << int(Test::LayerShellV1::layer_background) << DesktopLayer;
@ -356,22 +359,42 @@ void LayerShellV1WindowTest::testPlacementArea_data()
QTest::addColumn<int>("anchor");
QTest::addColumn<QMargins>("margins");
QTest::addColumn<int>("exclusiveZone");
QTest::addColumn<int>("exclusiveEdge");
QTest::addColumn<QRectF>("placementArea");
QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << QRectF(300, 0, 980, 1024);
QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << QRectF(0, 300, 1280, 724);
QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << QRectF(0, 0, 980, 1024);
QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << QRectF(0, 0, 1280, 724);
QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(300, 0, 980, 1024);
QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 300, 1280, 724);
QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 980, 1024);
QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 724);
QTest::addRow("left, negative margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(-5, 0, 0, 0) << 300 << QRectF(295, 0, 985, 1024);
QTest::addRow("top, negative margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, -5, 0, 0) << 300 << QRectF(0, 295, 1280, 729);
QTest::addRow("right, negative margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, -5, 0) << 300 << QRectF(0, 0, 985, 1024);
QTest::addRow("bottom, negative margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, -5) << 300 << QRectF(0, 0, 1280, 729);
QTest::addRow("top | left") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
QTest::addRow("top | right") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
QTest::addRow("bottom | left") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
QTest::addRow("bottom | right") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
QTest::addRow("left, positive margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(5, 0, 0, 0) << 300 << QRectF(305, 0, 975, 1024);
QTest::addRow("top, positive margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 5, 0, 0) << 300 << QRectF(0, 305, 1280, 719);
QTest::addRow("right, positive margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 5, 0) << 300 << QRectF(0, 0, 975, 1024);
QTest::addRow("bottom, positive margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 5) << 300 << QRectF(0, 0, 1280, 719);
QTest::addRow("left, negative margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(-5, 0, 0, 0) << 300 << 0 << QRectF(295, 0, 985, 1024);
QTest::addRow("top, negative margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, -5, 0, 0) << 300 << 0 << QRectF(0, 295, 1280, 729);
QTest::addRow("right, negative margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, -5, 0) << 300 << 0 << QRectF(0, 0, 985, 1024);
QTest::addRow("bottom, negative margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, -5) << 300 << 0 << QRectF(0, 0, 1280, 729);
QTest::addRow("left, positive margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(5, 0, 0, 0) << 300 << 0 << QRectF(305, 0, 975, 1024);
QTest::addRow("top, positive margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 5, 0, 0) << 300 << 0 << QRectF(0, 305, 1280, 719);
QTest::addRow("right, positive margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 5, 0) << 300 << 0 << QRectF(0, 0, 975, 1024);
QTest::addRow("bottom, positive margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 5) << 300 << 0 << QRectF(0, 0, 1280, 719);
QTest::addRow("left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
QTest::addRow("top + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
QTest::addRow("right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
QTest::addRow("bottom + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
QTest::addRow("top | left + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
QTest::addRow("top | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
QTest::addRow("top | right + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
QTest::addRow("top | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
QTest::addRow("bottom | left + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
QTest::addRow("bottom | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
QTest::addRow("bottom | right + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
QTest::addRow("bottom | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
}
void LayerShellV1WindowTest::testPlacementArea()
@ -384,9 +407,11 @@ void LayerShellV1WindowTest::testPlacementArea()
QFETCH(int, anchor);
QFETCH(QMargins, margins);
QFETCH(int, exclusiveZone);
QFETCH(int, exclusiveEdge);
shellSurface->set_anchor(anchor);
shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
shellSurface->set_exclusive_zone(exclusiveZone);
shellSurface->set_exclusive_edge(exclusiveEdge);
shellSurface->set_size(280, 124);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
@ -408,6 +433,54 @@ void LayerShellV1WindowTest::testPlacementArea()
QVERIFY(Test::waitForWindowClosed(window));
}
void LayerShellV1WindowTest::testPlacementAreaAfterOutputLayoutChange()
{
// This test verifies that layer shell windows correctly react to output layout changes.
// The output where the layer surface should be placed.
Output *output = workspace()->activeOutput();
// Create a layer surface with an exclusive zone.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("dock"), Test::waylandOutput(output->name())));
shellSurface->set_layer(Test::LayerShellV1::layer_top);
shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
shellSurface->set_size(100, 50);
shellSurface->set_exclusive_edge(Test::LayerSurfaceV1::anchor_bottom);
shellSurface->set_exclusive_zone(50);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
// Wait for the compositor to position the layer surface.
QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
QVERIFY(configureRequestedSpy.wait());
shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
Window *window = Test::renderAndWaitForShown(surface.get(), configureRequestedSpy.last().at(1).toSize(), Qt::red);
QVERIFY(window);
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
// Move the output 100px down.
OutputConfiguration config1;
{
auto changeSet = config1.changeSet(output);
changeSet->pos = output->geometry().topLeft() + QPoint(0, 100);
}
workspace()->applyOutputConfiguration(config1);
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
// Move the output back to its original position.
OutputConfiguration config2;
{
auto changeSet = config2.changeSet(output);
changeSet->pos = output->geometry().topLeft() - QPoint(0, 100);
}
workspace()->applyOutputConfiguration(config2);
QCOMPARE(workspace()->clientArea(PlacementArea, window), output->geometry().adjusted(0, 0, 0, -50));
// Destroy the window.
shellSurface.reset();
QVERIFY(Test::waitForWindowClosed(window));
}
void LayerShellV1WindowTest::testFill_data()
{
QTest::addColumn<int>("anchor");
@ -672,10 +745,18 @@ void LayerShellV1WindowTest::testUnmap()
QVERIFY(Test::waitForWindowClosed(window));
}
void LayerShellV1WindowTest::testScreenEdge_data()
{
QTest::addColumn<QMargins>("margins");
QTest::addRow("normal") << QMargins(0, 0, 0, 0);
QTest::addRow("with margin") << QMargins(0, 0, 0, 10);
}
void LayerShellV1WindowTest::testScreenEdge()
{
auto config = kwinApp()->config();
config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 150);
config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 75);
config->sync();
workspace()->slotReconfigure();
@ -685,9 +766,11 @@ void LayerShellV1WindowTest::testScreenEdge()
std::unique_ptr<Test::AutoHideScreenEdgeV1> screenEdge(Test::createAutoHideScreenEdgeV1(surface.get(), Test::ScreenEdgeManagerV1::border_bottom));
// Set the initial state of the layer surface.
QFETCH(QMargins, margins);
shellSurface->set_layer(Test::LayerShellV1::layer_top);
shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
shellSurface->set_size(100, 50);
shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
surface->commit(KWayland::Client::Surface::CommitFlag::None);
// Wait for the compositor to position the surface.
@ -701,25 +784,24 @@ void LayerShellV1WindowTest::testScreenEdge()
QVERIFY(window);
QVERIFY(!window->isActive());
QSignalSpy windowShowSpy(window, &Window::windowShown);
QSignalSpy windowHiddenSpy(window, &Window::windowHidden);
QSignalSpy hiddenChangedSpy(window, &Window::hiddenChanged);
quint32 timestamp = 0;
// The layer surface will be hidden and shown when the screen edge is activated or deactivated.
{
screenEdge->activate();
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
screenEdge->deactivate();
QVERIFY(windowShowSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
}
// The layer surface will be shown when the screen edge is triggered.
{
screenEdge->activate();
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
Test::pointerMotion(QPointF(640, 1023), timestamp);
@ -727,7 +809,7 @@ void LayerShellV1WindowTest::testScreenEdge()
Test::pointerMotion(QPointF(640, 1023), timestamp);
timestamp += 160;
Test::pointerMotion(QPointF(640, 512), timestamp);
QVERIFY(windowShowSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
}
@ -735,7 +817,7 @@ void LayerShellV1WindowTest::testScreenEdge()
{
QSignalSpy approachingSpy(workspace()->screenEdges(), &ScreenEdges::approaching);
screenEdge->activate();
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
Test::pointerMotion(QPointF(640, 1020), timestamp++);
@ -744,7 +826,7 @@ void LayerShellV1WindowTest::testScreenEdge()
QVERIFY(approachingSpy.last().at(1).toReal() != 0.0);
screenEdge->deactivate();
QVERIFY(windowShowSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);
@ -754,11 +836,11 @@ void LayerShellV1WindowTest::testScreenEdge()
// The layer surface will be shown when the screen edge is destroyed.
{
screenEdge->activate();
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
screenEdge.reset();
QVERIFY(windowShowSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
}
}

View File

@ -67,12 +67,19 @@ private Q_SLOTS:
void testPointerShortcut();
void testAxisShortcut_data();
void testAxisShortcut();
void testKeyboardShortcut();
void testKeyboardLockShortcut();
void testKeyboardShortcutsDisabledWhenLocked();
void testTouch();
private:
struct WindowHandle
{
Window *window;
std::unique_ptr<KWayland::Client::Surface> surface;
std::unique_ptr<Test::XdgToplevel> shellSurface;
};
void unlock();
std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> showWindow();
WindowHandle showWindow();
KWayland::Client::ConnectionThread *m_connection = nullptr;
KWayland::Client::Compositor *m_compositor = nullptr;
KWayland::Client::Seat *m_seat = nullptr;
@ -147,7 +154,7 @@ void LockScreenTest::unlock()
}
}
std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> LockScreenTest::showWindow()
LockScreenTest::WindowHandle LockScreenTest::showWindow()
{
#define VERIFY(statement) \
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
@ -158,8 +165,8 @@ std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> LockScreenTest::
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
VERIFY(surface.get());
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
VERIFY(shellSurface);
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
VERIFY(shellSurface.get());
// let's render
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
@ -169,7 +176,7 @@ std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> LockScreenTest::
#undef VERIFY
#undef COMPARE
return {window, std::move(surface)};
return {window, std::move(surface), std::move(shellSurface)};
}
void LockScreenTest::initTestCase()
@ -223,7 +230,7 @@ void LockScreenTest::testStackingOrder()
Window *window = windowAddedSpy.first().first().value<Window *>();
QVERIFY(window);
QVERIFY(window->isLockScreen());
QCOMPARE(window->layer(), UnmanagedLayer);
QCOMPARE(window->layer(), OverlayLayer);
UNLOCK;
}
@ -235,7 +242,7 @@ void LockScreenTest::testPointer()
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
QSignalSpy leftSpy(pointer.get(), &KWayland::Client::Pointer::left);
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
// first move cursor into the center of the window
@ -278,7 +285,7 @@ void LockScreenTest::testPointerButton()
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
QSignalSpy buttonChangedSpy(pointer.get(), &KWayland::Client::Pointer::buttonStateChanged);
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
// first move cursor into the center of the window
@ -317,7 +324,7 @@ void LockScreenTest::testPointerAxis()
QSignalSpy axisChangedSpy(pointer.get(), &KWayland::Client::Pointer::axisChanged);
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
// first move cursor into the center of the window
@ -356,7 +363,7 @@ void LockScreenTest::testKeyboard()
QSignalSpy leftSpy(keyboard.get(), &KWayland::Client::Keyboard::left);
QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
QVERIFY(enteredSpy.wait());
QTRY_COMPARE(enteredSpy.count(), 1);
@ -553,7 +560,7 @@ void LockScreenTest::testEffectsKeyboardAutorepeat()
void LockScreenTest::testMoveWindow()
{
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
quint32 timestamp = 1;
@ -685,7 +692,10 @@ void LockScreenTest::testAxisShortcut()
#undef PERFORM
}
void LockScreenTest::testKeyboardShortcut()
/**
* This test verifies that keyboard shortcuts are disabled when the screen is locked
*/
void LockScreenTest::testKeyboardShortcutsDisabledWhenLocked()
{
#if !KWIN_BUILD_GLOBALSHORTCUTS
QSKIP("Can't test shortcuts without shortcuts");
@ -732,12 +742,49 @@ void LockScreenTest::testKeyboardShortcut()
KEYRELEASE(KEY_LEFTALT);
}
/**
* This test verifies that the global keyboard shortcut to lock the screen works
*/
void LockScreenTest::testKeyboardLockShortcut()
{
#if !KWIN_BUILD_GLOBALSHORTCUTS
QSKIP("Can't test shortcuts without shortcuts");
return;
#endif
QList<QKeySequence> shortcuts = KGlobalAccel::self()->globalShortcut("ksmserver", "Lock Session");
// Verify the shortcut is Meta + L, the default
QCOMPARE(shortcuts.first().toString(), QString("Meta+L"));
// Verify the screen is not locked
QVERIFY(!waylandServer()->isScreenLocked());
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
// Trigger the shortcut
quint32 timestamp = 1;
KEYPRESS(KEY_LEFTMETA);
KEYPRESS(KEY_L);
KEYRELEASE(KEY_L);
KEYRELEASE(KEY_LEFTMETA);
// Verify the screen gets locked
QVERIFY(windowAddedSpy.wait());
Window *window = windowAddedSpy.first().first().value<Window *>();
QVERIFY(window);
QVERIFY(window->isLockScreen());
QTRY_COMPARE(ScreenLocker::KSldApp::self()->lockState(), ScreenLocker::KSldApp::Locked);
QVERIFY(waylandServer()->isScreenLocked());
UNLOCK;
}
void LockScreenTest::testTouch()
{
auto touch = m_seat->createTouch(m_seat);
QVERIFY(touch);
QVERIFY(touch->isValid());
auto [window, surface] = showWindow();
auto [window, surface, shellSurface] = showWindow();
QVERIFY(window);
QSignalSpy sequenceStartedSpy(touch, &KWayland::Client::Touch::sequenceStarted);
QSignalSpy cancelSpy(touch, &KWayland::Client::Touch::sequenceCanceled);

View File

@ -1,376 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kwin.h>
#include "kwin_wayland_test.h"
#include "input.h"
#include "keyboard_input.h"
#include "pointer_input.h"
#include "wayland_server.h"
#include "workspace.h"
#include "xkb.h"
#include <KConfigGroup>
#include <QDBusConnection>
#include <linux/input.h>
using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_modifier_only_shortcut-0");
static const QString s_serviceName = QStringLiteral("org.kde.KWin.Test.ModifierOnlyShortcut");
static const QString s_path = QStringLiteral("/Test");
class ModifierOnlyShortcutTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testTrigger_data();
void testTrigger();
void testCapsLock();
void testGlobalShortcutsDisabled_data();
void testGlobalShortcutsDisabled();
};
class Target : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Test.ModifierOnlyShortcut")
public:
Target();
~Target() override;
public Q_SLOTS:
Q_SCRIPTABLE void shortcut();
Q_SIGNALS:
void shortcutTriggered();
};
Target::Target()
: QObject()
{
QDBusConnection::sessionBus().registerService(s_serviceName);
QDBusConnection::sessionBus().registerObject(s_path, s_serviceName, this, QDBusConnection::ExportScriptableSlots);
}
Target::~Target()
{
QDBusConnection::sessionBus().unregisterObject(s_path);
QDBusConnection::sessionBus().unregisterService(s_serviceName);
}
void Target::shortcut()
{
Q_EMIT shortcutTriggered();
}
void ModifierOnlyShortcutTest::initTestCase()
{
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1");
qputenv("XKB_DEFAULT_RULES", "evdev");
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
}
void ModifierOnlyShortcutTest::init()
{
workspace()->setActiveOutput(QPoint(640, 512));
KWin::input()->pointer()->warp(QPoint(640, 512));
}
void ModifierOnlyShortcutTest::cleanup()
{
}
void ModifierOnlyShortcutTest::testTrigger_data()
{
QTest::addColumn<QStringList>("metaConfig");
QTest::addColumn<QStringList>("altConfig");
QTest::addColumn<QStringList>("controlConfig");
QTest::addColumn<QStringList>("shiftConfig");
QTest::addColumn<int>("modifier");
QTest::addColumn<QList<int>>("nonTriggeringMods");
const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")};
const QStringList e = QStringList();
QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
QTest::newRow("rightShift") << e << e << e << trigger << KEY_RIGHTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
}
void ModifierOnlyShortcutTest::testTrigger()
{
// this test verifies that modifier only shortcut triggers correctly
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("ModifierOnlyShortcuts"));
QFETCH(QStringList, metaConfig);
QFETCH(QStringList, altConfig);
QFETCH(QStringList, shiftConfig);
QFETCH(QStringList, controlConfig);
group.writeEntry("Meta", metaConfig);
group.writeEntry("Alt", altConfig);
group.writeEntry("Shift", shiftConfig);
group.writeEntry("Control", controlConfig);
group.sync();
workspace()->slotReconfigure();
// configured shortcut should trigger
quint32 timestamp = 1;
QFETCH(int, modifier);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
// the other shortcuts should not trigger
QFETCH(QList<int>, nonTriggeringMods);
for (auto it = nonTriggeringMods.constBegin(), end = nonTriggeringMods.constEnd(); it != end; it++) {
Test::keyboardKeyPressed(*it, timestamp++);
Test::keyboardKeyReleased(*it, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
}
// try configured again
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// click another key while modifier is held
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyPressed(KEY_A, timestamp++);
Test::keyboardKeyReleased(KEY_A, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// release other key after modifier release
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyPressed(KEY_A, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
Test::keyboardKeyReleased(KEY_A, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// press key before pressing modifier
Test::keyboardKeyPressed(KEY_A, timestamp++);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
Test::keyboardKeyReleased(KEY_A, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// mouse button pressed before clicking modifier
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::LeftButton);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::NoButton);
QCOMPARE(triggeredSpy.count(), 2);
// mouse button press before mod press, release before mod release
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::LeftButton);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::NoButton);
QCOMPARE(triggeredSpy.count(), 2);
// mouse button click while mod is pressed
Test::keyboardKeyPressed(modifier, timestamp++);
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::LeftButton);
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(input()->qtButtonStates(), Qt::NoButton);
QCOMPARE(triggeredSpy.count(), 2);
// scroll while mod is pressed
Test::keyboardKeyPressed(modifier, timestamp++);
Test::pointerAxisVertical(5.0, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// same for horizontal
Test::keyboardKeyPressed(modifier, timestamp++);
Test::pointerAxisHorizontal(5.0, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
#if KWIN_BUILD_SCREENLOCKER
// now try to lock the screen while modifier key is pressed
Test::keyboardKeyPressed(modifier, timestamp++);
QVERIFY(Test::lockScreen());
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
// now trigger while screen is locked, should also not work
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 2);
QVERIFY(Test::unlockScreen());
#endif
}
void ModifierOnlyShortcutTest::testCapsLock()
{
// this test verifies that Capslock does not trigger the shift shortcut
// but other shortcuts still trigger even when Capslock is on
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("ModifierOnlyShortcuts"));
group.writeEntry("Meta", QStringList());
group.writeEntry("Alt", QStringList());
group.writeEntry("Shift", QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")});
group.writeEntry("Control", QStringList());
group.sync();
workspace()->slotReconfigure();
// first test that the normal shortcut triggers
quint32 timestamp = 1;
const int modifier = KEY_LEFTSHIFT;
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
// now capslock
Test::keyboardKeyPressed(KEY_CAPSLOCK, timestamp++);
Test::keyboardKeyReleased(KEY_CAPSLOCK, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier);
QCOMPARE(triggeredSpy.count(), 1);
// currently caps lock is on
// shift still triggers
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier);
QCOMPARE(triggeredSpy.count(), 2);
// meta should also trigger
group.writeEntry("Meta", QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")});
group.writeEntry("Alt", QStringList());
group.writeEntry("Shift", QStringList{});
group.writeEntry("Control", QStringList());
group.sync();
workspace()->slotReconfigure();
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier | Qt::MetaModifier);
QCOMPARE(input()->keyboard()->xkb()->modifiersRelevantForGlobalShortcuts(), Qt::MetaModifier);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QCOMPARE(triggeredSpy.count(), 3);
// set back to shift to ensure we don't trigger with capslock
group.writeEntry("Meta", QStringList());
group.writeEntry("Alt", QStringList());
group.writeEntry("Shift", QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")});
group.writeEntry("Control", QStringList());
group.sync();
workspace()->slotReconfigure();
// release caps lock
Test::keyboardKeyPressed(KEY_CAPSLOCK, timestamp++);
Test::keyboardKeyReleased(KEY_CAPSLOCK, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::NoModifier);
QCOMPARE(triggeredSpy.count(), 3);
}
void ModifierOnlyShortcutTest::testGlobalShortcutsDisabled_data()
{
QTest::addColumn<QStringList>("metaConfig");
QTest::addColumn<QStringList>("altConfig");
QTest::addColumn<QStringList>("controlConfig");
QTest::addColumn<QStringList>("shiftConfig");
QTest::addColumn<int>("modifier");
const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")};
const QStringList e = QStringList();
QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA;
QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA;
QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT;
QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT;
QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL;
QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL;
QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT;
QTest::newRow("rightShift") << e << e << e << trigger << KEY_RIGHTSHIFT;
}
void ModifierOnlyShortcutTest::testGlobalShortcutsDisabled()
{
// this test verifies that when global shortcuts are disabled inside KWin (e.g. through a window rule)
// the modifier only shortcuts do not trigger.
// see BUG: 370146
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("ModifierOnlyShortcuts"));
QFETCH(QStringList, metaConfig);
QFETCH(QStringList, altConfig);
QFETCH(QStringList, shiftConfig);
QFETCH(QStringList, controlConfig);
group.writeEntry("Meta", metaConfig);
group.writeEntry("Alt", altConfig);
group.writeEntry("Shift", shiftConfig);
group.writeEntry("Control", controlConfig);
group.sync();
workspace()->slotReconfigure();
// trigger once to verify the shortcut works
quint32 timestamp = 1;
QFETCH(int, modifier);
QVERIFY(!workspace()->globalShortcutsDisabled());
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
triggeredSpy.clear();
// now disable global shortcuts
workspace()->disableGlobalShortcutsForClient(true);
QVERIFY(workspace()->globalShortcutsDisabled());
// Should not get triggered
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
triggeredSpy.clear();
// enable again
workspace()->disableGlobalShortcutsForClient(false);
QVERIFY(!workspace()->globalShortcutsDisabled());
// should get triggered again
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 1);
}
WAYLANDTEST_MAIN(ModifierOnlyShortcutTest)
#include "modifier_only_shortcut_test.moc"

View File

@ -54,11 +54,6 @@ private Q_SLOTS:
void testPointerMoveEnd_data();
void testPointerMoveEnd();
void testClientSideMove();
void testNetMove();
void testAdjustClientGeometryOfHiddenX11Panel_data();
void testAdjustClientGeometryOfHiddenX11Panel();
void testAdjustClientGeometryOfHiddenWaylandPanel_data();
void testAdjustClientGeometryOfHiddenWaylandPanel();
void testResizeForVirtualKeyboard_data();
void testResizeForVirtualKeyboard();
void testResizeForVirtualKeyboardWithMaximize();
@ -536,234 +531,6 @@ void MoveResizeWindowTest::testClientSideMove()
QCOMPARE(pointerEnteredSpy.last().last().toPoint(), QPoint(50, 25));
}
void MoveResizeWindowTest::testNetMove()
{
// this test verifies that a move request for an X11 window through NET API works
// create an xcb window
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
xcb_window_t windowId = xcb_generate_id(c.get());
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
0, 0, 100, 100,
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, 0, 0);
xcb_icccm_size_hints_set_size(&hints, 1, 100, 100);
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
// let's set a no-border
NETWinInfo winInfo(c.get(), windowId, rootWindow(), NET::WMWindowType, NET::Properties2());
winInfo.setWindowType(NET::Override);
xcb_map_window(c.get(), windowId);
xcb_flush(c.get());
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
QVERIFY(windowCreatedSpy.wait());
X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
QVERIFY(window);
QCOMPARE(window->window(), windowId);
const QRectF origGeo = window->frameGeometry();
// let's move the cursor outside the window
input()->pointer()->warp(workspace()->activeOutput()->geometry().center());
QVERIFY(!exclusiveContains(origGeo, Cursors::self()->mouse()->pos()));
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(!workspace()->moveResizeWindow());
// use NETRootInfo to trigger a move request
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(windowId, origGeo.center().x(), origGeo.center().y(), NET::Move);
xcb_flush(c.get());
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(workspace()->moveResizeWindow(), window);
QVERIFY(window->isInteractiveMove());
QCOMPARE(window->geometryRestore(), origGeo);
QCOMPARE(Cursors::self()->mouse()->pos(), origGeo.center());
// let's move a step
input()->pointer()->warp(Cursors::self()->mouse()->pos() + QPoint(10, 10));
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(interactiveMoveResizeSteppedSpy.first().last(), origGeo.translated(10, 10));
// let's cancel the move resize again through the net API
root.moveResizeRequest(windowId, window->frameGeometry().center().x(), window->frameGeometry().center().y(), NET::MoveResizeCancel);
xcb_flush(c.get());
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
// and destroy the window again
xcb_unmap_window(c.get(), windowId);
xcb_destroy_window(c.get(), windowId);
xcb_flush(c.get());
c.reset();
QSignalSpy windowClosedSpy(window, &X11Window::closed);
QVERIFY(windowClosedSpy.wait());
}
void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenX11Panel_data()
{
QTest::addColumn<QRect>("panelGeometry");
QTest::addColumn<QPoint>("targetPoint");
QTest::addColumn<QPoint>("expectedAdjustedPoint");
QTest::addColumn<quint32>("hideLocation");
QTest::newRow("top") << QRect(0, 0, 100, 20) << QPoint(50, 25) << QPoint(50, 20) << 0u;
QTest::newRow("bottom") << QRect(0, 1024 - 20, 100, 20) << QPoint(50, 1024 - 25 - 50) << QPoint(50, 1024 - 20 - 50) << 2u;
QTest::newRow("left") << QRect(0, 0, 20, 100) << QPoint(25, 50) << QPoint(20, 50) << 3u;
QTest::newRow("right") << QRect(1280 - 20, 0, 20, 100) << QPoint(1280 - 25 - 100, 50) << QPoint(1280 - 20 - 100, 50) << 1u;
}
void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenX11Panel()
{
// this test verifies that auto hiding panels are ignored when adjusting client geometry
// see BUG 365892
// first create our panel
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
xcb_window_t windowId = xcb_generate_id(c.get());
QFETCH(QRect, panelGeometry);
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
panelGeometry.x(), panelGeometry.y(), panelGeometry.width(), panelGeometry.height(),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, panelGeometry.x(), panelGeometry.y());
xcb_icccm_size_hints_set_size(&hints, 1, panelGeometry.width(), panelGeometry.height());
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
NETWinInfo winInfo(c.get(), windowId, rootWindow(), NET::WMWindowType, NET::Properties2());
winInfo.setWindowType(NET::Dock);
xcb_map_window(c.get(), windowId);
xcb_flush(c.get());
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
QVERIFY(windowCreatedSpy.wait());
X11Window *panel = windowCreatedSpy.first().first().value<X11Window *>();
QVERIFY(panel);
QCOMPARE(panel->window(), windowId);
QCOMPARE(panel->frameGeometry(), panelGeometry);
QVERIFY(panel->isDock());
// let's create a window
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
QVERIFY(surface != nullptr);
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
QVERIFY(shellSurface != nullptr);
auto testWindow = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(testWindow);
QVERIFY(testWindow->isMovable());
// panel is not yet hidden, we should snap against it
QFETCH(QPoint, targetPoint);
QTEST(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false).toPoint(), "expectedAdjustedPoint");
// now let's hide the panel
QSignalSpy panelHiddenSpy(panel, &Window::windowHidden);
QFETCH(quint32, hideLocation);
xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, windowId, atoms->kde_screen_edge_show, XCB_ATOM_CARDINAL, 32, 1, &hideLocation);
xcb_flush(c.get());
QVERIFY(panelHiddenSpy.wait());
// now try to snap again
QCOMPARE(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false), targetPoint);
// and destroy the panel again
xcb_unmap_window(c.get(), windowId);
xcb_destroy_window(c.get(), windowId);
xcb_flush(c.get());
c.reset();
QSignalSpy panelClosedSpy(panel, &X11Window::closed);
QVERIFY(panelClosedSpy.wait());
// snap once more
QCOMPARE(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false), targetPoint);
// and close
QSignalSpy windowClosedSpy(testWindow, &Window::closed);
shellSurface.reset();
surface.reset();
QVERIFY(windowClosedSpy.wait());
}
void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenWaylandPanel_data()
{
QTest::addColumn<uint32_t>("anchor");
QTest::addColumn<QRect>("panelGeometry");
QTest::addColumn<QPoint>("targetPoint");
QTest::addColumn<QPoint>("expectedAdjustedPoint");
QTest::newRow("top") << uint32_t(Test::LayerSurfaceV1::anchor_top) << QRect(0, 0, 1280, 20) << QPoint(50, 25) << QPoint(50, 20);
QTest::newRow("bottom") << uint32_t(Test::LayerSurfaceV1::anchor_bottom) << QRect(0, 1024 - 20, 1280, 20) << QPoint(50, 1024 - 25 - 50) << QPoint(50, 1024 - 20 - 50);
QTest::newRow("left") << uint32_t(Test::LayerSurfaceV1::anchor_left) << QRect(0, 0, 20, 1024) << QPoint(25, 50) << QPoint(20, 50);
QTest::newRow("right") << uint32_t(Test::LayerSurfaceV1::anchor_right) << QRect(1280 - 20, 0, 20, 1024) << QPoint(1280 - 25 - 100, 50) << QPoint(1280 - 20 - 100, 50);
}
void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenWaylandPanel()
{
// this test verifies that hidden panels are ignored when adjusting client geometry
// see BUG 365892
// first create our panel
std::unique_ptr<KWayland::Client::Surface> panelSurface(Test::createSurface());
std::unique_ptr<Test::LayerSurfaceV1> panelShellSurface(Test::createLayerSurfaceV1(panelSurface.get(), QStringLiteral("dock")));
QFETCH(QRect, panelGeometry);
QFETCH(uint32_t, anchor);
panelShellSurface->set_anchor(anchor);
panelShellSurface->set_size(panelGeometry.width(), panelGeometry.height());
panelSurface->commit(KWayland::Client::Surface::CommitFlag::None);
// let's render
QSignalSpy panelConfigureRequestedSpy(panelShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
QVERIFY(panelConfigureRequestedSpy.wait());
auto panel = Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
QVERIFY(panel);
QCOMPARE(panel->frameGeometry(), panelGeometry);
QVERIFY(panel->isDock());
// let's create a window
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
QVERIFY(surface != nullptr);
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
QVERIFY(shellSurface != nullptr);
auto testWindow = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(testWindow);
QVERIFY(testWindow->isMovable());
// panel is not yet hidden, we should snap against it
QFETCH(QPoint, targetPoint);
QTEST(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false).toPoint(), "expectedAdjustedPoint");
// now let's hide the panel
panel->setHidden(true);
// now try to snap again
QCOMPARE(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false), targetPoint);
// and destroy the panel again
QSignalSpy panelClosedSpy(panel, &Window::closed);
panelShellSurface.reset();
panelSurface.reset();
QVERIFY(panelClosedSpy.wait());
// snap once more
QCOMPARE(Workspace::self()->adjustWindowPosition(testWindow, targetPoint, false), targetPoint);
// and close
QSignalSpy windowClosedSpy(testWindow, &Window::closed);
shellSurface.reset();
surface.reset();
QVERIFY(windowClosedSpy.wait());
}
void MoveResizeWindowTest::testResizeForVirtualKeyboard_data()
{
QTest::addColumn<QRect>("windowRect");
@ -1039,6 +806,12 @@ void MoveResizeWindowTest::testCancelInteractiveMoveResize()
QVERIFY(shellSurface != nullptr);
Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
QSignalSpy frameGeomtryChangedSpy(window, &Window::frameGeometryChanged);
QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// tile / maximize window
QFETCH(QuickTileMode, quickTileMode);
@ -1048,21 +821,20 @@ void MoveResizeWindowTest::testCancelInteractiveMoveResize()
} else {
window->setQuickTileMode(quickTileMode, true);
}
QCOMPARE(window->quickTileMode(), quickTileMode);
QCOMPARE(window->requestedQuickTileMode(), quickTileMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().first().toSize(), Qt::blue);
QVERIFY(frameGeomtryChangedSpy.wait());
QCOMPARE(window->quickTileMode(), quickTileMode);
const QRectF geometry = window->moveResizeGeometry();
const QRectF geometryRestore = window->geometryRestore();
// Start resizing the client.
QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
QCOMPARE(workspace()->moveResizeWindow(), nullptr);
QCOMPARE(window->isInteractiveMove(), false);
QCOMPARE(window->isInteractiveResize(), false);
@ -1072,12 +844,22 @@ void MoveResizeWindowTest::testCancelInteractiveMoveResize()
QCOMPARE(window->isInteractiveMove(), false);
QCOMPARE(window->isInteractiveResize(), true);
Test::pointerMotionRelative(QPoint(1, 1), 1);
Test::pointerMotionRelative(QPoint(-10, -10), 1);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().first().toSize(), Qt::blue);
QVERIFY(frameGeomtryChangedSpy.wait());
QCOMPARE(window->quickTileMode(), QuickTileMode());
QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
// cancel moveresize, all state from before should be restored
window->keyPressEvent(Qt::Key::Key_Escape);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().first().toSize(), Qt::blue);
QVERIFY(frameGeomtryChangedSpy.wait());
QCOMPARE(window->moveResizeGeometry(), geometry);
QCOMPARE(window->quickTileMode(), quickTileMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);

View File

@ -26,8 +26,6 @@
using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_no_global_shortcuts-0");
static const QString s_serviceName = QStringLiteral("org.kde.KWin.Test.ModifierOnlyShortcut");
static const QString s_path = QStringLiteral("/Test");
Q_DECLARE_METATYPE(KWin::ElectricBorder)
@ -42,8 +40,6 @@ private Q_SLOTS:
void init();
void cleanup();
void testTrigger_data();
void testTrigger();
void testKGlobalAccel();
void testPointerShortcut();
void testAxisShortcut_data();
@ -54,7 +50,6 @@ private Q_SLOTS:
class Target : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Test.ModifierOnlyShortcut")
public:
Target();
@ -70,14 +65,10 @@ Q_SIGNALS:
Target::Target()
: QObject()
{
QDBusConnection::sessionBus().registerService(s_serviceName);
QDBusConnection::sessionBus().registerObject(s_path, s_serviceName, this, QDBusConnection::ExportScriptableSlots);
}
Target::~Target()
{
QDBusConnection::sessionBus().unregisterObject(s_path);
QDBusConnection::sessionBus().unregisterService(s_serviceName);
}
void Target::shortcut()
@ -89,7 +80,8 @@ void NoGlobalShortcutsTest::initTestCase()
{
qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder");
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName, KWin::WaylandServer::InitializationFlag::NoGlobalShortcuts));
kwinApp()->setSupportsGlobalShortcuts(false);
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
@ -113,62 +105,6 @@ void NoGlobalShortcutsTest::cleanup()
{
}
void NoGlobalShortcutsTest::testTrigger_data()
{
QTest::addColumn<QStringList>("metaConfig");
QTest::addColumn<QStringList>("altConfig");
QTest::addColumn<QStringList>("controlConfig");
QTest::addColumn<QStringList>("shiftConfig");
QTest::addColumn<int>("modifier");
QTest::addColumn<QList<int>>("nonTriggeringMods");
const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")};
const QStringList e = QStringList();
QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
QTest::newRow("rightShift") << e << e << e << trigger << KEY_RIGHTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
}
void NoGlobalShortcutsTest::testTrigger()
{
// test based on ModifierOnlyShortcutTest::testTrigger
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
KConfigGroup group = kwinApp()->config()->group(QStringLiteral("ModifierOnlyShortcuts"));
QFETCH(QStringList, metaConfig);
QFETCH(QStringList, altConfig);
QFETCH(QStringList, shiftConfig);
QFETCH(QStringList, controlConfig);
group.writeEntry("Meta", metaConfig);
group.writeEntry("Alt", altConfig);
group.writeEntry("Shift", shiftConfig);
group.writeEntry("Control", controlConfig);
group.sync();
workspace()->slotReconfigure();
// configured shortcut should trigger
quint32 timestamp = 1;
QFETCH(int, modifier);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
// the other shortcuts should not trigger
QFETCH(QList<int>, nonTriggeringMods);
for (auto it = nonTriggeringMods.constBegin(), end = nonTriggeringMods.constEnd(); it != end; it++) {
Test::keyboardKeyPressed(*it, timestamp++);
Test::keyboardKeyReleased(*it, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
}
}
void NoGlobalShortcutsTest::testKGlobalAccel()
{
std::unique_ptr<QAction> action(new QAction(nullptr));

View File

@ -10,11 +10,15 @@
#include "core/outputbackend.h"
#include "core/outputconfiguration.h"
#include "pointer_input.h"
#include "tiles/tilemanager.h"
#include "wayland_server.h"
#include "window.h"
#include "workspace.h"
#include "x11window.h"
#include <KWayland/Client/surface.h>
#include <netwm.h>
#include <xcb/xcb_icccm.h>
using namespace std::chrono_literals;
@ -41,8 +45,16 @@ private Q_SLOTS:
void testWindowRestoredAfterEnablingOutput();
void testMaximizedWindowRestoredAfterEnablingOutput();
void testFullScreenWindowRestoredAfterEnablingOutput();
void testQuickTiledWindowRestoredAfterEnablingOutput();
void testCustomTiledWindowRestoredAfterEnablingOutput_data();
void testCustomTiledWindowRestoredAfterEnablingOutput();
void testWindowRestoredAfterChangingScale();
void testMaximizeStateRestoredAfterEnablingOutput_data();
void testMaximizeStateRestoredAfterEnablingOutput();
void testInvalidGeometryRestoreAfterEnablingOutput();
void testMaximizedWindowDoesntDisappear_data();
void testMaximizedWindowDoesntDisappear();
void testXwaylandScaleChange();
void testWindowNotRestoredAfterMovingWindowAndEnablingOutput();
void testLaptopLidClosed();
@ -458,6 +470,182 @@ void OutputChangesTest::testFullScreenWindowRestoredAfterEnablingOutput()
QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 50, 100, 100, 50));
}
void OutputChangesTest::testQuickTiledWindowRestoredAfterEnablingOutput()
{
// This test verifies that a quick tiled window will be moved to
// its original output and tile when the output is re-enabled
const auto outputs = kwinApp()->outputBackend()->outputs();
// Create a window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
// kwin will send a configure event with the actived state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// Move the window to the right monitor and tile it to the right.
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->move(QPointF(1280 + 50, 100));
window->setQuickTileMode(QuickTileFlag::Right, true);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280 / 2, 1024));
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), QSize(1280 / 2, 1024), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
const QRectF rightQuickTileGeom = QRectF(1280 + 1280 / 2, 0, 1280 / 2, 1024);
QCOMPARE(window->frameGeometry(), rightQuickTileGeom);
QCOMPARE(window->moveResizeGeometry(), rightQuickTileGeom);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->quickTileMode(), QuickTileFlag::Right);
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Right);
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
// Disable the right output.
OutputConfiguration config1;
{
auto changeSet = config1.changeSet(outputs[1]);
changeSet->enabled = false;
}
workspace()->applyOutputConfiguration(config1);
// The window will be moved to the left monitor
QCOMPARE(window->output(), outputs[0]);
// Enable the right monitor again
OutputConfiguration config2;
{
auto changeSet = config2.changeSet(outputs[1]);
changeSet->enabled = true;
}
workspace()->applyOutputConfiguration(config2);
// The window will be moved back to the right monitor, and put in the correct tile
QCOMPARE(window->frameGeometry(), rightQuickTileGeom);
QCOMPARE(window->moveResizeGeometry(), rightQuickTileGeom);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->quickTileMode(), QuickTileFlag::Right);
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Right);
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
}
void OutputChangesTest::testCustomTiledWindowRestoredAfterEnablingOutput_data()
{
const auto outputs = kwinApp()->outputBackend()->outputs();
const size_t tileCount = workspace()->tileManager(outputs[1])->rootTile()->childTiles().size();
QTest::addColumn<size_t>("tileIndex");
for (size_t i = 0; i < tileCount; i++) {
QTest::addRow("tile %lu", i) << i;
}
}
void OutputChangesTest::testCustomTiledWindowRestoredAfterEnablingOutput()
{
// This test verifies that a custom tiled window will be moved to
// its original output and tile when the output is re-enabled
const auto outputs = kwinApp()->outputBackend()->outputs();
// start with only one output
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = false;
workspace()->applyOutputConfiguration(config);
}
// Create a window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
const auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
// kwin will send a configure event with the actived state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
const QRectF originalGeometry = window->moveResizeGeometry();
// Enable the right output
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = true;
workspace()->applyOutputConfiguration(config);
}
QFETCH(size_t, tileIndex);
const QRectF customTileGeom = workspace()->tileManager(outputs[1])->rootTile()->childTiles()[tileIndex]->windowGeometry();
// Move the window to the right monitor and put it in the middle tile.
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->move(customTileGeom.topLeft() + QPointF(50, 50));
const auto geomBeforeTiling = window->moveResizeGeometry();
window->setQuickTileMode(QuickTileFlag::Custom, true);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), customTileGeom.size().toSize());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), customTileGeom.size().toSize(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), customTileGeom);
QCOMPARE(window->moveResizeGeometry(), customTileGeom);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->quickTileMode(), QuickTileFlag::Custom);
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Custom);
QCOMPARE(window->geometryRestore(), geomBeforeTiling);
// Disable the right output.
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = false;
workspace()->applyOutputConfiguration(config);
}
// The window will be moved to the left monitor, and the original geometry restored
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), originalGeometry.size().toSize());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), originalGeometry.size().toSize(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry);
QCOMPARE(window->moveResizeGeometry(), originalGeometry);
QCOMPARE(window->output(), outputs[0]);
QCOMPARE(window->quickTileMode(), QuickTileFlag::None);
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::None);
// Enable the right monitor again
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = true;
workspace()->applyOutputConfiguration(config);
}
// The window will be moved back to the right monitor, and put in the correct tile
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), customTileGeom.size().toSize());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), customTileGeom.size().toSize(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), customTileGeom);
QCOMPARE(window->moveResizeGeometry(), customTileGeom);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->quickTileMode(), QuickTileFlag::Custom);
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Custom);
QCOMPARE(window->geometryRestore(), geomBeforeTiling);
}
void OutputChangesTest::testWindowRestoredAfterChangingScale()
{
// This test verifies that a window will be moved to its original position after changing the scale of an output
@ -501,11 +689,21 @@ void OutputChangesTest::testWindowRestoredAfterChangingScale()
QCOMPARE(window->output(), output);
}
void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput_data()
{
QTest::addColumn<MaximizeMode>("maximizeMode");
QTest::addRow("Vertical Maximization") << MaximizeMode::MaximizeVertical;
QTest::addRow("Horizontal Maximization") << MaximizeMode::MaximizeHorizontal;
QTest::addRow("Full Maximization") << MaximizeMode::MaximizeFull;
}
void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput()
{
// This test verifies that the window state will get restored after disabling and enabling an output,
// even if its maximize state changed in the process
QFETCH(MaximizeMode, maximizeMode);
const auto outputs = kwinApp()->outputBackend()->outputs();
// Disable the right output
@ -540,17 +738,16 @@ void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput()
// Move the window to the right monitor and make it maximized.
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->move(QPointF(1280 + 50, 100));
window->maximize(MaximizeFull);
window->maximize(maximizeMode);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(1280, 1024));
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
const auto maximizedGeometry = window->moveResizeGeometry();
QCOMPARE(window->frameGeometry(), maximizedGeometry);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
QCOMPARE(window->maximizeMode(), maximizeMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
// Disable the right output
@ -581,23 +778,199 @@ void OutputChangesTest::testMaximizeStateRestoredAfterEnablingOutput()
workspace()->applyOutputConfiguration(config);
}
// The window will be moved back to the right monitor, maximized and the geometry restore will be updated
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), maximizedGeometry.size());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), maximizedGeometry);
QCOMPARE(window->moveResizeGeometry(), maximizedGeometry);
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->maximizeMode(), maximizeMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
}
void OutputChangesTest::testInvalidGeometryRestoreAfterEnablingOutput()
{
// This test verifies that the geometry restore gets restore correctly, even if it's invalid
const auto outputs = kwinApp()->outputBackend()->outputs();
// Disable the right output
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = false;
workspace()->applyOutputConfiguration(config);
}
// Create a window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
shellSurface->set_maximized();
{
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
shellSurface->xdgSurface()->surface()->commit(KWayland::Client::Surface::CommitFlag::None);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().first().toUInt());
}
auto window = Test::renderAndWaitForShown(surface.get(), QSize(1280, 1024), Qt::blue);
QVERIFY(window);
QCOMPARE(window->maximizeMode(), MaximizeFull);
const QRectF originalGeometry = window->moveResizeGeometry();
const QRectF originalGeometryRestore = window->geometryRestore();
// Enable the right output
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = true;
workspace()->applyOutputConfiguration(config);
}
// Move the window to the right monitor
window->sendToOutput(outputs[1]);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
QVERIFY(outputs[1]->geometry().contains(window->geometryRestore().topLeft().toPoint()));
QCOMPARE(window->geometryRestore().size(), QSizeF(0, 0));
const QRectF rightGeometryRestore = window->geometryRestore();
// Disable the right output
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = false;
workspace()->applyOutputConfiguration(config);
}
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
// The window will be moved to its prior position on the left monitor, and still maximized
QCOMPARE(window->frameGeometry(), originalGeometry);
QCOMPARE(window->moveResizeGeometry(), originalGeometry);
QCOMPARE(window->output(), outputs[0]);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
QVERIFY(outputs[0]->geometry().contains(window->geometryRestore().topLeft().toPoint()));
QCOMPARE(window->geometryRestore(), originalGeometryRestore);
// Enable the right output again
{
OutputConfiguration config;
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = true;
workspace()->applyOutputConfiguration(config);
}
// The window will be moved back to the right monitor, maximized and the geometry restore will be updated
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), outputs[1]->geometry().size());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), outputs[1]->geometry().size(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->moveResizeGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->output(), outputs[1]);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
QCOMPARE(window->geometryRestore(), QRectF(1280 + 50, 100, 100, 50));
QCOMPARE(window->geometryRestore(), rightGeometryRestore);
}
void OutputChangesTest::testMaximizedWindowDoesntDisappear_data()
{
QTest::addColumn<MaximizeMode>("maximizeMode");
QTest::addRow("Vertical Maximization") << MaximizeMode::MaximizeVertical;
QTest::addRow("Horizontal Maximization") << MaximizeMode::MaximizeHorizontal;
QTest::addRow("Full Maximization") << MaximizeMode::MaximizeFull;
}
void OutputChangesTest::testMaximizedWindowDoesntDisappear()
{
// This test verifies that (vertically, horizontally) maximized windows don't get placed out of the screen
// when the output they're on gets disabled or removed
Test::setOutputConfig({
Test::OutputInfo{
.geometry = QRect(5120 / 3, 1440, 2256 / 1.3, 1504 / 1.3),
.scale = 1.3,
.internal = true,
},
Test::OutputInfo{
.geometry = QRect(0, 0, 5120, 1440),
.scale = 1,
.internal = false,
},
});
const auto outputs = kwinApp()->outputBackend()->outputs();
QFETCH(MaximizeMode, maximizeMode);
workspace()->setActiveOutput(outputs[1]);
// Create a window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(500, 300), Qt::blue);
QVERIFY(window);
// kwin will send a configure event with the actived state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
window->move(outputs[1]->geometry().topLeft() + QPoint(3500, 500));
const QRectF originalGeometry = window->frameGeometry();
QVERIFY(outputs[1]->geometryF().contains(originalGeometry));
// vertically maximize the window
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->maximize(maximizeMode);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->output(), outputs[1]);
const auto maximizedGeometry = window->moveResizeGeometry();
QCOMPARE(window->frameGeometry(), maximizedGeometry);
QCOMPARE(window->maximizeMode(), maximizeMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);
QCOMPARE(window->geometryRestore(), originalGeometry);
// Disable the top output
{
OutputConfiguration config;
auto changeSet0 = config.changeSet(outputs[0]);
changeSet0->pos = QPoint(0, 0);
auto changeSet = config.changeSet(outputs[1]);
changeSet->enabled = false;
workspace()->applyOutputConfiguration(config);
}
// The window should be moved to the left output
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->output(), outputs[0]);
QVERIFY(outputs[0]->geometryF().contains(window->frameGeometry()));
QVERIFY(outputs[0]->geometryF().contains(window->moveResizeGeometry()));
QCOMPARE(window->maximizeMode(), maximizeMode);
QCOMPARE(window->requestedMaximizeMode(), maximizeMode);
}
void OutputChangesTest::testLaptopLidClosed()
{
QSKIP("Laptop lid handling is disabled until config writing is moved into KWin");
Test::setOutputConfig({
Test::OutputInfo{
.geometry = QRect(0, 0, 1280, 1024),
@ -635,6 +1008,80 @@ void OutputChangesTest::testLaptopLidClosed()
input()->removeInputDevice(lidSwitch.get());
}
static X11Window *createX11Window(xcb_connection_t *connection, const QRect &geometry, std::function<void(xcb_window_t)> setup = {})
{
xcb_window_t windowId = xcb_generate_id(connection);
xcb_create_window(connection, XCB_COPY_FROM_PARENT, windowId, rootWindow(),
geometry.x(),
geometry.y(),
geometry.width(),
geometry.height(),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
xcb_icccm_size_hints_set_position(&hints, 1, geometry.x(), geometry.y());
xcb_icccm_size_hints_set_size(&hints, 1, geometry.width(), geometry.height());
xcb_icccm_set_wm_normal_hints(connection, windowId, &hints);
if (setup) {
setup(windowId);
}
xcb_map_window(connection, windowId);
xcb_flush(connection);
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
if (!windowCreatedSpy.wait()) {
return nullptr;
}
return windowCreatedSpy.last().first().value<X11Window *>();
}
void OutputChangesTest::testXwaylandScaleChange()
{
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
});
const auto outputs = workspace()->outputs();
{
OutputConfiguration config;
config.changeSet(outputs[0])->scale = 2;
config.changeSet(outputs[1])->scale = 1;
workspace()->applyOutputConfiguration(config);
}
QCOMPARE(kwinApp()->xwaylandScale(), 2);
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createX11Window(c.get(), QRect(0, 0, 100, 200));
const QRectF originalGeometry = window->frameGeometry();
// disable the left output -> window gets moved to the right output
{
OutputConfiguration config;
config.changeSet(outputs[0])->enabled = false;
workspace()->applyOutputConfiguration(config);
}
// the window should still have logical size of 100, 200
QCOMPARE(kwinApp()->xwaylandScale(), 1);
QCOMPARE(window->frameGeometry().size(), originalGeometry.size());
// enable the left output again
{
OutputConfiguration config;
config.changeSet(outputs[0])->enabled = true;
workspace()->applyOutputConfiguration(config);
}
// the window should be back in its original geometry
QCOMPARE(kwinApp()->xwaylandScale(), 2);
QCOMPARE(window->frameGeometry(), originalGeometry);
}
} // namespace KWin
WAYLANDTEST_MAIN(KWin::OutputChangesTest)

View File

@ -25,13 +25,6 @@ using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_placement-0");
struct PlaceWindowResult
{
QSizeF initiallyConfiguredSize;
Test::XdgToplevel::States initiallyConfiguredStates;
QRectF finalGeometry;
};
class TestPlacement : public QObject
{
Q_OBJECT
@ -56,12 +49,24 @@ private Q_SLOTS:
private:
void setPlacementPolicy(PlacementPolicy policy);
struct WindowHandle
{
Window *window;
std::unique_ptr<KWayland::Client::Surface> surface;
std::unique_ptr<Test::XdgToplevel> shellSurface;
};
struct PlaceWindowResult
{
QSizeF initiallyConfiguredSize;
Test::XdgToplevel::States initiallyConfiguredStates;
QRectF finalGeometry;
};
/*
* Create a window and return relevant results for testing
* defaultSize is the buffer size to use if the compositor returns an empty size in the first configure
* event.
*/
std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> createAndPlaceWindow(const QSize &defaultSize);
std::tuple<PlaceWindowResult, WindowHandle> createAndPlaceWindow(const QSize &defaultSize);
};
void TestPlacement::init()
@ -105,15 +110,15 @@ void TestPlacement::setPlacementPolicy(PlacementPolicy policy)
Workspace::self()->slotReconfigure();
}
std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> TestPlacement::createAndPlaceWindow(const QSize &defaultSize)
std::tuple<TestPlacement::PlaceWindowResult, TestPlacement::WindowHandle> TestPlacement::createAndPlaceWindow(const QSize &defaultSize)
{
PlaceWindowResult rc;
// create a new window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
surfaceConfigureRequestedSpy.wait();
@ -131,7 +136,11 @@ std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> TestPla
auto window = Test::renderAndWaitForShown(surface.get(), size.toSize(), Qt::red);
rc.finalGeometry = window->frameGeometry();
return {rc, std::move(surface)};
return {rc, WindowHandle{
.window = window,
.surface = std::move(surface),
.shellSurface = std::move(shellSurface),
}};
}
void TestPlacement::testPlaceSmart()
@ -150,11 +159,11 @@ void TestPlacement::testPlaceSmart()
setPlacementPolicy(PlacementSmart);
std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
std::vector<WindowHandle> handles;
for (const QRect &desiredGeometry : desiredGeometries) {
auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
surfaces.push_back(std::move(surface));
auto [windowPlacement, handle] = createAndPlaceWindow(QSize(600, 500));
handles.push_back(std::move(handle));
// smart placement shouldn't define a size on windows
QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
@ -181,15 +190,15 @@ void TestPlacement::testPlaceMaximized()
QVERIFY(panelConfigureRequestedSpy.wait());
Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
std::vector<WindowHandle> handles;
// all windows should be initially maximized with an initial configure size sent
for (int i = 0; i < 4; i++) {
auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
auto [windowPlacement, handle] = createAndPlaceWindow(QSize(600, 500));
QVERIFY(windowPlacement.initiallyConfiguredStates & Test::XdgToplevel::State::Maximized);
QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(1280, 1024 - 20));
QCOMPARE(windowPlacement.finalGeometry, QRect(0, 20, 1280, 1024 - 20)); // under the panel
surfaces.push_back(std::move(surface));
handles.push_back(std::move(handle));
}
}
@ -208,14 +217,14 @@ void TestPlacement::testPlaceMaximizedLeavesFullscreen()
QVERIFY(panelConfigureRequestedSpy.wait());
Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
std::vector<WindowHandle> handles;
// all windows should be initially fullscreen with an initial configure size sent, despite the policy
for (int i = 0; i < 4; i++) {
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly);
shellSurface->set_fullscreen(nullptr);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
surface->commit(KWayland::Client::Surface::CommitFlag::None);
QVERIFY(surfaceConfigureRequestedSpy.wait());
@ -230,7 +239,11 @@ void TestPlacement::testPlaceMaximizedLeavesFullscreen()
QCOMPARE(initiallyConfiguredSize, QSize(1280, 1024));
QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
surfaces.push_back(std::move(surface));
handles.emplace_back(WindowHandle{
.window = window,
.surface = std::move(surface),
.shellSurface = std::move(shellSurface),
});
}
}

View File

@ -185,7 +185,7 @@ void PlasmaSurfaceTest::testOSDPlacement()
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
QCOMPARE(window->windowType(), NET::OnScreenDisplay);
QCOMPARE(window->windowType(), WindowType::OnScreenDisplay);
QVERIFY(window->isOnScreenDisplay());
QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 100 / 2, 2 * 1024 / 3 - 50 / 2, 100, 50));
@ -224,7 +224,7 @@ void PlasmaSurfaceTest::testOSDPlacementManualPosition()
QVERIFY(window);
QVERIFY(!window->isPlaceable());
QCOMPARE(window->windowType(), NET::OnScreenDisplay);
QCOMPARE(window->windowType(), WindowType::OnScreenDisplay);
QVERIFY(window->isOnScreenDisplay());
QCOMPARE(window->frameGeometry(), QRect(50, 70, 100, 50));
}
@ -253,7 +253,7 @@ void PlasmaSurfaceTest::testPanelActivate()
auto panel = Test::renderAndWaitForShown(surface.get(), QSize(100, 200), Qt::blue);
QVERIFY(panel);
QCOMPARE(panel->windowType(), NET::Dock);
QCOMPARE(panel->windowType(), WindowType::Dock);
QVERIFY(panel->isDock());
QFETCH(bool, active);
QCOMPARE(panel->dockWantsInput(), active);

View File

@ -38,17 +38,6 @@
namespace KWin
{
static PlatformCursorImage loadReferenceThemeCursor_helper(const KXcursorTheme &theme,
const QByteArray &name)
{
const QList<KXcursorSprite> sprites = theme.shape(name);
if (sprites.isEmpty()) {
return PlatformCursorImage();
}
return PlatformCursorImage(sprites.constFirst().data(), sprites.constFirst().hotspot());
}
static PlatformCursorImage loadReferenceThemeCursor(const QByteArray &name)
{
const Cursor *pointerCursor = Cursors::self()->mouse();
@ -58,20 +47,11 @@ static PlatformCursorImage loadReferenceThemeCursor(const QByteArray &name)
return PlatformCursorImage();
}
PlatformCursorImage platformCursorImage = loadReferenceThemeCursor_helper(theme, name);
if (!platformCursorImage.isNull()) {
return platformCursorImage;
}
ShapeCursorSource source;
source.setShape(name);
source.setTheme(theme);
const QList<QByteArray> alternativeNames = Cursor::cursorAlternativeNames(name);
for (const QByteArray &alternativeName : alternativeNames) {
platformCursorImage = loadReferenceThemeCursor_helper(theme, alternativeName);
if (!platformCursorImage.isNull()) {
break;
}
}
return platformCursorImage;
return PlatformCursorImage(source.image(), source.hotspot());
}
static PlatformCursorImage loadReferenceThemeCursor(const CursorShape &shape)
@ -114,6 +94,8 @@ private Q_SLOTS:
void testWindowUnderCursorWhileButtonPressed();
void testConfineToScreenGeometry_data();
void testConfineToScreenGeometry();
void testEdgeBarrier_data();
void testEdgeBarrier();
void testResizeCursor_data();
void testResizeCursor();
void testMoveCursor();
@ -165,6 +147,11 @@ void PointerInputTest::init()
m_compositor = Test::waylandCompositor();
m_seat = Test::waylandSeat();
auto group = kwinApp()->config()->group(QStringLiteral("EdgeBarrier"));
group.writeEntry("EdgeBarrier", 0);
group.writeEntry("CornerBarrier", false);
group.sync();
Workspace::self()->slotReconfigure();
workspace()->setActiveOutput(QPoint(640, 512));
input()->pointer()->warp(QPoint(640, 512));
}
@ -195,7 +182,7 @@ void PointerInputTest::testWarpingUpdatesFocus()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -240,7 +227,7 @@ void PointerInputTest::testWarpingGeneratesPointerMotion()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -318,7 +305,7 @@ void PointerInputTest::testUpdateFocusAfterScreenChange()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get(), QSize(1280, 1024));
QVERIFY(windowAddedSpy.wait());
@ -503,7 +490,7 @@ void PointerInputTest::testModifierClickUnrestrictedMove()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -568,10 +555,10 @@ void PointerInputTest::testModifierClickUnrestrictedFullscreenMove()
// create a window
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
shellSurface->set_fullscreen(nullptr);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
@ -623,7 +610,7 @@ void PointerInputTest::testModifierClickUnrestrictedMoveGlobalShortcutsDisabled(
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -694,7 +681,7 @@ void PointerInputTest::testModifierScrollOpacity()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -752,7 +739,7 @@ void PointerInputTest::testModifierScrollOpacityGlobalShortcutsDisabled()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -799,7 +786,7 @@ void PointerInputTest::testScrollAction()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
std::unique_ptr<Test::XdgToplevel> shellSurface1 = Test::createXdgToplevelSurface(surface1.get());
QVERIFY(shellSurface1);
render(surface1.get());
QVERIFY(windowAddedSpy.wait());
@ -807,7 +794,7 @@ void PointerInputTest::testScrollAction()
QVERIFY(window1);
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
std::unique_ptr<Test::XdgToplevel> shellSurface2 = Test::createXdgToplevelSurface(surface2.get());
QVERIFY(shellSurface2);
render(surface2.get());
QVERIFY(windowAddedSpy.wait());
@ -854,7 +841,7 @@ void PointerInputTest::testFocusFollowsMouse()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
std::unique_ptr<Test::XdgToplevel> shellSurface1 = Test::createXdgToplevelSurface(surface1.get());
QVERIFY(shellSurface1);
render(surface1.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -862,7 +849,7 @@ void PointerInputTest::testFocusFollowsMouse()
QVERIFY(window1);
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
std::unique_ptr<Test::XdgToplevel> shellSurface2 = Test::createXdgToplevelSurface(surface2.get());
QVERIFY(shellSurface2);
render(surface2.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -936,7 +923,7 @@ void PointerInputTest::testMouseActionInactiveWindow()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
std::unique_ptr<Test::XdgToplevel> shellSurface1 = Test::createXdgToplevelSurface(surface1.get());
QVERIFY(shellSurface1);
render(surface1.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -944,7 +931,7 @@ void PointerInputTest::testMouseActionInactiveWindow()
QVERIFY(window1);
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
std::unique_ptr<Test::XdgToplevel> shellSurface2 = Test::createXdgToplevelSurface(surface2.get());
QVERIFY(shellSurface2);
render(surface2.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -1021,7 +1008,7 @@ void PointerInputTest::testMouseActionActiveWindow()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
std::unique_ptr<Test::XdgToplevel> shellSurface1 = Test::createXdgToplevelSurface(surface1.get());
QVERIFY(shellSurface1);
render(surface1.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -1030,7 +1017,7 @@ void PointerInputTest::testMouseActionActiveWindow()
QSignalSpy window1DestroyedSpy(window1, &QObject::destroyed);
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
std::unique_ptr<Test::XdgToplevel> shellSurface2 = Test::createXdgToplevelSurface(surface2.get());
QVERIFY(shellSurface2);
render(surface2.get(), QSize(800, 800));
QVERIFY(windowAddedSpy.wait());
@ -1097,7 +1084,7 @@ void PointerInputTest::testCursorImage()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -1170,7 +1157,7 @@ void PointerInputTest::testCursorShapeV1()
// move cursor somewhere the new window won't open
input()->pointer()->warp(QPointF(800, 800));
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("default"));
// create a window
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
@ -1191,10 +1178,10 @@ void PointerInputTest::testCursorShapeV1()
// cursor shape won't be changed if the window has no pointer focus
input()->pointer()->warp(QPointF(800, 800));
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("default"));
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_grab);
QVERIFY(Test::waylandSync());
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("default"));
}
class HelperEffect : public Effect
@ -1227,7 +1214,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -1245,19 +1232,19 @@ void PointerInputTest::testEffectOverrideCursorImage()
// now create an effect and set an override cursor
std::unique_ptr<HelperEffect> effect(new HelperEffect);
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("all-scroll"));
// let's change to arrow cursor, this should be our fallback
effects->defineCursor(Qt::ArrowCursor);
QCOMPARE(currentCursorShape(), QByteArray("left_ptr"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("default"));
// back to size all
effects->defineCursor(Qt::SizeAllCursor);
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("all-scroll"));
// move cursor outside the window area
input()->pointer()->warp(QPointF(800, 800));
QCOMPARE(currentCursorShape(), QByteArray("size_all"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("all-scroll"));
// move cursor to area of window
input()->pointer()->warp(window->frameGeometry().center());
@ -1270,7 +1257,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
QVERIFY(enteredSpy.wait());
cursorShapeDevice->set_shape(enteredSpy.last().at(0).value<quint32>(), Test::CursorShapeDeviceV1::shape_crosshair);
QVERIFY(cursorChanged.wait());
QCOMPARE(currentCursorShape(), QByteArray("cross"));
QCOMPARE(currentCursorShape(), QByteArrayLiteral("crosshair"));
}
void PointerInputTest::testPopup()
@ -1292,7 +1279,7 @@ void PointerInputTest::testPopup()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -1317,9 +1304,9 @@ void PointerInputTest::testPopup()
positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
std::unique_ptr<KWayland::Client::Surface> popupSurface = Test::createSurface();
QVERIFY(popupSurface);
Test::XdgPopup *popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
std::unique_ptr<Test::XdgPopup> popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
QVERIFY(popupShellSurface);
QSignalSpy doneReceivedSpy(popupShellSurface, &Test::XdgPopup::doneReceived);
QSignalSpy doneReceivedSpy(popupShellSurface.get(), &Test::XdgPopup::doneReceived);
popupShellSurface->grab(*Test::waylandSeat(), 0); // FIXME: Serial.
render(popupSurface.get(), QSize(100, 50));
QVERIFY(windowAddedSpy.wait());
@ -1398,9 +1385,9 @@ void PointerInputTest::testDecoCancelsPopup()
positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
std::unique_ptr<KWayland::Client::Surface> popupSurface = Test::createSurface();
QVERIFY(popupSurface);
Test::XdgPopup *popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
std::unique_ptr<Test::XdgPopup> popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
QVERIFY(popupShellSurface);
QSignalSpy doneReceivedSpy(popupShellSurface, &Test::XdgPopup::doneReceived);
QSignalSpy doneReceivedSpy(popupShellSurface.get(), &Test::XdgPopup::doneReceived);
popupShellSurface->grab(*Test::waylandSeat(), 0); // FIXME: Serial.
auto popupWindow = Test::renderAndWaitForShown(popupSurface.get(), QSize(100, 50), Qt::red);
QVERIFY(popupWindow);
@ -1435,7 +1422,7 @@ void PointerInputTest::testWindowUnderCursorWhileButtonPressed()
QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), surface.get());
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(shellSurface);
render(surface.get());
QVERIFY(windowAddedSpy.wait());
@ -1458,7 +1445,7 @@ void PointerInputTest::testWindowUnderCursorWhileButtonPressed()
positioner->set_gravity(Test::XdgPositioner::gravity_bottom_right);
std::unique_ptr<KWayland::Client::Surface> popupSurface = Test::createSurface();
QVERIFY(popupSurface);
Test::XdgPopup *popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
std::unique_ptr<Test::XdgPopup> popupShellSurface = Test::createXdgPopupSurface(popupSurface.get(), shellSurface->xdgSurface(), positioner.get());
QVERIFY(popupShellSurface);
render(popupSurface.get(), QSize(99, 49));
QVERIFY(windowAddedSpy.wait());
@ -1562,6 +1549,88 @@ void PointerInputTest::testConfineToScreenGeometry()
QCOMPARE(Cursors::self()->mouse()->pos(), expectedPos);
}
void PointerInputTest::testEdgeBarrier_data()
{
QTest::addColumn<QPoint>("startPos");
QTest::addColumn<QList<QPoint>>("movements");
QTest::addColumn<int>("targetOutputId");
QTest::addColumn<bool>("cornerBarrier");
// screen layout:
//
// +----------+----------+---------+
// | left | top | right |
// +----------+----------+---------+
// | bottom |
// +----------+
//
QTest::newRow("move right - barred") << QPoint(1270, 512) << QList<QPoint>{QPoint(20, 0)} << 0 << false;
QTest::newRow("move left - barred") << QPoint(1290, 512) << QList<QPoint>{QPoint(-20, 0)} << 1 << false;
QTest::newRow("move down - barred") << QPoint(1920, 1014) << QList<QPoint>{QPoint(0, 20)} << 1 << false;
QTest::newRow("move up - barred") << QPoint(1920, 1034) << QList<QPoint>{QPoint(0, -20)} << 3 << false;
QTest::newRow("move top-right - barred") << QPoint(2550, 1034) << QList<QPoint>{QPoint(20, -20)} << 3 << false;
QTest::newRow("move top-left - barred") << QPoint(1290, 1034) << QList<QPoint>{QPoint(-20, -20)} << 3 << false;
QTest::newRow("move bottom-right - barred") << QPoint(1270, 1014) << QList<QPoint>{QPoint(20, 20)} << 0 << false;
QTest::newRow("move bottom-left - barred") << QPoint(2570, 1014) << QList<QPoint>{QPoint(-20, 20)} << 2 << false;
QTest::newRow("move right - not barred") << QPoint(1270, 512) << QList<QPoint>{QPoint(100, 0)} << 1 << false;
QTest::newRow("move left - not barred") << QPoint(1290, 512) << QList<QPoint>{QPoint(-100, 0)} << 0 << false;
QTest::newRow("move down - not barred") << QPoint(1920, 1014) << QList<QPoint>{QPoint(0, 100)} << 3 << false;
QTest::newRow("move up - not barred") << QPoint(1920, 1034) << QList<QPoint>{QPoint(0, -100)} << 1 << false;
QTest::newRow("move top-right - not barred") << QPoint(2550, 1034) << QList<QPoint>{QPoint(100, -100)} << 2 << false;
QTest::newRow("move top-left - not barred") << QPoint(1290, 1034) << QList<QPoint>{QPoint(-100, -100)} << 0 << false;
QTest::newRow("move bottom-right - not barred") << QPoint(1270, 1014) << QList<QPoint>{QPoint(100, 100)} << 3 << false;
QTest::newRow("move bottom-left - not barred") << QPoint(2570, 1014) << QList<QPoint>{QPoint(-100, 100)} << 3 << false;
QTest::newRow("move cumulative") << QPoint(1279, 512) << QList<QPoint>{QPoint(24, 0), QPoint(24, 0)} << 1 << false;
QTest::newRow("move then idle") << QPoint(1279, 512) << QList<QPoint>{QPoint(24, 0), QPoint(0, 0), QPoint(0, 0), QPoint(3, 0)} << 0 << false;
QTest::newRow("move top-right - corner barrier") << QPoint(2550, 1034) << QList<QPoint>{QPoint(100, -100)} << 3 << true;
QTest::newRow("move top-left - corner barrier") << QPoint(1290, 1034) << QList<QPoint>{QPoint(-100, -100)} << 3 << true;
QTest::newRow("move bottom-right - corner barrier") << QPoint(1270, 1014) << QList<QPoint>{QPoint(100, 100)} << 0 << true;
QTest::newRow("move bottom-left - corner barrier") << QPoint(2570, 1014) << QList<QPoint>{QPoint(-100, 100)} << 2 << true;
}
void PointerInputTest::testEdgeBarrier()
{
// setup screen layout
const QList<QRect> geometries{
QRect(0, 0, 1280, 1024),
QRect(1280, 0, 1280, 1024),
QRect(2560, 0, 1280, 1024),
QRect(1280, 1024, 1280, 1024)};
Test::setOutputConfig(geometries);
const auto outputs = workspace()->outputs();
QCOMPARE(outputs.count(), geometries.count());
QCOMPARE(outputs[0]->geometry(), geometries.at(0));
QCOMPARE(outputs[1]->geometry(), geometries.at(1));
QCOMPARE(outputs[2]->geometry(), geometries.at(2));
QCOMPARE(outputs[3]->geometry(), geometries.at(3));
QFETCH(QPoint, startPos);
input()->pointer()->warp(startPos);
quint32 timestamp = waylandServer()->seat()->timestamp().count() + 5000;
Test::pointerMotionRelative(QPoint(0, 0), timestamp);
timestamp += 1000;
QCOMPARE(Cursors::self()->mouse()->pos(), startPos);
auto group = kwinApp()->config()->group(QStringLiteral("EdgeBarrier"));
group.writeEntry("EdgeBarrier", 25);
QFETCH(bool, cornerBarrier);
group.writeEntry("CornerBarrier", cornerBarrier);
group.sync();
workspace()->slotReconfigure();
QFETCH(QList<QPoint>, movements);
for (const auto &movement : movements) {
Test::pointerMotionRelative(movement, timestamp);
timestamp += 1000;
}
QFETCH(int, targetOutputId);
QCOMPARE(workspace()->outputAt(Cursors::self()->mouse()->pos()), workspace()->outputs().at(targetOutputId));
}
void PointerInputTest::testResizeCursor_data()
{
QTest::addColumn<Qt::Edges>("edges");

View File

@ -6,6 +6,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "effect/globals.h"
#include "kwin_wayland_test.h"
#include "core/output.h"
@ -14,6 +15,7 @@
#include "decorations/settings.h"
#include "pointer_input.h"
#include "scripting/scripting.h"
#include "tiles/tilemanager.h"
#include "utils/common.h"
#include "wayland_server.h"
#include "window.h"
@ -172,12 +174,15 @@ void QuickTilingTest::testQuickTiling()
QFETCH(QuickTileMode, mode);
QFETCH(QRectF, expectedGeometry);
const QuickTileMode oldQuickTileMode = window->quickTileMode();
window->setQuickTileMode(mode, true);
QCOMPARE(quickTileChangedSpy.count(), 1);
// at this point the geometry did not yet change
QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
// but quick tile mode already changed
QCOMPARE(window->quickTileMode(), mode);
// but requested quick tile mode already changed, proper quickTileMode not yet
QCOMPARE(window->requestedQuickTileMode(), mode);
// Actual quickTileMOde didn't change yet
QCOMPARE(window->quickTileMode(), oldQuickTileMode);
// but we got requested a new geometry
QVERIFY(surfaceConfigureRequestedSpy.wait());
@ -191,6 +196,8 @@ void QuickTilingTest::testQuickTiling()
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(frameGeometryChangedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), expectedGeometry);
QCOMPARE(quickTileChangedSpy.count(), 1);
QCOMPARE(window->quickTileMode(), mode);
// send window to other screen
QList<Output *> outputs = workspace()->outputs();
@ -200,9 +207,19 @@ void QuickTilingTest::testQuickTiling()
// quick tile should not be changed
QCOMPARE(window->quickTileMode(), mode);
QTEST(window->frameGeometry(), "secondScreen");
Tile *tile = workspace()->tileManager(outputs[1])->quickTile(mode);
QCOMPARE(window->tile(), tile);
// now try to toggle again
window->setQuickTileMode(mode, true);
QTEST(window->requestedQuickTileMode(), "expectedModeAfterToggle");
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
QVERIFY(quickTileChangedSpy.wait());
QCOMPARE(quickTileChangedSpy.count(), 2);
QTEST(window->quickTileMode(), "expectedModeAfterToggle");
}
@ -243,13 +260,14 @@ void QuickTilingTest::testQuickMaximizing()
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
QSignalSpy maximizeChangedSpy(window, &Window::maximizedChanged);
const QuickTileMode oldQuickTileMode = window->quickTileMode();
window->setQuickTileMode(QuickTileFlag::Maximize, true);
QCOMPARE(quickTileChangedSpy.count(), 1);
// at this point the geometry did not yet change
QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
// but quick tile mode already changed
QCOMPARE(window->quickTileMode(), QuickTileFlag::Maximize);
// but requested quick tile mode already changed
QCOMPARE(window->requestedQuickTileMode(), QuickTileFlag::Maximize);
QCOMPARE(window->quickTileMode(), oldQuickTileMode);
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
// but we got requested a new geometry
@ -263,19 +281,19 @@ void QuickTilingTest::testQuickMaximizing()
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(frameGeometryChangedSpy.count(), 1);
QCOMPARE(quickTileChangedSpy.count(), 1);
QCOMPARE(window->quickTileMode(), QuickTileFlag::Maximize);
QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
// window is now set to maximised
QCOMPARE(maximizeChangedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->tile(), nullptr);
// go back to quick tile none
QFETCH(QuickTileMode, mode);
window->setQuickTileMode(mode, true);
QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None));
QCOMPARE(quickTileChangedSpy.count(), 2);
QCOMPARE(window->requestedQuickTileMode(), QuickTileMode(QuickTileFlag::None));
// geometry not yet changed
QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
@ -286,10 +304,12 @@ void QuickTilingTest::testQuickMaximizing()
// render again
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), QSize(100, 50), Qt::yellow);
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::yellow);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(frameGeometryChangedSpy.count(), 2);
QCOMPARE(quickTileChangedSpy.count(), 2);
QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None));
QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
QCOMPARE(maximizeChangedSpy.count(), 2);
@ -324,6 +344,12 @@ void QuickTilingTest::testQuickTilingKeyboardMove()
QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None));
QCOMPARE(window->maximizeMode(), MaximizeRestore);
// We have to receive a configure event when the window becomes active.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged);
workspace()->performWindowOperation(window, Options::UnrestrictedMoveOp);
@ -355,6 +381,11 @@ void QuickTilingTest::testQuickTilingKeyboardMove()
QCOMPARE(Cursors::self()->mouse()->pos(), targetPos);
QVERIFY(!workspace()->moveResizeWindow());
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
QVERIFY(quickTileChangedSpy.wait());
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(window->quickTileMode(), "expectedMode");
}
@ -389,6 +420,7 @@ void QuickTilingTest::testQuickTilingPointerMove()
// we have to receive a configure event when the window becomes active
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
@ -405,13 +437,20 @@ void QuickTilingTest::testQuickTilingPointerMove()
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
Test::pointerMotion(pointerPos, timestamp++);
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(window->quickTileMode(), "expectedMode");
QTEST(window->requestedQuickTileMode(), "expectedMode");
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize);
// attach a new image
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), tileSize, Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry().size(), tileSize);
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(window->quickTileMode(), "expectedMode");
// verify that geometry restore is correct after user untiles the window, but changes
// their mind and tiles the window again while still holding left button
workspace()->performWindowOperation(window, Options::UnrestrictedMoveOp);
@ -419,20 +458,34 @@ void QuickTilingTest::testQuickTilingPointerMove()
Test::pointerButtonPressed(BTN_LEFT, timestamp++); // untile the window
Test::pointerMotion(QPoint(1280, 1024) / 2, timestamp++);
QCOMPARE(quickTileChangedSpy.count(), 2);
QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None));
QCOMPARE(window->requestedQuickTileMode(), QuickTileMode(QuickTileFlag::None));
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
// attach a new image
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), QSize(100, 50), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry().size(), QSize(100, 50));
QCOMPARE(quickTileChangedSpy.count(), 2);
QCOMPARE(window->quickTileMode(), QuickTileMode(QuickTileFlag::None));
Test::pointerMotion(pointerPos, timestamp++); // tile the window again
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
QCOMPARE(quickTileChangedSpy.count(), 3);
QTEST(window->quickTileMode(), "expectedMode");
QTEST(window->requestedQuickTileMode(), "expectedMode");
QCOMPARE(window->geometryRestore(), QRect(0, 0, 100, 50));
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), tileSize);
// attach a new image
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), QSize(100, 50), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry().size(), QSize(100, 50));
QCOMPARE(quickTileChangedSpy.count(), 3);
QTEST(window->quickTileMode(), "expectedMode");
}
void QuickTilingTest::testQuickTilingTouchMove_data()
@ -499,11 +552,17 @@ void QuickTilingTest::testQuickTilingTouchMove()
// TODO: we should test both cases with fixed fake decoration for autotests.
const bool hasBorders = Workspace::self()->decorationBridge()->settings()->borderSize() != KDecoration2::BorderSize::None;
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(window->quickTileMode(), "expectedMode");
QTEST(window->requestedQuickTileMode(), "expectedMode");
QVERIFY(surfaceConfigureRequestedSpy.wait());
QTRY_COMPARE(surfaceConfigureRequestedSpy.count(), hasBorders ? 4 : 3);
QCOMPARE(false, toplevelConfigureRequestedSpy.last().first().toSize().isEmpty());
// attach a new image
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
QVERIFY(quickTileChangedSpy.wait());
QCOMPARE(quickTileChangedSpy.count(), 1);
QTEST(window->quickTileMode(), "expectedMode");
}
void QuickTilingTest::testX11QuickTiling_data()
@ -564,7 +623,6 @@ void QuickTilingTest::testX11QuickTiling()
QCOMPARE(window->quickTileMode(), mode);
QTEST(window->frameGeometry(), "expectedGeometry");
QCOMPARE(window->geometryRestore(), origGeo);
QEXPECT_FAIL("maximize", "For maximize we get two changed signals", Continue);
QCOMPARE(quickTileChangedSpy.count(), 1);
// quick tile to same edge again should also act like send to screen
@ -650,7 +708,6 @@ void QuickTilingTest::testX11QuickTilingAfterVertMaximize()
window->setQuickTileMode(mode, true);
QCOMPARE(window->quickTileMode(), mode);
QTEST(window->frameGeometry(), "expectedGeometry");
QEXPECT_FAIL("", "We get two changed events", Continue);
QCOMPARE(quickTileChangedSpy.count(), 1);
// and destroy the window again
@ -717,6 +774,9 @@ void QuickTilingTest::testShortcut()
const int numberOfQuickTileActions = shortcutList.count();
QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged);
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
for (QString shortcut : shortcutList) {
// invoke global shortcut through dbus
auto msg = QDBusMessage::createMethodCall(
@ -726,28 +786,24 @@ void QuickTilingTest::testShortcut()
QStringLiteral("invokeShortcut"));
msg.setArguments(QList<QVariant>{shortcut});
QDBusConnection::sessionBus().asyncCall(msg);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
QVERIFY(quickTileChangedSpy.wait());
}
QSignalSpy quickTileChangedSpy(window, &Window::quickTileModeChanged);
QCOMPARE(surfaceConfigureRequestedSpy.count(), numberOfQuickTileActions + 1);
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size());
QCOMPARE(frameGeometryChangedSpy.count(), numberOfQuickTileActions);
QTRY_COMPARE(quickTileChangedSpy.count(), numberOfQuickTileActions);
// at this point the geometry did not yet change
QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
// but quick tile mode already changed
// geometry already changed
QCOMPARE(window->frameGeometry(), expectedGeometry);
// quick tile mode already changed
QTEST(window->quickTileMode(), "expectedMode");
// but we got requested a new geometry
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), expectedGeometry.size());
// attach a new image
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), expectedGeometry.size(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue);
QCOMPARE(frameGeometryChangedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), expectedGeometry);
}
@ -812,16 +868,14 @@ void QuickTilingTest::testScript()
QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
s->run();
QVERIFY(quickTileChangedSpy.wait());
QCOMPARE(quickTileChangedSpy.count(), 1);
QVERIFY(runningChangedSpy.wait());
QCOMPARE(runningChangedSpy.count(), 1);
QCOMPARE(runningChangedSpy.first().first().toBool(), true);
// at this point the geometry did not yet change
QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 50));
// but quick tile mode already changed
QCOMPARE(window->quickTileMode(), expectedMode);
// but requested quick tile mode already changed
QCOMPARE(window->requestedQuickTileMode(), expectedMode);
// but we got requested a new geometry
QVERIFY(surfaceConfigureRequestedSpy.wait());
@ -833,6 +887,8 @@ void QuickTilingTest::testScript()
Test::render(surface.get(), expectedGeometry.size(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(quickTileChangedSpy.count(), 1);
QCOMPARE(window->quickTileMode(), expectedMode);
QEXPECT_FAIL("maximize", "Geometry changed called twice for maximize", Continue);
QCOMPARE(frameGeometryChangedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), expectedGeometry);

View File

@ -23,8 +23,6 @@
#include <QPainter>
#include <QScreen>
Q_DECLARE_METATYPE(PipeWireFrame);
#define QCOMPAREIMG(actual, expected, id) \
{ \
if ((actual) != (expected)) { \
@ -49,8 +47,6 @@ public:
ScreencastingTest()
: GenericSceneOpenGLTest(QByteArrayLiteral("O2"))
{
qRegisterMetaType<PipeWireFrame>();
auto wrap = [this](const QString &process, const QStringList &arguments = {}) {
// Make sure PipeWire is running. If it's already running it will just exit
QProcess *p = new QProcess(this);
@ -114,7 +110,9 @@ std::optional<QImage> ScreencastingTest::oneFrameAndClose(Test::ScreencastingStr
std::optional<QImage> img;
connect(&pwStream, &PipeWireSourceStream::frameReceived, qGuiApp, [&img](const PipeWireFrame &frame) {
img = frame.image;
if (frame.dataFrame) {
img = frame.dataFrame->toImage();
}
});
QSignalSpy spy(&pwStream, &PipeWireSourceStream::frameReceived);

View File

@ -65,6 +65,8 @@ private Q_SLOTS:
void testPushBack();
void testObjectEdge_data();
void testObjectEdge();
void testMultipleEntry_data();
void testMultipleEntry();
void testKdeNetWmScreenEdgeShow();
};
@ -304,6 +306,50 @@ void ScreenEdgesTest::testObjectEdge()
QCOMPARE(spy.count(), 2);
}
void ScreenEdgesTest::testMultipleEntry_data()
{
QTest::addColumn<ElectricBorder>("border");
QTest::addColumn<QPointF>("triggerPoint");
QTest::addColumn<QPointF>("delta");
QTest::newRow("top") << ElectricTop << QPointF(640, 0) << QPointF(0, 50);
QTest::newRow("right") << ElectricRight << QPointF(1279, 512) << QPointF(-50, 0);
QTest::newRow("bottom") << ElectricBottom << QPointF(640, 1023) << QPointF(0, -50);
QTest::newRow("left") << ElectricLeft << QPointF(0, 512) << QPointF(50, 0);
}
void ScreenEdgesTest::testMultipleEntry()
{
TestObject callback;
QSignalSpy spy(&callback, &TestObject::gotCallback);
// Reserve a screen edge border.
QFETCH(ElectricBorder, border);
workspace()->screenEdges()->reserve(border, &callback, "callback");
QFETCH(QPointF, triggerPoint);
QFETCH(QPointF, delta);
qint64 timestamp = 0;
while (timestamp < 300) {
// doesn't activate from repeated entries of short duration
Test::pointerMotion(triggerPoint, timestamp);
QVERIFY(spy.isEmpty());
timestamp += 50;
Test::pointerMotion(triggerPoint + delta, timestamp);
QVERIFY(spy.isEmpty());
timestamp += 50;
}
// and this one triggers
Test::pointerMotion(triggerPoint, timestamp);
timestamp += 110;
Test::pointerMotion(triggerPoint, timestamp);
QVERIFY(!spy.isEmpty());
QCOMPARE(spy.count(), 1);
}
static void enableAutoHide(xcb_connection_t *connection, xcb_window_t windowId, ElectricBorder border)
{
if (border == ElectricNone) {
@ -379,7 +425,7 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
// _KDE_NET_WM_SCREEN_EDGE_SHOW has oneshot effect. It's deleted when the window is shown.
auto config = kwinApp()->config();
config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 150);
config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 75);
config->sync();
workspace()->slotReconfigure();
@ -414,15 +460,14 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
ScreenEdgePropertyMonitor screenEdgeMonitor(c.get(), windowId);
QSignalSpy withdrawnSpy(&screenEdgeMonitor, &ScreenEdgePropertyMonitor::withdrawn);
QSignalSpy windowShownSpy(window, &Window::windowShown);
QSignalSpy windowHiddenSpy(window, &Window::windowHidden);
QSignalSpy hiddenChangedSpy(window, &Window::hiddenChanged);
quint32 timestamp = 0;
// The window will be shown when the pointer approaches its reserved screen edge.
{
enableAutoHide(c.get(), windowId, ElectricBottom);
xcb_flush(c.get());
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
Test::pointerMotion(QPointF(640, 1023), timestamp);
@ -439,7 +484,7 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
{
enableAutoHide(c.get(), windowId, ElectricBottom);
xcb_flush(c.get());
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
Test::touchDown(0, QPointF(640, 1023), timestamp++);
@ -449,15 +494,20 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
QVERIFY(window->isShown());
}
// If the screen edge is destroyed (can happen when the screen layout changes), the window will be shown.
// The screen edge reservation won't be affected when recreating screen edges (can happen when the screen layout changes).
{
enableAutoHide(c.get(), windowId, ElectricBottom);
xcb_flush(c.get());
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
workspace()->screenEdges()->recreateEdges();
QVERIFY(withdrawnSpy.wait());
QVERIFY(!withdrawnSpy.wait(50));
QVERIFY(!window->isShown());
enableAutoHide(c.get(), windowId, ElectricNone);
xcb_flush(c.get());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
}
@ -465,12 +515,12 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
{
enableAutoHide(c.get(), windowId, ElectricBottom);
xcb_flush(c.get());
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
enableAutoHide(c.get(), windowId, ElectricNone);
xcb_flush(c.get());
QVERIFY(windowShownSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
}
@ -479,7 +529,7 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
QSignalSpy approachingSpy(workspace()->screenEdges(), &ScreenEdges::approaching);
enableAutoHide(c.get(), windowId, ElectricBottom);
xcb_flush(c.get());
QVERIFY(windowHiddenSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(!window->isShown());
Test::pointerMotion(QPointF(640, 1020), timestamp++);
@ -489,7 +539,7 @@ void ScreenEdgesTest::testKdeNetWmScreenEdgeShow()
enableAutoHide(c.get(), windowId, ElectricNone);
xcb_flush(c.get());
QVERIFY(windowShownSpy.wait());
QVERIFY(hiddenChangedSpy.wait());
QVERIFY(window->isShown());
QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);

View File

@ -30,10 +30,8 @@ private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testCurrent_data();
void testCurrent();
void testCurrentWithFollowsMouse_data();
void testCurrentWithFollowsMouse();
void testActiveOutputFollowsMouse_data();
void testActiveOutputFollowsMouse();
void testCurrentPoint_data();
void testCurrentPoint();
};
@ -92,30 +90,7 @@ void ScreensTest::cleanup()
});
}
void ScreensTest::testCurrent_data()
{
QTest::addColumn<int>("currentId");
QTest::newRow("first") << 0;
QTest::newRow("second") << 1;
}
void ScreensTest::testCurrent()
{
QFETCH(int, currentId);
Output *output = workspace()->outputs().at(currentId);
// Disable "active screen follows mouse"
auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
group.writeEntry("ActiveMouseScreen", false);
group.sync();
workspace()->slotReconfigure();
workspace()->setActiveOutput(output);
QCOMPARE(workspace()->activeOutput(), output);
}
void ScreensTest::testCurrentWithFollowsMouse_data()
void ScreensTest::testActiveOutputFollowsMouse_data()
{
QTest::addColumn<QList<QRect>>("geometries");
QTest::addColumn<QPoint>("cursorPos");
@ -127,12 +102,12 @@ void ScreensTest::testCurrentWithFollowsMouse_data()
QTest::newRow("gap") << QList<QRect>{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QPoint(15, 30) << 1;
}
void ScreensTest::testCurrentWithFollowsMouse()
void ScreensTest::testActiveOutputFollowsMouse()
{
// Enable "active screen follows mouse"
auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
group.writeEntry("ActiveMouseScreen", true);
group.sync();
auto edgeBarrierGroup = kwinApp()->config()->group(QStringLiteral("EdgeBarrier"));
edgeBarrierGroup.writeEntry("EdgeBarrier", 0);
edgeBarrierGroup.writeEntry("CornerBarrier", false);
edgeBarrierGroup.sync();
workspace()->slotReconfigure();
QFETCH(QList<QRect>, geometries);

View File

@ -28,6 +28,10 @@ private Q_SLOTS:
void testRestoreFocus();
void testRestoreFocusWithDesktopWindow();
void testQuitAfterActivatingHiddenWindow();
void testDontQuitAfterActivatingDock();
void testQuitAfterAddingWindow();
void testDontQuitAfterAddingDock();
};
void ShowingDesktopTest::initTestCase()
@ -115,5 +119,121 @@ void ShowingDesktopTest::testRestoreFocusWithDesktopWindow()
QCOMPARE(workspace()->activeWindow(), window2);
}
void ShowingDesktopTest::testQuitAfterActivatingHiddenWindow()
{
// This test verifies that the show desktop mode is deactivated after activating a hidden window.
std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
auto window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
auto window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
QCOMPARE(workspace()->activeWindow(), window2);
workspace()->slotToggleShowDesktop();
QVERIFY(workspace()->showingDesktop());
workspace()->activateWindow(window1);
QVERIFY(!workspace()->showingDesktop());
}
void ShowingDesktopTest::testDontQuitAfterActivatingDock()
{
// This test verifies that activating windows belonging to desktop doesn't break showing desktop mode.
std::unique_ptr<KWayland::Client::Surface> desktopSurface(Test::createSurface());
std::unique_ptr<Test::LayerSurfaceV1> desktopShellSurface(Test::createLayerSurfaceV1(desktopSurface.get(), QStringLiteral("desktop")));
desktopShellSurface->set_keyboard_interactivity(1);
desktopShellSurface->set_layer(Test::LayerShellV1::layer_background);
desktopShellSurface->set_size(0, 0);
desktopShellSurface->set_exclusive_zone(-1);
desktopShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom
| Test::LayerSurfaceV1::anchor_top
| Test::LayerSurfaceV1::anchor_left
| Test::LayerSurfaceV1::anchor_right);
desktopSurface->commit(KWayland::Client::Surface::CommitFlag::None);
QSignalSpy desktopConfigureRequestedSpy(desktopShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
QVERIFY(desktopConfigureRequestedSpy.wait());
auto desktop = Test::renderAndWaitForShown(desktopSurface.get(), desktopConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
std::unique_ptr<KWayland::Client::Surface> dockSurface{Test::createSurface()};
std::unique_ptr<Test::LayerSurfaceV1> dockShellSurface{Test::createLayerSurfaceV1(dockSurface.get(), QStringLiteral("dock"))};
dockShellSurface->set_size(1280, 50);
dockShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
dockShellSurface->set_exclusive_zone(50);
dockShellSurface->set_keyboard_interactivity(1);
dockSurface->commit(KWayland::Client::Surface::CommitFlag::None);
QSignalSpy dockConfigureRequestedSpy(dockShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
QVERIFY(dockConfigureRequestedSpy.wait());
auto dock = Test::renderAndWaitForShown(dockSurface.get(), dockConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window->isActive());
workspace()->slotToggleShowDesktop();
QVERIFY(workspace()->showingDesktop());
QVERIFY(desktop->isActive());
workspace()->activateWindow(dock);
QVERIFY(workspace()->showingDesktop());
QVERIFY(dock->isActive());
workspace()->activateWindow(desktop);
QVERIFY(workspace()->showingDesktop());
QVERIFY(desktop->isActive());
workspace()->slotToggleShowDesktop();
QVERIFY(!workspace()->showingDesktop());
}
void ShowingDesktopTest::testQuitAfterAddingWindow()
{
// This test verifies that the show desktop mode is deactivated after mapping a new window.
std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
workspace()->slotToggleShowDesktop();
QVERIFY(workspace()->showingDesktop());
std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
QVERIFY(!workspace()->showingDesktop());
}
void ShowingDesktopTest::testDontQuitAfterAddingDock()
{
// This test verifies that the show desktop mode is not broken after adding a dock.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window->isActive());
workspace()->slotToggleShowDesktop();
QVERIFY(workspace()->showingDesktop());
std::unique_ptr<KWayland::Client::Surface> dockSurface{Test::createSurface()};
std::unique_ptr<Test::LayerSurfaceV1> dockShellSurface{Test::createLayerSurfaceV1(dockSurface.get(), QStringLiteral("dock"))};
dockShellSurface->set_size(1280, 50);
dockShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
dockShellSurface->set_exclusive_zone(50);
dockShellSurface->set_keyboard_interactivity(1);
dockSurface->commit(KWayland::Client::Surface::CommitFlag::None);
QSignalSpy dockConfigureRequestedSpy(dockShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
QVERIFY(dockConfigureRequestedSpy.wait());
auto dock = Test::renderAndWaitForShown(dockSurface.get(), dockConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
QVERIFY(dock->isActive());
QVERIFY(workspace()->showingDesktop());
workspace()->slotToggleShowDesktop();
}
WAYLANDTEST_MAIN(ShowingDesktopTest)
#include "showing_desktop_test.moc"

View File

@ -84,7 +84,7 @@ void StackingOrderTest::testTransientIsAboveParent()
// Create the parent.
std::unique_ptr<KWayland::Client::Surface> parentSurface = Test::createSurface();
QVERIFY(parentSurface);
std::unique_ptr<Test::XdgToplevel> parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get(), parentSurface.get()));
std::unique_ptr<Test::XdgToplevel> parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get()));
QVERIFY(parentShellSurface);
Window *parent = Test::renderAndWaitForShown(parentSurface.get(), QSize(256, 256), Qt::blue);
QVERIFY(parent);
@ -97,7 +97,7 @@ void StackingOrderTest::testTransientIsAboveParent()
// Create the transient.
std::unique_ptr<KWayland::Client::Surface> transientSurface = Test::createSurface();
QVERIFY(transientSurface);
std::unique_ptr<Test::XdgToplevel> transientShellSurface(Test::createXdgToplevelSurface(transientSurface.get(), transientSurface.get()));
std::unique_ptr<Test::XdgToplevel> transientShellSurface(Test::createXdgToplevelSurface(transientSurface.get()));
QVERIFY(transientShellSurface);
transientShellSurface->set_parent(parentShellSurface->object());
Window *transient = Test::renderAndWaitForShown(transientSurface.get(), QSize(128, 128), Qt::red);
@ -123,7 +123,7 @@ void StackingOrderTest::testRaiseTransient()
// Create the parent.
std::unique_ptr<KWayland::Client::Surface> parentSurface = Test::createSurface();
QVERIFY(parentSurface);
std::unique_ptr<Test::XdgToplevel> parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get(), parentSurface.get()));
std::unique_ptr<Test::XdgToplevel> parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get()));
QVERIFY(parentShellSurface);
Window *parent = Test::renderAndWaitForShown(parentSurface.get(), QSize(256, 256), Qt::blue);
QVERIFY(parent);
@ -136,7 +136,7 @@ void StackingOrderTest::testRaiseTransient()
// Create the transient.
std::unique_ptr<KWayland::Client::Surface> transientSurface = Test::createSurface();
QVERIFY(transientSurface);
std::unique_ptr<Test::XdgToplevel> transientShellSurface(Test::createXdgToplevelSurface(transientSurface.get(), transientSurface.get()));
std::unique_ptr<Test::XdgToplevel> transientShellSurface(Test::createXdgToplevelSurface(transientSurface.get()));
QVERIFY(transientShellSurface);
transientShellSurface->set_parent(parentShellSurface->object());
Window *transient = Test::renderAndWaitForShown(transientSurface.get(), QSize(128, 128), Qt::red);
@ -150,7 +150,7 @@ void StackingOrderTest::testRaiseTransient()
// Create a window that doesn't have any relationship to the parent or the transient.
std::unique_ptr<KWayland::Client::Surface> anotherSurface = Test::createSurface();
QVERIFY(anotherSurface);
std::unique_ptr<Test::XdgToplevel> anotherShellSurface(Test::createXdgToplevelSurface(anotherSurface.get(), anotherSurface.get()));
std::unique_ptr<Test::XdgToplevel> anotherShellSurface(Test::createXdgToplevelSurface(anotherSurface.get()));
QVERIFY(anotherShellSurface);
Window *anotherWindow = Test::renderAndWaitForShown(anotherSurface.get(), QSize(128, 128), Qt::green);
QVERIFY(anotherWindow);
@ -200,8 +200,7 @@ void StackingOrderTest::testDeletedTransient()
// Create the parent.
std::unique_ptr<KWayland::Client::Surface> parentSurface = Test::createSurface();
QVERIFY(parentSurface);
std::unique_ptr<Test::XdgToplevel>
parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get(), parentSurface.get()));
std::unique_ptr<Test::XdgToplevel> parentShellSurface(Test::createXdgToplevelSurface(parentSurface.get()));
QVERIFY(parentShellSurface);
Window *parent = Test::renderAndWaitForShown(parentSurface.get(), QSize(256, 256), Qt::blue);
QVERIFY(parent);
@ -213,7 +212,7 @@ void StackingOrderTest::testDeletedTransient()
// Create the first transient.
std::unique_ptr<KWayland::Client::Surface> transient1Surface = Test::createSurface();
QVERIFY(transient1Surface);
std::unique_ptr<Test::XdgToplevel> transient1ShellSurface(Test::createXdgToplevelSurface(transient1Surface.get(), transient1Surface.get()));
std::unique_ptr<Test::XdgToplevel> transient1ShellSurface(Test::createXdgToplevelSurface(transient1Surface.get()));
QVERIFY(transient1ShellSurface);
transient1ShellSurface->set_parent(parentShellSurface->object());
Window *transient1 = Test::renderAndWaitForShown(transient1Surface.get(), QSize(128, 128), Qt::red);
@ -227,7 +226,7 @@ void StackingOrderTest::testDeletedTransient()
// Create the second transient.
std::unique_ptr<KWayland::Client::Surface> transient2Surface = Test::createSurface();
QVERIFY(transient2Surface);
std::unique_ptr<Test::XdgToplevel> transient2ShellSurface(Test::createXdgToplevelSurface(transient2Surface.get(), transient2Surface.get()));
std::unique_ptr<Test::XdgToplevel> transient2ShellSurface(Test::createXdgToplevelSurface(transient2Surface.get()));
QVERIFY(transient2ShellSurface);
transient2ShellSurface->set_parent(transient1ShellSurface->object());
Window *transient2 = Test::renderAndWaitForShown(transient2Surface.get(), QSize(128, 128), Qt::red);
@ -517,7 +516,7 @@ void StackingOrderTest::testRaiseGroupTransient()
// Create a Wayland window that is not a member of the window group.
std::unique_ptr<KWayland::Client::Surface> anotherSurface = Test::createSurface();
QVERIFY(anotherSurface);
std::unique_ptr<Test::XdgToplevel> anotherShellSurface(Test::createXdgToplevelSurface(anotherSurface.get(), anotherSurface.get()));
std::unique_ptr<Test::XdgToplevel> anotherShellSurface(Test::createXdgToplevelSurface(anotherSurface.get()));
QVERIFY(anotherShellSurface);
Window *anotherWindow = Test::renderAndWaitForShown(anotherSurface.get(), QSize(128, 128), Qt::green);
QVERIFY(anotherWindow);
@ -759,7 +758,7 @@ void StackingOrderTest::testKeepAbove()
// Create the first window.
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get(), surface1.get()));
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
QVERIFY(shellSurface1);
Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(128, 128), Qt::green);
QVERIFY(window1);
@ -771,7 +770,7 @@ void StackingOrderTest::testKeepAbove()
// Create the second window.
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get(), surface2.get()));
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
QVERIFY(shellSurface2);
Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(128, 128), Qt::green);
QVERIFY(window2);
@ -803,7 +802,7 @@ void StackingOrderTest::testKeepBelow()
// Create the first window.
std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
QVERIFY(surface1);
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get(), surface1.get()));
std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
QVERIFY(shellSurface1);
Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(128, 128), Qt::green);
QVERIFY(window1);
@ -815,7 +814,7 @@ void StackingOrderTest::testKeepBelow()
// Create the second window.
std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
QVERIFY(surface2);
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get(), surface2.get()));
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
QVERIFY(shellSurface2);
Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(128, 128), Qt::green);
QVERIFY(window2);
@ -850,7 +849,7 @@ void StackingOrderTest::testPreserveRelativeWindowStacking()
for (int i = 0; i < windowsQuantity; i++) {
surfaces[i] = Test::createSurface();
QVERIFY(surfaces[i]);
shellSurfaces[i] = std::unique_ptr<Test::XdgToplevel>(Test::createXdgToplevelSurface(surfaces[i].get(), surfaces[i].get()));
shellSurfaces[i] = Test::createXdgToplevelSurface(surfaces[i].get());
QVERIFY(shellSurfaces[i]);
}

View File

@ -367,7 +367,7 @@ void StrutsTest::testX11Struts()
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(!window->isDecorated());
QCOMPARE(window->windowType(), NET::Dock);
QCOMPARE(window->windowType(), WindowType::Dock);
QCOMPARE(window->frameGeometry(), windowGeometry);
// this should have affected the client area
@ -479,7 +479,7 @@ void StrutsTest::test363804()
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(!window->isDecorated());
QCOMPARE(window->windowType(), NET::Dock);
QCOMPARE(window->windowType(), WindowType::Dock);
QCOMPARE(window->frameGeometry(), windowGeometry);
// now verify the actual updated client areas
@ -557,7 +557,7 @@ void StrutsTest::testLeftScreenSmallerBottomAligned()
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(!window->isDecorated());
QCOMPARE(window->windowType(), NET::Dock);
QCOMPARE(window->windowType(), WindowType::Dock);
QCOMPARE(window->frameGeometry(), windowGeometry);
// now verify the actual updated client areas
@ -638,7 +638,7 @@ void StrutsTest::testWindowMoveWithPanelBetweenScreens()
QVERIFY(window);
QCOMPARE(window->window(), windowId);
QVERIFY(!window->isDecorated());
QCOMPARE(window->windowType(), NET::Dock);
QCOMPARE(window->windowType(), WindowType::Dock);
QCOMPARE(window->frameGeometry(), windowGeometry);
// now verify the actual updated client areas

View File

@ -104,11 +104,11 @@ void TabBoxTest::testCapsLock()
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_CAPSLOCK, timestamp++);
Test::keyboardKeyReleased(KEY_CAPSLOCK, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier);
QCOMPARE(input()->keyboardModifiers(), Qt::NoModifier);
// press alt+tab
Test::keyboardKeyPressed(KEY_LEFTALT, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier | Qt::AltModifier);
QCOMPARE(input()->keyboardModifiers(), Qt::AltModifier);
Test::keyboardKeyPressed(KEY_TAB, timestamp++);
Test::keyboardKeyReleased(KEY_TAB, timestamp++);

View File

@ -269,6 +269,21 @@ SecurityContextManagerV1::~SecurityContextManagerV1()
destroy();
}
XdgWmDialogV1::~XdgWmDialogV1()
{
destroy();
}
XdgDialogV1::XdgDialogV1(XdgWmDialogV1 *wm, XdgToplevel *toplevel)
: QtWayland::xdg_dialog_v1(wm->get_xdg_dialog(toplevel->object()))
{
}
XdgDialogV1::~XdgDialogV1()
{
destroy();
}
static struct
{
KWayland::Client::ConnectionThread *connection = nullptr;
@ -302,6 +317,7 @@ static struct
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
FakeInput *fakeInput = nullptr;
SecurityContextManagerV1 *securityContextManagerV1 = nullptr;
XdgWmDialogV1 *xdgWmDialogV1;
} s_waylandConnection;
MockInputMethod *inputMethod()
@ -326,14 +342,27 @@ void MockInputMethod::zwp_input_method_v1_activate(struct ::zwp_input_method_con
{
if (!m_inputSurface) {
m_inputSurface = Test::createSurface();
m_inputMethodSurface = Test::createInputPanelSurfaceV1(m_inputSurface.get(), s_waylandConnection.outputs.first());
m_inputMethodSurface = Test::createInputPanelSurfaceV1(m_inputSurface.get(), s_waylandConnection.outputs.first(), m_mode);
}
m_context = context;
Test::render(m_inputSurface.get(), QSize(1280, 400), Qt::blue);
switch (m_mode) {
case Mode::TopLevel:
Test::render(m_inputSurface.get(), QSize(1280, 400), Qt::blue);
break;
case Mode::Overlay:
Test::render(m_inputSurface.get(), QSize(200, 50), Qt::blue);
break;
}
Q_EMIT activate();
}
void MockInputMethod::setMode(MockInputMethod::Mode mode)
{
m_mode = mode;
}
void MockInputMethod::zwp_input_method_v1_deactivate(struct ::zwp_input_method_context_v1 *context)
{
QCOMPARE(context, m_context);
@ -344,8 +373,7 @@ void MockInputMethod::zwp_input_method_v1_deactivate(struct ::zwp_input_method_c
m_inputSurface->release();
m_inputSurface->destroy();
m_inputSurface.reset();
delete m_inputMethodSurface;
m_inputMethodSurface = nullptr;
m_inputMethodSurface.reset();
}
}
@ -505,6 +533,12 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
s_waylandConnection.securityContextManagerV1->init(*registry, name, version);
}
}
if (flags & AdditionalWaylandInterface::XdgDialogV1) {
if (interface == xdg_wm_dialog_v1_interface.name) {
s_waylandConnection.xdgWmDialogV1 = new XdgWmDialogV1();
s_waylandConnection.xdgWmDialogV1->init(*registry, name, version);
}
}
});
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
@ -630,6 +664,8 @@ void destroyWaylandConnection()
s_waylandConnection.fakeInput = nullptr;
delete s_waylandConnection.securityContextManagerV1;
s_waylandConnection.securityContextManagerV1 = nullptr;
delete s_waylandConnection.xdgWmDialogV1;
s_waylandConnection.xdgWmDialogV1 = nullptr;
delete s_waylandConnection.queue; // Must be destroyed last
s_waylandConnection.queue = nullptr;
@ -892,20 +928,19 @@ std::unique_ptr<KWayland::Client::Surface> createSurface()
return s->isValid() ? std::move(s) : nullptr;
}
KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface, QObject *parent)
std::unique_ptr<KWayland::Client::SubSurface> createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface)
{
if (!s_waylandConnection.subCompositor) {
return nullptr;
}
auto s = s_waylandConnection.subCompositor->createSubSurface(surface, parentSurface, parent);
std::unique_ptr<KWayland::Client::SubSurface> s(s_waylandConnection.subCompositor->createSubSurface(surface, parentSurface));
if (!s->isValid()) {
delete s;
return nullptr;
}
return s;
}
LayerSurfaceV1 *createLayerSurfaceV1(KWayland::Client::Surface *surface, const QString &scope, KWayland::Client::Output *output, LayerShellV1::layer layer)
std::unique_ptr<LayerSurfaceV1> createLayerSurfaceV1(KWayland::Client::Surface *surface, const QString &scope, KWayland::Client::Output *output, LayerShellV1::layer layer)
{
LayerShellV1 *shell = s_waylandConnection.layerShellV1;
if (!shell) {
@ -918,37 +953,42 @@ LayerSurfaceV1 *createLayerSurfaceV1(KWayland::Client::Surface *surface, const Q
nativeOutput = *output;
}
LayerSurfaceV1 *shellSurface = new LayerSurfaceV1();
auto shellSurface = std::make_unique<LayerSurfaceV1>();
shellSurface->init(shell->get_layer_surface(*surface, nativeOutput, layer, scope));
return shellSurface;
}
QtWayland::zwp_input_panel_surface_v1 *createInputPanelSurfaceV1(KWayland::Client::Surface *surface, KWayland::Client::Output *output)
std::unique_ptr<QtWayland::zwp_input_panel_surface_v1> createInputPanelSurfaceV1(KWayland::Client::Surface *surface, KWayland::Client::Output *output, MockInputMethod::Mode mode)
{
if (!s_waylandConnection.inputPanelV1) {
qWarning() << "Unable to create the input panel surface. The interface input_panel global is not bound";
return nullptr;
}
QtWayland::zwp_input_panel_surface_v1 *s = new QtWayland::zwp_input_panel_surface_v1(s_waylandConnection.inputPanelV1->get_input_panel_surface(*surface));
auto s = std::make_unique<QtWayland::zwp_input_panel_surface_v1>(s_waylandConnection.inputPanelV1->get_input_panel_surface(*surface));
if (!s->isInitialized()) {
delete s;
return nullptr;
}
s->set_toplevel(output->output(), QtWayland::zwp_input_panel_surface_v1::position_center_bottom);
switch (mode) {
case MockInputMethod::Mode::TopLevel:
s->set_toplevel(output->output(), QtWayland::zwp_input_panel_surface_v1::position_center_bottom);
break;
case MockInputMethod::Mode::Overlay:
s->set_overlay_panel();
break;
}
return s;
}
FractionalScaleV1 *createFractionalScaleV1(KWayland::Client::Surface *surface)
std::unique_ptr<FractionalScaleV1> createFractionalScaleV1(KWayland::Client::Surface *surface)
{
if (!s_waylandConnection.fractionalScaleManagerV1) {
qWarning() << "Unable to create fractional scale surface. The global is not bound";
return nullptr;
}
auto scale = new FractionalScaleV1();
auto scale = std::make_unique<FractionalScaleV1>();
scale->init(s_waylandConnection.fractionalScaleManagerV1->get_fractional_scale(*surface));
return scale;
@ -964,12 +1004,12 @@ static void waitForConfigured(XdgSurface *shellSurface)
shellSurface->ack_configure(surfaceConfigureRequestedSpy.last().first().toUInt());
}
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent)
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface)
{
return createXdgToplevelSurface(surface, CreationSetup::CreateAndConfigure, parent);
return createXdgToplevelSurface(surface, CreationSetup::CreateAndConfigure);
}
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, CreationSetup configureMode, QObject *parent)
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface, CreationSetup configureMode)
{
XdgShell *shell = s_waylandConnection.xdgShell;
@ -979,7 +1019,7 @@ XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, Creati
}
XdgSurface *xdgSurface = new XdgSurface(shell, surface);
XdgToplevel *xdgToplevel = new XdgToplevel(xdgSurface, parent);
std::unique_ptr<XdgToplevel> xdgToplevel = std::make_unique<XdgToplevel>(xdgSurface);
if (configureMode == CreationSetup::CreateAndConfigure) {
waitForConfigured(xdgSurface);
@ -988,7 +1028,25 @@ XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, Creati
return xdgToplevel;
}
XdgPositioner *createXdgPositioner()
std::unique_ptr<XdgToplevel> createXdgToplevelSurface(KWayland::Client::Surface *surface, std::function<void(XdgToplevel *toplevel)> setup)
{
XdgShell *shell = s_waylandConnection.xdgShell;
if (!shell) {
qWarning() << "Could not create an xdg_toplevel surface because xdg_wm_base global is not bound";
return nullptr;
}
XdgSurface *xdgSurface = new XdgSurface(shell, surface);
std::unique_ptr<XdgToplevel> xdgToplevel = std::make_unique<XdgToplevel>(xdgSurface);
setup(xdgToplevel.get());
waitForConfigured(xdgSurface);
return xdgToplevel;
}
std::unique_ptr<XdgPositioner> createXdgPositioner()
{
XdgShell *shell = s_waylandConnection.xdgShell;
@ -997,11 +1055,10 @@ XdgPositioner *createXdgPositioner()
return nullptr;
}
return new XdgPositioner(shell);
return std::make_unique<XdgPositioner>(shell);
}
XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface, XdgPositioner *positioner,
CreationSetup configureMode, QObject *parent)
std::unique_ptr<XdgPopup> createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface, XdgPositioner *positioner, CreationSetup configureMode)
{
XdgShell *shell = s_waylandConnection.xdgShell;
@ -1011,7 +1068,7 @@ XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *
}
XdgSurface *xdgSurface = new XdgSurface(shell, surface);
XdgPopup *xdgPopup = new XdgPopup(xdgSurface, parentSurface, positioner, parent);
std::unique_ptr<XdgPopup> xdgPopup = std::make_unique<XdgPopup>(xdgSurface, parentSurface, positioner);
if (configureMode == CreationSetup::CreateAndConfigure) {
waitForConfigured(xdgSurface);
@ -1020,7 +1077,7 @@ XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *
return xdgPopup;
}
XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent)
std::unique_ptr<XdgToplevelDecorationV1> createXdgToplevelDecorationV1(XdgToplevel *toplevel)
{
XdgDecorationManagerV1 *manager = s_waylandConnection.xdgDecorationManagerV1;
@ -1029,10 +1086,10 @@ XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QO
return nullptr;
}
return new XdgToplevelDecorationV1(manager, toplevel, parent);
return std::make_unique<XdgToplevelDecorationV1>(manager, toplevel);
}
IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface)
std::unique_ptr<IdleInhibitorV1> createIdleInhibitorV1(KWayland::Client::Surface *surface)
{
IdleInhibitManagerV1 *manager = s_waylandConnection.idleInhibitManagerV1;
if (!manager) {
@ -1040,10 +1097,10 @@ IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface)
return nullptr;
}
return new IdleInhibitorV1(manager, surface);
return std::make_unique<IdleInhibitorV1>(manager, surface);
}
AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border)
std::unique_ptr<AutoHideScreenEdgeV1> createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border)
{
ScreenEdgeManagerV1 *manager = s_waylandConnection.screenEdgeManagerV1;
if (!manager) {
@ -1051,10 +1108,10 @@ AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surf
return nullptr;
}
return new AutoHideScreenEdgeV1(manager, surface, border);
return std::make_unique<AutoHideScreenEdgeV1>(manager, surface, border);
}
CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer)
std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer)
{
CursorShapeManagerV1 *manager = s_waylandConnection.cursorShapeManagerV1;
if (!manager) {
@ -1062,7 +1119,17 @@ CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointe
return nullptr;
}
return new CursorShapeDeviceV1(manager, pointer);
return std::make_unique<CursorShapeDeviceV1>(manager, pointer);
}
std::unique_ptr<XdgDialogV1> createXdgDialogV1(XdgToplevel *toplevel)
{
XdgWmDialogV1 *wm = s_waylandConnection.xdgWmDialogV1;
if (!wm) {
qWarning() << "Could not create a xdg_dialog_v1 because xdg_wm_dialog_v1 global is not bound";
return nullptr;
}
return std::make_unique<XdgDialogV1>(wm, toplevel);
}
bool waitForWindowClosed(Window *window)
@ -1163,6 +1230,7 @@ bool renderNodeAvailable()
});
}
#if KWIN_BUILD_X11
void XcbConnectionDeleter::operator()(xcb_connection_t *pointer)
{
xcb_disconnect(pointer);
@ -1180,6 +1248,7 @@ Test::XcbConnectionPtr createX11Connection()
e.exec();
return Test::XcbConnectionPtr(future.result());
}
#endif
WaylandOutputManagementV2::WaylandOutputManagementV2(struct ::wl_registry *registry, int id, int version)
: QObject()
@ -1542,11 +1611,6 @@ bool VirtualInputDevice::isKeyboard() const
return m_keyboard;
}
bool VirtualInputDevice::isAlphaNumericKeyboard() const
{
return m_keyboard;
}
bool VirtualInputDevice::isPointer() const
{
return m_pointer;

View File

@ -46,7 +46,14 @@ private Q_SLOTS:
void testGestureDetection();
private:
std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> showWindow(bool decorated = false);
struct WindowHandle
{
Window *window;
std::unique_ptr<KWayland::Client::Surface> surface;
std::unique_ptr<Test::XdgToplevel> shellSurface;
std::unique_ptr<Test::XdgToplevelDecorationV1> decoration;
};
WindowHandle showWindow(bool decorated = false);
KWayland::Client::Touch *m_touch = nullptr;
};
@ -87,21 +94,22 @@ void TouchInputTest::cleanup()
Test::destroyWaylandConnection();
}
std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> TouchInputTest::showWindow(bool decorated)
TouchInputTest::WindowHandle TouchInputTest::showWindow(bool decorated)
{
#define VERIFY(statement) \
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) \
return {nullptr, nullptr};
return {};
#define COMPARE(actual, expected) \
if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
return {nullptr, nullptr};
return {};
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
VERIFY(surface.get());
Test::XdgToplevel *shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
VERIFY(shellSurface);
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly);
VERIFY(shellSurface.get());
std::unique_ptr<Test::XdgToplevelDecorationV1> decoration;
if (decorated) {
auto decoration = Test::createXdgToplevelDecorationV1(shellSurface, shellSurface);
decoration = Test::createXdgToplevelDecorationV1(shellSurface.get());
decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
}
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
@ -117,7 +125,7 @@ std::pair<Window *, std::unique_ptr<KWayland::Client::Surface>> TouchInputTest::
#undef VERIFY
#undef COMPARE
return {window, std::move(surface)};
return {window, std::move(surface), std::move(shellSurface), std::move(decoration)};
}
void TouchInputTest::testTouchHidesCursor()
@ -155,7 +163,7 @@ void TouchInputTest::testMultipleTouchPoints_data()
void TouchInputTest::testMultipleTouchPoints()
{
QFETCH(bool, decorated);
auto [window, surface] = showWindow(decorated);
auto [window, surface, shellSurface, decoration] = showWindow(decorated);
QCOMPARE(window->isDecorated(), decorated);
window->move(QPoint(100, 100));
QVERIFY(window);
@ -210,7 +218,7 @@ void TouchInputTest::testMultipleTouchPoints()
void TouchInputTest::testCancel()
{
auto [window, surface] = showWindow();
auto [window, surface, shellSurface, decoration] = showWindow();
window->move(QPoint(100, 100));
QVERIFY(window);
QSignalSpy sequenceStartedSpy(m_touch, &KWayland::Client::Touch::sequenceStarted);
@ -233,9 +241,9 @@ void TouchInputTest::testTouchMouseAction()
// this test verifies that a touch down on an inactive window will activate it
// create two windows
auto [c1, surface] = showWindow();
auto [c1, surface, shellSurface, decoration] = showWindow();
QVERIFY(c1);
auto [c2, surface2] = showWindow();
auto [c2, surface2, shellSurface2, decoration2] = showWindow();
QVERIFY(c2);
QVERIFY(!c1->isActive());

View File

@ -114,7 +114,7 @@ void TransientPlacementTest::testXdgPopup_data()
.anchor = Test::XdgPositioner::anchor_none,
.gravity = Test::XdgPositioner::gravity_bottom_right,
};
QTest::newRow("anchorCentre") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorCenter << QRect(550, 550, 200, 200);
QTest::newRow("anchorCenter") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorCenter << QRect(550, 550, 200, 200);
const PopupLayout layoutAnchorTopLeft{
.anchorRect = QRect(50, 50, 400, 400),
@ -189,7 +189,7 @@ void TransientPlacementTest::testXdgPopup_data()
.anchor = Test::XdgPositioner::anchor_bottom_right,
.gravity = Test::XdgPositioner::gravity_none,
};
QTest::newRow("gravityCentre") << QSize(500, 500) << QPoint(300, 300) << layoutGravityCenter << QRect(650, 650, 200, 200);
QTest::newRow("gravityCenter") << QSize(500, 500) << QPoint(300, 300) << layoutGravityCenter << QRect(650, 650, 200, 200);
const PopupLayout layoutGravityTopLeft{
.anchorRect = QRect(50, 50, 400, 400),
@ -423,7 +423,7 @@ void TransientPlacementTest::testXdgPopup()
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
QVERIFY(surface);
auto parentShellSurface = Test::createXdgToplevelSurface(surface.get(), Test::waylandCompositor());
std::unique_ptr<Test::XdgToplevel> parentShellSurface = Test::createXdgToplevelSurface(surface.get());
QVERIFY(parentShellSurface);
auto parent = Test::renderAndWaitForShown(surface.get(), parentSize, Qt::blue);
QVERIFY(parent);
@ -480,7 +480,7 @@ void TransientPlacementTest::testXdgPopupWithPanel()
QVERIFY(dockConfigureRequestedSpy.wait());
auto dock = Test::renderAndWaitForShown(dockSurface.get(), dockConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
QVERIFY(dock);
QCOMPARE(dock->windowType(), NET::Dock);
QCOMPARE(dock->windowType(), WindowType::Dock);
QVERIFY(dock->isDock());
QCOMPARE(dock->frameGeometry(), QRect(0, output->geometry().height() - 50, 1280, 50));
QCOMPARE(dock->hasStrut(), true);
@ -497,7 +497,7 @@ void TransientPlacementTest::testXdgPopupWithPanel()
QVERIFY(!parent->isDecorated());
parent->move(QPointF(0, output->geometry().height() - 600));
parent->keepInArea(workspace()->clientArea(PlacementArea, parent));
parent->moveResize(parent->keepInArea(parent->moveResizeGeometry(), workspace()->clientArea(PlacementArea, parent)));
QCOMPARE(parent->frameGeometry(), QRect(0, output->geometry().height() - 600 - 50, 800, 600));
std::unique_ptr<KWayland::Client::Surface> transientSurface(Test::createSurface());
@ -522,7 +522,7 @@ void TransientPlacementTest::testXdgPopupWithPanel()
QVERIFY(Test::waitForWindowClosed(transient));
// now parent to fullscreen - on fullscreen the panel is ignored
QSignalSpy toplevelConfigureRequestedSpy(parentShellSurface, &Test::XdgToplevel::configureRequested);
QSignalSpy toplevelConfigureRequestedSpy(parentShellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(parentShellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
parent->setFullScreen(true);
QVERIFY(surfaceConfigureRequestedSpy.wait());
@ -542,7 +542,7 @@ void TransientPlacementTest::testXdgPopupWithPanel()
positioner2->set_size(200, 200);
positioner2->set_anchor_rect(anchorRect2.x(), anchorRect2.y(), anchorRect2.width(), anchorRect2.height());
positioner2->set_constraint_adjustment(Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y);
transientShellSurface.reset(Test::createXdgPopupSurface(transientSurface.get(), parentShellSurface->xdgSurface(), positioner2.get()));
transientShellSurface = Test::createXdgPopupSurface(transientSurface.get(), parentShellSurface->xdgSurface(), positioner2.get());
transient = Test::renderAndWaitForShown(transientSurface.get(), QSize(200, 200), Qt::red);
QVERIFY(transient);

View File

@ -9,12 +9,15 @@
#include "kwin_wayland_test.h"
#include "main.h"
#include "utils/xcbutils.h"
#include "virtualdesktops.h"
#include "wayland_server.h"
#include "window.h"
#include "workspace.h"
#if KWIN_BUILD_X11
#include "utils/xcbutils.h"
#endif
#include <KWayland/Client/surface.h>
using namespace KWin;
@ -28,8 +31,9 @@ private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
#if KWIN_BUILD_X11
void testNetCurrentDesktop();
#endif
void testLastDesktopRemoved();
void testWindowOnMultipleDesktops();
void testRemoveDesktopWithWindow();
@ -52,6 +56,7 @@ void VirtualDesktopTest::initTestCase()
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
#if KWIN_BUILD_X11
if (kwinApp()->x11Connection()) {
// verify the current desktop x11 property on startup, see BUG: 391034
Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP");
@ -61,6 +66,7 @@ void VirtualDesktopTest::initTestCase()
QCOMPARE(currentDesktop.value(0, &ok), 0);
QVERIFY(ok);
}
#endif
}
void VirtualDesktopTest::init()
@ -75,6 +81,7 @@ void VirtualDesktopTest::cleanup()
Test::destroyWaylandConnection();
}
#if KWIN_BUILD_X11
void VirtualDesktopTest::testNetCurrentDesktop()
{
if (!kwinApp()->x11Connection()) {
@ -115,6 +122,7 @@ void VirtualDesktopTest::testNetCurrentDesktop()
QCOMPARE(currentDesktop.value(0, &ok), 0);
QVERIFY(ok);
}
#endif
void VirtualDesktopTest::testLastDesktopRemoved()
{

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2024 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "input.h"
#include "options.h"
#include "pointer_input.h"
#include "qabstracteventdispatcher.h"
#include "qsocketnotifier.h"
#include "wayland/keyboard.h"
#include "wayland/seat.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KConfigGroup>
#include <linux/input.h>
#define explicit xcb_explicit
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
#include <xcb/xinput.h>
#include <xcb/xkb.h>
#undef explicit
using namespace KWin;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_x11-key-read-0");
enum class State {
Press,
Release
} state;
typedef QPair<State, int> KeyAction;
Q_DECLARE_METATYPE(KeyAction);
/*
* This tests the "Legacy App Support" feature of allowing X11 apps to get notified of some key press events
*/
class X11KeyReadTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase_data();
void initTestCase();
void init();
void cleanup();
void testSimpleLetter();
void onlyModifier();
void letterWithModifier();
private:
QList<KeyAction> recievedX11EventsForInput(const QList<KeyAction> &keyEventsIn);
};
void X11KeyReadTest::initTestCase_data()
{
QTest::addColumn<XwaylandEavesdropsMode>("operatingMode");
QTest::newRow("all") << XwaylandEavesdropsMode::All;
QTest::newRow("allWithModifier") << XwaylandEavesdropsMode::AllKeysWithModifier;
QTest::newRow("nonCharacter") << XwaylandEavesdropsMode::NonCharacterKeys;
QTest::newRow("none") << XwaylandEavesdropsMode::None;
}
void X11KeyReadTest::initTestCase()
{
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName));
Test::setOutputConfig({
QRect(0, 0, 1280, 1024),
});
qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1");
qputenv("XKB_DEFAULT_RULES", "evdev");
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
}
void X11KeyReadTest::init()
{
QFETCH_GLOBAL(XwaylandEavesdropsMode, operatingMode);
options->setXwaylandEavesdrops(operatingMode);
workspace()->setActiveOutput(QPoint(640, 512));
KWin::input()->pointer()->warp(QPoint(640, 512));
}
void X11KeyReadTest::cleanup()
{
}
void X11KeyReadTest::testSimpleLetter()
{
// press a
QList<KeyAction> keyEvents = {
{State::Press, KEY_A},
{State::Release, KEY_A},
};
auto received = recievedX11EventsForInput(keyEvents);
QList<KeyAction> expected;
QFETCH_GLOBAL(XwaylandEavesdropsMode, operatingMode);
switch (operatingMode) {
case XwaylandEavesdropsMode::None:
case XwaylandEavesdropsMode::NonCharacterKeys:
case XwaylandEavesdropsMode::AllKeysWithModifier:
expected = {};
break;
case XwaylandEavesdropsMode::All:
expected = keyEvents;
break;
}
QCOMPARE(received, expected);
}
void X11KeyReadTest::onlyModifier()
{
QList<KeyAction> keyEvents = {
{State::Press, KEY_LEFTALT},
{State::Release, KEY_LEFTALT},
};
auto received = recievedX11EventsForInput(keyEvents);
QList<KeyAction> expected;
QFETCH_GLOBAL(XwaylandEavesdropsMode, operatingMode);
switch (operatingMode) {
case XwaylandEavesdropsMode::None:
expected = {};
break;
case XwaylandEavesdropsMode::NonCharacterKeys:
case XwaylandEavesdropsMode::AllKeysWithModifier:
case XwaylandEavesdropsMode::All:
expected = keyEvents;
break;
}
QCOMPARE(received, expected);
}
void X11KeyReadTest::letterWithModifier()
{
QList<KeyAction> keyEvents = {
{State::Press, KEY_LEFTALT},
{State::Press, KEY_F},
{State::Release, KEY_F},
{State::Release, KEY_LEFTALT},
};
auto received = recievedX11EventsForInput(keyEvents);
QList<KeyAction> expected;
QFETCH_GLOBAL(XwaylandEavesdropsMode, operatingMode);
switch (operatingMode) {
case XwaylandEavesdropsMode::None:
expected = {};
break;
case XwaylandEavesdropsMode::NonCharacterKeys:
expected = {
{State::Press, KEY_LEFTALT},
{State::Release, KEY_LEFTALT},
};
break;
case XwaylandEavesdropsMode::AllKeysWithModifier:
case XwaylandEavesdropsMode::All:
expected = keyEvents;
break;
}
QCOMPARE(received, expected);
}
class X11EventRecorder :
public
QObject
{
Q_OBJECT
public:
X11EventRecorder(xcb_connection_t * c);
QList<KeyAction> keyEvents() const
{
return m_keyEvents;
}
Q_SIGNALS:
void fenceReceived();
private:
void processXcbEvents();
QList<KeyAction> m_keyEvents;
xcb_connection_t *m_connection;
QSocketNotifier *m_notifier;
};
X11EventRecorder::X11EventRecorder(xcb_connection_t * c)
: QObject()
, m_connection(c)
, m_notifier(new QSocketNotifier(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read, this))
{
struct
{
xcb_input_event_mask_t head;
xcb_input_xi_event_mask_t mask;
} mask;
mask.head.deviceid = XCB_INPUT_DEVICE_ALL;
mask.head.mask_len = sizeof(mask.mask) / sizeof(uint32_t);
mask.mask = static_cast<xcb_input_xi_event_mask_t>(
XCB_INPUT_XI_EVENT_MASK_KEY_PRESS
| XCB_INPUT_XI_EVENT_MASK_KEY_RELEASE
| XCB_INPUT_RAW_KEY_PRESS
| XCB_INPUT_RAW_KEY_RELEASE);
xcb_input_xi_select_events(c, kwinApp()->x11RootWindow(), 1, &mask.head);
xcb_flush(c);
connect(m_notifier, &QSocketNotifier::activated, this, &X11EventRecorder::processXcbEvents);
connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &X11EventRecorder::processXcbEvents);
connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::awake, this, &X11EventRecorder::processXcbEvents);
}
void X11EventRecorder::processXcbEvents()
{
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(m_connection))) {
u_int8_t responseType = event->response_type & ~0x80;
if (responseType == XCB_GE_GENERIC) {
auto *geEvent = reinterpret_cast<xcb_ge_generic_event_t *>(event);
if (geEvent->event_type == XCB_INPUT_KEY_PRESS || geEvent->event_type == XCB_INPUT_KEY_RELEASE) {
auto keyEvent = reinterpret_cast<xcb_input_key_press_event_t *>(geEvent);
int nativeKeyCode = keyEvent->detail - 0x08;
if (nativeKeyCode == 0) {
Q_EMIT fenceReceived();
} else {
KeyAction action({geEvent->event_type == XCB_INPUT_KEY_PRESS ? State::Press : State::Release, nativeKeyCode});
m_keyEvents << action;
}
}
}
std::free(event);
}
xcb_flush(m_connection);
}
QList<KeyAction> X11KeyReadTest::recievedX11EventsForInput(const QList<KeyAction> &keysIn)
{
quint32 timestamp = 1;
Test::XcbConnectionPtr c = Test::createX11Connection();
X11EventRecorder eventReader(c.get());
QSignalSpy fenceEventSpy(&eventReader, &X11EventRecorder::fenceReceived);
for (const KeyAction &action : keysIn) {
if (action.first == State::Press) {
Test::keyboardKeyPressed(action.second, timestamp++);
} else {
Test::keyboardKeyReleased(action.second, timestamp++);
}
Test::flushWaylandConnection();
QTest::qWait(5);
}
// special case, explicitly send key 0, to use as a fence
ClientConnection *xwaylandClient = waylandServer()->xWaylandConnection();
waylandServer()->seat()->keyboard()->sendKey(0, KeyboardKeyState::Pressed, xwaylandClient);
Test::flushWaylandConnection();
bool fenceComplete = fenceEventSpy.wait();
Q_ASSERT(fenceComplete);
return eventReader.keyEvents();
}
WAYLANDTEST_MAIN(X11KeyReadTest)
#include "x11keyread.moc"

View File

@ -151,6 +151,14 @@ private Q_SLOTS:
void testScreenApplyNow();
void testScreenForceTemporarily();
void testLayerDontAffect();
void testLayerForce();
void testLayerForceTemporarily();
void testCloseableDontAffect();
void testCloseableForce();
void testCloseableForceTemporarily();
void testMatchAfterNameChange();
private:
@ -167,6 +175,7 @@ private:
Window *m_window;
std::unique_ptr<KWayland::Client::Surface> m_surface;
std::unique_ptr<Test::XdgToplevel> m_shellSurface;
std::unique_ptr<Test::XdgToplevelDecorationV1> m_decoration;
std::unique_ptr<QSignalSpy> m_toplevelConfigureRequestedSpy;
std::unique_ptr<QSignalSpy> m_surfaceConfigureRequestedSpy;
@ -229,15 +238,15 @@ void TestXdgShellWindowRules::createTestWindow(ClientFlags flags)
: Test::XdgToplevelDecorationV1::mode_client_side;
// Create an xdg surface.
m_surface = Test::createSurface();
m_shellSurface.reset(Test::createXdgToplevelSurface(m_surface.get(), Test::CreationSetup::CreateOnly, m_surface.get()));
Test::XdgToplevelDecorationV1 *decoration = Test::createXdgToplevelDecorationV1(m_shellSurface.get(), m_shellSurface.get());
m_shellSurface = Test::createXdgToplevelSurface(m_surface.get(), Test::CreationSetup::CreateOnly);
m_decoration = Test::createXdgToplevelDecorationV1(m_shellSurface.get());
// Add signal watchers
m_toplevelConfigureRequestedSpy = std::make_unique<QSignalSpy>(m_shellSurface.get(), &Test::XdgToplevel::configureRequested);
m_surfaceConfigureRequestedSpy = std::make_unique<QSignalSpy>(m_shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
m_shellSurface->set_app_id(QStringLiteral("org.kde.foo"));
decoration->set_mode(decorationMode);
m_decoration->set_mode(decorationMode);
// Wait for the initial configure event
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
@ -269,6 +278,7 @@ void TestXdgShellWindowRules::destroyTestWindow()
{
m_surfaceConfigureRequestedSpy.reset();
m_toplevelConfigureRequestedSpy.reset();
m_decoration.reset();
m_shellSurface.reset();
m_surface.reset();
QVERIFY(Test::waitForWindowClosed(m_window));
@ -2821,7 +2831,7 @@ void TestXdgShellWindowRules::testScreenDontAffect()
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
// The user can still move the window to another screen.
workspace()->sendWindowToOutput(m_window, outputs.at(1));
m_window->sendToOutput(outputs.at(1));
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
destroyTestWindow();
@ -2840,7 +2850,7 @@ void TestXdgShellWindowRules::testScreenApply()
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// The user can move the window to another screen.
workspace()->sendWindowToOutput(m_window, outputs.at(0));
m_window->sendToOutput(outputs.at(0));
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
destroyTestWindow();
@ -2858,11 +2868,12 @@ void TestXdgShellWindowRules::testScreenRemember()
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
// Move the window to the second screen.
workspace()->sendWindowToOutput(m_window, outputs.at(1));
m_window->sendToOutput(outputs.at(1));
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// Close and reopen the window.
destroyTestWindow();
workspace()->setActiveOutput(outputs.at(0));
createTestWindow();
QEXPECT_FAIL("", "Applying a screen rule on a new client fails on Wayland", Continue);
@ -2884,7 +2895,7 @@ void TestXdgShellWindowRules::testScreenForce()
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// User should not be able to move the window to another screen.
workspace()->sendWindowToOutput(m_window, outputs.at(0));
m_window->sendToOutput(outputs.at(0));
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// Disable the output where the window is on, so the window is moved the other screen
@ -2926,7 +2937,7 @@ void TestXdgShellWindowRules::testScreenApplyNow()
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// The user can move the window to another screen.
workspace()->sendWindowToOutput(m_window, outputs.at(0));
m_window->sendToOutput(outputs.at(0));
QCOMPARE(m_window->output()->name(), outputs.at(0)->name());
// The rule should not be applied again.
@ -2948,11 +2959,12 @@ void TestXdgShellWindowRules::testScreenForceTemporarily()
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// User is not allowed to move it
workspace()->sendWindowToOutput(m_window, outputs.at(0));
m_window->sendToOutput(outputs.at(0));
QCOMPARE(m_window->output()->name(), outputs.at(1)->name());
// Close and reopen the window.
destroyTestWindow();
workspace()->setActiveOutput(outputs.at(0));
createTestWindow();
// The rule should be discarded now
@ -2980,5 +2992,78 @@ void TestXdgShellWindowRules::testMatchAfterNameChange()
QCOMPARE(window->keepAbove(), true);
}
void TestXdgShellWindowRules::testLayerDontAffect()
{
setWindowRule("layer", QStringLiteral("overlay"), int(Rules::DontAffect));
createTestWindow();
// The layer should not be affected by the rule.
QCOMPARE(m_window->layer(), NormalLayer);
destroyTestWindow();
}
void TestXdgShellWindowRules::testLayerForce()
{
setWindowRule("layer", QStringLiteral("overlay"), int(Rules::Force));
createTestWindow();
QCOMPARE(m_window->layer(), OverlayLayer);
destroyTestWindow();
}
void TestXdgShellWindowRules::testLayerForceTemporarily()
{
setWindowRule("layer", QStringLiteral("overlay"), int(Rules::ForceTemporarily));
createTestWindow();
QCOMPARE(m_window->layer(), OverlayLayer);
// The rule should be discarded when the window is closed.
destroyTestWindow();
createTestWindow();
QCOMPARE(m_window->layer(), NormalLayer);
destroyTestWindow();
}
void TestXdgShellWindowRules::testCloseableDontAffect()
{
setWindowRule("closeable", false, int(Rules::DontAffect));
createTestWindow();
QVERIFY(m_window->isCloseable());
destroyTestWindow();
}
void TestXdgShellWindowRules::testCloseableForce()
{
setWindowRule("closeable", false, int(Rules::Force));
createTestWindow();
QVERIFY(!m_window->isCloseable());
destroyTestWindow();
}
void TestXdgShellWindowRules::testCloseableForceTemporarily()
{
setWindowRule("closeable", false, int(Rules::ForceTemporarily));
createTestWindow();
QVERIFY(!m_window->isCloseable());
// The rule should be discarded when the window is closed.
destroyTestWindow();
createTestWindow();
QVERIFY(m_window->isCloseable());
destroyTestWindow();
}
WAYLANDTEST_MAIN(TestXdgShellWindowRules)
#include "xdgshellwindow_rules_test.moc"

View File

@ -68,11 +68,14 @@ private Q_SLOTS:
void testMaximizedToFullscreen_data();
void testMaximizedToFullscreen();
void testSendMaximizedWindowToAnotherOutput();
void testInteractiveMoveUnmaximizeFull();
void testInteractiveMoveUnmaximizeInitiallyFull();
void testInteractiveMoveUnmaximizeHorizontal();
void testInteractiveMoveUnmaximizeVertical();
void testFullscreenMultipleOutputs();
void testHidden();
void testDesktopFileName();
void testCaptionSimplified();
void testCaptionMultipleWindows();
void testUnresponsiveWindow_data();
void testUnresponsiveWindow();
void testAppMenu();
@ -101,6 +104,9 @@ private Q_SLOTS:
void testMaximizeAndChangeDecorationModeAfterInitialCommit();
void testFullScreenAndChangeDecorationModeAfterInitialCommit();
void testChangeDecorationModeAfterInitialCommit();
void testModal();
void testCloseModal();
void testCloseInactiveModal();
};
void TestXdgShellWindow::testXdgPopupReactive_data()
@ -203,7 +209,7 @@ void TestXdgShellWindow::initTestCase()
void TestXdgShellWindow::init()
{
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::AppMenu));
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::AppMenu | Test::AdditionalWaylandInterface::XdgDialogV1));
QVERIFY(Test::waitForWaylandPointer());
workspace()->setActiveOutput(QPoint(640, 512));
@ -475,7 +481,7 @@ void TestXdgShellWindow::testSendFullScreenWindowToAnotherOutput()
QCOMPARE(window->output(), outputs[0]);
// Send the window to another output.
workspace()->sendWindowToOutput(window, outputs[1]);
window->sendToOutput(outputs[1]);
QCOMPARE(window->isFullScreen(), true);
QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->fullscreenGeometryRestore(), QRectF(1280 + 10, 20, 100, 50));
@ -708,52 +714,6 @@ void TestXdgShellWindow::testCaptionSimplified()
QCOMPARE(window->caption(), origTitle.simplified());
}
void TestXdgShellWindow::testCaptionMultipleWindows()
{
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
shellSurface->set_title(QStringLiteral("foo"));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
QVERIFY(window);
QCOMPARE(window->caption(), QStringLiteral("foo"));
QCOMPARE(window->captionNormal(), QStringLiteral("foo"));
QCOMPARE(window->captionSuffix(), QString());
std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
shellSurface2->set_title(QStringLiteral("foo"));
auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
QVERIFY(c2);
QCOMPARE(c2->caption(), QStringLiteral("foo <2>"));
QCOMPARE(c2->captionNormal(), QStringLiteral("foo"));
QCOMPARE(c2->captionSuffix(), QStringLiteral(" <2>"));
std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
shellSurface3->set_title(QStringLiteral("foo"));
auto c3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::blue);
QVERIFY(c3);
QCOMPARE(c3->caption(), QStringLiteral("foo <3>"));
QCOMPARE(c3->captionNormal(), QStringLiteral("foo"));
QCOMPARE(c3->captionSuffix(), QStringLiteral(" <3>"));
std::unique_ptr<KWayland::Client::Surface> surface4(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface4(Test::createXdgToplevelSurface(surface4.get()));
shellSurface4->set_title(QStringLiteral("bar"));
auto c4 = Test::renderAndWaitForShown(surface4.get(), QSize(100, 50), Qt::blue);
QVERIFY(c4);
QCOMPARE(c4->caption(), QStringLiteral("bar"));
QCOMPARE(c4->captionNormal(), QStringLiteral("bar"));
QCOMPARE(c4->captionSuffix(), QString());
QSignalSpy captionChangedSpy(c4, &Window::captionChanged);
shellSurface4->set_title(QStringLiteral("foo"));
QVERIFY(captionChangedSpy.wait());
QCOMPARE(captionChangedSpy.count(), 1);
QCOMPARE(c4->caption(), QStringLiteral("foo <4>"));
QCOMPARE(c4->captionNormal(), QStringLiteral("foo"));
QCOMPARE(c4->captionSuffix(), QStringLiteral(" <4>"));
}
void TestXdgShellWindow::testUnresponsiveWindow_data()
{
QTest::addColumn<QString>("shellInterface"); // see env selection in qwaylandintegration.cpp
@ -1835,13 +1795,321 @@ void TestXdgShellWindow::testSendMaximizedWindowToAnotherOutput()
QCOMPARE(window->output(), outputs[0]);
// Send the window to another output.
workspace()->sendWindowToOutput(window, outputs[1]);
window->sendToOutput(outputs[1]);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->frameGeometry(), QRectF(1280, 0, 1280, 1024));
QCOMPARE(window->geometryRestore(), QRectF(1280 + 10, 20, 100, 50));
QCOMPARE(window->output(), outputs[1]);
}
void TestXdgShellWindow::testInteractiveMoveUnmaximizeFull()
{
// This test verifies that a maximized xdg-toplevel is going to be properly unmaximized when it's dragged.
// Create the window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
// Wait for the compositor to send a configure event with the activated state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// Make the window maximized.
const QRectF originalGeometry = window->frameGeometry();
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->maximize(MaximizeFull);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
// Start interactive move.
QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
const qreal xOffset = 0.25;
const qreal yOffset = 0.5;
quint32 timestamp = 0;
Test::pointerMotion(QPointF(window->x() + window->width() * xOffset, window->y() + window->height() * yOffset), timestamp++);
window->performMouseCommand(Options::MouseMove, input()->pointer()->pos());
QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
// Move the window to unmaximize it.
const QRectF maximizedGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 100), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry);
// Move the window a tiny bit more.
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry);
// Render the window at the new size.
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), QRectF(input()->pointer()->pos() - QPointF(originalGeometry.width() * xOffset, originalGeometry.height() * yOffset), originalGeometry.size()));
// Move the window again.
const QRectF normalGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), normalGeometry.translated(0, 10));
// Finish interactive move.
window->keyPressEvent(Qt::Key_Enter);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
}
void TestXdgShellWindow::testInteractiveMoveUnmaximizeInitiallyFull()
{
// This test verifies that an initially maximized xdg-toplevel will be properly unmaximized when it's dragged.
// Create the window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), [](Test::XdgToplevel *toplevel) {
toplevel->set_maximized();
}));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
// Wait for the compositor to send a configure event with the activated state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// Start interactive move.
QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
const qreal xOffset = 0.25;
const qreal yOffset = 0.5;
quint32 timestamp = 0;
Test::pointerMotion(QPointF(window->x() + window->width() * xOffset, window->y() + window->height() * yOffset), timestamp++);
window->performMouseCommand(Options::MouseMove, input()->pointer()->pos());
QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeFull);
// Move the window to unmaximize it.
const QRectF maximizedGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 100), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry);
// Move the window a tiny bit more.
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QCOMPARE(window->maximizeMode(), MaximizeFull);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry);
// Render the window at the new size.
const QSize restoredSize(100, 50);
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
QVERIFY(surfaceConfigureRequestedSpy.wait());
QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), QSize(0, 0));
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), restoredSize, Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), QRectF(input()->pointer()->pos() - QPointF(restoredSize.width() * xOffset, restoredSize.height() * yOffset), restoredSize));
// Move the window again.
const QRectF normalGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), normalGeometry.translated(0, 10));
// Finish interactive move.
window->keyPressEvent(Qt::Key_Enter);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
}
void TestXdgShellWindow::testInteractiveMoveUnmaximizeHorizontal()
{
// This test verifies that a maximized horizontally xdg-toplevel is going to be properly unmaximized when it's dragged horizontally.
// Create the window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
// Wait for the compositor to send a configure event with the activated state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// Make the window maximized.
const QRectF originalGeometry = window->frameGeometry();
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->maximize(MaximizeHorizontal);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeHorizontal);
QCOMPARE(window->requestedMaximizeMode(), MaximizeHorizontal);
// Start interactive move.
QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
const qreal xOffset = 0.25;
const qreal yOffset = 0.5;
quint32 timestamp = 0;
Test::pointerMotion(QPointF(window->x() + window->width() * xOffset, window->y() + window->height() * yOffset), timestamp++);
window->performMouseCommand(Options::MouseMove, input()->pointer()->pos());
QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeHorizontal);
QCOMPARE(window->requestedMaximizeMode(), MaximizeHorizontal);
// Move the window vertically, it's not going to be unmaximized.
const QRectF maximizedGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 100), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeHorizontal);
QCOMPARE(window->requestedMaximizeMode(), MaximizeHorizontal);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(0, 100));
// Move the window horizontally.
Test::pointerMotionRelative(QPointF(100, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeHorizontal);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(0, 100));
// Move the window to the right a bit more.
Test::pointerMotionRelative(QPointF(10, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeHorizontal);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(0, 100));
// Render the window at the new size.
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), QRectF(input()->pointer()->pos() - QPointF(originalGeometry.width() * xOffset, originalGeometry.height() * yOffset), originalGeometry.size()));
// Move the window again.
const QRectF normalGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(10, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), normalGeometry.translated(10, 0));
// Finish interactive move.
window->keyPressEvent(Qt::Key_Enter);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
}
void TestXdgShellWindow::testInteractiveMoveUnmaximizeVertical()
{
// This test verifies that a maximized vertically xdg-toplevel is going to be properly unmaximized when it's dragged vertically.
// Create the window.
std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
// Wait for the compositor to send a configure event with the activated state.
QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
QVERIFY(surfaceConfigureRequestedSpy.wait());
// Make the window maximized.
const QRectF originalGeometry = window->frameGeometry();
QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
window->maximize(MaximizeVertical);
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeVertical);
QCOMPARE(window->requestedMaximizeMode(), MaximizeVertical);
// Start interactive move.
QSignalSpy interactiveMoveResizeStartedSpy(window, &Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &Window::interactiveMoveResizeStepped);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &Window::interactiveMoveResizeFinished);
const qreal xOffset = 0.25;
const qreal yOffset = 0.5;
quint32 timestamp = 0;
Test::pointerMotion(QPointF(window->x() + window->width() * xOffset, window->y() + window->height() * yOffset), timestamp++);
window->performMouseCommand(Options::MouseMove, input()->pointer()->pos());
QCOMPARE(interactiveMoveResizeStartedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeVertical);
QCOMPARE(window->requestedMaximizeMode(), MaximizeVertical);
// Move the window to the right, it's not going to be unmaximized.
const QRectF maximizedGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(100, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeVertical);
QCOMPARE(window->requestedMaximizeMode(), MaximizeVertical);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(100, 0));
// Move the window vertically.
Test::pointerMotionRelative(QPointF(0, 100), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeVertical);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(100, 0));
// Move the window down a bit more.
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->maximizeMode(), MaximizeVertical);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), maximizedGeometry.translated(100, 0));
// Render the window at the new size.
QVERIFY(surfaceConfigureRequestedSpy.wait());
shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), QRectF(input()->pointer()->pos() - QPointF(originalGeometry.width() * xOffset, originalGeometry.height() * yOffset), originalGeometry.size()));
// Move the window again.
const QRectF normalGeometry = window->frameGeometry();
Test::pointerMotionRelative(QPointF(0, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 2);
QCOMPARE(window->maximizeMode(), MaximizeRestore);
QCOMPARE(window->requestedMaximizeMode(), MaximizeRestore);
QCOMPARE(window->frameGeometry(), normalGeometry.translated(0, 10));
// Finish interactive move.
window->keyPressEvent(Qt::Key_Enter);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
}
void TestXdgShellWindow::testMaximizeAndChangeDecorationModeAfterInitialCommit()
{
// Ideally, the app would initialize the xdg-toplevel surface before the initial commit, but
@ -1925,5 +2193,134 @@ void TestXdgShellWindow::testChangeDecorationModeAfterInitialCommit()
QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_client_side);
}
void TestXdgShellWindow::testModal()
{
auto parentSurface = Test::createSurface();
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
auto parentWindow = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
QVERIFY(parentWindow);
auto childSurface = Test::createSurface();
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
toplevel->set_parent(parentToplevel->object());
});
auto childWindow = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
QVERIFY(childWindow);
QVERIFY(!childWindow->isModal());
QCOMPARE(childWindow->transientFor(), parentWindow);
auto dialog = Test::createXdgDialogV1(childToplevel.get());
QVERIFY(Test::waylandSync());
QVERIFY(dialog);
QVERIFY(!childWindow->isModal());
QSignalSpy modalChangedSpy(childWindow, &Window::modalChanged);
dialog->set_modal();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
QVERIFY(childWindow->isModal());
dialog->unset_modal();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
QVERIFY(!childWindow->isModal());
dialog->set_modal();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
Workspace::self()->activateWindow(parentWindow);
QCOMPARE(Workspace::self()->activeWindow(), childWindow);
dialog.reset();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
QVERIFY(!childWindow->isModal());
}
void TestXdgShellWindow::testCloseModal()
{
// This test verifies that the parent window will be activated when an active modal dialog is closed.
// Create a parent and a child windows.
auto parentSurface = Test::createSurface();
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
auto parent = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
QVERIFY(parent);
auto childSurface = Test::createSurface();
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
toplevel->set_parent(parentToplevel->object());
});
auto child = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
QVERIFY(child);
QVERIFY(!child->isModal());
QCOMPARE(child->transientFor(), parent);
// Set modal state.
auto dialog = Test::createXdgDialogV1(childToplevel.get());
QSignalSpy modalChangedSpy(child, &Window::modalChanged);
dialog->set_modal();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
QVERIFY(child->isModal());
QCOMPARE(workspace()->activeWindow(), child);
// Close the child.
QSignalSpy childClosedSpy(child, &Window::closed);
childToplevel.reset();
childSurface.reset();
dialog.reset();
Test::flushWaylandConnection();
QVERIFY(childClosedSpy.wait());
QCOMPARE(workspace()->activeWindow(), parent);
}
void TestXdgShellWindow::testCloseInactiveModal()
{
// This test verifies that the parent window will not be activated when an inactive modal dialog is closed.
// Create a parent and a child windows.
auto parentSurface = Test::createSurface();
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
auto parent = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
QVERIFY(parent);
auto childSurface = Test::createSurface();
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
toplevel->set_parent(parentToplevel->object());
});
auto child = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
QVERIFY(child);
QVERIFY(!child->isModal());
QCOMPARE(child->transientFor(), parent);
// Set modal state.
auto dialog = Test::createXdgDialogV1(childToplevel.get());
QSignalSpy modalChangedSpy(child, &Window::modalChanged);
dialog->set_modal();
Test::flushWaylandConnection();
QVERIFY(modalChangedSpy.wait());
QVERIFY(child->isModal());
QCOMPARE(workspace()->activeWindow(), child);
// Show another window.
auto otherSurface = Test::createSurface();
auto otherToplevel = Test::createXdgToplevelSurface(otherSurface.get());
auto otherWindow = Test::renderAndWaitForShown(otherSurface.get(), {200, 200}, Qt::magenta);
QVERIFY(otherWindow);
workspace()->setActiveWindow(otherWindow);
QCOMPARE(workspace()->activeWindow(), otherWindow);
// Close the child.
QSignalSpy childClosedSpy(child, &Window::closed);
childToplevel.reset();
childSurface.reset();
dialog.reset();
Test::flushWaylandConnection();
QVERIFY(childClosedSpy.wait());
QCOMPARE(workspace()->activeWindow(), otherWindow);
}
WAYLANDTEST_MAIN(TestXdgShellWindow)
#include "xdgshellwindow_test.moc"

View File

@ -0,0 +1,65 @@
/*
SPDX-FileCopyrightText: 2024 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "core/output.h"
#include "wayland_server.h"
#include "workspace.h"
namespace KWin
{
static const QString s_socketName = QStringLiteral("wayland_test_kwin_xinerama-0");
class XineramaTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void indexToOutput();
};
void XineramaTest::initTestCase()
{
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
QVERIFY(waylandServer()->init(s_socketName));
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
}
void XineramaTest::indexToOutput()
{
Test::setOutputConfig({
Test::OutputInfo{
.geometry = QRect(0, 0, 1280, 1024),
.scale = 1.5,
},
Test::OutputInfo{
.geometry = QRect(1280, 0, 1280, 1024),
.scale = 1.5,
},
});
kwinApp()->setXwaylandScale(1.5);
// Start Xwayland
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
const auto outputs = workspace()->outputs();
QCOMPARE(workspace()->xineramaIndexToOutput(0), outputs.at(0));
QCOMPARE(workspace()->xineramaIndexToOutput(1), outputs.at(1));
workspace()->setOutputOrder({outputs[1], outputs[0]});
QCOMPARE(workspace()->xineramaIndexToOutput(0), outputs.at(1));
QCOMPARE(workspace()->xineramaIndexToOutput(1), outputs.at(0));
}
} // namespace KWin
WAYLANDTEST_MAIN(KWin::XineramaTest)
#include "xinerama_test.moc"

View File

@ -53,7 +53,7 @@ void InputEventsTest::testInitMouseEvent()
QFETCH(QEvent::Type, type);
// now create our own event
MouseEvent event(type, QPointF(100, 200), Qt::LeftButton, Qt::LeftButton | Qt::RightButton,
Qt::ShiftModifier | Qt::ControlModifier, 300ms, QPointF(1, 2), QPointF(3, 4), &d);
Qt::ShiftModifier | Qt::ControlModifier, 300ms, QPointF(1, 2), QPointF(3, 4), &d, false);
// and verify the contract of QMouseEvent
QCOMPARE(event.type(), type);
QCOMPARE(event.globalPos(), QPoint(100, 200));

View File

@ -20,6 +20,7 @@ public:
private Q_SLOTS:
void roundtripConversion_data();
void roundtripConversion();
void nonNormalizedPrimaries();
};
static bool compareVectors(const QVector3D &one, const QVector3D &two, float maxDifference)
@ -33,6 +34,8 @@ static bool compareVectors(const QVector3D &one, const QVector3D &two, float max
return ret;
}
static const double s_resolution10bit = std::pow(1.0 / 2.0, 10);
void TestColorspaces::roundtripConversion_data()
{
QTest::addColumn<NamedColorimetry>("srcColorimetry");
@ -41,12 +44,11 @@ void TestColorspaces::roundtripConversion_data()
QTest::addColumn<NamedTransferFunction>("dstTransferFunction");
QTest::addColumn<double>("requiredAccuracy");
const double resolution10bit = std::pow(1.0 / 2.0, 10);
QTest::addRow("BT709 (sRGB) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::sRGB << NamedColorimetry::BT2020 << NamedTransferFunction::linear << resolution10bit;
QTest::addRow("BT709 (gamma 2.2) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::gamma22 << NamedColorimetry::BT2020 << NamedTransferFunction::linear << resolution10bit;
QTest::addRow("BT709 (scRGB) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::scRGB << NamedColorimetry::BT2020 << NamedTransferFunction::linear << resolution10bit;
QTest::addRow("BT709 (linear) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::linear << NamedColorimetry::BT2020 << NamedTransferFunction::linear << resolution10bit;
QTest::addRow("BT709 (PQ) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::PerceptualQuantizer << NamedColorimetry::BT2020 << NamedTransferFunction::linear << 3 * resolution10bit;
QTest::addRow("BT709 (sRGB) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::sRGB << NamedColorimetry::BT2020 << NamedTransferFunction::linear << s_resolution10bit;
QTest::addRow("BT709 (gamma 2.2) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::gamma22 << NamedColorimetry::BT2020 << NamedTransferFunction::linear << s_resolution10bit;
QTest::addRow("BT709 (scRGB) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::scRGB << NamedColorimetry::BT2020 << NamedTransferFunction::linear << s_resolution10bit;
QTest::addRow("BT709 (linear) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::linear << NamedColorimetry::BT2020 << NamedTransferFunction::linear << s_resolution10bit;
QTest::addRow("BT709 (PQ) <-> BT2020 (linear)") << NamedColorimetry::BT709 << NamedTransferFunction::PerceptualQuantizer << NamedColorimetry::BT2020 << NamedTransferFunction::linear << 3 * s_resolution10bit;
}
void TestColorspaces::roundtripConversion()
@ -57,8 +59,8 @@ void TestColorspaces::roundtripConversion()
QFETCH(NamedTransferFunction, dstTransferFunction);
QFETCH(double, requiredAccuracy);
const auto src = ColorDescription(srcColorimetry, srcTransferFunction, 100, 0, 100, 100, 0);
const auto dst = ColorDescription(dstColorimetry, dstTransferFunction, 100, 0, 100, 100, 0);
const auto src = ColorDescription(srcColorimetry, srcTransferFunction, 100, 0, 100, 100);
const auto dst = ColorDescription(dstColorimetry, dstTransferFunction, 100, 0, 100, 100);
const QVector3D red(1, 0, 0);
const QVector3D green(0, 1, 0);
@ -71,6 +73,18 @@ void TestColorspaces::roundtripConversion()
QVERIFY(compareVectors(dst.mapTo(src.mapTo(white, dst), src), white, requiredAccuracy));
}
void TestColorspaces::nonNormalizedPrimaries()
{
// this test ensures that non-normalized primaries don't mess up the transformations between color spaces
const auto from = Colorimetry::fromName(NamedColorimetry::BT709);
const auto to = Colorimetry(Colorimetry::xyToXYZ(from.red()) * 2, Colorimetry::xyToXYZ(from.green()) * 2, Colorimetry::xyToXYZ(from.blue()) * 2, Colorimetry::xyToXYZ(from.white()) * 2);
const auto convertedWhite = from.toOther(to) * QVector3D(1, 1, 1);
QCOMPARE_LE(std::abs(1 - convertedWhite.x()), s_resolution10bit);
QCOMPARE_LE(std::abs(1 - convertedWhite.y()), s_resolution10bit);
QCOMPARE_LE(std::abs(1 - convertedWhite.z()), s_resolution10bit);
}
QTEST_MAIN(TestColorspaces)
#include "test_colorspaces.moc"

View File

@ -419,47 +419,32 @@ void TestVirtualDesktops::updateGrid_data()
{
QTest::addColumn<uint>("initCount");
QTest::addColumn<QSize>("size");
QTest::addColumn<Qt::Orientation>("orientation");
QTest::addColumn<QPoint>("coords");
QTest::addColumn<uint>("desktop");
const Qt::Orientation h = Qt::Horizontal;
const Qt::Orientation v = Qt::Vertical;
QTest::newRow("one desktop, h") << (uint)1 << QSize(1, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("one desktop, v") << (uint)1 << QSize(1, 1) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("one desktop, h, 0") << (uint)1 << QSize(1, 1) << h << QPoint(1, 0) << (uint)0;
QTest::newRow("one desktop, v, 0") << (uint)1 << QSize(1, 1) << v << QPoint(0, 1) << (uint)0;
QTest::newRow("one desktop, h") << (uint)1 << QSize(1, 1) << QPoint(0, 0) << (uint)1;
QTest::newRow("one desktop, h, 0") << (uint)1 << QSize(1, 1) << QPoint(1, 0) << (uint)0;
QTest::newRow("two desktops, h, 1") << (uint)2 << QSize(2, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("two desktops, h, 2") << (uint)2 << QSize(2, 1) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("two desktops, h, 3") << (uint)2 << QSize(2, 1) << h << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, h, 4") << (uint)2 << QSize(2, 1) << h << QPoint(2, 0) << (uint)0;
QTest::newRow("two desktops, h, 1") << (uint)2 << QSize(2, 1) << QPoint(0, 0) << (uint)1;
QTest::newRow("two desktops, h, 2") << (uint)2 << QSize(2, 1) << QPoint(1, 0) << (uint)2;
QTest::newRow("two desktops, h, 3") << (uint)2 << QSize(2, 1) << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, h, 4") << (uint)2 << QSize(2, 1) << QPoint(2, 0) << (uint)0;
QTest::newRow("two desktops, v, 1") << (uint)2 << QSize(2, 1) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("two desktops, v, 2") << (uint)2 << QSize(2, 1) << v << QPoint(1, 0) << (uint)2;
QTest::newRow("two desktops, v, 3") << (uint)2 << QSize(2, 1) << v << QPoint(0, 1) << (uint)0;
QTest::newRow("two desktops, v, 4") << (uint)2 << QSize(2, 1) << v << QPoint(2, 0) << (uint)0;
QTest::newRow("four desktops, h, one row, 1") << (uint)4 << QSize(4, 1) << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, one row, 2") << (uint)4 << QSize(4, 1) << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, one row, 3") << (uint)4 << QSize(4, 1) << QPoint(2, 0) << (uint)3;
QTest::newRow("four desktops, h, one row, 4") << (uint)4 << QSize(4, 1) << QPoint(3, 0) << (uint)4;
QTest::newRow("four desktops, h, one row, 1") << (uint)4 << QSize(4, 1) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, one row, 2") << (uint)4 << QSize(4, 1) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, one row, 3") << (uint)4 << QSize(4, 1) << h << QPoint(2, 0) << (uint)3;
QTest::newRow("four desktops, h, one row, 4") << (uint)4 << QSize(4, 1) << h << QPoint(3, 0) << (uint)4;
QTest::newRow("four desktops, h, grid, 1") << (uint)4 << QSize(2, 2) << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, grid, 2") << (uint)4 << QSize(2, 2) << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, grid, 3") << (uint)4 << QSize(2, 2) << QPoint(0, 1) << (uint)3;
QTest::newRow("four desktops, h, grid, 4") << (uint)4 << QSize(2, 2) << QPoint(1, 1) << (uint)4;
QTest::newRow("four desktops, h, grid, 0/3") << (uint)4 << QSize(2, 2) << QPoint(0, 3) << (uint)0;
QTest::newRow("four desktops, v, one column, 1") << (uint)4 << QSize(1, 4) << v << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, v, one column, 2") << (uint)4 << QSize(1, 4) << v << QPoint(0, 1) << (uint)2;
QTest::newRow("four desktops, v, one column, 3") << (uint)4 << QSize(1, 4) << v << QPoint(0, 2) << (uint)3;
QTest::newRow("four desktops, v, one column, 4") << (uint)4 << QSize(1, 4) << v << QPoint(0, 3) << (uint)4;
QTest::newRow("four desktops, h, grid, 1") << (uint)4 << QSize(2, 2) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("four desktops, h, grid, 2") << (uint)4 << QSize(2, 2) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("four desktops, h, grid, 3") << (uint)4 << QSize(2, 2) << h << QPoint(0, 1) << (uint)3;
QTest::newRow("four desktops, h, grid, 4") << (uint)4 << QSize(2, 2) << h << QPoint(1, 1) << (uint)4;
QTest::newRow("four desktops, h, grid, 0/3") << (uint)4 << QSize(2, 2) << h << QPoint(0, 3) << (uint)0;
QTest::newRow("three desktops, h, grid, 1") << (uint)3 << QSize(2, 2) << h << QPoint(0, 0) << (uint)1;
QTest::newRow("three desktops, h, grid, 2") << (uint)3 << QSize(2, 2) << h << QPoint(1, 0) << (uint)2;
QTest::newRow("three desktops, h, grid, 3") << (uint)3 << QSize(2, 2) << h << QPoint(0, 1) << (uint)3;
QTest::newRow("three desktops, h, grid, 4") << (uint)3 << QSize(2, 2) << h << QPoint(1, 1) << (uint)0;
QTest::newRow("three desktops, h, grid, 1") << (uint)3 << QSize(2, 2) << QPoint(0, 0) << (uint)1;
QTest::newRow("three desktops, h, grid, 2") << (uint)3 << QSize(2, 2) << QPoint(1, 0) << (uint)2;
QTest::newRow("three desktops, h, grid, 3") << (uint)3 << QSize(2, 2) << QPoint(0, 1) << (uint)3;
QTest::newRow("three desktops, h, grid, 4") << (uint)3 << QSize(2, 2) << QPoint(1, 1) << (uint)0;
}
void TestVirtualDesktops::updateGrid()
@ -470,9 +455,8 @@ void TestVirtualDesktops::updateGrid()
VirtualDesktopGrid grid;
QFETCH(QSize, size);
QFETCH(Qt::Orientation, orientation);
QCOMPARE(vds->desktops().count(), int(initCount));
grid.update(size, orientation, vds->desktops());
grid.update(size, vds->desktops());
QCOMPARE(grid.size(), size);
QCOMPARE(grid.width(), size.width());
QCOMPARE(grid.height(), size.height());

View File

@ -19,6 +19,8 @@ class XkbTest : public QObject
private Q_SLOTS:
void testToQtKey_data();
void testToQtKey();
void testFromQtKey_data();
void testFromQtKey();
};
// from kwindowsystem/src/platforms/xcb/kkeyserver.cpp
@ -457,6 +459,28 @@ static const TransKey g_rgQtToSymX[] = {
{XKB_KEY_KP_7, Qt::Key_7, Qt::KeypadModifier},
{XKB_KEY_KP_8, Qt::Key_8, Qt::KeypadModifier},
{XKB_KEY_KP_9, Qt::Key_9, Qt::KeypadModifier},
{XKB_KEY_KP_Space, Qt::Key_Space, Qt::KeypadModifier},
{XKB_KEY_KP_Tab, Qt::Key_Tab, Qt::KeypadModifier},
{XKB_KEY_KP_Enter, Qt::Key_Enter, Qt::KeypadModifier},
{XKB_KEY_KP_Home, Qt::Key_Home, Qt::KeypadModifier},
{XKB_KEY_KP_Left, Qt::Key_Left, Qt::KeypadModifier},
{XKB_KEY_KP_Up, Qt::Key_Up, Qt::KeypadModifier},
{XKB_KEY_KP_Right, Qt::Key_Right, Qt::KeypadModifier},
{XKB_KEY_KP_Down, Qt::Key_Down, Qt::KeypadModifier},
{XKB_KEY_KP_Prior, Qt::Key_PageUp, Qt::KeypadModifier},
{XKB_KEY_KP_Next, Qt::Key_PageDown, Qt::KeypadModifier},
{XKB_KEY_KP_End, Qt::Key_End, Qt::KeypadModifier},
{XKB_KEY_KP_Begin, Qt::Key_Clear, Qt::KeypadModifier},
{XKB_KEY_KP_Insert, Qt::Key_Insert, Qt::KeypadModifier},
{XKB_KEY_KP_Delete, Qt::Key_Delete, Qt::KeypadModifier},
{XKB_KEY_KP_Equal, Qt::Key_Equal, Qt::KeypadModifier},
{XKB_KEY_KP_Multiply, Qt::Key_Asterisk, Qt::KeypadModifier},
{XKB_KEY_KP_Add, Qt::Key_Plus, Qt::KeypadModifier},
{XKB_KEY_KP_Separator, Qt::Key_Comma, Qt::KeypadModifier},
{XKB_KEY_KP_Subtract, Qt::Key_Minus, Qt::KeypadModifier},
{XKB_KEY_KP_Decimal, Qt::Key_Period, Qt::KeypadModifier},
{XKB_KEY_KP_Divide, Qt::Key_Slash, Qt::KeypadModifier},
};
void XkbTest::testToQtKey_data()
@ -476,5 +500,31 @@ void XkbTest::testToQtKey()
QTEST(xkb.toQtKey(keySym), "qt");
}
void XkbTest::testFromQtKey_data()
{
QTest::addColumn<xkb_keysym_t>("keySym");
QTest::addColumn<int>("keyQt");
for (std::size_t i = 0; i < sizeof(g_rgQtToSymX) / sizeof(TransKey); i++) {
const QByteArray row = QByteArray::number(g_rgQtToSymX[i].keySymX, 16);
QTest::newRow(row.constData()) << g_rgQtToSymX[i].keySymX << (g_rgQtToSymX[i].keySymQt | g_rgQtToSymX[i].modifiers).toCombined();
}
}
void XkbTest::testFromQtKey()
{
Xkb xkb;
QFETCH(xkb_keysym_t, keySym);
QFETCH(int, keyQt);
QList<xkb_keysym_t> keys = xkb.keysymsFromQtKey(keyQt);
QEXPECT_FAIL(QByteArray::number(XKB_KEY_Hyper_L, 16), "keysymsFromQtKey doesn't map hyper to meta", Continue);
QEXPECT_FAIL(QByteArray::number(XKB_KEY_Hyper_R, 16), "keysymsFromQtKey doesn't map hyper to meta", Continue);
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 1)
QEXPECT_FAIL(QByteArray::number(XKB_KEY_KP_Equal, 16), "KP_Equal is not correctly identified as keypad key in Qt 6.7.0; fixed in 6.7.1: https://codereview.qt-project.org/c/qt/qtbase/+/546889", Continue);
#endif
QVERIFY(keys.contains(keySym));
}
QTEST_MAIN(XkbTest)
#include "test_xkb.moc"

View File

@ -274,8 +274,6 @@ void TestDragAndDrop::testPointerDragAndDrop()
// verify that we did not get any further input events
QVERIFY(pointerMotionSpy.isEmpty());
// the release event is sent primarily for xwayland
QCOMPARE(buttonPressSpy.count(), 2);
}
void TestDragAndDrop::testTouchDragAndDrop()
@ -394,6 +392,7 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
QSignalSpy dragEnteredSpy(m_dataDevice, &KWayland::Client::DataDevice::dragEntered);
QSignalSpy dragMotionSpy(m_dataDevice, &KWayland::Client::DataDevice::dragMotion);
QSignalSpy pointerMotionSpy(m_pointer, &KWayland::Client::Pointer::motion);
QSignalSpy pointerLeftSpy(m_pointer, &KWayland::Client::Pointer::left);
QSignalSpy dragLeftSpy(m_dataDevice, &KWayland::Client::DataDevice::dragLeft);
// now we can start the drag and drop
@ -401,11 +400,12 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
m_dataSource->setDragAndDropActions(KWayland::Client::DataDeviceManager::DnDAction::Copy | KWayland::Client::DataDeviceManager::DnDAction::Move);
m_dataDevice->startDrag(buttonPressSpy.first().first().value<quint32>(), m_dataSource, s.get());
QVERIFY(dragStartedSpy.wait());
QCOMPARE(m_seatInterface->dragSurface(), serverSurface);
QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4());
QVERIFY(!m_seatInterface->dragIcon());
QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, buttonPressSpy.first().first().value<quint32>());
QVERIFY(dragEnteredSpy.wait());
QVERIFY(dragEnteredSpy.count() || dragEnteredSpy.wait());
QCOMPARE(dragEnteredSpy.count(), 1);
QCOMPARE(dragEnteredSpy.first().first().value<quint32>(), m_display->serial());
QCOMPARE(dragEnteredSpy.first().last().toPointF(), QPointF(0, 0));
@ -452,7 +452,6 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
// verify that we did not get any further input events
QVERIFY(pointerMotionSpy.isEmpty());
QCOMPARE(buttonPressSpy.count(), 2);
}
void TestDragAndDrop::testPointerEventsIgnored()
@ -528,14 +527,12 @@ void TestDragAndDrop::testPointerEventsIgnored()
m_seatInterface->notifyPointerButton(1, PointerButtonState::Released);
m_seatInterface->notifyPointerFrame();
QVERIFY(cancelledSpy.wait());
QVERIFY(pointerLeftSpy.count() || pointerLeftSpy.wait());
// all the changes should have been ignored
QCOMPARE(axisSpy.count(), 1);
QCOMPARE(pointerMotionSpy.count(), 1);
QCOMPARE(pointerEnteredSpy.count(), 1);
QVERIFY(pointerLeftSpy.isEmpty());
// the release event is sent primary for xwayland, see BUG 465444
QCOMPARE(buttonSpy.count(), 2);
}
QTEST_GUILESS_MAIN(TestDragAndDrop)

View File

@ -81,7 +81,6 @@ void TestWaylandServerDisplay::testClientConnection()
QVERIFY(client);
QVERIFY(connectedSpy.isEmpty());
QVERIFY(display.connections().isEmpty());
ClientConnection *connection = display.getConnection(client);
QVERIFY(connection);
QCOMPARE(connection->client(), client);
@ -101,8 +100,6 @@ void TestWaylandServerDisplay::testClientConnection()
QCOMPARE((wl_client *)constRef, client);
QCOMPARE(connectedSpy.count(), 1);
QCOMPARE(connectedSpy.first().first().value<ClientConnection *>(), connection);
QCOMPARE(display.connections().count(), 1);
QCOMPARE(display.connections().first(), connection);
QCOMPARE(connection, display.getConnection(client));
QCOMPARE(connectedSpy.count(), 1);
@ -119,10 +116,6 @@ void TestWaylandServerDisplay::testClientConnection()
QCOMPARE(connectedSpy.first().first().value<ClientConnection *>(), connection);
QCOMPARE(connectedSpy.last().first().value<ClientConnection *>(), connection2);
QCOMPARE(connectedSpy.last().first().value<ClientConnection *>(), client2);
QCOMPARE(display.connections().count(), 2);
QCOMPARE(display.connections().first(), connection);
QCOMPARE(display.connections().last(), connection2);
QCOMPARE(display.connections().last(), client2);
// and destroy
QVERIFY(disconnectedSpy.isEmpty());
@ -136,7 +129,6 @@ void TestWaylandServerDisplay::testClientConnection()
close(sv[1]);
close(sv2[0]);
close(sv2[1]);
QVERIFY(display.connections().isEmpty());
}
void TestWaylandServerDisplay::testConnectNoSocket()

View File

@ -17,6 +17,11 @@ uint32_t Xcb::toXNative(qreal value)
return value;
}
QRect Xcb::toXNative(const QRectF &rect)
{
return rect.toRect();
}
qreal Xcb::fromXNative(int value)
{
return value;

View File

@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2024 David Redondo <kde@david-redono.de>
# SPDX-License-Identifier: BSD-3-Clause
find_package(PkgConfig)
pkg_check_modules(PKG_Libeis QUIET libeis-1.0)
find_path(Libeis_INCLUDE_DIR
NAMES libeis.h
HINTS ${PKG_Libeis_INCLUDE_DIRS}
)
find_library(Libeis_LIBRARY
NAMES eis
PATHS ${PKG_Libeis_LIBRARY_DIRS}
)
set(Libeis_VERSION ${PKG_Libeis_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libeis-1.0
FOUND_VAR Libeis-1.0_FOUND
REQUIRED_VARS
Libeis_LIBRARY
Libeis_INCLUDE_DIR
VERSION_VAR Libeis_VERSION
)
if(Libeis-1.0_FOUND AND NOT TARGET Libeis::Libeis)
add_library(Libeis::Libeis UNKNOWN IMPORTED)
set_target_properties(Libeis::Libeis PROPERTIES
IMPORTED_LOCATION "${Libeis_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PKG_Libeis_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Libeis_INCLUDE_DIR}"
)
endif()
mark_as_advanced(Libeis_INCLUDE_DIR Libeis_LIBRARY)

View File

@ -12,6 +12,8 @@
# The version of Xwayland
# ``Xwayland_HAVE_LISTENFD``
# True if (the requested version of) Xwayland has -listenfd option
# ``Xwayland_HAVE_ENABLE_EI_PORTAL``
# True if (the requested version of) Xwayland has -enable-ei-portal option
#=============================================================================
# SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
@ -25,6 +27,7 @@ pkg_check_modules(PKG_xwayland QUIET xwayland)
set(Xwayland_VERSION ${PKG_xwayland_VERSION})
pkg_get_variable(Xwayland_HAVE_LISTENFD xwayland have_listenfd)
pkg_get_variable(Xwayland_HAVE_ENABLE_EI_PORTAL xwayland have_enable_ei_portal)
find_program(Xwayland_EXECUTABLE NAMES Xwayland)
find_package_handle_standard_args(Xwayland

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 877 B

After

Width:  |  Height:  |  Size: 874 B

View File

@ -9,11 +9,13 @@
// read additional window rules and add them to kwinrulesrc
#include <KConfig>
#include <KConfigGroup>
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDebug>
#include <QStandardPaths>
#include <QtDBus>
#include <kconfig.h>
#include <kconfiggroup.h>
int main(int argc, char *argv[])
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 B

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -284,15 +284,6 @@ This controls the behavior of window focus with multiple screens. Note that thes
<variablelist>
<varlistentry>
<term><guilabel>Active screen follows mouse</guilabel></term>
<listitem>
<para>
When this option is enabled, the active screen (where new windows appear, for example) is the screen containing the mouse pointer. When disabled, the active screen is the screen containing the focused window.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><guilabel>Separate screen focus</guilabel></term>
<listitem>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Some files were not shown because too many files have changed in this diff Show More