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

twin

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

twin

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