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

twin

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

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