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 <kconfig.h>
00014 
00015 #include "main.h"
00016 
00017 #include <klocale.h>
00018 #include <kglobal.h>
00019 #include <stdlib.h>
00020 #include <kcmdlineargs.h>
00021 #include <kaboutdata.h>
00022 #include <dcopclient.h>
00023 #include <unistd.h>
00024 #include <signal.h>
00025 #include <fcntl.h>
00026 
00027 #include "atoms.h"
00028 #include "options.h"
00029 #include "sm.h"
00030 
00031 #define INT8 _X11INT8
00032 #define INT32 _X11INT32
00033 #include <X11/Xproto.h>
00034 #undef INT8
00035 #undef INT32
00036 
00037 extern Time qt_x_time;
00038 
00039 namespace KWinInternal
00040 {
00041 
00042 Options* options;
00043 
00044 Atoms* atoms;
00045 
00046 int screen_number = -1;
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("kwin: it looks like there's already a window manager running. kwin 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, "kwin: %s(0x%lx): %s\n", req, e->resourceid, msg);
00075 
00076     if (initting) 
00077         {
00078         fputs(i18n("kwin: failure during initialization; aborting").local8Bit(), stderr);
00079         exit(1);
00080         }
00081     return 0;
00082     }
00083 
00084 Application::Application( )
00085 : KApplication( ), owner( screen_number )
00086     {
00087     KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
00088     if (!config()->isImmutable() && args->isSet("lock"))
00089         {
00090         config()->setReadOnly(true);
00091         config()->reparseConfiguration();
00092         }
00093 
00094     if (screen_number == -1)
00095         screen_number = DefaultScreen(qt_xdisplay());
00096 
00097     if( !owner.claim( args->isSet( "replace" ), true ))
00098         {
00099         fputs(i18n("kwin: unable to claim manager selection, another wm running? (try using --replace)\n").local8Bit(), stderr);
00100         ::exit(1);
00101         }
00102     connect( &owner, SIGNAL( lostOwnership()), SLOT( lostSelection()));
00103     
00104     // if there was already kwin running, it saved its configuration after loosing the selection -> reread
00105     config()->reparseConfiguration();
00106 
00107     initting = TRUE; // startup....
00108 
00109     // install X11 error handler
00110     XSetErrorHandler( x11ErrorHandler );
00111 
00112     // check  whether another windowmanager is running
00113     XSelectInput(qt_xdisplay(), qt_xrootwin(), SubstructureRedirectMask  );
00114     syncX(); // trigger error now
00115 
00116     options = new Options;
00117     atoms = new Atoms;
00118     
00119     // create workspace.
00120     (void) new Workspace( isSessionRestored() );
00121 
00122     syncX(); // trigger possible errors, there's still a chance to abort
00123 
00124     initting = FALSE; // startup done, we are up and running now.
00125        
00126     dcopClient()->send( "ksplash", "", "upAndRunning(QString)", QString("wm started"));
00127     XEvent e;
00128     e.xclient.type = ClientMessage;
00129     e.xclient.message_type = XInternAtom( qt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
00130     e.xclient.display = qt_xdisplay();
00131     e.xclient.window = qt_xrootwin();
00132     e.xclient.format = 8;
00133     strcpy( e.xclient.data.b, "wm started" );
00134     XSendEvent( qt_xdisplay(), qt_xrootwin(), False, SubstructureNotifyMask, &e );
00135     }
00136 
00137 Application::~Application()
00138     {
00139     delete Workspace::self();
00140     if( owner.ownerWindow() != None ) // if there was no --replace (no new WM)
00141         XSetInputFocus( qt_xdisplay(), PointerRoot, RevertToPointerRoot, qt_x_time );
00142     delete options;
00143     }
00144 
00145 void Application::lostSelection()
00146     {
00147     delete Workspace::self();
00148     // remove windowmanager privileges
00149     XSelectInput(qt_xdisplay(), qt_xrootwin(), PropertyChangeMask );
00150     quit();
00151     }
00152 
00153 bool Application::x11EventFilter( XEvent *e )
00154     {
00155     if ( Workspace::self()->workspaceEvent( e ) )
00156              return TRUE;
00157     return KApplication::x11EventFilter( e );
00158     }
00159     
00160 static void sighandler(int) 
00161     {
00162     QApplication::exit();
00163     }
00164 
00165 
00166 } // namespace
00167 
00168 static const char version[] = "3.0";
00169 static const char description[] = I18N_NOOP( "KDE window manager" );
00170 
00171 static KCmdLineOptions args[] =
00172     {
00173         { "lock", I18N_NOOP("Disable configuration options"), 0 },
00174         { "replace", I18N_NOOP("Replace already-running ICCCM2.0-compliant window manager"), 0 },
00175         KCmdLineLastOption
00176     };
00177 
00178 extern "C"
00179 KDE_EXPORT int kdemain( int argc, char * argv[] )
00180     {
00181     bool restored = false;
00182     for (int arg = 1; arg < argc; arg++) 
00183         {
00184         if (! qstrcmp(argv[arg], "-session")) 
00185             {
00186             restored = true;
00187             break;
00188             }
00189         }
00190 
00191     if (! restored) 
00192         {
00193         // we only do the multihead fork if we are not restored by the session
00194     // manager, since the session manager will register multiple kwins,
00195         // one for each screen...
00196         QCString multiHead = getenv("KDE_MULTIHEAD");
00197         if (multiHead.lower() == "true") 
00198             {
00199 
00200             Display* dpy = XOpenDisplay( NULL );
00201             if ( !dpy ) 
00202                 {
00203                 fprintf(stderr, "%s: FATAL ERROR while trying to open display %s\n",
00204                         argv[0], XDisplayName(NULL ) );
00205                 exit (1);
00206                 }
00207 
00208             int number_of_screens = ScreenCount( dpy );
00209             KWinInternal::screen_number = DefaultScreen( dpy );
00210             int pos; // temporarily needed to reconstruct DISPLAY var if multi-head
00211             QCString display_name = XDisplayString( dpy );
00212             XCloseDisplay( dpy );
00213             dpy = 0;
00214 
00215             if ((pos = display_name.findRev('.')) != -1 )
00216                 display_name.remove(pos,10); // 10 is enough to be sure we removed ".s"
00217 
00218             QCString envir;
00219             if (number_of_screens != 1) 
00220                 {
00221                 for (int i = 0; i < number_of_screens; i++ ) 
00222                     {
00223             // if execution doesn't pass by here, then kwin
00224             // acts exactly as previously
00225                     if ( i != KWinInternal::screen_number && fork() == 0 ) 
00226                         {
00227                         KWinInternal::screen_number = i;
00228             // break here because we are the child process, we don't
00229             // want to fork() anymore
00230                         break;
00231                         }
00232                     }
00233         // in the next statement, display_name shouldn't contain a screen
00234         //   number. If it had it, it was removed at the "pos" check
00235                 envir.sprintf("DISPLAY=%s.%d", display_name.data(), KWinInternal::screen_number);
00236 
00237                 if (putenv( strdup(envir.data())) ) 
00238                     {
00239                     fprintf(stderr,
00240                             "%s: WARNING: unable to set DISPLAY environment variable\n",
00241                             argv[0]);
00242                     perror("putenv()");
00243                     }
00244                 }
00245             }
00246         }
00247 
00248     KGlobal::locale()->setMainCatalogue("kwin");
00249 
00250     KAboutData aboutData( "kwin", I18N_NOOP("KWin"),
00251                           version, description, KAboutData::License_GPL,
00252                           I18N_NOOP("(c) 1999-2005, The KDE Developers"));
00253     aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org");
00254     aboutData.addAuthor("Cristian Tibirna",0, "tibirna@kde.org");
00255     aboutData.addAuthor("Daniel M. Duley",0, "mosfet@kde.org");
00256     aboutData.addAuthor("Luboš Luňák", I18N_NOOP( "Maintainer" ), "l.lunak@kde.org");
00257 
00258     KCmdLineArgs::init(argc, argv, &aboutData);
00259     KCmdLineArgs::addCmdLineOptions( args );
00260 
00261     if (signal(SIGTERM, KWinInternal::sighandler) == SIG_IGN)
00262         signal(SIGTERM, SIG_IGN);
00263     if (signal(SIGINT, KWinInternal::sighandler) == SIG_IGN)
00264         signal(SIGINT, SIG_IGN);
00265     if (signal(SIGHUP, KWinInternal::sighandler) == SIG_IGN)
00266         signal(SIGHUP, SIG_IGN);
00267 
00268     KApplication::disableAutoDcopRegistration();
00269     KWinInternal::Application a;
00270     KWinInternal::SessionManaged weAreIndeed;
00271     KWinInternal::SessionSaveDoneHelper helper;
00272 
00273     fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, 1);
00274 
00275     QCString appname;
00276     if (KWinInternal::screen_number == 0)
00277         appname = "kwin";
00278     else
00279         appname.sprintf("kwin-screen-%d", KWinInternal::screen_number);
00280 
00281     DCOPClient* client = a.dcopClient();
00282     client->registerAs( appname.data(), false);
00283     client->setDefaultObject( "KWinInterface" );
00284 
00285     return a.exec();
00286     }
00287 
00288 #include "main.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys