Commit graph

48 commits

Author SHA1 Message Date
Yifan Zhu
c441ce5cd1 Avoid accidental mixing of qreal and int
The code for placeSmart uses ints to store coordinates and dimensions,
but the various methods of QRectF return qreal types, which can be
non-integers under fractional scaling, causing multiple issues.

This commit explicitly converts the needed quantities to ints,
avoiding the issues.

Previously, the code relied on the assumption that
y = area.y() + area.height(); implies !(y < area.y() + area.height()).
This doesn't always hold when mixing qreals and ints, causing infinite loops
under fractional scaling when attempting to open large windows, as
reported in BUG 477820.

This commit also extends the fix in 5502ce9 to fractional scaling scenarios.
The ceiling of client widths and height is used, instead of the implicit
floor, which caused BUG 477886.

BUG: 477820
BUG: 477886
2023-12-04 08:59:58 -08:00
Kai Uwe Broulik
74b68a63b5 Drop bounds argument from transientPlacement
XdgPopupWindow disregards it for the most part anyway and asks workspace
for the placement area directly. Also gives XdgPopupWindow more control
on the placement when it's all contained inside of it for the upcoming commit.
2023-08-21 11:17:18 +00:00
Antonio Russo
5502ce9a9c placeSmart: Properly track width and height
`Placements::placeSmart` searches for an optimal position for windows, attempting to minimize overlap.  The core of this algorithm tracks the
client's height and width in `ch` and `cw`, which have been adjusted by -1. This simplifies logic determining the bottom and right points of a
window when you are starting at the top and left points.

However, this decision requires adjusting that number by +1 when doing the opposite: determining the top and left points when you start with
the bottom and right points.

placeSmart cycles through window locations, searching for acceptable nooks and crannies to fit a window in, nicely.  It begins by checking
for places to put the top left corner of the window which abut another constraint.  If that fails, it then tries to place the bottom right
abutting a constraining feature.

After finding a suitable bottom (or right) location, the top (or left) location must be determined, requiring the -1 adjustment to be undone.

This patch adds that +1 back in.

# The bug it solves

This error can be seen by opening a bunch of windows that are placed using the "Minimal Overlapping" rule.  The open space on the screen will be tiled from left to right, and then top to bottom in the windows.  Once no more windows can be placed like that, the next window will be placed at the extreme bottom-right corner.  However, it will be one pixel too low and one pixel too far to the right---if you try to move the window, it will "snap" to the correct spot.

This single pixel may seem minor or even irrelevant, but when you use the "Present Windows" desktop effect on a multiple-monitor setup, this one pixel will cause the window to show up on both monitors.
2023-08-07 07:14:18 +00:00
Vlad Zahorodnii
d76527e7e6 Port window cascading from X11 desktop ids to VirtualDesktop 2023-03-30 12:21:05 +03:00
Vlad Zahorodnii
8f21d444c6 Make Workspace::allClientList() return all windows
Currently windows are scattered in a few separate lists. If you need to
go through the windows, you have to do it piece by piece. On the other
hand, with the overhaul of window types, we've started converging
towards one universal type: Window. Keeping windows in the separate
buckets goes against this design.

Workspace::stackingOrder() already contains all windows. This change
repurposes Workspace::allClientList() from a list of "normal" windows to
all windows, i.e. Workspace::windows(), to be consistent.

There's one API change though. Scripting API will expose other window
types too. This is an intentional change so scripted effects could
operate with all windows. It also matches the current behavior observed
in libkwineffects, which exposes all windows as well.
2023-03-15 11:52:01 +00:00
Vlad Zahorodnii
392fb4eb01 Add explicit Window::isClient() checks
This is needed to prepare for introducing Workspace::windows().
2023-03-15 11:52:01 +00:00
Vlad Zahorodnii
c1eca80190 wayland: Remove implicit slide constraint adjustment
Panel sets constraint adjustments so let's remove the implicit slide
constraint adjustment to adhere more closely to the spec.
2023-03-09 13:05:42 +00:00
Natalie Clarius
39cea49a8f placement: don't cascade for the sake of windows that are already covered
When checking for overlap with other windows when placing a new window and cascading to avoid complete overlap, ignore those windows that are already covered by other windows further on the top anyway.

The computation of the covered area is not entirely accurate as it uses the bounding rect rather than the combined rects of the windows, but okay enough for our use case imo.

BUG: 466135
2023-03-08 19:04:57 +00:00
Natalie Clarius
b6412454c2 placement: remove cascaded placement policy
becomes redundant with cascade-if-covering for zero-cornered placement
2022-12-02 14:05:32 +00:00
Natalie Clarius
b08ef54727 placement: apply cascade-if-covering to placement modes: random, centered, zero-cornered, under mouse 2022-12-02 14:05:32 +00:00
Natalie Clarius
274922caaf placement: cascade if window would completely overlap another window
BUG: 58063
2022-12-02 14:05:32 +00:00
Xaver Hugl
147f3509ea Refactor placement code
This removes the usage of x11 virtual desktop ids and makes the code a bit
more readable
2022-11-18 23:35:31 +01:00
Xaver Hugl
d265535f9b qMin -> std::min 2022-11-13 14:32:16 +00:00
Xaver Hugl
b0b7c8b1d3 qMax -> std::max 2022-11-13 14:32:16 +00:00
Arjen Hiemstra
817d13d8c0 Ensure move() calls in placement move in integer values
Otherwise we run the risk of placing windows at floating coodinates,
which leads to interpolated rendering which doesn't look nice.

BUG: 457143
2022-09-14 09:00:47 +00:00
Vlad Zahorodnii
e97e520175 Move placement policy enum in KWin namespace
Other policy enums are declared in options.h so let's do the same for
placement policy. Besides consistency, another advantage of moving the
enum in kwin namespace is that the enum could be forward declared.
2022-09-05 14:11:42 +00:00
Vlad Zahorodnii
4a6e416289 Avoid mixing current and next maximize modes more
Mixing those two can make maximize mode behavior undefined.
2022-09-02 07:48:55 +00:00
Vlad Zahorodnii
0be0e8a7b0 Add Window::moveResizeOutput()
The Window::moveResizeOutput() property is used to track the output
where the window is expected to land after the move or resize operation
completes.

This can be used to decouple the current output from the next output,
which allows us to send better xdg_toplevel.configure_bounds events or
make windows stick to outputs while keeping Window::output() in sync
with the current output layout.
2022-09-02 06:46:38 +00:00
Xaver Hugl
3fff256b88 window: make resizeWithChecks not modify any window state 2022-08-31 11:32:30 +00:00
Xaver Hugl
0d704b8913 placement: move singleton to Workspace 2022-08-02 21:37:41 +00:00
Vlad Zahorodnii
519a2db950 Remove leftover qDebug()s 2022-07-25 09:19:44 +00:00
David Edmundson
7292af3d04 Use floating geometry throughout
With fractional scaling integer based logical geometry may not match
device pixels. Once we have a floating point base we can fix that. This
also is
important for our X11 scale override, with a scale of 2 we could
get logical sizes with halves.

We already have all input being floating point, this doubles down on it
for all remaining geometry.

- Outputs remain integer to ensure that any screen on the right remains
aligned.
 - Placement also remains integer based for now.
- Repainting is untouched as we always expand outwards
 			   (QRectF::toAdjustedRect().
 - Decoration is untouched for now
 - Rules are integer in the config, but floating in the adjusting/API
This should also be fine.

At some point we'll add a method to snap to the device pixel
grid. Effectively `round(value * dpr)  / dpr` though right now things
mostly work.

This also gets rid of a lot of hacks for QRect right and bottom which
are very
confusing.

Parts to watch out in the port are:
 QRectF::contains now includes edges
QRectF::right and bottom are now sane so previous hacks have to be
removed
 QRectF(QPoint, QPoint) behaves differently for the same reason
 QRectF::center too

In test results some adjusted values which are the result of
QRect.center because using QRectF's center should behave the same to the
user.
2022-07-14 10:04:46 +01:00
Vlad Zahorodnii
d6646d25d0 Remove unused screens.h includes 2022-07-14 09:51:18 +03:00
Vlad Zahorodnii
5ee044e6fc Some client/toplevel -> window 2022-04-29 17:47:39 +03:00
Vlad Zahorodnii
175037d9d1 Prefer the term "window" over "client" in Workspace 2022-04-25 11:33:55 +00:00
Vlad Zahorodnii
a21aa839b1 Rename X11Client to X11Window
The word "client" means different things in wayland and kwin. Use a
better word to refer to windows.
2022-04-23 07:55:51 +00:00
Nils Fenner
b491aeb9ae Rename AbstractClient to Window 2022-04-22 17:39:12 +00:00
Vlad Zahorodnii
94bbe14f4c Remove AbstractClient plumbing casts in Placement 2022-04-18 11:01:51 +03:00
Nils Fenner
aaa429ee0a Merge Toplevel into AbstractClient
References issue #81
2022-04-18 07:42:11 +00:00
Vlad Zahorodnii
8e7a8c5a11 Rename AbstractOutput to Output
AbstractOutput is not so Abstract and it's common to avoid the word
"Abstract" in class names as it doesn't contribute any new information.
It also significantly reduces the line width in some places.
2022-04-15 17:49:49 +03:00
Nils Fenner
d146a3d1dd Use Toplevel::isClient() to resolve AbstractClient type. 2022-04-14 13:50:12 +00:00
Vlad Zahorodnii
e293972eaa Run clang-tidy with -checks=readability-braces-around-statements fixit
This fixes style issues in old code.
2022-03-28 10:54:11 +00:00
Vlad Zahorodnii
7096e3ead8 Run clang-format
The .clang-format file is based on the one in ECM except the following
style options:

 - AlwaysBreakBeforeMultilineStrings
 - BinPackArguments
 - BinPackParameters
 - ColumnLimit
 - BreakBeforeBraces
 - KeepEmptyLinesAtTheStartOfBlocks
2022-03-25 13:25:15 +02:00
Vlad Zahorodnii
7120348932 Make checkWorkspacePosition() work without client geometry
A good portion of geometry handling code was written during the X11
times. The main difference between X11 and Wayland is that kwin doesn't
know where a window will exactly be after resize() or moveResize().

In order to handle Wayland specifics, every window has a bounding
geometry that is being manipulated by move(), resize(), and moveResize().
The frameGeometry(), the clientGeometry(), and the bufferGeometry() are
not manipulated by move(), resize(), and moveResize() directly. Almost
everything that manipulates geometry should use moveResizeGeometry().

This creates a problem though, since the clientGeometry() will be
updated only after the client provides a new buffer, kwin has absolutely
no idea what the client geometry for a given move resize geometry will
be.

Another side of the coin is that decoration updates are performed
asynchronously on wayland, meaning that you cannot use border properties
for anything related to geometry handling and you should avoid using
borderLeft(), borderTop(), borderRight(), and borderBottom() in general.

clientGeometry(), bufferGeometry(), and border*() are good only if you
want to forward an event or render something. They can't be used for
manipulating the geometry.

Unfortunately, AbstractClient::checkWorkspacePosition() needs both,
which is a bit of a problem. To add more oil to the fire, contents
of a decorated window can be snapped to a screen edge. This goes against
the nature of geometry updates on wayland, where we try to indicate
the bounds of the frame geometry and avoid using client and buffer
geometries.

In order to make geometry handling more correct on wayland, this change
removes the ability to snap the contents of a decorated window to a
screen edge. This allows to avoid using the client geometry in
checkWorkspacePosition(), which is a very important function that ensures
the window is inside the workspace.

There is nothing wrong with snapping the frame rather than its contents
and that's what kwin used to do. It was changed with the removal of
"Display borders on maximized windows" option, the relevant commit
didn't provide any reasoning behind the change.
2022-01-25 17:56:40 +00:00
Vlad Zahorodnii
5420e11bd4 Make AbstractClient::titlebarPosition() return Qt::Edge
Conceptually, it's an edge, the titlebar can't be in a window corner.
2022-01-04 15:57:42 +00:00
Vlad Zahorodnii
f1e96676ef Remove boolean trap in AbstractClient::isShown()
Check shaded state where needed.
2021-11-24 08:11:35 +00:00
Xaver Hugl
6ff4de2e05 port everything away from Q_FOREACH 2021-11-08 14:19:05 +00:00
Nate Graham
c1fb405b8d Rename "pack" actions for clarity
The English word "pack" is not really the correct word for these
actions, and does not succeed in communicating what they will do. Since
the actions simply move the active window as far as it will go in the
specified direction, the actions can be renamed to say that instead.

Also rename the action names in the code to match their new UI text for
clarity.
2021-10-13 14:28:23 +00:00
Kristen McWilliam
5fdf1da808 Add hotkey option to move active window to center 2021-09-20 13:14:24 +00:00
Kristen McWilliam
69417dd5f7 Fix required if statement before switch 2021-09-20 13:12:17 +00:00
Kristen McWilliam
b23f2ab3dd Refactor if-else chain in Placement::place to a switch statement
Was using a long & fragmented if-else chain. A switch statement
is often more performant, as well as being easier to read and modify.
2021-09-20 13:12:17 +00:00
Vlad Zahorodnii
6ca411a84a Port AbstractClient::sendToScreen() to AbstractOutput 2021-08-29 21:55:07 +00:00
Vlad Zahorodnii
d5c2518973 Add Workspace::clientArea() that take no desktop
The new overloads take the client (as context) and the desired screen id
or a point and return the client area.

The main motivation behind this change is to make the transition to the
new virtual desktop model where a window can be on several desktops less
painful.
2021-08-19 10:49:40 +00:00
Vlad Zahorodnii
a13fd02ea8 Remove virtualdesktops.h include in toplevel.h
toplevel.h is included in many places. Changing virtualdesktops.h may
trigger rebuild of all kwin.

With this change, only cpp files that use virtualdesktops.h will need to
be recompiled.
2021-08-12 17:23:15 +00:00
Marco Martin
ada29cfc9a don't place windows with invalid geometry
if a window has a size of 0x0, doesn't have its final place yet, so it can't be reliably
placed centered yet
2021-06-09 12:42:12 +00:00
Vlad Zahorodnii
1b2c7b248b Run clazy with qt-keywords fixit
In C++20, there will be emit() class member, which can conflict with the
emit keyword. Given that, there are plans to enable QT_NO_KEYWORDS by
default in the future.

See also
https://lists.qt-project.org/pipermail/development/2020-February/038812.html
2021-06-08 10:49:42 +03:00
Vlad Zahorodnii
9a7ab8a62e Rework async geometry updates
Window management features were written with synchronous geometry
updates in mind. Currently, this poses a big problem on Wayland because
geometry updates are done in asynchronous fashion there.

At the moment, geometry is updated in a so called pseudo-asynchronous
fashion, meaning that the frame geometry will be reset to the old value
once geometry updates are unblocked. The main drawback of this approach
is that it is too error prone, the data flow is hard to comprehend, etc.

It is worth noting that there is already a machinery to perform async
geometry which is used during interactive move/resize operations.

This change extends the move/resize geometry usage beyond interactive
move/resize to make asynchronous geometry updates less error prone and
easier to comprehend.

With the proposed solution, all geometry updates must be done on the
move/resize geometry first. After that, the new geometry is passed on to
the Client-specific implementation of moveResizeInternal().

To be more specific, the frameGeometry() returns the current frame
geometry, it is primarily useful only to the scene. If you want to move
or resize a window, you need to use moveResizeGeometry() because it
corresponds to the last requested frame geometry.

It is worth noting that the moveResizeGeometry() returns the desired
bounding geometry. The client may commit the xdg_toplevel surface with a
slightly smaller window geometry, for example to enforce a specific
aspect ratio. The client is not allowed to resize beyond the size as
indicated in moveResizeGeometry().

The data flow is very simple: moveResize() updates the move/resize
geometry and calls the client-specific implementation of the
moveResizeInternal() method. Based on whether a configure event is
needed, moveResizeInternal() will update the frameGeometry() either
immediately or after the client commits a new buffer.

Unfortunately, both the compositor and xdg-shell clients try to update
the window geometry. It means that it's possible to have conflicts
between the two. With this change, the compositor's move resize geometry
will be synced only if there are no pending configure events, meaning
that the user doesn't try to resize the window.
2021-05-25 06:17:41 +00:00
Vlad Zahorodnii
93e0265e4e Move source code to src/ directory
Once in a while, we receive complaints from other fellow KDE developers
about the file organization of kwin. This change addresses some of those
complaints by moving all of source code in a separate directory, src/,
thus making the project structure more traditional. Things such as tests
are kept in their own toplevel directories.

This change may wreak havoc on merge requests that add new files to kwin,
but if a patch modifies an already existing file, git should be smart
enough to figure out that the file has been relocated.

We may potentially split the src/ directory further to make navigating
the source code easier, but hopefully this is good enough already.
2021-02-10 15:31:43 +00:00
Renamed from placement.cpp (Browse further)