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

twin

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

twin

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