14#if KWIN_BUILD_ACTIVITIES
37#include <KDecoration2/DecoratedClient>
38#include <KDecoration2/Decoration>
40#include <KLocalizedString>
41#include <KStartupInfo>
44#include <QApplication>
53#include <xcb/xcb_icccm.h>
66static uint32_t frameEventMask()
69 return XCB_EVENT_MASK_FOCUS_CHANGE
70 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
71 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
72 | XCB_EVENT_MASK_PROPERTY_CHANGE;
74 return XCB_EVENT_MASK_FOCUS_CHANGE
75 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
76 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
77 | XCB_EVENT_MASK_PROPERTY_CHANGE
78 | XCB_EVENT_MASK_KEY_PRESS
79 | XCB_EVENT_MASK_KEY_RELEASE
80 | XCB_EVENT_MASK_ENTER_WINDOW
81 | XCB_EVENT_MASK_LEAVE_WINDOW
82 | XCB_EVENT_MASK_BUTTON_PRESS
83 | XCB_EVENT_MASK_BUTTON_RELEASE
84 | XCB_EVENT_MASK_BUTTON_MOTION
85 | XCB_EVENT_MASK_POINTER_MOTION
86 | XCB_EVENT_MASK_KEYMAP_STATE
87 | XCB_EVENT_MASK_EXPOSURE
88 | XCB_EVENT_MASK_VISIBILITY_CHANGE;
92static uint32_t wrapperEventMask()
95 return XCB_EVENT_MASK_FOCUS_CHANGE
96 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
97 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
98 | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
100 return XCB_EVENT_MASK_FOCUS_CHANGE
101 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
102 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
103 | XCB_EVENT_MASK_KEY_PRESS
104 | XCB_EVENT_MASK_KEY_RELEASE
105 | XCB_EVENT_MASK_ENTER_WINDOW
106 | XCB_EVENT_MASK_LEAVE_WINDOW
107 | XCB_EVENT_MASK_BUTTON_PRESS
108 | XCB_EVENT_MASK_BUTTON_RELEASE
109 | XCB_EVENT_MASK_BUTTON_MOTION
110 | XCB_EVENT_MASK_POINTER_MOTION
111 | XCB_EVENT_MASK_KEYMAP_STATE
112 | XCB_EVENT_MASK_EXPOSURE
113 | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
117static uint32_t clientEventMask()
120 return XCB_EVENT_MASK_FOCUS_CHANGE
121 | XCB_EVENT_MASK_PROPERTY_CHANGE;
123 return XCB_EVENT_MASK_FOCUS_CHANGE
124 | XCB_EVENT_MASK_PROPERTY_CHANGE
125 | XCB_EVENT_MASK_ENTER_WINDOW
126 | XCB_EVENT_MASK_LEAVE_WINDOW
127 | XCB_EVENT_MASK_KEY_PRESS
128 | XCB_EVENT_MASK_KEY_RELEASE;
143 | NET::NotificationMask
144 | NET::OnScreenDisplayMask
145 | NET::CriticalNotificationMask
146 | NET::AppletPopupMask;
159 | NET::DropdownMenuMask
162 | NET::NotificationMask
165 | NET::OnScreenDisplayMask
166 | NET::CriticalNotificationMask;
170 , m_scheduleTimer(new QTimer(this))
174 m_scheduleTimer->setSingleShot(
true);
175 m_scheduleTimer->setInterval(0);
176 connect(m_scheduleTimer, &QTimer::timeout,
this, &X11DecorationRenderer::update);
182 if (m_gc != XCB_NONE) {
183 xcb_free_gc(kwinApp()->x11Connection(), m_gc);
187void X11DecorationRenderer::update()
189 if (!
damage().isEmpty()) {
200 xcb_connection_t *c = kwinApp()->x11Connection();
203 if (m_gc == XCB_NONE) {
204 m_gc = xcb_generate_id(c);
205 xcb_create_gc(c, m_gc, window->
frameId(), 0,
nullptr);
208 QRectF left, top, right, bottom;
211 const QRect geometry = region.boundingRect();
212 left = left.intersected(geometry);
213 top = top.intersected(geometry);
214 right = right.intersected(geometry);
215 bottom = bottom.intersected(geometry);
217 auto renderPart = [
this, c, window](
const QRect &geo) {
218 if (!geo.isValid()) {
224 const int depth = window->
depth();
227 format = QImage::Format_A2RGB30_Premultiplied;
231 format = QImage::Format_ARGB32_Premultiplied;
234 qCCritical(KWIN_CORE) <<
"Unsupported client depth" << depth;
235 format = QImage::Format_ARGB32_Premultiplied;
239 QImage image(geo.width(), geo.height(),
format);
240 image.fill(Qt::transparent);
242 p.setRenderHint(QPainter::Antialiasing);
247 xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, window->
frameId(), m_gc,
248 image.width(), image.height(), geo.x(), geo.y(), 0, window->
depth(),
249 image.sizeInBytes(), image.constBits());
251 renderPart(left.toRect());
252 renderPart(top.toRect());
253 renderPart(right.toRect());
254 renderPart(bottom.toRect());
282 , m_activityUpdatesBlocked(false)
283 , m_blockedActivityUpdatesRequireTransients(false)
284 , m_moveResizeGrabWindow()
285 , move_resize_has_keyboard_grab(false)
287 , m_transientForId(XCB_WINDOW_NONE)
288 , m_originalTransientForId(XCB_WINDOW_NONE)
289 , shade_below(nullptr)
290 , m_motif(
atoms->motif_wm_hints)
291 , blocks_compositing(false)
293 , ping_timer(nullptr)
294 , m_pingTimestamp(XCB_TIME_CURRENT_TIME)
295 , m_userTime(XCB_TIME_CURRENT_TIME)
297 , shade_geometry_change(false)
298 , sm_stacking_order(-1)
299 , activitiesDefined(false)
300 , sessionActivityOverride(false)
301 , m_decoInputExtent()
302 , m_focusOutTimer(nullptr)
312 mapping_state = Withdrawn;
316 m_fullscreenMode = FullScreenNone;
318 app_noborder =
false;
319 ignore_focus_stealing =
false;
320 check_active_modal =
false;
333 if (m_decoInputExtent.
isValid()) {
338 xcb_change_active_pointer_grab(kwinApp()->x11Connection(), nativeCursor,
xTime(),
339 XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW);
344 m_releaseTimer.setSingleShot(
true);
345 connect(&m_releaseTimer, &QTimer::timeout,
this, [
this]() {
360 m_killPrompt->quit();
364 Q_ASSERT(!check_active_modal);
369 return std::make_unique<WindowItemX11>(
this, scene);
380 return m_releaseTimer.isActive();
390 item->destroyDamage();
397 m_releaseTimer.stop();
398 if (!findInternalWindow()) {
400 xcb_shape_select_input(kwinApp()->x11Connection(),
window(),
false);
402 Xcb::selectInput(
window(), XCB_EVENT_MASK_NO_EVENT);
413 leaveInteractiveMoveResize();
420 exportMappingState(XCB_ICCCM_WM_STATE_WITHDRAWN);
431 info->setState(NET::States(), info->state());
436 xcb_connection_t *c = kwinApp()->x11Connection();
441 m_client.
reparent(kwinApp()->x11RootWindow(), grav.x(), grav.y());
442 xcb_change_save_set(c, XCB_SET_MODE_DELETE, m_client);
458 if (m_syncRequest.
alarm != XCB_NONE) {
459 xcb_sync_destroy_alarm(kwinApp()->x11Connection(), m_syncRequest.
alarm);
460 m_syncRequest.
alarm = XCB_NONE;
474 item->forgetDamage();
481 m_releaseTimer.stop();
491 leaveInteractiveMoveResize();
507 if (m_syncRequest.
alarm != XCB_NONE) {
508 xcb_sync_destroy_alarm(kwinApp()->x11Connection(), m_syncRequest.
alarm);
509 m_syncRequest.
alarm = XCB_NONE;
519 Xcb::WindowAttributes attr(w);
521 if (attr.isNull() || attr->map_state != XCB_MAP_STATE_VIEWABLE) {
524 if (attr->_class == XCB_WINDOW_CLASS_INPUT_ONLY) {
533 m_frame.
reset(w,
false);
534 m_wrapper.
reset(w,
false);
535 m_client.
reset(w,
false);
537 Xcb::selectInput(w, attr->your_event_mask | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE);
542 m_visual = attr->visual;
543 bit_depth = geo->depth;
544 info =
new NETWinInfo(kwinApp()->x11Connection(), w, kwinApp()->x11RootWindow(),
545 NET::WMWindowType | NET::WMPid,
546 NET::WM2Opacity | NET::WM2WindowRole | NET::WM2WindowClass | NET::WM2OpaqueRegion);
550 getWmClientMachine();
552 xcb_shape_select_input(kwinApp()->x11Connection(), w,
true);
556 getSkipCloseAnimation();
559 if (QWindow *internalWindow = findInternalWindow()) {
560 m_outline = internalWindow->property(
"__kwin_outline").toBool();
566 switch (kwinApp()->operationMode()) {
596 Xcb::WindowAttributes attr(w);
598 if (attr.isNull() || windowGeometry.
isNull()) {
605 embedClient(w, attr->visual, attr->colormap, windowGeometry->depth);
607 m_visual = attr->visual;
608 bit_depth = windowGeometry->depth;
612 const NET::Properties properties =
613 NET::WMDesktop | NET::WMState | NET::WMWindowType | NET::WMStrut | NET::WMName | NET::WMIconGeometry | NET::WMIcon | NET::WMPid | NET::WMIconName;
614 const NET::Properties2 properties2 =
615 NET::WM2BlockCompositing | NET::WM2WindowClass | NET::WM2WindowRole | NET::WM2UserTime | NET::WM2StartupId | NET::WM2ExtendedStrut | NET::WM2Opacity | NET::WM2FullscreenMonitors | NET::WM2GroupLeader | NET::WM2Urgency | NET::WM2Input | NET::WM2Protocols | NET::WM2InitialMappingState | NET::WM2IconPixmap | NET::WM2OpaqueRegion | NET::WM2DesktopFileName | NET::WM2GTKFrameExtents | NET::WM2GTKApplicationId;
617 auto wmClientLeaderCookie = fetchWmClientLeader();
618 auto skipCloseAnimationCookie = fetchSkipCloseAnimation();
619 auto showOnScreenEdgeCookie = fetchShowOnScreenEdge();
621 auto transientCookie = fetchTransient();
622 auto activitiesCookie = fetchActivities();
628 info =
new WinInfo(
this, m_client, kwinApp()->x11RootWindow(), properties, properties2);
636 bool init_minimize = !isMapped && (info->initialMappingState() == NET::Iconic);
639 readWmClientLeader(wmClientLeaderCookie);
640 getWmClientMachine();
642 setCaption(readName());
648 xcb_shape_select_input(kwinApp()->x11Connection(),
window(),
true);
653 setClientFrameExtents(info->gtkFrameExtents());
658 updateAllowedActions();
660 setModal((info->state() & NET::Modal) != 0);
661 readTransientProperty(transientCookie);
670 m_geometryHints.
read();
673 readSkipCloseAnimation(skipCloseAnimationCookie);
684 KStartupInfoId asn_id;
685 KStartupInfoData asn_data;
703 readActivities(activitiesCookie);
706 std::optional<QList<VirtualDesktop *>> initialDesktops;
709 initialDesktops = QList<VirtualDesktop *>{};
713 initialDesktops = QList<VirtualDesktop *>{desktop};
723 bool on_current =
false;
727 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd(); ++it) {
728 if (mainwindows.count() > 1 &&
729 (*it)->isSpecialWindow() &&
730 !(info->state() & NET::Modal)) {
734 if ((*it)->isOnCurrentDesktop()) {
737 if ((*it)->isOnAllDesktops()) {
742 initialDesktops = QList<VirtualDesktop *>{};
743 }
else if (on_current) {
744 initialDesktops = QList<VirtualDesktop *>{VirtualDesktopManager::self()->currentDesktop()};
746 initialDesktops = maincl->
desktops();
754 if (info->desktop()) {
757 if (
desktopId == 0 && asn_valid && asn_data.desktop() != 0) {
762 initialDesktops = QList<VirtualDesktop *>{};
766 initialDesktops = QList<VirtualDesktop *>{desktop};
771#if KWIN_BUILD_ACTIVITIES
787 if (!initialDesktops.has_value()) {
789 initialDesktops = QList<VirtualDesktop *>{};
791 initialDesktops = QList<VirtualDesktop *>{VirtualDesktopManager::self()->currentDesktop()};
799 QStringList activitiesList;
801 if (!activitiesList.isEmpty()) {
805 QRectF geom = session ? session->
geometry : windowGeometry.
rect();
806 bool placementDone =
false;
809 bool partial_keep_in_area = isMapped || session;
810 if (isMapped || session) {
815 if (asn_data.xinerama() != -1) {
827 placementDone =
true;
830 bool usePosition =
false;
831 if (isMapped || session || placementDone) {
832 placementDone =
true;
860 if (!
rules()->checkIgnoreGeometry(!usePosition,
true)) {
862 placementDone =
true;
868 if (
isMovable() && (geom.x() > area.right() || geom.y() > area.bottom())) {
869 placementDone =
false;
873 QPointF position = geom.topLeft();
882 bool dontKeepInArea =
false;
888 updateDecoration(
false);
896 placementDone =
true;
898 partial_keep_in_area =
true;
901 if (!placementDone) {
906 dontKeepInArea =
true;
907 placementDone =
true;
928 if (
width() >= area.width()) {
931 if (
height() >= area.height()) {
943 bool keepInFsArea =
false;
944 if (
width() < fsa.width() && (cs.width() > ss.width() + 1)) {
945 pseudo_max &= ~MaximizeHorizontal;
948 if (
height() < fsa.height() && (cs.height() > ss.height() + 1)) {
949 pseudo_max &= ~MaximizeVertical;
957 QRectF savedGeometry;
959 savedGeometry.setY(
y());
960 savedGeometry.setHeight(
height());
963 savedGeometry.setX(
x());
964 savedGeometry.setWidth(
width());
985 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd(); ++it) {
986 if ((*it)->isShown()) {
987 init_minimize =
false;
993 bool visible_parent =
false;
997 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd(); ++it) {
998 if ((*it)->isShown()) {
999 visible_parent =
true;
1002 if (!visible_parent) {
1003 init_minimize =
true;
1052 setKeepAbove(
rules()->checkKeepAbove(info->state() & NET::KeepAbove, !isMapped));
1053 setKeepBelow(
rules()->checkKeepBelow(info->state() & NET::KeepBelow, !isMapped));
1055 setSkipPager(
rules()->checkSkipPager(info->state() & NET::SkipPager, !isMapped));
1057 if (info->state() & NET::DemandsAttention) {
1060 if (info->state() & NET::Modal) {
1068 updateAllowedActions(
true);
1071 m_userTime = readUserTimeMapTimestamp(asn_valid ? &asn_id :
nullptr, asn_valid ? &asn_data :
nullptr, session);
1103 VirtualDesktopManager::self()->setCurrent(
desktopId());
1110 for (
Window *w : windows) {
1112 mw->setSessionActivityOverride(
true);
1137 Q_ASSERT(mapping_state != Withdrawn);
1141 if (m_userTime == XCB_TIME_CURRENT_TIME || m_userTime == -1U) {
1143 m_userTime =
xTime() - 1000000;
1144 if (m_userTime == XCB_TIME_CURRENT_TIME || m_userTime == -1U) {
1145 m_userTime =
xTime() - 1000000 + 10;
1158 readShowOnScreenEdge(showOnScreenEdgeCookie);
1170 NETWinInfo info(kwinApp()->x11Connection(),
frameId(), kwinApp()->x11RootWindow(), NET::Properties(), NET::Properties2());
1174 switch (kwinApp()->operationMode()) {
1194void X11Window::embedClient(xcb_window_t w, xcb_visualid_t visualid, xcb_colormap_t colormap, uint8_t depth)
1196 Q_ASSERT(m_client == XCB_WINDOW_NONE);
1197 Q_ASSERT(
frameId() == XCB_WINDOW_NONE);
1198 Q_ASSERT(m_wrapper == XCB_WINDOW_NONE);
1199 m_client.
reset(w,
false);
1201 const uint32_t zero_value = 0;
1203 xcb_connection_t *conn = kwinApp()->x11Connection();
1206 xcb_change_save_set(conn, XCB_SET_MODE_INSERT, m_client);
1213 const uint32_t cw_values[] = {
1219 const uint32_t cw_mask = XCB_CW_BACK_PIXMAP
1220 | XCB_CW_BORDER_PIXEL
1225 xcb_window_t frame = xcb_generate_id(conn);
1226 xcb_create_window(conn,
depth, frame, kwinApp()->x11RootWindow(), 0, 0, 1, 1, 0,
1227 XCB_WINDOW_CLASS_INPUT_OUTPUT, visualid, cw_mask, cw_values);
1228 m_frame.
reset(frame);
1231 xcb_window_t
wrapperId = xcb_generate_id(conn);
1233 XCB_WINDOW_CLASS_INPUT_OUTPUT, visualid, cw_mask, cw_values);
1248void X11Window::updateInputWindow()
1261 const QMargins &r =
decoration()->resizeOnlyBorders();
1262 const int left = r.left();
1263 const int top = r.top();
1264 const int right = r.right();
1265 const int bottom = r.bottom();
1266 if (left != 0 || top != 0 || right != 0 || bottom != 0) {
1267 region = QRegion(-left,
1275 if (region.isEmpty()) {
1276 m_decoInputExtent.
reset();
1280 QRectF bounds = region.boundingRect();
1281 input_offset = bounds.topLeft();
1287 region.translate(-input_offset.toPoint());
1289 if (!m_decoInputExtent.
isValid()) {
1290 const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
1291 const uint32_t values[] = {
true,
1292 XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION};
1293 m_decoInputExtent.
create(bounds, XCB_WINDOW_CLASS_INPUT_ONLY, mask, values);
1294 if (mapping_state == Mapped) {
1295 m_decoInputExtent.
map();
1301 const QList<xcb_rectangle_t> rects = Xcb::regionToRects(region);
1302 xcb_shape_rectangles(kwinApp()->x11Connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
1303 m_decoInputExtent, 0, 0, rects.count(), rects.constData());
1306void X11Window::updateDecoration(
bool check_workspace_pos,
bool force)
1314 destroyDecoration();
1319 destroyDecoration();
1322 if (check_workspace_pos) {
1325 updateInputWindow();
1327 updateFrameExtents();
1332 updateDecoration(
true,
true);
1335void X11Window::createDecoration()
1339 connect(
decoration.get(), &KDecoration2::Decoration::resizeOnlyBordersChanged,
this, [
this]() {
1341 updateInputWindow();
1344 connect(
decoration.get(), &KDecoration2::Decoration::bordersChanged,
this, [
this]() {
1346 updateFrameExtents();
1349 connect(decoration.get(), &KDecoration2::Decoration::bordersChanged,
this, [
this]() {
1353 GeometryUpdatesBlocker blocker(
this);
1354 const QRectF oldGeometry = moveResizeGeometry();
1356 checkWorkspacePosition(oldGeometry);
1359 connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged,
this, [
this]() {
1361 updateInputWindow();
1365 setDecoration(decoration);
1367 moveResize(QRectF(calculateGravitation(
false), clientSizeToFrameSize(clientSize())));
1368 maybeCreateX11DecorationRenderer();
1371void X11Window::destroyDecoration()
1373 if (isDecorated()) {
1374 QPointF grav = calculateGravitation(
true);
1375 setDecoration(
nullptr);
1376 maybeDestroyX11DecorationRenderer();
1377 moveResize(QRectF(grav, clientSizeToFrameSize(clientSize())));
1379 m_decoInputExtent.reset();
1382void X11Window::maybeCreateX11DecorationRenderer()
1384 if (kwinApp()->operationMode() != Application::OperationModeX11) {
1387 if (!Compositor::compositing() && decoratedClient()) {
1388 m_decorationRenderer = std::make_unique<X11DecorationRenderer>(decoratedClient());
1389 decoration()->update();
1393void X11Window::maybeDestroyX11DecorationRenderer()
1395 m_decorationRenderer.reset();
1398void X11Window::detectNoBorder()
1402 app_noborder =
true;
1405 switch (windowType()) {
1410 case NET::Notification:
1411 case NET::OnScreenDisplay:
1412 case NET::CriticalNotification:
1413 case NET::AppletPopup:
1415 app_noborder =
true;
1431 if (info->windowType(NET::OverrideMask) == NET::Override) {
1433 app_noborder =
true;
1437void X11Window::updateFrameExtents()
1440 strut.left = Xcb::toXNative(borderLeft());
1441 strut.right = Xcb::toXNative(borderRight());
1442 strut.top = Xcb::toXNative(borderTop());
1443 strut.bottom = Xcb::toXNative(borderBottom());
1444 info->setFrameExtents(strut);
1447void X11Window::setClientFrameExtents(
const NETStrut &strut)
1449 const QMarginsF clientFrameExtents(Xcb::fromXNative(strut.left),
1450 Xcb::fromXNative(strut.top),
1451 Xcb::fromXNative(strut.right),
1452 Xcb::fromXNative(strut.bottom));
1453 if (m_clientFrameExtents == clientFrameExtents) {
1457 m_clientFrameExtents = clientFrameExtents;
1464 moveResize(moveResizeGeometry());
1474void X11Window::resizeDecoration()
1476 triggerDecorationRepaint();
1477 updateInputWindow();
1480bool X11Window::userNoBorder()
const
1485bool X11Window::isFullScreenable()
const
1487 if (isUnmanaged()) {
1490 if (!rules()->checkFullScreen(
true)) {
1493 if (rules()->checkStrictGeometry(
true)) {
1496 const QSizeF constrainedClientSize = constrainClientSize(fullScreenArea.size());
1497 if (rules()->checkSize(constrainedClientSize) != fullScreenArea.size()) {
1502 return isNormalWindow() || isDialog();
1505bool X11Window::noBorder()
const
1507 return userNoBorder() || isFullScreen();
1510bool X11Window::userCanSetNoBorder()
const
1512 if (isUnmanaged()) {
1517 if (isClientSideDecorated()) {
1521 return !isFullScreen() && !isShade();
1524void X11Window::setNoBorder(
bool set)
1526 if (!userCanSetNoBorder()) {
1529 set = rules()->checkNoBorder(set);
1530 if (noborder == set) {
1534 updateDecoration(
true,
false);
1535 updateWindowRules(Rules::NoBorder);
1538void X11Window::checkNoBorder()
1540 setNoBorder(app_noborder);
1543void X11Window::detectShape()
1545 is_shape = Xcb::Extensions::self()->hasShape(window());
1548void X11Window::updateShape()
1552 if (!app_noborder) {
1554 app_noborder =
true;
1555 noborder = rules()->checkNoBorder(
true);
1556 updateDecoration(
true);
1558 if (!isDecorated()) {
1559 xcb_shape_combine(kwinApp()->x11Connection(),
1561 XCB_SHAPE_SK_BOUNDING,
1562 XCB_SHAPE_SK_BOUNDING,
1564 Xcb::toXNative(wrapperPos().x()),
1565 Xcb::toXNative(wrapperPos().y()),
1568 }
else if (app_noborder) {
1569 xcb_shape_mask(kwinApp()->x11Connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, frameId(), 0, 0, XCB_PIXMAP_NONE);
1571 app_noborder = noborder;
1572 noborder = rules()->checkNoBorder(noborder || m_motif.noBorder());
1573 updateDecoration(
true);
1579 Q_EMIT shapeChanged();
1582static Xcb::Window shape_helper_window(XCB_WINDOW_NONE);
1584void X11Window::cleanupX11()
1586 shape_helper_window.
reset();
1589void X11Window::updateInputShape()
1591 if (hiddenPreview()) {
1594 if (Xcb::Extensions::self()->isShapeInputAvailable()) {
1605 if (!shape_helper_window.
isValid()) {
1606 shape_helper_window.
create(QRect(0, 0, 1, 1));
1608 const QSizeF bufferSize = m_bufferGeometry.size();
1609 shape_helper_window.
resize(bufferSize);
1610 xcb_connection_t *c = kwinApp()->x11Connection();
1611 xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_BOUNDING,
1612 shape_helper_window, 0, 0, frameId());
1613 xcb_shape_combine(c,
1614 XCB_SHAPE_SO_SUBTRACT,
1616 XCB_SHAPE_SK_BOUNDING,
1617 shape_helper_window,
1618 Xcb::toXNative(wrapperPos().x()),
1619 Xcb::toXNative(wrapperPos().y()),
1621 xcb_shape_combine(c,
1625 shape_helper_window,
1626 Xcb::toXNative(wrapperPos().x()),
1627 Xcb::toXNative(wrapperPos().y()),
1629 xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_INPUT,
1630 frameId(), 0, 0, shape_helper_window);
1634bool X11Window::setupCompositing()
1636 if (!Window::setupCompositing()) {
1640 maybeDestroyX11DecorationRenderer();
1645void X11Window::finishCompositing()
1647 Window::finishCompositing();
1650 maybeCreateX11DecorationRenderer();
1656bool X11Window::isMinimizable()
const
1658 if (isSpecialWindow() && !isTransient()) {
1661 if (isAppletPopup()) {
1664 if (!rules()->checkMinimize(
true)) {
1668 if (isTransient()) {
1670 bool shown_mainwindow =
false;
1671 auto mainwindows = mainWindows();
1672 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd(); ++it) {
1673 if ((*it)->isShown()) {
1674 shown_mainwindow =
true;
1677 if (!shown_mainwindow) {
1687 if (transientFor() != NULL)
1690 if (!wantsTabFocus()) {
1696void X11Window::doMinimize()
1699 if (isMinimized()) {
1705 info->setState(isMinimized() ? NET::States() : NET::Shaded, NET::Shaded);
1708 updateAllowedActions();
1712QRectF X11Window::iconGeometry()
const
1714 NETRect r = info->iconGeometry();
1715 QRectF geom = Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height));
1716 if (geom.isValid()) {
1720 const auto &clients = mainWindows();
1721 for (
Window *amainwin : clients) {
1727 if (geom.isValid()) {
1732 return Window::iconGeometry();
1736bool X11Window::isShadeable()
const
1738 return !isSpecialWindow() && isDecorated() && (rules()->checkShade(
ShadeNormal) != rules()->checkShade(
ShadeNone));
1745 shade_geometry_change =
true;
1746 QSizeF s(implicitSize());
1747 s.setHeight(borderTop() + borderBottom());
1748 m_wrapper.selectInput(wrapperEventMask() & ~XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
1751 m_wrapper.selectInput(wrapperEventMask());
1752 exportMappingState(XCB_ICCCM_WM_STATE_ICONIC);
1754 shade_geometry_change =
false;
1756 if (shade_below &&
workspace()->stackingOrder().indexOf(shade_below) > -1) {
1762 }
else if (isActive()) {
1766 shade_geometry_change =
true;
1767 if (decoratedClient()) {
1768 decoratedClient()->signalShadeChange();
1770 QSizeF s(implicitSize());
1771 shade_geometry_change =
false;
1773 setGeometryRestore(moveResizeGeometry());
1780 shade_below =
nullptr;
1782 for (
int idx = order.indexOf(
this) + 1; idx < order.count(); ++idx) {
1783 shade_below = qobject_cast<X11Window *>(order.at(idx));
1788 if (shade_below && shade_below->isNormalWindow()) {
1791 shade_below =
nullptr;
1796 exportMappingState(XCB_ICCCM_WM_STATE_NORMAL);
1801 info->setState(isShade() ? NET::Shaded : NET::States(), NET::Shaded);
1802 info->setState((isShade() || !isShown()) ? NET::Hidden : NET::States(), NET::Hidden);
1804 updateAllowedActions();
1805 discardWindowPixmap();
1808void X11Window::updateVisibility()
1810 if (isUnmanaged() || isDeleted()) {
1814 info->setState(NET::Hidden, NET::Hidden);
1815 setSkipTaskbar(
true);
1823 if (isHiddenByShowDesktop()) {
1834 setSkipTaskbar(originalSkipTaskbar());
1835 if (isMinimized()) {
1836 info->setState(NET::Hidden, NET::Hidden);
1844 info->setState(NET::States(), NET::Hidden);
1845 if (!isOnCurrentDesktop()) {
1853 if (!isOnCurrentActivity()) {
1868void X11Window::exportMappingState(
int s)
1870 Q_ASSERT(m_client != XCB_WINDOW_NONE);
1871 Q_ASSERT(!isDeleted() || s == XCB_ICCCM_WM_STATE_WITHDRAWN);
1872 if (s == XCB_ICCCM_WM_STATE_WITHDRAWN) {
1876 Q_ASSERT(s == XCB_ICCCM_WM_STATE_NORMAL || s == XCB_ICCCM_WM_STATE_ICONIC);
1884void X11Window::internalShow()
1886 if (mapping_state == Mapped) {
1889 MappingState old = mapping_state;
1890 mapping_state = Mapped;
1891 if (old == Unmapped || old == Withdrawn) {
1895 m_decoInputExtent.map();
1896 updateHiddenPreview();
1900void X11Window::internalHide()
1902 if (mapping_state == Unmapped) {
1905 MappingState old = mapping_state;
1906 mapping_state = Unmapped;
1907 if (old == Mapped || old == Kept) {
1911 updateHiddenPreview();
1915void X11Window::internalKeep()
1917 Q_ASSERT(Compositor::compositing());
1918 if (mapping_state == Kept) {
1921 MappingState old = mapping_state;
1922 mapping_state = Kept;
1923 if (old == Unmapped || old == Withdrawn) {
1926 m_decoInputExtent.unmap();
1930 updateHiddenPreview();
1938void X11Window::map()
1943 if (Compositor::compositing()) {
1944 discardWindowPixmap();
1950 m_decoInputExtent.map();
1951 exportMappingState(XCB_ICCCM_WM_STATE_NORMAL);
1953 exportMappingState(XCB_ICCCM_WM_STATE_ICONIC);
1960void X11Window::unmap()
1968 m_wrapper.selectInput(wrapperEventMask() & ~XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY);
1972 m_decoInputExtent.unmap();
1973 m_wrapper.selectInput(wrapperEventMask());
1974 exportMappingState(XCB_ICCCM_WM_STATE_ICONIC);
1988void X11Window::updateHiddenPreview()
1990 if (hiddenPreview()) {
1992 if (Xcb::Extensions::self()->isShapeInputAvailable()) {
1993 xcb_shape_rectangles(kwinApp()->x11Connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT,
1994 XCB_CLIP_ORDERING_UNSORTED, frameId(), 0, 0, 0,
nullptr);
2002void X11Window::sendClientMessage(xcb_window_t w, xcb_atom_t a, xcb_atom_t protocol, uint32_t data1, uint32_t data2, uint32_t data3)
2004 xcb_client_message_event_t ev;
2008 static_assert(
sizeof(ev) == 32,
"Would leak stack data otherwise");
2009 memset(&ev, 0,
sizeof(ev));
2010 ev.response_type = XCB_CLIENT_MESSAGE;
2014 ev.data.data32[0] = protocol;
2015 ev.data.data32[1] =
xTime();
2016 ev.data.data32[2] = data1;
2017 ev.data.data32[3] = data2;
2018 ev.data.data32[4] = data3;
2019 uint32_t eventMask = 0;
2020 if (w == kwinApp()->x11RootWindow()) {
2021 eventMask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
2023 xcb_send_event(kwinApp()->x11Connection(),
false, w, eventMask,
reinterpret_cast<const char *
>(&ev));
2024 xcb_flush(kwinApp()->x11Connection());
2030bool X11Window::isCloseable()
const
2032 return !isUnmanaged() && rules()->checkCloseable(m_motif.close() && !isSpecialWindow());
2038void X11Window::closeWindow()
2040 if (!isCloseable()) {
2047 if (info->supportsProtocol(NET::DeleteWindowProtocol)) {
2059void X11Window::killWindow()
2061 qCDebug(KWIN_CORE) <<
"X11Window::killWindow():" << window();
2062 if (isUnmanaged()) {
2063 xcb_kill_client(kwinApp()->x11Connection(), window());
2075void X11Window::pingWindow()
2077 if (!info->supportsProtocol(NET::PingProtocol)) {
2083 if (ping_timer !=
nullptr) {
2086 ping_timer =
new QTimer(
this);
2087 connect(ping_timer, &QTimer::timeout,
this, [
this]() {
2088 if (unresponsive()) {
2089 qCDebug(KWIN_CORE) <<
"Final ping timeout, asking to kill:" << caption();
2090 ping_timer->deleteLater();
2091 ping_timer =
nullptr;
2092 killProcess(
true, m_pingTimestamp);
2096 qCDebug(KWIN_CORE) <<
"First ping timeout:" << caption();
2098 setUnresponsive(
true);
2099 ping_timer->start();
2101 ping_timer->setSingleShot(
true);
2105 m_pingTimestamp =
xTime();
2106 rootInfo()->sendPing(window(), m_pingTimestamp);
2109void X11Window::gotPing(xcb_timestamp_t timestamp)
2112 if (NET::timestampCompare(timestamp, m_pingTimestamp) != 0) {
2116 ping_timer =
nullptr;
2118 setUnresponsive(
false);
2121 m_killPrompt->quit();
2125void X11Window::killProcess(
bool ask, xcb_timestamp_t timestamp)
2127 if (m_killPrompt && m_killPrompt->isRunning()) {
2130 Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME);
2131 pid_t pid = info->pid();
2132 if (pid <= 0 || clientMachine()->hostName().isEmpty()) {
2135 qCDebug(KWIN_CORE) <<
"Kill process:" << pid <<
"(" << clientMachine()->hostName() <<
")";
2137 if (!clientMachine()->isLocal()) {
2139 lst << clientMachine()->hostName() << QStringLiteral(
"kill") << QString::number(pid);
2140 QProcess::startDetached(QStringLiteral(
"xon"), lst);
2142 ::kill(pid, SIGTERM);
2145 if (!m_killPrompt) {
2146 m_killPrompt = std::make_unique<KillPrompt>(
this);
2148 m_killPrompt->start(timestamp);
2152void X11Window::doSetKeepAbove()
2154 info->setState(keepAbove() ? NET::KeepAbove : NET::States(), NET::KeepAbove);
2157void X11Window::doSetKeepBelow()
2159 info->setState(keepBelow() ? NET::KeepBelow : NET::States(), NET::KeepBelow);
2162void X11Window::doSetSkipTaskbar()
2164 info->setState(skipTaskbar() ? NET::SkipTaskbar : NET::States(), NET::SkipTaskbar);
2167void X11Window::doSetSkipPager()
2169 info->setState(skipPager() ? NET::SkipPager : NET::States(), NET::SkipPager);
2172void X11Window::doSetSkipSwitcher()
2174 info->setState(skipSwitcher() ? NET::SkipSwitcher : NET::States(), NET::SkipSwitcher);
2177void X11Window::doSetDesktop()
2179 info->setDesktop(desktopId());
2183void X11Window::doSetDemandsAttention()
2185 info->setState(isDemandingAttention() ? NET::DemandsAttention : NET::States(), NET::DemandsAttention);
2188void X11Window::doSetHidden()
2193void X11Window::doSetHiddenByShowDesktop()
2198void X11Window::doSetOnActivities(
const QStringList &activityList)
2200#if KWIN_BUILD_ACTIVITIES
2201 if (activityList.isEmpty()) {
2202 const QByteArray nullUuid = Activities::nullUuid().toUtf8();
2203 m_client.changeProperty(
atoms->
activities, XCB_ATOM_STRING, 8, nullUuid.length(), nullUuid.constData());
2205 QByteArray joined = activityList.join(QStringLiteral(
",")).toLatin1();
2206 m_client.changeProperty(
atoms->
activities, XCB_ATOM_STRING, 8, joined.length(), joined.constData());
2211void X11Window::updateActivities(
bool includeTransients)
2213 Window::updateActivities(includeTransients);
2214 if (!m_activityUpdatesBlocked) {
2224QStringList X11Window::activities()
const
2226 if (sessionActivityOverride) {
2227 return QStringList();
2229 return Window::activities();
2235bool X11Window::takeFocus()
2237 const bool effectiveAcceptFocus = rules()->checkAcceptFocus(info->input());
2238 const bool effectiveTakeFocus = rules()->checkAcceptFocus(info->supportsProtocol(NET::TakeFocusProtocol));
2240 if (effectiveAcceptFocus) {
2241 xcb_void_cookie_t cookie = xcb_set_input_focus_checked(kwinApp()->x11Connection(),
2242 XCB_INPUT_FOCUS_POINTER_ROOT,
2243 window(), XCB_TIME_CURRENT_TIME);
2246 qCWarning(KWIN_CORE,
"Failed to focus 0x%x (error %d)", window(), error->error_code);
2250 demandAttention(
false);
2252 if (effectiveTakeFocus) {
2253 kwinApp()->updateXTime();
2257 if (effectiveAcceptFocus || effectiveTakeFocus) {
2270bool X11Window::providesContextHelp()
const
2272 return info->supportsProtocol(NET::ContextHelpProtocol);
2281void X11Window::showContextHelp()
2283 if (info->supportsProtocol(NET::ContextHelpProtocol)) {
2292void X11Window::fetchName()
2294 setCaption(readName());
2297static inline QString readNameProperty(xcb_window_t w, xcb_atom_t atom)
2299 const auto cookie = xcb_icccm_get_text_property_unchecked(kwinApp()->x11Connection(), w, atom);
2300 xcb_icccm_get_text_property_reply_t reply;
2301 if (xcb_icccm_get_wm_name_reply(kwinApp()->x11Connection(), cookie, &reply,
nullptr)) {
2304 retVal = QString::fromUtf8(QByteArray(reply.name, reply.name_len));
2305 }
else if (reply.encoding == XCB_ATOM_STRING) {
2306 retVal = QString::fromLatin1(QByteArray(reply.name, reply.name_len));
2308 xcb_icccm_get_text_property_reply_wipe(&reply);
2309 return retVal.simplified();
2314QString X11Window::readName()
const
2316 if (info->name() && info->name()[0] !=
'\0') {
2317 return QString::fromUtf8(info->name()).simplified();
2319 return readNameProperty(window(), XCB_ATOM_WM_NAME);
2324static const QChar LRM(0x200E);
2326void X11Window::setCaption(
const QString &_s,
bool force)
2329 for (
int i = 0; i < s.length();) {
2330 if (!s[i].isPrint()) {
2331 if (QChar(s[i]).isHighSurrogate() && i + 1 < s.length() && QChar(s[i + 1]).isLowSurrogate()) {
2332 const uint uc = QChar::surrogateToUcs4(s[i], s[i + 1]);
2333 if (!QChar::isPrint(uc)) {
2345 const bool changed = (s != cap_normal);
2346 if (!force && !changed) {
2351 bool was_suffix = (!cap_suffix.isEmpty());
2353 QString machine_suffix;
2355 if (clientMachine()->hostName() != ClientMachine::localhost() && !clientMachine()->isLocal()) {
2356 machine_suffix = QLatin1String(
" <@") + clientMachine()->hostName() + QLatin1Char(
'>') + LRM;
2359 QString shortcut_suffix = shortcutCaptionSuffix();
2360 cap_suffix = machine_suffix + shortcut_suffix;
2361 if ((was_suffix && cap_suffix.isEmpty()) || force) {
2363 info->setVisibleName(
"");
2364 info->setVisibleIconName(
"");
2365 }
else if (!cap_suffix.isEmpty() && !cap_iconic.isEmpty()) {
2367 info->setVisibleIconName(QString(cap_iconic + cap_suffix).toUtf8().constData());
2371 Q_EMIT captionNormalChanged();
2373 Q_EMIT captionChanged();
2376void X11Window::updateCaption()
2378 setCaption(cap_normal,
true);
2381void X11Window::fetchIconicName()
2384 if (info->iconName() && info->iconName()[0] !=
'\0') {
2385 s = QString::fromUtf8(info->iconName());
2387 s = readNameProperty(window(), XCB_ATOM_WM_ICON_NAME);
2389 if (s != cap_iconic) {
2390 bool was_set = !cap_iconic.isEmpty();
2392 if (!cap_suffix.isEmpty()) {
2393 if (!cap_iconic.isEmpty()) {
2394 info->setVisibleIconName(QString(s + cap_suffix).toUtf8().constData());
2395 }
else if (was_set) {
2396 info->setVisibleIconName(
"");
2402void X11Window::getMotifHints()
2404 const bool wasClosable = isCloseable();
2405 const bool wasNoBorder = m_motif.noBorder();
2410 if (m_motif.hasDecoration() && m_motif.noBorder() != wasNoBorder) {
2412 if (m_motif.noBorder()) {
2413 noborder = rules()->checkNoBorder(
true);
2416 }
else if (!app_noborder) {
2417 noborder = rules()->checkNoBorder(
false);
2423 const bool closabilityChanged = wasClosable != isCloseable();
2425 updateDecoration(
true);
2427 if (closabilityChanged) {
2428 Q_EMIT closeableChanged(isCloseable());
2432void X11Window::getIcons()
2434 if (isUnmanaged()) {
2438 const QString themedIconName = iconFromDesktopFile();
2439 if (!themedIconName.isEmpty()) {
2440 setIcon(QIcon::fromTheme(themedIconName));
2444 auto readIcon = [
this, &icon](
int size,
bool scale =
true) {
2445 const QPixmap pix = KX11Extras::icon(window(), size, size, scale, KX11Extras::NETWM | KX11Extras::WMHints, info);
2446 if (!pix.isNull()) {
2447 icon.addPixmap(pix);
2452 readIcon(48,
false);
2453 readIcon(64,
false);
2454 readIcon(128,
false);
2455 if (icon.isNull()) {
2457 icon = group()->icon();
2459 if (icon.isNull() && isTransient()) {
2461 auto mainwindows = mainWindows();
2462 for (
auto it = mainwindows.constBegin(); it != mainwindows.constEnd() && icon.isNull(); ++it) {
2463 if (!(*it)->icon().isNull()) {
2464 icon = (*it)->icon();
2469 if (icon.isNull()) {
2471 icon.addPixmap(KX11Extras::icon(window(), 32, 32,
true, KX11Extras::ClassHint | KX11Extras::XApp, info));
2472 icon.addPixmap(KX11Extras::icon(window(), 16, 16,
true, KX11Extras::ClassHint | KX11Extras::XApp, info));
2473 icon.addPixmap(KX11Extras::icon(window(), 64, 64,
false, KX11Extras::ClassHint | KX11Extras::XApp, info));
2474 icon.addPixmap(KX11Extras::icon(window(), 128, 128,
false, KX11Extras::ClassHint | KX11Extras::XApp, info));
2482bool X11Window::wantsSyncCounter()
const
2492 static const quint32 xwaylandVersion = xcb_get_setup(kwinApp()->x11Connection())->release_number;
2493 return xwaylandVersion >= 12100000;
2496void X11Window::getSyncCounter()
2498 if (!Xcb::Extensions::self()->isSyncAvailable()) {
2501 if (!wantsSyncCounter()) {
2506 const xcb_sync_counter_t counter = syncProp.value<xcb_sync_counter_t>(XCB_NONE);
2507 if (counter != XCB_NONE) {
2508 m_syncRequest.counter = counter;
2509 m_syncRequest.value.hi = 0;
2510 m_syncRequest.value.lo = 0;
2511 auto *c = kwinApp()->x11Connection();
2512 xcb_sync_set_counter(c, m_syncRequest.counter, m_syncRequest.value);
2513 if (m_syncRequest.alarm == XCB_NONE) {
2514 const uint32_t mask = XCB_SYNC_CA_COUNTER | XCB_SYNC_CA_VALUE_TYPE | XCB_SYNC_CA_TEST_TYPE | XCB_SYNC_CA_EVENTS;
2515 const uint32_t values[] = {
2516 m_syncRequest.counter,
2517 XCB_SYNC_VALUETYPE_RELATIVE,
2518 XCB_SYNC_TESTTYPE_POSITIVE_TRANSITION,
2520 m_syncRequest.alarm = xcb_generate_id(c);
2521 auto cookie = xcb_sync_create_alarm_checked(c, m_syncRequest.alarm, mask, values);
2522 UniqueCPtr<xcb_generic_error_t> error(xcb_request_check(c, cookie));
2524 m_syncRequest.alarm = XCB_NONE;
2526 xcb_sync_change_alarm_value_list_t value;
2527 memset(&value, 0,
sizeof(value));
2532 xcb_sync_change_alarm_aux(c, m_syncRequest.alarm, XCB_SYNC_CA_DELTA | XCB_SYNC_CA_VALUE, &value);
2541void X11Window::sendSyncRequest()
2543 if (m_syncRequest.counter == XCB_NONE || m_syncRequest.isPending) {
2547 if (!m_syncRequest.failsafeTimeout) {
2548 m_syncRequest.failsafeTimeout =
new QTimer(
this);
2549 connect(m_syncRequest.failsafeTimeout, &QTimer::timeout,
this, [
this]() {
2551 if (!ready_for_painting) {
2553 setReadyForPainting();
2557 m_syncRequest.isPending =
false;
2558 m_syncRequest.interactiveResize =
false;
2559 m_syncRequest.counter = XCB_NONE;
2560 m_syncRequest.alarm = XCB_NONE;
2561 delete m_syncRequest.timeout;
2562 delete m_syncRequest.failsafeTimeout;
2563 m_syncRequest.timeout =
nullptr;
2564 m_syncRequest.failsafeTimeout =
nullptr;
2565 m_syncRequest.lastTimestamp = XCB_CURRENT_TIME;
2567 m_syncRequest.failsafeTimeout->setSingleShot(
true);
2571 m_syncRequest.failsafeTimeout->start(ready_for_painting ? 10000 : 1000);
2576 const uint32_t oldLo = m_syncRequest.value.lo;
2577 m_syncRequest.value.lo++;
2578 if (oldLo > m_syncRequest.value.lo) {
2579 m_syncRequest.value.hi++;
2581 if (m_syncRequest.lastTimestamp >=
xTime()) {
2582 kwinApp()->updateXTime();
2587 m_syncRequest.value.lo, m_syncRequest.value.hi);
2588 m_syncRequest.isPending =
true;
2589 m_syncRequest.interactiveResize = isInteractiveResize();
2590 m_syncRequest.lastTimestamp =
xTime();
2593bool X11Window::wantsInput()
const
2595 return rules()->checkAcceptFocus(acceptsFocus() || info->supportsProtocol(NET::TakeFocusProtocol));
2598bool X11Window::acceptsFocus()
const
2600 return info->input();
2603void X11Window::setBlockingCompositing(
bool block)
2609 unblockCompositing();
2613void X11Window::blockCompositing()
2615 if (blocks_compositing) {
2618 blocks_compositing =
true;
2619 Compositor::self()->inhibit(
this);
2622void X11Window::unblockCompositing()
2624 if (!blocks_compositing) {
2627 blocks_compositing =
false;
2628 Compositor::self()->uninhibit(
this);
2631void X11Window::updateAllowedActions(
bool force)
2633 if (!isManaged() && !force) {
2636 NET::Actions old_allowed_actions = NET::Actions(allowed_actions);
2637 allowed_actions = NET::Actions();
2639 allowed_actions |= NET::ActionMove;
2641 if (isResizable()) {
2642 allowed_actions |= NET::ActionResize;
2644 if (isMinimizable()) {
2645 allowed_actions |= NET::ActionMinimize;
2647 if (isShadeable()) {
2648 allowed_actions |= NET::ActionShade;
2651 if (isMaximizable()) {
2652 allowed_actions |= NET::ActionMax;
2654 if (isFullScreenable()) {
2655 allowed_actions |= NET::ActionFullScreen;
2657 allowed_actions |= NET::ActionChangeDesktop;
2658 if (isCloseable()) {
2659 allowed_actions |= NET::ActionClose;
2661 if (old_allowed_actions == allowed_actions) {
2665 info->setAllowedActions(allowed_actions);
2667 const NET::Actions relevant = ~(NET::ActionMove | NET::ActionResize);
2668 if ((allowed_actions & relevant) != (old_allowed_actions & relevant)) {
2669 if ((allowed_actions & NET::ActionMinimize) != (old_allowed_actions & NET::ActionMinimize)) {
2670 Q_EMIT minimizeableChanged(allowed_actions & NET::ActionMinimize);
2672 if ((allowed_actions & NET::ActionShade) != (old_allowed_actions & NET::ActionShade)) {
2673 Q_EMIT shadeableChanged(allowed_actions & NET::ActionShade);
2675 if ((allowed_actions & NET::ActionMax) != (old_allowed_actions & NET::ActionMax)) {
2676 Q_EMIT maximizeableChanged(allowed_actions & NET::ActionMax);
2678 if ((allowed_actions & NET::ActionClose) != (old_allowed_actions & NET::ActionClose)) {
2679 Q_EMIT closeableChanged(allowed_actions & NET::ActionClose);
2684Xcb::StringProperty X11Window::fetchActivities()
const
2686#if KWIN_BUILD_ACTIVITIES
2689 return Xcb::StringProperty();
2693void X11Window::readActivities(Xcb::StringProperty &property)
2695#if KWIN_BUILD_ACTIVITIES
2696 QString prop = QString::fromUtf8(property);
2697 activitiesDefined = !prop.isEmpty();
2699 if (prop == Activities::nullUuid()) {
2701 if (!m_activityList.isEmpty()) {
2702 m_activityList.clear();
2703 updateActivities(
true);
2707 if (prop.isEmpty()) {
2709 if (!m_activityList.isEmpty()) {
2710 m_activityList.clear();
2711 updateActivities(
true);
2716 const QStringList newActivitiesList = prop.split(u
',');
2718 if (newActivitiesList == m_activityList) {
2722 setOnActivities(newActivitiesList);
2726void X11Window::checkActivities()
2728#if KWIN_BUILD_ACTIVITIES
2730 readActivities(property);
2734void X11Window::setSessionActivityOverride(
bool needed)
2736 sessionActivityOverride = needed;
2737 updateActivities(
false);
2747 return rules()->checkDecoColor(QString::fromUtf8(property));
2750QString X11Window::preferredColorScheme()
const
2753 return readPreferredColorScheme(property);
2756bool X11Window::isClient()
const
2758 return !m_unmanaged;
2761bool X11Window::isUnmanaged()
const
2766bool X11Window::isOutline()
const
2771NET::WindowType X11Window::windowType()
const
2779 if (wt == NET::Unknown) {
2780 wt = isTransient() ? NET::Dialog : NET::Normal;
2785void X11Window::cancelFocusOutTimer()
2787 if (m_focusOutTimer) {
2788 m_focusOutTimer->stop();
2792xcb_window_t X11Window::frameId()
const
2797xcb_window_t X11Window::window()
const
2802xcb_window_t X11Window::wrapperId()
const
2807QPointF X11Window::framePosToClientPos(
const QPointF &point)
const
2809 qreal x = point.x();
2810 qreal y = point.y();
2812 if (isDecorated()) {
2816 x -= m_clientFrameExtents.left();
2817 y -= m_clientFrameExtents.top();
2820 return QPointF(x, y);
2823QPointF X11Window::clientPosToFramePos(
const QPointF &point)
const
2825 qreal x = point.x();
2826 qreal y = point.y();
2828 if (isDecorated()) {
2832 x += m_clientFrameExtents.left();
2833 y += m_clientFrameExtents.top();
2836 return QPointF(x, y);
2839QSizeF X11Window::frameSizeToClientSize(
const QSizeF &size)
const
2841 qreal width = size.width();
2842 qreal height = size.height();
2844 if (isDecorated()) {
2845 width -= borderLeft() + borderRight();
2846 height -= borderTop() + borderBottom();
2848 width += m_clientFrameExtents.left() + m_clientFrameExtents.right();
2849 height += m_clientFrameExtents.top() + m_clientFrameExtents.bottom();
2852 return QSizeF(width, height);
2855QSizeF X11Window::clientSizeToFrameSize(
const QSizeF &size)
const
2857 qreal width = size.width();
2858 qreal height = size.height();
2860 if (isDecorated()) {
2861 width += borderLeft() + borderRight();
2862 height += borderTop() + borderBottom();
2864 width -= m_clientFrameExtents.left() + m_clientFrameExtents.right();
2865 height -= m_clientFrameExtents.top() + m_clientFrameExtents.bottom();
2868 return QSizeF(width, height);
2871QRectF X11Window::frameRectToBufferRect(
const QRectF &rect)
const
2876 return frameRectToClientRect(rect);
2883QPointF X11Window::wrapperPos()
const
2885 return m_clientGeometry.topLeft() - m_bufferGeometry.topLeft();
2892QSizeF X11Window::implicitSize()
const
2894 return clientSizeToFrameSize(m_client.geometry().size());
2897pid_t X11Window::pid()
const
2902QString X11Window::windowRole()
const
2904 return QString::fromLatin1(info->windowRole());
2912void X11Window::readShowOnScreenEdge(Xcb::Property &property)
2914 const uint32_t value =
property.value<uint32_t>(ElectricNone);
2915 ElectricBorder border = ElectricNone;
2916 switch (value & 0xFF) {
2918 border = ElectricTop;
2921 border = ElectricRight;
2924 border = ElectricBottom;
2927 border = ElectricLeft;
2930 if (border != ElectricNone) {
2931 disconnect(m_edgeGeometryTrackingConnection);
2933 auto reserveScreenEdge = [
this, border]() {
2941 reserveScreenEdge();
2942 m_edgeGeometryTrackingConnection = connect(
this, &X11Window::frameGeometryChanged,
this, reserveScreenEdge);
2943 }
else if (!property.isNull() && property->type != XCB_ATOM_NONE) {
2949 disconnect(m_edgeGeometryTrackingConnection);
2957void X11Window::updateShowOnScreenEdge()
2959 Xcb::Property
property = fetchShowOnScreenEdge();
2960 readShowOnScreenEdge(property);
2963void X11Window::showOnScreenEdge()
2969bool X11Window::belongsToSameApplication(
const Window *other, SameApplicationChecks checks)
const
2975 return X11Window::belongToSameApplication(
this, c2, checks);
2978QSizeF X11Window::resizeIncrements()
const
2980 return m_geometryHints.resizeIncrements();
2990 updateApplicationMenuServiceName(QString::fromUtf8(property));
2993void X11Window::checkApplicationMenuServiceName()
2996 readApplicationMenuServiceName(property);
3006 updateApplicationMenuObjectPath(QString::fromUtf8(property));
3009void X11Window::checkApplicationMenuObjectPath()
3012 readApplicationMenuObjectPath(property);
3015void X11Window::handleSync()
3017 setReadyForPainting();
3018 m_syncRequest.isPending =
false;
3019 if (m_syncRequest.failsafeTimeout) {
3020 m_syncRequest.failsafeTimeout->stop();
3024 if (m_syncRequest.interactiveResize) {
3025 m_syncRequest.interactiveResize =
false;
3026 if (m_syncRequest.timeout) {
3027 m_syncRequest.timeout->stop();
3029 performInteractiveResize();
3030 updateWindowPixmap();
3034void X11Window::performInteractiveResize()
3036 resize(moveResizeGeometry().size());
3039bool X11Window::belongToSameApplication(
const X11Window *c1,
const X11Window *c2, SameApplicationChecks checks)
3041 bool same_app =
false;
3058 }
else if ((c1->
pid() != c2->
pid() && !checks.testFlag(SameApplicationCheck::AllowCrossProcesses))
3064 && !checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
3068 }
else if (!sameAppWindowRoleMatch(c1, c2, checks.testFlag(SameApplicationCheck::RelaxedForActive))
3069 && !checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
3071 }
else if (c1->
pid() == 0 || c2->
pid() == 0) {
3120 if ((pos1 >= 0 && pos2 >= 0)) {
3184void X11Window::readTransientProperty(Xcb::TransientFor &transientFor)
3186 xcb_window_t new_transient_for_id = XCB_WINDOW_NONE;
3187 if (transientFor.getTransientFor(&new_transient_for_id)) {
3188 m_originalTransientForId = new_transient_for_id;
3189 new_transient_for_id = verifyTransientFor(new_transient_for_id,
true);
3191 m_originalTransientForId = XCB_WINDOW_NONE;
3192 new_transient_for_id = verifyTransientFor(XCB_WINDOW_NONE,
false);
3194 setTransient(new_transient_for_id);
3197void X11Window::readTransient()
3199 if (isUnmanaged()) {
3202 Xcb::TransientFor transientFor = fetchTransient();
3203 readTransientProperty(transientFor);
3206void X11Window::setTransient(xcb_window_t new_transient_for_id)
3208 if (new_transient_for_id != m_transientForId) {
3209 removeFromMainClients();
3210 X11Window *transient_for =
nullptr;
3211 m_transientForId = new_transient_for_id;
3212 if (m_transientForId != XCB_WINDOW_NONE && !groupTransient()) {
3214 Q_ASSERT(transient_for !=
nullptr);
3215 transient_for->addTransient(
this);
3217 setTransientFor(transient_for);
3218 checkGroup(
nullptr,
true);
3221 Q_EMIT transientChanged();
3225void X11Window::removeFromMainClients()
3227 if (transientFor()) {
3228 transientFor()->removeTransient(
this);
3230 if (groupTransient()) {
3231 for (
auto it = group()->members().constBegin(); it != group()->members().constEnd(); ++it) {
3232 (*it)->removeTransient(
this);
3241void X11Window::cleanGrouping()
3246 if (transientFor()) {
3247 transientFor()->removeTransientFromList(
this);
3248 setTransientFor(
nullptr);
3251 if (groupTransient()) {
3252 const auto members = group()->members();
3253 for (
Window *member : members) {
3254 member->removeTransientFromList(
this);
3258 const auto children = transients();
3259 for (
Window *transient : children) {
3260 removeTransientFromList(transient);
3261 transient->setTransientFor(
nullptr);
3264 group()->removeMember(
this);
3266 m_transientForId = XCB_WINDOW_NONE;
3273void X11Window::checkGroupTransients()
3275 for (
auto it1 = group()->members().constBegin(); it1 != group()->members().constEnd(); ++it1) {
3276 if (!(*it1)->groupTransient()) {
3279 for (
auto it2 = group()->members().constBegin(); it2 != group()->members().constEnd(); ++it2) {
3284 for (
Window *cl = (*it2)->transientFor(); cl !=
nullptr; cl = cl->transientFor()) {
3287 (*it2)->removeTransientFromList(*it1);
3295 if ((*it2)->groupTransient() && (*it1)->hasTransient(*it2,
true) && (*it2)->hasTransient(*it1,
true)) {
3296 (*it2)->removeTransientFromList(*it1);
3303 for (
auto it3 = group()->members().constBegin(); it3 != group()->members().constEnd(); ++it3) {
3304 if (*it1 == *it2 || *it2 == *it3 || *it1 == *it3) {
3307 if ((*it2)->hasTransient(*it1,
false) && (*it3)->hasTransient(*it1,
false)) {
3308 if ((*it2)->hasTransient(*it3,
true)) {
3309 (*it2)->removeTransientFromList(*it1);
3311 if ((*it3)->hasTransient(*it2,
true)) {
3312 (*it3)->removeTransientFromList(*it1);
3323xcb_window_t X11Window::verifyTransientFor(xcb_window_t new_transient_for,
bool set)
3325 xcb_window_t new_property_value = new_transient_for;
3328 if (isSplash() && new_transient_for == XCB_WINDOW_NONE) {
3329 new_transient_for = kwinApp()->x11RootWindow();
3331 if (new_transient_for == XCB_WINDOW_NONE) {
3333 new_property_value = new_transient_for = kwinApp()->x11RootWindow();
3335 return XCB_WINDOW_NONE;
3338 if (new_transient_for == window()) {
3340 qCWarning(KWIN_CORE) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to itself.";
3341 new_property_value = new_transient_for = kwinApp()->x11RootWindow();
3346 xcb_window_t before_search = new_transient_for;
3347 while (new_transient_for != XCB_WINDOW_NONE
3348 && new_transient_for != kwinApp()->x11RootWindow()
3349 && !
workspace()->findClient(Predicate::WindowMatch, new_transient_for)) {
3350 Xcb::Tree tree(new_transient_for);
3351 if (tree.isNull()) {
3354 new_transient_for = tree->parent;
3356 if (X11Window *new_transient_for_client =
workspace()->findClient(Predicate::WindowMatch, new_transient_for)) {
3357 if (new_transient_for != before_search) {
3358 qCDebug(KWIN_CORE) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to non-toplevel window "
3359 << before_search <<
", child of " << new_transient_for_client <<
", adjusting.";
3360 new_property_value = new_transient_for;
3363 new_transient_for = before_search;
3369 xcb_window_t loop_pos = new_transient_for;
3370 while (loop_pos != XCB_WINDOW_NONE && loop_pos != kwinApp()->x11RootWindow()) {
3372 if (pos ==
nullptr) {
3375 loop_pos = pos->m_transientForId;
3376 if (--count == 0 || pos ==
this) {
3377 qCWarning(KWIN_CORE) <<
"Client " <<
this <<
" caused WM_TRANSIENT_FOR loop.";
3378 new_transient_for = kwinApp()->x11RootWindow();
3381 if (new_transient_for != kwinApp()->x11RootWindow()
3382 &&
workspace()->findClient(Predicate::WindowMatch, new_transient_for) ==
nullptr) {
3384 new_transient_for = kwinApp()->x11RootWindow();
3386 if (new_property_value != m_originalTransientForId) {
3387 Xcb::setTransientFor(window(), new_property_value);
3389 return new_transient_for;
3392void X11Window::addTransient(
Window *cl)
3394 Window::addTransient(cl);
3395 if (
workspace()->mostRecentlyActivatedWindow() ==
this && cl->isModal()) {
3396 check_active_modal =
true;
3401void X11Window::checkTransient(xcb_window_t w)
3403 if (m_originalTransientForId != w) {
3406 w = verifyTransientFor(w,
true);
3412bool X11Window::hasTransient(
const Window *cl,
bool indirect)
const
3416 QList<const X11Window *> set;
3417 return hasTransientInternal(c, indirect, set);
3422bool X11Window::hasTransientInternal(
const X11Window *cl,
bool indirect, QList<const X11Window *> &set)
const
3431 if (set.contains(cl)) {
3435 return hasTransientInternal(t, indirect, set);
3440 if (group() != cl->
group()) {
3444 if (transients().contains(cl)) {
3450 if (set.contains(
this)) {
3454 for (
auto it = transients().constBegin(); it != transients().constEnd(); ++it) {
3455 const X11Window *c = qobject_cast<const X11Window *>(*it);
3459 if (c->hasTransientInternal(cl, indirect, set)) {
3466QList<Window *> X11Window::mainWindows()
const
3468 if (!isTransient()) {
3469 return QList<Window *>();
3471 if (
const Window *t = transientFor()) {
3472 return QList<Window *>{
const_cast<Window *
>(t)};
3474 QList<Window *> result;
3476 for (
auto it = group()->members().constBegin(); it != group()->members().constEnd(); ++it) {
3477 if ((*it)->hasTransient(
this,
false)) {
3484Window *X11Window::findModal(
bool allow_itself)
3486 for (
auto it = transients().constBegin(); it != transients().constEnd(); ++it) {
3491 if (isModal() && allow_itself) {
3500void X11Window::checkGroup(
Group *set_group,
bool force)
3502 Group *old_group = in_group;
3503 if (old_group !=
nullptr) {
3506 if (set_group !=
nullptr) {
3507 if (set_group != in_group) {
3508 if (in_group !=
nullptr) {
3509 in_group->removeMember(
this);
3511 in_group = set_group;
3514 }
else if (info->groupLeader() != XCB_WINDOW_NONE) {
3516 X11Window *t = qobject_cast<X11Window *>(transientFor());
3517 if (t !=
nullptr && t->
group() != new_group) {
3520 new_group = t->
group();
3522 if (new_group ==
nullptr) {
3523 new_group =
new Group(info->groupLeader());
3525 if (new_group != in_group) {
3526 if (in_group !=
nullptr) {
3527 in_group->removeMember(
this);
3529 in_group = new_group;
3533 if (
X11Window *t = qobject_cast<X11Window *>(transientFor())) {
3536 Group *new_group = t->group();
3537 if (new_group != in_group) {
3538 if (in_group !=
nullptr) {
3541 in_group = t->group();
3542 in_group->addMember(
this);
3544 }
else if (groupTransient()) {
3548 if (new_group ==
nullptr) {
3549 new_group =
new Group(XCB_WINDOW_NONE);
3551 if (new_group != in_group) {
3552 if (in_group !=
nullptr) {
3553 in_group->removeMember(
this);
3555 in_group = new_group;
3563 if (in_group !=
nullptr && in_group != new_group) {
3567 if (new_group ==
nullptr) {
3568 new_group =
new Group(XCB_WINDOW_NONE);
3570 if (in_group != new_group) {
3571 in_group = new_group;
3576 if (in_group != old_group || force) {
3577 for (
auto it = transients().constBegin(); it != transients().constEnd();) {
3580 if (c->groupTransient() && c->group() != group()) {
3581 removeTransientFromList(c);
3582 it = transients().constBegin();
3587 if (groupTransient()) {
3589 if (old_group !=
nullptr) {
3590 for (
auto it = old_group->
members().constBegin(); it != old_group->
members().constEnd(); ++it) {
3591 (*it)->removeTransient(
this);
3595 for (
auto it = group()->members().constBegin(); it != group()->members().constEnd(); ++it) {
3599 (*it)->addTransient(
this);
3604 for (
auto it = group()->members().constBegin(); it != group()->members().constEnd(); ++it) {
3605 if (!(*it)->isSplash()) {
3608 if (!(*it)->groupTransient()) {
3611 if (*it ==
this || hasTransient(*it,
true)) {
3617 if (old_group !=
nullptr) {
3620 checkGroupTransients();
3626void X11Window::changeClientLeaderGroup(
Group *gr)
3629 if (transientFor() !=
nullptr) {
3633 if (info->groupLeader()) {
3639bool X11Window::check_active_modal =
false;
3641void X11Window::checkActiveModal()
3647 if (check_modal !=
nullptr && check_modal->check_active_modal) {
3649 if (new_modal !=
nullptr && new_modal != check_modal) {
3650 if (!new_modal->isManaged()) {
3655 check_modal->check_active_modal =
false;
3659QSizeF X11Window::constrainClientSize(
const QSizeF &size,
SizeMode mode)
const
3661 qreal w = size.width();
3662 qreal h = size.height();
3673 QSizeF min_size = minSize();
3674 QSizeF max_size = maxSize();
3675 if (isDecorated()) {
3676 QSizeF decominsize(0, 0);
3677 QSizeF border_size(borderLeft() + borderRight(), borderTop() + borderBottom());
3678 if (border_size.width() > decominsize.width()) {
3679 decominsize.setWidth(border_size.width());
3681 if (border_size.height() > decominsize.height()) {
3682 decominsize.setHeight(border_size.height());
3684 if (decominsize.width() > min_size.width()) {
3685 min_size.setWidth(decominsize.width());
3687 if (decominsize.height() > min_size.height()) {
3688 min_size.setHeight(decominsize.height());
3691 w = std::min(max_size.width(), w);
3692 h = std::min(max_size.height(), h);
3693 w = std::max(min_size.width(), w);
3694 h = std::max(min_size.height(), h);
3696 if (!rules()->checkStrictGeometry(!isFullScreen())) {
3698 return QSizeF(w, h);
3701 qreal width_inc = m_geometryHints.resizeIncrements().width();
3702 qreal height_inc = m_geometryHints.resizeIncrements().height();
3703 qreal basew_inc = m_geometryHints.baseSize().width();
3704 qreal baseh_inc = m_geometryHints.baseSize().height();
3705 if (!m_geometryHints.hasBaseSize()) {
3706 basew_inc = m_geometryHints.minSize().width();
3707 baseh_inc = m_geometryHints.minSize().height();
3710 w = std::floor((w - basew_inc) / width_inc) * width_inc + basew_inc;
3711 h = std::floor((h - baseh_inc) / height_inc) * height_inc + baseh_inc;
3728 if (m_geometryHints.hasAspect()) {
3729 double min_aspect_w = m_geometryHints.minAspect().width();
3730 double min_aspect_h = m_geometryHints.minAspect().height();
3731 double max_aspect_w = m_geometryHints.maxAspect().width();
3732 double max_aspect_h = m_geometryHints.maxAspect().height();
3736 const QSizeF baseSize = m_geometryHints.baseSize();
3737 w -= baseSize.width();
3738 h -= baseSize.height();
3739 qreal max_width = max_size.width() - baseSize.width();
3740 qreal min_width = min_size.width() - baseSize.width();
3741 qreal max_height = max_size.height() - baseSize.height();
3742 qreal min_height = min_size.height() - baseSize.height();
3743#define ASPECT_CHECK_GROW_W \
3744 if (min_aspect_w * h > min_aspect_h * w) { \
3745 int delta = int(min_aspect_w * h / min_aspect_h - w) / width_inc * width_inc; \
3746 if (w + delta <= max_width) \
3749#define ASPECT_CHECK_SHRINK_H_GROW_W \
3750 if (min_aspect_w * h > min_aspect_h * w) { \
3751 int delta = int(h - w * min_aspect_h / min_aspect_w) / height_inc * height_inc; \
3752 if (h - delta >= min_height) \
3755 int delta = int(min_aspect_w * h / min_aspect_h - w) / width_inc * width_inc; \
3756 if (w + delta <= max_width) \
3760#define ASPECT_CHECK_GROW_H \
3761 if (max_aspect_w * h < max_aspect_h * w) { \
3762 int delta = int(w * max_aspect_h / max_aspect_w - h) / height_inc * height_inc; \
3763 if (h + delta <= max_height) \
3766#define ASPECT_CHECK_SHRINK_W_GROW_H \
3767 if (max_aspect_w * h < max_aspect_h * w) { \
3768 int delta = int(w - max_aspect_w * h / max_aspect_h) / width_inc * width_inc; \
3769 if (w - delta >= min_width) \
3772 int delta = int(w * max_aspect_h / max_aspect_w - h) / height_inc * height_inc; \
3773 if (h + delta <= max_height) \
3789 case SizeModeFixedW: {
3797 case SizeModeFixedH: {
3813#undef ASPECT_CHECK_SHRINK_H_GROW_W
3814#undef ASPECT_CHECK_SHRINK_W_GROW_H
3815#undef ASPECT_CHECK_GROW_W
3816#undef ASPECT_CHECK_GROW_H
3817 w += baseSize.width();
3818 h += baseSize.height();
3821 return QSizeF(w, h);
3824void X11Window::getResourceClass()
3826 setResourceClass(QString::fromLatin1(info->windowClassName()), QString::fromLatin1(info->windowClassClass()));
3832void X11Window::getWmNormalHints()
3834 if (isUnmanaged()) {
3837 const bool hadFixedAspect = m_geometryHints.hasAspect();
3839 m_geometryHints.fetch();
3840 m_geometryHints.read();
3842 if (!hadFixedAspect && m_geometryHints.hasAspect()) {
3848 QSizeF new_size = clientSizeToFrameSize(constrainClientSize(clientSize()));
3849 if (new_size != size() && !isFullScreen()) {
3850 QRectF origClientGeometry = m_clientGeometry;
3851 moveResize(resizeWithChecks(moveResizeGeometry(), new_size));
3852 if ((!isSpecialWindow() || isToolbar()) && !isFullScreen()) {
3856 if (area.contains(origClientGeometry)) {
3860 if (area.contains(origClientGeometry)) {
3866 updateAllowedActions();
3869QSizeF X11Window::minSize()
const
3871 return rules()->checkMinSize(m_geometryHints.minSize());
3874QSizeF X11Window::maxSize()
const
3876 return rules()->checkMaxSize(m_geometryHints.maxSize());
3879QSizeF X11Window::basicUnit()
const
3881 return m_geometryHints.resizeIncrements();
3888void X11Window::sendSyntheticConfigureNotify()
3893 xcb_configure_notify_event_t event;
3896 static_assert(
sizeof(u.event) < 32,
"wouldn't need the union otherwise");
3897 memset(&u, 0,
sizeof(u));
3898 xcb_configure_notify_event_t &c = u.event;
3899 u.event.response_type = XCB_CONFIGURE_NOTIFY;
3900 u.event.event = window();
3901 u.event.window = window();
3902 u.event.x = Xcb::toXNative(m_clientGeometry.x());
3903 u.event.y = Xcb::toXNative(m_clientGeometry.y());
3904 u.event.width = Xcb::toXNative(m_clientGeometry.width());
3905 u.event.height = Xcb::toXNative(m_clientGeometry.height());
3906 u.event.border_width = 0;
3907 u.event.above_sibling = XCB_WINDOW_NONE;
3908 u.event.override_redirect = 0;
3909 xcb_send_event(kwinApp()->x11Connection(),
true, c.event, XCB_EVENT_MASK_STRUCTURE_NOTIFY,
reinterpret_cast<const char *
>(&u));
3910 xcb_flush(kwinApp()->x11Connection());
3913void X11Window::handleXwaylandScaleChanged()
3917 resize(moveResizeGeometry().size());
3920QPointF X11Window::gravityAdjustment(xcb_gravity_t gravity)
const
3932 case XCB_GRAVITY_NORTH_WEST:
3937 case XCB_GRAVITY_NORTH:
3941 case XCB_GRAVITY_NORTH_EAST:
3942 dx = -borderRight();
3945 case XCB_GRAVITY_WEST:
3949 case XCB_GRAVITY_CENTER:
3950 dx = (borderLeft() - borderRight()) / 2;
3951 dy = (borderTop() - borderBottom()) / 2;
3953 case XCB_GRAVITY_STATIC:
3957 case XCB_GRAVITY_EAST:
3958 dx = -borderRight();
3961 case XCB_GRAVITY_SOUTH_WEST:
3963 dy = -borderBottom();
3965 case XCB_GRAVITY_SOUTH:
3967 dy = -borderBottom();
3969 case XCB_GRAVITY_SOUTH_EAST:
3970 dx = -borderRight();
3971 dy = -borderBottom();
3975 return QPoint(dx, dy);
3978const QPointF X11Window::calculateGravitation(
bool invert)
const
3980 const QPointF adjustment = gravityAdjustment(m_geometryHints.windowGravity());
3983 const qreal dx = adjustment.x() - borderLeft();
3984 const qreal dy = adjustment.y() - borderTop();
3987 return QPointF(x() + dx, y() + dy);
3989 return QPointF(x() - dx, y() - dy);
3994void X11Window::configureRequest(
int value_mask, qreal rx, qreal ry, qreal rw, qreal rh,
int gravity,
bool from_tool)
3996 const int configurePositionMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
3997 const int configureSizeMask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
3998 const int configureGeometryMask = configurePositionMask | configureSizeMask;
4002 qCDebug(KWIN_CORE) <<
this << bool(value_mask & configureGeometryMask) << bool(maximizeMode() & MaximizeVertical) << bool(maximizeMode() & MaximizeHorizontal);
4005 bool ignore = !app_noborder && (quickTileMode() != QuickTileMode(QuickTileFlag::None) || maximizeMode() !=
MaximizeRestore);
4007 ignore = rules()->checkIgnoreGeometry(ignore);
4009 updateQuickTileMode(QuickTileFlag::None);
4011 Q_EMIT quickTileModeChanged();
4012 }
else if (!app_noborder && quickTileMode() == QuickTileMode(QuickTileFlag::None) && (maximizeMode() == MaximizeVertical || maximizeMode() == MaximizeHorizontal)) {
4018 ignore = rules()->checkIgnoreGeometry(
false);
4020 if (maximizeMode() == MaximizeVertical) {
4021 value_mask &= ~(XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_HEIGHT);
4024 value_mask &= ~(XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_WIDTH);
4026 if (!(value_mask & configureGeometryMask)) {
4033 qCDebug(KWIN_CORE) <<
"DENIED";
4037 qCDebug(KWIN_CORE) <<
"PERMITTED" <<
this << bool(value_mask & configureGeometryMask);
4040 gravity = m_geometryHints.windowGravity();
4042 if (value_mask & configurePositionMask) {
4043 QPointF new_pos = framePosToClientPos(pos());
4044 new_pos -= gravityAdjustment(xcb_gravity_t(gravity));
4045 if (value_mask & XCB_CONFIG_WINDOW_X) {
4048 if (value_mask & XCB_CONFIG_WINDOW_Y) {
4051 new_pos += gravityAdjustment(xcb_gravity_t(gravity));
4052 new_pos = clientPosToFramePos(new_pos);
4054 qreal nw = clientSize().width();
4055 qreal nh = clientSize().height();
4056 if (value_mask & XCB_CONFIG_WINDOW_WIDTH) {
4059 if (value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
4062 const QSizeF requestedClientSize = constrainClientSize(QSizeF(nw, nh));
4063 QSizeF requestedFrameSize = clientSizeToFrameSize(requestedClientSize);
4064 requestedFrameSize = rules()->checkSize(requestedFrameSize);
4065 new_pos = rules()->checkPosition(new_pos);
4067 Output *newOutput =
workspace()->
outputAt(QRectF(new_pos, requestedFrameSize).center());
4068 if (newOutput != rules()->checkOutput(newOutput)) {
4072 QRectF origClientGeometry = m_clientGeometry;
4073 GeometryUpdatesBlocker blocker(
this);
4075 resize(requestedFrameSize);
4077 if (!from_tool && (!isSpecialWindow() || isToolbar()) && !isFullScreen()
4078 && area.contains(origClientGeometry)) {
4091 if (value_mask & configureSizeMask && !(value_mask & configurePositionMask)) {
4092 qreal nw = clientSize().width();
4093 qreal nh = clientSize().height();
4094 if (value_mask & XCB_CONFIG_WINDOW_WIDTH) {
4097 if (value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
4101 const QSizeF requestedClientSize = constrainClientSize(QSizeF(nw, nh));
4102 QSizeF requestedFrameSize = clientSizeToFrameSize(requestedClientSize);
4103 requestedFrameSize = rules()->checkSize(requestedFrameSize);
4105 if (requestedFrameSize != size()) {
4106 QRectF origClientGeometry = m_clientGeometry;
4107 GeometryUpdatesBlocker blocker(
this);
4108 moveResize(resizeWithChecks(moveResizeGeometry(), requestedFrameSize, xcb_gravity_t(gravity)));
4109 if (!from_tool && (!isSpecialWindow() || isToolbar()) && !isFullScreen()) {
4113 if (area.contains(origClientGeometry)) {
4117 if (area.contains(origClientGeometry)) {
4128QRectF X11Window::resizeWithChecks(
const QRectF &geometry, qreal w, qreal h, xcb_gravity_t gravity)
4130 Q_ASSERT(!shade_geometry_change);
4132 if (h == borderTop() + borderBottom()) {
4133 qCWarning(KWIN_CORE) <<
"Shaded geometry passed for size:";
4136 qreal newx = geometry.x();
4137 qreal newy = geometry.y();
4140 if (w > area.width()) {
4143 if (h > area.height()) {
4146 QSizeF tmp = constrainFrameSize(QSizeF(w, h));
4150 gravity = m_geometryHints.windowGravity();
4153 case XCB_GRAVITY_NORTH_WEST:
4156 case XCB_GRAVITY_NORTH:
4157 newx = (newx + geometry.width() / 2) - (w / 2);
4159 case XCB_GRAVITY_NORTH_EAST:
4160 newx = newx + geometry.width() - w;
4162 case XCB_GRAVITY_WEST:
4163 newy = (newy + geometry.height() / 2) - (h / 2);
4165 case XCB_GRAVITY_CENTER:
4166 newx = (newx + geometry.width() / 2) - (w / 2);
4167 newy = (newy + geometry.height() / 2) - (h / 2);
4169 case XCB_GRAVITY_STATIC:
4172 case XCB_GRAVITY_EAST:
4173 newx = newx + geometry.width() - w;
4174 newy = (newy + geometry.height() / 2) - (h / 2);
4176 case XCB_GRAVITY_SOUTH_WEST:
4177 newy = newy + geometry.height() - h;
4179 case XCB_GRAVITY_SOUTH:
4180 newx = (newx + geometry.width() / 2) - (w / 2);
4181 newy = newy + geometry.height() - h;
4183 case XCB_GRAVITY_SOUTH_EAST:
4184 newx = newx + geometry.width() - w;
4185 newy = newy + geometry.height() - h;
4188 return QRectF{newx, newy, w, h};
4193void X11Window::NETMoveResizeWindow(
int flags, qreal x, qreal y, qreal width, qreal height)
4195 int gravity = flags & 0xff;
4197 if (flags & (1 << 8)) {
4198 value_mask |= XCB_CONFIG_WINDOW_X;
4200 if (flags & (1 << 9)) {
4201 value_mask |= XCB_CONFIG_WINDOW_Y;
4203 if (flags & (1 << 10)) {
4204 value_mask |= XCB_CONFIG_WINDOW_WIDTH;
4206 if (flags & (1 << 11)) {
4207 value_mask |= XCB_CONFIG_WINDOW_HEIGHT;
4209 configureRequest(value_mask, x, y, width, height, gravity,
true);
4213void X11Window::GTKShowWindowMenu(qreal x_root, qreal y_root)
4215 QPoint globalPos(x_root, y_root);
4219bool X11Window::isMovable()
const
4221 if (isUnmanaged()) {
4224 if (!hasNETSupport() && !m_motif.move()) {
4227 if (isFullScreen()) {
4230 if (isSpecialWindow() && !isSplash() && !isToolbar()) {
4239bool X11Window::isMovableAcrossScreens()
const
4241 if (isUnmanaged()) {
4244 if (!hasNETSupport() && !m_motif.move()) {
4247 if (isSpecialWindow() && !isSplash() && !isToolbar()) {
4256bool X11Window::isResizable()
const
4258 if (isUnmanaged()) {
4261 if (!hasNETSupport() && !m_motif.resize()) {
4264 if (isFullScreen()) {
4267 if (isSpecialWindow() || isSplash() || isToolbar()) {
4270 if (rules()->checkSize(QSize()).isValid()) {
4273 const Gravity gravity = interactiveMoveResizeGravity();
4274 if ((gravity == Gravity::Top || gravity == Gravity::TopLeft || gravity == Gravity::TopRight || gravity == Gravity::Left || gravity == Gravity::BottomLeft) && rules()->checkPosition(
invalidPoint) !=
invalidPoint) {
4278 QSizeF min = minSize();
4279 QSizeF max = maxSize();
4280 return min.width() < max.width() || min.height() < max.height();
4283bool X11Window::isMaximizable()
const
4285 if (isUnmanaged()) {
4288 if (!isResizable() || isToolbar()) {
4291 if (isAppletPopup()) {
4316 if (isUnmanaged()) {
4317 qCWarning(KWIN_CORE) <<
"Cannot move or resize unmanaged window" <<
this;
4321 QRectF frameGeometry = Xcb::fromXNative(Xcb::toXNative(rect));
4323 if (shade_geometry_change) {
4325 }
else if (isShade()) {
4326 if (frameGeometry.height() == borderTop() + borderBottom()) {
4327 qCDebug(KWIN_CORE) <<
"Shaded geometry passed for size:";
4329 m_clientGeometry = frameRectToClientRect(frameGeometry);
4330 frameGeometry.setHeight(borderTop() + borderBottom());
4333 m_clientGeometry = frameRectToClientRect(frameGeometry);
4335 m_frameGeometry = frameGeometry;
4336 m_bufferGeometry = frameRectToBufferRect(frameGeometry);
4338 if (pendingMoveResizeMode() == MoveResizeMode::None && m_lastBufferGeometry == m_bufferGeometry && m_lastFrameGeometry == m_frameGeometry && m_lastClientGeometry == m_clientGeometry) {
4343 if (areGeometryUpdatesBlocked()) {
4344 setPendingMoveResizeMode(mode);
4348 Q_EMIT frameGeometryAboutToChange();
4349 const QRectF oldBufferGeometry = m_lastBufferGeometry;
4350 const QRectF oldFrameGeometry = m_lastFrameGeometry;
4351 const QRectF oldClientGeometry = m_lastClientGeometry;
4352 const Output *oldOutput = m_lastOutput;
4354 updateServerGeometry();
4355 updateWindowRules(Rules::Position | Rules::Size);
4357 m_lastBufferGeometry = m_bufferGeometry;
4358 m_lastFrameGeometry = m_frameGeometry;
4359 m_lastClientGeometry = m_clientGeometry;
4360 m_lastOutput = m_output;
4367 if (oldBufferGeometry != m_bufferGeometry) {
4368 Q_EMIT bufferGeometryChanged(oldBufferGeometry);
4370 if (oldClientGeometry != m_clientGeometry) {
4371 Q_EMIT clientGeometryChanged(oldClientGeometry);
4373 if (oldFrameGeometry != m_frameGeometry) {
4374 Q_EMIT frameGeometryChanged(oldFrameGeometry);
4376 if (oldOutput != m_output) {
4377 Q_EMIT outputChanged();
4379 Q_EMIT shapeChanged();
4382void X11Window::updateServerGeometry()
4384 const QRectF oldBufferGeometry = m_lastBufferGeometry;
4387 const QRectF oldClientRect = m_lastClientGeometry.translated(-m_lastBufferGeometry.topLeft());
4388 const QRectF clientRect = m_clientGeometry.translated(-m_bufferGeometry.topLeft());
4390 if (oldBufferGeometry.size() != m_bufferGeometry.size() || oldClientRect != clientRect) {
4395 if (m_frame.geometry() != m_bufferGeometry) {
4396 m_frame.setGeometry(m_bufferGeometry);
4399 if (m_wrapper.geometry() != clientRect) {
4400 m_wrapper.setGeometry(clientRect);
4402 if (m_client.geometry() != QRectF(QPointF(0, 0), clientRect.size())) {
4403 m_client.setGeometry(QRectF(QPointF(0, 0), clientRect.size()));
4407 sendSyntheticConfigureNotify();
4411 m_frame.move(m_bufferGeometry.topLeft());
4412 sendSyntheticConfigureNotify();
4414 m_decoInputExtent.move(pos().toPoint() + inputPos());
4418static bool changeMaximizeRecursion =
false;
4421 if (isUnmanaged()) {
4422 qCWarning(KWIN_CORE) <<
"Cannot change maximized state of unmanaged window" <<
this;
4426 if (changeMaximizeRecursion) {
4430 if (!isResizable() || isToolbar()) {
4433 if (!isMaximizable()) {
4438 if (isElectricBorderMaximizing()) {
4448 if (m_geometryHints.hasAspect() &&
4450 rules()->checkStrictGeometry(
true)) {
4451 const QSize minAspect = m_geometryHints.minAspect();
4452 const QSize maxAspect = m_geometryHints.maxAspect();
4454 const double fx = minAspect.width();
4455 const double fy = maxAspect.height();
4456 if (fx * clientArea.height() / fy > clientArea.width()) {
4460 const double fx = maxAspect.width();
4461 const double fy = minAspect.height();
4462 if (fy * clientArea.width() / fx > clientArea.height()) {
4468 mode = rules()->checkMaximize(mode);
4469 if (max_mode == mode) {
4473 blockGeometryUpdates(
true);
4482 Q_EMIT maximizedAboutToChange(mode);
4488 sz = implicitSize();
4493 if (quickTileMode() == QuickTileMode(QuickTileFlag::None)) {
4494 QRectF savedGeometry = geometryRestore();
4496 savedGeometry.setTop(y());
4497 savedGeometry.setHeight(sz.height());
4500 savedGeometry.setLeft(x());
4501 savedGeometry.setWidth(sz.width());
4503 setGeometryRestore(savedGeometry);
4508 changeMaximizeRecursion =
true;
4509 const auto c = decoration()->client();
4519 changeMaximizeRecursion =
false;
4525 changeMaximizeRecursion =
true;
4526 setNoBorder(rules()->checkNoBorder(app_noborder || (m_motif.hasDecoration() && m_motif.noBorder()) || max_mode ==
MaximizeFull));
4527 changeMaximizeRecursion =
false;
4531 if (quickTileMode() != QuickTileMode(QuickTileFlag::None)) {
4532 if (old_mode ==
MaximizeFull && !clientArea.contains(geometryRestore().center())) {
4538 updateQuickTileMode(QuickTileFlag::None);
4546 if (geometryRestore().width() == 0 || !clientArea.contains(geometryRestore().center())) {
4548 resize(constrainFrameSize(QSize(width() * 2 / 3, clientArea.height()), SizeModeFixedH));
4551 moveResize(QRectF(QPointF(geometryRestore().x(), clientArea.top()),
4552 constrainFrameSize(QSize(geometryRestore().width(), clientArea.height()), SizeModeFixedH)));
4555 QRectF r(x(), clientArea.top(), width(), clientArea.height());
4556 r.setTopLeft(rules()->checkPosition(r.topLeft()));
4557 r.setSize(constrainFrameSize(r.size(), SizeModeFixedH));
4560 info->setState(NET::MaxVert, NET::Max);
4566 if (geometryRestore().height() == 0 || !clientArea.contains(geometryRestore().center())) {
4568 resize(constrainFrameSize(QSize(clientArea.width(), height() * 2 / 3), SizeModeFixedW));
4571 moveResize(QRectF(QPoint(clientArea.left(), geometryRestore().y()),
4572 constrainFrameSize(QSize(clientArea.width(), geometryRestore().height()), SizeModeFixedW)));
4575 QRectF r(clientArea.left(), y(), clientArea.width(), height());
4576 r.setTopLeft(rules()->checkPosition(r.topLeft()));
4577 r.setSize(constrainFrameSize(r.size(), SizeModeFixedW));
4580 info->setState(NET::MaxHoriz, NET::Max);
4585 QRectF restore = moveResizeGeometry();
4588 restore.setTop(geometryRestore().top());
4589 restore.setBottom(geometryRestore().bottom());
4592 restore.setLeft(geometryRestore().left());
4593 restore.setRight(geometryRestore().right());
4595 if (!restore.isValid()) {
4596 QSize s = QSize(clientArea.width() * 2 / 3, clientArea.height() * 2 / 3);
4597 if (geometryRestore().width() > 0) {
4598 s.setWidth(geometryRestore().width());
4600 if (geometryRestore().height() > 0) {
4601 s.setHeight(geometryRestore().height());
4603 resize(constrainFrameSize(s));
4605 restore = moveResizeGeometry();
4606 if (geometryRestore().width() > 0) {
4607 restore.moveLeft(geometryRestore().x());
4609 if (geometryRestore().height() > 0) {
4610 restore.moveTop(geometryRestore().y());
4612 setGeometryRestore(restore);
4614 if (m_geometryHints.hasAspect()) {
4615 restore.setSize(constrainFrameSize(restore.size(), SizeModeAny));
4617 moveResize(restore);
4618 if (!clientArea.contains(geometryRestore().center())) {
4621 info->setState(NET::States(), NET::Max);
4622 updateQuickTileMode(QuickTileFlag::None);
4627 QRectF r(clientArea);
4628 r.setTopLeft(rules()->checkPosition(r.topLeft()));
4629 r.setSize(constrainFrameSize(r.size(), SizeModeMax));
4630 if (r.size() != clientArea.size()) {
4631 if (isElectricBorderMaximizing() && r.width() < clientArea.width()) {
4632 r.moveLeft(std::max(clientArea.left(), Cursors::self()->mouse()->pos().x() - r.width() / 2));
4633 r.moveRight(std::min(clientArea.right(), r.right()));
4635 r.moveCenter(clientArea.center());
4636 const bool closeHeight = r.height() > 97 * clientArea.height() / 100;
4637 const bool closeWidth = r.width() > 97 * clientArea.width() / 100;
4638 const bool overHeight = r.height() > clientArea.height();
4639 const bool overWidth = r.width() > clientArea.width();
4640 if (closeWidth || closeHeight) {
4641 Qt::Edge titlePos = titlebarPosition();
4644 bool tryBottom = titlePos == Qt::BottomEdge;
4645 if ((overHeight && titlePos == Qt::TopEdge) || screenArea.top() == clientArea.top()) {
4646 r.setTop(clientArea.top());
4650 if (tryBottom && (overHeight || screenArea.bottom() == clientArea.bottom())) {
4651 r.setBottom(clientArea.bottom());
4655 bool tryLeft = titlePos == Qt::LeftEdge;
4656 if ((overWidth && titlePos == Qt::RightEdge) || screenArea.right() == clientArea.right()) {
4657 r.setRight(clientArea.right());
4661 if (tryLeft && (overWidth || screenArea.left() == clientArea.left())) {
4662 r.setLeft(clientArea.left());
4667 r.moveTopLeft(rules()->checkPosition(r.topLeft()));
4671 r = Xcb::nativeFloor(r);
4675 updateQuickTileMode(QuickTileFlag::Maximize);
4677 updateQuickTileMode(QuickTileFlag::None);
4680 info->setState(NET::Max, NET::Max);
4687 blockGeometryUpdates(
false);
4688 updateAllowedActions();
4689 updateWindowRules(Rules::MaximizeVert | Rules::MaximizeHoriz | Rules::Position | Rules::Size);
4690 Q_EMIT quickTileModeChanged();
4692 if (max_mode != old_mode) {
4693 Q_EMIT maximizedChanged();
4697void X11Window::setFullScreen(
bool set)
4699 set = rules()->checkFullScreen(set);
4701 const bool wasFullscreen = isFullScreen();
4702 if (wasFullscreen == set) {
4705 if (!isFullScreenable()) {
4711 if (wasFullscreen) {
4714 setFullscreenGeometryRestore(moveResizeGeometry());
4718 m_fullscreenMode = FullScreenNormal;
4721 m_fullscreenMode = FullScreenNone;
4730 info->setState(isFullScreen() ? NET::FullScreen : NET::States(), NET::FullScreen);
4731 updateDecoration(
false,
false);
4734 if (info->fullscreenMonitors().isSet()) {
4735 moveResize(fullscreenMonitorsArea(info->fullscreenMonitors()));
4740 Q_ASSERT(!fullscreenGeometryRestore().isNull());
4741 moveResize(QRectF(fullscreenGeometryRestore().topLeft(), constrainFrameSize(fullscreenGeometryRestore().size())));
4744 updateWindowRules(Rules::Fullscreen | Rules::Position | Rules::Size);
4745 updateAllowedActions(
false);
4746 Q_EMIT fullScreenChanged();
4749void X11Window::updateFullscreenMonitors(NETFullscreenMonitors topology)
4757 if (topology.top >= outputCount || topology.bottom >= outputCount || topology.left >= outputCount || topology.right >= outputCount) {
4758 qCWarning(KWIN_CORE) <<
"fullscreenMonitors update failed. request higher than number of screens.";
4762 info->setFullscreenMonitors(topology);
4763 if (isFullScreen()) {
4764 moveResize(fullscreenMonitorsArea(topology));
4772QRect X11Window::fullscreenMonitorsArea(NETFullscreenMonitors requestedTopology)
const
4776 if (
auto output =
workspace()->xineramaIndexToOutput(requestedTopology.top)) {
4777 total = total.united(output->geometry());
4779 if (
auto output = workspace()->xineramaIndexToOutput(requestedTopology.bottom)) {
4780 total = total.united(output->geometry());
4782 if (
auto output =
workspace()->xineramaIndexToOutput(requestedTopology.left)) {
4783 total = total.united(output->geometry());
4785 if (
auto output =
workspace()->xineramaIndexToOutput(requestedTopology.right)) {
4786 total = total.united(output->geometry());
4792bool X11Window::doStartInteractiveMoveResize()
4794 if (kwinApp()->operationMode() == Application::OperationModeX11) {
4795 bool has_grab =
false;
4800 m_moveResizeGrabWindow.create(Xcb::toXNative(r), XCB_WINDOW_CLASS_INPUT_ONLY, 0,
nullptr, kwinApp()->x11RootWindow());
4801 m_moveResizeGrabWindow.map();
4802 m_moveResizeGrabWindow.raise();
4803 kwinApp()->updateXTime();
4804 const xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer_unchecked(kwinApp()->x11Connection(),
false, m_moveResizeGrabWindow,
4805 XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW,
4806 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, m_moveResizeGrabWindow, Cursors::self()->mouse()->x11Cursor(cursor()),
xTime());
4808 if (pointerGrab && pointerGrab->status == XCB_GRAB_STATUS_SUCCESS) {
4812 has_grab = move_resize_has_keyboard_grab =
true;
4815 m_moveResizeGrabWindow.reset();
4822void X11Window::leaveInteractiveMoveResize()
4824 if (kwinApp()->operationMode() == Application::OperationModeX11) {
4825 if (move_resize_has_keyboard_grab) {
4828 move_resize_has_keyboard_grab =
false;
4829 xcb_ungrab_pointer(kwinApp()->x11Connection(), xTime());
4830 m_moveResizeGrabWindow.reset();
4832 Window::leaveInteractiveMoveResize();
4835bool X11Window::isWaitingForInteractiveMoveResizeSync()
const
4837 return m_syncRequest.isPending && m_syncRequest.interactiveResize;
4840void X11Window::doInteractiveResizeSync(
const QRectF &rect)
4842 setMoveResizeGeometry(rect);
4844 if (!m_syncRequest.timeout) {
4845 m_syncRequest.timeout =
new QTimer(
this);
4846 connect(m_syncRequest.timeout, &QTimer::timeout,
this, &X11Window::handleSyncTimeout);
4847 m_syncRequest.timeout->setSingleShot(
true);
4850 if (m_syncRequest.counter != XCB_NONE) {
4851 m_syncRequest.timeout->start(250);
4857 m_syncRequest.isPending =
true;
4858 m_syncRequest.interactiveResize =
true;
4859 m_syncRequest.timeout->start(33);
4862 const QRectF moveResizeClientGeometry = frameRectToClientRect(moveResizeGeometry());
4863 const QRectF moveResizeBufferGeometry = frameRectToBufferRect(moveResizeGeometry());
4869 m_frame.setGeometry(moveResizeBufferGeometry);
4870 m_wrapper.setGeometry(moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft()));
4871 m_client.setGeometry(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
4874void X11Window::handleSyncTimeout()
4876 if (m_syncRequest.counter == XCB_NONE) {
4877 m_syncRequest.isPending =
false;
4878 m_syncRequest.interactiveResize =
false;
4880 performInteractiveResize();
4883NETExtendedStrut X11Window::strut()
const
4885 NETExtendedStrut ext = info->extendedStrut();
4886 NETStrut str = info->strut();
4888 if (ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
4889 && (str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0)) {
4891 if (str.left != 0) {
4892 ext.left_width = str.left;
4894 ext.left_end = displaySize.height();
4896 if (str.right != 0) {
4897 ext.right_width = str.right;
4898 ext.right_start = 0;
4899 ext.right_end = displaySize.height();
4902 ext.top_width = str.top;
4904 ext.top_end = displaySize.width();
4906 if (str.bottom != 0) {
4907 ext.bottom_width = str.bottom;
4908 ext.bottom_start = 0;
4909 ext.bottom_end = displaySize.width();
4919 NETExtendedStrut strutArea = strut();
4922 if (strutArea.top_width != 0) {
4924 strutArea.top_start, 0,
4925 strutArea.top_end - strutArea.top_start, strutArea.top_width),
4930 if (strutArea.right_width != 0) {
4932 displaySize.width() - strutArea.right_width, strutArea.right_start,
4933 strutArea.right_width, strutArea.right_end - strutArea.right_start),
4938 if (strutArea.bottom_width != 0) {
4940 strutArea.bottom_start, displaySize.height() - strutArea.bottom_width,
4941 strutArea.bottom_end - strutArea.bottom_start, strutArea.bottom_width),
4946 if (strutArea.left_width != 0) {
4948 0, strutArea.left_start,
4949 strutArea.left_width, strutArea.left_end - strutArea.left_start),
4959bool X11Window::hasStrut()
const
4961 NETExtendedStrut ext = strut();
4962 if (ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0) {
4968void X11Window::applyWindowRules()
4970 Window::applyWindowRules();
4971 updateAllowedActions();
4972 setBlockingCompositing(info->isBlockingCompositing());
4975bool X11Window::supportsWindowRules()
const
4977 return !isUnmanaged();
4980void X11Window::updateWindowRules(Rules::Types selection)
4985 Window::updateWindowRules(selection);
4988void X11Window::damageNotifyEvent()
4990 Q_ASSERT(kwinApp()->operationMode() == Application::OperationModeX11);
4992 if (!readyForPainting()) {
4993 if (m_syncRequest.counter == XCB_NONE) {
4994 setReadyForPainting();
4998 SurfaceItemX11 *item =
static_cast<SurfaceItemX11 *
>(surfaceItem());
5000 item->processDamage();
5004void X11Window::discardWindowPixmap()
5006 if (
auto item = surfaceItem()) {
5007 item->discardPixmap();
5011void X11Window::updateWindowPixmap()
5013 if (
auto item = surfaceItem()) {
5014 item->updatePixmap();
5018void X11Window::associate()
5020 auto handleMapped = [
this]() {
5021 if (syncRequest().counter == XCB_NONE) {
5022 setReadyForPainting();
5026 if (surface()->isMapped()) {
5031 connect(surface(), &SurfaceInterface::mapped,
this, handleMapped, Qt::QueuedConnection);
5034 m_pendingSurfaceId = 0;
5037QWindow *X11Window::findInternalWindow()
const
5039 const QWindowList windows = kwinApp()->topLevelWindows();
5040 for (QWindow *w : windows) {
5041 if (w->handle() && w->winId() == window()) {
5048void X11Window::checkOutput()
5050 setOutput(
workspace()->outputAt(frameGeometry().center()));
5053void X11Window::getWmOpaqueRegion()
5055 const auto rects = info->opaqueRegion();
5056 QRegion new_opaque_region;
5057 for (
const auto &r : rects) {
5058 new_opaque_region += Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height)).toRect();
5060 opaque_region = new_opaque_region;
5063QList<QRectF> X11Window::shapeRegion()
const
5065 if (m_shapeRegionIsValid) {
5066 return m_shapeRegion;
5069 const QRectF bufferGeometry = this->bufferGeometry();
5072 auto cookie = xcb_shape_get_rectangles_unchecked(kwinApp()->x11Connection(), frameId(), XCB_SHAPE_SK_BOUNDING);
5075 m_shapeRegion.clear();
5076 const xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.get());
5077 const int rectCount = xcb_shape_get_rectangles_rectangles_length(reply.get());
5078 for (
int i = 0; i < rectCount; ++i) {
5079 QRectF region = Xcb::fromXNative(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)).toAlignedRect();
5081 region = region.intersected(QRectF(QPointF(0, 0), bufferGeometry.size()));
5083 m_shapeRegion += region;
5086 m_shapeRegion.clear();
5089 m_shapeRegion = {QRectF(0, 0, bufferGeometry.width(), bufferGeometry.height())};
5092 m_shapeRegionIsValid =
true;
5093 return m_shapeRegion;
5096void X11Window::discardShapeRegion()
5098 m_shapeRegionIsValid =
false;
5099 m_shapeRegion.clear();
5102Xcb::Property X11Window::fetchWmClientLeader()
const
5104 return Xcb::Property(
false, window(), atoms->
wm_client_leader, XCB_ATOM_WINDOW, 0, 10000);
5107void X11Window::readWmClientLeader(Xcb::Property &prop)
5109 m_wmClientLeader = prop.value<xcb_window_t>(window());
5112void X11Window::getWmClientLeader()
5114 if (isUnmanaged()) {
5117 auto prop = fetchWmClientLeader();
5118 readWmClientLeader(prop);
5121int X11Window::desktopId()
const
5123 return m_desktops.isEmpty() ? -1 : m_desktops.last()->x11DesktopNumber();
5130QByteArray X11Window::sessionId()
const
5133 if (result.isEmpty() && m_wmClientLeader && m_wmClientLeader != window()) {
5143QString X11Window::wmCommand()
5146 if (result.isEmpty() && m_wmClientLeader && m_wmClientLeader != window()) {
5149 result.replace(0,
' ');
5157xcb_window_t X11Window::wmClientLeader()
const
5159 if (m_wmClientLeader != XCB_WINDOW_NONE) {
5160 return m_wmClientLeader;
5165void X11Window::getWmClientMachine()
5167 clientMachine()->resolve(window(), wmClientLeader());
5170Xcb::Property X11Window::fetchSkipCloseAnimation()
const
5175void X11Window::readSkipCloseAnimation(Xcb::Property &property)
5177 setSkipCloseAnimation(property.toBool());
5180void X11Window::getSkipCloseAnimation()
5182 Xcb::Property
property = fetchSkipCloseAnimation();
5183 readSkipCloseAnimation(property);
5188#include "moc_x11window.cpp"
void xwaylandScaleChanged()
@ OperationModeXwayland
KWin uses Wayland and controls a nested Xwayland server.
@ OperationModeX11
KWin uses only X11 for managing windows and compositing.
@ OperationModeWaylandOnly
KWin uses only Wayland.
Xcb::Atom kde_skip_close_animation
Xcb::Atom wm_delete_window
Xcb::Atom kde_net_wm_appmenu_object_path
Xcb::Atom net_wm_sync_request
Xcb::Atom kde_net_wm_frame_strut
Xcb::Atom wm_client_leader
Xcb::Atom kde_color_sheme
Xcb::Atom net_frame_extents
Xcb::Atom kde_net_wm_appmenu_service_name
Xcb::Atom net_wm_context_help
Xcb::Atom net_wm_sync_request_counter
Xcb::Atom kde_net_wm_user_creation_time
Xcb::Atom kde_screen_edge_show
void compositingToggled(bool active)
static bool compositing()
Static check to test whether the Compositor is available and active.
static Compositor * self()
xcb_cursor_t x11Cursor(CursorShape shape)
Wrapper round Qt::CursorShape with extensions enums into a single entity.
void resetImageSizesDirty()
void renderToPainter(QPainter *painter, const QRect &rect)
void damaged(const QRegion ®ion)
Decoration::DecoratedClientImpl * client() const
void checkInputWindowStacking()
void updateUserTime(xcb_timestamp_t time)
void addMember(X11Window *member)
const QList< X11Window * > & members() const
const X11Window * leaderClient() const
void removeMember(X11Window *member)
bool borderlessMaximizedWindows
void condensedTitleChanged()
bool windowsBlockCompositing
bool focusPolicyIsReasonable
bool electricBorderMaximize
void placeSmart(Window *c, const QRectF &area, PlacementPolicy next=PlacementUnknown)
void place(Window *c, const QRectF &area)
void discardUsed(Window *c, bool withdraw)
void reserve(ElectricBorder border, QObject *object, const char *callback)
SessionInfo * takeSessionInfo(X11Window *)
SessionState state() const
void setOpacity(qreal opacity)
void setMinimized(bool set)
void setDesktopFileName(const QString &name)
QString wmClientMachine(bool use_localhost) const
void keepInArea(QRectF area, bool partial=false)
QRectF fullscreenGeometryRestore() const
ClientMachine * clientMachine() const
void setFullscreenGeometryRestore(const QRectF &geom)
void setModal(bool modal)
SurfaceInterface * surface() const
bool wantsTabFocus() const
bool isNormalWindow() const
void setGeometryRestore(const QRectF &rect)
void setColorScheme(const QString &colorScheme)
bool isInteractiveMoveResize() const
SurfaceItem * surfaceItem() const
bool isOnCurrentActivity() const
void demandAttention(bool set=true)
std::shared_ptr< KDecoration2::Decoration > decoration
void checkOffscreenPosition(QRectF *geom, const QRectF &screenArea)
QSizeF clientSize() const
void interactiveMoveResizeFinished()
bool isOnCurrentDesktop() const
void setDesktops(QList< VirtualDesktop * > desktops)
void setOriginalSkipTaskbar(bool set)
void setupWindowManagementInterface()
void setOnActivity(const QString &activity, bool enable)
QList< KWin::VirtualDesktop * > desktops
void destroyWindowManagementInterface()
Output * moveResizeOutput() const
void evaluateWindowRules()
QRectF moveResizeGeometry() const
QRectF geometryRestore() const
void desktopFileNameChanged()
const WindowRules * rules() const
QList< Window * > allMainWindows() const
void setReadyForPainting()
void unblockGeometryUpdates()
void setSkipPager(bool set)
KWin::Window * transientFor
void checkWorkspacePosition(QRectF oldGeometry=QRectF(), const VirtualDesktop *oldDesktop=nullptr)
void blockGeometryUpdates()
void layoutDecorationRects(QRectF &left, QRectF &top, QRectF &right, QRectF &bottom) const
bool isSpecialWindow() const
void windowClassChanged()
virtual Window * findModal(bool allow_itself=false)=0
void setOnActivities(const QStringList &newActivitiesList)
void setShortcut(const QString &cut)
void setSkipSwitcher(bool set)
void moveResizeCursorChanged(CursorShape)
QPointF checkPositionSafe(QPointF pos, bool init=false) const
bool checkNoBorder(bool noborder, bool init=false) const
Output * checkOutput(Output *output, bool init=false) const
QStringList checkActivity(QStringList activity, bool init=false) const
MaximizeMode checkMaximize(MaximizeMode mode, bool init=false) const
bool checkMinimize(bool minimized, bool init=false) const
Group * findClientLeaderGroup(const X11Window *c) const
Window * mostRecentlyActivatedWindow() const
void updateOnAllDesktopsOfTransients(Window *)
void resetUpdateToolWindowsTimer()
Window * activeWindow() const
QRectF clientArea(clientAreaOption, const Output *output, const VirtualDesktop *desktop) const
void windowHidden(Window *)
ScreenEdges * screenEdges() const
X11Window * findClient(std::function< bool(const X11Window *)> func) const
Finds the first Client matching the condition expressed by passed in func.
void updateMinimizedOfTransients(Window *)
void activateWindow(Window *window, bool force=false)
const QList< Window * > & stackingOrder() const
void removeX11Window(X11Window *)
void showWindowMenu(const QRect &pos, Window *cl)
bool wasUserInteraction() const
Group * findGroup(xcb_window_t leader) const
Output * activeOutput() const
void restack(Window *window, Window *under, bool force=false)
void updateStackingOrder(bool propagate_new_windows=false)
void raiseWindow(Window *window, bool nogroup=false)
bool checkStartupNotification(xcb_window_t w, KStartupInfoId &id, KStartupInfoData &data)
Placement * placement() const
static Workspace * self()
void updateFocusMousePosition(const QPointF &pos)
RuleBook * rulebook() const
QList< Output * > outputs() const
bool activateNextWindow(Window *window)
void removeUnmanaged(X11Window *)
bool requestFocus(Window *window, bool force=false)
void setActiveOutput(Output *output)
Output * outputAt(const QPointF &pos) const
void restoreSessionStackingOrder(X11Window *window)
SessionManager * sessionManager() const
void restackWindowUnderActive(Window *window)
Output * xineramaIndexToOutput(int index) const
void setShouldGetFocus(Window *window)
void render(const QRegion ®ion) override
X11DecorationRenderer(Decoration::DecoratedClientImpl *client)
~X11DecorationRenderer() override
QSizeF clientSizeToFrameSize(const QSizeF &size) const override
void updateVisibility()
Updates visibility depending on being shaded, virtual desktop, etc.
QString readPreferredColorScheme(Xcb::StringProperty &property) const
bool hasTransient(const Window *c, bool indirect) const override
QList< Window * > mainWindows() const override
void checkGroup(Group *gr=nullptr, bool force=false)
void readApplicationMenuObjectPath(Xcb::StringProperty &property)
void updateCaption() override
QStringList activities() const override
Xcb::StringProperty fetchApplicationMenuObjectPath() const
bool isMaximizable() const override
void setFullScreen(bool set) override
bool isTransient() const override
static void deleteClient(X11Window *c)
Does 'delete c;'.
bool noBorder() const override
xcb_window_t frameId() const
Window * findModal(bool allow_itself=false) override
QPointF clientPosToFramePos(const QPointF &point) const override
bool hasScheduledRelease() const
void updateWindowRules(Rules::Types selection) override
~X11Window() override
Use destroyWindow() or releaseWindow()
QRectF iconGeometry() const override
void readApplicationMenuServiceName(Xcb::StringProperty &property)
void updateMouseGrab() override
void destroyWindow() override
void maximize(MaximizeMode mode) override
Xcb::StringProperty fetchApplicationMenuServiceName() const
bool isUnmanaged() const override
pid_t pid() const override
void invalidateDecoration() override
const QPointF calculateGravitation(bool invert) const
xcb_window_t window() const
bool manage(xcb_window_t w, bool isMapped)
bool track(xcb_window_t w)
void applyWindowRules() override
bool allowWindowActivation(xcb_timestamp_t time=-1U, bool focus_in=false)
xcb_window_t wmClientLeader() const
const Group * group() const override
void unblockCompositing()
bool hasNETSupport() const
QSizeF constrainClientSize(const QSizeF &size, SizeMode mode=SizeModeAny) const override
xcb_timestamp_t userTime() const override
bool setupCompositing() override
QString windowRole() const override
void releaseWindow(bool on_shutdown=false)
void setSessionActivityOverride(bool needed)
xcb_window_t wrapperId() const
void setBlockingCompositing(bool block)
std::unique_ptr< WindowItem > createItem(Scene *scene) override
bool isMovable() const override
Xcb::StringProperty fetchPreferredColorScheme() const
bool groupTransient() const override
static Extensions * self()
void init(xcb_window_t window)
void init(xcb_window_t window)
void setBorderWidth(uint32_t width)
void deleteProperty(xcb_atom_t property)
void resize(const QSizeF &size)
void reparent(xcb_window_t parent, qreal x=0, qreal y=0)
void defineCursor(xcb_cursor_t cursor)
void create(const QRectF &geometry, uint32_t mask=0, const uint32_t *values=nullptr, xcb_window_t parent=rootWindow())
void selectInput(uint32_t events)
void setGeometry(const QRectF &geometry)
void reset(xcb_window_t window=XCB_WINDOW_NONE, bool destroy=true)
const QPoint invalidPoint(INT_MIN, INT_MIN)
@ MaximizeVertical
The window is maximized vertically.
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
const NET::WindowTypes SUPPORTED_MANAGED_WINDOW_TYPES_MASK
KWIN_EXPORT xcb_timestamp_t xTime()
const NET::WindowTypes SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK
WaylandServer * waylandServer()
void KWIN_EXPORT ungrabXKeyboard()
void KWIN_EXPORT grabXServer()
void KWIN_EXPORT ungrabXServer()
bool KWIN_EXPORT grabXKeyboard(xcb_window_t w=XCB_WINDOW_NONE)
KWIN_EXPORT Atoms * atoms
std::unique_ptr< T, CDeleter > UniqueCPtr
xcb_sync_counter_t counter
xcb_timestamp_t lastTimestamp
#define ASPECT_CHECK_SHRINK_H_GROW_W
#define ASPECT_CHECK_GROW_H
#define ASPECT_CHECK_SHRINK_W_GROW_H
#define ASPECT_CHECK_GROW_W