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

twin

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

twin

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