• 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 passig pointers around.
133 
134  // restack the windows according to the stacking order
135 #if 0
136  Window* new_stack = new Window[ stacking_order.count() + 2 ];
137  int pos = 0;
138 #endif
139  NET::WindowType t;
140  Window shadow;
141  Window *dock_shadow_stack, *window_stack;
142  int i, numDocks, pos, topmenu_space_pos;
143 
144  dock_shadow_stack = new Window[ stacking_order.count() * 2 ];
145  window_stack = new Window[ stacking_order.count() * 2 + 2 ];
146  i = 0;
147  pos = 0;
148  topmenu_space_pos = 1; // not 0, that's supportWindow !!!
149 
150  // Stack all windows under the support window. The support window is
151  // not used for anything (besides the NETWM property), and it's not shown,
152  // but it was lowered after twin startup. Stacking all clients below
153  // it ensures that no client will be ever shown above override-redirect
154  // windows (e.g. popups).
155 #if 0
156  new_stack[ pos++ ] = supportWindow->winId();
157  int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
158 #endif
159  window_stack[pos++] = supportWindow->winId();
160  for( ClientList::ConstIterator it = stacking_order.fromLast();
161  it != stacking_order.end();
162  --it )
163  {
164 #if 0
165  new_stack[ pos++ ] = (*it)->frameId();
166  if( (*it)->belongsToLayer() >= DockLayer )
167  topmenu_space_pos = pos;
168 #endif
169  t = (*it)->windowType();
170  switch (t)
171  {
172  case NET::Dock:
173  window_stack[pos++] = (*it)->frameId();
174  if ((shadow = (*it)->shadowId()) != None)
175  dock_shadow_stack[i++] = shadow;
176  break;
177  case NET::Desktop:
178  numDocks = i;
179  for (i = 0; i < numDocks; i++)
180  // Shadows for dock windows go just above the desktop
181  window_stack[pos++] = dock_shadow_stack[i];
182  window_stack[pos++] = (*it)->frameId();
183  break;
184  case NET::TopMenu:
185  topmenu_space_pos = pos;
186  // fall through
187  default:
188  window_stack[pos++] = (*it)->frameId();
189  if ((shadow = (*it)->shadowId()) != None)
190  // If the current window also has a shadow, place it
191  // immediately under the current window
192  window_stack[pos++] = shadow;
193  }
194  }
195  if( topmenu_space != NULL )
196  { // make sure the topmenu space is below all topmenus, fullscreens, etc.
197  for( int i = pos;
198  i > topmenu_space_pos;
199  --i )
200 #if 0
201  new_stack[ i ] = new_stack[ i - 1 ];
202  new_stack[ topmenu_space_pos ] = topmenu_space->winId();
203 #endif
204  window_stack[ i ] = window_stack[ i - 1 ];
205  window_stack[ topmenu_space_pos ] = topmenu_space->winId();
206  ++pos;
207  }
208 #if 0
209  // TODO isn't it too inefficient to restart always all clients?
210  // TODO don't restack not visible windows?
211  assert( new_stack[ 0 ] = supportWindow->winId());
212 #endif
213 #if 0
214  XRestackWindows(tqt_xdisplay(), new_stack, pos);
215  delete [] new_stack;
216 #endif
217  XRestackWindows(tqt_xdisplay(), window_stack, pos);
218  delete [] dock_shadow_stack;
219  delete [] window_stack;
220 
221  if ( propagate_new_clients )
222  {
223  cl = new Window[ desktops.count() + clients.count()];
224  pos = 0;
225  // TODO this is still not completely in the map order
226  for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
227  cl[pos++] = (*it)->window();
228  for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
229  cl[pos++] = (*it)->window();
230  rootInfo->setClientList( cl, pos );
231  delete [] cl;
232  }
233 
234  cl = new Window[ stacking_order.count()];
235  pos = 0;
236  for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
237  cl[pos++] = (*it)->window();
238  rootInfo->setClientListStacking( cl, pos );
239  delete [] cl;
240  }
241 
242 
248 // TODO misleading name for this method
249 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained, bool only_normal ) const
250  {
251 // TODO Q_ASSERT( block_stacking_updates == 0 );
252  ClientList::ConstIterator begin, end;
253  if( !unconstrained )
254  {
255  begin = stacking_order.fromLast();
256  end = stacking_order.end();
257  }
258  else
259  {
260  begin = unconstrained_stacking_order.fromLast();
261  end = unconstrained_stacking_order.end();
262  }
263  for( ClientList::ConstIterator it = begin;
264  it != end;
265  --it )
266  {
267  if( (*it)->isOnDesktop( desktop ) && (*it)->isShown( false ))
268  {
269  if( !only_normal )
270  return *it;
271  if( (*it)->wantsTabFocus() && !(*it)->isSpecialWindow())
272  return *it;
273  }
274  }
275  return 0;
276  }
277 
278 Client* Workspace::findDesktop( bool topmost, int desktop ) const
279  {
280 // TODO Q_ASSERT( block_stacking_updates == 0 );
281  if( topmost )
282  {
283  for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
284  {
285  if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
286  && (*it)->isShown( true ))
287  return *it;
288  }
289  }
290  else // bottom-most
291  {
292  for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
293  {
294  if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
295  && (*it)->isShown( true ))
296  return *it;
297  }
298  }
299  return NULL;
300  }
301 
302 void Workspace::raiseOrLowerClient( Client *c)
303  {
304  if (!c) return;
305  Client* topmost = NULL;
306 // TODO Q_ASSERT( block_stacking_updates == 0 );
307  if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
308  most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
309  topmost = most_recently_raised;
310  else
311  topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
312 
313  if( c == topmost)
314  lowerClient(c);
315  else
316  raiseClient(c);
317  }
318 
319 
320 void Workspace::lowerClient( Client* c )
321  {
322  if ( !c )
323  return;
324  if( c->isTopMenu())
325  return;
326 
327  c->cancelAutoRaise();
328 
329  StackingUpdatesBlocker blocker( this );
330 
331  unconstrained_stacking_order.remove( c );
332  unconstrained_stacking_order.prepend( c );
333  if( c->isTransient())
334  {
335  // lower also mainclients, in their reversed stacking order
336  ClientList mainclients = ensureStackingOrder( c->mainClients());
337  for( ClientList::ConstIterator it = mainclients.fromLast();
338  it != mainclients.end();
339  ++it )
340  lowerClient( *it );
341  }
342 
343  if ( c == most_recently_raised )
344  most_recently_raised = 0;
345  }
346 
347 void Workspace::lowerClientWithinApplication( Client* c )
348  {
349  if ( !c )
350  return;
351  if( c->isTopMenu())
352  return;
353 
354  c->cancelAutoRaise();
355 
356  StackingUpdatesBlocker blocker( this );
357 
358  unconstrained_stacking_order.remove( c );
359  bool lowered = false;
360  // first try to put it below the bottom-most window of the application
361  for( ClientList::Iterator it = unconstrained_stacking_order.begin();
362  it != unconstrained_stacking_order.end();
363  ++it )
364  if( Client::belongToSameApplication( *it, c ))
365  {
366  unconstrained_stacking_order.insert( it, c );
367  lowered = true;
368  break;
369  }
370  if( !lowered )
371  unconstrained_stacking_order.prepend( c );
372  // ignore mainwindows
373  }
374 
375 void Workspace::raiseClient( Client* c )
376  {
377  if ( !c )
378  return;
379  if( c->isTopMenu())
380  return;
381 
382  c->cancelAutoRaise();
383 
384  StackingUpdatesBlocker blocker( this );
385 
386  if( c->isTransient())
387  {
388  ClientList mainclients = ensureStackingOrder( c->mainClients());
389  for( ClientList::ConstIterator it = mainclients.begin();
390  it != mainclients.end();
391  ++it )
392  raiseClient( *it );
393  }
394 
395  unconstrained_stacking_order.remove( c );
396  unconstrained_stacking_order.append( c );
397  if (options->shadowEnabled(c->isActive()))
398  {
399  c->removeShadow();
400  c->drawDelayedShadow();
401  }
402 
403  if( !c->isSpecialWindow())
404  {
405  most_recently_raised = c;
406  pending_take_activity = NULL;
407  }
408  }
409 
410 void Workspace::raiseClientWithinApplication( Client* c )
411  {
412  if ( !c )
413  return;
414  if( c->isTopMenu())
415  return;
416 
417  c->cancelAutoRaise();
418 
419  StackingUpdatesBlocker blocker( this );
420  // ignore mainwindows
421 
422  // first try to put it above the top-most window of the application
423  for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
424  it != unconstrained_stacking_order.end();
425  --it )
426  {
427  if( *it == c ) // don't lower it just because it asked to be raised
428  return;
429  if( Client::belongToSameApplication( *it, c ))
430  {
431  unconstrained_stacking_order.remove( c );
432  ++it; // insert after the found one
433  unconstrained_stacking_order.insert( it, c );
434  return;
435  }
436  }
437  }
438 
439 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
440  {
441  if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
442  raiseClient( c );
443  else
444  {
445  raiseClientWithinApplication( c );
446  c->demandAttention();
447  }
448  }
449 
450 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
451  {
452  // If the client has support for all this focus stealing prevention stuff,
453  // do only lowering within the application, as that's the more logical
454  // variant of lowering when application requests it.
455  // No demanding of attention here of course.
456  if( src == NET::FromTool || !c->hasUserTimeSupport())
457  lowerClient( c );
458  else
459  lowerClientWithinApplication( c );
460  }
461 
462 void Workspace::restackClientUnderActive( Client* c )
463  {
464  if( c->isTopMenu())
465  return;
466  if( !active_client || active_client == c )
467  {
468  raiseClient( c );
469  return;
470  }
471 
472  assert( unconstrained_stacking_order.contains( active_client ));
473  if( Client::belongToSameApplication( active_client, c ))
474  { // put it below the active window if it's the same app
475  unconstrained_stacking_order.remove( c );
476  unconstrained_stacking_order.insert( unconstrained_stacking_order.find( active_client ), c );
477  }
478  else
479  { // put in the stacking order below _all_ windows belonging to the active application
480  for( ClientList::Iterator it = unconstrained_stacking_order.begin();
481  it != unconstrained_stacking_order.end();
482  ++it )
483  { // TODO ignore topmenus?
484  if( Client::belongToSameApplication( active_client, *it ))
485  {
486  if( *it != c )
487  {
488  unconstrained_stacking_order.remove( c );
489  unconstrained_stacking_order.insert( it, c );
490  }
491  break;
492  }
493  }
494  }
495  assert( unconstrained_stacking_order.contains( c ));
496  for( int desktop = 1;
497  desktop <= numberOfDesktops();
498  ++desktop )
499  { // do for every virtual desktop to handle the case of onalldesktop windows
500  if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
501  {
502  if( Client::belongToSameApplication( active_client, c ))
503  { // put it after the active window if it's the same app
504  focus_chain[ desktop ].remove( c );
505  focus_chain[ desktop ].insert( focus_chain[ desktop ].find( active_client ), c );
506  }
507  else
508  { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
509  focus_chain[ desktop ].remove( c );
510  for( ClientList::Iterator it = focus_chain[ desktop ].fromLast();
511  it != focus_chain[ desktop ].end();
512  --it )
513  {
514  if( Client::belongToSameApplication( active_client, *it ))
515  {
516  focus_chain[ desktop ].insert( it, c );
517  break;
518  }
519  }
520  }
521  }
522  }
523  // the same for global_focus_chain
524  if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
525  {
526  if( Client::belongToSameApplication( active_client, c ))
527  {
528  global_focus_chain.remove( c );
529  global_focus_chain.insert( global_focus_chain.find( active_client ), c );
530  }
531  else
532  {
533  global_focus_chain.remove( c );
534  for( ClientList::Iterator it = global_focus_chain.fromLast();
535  it != global_focus_chain.end();
536  --it )
537  {
538  if( Client::belongToSameApplication( active_client, *it ))
539  {
540  global_focus_chain.insert( it, c );
541  break;
542  }
543  }
544  }
545  }
546  updateStackingOrder();
547  }
548 
549 void Workspace::circulateDesktopApplications()
550  {
551  if ( desktops.count() > 1 )
552  {
553  bool change_active = activeClient()->isDesktop();
554  raiseClient( findDesktop( false, currentDesktop()));
555  if( change_active ) // if the previously topmost Desktop was active, activate this new one
556  activateClient( findDesktop( true, currentDesktop()));
557  }
558  // if there's no active client, make desktop the active one
559  if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
560  activateClient( findDesktop( true, currentDesktop()));
561  }
562 
563 
567 ClientList Workspace::constrainedStackingOrder()
568  {
569  ClientList layer[ NumLayers ];
570 
571 #if 0
572  kdDebug() << "stacking1:" << endl;
573 #endif
574  // build the order from layers
575  TQMap< Group*, Layer > minimum_layer;
576  for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
577  it != unconstrained_stacking_order.end();
578  ++it )
579  {
580  Layer l = (*it)->layer();
581  // If a window is raised above some other window in the same window group
582  // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
583  // above that window (see #95731).
584  if( minimum_layer.contains( (*it)->group())
585  && minimum_layer[ (*it)->group() ] == ActiveLayer
586  && ( l == NormalLayer || l == AboveLayer ))
587  {
588  l = minimum_layer[ (*it)->group() ];
589  }
590  minimum_layer[ (*it)->group() ] = l;
591  layer[ l ].append( *it );
592  }
593  ClientList stacking;
594  for( Layer lay = FirstLayer;
595  lay < NumLayers;
596  ++lay )
597  stacking += layer[ lay ];
598 #if 0
599  kdDebug() << "stacking2:" << endl;
600  for( ClientList::ConstIterator it = stacking.begin();
601  it != stacking.end();
602  ++it )
603  kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
604 #endif
605  // now keep transients above their mainwindows
606  // TODO this could(?) use some optimization
607  for( ClientList::Iterator it = stacking.fromLast();
608  it != stacking.end();
609  )
610  {
611  if( !(*it)->isTransient())
612  {
613  --it;
614  continue;
615  }
616  ClientList::Iterator it2 = stacking.end();
617  if( (*it)->groupTransient())
618  {
619  if( (*it)->group()->members().count() > 0 )
620  { // find topmost client this one is transient for
621  for( it2 = stacking.fromLast();
622  it2 != stacking.end();
623  --it2 )
624  {
625  if( *it2 == *it )
626  {
627  it2 = stacking.end(); // don't reorder
628  break;
629  }
630  if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
631  break;
632  }
633  } // else it2 remains pointing at stacking.end()
634  }
635  else
636  {
637  for( it2 = stacking.fromLast();
638  it2 != stacking.end();
639  --it2 )
640  {
641  if( *it2 == *it )
642  {
643  it2 = stacking.end(); // don't reorder
644  break;
645  }
646  if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
647  break;
648  }
649  }
650 // kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl;
651  if( it2 == stacking.end())
652  {
653  --it;
654  continue;
655  }
656  Client* current = *it;
657  ClientList::Iterator remove_it = it;
658  --it;
659  stacking.remove( remove_it );
660  if( !current->transients().isEmpty()) // this one now can be possibly above its transients,
661  it = it2; // so go again higher in the stack order and possibly move those transients again
662  ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end()
663  stacking.insert( it2, current );
664  }
665 #if 0
666  kdDebug() << "stacking3:" << endl;
667  for( ClientList::ConstIterator it = stacking.begin();
668  it != stacking.end();
669  ++it )
670  kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
671  kdDebug() << "\n\n" << endl;
672 #endif
673  return stacking;
674  }
675 
676 void Workspace::blockStackingUpdates( bool block )
677  {
678  if( block )
679  {
680  if( block_stacking_updates == 0 )
681  blocked_propagating_new_clients = false;
682  ++block_stacking_updates;
683  }
684  else // !block
685  if( --block_stacking_updates == 0 )
686  updateStackingOrder( blocked_propagating_new_clients );
687  }
688 
689 // Ensure list is in stacking order
690 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
691  {
692 // TODO Q_ASSERT( block_stacking_updates == 0 );
693  if( list.count() < 2 )
694  return list;
695  // TODO is this worth optimizing?
696  ClientList result = list;
697  for( ClientList::ConstIterator it = stacking_order.begin();
698  it != stacking_order.end();
699  ++it )
700  if( result.remove( *it ) != 0 )
701  result.append( *it );
702  return result;
703  }
704 
705 // check whether a transient should be actually kept above its mainwindow
706 // there may be some special cases where this rule shouldn't be enfored
707 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
708  {
709  // When topmenu's mainwindow becomes active, topmenu is raised and shown.
710  // They also belong to the Dock layer. This makes them to be very high.
711  // Therefore don't keep group transients above them, otherwise this would move
712  // group transients way too high.
713  if( mainwindow->isTopMenu() && transient->groupTransient())
714  return false;
715  // #93832 - don't keep splashscreens above dialogs
716  if( transient->isSplash() && mainwindow->isDialog())
717  return false;
718  // This is rather a hack for #76026. Don't keep non-modal dialogs above
719  // the mainwindow, but only if they're group transient (since only such dialogs
720  // have taskbar entry in Kicker). A proper way of doing this (both twin and kicker)
721  // needs to be found.
722  if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
723  return false;
724  // #63223 - don't keep transients above docks, because the dock is kept high,
725  // and e.g. dialogs for them would be too high too
726  if( mainwindow->isDock())
727  return false;
728  return true;
729  }
730 
731 //*******************************
732 // Client
733 //*******************************
734 
735 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
736  {
737  switch ( detail )
738  {
739  case Above:
740  case TopIf:
741  workspace()->raiseClientRequest( this, src, timestamp );
742  break;
743  case Below:
744  case BottomIf:
745  workspace()->lowerClientRequest( this, src, timestamp );
746  break;
747  case Opposite:
748  default:
749  break;
750  }
751  if( send_event )
752  sendSyntheticConfigureNotify();
753  }
754 
755 void Client::setKeepAbove( bool b )
756  {
757  b = rules()->checkKeepAbove( b );
758  if( b && !rules()->checkKeepBelow( false ))
759  setKeepBelow( false );
760  if ( b == keepAbove())
761  { // force hint change if different
762  if( bool( info->state() & NET::KeepAbove ) != keepAbove())
763  info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
764  return;
765  }
766  keep_above = b;
767  info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
768  if( decoration != NULL )
769  decoration->emitKeepAboveChanged( keepAbove());
770  workspace()->updateClientLayer( this );
771  updateWindowRules();
772  }
773 
774 void Client::setKeepBelow( bool b )
775  {
776  b = rules()->checkKeepBelow( b );
777  if( b && !rules()->checkKeepAbove( false ))
778  setKeepAbove( false );
779  if ( b == keepBelow())
780  { // force hint change if different
781  if( bool( info->state() & NET::KeepBelow ) != keepBelow())
782  info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
783  return;
784  }
785  keep_below = b;
786  info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
787  if( decoration != NULL )
788  decoration->emitKeepBelowChanged( keepBelow());
789  workspace()->updateClientLayer( this );
790  updateWindowRules();
791  }
792 
793 Layer Client::layer() const
794  {
795  if( in_layer == UnknownLayer )
796  const_cast< Client* >( this )->in_layer = belongsToLayer();
797  return in_layer;
798  }
799 
800 Layer Client::belongsToLayer() const
801  {
802  if( isDesktop())
803  return DesktopLayer;
804  if( isSplash()) // no damn annoying splashscreens
805  return NormalLayer; // getting in the way of everything else
806  if( isDock() && keepBelow())
807  // slight hack for the 'allow window to cover panel' Kicker setting
808  // don't move keepbelow docks below normal window, but only to the same
809  // layer, so that both may be raised to cover the other
810  return NormalLayer;
811  if( keepBelow())
812  return BelowLayer;
813  if( isDock() && !keepBelow())
814  return DockLayer;
815  if( isTopMenu())
816  return DockLayer;
817  // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
818  // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
819  const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
820  const Client* top = workspace()->topClientOnDesktop( desktop(), true, false );
821  if( isFullScreen() && ac != NULL && top != NULL
822  && ( ac == this || this->group() == ac->group())
823  && ( top == this || this->group() == top->group()))
824  return ActiveLayer;
825  if( keepAbove())
826  return AboveLayer;
827  return NormalLayer;
828  }
829 
830 } // namespace

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