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