• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

  • twin
layers.cpp
1/*****************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7
8You can Freely distribute this program under the GNU General Public
9License. See the file "COPYING" for the exact licensing terms.
10******************************************************************/
11
12// SELI zmenit doc
13
14/*
15
16 This file contains things relevant to stacking order and layers.
17
18 Design:
19
20 Normal unconstrained stacking order, as requested by the user (by clicking
21 on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
22 That list shouldn't be used at all, except for building
23 Workspace::stacking_order. The building is done
24 in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
25 be used to get the stacking order, because it also checks the stacking order
26 is up to date.
27 All clients are also stored in Workspace::clients (except for isDesktop() clients,
28 as those are very special, and are stored in Workspace::desktops), in the order
29 the clients were created.
30
31 Every window has one layer assigned in which it is. There are 6 layers,
32 from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer
33 and ActiveLayer (see also NETWM sect.7.10.). The layer a window is in depends
34 on the window type, and on other things like whether the window is active.
35
36 NET::Splash clients belong to the Normal layer. NET::TopMenu clients
37 belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
38 are in the Normal layer in order to keep the 'allow window to cover
39 the panel' Kicker setting to work as intended (this may look like a slight
40 spec violation, but a) I have no better idea, b) the spec allows adjusting
41 the stacking order if the WM thinks it's a good idea . We put all
42 NET::KeepAbove above all Docks too, even though the spec suggests putting
43 them in the same layer.
44
45 Most transients are in the same layer as their mainwindow,
46 see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
47 they should never be below their mainwindow.
48
49 When some client attribute changes (above/below flag, transiency...),
50 Workspace::updateClientLayer() should be called in order to make
51 sure it's moved to the appropriate layer ClientList if needed.
52
53 Currently the things that affect client in which layer a client
54 belongs: KeepAbove/Keep Below flags, window type, fullscreen
55 state and whether the client is active, mainclient (transiency).
56
57 Make sure updateStackingOrder() is called in order to make
58 Workspace::stackingOrder() up to date and propagated to the world.
59 Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
60 helper class) it's possible to temporarily disable updates
61 and the stacking order will be updated once after it's allowed again.
62
63*/
64
65#include <assert.h>
66
67#include <kdebug.h>
68
69#include "utils.h"
70#include "client.h"
71#include "workspace.h"
72#include "tabbox.h"
73#include "group.h"
74#include "rules.h"
75
76namespace KWinInternal
77{
78
79//*******************************
80// Workspace
81//*******************************
82
83void Workspace::updateClientLayer( Client* c )
84 {
85 if( c == NULL )
86 return;
87 if( c->layer() == c->belongsToLayer())
88 return;
89 StackingUpdatesBlocker blocker( this );
90 c->invalidateLayer(); // invalidate, will be updated when doing restacking
91 for( ClientList::ConstIterator it = c->transients().begin();
92 it != c->transients().end();
93 ++it )
94 updateClientLayer( *it );
95 }
96
97void Workspace::updateStackingOrder( bool propagate_new_clients )
98 {
99 if( block_stacking_updates > 0 )
100 {
101 blocked_propagating_new_clients = blocked_propagating_new_clients || propagate_new_clients;
102 return;
103 }
104 ClientList new_stacking_order = constrainedStackingOrder();
105 bool changed = ( new_stacking_order != stacking_order );
106 stacking_order = new_stacking_order;
107#if 0
108 kdDebug() << "stacking:" << changed << endl;
109 if( changed || propagate_new_clients )
110 {
111 for( ClientList::ConstIterator it = stacking_order.begin();
112 it != stacking_order.end();
113 ++it )
114 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
115 }
116#endif
117 if( changed || propagate_new_clients )
118 {
119 propagateClients( propagate_new_clients );
120 if( active_client )
121 active_client->updateMouseGrab();
122 }
123 }
124
129void Workspace::propagateClients( bool propagate_new_clients )
130 {
131 Window *cl; // MW we should not assume WId and Window to be compatible
132 // when passing pointers around.
133
134 // restack the windows according to the stacking order
135 NET::WindowType t;
136 Window shadow;
137 Window *dock_shadow_stack, *window_stack;
138 int i, numDocks, pos, topmenu_space_pos;
139
140 // Dock Stack size magic number explanation:
141 // -> (count * 2) because we might need to also store the shadow window
142 // for each dock window (Chakra shadow patch, introduced in 9cc1e2c1aa)
143 dock_shadow_stack = new Window[ stacking_order.count() * 2 ];
144
145 // Window Stack size magic number explanation:
146 // -> (count * 2) because we might need to store shadow windows (see above)
147 // -> + 1 for supportWindow
148 // -> + 1 for topmenu_space
149 // -> + 8 for active borders
150 window_stack = new Window[ stacking_order.count() * 2 + 1 + 1 + 8 ];
151 i = 0;
152 pos = 0;
153 topmenu_space_pos = 1; // not 0, that's supportWindow !!!
154
155 // Stack active windows under the support window.
156 /* The support window is not used for anything (besides the NETWM property),
157 * and it's not shown, but it was lowered after TWin startup.
158 * Stacking all clients below it ensures that no client will be ever shown
159 * above override-redirect windows (e.g. popups).
160 */
161 for (int i = 0; i < ACTIVE_BORDER_COUNT; ++i)
162 {
163 if (active_windows[i] != None)
164 {
165 window_stack[pos++] = active_windows[i];
166 }
167 }
168
169 // Stack all windows under the support and active borders windows.
170 window_stack[pos++] = supportWindow->winId();
171 for( ClientList::ConstIterator it = stacking_order.fromLast();
172 it != stacking_order.end();
173 --it )
174 {
175
176 t = (*it)->windowType();
177 switch (t)
178 {
179 case NET::Dock:
180 window_stack[pos++] = (*it)->frameId();
181 if ((shadow = (*it)->shadowId()) != None)
182 dock_shadow_stack[i++] = shadow;
183 break;
184 case NET::Desktop:
185 numDocks = i;
186 for (i = 0; i < numDocks; i++)
187 // Shadows for dock windows go just above the desktop
188 window_stack[pos++] = dock_shadow_stack[i];
189 window_stack[pos++] = (*it)->frameId();
190 break;
191 case NET::TopMenu:
192 topmenu_space_pos = pos;
193 // fall through
194 default:
195 window_stack[pos++] = (*it)->frameId();
196 if ((shadow = (*it)->shadowId()) != None)
197 // If the current window also has a shadow, place it
198 // immediately under the current window
199 window_stack[pos++] = shadow;
200 }
201 }
202 if( topmenu_space != NULL )
203 { // make sure the topmenu space is below all topmenus, fullscreens, etc.
204 for( int i = pos;
205 i > topmenu_space_pos;
206 --i )
207#if 0
208 new_stack[ i ] = new_stack[ i - 1 ];
209 new_stack[ topmenu_space_pos ] = topmenu_space->winId();
210#endif
211 window_stack[ i ] = window_stack[ i - 1 ];
212 window_stack[ topmenu_space_pos ] = topmenu_space->winId();
213 ++pos;
214 }
215#if 0
216 // TODO isn't it too inefficient to restart always all clients?
217 // TODO don't restack not visible windows?
218 assert( new_stack[ 0 ] = supportWindow->winId());
219
220 XRestackWindows(tqt_xdisplay(), new_stack, pos);
221 delete [] new_stack;
222#endif
223 XRestackWindows(tqt_xdisplay(), window_stack, pos);
224 delete [] dock_shadow_stack;
225 delete [] window_stack;
226
227 if ( propagate_new_clients )
228 {
229 cl = new Window[ desktops.count() + clients.count()];
230 pos = 0;
231 // TODO this is still not completely in the map order
232 for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
233 cl[pos++] = (*it)->window();
234 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
235 cl[pos++] = (*it)->window();
236 rootInfo->setClientList( cl, pos );
237 delete [] cl;
238 }
239
240 cl = new Window[ stacking_order.count()];
241 pos = 0;
242 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
243 cl[pos++] = (*it)->window();
244 rootInfo->setClientListStacking( cl, pos );
245 delete [] cl;
246 }
247
248
254// TODO misleading name for this method
255Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained, bool only_normal ) const
256 {
257// TODO Q_ASSERT( block_stacking_updates == 0 );
258 ClientList::ConstIterator begin, end;
259 if( !unconstrained )
260 {
261 begin = stacking_order.fromLast();
262 end = stacking_order.end();
263 }
264 else
265 {
266 begin = unconstrained_stacking_order.fromLast();
267 end = unconstrained_stacking_order.end();
268 }
269 for( ClientList::ConstIterator it = begin;
270 it != end;
271 --it )
272 {
273 if( (*it)->isOnDesktop( desktop ) && (*it)->isShown( false ))
274 {
275 if( !only_normal )
276 return *it;
277 if( (*it)->wantsTabFocus() && !(*it)->isSpecialWindow())
278 return *it;
279 }
280 }
281 return 0;
282 }
283
284Client* Workspace::findDesktop( bool topmost, int desktop ) const
285 {
286// TODO Q_ASSERT( block_stacking_updates == 0 );
287 if( topmost )
288 {
289 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
290 {
291 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
292 && (*it)->isShown( true ))
293 return *it;
294 }
295 }
296 else // bottom-most
297 {
298 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
299 {
300 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
301 && (*it)->isShown( true ))
302 return *it;
303 }
304 }
305 return NULL;
306 }
307
308void Workspace::raiseOrLowerClient( Client *c)
309 {
310 if (!c) return;
311 Client* topmost = NULL;
312// TODO Q_ASSERT( block_stacking_updates == 0 );
313 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
314 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
315 topmost = most_recently_raised;
316 else
317 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
318
319 if( c == topmost)
320 lowerClient(c);
321 else
322 raiseClient(c);
323 }
324
325
326void Workspace::lowerClient( Client* c )
327 {
328 if ( !c )
329 return;
330 if( c->isTopMenu())
331 return;
332
333 c->cancelAutoRaise();
334
335 StackingUpdatesBlocker blocker( this );
336
337 unconstrained_stacking_order.remove( c );
338 unconstrained_stacking_order.prepend( c );
339 if( c->isTransient())
340 {
341 // lower also mainclients, in their reversed stacking order
342 ClientList mainclients = ensureStackingOrder( c->mainClients());
343 for( ClientList::ConstIterator it = mainclients.fromLast();
344 it != mainclients.end();
345 ++it )
346 lowerClient( *it );
347 }
348
349 if ( c == most_recently_raised )
350 most_recently_raised = 0;
351 }
352
353void Workspace::lowerClientWithinApplication( Client* c )
354 {
355 if ( !c )
356 return;
357 if( c->isTopMenu())
358 return;
359
360 c->cancelAutoRaise();
361
362 StackingUpdatesBlocker blocker( this );
363
364 unconstrained_stacking_order.remove( c );
365 bool lowered = false;
366 // first try to put it below the bottom-most window of the application
367 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
368 it != unconstrained_stacking_order.end();
369 ++it )
370 if( Client::belongToSameApplication( *it, c ))
371 {
372 unconstrained_stacking_order.insert( it, c );
373 lowered = true;
374 break;
375 }
376 if( !lowered )
377 unconstrained_stacking_order.prepend( c );
378 // ignore mainwindows
379 }
380
381void Workspace::raiseClient( Client* c )
382 {
383 if ( !c )
384 return;
385 if( c->isTopMenu())
386 return;
387
388 c->cancelAutoRaise();
389
390 StackingUpdatesBlocker blocker( this );
391
392 if( c->isTransient())
393 {
394 ClientList mainclients = ensureStackingOrder( c->mainClients());
395 for( ClientList::ConstIterator it = mainclients.begin();
396 it != mainclients.end();
397 ++it )
398 raiseClient( *it );
399 }
400
401 unconstrained_stacking_order.remove( c );
402 unconstrained_stacking_order.append( c );
403 if (options->shadowEnabled(c->isActive()))
404 {
405 c->removeShadow();
406 c->drawDelayedShadow();
407 }
408
409 if( !c->isSpecialWindow())
410 {
411 most_recently_raised = c;
412 pending_take_activity = NULL;
413 }
414 }
415
416void Workspace::raiseClientWithinApplication( Client* c )
417 {
418 if ( !c )
419 return;
420 if( c->isTopMenu())
421 return;
422
423 c->cancelAutoRaise();
424
425 StackingUpdatesBlocker blocker( this );
426 // ignore mainwindows
427
428 // first try to put it above the top-most window of the application
429 for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
430 it != unconstrained_stacking_order.end();
431 --it )
432 {
433 if( *it == c ) // don't lower it just because it asked to be raised
434 return;
435 if( Client::belongToSameApplication( *it, c ))
436 {
437 unconstrained_stacking_order.remove( c );
438 ++it; // insert after the found one
439 unconstrained_stacking_order.insert( it, c );
440 return;
441 }
442 }
443 }
444
445void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
446 {
447 if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
448 raiseClient( c );
449 else
450 {
451 raiseClientWithinApplication( c );
452 c->demandAttention();
453 }
454 }
455
456void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
457 {
458 // If the client has support for all this focus stealing prevention stuff,
459 // do only lowering within the application, as that's the more logical
460 // variant of lowering when application requests it.
461 // No demanding of attention here of course.
462 if( src == NET::FromTool || !c->hasUserTimeSupport())
463 lowerClient( c );
464 else
465 lowerClientWithinApplication( c );
466 }
467
468void Workspace::restackClientUnderActive( Client* c )
469 {
470 if( c->isTopMenu())
471 return;
472 if( !active_client || active_client == c )
473 {
474 raiseClient( c );
475 return;
476 }
477
478 assert( unconstrained_stacking_order.contains( active_client ));
479 if( Client::belongToSameApplication( active_client, c ))
480 { // put it below the active window if it's the same app
481 unconstrained_stacking_order.remove( c );
482 unconstrained_stacking_order.insert( unconstrained_stacking_order.find( active_client ), c );
483 }
484 else
485 { // put in the stacking order below _all_ windows belonging to the active application
486 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
487 it != unconstrained_stacking_order.end();
488 ++it )
489 { // TODO ignore topmenus?
490 if( Client::belongToSameApplication( active_client, *it ))
491 {
492 if( *it != c )
493 {
494 unconstrained_stacking_order.remove( c );
495 unconstrained_stacking_order.insert( it, c );
496 }
497 break;
498 }
499 }
500 }
501 assert( unconstrained_stacking_order.contains( c ));
502 for( int desktop = 1;
503 desktop <= numberOfDesktops();
504 ++desktop )
505 { // do for every virtual desktop to handle the case of onalldesktop windows
506 if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
507 {
508 if( Client::belongToSameApplication( active_client, c ))
509 { // put it after the active window if it's the same app
510 focus_chain[ desktop ].remove( c );
511 focus_chain[ desktop ].insert( focus_chain[ desktop ].find( active_client ), c );
512 }
513 else
514 { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
515 focus_chain[ desktop ].remove( c );
516 for( ClientList::Iterator it = focus_chain[ desktop ].fromLast();
517 it != focus_chain[ desktop ].end();
518 --it )
519 {
520 if( Client::belongToSameApplication( active_client, *it ))
521 {
522 focus_chain[ desktop ].insert( it, c );
523 break;
524 }
525 }
526 }
527 }
528 }
529 // the same for global_focus_chain
530 if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
531 {
532 if( Client::belongToSameApplication( active_client, c ))
533 {
534 global_focus_chain.remove( c );
535 global_focus_chain.insert( global_focus_chain.find( active_client ), c );
536 }
537 else
538 {
539 global_focus_chain.remove( c );
540 for( ClientList::Iterator it = global_focus_chain.fromLast();
541 it != global_focus_chain.end();
542 --it )
543 {
544 if( Client::belongToSameApplication( active_client, *it ))
545 {
546 global_focus_chain.insert( it, c );
547 break;
548 }
549 }
550 }
551 }
552 updateStackingOrder();
553 }
554
555void Workspace::circulateDesktopApplications()
556 {
557 if ( desktops.count() > 1 )
558 {
559 bool change_active = activeClient()->isDesktop();
560 raiseClient( findDesktop( false, currentDesktop()));
561 if( change_active ) // if the previously topmost Desktop was active, activate this new one
562 activateClient( findDesktop( true, currentDesktop()));
563 }
564 // if there's no active client, make desktop the active one
565 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
566 activateClient( findDesktop( true, currentDesktop()));
567 }
568
569
573ClientList Workspace::constrainedStackingOrder()
574 {
575 ClientList layer[ NumLayers ];
576
577#if 0
578 kdDebug() << "stacking1:" << endl;
579#endif
580 // build the order from layers
581 TQMap< Group*, Layer > minimum_layer;
582 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
583 it != unconstrained_stacking_order.end();
584 ++it )
585 {
586 Layer l = (*it)->layer();
587 // If a window is raised above some other window in the same window group
588 // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
589 // above that window (see #95731).
590 if( minimum_layer.contains( (*it)->group())
591 && minimum_layer[ (*it)->group() ] == ActiveLayer
592 && ( l == NormalLayer || l == AboveLayer ))
593 {
594 l = minimum_layer[ (*it)->group() ];
595 }
596 minimum_layer[ (*it)->group() ] = l;
597 layer[ l ].append( *it );
598 }
599 ClientList stacking;
600 for( Layer lay = FirstLayer;
601 lay < NumLayers;
602 ++lay )
603 stacking += layer[ lay ];
604#if 0
605 kdDebug() << "stacking2:" << endl;
606 for( ClientList::ConstIterator it = stacking.begin();
607 it != stacking.end();
608 ++it )
609 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
610#endif
611 // now keep transients above their mainwindows
612 // TODO this could(?) use some optimization
613 for( ClientList::Iterator it = stacking.fromLast();
614 it != stacking.end();
615 )
616 {
617 if( !(*it)->isTransient())
618 {
619 --it;
620 continue;
621 }
622 ClientList::Iterator it2 = stacking.end();
623 if( (*it)->groupTransient())
624 {
625 if( (*it)->group()->members().count() > 0 )
626 { // find topmost client this one is transient for
627 for( it2 = stacking.fromLast();
628 it2 != stacking.end();
629 --it2 )
630 {
631 if( *it2 == *it )
632 {
633 it2 = stacking.end(); // don't reorder
634 break;
635 }
636 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
637 break;
638 }
639 } // else it2 remains pointing at stacking.end()
640 }
641 else
642 {
643 for( it2 = stacking.fromLast();
644 it2 != stacking.end();
645 --it2 )
646 {
647 if( *it2 == *it )
648 {
649 it2 = stacking.end(); // don't reorder
650 break;
651 }
652 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
653 break;
654 }
655 }
656// kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl;
657 if( it2 == stacking.end())
658 {
659 --it;
660 continue;
661 }
662 Client* current = *it;
663 ClientList::Iterator remove_it = it;
664 --it;
665 stacking.remove( remove_it );
666 if( !current->transients().isEmpty()) // this one now can be possibly above its transients,
667 it = it2; // so go again higher in the stack order and possibly move those transients again
668 ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end()
669 stacking.insert( it2, current );
670 }
671#if 0
672 kdDebug() << "stacking3:" << endl;
673 for( ClientList::ConstIterator it = stacking.begin();
674 it != stacking.end();
675 ++it )
676 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
677 kdDebug() << "\n\n" << endl;
678#endif
679 return stacking;
680 }
681
682void Workspace::blockStackingUpdates( bool block )
683 {
684 if( block )
685 {
686 if( block_stacking_updates == 0 )
687 blocked_propagating_new_clients = false;
688 ++block_stacking_updates;
689 }
690 else // !block
691 if( --block_stacking_updates == 0 )
692 updateStackingOrder( blocked_propagating_new_clients );
693 }
694
695// Ensure list is in stacking order
696ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
697 {
698// TODO Q_ASSERT( block_stacking_updates == 0 );
699 if( list.count() < 2 )
700 return list;
701 // TODO is this worth optimizing?
702 ClientList result = list;
703 for( ClientList::ConstIterator it = stacking_order.begin();
704 it != stacking_order.end();
705 ++it )
706 if( result.remove( *it ) != 0 )
707 result.append( *it );
708 return result;
709 }
710
711// check whether a transient should be actually kept above its mainwindow
712// there may be some special cases where this rule shouldn't be enfored
713bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
714 {
715 // When topmenu's mainwindow becomes active, topmenu is raised and shown.
716 // They also belong to the Dock layer. This makes them to be very high.
717 // Therefore don't keep group transients above them, otherwise this would move
718 // group transients way too high.
719 if( mainwindow->isTopMenu() && transient->groupTransient())
720 return false;
721 // #93832 - don't keep splashscreens above dialogs
722 if( transient->isSplash() && mainwindow->isDialog())
723 return false;
724 // This is rather a hack for #76026. Don't keep non-modal dialogs above
725 // the mainwindow, but only if they're group transient (since only such dialogs
726 // have taskbar entry in Kicker). A proper way of doing this (both twin and kicker)
727 // needs to be found.
728 if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
729 return false;
730 // #63223 - don't keep transients above docks, because the dock is kept high,
731 // and e.g. dialogs for them would be too high too
732 if( mainwindow->isDock())
733 return false;
734 return true;
735 }
736
737//*******************************
738// Client
739//*******************************
740
741void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
742 {
743 switch ( detail )
744 {
745 case Above:
746 case TopIf:
747 workspace()->raiseClientRequest( this, src, timestamp );
748 break;
749 case Below:
750 case BottomIf:
751 workspace()->lowerClientRequest( this, src, timestamp );
752 break;
753 case Opposite:
754 default:
755 break;
756 }
757 if( send_event )
758 sendSyntheticConfigureNotify();
759 }
760
761void Client::setKeepAbove( bool b )
762 {
763 b = rules()->checkKeepAbove( b );
764 if( b && !rules()->checkKeepBelow( false ))
765 setKeepBelow( false );
766 if ( b == keepAbove())
767 { // force hint change if different
768 if( bool( info->state() & NET::KeepAbove ) != keepAbove())
769 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
770 return;
771 }
772 keep_above = b;
773 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
774 if( decoration != NULL )
775 decoration->emitKeepAboveChanged( keepAbove());
776 workspace()->updateClientLayer( this );
777 updateWindowRules();
778 }
779
780void Client::setKeepBelow( bool b )
781 {
782 b = rules()->checkKeepBelow( b );
783 if( b && !rules()->checkKeepAbove( false ))
784 setKeepAbove( false );
785 if ( b == keepBelow())
786 { // force hint change if different
787 if( bool( info->state() & NET::KeepBelow ) != keepBelow())
788 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
789 return;
790 }
791 keep_below = b;
792 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
793 if( decoration != NULL )
794 decoration->emitKeepBelowChanged( keepBelow());
795 workspace()->updateClientLayer( this );
796 updateWindowRules();
797 }
798
799Layer Client::layer() const
800 {
801 if( in_layer == UnknownLayer )
802 const_cast< Client* >( this )->in_layer = belongsToLayer();
803 return in_layer;
804 }
805
806Layer Client::belongsToLayer() const
807 {
808 if( isDesktop())
809 return DesktopLayer;
810 if( isSplash()) // no damn annoying splashscreens
811 return NormalLayer; // getting in the way of everything else
812 if( isDock() && keepBelow())
813 // slight hack for the 'allow window to cover panel' Kicker setting
814 // don't move keepbelow docks below normal window, but only to the same
815 // layer, so that both may be raised to cover the other
816 return NormalLayer;
817 if( keepBelow())
818 return BelowLayer;
819 if( isDock() && !keepBelow())
820 return DockLayer;
821 if( isTopMenu())
822 return DockLayer;
823 // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
824 // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
825 const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
826 const Client* top = workspace()->topClientOnDesktop( desktop(), true, false );
827 if( isFullScreen() && ac != NULL && top != NULL
828 && ( ac == this || this->group() == ac->group())
829 && ( top == this || this->group() == top->group()))
830 return ActiveLayer;
831 if( keepAbove())
832 return AboveLayer;
833 return NormalLayer;
834 }
835
836} // namespace
KWinInternal::Client::desktop
int desktop() const
Definition: client.h:751
KWinInternal::Client::keepAbove
bool keepAbove() const
Definition: client.cpp:663
KWinInternal::Client::Client
Client(Workspace *ws)
Definition: client.cpp:94

twin

Skip menu "twin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.9.4
This website is maintained by Timothy Pearson.