Changeset View
Changeset View
Standalone View
Standalone View
x11client.cpp
- This file was moved from client.cpp.
Show All 13 Lines | |||||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. | ||
17 | 17 | | |||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | *********************************************************************/ | 20 | *********************************************************************/ | ||
21 | // own | 21 | // own | ||
22 | #include "client.h" | 22 | #include "x11client.h" | ||
23 | // kwin | 23 | // kwin | ||
24 | #ifdef KWIN_BUILD_ACTIVITIES | 24 | #ifdef KWIN_BUILD_ACTIVITIES | ||
25 | #include "activities.h" | 25 | #include "activities.h" | ||
26 | #endif | 26 | #endif | ||
27 | #include "atoms.h" | 27 | #include "atoms.h" | ||
28 | #include "client_machine.h" | 28 | #include "client_machine.h" | ||
29 | #include "composite.h" | 29 | #include "composite.h" | ||
30 | #include "cursor.h" | 30 | #include "cursor.h" | ||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | |||||
87 | // - only by calling Workspace::createClient() | 87 | // - only by calling Workspace::createClient() | ||
88 | // - it creates a new client and calls manage() for it | 88 | // - it creates a new client and calls manage() for it | ||
89 | // | 89 | // | ||
90 | // Destroying a client: | 90 | // Destroying a client: | ||
91 | // - destroyClient() - only when the window itself has been destroyed | 91 | // - destroyClient() - only when the window itself has been destroyed | ||
92 | // - releaseWindow() - the window is kept, only the client itself is destroyed | 92 | // - releaseWindow() - the window is kept, only the client itself is destroyed | ||
93 | 93 | | |||
94 | /** | 94 | /** | ||
95 | * \class Client client.h | 95 | * \class Client x11client.h | ||
96 | * \brief The Client class encapsulates a window decoration frame. | 96 | * \brief The Client class encapsulates a window decoration frame. | ||
97 | */ | 97 | */ | ||
98 | 98 | | |||
99 | /** | 99 | /** | ||
100 | * This ctor is "dumb" - it only initializes data. All the real initialization | 100 | * This ctor is "dumb" - it only initializes data. All the real initialization | ||
101 | * is done in manage(). | 101 | * is done in manage(). | ||
102 | */ | 102 | */ | ||
103 | Client::Client() | 103 | X11Client::X11Client() | ||
104 | : AbstractClient() | 104 | : AbstractClient() | ||
105 | , m_client() | 105 | , m_client() | ||
106 | , m_wrapper() | 106 | , m_wrapper() | ||
107 | , m_frame() | 107 | , m_frame() | ||
108 | , m_activityUpdatesBlocked(false) | 108 | , m_activityUpdatesBlocked(false) | ||
109 | , m_blockedActivityUpdatesRequireTransients(false) | 109 | , m_blockedActivityUpdatesRequireTransients(false) | ||
110 | , m_moveResizeGrabWindow() | 110 | , m_moveResizeGrabWindow() | ||
111 | , move_resize_has_keyboard_grab(false) | 111 | , move_resize_has_keyboard_grab(false) | ||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | 134 | { | |||
155 | max_mode = MaximizeRestore; | 155 | max_mode = MaximizeRestore; | ||
156 | 156 | | |||
157 | //Client to workspace connections require that each | 157 | //Client to workspace connections require that each | ||
158 | //client constructed be connected to the workspace wrapper | 158 | //client constructed be connected to the workspace wrapper | ||
159 | 159 | | |||
160 | geom = QRect(0, 0, 100, 100); // So that decorations don't start with size being (0,0) | 160 | geom = QRect(0, 0, 100, 100); // So that decorations don't start with size being (0,0) | ||
161 | client_size = QSize(100, 100); | 161 | client_size = QSize(100, 100); | ||
162 | 162 | | |||
163 | connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption); | 163 | connect(clientMachine(), &ClientMachine::localhostChanged, this, &X11Client::updateCaption); | ||
164 | connect(options, &Options::condensedTitleChanged, this, &Client::updateCaption); | 164 | connect(options, &Options::condensedTitleChanged, this, &X11Client::updateCaption); | ||
165 | 165 | | |||
166 | connect(this, &Client::moveResizeCursorChanged, this, [this] (CursorShape cursor) { | 166 | connect(this, &X11Client::moveResizeCursorChanged, this, [this] (CursorShape cursor) { | ||
167 | xcb_cursor_t nativeCursor = Cursor::x11Cursor(cursor); | 167 | xcb_cursor_t nativeCursor = Cursor::x11Cursor(cursor); | ||
168 | m_frame.defineCursor(nativeCursor); | 168 | m_frame.defineCursor(nativeCursor); | ||
169 | if (m_decoInputExtent.isValid()) | 169 | if (m_decoInputExtent.isValid()) | ||
170 | m_decoInputExtent.defineCursor(nativeCursor); | 170 | m_decoInputExtent.defineCursor(nativeCursor); | ||
171 | if (isMoveResize()) { | 171 | if (isMoveResize()) { | ||
172 | // changing window attributes doesn't change cursor if there's pointer grab active | 172 | // changing window attributes doesn't change cursor if there's pointer grab active | ||
173 | xcb_change_active_pointer_grab(connection(), nativeCursor, xTime(), | 173 | xcb_change_active_pointer_grab(connection(), nativeCursor, xTime(), | ||
174 | 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); | 174 | 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); | ||
175 | } | 175 | } | ||
176 | }); | 176 | }); | ||
177 | 177 | | |||
178 | // SELI TODO: Initialize xsizehints?? | 178 | // SELI TODO: Initialize xsizehints?? | ||
179 | } | 179 | } | ||
180 | 180 | | |||
181 | /** | 181 | /** | ||
182 | * "Dumb" destructor. | 182 | * "Dumb" destructor. | ||
183 | */ | 183 | */ | ||
184 | Client::~Client() | 184 | X11Client::~X11Client() | ||
185 | { | 185 | { | ||
186 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive | 186 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive | ||
187 | ::kill(m_killHelperPID, SIGTERM); | 187 | ::kill(m_killHelperPID, SIGTERM); | ||
188 | m_killHelperPID = 0; | 188 | m_killHelperPID = 0; | ||
189 | } | 189 | } | ||
190 | if (syncRequest.alarm != XCB_NONE) | 190 | if (syncRequest.alarm != XCB_NONE) | ||
191 | xcb_sync_destroy_alarm(connection(), syncRequest.alarm); | 191 | xcb_sync_destroy_alarm(connection(), syncRequest.alarm); | ||
192 | Q_ASSERT(!isMoveResize()); | 192 | Q_ASSERT(!isMoveResize()); | ||
193 | Q_ASSERT(m_client == XCB_WINDOW_NONE); | 193 | Q_ASSERT(m_client == XCB_WINDOW_NONE); | ||
194 | Q_ASSERT(m_wrapper == XCB_WINDOW_NONE); | 194 | Q_ASSERT(m_wrapper == XCB_WINDOW_NONE); | ||
195 | Q_ASSERT(m_frame == XCB_WINDOW_NONE); | 195 | Q_ASSERT(m_frame == XCB_WINDOW_NONE); | ||
196 | Q_ASSERT(!check_active_modal); | 196 | Q_ASSERT(!check_active_modal); | ||
197 | for (auto it = m_connections.constBegin(); it != m_connections.constEnd(); ++it) { | 197 | for (auto it = m_connections.constBegin(); it != m_connections.constEnd(); ++it) { | ||
198 | disconnect(*it); | 198 | disconnect(*it); | ||
199 | } | 199 | } | ||
200 | } | 200 | } | ||
201 | 201 | | |||
202 | // Use destroyClient() or releaseWindow(), Client instances cannot be deleted directly | 202 | // Use destroyClient() or releaseWindow(), Client instances cannot be deleted directly | ||
203 | void Client::deleteClient(Client* c) | 203 | void X11Client::deleteClient(X11Client *c) | ||
204 | { | 204 | { | ||
205 | delete c; | 205 | delete c; | ||
206 | } | 206 | } | ||
207 | 207 | | |||
208 | /** | 208 | /** | ||
209 | * Releases the window. The client has done its job and the window is still existing. | 209 | * Releases the window. The client has done its job and the window is still existing. | ||
210 | */ | 210 | */ | ||
211 | void Client::releaseWindow(bool on_shutdown) | 211 | void X11Client::releaseWindow(bool on_shutdown) | ||
212 | { | 212 | { | ||
213 | Q_ASSERT(!deleting); | 213 | Q_ASSERT(!deleting); | ||
214 | deleting = true; | 214 | deleting = true; | ||
215 | #ifdef KWIN_BUILD_TABBOX | 215 | #ifdef KWIN_BUILD_TABBOX | ||
216 | TabBox::TabBox *tabBox = TabBox::TabBox::self(); | 216 | TabBox::TabBox *tabBox = TabBox::TabBox::self(); | ||
217 | if (tabBox->isDisplayed() && tabBox->currentClient() == this) { | 217 | if (tabBox->isDisplayed() && tabBox->currentClient() == this) { | ||
218 | tabBox->nextPrev(true); | 218 | tabBox->nextPrev(true); | ||
219 | } | 219 | } | ||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Line(s) | 220 | #endif | |||
277 | deleteClient(this); | 277 | deleteClient(this); | ||
278 | ungrabXServer(); | 278 | ungrabXServer(); | ||
279 | } | 279 | } | ||
280 | 280 | | |||
281 | /** | 281 | /** | ||
282 | * Like releaseWindow(), but this one is called when the window has been already destroyed | 282 | * Like releaseWindow(), but this one is called when the window has been already destroyed | ||
283 | * (E.g. The application closed it) | 283 | * (E.g. The application closed it) | ||
284 | */ | 284 | */ | ||
285 | void Client::destroyClient() | 285 | void X11Client::destroyClient() | ||
286 | { | 286 | { | ||
287 | Q_ASSERT(!deleting); | 287 | Q_ASSERT(!deleting); | ||
288 | deleting = true; | 288 | deleting = true; | ||
289 | #ifdef KWIN_BUILD_TABBOX | 289 | #ifdef KWIN_BUILD_TABBOX | ||
290 | TabBox::TabBox *tabBox = TabBox::TabBox::self(); | 290 | TabBox::TabBox *tabBox = TabBox::TabBox::self(); | ||
291 | if (tabBox && tabBox->isDisplayed() && tabBox->currentClient() == this) { | 291 | if (tabBox && tabBox->isDisplayed() && tabBox->currentClient() == this) { | ||
292 | tabBox->nextPrev(true); | 292 | tabBox->nextPrev(true); | ||
293 | } | 293 | } | ||
Show All 22 Lines | 294 | #endif | |||
316 | m_wrapper.reset(); | 316 | m_wrapper.reset(); | ||
317 | m_frame.reset(); | 317 | m_frame.reset(); | ||
318 | unblockGeometryUpdates(); // Don't use GeometryUpdatesBlocker, it would now set the geometry | 318 | unblockGeometryUpdates(); // Don't use GeometryUpdatesBlocker, it would now set the geometry | ||
319 | disownDataPassedToDeleted(); | 319 | disownDataPassedToDeleted(); | ||
320 | del->unrefWindow(); | 320 | del->unrefWindow(); | ||
321 | deleteClient(this); | 321 | deleteClient(this); | ||
322 | } | 322 | } | ||
323 | 323 | | |||
324 | void Client::updateInputWindow() | 324 | void X11Client::updateInputWindow() | ||
325 | { | 325 | { | ||
326 | if (!Xcb::Extensions::self()->isShapeInputAvailable()) | 326 | if (!Xcb::Extensions::self()->isShapeInputAvailable()) | ||
327 | return; | 327 | return; | ||
328 | 328 | | |||
329 | QRegion region; | 329 | QRegion region; | ||
330 | 330 | | |||
331 | if (!noBorder() && isDecorated()) { | 331 | if (!noBorder() && isDecorated()) { | ||
332 | const QMargins &r = decoration()->resizeOnlyBorders(); | 332 | const QMargins &r = decoration()->resizeOnlyBorders(); | ||
Show All 40 Lines | 372 | } else { | |||
373 | m_decoInputExtent.setGeometry(bounds); | 373 | m_decoInputExtent.setGeometry(bounds); | ||
374 | } | 374 | } | ||
375 | 375 | | |||
376 | const QVector<xcb_rectangle_t> rects = Xcb::regionToRects(region); | 376 | const QVector<xcb_rectangle_t> rects = Xcb::regionToRects(region); | ||
377 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, | 377 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, | ||
378 | m_decoInputExtent, 0, 0, rects.count(), rects.constData()); | 378 | m_decoInputExtent, 0, 0, rects.count(), rects.constData()); | ||
379 | } | 379 | } | ||
380 | 380 | | |||
381 | void Client::updateDecoration(bool check_workspace_pos, bool force) | 381 | void X11Client::updateDecoration(bool check_workspace_pos, bool force) | ||
382 | { | 382 | { | ||
383 | if (!force && | 383 | if (!force && | ||
384 | ((!isDecorated() && noBorder()) || (isDecorated() && !noBorder()))) | 384 | ((!isDecorated() && noBorder()) || (isDecorated() && !noBorder()))) | ||
385 | return; | 385 | return; | ||
386 | QRect oldgeom = geometry(); | 386 | QRect oldgeom = geometry(); | ||
387 | QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom()); | 387 | QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom()); | ||
388 | blockGeometryUpdates(true); | 388 | blockGeometryUpdates(true); | ||
389 | if (force) | 389 | if (force) | ||
390 | destroyDecoration(); | 390 | destroyDecoration(); | ||
391 | if (!noBorder()) { | 391 | if (!noBorder()) { | ||
392 | createDecoration(oldgeom); | 392 | createDecoration(oldgeom); | ||
393 | } else | 393 | } else | ||
394 | destroyDecoration(); | 394 | destroyDecoration(); | ||
395 | getShadow(); | 395 | getShadow(); | ||
396 | if (check_workspace_pos) | 396 | if (check_workspace_pos) | ||
397 | checkWorkspacePosition(oldgeom, -2, oldClientGeom); | 397 | checkWorkspacePosition(oldgeom, -2, oldClientGeom); | ||
398 | updateInputWindow(); | 398 | updateInputWindow(); | ||
399 | blockGeometryUpdates(false); | 399 | blockGeometryUpdates(false); | ||
400 | updateFrameExtents(); | 400 | updateFrameExtents(); | ||
401 | } | 401 | } | ||
402 | 402 | | |||
403 | void Client::createDecoration(const QRect& oldgeom) | 403 | void X11Client::createDecoration(const QRect& oldgeom) | ||
404 | { | 404 | { | ||
405 | KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this); | 405 | KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this); | ||
406 | if (decoration) { | 406 | if (decoration) { | ||
407 | QMetaObject::invokeMethod(decoration, "update", Qt::QueuedConnection); | 407 | QMetaObject::invokeMethod(decoration, "update", Qt::QueuedConnection); | ||
408 | connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow); | 408 | connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow); | ||
409 | connect(decoration, &KDecoration2::Decoration::resizeOnlyBordersChanged, this, &Client::updateInputWindow); | 409 | connect(decoration, &KDecoration2::Decoration::resizeOnlyBordersChanged, this, &X11Client::updateInputWindow); | ||
410 | connect(decoration, &KDecoration2::Decoration::bordersChanged, this, | 410 | connect(decoration, &KDecoration2::Decoration::bordersChanged, this, | ||
411 | [this]() { | 411 | [this]() { | ||
412 | updateFrameExtents(); | 412 | updateFrameExtents(); | ||
413 | GeometryUpdatesBlocker blocker(this); | 413 | GeometryUpdatesBlocker blocker(this); | ||
414 | // TODO: this is obviously idempotent | 414 | // TODO: this is obviously idempotent | ||
415 | // calculateGravitation(true) would have to operate on the old border sizes | 415 | // calculateGravitation(true) would have to operate on the old border sizes | ||
416 | // move(calculateGravitation(true)); | 416 | // move(calculateGravitation(true)); | ||
417 | // move(calculateGravitation(false)); | 417 | // move(calculateGravitation(false)); | ||
418 | QRect oldgeom = geometry(); | 418 | QRect oldgeom = geometry(); | ||
419 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | 419 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | ||
420 | if (!isShade()) | 420 | if (!isShade()) | ||
421 | checkWorkspacePosition(oldgeom); | 421 | checkWorkspacePosition(oldgeom); | ||
422 | emit geometryShapeChanged(this, oldgeom); | 422 | emit geometryShapeChanged(this, oldgeom); | ||
423 | } | 423 | } | ||
424 | ); | 424 | ); | ||
425 | connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::widthChanged, this, &Client::updateInputWindow); | 425 | connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::widthChanged, this, &X11Client::updateInputWindow); | ||
426 | connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::heightChanged, this, &Client::updateInputWindow); | 426 | connect(decoratedClient()->decoratedClient(), &KDecoration2::DecoratedClient::heightChanged, this, &X11Client::updateInputWindow); | ||
427 | } | 427 | } | ||
428 | setDecoration(decoration); | 428 | setDecoration(decoration); | ||
429 | 429 | | |||
430 | move(calculateGravitation(false)); | 430 | move(calculateGravitation(false)); | ||
431 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | 431 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | ||
432 | if (Compositor::compositing()) { | 432 | if (Compositor::compositing()) { | ||
433 | discardWindowPixmap(); | 433 | discardWindowPixmap(); | ||
434 | } | 434 | } | ||
435 | emit geometryShapeChanged(this, oldgeom); | 435 | emit geometryShapeChanged(this, oldgeom); | ||
436 | } | 436 | } | ||
437 | 437 | | |||
438 | void Client::destroyDecoration() | 438 | void X11Client::destroyDecoration() | ||
439 | { | 439 | { | ||
440 | QRect oldgeom = geometry(); | 440 | QRect oldgeom = geometry(); | ||
441 | if (isDecorated()) { | 441 | if (isDecorated()) { | ||
442 | QPoint grav = calculateGravitation(true); | 442 | QPoint grav = calculateGravitation(true); | ||
443 | AbstractClient::destroyDecoration(); | 443 | AbstractClient::destroyDecoration(); | ||
444 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | 444 | plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); | ||
445 | move(grav); | 445 | move(grav); | ||
446 | if (compositing()) | 446 | if (compositing()) | ||
447 | discardWindowPixmap(); | 447 | discardWindowPixmap(); | ||
448 | if (!deleting) { | 448 | if (!deleting) { | ||
449 | emit geometryShapeChanged(this, oldgeom); | 449 | emit geometryShapeChanged(this, oldgeom); | ||
450 | } | 450 | } | ||
451 | } | 451 | } | ||
452 | m_decoInputExtent.reset(); | 452 | m_decoInputExtent.reset(); | ||
453 | } | 453 | } | ||
454 | 454 | | |||
455 | void Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const | 455 | void X11Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const | ||
456 | { | 456 | { | ||
457 | if (!isDecorated()) { | 457 | if (!isDecorated()) { | ||
458 | return; | 458 | return; | ||
459 | } | 459 | } | ||
460 | QRect r = decoration()->rect(); | 460 | QRect r = decoration()->rect(); | ||
461 | 461 | | |||
462 | NETStrut strut = info->frameOverlap(); | 462 | NETStrut strut = info->frameOverlap(); | ||
463 | 463 | | |||
Show All 12 Lines | |||||
476 | bottom = QRect(r.x(), r.y() + r.height() - borderBottom() - strut.bottom, | 476 | bottom = QRect(r.x(), r.y() + r.height() - borderBottom() - strut.bottom, | ||
477 | r.width(), borderBottom() + strut.bottom); | 477 | r.width(), borderBottom() + strut.bottom); | ||
478 | left = QRect(r.x(), r.y() + top.height(), | 478 | left = QRect(r.x(), r.y() + top.height(), | ||
479 | borderLeft() + strut.left, r.height() - top.height() - bottom.height()); | 479 | borderLeft() + strut.left, r.height() - top.height() - bottom.height()); | ||
480 | right = QRect(r.x() + r.width() - borderRight() - strut.right, r.y() + top.height(), | 480 | right = QRect(r.x() + r.width() - borderRight() - strut.right, r.y() + top.height(), | ||
481 | borderRight() + strut.right, r.height() - top.height() - bottom.height()); | 481 | borderRight() + strut.right, r.height() - top.height() - bottom.height()); | ||
482 | } | 482 | } | ||
483 | 483 | | |||
484 | QRect Client::transparentRect() const | 484 | QRect X11Client::transparentRect() const | ||
485 | { | 485 | { | ||
486 | if (isShade()) | 486 | if (isShade()) | ||
487 | return QRect(); | 487 | return QRect(); | ||
488 | 488 | | |||
489 | NETStrut strut = info->frameOverlap(); | 489 | NETStrut strut = info->frameOverlap(); | ||
490 | // Ignore the strut when compositing is disabled or the decoration doesn't support it | 490 | // Ignore the strut when compositing is disabled or the decoration doesn't support it | ||
491 | if (!compositing()) | 491 | if (!compositing()) | ||
492 | strut.left = strut.top = strut.right = strut.bottom = 0; | 492 | strut.left = strut.top = strut.right = strut.bottom = 0; | ||
493 | else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) | 493 | else if (strut.left == -1 && strut.top == -1 && strut.right == -1 && strut.bottom == -1) | ||
494 | return QRect(); | 494 | return QRect(); | ||
495 | 495 | | |||
496 | const QRect r = QRect(clientPos(), clientSize()) | 496 | const QRect r = QRect(clientPos(), clientSize()) | ||
497 | .adjusted(strut.left, strut.top, -strut.right, -strut.bottom); | 497 | .adjusted(strut.left, strut.top, -strut.right, -strut.bottom); | ||
498 | if (r.isValid()) | 498 | if (r.isValid()) | ||
499 | return r; | 499 | return r; | ||
500 | 500 | | |||
501 | return QRect(); | 501 | return QRect(); | ||
502 | } | 502 | } | ||
503 | 503 | | |||
504 | void Client::detectNoBorder() | 504 | void X11Client::detectNoBorder() | ||
505 | { | 505 | { | ||
506 | if (shape()) { | 506 | if (shape()) { | ||
507 | noborder = true; | 507 | noborder = true; | ||
508 | app_noborder = true; | 508 | app_noborder = true; | ||
509 | return; | 509 | return; | ||
510 | } | 510 | } | ||
511 | switch(windowType()) { | 511 | switch(windowType()) { | ||
512 | case NET::Desktop : | 512 | case NET::Desktop : | ||
Show All 21 Lines | |||||
534 | // just meaning "noborder", so let's treat it only as such flag, and ignore it as | 534 | // just meaning "noborder", so let's treat it only as such flag, and ignore it as | ||
535 | // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it) | 535 | // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it) | ||
536 | if (info->windowType(NET::OverrideMask) == NET::Override) { | 536 | if (info->windowType(NET::OverrideMask) == NET::Override) { | ||
537 | noborder = true; | 537 | noborder = true; | ||
538 | app_noborder = true; | 538 | app_noborder = true; | ||
539 | } | 539 | } | ||
540 | } | 540 | } | ||
541 | 541 | | |||
542 | void Client::updateFrameExtents() | 542 | void X11Client::updateFrameExtents() | ||
543 | { | 543 | { | ||
544 | NETStrut strut; | 544 | NETStrut strut; | ||
545 | strut.left = borderLeft(); | 545 | strut.left = borderLeft(); | ||
546 | strut.right = borderRight(); | 546 | strut.right = borderRight(); | ||
547 | strut.top = borderTop(); | 547 | strut.top = borderTop(); | ||
548 | strut.bottom = borderBottom(); | 548 | strut.bottom = borderBottom(); | ||
549 | info->setFrameExtents(strut); | 549 | info->setFrameExtents(strut); | ||
550 | } | 550 | } | ||
551 | 551 | | |||
552 | Xcb::Property Client::fetchGtkFrameExtents() const | 552 | Xcb::Property X11Client::fetchGtkFrameExtents() const | ||
553 | { | 553 | { | ||
554 | return Xcb::Property(false, m_client, atoms->gtk_frame_extents, XCB_ATOM_CARDINAL, 0, 4); | 554 | return Xcb::Property(false, m_client, atoms->gtk_frame_extents, XCB_ATOM_CARDINAL, 0, 4); | ||
555 | } | 555 | } | ||
556 | 556 | | |||
557 | void Client::readGtkFrameExtents(Xcb::Property &prop) | 557 | void X11Client::readGtkFrameExtents(Xcb::Property &prop) | ||
558 | { | 558 | { | ||
559 | m_clientSideDecorated = !prop.isNull() && prop->type != 0; | 559 | m_clientSideDecorated = !prop.isNull() && prop->type != 0; | ||
560 | emit clientSideDecoratedChanged(); | 560 | emit clientSideDecoratedChanged(); | ||
561 | } | 561 | } | ||
562 | 562 | | |||
563 | void Client::detectGtkFrameExtents() | 563 | void X11Client::detectGtkFrameExtents() | ||
564 | { | 564 | { | ||
565 | Xcb::Property prop = fetchGtkFrameExtents(); | 565 | Xcb::Property prop = fetchGtkFrameExtents(); | ||
566 | readGtkFrameExtents(prop); | 566 | readGtkFrameExtents(prop); | ||
567 | } | 567 | } | ||
568 | 568 | | |||
569 | /** | 569 | /** | ||
570 | * Resizes the decoration, and makes sure the decoration widget gets resize event | 570 | * Resizes the decoration, and makes sure the decoration widget gets resize event | ||
571 | * even if the size hasn't changed. This is needed to make sure the decoration | 571 | * even if the size hasn't changed. This is needed to make sure the decoration | ||
572 | * re-layouts (e.g. when maximization state changes, | 572 | * re-layouts (e.g. when maximization state changes, | ||
573 | * the decoration may alter some borders, but the actual size | 573 | * the decoration may alter some borders, but the actual size | ||
574 | * of the decoration stays the same). | 574 | * of the decoration stays the same). | ||
575 | */ | 575 | */ | ||
576 | void Client::resizeDecoration() | 576 | void X11Client::resizeDecoration() | ||
577 | { | 577 | { | ||
578 | triggerDecorationRepaint(); | 578 | triggerDecorationRepaint(); | ||
579 | updateInputWindow(); | 579 | updateInputWindow(); | ||
580 | } | 580 | } | ||
581 | 581 | | |||
582 | bool Client::userNoBorder() const | 582 | bool X11Client::userNoBorder() const | ||
583 | { | 583 | { | ||
584 | return noborder; | 584 | return noborder; | ||
585 | } | 585 | } | ||
586 | 586 | | |||
587 | bool Client::isFullScreenable() const | 587 | bool X11Client::isFullScreenable() const | ||
588 | { | 588 | { | ||
589 | if (!rules()->checkFullScreen(true)) { | 589 | if (!rules()->checkFullScreen(true)) { | ||
590 | return false; | 590 | return false; | ||
591 | } | 591 | } | ||
592 | if (rules()->checkStrictGeometry(true)) { | 592 | if (rules()->checkStrictGeometry(true)) { | ||
593 | // check geometry constraints (rule to obey is set) | 593 | // check geometry constraints (rule to obey is set) | ||
594 | const QRect fsarea = workspace()->clientArea(FullScreenArea, this); | 594 | const QRect fsarea = workspace()->clientArea(FullScreenArea, this); | ||
595 | if (sizeForClientSize(fsarea.size(), SizemodeAny, true) != fsarea.size()) { | 595 | if (sizeForClientSize(fsarea.size(), SizemodeAny, true) != fsarea.size()) { | ||
596 | return false; // the app wouldn't fit exactly fullscreen geometry due to its strict geometry requirements | 596 | return false; // the app wouldn't fit exactly fullscreen geometry due to its strict geometry requirements | ||
597 | } | 597 | } | ||
598 | } | 598 | } | ||
599 | // don't check size constrains - some apps request fullscreen despite requesting fixed size | 599 | // don't check size constrains - some apps request fullscreen despite requesting fixed size | ||
600 | return !isSpecialWindow(); // also better disallow only weird types to go fullscreen | 600 | return !isSpecialWindow(); // also better disallow only weird types to go fullscreen | ||
601 | } | 601 | } | ||
602 | 602 | | |||
603 | bool Client::noBorder() const | 603 | bool X11Client::noBorder() const | ||
604 | { | 604 | { | ||
605 | return userNoBorder() || isFullScreen(); | 605 | return userNoBorder() || isFullScreen(); | ||
606 | } | 606 | } | ||
607 | 607 | | |||
608 | bool Client::userCanSetNoBorder() const | 608 | bool X11Client::userCanSetNoBorder() const | ||
609 | { | 609 | { | ||
610 | return !isFullScreen() && !isShade(); | 610 | return !isFullScreen() && !isShade(); | ||
611 | } | 611 | } | ||
612 | 612 | | |||
613 | void Client::setNoBorder(bool set) | 613 | void X11Client::setNoBorder(bool set) | ||
614 | { | 614 | { | ||
615 | if (!userCanSetNoBorder()) | 615 | if (!userCanSetNoBorder()) | ||
616 | return; | 616 | return; | ||
617 | set = rules()->checkNoBorder(set); | 617 | set = rules()->checkNoBorder(set); | ||
618 | if (noborder == set) | 618 | if (noborder == set) | ||
619 | return; | 619 | return; | ||
620 | noborder = set; | 620 | noborder = set; | ||
621 | updateDecoration(true, false); | 621 | updateDecoration(true, false); | ||
622 | updateWindowRules(Rules::NoBorder); | 622 | updateWindowRules(Rules::NoBorder); | ||
623 | } | 623 | } | ||
624 | 624 | | |||
625 | void Client::checkNoBorder() | 625 | void X11Client::checkNoBorder() | ||
626 | { | 626 | { | ||
627 | setNoBorder(app_noborder); | 627 | setNoBorder(app_noborder); | ||
628 | } | 628 | } | ||
629 | 629 | | |||
630 | bool Client::wantsShadowToBeRendered() const | 630 | bool X11Client::wantsShadowToBeRendered() const | ||
631 | { | 631 | { | ||
632 | return !isFullScreen() && maximizeMode() != MaximizeFull; | 632 | return !isFullScreen() && maximizeMode() != MaximizeFull; | ||
633 | } | 633 | } | ||
634 | 634 | | |||
635 | void Client::updateShape() | 635 | void X11Client::updateShape() | ||
636 | { | 636 | { | ||
637 | if (shape()) { | 637 | if (shape()) { | ||
638 | // Workaround for #19644 - Shaped windows shouldn't have decoration | 638 | // Workaround for #19644 - Shaped windows shouldn't have decoration | ||
639 | if (!app_noborder) { | 639 | if (!app_noborder) { | ||
640 | // Only when shape is detected for the first time, still let the user to override | 640 | // Only when shape is detected for the first time, still let the user to override | ||
641 | app_noborder = true; | 641 | app_noborder = true; | ||
642 | noborder = rules()->checkNoBorder(true); | 642 | noborder = rules()->checkNoBorder(true); | ||
643 | updateDecoration(true); | 643 | updateDecoration(true); | ||
Show All 17 Lines | 660 | if (compositing()) { | |||
661 | addRepaintFull(); | 661 | addRepaintFull(); | ||
662 | addWorkspaceRepaint(visibleRect()); // In case shape change removes part of this window | 662 | addWorkspaceRepaint(visibleRect()); // In case shape change removes part of this window | ||
663 | } | 663 | } | ||
664 | emit geometryShapeChanged(this, geometry()); | 664 | emit geometryShapeChanged(this, geometry()); | ||
665 | } | 665 | } | ||
666 | 666 | | |||
667 | static Xcb::Window shape_helper_window(XCB_WINDOW_NONE); | 667 | static Xcb::Window shape_helper_window(XCB_WINDOW_NONE); | ||
668 | 668 | | |||
669 | void Client::cleanupX11() | 669 | void X11Client::cleanupX11() | ||
670 | { | 670 | { | ||
671 | shape_helper_window.reset(); | 671 | shape_helper_window.reset(); | ||
672 | } | 672 | } | ||
673 | 673 | | |||
674 | void Client::updateInputShape() | 674 | void X11Client::updateInputShape() | ||
675 | { | 675 | { | ||
676 | if (hiddenPreview()) // Sets it to none, don't change | 676 | if (hiddenPreview()) // Sets it to none, don't change | ||
677 | return; | 677 | return; | ||
678 | if (Xcb::Extensions::self()->isShapeInputAvailable()) { | 678 | if (Xcb::Extensions::self()->isShapeInputAvailable()) { | ||
679 | // There appears to be no way to find out if a window has input | 679 | // There appears to be no way to find out if a window has input | ||
680 | // shape set or not, so always propagate the input shape | 680 | // shape set or not, so always propagate the input shape | ||
681 | // (it's the same like the bounding shape by default). | 681 | // (it's the same like the bounding shape by default). | ||
682 | // Also, build the shape using a helper window, not directly | 682 | // Also, build the shape using a helper window, not directly | ||
Show All 13 Lines | 695 | xcb_shape_combine(c, XCB_SHAPE_SO_SUBTRACT, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_BOUNDING, | |||
696 | shape_helper_window, clientPos().x(), clientPos().y(), window()); | 696 | shape_helper_window, clientPos().x(), clientPos().y(), window()); | ||
697 | xcb_shape_combine(c, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_INPUT, | 697 | xcb_shape_combine(c, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_INPUT, | ||
698 | shape_helper_window, clientPos().x(), clientPos().y(), window()); | 698 | shape_helper_window, clientPos().x(), clientPos().y(), window()); | ||
699 | xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_INPUT, | 699 | xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_INPUT, | ||
700 | frameId(), 0, 0, shape_helper_window); | 700 | frameId(), 0, 0, shape_helper_window); | ||
701 | } | 701 | } | ||
702 | } | 702 | } | ||
703 | 703 | | |||
704 | void Client::hideClient(bool hide) | 704 | void X11Client::hideClient(bool hide) | ||
705 | { | 705 | { | ||
706 | if (hidden == hide) | 706 | if (hidden == hide) | ||
707 | return; | 707 | return; | ||
708 | hidden = hide; | 708 | hidden = hide; | ||
709 | updateVisibility(); | 709 | updateVisibility(); | ||
710 | } | 710 | } | ||
711 | 711 | | |||
712 | bool Client::setupCompositing() | 712 | bool X11Client::setupCompositing() | ||
713 | { | 713 | { | ||
714 | if (!Toplevel::setupCompositing()){ | 714 | if (!Toplevel::setupCompositing()){ | ||
715 | return false; | 715 | return false; | ||
716 | } | 716 | } | ||
717 | updateVisibility(); // for internalKeep() | 717 | updateVisibility(); // for internalKeep() | ||
718 | return true; | 718 | return true; | ||
719 | } | 719 | } | ||
720 | 720 | | |||
721 | void Client::finishCompositing(ReleaseReason releaseReason) | 721 | void X11Client::finishCompositing(ReleaseReason releaseReason) | ||
722 | { | 722 | { | ||
723 | Toplevel::finishCompositing(releaseReason); | 723 | Toplevel::finishCompositing(releaseReason); | ||
724 | updateVisibility(); | 724 | updateVisibility(); | ||
725 | // for safety in case KWin is just resizing the window | 725 | // for safety in case KWin is just resizing the window | ||
726 | resetHaveResizeEffect(); | 726 | resetHaveResizeEffect(); | ||
727 | } | 727 | } | ||
728 | 728 | | |||
729 | /** | 729 | /** | ||
730 | * Returns whether the window is minimizable or not | 730 | * Returns whether the window is minimizable or not | ||
731 | */ | 731 | */ | ||
732 | bool Client::isMinimizable() const | 732 | bool X11Client::isMinimizable() const | ||
733 | { | 733 | { | ||
734 | if (isSpecialWindow() && !isTransient()) | 734 | if (isSpecialWindow() && !isTransient()) | ||
735 | return false; | 735 | return false; | ||
736 | if (!rules()->checkMinimize(true)) | 736 | if (!rules()->checkMinimize(true)) | ||
737 | return false; | 737 | return false; | ||
738 | 738 | | |||
739 | if (isTransient()) { | 739 | if (isTransient()) { | ||
740 | // #66868 - Let other xmms windows be minimized when the mainwindow is minimized | 740 | // #66868 - Let other xmms windows be minimized when the mainwindow is minimized | ||
Show All 16 Lines | 751 | #if 0 | |||
757 | if (transientFor() != NULL) | 757 | if (transientFor() != NULL) | ||
758 | return false; | 758 | return false; | ||
759 | #endif | 759 | #endif | ||
760 | if (!wantsTabFocus()) // SELI, TODO: - NET::Utility? why wantsTabFocus() - skiptaskbar? ? | 760 | if (!wantsTabFocus()) // SELI, TODO: - NET::Utility? why wantsTabFocus() - skiptaskbar? ? | ||
761 | return false; | 761 | return false; | ||
762 | return true; | 762 | return true; | ||
763 | } | 763 | } | ||
764 | 764 | | |||
765 | void Client::doMinimize() | 765 | void X11Client::doMinimize() | ||
766 | { | 766 | { | ||
767 | updateVisibility(); | 767 | updateVisibility(); | ||
768 | updateAllowedActions(); | 768 | updateAllowedActions(); | ||
769 | workspace()->updateMinimizedOfTransients(this); | 769 | workspace()->updateMinimizedOfTransients(this); | ||
770 | } | 770 | } | ||
771 | 771 | | |||
772 | QRect Client::iconGeometry() const | 772 | QRect X11Client::iconGeometry() const | ||
773 | { | 773 | { | ||
774 | NETRect r = info->iconGeometry(); | 774 | NETRect r = info->iconGeometry(); | ||
775 | QRect geom(r.pos.x, r.pos.y, r.size.width, r.size.height); | 775 | QRect geom(r.pos.x, r.pos.y, r.size.width, r.size.height); | ||
776 | if (geom.isValid()) | 776 | if (geom.isValid()) | ||
777 | return geom; | 777 | return geom; | ||
778 | else { | 778 | else { | ||
779 | // Check all mainwindows of this window (recursively) | 779 | // Check all mainwindows of this window (recursively) | ||
780 | foreach (AbstractClient * amainwin, mainClients()) { | 780 | foreach (AbstractClient * amainwin, mainClients()) { | ||
781 | Client *mainwin = dynamic_cast<Client*>(amainwin); | 781 | X11Client *mainwin = dynamic_cast<X11Client *>(amainwin); | ||
782 | if (!mainwin) { | 782 | if (!mainwin) { | ||
783 | continue; | 783 | continue; | ||
784 | } | 784 | } | ||
785 | geom = mainwin->iconGeometry(); | 785 | geom = mainwin->iconGeometry(); | ||
786 | if (geom.isValid()) | 786 | if (geom.isValid()) | ||
787 | return geom; | 787 | return geom; | ||
788 | } | 788 | } | ||
789 | // No mainwindow (or their parents) with icon geometry was found | 789 | // No mainwindow (or their parents) with icon geometry was found | ||
790 | return AbstractClient::iconGeometry(); | 790 | return AbstractClient::iconGeometry(); | ||
791 | } | 791 | } | ||
792 | } | 792 | } | ||
793 | 793 | | |||
794 | bool Client::isShadeable() const | 794 | bool X11Client::isShadeable() const | ||
795 | { | 795 | { | ||
796 | return !isSpecialWindow() && !noBorder() && (rules()->checkShade(ShadeNormal) != rules()->checkShade(ShadeNone)); | 796 | return !isSpecialWindow() && !noBorder() && (rules()->checkShade(ShadeNormal) != rules()->checkShade(ShadeNone)); | ||
797 | } | 797 | } | ||
798 | 798 | | |||
799 | void Client::setShade(ShadeMode mode) | 799 | void X11Client::setShade(ShadeMode mode) | ||
800 | { | 800 | { | ||
801 | if (mode == ShadeHover && isMove()) | 801 | if (mode == ShadeHover && isMove()) | ||
802 | return; // causes geometry breaks and is probably nasty | 802 | return; // causes geometry breaks and is probably nasty | ||
803 | if (isSpecialWindow() || noBorder()) | 803 | if (isSpecialWindow() || noBorder()) | ||
804 | mode = ShadeNone; | 804 | mode = ShadeNone; | ||
805 | mode = rules()->checkShade(mode); | 805 | mode = rules()->checkShade(mode); | ||
806 | if (shade_mode == mode) | 806 | if (shade_mode == mode) | ||
807 | return; | 807 | return; | ||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | 851 | } else { | |||
859 | if ((shade_mode == ShadeHover || shade_mode == ShadeActivated) && rules()->checkAcceptFocus(info->input())) | 859 | if ((shade_mode == ShadeHover || shade_mode == ShadeActivated) && rules()->checkAcceptFocus(info->input())) | ||
860 | setActive(true); | 860 | setActive(true); | ||
861 | if (shade_mode == ShadeHover) { | 861 | if (shade_mode == ShadeHover) { | ||
862 | ToplevelList order = workspace()->stackingOrder(); | 862 | ToplevelList order = workspace()->stackingOrder(); | ||
863 | // invalidate, since "this" could be the topmost toplevel and shade_below dangeling | 863 | // invalidate, since "this" could be the topmost toplevel and shade_below dangeling | ||
864 | shade_below = nullptr; | 864 | shade_below = nullptr; | ||
865 | // this is likely related to the index parameter?! | 865 | // this is likely related to the index parameter?! | ||
866 | for (int idx = order.indexOf(this) + 1; idx < order.count(); ++idx) { | 866 | for (int idx = order.indexOf(this) + 1; idx < order.count(); ++idx) { | ||
867 | shade_below = qobject_cast<Client*>(order.at(idx)); | 867 | shade_below = qobject_cast<X11Client *>(order.at(idx)); | ||
868 | if (shade_below) { | 868 | if (shade_below) { | ||
869 | break; | 869 | break; | ||
870 | } | 870 | } | ||
871 | } | 871 | } | ||
872 | if (shade_below && shade_below->isNormalWindow()) | 872 | if (shade_below && shade_below->isNormalWindow()) | ||
873 | workspace()->raiseClient(this); | 873 | workspace()->raiseClient(this); | ||
874 | else | 874 | else | ||
875 | shade_below = nullptr; | 875 | shade_below = nullptr; | ||
Show All 9 Lines | |||||
885 | discardWindowPixmap(); | 885 | discardWindowPixmap(); | ||
886 | updateVisibility(); | 886 | updateVisibility(); | ||
887 | updateAllowedActions(); | 887 | updateAllowedActions(); | ||
888 | updateWindowRules(Rules::Shade); | 888 | updateWindowRules(Rules::Shade); | ||
889 | 889 | | |||
890 | emit shadeChanged(); | 890 | emit shadeChanged(); | ||
891 | } | 891 | } | ||
892 | 892 | | |||
893 | void Client::shadeHover() | 893 | void X11Client::shadeHover() | ||
894 | { | 894 | { | ||
895 | setShade(ShadeHover); | 895 | setShade(ShadeHover); | ||
896 | cancelShadeHoverTimer(); | 896 | cancelShadeHoverTimer(); | ||
897 | } | 897 | } | ||
898 | 898 | | |||
899 | void Client::shadeUnhover() | 899 | void X11Client::shadeUnhover() | ||
900 | { | 900 | { | ||
901 | setShade(ShadeNormal); | 901 | setShade(ShadeNormal); | ||
902 | cancelShadeHoverTimer(); | 902 | cancelShadeHoverTimer(); | ||
903 | } | 903 | } | ||
904 | 904 | | |||
905 | void Client::cancelShadeHoverTimer() | 905 | void X11Client::cancelShadeHoverTimer() | ||
906 | { | 906 | { | ||
907 | delete shadeHoverTimer; | 907 | delete shadeHoverTimer; | ||
908 | shadeHoverTimer = nullptr; | 908 | shadeHoverTimer = nullptr; | ||
909 | } | 909 | } | ||
910 | 910 | | |||
911 | void Client::toggleShade() | 911 | void X11Client::toggleShade() | ||
912 | { | 912 | { | ||
913 | // If the mode is ShadeHover or ShadeActive, cancel shade too | 913 | // If the mode is ShadeHover or ShadeActive, cancel shade too | ||
914 | setShade(shade_mode == ShadeNone ? ShadeNormal : ShadeNone); | 914 | setShade(shade_mode == ShadeNone ? ShadeNormal : ShadeNone); | ||
915 | } | 915 | } | ||
916 | 916 | | |||
917 | void Client::updateVisibility() | 917 | void X11Client::updateVisibility() | ||
918 | { | 918 | { | ||
919 | if (deleting) | 919 | if (deleting) | ||
920 | return; | 920 | return; | ||
921 | if (hidden) { | 921 | if (hidden) { | ||
922 | info->setState(NET::Hidden, NET::Hidden); | 922 | info->setState(NET::Hidden, NET::Hidden); | ||
923 | setSkipTaskbar(true); // Also hide from taskbar | 923 | setSkipTaskbar(true); // Also hide from taskbar | ||
924 | if (compositing() && options->hiddenPreviews() == HiddenPreviewsAlways) | 924 | if (compositing() && options->hiddenPreviews() == HiddenPreviewsAlways) | ||
925 | internalKeep(); | 925 | internalKeep(); | ||
Show All 28 Lines | |||||
954 | internalShow(); | 954 | internalShow(); | ||
955 | } | 955 | } | ||
956 | 956 | | |||
957 | 957 | | |||
958 | /** | 958 | /** | ||
959 | * Sets the client window's mapping state. Possible values are | 959 | * Sets the client window's mapping state. Possible values are | ||
960 | * WithdrawnState, IconicState, NormalState. | 960 | * WithdrawnState, IconicState, NormalState. | ||
961 | */ | 961 | */ | ||
962 | void Client::exportMappingState(int s) | 962 | void X11Client::exportMappingState(int s) | ||
963 | { | 963 | { | ||
964 | Q_ASSERT(m_client != XCB_WINDOW_NONE); | 964 | Q_ASSERT(m_client != XCB_WINDOW_NONE); | ||
965 | Q_ASSERT(!deleting || s == XCB_ICCCM_WM_STATE_WITHDRAWN); | 965 | Q_ASSERT(!deleting || s == XCB_ICCCM_WM_STATE_WITHDRAWN); | ||
966 | if (s == XCB_ICCCM_WM_STATE_WITHDRAWN) { | 966 | if (s == XCB_ICCCM_WM_STATE_WITHDRAWN) { | ||
967 | m_client.deleteProperty(atoms->wm_state); | 967 | m_client.deleteProperty(atoms->wm_state); | ||
968 | return; | 968 | return; | ||
969 | } | 969 | } | ||
970 | Q_ASSERT(s == XCB_ICCCM_WM_STATE_NORMAL || s == XCB_ICCCM_WM_STATE_ICONIC); | 970 | Q_ASSERT(s == XCB_ICCCM_WM_STATE_NORMAL || s == XCB_ICCCM_WM_STATE_ICONIC); | ||
971 | 971 | | |||
972 | int32_t data[2]; | 972 | int32_t data[2]; | ||
973 | data[0] = s; | 973 | data[0] = s; | ||
974 | data[1] = XCB_NONE; | 974 | data[1] = XCB_NONE; | ||
975 | m_client.changeProperty(atoms->wm_state, atoms->wm_state, 32, 2, data); | 975 | m_client.changeProperty(atoms->wm_state, atoms->wm_state, 32, 2, data); | ||
976 | } | 976 | } | ||
977 | 977 | | |||
978 | void Client::internalShow() | 978 | void X11Client::internalShow() | ||
979 | { | 979 | { | ||
980 | if (mapping_state == Mapped) | 980 | if (mapping_state == Mapped) | ||
981 | return; | 981 | return; | ||
982 | MappingState old = mapping_state; | 982 | MappingState old = mapping_state; | ||
983 | mapping_state = Mapped; | 983 | mapping_state = Mapped; | ||
984 | if (old == Unmapped || old == Withdrawn) | 984 | if (old == Unmapped || old == Withdrawn) | ||
985 | map(); | 985 | map(); | ||
986 | if (old == Kept) { | 986 | if (old == Kept) { | ||
987 | m_decoInputExtent.map(); | 987 | m_decoInputExtent.map(); | ||
988 | updateHiddenPreview(); | 988 | updateHiddenPreview(); | ||
989 | } | 989 | } | ||
990 | emit windowShown(this); | 990 | emit windowShown(this); | ||
991 | } | 991 | } | ||
992 | 992 | | |||
993 | void Client::internalHide() | 993 | void X11Client::internalHide() | ||
994 | { | 994 | { | ||
995 | if (mapping_state == Unmapped) | 995 | if (mapping_state == Unmapped) | ||
996 | return; | 996 | return; | ||
997 | MappingState old = mapping_state; | 997 | MappingState old = mapping_state; | ||
998 | mapping_state = Unmapped; | 998 | mapping_state = Unmapped; | ||
999 | if (old == Mapped || old == Kept) | 999 | if (old == Mapped || old == Kept) | ||
1000 | unmap(); | 1000 | unmap(); | ||
1001 | if (old == Kept) | 1001 | if (old == Kept) | ||
1002 | updateHiddenPreview(); | 1002 | updateHiddenPreview(); | ||
1003 | addWorkspaceRepaint(visibleRect()); | 1003 | addWorkspaceRepaint(visibleRect()); | ||
1004 | workspace()->clientHidden(this); | 1004 | workspace()->clientHidden(this); | ||
1005 | emit windowHidden(this); | 1005 | emit windowHidden(this); | ||
1006 | } | 1006 | } | ||
1007 | 1007 | | |||
1008 | void Client::internalKeep() | 1008 | void X11Client::internalKeep() | ||
1009 | { | 1009 | { | ||
1010 | Q_ASSERT(compositing()); | 1010 | Q_ASSERT(compositing()); | ||
1011 | if (mapping_state == Kept) | 1011 | if (mapping_state == Kept) | ||
1012 | return; | 1012 | return; | ||
1013 | MappingState old = mapping_state; | 1013 | MappingState old = mapping_state; | ||
1014 | mapping_state = Kept; | 1014 | mapping_state = Kept; | ||
1015 | if (old == Unmapped || old == Withdrawn) | 1015 | if (old == Unmapped || old == Withdrawn) | ||
1016 | map(); | 1016 | map(); | ||
1017 | m_decoInputExtent.unmap(); | 1017 | m_decoInputExtent.unmap(); | ||
1018 | if (isActive()) | 1018 | if (isActive()) | ||
1019 | workspace()->focusToNull(); // get rid of input focus, bug #317484 | 1019 | workspace()->focusToNull(); // get rid of input focus, bug #317484 | ||
1020 | updateHiddenPreview(); | 1020 | updateHiddenPreview(); | ||
1021 | addWorkspaceRepaint(visibleRect()); | 1021 | addWorkspaceRepaint(visibleRect()); | ||
1022 | workspace()->clientHidden(this); | 1022 | workspace()->clientHidden(this); | ||
1023 | } | 1023 | } | ||
1024 | 1024 | | |||
1025 | /** | 1025 | /** | ||
1026 | * Maps (shows) the client. Note that it is mapping state of the frame, | 1026 | * Maps (shows) the client. Note that it is mapping state of the frame, | ||
1027 | * not necessarily the client window itself (i.e. a shaded window is here | 1027 | * not necessarily the client window itself (i.e. a shaded window is here | ||
1028 | * considered mapped, even though it is in IconicState). | 1028 | * considered mapped, even though it is in IconicState). | ||
1029 | */ | 1029 | */ | ||
1030 | void Client::map() | 1030 | void X11Client::map() | ||
1031 | { | 1031 | { | ||
1032 | // XComposite invalidates backing pixmaps on unmap (minimize, different | 1032 | // XComposite invalidates backing pixmaps on unmap (minimize, different | ||
1033 | // virtual desktop, etc.). We kept the last known good pixmap around | 1033 | // virtual desktop, etc.). We kept the last known good pixmap around | ||
1034 | // for use in effects, but now we want to have access to the new pixmap | 1034 | // for use in effects, but now we want to have access to the new pixmap | ||
1035 | if (compositing()) | 1035 | if (compositing()) | ||
1036 | discardWindowPixmap(); | 1036 | discardWindowPixmap(); | ||
1037 | m_frame.map(); | 1037 | m_frame.map(); | ||
1038 | if (!isShade()) { | 1038 | if (!isShade()) { | ||
1039 | m_wrapper.map(); | 1039 | m_wrapper.map(); | ||
1040 | m_client.map(); | 1040 | m_client.map(); | ||
1041 | m_decoInputExtent.map(); | 1041 | m_decoInputExtent.map(); | ||
1042 | exportMappingState(XCB_ICCCM_WM_STATE_NORMAL); | 1042 | exportMappingState(XCB_ICCCM_WM_STATE_NORMAL); | ||
1043 | } else | 1043 | } else | ||
1044 | exportMappingState(XCB_ICCCM_WM_STATE_ICONIC); | 1044 | exportMappingState(XCB_ICCCM_WM_STATE_ICONIC); | ||
1045 | addLayerRepaint(visibleRect()); | 1045 | addLayerRepaint(visibleRect()); | ||
1046 | } | 1046 | } | ||
1047 | 1047 | | |||
1048 | /** | 1048 | /** | ||
1049 | * Unmaps the client. Again, this is about the frame. | 1049 | * Unmaps the client. Again, this is about the frame. | ||
1050 | */ | 1050 | */ | ||
1051 | void Client::unmap() | 1051 | void X11Client::unmap() | ||
1052 | { | 1052 | { | ||
1053 | // Here it may look like a race condition, as some other client might try to unmap | 1053 | // Here it may look like a race condition, as some other client might try to unmap | ||
1054 | // the window between these two XSelectInput() calls. However, they're supposed to | 1054 | // the window between these two XSelectInput() calls. However, they're supposed to | ||
1055 | // use XWithdrawWindow(), which also sends a synthetic event to the root window, | 1055 | // use XWithdrawWindow(), which also sends a synthetic event to the root window, | ||
1056 | // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify | 1056 | // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify | ||
1057 | // will be missed is also very minimal, so I don't think it's needed to grab the server | 1057 | // will be missed is also very minimal, so I don't think it's needed to grab the server | ||
1058 | // here. | 1058 | // here. | ||
1059 | m_wrapper.selectInput(ClientWinMask); // Avoid getting UnmapNotify | 1059 | m_wrapper.selectInput(ClientWinMask); // Avoid getting UnmapNotify | ||
Show All 11 Lines | |||||
1071 | * virtual desktop. Therefore rawHide() actually keeps such windows mapped. | 1071 | * virtual desktop. Therefore rawHide() actually keeps such windows mapped. | ||
1072 | * However special care needs to be taken so that such windows don't interfere. | 1072 | * However special care needs to be taken so that such windows don't interfere. | ||
1073 | * Therefore they're put very low in the stacking order and they have input shape | 1073 | * Therefore they're put very low in the stacking order and they have input shape | ||
1074 | * set to none, which hopefully is enough. If there's no input shape available, | 1074 | * set to none, which hopefully is enough. If there's no input shape available, | ||
1075 | * then it's hoped that there will be some other desktop above it *shrug*. | 1075 | * then it's hoped that there will be some other desktop above it *shrug*. | ||
1076 | * Using normal shape would be better, but that'd affect other things, e.g. painting | 1076 | * Using normal shape would be better, but that'd affect other things, e.g. painting | ||
1077 | * of the actual preview. | 1077 | * of the actual preview. | ||
1078 | */ | 1078 | */ | ||
1079 | void Client::updateHiddenPreview() | 1079 | void X11Client::updateHiddenPreview() | ||
1080 | { | 1080 | { | ||
1081 | if (hiddenPreview()) { | 1081 | if (hiddenPreview()) { | ||
1082 | workspace()->forceRestacking(); | 1082 | workspace()->forceRestacking(); | ||
1083 | if (Xcb::Extensions::self()->isShapeInputAvailable()) { | 1083 | if (Xcb::Extensions::self()->isShapeInputAvailable()) { | ||
1084 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, | 1084 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, | ||
1085 | XCB_CLIP_ORDERING_UNSORTED, frameId(), 0, 0, 0, nullptr); | 1085 | XCB_CLIP_ORDERING_UNSORTED, frameId(), 0, 0, 0, nullptr); | ||
1086 | } | 1086 | } | ||
1087 | } else { | 1087 | } else { | ||
1088 | workspace()->forceRestacking(); | 1088 | workspace()->forceRestacking(); | ||
1089 | updateInputShape(); | 1089 | updateInputShape(); | ||
1090 | } | 1090 | } | ||
1091 | } | 1091 | } | ||
1092 | 1092 | | |||
1093 | void Client::sendClientMessage(xcb_window_t w, xcb_atom_t a, xcb_atom_t protocol, uint32_t data1, uint32_t data2, uint32_t data3, xcb_timestamp_t timestamp) | 1093 | void X11Client::sendClientMessage(xcb_window_t w, xcb_atom_t a, xcb_atom_t protocol, uint32_t data1, uint32_t data2, uint32_t data3, xcb_timestamp_t timestamp) | ||
1094 | { | 1094 | { | ||
1095 | xcb_client_message_event_t ev; | 1095 | xcb_client_message_event_t ev; | ||
1096 | memset(&ev, 0, sizeof(ev)); | 1096 | memset(&ev, 0, sizeof(ev)); | ||
1097 | ev.response_type = XCB_CLIENT_MESSAGE; | 1097 | ev.response_type = XCB_CLIENT_MESSAGE; | ||
1098 | ev.window = w; | 1098 | ev.window = w; | ||
1099 | ev.type = a; | 1099 | ev.type = a; | ||
1100 | ev.format = 32; | 1100 | ev.format = 32; | ||
1101 | ev.data.data32[0] = protocol; | 1101 | ev.data.data32[0] = protocol; | ||
1102 | ev.data.data32[1] = timestamp; | 1102 | ev.data.data32[1] = timestamp; | ||
1103 | ev.data.data32[2] = data1; | 1103 | ev.data.data32[2] = data1; | ||
1104 | ev.data.data32[3] = data2; | 1104 | ev.data.data32[3] = data2; | ||
1105 | ev.data.data32[4] = data3; | 1105 | ev.data.data32[4] = data3; | ||
1106 | uint32_t eventMask = 0; | 1106 | uint32_t eventMask = 0; | ||
1107 | if (w == rootWindow()) { | 1107 | if (w == rootWindow()) { | ||
1108 | eventMask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; // Magic! | 1108 | eventMask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; // Magic! | ||
1109 | } | 1109 | } | ||
1110 | xcb_send_event(connection(), false, w, eventMask, reinterpret_cast<const char*>(&ev)); | 1110 | xcb_send_event(connection(), false, w, eventMask, reinterpret_cast<const char*>(&ev)); | ||
1111 | xcb_flush(connection()); | 1111 | xcb_flush(connection()); | ||
1112 | } | 1112 | } | ||
1113 | 1113 | | |||
1114 | /** | 1114 | /** | ||
1115 | * Returns whether the window may be closed (have a close button) | 1115 | * Returns whether the window may be closed (have a close button) | ||
1116 | */ | 1116 | */ | ||
1117 | bool Client::isCloseable() const | 1117 | bool X11Client::isCloseable() const | ||
1118 | { | 1118 | { | ||
1119 | return rules()->checkCloseable(m_motif.close() && !isSpecialWindow()); | 1119 | return rules()->checkCloseable(m_motif.close() && !isSpecialWindow()); | ||
1120 | } | 1120 | } | ||
1121 | 1121 | | |||
1122 | /** | 1122 | /** | ||
1123 | * Closes the window by either sending a delete_window message or using XKill. | 1123 | * Closes the window by either sending a delete_window message or using XKill. | ||
1124 | */ | 1124 | */ | ||
1125 | void Client::closeWindow() | 1125 | void X11Client::closeWindow() | ||
1126 | { | 1126 | { | ||
1127 | if (!isCloseable()) | 1127 | if (!isCloseable()) | ||
1128 | return; | 1128 | return; | ||
1129 | 1129 | | |||
1130 | // Update user time, because the window may create a confirming dialog. | 1130 | // Update user time, because the window may create a confirming dialog. | ||
1131 | updateUserTime(); | 1131 | updateUserTime(); | ||
1132 | 1132 | | |||
1133 | if (info->supportsProtocol(NET::DeleteWindowProtocol)) { | 1133 | if (info->supportsProtocol(NET::DeleteWindowProtocol)) { | ||
1134 | sendClientMessage(window(), atoms->wm_protocols, atoms->wm_delete_window); | 1134 | sendClientMessage(window(), atoms->wm_protocols, atoms->wm_delete_window); | ||
1135 | pingWindow(); | 1135 | pingWindow(); | ||
1136 | } else // Client will not react on wm_delete_window. We have not choice | 1136 | } else // Client will not react on wm_delete_window. We have not choice | ||
1137 | // but destroy his connection to the XServer. | 1137 | // but destroy his connection to the XServer. | ||
1138 | killWindow(); | 1138 | killWindow(); | ||
1139 | } | 1139 | } | ||
1140 | 1140 | | |||
1141 | 1141 | | |||
1142 | /** | 1142 | /** | ||
1143 | * Kills the window via XKill | 1143 | * Kills the window via XKill | ||
1144 | */ | 1144 | */ | ||
1145 | void Client::killWindow() | 1145 | void X11Client::killWindow() | ||
1146 | { | 1146 | { | ||
1147 | qCDebug(KWIN_CORE) << "Client::killWindow():" << caption(); | 1147 | qCDebug(KWIN_CORE) << "X11Client::killWindow():" << caption(); | ||
1148 | killProcess(false); | 1148 | killProcess(false); | ||
1149 | m_client.kill(); // Always kill this client at the server | 1149 | m_client.kill(); // Always kill this client at the server | ||
1150 | destroyClient(); | 1150 | destroyClient(); | ||
1151 | } | 1151 | } | ||
1152 | 1152 | | |||
1153 | /** | 1153 | /** | ||
1154 | * Send a ping to the window using _NET_WM_PING if possible if it | 1154 | * Send a ping to the window using _NET_WM_PING if possible if it | ||
1155 | * doesn't respond within a reasonable time, it will be killed. | 1155 | * doesn't respond within a reasonable time, it will be killed. | ||
1156 | */ | 1156 | */ | ||
1157 | void Client::pingWindow() | 1157 | void X11Client::pingWindow() | ||
1158 | { | 1158 | { | ||
1159 | if (!info->supportsProtocol(NET::PingProtocol)) | 1159 | if (!info->supportsProtocol(NET::PingProtocol)) | ||
1160 | return; // Can't ping :( | 1160 | return; // Can't ping :( | ||
1161 | if (options->killPingTimeout() == 0) | 1161 | if (options->killPingTimeout() == 0) | ||
1162 | return; // Turned off | 1162 | return; // Turned off | ||
1163 | if (ping_timer != nullptr) | 1163 | if (ping_timer != nullptr) | ||
1164 | return; // Pinging already | 1164 | return; // Pinging already | ||
1165 | ping_timer = new QTimer(this); | 1165 | ping_timer = new QTimer(this); | ||
Show All 16 Lines | |||||
1182 | ping_timer->setSingleShot(true); | 1182 | ping_timer->setSingleShot(true); | ||
1183 | // we'll run the timer twice, at first we'll desaturate the window | 1183 | // we'll run the timer twice, at first we'll desaturate the window | ||
1184 | // and the second time we'll show the "do you want to kill" prompt | 1184 | // and the second time we'll show the "do you want to kill" prompt | ||
1185 | ping_timer->start(options->killPingTimeout() / 2); | 1185 | ping_timer->start(options->killPingTimeout() / 2); | ||
1186 | m_pingTimestamp = xTime(); | 1186 | m_pingTimestamp = xTime(); | ||
1187 | workspace()->sendPingToWindow(window(), m_pingTimestamp); | 1187 | workspace()->sendPingToWindow(window(), m_pingTimestamp); | ||
1188 | } | 1188 | } | ||
1189 | 1189 | | |||
1190 | void Client::gotPing(xcb_timestamp_t timestamp) | 1190 | void X11Client::gotPing(xcb_timestamp_t timestamp) | ||
1191 | { | 1191 | { | ||
1192 | // Just plain compare is not good enough because of 64bit and truncating and whatnot | 1192 | // Just plain compare is not good enough because of 64bit and truncating and whatnot | ||
1193 | if (NET::timestampCompare(timestamp, m_pingTimestamp) != 0) | 1193 | if (NET::timestampCompare(timestamp, m_pingTimestamp) != 0) | ||
1194 | return; | 1194 | return; | ||
1195 | delete ping_timer; | 1195 | delete ping_timer; | ||
1196 | ping_timer = nullptr; | 1196 | ping_timer = nullptr; | ||
1197 | 1197 | | |||
1198 | setUnresponsive(false); | 1198 | setUnresponsive(false); | ||
1199 | 1199 | | |||
1200 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive | 1200 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) { // means the process is alive | ||
1201 | ::kill(m_killHelperPID, SIGTERM); | 1201 | ::kill(m_killHelperPID, SIGTERM); | ||
1202 | m_killHelperPID = 0; | 1202 | m_killHelperPID = 0; | ||
1203 | } | 1203 | } | ||
1204 | } | 1204 | } | ||
1205 | 1205 | | |||
1206 | void Client::killProcess(bool ask, xcb_timestamp_t timestamp) | 1206 | void X11Client::killProcess(bool ask, xcb_timestamp_t timestamp) | ||
1207 | { | 1207 | { | ||
1208 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) // means the process is alive | 1208 | if (m_killHelperPID && !::kill(m_killHelperPID, 0)) // means the process is alive | ||
1209 | return; | 1209 | return; | ||
1210 | Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME); | 1210 | Q_ASSERT(!ask || timestamp != XCB_TIME_CURRENT_TIME); | ||
1211 | pid_t pid = info->pid(); | 1211 | pid_t pid = info->pid(); | ||
1212 | if (pid <= 0 || clientMachine()->hostName().isEmpty()) // Needed properties missing | 1212 | if (pid <= 0 || clientMachine()->hostName().isEmpty()) // Needed properties missing | ||
1213 | return; | 1213 | return; | ||
1214 | qCDebug(KWIN_CORE) << "Kill process:" << pid << "(" << clientMachine()->hostName() << ")"; | 1214 | qCDebug(KWIN_CORE) << "Kill process:" << pid << "(" << clientMachine()->hostName() << ")"; | ||
Show All 13 Lines | 1226 | QProcess::startDetached(buildDirBinary.exists() ? buildDirBinary.absoluteFilePath() : QStringLiteral(KWIN_KILLER_BIN), | |||
1228 | << QStringLiteral("--windowname") << captionNormal() | 1228 | << QStringLiteral("--windowname") << captionNormal() | ||
1229 | << QStringLiteral("--applicationname") << QString::fromUtf8(resourceClass()) | 1229 | << QStringLiteral("--applicationname") << QString::fromUtf8(resourceClass()) | ||
1230 | << QStringLiteral("--wid") << QString::number(window()) | 1230 | << QStringLiteral("--wid") << QString::number(window()) | ||
1231 | << QStringLiteral("--timestamp") << QString::number(timestamp), | 1231 | << QStringLiteral("--timestamp") << QString::number(timestamp), | ||
1232 | QString(), &m_killHelperPID); | 1232 | QString(), &m_killHelperPID); | ||
1233 | } | 1233 | } | ||
1234 | } | 1234 | } | ||
1235 | 1235 | | |||
1236 | void Client::doSetSkipTaskbar() | 1236 | void X11Client::doSetSkipTaskbar() | ||
1237 | { | 1237 | { | ||
1238 | info->setState(skipTaskbar() ? NET::SkipTaskbar : NET::States(), NET::SkipTaskbar); | 1238 | info->setState(skipTaskbar() ? NET::SkipTaskbar : NET::States(), NET::SkipTaskbar); | ||
1239 | } | 1239 | } | ||
1240 | 1240 | | |||
1241 | void Client::doSetSkipPager() | 1241 | void X11Client::doSetSkipPager() | ||
1242 | { | 1242 | { | ||
1243 | info->setState(skipPager() ? NET::SkipPager : NET::States(), NET::SkipPager); | 1243 | info->setState(skipPager() ? NET::SkipPager : NET::States(), NET::SkipPager); | ||
1244 | } | 1244 | } | ||
1245 | 1245 | | |||
1246 | void Client::doSetSkipSwitcher() | 1246 | void X11Client::doSetSkipSwitcher() | ||
1247 | { | 1247 | { | ||
1248 | info->setState(skipSwitcher() ? NET::SkipSwitcher : NET::States(), NET::SkipSwitcher); | 1248 | info->setState(skipSwitcher() ? NET::SkipSwitcher : NET::States(), NET::SkipSwitcher); | ||
1249 | } | 1249 | } | ||
1250 | 1250 | | |||
1251 | void Client::doSetDesktop(int desktop, int was_desk) | 1251 | void X11Client::doSetDesktop(int desktop, int was_desk) | ||
1252 | { | 1252 | { | ||
1253 | Q_UNUSED(desktop) | 1253 | Q_UNUSED(desktop) | ||
1254 | Q_UNUSED(was_desk) | 1254 | Q_UNUSED(was_desk) | ||
1255 | updateVisibility(); | 1255 | updateVisibility(); | ||
1256 | } | 1256 | } | ||
1257 | 1257 | | |||
1258 | /** | 1258 | /** | ||
1259 | * Sets whether the client is on @p activity. | 1259 | * Sets whether the client is on @p activity. | ||
1260 | * If you remove it from its last activity, then it's on all activities. | 1260 | * If you remove it from its last activity, then it's on all activities. | ||
1261 | * | 1261 | * | ||
1262 | * Note: If it was on all activities and you try to remove it from one, nothing will happen; | 1262 | * Note: If it was on all activities and you try to remove it from one, nothing will happen; | ||
1263 | * I don't think that's an important enough use case to handle here. | 1263 | * I don't think that's an important enough use case to handle here. | ||
1264 | */ | 1264 | */ | ||
1265 | void Client::setOnActivity(const QString &activity, bool enable) | 1265 | void X11Client::setOnActivity(const QString &activity, bool enable) | ||
1266 | { | 1266 | { | ||
1267 | #ifdef KWIN_BUILD_ACTIVITIES | 1267 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1268 | if (! Activities::self()) { | 1268 | if (! Activities::self()) { | ||
1269 | return; | 1269 | return; | ||
1270 | } | 1270 | } | ||
1271 | QStringList newActivitiesList = activities(); | 1271 | QStringList newActivitiesList = activities(); | ||
1272 | if (newActivitiesList.contains(activity) == enable) //nothing to do | 1272 | if (newActivitiesList.contains(activity) == enable) //nothing to do | ||
1273 | return; | 1273 | return; | ||
Show All 9 Lines | 1282 | #else | |||
1283 | Q_UNUSED(activity) | 1283 | Q_UNUSED(activity) | ||
1284 | Q_UNUSED(enable) | 1284 | Q_UNUSED(enable) | ||
1285 | #endif | 1285 | #endif | ||
1286 | } | 1286 | } | ||
1287 | 1287 | | |||
1288 | /** | 1288 | /** | ||
1289 | * set exactly which activities this client is on | 1289 | * set exactly which activities this client is on | ||
1290 | */ | 1290 | */ | ||
1291 | void Client::setOnActivities(QStringList newActivitiesList) | 1291 | void X11Client::setOnActivities(QStringList newActivitiesList) | ||
1292 | { | 1292 | { | ||
1293 | #ifdef KWIN_BUILD_ACTIVITIES | 1293 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1294 | if (!Activities::self()) { | 1294 | if (!Activities::self()) { | ||
1295 | return; | 1295 | return; | ||
1296 | } | 1296 | } | ||
1297 | QString joinedActivitiesList = newActivitiesList.join(QStringLiteral(",")); | 1297 | QString joinedActivitiesList = newActivitiesList.join(QStringLiteral(",")); | ||
1298 | joinedActivitiesList = rules()->checkActivity(joinedActivitiesList, false); | 1298 | joinedActivitiesList = rules()->checkActivity(joinedActivitiesList, false); | ||
1299 | newActivitiesList = joinedActivitiesList.split(u',', QString::SkipEmptyParts); | 1299 | newActivitiesList = joinedActivitiesList.split(u',', QString::SkipEmptyParts); | ||
Show All 25 Lines | |||||
1325 | } | 1325 | } | ||
1326 | 1326 | | |||
1327 | updateActivities(false); | 1327 | updateActivities(false); | ||
1328 | #else | 1328 | #else | ||
1329 | Q_UNUSED(newActivitiesList) | 1329 | Q_UNUSED(newActivitiesList) | ||
1330 | #endif | 1330 | #endif | ||
1331 | } | 1331 | } | ||
1332 | 1332 | | |||
1333 | void Client::blockActivityUpdates(bool b) | 1333 | void X11Client::blockActivityUpdates(bool b) | ||
1334 | { | 1334 | { | ||
1335 | if (b) { | 1335 | if (b) { | ||
1336 | ++m_activityUpdatesBlocked; | 1336 | ++m_activityUpdatesBlocked; | ||
1337 | } else { | 1337 | } else { | ||
1338 | Q_ASSERT(m_activityUpdatesBlocked); | 1338 | Q_ASSERT(m_activityUpdatesBlocked); | ||
1339 | --m_activityUpdatesBlocked; | 1339 | --m_activityUpdatesBlocked; | ||
1340 | if (!m_activityUpdatesBlocked) | 1340 | if (!m_activityUpdatesBlocked) | ||
1341 | updateActivities(m_blockedActivityUpdatesRequireTransients); | 1341 | updateActivities(m_blockedActivityUpdatesRequireTransients); | ||
1342 | } | 1342 | } | ||
1343 | } | 1343 | } | ||
1344 | 1344 | | |||
1345 | /** | 1345 | /** | ||
1346 | * update after activities changed | 1346 | * update after activities changed | ||
1347 | */ | 1347 | */ | ||
1348 | void Client::updateActivities(bool includeTransients) | 1348 | void X11Client::updateActivities(bool includeTransients) | ||
1349 | { | 1349 | { | ||
1350 | if (m_activityUpdatesBlocked) { | 1350 | if (m_activityUpdatesBlocked) { | ||
1351 | m_blockedActivityUpdatesRequireTransients |= includeTransients; | 1351 | m_blockedActivityUpdatesRequireTransients |= includeTransients; | ||
1352 | return; | 1352 | return; | ||
1353 | } | 1353 | } | ||
1354 | emit activitiesChanged(this); | 1354 | emit activitiesChanged(this); | ||
1355 | m_blockedActivityUpdatesRequireTransients = false; // reset | 1355 | m_blockedActivityUpdatesRequireTransients = false; // reset | ||
1356 | FocusChain::self()->update(this, FocusChain::MakeFirst); | 1356 | FocusChain::self()->update(this, FocusChain::MakeFirst); | ||
1357 | updateVisibility(); | 1357 | updateVisibility(); | ||
1358 | updateWindowRules(Rules::Activity); | 1358 | updateWindowRules(Rules::Activity); | ||
1359 | } | 1359 | } | ||
1360 | 1360 | | |||
1361 | /** | 1361 | /** | ||
1362 | * Returns the list of activities the client window is on. | 1362 | * Returns the list of activities the client window is on. | ||
1363 | * if it's on all activities, the list will be empty. | 1363 | * if it's on all activities, the list will be empty. | ||
1364 | * Don't use this, use isOnActivity() and friends (from class Toplevel) | 1364 | * Don't use this, use isOnActivity() and friends (from class Toplevel) | ||
1365 | */ | 1365 | */ | ||
1366 | QStringList Client::activities() const | 1366 | QStringList X11Client::activities() const | ||
1367 | { | 1367 | { | ||
1368 | if (sessionActivityOverride) { | 1368 | if (sessionActivityOverride) { | ||
1369 | return QStringList(); | 1369 | return QStringList(); | ||
1370 | } | 1370 | } | ||
1371 | return activityList; | 1371 | return activityList; | ||
1372 | } | 1372 | } | ||
1373 | 1373 | | |||
1374 | /** | 1374 | /** | ||
1375 | * if @p on is true, sets on all activities. | 1375 | * if @p on is true, sets on all activities. | ||
1376 | * if it's false, sets it to only be on the current activity | 1376 | * if it's false, sets it to only be on the current activity | ||
1377 | */ | 1377 | */ | ||
1378 | void Client::setOnAllActivities(bool on) | 1378 | void X11Client::setOnAllActivities(bool on) | ||
1379 | { | 1379 | { | ||
1380 | #ifdef KWIN_BUILD_ACTIVITIES | 1380 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1381 | if (on == isOnAllActivities()) | 1381 | if (on == isOnAllActivities()) | ||
1382 | return; | 1382 | return; | ||
1383 | if (on) { | 1383 | if (on) { | ||
1384 | setOnActivities(QStringList()); | 1384 | setOnActivities(QStringList()); | ||
1385 | 1385 | | |||
1386 | } else { | 1386 | } else { | ||
1387 | setOnActivity(Activities::self()->current(), true); | 1387 | setOnActivity(Activities::self()->current(), true); | ||
1388 | } | 1388 | } | ||
1389 | #else | 1389 | #else | ||
1390 | Q_UNUSED(on) | 1390 | Q_UNUSED(on) | ||
1391 | #endif | 1391 | #endif | ||
1392 | } | 1392 | } | ||
1393 | 1393 | | |||
1394 | /** | 1394 | /** | ||
1395 | * Performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS | 1395 | * Performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS | ||
1396 | */ | 1396 | */ | ||
1397 | void Client::takeFocus() | 1397 | void X11Client::takeFocus() | ||
1398 | { | 1398 | { | ||
1399 | if (rules()->checkAcceptFocus(info->input())) | 1399 | if (rules()->checkAcceptFocus(info->input())) | ||
1400 | m_client.focus(); | 1400 | m_client.focus(); | ||
1401 | else | 1401 | else | ||
1402 | demandAttention(false); // window cannot take input, at least withdraw urgency | 1402 | demandAttention(false); // window cannot take input, at least withdraw urgency | ||
1403 | if (info->supportsProtocol(NET::TakeFocusProtocol)) { | 1403 | if (info->supportsProtocol(NET::TakeFocusProtocol)) { | ||
1404 | sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus, 0, 0, 0, XCB_CURRENT_TIME); | 1404 | sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus, 0, 0, 0, XCB_CURRENT_TIME); | ||
1405 | } | 1405 | } | ||
1406 | workspace()->setShouldGetFocus(this); | 1406 | workspace()->setShouldGetFocus(this); | ||
1407 | 1407 | | |||
1408 | bool breakShowingDesktop = !keepAbove(); | 1408 | bool breakShowingDesktop = !keepAbove(); | ||
1409 | if (breakShowingDesktop) { | 1409 | if (breakShowingDesktop) { | ||
1410 | foreach (const Client *c, group()->members()) { | 1410 | foreach (const X11Client *c, group()->members()) { | ||
1411 | if (c->isDesktop()) { | 1411 | if (c->isDesktop()) { | ||
1412 | breakShowingDesktop = false; | 1412 | breakShowingDesktop = false; | ||
1413 | break; | 1413 | break; | ||
1414 | } | 1414 | } | ||
1415 | } | 1415 | } | ||
1416 | } | 1416 | } | ||
1417 | if (breakShowingDesktop) | 1417 | if (breakShowingDesktop) | ||
1418 | workspace()->setShowingDesktop(false); | 1418 | workspace()->setShowingDesktop(false); | ||
1419 | } | 1419 | } | ||
1420 | 1420 | | |||
1421 | /** | 1421 | /** | ||
1422 | * Returns whether the window provides context help or not. If it does, | 1422 | * Returns whether the window provides context help or not. If it does, | ||
1423 | * you should show a help menu item or a help button like '?' and call | 1423 | * you should show a help menu item or a help button like '?' and call | ||
1424 | * contextHelp() if this is invoked. | 1424 | * contextHelp() if this is invoked. | ||
1425 | * | 1425 | * | ||
1426 | * \sa contextHelp() | 1426 | * \sa contextHelp() | ||
1427 | */ | 1427 | */ | ||
1428 | bool Client::providesContextHelp() const | 1428 | bool X11Client::providesContextHelp() const | ||
1429 | { | 1429 | { | ||
1430 | return info->supportsProtocol(NET::ContextHelpProtocol); | 1430 | return info->supportsProtocol(NET::ContextHelpProtocol); | ||
1431 | } | 1431 | } | ||
1432 | 1432 | | |||
1433 | /** | 1433 | /** | ||
1434 | * Invokes context help on the window. Only works if the window | 1434 | * Invokes context help on the window. Only works if the window | ||
1435 | * actually provides context help. | 1435 | * actually provides context help. | ||
1436 | * | 1436 | * | ||
1437 | * \sa providesContextHelp() | 1437 | * \sa providesContextHelp() | ||
1438 | */ | 1438 | */ | ||
1439 | void Client::showContextHelp() | 1439 | void X11Client::showContextHelp() | ||
1440 | { | 1440 | { | ||
1441 | if (info->supportsProtocol(NET::ContextHelpProtocol)) { | 1441 | if (info->supportsProtocol(NET::ContextHelpProtocol)) { | ||
1442 | sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help); | 1442 | sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help); | ||
1443 | } | 1443 | } | ||
1444 | } | 1444 | } | ||
1445 | 1445 | | |||
1446 | /** | 1446 | /** | ||
1447 | * Fetches the window's caption (WM_NAME property). It will be | 1447 | * Fetches the window's caption (WM_NAME property). It will be | ||
1448 | * stored in the client's caption(). | 1448 | * stored in the client's caption(). | ||
1449 | */ | 1449 | */ | ||
1450 | void Client::fetchName() | 1450 | void X11Client::fetchName() | ||
1451 | { | 1451 | { | ||
1452 | setCaption(readName()); | 1452 | setCaption(readName()); | ||
1453 | } | 1453 | } | ||
1454 | 1454 | | |||
1455 | static inline QString readNameProperty(xcb_window_t w, xcb_atom_t atom) | 1455 | static inline QString readNameProperty(xcb_window_t w, xcb_atom_t atom) | ||
1456 | { | 1456 | { | ||
1457 | const auto cookie = xcb_icccm_get_text_property_unchecked(connection(), w, atom); | 1457 | const auto cookie = xcb_icccm_get_text_property_unchecked(connection(), w, atom); | ||
1458 | xcb_icccm_get_text_property_reply_t reply; | 1458 | xcb_icccm_get_text_property_reply_t reply; | ||
1459 | if (xcb_icccm_get_wm_name_reply(connection(), cookie, &reply, nullptr)) { | 1459 | if (xcb_icccm_get_wm_name_reply(connection(), cookie, &reply, nullptr)) { | ||
1460 | QString retVal; | 1460 | QString retVal; | ||
1461 | if (reply.encoding == atoms->utf8_string) { | 1461 | if (reply.encoding == atoms->utf8_string) { | ||
1462 | retVal = QString::fromUtf8(QByteArray(reply.name, reply.name_len)); | 1462 | retVal = QString::fromUtf8(QByteArray(reply.name, reply.name_len)); | ||
1463 | } else if (reply.encoding == XCB_ATOM_STRING) { | 1463 | } else if (reply.encoding == XCB_ATOM_STRING) { | ||
1464 | retVal = QString::fromLocal8Bit(QByteArray(reply.name, reply.name_len)); | 1464 | retVal = QString::fromLocal8Bit(QByteArray(reply.name, reply.name_len)); | ||
1465 | } | 1465 | } | ||
1466 | xcb_icccm_get_text_property_reply_wipe(&reply); | 1466 | xcb_icccm_get_text_property_reply_wipe(&reply); | ||
1467 | return retVal.simplified(); | 1467 | return retVal.simplified(); | ||
1468 | } | 1468 | } | ||
1469 | return QString(); | 1469 | return QString(); | ||
1470 | } | 1470 | } | ||
1471 | 1471 | | |||
1472 | QString Client::readName() const | 1472 | QString X11Client::readName() const | ||
1473 | { | 1473 | { | ||
1474 | if (info->name() && info->name()[0] != '\0') | 1474 | if (info->name() && info->name()[0] != '\0') | ||
1475 | return QString::fromUtf8(info->name()).simplified(); | 1475 | return QString::fromUtf8(info->name()).simplified(); | ||
1476 | else { | 1476 | else { | ||
1477 | return readNameProperty(window(), XCB_ATOM_WM_NAME); | 1477 | return readNameProperty(window(), XCB_ATOM_WM_NAME); | ||
1478 | } | 1478 | } | ||
1479 | } | 1479 | } | ||
1480 | 1480 | | |||
1481 | // The list is taken from https://www.unicode.org/reports/tr9/ (#154840) | 1481 | // The list is taken from https://www.unicode.org/reports/tr9/ (#154840) | ||
1482 | static const QChar LRM(0x200E); | 1482 | static const QChar LRM(0x200E); | ||
1483 | 1483 | | |||
1484 | void Client::setCaption(const QString& _s, bool force) | 1484 | void X11Client::setCaption(const QString& _s, bool force) | ||
1485 | { | 1485 | { | ||
1486 | QString s(_s); | 1486 | QString s(_s); | ||
1487 | for (int i = 0; i < s.length(); ) { | 1487 | for (int i = 0; i < s.length(); ) { | ||
1488 | if (!s[i].isPrint()) { | 1488 | if (!s[i].isPrint()) { | ||
1489 | if (QChar(s[i]).isHighSurrogate() && i + 1 < s.length() && QChar(s[i + 1]).isLowSurrogate()) { | 1489 | if (QChar(s[i]).isHighSurrogate() && i + 1 < s.length() && QChar(s[i + 1]).isLowSurrogate()) { | ||
1490 | const uint uc = QChar::surrogateToUcs4(s[i], s[i + 1]); | 1490 | const uint uc = QChar::surrogateToUcs4(s[i], s[i + 1]); | ||
1491 | if (!QChar::isPrint(uc)) { | 1491 | if (!QChar::isPrint(uc)) { | ||
1492 | s.remove(i, 2); | 1492 | s.remove(i, 2); | ||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Line(s) | 1532 | if ((was_suffix && cap_suffix.isEmpty()) || reset_name) { | |||
1535 | info->setVisibleIconName(""); | 1535 | info->setVisibleIconName(""); | ||
1536 | } else if (!cap_suffix.isEmpty() && !cap_iconic.isEmpty()) | 1536 | } else if (!cap_suffix.isEmpty() && !cap_iconic.isEmpty()) | ||
1537 | // Keep the same suffix in iconic name if it's set | 1537 | // Keep the same suffix in iconic name if it's set | ||
1538 | info->setVisibleIconName(QString(cap_iconic + cap_suffix).toUtf8().constData()); | 1538 | info->setVisibleIconName(QString(cap_iconic + cap_suffix).toUtf8().constData()); | ||
1539 | 1539 | | |||
1540 | emit captionChanged(); | 1540 | emit captionChanged(); | ||
1541 | } | 1541 | } | ||
1542 | 1542 | | |||
1543 | void Client::updateCaption() | 1543 | void X11Client::updateCaption() | ||
1544 | { | 1544 | { | ||
1545 | setCaption(cap_normal, true); | 1545 | setCaption(cap_normal, true); | ||
1546 | } | 1546 | } | ||
1547 | 1547 | | |||
1548 | void Client::fetchIconicName() | 1548 | void X11Client::fetchIconicName() | ||
1549 | { | 1549 | { | ||
1550 | QString s; | 1550 | QString s; | ||
1551 | if (info->iconName() && info->iconName()[0] != '\0') | 1551 | if (info->iconName() && info->iconName()[0] != '\0') | ||
1552 | s = QString::fromUtf8(info->iconName()); | 1552 | s = QString::fromUtf8(info->iconName()); | ||
1553 | else | 1553 | else | ||
1554 | s = readNameProperty(window(), XCB_ATOM_WM_ICON_NAME); | 1554 | s = readNameProperty(window(), XCB_ATOM_WM_ICON_NAME); | ||
1555 | if (s != cap_iconic) { | 1555 | if (s != cap_iconic) { | ||
1556 | bool was_set = !cap_iconic.isEmpty(); | 1556 | bool was_set = !cap_iconic.isEmpty(); | ||
1557 | cap_iconic = s; | 1557 | cap_iconic = s; | ||
1558 | if (!cap_suffix.isEmpty()) { | 1558 | if (!cap_suffix.isEmpty()) { | ||
1559 | if (!cap_iconic.isEmpty()) // Keep the same suffix in iconic name if it's set | 1559 | if (!cap_iconic.isEmpty()) // Keep the same suffix in iconic name if it's set | ||
1560 | info->setVisibleIconName(QString(s + cap_suffix).toUtf8().constData()); | 1560 | info->setVisibleIconName(QString(s + cap_suffix).toUtf8().constData()); | ||
1561 | else if (was_set) | 1561 | else if (was_set) | ||
1562 | info->setVisibleIconName(""); | 1562 | info->setVisibleIconName(""); | ||
1563 | } | 1563 | } | ||
1564 | } | 1564 | } | ||
1565 | } | 1565 | } | ||
1566 | 1566 | | |||
1567 | void Client::setClientShown(bool shown) | 1567 | void X11Client::setClientShown(bool shown) | ||
1568 | { | 1568 | { | ||
1569 | if (deleting) | 1569 | if (deleting) | ||
1570 | return; // Don't change shown status if this client is being deleted | 1570 | return; // Don't change shown status if this client is being deleted | ||
1571 | if (shown != hidden) | 1571 | if (shown != hidden) | ||
1572 | return; // nothing to change | 1572 | return; // nothing to change | ||
1573 | hidden = !shown; | 1573 | hidden = !shown; | ||
1574 | if (shown) { | 1574 | if (shown) { | ||
1575 | map(); | 1575 | map(); | ||
1576 | takeFocus(); | 1576 | takeFocus(); | ||
1577 | autoRaise(); | 1577 | autoRaise(); | ||
1578 | FocusChain::self()->update(this, FocusChain::MakeFirst); | 1578 | FocusChain::self()->update(this, FocusChain::MakeFirst); | ||
1579 | } else { | 1579 | } else { | ||
1580 | unmap(); | 1580 | unmap(); | ||
1581 | // Don't move tabs to the end of the list when another tab get's activated | 1581 | // Don't move tabs to the end of the list when another tab get's activated | ||
1582 | FocusChain::self()->update(this, FocusChain::MakeLast); | 1582 | FocusChain::self()->update(this, FocusChain::MakeLast); | ||
1583 | addWorkspaceRepaint(visibleRect()); | 1583 | addWorkspaceRepaint(visibleRect()); | ||
1584 | } | 1584 | } | ||
1585 | } | 1585 | } | ||
1586 | 1586 | | |||
1587 | void Client::getMotifHints() | 1587 | void X11Client::getMotifHints() | ||
1588 | { | 1588 | { | ||
1589 | const bool wasClosable = m_motif.close(); | 1589 | const bool wasClosable = m_motif.close(); | ||
1590 | const bool wasNoBorder = m_motif.noBorder(); | 1590 | const bool wasNoBorder = m_motif.noBorder(); | ||
1591 | if (m_managed) // only on property change, initial read is prefetched | 1591 | if (m_managed) // only on property change, initial read is prefetched | ||
1592 | m_motif.fetch(); | 1592 | m_motif.fetch(); | ||
1593 | m_motif.read(); | 1593 | m_motif.read(); | ||
1594 | if (m_motif.hasDecoration() && m_motif.noBorder() != wasNoBorder) { | 1594 | if (m_motif.hasDecoration() && m_motif.noBorder() != wasNoBorder) { | ||
1595 | // If we just got a hint telling us to hide decorations, we do so. | 1595 | // If we just got a hint telling us to hide decorations, we do so. | ||
Show All 10 Lines | |||||
1606 | const bool closabilityChanged = wasClosable != m_motif.close(); | 1606 | const bool closabilityChanged = wasClosable != m_motif.close(); | ||
1607 | if (isManaged()) | 1607 | if (isManaged()) | ||
1608 | updateDecoration(true); // Check if noborder state has changed | 1608 | updateDecoration(true); // Check if noborder state has changed | ||
1609 | if (closabilityChanged) { | 1609 | if (closabilityChanged) { | ||
1610 | emit closeableChanged(isCloseable()); | 1610 | emit closeableChanged(isCloseable()); | ||
1611 | } | 1611 | } | ||
1612 | } | 1612 | } | ||
1613 | 1613 | | |||
1614 | void Client::getIcons() | 1614 | void X11Client::getIcons() | ||
1615 | { | 1615 | { | ||
1616 | // First read icons from the window itself | 1616 | // First read icons from the window itself | ||
1617 | const QString themedIconName = iconFromDesktopFile(); | 1617 | const QString themedIconName = iconFromDesktopFile(); | ||
1618 | if (!themedIconName.isEmpty()) { | 1618 | if (!themedIconName.isEmpty()) { | ||
1619 | setIcon(QIcon::fromTheme(themedIconName)); | 1619 | setIcon(QIcon::fromTheme(themedIconName)); | ||
1620 | return; | 1620 | return; | ||
1621 | } | 1621 | } | ||
1622 | QIcon icon; | 1622 | QIcon icon; | ||
Show All 29 Lines | 1650 | if (icon.isNull()) { | |||
1652 | icon.addPixmap(KWindowSystem::icon(window(), 32, 32, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | 1652 | icon.addPixmap(KWindowSystem::icon(window(), 32, 32, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | ||
1653 | icon.addPixmap(KWindowSystem::icon(window(), 16, 16, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | 1653 | icon.addPixmap(KWindowSystem::icon(window(), 16, 16, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | ||
1654 | icon.addPixmap(KWindowSystem::icon(window(), 64, 64, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | 1654 | icon.addPixmap(KWindowSystem::icon(window(), 64, 64, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | ||
1655 | icon.addPixmap(KWindowSystem::icon(window(), 128, 128, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | 1655 | icon.addPixmap(KWindowSystem::icon(window(), 128, 128, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info)); | ||
1656 | } | 1656 | } | ||
1657 | setIcon(icon); | 1657 | setIcon(icon); | ||
1658 | } | 1658 | } | ||
1659 | 1659 | | |||
1660 | void Client::getSyncCounter() | 1660 | void X11Client::getSyncCounter() | ||
1661 | { | 1661 | { | ||
1662 | // TODO: make sync working on XWayland | 1662 | // TODO: make sync working on XWayland | ||
1663 | static const bool isX11 = kwinApp()->operationMode() == Application::OperationModeX11; | 1663 | static const bool isX11 = kwinApp()->operationMode() == Application::OperationModeX11; | ||
1664 | if (!Xcb::Extensions::self()->isSyncAvailable() || !isX11) | 1664 | if (!Xcb::Extensions::self()->isSyncAvailable() || !isX11) | ||
1665 | return; | 1665 | return; | ||
1666 | 1666 | | |||
1667 | Xcb::Property syncProp(false, window(), atoms->net_wm_sync_request_counter, XCB_ATOM_CARDINAL, 0, 1); | 1667 | Xcb::Property syncProp(false, window(), atoms->net_wm_sync_request_counter, XCB_ATOM_CARDINAL, 0, 1); | ||
1668 | const xcb_sync_counter_t counter = syncProp.value<xcb_sync_counter_t>(XCB_NONE); | 1668 | const xcb_sync_counter_t counter = syncProp.value<xcb_sync_counter_t>(XCB_NONE); | ||
Show All 27 Lines | 1675 | if (syncRequest.alarm == XCB_NONE) { | |||
1696 | } | 1696 | } | ||
1697 | } | 1697 | } | ||
1698 | } | 1698 | } | ||
1699 | } | 1699 | } | ||
1700 | 1700 | | |||
1701 | /** | 1701 | /** | ||
1702 | * Send the client a _NET_SYNC_REQUEST | 1702 | * Send the client a _NET_SYNC_REQUEST | ||
1703 | */ | 1703 | */ | ||
1704 | void Client::sendSyncRequest() | 1704 | void X11Client::sendSyncRequest() | ||
1705 | { | 1705 | { | ||
1706 | if (syncRequest.counter == XCB_NONE || syncRequest.isPending) | 1706 | if (syncRequest.counter == XCB_NONE || syncRequest.isPending) | ||
1707 | return; // do NOT, NEVER send a sync request when there's one on the stack. the clients will just stop respoding. FOREVER! ... | 1707 | return; // do NOT, NEVER send a sync request when there's one on the stack. the clients will just stop respoding. FOREVER! ... | ||
1708 | 1708 | | |||
1709 | if (!syncRequest.failsafeTimeout) { | 1709 | if (!syncRequest.failsafeTimeout) { | ||
1710 | syncRequest.failsafeTimeout = new QTimer(this); | 1710 | syncRequest.failsafeTimeout = new QTimer(this); | ||
1711 | connect(syncRequest.failsafeTimeout, &QTimer::timeout, this, | 1711 | connect(syncRequest.failsafeTimeout, &QTimer::timeout, this, | ||
1712 | [this]() { | 1712 | [this]() { | ||
Show All 10 Lines | |||||
1723 | delete syncRequest.timeout; delete syncRequest.failsafeTimeout; | 1723 | delete syncRequest.timeout; delete syncRequest.failsafeTimeout; | ||
1724 | syncRequest.timeout = syncRequest.failsafeTimeout = nullptr; | 1724 | syncRequest.timeout = syncRequest.failsafeTimeout = nullptr; | ||
1725 | syncRequest.lastTimestamp = XCB_CURRENT_TIME; | 1725 | syncRequest.lastTimestamp = XCB_CURRENT_TIME; | ||
1726 | } | 1726 | } | ||
1727 | ); | 1727 | ); | ||
1728 | syncRequest.failsafeTimeout->setSingleShot(true); | 1728 | syncRequest.failsafeTimeout->setSingleShot(true); | ||
1729 | } | 1729 | } | ||
1730 | // if there's no response within 10 seconds, sth. went wrong and we remove XSYNC support from this client. | 1730 | // if there's no response within 10 seconds, sth. went wrong and we remove XSYNC support from this client. | ||
1731 | // see events.cpp Client::syncEvent() | 1731 | // see events.cpp X11Client::syncEvent() | ||
1732 | syncRequest.failsafeTimeout->start(ready_for_painting ? 10000 : 1000); | 1732 | syncRequest.failsafeTimeout->start(ready_for_painting ? 10000 : 1000); | ||
1733 | 1733 | | |||
1734 | // We increment before the notify so that after the notify | 1734 | // We increment before the notify so that after the notify | ||
1735 | // syncCounterSerial will equal the value we are expecting | 1735 | // syncCounterSerial will equal the value we are expecting | ||
1736 | // in the acknowledgement | 1736 | // in the acknowledgement | ||
1737 | const uint32_t oldLo = syncRequest.value.lo; | 1737 | const uint32_t oldLo = syncRequest.value.lo; | ||
1738 | syncRequest.value.lo++;; | 1738 | syncRequest.value.lo++;; | ||
1739 | if (oldLo > syncRequest.value.lo) { | 1739 | if (oldLo > syncRequest.value.lo) { | ||
1740 | syncRequest.value.hi++; | 1740 | syncRequest.value.hi++; | ||
1741 | } | 1741 | } | ||
1742 | if (syncRequest.lastTimestamp >= xTime()) { | 1742 | if (syncRequest.lastTimestamp >= xTime()) { | ||
1743 | updateXTime(); | 1743 | updateXTime(); | ||
1744 | } | 1744 | } | ||
1745 | 1745 | | |||
1746 | // Send the message to client | 1746 | // Send the message to client | ||
1747 | sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_sync_request, syncRequest.value.lo, syncRequest.value.hi); | 1747 | sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_sync_request, syncRequest.value.lo, syncRequest.value.hi); | ||
1748 | syncRequest.isPending = true; | 1748 | syncRequest.isPending = true; | ||
1749 | syncRequest.lastTimestamp = xTime(); | 1749 | syncRequest.lastTimestamp = xTime(); | ||
1750 | } | 1750 | } | ||
1751 | 1751 | | |||
1752 | bool Client::wantsInput() const | 1752 | bool X11Client::wantsInput() const | ||
1753 | { | 1753 | { | ||
1754 | return rules()->checkAcceptFocus(acceptsFocus() || info->supportsProtocol(NET::TakeFocusProtocol)); | 1754 | return rules()->checkAcceptFocus(acceptsFocus() || info->supportsProtocol(NET::TakeFocusProtocol)); | ||
1755 | } | 1755 | } | ||
1756 | 1756 | | |||
1757 | bool Client::acceptsFocus() const | 1757 | bool X11Client::acceptsFocus() const | ||
1758 | { | 1758 | { | ||
1759 | return info->input(); | 1759 | return info->input(); | ||
1760 | } | 1760 | } | ||
1761 | 1761 | | |||
1762 | void Client::setBlockingCompositing(bool block) | 1762 | void X11Client::setBlockingCompositing(bool block) | ||
1763 | { | 1763 | { | ||
1764 | const bool usedToBlock = blocks_compositing; | 1764 | const bool usedToBlock = blocks_compositing; | ||
1765 | blocks_compositing = rules()->checkBlockCompositing(block && options->windowsBlockCompositing()); | 1765 | blocks_compositing = rules()->checkBlockCompositing(block && options->windowsBlockCompositing()); | ||
1766 | if (usedToBlock != blocks_compositing) { | 1766 | if (usedToBlock != blocks_compositing) { | ||
1767 | emit blockingCompositingChanged(blocks_compositing ? this : nullptr); | 1767 | emit blockingCompositingChanged(blocks_compositing ? this : nullptr); | ||
1768 | } | 1768 | } | ||
1769 | } | 1769 | } | ||
1770 | 1770 | | |||
1771 | void Client::updateAllowedActions(bool force) | 1771 | void X11Client::updateAllowedActions(bool force) | ||
1772 | { | 1772 | { | ||
1773 | if (!isManaged() && !force) | 1773 | if (!isManaged() && !force) | ||
1774 | return; | 1774 | return; | ||
1775 | NET::Actions old_allowed_actions = NET::Actions(allowed_actions); | 1775 | NET::Actions old_allowed_actions = NET::Actions(allowed_actions); | ||
1776 | allowed_actions = NET::Actions(); | 1776 | allowed_actions = NET::Actions(); | ||
1777 | if (isMovable()) | 1777 | if (isMovable()) | ||
1778 | allowed_actions |= NET::ActionMove; | 1778 | allowed_actions |= NET::ActionMove; | ||
1779 | if (isResizable()) | 1779 | if (isResizable()) | ||
Show All 25 Lines | 1804 | if ((allowed_actions & NET::ActionShade) != (old_allowed_actions & NET::ActionShade)) { | |||
1805 | emit shadeableChanged(allowed_actions & NET::ActionShade); | 1805 | emit shadeableChanged(allowed_actions & NET::ActionShade); | ||
1806 | } | 1806 | } | ||
1807 | if ((allowed_actions & NET::ActionMax) != (old_allowed_actions & NET::ActionMax)) { | 1807 | if ((allowed_actions & NET::ActionMax) != (old_allowed_actions & NET::ActionMax)) { | ||
1808 | emit maximizeableChanged(allowed_actions & NET::ActionMax); | 1808 | emit maximizeableChanged(allowed_actions & NET::ActionMax); | ||
1809 | } | 1809 | } | ||
1810 | } | 1810 | } | ||
1811 | } | 1811 | } | ||
1812 | 1812 | | |||
1813 | void Client::debug(QDebug& stream) const | 1813 | void X11Client::debug(QDebug& stream) const | ||
1814 | { | 1814 | { | ||
1815 | stream.nospace(); | 1815 | stream.nospace(); | ||
1816 | print<QDebug>(stream); | 1816 | print<QDebug>(stream); | ||
1817 | } | 1817 | } | ||
1818 | 1818 | | |||
1819 | Xcb::StringProperty Client::fetchActivities() const | 1819 | Xcb::StringProperty X11Client::fetchActivities() const | ||
1820 | { | 1820 | { | ||
1821 | #ifdef KWIN_BUILD_ACTIVITIES | 1821 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1822 | return Xcb::StringProperty(window(), atoms->activities); | 1822 | return Xcb::StringProperty(window(), atoms->activities); | ||
1823 | #else | 1823 | #else | ||
1824 | return Xcb::StringProperty(); | 1824 | return Xcb::StringProperty(); | ||
1825 | #endif | 1825 | #endif | ||
1826 | } | 1826 | } | ||
1827 | 1827 | | |||
1828 | void Client::readActivities(Xcb::StringProperty &property) | 1828 | void X11Client::readActivities(Xcb::StringProperty &property) | ||
1829 | { | 1829 | { | ||
1830 | #ifdef KWIN_BUILD_ACTIVITIES | 1830 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1831 | QStringList newActivitiesList; | 1831 | QStringList newActivitiesList; | ||
1832 | QString prop = QString::fromUtf8(property); | 1832 | QString prop = QString::fromUtf8(property); | ||
1833 | activitiesDefined = !prop.isEmpty(); | 1833 | activitiesDefined = !prop.isEmpty(); | ||
1834 | 1834 | | |||
1835 | if (prop == Activities::nullUuid()) { | 1835 | if (prop == Activities::nullUuid()) { | ||
1836 | //copied from setOnAllActivities to avoid a redundant XChangeProperty. | 1836 | //copied from setOnAllActivities to avoid a redundant XChangeProperty. | ||
Show All 38 Lines | 1861 | if (Activities::self() && Activities::self()->serviceStatus() != KActivities::Consumer::Unknown) { | |||
1875 | } | 1875 | } | ||
1876 | } | 1876 | } | ||
1877 | setOnActivities(newActivitiesList); | 1877 | setOnActivities(newActivitiesList); | ||
1878 | #else | 1878 | #else | ||
1879 | Q_UNUSED(property) | 1879 | Q_UNUSED(property) | ||
1880 | #endif | 1880 | #endif | ||
1881 | } | 1881 | } | ||
1882 | 1882 | | |||
1883 | void Client::checkActivities() | 1883 | void X11Client::checkActivities() | ||
1884 | { | 1884 | { | ||
1885 | #ifdef KWIN_BUILD_ACTIVITIES | 1885 | #ifdef KWIN_BUILD_ACTIVITIES | ||
1886 | Xcb::StringProperty property = fetchActivities(); | 1886 | Xcb::StringProperty property = fetchActivities(); | ||
1887 | readActivities(property); | 1887 | readActivities(property); | ||
1888 | #endif | 1888 | #endif | ||
1889 | } | 1889 | } | ||
1890 | 1890 | | |||
1891 | void Client::setSessionActivityOverride(bool needed) | 1891 | void X11Client::setSessionActivityOverride(bool needed) | ||
1892 | { | 1892 | { | ||
1893 | sessionActivityOverride = needed; | 1893 | sessionActivityOverride = needed; | ||
1894 | updateActivities(false); | 1894 | updateActivities(false); | ||
1895 | } | 1895 | } | ||
1896 | 1896 | | |||
1897 | QRect Client::decorationRect() const | 1897 | QRect X11Client::decorationRect() const | ||
1898 | { | 1898 | { | ||
1899 | return QRect(0, 0, width(), height()); | 1899 | return QRect(0, 0, width(), height()); | ||
1900 | } | 1900 | } | ||
1901 | 1901 | | |||
1902 | Xcb::Property Client::fetchFirstInTabBox() const | 1902 | Xcb::Property X11Client::fetchFirstInTabBox() const | ||
1903 | { | 1903 | { | ||
1904 | return Xcb::Property(false, m_client, atoms->kde_first_in_window_list, | 1904 | return Xcb::Property(false, m_client, atoms->kde_first_in_window_list, | ||
1905 | atoms->kde_first_in_window_list, 0, 1); | 1905 | atoms->kde_first_in_window_list, 0, 1); | ||
1906 | } | 1906 | } | ||
1907 | 1907 | | |||
1908 | void Client::readFirstInTabBox(Xcb::Property &property) | 1908 | void X11Client::readFirstInTabBox(Xcb::Property &property) | ||
1909 | { | 1909 | { | ||
1910 | setFirstInTabBox(property.toBool(32, atoms->kde_first_in_window_list)); | 1910 | setFirstInTabBox(property.toBool(32, atoms->kde_first_in_window_list)); | ||
1911 | } | 1911 | } | ||
1912 | 1912 | | |||
1913 | void Client::updateFirstInTabBox() | 1913 | void X11Client::updateFirstInTabBox() | ||
1914 | { | 1914 | { | ||
1915 | // TODO: move into KWindowInfo | 1915 | // TODO: move into KWindowInfo | ||
1916 | Xcb::Property property = fetchFirstInTabBox(); | 1916 | Xcb::Property property = fetchFirstInTabBox(); | ||
1917 | readFirstInTabBox(property); | 1917 | readFirstInTabBox(property); | ||
1918 | } | 1918 | } | ||
1919 | 1919 | | |||
1920 | Xcb::StringProperty Client::fetchColorScheme() const | 1920 | Xcb::StringProperty X11Client::fetchColorScheme() const | ||
1921 | { | 1921 | { | ||
1922 | return Xcb::StringProperty(m_client, atoms->kde_color_sheme); | 1922 | return Xcb::StringProperty(m_client, atoms->kde_color_sheme); | ||
1923 | } | 1923 | } | ||
1924 | 1924 | | |||
1925 | void Client::readColorScheme(Xcb::StringProperty &property) | 1925 | void X11Client::readColorScheme(Xcb::StringProperty &property) | ||
1926 | { | 1926 | { | ||
1927 | AbstractClient::updateColorScheme(rules()->checkDecoColor(QString::fromUtf8(property))); | 1927 | AbstractClient::updateColorScheme(rules()->checkDecoColor(QString::fromUtf8(property))); | ||
1928 | } | 1928 | } | ||
1929 | 1929 | | |||
1930 | void Client::updateColorScheme() | 1930 | void X11Client::updateColorScheme() | ||
1931 | { | 1931 | { | ||
1932 | Xcb::StringProperty property = fetchColorScheme(); | 1932 | Xcb::StringProperty property = fetchColorScheme(); | ||
1933 | readColorScheme(property); | 1933 | readColorScheme(property); | ||
1934 | } | 1934 | } | ||
1935 | 1935 | | |||
1936 | bool Client::isClient() const | 1936 | bool X11Client::isClient() const | ||
1937 | { | 1937 | { | ||
1938 | return true; | 1938 | return true; | ||
1939 | } | 1939 | } | ||
1940 | 1940 | | |||
1941 | NET::WindowType Client::windowType(bool direct, int supportedTypes) const | 1941 | NET::WindowType X11Client::windowType(bool direct, int supportedTypes) const | ||
1942 | { | 1942 | { | ||
1943 | // TODO: does it make sense to cache the returned window type for SUPPORTED_MANAGED_WINDOW_TYPES_MASK? | 1943 | // TODO: does it make sense to cache the returned window type for SUPPORTED_MANAGED_WINDOW_TYPES_MASK? | ||
1944 | if (supportedTypes == 0) { | 1944 | if (supportedTypes == 0) { | ||
1945 | supportedTypes = SUPPORTED_MANAGED_WINDOW_TYPES_MASK; | 1945 | supportedTypes = SUPPORTED_MANAGED_WINDOW_TYPES_MASK; | ||
1946 | } | 1946 | } | ||
1947 | NET::WindowType wt = info->windowType(NET::WindowTypes(supportedTypes)); | 1947 | NET::WindowType wt = info->windowType(NET::WindowTypes(supportedTypes)); | ||
1948 | if (direct) { | 1948 | if (direct) { | ||
1949 | return wt; | 1949 | return wt; | ||
1950 | } | 1950 | } | ||
1951 | NET::WindowType wt2 = rules()->checkType(wt); | 1951 | NET::WindowType wt2 = rules()->checkType(wt); | ||
1952 | if (wt != wt2) { | 1952 | if (wt != wt2) { | ||
1953 | wt = wt2; | 1953 | wt = wt2; | ||
1954 | info->setWindowType(wt); // force hint change | 1954 | info->setWindowType(wt); // force hint change | ||
1955 | } | 1955 | } | ||
1956 | // hacks here | 1956 | // hacks here | ||
1957 | if (wt == NET::Unknown) // this is more or less suggested in NETWM spec | 1957 | if (wt == NET::Unknown) // this is more or less suggested in NETWM spec | ||
1958 | wt = isTransient() ? NET::Dialog : NET::Normal; | 1958 | wt = isTransient() ? NET::Dialog : NET::Normal; | ||
1959 | return wt; | 1959 | return wt; | ||
1960 | } | 1960 | } | ||
1961 | 1961 | | |||
1962 | void Client::cancelFocusOutTimer() | 1962 | void X11Client::cancelFocusOutTimer() | ||
1963 | { | 1963 | { | ||
1964 | if (m_focusOutTimer) { | 1964 | if (m_focusOutTimer) { | ||
1965 | m_focusOutTimer->stop(); | 1965 | m_focusOutTimer->stop(); | ||
1966 | } | 1966 | } | ||
1967 | } | 1967 | } | ||
1968 | 1968 | | |||
1969 | xcb_window_t Client::frameId() const | 1969 | xcb_window_t X11Client::frameId() const | ||
1970 | { | 1970 | { | ||
1971 | return m_frame; | 1971 | return m_frame; | ||
1972 | } | 1972 | } | ||
1973 | 1973 | | |||
1974 | Xcb::Property Client::fetchShowOnScreenEdge() const | 1974 | Xcb::Property X11Client::fetchShowOnScreenEdge() const | ||
1975 | { | 1975 | { | ||
1976 | return Xcb::Property(false, window(), atoms->kde_screen_edge_show, XCB_ATOM_CARDINAL, 0, 1); | 1976 | return Xcb::Property(false, window(), atoms->kde_screen_edge_show, XCB_ATOM_CARDINAL, 0, 1); | ||
1977 | } | 1977 | } | ||
1978 | 1978 | | |||
1979 | void Client::readShowOnScreenEdge(Xcb::Property &property) | 1979 | void X11Client::readShowOnScreenEdge(Xcb::Property &property) | ||
1980 | { | 1980 | { | ||
1981 | //value comes in two parts, edge in the lower byte | 1981 | //value comes in two parts, edge in the lower byte | ||
1982 | //then the type in the upper byte | 1982 | //then the type in the upper byte | ||
1983 | // 0 = autohide | 1983 | // 0 = autohide | ||
1984 | // 1 = raise in front on activate | 1984 | // 1 = raise in front on activate | ||
1985 | 1985 | | |||
1986 | const uint32_t value = property.value<uint32_t>(ElectricNone); | 1986 | const uint32_t value = property.value<uint32_t>(ElectricNone); | ||
1987 | ElectricBorder border = ElectricNone; | 1987 | ElectricBorder border = ElectricNone; | ||
Show All 24 Lines | 2011 | m_edgeRemoveConnection = connect(this, &AbstractClient::keepBelowChanged, this, [this](){ | |||
2012 | if (!keepBelow()) { | 2012 | if (!keepBelow()) { | ||
2013 | ScreenEdges::self()->reserve(this, ElectricNone); | 2013 | ScreenEdges::self()->reserve(this, ElectricNone); | ||
2014 | } | 2014 | } | ||
2015 | }); | 2015 | }); | ||
2016 | } else { | 2016 | } else { | ||
2017 | hideClient(true); | 2017 | hideClient(true); | ||
2018 | successfullyHidden = isHiddenInternal(); | 2018 | successfullyHidden = isHiddenInternal(); | ||
2019 | 2019 | | |||
2020 | m_edgeGeometryTrackingConnection = connect(this, &Client::geometryChanged, this, [this, border](){ | 2020 | m_edgeGeometryTrackingConnection = connect(this, &X11Client::geometryChanged, this, [this, border](){ | ||
2021 | hideClient(true); | 2021 | hideClient(true); | ||
2022 | ScreenEdges::self()->reserve(this, border); | 2022 | ScreenEdges::self()->reserve(this, border); | ||
2023 | }); | 2023 | }); | ||
2024 | } | 2024 | } | ||
2025 | 2025 | | |||
2026 | if (successfullyHidden) { | 2026 | if (successfullyHidden) { | ||
2027 | ScreenEdges::self()->reserve(this, border); | 2027 | ScreenEdges::self()->reserve(this, border); | ||
2028 | } else { | 2028 | } else { | ||
2029 | ScreenEdges::self()->reserve(this, ElectricNone); | 2029 | ScreenEdges::self()->reserve(this, ElectricNone); | ||
2030 | } | 2030 | } | ||
2031 | } else if (!property.isNull() && property->type != XCB_ATOM_NONE) { | 2031 | } else if (!property.isNull() && property->type != XCB_ATOM_NONE) { | ||
2032 | // property value is incorrect, delete the property | 2032 | // property value is incorrect, delete the property | ||
2033 | // so that the client knows that it is not hidden | 2033 | // so that the client knows that it is not hidden | ||
2034 | xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show); | 2034 | xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show); | ||
2035 | } else { | 2035 | } else { | ||
2036 | // restore | 2036 | // restore | ||
2037 | // TODO: add proper unreserve | 2037 | // TODO: add proper unreserve | ||
2038 | 2038 | | |||
2039 | //this will call showOnScreenEdge to reset the state | 2039 | //this will call showOnScreenEdge to reset the state | ||
2040 | disconnect(m_edgeGeometryTrackingConnection); | 2040 | disconnect(m_edgeGeometryTrackingConnection); | ||
2041 | ScreenEdges::self()->reserve(this, ElectricNone); | 2041 | ScreenEdges::self()->reserve(this, ElectricNone); | ||
2042 | } | 2042 | } | ||
2043 | } | 2043 | } | ||
2044 | 2044 | | |||
2045 | void Client::updateShowOnScreenEdge() | 2045 | void X11Client::updateShowOnScreenEdge() | ||
2046 | { | 2046 | { | ||
2047 | Xcb::Property property = fetchShowOnScreenEdge(); | 2047 | Xcb::Property property = fetchShowOnScreenEdge(); | ||
2048 | readShowOnScreenEdge(property); | 2048 | readShowOnScreenEdge(property); | ||
2049 | } | 2049 | } | ||
2050 | 2050 | | |||
2051 | void Client::showOnScreenEdge() | 2051 | void X11Client::showOnScreenEdge() | ||
2052 | { | 2052 | { | ||
2053 | disconnect(m_edgeRemoveConnection); | 2053 | disconnect(m_edgeRemoveConnection); | ||
2054 | 2054 | | |||
2055 | hideClient(false); | 2055 | hideClient(false); | ||
2056 | setKeepBelow(false); | 2056 | setKeepBelow(false); | ||
2057 | xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show); | 2057 | xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show); | ||
2058 | } | 2058 | } | ||
2059 | 2059 | | |||
2060 | void Client::addDamage(const QRegion &damage) | 2060 | void X11Client::addDamage(const QRegion &damage) | ||
2061 | { | 2061 | { | ||
2062 | if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead | 2062 | if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead | ||
2063 | if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now | 2063 | if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now | ||
2064 | setReadyForPainting(); | 2064 | setReadyForPainting(); | ||
2065 | setupWindowManagementInterface(); | 2065 | setupWindowManagementInterface(); | ||
2066 | } | 2066 | } | ||
2067 | } | 2067 | } | ||
2068 | repaints_region += damage; | 2068 | repaints_region += damage; | ||
2069 | Toplevel::addDamage(damage); | 2069 | Toplevel::addDamage(damage); | ||
2070 | } | 2070 | } | ||
2071 | 2071 | | |||
2072 | bool Client::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const | 2072 | bool X11Client::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const | ||
2073 | { | 2073 | { | ||
2074 | const Client *c2 = dynamic_cast<const Client*>(other); | 2074 | const X11Client *c2 = dynamic_cast<const X11Client *>(other); | ||
2075 | if (!c2) { | 2075 | if (!c2) { | ||
2076 | return false; | 2076 | return false; | ||
2077 | } | 2077 | } | ||
2078 | return Client::belongToSameApplication(this, c2, checks); | 2078 | return X11Client::belongToSameApplication(this, c2, checks); | ||
2079 | } | 2079 | } | ||
2080 | 2080 | | |||
2081 | QSize Client::resizeIncrements() const | 2081 | QSize X11Client::resizeIncrements() const | ||
2082 | { | 2082 | { | ||
2083 | return m_geometryHints.resizeIncrements(); | 2083 | return m_geometryHints.resizeIncrements(); | ||
2084 | } | 2084 | } | ||
2085 | 2085 | | |||
2086 | Xcb::StringProperty Client::fetchApplicationMenuServiceName() const | 2086 | Xcb::StringProperty X11Client::fetchApplicationMenuServiceName() const | ||
2087 | { | 2087 | { | ||
2088 | return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_service_name); | 2088 | return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_service_name); | ||
2089 | } | 2089 | } | ||
2090 | 2090 | | |||
2091 | void Client::readApplicationMenuServiceName(Xcb::StringProperty &property) | 2091 | void X11Client::readApplicationMenuServiceName(Xcb::StringProperty &property) | ||
2092 | { | 2092 | { | ||
2093 | updateApplicationMenuServiceName(QString::fromUtf8(property)); | 2093 | updateApplicationMenuServiceName(QString::fromUtf8(property)); | ||
2094 | } | 2094 | } | ||
2095 | 2095 | | |||
2096 | void Client::checkApplicationMenuServiceName() | 2096 | void X11Client::checkApplicationMenuServiceName() | ||
2097 | { | 2097 | { | ||
2098 | Xcb::StringProperty property = fetchApplicationMenuServiceName(); | 2098 | Xcb::StringProperty property = fetchApplicationMenuServiceName(); | ||
2099 | readApplicationMenuServiceName(property); | 2099 | readApplicationMenuServiceName(property); | ||
2100 | } | 2100 | } | ||
2101 | 2101 | | |||
2102 | Xcb::StringProperty Client::fetchApplicationMenuObjectPath() const | 2102 | Xcb::StringProperty X11Client::fetchApplicationMenuObjectPath() const | ||
2103 | { | 2103 | { | ||
2104 | return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_object_path); | 2104 | return Xcb::StringProperty(m_client, atoms->kde_net_wm_appmenu_object_path); | ||
2105 | } | 2105 | } | ||
2106 | 2106 | | |||
2107 | void Client::readApplicationMenuObjectPath(Xcb::StringProperty &property) | 2107 | void X11Client::readApplicationMenuObjectPath(Xcb::StringProperty &property) | ||
2108 | { | 2108 | { | ||
2109 | updateApplicationMenuObjectPath(QString::fromUtf8(property)); | 2109 | updateApplicationMenuObjectPath(QString::fromUtf8(property)); | ||
2110 | } | 2110 | } | ||
2111 | 2111 | | |||
2112 | void Client::checkApplicationMenuObjectPath() | 2112 | void X11Client::checkApplicationMenuObjectPath() | ||
2113 | { | 2113 | { | ||
2114 | Xcb::StringProperty property = fetchApplicationMenuObjectPath(); | 2114 | Xcb::StringProperty property = fetchApplicationMenuObjectPath(); | ||
2115 | readApplicationMenuObjectPath(property); | 2115 | readApplicationMenuObjectPath(property); | ||
2116 | } | 2116 | } | ||
2117 | 2117 | | |||
2118 | void Client::handleSync() | 2118 | void X11Client::handleSync() | ||
2119 | { | 2119 | { | ||
2120 | setReadyForPainting(); | 2120 | setReadyForPainting(); | ||
2121 | setupWindowManagementInterface(); | 2121 | setupWindowManagementInterface(); | ||
2122 | syncRequest.isPending = false; | 2122 | syncRequest.isPending = false; | ||
2123 | if (syncRequest.failsafeTimeout) | 2123 | if (syncRequest.failsafeTimeout) | ||
2124 | syncRequest.failsafeTimeout->stop(); | 2124 | syncRequest.failsafeTimeout->stop(); | ||
2125 | if (isResize()) { | 2125 | if (isResize()) { | ||
2126 | if (syncRequest.timeout) | 2126 | if (syncRequest.timeout) | ||
2127 | syncRequest.timeout->stop(); | 2127 | syncRequest.timeout->stop(); | ||
2128 | performMoveResize(); | 2128 | performMoveResize(); | ||
2129 | } else // setReadyForPainting does as well, but there's a small chance for resize syncs after the resize ended | 2129 | } else // setReadyForPainting does as well, but there's a small chance for resize syncs after the resize ended | ||
2130 | addRepaintFull(); | 2130 | addRepaintFull(); | ||
2131 | } | 2131 | } | ||
2132 | 2132 | | |||
2133 | } // namespace | 2133 | } // namespace | ||
2134 | 2134 | |