main.cpp
00001 /***************************************************************** 00002 KWin - the KDE window manager 00003 This file is part of the KDE project. 00004 00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> 00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> 00007 00008 You can Freely distribute this program under the GNU General Public 00009 License. See the file "COPYING" for the exact licensing terms. 00010 ******************************************************************/ 00011 00012 //#define QT_CLEAN_NAMESPACE 00013 #include <tdeconfig.h> 00014 00015 #include "main.h" 00016 00017 #include <tdelocale.h> 00018 #include <tdeglobal.h> 00019 #include <kdebug.h> 00020 #include <stdlib.h> 00021 #include <tdecmdlineargs.h> 00022 #include <tdeaboutdata.h> 00023 #include <dcopclient.h> 00024 #include <dcopref.h> 00025 #include <unistd.h> 00026 #include <signal.h> 00027 #include <fcntl.h> 00028 00029 #include "atoms.h" 00030 #include "options.h" 00031 #include "sm.h" 00032 00033 #define INT8 _X11INT8 00034 #define INT32 _X11INT32 00035 #include <X11/Xproto.h> 00036 #undef INT8 00037 #undef INT32 00038 00039 namespace KWinInternal 00040 { 00041 00042 Options* options; 00043 00044 Atoms* atoms; 00045 00046 int screen_number = -1; 00047 bool disable_twin_composition_manager = false; 00048 00049 static bool initting = FALSE; 00050 00051 static 00052 int x11ErrorHandler(Display *d, XErrorEvent *e) 00053 { 00054 char msg[80], req[80], number[80]; 00055 bool ignore_badwindow = TRUE; //maybe temporary 00056 00057 if (initting && 00058 ( 00059 e->request_code == X_ChangeWindowAttributes 00060 || e->request_code == X_GrabKey 00061 ) 00062 && (e->error_code == BadAccess)) 00063 { 00064 fputs(i18n("[twin] it looks like there's already a window manager running. twin not started.\n").local8Bit(), stderr); 00065 exit(1); 00066 } 00067 00068 if (ignore_badwindow && (e->error_code == BadWindow || e->error_code == BadColor)) 00069 return 0; 00070 00071 XGetErrorText(d, e->error_code, msg, sizeof(msg)); 00072 sprintf(number, "%d", e->request_code); 00073 XGetErrorDatabaseText(d, "XRequest", number, "<unknown>", req, sizeof(req)); 00074 00075 fprintf(stderr, "[twin] %s(0x%lx): %s\n", req, e->resourceid, msg); 00076 00077 if (initting) 00078 { 00079 fputs(i18n("[twin] failure during initialization; aborting").local8Bit(), stderr); 00080 exit(1); 00081 } 00082 return 0; 00083 } 00084 00085 Application::Application( ) 00086 : TDEApplication( ), owner( screen_number ) 00087 { 00088 #ifdef USE_QT4 00089 // I'm special... 00090 setQuitOnLastWindowClosed(false); 00091 #endif // USE_QT4 00092 TDECmdLineArgs* args = TDECmdLineArgs::parsedArgs(); 00093 if (!config()->isImmutable() && args->isSet("lock")) 00094 { 00095 config()->setReadOnly(true); 00096 config()->reparseConfiguration(); 00097 } 00098 00099 if (screen_number == -1) { 00100 screen_number = DefaultScreen(tqt_xdisplay()); 00101 } 00102 00103 if (args->isSet( "disablecompositionmanager" )) { 00104 disable_twin_composition_manager = true; 00105 } 00106 00107 if( !owner.claim( args->isSet( "replace" ), true )) 00108 { 00109 Display* dpy = tqt_xdisplay(); 00110 Window w; 00111 Atom a; 00112 static char net_wm_sm[] = "WM_Sxx"; 00113 00114 snprintf (net_wm_sm, sizeof (net_wm_sm), "WM_S%d", screen_number); 00115 a = XInternAtom (dpy, net_wm_sm, False); 00116 00117 w = XGetSelectionOwner (dpy, a); 00118 00119 if (w != None) 00120 { 00121 Atom actual; 00122 int format; 00123 unsigned long n, left; 00124 unsigned char *data; 00125 Atom twinRunningAtom = XInternAtom (dpy, "_KDE_WM_IS_KWIN", True); 00126 00127 int result = XGetWindowProperty (dpy, w, twinRunningAtom, 0L, 1L, False, 00128 XA_ATOM, &actual, &format, 00129 &n, &left, &data); 00130 00131 if (result == Success && data != None && format == 32 ) 00132 { 00133 Atom a; 00134 a = *(long*)data; 00135 XFree ( (void *) data); 00136 if( !owner.claim( true, true )) 00137 { 00138 fputs(i18n("[twin] unable to claim manager selection, another wm running? (try using --replace)\n").local8Bit(), stderr); 00139 ::exit(1); 00140 } 00141 } 00142 else 00143 { 00144 fputs(i18n("[twin] unable to claim manager selection, another wm running? (try using --replace)\n").local8Bit(), stderr); 00145 ::exit(1); 00146 } 00147 } 00148 else 00149 { 00150 fputs(i18n("[twin] unable to claim manager selection, another wm running? (try using --replace)\n").local8Bit(), stderr); 00151 ::exit(1); 00152 } 00153 } 00154 connect( &owner, TQT_SIGNAL( lostOwnership()), TQT_SLOT( lostSelection())); 00155 00156 // if there was already twin running, it saved its configuration after loosing the selection -> reread 00157 config()->reparseConfiguration(); 00158 00159 initting = TRUE; // startup.... 00160 00161 // install X11 error handler 00162 XSetErrorHandler( x11ErrorHandler ); 00163 00164 // check whether another windowmanager is running 00165 XSelectInput(tqt_xdisplay(), tqt_xrootwin(), SubstructureRedirectMask ); 00166 syncX(); // trigger error now 00167 00168 options = new Options; 00169 atoms = new Atoms; 00170 00171 // Signal that we are The KWin! 00172 Atom kde_wm_system_modal_notification; 00173 kde_wm_system_modal_notification = XInternAtom(tqt_xdisplay(), "_KDE_WM_IS_KWIN", False); 00174 XChangeProperty(tqt_xdisplay(), owner.ownerWindow(), kde_wm_system_modal_notification, XA_INTEGER, 32, PropModeReplace, (unsigned char *) "TRUE", 1L); 00175 00176 // create workspace. 00177 (void) new Workspace( isSessionRestored() ); 00178 00179 syncX(); // trigger possible errors, there's still a chance to abort 00180 00181 DCOPRef ref( "kded", "kded" ); 00182 ref.send( "unloadModule", TQCString( "kdetrayproxy" )); 00183 00184 initting = FALSE; // startup done, we are up and running now. 00185 00186 dcopClient()->send( "ksplash", "", "upAndRunning(TQString)", TQString("wm started")); 00187 XEvent e; 00188 e.xclient.type = ClientMessage; 00189 e.xclient.message_type = XInternAtom( tqt_xdisplay(), "_KDE_SPLASH_PROGRESS", False ); 00190 e.xclient.display = tqt_xdisplay(); 00191 e.xclient.window = tqt_xrootwin(); 00192 e.xclient.format = 8; 00193 strcpy( e.xclient.data.b, "wm started" ); 00194 XSendEvent( tqt_xdisplay(), tqt_xrootwin(), False, SubstructureNotifyMask, &e ); 00195 } 00196 00197 Application::~Application() 00198 { 00199 delete Workspace::self(); 00200 if( owner.ownerWindow() != None ) // if there was no --replace (no new WM) 00201 { 00202 XSetInputFocus( tqt_xdisplay(), PointerRoot, RevertToPointerRoot, GET_QT_X_TIME() ); 00203 DCOPRef ref( "kded", "kded" ); 00204 if( !ref.send( "loadModule", TQCString( "kdetrayproxy" ))) 00205 kdWarning( 176 ) << "Loading of kdetrayproxy failed." << endl; 00206 } 00207 delete options; 00208 } 00209 00210 void Application::lostSelection() 00211 { 00212 delete Workspace::self(); 00213 // remove windowmanager privileges 00214 XSelectInput(tqt_xdisplay(), tqt_xrootwin(), PropertyChangeMask ); 00215 DCOPRef ref( "kded", "kded" ); 00216 if( !ref.send( "loadModule", TQCString( "kdetrayproxy" ))) 00217 kdWarning( 176 ) << "Loading of kdetrayproxy failed." << endl; 00218 quit(); 00219 } 00220 00221 bool Application::x11EventFilter( XEvent *e ) 00222 { 00223 if ( Workspace::self()->workspaceEvent( e ) ) 00224 return TRUE; 00225 return TDEApplication::x11EventFilter( e ); 00226 } 00227 00228 static void sighandler(int) 00229 { 00230 TQApplication::exit(); 00231 } 00232 00233 00234 } // namespace 00235 00236 static const char version[] = "3.0"; 00237 static const char description[] = I18N_NOOP( "TDE window manager" ); 00238 00239 static TDECmdLineOptions args[] = 00240 { 00241 { "lock", I18N_NOOP("Disable configuration options"), 0 }, 00242 { "replace", I18N_NOOP("Replace already-running ICCCM2.0-compliant window manager"), 0 }, 00243 { "disablecompositionmanager", I18N_NOOP("Do not start composition manager"), 0 }, 00244 TDECmdLineLastOption 00245 }; 00246 00247 extern "C" 00248 KDE_EXPORT int kdemain( int argc, char * argv[] ) 00249 { 00250 bool restored = false; 00251 for (int arg = 1; arg < argc; arg++) 00252 { 00253 if (! qstrcmp(argv[arg], "-session")) 00254 { 00255 restored = true; 00256 break; 00257 } 00258 } 00259 00260 if (! restored) 00261 { 00262 // we only do the multihead fork if we are not restored by the session 00263 // manager, since the session manager will register multiple twins, 00264 // one for each screen... 00265 TQCString multiHead = getenv("TDE_MULTIHEAD"); 00266 if (multiHead.lower() == "true") 00267 { 00268 00269 Display* dpy = XOpenDisplay( NULL ); 00270 if ( !dpy ) 00271 { 00272 fprintf(stderr, "%s: FATAL ERROR while trying to open display %s\n", 00273 argv[0], XDisplayName(NULL ) ); 00274 exit (1); 00275 } 00276 00277 int number_of_screens = ScreenCount( dpy ); 00278 KWinInternal::screen_number = DefaultScreen( dpy ); 00279 int pos; // temporarily needed to reconstruct DISPLAY var if multi-head 00280 TQCString display_name = XDisplayString( dpy ); 00281 XCloseDisplay( dpy ); 00282 dpy = 0; 00283 00284 if ((pos = display_name.findRev('.')) != -1 ) 00285 display_name.remove(pos,10); // 10 is enough to be sure we removed ".s" 00286 00287 TQCString envir; 00288 if (number_of_screens != 1) 00289 { 00290 for (int i = 0; i < number_of_screens; i++ ) 00291 { 00292 // if execution doesn't pass by here, then twin 00293 // acts exactly as previously 00294 if ( i != KWinInternal::screen_number && fork() == 0 ) 00295 { 00296 KWinInternal::screen_number = i; 00297 // break here because we are the child process, we don't 00298 // want to fork() anymore 00299 break; 00300 } 00301 } 00302 // in the next statement, display_name shouldn't contain a screen 00303 // number. If it had it, it was removed at the "pos" check 00304 envir.sprintf("DISPLAY=%s.%d", display_name.data(), KWinInternal::screen_number); 00305 00306 if (putenv( strdup(envir.data())) ) 00307 { 00308 fprintf(stderr, 00309 "[twin] %s: WARNING: unable to set DISPLAY environment variable\n", 00310 argv[0]); 00311 perror("[twin] putenv()"); 00312 } 00313 } 00314 } 00315 } 00316 00317 TDEGlobal::locale()->setMainCatalogue("twin"); 00318 00319 TDEAboutData aboutData( "twin", I18N_NOOP("TWin"), 00320 version, description, TDEAboutData::License_GPL, 00321 I18N_NOOP("(c) 1999-2005, The KDE Developers")); 00322 aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); 00323 aboutData.addAuthor("Cristian Tibirna",0, "tibirna@kde.org"); 00324 aboutData.addAuthor("Daniel M. Duley",0, "mosfet@kde.org"); 00325 aboutData.addAuthor("Luboš Luňák", I18N_NOOP( "Maintainer" ), "l.lunak@kde.org"); 00326 00327 TDECmdLineArgs::init(argc, argv, &aboutData); 00328 TDECmdLineArgs::addCmdLineOptions( args ); 00329 00330 if (signal(SIGTERM, KWinInternal::sighandler) == SIG_IGN) 00331 signal(SIGTERM, SIG_IGN); 00332 if (signal(SIGINT, KWinInternal::sighandler) == SIG_IGN) 00333 signal(SIGINT, SIG_IGN); 00334 if (signal(SIGHUP, KWinInternal::sighandler) == SIG_IGN) 00335 signal(SIGHUP, SIG_IGN); 00336 00337 TDEApplication::disableAutoDcopRegistration(); 00338 KWinInternal::Application a; 00339 KWinInternal::SessionManaged weAreIndeed; 00340 KWinInternal::SessionSaveDoneHelper helper; 00341 00342 fcntl(ConnectionNumber(tqt_xdisplay()), F_SETFD, 1); 00343 00344 TQCString appname; 00345 if (KWinInternal::screen_number == 0) 00346 appname = "twin"; 00347 else 00348 appname.sprintf("twin-screen-%d", KWinInternal::screen_number); 00349 00350 DCOPClient* client = a.dcopClient(); 00351 client->registerAs( appname.data(), false); 00352 client->setDefaultObject( "KWinInterface" ); 00353 00354 return a.exec(); 00355 } 00356 00357 #include "main.moc"