You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
477 lines
12 KiB
477 lines
12 KiB
/*
|
|
|
|
Greeter module for xdm
|
|
|
|
Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
|
|
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "tdm_greet.h"
|
|
#include "tdmshutdown.h"
|
|
#include "tdmconfig.h"
|
|
#include "kgapp.h"
|
|
#include "kgreeter.h"
|
|
#ifdef XDMCP
|
|
# include "kchooser.h"
|
|
#endif
|
|
#include "sakdlg.h"
|
|
|
|
#include <kprocess.h>
|
|
#include <kcmdlineargs.h>
|
|
#include <kcrash.h>
|
|
#include <kstandarddirs.h>
|
|
#include <ksimpleconfig.h>
|
|
#include <klocale.h>
|
|
#include <kdebug.h>
|
|
#ifdef WITH_XRANDR
|
|
#include <libkrandr/libkrandr.h>
|
|
#endif
|
|
|
|
#include <tqtimer.h>
|
|
#include <tqstring.h>
|
|
#include <tqcursor.h>
|
|
#include <tqpalette.h>
|
|
|
|
#include <stdlib.h> // free(), exit()
|
|
#include <unistd.h> // alarm()
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/cursorfont.h>
|
|
|
|
#ifdef HAVE_XCOMPOSITE
|
|
#include <X11/extensions/Xrender.h>
|
|
#include <X11/extensions/Xcomposite.h>
|
|
#endif
|
|
|
|
#include <pwd.h>
|
|
|
|
bool argb_visual_available = false;
|
|
bool has_twin = false;
|
|
bool is_themed = false;
|
|
bool trinity_desktop_lock_use_sak = TRUE;
|
|
|
|
static int
|
|
ignoreXError( Display *dpy ATTR_UNUSED, XErrorEvent *event ATTR_UNUSED )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
static void
|
|
sigAlarm( int )
|
|
{
|
|
exit( EX_RESERVER_DPY );
|
|
}
|
|
|
|
}
|
|
|
|
GreeterApp::GreeterApp()
|
|
{
|
|
pingInterval = _isLocal ? 0 : _pingInterval;
|
|
if (pingInterval) {
|
|
struct sigaction sa;
|
|
sigemptyset( &sa.sa_mask );
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = sigAlarm;
|
|
sigaction( SIGALRM, &sa, 0 );
|
|
alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
|
|
startTimer( pingInterval * 60000 );
|
|
}
|
|
}
|
|
|
|
GreeterApp::GreeterApp(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap) : KApplication(dpy, visual, colormap)
|
|
{
|
|
pingInterval = _isLocal ? 0 : _pingInterval;
|
|
if (pingInterval) {
|
|
struct sigaction sa;
|
|
sigemptyset( &sa.sa_mask );
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = sigAlarm;
|
|
sigaction( SIGALRM, &sa, 0 );
|
|
alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
|
|
startTimer( pingInterval * 60000 );
|
|
}
|
|
}
|
|
|
|
void
|
|
GreeterApp::timerEvent( TQTimerEvent * )
|
|
{
|
|
alarm( 0 );
|
|
if (!PingServer( qt_xdisplay() ))
|
|
::exit( EX_RESERVER_DPY );
|
|
alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
|
|
}
|
|
|
|
bool
|
|
GreeterApp::x11EventFilter( XEvent * ev )
|
|
{
|
|
KeySym sym;
|
|
|
|
switch (ev->type) {
|
|
case FocusIn:
|
|
case FocusOut:
|
|
// Hack to tell dialogs to take focus when the keyboard is grabbed
|
|
ev->xfocus.mode = NotifyNormal;
|
|
break;
|
|
case KeyPress:
|
|
sym = XLookupKeysym( &ev->xkey, 0 );
|
|
if (sym != XK_Return && !IsModifierKey( sym ))
|
|
emit activity();
|
|
break;
|
|
case ButtonPress:
|
|
emit activity();
|
|
/* fall through */
|
|
case ButtonRelease:
|
|
// Hack to let the RMB work as LMB
|
|
if (ev->xbutton.button == 3)
|
|
ev->xbutton.button = 1;
|
|
/* fall through */
|
|
case MotionNotify:
|
|
if (ev->xbutton.state & Button3Mask)
|
|
ev->xbutton.state = (ev->xbutton.state & ~Button3Mask) | Button1Mask;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
extern bool kde_have_kipc;
|
|
|
|
extern "C" {
|
|
|
|
static int
|
|
xIOErr( Display * )
|
|
{
|
|
exit( EX_RESERVER_DPY );
|
|
}
|
|
|
|
//KSimpleConfig *iccconfig;
|
|
|
|
void
|
|
checkSAK(GreeterApp* app)
|
|
{
|
|
app->restoreOverrideCursor();
|
|
SAKDlg sak(0);
|
|
sak.exec();
|
|
app->setOverrideCursor( Qt::WaitCursor );
|
|
}
|
|
|
|
void
|
|
kg_main( const char *argv0 )
|
|
{
|
|
static char *argv[] = { (char *)"tdmgreet", 0 };
|
|
KCmdLineArgs::init( 1, argv, *argv, 0, 0, 0, true );
|
|
|
|
kdDebug() << timestamp() << "start" << endl;
|
|
kde_have_kipc = false;
|
|
KApplication::disableAutoDcopRegistration();
|
|
KCrash::setSafer( true );
|
|
|
|
KProcess *tsak = 0;
|
|
KProcess *proc = 0;
|
|
KProcess *comp = 0;
|
|
KProcess *twin = 0;
|
|
|
|
trinity_desktop_lock_use_sak = _useSAK;
|
|
if (trinity_desktop_lock_use_sak) {
|
|
tsak = new KProcess;
|
|
*tsak << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "tsak";
|
|
tsak->start(KProcess::Block);
|
|
}
|
|
if (tsak) {
|
|
tsak->closeStdin();
|
|
tsak->detach();
|
|
delete tsak;
|
|
}
|
|
|
|
#ifdef HAVE_XCOMPOSITE
|
|
// Begin ARGB initialization
|
|
XSetErrorHandler( ignoreXError );
|
|
argb_visual_available = false;
|
|
char *display = 0;
|
|
|
|
Display *dpyi = XOpenDisplay( display );
|
|
if ( !dpyi ) {
|
|
kdError() << "cannot connect to X server " << display << endl;
|
|
exit( 1 );
|
|
}
|
|
|
|
int screen = DefaultScreen( dpyi );
|
|
Colormap colormap = 0;
|
|
Visual *visual = 0;
|
|
int event_base, error_base;
|
|
|
|
if ( XRenderQueryExtension( dpyi, &event_base, &error_base ) ) {
|
|
int nvi;
|
|
XVisualInfo templ;
|
|
templ.screen = screen;
|
|
templ.depth = 32;
|
|
templ.c_class = TrueColor;
|
|
XVisualInfo *xvi = XGetVisualInfo( dpyi, VisualScreenMask | VisualDepthMask
|
|
| VisualClassMask, &templ, &nvi );
|
|
|
|
for ( int i = 0; i < nvi; i++ ) {
|
|
XRenderPictFormat *format = XRenderFindVisualFormat( dpyi, xvi[i].visual );
|
|
if ( format->type == PictTypeDirect && format->direct.alphaMask ) {
|
|
visual = xvi[i].visual;
|
|
colormap = XCreateColormap( dpyi, RootWindow( dpyi, screen ), visual, AllocNone );
|
|
kdDebug() << "found visual with alpha support" << endl;
|
|
argb_visual_available = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
XSetErrorHandler( (XErrorHandler)0 );
|
|
|
|
GreeterApp *app;
|
|
if ( (argb_visual_available == true) && (!_compositor.isEmpty()) ) {
|
|
app = new GreeterApp(dpyi, Qt::HANDLE( visual ), Qt::HANDLE( colormap ));
|
|
}
|
|
else {
|
|
app = new GreeterApp();
|
|
}
|
|
// End ARGB initialization
|
|
#else
|
|
GreeterApp *app = new GreeterApp();
|
|
#endif
|
|
|
|
XSetIOErrorHandler( xIOErr );
|
|
TQString login_user;
|
|
TQString login_session_wm;
|
|
|
|
Display *dpy = qt_xdisplay();
|
|
|
|
if (!_GUIStyle.isEmpty())
|
|
app->setStyle( _GUIStyle );
|
|
|
|
// Load up systemwide display settings
|
|
#ifdef WITH_XRANDR
|
|
KRandrSimpleAPI *randrsimple = new KRandrSimpleAPI();
|
|
TQPoint primaryScreenPosition = randrsimple->applySystemwideDisplayConfiguration("", KDE_CONFDIR);
|
|
delete randrsimple;
|
|
#endif
|
|
|
|
// Load up the systemwide ICC profile
|
|
TQString iccConfigFile = TQString(KDE_CONFDIR);
|
|
iccConfigFile += "/kicc/kiccconfigrc";
|
|
KSimpleConfig iccconfig(iccConfigFile, true);
|
|
if (iccconfig.readBoolEntry("EnableICC", false) == true) {
|
|
TQString iccCommand = TQString("/usr/bin/xcalib ");
|
|
iccCommand += iccconfig.readEntry("ICCFile");
|
|
iccCommand += TQString(" &");
|
|
system(iccCommand.ascii());
|
|
}
|
|
|
|
_colorScheme = locate( "data", "kdisplay/color-schemes/" + _colorScheme + ".kcsrc" );
|
|
if (!_colorScheme.isEmpty()) {
|
|
KSimpleConfig config( _colorScheme, true );
|
|
config.setGroup( "Color Scheme" );
|
|
app->setPalette( app->createApplicationPalette( &config, 7 ) );
|
|
}
|
|
|
|
app->setFont( _normalFont );
|
|
|
|
setup_modifiers( dpy, _numLockStatus );
|
|
SecureDisplay( dpy );
|
|
if (!_grabServer) {
|
|
if (_useBackground) {
|
|
proc = new KProcess;
|
|
*proc << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "krootimage";
|
|
*proc << _backgroundCfg;
|
|
proc->start();
|
|
}
|
|
GSendInt( G_SetupDpy );
|
|
GRecvInt();
|
|
}
|
|
|
|
if (!_compositor.isEmpty()) {
|
|
comp = new KProcess;
|
|
*comp << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + _compositor.ascii();
|
|
comp->start(KProcess::NotifyOnExit, KProcess::Stdin);
|
|
}
|
|
|
|
if (!_windowManager.isEmpty()) {
|
|
twin = new KProcess;
|
|
*twin << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + _windowManager.ascii();
|
|
twin->start();
|
|
has_twin = true;
|
|
}
|
|
|
|
GSendInt( G_Ready );
|
|
|
|
kdDebug() << timestamp() << " main1" << endl;
|
|
setCursor( dpy, app->desktop()->winId(), XC_left_ptr );
|
|
|
|
for (;;) {
|
|
int rslt, cmd = GRecvInt();
|
|
|
|
if (cmd == G_ConfShutdown) {
|
|
int how = GRecvInt(), uid = GRecvInt();
|
|
char *os = GRecvStr();
|
|
TDMSlimShutdown::externShutdown( how, os, uid );
|
|
if (os)
|
|
free( os );
|
|
GSendInt( G_Ready );
|
|
_autoLoginDelay = 0;
|
|
continue;
|
|
}
|
|
|
|
if (cmd == G_ErrorGreet) {
|
|
if (KGVerify::handleFailVerify( TQT_TQWIDGET(tqApp->desktop()->screen( _greeterScreen )) ))
|
|
break;
|
|
_autoLoginDelay = 0;
|
|
cmd = G_Greet;
|
|
}
|
|
|
|
KProcess *proc2 = 0;
|
|
app->setOverrideCursor( Qt::WaitCursor );
|
|
FDialog *dialog = NULL;
|
|
#ifdef XDMCP
|
|
if (cmd == G_Choose) {
|
|
dialog = new ChooserDlg;
|
|
GSendInt( G_Ready ); /* tell chooser to go into async mode */
|
|
GRecvInt(); /* ack */
|
|
} else
|
|
#endif
|
|
{
|
|
if ((cmd != G_GreetTimed && !_autoLoginAgain) ||
|
|
_autoLoginUser.isEmpty())
|
|
_autoLoginDelay = 0;
|
|
if (_useTheme && !_theme.isEmpty()) {
|
|
// Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them
|
|
// This also prevents the user from being dropped to a console login if Xorg glitches or is buggy
|
|
XSetErrorHandler( ignoreXError );
|
|
KThemedGreeter *tgrt;
|
|
bool has_twin_bkp = has_twin;
|
|
is_themed = true;
|
|
has_twin = false; // [FIXME] The themed greeter is built on the assumption that there is no window manager available (i.e. it keeps stealing focus) and needs to be repaired.
|
|
dialog = tgrt = new KThemedGreeter;
|
|
kdDebug() << timestamp() << " themed" << endl;
|
|
if (!tgrt->isOK()) {
|
|
is_themed = false;
|
|
has_twin = has_twin_bkp;
|
|
delete tgrt;
|
|
checkSAK(app);
|
|
dialog = new KStdGreeter;
|
|
#ifdef WITH_XRANDR
|
|
dialog->move(dialog->x() + primaryScreenPosition.x(), dialog->y() + primaryScreenPosition.y());
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef WITH_XRANDR
|
|
dialog->move(primaryScreenPosition.x(), primaryScreenPosition.y());
|
|
#endif
|
|
}
|
|
XSetErrorHandler( (XErrorHandler)0 );
|
|
} else {
|
|
checkSAK(app);
|
|
dialog = new KStdGreeter;
|
|
#ifdef WITH_XRANDR
|
|
dialog->move(dialog->x() + primaryScreenPosition.x(), dialog->y() + primaryScreenPosition.y());
|
|
#endif
|
|
}
|
|
TQPoint oldCursorPos = TQCursor::pos();
|
|
#ifdef WITH_XRANDR
|
|
TQCursor::setPos(oldCursorPos.x() + primaryScreenPosition.x(), oldCursorPos.y() + primaryScreenPosition.y());
|
|
#endif
|
|
if (*_preloader) {
|
|
proc2 = new KProcess;
|
|
*proc2 << _preloader;
|
|
proc2->start();
|
|
}
|
|
}
|
|
app->restoreOverrideCursor();
|
|
Debug( "entering event loop\n" );
|
|
// Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them
|
|
// This also prevents the user from being dropped to a console login if Xorg glitches or is buggy
|
|
XSetErrorHandler( ignoreXError );
|
|
rslt = dialog->exec();
|
|
XSetErrorHandler( (XErrorHandler)0 );
|
|
Debug( "left event loop\n" );
|
|
|
|
login_user = static_cast<KGreeter*>(dialog)->curUser;
|
|
login_session_wm = static_cast<KGreeter*>(dialog)->curWMSession;
|
|
|
|
if (rslt != ex_greet) {
|
|
delete dialog;
|
|
}
|
|
delete proc2;
|
|
#ifdef XDMCP
|
|
switch (rslt) {
|
|
case ex_greet:
|
|
GSendInt( G_DGreet );
|
|
continue;
|
|
case ex_choose:
|
|
GSendInt( G_DChoose );
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
KGVerify::done();
|
|
|
|
if (comp) {
|
|
if (_compositor == "kompmgr") {
|
|
// Change process UID
|
|
// Get user UID
|
|
passwd* userinfo = getpwnam(login_user.ascii());
|
|
if (userinfo) {
|
|
TQString newuid = TQString("%1").arg(userinfo->pw_uid);
|
|
// kompmgr allows us to change its uid in this manner:
|
|
// 1.) Send SIGUSER1
|
|
// 2.) Send the new UID to it on the command line
|
|
comp->kill(SIGUSR1);
|
|
comp->writeStdin(newuid.ascii(), newuid.length());
|
|
usleep(50000); // Give the above function some time to execute. Note that on REALLY slow systems this could fail, leaving kompmgr running as root. TODO: Look into ways to make this more robust.
|
|
}
|
|
}
|
|
comp->closeStdin();
|
|
comp->detach();
|
|
delete comp;
|
|
}
|
|
if (twin) {
|
|
if (login_session_wm.endsWith("/starttde") || (login_session_wm == "failsafe")) {
|
|
twin->closeStdin();
|
|
twin->detach();
|
|
}
|
|
else {
|
|
twin->kill();
|
|
}
|
|
delete twin;
|
|
}
|
|
delete proc;
|
|
UnsecureDisplay( dpy );
|
|
restore_modifiers();
|
|
|
|
XSetInputFocus( qt_xdisplay(), PointerRoot, PointerRoot, CurrentTime );
|
|
|
|
delete app;
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
#include "kgapp.moc"
|