TDE base libraries and programs
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.

kgapp.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*
  2. Greeter module for xdm
  3. Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
  4. Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. */
  17. #include <config.h>
  18. #include "tdm_greet.h"
  19. #include "tdmshutdown.h"
  20. #include "tdmconfig.h"
  21. #include "kgapp.h"
  22. #include "kgreeter.h"
  23. #ifdef XDMCP
  24. # include "kchooser.h"
  25. #endif
  26. #include "sakdlg.h"
  27. #include <kprocess.h>
  28. #include <tdecmdlineargs.h>
  29. #include <kcrash.h>
  30. #include <kstandarddirs.h>
  31. #include <ksimpleconfig.h>
  32. #include <tdelocale.h>
  33. #include <kdebug.h>
  34. #ifdef WITH_XRANDR
  35. #include <libtderandr/libtderandr.h>
  36. #endif
  37. #include <tqtimer.h>
  38. #include <tqstring.h>
  39. #include <tqcursor.h>
  40. #include <tqpalette.h>
  41. #include <stdlib.h> // free(), exit()
  42. #include <unistd.h> // alarm()
  43. #include <X11/Xlib.h>
  44. #include <X11/Xutil.h>
  45. #include <X11/keysym.h>
  46. #include <X11/cursorfont.h>
  47. #ifdef HAVE_XCOMPOSITE
  48. #include <X11/extensions/Xrender.h>
  49. #include <X11/extensions/Xcomposite.h>
  50. #endif
  51. #include <pwd.h>
  52. #define TSAK_FIFO_FILE "/tmp/tdesocket-global/tsak"
  53. bool argb_visual_available = false;
  54. bool has_twin = false;
  55. bool is_themed = false;
  56. bool trinity_desktop_lock_use_sak = TRUE;
  57. TQPoint primaryScreenPosition;
  58. static int
  59. ignoreXError( Display *dpy ATTR_UNUSED, XErrorEvent *event ATTR_UNUSED )
  60. {
  61. return 0;
  62. }
  63. extern "C" {
  64. static void
  65. sigAlarm( int )
  66. {
  67. exit( EX_RESERVER_DPY );
  68. }
  69. }
  70. GreeterApp::GreeterApp()
  71. {
  72. init();
  73. }
  74. GreeterApp::GreeterApp(Display *dpy) : TDEApplication(dpy)
  75. {
  76. init();
  77. }
  78. GreeterApp::GreeterApp(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap) : TDEApplication(dpy, visual, colormap)
  79. {
  80. init();
  81. }
  82. GreeterApp::~GreeterApp()
  83. {
  84. //
  85. }
  86. void GreeterApp::init()
  87. {
  88. pingInterval = _isLocal ? 0 : _pingInterval;
  89. if (pingInterval) {
  90. struct sigaction sa;
  91. sigemptyset( &sa.sa_mask );
  92. sa.sa_flags = 0;
  93. sa.sa_handler = sigAlarm;
  94. sigaction( SIGALRM, &sa, 0 );
  95. alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
  96. startTimer( pingInterval * 60000 );
  97. }
  98. TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices();
  99. connect(hwdevices, TQT_SIGNAL(hardwareUpdated(TDEGenericDevice*)), this, TQT_SLOT(deviceChanged(TDEGenericDevice*)));
  100. }
  101. void GreeterApp::deviceChanged(TDEGenericDevice* device) {
  102. if (device->type() == TDEGenericDeviceType::Monitor) {
  103. KRandrSimpleAPI *randrsimple = new KRandrSimpleAPI();
  104. randrsimple->applyHotplugRules(KDE_CONFDIR);
  105. delete randrsimple;
  106. }
  107. }
  108. void
  109. GreeterApp::timerEvent( TQTimerEvent * )
  110. {
  111. alarm( 0 );
  112. if (!PingServer( tqt_xdisplay() ))
  113. ::exit( EX_RESERVER_DPY );
  114. alarm( pingInterval * 70 ); // sic! give the "proper" pinger enough time
  115. }
  116. bool
  117. GreeterApp::x11EventFilter( XEvent * ev )
  118. {
  119. KeySym sym;
  120. switch (ev->type) {
  121. case FocusIn:
  122. case FocusOut:
  123. // Hack to tell dialogs to take focus when the keyboard is grabbed
  124. ev->xfocus.mode = NotifyNormal;
  125. break;
  126. case KeyPress:
  127. sym = XLookupKeysym( &ev->xkey, 0 );
  128. if (sym != XK_Return && !IsModifierKey( sym ))
  129. emit activity();
  130. break;
  131. case ButtonPress:
  132. emit activity();
  133. /* fall through */
  134. case ButtonRelease:
  135. // Hack to let the RMB work as LMB
  136. if (ev->xbutton.button == 3)
  137. ev->xbutton.button = 1;
  138. /* fall through */
  139. case MotionNotify:
  140. if (ev->xbutton.state & Button3Mask)
  141. ev->xbutton.state = (ev->xbutton.state & ~Button3Mask) | Button1Mask;
  142. break;
  143. }
  144. return false;
  145. }
  146. extern bool kde_have_kipc;
  147. extern "C" {
  148. static int
  149. xIOErr( Display * )
  150. {
  151. exit( EX_RESERVER_DPY );
  152. }
  153. //KSimpleConfig *iccconfig;
  154. void
  155. checkSAK(GreeterApp* app)
  156. {
  157. app->restoreOverrideCursor();
  158. SAKDlg sak(0);
  159. sak.exec();
  160. app->setOverrideCursor( Qt::WaitCursor );
  161. }
  162. void
  163. kg_main( const char *argv0 )
  164. {
  165. static char *argv[] = { (char *)"tdmgreet", 0 };
  166. TDECmdLineArgs::init( 1, argv, *argv, 0, 0, 0, true );
  167. kdDebug() << timestamp() << "start" << endl;
  168. kde_have_kipc = false;
  169. TDEApplication::disableAutoDcopRegistration();
  170. TDECrash::setSafer( true );
  171. TDEProcess *tsak = 0;
  172. TDEProcess *proc = 0;
  173. TDEProcess *comp = 0;
  174. TDEProcess *dcop = 0;
  175. TDEProcess *twin = 0;
  176. #ifdef BUILD_TSAK
  177. trinity_desktop_lock_use_sak = _useSAK;
  178. #else
  179. trinity_desktop_lock_use_sak = false;
  180. #endif
  181. if (trinity_desktop_lock_use_sak) {
  182. tsak = new TDEProcess;
  183. *tsak << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "tsak";
  184. tsak->start(TDEProcess::Block, TDEProcess::AllOutput);
  185. }
  186. else {
  187. remove(TSAK_FIFO_FILE);
  188. }
  189. if (tsak) {
  190. tsak->closeStdin();
  191. tsak->closeStdout();
  192. tsak->detach();
  193. delete tsak;
  194. }
  195. XSetErrorHandler( ignoreXError );
  196. argb_visual_available = false;
  197. char *display = 0;
  198. Display *dpyi = XOpenDisplay( display );
  199. if ( !dpyi ) {
  200. kdError() << "cannot connect to X server " << display << endl;
  201. exit( 1 );
  202. }
  203. #ifdef HAVE_XCOMPOSITE
  204. // Begin ARGB initialization
  205. int screen = DefaultScreen( dpyi );
  206. Colormap colormap = 0;
  207. Visual *visual = 0;
  208. int event_base, error_base;
  209. if ( XRenderQueryExtension( dpyi, &event_base, &error_base ) ) {
  210. int nvi;
  211. XVisualInfo templ;
  212. templ.screen = screen;
  213. templ.depth = 32;
  214. templ.c_class = TrueColor;
  215. XVisualInfo *xvi = XGetVisualInfo( dpyi, VisualScreenMask | VisualDepthMask
  216. | VisualClassMask, &templ, &nvi );
  217. for ( int i = 0; i < nvi; i++ ) {
  218. XRenderPictFormat *format = XRenderFindVisualFormat( dpyi, xvi[i].visual );
  219. if ( format->type == PictTypeDirect && format->direct.alphaMask ) {
  220. visual = xvi[i].visual;
  221. colormap = XCreateColormap( dpyi, RootWindow( dpyi, screen ), visual, AllocNone );
  222. kdDebug() << "found visual with alpha support" << endl;
  223. argb_visual_available = true;
  224. break;
  225. }
  226. }
  227. }
  228. XSetErrorHandler( (XErrorHandler)0 );
  229. GreeterApp *app;
  230. if ( (argb_visual_available == true) && (!_compositor.isEmpty()) ) {
  231. app = new GreeterApp(dpyi, Qt::HANDLE( visual ), Qt::HANDLE( colormap ));
  232. }
  233. else {
  234. app = new GreeterApp(dpyi);
  235. }
  236. // End ARGB initialization
  237. #else
  238. GreeterApp *app = new GreeterApp(dpyi);
  239. #endif
  240. // Load up systemwide display settings
  241. #ifdef WITH_XRANDR
  242. KRandrSimpleAPI *randrsimple = new KRandrSimpleAPI();
  243. primaryScreenPosition = randrsimple->applyStartupDisplayConfiguration(KDE_CONFDIR);
  244. randrsimple->applyHotplugRules(KDE_CONFDIR);
  245. delete randrsimple;
  246. #endif
  247. // Load up the systemwide ICC profile
  248. TQString iccConfigFile = TQString(KDE_CONFDIR);
  249. iccConfigFile += "/kicc/kiccconfigrc";
  250. KSimpleConfig iccconfig(iccConfigFile, true);
  251. if (iccconfig.readBoolEntry("EnableICC", false) == true) {
  252. TQString iccCommand = TQString("/usr/bin/xcalib ");
  253. iccCommand += iccconfig.readEntry("ICCFile");
  254. iccCommand += TQString(" &");
  255. if (system(iccCommand.ascii()) < 0) {
  256. printf("WARNING: Unable to execute command \"%s\"\n", iccCommand.ascii());
  257. }
  258. }
  259. // Make sure TQt is aware of the screen geometry changes before any dialogs are created
  260. XSync(tqt_xdisplay(), false);
  261. app->processEvents();
  262. TQRect screenRect = TQApplication::desktop()->screenGeometry();
  263. TQCursor::setPos(screenRect.center().x(), screenRect.center().y());
  264. XSetIOErrorHandler( xIOErr );
  265. TQString login_user;
  266. TQString login_session_wm;
  267. Display *dpy = tqt_xdisplay();
  268. if (!_GUIStyle.isEmpty()) {
  269. app->setStyle( _GUIStyle );
  270. }
  271. _colorScheme = locate( "data", "tdedisplay/color-schemes/" + _colorScheme + ".kcsrc" );
  272. if (!_colorScheme.isEmpty()) {
  273. KSimpleConfig config( _colorScheme, true );
  274. config.setGroup( "Color Scheme" );
  275. app->setPalette( app->createApplicationPalette( &config, 7 ) );
  276. }
  277. app->setFont( _normalFont );
  278. setup_modifiers( dpy, _numLockStatus );
  279. SecureDisplay( dpy );
  280. if (!_grabServer) {
  281. if (_useBackground) {
  282. proc = new TDEProcess;
  283. *proc << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "krootimage";
  284. *proc << _backgroundCfg;
  285. proc->start();
  286. }
  287. GSendInt( G_SetupDpy );
  288. GRecvInt();
  289. }
  290. if (!_compositor.isEmpty()) {
  291. comp = new TDEProcess;
  292. *comp << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + _compositor.ascii();
  293. comp->start(TDEProcess::NotifyOnExit, TDEProcess::Stdin);
  294. }
  295. if (!_windowManager.isEmpty()) {
  296. if (_windowManager == "twin") {
  297. // Special case
  298. // Start DCOP...
  299. dcop = new TDEProcess;
  300. *dcop << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + "dcopserver" << TQCString("--suicide");
  301. dcop->start();
  302. }
  303. twin = new TDEProcess;
  304. *twin << TQCString( argv0, strrchr( argv0, '/' ) - argv0 + 2 ) + _windowManager.ascii();
  305. twin->start();
  306. has_twin = true;
  307. }
  308. GSendInt( G_Ready );
  309. kdDebug() << timestamp() << " main1" << endl;
  310. setCursor( dpy, app->desktop()->winId(), XC_left_ptr );
  311. for (;;) {
  312. int rslt, cmd = GRecvInt();
  313. if (cmd == G_ConfShutdown) {
  314. int how = GRecvInt(), uid = GRecvInt();
  315. char *os = GRecvStr();
  316. TDMSlimShutdown::externShutdown( how, os, uid );
  317. if (os)
  318. free( os );
  319. GSendInt( G_Ready );
  320. _autoLoginDelay = 0;
  321. continue;
  322. }
  323. if (cmd == G_ErrorGreet) {
  324. if (KGVerify::handleFailVerify( TQT_TQWIDGET(tqApp->desktop()->screen( _greeterScreen )) ))
  325. break;
  326. _autoLoginDelay = 0;
  327. cmd = G_Greet;
  328. }
  329. TDEProcess *proc2 = 0;
  330. app->setOverrideCursor( Qt::WaitCursor );
  331. FDialog *dialog = NULL;
  332. #ifdef XDMCP
  333. if (cmd == G_Choose) {
  334. dialog = new ChooserDlg;
  335. GSendInt( G_Ready ); /* tell chooser to go into async mode */
  336. GRecvInt(); /* ack */
  337. } else
  338. #endif
  339. {
  340. if ((cmd != G_GreetTimed && !_autoLoginAgain) ||
  341. _autoLoginUser.isEmpty())
  342. _autoLoginDelay = 0;
  343. if (_useTheme && !_theme.isEmpty() && !trinity_desktop_lock_use_sak) {
  344. // Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them
  345. // This also prevents the user from being dropped to a console login if Xorg glitches or is buggy
  346. XSetErrorHandler( ignoreXError );
  347. KThemedGreeter *tgrt;
  348. bool has_twin_bkp = has_twin;
  349. is_themed = true;
  350. 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.
  351. dialog = tgrt = new KThemedGreeter;
  352. kdDebug() << timestamp() << " themed" << endl;
  353. if (!tgrt->isOK()) {
  354. is_themed = false;
  355. has_twin = has_twin_bkp;
  356. delete tgrt;
  357. if (trinity_desktop_lock_use_sak) {
  358. checkSAK(app);
  359. }
  360. dialog = new KStdGreeter;
  361. #ifdef WITH_XRANDR
  362. dialog->move(dialog->x() + primaryScreenPosition.x(), dialog->y() + primaryScreenPosition.y());
  363. #endif
  364. }
  365. else {
  366. #ifdef WITH_XRANDR
  367. dialog->move(primaryScreenPosition.x(), primaryScreenPosition.y());
  368. #endif
  369. }
  370. XSetErrorHandler( (XErrorHandler)0 );
  371. } else {
  372. if (trinity_desktop_lock_use_sak) {
  373. checkSAK(app);
  374. }
  375. dialog = new KStdGreeter;
  376. #ifdef WITH_XRANDR
  377. dialog->move(dialog->x() + primaryScreenPosition.x(), dialog->y() + primaryScreenPosition.y());
  378. #endif
  379. }
  380. TQPoint oldCursorPos = TQCursor::pos();
  381. #ifdef WITH_XRANDR
  382. TQCursor::setPos(oldCursorPos.x() + primaryScreenPosition.x(), oldCursorPos.y() + primaryScreenPosition.y());
  383. #endif
  384. if (*_preloader) {
  385. proc2 = new TDEProcess;
  386. *proc2 << _preloader;
  387. proc2->start();
  388. }
  389. }
  390. app->restoreOverrideCursor();
  391. Debug( "entering event loop\n" );
  392. // Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them
  393. // This also prevents the user from being dropped to a console login if Xorg glitches or is buggy
  394. XSetErrorHandler( ignoreXError );
  395. rslt = dialog->exec();
  396. XSetErrorHandler( (XErrorHandler)0 );
  397. Debug( "left event loop\n" );
  398. login_user = static_cast<KGreeter*>(dialog)->curUser;
  399. login_session_wm = static_cast<KGreeter*>(dialog)->curWMSession;
  400. if (rslt != ex_greet) {
  401. delete dialog;
  402. }
  403. delete proc2;
  404. #ifdef XDMCP
  405. switch (rslt) {
  406. case ex_greet:
  407. GSendInt( G_DGreet );
  408. continue;
  409. case ex_choose:
  410. GSendInt( G_DChoose );
  411. continue;
  412. default:
  413. break;
  414. }
  415. #endif
  416. break;
  417. }
  418. KGVerify::done();
  419. if (comp) {
  420. if (comp->isRunning()) {
  421. if (_compositor == "kompmgr") {
  422. // Change process UID
  423. // Get user UID
  424. passwd* userinfo = getpwnam(login_user.ascii());
  425. if (userinfo) {
  426. TQString newuid = TQString("%1").arg(userinfo->pw_uid);
  427. // kompmgr allows us to change its uid in this manner:
  428. // 1.) Send SIGUSER1
  429. // 2.) Send the new UID to it on the command line
  430. comp->kill(SIGUSR1);
  431. comp->writeStdin(newuid.ascii(), newuid.length());
  432. 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.
  433. }
  434. }
  435. comp->closeStdin();
  436. comp->detach();
  437. }
  438. delete comp;
  439. }
  440. if (twin) {
  441. if (twin->isRunning()) {
  442. if (login_session_wm.endsWith("/starttde") || (login_session_wm == "failsafe")) {
  443. twin->closeStdin();
  444. twin->detach();
  445. dcop->detach();
  446. }
  447. else {
  448. twin->kill();
  449. dcop->kill();
  450. }
  451. }
  452. delete twin;
  453. delete dcop;
  454. }
  455. delete proc;
  456. UnsecureDisplay( dpy );
  457. restore_modifiers();
  458. // Qt4 has a nasty habit of generating BadWindow errors in normal operation, so we simply ignore them
  459. // This also prevents the user from being dropped to a console login if Xorg glitches or is buggy
  460. XSetErrorHandler( ignoreXError );
  461. XSetInputFocus( tqt_xdisplay(), PointerRoot, PointerRoot, CurrentTime );
  462. XSetErrorHandler( (XErrorHandler)0 );
  463. delete app;
  464. }
  465. } // extern "C"
  466. #include "kgapp.moc"