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

tdecore

  • tdecore
tdestartupinfo.cpp
1 /****************************************************************************
2 
3  $Id$
4 
5  Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE.
24 
25 ****************************************************************************/
26 
27 // kdDebug() can't be turned off in tdeinit
28 #if 0
29 #define KSTARTUPINFO_ALL_DEBUG
30 #warning Extra TDEStartupInfo debug messages enabled.
31 #endif
32 
33 #include <tqwidget.h>
34 
35 #include "config.h"
36 #ifdef Q_WS_X11
37 //#ifdef Q_WS_X11 // FIXME(E): Re-implement in a less X11 specific way
38 #include <tqglobal.h>
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 
43 // need to resolve INT32(tqglobal.h)<>INT32(Xlibint.h) conflict
44 #ifndef QT_CLEAN_NAMESPACE
45 #define QT_CLEAN_NAMESPACE
46 #endif
47 
48 #include "tdestartupinfo.h"
49 
50 #include <unistd.h>
51 #include <sys/time.h>
52 #include <stdlib.h>
53 #include <tqtimer.h>
54 #ifdef Q_WS_X11
55 #include <netwm.h>
56 #endif
57 #include <kdebug.h>
58 #include <tdeapplication.h>
59 #include <signal.h>
60 #ifdef Q_WS_X11
61 #include <twinmodule.h>
62 #include <kxmessages.h>
63 #include <twin.h>
64 #endif
65 
66 static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO";
67 static const char* const NET_STARTUP_WINDOW = "_NET_STARTUP_ID";
68 // DESKTOP_STARTUP_ID is used also in tdeinit/wrapper.c ,
69 // tdesu in both tdelibs and tdebase and who knows where else
70 static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID";
71 
72 static bool auto_app_started_sending = true;
73 
74 static long get_num( const TQString& item_P );
75 static unsigned long get_unum( const TQString& item_P );
76 static TQString get_str( const TQString& item_P );
77 static TQCString get_cstr( const TQString& item_P );
78 static TQStringList get_fields( const TQString& txt_P );
79 static TQString escape_str( const TQString& str_P );
80 
81 static Atom utf8_string_atom = None;
82 
83 class TDEStartupInfo::Data
84  : public TDEStartupInfoData
85  {
86  public:
87  Data() : TDEStartupInfoData(), age(0) {} // just because it's in a QMap
88  Data( const TQString& txt_P )
89  : TDEStartupInfoData( txt_P ), age( 0 ) {}
90  unsigned int age;
91  };
92 
93 struct TDEStartupInfoPrivate
94  {
95  public:
96  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > startups;
97  // contains silenced ASN's only if !AnnounceSilencedChanges
98  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > silent_startups;
99  // contains ASN's that had change: but no new: yet
100  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > uninited_startups;
101 #ifdef Q_WS_X11
102  KWinModule* wm_module;
103  KXMessages msgs;
104 #endif
105  TQTimer* cleanup;
106  int flags;
107  TDEStartupInfoPrivate( int flags_P )
108  :
109 #ifdef Q_WS_X11
110  msgs( NET_STARTUP_MSG, NULL, false ),
111 #endif
112  flags( flags_P ) {}
113  };
114 
115 TDEStartupInfo::TDEStartupInfo( int flags_P, TQObject* parent_P, const char* name_P )
116  : TQObject( parent_P, name_P ),
117  timeout( 60 ), d( NULL )
118  {
119  init( flags_P );
120  }
121 
122 TDEStartupInfo::TDEStartupInfo( bool clean_on_cantdetect_P, TQObject* parent_P, const char* name_P )
123  : TQObject( parent_P, name_P ),
124  timeout( 60 ), d( NULL )
125  {
126  init( clean_on_cantdetect_P ? CleanOnCantDetect : 0 );
127  }
128 
129 void TDEStartupInfo::init( int flags_P )
130  {
131  // d == NULL means "disabled"
132  if( !TDEApplication::kApplication())
133  return;
134  if( !TDEApplication::kApplication()->getDisplay())
135  return;
136 
137  d = new TDEStartupInfoPrivate( flags_P );
138 #ifdef Q_WS_X11
139  if( !( d->flags & DisableKWinModule ))
140  {
141  d->wm_module = new KWinModule( this );
142  connect( d->wm_module, TQT_SIGNAL( windowAdded( WId )), TQT_SLOT( slot_window_added( WId )));
143  connect( d->wm_module, TQT_SIGNAL( systemTrayWindowAdded( WId )), TQT_SLOT( slot_window_added( WId )));
144  }
145  else
146  d->wm_module = NULL;
147  connect( &d->msgs, TQT_SIGNAL( gotMessage( const TQString& )), TQT_SLOT( got_message( const TQString& )));
148 #endif
149  d->cleanup = new TQTimer( this, "cleanup" );
150  connect( d->cleanup, TQT_SIGNAL( timeout()), TQT_SLOT( startups_cleanup()));
151  }
152 
153 TDEStartupInfo::~TDEStartupInfo()
154  {
155  delete d;
156  }
157 
158 void TDEStartupInfo::got_message( const TQString& msg_P )
159  {
160 // TODO do something with SCREEN= ?
161  kdDebug( 172 ) << "[tdecore-tdestartupinfo] got:" << msg_P << endl;
162  TQString msg = msg_P.stripWhiteSpace();
163  if( msg.startsWith( "new:" )) // must match length below
164  got_startup_info( msg.mid( 4 ), false );
165  else if( msg.startsWith( "change:" )) // must match length below
166  got_startup_info( msg.mid( 7 ), true );
167  else if( msg.startsWith( "remove:" )) // must match length below
168  got_remove_startup_info( msg.mid( 7 ));
169  }
170 
171 // if the application stops responding for a while, KWinModule may get
172 // the information about the already mapped window before KXMessages
173 // actually gets the info about the started application (depends
174 // on their order in X11 event filter in TDEApplication)
175 // simply delay info from KWinModule a bit
176 // SELI???
177 namespace
178 {
179 class DelayedWindowEvent
180  : public TQCustomEvent
181  {
182  public:
183  DelayedWindowEvent( WId w_P )
184  : TQCustomEvent( TQEvent::User + 15 ), w( w_P ) {}
185  Window w;
186  };
187 }
188 
189 void TDEStartupInfo::slot_window_added( WId w_P )
190  {
191  kapp->postEvent( this, new DelayedWindowEvent( w_P ));
192  }
193 
194 void TDEStartupInfo::customEvent( TQCustomEvent* e_P )
195  {
196  if( e_P->type() == TQEvent::User + 15 )
197  window_added( static_cast< DelayedWindowEvent* >( e_P )->w );
198  else
199  TQObject::customEvent( e_P );
200  }
201 
202 void TDEStartupInfo::window_added( WId w_P )
203  {
204  TDEStartupInfoId id;
205  TDEStartupInfoData data;
206  startup_t ret = check_startup_internal( w_P, &id, &data );
207  switch( ret )
208  {
209  case Match:
210  kdDebug( 172 ) << "[tdecore-tdestartupinfo] new window match" << endl;
211  break;
212  case NoMatch:
213  break; // nothing
214  case CantDetect:
215  if( d->flags & CleanOnCantDetect )
216  clean_all_noncompliant();
217  break;
218  }
219  }
220 
221 void TDEStartupInfo::got_startup_info( const TQString& msg_P, bool update_P )
222  {
223  TDEStartupInfoId id( msg_P );
224  if( id.none())
225  return;
226  TDEStartupInfo::Data data( msg_P );
227  new_startup_info_internal( id, data, update_P );
228  }
229 
230 void TDEStartupInfo::new_startup_info_internal( const TDEStartupInfoId& id_P,
231  Data& data_P, bool update_P )
232  {
233  if( d == NULL )
234  return;
235  if( id_P.none())
236  return;
237  if( d->startups.contains( id_P ))
238  { // already reported, update
239  d->startups[ id_P ].update( data_P );
240  d->startups[ id_P ].age = 0; // CHECKME
241  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating" << endl;
242  if( d->startups[ id_P ].silent() == Data::Yes
243  && !( d->flags & AnnounceSilenceChanges ))
244  {
245  d->silent_startups[ id_P ] = d->startups[ id_P ];
246  d->startups.remove( id_P );
247  emit gotRemoveStartup( id_P, d->silent_startups[ id_P ] );
248  return;
249  }
250  emit gotStartupChange( id_P, d->startups[ id_P ] );
251  return;
252  }
253  if( d->silent_startups.contains( id_P ))
254  { // already reported, update
255  d->silent_startups[ id_P ].update( data_P );
256  d->silent_startups[ id_P ].age = 0; // CHECKME
257  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating silenced" << endl;
258  if( d->silent_startups[ id_P ].silent() != Data::Yes )
259  {
260  d->startups[ id_P ] = d->silent_startups[ id_P ];
261  d->silent_startups.remove( id_P );
262  emit gotNewStartup( id_P, d->startups[ id_P ] );
263  return;
264  }
265  emit gotStartupChange( id_P, d->silent_startups[ id_P ] );
266  return;
267  }
268  if( d->uninited_startups.contains( id_P ))
269  {
270  d->uninited_startups[ id_P ].update( data_P );
271  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating uninited" << endl;
272  if( !update_P ) // uninited finally got new:
273  {
274  d->startups[ id_P ] = d->uninited_startups[ id_P ];
275  d->uninited_startups.remove( id_P );
276  emit gotNewStartup( id_P, d->startups[ id_P ] );
277  return;
278  }
279  // no change announce, it's still uninited
280  return;
281  }
282  if( update_P ) // change: without any new: first
283  {
284  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding uninited" << endl;
285  d->uninited_startups.insert( id_P, data_P );
286  }
287  else if( data_P.silent() != Data::Yes || d->flags & AnnounceSilenceChanges )
288  {
289  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding" << endl;
290  d->startups.insert( id_P, data_P );
291  emit gotNewStartup( id_P, data_P );
292  }
293  else // new silenced, and silent shouldn't be announced
294  {
295  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding silent" << endl;
296  d->silent_startups.insert( id_P, data_P );
297  }
298  d->cleanup->start( 1000 ); // 1 sec
299  }
300 
301 void TDEStartupInfo::got_remove_startup_info( const TQString& msg_P )
302  {
303  TDEStartupInfoId id( msg_P );
304  TDEStartupInfoData data( msg_P );
305  if( data.pids().count() > 0 )
306  {
307  if( !id.none())
308  remove_startup_pids( id, data );
309  else
310  remove_startup_pids( data );
311  return;
312  }
313  remove_startup_info_internal( id );
314  }
315 
316 void TDEStartupInfo::remove_startup_info_internal( const TDEStartupInfoId& id_P )
317  {
318  if( d == NULL )
319  return;
320  if( d->startups.contains( id_P ))
321  {
322  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing" << endl;
323  emit gotRemoveStartup( id_P, d->startups[ id_P ]);
324  d->startups.remove( id_P );
325  }
326  else if( d->silent_startups.contains( id_P ))
327  {
328  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing silent" << endl;
329  d->silent_startups.remove( id_P );
330  }
331  else if( d->uninited_startups.contains( id_P ))
332  {
333  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing uninited" << endl;
334  d->uninited_startups.remove( id_P );
335  }
336  return;
337  }
338 
339 void TDEStartupInfo::remove_startup_pids( const TDEStartupInfoData& data_P )
340  { // first find the matching info
341  if( d == NULL )
342  return;
343  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
344  it != d->startups.end();
345  ++it )
346  {
347  if( ( *it ).hostname() != data_P.hostname())
348  continue;
349  if( !( *it ).is_pid( data_P.pids().first()))
350  continue; // not the matching info
351  remove_startup_pids( it.key(), data_P );
352  break;
353  }
354  }
355 
356 void TDEStartupInfo::remove_startup_pids( const TDEStartupInfoId& id_P,
357  const TDEStartupInfoData& data_P )
358  {
359  if( d == NULL )
360  return;
361  kdFatal( data_P.pids().count() == 0, 172 );
362  Data* data = NULL;
363  if( d->startups.contains( id_P ))
364  data = &d->startups[ id_P ];
365  else if( d->silent_startups.contains( id_P ))
366  data = &d->silent_startups[ id_P ];
367  else if( d->uninited_startups.contains( id_P ))
368  data = &d->uninited_startups[ id_P ];
369  else
370  return;
371  for( TQValueList< pid_t >::ConstIterator it2 = data_P.pids().begin();
372  it2 != data_P.pids().end();
373  ++it2 )
374  data->remove_pid( *it2 ); // remove all pids from the info
375  if( data->pids().count() == 0 ) // all pids removed -> remove info
376  remove_startup_info_internal( id_P );
377  }
378 
379 bool TDEStartupInfo::sendStartup( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
380  {
381  if( id_P.none())
382  return false;
383  KXMessages msgs;
384  TQString msg = TQString::fromLatin1( "new: %1 %2" )
385  .arg( id_P.to_text()).arg( data_P.to_text());
386  msg = check_required_startup_fields( msg, data_P, tqt_xscreen());
387  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
388  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
389  return true;
390  }
391 
392 bool TDEStartupInfo::sendStartupX( Display* disp_P, const TDEStartupInfoId& id_P,
393  const TDEStartupInfoData& data_P )
394  {
395  if( id_P.none())
396  return false;
397  TQString msg = TQString::fromLatin1( "new: %1 %2" )
398  .arg( id_P.to_text()).arg( data_P.to_text());
399  msg = check_required_startup_fields( msg, data_P, DefaultScreen( disp_P ));
400 #ifdef KSTARTUPINFO_ALL_DEBUG
401  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
402 #endif
403  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
404  }
405 
406 TQString TDEStartupInfo::check_required_startup_fields( const TQString& msg, const TDEStartupInfoData& data_P,
407  int screen )
408  {
409  TQString ret = msg;
410  if( data_P.name().isEmpty())
411  {
412 // kdWarning( 172 ) << "[tdecore-tdestartupinfo] NAME not specified in initial startup message" << endl;
413  TQString name = data_P.bin();
414  if( name.isEmpty())
415  name = "UNKNOWN";
416  ret += TQString( " NAME=\"%1\"" ).arg( escape_str( name ));
417  }
418  if( data_P.screen() == -1 ) // add automatically if needed
419  ret += TQString( " SCREEN=%1" ).arg( screen );
420  return ret;
421  }
422 
423 bool TDEStartupInfo::sendChange( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
424  {
425  if( id_P.none())
426  return false;
427  KXMessages msgs;
428  TQString msg = TQString::fromLatin1( "change: %1 %2" )
429  .arg( id_P.to_text()).arg( data_P.to_text());
430  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
431  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
432  return true;
433  }
434 
435 bool TDEStartupInfo::sendChangeX( Display* disp_P, const TDEStartupInfoId& id_P,
436  const TDEStartupInfoData& data_P )
437  {
438  if( id_P.none())
439  return false;
440  TQString msg = TQString::fromLatin1( "change: %1 %2" )
441  .arg( id_P.to_text()).arg( data_P.to_text());
442 #ifdef KSTARTUPINFO_ALL_DEBUG
443  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
444 #endif
445  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
446  }
447 
448 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P )
449  {
450  if( id_P.none())
451  return false;
452  KXMessages msgs;
453  TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
454  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
455  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
456  return true;
457  }
458 
459 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P )
460  {
461  if( id_P.none())
462  return false;
463  TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
464 #ifdef KSTARTUPINFO_ALL_DEBUG
465  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
466 #endif
467  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
468  }
469 
470 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
471  {
472 // if( id_P.none()) // id may be none, the pids and hostname matter then
473 // return false;
474  KXMessages msgs;
475  TQString msg = TQString::fromLatin1( "remove: %1 %2" )
476  .arg( id_P.to_text()).arg( data_P.to_text());
477  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
478  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
479  return true;
480  }
481 
482 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P,
483  const TDEStartupInfoData& data_P )
484  {
485 // if( id_P.none()) // id may be none, the pids and hostname matter then
486 // return false;
487  TQString msg = TQString::fromLatin1( "remove: %1 %2" )
488  .arg( id_P.to_text()).arg( data_P.to_text());
489 #ifdef KSTARTUPINFO_ALL_DEBUG
490  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
491 #endif
492  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
493  }
494 
495 void TDEStartupInfo::appStarted()
496  {
497  if( kapp != NULL ) // TDEApplication constructor unsets the env. variable
498  appStarted( kapp->startupId());
499  else
500  appStarted( TDEStartupInfo::currentStartupIdEnv().id());
501  }
502 
503 void TDEStartupInfo::appStarted( const TQCString& startup_id )
504  {
505  TDEStartupInfoId id;
506  id.initId( startup_id );
507  if( id.none())
508  return;
509  if( kapp != NULL )
510  TDEStartupInfo::sendFinish( id );
511  else if( getenv( "DISPLAY" ) != NULL ) // don't rely on tqt_xdisplay()
512  {
513 #ifdef Q_WS_X11
514  Display* disp = XOpenDisplay( NULL );
515  if( disp != NULL )
516  {
517  TDEStartupInfo::sendFinishX( disp, id );
518  XCloseDisplay( disp );
519  }
520 #endif
521  }
522  }
523 
524 void TDEStartupInfo::disableAutoAppStartedSending( bool disable )
525  {
526  auto_app_started_sending = !disable;
527  }
528 
529 void TDEStartupInfo::silenceStartup( bool silence )
530  {
531  TDEStartupInfoId id;
532  id.initId( kapp->startupId());
533  if( id.none())
534  return;
535  TDEStartupInfoData data;
536  data.setSilent( silence ? TDEStartupInfoData::Yes : TDEStartupInfoData::No );
537  sendChange( id, data );
538  }
539 
540 void TDEStartupInfo::handleAutoAppStartedSending()
541  {
542  if( auto_app_started_sending )
543  appStarted();
544  }
545 
546 void TDEStartupInfo::setNewStartupId( TQWidget* window, const TQCString& startup_id )
547  {
548  bool activate = true;
549  kapp->setStartupId( startup_id );
550  if( window != NULL )
551  {
552  if( !startup_id.isEmpty() && startup_id != "0" )
553  {
554  NETRootInfo i( tqt_xdisplay(), NET::Supported );
555  if( i.isSupported( NET::WM2StartupId ))
556  {
557  TDEStartupInfo::setWindowStartupId( window->winId(), startup_id );
558  activate = false; // WM will take care of it
559  }
560  }
561  if( activate )
562  {
563  KWin::setOnDesktop( window->winId(), KWin::currentDesktop());
564  // This is not very nice, but there's no way how to get any
565  // usable timestamp without ASN, so force activating the window.
566  // And even with ASN, it's not possible to get the timestamp here,
567  // so if the WM doesn't have support for ASN, it can't be used either.
568  KWin::forceActiveWindow( window->winId());
569  }
570  }
571  TDEStartupInfo::handleAutoAppStartedSending();
572  }
573 
574 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O,
575  TDEStartupInfoData& data_O )
576  {
577  return check_startup_internal( w_P, &id_O, &data_O );
578  }
579 
580 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O )
581  {
582  return check_startup_internal( w_P, &id_O, NULL );
583  }
584 
585 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoData& data_O )
586  {
587  return check_startup_internal( w_P, NULL, &data_O );
588  }
589 
590 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P )
591  {
592  return check_startup_internal( w_P, NULL, NULL );
593  }
594 
595 TDEStartupInfo::startup_t TDEStartupInfo::check_startup_internal( WId w_P, TDEStartupInfoId* id_O,
596  TDEStartupInfoData* data_O )
597  {
598  if( d == NULL )
599  return NoMatch;
600  if( d->startups.count() == 0 )
601  return NoMatch; // no startups
602  // Strategy:
603  //
604  // Is this a compliant app ?
605  // - Yes - test for match
606  // - No - Is this a NET_WM compliant app ?
607  // - Yes - test for pid match
608  // - No - test for WM_CLASS match
609  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup" << endl;
610  TQCString id = windowStartupId( w_P );
611  if( !id.isNull())
612  {
613  if( id.isEmpty() || id == "0" ) // means ignore this window
614  {
615  kdDebug( 172 ) << "[tdecore-tdestartupinfo] ignore" << endl;
616  return NoMatch;
617  }
618  return find_id( id, id_O, data_O ) ? Match : NoMatch;
619  }
620 #ifdef Q_WS_X11
621  NETWinInfo info( tqt_xdisplay(), w_P, tqt_xrootwin(),
622  NET::WMWindowType | NET::WMPid | NET::WMState );
623  pid_t pid = info.pid();
624  if( pid > 0 )
625  {
626  TQCString hostname = get_window_hostname( w_P );
627  if( !hostname.isEmpty()
628  && find_pid( pid, hostname, id_O, data_O ))
629  return Match;
630  // try XClass matching , this PID stuff sucks :(
631  }
632  XClassHint hint;
633  if( XGetClassHint( tqt_xdisplay(), w_P, &hint ) != 0 )
634  { // We managed to read the class hint
635  TQCString res_name = hint.res_name;
636  TQCString res_class = hint.res_class;
637  XFree( hint.res_name );
638  XFree( hint.res_class );
639  if( find_wclass( res_name, res_class, id_O, data_O ))
640  return Match;
641  }
642  // ignore NET::Tool and other special window types, if they can't be matched
643  NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
644  | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
645  | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
646  if( type != NET::Normal
647  && type != NET::Override
648  && type != NET::Unknown
649  && type != NET::Dialog
650  && type != NET::Utility )
651 // && type != NET::Dock ) why did I put this here?
652  return NoMatch;
653  // lets see if this is a transient
654  Window transient_for;
655  if( XGetTransientForHint( tqt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
656  && static_cast< WId >( transient_for ) != tqt_xrootwin()
657  && transient_for != None )
658  return NoMatch;
659 #endif
660  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup:cantdetect" << endl;
661  return CantDetect;
662  }
663 
664 bool TDEStartupInfo::find_id( const TQCString& id_P, TDEStartupInfoId* id_O,
665  TDEStartupInfoData* data_O )
666  {
667  if( d == NULL )
668  return false;
669  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_id:" << id_P << endl;
670  TDEStartupInfoId id;
671  id.initId( id_P );
672  if( d->startups.contains( id ))
673  {
674  if( id_O != NULL )
675  *id_O = id;
676  if( data_O != NULL )
677  *data_O = d->startups[ id ];
678  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_id:match" << endl;
679  return true;
680  }
681  return false;
682  }
683 
684 bool TDEStartupInfo::find_pid( pid_t pid_P, const TQCString& hostname_P,
685  TDEStartupInfoId* id_O, TDEStartupInfoData* data_O )
686  {
687  if( d == NULL )
688  return false;
689  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_pid:" << pid_P << endl;
690  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
691  it != d->startups.end();
692  ++it )
693  {
694  if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
695  { // Found it !
696  if( id_O != NULL )
697  *id_O = it.key();
698  if( data_O != NULL )
699  *data_O = *it;
700  // non-compliant, remove on first match
701  remove_startup_info_internal( it.key());
702  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_pid:match" << endl;
703  return true;
704  }
705  }
706  return false;
707  }
708 
709 bool TDEStartupInfo::find_wclass( TQCString res_name, TQCString res_class,
710  TDEStartupInfoId* id_O, TDEStartupInfoData* data_O )
711  {
712  if( d == NULL )
713  return false;
714  res_name = res_name.lower();
715  res_class = res_class.lower();
716  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_wclass:" << res_name << ":" << res_class << endl;
717  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
718  it != d->startups.end();
719  ++it )
720  {
721  const TQCString wmclass = ( *it ).findWMClass();
722  if( wmclass.lower() == res_name || wmclass.lower() == res_class )
723  { // Found it !
724  if( id_O != NULL )
725  *id_O = it.key();
726  if( data_O != NULL )
727  *data_O = *it;
728  // non-compliant, remove on first match
729  remove_startup_info_internal( it.key());
730  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_wclass:match" << endl;
731  return true;
732  }
733  }
734  return false;
735  }
736 
737 #ifdef Q_WS_X11
738 static Atom net_startup_atom = None;
739 
740 static TQCString read_startup_id_property( WId w_P )
741  {
742  TQCString ret;
743  unsigned char *name_ret;
744  Atom type_ret;
745  int format_ret;
746  unsigned long nitems_ret = 0, after_ret = 0;
747  if( XGetWindowProperty( tqt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
748  False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
749  == Success )
750  {
751  if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
752  ret = reinterpret_cast< char* >( name_ret );
753  if ( name_ret != NULL )
754  XFree( name_ret );
755  }
756  return ret;
757  }
758 
759 #endif
760 
761 TQCString TDEStartupInfo::windowStartupId( WId w_P )
762  {
763 #ifdef Q_WS_X11
764  if( net_startup_atom == None )
765  net_startup_atom = XInternAtom( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
766  if( utf8_string_atom == None )
767  utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
768  TQCString ret = read_startup_id_property( w_P );
769  if( ret.isEmpty())
770  { // retry with window group leader, as the spec says
771  XWMHints* hints = XGetWMHints( tqt_xdisplay(), w_P );
772  if( hints && ( hints->flags & WindowGroupHint ) != 0 )
773  ret = read_startup_id_property( hints->window_group );
774  if( hints )
775  XFree( hints );
776  }
777  return ret;
778 #else
779  return TQCString();
780 #endif
781  }
782 
783 void TDEStartupInfo::setWindowStartupId( WId w_P, const TQCString& id_P )
784  {
785 #ifdef Q_WS_X11
786  if( id_P.isNull())
787  return;
788  if( net_startup_atom == None )
789  net_startup_atom = XInternAtom( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
790  if( utf8_string_atom == None )
791  utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
792  XChangeProperty( tqt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
793  PropModeReplace, reinterpret_cast< unsigned char* >( const_cast<TQCString&>(id_P).data()), id_P.length());
794 #endif
795  }
796 
797 TQCString TDEStartupInfo::get_window_hostname( WId w_P )
798  {
799 #ifdef Q_WS_X11
800  XTextProperty tp;
801  char** hh;
802  int cnt;
803  if( XGetWMClientMachine( tqt_xdisplay(), w_P, &tp ) != 0
804  && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
805  {
806  if( cnt == 1 )
807  {
808  TQCString hostname = hh[ 0 ];
809  XFreeStringList( hh );
810  return hostname;
811  }
812  XFreeStringList( hh );
813  }
814 #endif
815  // no hostname
816  return TQCString();
817  }
818 
819 void TDEStartupInfo::setTimeout( unsigned int secs_P )
820  {
821  timeout = secs_P;
822  // schedule removing entries that are older than the new timeout
823  TQTimer::singleShot( 0, this, TQT_SLOT( startups_cleanup_no_age()));
824  }
825 
826 void TDEStartupInfo::startups_cleanup_no_age()
827  {
828  startups_cleanup_internal( false );
829  }
830 
831 void TDEStartupInfo::startups_cleanup()
832  {
833  if( d == NULL )
834  return;
835  if( d->startups.count() == 0 && d->silent_startups.count() == 0
836  && d->uninited_startups.count() == 0 )
837  {
838  d->cleanup->stop();
839  return;
840  }
841  startups_cleanup_internal( true );
842  }
843 
844 void TDEStartupInfo::startups_cleanup_internal( bool age_P )
845  {
846  if( d == NULL )
847  return;
848  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
849  it != d->startups.end();
850  )
851  {
852  if( age_P )
853  ( *it ).age++;
854  unsigned int tout = timeout;
855  if( ( *it ).silent() == Data::Yes ) // TODO
856  tout *= 20;
857  if( ( *it ).age >= tout )
858  {
859  const TDEStartupInfoId& key = it.key();
860  ++it;
861  kdDebug( 172 ) << "[tdecore-tdestartupinfo] startups entry timeout:" << key.id() << endl;
862  remove_startup_info_internal( key );
863  }
864  else
865  ++it;
866  }
867  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
868  it != d->silent_startups.end();
869  )
870  {
871  if( age_P )
872  ( *it ).age++;
873  unsigned int tout = timeout;
874  if( ( *it ).silent() == Data::Yes ) // TODO
875  tout *= 20;
876  if( ( *it ).age >= tout )
877  {
878  const TDEStartupInfoId& key = it.key();
879  ++it;
880  kdDebug( 172 ) << "[tdecore-tdestartupinfo] silent entry timeout:" << key.id() << endl;
881  remove_startup_info_internal( key );
882  }
883  else
884  ++it;
885  }
886  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->uninited_startups.begin();
887  it != d->uninited_startups.end();
888  )
889  {
890  if( age_P )
891  ( *it ).age++;
892  unsigned int tout = timeout;
893  if( ( *it ).silent() == Data::Yes ) // TODO
894  tout *= 20;
895  if( ( *it ).age >= tout )
896  {
897  const TDEStartupInfoId& key = it.key();
898  ++it;
899  kdDebug( 172 ) << "[tdecore-tdestartupinfo] uninited entry timeout:" << key.id() << endl;
900  remove_startup_info_internal( key );
901  }
902  else
903  ++it;
904  }
905  }
906 
907 void TDEStartupInfo::clean_all_noncompliant()
908  {
909  if( d == NULL )
910  return;
911  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
912  it != d->startups.end();
913  )
914  {
915  if( ( *it ).WMClass() != "0" )
916  {
917  ++it;
918  continue;
919  }
920  const TDEStartupInfoId& key = it.key();
921  ++it;
922  kdDebug( 172 ) << "[tdecore-tdestartupinfo] entry cleaning:" << key.id() << endl;
923  remove_startup_info_internal( key );
924  }
925  }
926 
927 TQCString TDEStartupInfo::createNewStartupId()
928  {
929  // Assign a unique id, use hostname+time+pid, that should be 200% unique.
930  // Also append the user timestamp (for focus stealing prevention).
931  struct timeval tm;
932  gettimeofday( &tm, NULL );
933  char hostname[ 256 ];
934  hostname[ 0 ] = '\0';
935  if (!gethostname( hostname, 255 ))
936  hostname[sizeof(hostname)-1] = '\0';
937  TQCString id = TQString(TQString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec )
938  .arg( tm.tv_usec ).arg( getpid()).arg( GET_QT_X_USER_TIME() )).utf8();
939  kdDebug( 172 ) << "[tdecore-tdestartupinfo] creating: " << id << ":" << tqAppName() << endl;
940  return id;
941  }
942 
943 
944 struct TDEStartupInfoIdPrivate
945  {
946  TDEStartupInfoIdPrivate() : id( "" ) {}
947  TQCString id; // id
948  };
949 
950 const TQCString& TDEStartupInfoId::id() const
951  {
952  return d->id;
953  }
954 
955 
956 TQString TDEStartupInfoId::to_text() const
957  {
958  return TQString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
959  }
960 
961 TDEStartupInfoId::TDEStartupInfoId( const TQString& txt_P )
962  {
963  d = new TDEStartupInfoIdPrivate;
964  TQStringList items = get_fields( txt_P );
965  const TQString id_str = TQString::fromLatin1( "ID=" );
966  for( TQStringList::Iterator it = items.begin();
967  it != items.end();
968  ++it )
969  {
970  if( ( *it ).startsWith( id_str ))
971  d->id = get_cstr( *it );
972  }
973  }
974 
975 void TDEStartupInfoId::initId( const TQCString& id_P )
976  {
977  if( !id_P.isEmpty())
978  {
979  d->id = id_P;
980 #ifdef KSTARTUPINFO_ALL_DEBUG
981  kdDebug( 172 ) << "[tdecore-tdestartupinfo] using: " << d->id << endl;
982 #endif
983  return;
984  }
985  const char* startup_env = getenv( NET_STARTUP_ENV );
986  if( startup_env != NULL && *startup_env != '\0' )
987  { // already has id
988  d->id = startup_env;
989 #ifdef KSTARTUPINFO_ALL_DEBUG
990  kdDebug( 172 ) << "[tdecore-tdestartupinfo] reusing: " << d->id << endl;
991 #endif
992  return;
993  }
994  d->id = TDEStartupInfo::createNewStartupId();
995  }
996 
997 bool TDEStartupInfoId::setupStartupEnv() const
998  {
999  if( id().isEmpty())
1000  {
1001  unsetenv( NET_STARTUP_ENV );
1002  return false;
1003  }
1004  return setenv( NET_STARTUP_ENV, id(), true ) == 0;
1005  }
1006 
1007 TDEStartupInfoId TDEStartupInfo::currentStartupIdEnv()
1008  {
1009  const char* startup_env = getenv( NET_STARTUP_ENV );
1010  TDEStartupInfoId id;
1011  if( startup_env != NULL && *startup_env != '\0' )
1012  id.d->id = startup_env;
1013  else
1014  id.d->id = "0";
1015  return id;
1016  }
1017 
1018 void TDEStartupInfo::resetStartupEnv()
1019  {
1020  unsetenv( NET_STARTUP_ENV );
1021  }
1022 
1023 TDEStartupInfoId::TDEStartupInfoId()
1024  {
1025  d = new TDEStartupInfoIdPrivate;
1026  }
1027 
1028 TDEStartupInfoId::~TDEStartupInfoId()
1029  {
1030  delete d;
1031  }
1032 
1033 TDEStartupInfoId::TDEStartupInfoId( const TDEStartupInfoId& id_P )
1034  {
1035  d = new TDEStartupInfoIdPrivate( *id_P.d );
1036  }
1037 
1038 TDEStartupInfoId& TDEStartupInfoId::operator=( const TDEStartupInfoId& id_P )
1039  {
1040  if( &id_P == this )
1041  return *this;
1042  delete d;
1043  d = new TDEStartupInfoIdPrivate( *id_P.d );
1044  return *this;
1045  }
1046 
1047 bool TDEStartupInfoId::operator==( const TDEStartupInfoId& id_P ) const
1048  {
1049  return id() == id_P.id();
1050  }
1051 
1052 bool TDEStartupInfoId::operator!=( const TDEStartupInfoId& id_P ) const
1053  {
1054  return !(*this == id_P );
1055  }
1056 
1057 // needed for QMap
1058 bool TDEStartupInfoId::operator<( const TDEStartupInfoId& id_P ) const
1059  {
1060  return id() < id_P.id();
1061  }
1062 
1063 bool TDEStartupInfoId::none() const
1064  {
1065  return d->id.isEmpty() || d->id == "0";
1066  }
1067 
1068 unsigned long TDEStartupInfoId::timestamp() const
1069  {
1070  if( none())
1071  return 0;
1072  int pos = d->id.findRev( "_TIME" );
1073  if( pos >= 0 )
1074  {
1075  bool ok;
1076  unsigned long time = d->id.mid( pos + 5 ).toULong( &ok );
1077  if( !ok && d->id[ pos + 5 ] == '-' ) // try if it's as a negative signed number perhaps
1078  time = d->id.mid( pos + 5 ).toLong( &ok );
1079  if( ok )
1080  return time;
1081  }
1082  // libstartup-notification style :
1083  // snprintf (s, len, "%s/%s/%lu/%d-%d-%s",
1084  // canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp,
1085  // (int) getpid (), (int) sequence_number, hostbuf);
1086  int pos1 = d->id.findRev( '/' );
1087  if( pos1 > 0 )
1088  {
1089  int pos2 = d->id.findRev( '/', pos1 - 1 );
1090  if( pos2 >= 0 )
1091  {
1092  bool ok;
1093  unsigned long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toULong( &ok );
1094  if( !ok && d->id[ pos2 + 1 ] == '-' ) // try if it's as a negative signed number perhaps
1095  time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok );
1096  if( ok )
1097  return time;
1098  }
1099  }
1100  // bah ... old TDEStartupInfo or a problem
1101  return 0;
1102  }
1103 
1104 struct TDEStartupInfoDataPrivate
1105  {
1106  TDEStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
1107  silent( TDEStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ), xinerama( -1 ), launched_by( 0 ) {}
1108  TQString bin;
1109  TQString name;
1110  TQString description;
1111  TQString icon;
1112  int desktop;
1113  TQValueList< pid_t > pids;
1114  TQCString wmclass;
1115  TQCString hostname;
1116  TDEStartupInfoData::TriState silent;
1117  unsigned long timestamp;
1118  int screen;
1119  int xinerama;
1120  WId launched_by;
1121  };
1122 
1123 TQString TDEStartupInfoData::to_text() const
1124  {
1125  TQString ret = "";
1126  if( !d->bin.isEmpty())
1127  ret += TQString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
1128  if( !d->name.isEmpty())
1129  ret += TQString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
1130  if( !d->description.isEmpty())
1131  ret += TQString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
1132  if( !d->icon.isEmpty())
1133  ret += TQString::fromLatin1( " ICON=%1" ).arg( d->icon );
1134  if( d->desktop != 0 )
1135  ret += TQString::fromLatin1( " DESKTOP=%1" )
1136  .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
1137  if( !d->wmclass.isEmpty())
1138  ret += TQString::fromLatin1( " WMCLASS=\"%1\"" ).arg( QString(d->wmclass) );
1139  if( !d->hostname.isEmpty())
1140  ret += TQString::fromLatin1( " HOSTNAME=%1" ).arg( QString(d->hostname) );
1141  for( TQValueList< pid_t >::ConstIterator it = d->pids.begin();
1142  it != d->pids.end();
1143  ++it )
1144  ret += TQString::fromLatin1( " PID=%1" ).arg( *it );
1145  if( d->silent != Unknown )
1146  ret += TQString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
1147  if( d->timestamp != -1U )
1148  ret += TQString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
1149  if( d->screen != -1 )
1150  ret += TQString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
1151  if( d->xinerama != -1 )
1152  ret += TQString::fromLatin1( " XINERAMA=%1" ).arg( d->xinerama );
1153  if( d->launched_by != 0 )
1154  ret += TQString::fromLatin1( " LAUNCHED_BY=%1" ).arg( d->launched_by );
1155  return ret;
1156  }
1157 
1158 TDEStartupInfoData::TDEStartupInfoData( const TQString& txt_P )
1159  {
1160  d = new TDEStartupInfoDataPrivate;
1161  TQStringList items = get_fields( txt_P );
1162  const TQString bin_str = TQString::fromLatin1( "BIN=" );
1163  const TQString name_str = TQString::fromLatin1( "NAME=" );
1164  const TQString description_str = TQString::fromLatin1( "DESCRIPTION=" );
1165  const TQString icon_str = TQString::fromLatin1( "ICON=" );
1166  const TQString desktop_str = TQString::fromLatin1( "DESKTOP=" );
1167  const TQString wmclass_str = TQString::fromLatin1( "WMCLASS=" );
1168  const TQString hostname_str = TQString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
1169  const TQString pid_str = TQString::fromLatin1( "PID=" ); // SELI nonstd
1170  const TQString silent_str = TQString::fromLatin1( "SILENT=" );
1171  const TQString timestamp_str = TQString::fromLatin1( "TIMESTAMP=" );
1172  const TQString screen_str = TQString::fromLatin1( "SCREEN=" );
1173  const TQString xinerama_str = TQString::fromLatin1( "XINERAMA=" );
1174  const TQString launched_by_str = TQString::fromLatin1( "LAUNCHED_BY=" );
1175  for( TQStringList::Iterator it = items.begin();
1176  it != items.end();
1177  ++it )
1178  {
1179  if( ( *it ).startsWith( bin_str ))
1180  d->bin = get_str( *it );
1181  else if( ( *it ).startsWith( name_str ))
1182  d->name = get_str( *it );
1183  else if( ( *it ).startsWith( description_str ))
1184  d->description = get_str( *it );
1185  else if( ( *it ).startsWith( icon_str ))
1186  d->icon = get_str( *it );
1187  else if( ( *it ).startsWith( desktop_str ))
1188  {
1189  d->desktop = get_num( *it );
1190  if( d->desktop != NET::OnAllDesktops )
1191  ++d->desktop; // spec counts from 0
1192  }
1193  else if( ( *it ).startsWith( wmclass_str ))
1194  d->wmclass = get_cstr( *it );
1195  else if( ( *it ).startsWith( hostname_str ))
1196  d->hostname = get_cstr( *it );
1197  else if( ( *it ).startsWith( pid_str ))
1198  addPid( get_num( *it ));
1199  else if( ( *it ).startsWith( silent_str ))
1200  d->silent = get_num( *it ) != 0 ? Yes : No;
1201  else if( ( *it ).startsWith( timestamp_str ))
1202  d->timestamp = get_unum( *it );
1203  else if( ( *it ).startsWith( screen_str ))
1204  d->screen = get_num( *it );
1205  else if( ( *it ).startsWith( xinerama_str ))
1206  d->xinerama = get_num( *it );
1207  else if( ( *it ).startsWith( launched_by_str ))
1208  d->launched_by = get_num( *it );
1209  }
1210  }
1211 
1212 TDEStartupInfoData::TDEStartupInfoData( const TDEStartupInfoData& data )
1213 {
1214  d = new TDEStartupInfoDataPrivate( *data.d );
1215 }
1216 
1217 TDEStartupInfoData& TDEStartupInfoData::operator=( const TDEStartupInfoData& data )
1218 {
1219  if( &data == this )
1220  return *this;
1221  delete d;
1222  d = new TDEStartupInfoDataPrivate( *data.d );
1223  return *this;
1224 }
1225 
1226 void TDEStartupInfoData::update( const TDEStartupInfoData& data_P )
1227  {
1228  if( !data_P.bin().isEmpty())
1229  d->bin = data_P.bin();
1230  if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
1231  d->name = data_P.name();
1232  if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
1233  d->description = data_P.description();
1234  if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
1235  d->icon = data_P.icon();
1236  if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
1237  d->desktop = data_P.desktop();
1238  if( !data_P.d->wmclass.isEmpty())
1239  d->wmclass = data_P.d->wmclass;
1240  if( !data_P.d->hostname.isEmpty())
1241  d->hostname = data_P.d->hostname;
1242  for( TQValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
1243  it != data_P.d->pids.end();
1244  ++it )
1245  addPid( *it );
1246  if( data_P.silent() != Unknown )
1247  d->silent = data_P.silent();
1248  if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
1249  d->timestamp = data_P.timestamp();
1250  if( data_P.screen() != -1 )
1251  d->screen = data_P.screen();
1252  if( data_P.xinerama() != -1 && xinerama() != -1 ) // don't overwrite
1253  d->xinerama = data_P.xinerama();
1254  if( data_P.launchedBy() != 0 && launchedBy() != 0 ) // don't overwrite
1255  d->launched_by = data_P.launchedBy();
1256  }
1257 
1258 TDEStartupInfoData::TDEStartupInfoData()
1259 {
1260  d = new TDEStartupInfoDataPrivate;
1261 }
1262 
1263 TDEStartupInfoData::~TDEStartupInfoData()
1264 {
1265  delete d;
1266 }
1267 
1268 void TDEStartupInfoData::setBin( const TQString& bin_P )
1269  {
1270  d->bin = bin_P;
1271  }
1272 
1273 const TQString& TDEStartupInfoData::bin() const
1274  {
1275  return d->bin;
1276  }
1277 
1278 void TDEStartupInfoData::setName( const TQString& name_P )
1279  {
1280  d->name = name_P;
1281  }
1282 
1283 const TQString& TDEStartupInfoData::name() const
1284  {
1285  return d->name;
1286  }
1287 
1288 const TQString& TDEStartupInfoData::findName() const
1289  {
1290  if( !name().isEmpty())
1291  return name();
1292  return bin();
1293  }
1294 
1295 void TDEStartupInfoData::setDescription( const TQString& desc_P )
1296  {
1297  d->description = desc_P;
1298  }
1299 
1300 const TQString& TDEStartupInfoData::description() const
1301  {
1302  return d->description;
1303  }
1304 
1305 const TQString& TDEStartupInfoData::findDescription() const
1306  {
1307  if( !description().isEmpty())
1308  return description();
1309  return name();
1310  }
1311 
1312 void TDEStartupInfoData::setIcon( const TQString& icon_P )
1313  {
1314  d->icon = icon_P;
1315  }
1316 
1317 const TQString& TDEStartupInfoData::findIcon() const
1318  {
1319  if( !icon().isEmpty())
1320  return icon();
1321  return bin();
1322  }
1323 
1324 const TQString& TDEStartupInfoData::icon() const
1325  {
1326  return d->icon;
1327  }
1328 
1329 void TDEStartupInfoData::setDesktop( int desktop_P )
1330  {
1331  d->desktop = desktop_P;
1332  }
1333 
1334 int TDEStartupInfoData::desktop() const
1335  {
1336  return d->desktop;
1337  }
1338 
1339 void TDEStartupInfoData::setWMClass( const TQCString& wmclass_P )
1340  {
1341  d->wmclass = wmclass_P;
1342  }
1343 
1344 const TQCString TDEStartupInfoData::findWMClass() const
1345  {
1346  if( !WMClass().isEmpty() && WMClass() != "0" )
1347  return WMClass();
1348  return bin().utf8();
1349  }
1350 
1351 const TQCString& TDEStartupInfoData::WMClass() const
1352  {
1353  return d->wmclass;
1354  }
1355 
1356 void TDEStartupInfoData::setHostname( const TQCString& hostname_P )
1357  {
1358  if( !hostname_P.isNull())
1359  d->hostname = hostname_P;
1360  else
1361  {
1362  char tmp[ 256 ];
1363  tmp[ 0 ] = '\0';
1364  if (!gethostname( tmp, 255 ))
1365  tmp[sizeof(tmp)-1] = '\0';
1366  d->hostname = tmp;
1367  }
1368  }
1369 
1370 const TQCString& TDEStartupInfoData::hostname() const
1371  {
1372  return d->hostname;
1373  }
1374 
1375 void TDEStartupInfoData::addPid( pid_t pid_P )
1376  {
1377  if( !d->pids.contains( pid_P ))
1378  d->pids.append( pid_P );
1379  }
1380 
1381 void TDEStartupInfoData::remove_pid( pid_t pid_P )
1382  {
1383  d->pids.remove( pid_P );
1384  }
1385 
1386 const TQValueList< pid_t >& TDEStartupInfoData::pids() const
1387  {
1388  return d->pids;
1389  }
1390 
1391 bool TDEStartupInfoData::is_pid( pid_t pid_P ) const
1392  {
1393  return d->pids.contains( pid_P );
1394  }
1395 
1396 void TDEStartupInfoData::setSilent( TriState state_P )
1397  {
1398  d->silent = state_P;
1399  }
1400 
1401 TDEStartupInfoData::TriState TDEStartupInfoData::silent() const
1402  {
1403  return d->silent;
1404  }
1405 
1406 void TDEStartupInfoData::setTimestamp( unsigned long time )
1407  {
1408  d->timestamp = time;
1409  }
1410 
1411 unsigned long TDEStartupInfoData::timestamp() const
1412  {
1413  return d->timestamp;
1414  }
1415 
1416 void TDEStartupInfoData::setScreen( int screen )
1417  {
1418  d->screen = screen;
1419  }
1420 
1421 int TDEStartupInfoData::screen() const
1422  {
1423  return d->screen;
1424  }
1425 
1426 void TDEStartupInfoData::setXinerama( int xinerama )
1427  {
1428  d->xinerama = xinerama;
1429  }
1430 
1431 int TDEStartupInfoData::xinerama() const
1432  {
1433  return d->xinerama;
1434  }
1435 
1436 void TDEStartupInfoData::setLaunchedBy( WId window )
1437  {
1438  d->launched_by = window;
1439  }
1440 
1441 WId TDEStartupInfoData::launchedBy() const
1442  {
1443  return d->launched_by;
1444  }
1445 
1446 static
1447 long get_num( const TQString& item_P )
1448  {
1449  unsigned int pos = item_P.find( '=' );
1450  return item_P.mid( pos + 1 ).toLong();
1451  }
1452 
1453 static
1454 unsigned long get_unum( const TQString& item_P )
1455  {
1456  unsigned int pos = item_P.find( '=' );
1457  return item_P.mid( pos + 1 ).toULong();
1458  }
1459 
1460 static
1461 TQString get_str( const TQString& item_P )
1462  {
1463  unsigned int pos = item_P.find( '=' );
1464  if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == (QChar)'\"' )
1465  {
1466  int pos2 = item_P.left( pos + 2 ).find( '\"' );
1467  if( pos2 < 0 )
1468  return TQString::null; // 01234
1469  return item_P.mid( pos + 2, pos2 - 2 - pos ); // A="C"
1470  }
1471  return item_P.mid( pos + 1 );
1472  }
1473 
1474 static
1475 TQCString get_cstr( const TQString& item_P )
1476  {
1477  return get_str( item_P ).utf8();
1478  }
1479 
1480 static
1481 TQStringList get_fields( const TQString& txt_P )
1482  {
1483  TQString txt = txt_P.simplifyWhiteSpace();
1484  TQStringList ret;
1485  TQString item = "";
1486  bool in = false;
1487  bool escape = false;
1488  for( unsigned int pos = 0;
1489  pos < txt.length();
1490  ++pos )
1491  {
1492  if( escape )
1493  {
1494  item += txt[ pos ];
1495  escape = false;
1496  }
1497  else if( txt[ pos ] == '\\' )
1498  escape = true;
1499  else if( txt[ pos ] == '\"' )
1500  in = !in;
1501  else if( txt[ pos ] == ' ' && !in )
1502  {
1503  ret.append( item );
1504  item = "";
1505  }
1506  else
1507  item += txt[ pos ];
1508  }
1509  ret.append( item );
1510  return ret;
1511  }
1512 
1513 static TQString escape_str( const TQString& str_P )
1514  {
1515  TQString ret = "";
1516  for( unsigned int pos = 0;
1517  pos < str_P.length();
1518  ++pos )
1519  {
1520  if( str_P[ pos ] == (QChar)'\\'
1521  || str_P[ pos ] == (QChar)'"' )
1522  ret += '\\';
1523  ret += str_P[ pos ];
1524  }
1525  return ret;
1526  }
1527 
1528 #include "tdestartupinfo.moc"
1529 #endif
TDEStdAccel::description
TQString description(StdAccel id)
Definition: tdestdaccel.cpp:381
TDEStdAccel::key
int key(StdAccel id)
Definition: tdestdaccel.cpp:383
NET::Override
Definition: netwm_def.h:302
KWinModule
The class KWinModule provides information about the state of the window manager as required by window...
Definition: twinmodule.h:56
NET::WindowType
WindowType
Window type.
Definition: netwm_def.h:294
KWin::forceActiveWindow
static void forceActiveWindow(WId win, long time=0)
Sets window win to be the active window.
Definition: twin.cpp:249
KStdAction::name
const char * name(StdAction id)
KWin::currentDesktop
static int currentDesktop()
Convenience function to access the current desktop.
Definition: twin.cpp:641
TDEApplication::kApplication
static TDEApplication * kApplication()
Returns the current application object.
Definition: tdeapplication.h:301
NET::Utility
Definition: netwm_def.h:305
endl
kndbgstream & endl(kndbgstream &s)
Does nothing.
Definition: kdebug.h:583
KWin::setOnDesktop
static void setOnDesktop(WId win, int desktop)
Moves window win to desktop desktop.
Definition: twin.cpp:597

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.