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

kwin

  • kwin
client.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 #include "client.h"
13 
14 #include <math.h>
15 
16 #include <tqapplication.h>
17 #include <tqpainter.h>
18 #include <tqdatetime.h>
19 #include <tqimage.h>
20 #include <kprocess.h>
21 #include <unistd.h>
22 #include <kstandarddirs.h>
23 #include <tqwhatsthis.h>
24 #include <kwin.h>
25 #include <kiconloader.h>
26 #include <stdlib.h>
27 
28 #include "bridge.h"
29 #include "group.h"
30 #include "workspace.h"
31 #include "atoms.h"
32 #include "notifications.h"
33 #include "rules.h"
34 
35 #include <X11/extensions/shape.h>
36 
37 // put all externs before the namespace statement to allow the linker
38 // to resolve them properly
39 
40 extern Atom qt_wm_state;
41 extern Atom qt_window_role;
42 extern Atom qt_sm_client_id;
43 
44 // wait 200 ms before drawing shadow after move/resize
45 static const int SHADOW_DELAY = 200;
46 
47 namespace KWinInternal
48 {
49 
50 /* TODO: Remove this once X has real translucency.
51  *
52  * A list of the regions covered by all shadows and the Clients to which they
53  * belong. Used to redraw shadows when a window overlapping or underlying a
54  * shadow is moved, resized, or hidden.
55  */
56 struct ShadowRegion
57  {
58  TQRegion region;
59  Client *client;
60  };
61 static TQValueList<ShadowRegion> shadowRegions;
62 
63 /*
64 
65  Creating a client:
66  - only by calling Workspace::createClient()
67  - it creates a new client and calls manage() for it
68 
69  Destroying a client:
70  - destroyClient() - only when the window itself has been destroyed
71  - releaseWindow() - the window is kept, only the client itself is destroyed
72 
73 */
74 
75 
87 Client::Client( Workspace *ws )
88  : TQObject( NULL ),
89  client( None ),
90  wrapper( None ),
91  frame( None ),
92  decoration( NULL ),
93  wspace( ws ),
94  bridge( new Bridge( this )),
95  move_faked_activity( false ),
96  move_resize_grab_window( None ),
97  transient_for( NULL ),
98  transient_for_id( None ),
99  original_transient_for_id( None ),
100  in_group( NULL ),
101  window_group( None ),
102  in_layer( UnknownLayer ),
103  ping_timer( NULL ),
104  process_killer( NULL ),
105  user_time( CurrentTime ), // not known yet
106  allowed_actions( 0 ),
107  postpone_geometry_updates( 0 ),
108  pending_geometry_update( false ),
109  shade_geometry_change( false ),
110  border_left( 0 ),
111  border_right( 0 ),
112  border_top( 0 ),
113  border_bottom( 0 ),
114  opacity_( 0 ),
115  demandAttentionKNotifyTimer( NULL )
116 // SELI do all as initialization
117  {
118  autoRaiseTimer = 0;
119  shadeHoverTimer = 0;
120 
121  shadowDelayTimer = new TQTimer(this);
122  opacityCache = &activeOpacityCache;
123  shadowAfterClient = NULL;
124  shadowWidget = NULL;
125  shadowMe = true;
126  connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
127 
128  // set the initial mapping state
129  mapping_state = WithdrawnState;
130  desk = 0; // no desktop yet
131 
132  mode = PositionCenter;
133  buttonDown = FALSE;
134  moveResizeMode = FALSE;
135 
136  info = NULL;
137 
138  shade_mode = ShadeNone;
139  active = FALSE;
140  deleting = false;
141  keep_above = FALSE;
142  keep_below = FALSE;
143  is_shape = FALSE;
144  motif_noborder = false;
145  motif_may_move = TRUE;
146  motif_may_resize = TRUE;
147  motif_may_close = TRUE;
148  fullscreen_mode = FullScreenNone;
149  skip_taskbar = FALSE;
150  original_skip_taskbar = false;
151  minimized = false;
152  hidden = false;
153  modal = false;
154  noborder = false;
155  user_noborder = false;
156  urgency = false;
157  ignore_focus_stealing = false;
158  demands_attention = false;
159  check_active_modal = false;
160 
161  Pdeletewindow = 0;
162  Ptakefocus = 0;
163  Ptakeactivity = 0;
164  Pcontexthelp = 0;
165  Pping = 0;
166  input = FALSE;
167  skip_pager = FALSE;
168 
169  max_mode = MaximizeRestore;
170  maxmode_restore = MaximizeRestore;
171 
172  cmap = None;
173 
174  frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
175  client_size = TQSize( 100, 100 );
176  custom_opacity = false;
177  rule_opacity_active = 0;; //translucency rules
178  rule_opacity_inactive = 0; //dito.
179 
180  // SELI initialize xsizehints??
181  }
182 
186 Client::~Client()
187  {
188  assert(!moveResizeMode);
189  assert( client == None );
190  assert( frame == None && wrapper == None );
191  assert( decoration == NULL );
192  assert( postpone_geometry_updates == 0 );
193  assert( !check_active_modal );
194  delete info;
195  delete bridge;
196  }
197 
198 // use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
199 void Client::deleteClient( Client* c, allowed_t )
200  {
201  delete c;
202  }
203 
207 void Client::releaseWindow( bool on_shutdown )
208  {
209  assert( !deleting );
210  deleting = true;
211  workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
212  StackingUpdatesBlocker blocker( workspace());
213  if (!custom_opacity) setOpacity(FALSE);
214  if (moveResizeMode)
215  leaveMoveResize();
216  removeShadow();
217  drawIntersectingShadows();
218  finishWindowRules();
219  ++postpone_geometry_updates;
220  // grab X during the release to make removing of properties, setting to withdrawn state
221  // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
222  grabXServer();
223  setMappingState( WithdrawnState );
224  setModal( false ); // otherwise its mainwindow wouldn't get focus
225  hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
226  if( !on_shutdown )
227  workspace()->clientHidden( this );
228  XUnmapWindow( qt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
229  destroyDecoration();
230  cleanGrouping();
231  if( !on_shutdown )
232  {
233  workspace()->removeClient( this, Allowed );
234  // only when the window is being unmapped, not when closing down KWin
235  // (NETWM sections 5.5,5.7)
236  info->setDesktop( 0 );
237  desk = 0;
238  info->setState( 0, info->state()); // reset all state flags
239  }
240  XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
241  XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
242  XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
243  XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
244  XRemoveFromSaveSet( qt_xdisplay(), client );
245  XSelectInput( qt_xdisplay(), client, NoEventMask );
246  if( on_shutdown )
247  { // map the window, so it can be found after another WM is started
248  XMapWindow( qt_xdisplay(), client );
249  // TODO preserve minimized, shaded etc. state?
250  }
251  else
252  {
253  // Make sure it's not mapped if the app unmapped it (#65279). The app
254  // may do map+unmap before we initially map the window by calling rawShow() from manage().
255  XUnmapWindow( qt_xdisplay(), client );
256  }
257  client = None;
258  XDestroyWindow( qt_xdisplay(), wrapper );
259  wrapper = None;
260  XDestroyWindow( qt_xdisplay(), frame );
261  frame = None;
262  --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
263  checkNonExistentClients();
264  deleteClient( this, Allowed );
265  ungrabXServer();
266  }
267 
268 // like releaseWindow(), but this one is called when the window has been already destroyed
269 // (e.g. the application closed it)
270 void Client::destroyClient()
271  {
272  assert( !deleting );
273  deleting = true;
274  workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
275  StackingUpdatesBlocker blocker( workspace());
276  if (moveResizeMode)
277  leaveMoveResize();
278  removeShadow();
279  drawIntersectingShadows();
280  finishWindowRules();
281  ++postpone_geometry_updates;
282  setModal( false );
283  hidden = true; // so that it's not considered visible anymore
284  workspace()->clientHidden( this );
285  destroyDecoration();
286  cleanGrouping();
287  workspace()->removeClient( this, Allowed );
288  client = None; // invalidate
289  XDestroyWindow( qt_xdisplay(), wrapper );
290  wrapper = None;
291  XDestroyWindow( qt_xdisplay(), frame );
292  frame = None;
293  --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
294  checkNonExistentClients();
295  deleteClient( this, Allowed );
296  }
297 
298 void Client::updateDecoration( bool check_workspace_pos, bool force )
299  {
300  if( !force && (( decoration == NULL && noBorder())
301  || ( decoration != NULL && !noBorder())))
302  return;
303  bool do_show = false;
304  postponeGeometryUpdates( true );
305  if( force )
306  destroyDecoration();
307  if( !noBorder())
308  {
309  setMask( TQRegion()); // reset shape mask
310  decoration = workspace()->createDecoration( bridge );
311  // TODO check decoration's minimum size?
312  decoration->init();
313  decoration->widget()->installEventFilter( this );
314  XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
315  decoration->widget()->lower();
316  decoration->borders( border_left, border_right, border_top, border_bottom );
317  options->onlyDecoTranslucent ?
318  setDecoHashProperty(border_top, border_right, border_bottom, border_left):
319  unsetDecoHashProperty();
320  int save_workarea_diff_x = workarea_diff_x;
321  int save_workarea_diff_y = workarea_diff_y;
322  move( calculateGravitation( false ));
323  plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
324  workarea_diff_x = save_workarea_diff_x;
325  workarea_diff_y = save_workarea_diff_y;
326  do_show = true;
327  }
328  else
329  destroyDecoration();
330  if( check_workspace_pos )
331  checkWorkspacePosition();
332  postponeGeometryUpdates( false );
333  if( do_show )
334  decoration->widget()->show();
335  updateFrameExtents();
336  updateOpacityCache();
337  }
338 
339 void Client::destroyDecoration()
340  {
341  if( decoration != NULL )
342  {
343  delete decoration;
344  decoration = NULL;
345  TQPoint grav = calculateGravitation( true );
346  border_left = border_right = border_top = border_bottom = 0;
347  setMask( TQRegion()); // reset shape mask
348  int save_workarea_diff_x = workarea_diff_x;
349  int save_workarea_diff_y = workarea_diff_y;
350  plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
351  move( grav );
352  workarea_diff_x = save_workarea_diff_x;
353  workarea_diff_y = save_workarea_diff_y;
354  }
355  }
356 
357 void Client::checkBorderSizes()
358  {
359  if( decoration == NULL )
360  return;
361  int new_left, new_right, new_top, new_bottom;
362  decoration->borders( new_left, new_right, new_top, new_bottom );
363  if( new_left == border_left && new_right == border_right
364  && new_top == border_top && new_bottom == border_bottom )
365  return;
366  GeometryUpdatesPostponer blocker( this );
367  move( calculateGravitation( true ));
368  border_left = new_left;
369  border_right = new_right;
370  border_top = new_top;
371  border_bottom = new_bottom;
372  if (border_left != new_left ||
373  border_right != new_right ||
374  border_top != new_top ||
375  border_bottom != new_bottom)
376  options->onlyDecoTranslucent ?
377  setDecoHashProperty(new_top, new_right, new_bottom, new_left):
378  unsetDecoHashProperty();
379  move( calculateGravitation( false ));
380  plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
381  checkWorkspacePosition();
382  }
383 
384 void Client::detectNoBorder()
385  {
386  if( Shape::hasShape( window()))
387  {
388  noborder = true;
389  return;
390  }
391  switch( windowType())
392  {
393  case NET::Desktop :
394  case NET::Dock :
395  case NET::TopMenu :
396  case NET::Splash :
397  noborder = true;
398  break;
399  case NET::Unknown :
400  case NET::Normal :
401  case NET::Toolbar :
402  case NET::Menu :
403  case NET::Dialog :
404  case NET::Utility :
405  noborder = false;
406  break;
407  default:
408  assert( false );
409  }
410  // NET::Override is some strange beast without clear definition, usually
411  // just meaning "noborder", so let's treat it only as such flag, and ignore it as
412  // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
413  if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
414  noborder = true;
415  }
416 
417 void Client::detectShapable()
418  {
419  if( Shape::hasShape( window()))
420  return;
421  switch( windowType())
422  {
423  case NET::Desktop :
424  case NET::Dock :
425  case NET::TopMenu :
426  case NET::Splash :
427  break;
428  case NET::Unknown :
429  case NET::Normal :
430  case NET::Toolbar :
431  case NET::Menu :
432  case NET::Dialog :
433  case NET::Utility :
434  setShapable(FALSE);
435  break;
436  default:
437  assert( false );
438  }
439  }
440 
441 void Client::updateFrameExtents()
442  {
443  NETStrut strut;
444  strut.left = border_left;
445  strut.right = border_right;
446  strut.top = border_top;
447  strut.bottom = border_bottom;
448  info->setFrameExtents( strut );
449  }
450 
451 // Resizes the decoration, and makes sure the decoration widget gets resize event
452 // even if the size hasn't changed. This is needed to make sure the decoration
453 // re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
454 // the decoration may turn on/off some borders, but the actual size
455 // of the decoration stays the same).
456 void Client::resizeDecoration( const TQSize& s )
457  {
458  if( decoration == NULL )
459  return;
460  TQSize oldsize = decoration->widget()->size();
461  decoration->resize( s );
462  if( oldsize == s )
463  {
464  TQResizeEvent e( s, oldsize );
465  TQApplication::sendEvent( decoration->widget(), &e );
466  }
467  if (!moveResizeMode && options->shadowEnabled(isActive()))
468  {
469  // If the user is manually resizing, let Client::leaveMoveResize()
470  // decide when to redraw the shadow
471  updateOpacityCache();
472  }
473  }
474 
475 bool Client::noBorder() const
476  {
477  return noborder || isFullScreen() || user_noborder || motif_noborder;
478  }
479 
480 bool Client::userCanSetNoBorder() const
481  {
482  return !noborder && !isFullScreen() && !isShade();
483  }
484 
485 bool Client::isUserNoBorder() const
486  {
487  return user_noborder;
488  }
489 
490 void Client::setUserNoBorder( bool set )
491  {
492  if( !userCanSetNoBorder())
493  return;
494  set = rules()->checkNoBorder( set );
495  if( user_noborder == set )
496  return;
497  user_noborder = set;
498  updateDecoration( true, false );
499  updateWindowRules();
500  }
501 
502 bool Client::isModalSystemNotification() const
503  {
504  unsigned char *data = 0;
505  Atom actual;
506  int format, result;
507  unsigned long n, left;
508  result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
509  if (result == Success && data != None && format == 32 )
510  {
511  return TRUE;
512  }
513  return FALSE;
514  }
515 
516 void Client::updateShape()
517  {
518  // workaround for #19644 - shaped windows shouldn't have decoration
519  if( shape() && !noBorder())
520  {
521  noborder = true;
522  updateDecoration( true );
523  }
524  updateOpacityCache();
525  if ( shape() )
526  {
527  XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
528  clientPos().x(), clientPos().y(),
529  window(), ShapeBounding, ShapeSet);
530  setShapable(TRUE);
531  }
532  // !shape() mask setting is done in setMask() when the decoration
533  // calls it or when the decoration is created/destroyed
534 
535  if( Shape::version() >= 0x11 ) // 1.1, has input shape support
536  { // There appears to be no way to find out if a window has input
537  // shape set or not, so always propagate the input shape
538  // (it's the same like the bounding shape by default).
539  // Also, build the shape using a helper window, not directly
540  // in the frame window, because the sequence set-shape-to-frame,
541  // remove-shape-of-client, add-input-shape-of-client has the problem
542  // that after the second step there's a hole in the input shape
543  // until the real shape of the client is added and that can make
544  // the window lose focus (which is a problem with mouse focus policies)
545  static Window helper_window = None;
546  if( helper_window == None )
547  helper_window = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(),
548  0, 0, 1, 1, 0, 0, 0 );
549  XResizeWindow( qt_xdisplay(), helper_window, width(), height());
550  XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput, 0, 0,
551  frameId(), ShapeBounding, ShapeSet );
552  XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
553  clientPos().x(), clientPos().y(),
554  window(), ShapeBounding, ShapeSubtract );
555  XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
556  clientPos().x(), clientPos().y(),
557  window(), ShapeInput, ShapeUnion );
558  XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
559  helper_window, ShapeInput, ShapeSet );
560  }
561  }
562 
563 void Client::setMask( const TQRegion& reg, int mode )
564  {
565  _mask = reg;
566  if( reg.isNull())
567  XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
568  None, ShapeSet );
569  else if( mode == X::Unsorted )
570  XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
571  reg.handle(), ShapeSet );
572  else
573  {
574  TQMemArray< TQRect > rects = reg.rects();
575  XRectangle* xrects = new XRectangle[ rects.count() ];
576  for( unsigned int i = 0;
577  i < rects.count();
578  ++i )
579  {
580  xrects[ i ].x = rects[ i ].x();
581  xrects[ i ].y = rects[ i ].y();
582  xrects[ i ].width = rects[ i ].width();
583  xrects[ i ].height = rects[ i ].height();
584  }
585  XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
586  xrects, rects.count(), ShapeSet, mode );
587  delete[] xrects;
588  }
589  updateShape();
590  }
591 
592 TQRegion Client::mask() const
593  {
594  if( _mask.isEmpty())
595  return TQRegion( 0, 0, width(), height());
596  return _mask;
597  }
598 
599 void Client::setShapable(bool b)
600  {
601  long tmp = b?1:0;
602  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
603  }
604 
605 void Client::hideClient( bool hide )
606  {
607  if( hidden == hide )
608  return;
609  hidden = hide;
610  updateVisibility();
611  }
612 
616 bool Client::isMinimizable() const
617  {
618  if( isSpecialWindow())
619  return false;
620  if( isModalSystemNotification())
621  return false;
622  if( isTransient())
623  { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
624  bool shown_mainwindow = false;
625  ClientList mainclients = mainClients();
626  for( ClientList::ConstIterator it = mainclients.begin();
627  it != mainclients.end();
628  ++it )
629  {
630  if( (*it)->isShown( true ))
631  shown_mainwindow = true;
632  }
633  if( !shown_mainwindow )
634  return true;
635  }
636  // this is here because kicker's taskbar doesn't provide separate entries
637  // for windows with an explicitly given parent
638  // TODO perhaps this should be redone
639  if( transientFor() != NULL )
640  return false;
641  if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
642  return false;
643  return true;
644  }
645 
649 bool Client::keepAbove() const
650  {
651  if( isModalSystemNotification())
652  return true;
653  return keep_above;
654  }
655 
659 void Client::minimize( bool avoid_animation )
660  {
661  if ( !isMinimizable() || isMinimized())
662  return;
663 
664  if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
665  info->setState(0, NET::Shaded);
666 
667  Notify::raise( Notify::Minimize );
668 
669  // SELI mainClients().isEmpty() ??? - and in unminimize() too
670  if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
671  animateMinimizeOrUnminimize( true ); // was visible or shaded
672 
673  minimized = true;
674 
675  updateVisibility();
676  updateAllowedActions();
677  workspace()->updateMinimizedOfTransients( this );
678  updateWindowRules();
679  workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
680  }
681 
682 void Client::unminimize( bool avoid_animation )
683  {
684  if( !isMinimized())
685  return;
686 
687  if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
688  info->setState(NET::Shaded, NET::Shaded);
689 
690  Notify::raise( Notify::UnMinimize );
691  minimized = false;
692  if( isOnCurrentDesktop() && isShown( true ))
693  {
694  if( mainClients().isEmpty() && !avoid_animation )
695  animateMinimizeOrUnminimize( FALSE );
696  }
697  updateVisibility();
698  updateAllowedActions();
699  workspace()->updateMinimizedOfTransients( this );
700  updateWindowRules();
701  }
702 
703 extern bool blockAnimation;
704 
705 void Client::animateMinimizeOrUnminimize( bool minimize )
706  {
707  if ( blockAnimation )
708  return;
709  if ( !options->animateMinimize )
710  return;
711 
712  if( decoration != NULL && decoration->animateMinimize( minimize ))
713  return; // decoration did it
714 
715  // the function is a bit tricky since it will ensure that an
716  // animation action needs always the same time regardless of the
717  // performance of the machine or the X-Server.
718 
719  float lf,rf,tf,bf,step;
720 
721  int speed = options->animateMinimizeSpeed;
722  if ( speed > 10 )
723  speed = 10;
724  if ( speed < 0 )
725  speed = 0;
726 
727  step = 40. * (11 - speed );
728 
729  NETRect r = info->iconGeometry();
730  TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
731  if ( !icongeom.isValid() )
732  return;
733 
734  TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
735 
736  TQRect before, after;
737  if ( minimize )
738  {
739  before = TQRect( x(), y(), width(), pm.height() );
740  after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
741  }
742  else
743  {
744  before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
745  after = TQRect( x(), y(), width(), pm.height() );
746  }
747 
748  lf = (after.left() - before.left())/step;
749  rf = (after.right() - before.right())/step;
750  tf = (after.top() - before.top())/step;
751  bf = (after.bottom() - before.bottom())/step;
752 
753  grabXServer();
754 
755  TQRect area = before;
756  TQRect area2;
757  TQPixmap pm2;
758 
759  TQTime t;
760  t.start();
761  float diff;
762 
763  TQPainter p ( workspace()->desktopWidget() );
764  bool need_to_clear = FALSE;
765  TQPixmap pm3;
766  do
767  {
768  if (area2 != area)
769  {
770  pm = animationPixmap( area.width() );
771  pm2 = TQPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
772  p.drawPixmap( area.x(), area.y(), pm );
773  if ( need_to_clear )
774  {
775  p.drawPixmap( area2.x(), area2.y(), pm3 );
776  need_to_clear = FALSE;
777  }
778  area2 = area;
779  }
780  XFlush(qt_xdisplay());
781  XSync( qt_xdisplay(), FALSE );
782  diff = t.elapsed();
783  if (diff > step)
784  diff = step;
785  area.setLeft(before.left() + int(diff*lf));
786  area.setRight(before.right() + int(diff*rf));
787  area.setTop(before.top() + int(diff*tf));
788  area.setBottom(before.bottom() + int(diff*bf));
789  if (area2 != area )
790  {
791  if ( area2.intersects( area ) )
792  p.drawPixmap( area2.x(), area2.y(), pm2 );
793  else
794  { // no overlap, we can clear later to avoid flicker
795  pm3 = pm2;
796  need_to_clear = TRUE;
797  }
798  }
799  } while ( t.elapsed() < step);
800  if (area2 == area || need_to_clear )
801  p.drawPixmap( area2.x(), area2.y(), pm2 );
802 
803  p.end();
804  ungrabXServer();
805  }
806 
807 
811 TQPixmap Client::animationPixmap( int w )
812  {
813  TQFont font = options->font(isActive());
814  TQFontMetrics fm( font );
815  TQPixmap pm( w, fm.lineSpacing() );
816  pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
817  TQPainter p( &pm );
818  p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
819  p.setFont(options->font(isActive()));
820  p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
821  return pm;
822  }
823 
824 
825 bool Client::isShadeable() const
826  {
827  return !isSpecialWindow() && !noBorder();
828  }
829 
830 void Client::setShade( ShadeMode mode )
831  {
832  if( !isShadeable())
833  return;
834  if( isModalSystemNotification())
835  return;
836  mode = rules()->checkShade( mode );
837  if( shade_mode == mode )
838  return;
839  bool was_shade = isShade();
840  ShadeMode was_shade_mode = shade_mode;
841  shade_mode = mode;
842  if( was_shade == isShade())
843  {
844  if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
845  decoration->shadeChange();
846  return; // no real change in shaded state
847  }
848 
849  if( shade_mode == ShadeNormal )
850  {
851  if ( isShown( true ) && isOnCurrentDesktop())
852  Notify::raise( Notify::ShadeUp );
853  }
854  else if( shade_mode == ShadeNone )
855  {
856  if( isShown( true ) && isOnCurrentDesktop())
857  Notify::raise( Notify::ShadeDown );
858  }
859 
860  assert( decoration != NULL ); // noborder windows can't be shaded
861  GeometryUpdatesPostponer blocker( this );
862  // decorations may turn off some borders when shaded
863  decoration->borders( border_left, border_right, border_top, border_bottom );
864 
865  int as = options->animateShade? 10 : 1;
866 // TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
867  if ( isShade())
868  { // shade_mode == ShadeNormal
869  // we're about to shade, texx xcompmgr to prepare
870  long _shade = 1;
871  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
872  // shade
873  int h = height();
874  shade_geometry_change = true;
875  TQSize s( sizeForClientSize( TQSize( clientSize())));
876  s.setHeight( border_top + border_bottom );
877  XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
878  XUnmapWindow( qt_xdisplay(), wrapper );
879  XUnmapWindow( qt_xdisplay(), client );
880  XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
881  //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
882  //done xcompmgr workaround
883 // FRAME repaint( FALSE );
884 // bool wasStaticContents = testWFlags( WStaticContents );
885 // setWFlags( WStaticContents );
886  int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
887  do
888  {
889  h -= step;
890  XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
891  resizeDecoration( TQSize( s.width(), h ));
892  TQApplication::syncX();
893  } while ( h > s.height() + step );
894 // if ( !wasStaticContents )
895 // clearWFlags( WStaticContents );
896  plainResize( s );
897  shade_geometry_change = false;
898  if( isActive())
899  {
900  if( was_shade_mode == ShadeHover )
901  workspace()->activateNextClient( this );
902  else
903  workspace()->focusToNull();
904  }
905  // tell xcompmgr shade's done
906  _shade = 2;
907  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
908  }
909  else
910  {
911  int h = height();
912  shade_geometry_change = true;
913  TQSize s( sizeForClientSize( clientSize()));
914 // FRAME bool wasStaticContents = testWFlags( WStaticContents );
915 // setWFlags( WStaticContents );
916  int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
917  do
918  {
919  h += step;
920  XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
921  resizeDecoration( TQSize( s.width(), h ));
922  // assume a border
923  // we do not have time to wait for X to send us paint events
924 // FRAME repaint( 0, h - step-5, width(), step+5, TRUE);
925  TQApplication::syncX();
926  } while ( h < s.height() - step );
927 // if ( !wasStaticContents )
928 // clearWFlags( WStaticContents );
929  shade_geometry_change = false;
930  plainResize( s );
931  if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
932  setActive( TRUE );
933  XMapWindow( qt_xdisplay(), wrapperId());
934  XMapWindow( qt_xdisplay(), window());
935  XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
936  if (options->shadowEnabled(false))
937  {
938  for (ClientList::ConstIterator it = transients().begin();
939  it != transients().end(); ++it)
940  {
941  (*it)->removeShadow();
942  (*it)->drawDelayedShadow();
943  }
944  }
945 
946  if ( isActive() )
947  workspace()->requestFocus( this );
948  }
949  checkMaximizeGeometry();
950  info->setState( (isShade() && !isMinimized()) ? NET::Shaded : 0, NET::Shaded );
951  info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
952  updateVisibility();
953  updateAllowedActions();
954  workspace()->updateMinimizedOfTransients( this );
955  decoration->shadeChange();
956  updateWindowRules();
957  }
958 
959 void Client::shadeHover()
960  {
961  setShade( ShadeHover );
962  cancelShadeHover();
963  }
964 
965 void Client::cancelShadeHover()
966  {
967  delete shadeHoverTimer;
968  shadeHoverTimer = 0;
969  }
970 
971 void Client::toggleShade()
972  {
973  // if the mode is ShadeHover or ShadeActive, cancel shade too
974  setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
975  }
976 
977 void Client::updateVisibility()
978  {
979  if( deleting )
980  return;
981  bool show = true;
982  if( hidden )
983  {
984  setMappingState( IconicState );
985  info->setState( NET::Hidden, NET::Hidden );
986  setSkipTaskbar( true, false ); // also hide from taskbar
987  rawHide();
988  show = false;
989  }
990  else
991  {
992  setSkipTaskbar( original_skip_taskbar, false );
993  }
994  if( minimized )
995  {
996  setMappingState( IconicState );
997  info->setState( NET::Hidden, NET::Hidden );
998  rawHide();
999  show = false;
1000  }
1001  if( show )
1002  info->setState( 0, NET::Hidden );
1003  if( !isOnCurrentDesktop())
1004  {
1005  setMappingState( IconicState );
1006  rawHide();
1007  show = false;
1008  }
1009  if( show )
1010  {
1011  bool belongs_to_desktop = false;
1012  for( ClientList::ConstIterator it = group()->members().begin();
1013  it != group()->members().end();
1014  ++it )
1015  if( (*it)->isDesktop())
1016  {
1017  belongs_to_desktop = true;
1018  break;
1019  }
1020  if( !belongs_to_desktop && workspace()->showingDesktop())
1021  workspace()->resetShowingDesktop( true );
1022  if( isShade())
1023  setMappingState( IconicState );
1024  else
1025  setMappingState( NormalState );
1026  rawShow();
1027  }
1028  }
1029 
1030 void Client::setShadowed(bool shadowed)
1031 {
1032  bool wasShadowed;
1033 
1034  wasShadowed = isShadowed();
1035  shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
1036 
1037  if (shadowMe) {
1038  if (!wasShadowed)
1039  drawShadow();
1040  }
1041  else {
1042  if (wasShadowed) {
1043  removeShadow();
1044 
1045  if (!activeOpacityCache.isNull())
1046  activeOpacityCache.resize(0);
1047  if (!inactiveOpacityCache.isNull())
1048  inactiveOpacityCache.resize(0);
1049  }
1050  }
1051 }
1052 
1053 void Client::updateOpacityCache()
1054 {
1055  if (!activeOpacityCache.isNull())
1056  activeOpacityCache.resize(0);
1057  if (!inactiveOpacityCache.isNull())
1058  inactiveOpacityCache.resize(0);
1059 
1060  if (!moveResizeMode) {
1061  // If the user is manually resizing, let Client::finishMoveResize()
1062  // decide when to redraw the shadow
1063  removeShadow();
1064  drawIntersectingShadows();
1065  if (options->shadowEnabled(isActive()))
1066  drawDelayedShadow();
1067  }
1068 }
1069 
1074 void Client::drawIntersectingShadows() {
1075  //Client *reshadowClient;
1076  TQRegion region;
1077  //TQPtrList<Client> reshadowClients;
1078  TQValueList<Client *> reshadowClients;
1079  TQValueListIterator<ShadowRegion> it;
1080  TQValueListIterator<Client *> it2;
1081 
1082  if (!options->shadowEnabled(false))
1083  // No point in redrawing overlapping/overlapped shadows if only the
1084  // active window has a shadow.
1085  return;
1086 
1087  region = shapeBoundingRegion;
1088 
1089  // Generate list of Clients whose shadows need to be redrawn. That is,
1090  // those that are currently intersecting or intersected by other windows or
1091  // shadows.
1092  for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
1093  if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
1094  !(*it).region.intersect(region).isEmpty())
1095  reshadowClients.append((*it).client);
1096 
1097  // Redraw shadows for each of the Clients in the list generated above
1098  for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
1099  ++it2) {
1100  (*it2)->removeShadow();
1101  (*it2)->drawDelayedShadow();
1102  }
1103 }
1104 
1110 void Client::drawOverlappingShadows(bool waitForMe)
1111 {
1112  Client *aClient;
1113  TQRegion region;
1114  TQValueList<Client *> reshadowClients;
1115  ClientList stacking_order;
1116  ClientList::ConstIterator it;
1117  TQValueListIterator<ShadowRegion> it2;
1118  TQValueListIterator<Client *> it3;
1119 
1120  if (!options->shadowEnabled(false))
1121  // No point in redrawing overlapping/overlapped shadows if only the
1122  // active window has a shadow.
1123  return;
1124 
1125  region = shapeBoundingRegion;
1126 
1127  stacking_order = workspace()->stackingOrder();
1128  for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
1129  // Find the position of this window in the stacking order.
1130  if ((*it) == this)
1131  break;
1132  }
1133  ++it;
1134  while (it != stacking_order.end()) {
1135  if ((*it)->windowType() == NET::Dock) {
1136  // This function is only interested in windows whose shadows don't
1137  // have weird stacking rules.
1138  ++it;
1139  continue;
1140  }
1141 
1142  // Generate list of Clients whose shadows need to be redrawn. That is,
1143  // those that are currently overlapping or overlapped by other windows
1144  // or shadows. The list should be in order from bottom to top in the
1145  // stacking order.
1146  for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
1147  if ((*it2).client == (*it)) {
1148  if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
1149  && !(*it2).region.intersect(region).isEmpty())
1150  reshadowClients.append((*it2).client);
1151  }
1152  }
1153  ++it;
1154  }
1155 
1156  // Redraw shadows for each of the Clients in the list generated above
1157  for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
1158  (*it3)->removeShadow();
1159  if (it3 == reshadowClients.begin()) {
1160  if (waitForMe)
1161  (*it3)->drawShadowAfter(this);
1162  else
1163  (*it3)->drawDelayedShadow();
1164  }
1165  else {
1166  --it3;
1167  aClient = (*it3);
1168  ++it3;
1169  (*it3)->drawShadowAfter(aClient);
1170  }
1171  }
1172 }
1173 
1178 void Client::drawDelayedShadow()
1179 {
1180  shadowDelayTimer->stop();
1181  shadowDelayTimer->start(SHADOW_DELAY, true);
1182 }
1183 
1187 void Client::drawShadowAfter(Client *after)
1188 {
1189  shadowAfterClient = after;
1190  connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow()));
1191 }
1192 
1196 void Client::drawShadow()
1197 {
1198  Window shadows[2];
1199  XRectangle *shapes;
1200  int i, count, ordering;
1201 
1202  // If we are waiting for another Client's shadow to be drawn, stop waiting now
1203  if (shadowAfterClient != NULL) {
1204  disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow()));
1205  shadowAfterClient = NULL;
1206  }
1207 
1208  if (!isOnCurrentDesktop())
1209  return;
1210 
1211  /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
1212  * this type of window. Otherwise, drawIntersectingShadows() won't update
1213  * properly when this window is moved/resized/hidden/closed.
1214  */
1215  shapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding,
1216  &count, &ordering);
1217  if (!shapes)
1218  // XShape extension not supported
1219  shapeBoundingRegion = TQRegion(x(), y(), width(), height());
1220  else {
1221  shapeBoundingRegion = TQRegion();
1222  for (i = 0; i < count; i++) {
1223  // Translate XShaped window into a TQRegion
1224  TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
1225  shapes[i].height);
1226  shapeBoundingRegion += shapeRectangle;
1227  }
1228  if (isShade())
1229  // Since XResize() doesn't change a window's XShape regions, ensure that
1230  // shapeBoundingRegion is not taller than the window's shaded height,
1231  // or the bottom shadow will appear to be missing
1232  shapeBoundingRegion &= TQRegion(0, 0, width(), height());
1233  shapeBoundingRegion.translate(x(), y());
1234  }
1235 
1236  if (!isShadowed() || hidden || isMinimized() ||
1237  maximizeMode() == MaximizeFull ||
1238  !options->shadowWindowType(windowType())) {
1239  XFree(shapes);
1240 
1241  // Tell whatever Clients are listening that this Client's shadow has been drawn.
1242  // It hasn't, but there's no sense waiting for something that won't happen.
1243  emit shadowDrawn();
1244 
1245  return;
1246  }
1247 
1248  removeShadow();
1249 
1250  TQMemArray<QRgb> pixelData;
1251  TQPixmap shadowPixmap;
1252  TQRect shadow;
1253  TQRegion exposedRegion;
1254  ShadowRegion shadowRegion;
1255  int thickness, xOffset, yOffset;
1256 
1257  thickness = options->shadowThickness(isActive());
1258  xOffset = options->shadowXOffset(isActive());
1259  yOffset = options->shadowYOffset(isActive());
1260  opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
1261 
1262  shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
1263  width() + thickness * 2, height() + thickness * 2);
1264  shadowPixmap.resize(shadow.size());
1265 
1266  // Create a fake drop-down shadow effect via blended Xwindows
1267  shadowWidget = new TQWidget(0, 0, (WFlags)(WStyle_Customize | WX11BypassWM));
1268  shadowWidget->setGeometry(shadow);
1269  XSelectInput(qt_xdisplay(), shadowWidget->winId(),
1270  ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
1271  shadowWidget->installEventFilter(this);
1272 
1273  if (!shapes) {
1274  // XShape extension not supported
1275  exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
1276  shadow.y(), shadow.width(), shadow.height(), thickness,
1277  xOffset, yOffset);
1278  shadowRegion.region = exposedRegion;
1279  shadowRegion.client = this;
1280  shadowRegions.append(shadowRegion);
1281 
1282  if (opacityCache->isNull())
1283  imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
1284  exposedRegion, thickness,
1285  options->shadowOpacity(isActive()));
1286  else
1287  imposeCachedShadow(shadowPixmap, exposedRegion);
1288  }
1289  else {
1290  TQMemArray<TQRect> exposedRects;
1291  TQMemArray<TQRect>::Iterator it, itEnd;
1292  XRectangle *shadowShapes;
1293 
1294  exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
1295  shadow.y(), shadow.width(), shadow.height(), thickness,
1296  xOffset, yOffset);
1297  shadowRegion.region = exposedRegion;
1298  shadowRegion.client = this;
1299  shadowRegions.append(shadowRegion);
1300 
1301  // XShape the shadow
1302  exposedRects = exposedRegion.rects();
1303  i = 0;
1304  itEnd = exposedRects.end();
1305  shadowShapes = new XRectangle[exposedRects.count()];
1306  for (it = exposedRects.begin(); it != itEnd; ++it) {
1307  shadowShapes[i].x = (*it).x();
1308  shadowShapes[i].y = (*it).y();
1309  shadowShapes[i].width = (*it).width();
1310  shadowShapes[i].height = (*it).height();
1311  i++;
1312  }
1313  XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(),
1314  ShapeBounding, -x() + thickness - xOffset,
1315  -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
1316  Unsorted);
1317  delete [] shadowShapes;
1318 
1319  if (opacityCache->isNull())
1320  imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
1321  exposedRegion, thickness,
1322  options->shadowOpacity(isActive()));
1323  else
1324  imposeCachedShadow(shadowPixmap, exposedRegion);
1325  }
1326 
1327  XFree(shapes);
1328 
1329  // Set the background pixmap
1330  //shadowPixmap.convertFromImage(shadowImage);
1331  shadowWidget->setErasePixmap(shadowPixmap);
1332 
1333  // Restack shadows under this window so that shadows drawn for a newly
1334  // focused (but not raised) window don't overlap any windows above it.
1335  if (isDock()) {
1336  ClientList stacking_order = workspace()->stackingOrder();
1337  for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
1338  if ((*it)->isDesktop())
1339  {
1340  ++it;
1341  shadows[0] = (*it)->frameId();
1342  shadows[1] = shadowWidget->winId();
1343  }
1344  }
1345  else {
1346  shadows[0] = frameId();
1347  if (shadowWidget != NULL)
1348  shadows[1] = shadowWidget->winId();
1349  }
1350 
1351  XRestackWindows(qt_xdisplay(), shadows, 2);
1352 
1353  // Don't use TQWidget::show() so we don't confuse QEffects, thus causing
1354  // broken focus.
1355  XMapWindow(qt_xdisplay(), shadowWidget->winId());
1356 
1357  // Tell whatever Clients are listening that this Client's shadow has been drawn.
1358  emit shadowDrawn();
1359 }
1360 
1364 void Client::removeShadow()
1365 {
1366  TQValueList<ShadowRegion>::Iterator it;
1367 
1368  shadowDelayTimer->stop();
1369 
1370  if (shadowWidget != NULL) {
1371  for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
1372  if ((*it).client == this) {
1373  shadowRegions.remove(it);
1374  break;
1375  }
1376  delete shadowWidget;
1377  shadowWidget = NULL;
1378  }
1379 }
1380 
1385 TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
1386  int h, int thickness, int xOffset, int yOffset)
1387 {
1388  TQRegion exposedRegion;
1389 
1390  exposedRegion = TQRegion(x, y, w, h);
1391  exposedRegion -= occludedRegion;
1392 
1393  if (thickness > 0) {
1394  // Limit exposedRegion to include only where a shadow of the specified
1395  // thickness will be drawn
1396  TQMemArray<TQRect> occludedRects;
1397  TQMemArray<TQRect>::Iterator it, itEnd;
1398  TQRegion shadowRegion;
1399 
1400  occludedRects = occludedRegion.rects();
1401  itEnd = occludedRects.end();
1402  for (it = occludedRects.begin(); it != itEnd; ++it) {
1403  // Expand each of the occluded region's shape rectangles to contain
1404  // where a shadow of the specified thickness will be drawn. Create
1405  // a new TQRegion that contains the expanded occluded region
1406  it->setTop(it->top() - thickness + yOffset);
1407  it->setLeft(it->left() - thickness + xOffset);
1408  it->setRight(it->right() + thickness + xOffset);
1409  it->setBottom(it->bottom() + thickness + yOffset);
1410  shadowRegion += TQRegion(*it);
1411  }
1412  exposedRegion -= exposedRegion - shadowRegion;
1413  }
1414 
1415  return exposedRegion;
1416 }
1417 
1421 void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
1422 {
1423  QRgb pixel;
1424  double opacity;
1425  int red, green, blue, pixelRed, pixelGreen, pixelBlue;
1426  int subW, subH, w, h, x, y, zeroX, zeroY;
1427  TQImage image;
1428  TQMemArray<TQRect>::Iterator it, itEnd;
1429  TQMemArray<TQRect> rectangles;
1430  TQPixmap subPixmap;
1431  Window rootWindow;
1432  int thickness, windowX, windowY, xOffset, yOffset;
1433 
1434  rectangles = exposed.rects();
1435  rootWindow = qt_xrootwin();
1436  thickness = options->shadowThickness(isActive());
1437  windowX = this->x();
1438  windowY = this->y();
1439  xOffset = options->shadowXOffset(isActive());
1440  yOffset = options->shadowYOffset(isActive());
1441  options->shadowColour(isActive()).rgb(&red, &green, &blue);
1442  w = pixmap.width();
1443  h = pixmap.height();
1444 
1445  itEnd = rectangles.end();
1446  for (it = rectangles.begin(); it != itEnd; ++it) {
1447  subW = (*it).width();
1448  subH = (*it).height();
1449  subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
1450  subW, subH);
1451  zeroX = (*it).x() - windowX + thickness - xOffset;
1452  zeroY = (*it).y() - windowY + thickness - yOffset;
1453  image = subPixmap.convertToImage();
1454 
1455  for (x = 0; x < subW; x++) {
1456  for (y = 0; y < subH; y++) {
1457  opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
1458  pixel = image.pixel(x, y);
1459  pixelRed = tqRed(pixel);
1460  pixelGreen = tqGreen(pixel);
1461  pixelBlue = tqBlue(pixel);
1462  image.setPixel(x, y,
1463  tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
1464  (int)(pixelGreen + (green - pixelGreen) * opacity),
1465  (int)(pixelBlue + (blue - pixelBlue) * opacity)));
1466  }
1467  }
1468 
1469  subPixmap.convertFromImage(image);
1470  bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
1471  }
1472 }
1473 
1477 void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
1478  TQRegion exposed, int thickness, double maxOpacity)
1479 {
1480  register int distance, intersectCount, i, j, x, y;
1481  QRgb pixel;
1482  double decay, factor, opacity;
1483  int red, green, blue, pixelRed, pixelGreen, pixelBlue;
1484  int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
1485  int irBottom, irLeft, irRight, irTop, yIncrement;
1486  int subW, subH, w, h, zeroX, zeroY;
1487  TQImage image;
1488  TQMemArray<TQRect>::Iterator it, itEnd;
1489  TQMemArray<TQRect> rectangles;
1490  TQPixmap subPixmap;
1491  Window rootWindow;
1492  int windowX, windowY, xOffset, yOffset;
1493 
1494  rectangles = exposed.rects();
1495  rootWindow = qt_xrootwin();
1496  windowX = this->x();
1497  windowY = this->y();
1498  xOffset = options->shadowXOffset(isActive());
1499  yOffset = options->shadowYOffset(isActive());
1500  options->shadowColour(isActive()).rgb(&red, &green, &blue);
1501  maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
1502  halfMaxIntersects = maxIntersects / 2;
1503  lineIntersects = thickness * 2 + 1;
1504  factor = maxIntersects / maxOpacity;
1505  decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
1506  w = pixmap.width();
1507  h = pixmap.height();
1508  xOffset = options->shadowXOffset(isActive());
1509  yOffset = options->shadowYOffset(isActive());
1510 
1511  opacityCache->resize(0);
1512  opacityCache->resize(w * h);
1513  occluded.translate(-windowX + thickness, -windowY + thickness);
1514 
1515  itEnd = rectangles.end();
1516  for (it = rectangles.begin(); it != itEnd; ++it) {
1517  subW = (*it).width();
1518  subH = (*it).height();
1519  subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
1520  subW, subH);
1521  maxY = subH;
1522  zeroX = (*it).x() - windowX + thickness - xOffset;
1523  zeroY = (*it).y() - windowY + thickness - yOffset;
1524  image = subPixmap.convertToImage();
1525 
1526  intersectCount = 0;
1527  opacity = -1;
1528  y = 0;
1529  yIncrement = 1;
1530  for (x = 0; x < subW; x++) {
1531  irLeft = zeroX + x - thickness;
1532  irRight = zeroX + x + thickness;
1533 
1534  while (y != maxY) {
1535  // horizontal row about to leave the intersect region, not
1536  // necessarily the top row
1537  irTop = zeroY + y - thickness * yIncrement;
1538  // horizontal row that just came into the intersect region,
1539  // not necessarily the bottom row
1540  irBottom = zeroY + y + thickness * yIncrement;
1541 
1542  if (opacity == -1) {
1543  // If occluded pixels caused an intersect count to be
1544  // skipped, recount it
1545  intersectCount = 0;
1546 
1547  for (j = irTop; j != irBottom; j += yIncrement) {
1548  // irTop is not necessarily larger than irBottom and
1549  // yIncrement isn't necessarily positive
1550  for (i = irLeft; i <= irRight; i++) {
1551  if (occluded.contains(TQPoint(i, j)))
1552  intersectCount++;
1553  }
1554  }
1555  }
1556  else {
1557  if (intersectCount < 0)
1558  intersectCount = 0;
1559 
1560  for (i = irLeft; i <= irRight; i++) {
1561  if (occluded.contains(TQPoint(i, irBottom)))
1562  intersectCount++;
1563  }
1564  }
1565 
1566  distance = maxIntersects - intersectCount;
1567  opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
1568 
1569  (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
1570  pixel = image.pixel(x, y);
1571  pixelRed = tqRed(pixel);
1572  pixelGreen = tqGreen(pixel);
1573  pixelBlue = tqBlue(pixel);
1574  image.setPixel(x, y,
1575  tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
1576  (int)(pixelGreen + (green - pixelGreen) * opacity),
1577  (int)(pixelBlue + (blue - pixelBlue) * opacity)));
1578 
1579  for (i = irLeft; i <= irRight; i++) {
1580  if (occluded.contains(TQPoint(i, irTop)))
1581  intersectCount--;
1582  }
1583 
1584  y += yIncrement;
1585  }
1586  y -= yIncrement;
1587 
1588  irTop += yIncrement;
1589  for (j = irTop; j != irBottom; j += yIncrement) {
1590  if (occluded.contains(TQPoint(irLeft, j)))
1591  intersectCount--;
1592  }
1593  irRight++;
1594  for (j = irTop; j != irBottom; j += yIncrement) {
1595  if (occluded.contains(TQPoint(irRight, j)))
1596  intersectCount++;
1597  }
1598 
1599  yIncrement *= -1;
1600  if (yIncrement < 0)
1601  // Scan Y-axis bottom-up for next X-coordinate iteration
1602  maxY = -1;
1603  else
1604  // Scan Y-axis top-down for next X-coordinate iteration
1605  maxY = subH;
1606  }
1607 
1608  subPixmap.convertFromImage(image);
1609  bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
1610  }
1611 }
1612 
1617 void Client::setMappingState(int s)
1618  {
1619  assert( client != None );
1620  assert( !deleting || s == WithdrawnState );
1621  if( mapping_state == s )
1622  return;
1623  bool was_unmanaged = ( mapping_state == WithdrawnState );
1624  mapping_state = s;
1625  if( mapping_state == WithdrawnState )
1626  {
1627  XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
1628  return;
1629  }
1630  assert( s == NormalState || s == IconicState );
1631 
1632  unsigned long data[2];
1633  data[0] = (unsigned long) s;
1634  data[1] = (unsigned long) None;
1635  XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
1636  PropModeReplace, (unsigned char *)data, 2);
1637 
1638  if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
1639  postponeGeometryUpdates( false );
1640  }
1641 
1646 void Client::rawShow()
1647  {
1648  if( decoration != NULL )
1649  decoration->widget()->show(); // not really necessary, but let it know the state
1650  XMapWindow( qt_xdisplay(), frame );
1651  if( !isShade())
1652  {
1653  XMapWindow( qt_xdisplay(), wrapper );
1654  XMapWindow( qt_xdisplay(), client );
1655  }
1656  if (options->shadowEnabled(isActive()))
1657  drawDelayedShadow();
1658  }
1659 
1665 void Client::rawHide()
1666  {
1667 // Here it may look like a race condition, as some other client might try to unmap
1668 // the window between these two XSelectInput() calls. However, they're supposed to
1669 // use XWithdrawWindow(), which also sends a synthetic event to the root window,
1670 // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
1671 // will be missed is also very minimal, so I don't think it's needed to grab the server
1672 // here.
1673  removeShadow();
1674  drawIntersectingShadows();
1675  XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
1676  XUnmapWindow( qt_xdisplay(), frame );
1677  XUnmapWindow( qt_xdisplay(), wrapper );
1678  XUnmapWindow( qt_xdisplay(), client );
1679  XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
1680  if( decoration != NULL )
1681  decoration->widget()->hide(); // not really necessary, but let it know the state
1682  workspace()->clientHidden( this );
1683  }
1684 
1685 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
1686  {
1687  XEvent ev;
1688  long mask;
1689 
1690  memset(&ev, 0, sizeof(ev));
1691  ev.xclient.type = ClientMessage;
1692  ev.xclient.window = w;
1693  ev.xclient.message_type = a;
1694  ev.xclient.format = 32;
1695  ev.xclient.data.l[0] = protocol;
1696  ev.xclient.data.l[1] = GET_QT_X_TIME();
1697  ev.xclient.data.l[2] = data1;
1698  ev.xclient.data.l[3] = data2;
1699  ev.xclient.data.l[4] = data3;
1700  mask = 0L;
1701  if (w == qt_xrootwin())
1702  mask = SubstructureRedirectMask; /* magic! */
1703  XSendEvent(qt_xdisplay(), w, False, mask, &ev);
1704  }
1705 
1706 /*
1707  Returns whether the window may be closed (have a close button)
1708  */
1709 bool Client::isCloseable() const
1710  {
1711  if( isModalSystemNotification())
1712  return false;
1713  return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
1714  }
1715 
1720 void Client::closeWindow()
1721  {
1722  if( !isCloseable())
1723  return;
1724  // Update user time, because the window may create a confirming dialog.
1725  updateUserTime();
1726  if ( Pdeletewindow )
1727  {
1728  Notify::raise( Notify::Close );
1729  sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
1730  pingWindow();
1731  }
1732  else
1733  {
1734  // client will not react on wm_delete_window. We have not choice
1735  // but destroy his connection to the XServer.
1736  killWindow();
1737  }
1738  }
1739 
1740 
1744 void Client::killWindow()
1745  {
1746  kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
1747  // not sure if we need an Notify::Kill or not.. until then, use
1748  // Notify::Close
1749  Notify::raise( Notify::Close );
1750 
1751  if( isDialog())
1752  Notify::raise( Notify::TransDelete );
1753  if( isNormalWindow())
1754  Notify::raise( Notify::Delete );
1755  killProcess( false );
1756  // always kill this client at the server
1757  XKillClient(qt_xdisplay(), window() );
1758  destroyClient();
1759  }
1760 
1761 // send a ping to the window using _NET_WM_PING if possible
1762 // if it doesn't respond within a reasonable time, it will be
1763 // killed
1764 void Client::pingWindow()
1765  {
1766  if( !Pping )
1767  return; // can't ping :(
1768  if( options->killPingTimeout == 0 )
1769  return; // turned off
1770  if( ping_timer != NULL )
1771  return; // pinging already
1772  ping_timer = new TQTimer( this );
1773  connect( ping_timer, TQT_SIGNAL( timeout()), TQT_SLOT( pingTimeout()));
1774  ping_timer->start( options->killPingTimeout, true );
1775  ping_timestamp = GET_QT_X_TIME();
1776  workspace()->sendPingToWindow( window(), ping_timestamp );
1777  }
1778 
1779 void Client::gotPing( Time timestamp )
1780  {
1781  // just plain compare is not good enough because of 64bit and truncating and whatnot
1782  if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
1783  return;
1784  delete ping_timer;
1785  ping_timer = NULL;
1786  if( process_killer != NULL )
1787  {
1788  process_killer->kill();
1789  delete process_killer;
1790  process_killer = NULL;
1791  }
1792  }
1793 
1794 void Client::pingTimeout()
1795  {
1796  kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
1797  delete ping_timer;
1798  ping_timer = NULL;
1799  killProcess( true, ping_timestamp );
1800  }
1801 
1802 void Client::killProcess( bool ask, Time timestamp )
1803  {
1804  if( process_killer != NULL )
1805  return;
1806  Q_ASSERT( !ask || timestamp != CurrentTime );
1807  TQCString machine = wmClientMachine( true );
1808  pid_t pid = info->pid();
1809  if( pid <= 0 || machine.isEmpty()) // needed properties missing
1810  return;
1811  kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
1812  if( !ask )
1813  {
1814  if( machine != "localhost" )
1815  {
1816  KProcess proc;
1817  proc << "xon" << machine << "kill" << pid;
1818  proc.start( KProcess::DontCare );
1819  }
1820  else
1821  ::kill( pid, SIGTERM );
1822  }
1823  else
1824  { // SELI TODO handle the window created by handler specially (on top,urgent?)
1825  process_killer = new KProcess( this );
1826  *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
1827  << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
1828  << "--windowname" << caption().utf8()
1829  << "--applicationname" << resourceClass()
1830  << "--wid" << TQCString().setNum( window())
1831  << "--timestamp" << TQCString().setNum( timestamp );
1832  connect( process_killer, TQT_SIGNAL( processExited( KProcess* )),
1833  TQT_SLOT( processKillerExited()));
1834  if( !process_killer->start( KProcess::NotifyOnExit ))
1835  {
1836  delete process_killer;
1837  process_killer = NULL;
1838  return;
1839  }
1840  }
1841  }
1842 
1843 void Client::processKillerExited()
1844  {
1845  kdDebug( 1212 ) << "Killer exited" << endl;
1846  delete process_killer;
1847  process_killer = NULL;
1848  }
1849 
1850 void Client::setSkipTaskbar( bool b, bool from_outside )
1851  {
1852  int was_wants_tab_focus = wantsTabFocus();
1853  if( from_outside )
1854  {
1855  b = rules()->checkSkipTaskbar( b );
1856  original_skip_taskbar = b;
1857  }
1858  if ( b == skipTaskbar() )
1859  return;
1860  skip_taskbar = b;
1861  info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
1862  updateWindowRules();
1863  if( was_wants_tab_focus != wantsTabFocus())
1864  workspace()->updateFocusChains( this,
1865  isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
1866  }
1867 
1868 void Client::setSkipPager( bool b )
1869  {
1870  b = rules()->checkSkipPager( b );
1871  if ( b == skipPager() )
1872  return;
1873  skip_pager = b;
1874  info->setState( b?NET::SkipPager:0, NET::SkipPager );
1875  updateWindowRules();
1876  }
1877 
1878 void Client::setModal( bool m )
1879  { // Qt-3.2 can have even modal normal windows :(
1880  if( modal == m )
1881  return;
1882  modal = m;
1883  if( !modal )
1884  return;
1885  // changing modality for a mapped window is weird (?)
1886  // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
1887  }
1888 
1889 void Client::setDesktop( int desktop )
1890  {
1891  if( desktop != NET::OnAllDesktops ) // do range check
1892  desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
1893  desktop = rules()->checkDesktop( desktop );
1894  if( desk == desktop )
1895  return;
1896  int was_desk = desk;
1897  desk = desktop;
1898  info->setDesktop( desktop );
1899  if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
1900  { // onAllDesktops changed
1901  if ( isShown( true ))
1902  Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
1903  workspace()->updateOnAllDesktopsOfTransients( this );
1904  }
1905  if( decoration != NULL )
1906  decoration->desktopChange();
1907  workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
1908  updateVisibility();
1909  updateWindowRules();
1910  }
1911 
1912 void Client::setOnAllDesktops( bool b )
1913  {
1914  if(( b && isOnAllDesktops())
1915  || ( !b && !isOnAllDesktops()))
1916  return;
1917  if( b )
1918  setDesktop( NET::OnAllDesktops );
1919  else
1920  setDesktop( workspace()->currentDesktop());
1921  }
1922 
1923 bool Client::isOnCurrentDesktop() const
1924  {
1925  return isOnDesktop( workspace()->currentDesktop());
1926  }
1927 
1928 int Client::screen() const
1929  {
1930  if( !options->xineramaEnabled )
1931  return 0;
1932  return workspace()->screenNumber( geometry().center());
1933  }
1934 
1935 bool Client::isOnScreen( int screen ) const
1936  {
1937  if( !options->xineramaEnabled )
1938  return screen == 0;
1939  return workspace()->screenGeometry( screen ).intersects( geometry());
1940  }
1941 
1942 // performs activation and/or raising of the window
1943 void Client::takeActivity( int flags, bool handled, allowed_t )
1944  {
1945  if( !handled || !Ptakeactivity )
1946  {
1947  if( flags & ActivityFocus )
1948  takeFocus( Allowed );
1949  if( flags & ActivityRaise )
1950  workspace()->raiseClient( this );
1951  return;
1952  }
1953 
1954 #ifndef NDEBUG
1955  static Time previous_activity_timestamp;
1956  static Client* previous_client;
1957  if( previous_activity_timestamp == GET_QT_X_TIME() && previous_client != this )
1958  {
1959  kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
1960  kdDebug( 1212 ) << kdBacktrace() << endl;
1961  }
1962  previous_activity_timestamp = GET_QT_X_TIME();
1963  previous_client = this;
1964 #endif
1965  workspace()->sendTakeActivity( this, GET_QT_X_TIME(), flags );
1966  }
1967 
1968 // performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
1969 void Client::takeFocus( allowed_t )
1970  {
1971 #ifndef NDEBUG
1972  static Time previous_focus_timestamp;
1973  static Client* previous_client;
1974  if( previous_focus_timestamp == GET_QT_X_TIME() && previous_client != this )
1975  {
1976  kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
1977  kdDebug( 1212 ) << kdBacktrace() << endl;
1978  }
1979  previous_focus_timestamp = GET_QT_X_TIME();
1980  previous_client = this;
1981 #endif
1982  if ( rules()->checkAcceptFocus( input ))
1983  {
1984  XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, GET_QT_X_TIME() );
1985  }
1986  if ( Ptakefocus )
1987  sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
1988  workspace()->setShouldGetFocus( this );
1989  }
1990 
1998 bool Client::providesContextHelp() const
1999  {
2000  if (isModalSystemNotification())
2001  return false;
2002  return Pcontexthelp;
2003  }
2004 
2005 
2012 void Client::showContextHelp()
2013  {
2014  if ( Pcontexthelp )
2015  {
2016  sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
2017  TQWhatsThis::enterWhatsThisMode(); // SELI?
2018  }
2019  }
2020 
2021 
2026 void Client::fetchName()
2027  {
2028  setCaption( readName());
2029  }
2030 
2031 TQString Client::readName() const
2032  {
2033  if ( info->name() && info->name()[ 0 ] != '\0' )
2034  return TQString::fromUtf8( info->name() );
2035  else
2036  return KWin::readNameProperty( window(), XA_WM_NAME );
2037  }
2038 
2039 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
2040 
2041 void Client::setCaption( const TQString& s, bool force )
2042  {
2043  if ( s != cap_normal || force )
2044  {
2045  bool reset_name = force;
2046  for( unsigned int i = 0;
2047  i < s.length();
2048  ++i )
2049  if( !s[ i ].isPrint())
2050  s[ i ] = ' ';
2051  cap_normal = s;
2052  bool was_suffix = ( !cap_suffix.isEmpty());
2053  TQString machine_suffix;
2054  if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
2055  machine_suffix = " <@" + wmClientMachine( true ) + ">";
2056  TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
2057  cap_suffix = machine_suffix + shortcut_suffix;
2058  if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
2059  {
2060  int i = 2;
2061  do
2062  {
2063  cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
2064  i++;
2065  } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
2066  info->setVisibleName( caption().utf8() );
2067  reset_name = false;
2068  }
2069  if(( was_suffix && cap_suffix.isEmpty()
2070  || reset_name )) // if it was new window, it may have old value still set, if the window is reused
2071  {
2072  info->setVisibleName( "" ); // remove
2073  info->setVisibleIconName( "" ); // remove
2074  }
2075  else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
2076  info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
2077 
2078  if( isManaged() && decoration != NULL )
2079  decoration->captionChange();
2080  }
2081  }
2082 
2083 void Client::updateCaption()
2084  {
2085  setCaption( cap_normal, true );
2086  }
2087 
2088 void Client::fetchIconicName()
2089  {
2090  TQString s;
2091  if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
2092  s = TQString::fromUtf8( info->iconName() );
2093  else
2094  s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
2095  if ( s != cap_iconic )
2096  {
2097  bool was_set = !cap_iconic.isEmpty();
2098  cap_iconic = s;
2099  if( !cap_suffix.isEmpty())
2100  {
2101  if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
2102  info->setVisibleIconName( ( s + cap_suffix ).utf8() );
2103  else if( was_set )
2104  info->setVisibleIconName( "" ); //remove
2105  }
2106  }
2107  }
2108 
2111 TQString Client::caption( bool full ) const
2112  {
2113  return full ? cap_normal + cap_suffix : cap_normal;
2114  }
2115 
2116 void Client::getWMHints()
2117  {
2118  XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
2119  input = true;
2120  window_group = None;
2121  urgency = false;
2122  if ( hints )
2123  {
2124  if( hints->flags & InputHint )
2125  input = hints->input;
2126  if( hints->flags & WindowGroupHint )
2127  window_group = hints->window_group;
2128  urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
2129  XFree( (char*)hints );
2130  }
2131  checkGroup();
2132  updateUrgency();
2133  updateAllowedActions(); // group affects isMinimizable()
2134  }
2135 
2136 void Client::getMotifHints()
2137  {
2138  bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
2139  Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
2140  motif_noborder = mnoborder;
2141  if( !hasNETSupport()) // NETWM apps should set type and size constraints
2142  {
2143  motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
2144  motif_may_move = mmove;
2145  }
2146  else
2147  motif_may_resize = motif_may_move = true;
2148  // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
2149  // mmaximize; - ignore, bogus - maximizing is basically just resizing
2150  motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
2151  if( isManaged())
2152  updateDecoration( true ); // check if noborder state has changed
2153  }
2154 
2155 void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
2156  {
2157  // get the icons, allow scaling
2158  if( icon != NULL )
2159  *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
2160  if( miniicon != NULL )
2161  if( icon == NULL || !icon->isNull())
2162  *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
2163  else
2164  *miniicon = TQPixmap();
2165  }
2166 
2167 void Client::getIcons()
2168  {
2169  // first read icons from the window itself
2170  readIcons( window(), &icon_pix, &miniicon_pix );
2171  if( icon_pix.isNull())
2172  { // then try window group
2173  icon_pix = group()->icon();
2174  miniicon_pix = group()->miniIcon();
2175  }
2176  if( icon_pix.isNull() && isTransient())
2177  { // then mainclients
2178  ClientList mainclients = mainClients();
2179  for( ClientList::ConstIterator it = mainclients.begin();
2180  it != mainclients.end() && icon_pix.isNull();
2181  ++it )
2182  {
2183  icon_pix = (*it)->icon();
2184  miniicon_pix = (*it)->miniIcon();
2185  }
2186  }
2187  if( icon_pix.isNull())
2188  { // and if nothing else, load icon from classhint or xapp icon
2189  icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
2190  miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
2191  }
2192  if( isManaged() && decoration != NULL )
2193  decoration->iconChange();
2194  }
2195 
2196 void Client::getWindowProtocols()
2197  {
2198  Atom *p;
2199  int i,n;
2200 
2201  Pdeletewindow = 0;
2202  Ptakefocus = 0;
2203  Ptakeactivity = 0;
2204  Pcontexthelp = 0;
2205  Pping = 0;
2206 
2207  if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
2208  {
2209  for (i = 0; i < n; i++)
2210  if (p[i] == atoms->wm_delete_window)
2211  Pdeletewindow = 1;
2212  else if (p[i] == atoms->wm_take_focus)
2213  Ptakefocus = 1;
2214  else if (p[i] == atoms->net_wm_take_activity)
2215  Ptakeactivity = 1;
2216  else if (p[i] == atoms->net_wm_context_help)
2217  Pcontexthelp = 1;
2218  else if (p[i] == atoms->net_wm_ping)
2219  Pping = 1;
2220  if (n>0)
2221  XFree(p);
2222  }
2223  }
2224 
2225 static int nullErrorHandler(Display *, XErrorEvent *)
2226  {
2227  return 0;
2228  }
2229 
2233 TQCString Client::staticWindowRole(WId w)
2234  {
2235  return getStringProperty(w, qt_window_role).lower();
2236  }
2237 
2241 TQCString Client::staticSessionId(WId w)
2242  {
2243  return getStringProperty(w, qt_sm_client_id);
2244  }
2245 
2249 TQCString Client::staticWmCommand(WId w)
2250  {
2251  return getStringProperty(w, XA_WM_COMMAND, ' ');
2252  }
2253 
2257 Window Client::staticWmClientLeader(WId w)
2258  {
2259  Atom type;
2260  int format, status;
2261  unsigned long nitems = 0;
2262  unsigned long extra = 0;
2263  unsigned char *data = 0;
2264  Window result = w;
2265  XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
2266  status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
2267  FALSE, XA_WINDOW, &type, &format,
2268  &nitems, &extra, &data );
2269  XSetErrorHandler(oldHandler);
2270  if (status == Success )
2271  {
2272  if (data && nitems > 0)
2273  result = *((Window*) data);
2274  XFree(data);
2275  }
2276  return result;
2277  }
2278 
2279 
2280 void Client::getWmClientLeader()
2281  {
2282  wmClientLeaderWin = staticWmClientLeader(window());
2283  }
2284 
2289 TQCString Client::sessionId()
2290  {
2291  TQCString result = staticSessionId(window());
2292  if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2293  result = staticSessionId(wmClientLeaderWin);
2294  return result;
2295  }
2296 
2301 TQCString Client::wmCommand()
2302  {
2303  TQCString result = staticWmCommand(window());
2304  if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2305  result = staticWmCommand(wmClientLeaderWin);
2306  return result;
2307  }
2308 
2309 void Client::getWmClientMachine()
2310  {
2311  client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
2312  if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2313  client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
2314  if( client_machine.isEmpty())
2315  client_machine = "localhost";
2316  }
2317 
2322 TQCString Client::wmClientMachine( bool use_localhost ) const
2323  {
2324  TQCString result = client_machine;
2325  if( use_localhost )
2326  { // special name for the local machine (localhost)
2327  if( result != "localhost" && isLocalMachine( result ))
2328  result = "localhost";
2329  }
2330  return result;
2331  }
2332 
2337 Window Client::wmClientLeader() const
2338  {
2339  if (wmClientLeaderWin)
2340  return wmClientLeaderWin;
2341  return window();
2342  }
2343 
2344 bool Client::wantsTabFocus() const
2345  {
2346  return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
2347  }
2348 
2349 
2350 bool Client::wantsInput() const
2351  {
2352  return rules()->checkAcceptFocus( input || Ptakefocus );
2353  }
2354 
2355 bool Client::isDesktop() const
2356  {
2357  return windowType() == NET::Desktop;
2358  }
2359 
2360 bool Client::isDock() const
2361  {
2362  return windowType() == NET::Dock;
2363  }
2364 
2365 bool Client::isTopMenu() const
2366  {
2367  return windowType() == NET::TopMenu;
2368  }
2369 
2370 
2371 bool Client::isMenu() const
2372  {
2373  return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
2374  }
2375 
2376 bool Client::isToolbar() const
2377  {
2378  return windowType() == NET::Toolbar;
2379  }
2380 
2381 bool Client::isSplash() const
2382  {
2383  return windowType() == NET::Splash;
2384  }
2385 
2386 bool Client::isUtility() const
2387  {
2388  return windowType() == NET::Utility;
2389  }
2390 
2391 bool Client::isDialog() const
2392  {
2393  return windowType() == NET::Dialog;
2394  }
2395 
2396 bool Client::isNormalWindow() const
2397  {
2398  return windowType() == NET::Normal;
2399  }
2400 
2401 bool Client::isSpecialWindow() const
2402  {
2403  return isDesktop() || isDock() || isSplash() || isTopMenu()
2404  || isToolbar(); // TODO
2405  }
2406 
2407 NET::WindowType Client::windowType( bool direct, int supported_types ) const
2408  {
2409  NET::WindowType wt = info->windowType( supported_types );
2410  if( direct )
2411  return wt;
2412  NET::WindowType wt2 = rules()->checkType( wt );
2413  if( wt != wt2 )
2414  {
2415  wt = wt2;
2416  info->setWindowType( wt ); // force hint change
2417  }
2418  // hacks here
2419  if( wt == NET::Menu )
2420  {
2421  // ugly hack to support the times when NET::Menu meant NET::TopMenu
2422  // if it's as wide as the screen, not very high and has its upper-left
2423  // corner a bit above the screen's upper-left cornet, it's a topmenu
2424  if( x() == 0 && y() < 0 && y() > -10 && height() < 100
2425  && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
2426  wt = NET::TopMenu;
2427  }
2428  // TODO change this to rule
2429  const char* const oo_prefix = "openoffice.org"; // TQCString has no startsWith()
2430  // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
2431  if( tqstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
2432  wt = NET::Normal; // see bug #66065
2433  if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
2434  wt = isTransient() ? NET::Dialog : NET::Normal;
2435  return wt;
2436  }
2437 
2442 void Client::setCursor( Position m )
2443  {
2444  if( !isResizable() || isShade())
2445  {
2446  m = PositionCenter;
2447  }
2448  switch ( m )
2449  {
2450  case PositionTopLeft:
2451  case PositionBottomRight:
2452  setCursor( tqsizeFDiagCursor );
2453  break;
2454  case PositionBottomLeft:
2455  case PositionTopRight:
2456  setCursor( tqsizeBDiagCursor );
2457  break;
2458  case PositionTop:
2459  case PositionBottom:
2460  setCursor( tqsizeVerCursor );
2461  break;
2462  case PositionLeft:
2463  case PositionRight:
2464  setCursor( tqsizeHorCursor );
2465  break;
2466  default:
2467  if( buttonDown && isMovable())
2468  setCursor( tqsizeAllCursor );
2469  else
2470  setCursor( tqarrowCursor );
2471  break;
2472  }
2473  }
2474 
2475 // TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
2476 void Client::setCursor( const TQCursor& c )
2477  {
2478  if( c.handle() == cursor.handle())
2479  return;
2480  cursor = c;
2481  if( decoration != NULL )
2482  decoration->widget()->setCursor( cursor );
2483  XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
2484  }
2485 
2486 Client::Position Client::mousePosition( const TQPoint& p ) const
2487  {
2488  if( decoration != NULL )
2489  return decoration->mousePosition( p );
2490  return PositionCenter;
2491  }
2492 
2493 void Client::updateAllowedActions( bool force )
2494  {
2495  if( !isManaged() && !force )
2496  return;
2497  unsigned long old_allowed_actions = allowed_actions;
2498  allowed_actions = 0;
2499  if( isMovable())
2500  allowed_actions |= NET::ActionMove;
2501  if( isResizable())
2502  allowed_actions |= NET::ActionResize;
2503  if( isMinimizable())
2504  allowed_actions |= NET::ActionMinimize;
2505  if( isShadeable())
2506  allowed_actions |= NET::ActionShade;
2507  // sticky state not supported
2508  if( isMaximizable())
2509  allowed_actions |= NET::ActionMax;
2510  if( userCanSetFullScreen())
2511  allowed_actions |= NET::ActionFullScreen;
2512  allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
2513  if( isCloseable())
2514  allowed_actions |= NET::ActionClose;
2515  if( old_allowed_actions == allowed_actions )
2516  return;
2517  // TODO this could be delayed and compressed - it's only for pagers etc. anyway
2518  info->setAllowedActions( allowed_actions );
2519  // TODO this should also tell the decoration, so that it can update the buttons
2520  }
2521 
2522 void Client::autoRaise()
2523  {
2524  workspace()->raiseClient( this );
2525  cancelAutoRaise();
2526  }
2527 
2528 void Client::cancelAutoRaise()
2529  {
2530  delete autoRaiseTimer;
2531  autoRaiseTimer = 0;
2532  }
2533 
2534 void Client::setOpacity(bool translucent, uint opacity)
2535  {
2536  if (isDesktop())
2537  return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
2538 // qWarning("setting opacity for %d",qt_xdisplay());
2539  //rule out activated translulcency with 100% opacity
2540  if (!translucent || opacity == 0xFFFFFFFF)
2541  {
2542  opacity_ = 0xFFFFFFFF;
2543  XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
2544  XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
2545  }
2546  else{
2547  if(opacity == opacity_)
2548  return;
2549  opacity_ = opacity;
2550  long data = opacity; // 32bit XChangeProperty needs long
2551  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2552  XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2553  }
2554  }
2555 
2556 void Client::setShadowSize(uint shadowSize)
2557  {
2558  // ignoring all individual settings - if we control a window, we control it's shadow
2559  // TODO somehow handle individual settings for docks (besides custom sizes)
2560  long data = shadowSize;
2561  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2562  }
2563 
2564 void Client::updateOpacity()
2565 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
2566  {
2567  if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
2568  return;
2569  if (isActive())
2570  {
2571  if( ruleOpacityActive() )
2572  setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
2573  else
2574  setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
2575  if (isBMP())
2576  // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
2577  {
2578  ClientList tmpGroupMembers = group()->members();
2579  ClientList activeGroupMembers;
2580  activeGroupMembers.append(this);
2581  tmpGroupMembers.remove(this);
2582  ClientList::Iterator it = tmpGroupMembers.begin();
2583  while (it != tmpGroupMembers.end())
2584  // search for next attached and not activated client and repeat if found
2585  {
2586  if ((*it) != this && (*it)->isBMP())
2587  // potential "to activate" client found
2588  {
2589 // qWarning("client found");
2590  if ((*it)->touches(this)) // first test, if the new client touches the just activated one
2591  {
2592 // qWarning("found client touches me");
2593  if( ruleOpacityActive() )
2594  (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
2595  else
2596  (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
2597 // qWarning("activated, search restarted (1)");
2598  (*it)->setShadowSize(options->activeWindowShadowSize);
2599  activeGroupMembers.append(*it);
2600  tmpGroupMembers.remove(it);
2601  it = tmpGroupMembers.begin(); // restart, search next client
2602  continue;
2603  }
2604  else
2605  { // pot. client does not touch c, so we have to search if it touches some other activated client
2606  bool found = false;
2607  for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
2608  {
2609  if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
2610  {
2611 // qWarning("found client touches other active client");
2612  if( ruleOpacityActive() )
2613  (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
2614  else
2615  (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
2616  (*it)->setShadowSize(options->activeWindowShadowSize);
2617  activeGroupMembers.append(*it);
2618  tmpGroupMembers.remove(it);
2619  it = tmpGroupMembers.begin(); // reset potential client search
2620  found = true;
2621 // qWarning("activated, search restarted (2)");
2622  break; // skip this loop
2623  }
2624  }
2625  if (found) continue;
2626  }
2627  }
2628  it++;
2629  }
2630  }
2631  else if (isNormalWindow())
2632  // activate dependend minor windows as well
2633  {
2634  for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
2635  if ((*it)->isDialog() || (*it)->isUtility())
2636  if( (*it)->ruleOpacityActive() )
2637  (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
2638  else
2639  (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
2640  }
2641  }
2642  else
2643  {
2644  if( ruleOpacityInactive() )
2645  setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
2646  else
2647  setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
2648  options->inactiveWindowOpacity);
2649  // deactivate dependend minor windows as well
2650  if (isBMP())
2651  // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
2652  {
2653  ClientList tmpGroupMembers = group()->members();
2654  ClientList inactiveGroupMembers;
2655  inactiveGroupMembers.append(this);
2656  tmpGroupMembers.remove(this);
2657  ClientList::Iterator it = tmpGroupMembers.begin();
2658  while ( it != tmpGroupMembers.end() )
2659  // search for next attached and not activated client and repeat if found
2660  {
2661  if ((*it) != this && (*it)->isBMP())
2662  // potential "to activate" client found
2663  {
2664 // qWarning("client found");
2665  if ((*it)->touches(this)) // first test, if the new client touches the just activated one
2666  {
2667 // qWarning("found client touches me");
2668  if( (*it)->ruleOpacityInactive() )
2669  (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
2670  else
2671  (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
2672  (*it)->setShadowSize(options->inactiveWindowShadowSize);
2673 // qWarning("deactivated, search restarted (1)");
2674  inactiveGroupMembers.append(*it);
2675  tmpGroupMembers.remove(it);
2676  it = tmpGroupMembers.begin(); // restart, search next client
2677  continue;
2678  }
2679  else // pot. client does not touch c, so we have to search if it touches some other activated client
2680  {
2681  bool found = false;
2682  for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
2683  {
2684  if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
2685  {
2686 // qWarning("found client touches other inactive client");
2687  if( (*it)->ruleOpacityInactive() )
2688  (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
2689  else
2690  (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
2691  (*it)->setShadowSize(options->inactiveWindowShadowSize);
2692 // qWarning("deactivated, search restarted (2)");
2693  inactiveGroupMembers.append(*it);
2694  tmpGroupMembers.remove(it);
2695  it = tmpGroupMembers.begin(); // reset potential client search
2696  found = true;
2697  break; // skip this loop
2698  }
2699  }
2700  if (found) continue;
2701  }
2702  }
2703  it++;
2704  }
2705  }
2706  else if (isNormalWindow())
2707  {
2708  for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
2709  if ((*it)->isUtility()) //don't deactivate dialogs...
2710  if( (*it)->ruleOpacityInactive() )
2711  (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
2712  else
2713  (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
2714  }
2715  }
2716  }
2717 
2718 void Client::updateShadowSize()
2719 // extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
2720  {
2721  if (!(isNormalWindow() || isDialog() || isUtility() ))
2722  return;
2723  if (isActive())
2724  setShadowSize(options->activeWindowShadowSize);
2725  else
2726  setShadowSize(options->inactiveWindowShadowSize);
2727  }
2728 
2729 uint Client::ruleOpacityInactive()
2730  {
2731  return rule_opacity_inactive;// != 0 ;
2732  }
2733 
2734 uint Client::ruleOpacityActive()
2735  {
2736  return rule_opacity_active;// != 0;
2737  }
2738 
2739 bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
2740  {
2741  unsigned char *data = 0;
2742  Atom actual;
2743  int format, result;
2744  unsigned long n, left;
2745  result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
2746  if (result == Success && data != None && format == 32 )
2747  {
2748  opacity_ = *reinterpret_cast< long* >( data );
2749  custom_opacity = true;
2750 // setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
2751  XFree ((char*)data);
2752  return TRUE;
2753  }
2754  return FALSE;
2755  }
2756 
2757 void Client::setCustomOpacityFlag(bool custom)
2758  {
2759  custom_opacity = custom;
2760  }
2761 
2762 uint Client::opacity()
2763  {
2764  return opacity_;
2765  }
2766 
2767 int Client::opacityPercentage()
2768  {
2769  return int(100*((double)opacity_/0xffffffff));
2770  }
2771 
2772 bool Client::touches(const Client* c)
2773 // checks if this client borders c, needed to test beep media player window state
2774  {
2775  if (y() == c->y() + c->height()) // this bottom to c
2776  return TRUE;
2777  if (y() + height() == c->y()) // this top to c
2778  return TRUE;
2779  if (x() == c->x() + c->width()) // this right to c
2780  return TRUE;
2781  if (x() + width() == c->x()) // this left to c
2782  return TRUE;
2783  return FALSE;
2784  }
2785 
2786 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
2787 {
2788  long data = (topHeight < 255 ? topHeight : 255) << 24 |
2789  (rightWidth < 255 ? rightWidth : 255) << 16 |
2790  (bottomHeight < 255 ? bottomHeight : 255) << 8 |
2791  (leftWidth < 255 ? leftWidth : 255);
2792  XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2793 }
2794 
2795 void Client::unsetDecoHashProperty()
2796 {
2797  XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
2798 }
2799 
2800 #ifndef NDEBUG
2801 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
2802  {
2803  if( cl == NULL )
2804  return stream << "\'NULL_CLIENT\'";
2805  return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
2806  }
2807 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
2808  {
2809  stream << "LIST:(";
2810  bool first = true;
2811  for( ClientList::ConstIterator it = list.begin();
2812  it != list.end();
2813  ++it )
2814  {
2815  if( !first )
2816  stream << ":";
2817  first = false;
2818  stream << *it;
2819  }
2820  stream << ")";
2821  return stream;
2822  }
2823 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
2824  {
2825  stream << "LIST:(";
2826  bool first = true;
2827  for( ConstClientList::ConstIterator it = list.begin();
2828  it != list.end();
2829  ++it )
2830  {
2831  if( !first )
2832  stream << ":";
2833  first = false;
2834  stream << *it;
2835  }
2836  stream << ")";
2837  return stream;
2838  }
2839 #endif
2840 
2841 TQPixmap * kwin_get_menu_pix_hack()
2842  {
2843  static TQPixmap p;
2844  if ( p.isNull() )
2845  p = SmallIcon( "bx2" );
2846  return &p;
2847  }
2848 
2849 } // namespace
2850 
2851 #include "client.moc"

kwin

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

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.8.1.2
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |