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

twin

  • twin
workspace.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 //#define QT_CLEAN_NAMESPACE
13 
14 #include "workspace.h"
15 
16 #include <tdeapplication.h>
17 #include <tdestartupinfo.h>
18 #include <fixx11h.h>
19 #include <tdeconfig.h>
20 #include <tdeglobal.h>
21 #include <tqpopupmenu.h>
22 #include <tdelocale.h>
23 #include <tqregexp.h>
24 #include <tqpainter.h>
25 #include <tqbitmap.h>
26 #include <tqclipboard.h>
27 #include <tdemenubar.h>
28 #include <kprocess.h>
29 #include <kglobalaccel.h>
30 #include <dcopclient.h>
31 #include <kipc.h>
32 
33 #include "plugins.h"
34 #include "client.h"
35 #include "popupinfo.h"
36 #include "tabbox.h"
37 #include "atoms.h"
38 #include "placement.h"
39 #include "notifications.h"
40 #include "group.h"
41 #include "rules.h"
42 
43 #include <X11/XKBlib.h>
44 #include <X11/extensions/shape.h>
45 #include <X11/keysym.h>
46 #include <X11/keysymdef.h>
47 #include <X11/cursorfont.h>
48 
49 #include <pwd.h>
50 
51 #include "config.h"
52 
53 namespace KWinInternal
54 {
55 
56 extern int screen_number;
57 
58 Workspace *Workspace::_self = 0;
59 
60 TDEProcess* kompmgr = 0;
61 TDESelectionOwner* kompmgr_selection;
62 
63 bool allowKompmgrRestart = TRUE;
64 extern bool disable_twin_composition_manager;
65 
66 bool supportsCompMgr()
67 {
68  if (disable_twin_composition_manager) {
69  return false;
70  }
71 
72  int i;
73 
74  bool damageExt = XQueryExtension(tqt_xdisplay(), "DAMAGE", &i, &i, &i);
75  bool compositeExt = XQueryExtension(tqt_xdisplay(), "Composite", &i, &i, &i);
76  bool xfixesExt = XQueryExtension(tqt_xdisplay(), "XFIXES", &i, &i, &i);
77 
78  return damageExt && compositeExt && xfixesExt;
79 }
80 
81 pid_t getCompositorPID() {
82  // Attempt to load the compton-tde pid file
83  char *filename;
84  const char *pidfile = "compton-tde.pid";
85  char uidstr[sizeof(uid_t)*8+1];
86  sprintf(uidstr, "%d", getuid());
87  int n = strlen(P_tmpdir)+strlen(uidstr)+strlen(pidfile)+3;
88  filename = (char*)malloc(n*sizeof(char)+1);
89  memset(filename,0,n);
90  strcat(filename, P_tmpdir);
91  strcat(filename, "/.");
92  strcat(filename, uidstr);
93  strcat(filename, "-");
94  strcat(filename, pidfile);
95 
96  // Now that we did all that by way of introduction...read the file!
97  FILE *pFile;
98  char buffer[255];
99  pFile = fopen(filename, "r");
100  pid_t kompmgrpid = 0;
101  if (pFile)
102  {
103  printf("[twin-workspace] Using '%s' as compton-tde pidfile\n\n", filename);
104  // obtain file size
105  fseek (pFile , 0 , SEEK_END);
106  unsigned long lSize = ftell (pFile);
107  if (lSize > 254)
108  lSize = 254;
109  rewind (pFile);
110  size_t result = fread (buffer, 1, lSize, pFile);
111  fclose(pFile);
112  if (result > 0)
113  {
114  kompmgrpid = atoi(buffer);
115  }
116  }
117 
118  free(filename);
119  filename = NULL;
120 
121  return kompmgrpid;
122 }
123 
124 // Rikkus: This class is too complex. It needs splitting further.
125 // It's a nightmare to understand, especially with so few comments :(
126 
127 // Matthias: Feel free to ask me questions about it. Feel free to add
128 // comments. I disagree that further splittings makes it easier. 2500
129 // lines are not too much. It's the task that is complex, not the
130 // code.
131 Workspace::Workspace( bool restore )
132  : DCOPObject ("KWinInterface"),
133  TQObject (0, "workspace"),
134  current_desktop (0),
135  number_of_desktops(0),
136  active_screen (0),
137  active_popup( NULL ),
138  active_popup_client( NULL ),
139  desktop_widget (0),
140  temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ),
141  rules_updates_disabled( false ),
142  active_client (0),
143  last_active_client (0),
144  next_active_client (0),
145  most_recently_raised (0),
146  movingClient(0),
147  pending_take_activity ( NULL ),
148  delayfocus_client (0),
149  showing_desktop( false ),
150  block_showing_desktop( 0 ),
151  was_user_interaction (false),
152  session_saving (false),
153  control_grab (false),
154  tab_grab (false),
155  mouse_emulation (false),
156  block_focus (0),
157  tab_box (0),
158  popupinfo (0),
159  popup (0),
160  advanced_popup (0),
161  desk_popup (0),
162  desk_popup_index (0),
163  keys (0),
164  client_keys ( NULL ),
165  client_keys_dialog ( NULL ),
166  client_keys_client ( NULL ),
167  disable_shortcuts_keys ( NULL ),
168  global_shortcuts_disabled( false ),
169  global_shortcuts_disabled_for_client( false ),
170  root (0),
171  workspaceInit (true),
172  startup(0), electric_have_borders(false),
173  electric_current_border(0),
174  electric_top_border(None),
175  electric_bottom_border(None),
176  electric_left_border(None),
177  electric_right_border(None),
178  layoutOrientation(Qt::Vertical),
179  layoutX(-1),
180  layoutY(2),
181  workarea(NULL),
182  screenarea(NULL),
183  managing_topmenus( false ),
184  topmenu_selection( NULL ),
185  topmenu_watcher( NULL ),
186  topmenu_height( 0 ),
187  topmenu_space( NULL ),
188  set_active_client_recursion( 0 ),
189  block_stacking_updates( 0 ),
190  forced_global_mouse_grab( false )
191  {
192  _self = this;
193  mgr = new PluginMgr;
194  root = tqt_xrootwin();
195  default_colormap = DefaultColormap(tqt_xdisplay(), tqt_xscreen() );
196  installed_colormap = default_colormap;
197  session.setAutoDelete( TRUE );
198 
199  connect( &temporaryRulesMessages, TQT_SIGNAL( gotMessage( const TQString& )),
200  this, TQT_SLOT( gotTemporaryRulesMessage( const TQString& )));
201  connect( &rulesUpdatedTimer, TQT_SIGNAL( timeout()), this, TQT_SLOT( writeWindowRules()));
202 
203  updateXTime(); // needed for proper initialization of user_time in Client ctor
204 
205  delayFocusTimer = 0;
206 
207  electric_time_first = GET_QT_X_TIME();
208  electric_time_last = GET_QT_X_TIME();
209 
210  if ( restore )
211  loadSessionInfo();
212 
213  loadWindowRules();
214 
215  (void) TQApplication::desktop(); // trigger creation of desktop widget
216 
217  desktop_widget =
218  new TQWidget(
219  0,
220  "desktop_widget",
221  (WFlags)(TQt::WType_Desktop | TQt::WPaintUnclipped)
222  );
223 
224  kapp->setGlobalMouseTracking( true ); // so that this doesn't mess eventmask on root window later
225  // call this before XSelectInput() on the root window
226  startup = new TDEStartupInfo(
227  TDEStartupInfo::DisableKWinModule | TDEStartupInfo::AnnounceSilenceChanges, this );
228 
229  // select windowmanager privileges
230  XSelectInput(tqt_xdisplay(), root,
231  KeyPressMask |
232  PropertyChangeMask |
233  ColormapChangeMask |
234  SubstructureRedirectMask |
235  SubstructureNotifyMask |
236  FocusChangeMask // for NotifyDetailNone
237  );
238 
239  Shape::init();
240 
241  // compatibility
242  long data = 1;
243 
244  XChangeProperty(
245  tqt_xdisplay(),
246  tqt_xrootwin(),
247  atoms->twin_running,
248  atoms->twin_running,
249  32,
250  PropModeAppend,
251  (unsigned char*) &data,
252  1
253  );
254 
255  client_keys = new TDEGlobalAccel( this );
256  initShortcuts();
257  tab_box = new TabBox( this );
258  popupinfo = new PopupInfo( this );
259 
260  init();
261 
262 #if (TQT_VERSION-0 >= 0x030200) // XRANDR support
263  connect( kapp->desktop(), TQT_SIGNAL( resized( int )), TQT_SLOT( desktopResized()));
264 #endif
265 
266  if (!supportsCompMgr()) {
267  options->useTranslucency = false;
268  }
269 
270  // start kompmgr - i wanted to put this into main.cpp, but that would prevent dcop support, as long as Application was no dcop_object
271 
272  // If compton-tde is already running, send it SIGTERM
273  pid_t kompmgrpid = getCompositorPID();
274 
275  if (options->useTranslucency)
276  {
277  kompmgr = new TDEProcess;
278  connect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
279  *kompmgr << TDE_COMPOSITOR_BINARY;
280  if (kompmgrpid)
281  {
282  if (kill(kompmgrpid, 0) < 0)
283  {
284  // Stale PID file detected; (re)start compositor!
285  startKompmgr();
286  }
287  }
288  else
289  {
290  startKompmgr();
291  }
292  }
293  else if (!disable_twin_composition_manager)
294  {
295 
296  if (kompmgrpid)
297  {
298  kill(kompmgrpid, SIGTERM);
299  }
300  else
301  {
302  stopKompmgr();
303  }
304  }
305  }
306 
307 
308 void Workspace::init()
309  {
310  checkElectricBorders();
311 
312 // not used yet
313 // topDock = 0L;
314 // maximizedWindowCounter = 0;
315 
316  supportWindow = new TQWidget;
317  XLowerWindow( tqt_xdisplay(), supportWindow->winId()); // see usage in layers.cpp
318 
319  XSetWindowAttributes attr;
320  attr.override_redirect = 1;
321  null_focus_window = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), -1,-1, 1, 1, 0, CopyFromParent,
322  InputOnly, CopyFromParent, CWOverrideRedirect, &attr );
323  XMapWindow(tqt_xdisplay(), null_focus_window);
324 
325  unsigned long protocols[ 5 ] =
326  {
327  NET::Supported |
328  NET::SupportingWMCheck |
329  NET::ClientList |
330  NET::ClientListStacking |
331  NET::DesktopGeometry |
332  NET::NumberOfDesktops |
333  NET::CurrentDesktop |
334  NET::ActiveWindow |
335  NET::WorkArea |
336  NET::CloseWindow |
337  NET::DesktopNames |
338  NET::KDESystemTrayWindows |
339  NET::WMName |
340  NET::WMVisibleName |
341  NET::WMDesktop |
342  NET::WMWindowType |
343  NET::WMState |
344  NET::WMStrut |
345  NET::WMIconGeometry |
346  NET::WMIcon |
347  NET::WMPid |
348  NET::WMMoveResize |
349  NET::WMKDESystemTrayWinFor |
350  NET::WMFrameExtents |
351  NET::WMPing
352  ,
353  NET::NormalMask |
354  NET::DesktopMask |
355  NET::DockMask |
356  NET::ToolbarMask |
357  NET::MenuMask |
358  NET::DialogMask |
359  NET::OverrideMask |
360  NET::TopMenuMask |
361  NET::UtilityMask |
362  NET::SplashMask |
363  0
364  ,
365  NET::Modal |
366 // NET::Sticky | // large desktops not supported (and probably never will be)
367  NET::MaxVert |
368  NET::MaxHoriz |
369  NET::Shaded |
370  NET::SkipTaskbar |
371  NET::KeepAbove |
372 // NET::StaysOnTop | the same like KeepAbove
373  NET::SkipPager |
374  NET::Hidden |
375  NET::FullScreen |
376  NET::KeepBelow |
377  NET::DemandsAttention |
378  0
379  ,
380  NET::WM2UserTime |
381  NET::WM2StartupId |
382  NET::WM2AllowedActions |
383  NET::WM2RestackWindow |
384  NET::WM2MoveResizeWindow |
385  NET::WM2ExtendedStrut |
386  NET::WM2KDETemporaryRules |
387  NET::WM2ShowingDesktop |
388  NET::WM2FullPlacement |
389  NET::WM2DesktopLayout |
390  0
391  ,
392  NET::ActionMove |
393  NET::ActionResize |
394  NET::ActionMinimize |
395  NET::ActionShade |
396 // NET::ActionStick | // Sticky state is not supported
397  NET::ActionMaxVert |
398  NET::ActionMaxHoriz |
399  NET::ActionFullScreen |
400  NET::ActionChangeDesktop |
401  NET::ActionClose |
402  0
403  ,
404  };
405 
406  rootInfo = new RootInfo( this, tqt_xdisplay(), supportWindow->winId(), "KWin",
407  protocols, 5, tqt_xscreen() );
408 
409  loadDesktopSettings();
410  updateDesktopLayout();
411  // extra NETRootInfo instance in Client mode is needed to get the values of the properties
412  NETRootInfo client_info( tqt_xdisplay(), NET::ActiveWindow | NET::CurrentDesktop );
413  int initial_desktop;
414  if( !kapp->isSessionRestored())
415  initial_desktop = client_info.currentDesktop();
416  else
417  {
418  TDEConfigGroupSaver saver( kapp->sessionConfig(), "Session" );
419  initial_desktop = kapp->sessionConfig()->readNumEntry( "desktop", 1 );
420  }
421  if( !setCurrentDesktop( initial_desktop ))
422  setCurrentDesktop( 1 );
423 
424  // now we know how many desktops we'll, thus, we initialise the positioning object
425  initPositioning = new Placement(this);
426 
427  connect(&reconfigureTimer, TQT_SIGNAL(timeout()), this,
428  TQT_SLOT(slotReconfigure()));
429  connect( &updateToolWindowsTimer, TQT_SIGNAL( timeout()), this, TQT_SLOT( slotUpdateToolWindows()));
430 
431  connect(kapp, TQT_SIGNAL(appearanceChanged()), this,
432  TQT_SLOT(slotReconfigure()));
433  connect(kapp, TQT_SIGNAL(settingsChanged(int)), this,
434  TQT_SLOT(slotSettingsChanged(int)));
435  connect(kapp, TQT_SIGNAL( kipcMessage( int, int )), this, TQT_SLOT( kipcMessage( int, int )));
436 
437  active_client = NULL;
438  rootInfo->setActiveWindow( None );
439  focusToNull();
440  if( !kapp->isSessionRestored())
441  ++block_focus; // because it will be set below
442 
443  char nm[ 100 ];
444  sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( tqt_xdisplay()));
445  Atom topmenu_atom = XInternAtom( tqt_xdisplay(), nm, False );
446  topmenu_selection = new TDESelectionOwner( topmenu_atom );
447  topmenu_watcher = new TDESelectionWatcher( topmenu_atom );
448 // TODO grabXServer(); - where exactly put this? topmenu selection claiming down belong must be before
449 
450  { // begin updates blocker block
451  StackingUpdatesBlocker blocker( this );
452 
453  if( options->topMenuEnabled() && topmenu_selection->claim( false ))
454  setupTopMenuHandling(); // this can call updateStackingOrder()
455  else
456  lostTopMenuSelection();
457 
458  unsigned int i, nwins;
459  Window root_return, parent_return, *wins;
460  XQueryTree(tqt_xdisplay(), root, &root_return, &parent_return, &wins, &nwins);
461  for (i = 0; i < nwins; i++)
462  {
463  XWindowAttributes attr;
464  XGetWindowAttributes(tqt_xdisplay(), wins[i], &attr);
465  if (attr.override_redirect )
466  continue;
467  if( topmenu_space && topmenu_space->winId() == wins[ i ] )
468  continue;
469  if (attr.map_state != IsUnmapped)
470  {
471  if ( addSystemTrayWin( wins[i] ) )
472  continue;
473  Client* c = createClient( wins[i], true );
474  if ( c != NULL && root != tqt_xrootwin() )
475  { // TODO what is this?
476  // TODO may use TQWidget:.create
477  XReparentWindow( tqt_xdisplay(), c->frameId(), root, 0, 0 );
478  c->move(0,0);
479  }
480  }
481  }
482  if ( wins )
483  XFree((void *) wins);
484  // propagate clients, will really happen at the end of the updates blocker block
485  updateStackingOrder( true );
486 
487  updateClientArea();
488  raiseElectricBorders();
489 
490  // NETWM spec says we have to set it to (0,0) if we don't support it
491  NETPoint* viewports = new NETPoint[ number_of_desktops ];
492  rootInfo->setDesktopViewport( number_of_desktops, *viewports );
493  delete[] viewports;
494  TQRect geom = TQApplication::desktop()->geometry();
495  NETSize desktop_geometry;
496  desktop_geometry.width = geom.width();
497  desktop_geometry.height = geom.height();
498  rootInfo->setDesktopGeometry( -1, desktop_geometry );
499  setShowingDesktop( false );
500 
501  } // end updates blocker block
502 
503  Client* new_active_client = NULL;
504  if( !kapp->isSessionRestored())
505  {
506  --block_focus;
507  new_active_client = findClient( WindowMatchPredicate( client_info.activeWindow()));
508  }
509  if( new_active_client == NULL
510  && activeClient() == NULL && should_get_focus.count() == 0 ) // no client activated in manage()
511  {
512  if( new_active_client == NULL )
513  new_active_client = topClientOnDesktop( currentDesktop());
514  if( new_active_client == NULL && !desktops.isEmpty() )
515  new_active_client = findDesktop( true, currentDesktop());
516  }
517  if( new_active_client != NULL )
518  activateClient( new_active_client );
519  // SELI TODO this won't work with unreasonable focus policies,
520  // and maybe in rare cases also if the selected client doesn't
521  // want focus
522  workspaceInit = false;
523 // TODO ungrabXServer()
524  }
525 
526 Workspace::~Workspace()
527  {
528  if (kompmgr)
529  delete kompmgr;
530  blockStackingUpdates( true );
531 // TODO grabXServer();
532  // use stacking_order, so that twin --replace keeps stacking order
533  for( ClientList::ConstIterator it = stacking_order.begin();
534  it != stacking_order.end();
535  ++it )
536  {
537  // only release the window
538  (*it)->releaseWindow( true );
539  // No removeClient() is called, it does more than just removing.
540  // However, remove from some lists to e.g. prevent performTransiencyCheck()
541  // from crashing.
542  clients.remove( *it );
543  desktops.remove( *it );
544  }
545  delete desktop_widget;
546  delete tab_box;
547  delete popupinfo;
548  delete popup;
549  if ( root == tqt_xrootwin() )
550  XDeleteProperty(tqt_xdisplay(), tqt_xrootwin(), atoms->twin_running);
551 
552  writeWindowRules();
553  TDEGlobal::config()->sync();
554 
555  delete rootInfo;
556  delete supportWindow;
557  delete mgr;
558  delete[] workarea;
559  delete[] screenarea;
560  delete startup;
561  delete initPositioning;
562  delete topmenu_watcher;
563  delete topmenu_selection;
564  delete topmenu_space;
565  delete client_keys_dialog;
566  while( !rules.isEmpty())
567  {
568  delete rules.front();
569  rules.pop_front();
570  }
571  XDestroyWindow( tqt_xdisplay(), null_focus_window );
572 // TODO ungrabXServer();
573  _self = 0;
574  }
575 
576 Client* Workspace::createClient( Window w, bool is_mapped )
577  {
578  StackingUpdatesBlocker blocker( this );
579  Client* c = new Client( this );
580  if( !c->manage( w, is_mapped ))
581  {
582  Client::deleteClient( c, Allowed );
583  return NULL;
584  }
585  addClient( c, Allowed );
586  return c;
587  }
588 
589 void Workspace::addClient( Client* c, allowed_t )
590  {
591  // waited with trans settings until window figured out if active or not ;)
592 // tqWarning("%s", (const char*)(c->resourceClass()));
593  c->setBMP(c->resourceName() == "beep-media-player" || c->decorationId() == None);
594  // first check if the window has it's own opinion of it's translucency ;)
595  c->getWindowOpacity();
596  if (c->isDock())
597  {
598 // if (c->x() == 0 && c->y() == 0 && c->width() > c->height()) topDock = c;
599  if (!c->hasCustomOpacity()) // this xould be done slightly more efficient, but we want to support the topDock in future
600  {
601  c->setShadowSize(options->dockShadowSize);
602  c->setOpacity(options->translucentDocks, options->dockOpacity);
603  }
604  }
605 
606  if (c->isMenu() || c->isTopMenu())
607  {
608  c->setShadowSize(options->menuShadowSize);
609  }
610 //------------------------------------------------
611  Group* grp = findGroup( c->window());
612  if( grp != NULL )
613  grp->gotLeader( c );
614 
615  if ( c->isDesktop() )
616  {
617  desktops.append( c );
618  if( active_client == NULL && should_get_focus.isEmpty() && c->isOnCurrentDesktop())
619  requestFocus( c ); // CHECKME? make sure desktop is active after startup if there's no other window active
620  }
621  else
622  {
623  updateFocusChains( c, FocusChainUpdate ); // add to focus chain if not already there
624  clients.append( c );
625  }
626  if( !unconstrained_stacking_order.contains( c ))
627  unconstrained_stacking_order.append( c );
628  if( !stacking_order.contains( c )) // it'll be updated later, and updateToolWindows() requires
629  stacking_order.append( c ); // c to be in stacking_order
630  if( c->isTopMenu())
631  addTopMenu( c );
632  updateClientArea(); // this cannot be in manage(), because the client got added only now
633  updateClientLayer( c );
634  if( c->isDesktop())
635  {
636  raiseClient( c );
637  // if there's no active client, make this desktop the active one
638  if( activeClient() == NULL && should_get_focus.count() == 0 )
639  activateClient( findDesktop( true, currentDesktop()));
640  }
641  c->checkActiveModal();
642  checkTransients( c->window()); // SELI does this really belong here?
643  updateStackingOrder( true ); // propagate new client
644  if( c->isUtility() || c->isMenu() || c->isToolbar())
645  updateToolWindows( true );
646  checkNonExistentClients();
647  }
648 
649 /*
650  Destroys the client \a c
651  */
652 void Workspace::removeClient( Client* c, allowed_t )
653  {
654  if (c == active_popup_client)
655  closeActivePopup();
656 
657  if( client_keys_client == c )
658  setupWindowShortcutDone( false );
659  if( !c->shortcut().isNull())
660  c->setShortcut( TQString::null ); // remove from client_keys
661 
662  if( c->isDialog())
663  Notify::raise( Notify::TransDelete );
664  if( c->isNormalWindow())
665  Notify::raise( Notify::Delete );
666 
667  Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
668  clients.remove( c );
669  desktops.remove( c );
670  unconstrained_stacking_order.remove( c );
671  stacking_order.remove( c );
672  for( int i = 1;
673  i <= numberOfDesktops();
674  ++i )
675  focus_chain[ i ].remove( c );
676  global_focus_chain.remove( c );
677  attention_chain.remove( c );
678  showing_desktop_clients.remove( c );
679  if( c->isTopMenu())
680  removeTopMenu( c );
681  Group* group = findGroup( c->window());
682  if( group != NULL )
683  group->lostLeader();
684 
685  if ( c == most_recently_raised )
686  most_recently_raised = 0;
687  should_get_focus.remove( c );
688  Q_ASSERT( c != active_client );
689  if ( c == last_active_client )
690  last_active_client = 0;
691  if( c == pending_take_activity )
692  pending_take_activity = NULL;
693  if( c == delayfocus_client )
694  cancelDelayFocus();
695 
696  updateStackingOrder( true );
697 
698  if (tab_grab)
699  tab_box->repaint();
700 
701  updateClientArea();
702  }
703 
704 void Workspace::updateFocusChains( Client* c, FocusChainChange change )
705  {
706  if( !c->wantsTabFocus()) // doesn't want tab focus, remove
707  {
708  for( int i=1;
709  i<= numberOfDesktops();
710  ++i )
711  focus_chain[i].remove(c);
712  global_focus_chain.remove( c );
713  return;
714  }
715  if(c->desktop() == NET::OnAllDesktops)
716  { //now on all desktops, add it to focus_chains it is not already in
717  for( int i=1; i<= numberOfDesktops(); i++)
718  { // making first/last works only on current desktop, don't affect all desktops
719  if( i == currentDesktop()
720  && ( change == FocusChainMakeFirst || change == FocusChainMakeLast ))
721  {
722  focus_chain[ i ].remove( c );
723  if( change == FocusChainMakeFirst )
724  focus_chain[ i ].append( c );
725  else
726  focus_chain[ i ].prepend( c );
727  }
728  else if( !focus_chain[ i ].contains( c ))
729  { // add it after the active one
730  if( active_client != NULL && active_client != c
731  && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
732  focus_chain[ i ].insert( focus_chain[ i ].fromLast(), c );
733  else
734  focus_chain[ i ].append( c ); // otherwise add as the first one
735  }
736  }
737  }
738  else //now only on desktop, remove it anywhere else
739  {
740  for( int i=1; i<= numberOfDesktops(); i++)
741  {
742  if( i == c->desktop())
743  {
744  if( change == FocusChainMakeFirst )
745  {
746  focus_chain[ i ].remove( c );
747  focus_chain[ i ].append( c );
748  }
749  else if( change == FocusChainMakeLast )
750  {
751  focus_chain[ i ].remove( c );
752  focus_chain[ i ].prepend( c );
753  }
754  else if( !focus_chain[ i ].contains( c ))
755  {
756  if( active_client != NULL && active_client != c
757  && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
758  focus_chain[ i ].insert( focus_chain[ i ].fromLast(), c );
759  else
760  focus_chain[ i ].append( c ); // otherwise add as the first one
761  }
762  }
763  else
764  focus_chain[ i ].remove( c );
765  }
766  }
767  if( change == FocusChainMakeFirst )
768  {
769  global_focus_chain.remove( c );
770  global_focus_chain.append( c );
771  }
772  else if( change == FocusChainMakeLast )
773  {
774  global_focus_chain.remove( c );
775  global_focus_chain.prepend( c );
776  }
777  else if( !global_focus_chain.contains( c ))
778  {
779  if( active_client != NULL && active_client != c
780  && !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client )
781  global_focus_chain.insert( global_focus_chain.fromLast(), c );
782  else
783  global_focus_chain.append( c ); // otherwise add as the first one
784  }
785  }
786 
787 void Workspace::updateOverlappingShadows(unsigned long window)
788  {
789  Client *client;
790 
791  if ((client = findClient(WindowMatchPredicate((WId)window))))
792  // Redraw overlapping shadows without waiting for the specified window
793  // to redraw its own shadow
794  client->drawOverlappingShadows(false);
795  }
796 
797 void Workspace::setShadowed(unsigned long window, bool shadowed)
798  {
799  Client *client;
800 
801  if ((client = findClient(WindowMatchPredicate((WId)window))))
802  client->setShadowed(shadowed);
803  }
804 
805 void Workspace::updateCurrentTopMenu()
806  {
807  if( !managingTopMenus())
808  return;
809  // toplevel menubar handling
810  Client* menubar = 0;
811  bool block_desktop_menubar = false;
812  if( active_client )
813  {
814  // show the new menu bar first...
815  Client* menu_client = active_client;
816  for(;;)
817  {
818  if( menu_client->isFullScreen())
819  block_desktop_menubar = true;
820  for( ClientList::ConstIterator it = menu_client->transients().begin();
821  it != menu_client->transients().end();
822  ++it )
823  if( (*it)->isTopMenu())
824  {
825  menubar = *it;
826  break;
827  }
828  if( menubar != NULL || !menu_client->isTransient())
829  break;
830  if( menu_client->isModal() || menu_client->transientFor() == NULL )
831  break; // don't use mainwindow's menu if this is modal or group transient
832  menu_client = menu_client->transientFor();
833  }
834  if( !menubar )
835  { // try to find any topmenu from the application (#72113)
836  for( ClientList::ConstIterator it = active_client->group()->members().begin();
837  it != active_client->group()->members().end();
838  ++it )
839  if( (*it)->isTopMenu())
840  {
841  menubar = *it;
842  break;
843  }
844  }
845  }
846  if( !menubar && !block_desktop_menubar && options->desktopTopMenu())
847  {
848  // Find the menubar of the desktop
849  Client* desktop = findDesktop( true, currentDesktop());
850  if( desktop != NULL )
851  {
852  for( ClientList::ConstIterator it = desktop->transients().begin();
853  it != desktop->transients().end();
854  ++it )
855  if( (*it)->isTopMenu())
856  {
857  menubar = *it;
858  break;
859  }
860  }
861  // TODO to be cleaned app with window grouping
862  // Without qt-copy patch #0009, the topmenu and desktop are not in the same group,
863  // thus the topmenu is not transient for it :-/.
864  if( menubar == NULL )
865  {
866  for( ClientList::ConstIterator it = topmenus.begin();
867  it != topmenus.end();
868  ++it )
869  if( (*it)->wasOriginallyGroupTransient()) // kdesktop's topmenu has WM_TRANSIENT_FOR
870  { // set pointing to the root window
871  menubar = *it; // to recognize it here
872  break; // Also, with the xroot hack in kdesktop,
873  } // there's no NET::Desktop window to be transient for
874  }
875  }
876 
877 // kdDebug() << "CURRENT TOPMENU:" << menubar << ":" << active_client << endl;
878  if ( menubar )
879  {
880  if( active_client && !menubar->isOnDesktop( active_client->desktop()))
881  menubar->setDesktop( active_client->desktop());
882  menubar->hideClient( false );
883  topmenu_space->hide();
884  // make it appear like it's been raised manually - it's in the Dock layer anyway,
885  // and not raising it could mess up stacking order of topmenus within one application,
886  // and thus break raising of mainclients in raiseClient()
887  unconstrained_stacking_order.remove( menubar );
888  unconstrained_stacking_order.append( menubar );
889  }
890  else if( !block_desktop_menubar )
891  { // no topmenu active - show the space window, so that there's not empty space
892  topmenu_space->show();
893  }
894 
895  // ... then hide the other ones. Avoids flickers.
896  for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
897  {
898  if( (*it)->isTopMenu() && (*it) != menubar )
899  (*it)->hideClient( true );
900  }
901  }
902 
903 
904 void Workspace::updateToolWindows( bool also_hide )
905  {
906  // TODO what if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
907  if( !options->hideUtilityWindowsForInactive )
908  {
909  for( ClientList::ConstIterator it = clients.begin();
910  it != clients.end();
911  ++it )
912  (*it)->hideClient( false );
913  return;
914  }
915  const Group* group = NULL;
916  const Client* client = active_client;
917 // Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow
918 // will be shown; if a group transient is group, all tools in the group will be shown
919  while( client != NULL )
920  {
921  if( !client->isTransient())
922  break;
923  if( client->groupTransient())
924  {
925  group = client->group();
926  break;
927  }
928  client = client->transientFor();
929  }
930  // use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0,
931  // i.e. if it's not up to date
932 
933  // SELI but maybe it should - what if a new client has been added that's not in stacking order yet?
934  ClientList to_show, to_hide;
935  for( ClientList::ConstIterator it = stacking_order.begin();
936  it != stacking_order.end();
937  ++it )
938  {
939  if( (*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar())
940  {
941  bool show = true;
942  if( !(*it)->isTransient())
943  {
944  if( (*it)->group()->members().count() == 1 ) // has its own group, keep always visible
945  show = true;
946  else if( client != NULL && (*it)->group() == client->group())
947  show = true;
948  else
949  show = false;
950  }
951  else
952  {
953  if( group != NULL && (*it)->group() == group )
954  show = true;
955  else if( client != NULL && client->hasTransient( (*it), true ))
956  show = true;
957  else
958  show = false;
959  }
960  if( !show && also_hide )
961  {
962  const ClientList mainclients = (*it)->mainClients();
963  // don't hide utility windows which are standalone(?) or
964  // have e.g. kicker as mainwindow
965  if( mainclients.isEmpty())
966  show = true;
967  for( ClientList::ConstIterator it2 = mainclients.begin();
968  it2 != mainclients.end();
969  ++it2 )
970  {
971  if( (*it2)->isSpecialWindow())
972  show = true;
973  }
974  if( !show )
975  to_hide.append( *it );
976  }
977  if( show )
978  to_show.append( *it );
979  }
980  } // first show new ones, then hide
981  for( ClientList::ConstIterator it = to_show.fromLast();
982  it != to_show.end();
983  --it ) // from topmost
984  // TODO since this is in stacking order, the order of taskbar entries changes :(
985  (*it)->hideClient( false );
986  if( also_hide )
987  {
988  for( ClientList::ConstIterator it = to_hide.begin();
989  it != to_hide.end();
990  ++it ) // from bottommost
991  (*it)->hideClient( true );
992  updateToolWindowsTimer.stop();
993  }
994  else // setActiveClient() is after called with NULL client, quickly followed
995  { // by setting a new client, which would result in flickering
996  updateToolWindowsTimer.start( 50, true );
997  }
998  }
999 
1000 void Workspace::slotUpdateToolWindows()
1001  {
1002  updateToolWindows( true );
1003  }
1004 
1008 void Workspace::updateColormap()
1009  {
1010  Colormap cmap = default_colormap;
1011  if ( activeClient() && activeClient()->colormap() != None )
1012  cmap = activeClient()->colormap();
1013  if ( cmap != installed_colormap )
1014  {
1015  XInstallColormap(tqt_xdisplay(), cmap );
1016  installed_colormap = cmap;
1017  }
1018  }
1019 
1020 void Workspace::reconfigure()
1021  {
1022  reconfigureTimer.start(200, true);
1023  }
1024 
1025 
1026 void Workspace::slotSettingsChanged(int category)
1027  {
1028  kdDebug(1212) << "Workspace::slotSettingsChanged()" << endl;
1029  if( category == (int) TDEApplication::SETTINGS_SHORTCUTS )
1030  readShortcuts();
1031  }
1032 
1036 KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
1037 
1038 void Workspace::slotReconfigure()
1039  {
1040  kdDebug(1212) << "Workspace::slotReconfigure()" << endl;
1041  reconfigureTimer.stop();
1042 
1043  TDEGlobal::config()->reparseConfiguration();
1044  unsigned long changed = options->updateSettings();
1045  tab_box->reconfigure();
1046  popupinfo->reconfigure();
1047  initPositioning->reinitCascading( 0 );
1048  readShortcuts();
1049  forEachClient( CheckIgnoreFocusStealingProcedure());
1050  updateToolWindows( true );
1051 
1052  if( mgr->reset( changed ))
1053  { // decorations need to be recreated
1054 #if 0 // This actually seems to make things worse now
1055  TQWidget curtain;
1056  curtain.setBackgroundMode( NoBackground );
1057  curtain.setGeometry( TQApplication::desktop()->geometry() );
1058  curtain.show();
1059 #endif
1060  for( ClientList::ConstIterator it = clients.begin();
1061  it != clients.end();
1062  ++it )
1063  {
1064  (*it)->updateDecoration( true, true );
1065  }
1066  mgr->destroyPreviousPlugin();
1067  }
1068  else
1069  {
1070  forEachClient( CheckBorderSizesProcedure());
1071  }
1072 
1073  checkElectricBorders();
1074 
1075  if( options->topMenuEnabled() && !managingTopMenus())
1076  {
1077  if( topmenu_selection->claim( false ))
1078  setupTopMenuHandling();
1079  else
1080  lostTopMenuSelection();
1081  }
1082  else if( !options->topMenuEnabled() && managingTopMenus())
1083  {
1084  topmenu_selection->release();
1085  lostTopMenuSelection();
1086  }
1087  topmenu_height = 0; // invalidate used menu height
1088  if( managingTopMenus())
1089  {
1090  updateTopMenuGeometry();
1091  updateCurrentTopMenu();
1092  }
1093 
1094  loadWindowRules();
1095  for( ClientList::Iterator it = clients.begin();
1096  it != clients.end();
1097  ++it )
1098  {
1099  (*it)->setupWindowRules( true );
1100  (*it)->applyWindowRules();
1101  discardUsedWindowRules( *it, false );
1102  }
1103 
1104  if (options->resetKompmgr) // need restart
1105  {
1106  bool tmp = options->useTranslucency;
1107 
1108  // If compton-tde is already running, sending SIGUSR2 will force a reload of its settings
1109  // Attempt to load the compton-tde pid file
1110  char *filename;
1111  const char *pidfile = "compton-tde.pid";
1112  char uidstr[sizeof(uid_t)*8+1];
1113  sprintf(uidstr, "%d", getuid());
1114  int n = strlen(P_tmpdir)+strlen(uidstr)+strlen(pidfile)+3;
1115  filename = (char*)malloc(n*sizeof(char)+1);
1116  memset(filename,0,n);
1117  strcat(filename, P_tmpdir);
1118  strcat(filename, "/.");
1119  strcat(filename, uidstr);
1120  strcat(filename, "-");
1121  strcat(filename, pidfile);
1122 
1123  // Now that we did all that by way of introduction...read the file!
1124  FILE *pFile;
1125  char buffer[255];
1126  pFile = fopen(filename, "r");
1127  int kompmgrpid = 0;
1128  if (pFile)
1129  {
1130  printf("[twin-workspace] Using '%s' as compton-tde pidfile\n\n", filename);
1131  // obtain file size
1132  fseek (pFile , 0 , SEEK_END);
1133  unsigned long lSize = ftell (pFile);
1134  if (lSize > 254)
1135  lSize = 254;
1136  rewind (pFile);
1137  size_t result = fread (buffer, 1, lSize, pFile);
1138  fclose(pFile);
1139  if (result > 0)
1140  {
1141  kompmgrpid = atoi(buffer);
1142  }
1143  }
1144 
1145  free(filename);
1146  filename = NULL;
1147 
1148  if (tmp)
1149  {
1150  if (kompmgrpid)
1151  {
1152  kill(kompmgrpid, SIGUSR2);
1153  }
1154  else
1155  {
1156  stopKompmgr();
1157  if (!kompmgr)
1158  {
1159  kompmgr = new TDEProcess;
1160  connect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
1161  *kompmgr << TDE_COMPOSITOR_BINARY;
1162  }
1163  TQTimer::singleShot( 200, this, TQT_SLOT(startKompmgr()) ); // wait some time to ensure system's ready for restart
1164  }
1165  }
1166  else
1167  {
1168  if (kompmgrpid)
1169  {
1170  kill(kompmgrpid, SIGTERM);
1171  }
1172  else
1173  {
1174  stopKompmgr();
1175  }
1176  }
1177  }
1178  }
1179 
1180 void Workspace::loadDesktopSettings()
1181  {
1182  TDEConfig* c = TDEGlobal::config();
1183  TQCString groupname;
1184  if (screen_number == 0)
1185  groupname = "Desktops";
1186  else
1187  groupname.sprintf("Desktops-screen-%d", screen_number);
1188  TDEConfigGroupSaver saver(c,groupname);
1189 
1190  int n = c->readNumEntry("Number", 4);
1191  number_of_desktops = n;
1192  delete workarea;
1193  workarea = new TQRect[ n + 1 ];
1194  delete screenarea;
1195  screenarea = NULL;
1196  rootInfo->setNumberOfDesktops( number_of_desktops );
1197  desktop_focus_chain.resize( n );
1198  // make it +1, so that it can be accessed as [1..numberofdesktops]
1199  focus_chain.resize( n + 1 );
1200  for(int i = 1; i <= n; i++)
1201  {
1202  TQString s = c->readEntry(TQString("Name_%1").arg(i),
1203  i18n("Desktop %1").arg(i));
1204  rootInfo->setDesktopName( i, s.utf8().data() );
1205  desktop_focus_chain[i-1] = i;
1206  }
1207  }
1208 
1209 void Workspace::saveDesktopSettings()
1210  {
1211  TDEConfig* c = TDEGlobal::config();
1212  TQCString groupname;
1213  if (screen_number == 0)
1214  groupname = "Desktops";
1215  else
1216  groupname.sprintf("Desktops-screen-%d", screen_number);
1217  TDEConfigGroupSaver saver(c,groupname);
1218 
1219  c->writeEntry("Number", number_of_desktops );
1220  for(int i = 1; i <= number_of_desktops; i++)
1221  {
1222  TQString s = desktopName( i );
1223  TQString defaultvalue = i18n("Desktop %1").arg(i);
1224  if ( s.isEmpty() )
1225  {
1226  s = defaultvalue;
1227  rootInfo->setDesktopName( i, s.utf8().data() );
1228  }
1229 
1230  if (s != defaultvalue)
1231  {
1232  c->writeEntry( TQString("Name_%1").arg(i), s );
1233  }
1234  else
1235  {
1236  TQString currentvalue = c->readEntry(TQString("Name_%1").arg(i));
1237  if (currentvalue != defaultvalue)
1238  c->writeEntry( TQString("Name_%1").arg(i), "" );
1239  }
1240  }
1241  }
1242 
1243 TQStringList Workspace::configModules(bool controlCenter)
1244  {
1245  TQStringList args;
1246  args << "tde-twindecoration.desktop";
1247  if (controlCenter)
1248  args << "tde-twinoptions.desktop";
1249  else if (kapp->authorizeControlModule("tde-twinoptions.desktop"))
1250  args << "twinactions" << "twinfocus" << "twinmoving" << "twinadvanced" << "twinrules" << "twintranslucency";
1251  return args;
1252  }
1253 
1254 void Workspace::configureWM()
1255  {
1256  TDEApplication::tdeinitExec( "tdecmshell", configModules(false) );
1257  }
1258 
1262 void Workspace::doNotManage( TQString title )
1263  {
1264  doNotManageList.append( title );
1265  }
1266 
1270 bool Workspace::isNotManaged( const TQString& title )
1271  {
1272  for ( TQStringList::Iterator it = doNotManageList.begin(); it != doNotManageList.end(); ++it )
1273  {
1274  TQRegExp r( (*it) );
1275  if (r.search(title) != -1)
1276  {
1277  doNotManageList.remove( it );
1278  return TRUE;
1279  }
1280  }
1281  return FALSE;
1282  }
1283 
1287 void Workspace::refresh()
1288  {
1289  TQWidget w;
1290  w.setGeometry( TQApplication::desktop()->geometry() );
1291  w.show();
1292  w.hide();
1293  TQApplication::flushX();
1294  }
1295 
1303 class ObscuringWindows
1304  {
1305  public:
1306  ~ObscuringWindows();
1307  void create( Client* c );
1308  private:
1309  TQValueList<Window> obscuring_windows;
1310  static TQValueList<Window>* cached;
1311  static unsigned int max_cache_size;
1312  };
1313 
1314 TQValueList<Window>* ObscuringWindows::cached = 0;
1315 unsigned int ObscuringWindows::max_cache_size = 0;
1316 
1317 void ObscuringWindows::create( Client* c )
1318  {
1319  if( cached == 0 )
1320  cached = new TQValueList<Window>;
1321  Window obs_win;
1322  XWindowChanges chngs;
1323  int mask = CWSibling | CWStackMode;
1324  if( cached->count() > 0 )
1325  {
1326  cached->remove( obs_win = cached->first());
1327  chngs.x = c->x();
1328  chngs.y = c->y();
1329  chngs.width = c->width();
1330  chngs.height = c->height();
1331  mask |= CWX | CWY | CWWidth | CWHeight;
1332  }
1333  else
1334  {
1335  XSetWindowAttributes a;
1336  a.background_pixmap = None;
1337  a.override_redirect = True;
1338  obs_win = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), c->x(), c->y(),
1339  c->width(), c->height(), 0, CopyFromParent, InputOutput,
1340  CopyFromParent, CWBackPixmap | CWOverrideRedirect, &a );
1341  }
1342  chngs.sibling = c->frameId();
1343  chngs.stack_mode = Below;
1344  XConfigureWindow( tqt_xdisplay(), obs_win, mask, &chngs );
1345  XMapWindow( tqt_xdisplay(), obs_win );
1346  obscuring_windows.append( obs_win );
1347  }
1348 
1349 ObscuringWindows::~ObscuringWindows()
1350  {
1351  max_cache_size = TQMAX( max_cache_size, obscuring_windows.count() + 4 ) - 1;
1352  for( TQValueList<Window>::ConstIterator it = obscuring_windows.begin();
1353  it != obscuring_windows.end();
1354  ++it )
1355  {
1356  XUnmapWindow( tqt_xdisplay(), *it );
1357  if( cached->count() < max_cache_size )
1358  cached->prepend( *it );
1359  else
1360  XDestroyWindow( tqt_xdisplay(), *it );
1361  }
1362  }
1363 
1364 
1371 bool Workspace::setCurrentDesktop( int new_desktop )
1372  {
1373  if (new_desktop < 1 || new_desktop > number_of_desktops )
1374  return false;
1375 
1376  closeActivePopup();
1377  ++block_focus;
1378 // TODO Q_ASSERT( block_stacking_updates == 0 ); // make sure stacking_order is up to date
1379  StackingUpdatesBlocker blocker( this );
1380 
1381  int old_desktop = current_desktop;
1382  if (new_desktop != current_desktop)
1383  {
1384  ++block_showing_desktop;
1385  /*
1386  optimized Desktop switching: unmapping done from back to front
1387  mapping done from front to back => less exposure events
1388  */
1389  Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop));
1390 
1391  ObscuringWindows obs_wins;
1392 
1393  current_desktop = new_desktop; // change the desktop (so that Client::updateVisibility() works)
1394 
1395  bool desktopHasCompositing = kapp->isCompositionManagerAvailable(); // Technically I should call isX11CompositionAvailable(), but it isn't initialized via my kapp constructir, and in this case it doesn't really matter anyway....
1396  if (!desktopHasCompositing) {
1397  // If composition is not in use then we can hide the old windows before showing the new ones
1398  for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
1399  if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
1400  {
1401  if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop )) {
1402  obs_wins.create( *it );
1403  }
1404  (*it)->updateVisibility();
1405  }
1406  }
1407  }
1408 
1409  rootInfo->setCurrentDesktop( current_desktop ); // now propagate the change, after hiding, before showing
1410 
1411  if( movingClient && !movingClient->isOnDesktop( new_desktop ))
1412  movingClient->setDesktop( new_desktop );
1413 
1414  for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
1415  if ( (*it)->isOnDesktop( new_desktop ) ) {
1416  (*it)->updateVisibility();
1417  }
1418  }
1419 
1420  if (desktopHasCompositing) {
1421  // If composition is in use then we cannot hide the old windows before showing the new ones,
1422  // unless you happen to like the "flicker annoyingly to desktop" effect... :-P
1423  XSync( tqt_xdisplay(), false); // Make absolutely certain all new windows are shown before hiding the old ones
1424  for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
1425  if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
1426  {
1427  if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop )) {
1428  obs_wins.create( *it );
1429  }
1430  (*it)->updateVisibility();
1431  }
1432  }
1433  }
1434 
1435  --block_showing_desktop;
1436  if( showingDesktop()) // do this only after desktop change to avoid flicker
1437  resetShowingDesktop( false );
1438  }
1439 
1440  // restore the focus on this desktop
1441  --block_focus;
1442  Client* c = 0;
1443 
1444  if ( options->focusPolicyIsReasonable())
1445  {
1446  // Search in focus chain
1447  if ( movingClient != NULL && active_client == movingClient
1448  && focus_chain[currentDesktop()].contains( active_client )
1449  && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
1450  {
1451  c = active_client; // the requestFocus below will fail, as the client is already active
1452  }
1453  if ( !c )
1454  {
1455  for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast();
1456  it != focus_chain[currentDesktop()].end();
1457  --it )
1458  {
1459  if ( (*it)->isShown( false ) && (*it)->isOnCurrentDesktop())
1460  {
1461  c = *it;
1462  break;
1463  }
1464  }
1465  }
1466  }
1467 
1468  //if "unreasonable focus policy"
1469  // and active_client is on_all_desktops and under mouse (hence == old_active_client),
1470  // conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>)
1471  else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
1472  c = active_client;
1473 
1474  if( c == NULL && !desktops.isEmpty())
1475  c = findDesktop( true, currentDesktop());
1476 
1477  if( c != active_client )
1478  setActiveClient( NULL, Allowed );
1479 
1480  if ( c )
1481  requestFocus( c );
1482  else
1483  focusToNull();
1484 
1485  updateCurrentTopMenu();
1486 
1487  // Update focus chain:
1488  // If input: chain = { 1, 2, 3, 4 } and current_desktop = 3,
1489  // Output: chain = { 3, 1, 2, 4 }.
1490 // kdDebug(1212) << TQString("Switching to desktop #%1, at focus_chain[currentDesktop()] index %2\n")
1491 // .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() ));
1492  for( int i = desktop_focus_chain.find( currentDesktop() ); i > 0; i-- )
1493  desktop_focus_chain[i] = desktop_focus_chain[i-1];
1494  desktop_focus_chain[0] = currentDesktop();
1495 
1496 // TQString s = "desktop_focus_chain[] = { ";
1497 // for( uint i = 0; i < desktop_focus_chain.size(); i++ )
1498 // s += TQString::number(desktop_focus_chain[i]) + ", ";
1499 // kdDebug(1212) << s << "}\n";
1500 
1501  if( old_desktop != 0 ) // not for the very first time
1502  popupinfo->showInfo( desktopName(currentDesktop()) );
1503  return true;
1504  }
1505 
1506 // called only from DCOP
1507 void Workspace::nextDesktop()
1508  {
1509  int desktop = currentDesktop() + 1;
1510  setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
1511  }
1512 
1513 // called only from DCOP
1514 void Workspace::previousDesktop()
1515  {
1516  int desktop = currentDesktop() - 1;
1517  setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
1518  }
1519 
1520 int Workspace::desktopToRight( int desktop ) const
1521  {
1522  int x,y;
1523  calcDesktopLayout(x,y);
1524  int dt = desktop-1;
1525  if (layoutOrientation == Qt::Vertical)
1526  {
1527  dt += y;
1528  if ( dt >= numberOfDesktops() )
1529  {
1530  if ( options->rollOverDesktops )
1531  dt -= numberOfDesktops();
1532  else
1533  return desktop;
1534  }
1535  }
1536  else
1537  {
1538  int d = (dt % x) + 1;
1539  if ( d >= x )
1540  {
1541  if ( options->rollOverDesktops )
1542  d -= x;
1543  else
1544  return desktop;
1545  }
1546  dt = dt - (dt % x) + d;
1547  }
1548  return dt+1;
1549  }
1550 
1551 int Workspace::desktopToLeft( int desktop ) const
1552  {
1553  int x,y;
1554  calcDesktopLayout(x,y);
1555  int dt = desktop-1;
1556  if (layoutOrientation == Qt::Vertical)
1557  {
1558  dt -= y;
1559  if ( dt < 0 )
1560  {
1561  if ( options->rollOverDesktops )
1562  dt += numberOfDesktops();
1563  else
1564  return desktop;
1565  }
1566  }
1567  else
1568  {
1569  int d = (dt % x) - 1;
1570  if ( d < 0 )
1571  {
1572  if ( options->rollOverDesktops )
1573  d += x;
1574  else
1575  return desktop;
1576  }
1577  dt = dt - (dt % x) + d;
1578  }
1579  return dt+1;
1580  }
1581 
1582 int Workspace::desktopUp( int desktop ) const
1583  {
1584  int x,y;
1585  calcDesktopLayout(x,y);
1586  int dt = desktop-1;
1587  if (layoutOrientation == Qt::Horizontal)
1588  {
1589  dt -= x;
1590  if ( dt < 0 )
1591  {
1592  if ( options->rollOverDesktops )
1593  dt += numberOfDesktops();
1594  else
1595  return desktop;
1596  }
1597  }
1598  else
1599  {
1600  int d = (dt % y) - 1;
1601  if ( d < 0 )
1602  {
1603  if ( options->rollOverDesktops )
1604  d += y;
1605  else
1606  return desktop;
1607  }
1608  dt = dt - (dt % y) + d;
1609  }
1610  return dt+1;
1611  }
1612 
1613 int Workspace::desktopDown( int desktop ) const
1614  {
1615  int x,y;
1616  calcDesktopLayout(x,y);
1617  int dt = desktop-1;
1618  if (layoutOrientation == Qt::Horizontal)
1619  {
1620  dt += x;
1621  if ( dt >= numberOfDesktops() )
1622  {
1623  if ( options->rollOverDesktops )
1624  dt -= numberOfDesktops();
1625  else
1626  return desktop;
1627  }
1628  }
1629  else
1630  {
1631  int d = (dt % y) + 1;
1632  if ( d >= y )
1633  {
1634  if ( options->rollOverDesktops )
1635  d -= y;
1636  else
1637  return desktop;
1638  }
1639  dt = dt - (dt % y) + d;
1640  }
1641  return dt+1;
1642  }
1643 
1644 
1648 void Workspace::setNumberOfDesktops( int n )
1649  {
1650  if ( n == number_of_desktops )
1651  return;
1652  int old_number_of_desktops = number_of_desktops;
1653  number_of_desktops = n;
1654 
1655  if( currentDesktop() > numberOfDesktops())
1656  setCurrentDesktop( numberOfDesktops());
1657 
1658  // if increasing the number, do the resizing now,
1659  // otherwise after the moving of windows to still existing desktops
1660  if( old_number_of_desktops < number_of_desktops )
1661  {
1662  rootInfo->setNumberOfDesktops( number_of_desktops );
1663  NETPoint* viewports = new NETPoint[ number_of_desktops ];
1664  rootInfo->setDesktopViewport( number_of_desktops, *viewports );
1665  delete[] viewports;
1666  updateClientArea( true );
1667  focus_chain.resize( number_of_desktops + 1 );
1668  }
1669 
1670  // if the number of desktops decreased, move all
1671  // windows that would be hidden to the last visible desktop
1672  if( old_number_of_desktops > number_of_desktops )
1673  {
1674  for( ClientList::ConstIterator it = clients.begin();
1675  it != clients.end();
1676  ++it)
1677  {
1678  if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
1679  sendClientToDesktop( *it, numberOfDesktops(), true );
1680  }
1681  }
1682  if( old_number_of_desktops > number_of_desktops )
1683  {
1684  rootInfo->setNumberOfDesktops( number_of_desktops );
1685  NETPoint* viewports = new NETPoint[ number_of_desktops ];
1686  rootInfo->setDesktopViewport( number_of_desktops, *viewports );
1687  delete[] viewports;
1688  updateClientArea( true );
1689  focus_chain.resize( number_of_desktops + 1 );
1690  }
1691 
1692  saveDesktopSettings();
1693 
1694  // Resize and reset the desktop focus chain.
1695  desktop_focus_chain.resize( n );
1696  for( int i = 0; i < (int)desktop_focus_chain.size(); i++ )
1697  desktop_focus_chain[i] = i+1;
1698  }
1699 
1705 void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
1706  {
1707  bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
1708  c->setDesktop( desk );
1709  if ( c->desktop() != desk ) // no change or desktop forced
1710  return;
1711  desk = c->desktop(); // Client did range checking
1712 
1713  if ( c->isOnDesktop( currentDesktop() ) )
1714  {
1715  if ( c->wantsTabFocus() && options->focusPolicyIsReasonable()
1716  && !was_on_desktop // for stickyness changes
1717  && !dont_activate )
1718  requestFocus( c );
1719  else
1720  restackClientUnderActive( c );
1721  }
1722  else
1723  {
1724  raiseClient( c );
1725  }
1726 
1727  ClientList transients_stacking_order = ensureStackingOrder( c->transients());
1728  for( ClientList::ConstIterator it = transients_stacking_order.begin();
1729  it != transients_stacking_order.end();
1730  ++it )
1731  sendClientToDesktop( *it, desk, dont_activate );
1732  updateClientArea();
1733  }
1734 
1735 int Workspace::numScreens() const
1736  {
1737  if( !options->xineramaEnabled )
1738  return 0;
1739  return tqApp->desktop()->numScreens();
1740  }
1741 
1742 int Workspace::activeScreen() const
1743  {
1744  if( !options->xineramaEnabled )
1745  return 0;
1746  if( !options->activeMouseScreen )
1747  {
1748  if( activeClient() != NULL && !activeClient()->isOnScreen( active_screen ))
1749  return tqApp->desktop()->screenNumber( activeClient()->geometry().center());
1750  return active_screen;
1751  }
1752  return tqApp->desktop()->screenNumber( TQCursor::pos());
1753  }
1754 
1755 // check whether a client moved completely out of what's considered the active screen,
1756 // if yes, set a new active screen
1757 void Workspace::checkActiveScreen( const Client* c )
1758  {
1759  if( !options->xineramaEnabled )
1760  return;
1761  if( !c->isActive())
1762  return;
1763  if( !c->isOnScreen( active_screen ))
1764  active_screen = c->screen();
1765  }
1766 
1767 // called e.g. when a user clicks on a window, set active screen to be the screen
1768 // where the click occured
1769 void Workspace::setActiveScreenMouse( TQPoint mousepos )
1770  {
1771  if( !options->xineramaEnabled )
1772  return;
1773  active_screen = tqApp->desktop()->screenNumber( mousepos );
1774  }
1775 
1776 TQRect Workspace::screenGeometry( int screen ) const
1777  {
1778  if (( !options->xineramaEnabled ) || (kapp->desktop()->numScreens() < 2))
1779  return tqApp->desktop()->geometry();
1780  return tqApp->desktop()->screenGeometry( screen );
1781  }
1782 
1783 int Workspace::screenNumber( TQPoint pos ) const
1784  {
1785  if( !options->xineramaEnabled )
1786  return 0;
1787  return tqApp->desktop()->screenNumber( pos );
1788  }
1789 
1790 void Workspace::sendClientToScreen( Client* c, int screen )
1791  {
1792  if( c->screen() == screen ) // don't use isOnScreen(), that's true even when only partially
1793  return;
1794  GeometryUpdatesPostponer blocker( c );
1795  TQRect old_sarea = clientArea( MaximizeArea, c );
1796  TQRect sarea = clientArea( MaximizeArea, screen, c->desktop());
1797  c->setGeometry( sarea.x() - old_sarea.x() + c->x(), sarea.y() - old_sarea.y() + c->y(),
1798  c->size().width(), c->size().height());
1799  c->checkWorkspacePosition();
1800  ClientList transients_stacking_order = ensureStackingOrder( c->transients());
1801  for( ClientList::ConstIterator it = transients_stacking_order.begin();
1802  it != transients_stacking_order.end();
1803  ++it )
1804  sendClientToScreen( *it, screen );
1805  if( c->isActive())
1806  active_screen = screen;
1807  }
1808 
1809 
1810 void Workspace::setDesktopLayout( int, int, int )
1811  { // DCOP-only, unused
1812  }
1813 
1814 void Workspace::updateDesktopLayout()
1815  {
1816  // rootInfo->desktopLayoutCorner(); // I don't find this worth bothering, feel free to
1817  layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal
1818  ? Qt::Horizontal : Qt::Vertical );
1819  layoutX = rootInfo->desktopLayoutColumnsRows().width();
1820  layoutY = rootInfo->desktopLayoutColumnsRows().height();
1821  if( layoutX == 0 && layoutY == 0 ) // not given, set default layout
1822  layoutY = 2;
1823  }
1824 
1825 void Workspace::calcDesktopLayout(int &x, int &y) const
1826  {
1827  x = layoutX; // <= 0 means compute it from the other and total number of desktops
1828  y = layoutY;
1829  if((x <= 0) && (y > 0))
1830  x = (numberOfDesktops()+y-1) / y;
1831  else if((y <=0) && (x > 0))
1832  y = (numberOfDesktops()+x-1) / x;
1833 
1834  if(x <=0)
1835  x = 1;
1836  if (y <= 0)
1837  y = 1;
1838  }
1839 
1844 bool Workspace::addSystemTrayWin( WId w )
1845  {
1846  if ( systemTrayWins.contains( w ) )
1847  return TRUE;
1848 
1849  NETWinInfo ni( tqt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
1850  WId trayWinFor = ni.kdeSystemTrayWinFor();
1851  if ( !trayWinFor )
1852  return FALSE;
1853  systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
1854  XSelectInput( tqt_xdisplay(), w,
1855  StructureNotifyMask
1856  );
1857  XAddToSaveSet( tqt_xdisplay(), w );
1858  propagateSystemTrayWins();
1859  return TRUE;
1860  }
1861 
1866 bool Workspace::removeSystemTrayWin( WId w, bool check )
1867  {
1868  if ( !systemTrayWins.contains( w ) )
1869  return FALSE;
1870  if( check )
1871  {
1872  // When getting UnmapNotify, it's not clear if it's the systray
1873  // reparenting the window into itself, or if it's the window
1874  // going away. This is obviously a flaw in the design, and we were
1875  // just lucky it worked for so long. Kicker's systray temporarily
1876  // sets _TDE_SYSTEM_TRAY_EMBEDDING property on the window while
1877  // embedding it, allowing KWin to figure out. Kicker just mustn't
1878  // crash before removing it again ... *shrug* .
1879  int num_props;
1880  Atom* props = XListProperties( tqt_xdisplay(), w, &num_props );
1881  if( props != NULL )
1882  {
1883  for( int i = 0;
1884  i < num_props;
1885  ++i )
1886  if( props[ i ] == atoms->kde_system_tray_embedding )
1887  {
1888  XFree( props );
1889  return false;
1890  }
1891  XFree( props );
1892  }
1893  }
1894  systemTrayWins.remove( w );
1895  XRemoveFromSaveSet (tqt_xdisplay (), w);
1896  propagateSystemTrayWins();
1897  return TRUE;
1898  }
1899 
1900 
1904 void Workspace::propagateSystemTrayWins()
1905  {
1906  Window *cl = new Window[ systemTrayWins.count()];
1907 
1908  int i = 0;
1909  for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it )
1910  {
1911  cl[i++] = (*it).win;
1912  }
1913 
1914  rootInfo->setKDESystemTrayWindows( cl, i );
1915  delete [] cl;
1916  }
1917 
1918 
1919 void Workspace::killWindowId( Window window_to_kill )
1920  {
1921  if( window_to_kill == None )
1922  return;
1923  Window window = window_to_kill;
1924  Client* client = NULL;
1925  for(;;)
1926  {
1927  client = findClient( FrameIdMatchPredicate( window ));
1928  if( client != NULL ) // found the client
1929  break;
1930  Window parent = 0L;
1931  Window root = 0L;
1932  Window* children = 0L;
1933  unsigned int children_count;
1934  XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
1935  if( children != NULL )
1936  XFree( children );
1937  if( window == root ) // we didn't find the client, probably an override-redirect window
1938  break;
1939  window = parent; // go up
1940  if( window == 0L )
1941  break;
1942  }
1943  if( client != NULL )
1944  client->killWindow();
1945  else
1946  XKillClient( tqt_xdisplay(), window_to_kill );
1947  }
1948 
1949 void Workspace::suspendWindowId( Window window_to_suspend )
1950  {
1951  if( window_to_suspend == None )
1952  return;
1953  Window window = window_to_suspend;
1954  Client* client = NULL;
1955  for(;;)
1956  {
1957  client = findClient( FrameIdMatchPredicate( window ));
1958  if( client != NULL ) // found the client
1959  break;
1960  Window parent = 0L;
1961  Window root = 0L;
1962  Window* children = 0L;
1963  unsigned int children_count;
1964  XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
1965  if( children != NULL )
1966  XFree( children );
1967  if( window == root ) // we didn't find the client, probably an override-redirect window
1968  break;
1969  window = parent; // go up
1970  if( window == 0L )
1971  break;
1972  }
1973  if( client != NULL )
1974  client->suspendWindow();
1975  else
1976  return;
1977  }
1978 
1979 void Workspace::resumeWindowId( Window window_to_resume )
1980  {
1981  if( window_to_resume == None )
1982  return;
1983  Window window = window_to_resume;
1984  Client* client = NULL;
1985  for(;;)
1986  {
1987  client = findClient( FrameIdMatchPredicate( window ));
1988  if( client != NULL ) // found the client
1989  break;
1990  Window parent = 0L;
1991  Window root = 0L;
1992  Window* children = 0L;
1993  unsigned int children_count;
1994  XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
1995  if( children != NULL )
1996  XFree( children );
1997  if( window == root ) // we didn't find the client, probably an override-redirect window
1998  break;
1999  window = parent; // go up
2000  if( window == 0L )
2001  break;
2002  }
2003  if( client != NULL )
2004  client->resumeWindow();
2005  else
2006  return;
2007  }
2008 
2009 
2010 bool Workspace::isResumeableWindowID( Window window_to_check )
2011  {
2012  if( window_to_check == None )
2013  return false;
2014  Window window = window_to_check;
2015  Client* client = NULL;
2016  for(;;)
2017  {
2018  client = findClient( FrameIdMatchPredicate( window ));
2019  if( client != NULL ) // found the client
2020  break;
2021  Window parent = 0L;
2022  Window root = 0L;
2023  Window* children = 0L;
2024  unsigned int children_count;
2025  XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
2026  if( children != NULL )
2027  XFree( children );
2028  if( window == root ) // we didn't find the client, probably an override-redirect window
2029  break;
2030  window = parent; // go up
2031  if( window == 0L )
2032  break;
2033  }
2034  if( client != NULL )
2035  return client->isResumeable();
2036  else
2037  return false;
2038  }
2039 
2040 
2041 void Workspace::sendPingToWindow( Window window, Time timestamp )
2042  {
2043  rootInfo->sendPing( window, timestamp );
2044  }
2045 
2046 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
2047  {
2048  rootInfo->takeActivity( c->window(), timestamp, flags );
2049  pending_take_activity = c;
2050  }
2051 
2052 
2056 void Workspace::slotGrabWindow()
2057  {
2058  if ( active_client )
2059  {
2060  TQPixmap snapshot = TQPixmap::grabWindow( active_client->frameId() );
2061 
2062  //No XShape - no work.
2063  if( Shape::available())
2064  {
2065  //As the first step, get the mask from XShape.
2066  int count, order;
2067  XRectangle* rects = XShapeGetRectangles( tqt_xdisplay(), active_client->frameId(),
2068  ShapeBounding, &count, &order);
2069  //The ShapeBounding region is the outermost shape of the window;
2070  //ShapeBounding - ShapeClipping is defined to be the border.
2071  //Since the border area is part of the window, we use bounding
2072  // to limit our work region
2073  if (rects)
2074  {
2075  //Create a TQRegion from the rectangles describing the bounding mask.
2076  TQRegion contents;
2077  for (int pos = 0; pos < count; pos++)
2078  contents += TQRegion(rects[pos].x, rects[pos].y,
2079  rects[pos].width, rects[pos].height);
2080  XFree(rects);
2081 
2082  //Create the bounding box.
2083  TQRegion bbox(0, 0, snapshot.width(), snapshot.height());
2084 
2085  //Get the masked away area.
2086  TQRegion maskedAway = bbox - contents;
2087  TQMemArray<TQRect> maskedAwayRects = maskedAway.rects();
2088 
2089  //Construct a bitmap mask from the rectangles
2090  TQBitmap mask( snapshot.width(), snapshot.height());
2091  TQPainter p(&mask);
2092  p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
2093  for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
2094  p.fillRect(maskedAwayRects[pos], Qt::color0);
2095  p.end();
2096  snapshot.setMask(mask);
2097  }
2098  }
2099 
2100  TQClipboard *cb = TQApplication::clipboard();
2101  cb->setPixmap( snapshot );
2102  }
2103  else
2104  slotGrabDesktop();
2105  }
2106 
2110 void Workspace::slotGrabDesktop()
2111  {
2112  TQPixmap p = TQPixmap::grabWindow( tqt_xrootwin() );
2113  TQClipboard *cb = TQApplication::clipboard();
2114  cb->setPixmap( p );
2115  }
2116 
2117 
2121 void Workspace::slotMouseEmulation()
2122  {
2123 
2124  if ( mouse_emulation )
2125  {
2126  XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME());
2127  mouse_emulation = FALSE;
2128  return;
2129  }
2130 
2131  if ( XGrabKeyboard(tqt_xdisplay(),
2132  root, FALSE,
2133  GrabModeAsync, GrabModeAsync,
2134  GET_QT_X_TIME()) == GrabSuccess )
2135  {
2136  mouse_emulation = TRUE;
2137  mouse_emulation_state = 0;
2138  mouse_emulation_window = 0;
2139  }
2140  }
2141 
2148 WId Workspace::getMouseEmulationWindow()
2149  {
2150  Window root;
2151  Window child = tqt_xrootwin();
2152  int root_x, root_y, lx, ly;
2153  uint state;
2154  Window w;
2155  Client * c = 0;
2156  do
2157  {
2158  w = child;
2159  if (!c)
2160  c = findClient( FrameIdMatchPredicate( w ));
2161  XQueryPointer( tqt_xdisplay(), w, &root, &child,
2162  &root_x, &root_y, &lx, &ly, &state );
2163  } while ( child != None && child != w );
2164 
2165  if ( c && !c->isActive() )
2166  activateClient( c );
2167  return (WId) w;
2168  }
2169 
2173 unsigned int Workspace::sendFakedMouseEvent( TQPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
2174  {
2175  if ( !w )
2176  return state;
2177  TQWidget* widget = TQWidget::find( w );
2178  if ( (!widget || widget->inherits(TQTOOLBUTTON_OBJECT_NAME_STRING) ) && !findClient( WindowMatchPredicate( w )) )
2179  {
2180  int x, y;
2181  Window xw;
2182  XTranslateCoordinates( tqt_xdisplay(), tqt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
2183  if ( type == EmuMove )
2184  { // motion notify events
2185  XEvent e;
2186  e.type = MotionNotify;
2187  e.xmotion.window = w;
2188  e.xmotion.root = tqt_xrootwin();
2189  e.xmotion.subwindow = w;
2190  e.xmotion.time = GET_QT_X_TIME();
2191  e.xmotion.x = x;
2192  e.xmotion.y = y;
2193  e.xmotion.x_root = pos.x();
2194  e.xmotion.y_root = pos.y();
2195  e.xmotion.state = state;
2196  e.xmotion.is_hint = NotifyNormal;
2197  XSendEvent( tqt_xdisplay(), w, TRUE, ButtonMotionMask, &e );
2198  }
2199  else
2200  {
2201  XEvent e;
2202  e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
2203  e.xbutton.window = w;
2204  e.xbutton.root = tqt_xrootwin();
2205  e.xbutton.subwindow = w;
2206  e.xbutton.time = GET_QT_X_TIME();
2207  e.xbutton.x = x;
2208  e.xbutton.y = y;
2209  e.xbutton.x_root = pos.x();
2210  e.xbutton.y_root = pos.y();
2211  e.xbutton.state = state;
2212  e.xbutton.button = button;
2213  XSendEvent( tqt_xdisplay(), w, TRUE, ButtonPressMask, &e );
2214 
2215  if ( type == EmuPress )
2216  {
2217  switch ( button )
2218  {
2219  case 2:
2220  state |= Button2Mask;
2221  break;
2222  case 3:
2223  state |= Button3Mask;
2224  break;
2225  default: // 1
2226  state |= Button1Mask;
2227  break;
2228  }
2229  }
2230  else
2231  {
2232  switch ( button )
2233  {
2234  case 2:
2235  state &= ~Button2Mask;
2236  break;
2237  case 3:
2238  state &= ~Button3Mask;
2239  break;
2240  default: // 1
2241  state &= ~Button1Mask;
2242  break;
2243  }
2244  }
2245  }
2246  }
2247  return state;
2248  }
2249 
2253 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
2254  {
2255  if ( root != tqt_xrootwin() )
2256  return FALSE;
2257  int kc = XkbKeycodeToKeysym(tqt_xdisplay(), ev.keycode, 0, 0);
2258  int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
2259 
2260  bool is_control = km & ControlMask;
2261  bool is_alt = km & Mod1Mask;
2262  bool is_shift = km & ShiftMask;
2263  int delta = is_control?1:is_alt?32:8;
2264  TQPoint pos = TQCursor::pos();
2265 
2266  switch ( kc )
2267  {
2268  case XK_Left:
2269  case XK_KP_Left:
2270  pos.rx() -= delta;
2271  break;
2272  case XK_Right:
2273  case XK_KP_Right:
2274  pos.rx() += delta;
2275  break;
2276  case XK_Up:
2277  case XK_KP_Up:
2278  pos.ry() -= delta;
2279  break;
2280  case XK_Down:
2281  case XK_KP_Down:
2282  pos.ry() += delta;
2283  break;
2284  case XK_F1:
2285  if ( !mouse_emulation_state )
2286  mouse_emulation_window = getMouseEmulationWindow();
2287  if ( (mouse_emulation_state & Button1Mask) == 0 )
2288  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
2289  if ( !is_shift )
2290  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
2291  break;
2292  case XK_F2:
2293  if ( !mouse_emulation_state )
2294  mouse_emulation_window = getMouseEmulationWindow();
2295  if ( (mouse_emulation_state & Button2Mask) == 0 )
2296  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
2297  if ( !is_shift )
2298  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
2299  break;
2300  case XK_F3:
2301  if ( !mouse_emulation_state )
2302  mouse_emulation_window = getMouseEmulationWindow();
2303  if ( (mouse_emulation_state & Button3Mask) == 0 )
2304  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
2305  if ( !is_shift )
2306  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
2307  break;
2308  case XK_Return:
2309  case XK_space:
2310  case XK_KP_Enter:
2311  case XK_KP_Space:
2312  {
2313  if ( !mouse_emulation_state )
2314  {
2315  // nothing was pressed, fake a LMB click
2316  mouse_emulation_window = getMouseEmulationWindow();
2317  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
2318  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
2319  }
2320  else
2321  { // release all
2322  if ( mouse_emulation_state & Button1Mask )
2323  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
2324  if ( mouse_emulation_state & Button2Mask )
2325  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
2326  if ( mouse_emulation_state & Button3Mask )
2327  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
2328  }
2329  }
2330  // fall through
2331  case XK_Escape:
2332  XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME());
2333  mouse_emulation = FALSE;
2334  return TRUE;
2335  default:
2336  return FALSE;
2337  }
2338 
2339  TQCursor::setPos( pos );
2340  if ( mouse_emulation_state )
2341  mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
2342  return TRUE;
2343 
2344  }
2345 
2351 TQWidget* Workspace::desktopWidget()
2352  {
2353  return desktop_widget;
2354  }
2355 
2356 //Delayed focus functions
2357 void Workspace::delayFocus()
2358  {
2359  requestFocus( delayfocus_client );
2360  cancelDelayFocus();
2361  }
2362 
2363 void Workspace::requestDelayFocus( Client* c )
2364  {
2365  delayfocus_client = c;
2366  delete delayFocusTimer;
2367  delayFocusTimer = new TQTimer( this );
2368  connect( delayFocusTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( delayFocus() ) );
2369  delayFocusTimer->start( options->delayFocusInterval, TRUE );
2370  }
2371 
2372 void Workspace::cancelDelayFocus()
2373  {
2374  delete delayFocusTimer;
2375  delayFocusTimer = 0;
2376  }
2377 
2378 // Electric Borders
2379 //========================================================================//
2380 // Electric Border Window management. Electric borders allow a user
2381 // to change the virtual desktop by moving the mouse pointer to the
2382 // borders. Technically this is done with input only windows. Since
2383 // electric borders can be switched on and off, we have these two
2384 // functions to create and destroy them.
2385 void Workspace::checkElectricBorders( bool force )
2386  {
2387  if( force )
2388  destroyBorderWindows();
2389 
2390  electric_current_border = 0;
2391 
2392  TQRect r = TQApplication::desktop()->geometry();
2393  electricTop = r.top();
2394  electricBottom = r.bottom();
2395  electricLeft = r.left();
2396  electricRight = r.right();
2397 
2398  if (options->electricBorders() == Options::ElectricAlways)
2399  createBorderWindows();
2400  else
2401  destroyBorderWindows();
2402  }
2403 
2404 void Workspace::createBorderWindows()
2405  {
2406  if ( electric_have_borders )
2407  return;
2408 
2409  electric_have_borders = true;
2410 
2411  TQRect r = TQApplication::desktop()->geometry();
2412  XSetWindowAttributes attributes;
2413  unsigned long valuemask;
2414  attributes.override_redirect = True;
2415  attributes.event_mask = ( EnterWindowMask | LeaveWindowMask );
2416  valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
2417  attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
2418  XC_sb_up_arrow);
2419  electric_top_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
2420  0,0,
2421  r.width(),1,
2422  0,
2423  CopyFromParent, InputOnly,
2424  CopyFromParent,
2425  valuemask, &attributes);
2426  XMapWindow(tqt_xdisplay(), electric_top_border);
2427 
2428  attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
2429  XC_sb_down_arrow);
2430  electric_bottom_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
2431  0,r.height()-1,
2432  r.width(),1,
2433  0,
2434  CopyFromParent, InputOnly,
2435  CopyFromParent,
2436  valuemask, &attributes);
2437  XMapWindow(tqt_xdisplay(), electric_bottom_border);
2438 
2439  attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
2440  XC_sb_left_arrow);
2441  electric_left_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
2442  0,0,
2443  1,r.height(),
2444  0,
2445  CopyFromParent, InputOnly,
2446  CopyFromParent,
2447  valuemask, &attributes);
2448  XMapWindow(tqt_xdisplay(), electric_left_border);
2449 
2450  attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
2451  XC_sb_right_arrow);
2452  electric_right_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
2453  r.width()-1,0,
2454  1,r.height(),
2455  0,
2456  CopyFromParent, InputOnly,
2457  CopyFromParent,
2458  valuemask, &attributes);
2459  XMapWindow(tqt_xdisplay(), electric_right_border);
2460  // Set XdndAware on the windows, so that DND enter events are received (#86998)
2461  Atom version = 4; // XDND version
2462  XChangeProperty( tqt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
2463  32, PropModeReplace, ( unsigned char* )&version, 1 );
2464  XChangeProperty( tqt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
2465  32, PropModeReplace, ( unsigned char* )&version, 1 );
2466  XChangeProperty( tqt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
2467  32, PropModeReplace, ( unsigned char* )&version, 1 );
2468  XChangeProperty( tqt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
2469  32, PropModeReplace, ( unsigned char* )&version, 1 );
2470  }
2471 
2472 
2473 // Electric Border Window management. Electric borders allow a user
2474 // to change the virtual desktop by moving the mouse pointer to the
2475 // borders. Technically this is done with input only windows. Since
2476 // electric borders can be switched on and off, we have these two
2477 // functions to create and destroy them.
2478 void Workspace::destroyBorderWindows()
2479  {
2480  if( !electric_have_borders)
2481  return;
2482 
2483  electric_have_borders = false;
2484 
2485  if(electric_top_border)
2486  XDestroyWindow(tqt_xdisplay(),electric_top_border);
2487  if(electric_bottom_border)
2488  XDestroyWindow(tqt_xdisplay(),electric_bottom_border);
2489  if(electric_left_border)
2490  XDestroyWindow(tqt_xdisplay(),electric_left_border);
2491  if(electric_right_border)
2492  XDestroyWindow(tqt_xdisplay(),electric_right_border);
2493 
2494  electric_top_border = None;
2495  electric_bottom_border = None;
2496  electric_left_border = None;
2497  electric_right_border = None;
2498  }
2499 
2500 void Workspace::clientMoved(const TQPoint &pos, Time now)
2501  {
2502  if (options->electricBorders() == Options::ElectricDisabled)
2503  return;
2504 
2505  if ((pos.x() != electricLeft) &&
2506  (pos.x() != electricRight) &&
2507  (pos.y() != electricTop) &&
2508  (pos.y() != electricBottom))
2509  return;
2510 
2511  Time treshold_set = options->electricBorderDelay(); // set timeout
2512  Time treshold_reset = 250; // reset timeout
2513  int distance_reset = 30; // Mouse should not move more than this many pixels
2514 
2515  int border = 0;
2516  if (pos.x() == electricLeft)
2517  border = 1;
2518  else if (pos.x() == electricRight)
2519  border = 2;
2520  else if (pos.y() == electricTop)
2521  border = 3;
2522  else if (pos.y() == electricBottom)
2523  border = 4;
2524 
2525  if ((electric_current_border == border) &&
2526  (timestampDiff(electric_time_last, now) < treshold_reset) &&
2527  ((pos-electric_push_point).manhattanLength() < distance_reset))
2528  {
2529  electric_time_last = now;
2530 
2531  if (timestampDiff(electric_time_first, now) > treshold_set)
2532  {
2533  electric_current_border = 0;
2534 
2535  TQRect r = TQApplication::desktop()->geometry();
2536  int offset;
2537 
2538  int desk_before = currentDesktop();
2539  switch(border)
2540  {
2541  case 1:
2542  slotSwitchDesktopLeft();
2543  if (currentDesktop() != desk_before)
2544  {
2545  offset = r.width() / 5;
2546  TQCursor::setPos(r.width() - offset, pos.y());
2547  }
2548  break;
2549 
2550  case 2:
2551  slotSwitchDesktopRight();
2552  if (currentDesktop() != desk_before)
2553  {
2554  offset = r.width() / 5;
2555  TQCursor::setPos(offset, pos.y());
2556  }
2557  break;
2558 
2559  case 3:
2560  slotSwitchDesktopUp();
2561  if (currentDesktop() != desk_before)
2562  {
2563  offset = r.height() / 5;
2564  TQCursor::setPos(pos.x(), r.height() - offset);
2565  }
2566  break;
2567 
2568  case 4:
2569  slotSwitchDesktopDown();
2570  if (currentDesktop() != desk_before)
2571  {
2572  offset = r.height() / 5;
2573  TQCursor::setPos(pos.x(), offset);
2574  }
2575  break;
2576  }
2577  return;
2578  }
2579  }
2580  else
2581  {
2582  electric_current_border = border;
2583  electric_time_first = now;
2584  electric_time_last = now;
2585  electric_push_point = pos;
2586  }
2587 
2588  int mouse_warp = 1;
2589 
2590  // reset the pointer to find out wether the user is really pushing
2591  switch( border)
2592  {
2593  case 1: TQCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
2594  case 2: TQCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
2595  case 3: TQCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
2596  case 4: TQCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
2597  }
2598  }
2599 
2600 // this function is called when the user entered an electric border
2601 // with the mouse. It may switch to another virtual desktop
2602 bool Workspace::electricBorder(XEvent *e)
2603  {
2604  if( !electric_have_borders )
2605  return false;
2606  if( e->type == EnterNotify )
2607  {
2608  if( e->xcrossing.window == electric_top_border ||
2609  e->xcrossing.window == electric_left_border ||
2610  e->xcrossing.window == electric_bottom_border ||
2611  e->xcrossing.window == electric_right_border)
2612  // the user entered an electric border
2613  {
2614  clientMoved( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
2615  return true;
2616  }
2617  }
2618  if( e->type == ClientMessage )
2619  {
2620  if( e->xclient.message_type == atoms->xdnd_position
2621  && ( e->xclient.window == electric_top_border
2622  || e->xclient.window == electric_bottom_border
2623  || e->xclient.window == electric_left_border
2624  || e->xclient.window == electric_right_border ))
2625  {
2626  updateXTime();
2627  clientMoved( TQPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), GET_QT_X_TIME() );
2628  return true;
2629  }
2630  }
2631  return false;
2632  }
2633 
2634 // electric borders (input only windows) have to be always on the
2635 // top. For that reason kwm calls this function always after some
2636 // windows have been raised.
2637 void Workspace::raiseElectricBorders()
2638  {
2639 
2640  if(electric_have_borders)
2641  {
2642  XRaiseWindow(tqt_xdisplay(), electric_top_border);
2643  XRaiseWindow(tqt_xdisplay(), electric_left_border);
2644  XRaiseWindow(tqt_xdisplay(), electric_bottom_border);
2645  XRaiseWindow(tqt_xdisplay(), electric_right_border);
2646  }
2647  }
2648 
2649 void Workspace::addTopMenu( Client* c )
2650  {
2651  assert( c->isTopMenu());
2652  assert( !topmenus.contains( c ));
2653  topmenus.append( c );
2654  if( managingTopMenus())
2655  {
2656  int minsize = c->minSize().height();
2657  if( minsize > topMenuHeight())
2658  {
2659  topmenu_height = minsize;
2660  updateTopMenuGeometry();
2661  }
2662  updateTopMenuGeometry( c );
2663  updateCurrentTopMenu();
2664  }
2665 // kdDebug() << "NEW TOPMENU:" << c << endl;
2666  }
2667 
2668 void Workspace::removeTopMenu( Client* c )
2669  {
2670 // if( c->isTopMenu())
2671 // kdDebug() << "REMOVE TOPMENU:" << c << endl;
2672  assert( c->isTopMenu());
2673  assert( topmenus.contains( c ));
2674  topmenus.remove( c );
2675  updateCurrentTopMenu();
2676  // TODO reduce topMenuHeight() if possible?
2677  }
2678 
2679 void Workspace::lostTopMenuSelection()
2680  {
2681 // kdDebug() << "lost TopMenu selection" << endl;
2682  // make sure this signal is always set when not owning the selection
2683  disconnect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
2684  connect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
2685  if( !managing_topmenus )
2686  return;
2687  connect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
2688  disconnect( topmenu_selection, TQT_SIGNAL( lostOwnership()), this, TQT_SLOT( lostTopMenuSelection()));
2689  managing_topmenus = false;
2690  delete topmenu_space;
2691  topmenu_space = NULL;
2692  updateClientArea();
2693  for( ClientList::ConstIterator it = topmenus.begin();
2694  it != topmenus.end();
2695  ++it )
2696  (*it)->checkWorkspacePosition();
2697  }
2698 
2699 void Workspace::lostTopMenuOwner()
2700  {
2701  if( !options->topMenuEnabled())
2702  return;
2703 // kdDebug() << "TopMenu selection lost owner" << endl;
2704  if( !topmenu_selection->claim( false ))
2705  {
2706 // kdDebug() << "Failed to claim TopMenu selection" << endl;
2707  return;
2708  }
2709 // kdDebug() << "claimed TopMenu selection" << endl;
2710  setupTopMenuHandling();
2711  }
2712 
2713 void Workspace::setupTopMenuHandling()
2714  {
2715  if( managing_topmenus )
2716  return;
2717  connect( topmenu_selection, TQT_SIGNAL( lostOwnership()), this, TQT_SLOT( lostTopMenuSelection()));
2718  disconnect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
2719  managing_topmenus = true;
2720  topmenu_space = new TQWidget;
2721  Window stack[ 2 ];
2722  stack[ 0 ] = supportWindow->winId();
2723  stack[ 1 ] = topmenu_space->winId();
2724  XRestackWindows(tqt_xdisplay(), stack, 2);
2725  updateTopMenuGeometry();
2726  topmenu_space->show();
2727  updateClientArea();
2728  updateCurrentTopMenu();
2729  }
2730 
2731 int Workspace::topMenuHeight() const
2732  {
2733  if( topmenu_height == 0 )
2734  { // simply create a dummy menubar and use its preffered height as the menu height
2735  KMenuBar tmpmenu;
2736  tmpmenu.insertItem( "dummy" );
2737  topmenu_height = tmpmenu.sizeHint().height();
2738  }
2739  return topmenu_height;
2740  }
2741 
2742 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
2743  {
2744  return mgr->createDecoration( bridge );
2745  }
2746 
2747 TQString Workspace::desktopName( int desk ) const
2748  {
2749  return TQString::fromUtf8( rootInfo->desktopName( desk ) );
2750  }
2751 
2752 bool Workspace::checkStartupNotification( Window w, TDEStartupInfoId& id, TDEStartupInfoData& data )
2753  {
2754  return startup->checkStartup( w, id, data ) == TDEStartupInfo::Match;
2755  }
2756 
2761 void Workspace::focusToNull()
2762  {
2763  XSetInputFocus(tqt_xdisplay(), null_focus_window, RevertToPointerRoot, GET_QT_X_TIME() );
2764  }
2765 
2766 void Workspace::helperDialog( const TQString& message, const Client* c )
2767  {
2768  TQStringList args;
2769  TQString type;
2770  if( message == "noborderaltf3" )
2771  {
2772  TQString shortcut = TQString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
2773  .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
2774  args << "--msgbox" <<
2775  i18n( "You have selected to show a window without its border.\n"
2776  "Without the border, you will not be able to enable the border "
2777  "again using the mouse: use the window operations menu instead, "
2778  "activated using the %1 keyboard shortcut." )
2779  .arg( shortcut );
2780  type = "altf3warning";
2781  }
2782  else if( message == "fullscreenaltf3" )
2783  {
2784  TQString shortcut = TQString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
2785  .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
2786  args << "--msgbox" <<
2787  i18n( "You have selected to show a window in fullscreen mode.\n"
2788  "If the application itself does not have an option to turn the fullscreen "
2789  "mode off you will not be able to disable it "
2790  "again using the mouse: use the window operations menu instead, "
2791  "activated using the %1 keyboard shortcut." )
2792  .arg( shortcut );
2793  type = "altf3warning";
2794  }
2795  else
2796  assert( false );
2797  TDEProcess proc;
2798  proc << "kdialog" << args;
2799  if( !type.isEmpty())
2800  {
2801  TDEConfig cfg( "twin_dialogsrc" );
2802  cfg.setGroup( "Notification Messages" ); // this depends on KMessageBox
2803  if( !cfg.readBoolEntry( type, true )) // has don't show again checked
2804  return; // save launching kdialog
2805  proc << "--dontagain" << "twin_dialogsrc:" + type;
2806  }
2807  if( c != NULL )
2808  proc << "--embed" << TQString::number( c->window());
2809  proc.start( TDEProcess::DontCare );
2810  }
2811 
2812 
2813 // kompmgr stuff
2814 
2815 void Workspace::startKompmgr()
2816 {
2817  // See if the desktop is loaded yet
2818  Atom type;
2819  int format;
2820  unsigned long length, after;
2821  unsigned char* data_root;
2822  Atom prop_root;
2823  prop_root = XInternAtom(tqt_xdisplay(), "_XROOTPMAP_ID", False);
2824  if( XGetWindowProperty( tqt_xdisplay(), tqt_xrootwin(), prop_root, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_root) == Success && data_root != NULL ) {
2825  // Root pixmap is available; OK to load...
2826  }
2827  else {
2828  // Try again a bit later!
2829  TQTimer::singleShot( 200, this, TQT_SLOT(startKompmgr()) );
2830  return;
2831  }
2832  pid_t kompmgrpid = getCompositorPID();
2833  if (kompmgrpid && kill(kompmgrpid, 0) >= 0)
2834  {
2835  // Active PID file detected; do not attempt to restart
2836  return;
2837  }
2838  if (!kompmgr || kompmgr->isRunning()) {
2839  kompmgrReloadSettings();
2840  return;
2841  }
2842  if (!kompmgr->start(TDEProcess::OwnGroup, TDEProcess::Stderr))
2843  {
2844  options->useTranslucency = FALSE;
2845  TDEProcess proc;
2846  proc << "kdialog" << "--error"
2847  << i18n("The Composite Manager could not be started.\\nMake sure you have \"" TDE_COMPOSITOR_BINARY "\" in a $PATH directory.")
2848  << "--title" << "Composite Manager Failure";
2849  proc.start(TDEProcess::DontCare);
2850  }
2851  else
2852  {
2853  delete kompmgr_selection;
2854  char selection_name[ 100 ];
2855  sprintf( selection_name, "_NET_WM_CM_S%d", DefaultScreen( tqt_xdisplay()));
2856  kompmgr_selection = new TDESelectionOwner( selection_name );
2857  connect( kompmgr_selection, TQT_SIGNAL( lostOwnership()), TQT_SLOT( stopKompmgr()));
2858  kompmgr_selection->claim( true );
2859  connect(kompmgr, TQT_SIGNAL(processExited(TDEProcess*)), TQT_SLOT(restartKompmgr(TDEProcess*)));
2860  options->useTranslucency = TRUE;
2861  //allowKompmgrRestart = FALSE;
2862  //TQTimer::singleShot( 60000, this, TQT_SLOT(unblockKompmgrRestart()) );
2863  TQByteArray ba;
2864  TQDataStream arg(ba, IO_WriteOnly);
2865  arg << "";
2866  kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStarted()", ba);
2867  }
2868  if (popup){ delete popup; popup = 0L; } // to add/remove opacity slider
2869 }
2870 
2871 void Workspace::stopKompmgr()
2872 {
2873  if (!kompmgr || !kompmgr->isRunning()) {
2874  return;
2875  }
2876  delete kompmgr_selection;
2877  kompmgr_selection = NULL;
2878  kompmgr->disconnect(this, TQT_SLOT(restartKompmgr(TDEProcess*)));
2879  options->useTranslucency = FALSE;
2880  if (popup){ delete popup; popup = 0L; } // to add/remove opacity slider
2881  kompmgr->kill(SIGKILL);
2882  TQByteArray ba;
2883  TQDataStream arg(ba, IO_WriteOnly);
2884  arg << "";
2885  kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStopped()", ba);
2886 }
2887 
2888 void Workspace::kompmgrReloadSettings()
2889 {
2890  if (!kompmgr || !kompmgr->isRunning()) {
2891  return;
2892  }
2893  kompmgr->kill(SIGUSR2);
2894 }
2895 
2896 bool Workspace::kompmgrIsRunning()
2897 {
2898  return kompmgr && kompmgr->isRunning();
2899 }
2900 
2901 void Workspace::unblockKompmgrRestart()
2902 {
2903  allowKompmgrRestart = TRUE;
2904 }
2905 
2906 void Workspace::restartKompmgr( TDEProcess *proc )
2907 // this is for inernal purpose (crashhandling) only, usually you want to use workspace->stopKompmgr(); TQTimer::singleShot(200, workspace, TQT_SLOT(startKompmgr()));
2908 {
2909  bool crashed;
2910  if (proc->signalled()) { // looks like kompmgr may have crashed
2911  int exit_signal_number = proc->exitSignal();
2912  if ( (exit_signal_number == SIGILL) || (exit_signal_number == SIGTRAP) || (exit_signal_number == SIGABRT) || (exit_signal_number == SIGSYS) || (exit_signal_number == SIGFPE) || (exit_signal_number == SIGBUS) || (exit_signal_number == SIGSEGV) ) {
2913  crashed = true;
2914  }
2915  else {
2916  crashed = false;
2917  }
2918  if (!allowKompmgrRestart) // uh oh, it exited recently already
2919  {
2920  delete kompmgr_selection;
2921  kompmgr_selection = NULL;
2922  options->useTranslucency = FALSE;
2923  if (crashed) {
2924  TDEProcess proc;
2925  proc << "kdialog" << "--error"
2926  << i18n( "The Composite Manager crashed twice within a minute and is therefore disabled for this session.")
2927  << "--title" << i18n("Composite Manager Failure");
2928  proc.start(TDEProcess::DontCare);
2929  }
2930  return;
2931  }
2932  if (!kompmgr)
2933  return;
2934 // this should be useless, i keep it for maybe future need
2935 // if (!kcompmgr)
2936 // {
2937 // kompmgr = new TDEProcess;
2938 // kompmgr->clearArguments();
2939 // *kompmgr << TDE_COMPOSITOR_BINARY;
2940 // }
2941 // -------------------
2942  if (!kompmgr->start(TDEProcess::NotifyOnExit, TDEProcess::Stderr))
2943  {
2944  delete kompmgr_selection;
2945  kompmgr_selection = NULL;
2946  options->useTranslucency = FALSE;
2947  TDEProcess proc;
2948  proc << "kdialog" << "--error"
2949  << i18n("The Composite Manager could not be started.\\nMake sure you have \"" TDE_COMPOSITOR_BINARY "\" in a $PATH directory.")
2950  << "--title" << i18n("Composite Manager Failure");
2951  proc.start(TDEProcess::DontCare);
2952  }
2953  else
2954  {
2955  allowKompmgrRestart = FALSE;
2956  TQTimer::singleShot( 60000, this, TQT_SLOT(unblockKompmgrRestart()) );
2957  }
2958  }
2959 }
2960 
2961 void Workspace::handleKompmgrOutput( TDEProcess* , char *buffer, int buflen)
2962 {
2963  TQString message;
2964  TQString output = TQString::fromLocal8Bit( buffer, buflen );
2965  if (output.contains("Started",false))
2966  ; // don't do anything, just pass to the connection release
2967  else if (output.contains("Can't open display",false))
2968  message = i18n("<qt><b>The TDE composition manager failed to open the display</b><br>There is probably an invalid display entry in your ~/.compton-tde.conf file.</qt>");
2969  else if (output.contains("No render extension",false))
2970  message = i18n("<qt><b>The TDE composition manager cannot find the Xrender extension</b><br>You are using either an outdated or a crippled version of XOrg.<br>Get XOrg &ge; 6.8 from www.freedesktop.org.<br></qt>");
2971  else if (output.contains("No composite extension",false))
2972  message = i18n("<qt><b>Composite extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.<br>Additionally, you need to add a new section to your X config file:<br>"
2973  "<i>Section \"Extensions\"<br>"
2974  "Option \"Composite\" \"Enable\"<br>"
2975  "EndSection</i></qt>");
2976  else if (output.contains("No damage extension",false))
2977  message = i18n("<qt><b>Damage extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.</qt>");
2978  else if (output.contains("No XFixes extension",false))
2979  message = i18n("<qt><b>XFixes extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.</qt>");
2980  else return; //skip others
2981  // kompmgr startup failed or succeeded, release connection
2982  kompmgr->closeStderr();
2983  disconnect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), this, TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
2984  if( !message.isEmpty())
2985  {
2986  TDEProcess proc;
2987  proc << "kdialog" << "--error"
2988  << message
2989  << "--title" << i18n("Composite Manager Failure");
2990  proc.start(TDEProcess::DontCare);
2991  }
2992 }
2993 
2994 
2995 void Workspace::setOpacity(unsigned long winId, unsigned int opacityPercent)
2996 {
2997  if (opacityPercent > 100) opacityPercent = 100;
2998  for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
2999  if (winId == (*it)->window())
3000  {
3001  (*it)->setOpacity(opacityPercent < 100, (unsigned int)((opacityPercent/100.0)*0xFFFFFFFF));
3002  return;
3003  }
3004 }
3005 
3006 void Workspace::setShadowSize(unsigned long winId, unsigned int shadowSizePercent)
3007 {
3008  //this is open to the user by dcop - to avoid stupid trials, we limit the max shadow size to 400%
3009  if (shadowSizePercent > 400) shadowSizePercent = 400;
3010  for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
3011  if (winId == (*it)->window())
3012  {
3013  (*it)->setShadowSize(shadowSizePercent);
3014  return;
3015  }
3016 }
3017 
3018 void Workspace::setUnshadowed(unsigned long winId)
3019 {
3020  for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
3021  if (winId == (*it)->window())
3022  {
3023  (*it)->setShadowSize(0);
3024  return;
3025  }
3026 }
3027 
3028 void Workspace::setShowingDesktop( bool showing )
3029  {
3030  rootInfo->setShowingDesktop( showing );
3031  showing_desktop = showing;
3032  ++block_showing_desktop;
3033  if( showing_desktop )
3034  {
3035  showing_desktop_clients.clear();
3036  ++block_focus;
3037  ClientList cls = stackingOrder();
3038  // find them first, then minimize, otherwise transients may get minimized with the window
3039  // they're transient for
3040  for( ClientList::ConstIterator it = cls.begin();
3041  it != cls.end();
3042  ++it )
3043  {
3044  if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
3045  showing_desktop_clients.prepend( *it ); // topmost first to reduce flicker
3046  }
3047  for( ClientList::ConstIterator it = showing_desktop_clients.begin();
3048  it != showing_desktop_clients.end();
3049  ++it )
3050  (*it)->minimize(true);
3051  --block_focus;
3052  if( Client* desk = findDesktop( true, currentDesktop()))
3053  requestFocus( desk );
3054  }
3055  else
3056  {
3057  for( ClientList::ConstIterator it = showing_desktop_clients.begin();
3058  it != showing_desktop_clients.end();
3059  ++it )
3060  (*it)->unminimize(true);
3061  if( showing_desktop_clients.count() > 0 )
3062  requestFocus( showing_desktop_clients.first());
3063  showing_desktop_clients.clear();
3064  }
3065  --block_showing_desktop;
3066  }
3067 
3068 // Following Kicker's behavior:
3069 // Changing a virtual desktop resets the state and shows the windows again.
3070 // Unminimizing a window resets the state but keeps the windows hidden (except
3071 // the one that was unminimized).
3072 // A new window resets the state and shows the windows again, with the new window
3073 // being active. Due to popular demand (#67406) by people who apparently
3074 // don't see a difference between "show desktop" and "minimize all", this is not
3075 // true if "showDesktopIsMinimizeAll" is set in twinrc. In such case showing
3076 // a new window resets the state but doesn't show windows.
3077 void Workspace::resetShowingDesktop( bool keep_hidden )
3078  {
3079  if( block_showing_desktop > 0 )
3080  return;
3081  rootInfo->setShowingDesktop( false );
3082  showing_desktop = false;
3083  ++block_showing_desktop;
3084  if( !keep_hidden )
3085  {
3086  for( ClientList::ConstIterator it = showing_desktop_clients.begin();
3087  it != showing_desktop_clients.end();
3088  ++it )
3089  (*it)->unminimize(true);
3090  }
3091  showing_desktop_clients.clear();
3092  --block_showing_desktop;
3093  }
3094 
3095 // Activating/deactivating this feature works like this:
3096 // When nothing is active, and the shortcut is pressed, global shortcuts are disabled
3097 // (using global_shortcuts_disabled)
3098 // When a window that has disabling forced is activated, global shortcuts are disabled.
3099 // (using global_shortcuts_disabled_for_client)
3100 // When a shortcut is pressed and global shortcuts are disabled (either by a shortcut
3101 // or for a client), they are enabled again.
3102 void Workspace::slotDisableGlobalShortcuts()
3103  {
3104  if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
3105  disableGlobalShortcuts( false );
3106  else
3107  disableGlobalShortcuts( true );
3108  }
3109 
3110 static bool pending_dfc = false;
3111 
3112 void Workspace::disableGlobalShortcutsForClient( bool disable )
3113  {
3114  if( global_shortcuts_disabled_for_client == disable )
3115  return;
3116  if( !global_shortcuts_disabled )
3117  {
3118  if( disable )
3119  pending_dfc = true;
3120  KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
3121  // twin will get the kipc message too
3122  }
3123  }
3124 
3125 void Workspace::disableGlobalShortcuts( bool disable )
3126  {
3127  KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
3128  // twin will get the kipc message too
3129  }
3130 
3131 void Workspace::kipcMessage( int id, int data )
3132  {
3133  if( id != KIPC::BlockShortcuts )
3134  return;
3135  if( pending_dfc && data )
3136  {
3137  global_shortcuts_disabled_for_client = true;
3138  pending_dfc = false;
3139  }
3140  else
3141  {
3142  global_shortcuts_disabled = data;
3143  global_shortcuts_disabled_for_client = false;
3144  }
3145  // update also Alt+LMB actions etc.
3146  for( ClientList::ConstIterator it = clients.begin();
3147  it != clients.end();
3148  ++it )
3149  (*it)->updateMouseGrab();
3150  }
3151 
3152 } // namespace
3153 
3154 #include "workspace.moc"

twin

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

twin

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