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

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.