2007-11-27 19:40:25 +00:00
|
|
|
/********************************************************************
|
2007-04-29 17:35:43 +00:00
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
|
|
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
|
2007-11-27 19:40:25 +00:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// This file contains things relevant to handling incoming events.
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-09-24 08:48:08 +00:00
|
|
|
#include "x11client.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#include <kstartupinfo.h>
|
|
|
|
|
2013-04-04 14:14:12 +00:00
|
|
|
#ifdef KWIN_BUILD_ACTIVITIES
|
|
|
|
#include "activities.h"
|
|
|
|
#endif
|
2019-03-19 10:02:45 +00:00
|
|
|
#include "composite.h"
|
2013-02-19 10:25:46 +00:00
|
|
|
#include "cursor.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
#include "rules.h"
|
|
|
|
#include "group.h"
|
2013-04-26 08:41:24 +00:00
|
|
|
#include "netinfo.h"
|
2013-04-03 10:19:27 +00:00
|
|
|
#include "screens.h"
|
2013-04-26 09:52:15 +00:00
|
|
|
#include "workspace.h"
|
2012-12-21 14:11:31 +00:00
|
|
|
#include "xcbutils.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-08-20 07:48:14 +00:00
|
|
|
#include <xcb/shape.h>
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
/**
|
|
|
|
* Manages the clients. This means handling the very first maprequest:
|
|
|
|
* reparenting, initial geometry, initial state, placement, etc.
|
|
|
|
* Returns false if KWin is not going to manage this window.
|
2007-04-29 17:35:43 +00:00
|
|
|
*/
|
2019-09-24 08:48:08 +00:00
|
|
|
bool X11Client::manage(xcb_window_t w, bool isMapped)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
StackingUpdatesBlocker stacking_blocker(workspace());
|
2010-11-14 08:45:55 +00:00
|
|
|
|
2014-04-25 11:42:52 +00:00
|
|
|
Xcb::WindowAttributes attr(w);
|
|
|
|
Xcb::WindowGeometry windowGeometry(w);
|
|
|
|
if (attr.isNull() || windowGeometry.isNull()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// From this place on, manage() must not return false
|
2015-10-13 11:15:39 +00:00
|
|
|
blockGeometryUpdates();
|
|
|
|
setPendingGeometryUpdate(PendingGeometryForced); // Force update when finishing with geometry changes
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2014-04-25 11:42:52 +00:00
|
|
|
embedClient(w, attr->visual, attr->colormap, windowGeometry->depth);
|
2008-12-18 15:01:25 +00:00
|
|
|
|
2014-04-25 11:42:52 +00:00
|
|
|
m_visual = attr->visual;
|
|
|
|
bit_depth = windowGeometry->depth;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// SELI TODO: Order all these things in some sane manner
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2014-03-04 09:48:23 +00:00
|
|
|
const NET::Properties properties =
|
2007-04-29 17:35:43 +00:00
|
|
|
NET::WMDesktop |
|
|
|
|
NET::WMState |
|
|
|
|
NET::WMWindowType |
|
|
|
|
NET::WMStrut |
|
|
|
|
NET::WMName |
|
|
|
|
NET::WMIconGeometry |
|
|
|
|
NET::WMIcon |
|
|
|
|
NET::WMPid |
|
2014-02-03 08:37:08 +00:00
|
|
|
NET::WMIconName;
|
2014-03-04 09:48:23 +00:00
|
|
|
const NET::Properties2 properties2 =
|
2014-04-14 13:32:45 +00:00
|
|
|
NET::WM2BlockCompositing |
|
2014-04-11 06:06:26 +00:00
|
|
|
NET::WM2WindowClass |
|
2014-04-10 09:12:48 +00:00
|
|
|
NET::WM2WindowRole |
|
2007-04-29 17:35:43 +00:00
|
|
|
NET::WM2UserTime |
|
|
|
|
NET::WM2StartupId |
|
|
|
|
NET::WM2ExtendedStrut |
|
|
|
|
NET::WM2Opacity |
|
2008-11-17 08:03:39 +00:00
|
|
|
NET::WM2FullscreenMonitors |
|
2014-09-12 11:56:34 +00:00
|
|
|
NET::WM2FrameOverlap |
|
|
|
|
NET::WM2GroupLeader |
|
|
|
|
NET::WM2Urgency |
|
2014-09-18 06:43:20 +00:00
|
|
|
NET::WM2Input |
|
2015-01-15 09:02:42 +00:00
|
|
|
NET::WM2Protocols |
|
2015-01-21 09:17:26 +00:00
|
|
|
NET::WM2InitialMappingState |
|
2015-01-22 14:46:12 +00:00
|
|
|
NET::WM2IconPixmap |
|
2016-10-27 13:59:08 +00:00
|
|
|
NET::WM2OpaqueRegion |
|
[x11] Add support for _GTK_FRAME_EXTENTS
Summary:
KDE is known for having a strong view on the client-side decorations vs
server-side decorations issue. The main argument raised against CSD is
that desktop will look less consistent when clients start drawing window
decorations by themselves, which is somewhat true. It all ties to how
well each toolkit is integrated with the desktop environment.
KDE doesn't control the desktop market on Linux. Another big "player"
is GNOME. Both KDE and GNOME have very polarized views on in which
direction desktop should move forward. The KDE community is pushing more
toward server-side decorations while the GNOME community is pushing
more toward client-side decorations. Both communities have developed
great applications and it's not rare to see a GNOME application being
used in KDE Plasma. The only problem is that these different views are
not left behind the curtain and our users pay the price. Resizing GTK
clients in Plasma became practically impossible due to resize borders
having small hit area.
When a client draws its window decoration, it's more likely that it also
draws the drop-shadow around the decoration. The compositor must know
the extents of the shadow so things like snapping and so on work as
expected. And here lies the problem... While the xdg-shell protocol has
a way to specify such things, the NetWM spec doesn't have anything like
that. There's _GTK_FRAME_EXTENTS in the wild, however the problem with
it is that it's a proprietary atom, which is specific only to GTK apps.
Due to that, _GTK_FRAME_EXTENTS wasn't implemented because implementing
anything like that would require major changes in how we think about
geometry.
Recent xdg-shell window geometry patches adjusted geometry abstractions
in kwin to such a degree that it's very easy to add support for client
side decorated clients on X11. We just have to make sure that the
X11Client class provides correct buffer geometry and frame geometry when
the gtk frame extents are set.
Even though the X11 code is feature frozen, I still think it's worth
to have _GTK_FRAME_EXTENTS support in kwin because it will fix the resize
issues. Also, because KWin/Wayland is unfortunately far from becoming
default, it will help us with testing some implementation bits of the
window geometry from xdg-shell.
BUG: 390550
FIXED-IN: 5.18.0
Test Plan:
Things like quick tiling, maximizing, tiling scripts and so on work as
expected with GTK clients.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: cblack, trmdi, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D24660
2019-10-08 08:46:59 +00:00
|
|
|
NET::WM2DesktopFileName |
|
|
|
|
NET::WM2GTKFrameExtents;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2015-01-15 13:33:28 +00:00
|
|
|
auto wmClientLeaderCookie = fetchWmClientLeader();
|
2015-01-15 14:19:04 +00:00
|
|
|
auto skipCloseAnimationCookie = fetchSkipCloseAnimation();
|
2015-01-15 14:51:21 +00:00
|
|
|
auto showOnScreenEdgeCookie = fetchShowOnScreenEdge();
|
2015-01-15 15:09:05 +00:00
|
|
|
auto colorSchemeCookie = fetchColorScheme();
|
2015-01-15 15:14:28 +00:00
|
|
|
auto firstInTabBoxCookie = fetchFirstInTabBox();
|
2015-01-15 15:23:29 +00:00
|
|
|
auto transientCookie = fetchTransient();
|
2015-01-15 15:31:20 +00:00
|
|
|
auto activitiesCookie = fetchActivities();
|
2017-01-11 09:21:03 +00:00
|
|
|
auto applicationMenuServiceNameCookie = fetchApplicationMenuServiceName();
|
|
|
|
auto applicationMenuObjectPathCookie = fetchApplicationMenuObjectPath();
|
|
|
|
|
2015-01-21 15:05:29 +00:00
|
|
|
m_geometryHints.init(window());
|
2015-02-02 13:56:21 +00:00
|
|
|
m_motif.init(window());
|
2014-03-04 09:48:23 +00:00
|
|
|
info = new WinInfo(this, m_client, rootWindow(), properties, properties2);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2016-08-09 11:50:29 +00:00
|
|
|
if (isDesktop() && bit_depth == 32) {
|
|
|
|
// force desktop windows to be opaque. It's a desktop after all, there is no window below
|
|
|
|
bit_depth = 24;
|
|
|
|
}
|
|
|
|
|
2015-01-15 09:02:42 +00:00
|
|
|
// If it's already mapped, ignore hint
|
|
|
|
bool init_minimize = !isMapped && (info->initialMappingState() == NET::Iconic);
|
|
|
|
|
2014-04-25 11:42:52 +00:00
|
|
|
m_colormap = attr->colormap;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
getResourceClass();
|
2015-01-15 13:33:28 +00:00
|
|
|
readWmClientLeader(wmClientLeaderCookie);
|
2007-04-29 17:35:43 +00:00
|
|
|
getWmClientMachine();
|
2007-06-25 08:51:44 +00:00
|
|
|
getSyncCounter();
|
2008-12-18 15:01:25 +00:00
|
|
|
// First only read the caption text, so that setupWindowRules() can use it for matching,
|
2007-04-29 17:35:43 +00:00
|
|
|
// and only then really set the caption using setCaption(), which checks for duplicates etc.
|
|
|
|
// and also relies on rules already existing
|
|
|
|
cap_normal = readName();
|
2011-01-30 14:34:42 +00:00
|
|
|
setupWindowRules(false);
|
|
|
|
setCaption(cap_normal, true);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-09-24 08:48:08 +00:00
|
|
|
connect(this, &X11Client::windowClassChanged, this, &X11Client::evaluateWindowRules);
|
2018-11-04 19:23:00 +00:00
|
|
|
|
2012-12-21 14:11:31 +00:00
|
|
|
if (Xcb::Extensions::self()->isShapeAvailable())
|
2013-08-20 07:48:14 +00:00
|
|
|
xcb_shape_select_input(connection(), window(), true);
|
2011-01-30 14:34:42 +00:00
|
|
|
detectShape(window());
|
2007-04-29 17:35:43 +00:00
|
|
|
detectNoBorder();
|
|
|
|
fetchIconicName();
|
[x11] Add support for _GTK_FRAME_EXTENTS
Summary:
KDE is known for having a strong view on the client-side decorations vs
server-side decorations issue. The main argument raised against CSD is
that desktop will look less consistent when clients start drawing window
decorations by themselves, which is somewhat true. It all ties to how
well each toolkit is integrated with the desktop environment.
KDE doesn't control the desktop market on Linux. Another big "player"
is GNOME. Both KDE and GNOME have very polarized views on in which
direction desktop should move forward. The KDE community is pushing more
toward server-side decorations while the GNOME community is pushing
more toward client-side decorations. Both communities have developed
great applications and it's not rare to see a GNOME application being
used in KDE Plasma. The only problem is that these different views are
not left behind the curtain and our users pay the price. Resizing GTK
clients in Plasma became practically impossible due to resize borders
having small hit area.
When a client draws its window decoration, it's more likely that it also
draws the drop-shadow around the decoration. The compositor must know
the extents of the shadow so things like snapping and so on work as
expected. And here lies the problem... While the xdg-shell protocol has
a way to specify such things, the NetWM spec doesn't have anything like
that. There's _GTK_FRAME_EXTENTS in the wild, however the problem with
it is that it's a proprietary atom, which is specific only to GTK apps.
Due to that, _GTK_FRAME_EXTENTS wasn't implemented because implementing
anything like that would require major changes in how we think about
geometry.
Recent xdg-shell window geometry patches adjusted geometry abstractions
in kwin to such a degree that it's very easy to add support for client
side decorated clients on X11. We just have to make sure that the
X11Client class provides correct buffer geometry and frame geometry when
the gtk frame extents are set.
Even though the X11 code is feature frozen, I still think it's worth
to have _GTK_FRAME_EXTENTS support in kwin because it will fix the resize
issues. Also, because KWin/Wayland is unfortunately far from becoming
default, it will help us with testing some implementation bits of the
window geometry from xdg-shell.
BUG: 390550
FIXED-IN: 5.18.0
Test Plan:
Things like quick tiling, maximizing, tiling scripts and so on work as
expected with GTK clients.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: cblack, trmdi, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D24660
2019-10-08 08:46:59 +00:00
|
|
|
setClientFrameExtents(info->gtkFrameExtents());
|
2014-09-12 11:56:34 +00:00
|
|
|
|
|
|
|
// Needs to be done before readTransient() because of reading the group
|
|
|
|
checkGroup();
|
|
|
|
updateUrgency();
|
|
|
|
updateAllowedActions(); // Group affects isMinimizable()
|
|
|
|
|
2015-09-14 07:04:20 +00:00
|
|
|
setModal((info->state() & NET::Modal) != 0); // Needs to be valid before handling groups
|
2015-01-15 15:23:29 +00:00
|
|
|
readTransientProperty(transientCookie);
|
2018-03-11 16:13:32 +00:00
|
|
|
setDesktopFileName(rules()->checkDesktopFile(QByteArray(info->desktopFileName()), true).toUtf8());
|
2007-04-29 17:35:43 +00:00
|
|
|
getIcons();
|
2019-09-24 08:48:08 +00:00
|
|
|
connect(this, &X11Client::desktopFileNameChanged, this, &X11Client::getIcons);
|
2016-10-27 13:59:08 +00:00
|
|
|
|
2015-01-21 15:05:29 +00:00
|
|
|
m_geometryHints.read();
|
2007-04-29 17:35:43 +00:00
|
|
|
getMotifHints();
|
2011-10-22 09:02:49 +00:00
|
|
|
getWmOpaqueRegion();
|
2015-01-15 14:19:04 +00:00
|
|
|
readSkipCloseAnimation(skipCloseAnimationCookie);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// TODO: Try to obey all state information from info->state()
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2015-06-06 20:08:12 +00:00
|
|
|
setOriginalSkipTaskbar((info->state() & NET::SkipTaskbar) != 0);
|
2015-06-06 19:17:23 +00:00
|
|
|
setSkipPager((info->state() & NET::SkipPager) != 0);
|
2018-05-24 04:33:39 +00:00
|
|
|
setSkipSwitcher((info->state() & NET::SkipSwitcher) != 0);
|
2015-01-15 15:14:28 +00:00
|
|
|
readFirstInTabBox(firstInTabBoxCookie);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-08-12 11:02:58 +00:00
|
|
|
setupCompositing();
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
KStartupInfoId asn_id;
|
|
|
|
KStartupInfoData asn_data;
|
2011-01-30 14:34:42 +00:00
|
|
|
bool asn_valid = workspace()->checkStartupNotification(window(), asn_id, asn_data);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-11-09 19:39:13 +00:00
|
|
|
// Make sure that the input window is created before we update the stacking order
|
|
|
|
updateInputWindow();
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
workspace()->updateClientLayer(this);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
SessionInfo* session = workspace()->takeSessionInfo(this);
|
|
|
|
if (session) {
|
2008-03-23 00:12:11 +00:00
|
|
|
init_minimize = session->minimized;
|
|
|
|
noborder = session->noBorder;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
setShortcut(rules()->checkShortcut(session ? session->shortcut : QString(), true));
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
init_minimize = rules()->checkMinimize(init_minimize, !isMapped);
|
|
|
|
noborder = rules()->checkNoBorder(noborder, !isMapped);
|
2008-12-18 15:01:25 +00:00
|
|
|
|
2015-01-15 15:31:20 +00:00
|
|
|
readActivities(activitiesCookie);
|
2010-09-24 12:03:22 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// Initial desktop placement
|
2015-03-13 11:54:11 +00:00
|
|
|
int desk = 0;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session) {
|
2007-04-29 17:35:43 +00:00
|
|
|
desk = session->desktop;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session->onAllDesktops)
|
2007-04-29 17:35:43 +00:00
|
|
|
desk = NET::OnAllDesktops;
|
2010-10-02 17:04:24 +00:00
|
|
|
setOnActivities(session->activities);
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2008-12-18 15:01:25 +00:00
|
|
|
// If this window is transient, ensure that it is opened on the
|
2007-04-29 17:35:43 +00:00
|
|
|
// same window as its parent. this is necessary when an application
|
|
|
|
// starts up on a different desktop than is currently displayed
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isTransient()) {
|
2015-09-11 13:55:23 +00:00
|
|
|
auto mainclients = mainClients();
|
2007-04-29 17:35:43 +00:00
|
|
|
bool on_current = false;
|
2010-08-19 12:07:44 +00:00
|
|
|
bool on_all = false;
|
2015-09-11 13:55:23 +00:00
|
|
|
AbstractClient* maincl = nullptr;
|
2008-12-18 15:01:25 +00:00
|
|
|
// This is slightly duplicated from Placement::placeOnMainWindow()
|
2015-09-11 13:55:23 +00:00
|
|
|
for (auto it = mainclients.constBegin();
|
2011-01-30 14:34:42 +00:00
|
|
|
it != mainclients.constEnd();
|
|
|
|
++it) {
|
2015-10-22 21:46:19 +00:00
|
|
|
if (mainclients.count() > 1 && // A group-transient
|
|
|
|
(*it)->isSpecialWindow() && // Don't consider toolbars etc when placing
|
|
|
|
!(info->state() & NET::Modal)) // except when it's modal (blocks specials as well)
|
|
|
|
continue;
|
2007-04-29 17:35:43 +00:00
|
|
|
maincl = *it;
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((*it)->isOnCurrentDesktop())
|
2007-04-29 17:35:43 +00:00
|
|
|
on_current = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((*it)->isOnAllDesktops())
|
2010-08-19 12:07:44 +00:00
|
|
|
on_all = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (on_all)
|
2010-08-19 12:07:44 +00:00
|
|
|
desk = NET::OnAllDesktops;
|
2011-01-30 14:34:42 +00:00
|
|
|
else if (on_current)
|
2012-11-16 07:23:47 +00:00
|
|
|
desk = VirtualDesktopManager::self()->current();
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
else if (maincl != nullptr)
|
2007-04-29 17:35:43 +00:00
|
|
|
desk = maincl->desktop();
|
2010-09-26 16:44:07 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (maincl)
|
2010-09-26 16:44:07 +00:00
|
|
|
setOnActivities(maincl->activities());
|
2015-10-22 21:46:19 +00:00
|
|
|
} else { // a transient shall appear on its leader and not drag that around
|
|
|
|
if (info->desktop())
|
|
|
|
desk = info->desktop(); // Window had the initial desktop property, force it
|
|
|
|
if (desktop() == 0 && asn_valid && asn_data.desktop() != 0)
|
|
|
|
desk = asn_data.desktop();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2013-04-04 14:14:12 +00:00
|
|
|
#ifdef KWIN_BUILD_ACTIVITIES
|
2015-07-07 09:48:42 +00:00
|
|
|
if (Activities::self() && !isMapped && !noborder && isNormalWindow() && !activitiesDefined) {
|
2010-11-11 23:37:50 +00:00
|
|
|
//a new, regular window, when we're not recovering from a crash,
|
|
|
|
//and it hasn't got an activity. let's try giving it the current one.
|
|
|
|
//TODO: decide whether to keep this before the 4.6 release
|
2010-11-14 10:35:16 +00:00
|
|
|
//TODO: if we are keeping it (at least as an option), replace noborder checking
|
|
|
|
//with a public API for setting windows to be on all activities.
|
|
|
|
//something like KWindowSystem::setOnAllActivities or
|
|
|
|
//KActivityConsumer::setOnAllActivities
|
2013-04-04 14:14:12 +00:00
|
|
|
setOnActivity(Activities::self()->current(), true);
|
2010-11-11 23:37:50 +00:00
|
|
|
}
|
2013-04-04 14:14:12 +00:00
|
|
|
#endif
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-05-17 14:32:06 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (desk == 0) // Assume window wants to be visible on the current desktop
|
2013-01-08 10:04:07 +00:00
|
|
|
desk = isDesktop() ? static_cast<int>(NET::OnAllDesktops) : VirtualDesktopManager::self()->current();
|
2011-01-30 14:34:42 +00:00
|
|
|
desk = rules()->checkDesktop(desk, !isMapped);
|
|
|
|
if (desk != NET::OnAllDesktops) // Do range check
|
2012-11-16 07:23:47 +00:00
|
|
|
desk = qBound(1, desk, static_cast<int>(VirtualDesktopManager::self()->count()));
|
2015-03-13 11:54:11 +00:00
|
|
|
setDesktop(desk);
|
2011-01-30 14:34:42 +00:00
|
|
|
info->setDesktop(desk);
|
|
|
|
workspace()->updateOnAllDesktopsOfTransients(this); // SELI TODO
|
2008-12-18 15:01:25 +00:00
|
|
|
//onAllDesktopsChange(); // Decoration doesn't exist here yet
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2012-05-17 14:32:06 +00:00
|
|
|
QString activitiesList;
|
|
|
|
activitiesList = rules()->checkActivity(activitiesList, !isMapped);
|
|
|
|
if (!activitiesList.isEmpty())
|
2013-07-23 05:02:52 +00:00
|
|
|
setOnActivities(activitiesList.split(QStringLiteral(",")));
|
2012-05-17 14:32:06 +00:00
|
|
|
|
2014-04-25 11:42:52 +00:00
|
|
|
QRect geom(windowGeometry.rect());
|
2007-04-29 17:35:43 +00:00
|
|
|
bool placementDone = false;
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session)
|
2007-04-29 17:35:43 +00:00
|
|
|
geom = session->geometry;
|
|
|
|
|
|
|
|
QRect area;
|
|
|
|
bool partial_keep_in_area = isMapped || session;
|
2015-02-06 15:27:42 +00:00
|
|
|
if (isMapped || session) {
|
2011-01-30 14:34:42 +00:00
|
|
|
area = workspace()->clientArea(FullArea, geom.center(), desktop());
|
2015-02-06 15:27:42 +00:00
|
|
|
checkOffscreenPosition(&geom, area);
|
|
|
|
} else {
|
2013-04-03 10:19:27 +00:00
|
|
|
int screen = asn_data.xinerama() == -1 ? screens()->current() : asn_data.xinerama();
|
2012-08-24 16:48:50 +00:00
|
|
|
screen = rules()->checkScreen(screen, !isMapped);
|
2013-04-03 10:19:27 +00:00
|
|
|
area = workspace()->clientArea(PlacementArea, screens()->geometry(screen).center(), desktop());
|
2012-01-22 10:04:55 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isDesktop())
|
2008-12-18 15:01:25 +00:00
|
|
|
// KWin doesn't manage desktop windows
|
2008-05-02 16:39:49 +00:00
|
|
|
placementDone = true;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
bool usePosition = false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isMapped || session || placementDone)
|
2008-12-18 15:01:25 +00:00
|
|
|
placementDone = true; // Use geometry
|
2011-01-30 14:34:42 +00:00
|
|
|
else if (isTransient() && !isUtility() && !isDialog() && !isSplash())
|
2007-04-29 17:35:43 +00:00
|
|
|
usePosition = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
else if (isTransient() && !hasNETSupport())
|
2007-04-29 17:35:43 +00:00
|
|
|
usePosition = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
else if (isDialog() && hasNETSupport()) {
|
|
|
|
// If the dialog is actually non-NETWM transient window, don't try to apply placement to it,
|
|
|
|
// it breaks with too many things (xmms, display)
|
|
|
|
if (mainClients().count() >= 1) {
|
2007-04-29 17:35:43 +00:00
|
|
|
#if 1
|
2007-07-19 16:38:46 +00:00
|
|
|
// #78082 - Ok, it seems there are after all some cases when an application has a good
|
2007-04-29 17:35:43 +00:00
|
|
|
// reason to specify a position for its dialog. Too bad other WMs have never bothered
|
|
|
|
// with placement for dialogs, so apps always specify positions for their dialogs,
|
|
|
|
// including such silly positions like always centered on the screen or under mouse.
|
2007-07-19 16:38:46 +00:00
|
|
|
// Using ignoring requested position in window-specific settings helps, and now
|
|
|
|
// there's also _NET_WM_FULL_PLACEMENT.
|
2007-04-29 17:35:43 +00:00
|
|
|
usePosition = true;
|
|
|
|
#else
|
2008-12-18 15:01:25 +00:00
|
|
|
; // Force using placement policy
|
2007-04-29 17:35:43 +00:00
|
|
|
#endif
|
2011-01-30 14:34:42 +00:00
|
|
|
} else
|
2007-04-29 17:35:43 +00:00
|
|
|
usePosition = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else if (isSplash())
|
2008-12-18 15:01:25 +00:00
|
|
|
; // Force using placement policy
|
2007-04-29 17:35:43 +00:00
|
|
|
else
|
|
|
|
usePosition = true;
|
2013-03-24 18:13:00 +00:00
|
|
|
if (!rules()->checkIgnoreGeometry(!usePosition, true)) {
|
2015-01-21 15:05:29 +00:00
|
|
|
if (m_geometryHints.hasPosition()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
placementDone = true;
|
2008-12-18 15:01:25 +00:00
|
|
|
// Disobey xinerama placement option for now (#70943)
|
2011-01-30 14:34:42 +00:00
|
|
|
area = workspace()->clientArea(PlacementArea, geom.center(), desktop());
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isMovable() && (geom.x() > area.right() || geom.y() > area.bottom()))
|
2008-12-18 15:01:25 +00:00
|
|
|
placementDone = false; // Weird, do not trust.
|
2007-04-29 17:35:43 +00:00
|
|
|
|
[x11] Add support for _GTK_FRAME_EXTENTS
Summary:
KDE is known for having a strong view on the client-side decorations vs
server-side decorations issue. The main argument raised against CSD is
that desktop will look less consistent when clients start drawing window
decorations by themselves, which is somewhat true. It all ties to how
well each toolkit is integrated with the desktop environment.
KDE doesn't control the desktop market on Linux. Another big "player"
is GNOME. Both KDE and GNOME have very polarized views on in which
direction desktop should move forward. The KDE community is pushing more
toward server-side decorations while the GNOME community is pushing
more toward client-side decorations. Both communities have developed
great applications and it's not rare to see a GNOME application being
used in KDE Plasma. The only problem is that these different views are
not left behind the curtain and our users pay the price. Resizing GTK
clients in Plasma became practically impossible due to resize borders
having small hit area.
When a client draws its window decoration, it's more likely that it also
draws the drop-shadow around the decoration. The compositor must know
the extents of the shadow so things like snapping and so on work as
expected. And here lies the problem... While the xdg-shell protocol has
a way to specify such things, the NetWM spec doesn't have anything like
that. There's _GTK_FRAME_EXTENTS in the wild, however the problem with
it is that it's a proprietary atom, which is specific only to GTK apps.
Due to that, _GTK_FRAME_EXTENTS wasn't implemented because implementing
anything like that would require major changes in how we think about
geometry.
Recent xdg-shell window geometry patches adjusted geometry abstractions
in kwin to such a degree that it's very easy to add support for client
side decorated clients on X11. We just have to make sure that the
X11Client class provides correct buffer geometry and frame geometry when
the gtk frame extents are set.
Even though the X11 code is feature frozen, I still think it's worth
to have _GTK_FRAME_EXTENTS support in kwin because it will fix the resize
issues. Also, because KWin/Wayland is unfortunately far from becoming
default, it will help us with testing some implementation bits of the
window geometry from xdg-shell.
BUG: 390550
FIXED-IN: 5.18.0
Test Plan:
Things like quick tiling, maximizing, tiling scripts and so on work as
expected with GTK clients.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: cblack, trmdi, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D24660
2019-10-08 08:46:59 +00:00
|
|
|
if (placementDone) {
|
|
|
|
QPoint position = geom.topLeft();
|
|
|
|
// Session contains the position of the frame geometry before gravitating.
|
|
|
|
if (!session) {
|
|
|
|
position = clientPosToFramePos(position);
|
|
|
|
}
|
|
|
|
move(position);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2009-11-15 03:24:04 +00:00
|
|
|
// Create client group if the window will have a decoration
|
2009-11-16 13:31:02 +00:00
|
|
|
bool dontKeepInArea = false;
|
2015-03-31 13:26:42 +00:00
|
|
|
readColorScheme(colorSchemeCookie);
|
|
|
|
|
2017-01-11 09:21:03 +00:00
|
|
|
readApplicationMenuServiceName(applicationMenuServiceNameCookie);
|
|
|
|
readApplicationMenuObjectPath(applicationMenuObjectPathCookie);
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
updateDecoration(false); // Also gravitates
|
2008-12-18 15:01:25 +00:00
|
|
|
// TODO: Is CentralGravity right here, when resizing is done after gravitating?
|
2011-01-30 14:34:42 +00:00
|
|
|
plainResize(rules()->checkSize(sizeForClientSize(geom.size()), !isMapped));
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QPoint forced_pos = rules()->checkPosition(invalidPoint, !isMapped);
|
|
|
|
if (forced_pos != invalidPoint) {
|
|
|
|
move(forced_pos);
|
2007-04-29 17:35:43 +00:00
|
|
|
placementDone = true;
|
2008-12-18 15:01:25 +00:00
|
|
|
// Don't keep inside workarea if the window has specially configured position
|
2007-04-29 17:35:43 +00:00
|
|
|
partial_keep_in_area = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
area = workspace()->clientArea(FullArea, geom.center(), desktop());
|
|
|
|
}
|
|
|
|
if (!placementDone) {
|
|
|
|
// Placement needs to be after setting size
|
2012-11-22 12:33:23 +00:00
|
|
|
Placement::self()->place(this, area);
|
2019-09-12 14:52:47 +00:00
|
|
|
// The client may have been moved to another screen, update placement area.
|
|
|
|
area = workspace()->clientArea(PlacementArea, this);
|
2013-08-15 09:53:02 +00:00
|
|
|
dontKeepInArea = true;
|
2007-04-29 17:35:43 +00:00
|
|
|
placementDone = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-11-12 20:39:06 +00:00
|
|
|
// bugs #285967, #286146, #183694
|
|
|
|
// geometry() now includes the requested size and the decoration and is at the correct screen/position (hopefully)
|
|
|
|
// Maximization for oversized windows must happen NOW.
|
|
|
|
// If we effectively pass keepInArea(), the window will resizeWithChecks() - i.e. constrained
|
|
|
|
// to the combo of all screen MINUS all struts on the edges
|
|
|
|
// If only one screen struts, this will affect screens as a side-effect, the window is artificailly shrinked
|
|
|
|
// below the screen size and as result no more maximized what breaks KMainWindow's stupid width+1, height+1 hack
|
|
|
|
// TODO: get KMainWindow a correct state storage what will allow to store the restore size as well.
|
|
|
|
|
|
|
|
if (!session) { // has a better handling of this
|
2019-09-27 10:01:10 +00:00
|
|
|
geom_restore = frameGeometry(); // Remember restore geometry
|
2011-11-12 20:39:06 +00:00
|
|
|
if (isMaximizable() && (width() >= area.width() || height() >= area.height())) {
|
|
|
|
// Window is too large for the screen, maximize in the
|
|
|
|
// directions necessary
|
2013-02-01 18:44:06 +00:00
|
|
|
const QSize ss = workspace()->clientArea(ScreenArea, area.center(), desktop()).size();
|
2014-05-29 20:40:05 +00:00
|
|
|
const QRect fsa = workspace()->clientArea(FullArea, geom.center(), desktop());
|
2013-02-01 18:44:06 +00:00
|
|
|
const QSize cs = clientSize();
|
2015-09-03 18:45:36 +00:00
|
|
|
int pseudo_max = ((info->state() & NET::MaxVert) ? MaximizeVertical : 0) |
|
|
|
|
((info->state() & NET::MaxHoriz) ? MaximizeHorizontal : 0);
|
2013-02-01 18:44:06 +00:00
|
|
|
if (width() >= area.width())
|
2014-12-02 12:49:08 +00:00
|
|
|
pseudo_max |= MaximizeHorizontal;
|
2013-02-01 18:44:06 +00:00
|
|
|
if (height() >= area.height())
|
2014-12-02 12:49:08 +00:00
|
|
|
pseudo_max |= MaximizeVertical;
|
2013-02-01 18:44:06 +00:00
|
|
|
|
|
|
|
// heuristics:
|
|
|
|
// if decorated client is smaller than the entire screen, the user might want to move it around (multiscreen)
|
|
|
|
// in this case, if the decorated client is bigger than the screen (+1), we don't take this as an
|
|
|
|
// attempt for maximization, but just constrain the size (the window simply wants to be bigger)
|
|
|
|
// NOTICE
|
|
|
|
// i intended a second check on cs < area.size() ("the managed client ("minus border") is smaller
|
|
|
|
// than the workspace") but gtk / gimp seems to store it's size including the decoration,
|
|
|
|
// thus a former maximized window wil become non-maximized
|
2014-05-29 20:40:05 +00:00
|
|
|
bool keepInFsArea = false;
|
|
|
|
if (width() < fsa.width() && (cs.width() > ss.width()+1)) {
|
2014-12-02 12:49:08 +00:00
|
|
|
pseudo_max &= ~MaximizeHorizontal;
|
2014-05-29 20:40:05 +00:00
|
|
|
keepInFsArea = true;
|
|
|
|
}
|
|
|
|
if (height() < fsa.height() && (cs.height() > ss.height()+1)) {
|
2014-12-02 12:49:08 +00:00
|
|
|
pseudo_max &= ~MaximizeVertical;
|
2014-05-29 20:40:05 +00:00
|
|
|
keepInFsArea = true;
|
|
|
|
}
|
2013-02-01 18:44:06 +00:00
|
|
|
|
2014-12-02 12:49:08 +00:00
|
|
|
if (pseudo_max != MaximizeRestore) {
|
2013-02-01 18:44:06 +00:00
|
|
|
maximize((MaximizeMode)pseudo_max);
|
|
|
|
// from now on, care about maxmode, since the maximization call will override mode for fix aspects
|
2014-12-02 12:49:08 +00:00
|
|
|
dontKeepInArea |= (max_mode == MaximizeFull);
|
2013-02-01 18:44:06 +00:00
|
|
|
geom_restore = QRect(); // Use placement when unmaximizing ...
|
2014-12-02 12:49:08 +00:00
|
|
|
if (!(max_mode & MaximizeVertical)) {
|
2013-02-01 18:44:06 +00:00
|
|
|
geom_restore.setY(y()); // ...but only for horizontal direction
|
|
|
|
geom_restore.setHeight(height());
|
|
|
|
}
|
2014-12-02 12:49:08 +00:00
|
|
|
if (!(max_mode & MaximizeHorizontal)) {
|
2013-02-01 18:44:06 +00:00
|
|
|
geom_restore.setX(x()); // ...but only for vertical direction
|
|
|
|
geom_restore.setWidth(width());
|
|
|
|
}
|
2011-11-12 20:39:06 +00:00
|
|
|
}
|
2014-05-29 20:40:05 +00:00
|
|
|
if (keepInFsArea)
|
|
|
|
keepInArea(fsa, partial_keep_in_area);
|
2011-11-12 20:39:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if ((!isSpecialWindow() || isToolbar()) && isMovable() && !dontKeepInArea)
|
|
|
|
keepInArea(area, partial_keep_in_area);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2007-12-17 16:30:36 +00:00
|
|
|
updateShape();
|
2008-12-18 15:01:25 +00:00
|
|
|
|
|
|
|
// CT: Extra check for stupid jdk 1.3.1. But should make sense in general
|
2007-04-29 17:35:43 +00:00
|
|
|
// if client has initial state set to Iconic and is transient with a parent
|
|
|
|
// window that is not Iconic, set init_state to Normal
|
2011-01-30 14:34:42 +00:00
|
|
|
if (init_minimize && isTransient()) {
|
2015-09-11 13:55:23 +00:00
|
|
|
auto mainclients = mainClients();
|
|
|
|
for (auto it = mainclients.constBegin();
|
2011-01-30 14:34:42 +00:00
|
|
|
it != mainclients.constEnd();
|
|
|
|
++it)
|
|
|
|
if ((*it)->isShown(true))
|
2008-12-18 15:01:25 +00:00
|
|
|
init_minimize = false; // SELI TODO: Even e.g. for NET::Utility?
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-12-18 15:01:25 +00:00
|
|
|
// If a dialog is shown for minimized window, minimize it too
|
2019-10-31 16:16:53 +00:00
|
|
|
if (!init_minimize && isTransient() && mainClients().count() > 0 &&
|
|
|
|
workspace()->sessionManager()->state() != SessionState::Saving) {
|
2008-03-18 14:56:57 +00:00
|
|
|
bool visible_parent = false;
|
2008-12-18 15:01:25 +00:00
|
|
|
// Use allMainClients(), to include also main clients of group transients
|
2019-09-24 08:48:08 +00:00
|
|
|
// that have been optimized out in X11Client::checkGroupTransients()
|
2015-09-11 13:55:23 +00:00
|
|
|
auto mainclients = allMainClients();
|
|
|
|
for (auto it = mainclients.constBegin();
|
2011-01-30 14:34:42 +00:00
|
|
|
it != mainclients.constEnd();
|
|
|
|
++it)
|
|
|
|
if ((*it)->isShown(true))
|
2008-03-18 14:56:57 +00:00
|
|
|
visible_parent = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!visible_parent) {
|
2008-03-18 14:56:57 +00:00
|
|
|
init_minimize = true;
|
|
|
|
demandAttention();
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (init_minimize)
|
|
|
|
minimize(true); // No animation
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// Other settings from the previous session
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session) {
|
2008-12-18 15:01:25 +00:00
|
|
|
// Session restored windows are not considered to be new windows WRT rules,
|
|
|
|
// I.e. obey only forcing rules
|
2011-01-30 14:34:42 +00:00
|
|
|
setKeepAbove(session->keepAbove);
|
|
|
|
setKeepBelow(session->keepBelow);
|
2015-06-06 20:08:12 +00:00
|
|
|
setOriginalSkipTaskbar(session->skipTaskbar);
|
2011-01-30 14:34:42 +00:00
|
|
|
setSkipPager(session->skipPager);
|
|
|
|
setSkipSwitcher(session->skipSwitcher);
|
|
|
|
setShade(session->shaded ? ShadeNormal : ShadeNone);
|
|
|
|
setOpacity(session->opacity);
|
2012-04-11 16:18:50 +00:00
|
|
|
geom_restore = session->restore;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session->maximized != MaximizeRestore) {
|
|
|
|
maximize(MaximizeMode(session->maximized));
|
|
|
|
}
|
2019-01-10 15:01:42 +00:00
|
|
|
if (session->fullscreen != FullScreenNone) {
|
2011-01-30 14:34:42 +00:00
|
|
|
setFullScreen(true, false);
|
2007-04-29 17:35:43 +00:00
|
|
|
geom_fs_restore = session->fsrestore;
|
|
|
|
}
|
2015-02-06 15:27:42 +00:00
|
|
|
checkOffscreenPosition(&geom_restore, area);
|
|
|
|
checkOffscreenPosition(&geom_fs_restore, area);
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2008-12-18 15:01:25 +00:00
|
|
|
// Window may want to be maximized
|
2007-04-29 17:35:43 +00:00
|
|
|
// done after checking that the window isn't larger than the workarea, so that
|
|
|
|
// the restore geometry from the checks above takes precedence, and window
|
|
|
|
// isn't restored larger than the workarea
|
2008-12-18 15:01:25 +00:00
|
|
|
MaximizeMode maxmode = static_cast<MaximizeMode>(
|
2011-01-30 14:34:42 +00:00
|
|
|
((info->state() & NET::MaxVert) ? MaximizeVertical : 0) |
|
|
|
|
((info->state() & NET::MaxHoriz) ? MaximizeHorizontal : 0));
|
|
|
|
MaximizeMode forced_maxmode = rules()->checkMaximize(maxmode, !isMapped);
|
2008-12-18 15:01:25 +00:00
|
|
|
|
|
|
|
// Either hints were set to maximize, or is forced to maximize,
|
2007-04-29 17:35:43 +00:00
|
|
|
// or is forced to non-maximize and hints were set to maximize
|
2011-01-30 14:34:42 +00:00
|
|
|
if (forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore)
|
|
|
|
maximize(forced_maxmode);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// Read other initial states
|
2011-01-30 14:34:42 +00:00
|
|
|
setShade(rules()->checkShade(info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped));
|
|
|
|
setKeepAbove(rules()->checkKeepAbove(info->state() & NET::KeepAbove, !isMapped));
|
|
|
|
setKeepBelow(rules()->checkKeepBelow(info->state() & NET::KeepBelow, !isMapped));
|
2015-06-06 20:08:12 +00:00
|
|
|
setOriginalSkipTaskbar(rules()->checkSkipTaskbar(info->state() & NET::SkipTaskbar, !isMapped));
|
2011-01-30 14:34:42 +00:00
|
|
|
setSkipPager(rules()->checkSkipPager(info->state() & NET::SkipPager, !isMapped));
|
2018-05-24 04:33:39 +00:00
|
|
|
setSkipSwitcher(rules()->checkSkipSwitcher(info->state() & NET::SkipSwitcher, !isMapped));
|
2011-01-30 14:34:42 +00:00
|
|
|
if (info->state() & NET::DemandsAttention)
|
2007-04-29 17:35:43 +00:00
|
|
|
demandAttention();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (info->state() & NET::Modal)
|
|
|
|
setModal(true);
|
2019-01-10 15:01:42 +00:00
|
|
|
|
|
|
|
setFullScreen(rules()->checkFullScreen(info->state() & NET::FullScreen, !isMapped), false);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
updateAllowedActions(true);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// Set initial user time directly
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
m_userTime = readUserTimeMapTimestamp(asn_valid ? &asn_id : nullptr, asn_valid ? &asn_data : nullptr, session);
|
2019-09-24 08:48:08 +00:00
|
|
|
group()->updateUserTime(m_userTime); // And do what X11Client::updateUserTime() does
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// This should avoid flicker, because real restacking is done
|
2007-04-29 17:35:43 +00:00
|
|
|
// only after manage() finishes because of blocking, but the window is shown sooner
|
2013-09-10 07:11:19 +00:00
|
|
|
m_frame.lower();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session && session->stackingOrder != -1) {
|
2007-04-29 17:35:43 +00:00
|
|
|
sm_stacking_order = session->stackingOrder;
|
2011-01-30 14:34:42 +00:00
|
|
|
workspace()->restoreSessionStackingOrder(this);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (compositing())
|
2008-12-18 15:01:25 +00:00
|
|
|
// Sending ConfigureNotify is done when setting mapping state below,
|
|
|
|
// Getting the first sync response means window is ready for compositing
|
|
|
|
sendSyncRequest();
|
2011-08-13 14:39:58 +00:00
|
|
|
else
|
|
|
|
ready_for_painting = true; // set to true in case compositing is turned on later. bug #160393
|
2007-06-25 08:51:44 +00:00
|
|
|
|
2013-03-01 07:49:04 +00:00
|
|
|
if (isShown(true)) {
|
2007-04-29 17:35:43 +00:00
|
|
|
bool allow;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (session)
|
2008-12-18 15:01:25 +00:00
|
|
|
allow = session->active &&
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
(!workspace()->wasUserInteraction() || workspace()->activeClient() == nullptr ||
|
2011-01-30 14:34:42 +00:00
|
|
|
workspace()->activeClient()->isDesktop());
|
2007-04-29 17:35:43 +00:00
|
|
|
else
|
2011-01-30 14:34:42 +00:00
|
|
|
allow = workspace()->allowClientActivation(this, userTime(), false);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-10-31 16:16:53 +00:00
|
|
|
const bool isSessionSaving = workspace()->sessionManager()->state() == SessionState::Saving;
|
|
|
|
|
2017-04-27 09:40:35 +00:00
|
|
|
// If session saving, force showing new windows (i.e. "save file?" dialogs etc.)
|
|
|
|
// also force if activation is allowed
|
2019-10-31 16:16:53 +00:00
|
|
|
if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || isSessionSaving ))
|
2017-04-27 09:40:35 +00:00
|
|
|
VirtualDesktopManager::self()->setCurrent( desktop());
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2017-04-27 10:18:41 +00:00
|
|
|
// If the window is on an inactive activity during session saving, temporarily force it to show.
|
2019-10-31 16:16:53 +00:00
|
|
|
if( !isMapped && !session && isSessionSaving && !isOnCurrentActivity()) {
|
2017-04-27 10:18:41 +00:00
|
|
|
setSessionActivityOverride( true );
|
|
|
|
foreach( AbstractClient* c, mainClients()) {
|
2019-09-24 08:48:08 +00:00
|
|
|
if (X11Client *mc = dynamic_cast<X11Client *>(c)) {
|
2017-04-27 10:18:41 +00:00
|
|
|
mc->setSessionActivityOverride(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isOnCurrentDesktop() && !isMapped && !allow && (!session || session->stackingOrder < 0))
|
|
|
|
workspace()->restackClientUnderActive(this);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
updateVisibility();
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!isMapped) {
|
|
|
|
if (allow && isOnCurrentDesktop()) {
|
|
|
|
if (!isSpecialWindow())
|
|
|
|
if (options->focusPolicyIsReasonable() && wantsTabFocus())
|
|
|
|
workspace()->requestFocus(this);
|
|
|
|
} else if (!session && !isSpecialWindow())
|
2008-12-18 15:01:25 +00:00
|
|
|
demandAttention();
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2013-03-01 07:49:04 +00:00
|
|
|
} else
|
2007-04-29 17:35:43 +00:00
|
|
|
updateVisibility();
|
2019-08-31 14:28:37 +00:00
|
|
|
Q_ASSERT(mapping_state != Withdrawn);
|
2012-06-19 21:12:37 +00:00
|
|
|
m_managed = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
blockGeometryUpdates(false);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-05-03 09:29:50 +00:00
|
|
|
if (m_userTime == XCB_TIME_CURRENT_TIME || m_userTime == -1U) {
|
2011-01-30 14:34:42 +00:00
|
|
|
// No known user time, set something old
|
2013-05-03 09:29:50 +00:00
|
|
|
m_userTime = xTime() - 1000000;
|
|
|
|
if (m_userTime == XCB_TIME_CURRENT_TIME || m_userTime == -1U) // Let's be paranoid
|
|
|
|
m_userTime = xTime() - 1000000 + 10;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
//sendSyntheticConfigureNotify(); // Done when setting mapping state
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
delete session;
|
2008-12-18 15:01:25 +00:00
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
discardTemporaryRules();
|
2008-12-18 15:01:25 +00:00
|
|
|
applyWindowRules(); // Just in case
|
2013-04-26 12:40:35 +00:00
|
|
|
RuleBook::self()->discardUsed(this, false); // Remove ApplyNow rules
|
2012-02-05 17:50:23 +00:00
|
|
|
updateWindowRules(Rules::All); // Was blocked while !isManaged()
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2014-04-14 13:32:45 +00:00
|
|
|
setBlockingCompositing(info->isBlockingCompositing());
|
2015-01-15 14:51:21 +00:00
|
|
|
readShowOnScreenEdge(showOnScreenEdgeCookie);
|
2011-03-20 14:42:05 +00:00
|
|
|
|
2019-03-19 10:02:45 +00:00
|
|
|
// Forward all opacity values to the frame in case there'll be other CM running.
|
|
|
|
connect(Compositor::self(), &Compositor::compositingToggled, this,
|
|
|
|
[this](bool active) {
|
|
|
|
if (active) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (opacity() == 1.0) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-19 15:16:14 +00:00
|
|
|
NETWinInfo info(connection(), frameId(), rootWindow(), NET::Properties(), NET::Properties2());
|
2019-03-19 10:02:45 +00:00
|
|
|
info.setOpacity(static_cast<unsigned long>(opacity() * 0xffffffff));
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// TODO: there's a small problem here - isManaged() depends on the mapping state,
|
|
|
|
// but this client is not yet in Workspace's client list at this point, will
|
|
|
|
// be only done in addClient()
|
2012-01-21 09:51:22 +00:00
|
|
|
emit clientManaging(this);
|
2007-04-29 17:35:43 +00:00
|
|
|
return true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-12-18 15:01:25 +00:00
|
|
|
// Called only from manage()
|
2019-09-24 08:48:08 +00:00
|
|
|
void X11Client::embedClient(xcb_window_t w, xcb_visualid_t visualid, xcb_colormap_t colormap, uint8_t depth)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-08-31 14:28:37 +00:00
|
|
|
Q_ASSERT(m_client == XCB_WINDOW_NONE);
|
|
|
|
Q_ASSERT(frameId() == XCB_WINDOW_NONE);
|
|
|
|
Q_ASSERT(m_wrapper == XCB_WINDOW_NONE);
|
2013-09-10 05:27:39 +00:00
|
|
|
m_client.reset(w, false);
|
2008-12-18 15:01:25 +00:00
|
|
|
|
2012-03-28 14:50:44 +00:00
|
|
|
const uint32_t zero_value = 0;
|
|
|
|
|
|
|
|
xcb_connection_t *conn = connection();
|
|
|
|
|
|
|
|
// We don't want the window to be destroyed when we quit
|
2013-05-02 16:43:49 +00:00
|
|
|
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, m_client);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
2013-09-10 05:38:21 +00:00
|
|
|
m_client.selectInput(zero_value);
|
|
|
|
m_client.unmap();
|
2013-09-10 07:51:31 +00:00
|
|
|
m_client.setBorderWidth(zero_value);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
|
|
|
// Note: These values must match the order in the xcb_cw_t enum
|
|
|
|
const uint32_t cw_values[] = {
|
|
|
|
0, // back_pixmap
|
|
|
|
0, // border_pixel
|
2014-04-25 11:42:52 +00:00
|
|
|
colormap, // colormap
|
2013-02-19 10:25:46 +00:00
|
|
|
Cursor::x11Cursor(Qt::ArrowCursor)
|
2012-03-28 14:50:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const uint32_t cw_mask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
|
|
|
|
XCB_CW_COLORMAP | XCB_CW_CURSOR;
|
|
|
|
|
|
|
|
const uint32_t common_event_mask = XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
|
|
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
|
|
|
|
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
|
|
|
|
XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION |
|
|
|
|
XCB_EVENT_MASK_KEYMAP_STATE |
|
|
|
|
XCB_EVENT_MASK_FOCUS_CHANGE |
|
|
|
|
XCB_EVENT_MASK_EXPOSURE |
|
|
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
|
|
|
|
|
2014-07-22 11:11:19 +00:00
|
|
|
const uint32_t frame_event_mask = common_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_VISIBILITY_CHANGE;
|
2012-03-28 14:50:44 +00:00
|
|
|
const uint32_t wrapper_event_mask = common_event_mask | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
|
|
|
|
|
|
|
|
const uint32_t client_event_mask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE |
|
|
|
|
XCB_EVENT_MASK_COLOR_MAP_CHANGE |
|
|
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
|
|
|
|
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE;
|
|
|
|
|
|
|
|
// Create the frame window
|
|
|
|
xcb_window_t frame = xcb_generate_id(conn);
|
2014-04-25 11:42:52 +00:00
|
|
|
xcb_create_window(conn, depth, frame, rootWindow(), 0, 0, 1, 1, 0,
|
2012-03-28 14:50:44 +00:00
|
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, visualid, cw_mask, cw_values);
|
2013-09-10 06:13:33 +00:00
|
|
|
m_frame.reset(frame);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
2013-09-10 06:13:33 +00:00
|
|
|
setWindowHandles(m_client);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
|
|
|
// Create the wrapper window
|
2013-05-02 16:26:05 +00:00
|
|
|
xcb_window_t wrapperId = xcb_generate_id(conn);
|
2014-04-25 11:42:52 +00:00
|
|
|
xcb_create_window(conn, depth, wrapperId, frame, 0, 0, 1, 1, 0,
|
2012-03-28 14:50:44 +00:00
|
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, visualid, cw_mask, cw_values);
|
2013-05-02 16:26:05 +00:00
|
|
|
m_wrapper.reset(wrapperId);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
2013-09-10 07:20:12 +00:00
|
|
|
m_client.reparent(m_wrapper);
|
2012-03-28 14:50:44 +00:00
|
|
|
|
|
|
|
// We could specify the event masks when we create the windows, but the original
|
|
|
|
// Xlib code didn't. Let's preserve that behavior here for now so we don't end up
|
|
|
|
// receiving any unexpected events from the wrapper creation or the reparenting.
|
2013-09-10 07:22:36 +00:00
|
|
|
m_frame.selectInput(frame_event_mask);
|
|
|
|
m_wrapper.selectInput(wrapper_event_mask);
|
2013-09-10 05:38:21 +00:00
|
|
|
m_client.selectInput(client_event_mask);
|
2008-12-18 15:01:25 +00:00
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
updateMouseGrab();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
} // namespace
|