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

twin

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

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