• 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 
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7 
8 You can Freely distribute this program under the GNU General Public
9 License. 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 
76 namespace KWinInternal
77 {
78 
79 //*******************************
80 // Workspace
81 //*******************************
82 
83 void 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 
97 void 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 
129 void 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
255 Client* 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 
284 Client* 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 
308 void 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 
326 void 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 
353 void 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 
381 void 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 
416 void 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 
445 void 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 
456 void 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 
468 void 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 
555 void 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 
573 ClientList 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 
682 void 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
696 ClientList 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
713 bool 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 
741 void 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 
761 void 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 
780 void 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 
799 Layer Client::layer() const
800  {
801  if( in_layer == UnknownLayer )
802  const_cast< Client* >( this )->in_layer = belongsToLayer();
803  return in_layer;
804  }
805 
806 Layer 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::Client
Client(Workspace *ws)
Definition: client.cpp:94
KWinInternal::Client::desktop
int desktop() const
Definition: client.h:753
KWinInternal::Client::keepAbove
bool keepAbove() const
Definition: client.cpp:663
KWinInternal
Definition: activation.cpp:34

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.8.13
This website is maintained by Timothy Pearson.