00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "plasmaapp.h"
00027
00028 #include <unistd.h>
00029
00030 #ifndef _SC_PHYS_PAGES
00031 #ifdef Q_OS_FREEBSD
00032 #include <sys/types.h>
00033 #include <sys/sysctl.h>
00034 #endif
00035
00036 #ifdef Q_OS_NETBSD
00037 #include <sys/param.h>
00038 #include <sys/sysctl.h>
00039 #endif
00040 #endif
00041
00042 #include <QApplication>
00043 #include <QDesktopWidget>
00044 #include <QPixmapCache>
00045 #include <QtDBus/QtDBus>
00046
00047
00048 #include <KDebug>
00049 #include <KCmdLineArgs>
00050 #include <KWindowSystem>
00051
00052
00053
00054 #include <Plasma/Containment>
00055 #include <Plasma/Theme>
00056 #include <Plasma/Dialog>
00057
00058 #include "appadaptor.h"
00059 #include "savercorona.h"
00060 #include "saverview.h"
00061 #include "backgrounddialog.h"
00062
00063
00064 #include <X11/Xlib.h>
00065 #include <X11/extensions/Xrender.h>
00066
00067 Atom tag;
00068 const unsigned char DIALOG = 1;
00069 const unsigned char VIEW = 2;
00070
00071 Display* dpy = 0;
00072 Colormap colormap = 0;
00073 Visual *visual = 0;
00074 bool composite = false;
00075
00076 void checkComposite()
00077 {
00078 dpy = XOpenDisplay(0);
00079 if (!dpy) {
00080 kError() << "Cannot connect to the X server" << endl;
00081 return;
00082 }
00083 if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
00084 return;
00085
00086 int screen = DefaultScreen(dpy);
00087 int eventBase, errorBase;
00088
00089 if (XRenderQueryExtension(dpy, &eventBase, &errorBase)) {
00090 int nvi;
00091 XVisualInfo templ;
00092 templ.screen = screen;
00093 templ.depth = 32;
00094 templ.c_class = TrueColor;
00095 XVisualInfo *xvi = XGetVisualInfo(dpy,
00096 VisualScreenMask | VisualDepthMask | VisualClassMask,
00097 &templ, &nvi);
00098 for (int i = 0; i < nvi; ++i) {
00099 XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual);
00100 if (format->type == PictTypeDirect && format->direct.alphaMask) {
00101 visual = xvi[i].visual;
00102 colormap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
00103 break;
00104 }
00105 }
00106 XFree(xvi);
00107 }
00108
00109 composite = KWindowSystem::compositingActive() && colormap;
00110
00111 kDebug() << (colormap ? "Plasma has an argb visual" : "Plasma lacks an argb visual") << visual << colormap;
00112 kDebug() << ((KWindowSystem::compositingActive() && colormap) ? "Plasma can use COMPOSITE for effects"
00113 : "Plasma is COMPOSITE-less") << "on" << dpy;
00114 }
00115
00116 PlasmaApp* PlasmaApp::self()
00117 {
00118 if (!kapp) {
00119 checkComposite();
00120 return new PlasmaApp(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0);
00121 }
00122
00123 return qobject_cast<PlasmaApp*>(kapp);
00124 }
00125
00126 PlasmaApp::PlasmaApp(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap)
00127 : KUniqueApplication(display, visual, colormap),
00128 m_corona(0),
00129 m_view(0),
00130 m_configDialog(0)
00131 {
00132
00133 KGlobal::locale()->insertCatalog("libplasma");
00134 KGlobal::locale()->insertCatalog("plasma-shells-common");
00135
00136 new AppAdaptor(this);
00137 QDBusConnection::sessionBus().registerObject("/App", this);
00138
00139
00140
00141
00142
00143 int cacheSize = 0;
00144 QDesktopWidget *desktop = QApplication::desktop();
00145 for (int i = 0; i < desktop->numScreens(); i++) {
00146 QRect geometry = desktop->screenGeometry(i);
00147 cacheSize += 4 * geometry.width() * geometry.height() / 1024;
00148 }
00149 cacheSize += cacheSize / 10;
00150
00151
00152
00153
00154
00155
00156 #if defined(_SC_PHYS_PAGES)
00157 int memorySize = sysconf(_SC_PHYS_PAGES);
00158 memorySize *= sysconf(_SC_PAGESIZE) / 1024;
00159 #else
00160 #ifdef Q_OS_FREEBSD
00161 int sysctlbuf[2];
00162 size_t size = sizeof(sysctlbuf);
00163 int memorySize;
00164
00165
00166
00167 if (!sysctlbyname("vm.stats.vm.v_page_size", sysctlbuf, &size, NULL, 0)) {
00168 memorySize = sysctlbuf[0] / 1024;
00169 size = sizeof(sysctlbuf);
00170 if (!sysctlbyname("vm.stats.vm.v_page_count", sysctlbuf, &size, NULL, 0)) {
00171 memorySize *= sysctlbuf[0];
00172 }
00173 }
00174 #endif
00175 #ifdef Q_OS_NETBSD
00176 size_t memorySize;
00177 size_t len;
00178 static int mib[] = { CTL_HW, HW_PHYSMEM };
00179
00180 len = sizeof(memorySize);
00181 sysctl(mib, 2, &memorySize, &len, NULL, 0);
00182 memorySize /= 1024;
00183 #endif
00184
00185
00186 #endif
00187
00188
00189
00190 if (cacheSize < memorySize / 100) {
00191 cacheSize = memorySize / 100;
00192 }
00193
00194 kDebug() << "Setting the pixmap cache size to" << cacheSize << "kilobytes";
00195 QPixmapCache::setCacheLimit(cacheSize);
00196
00197 KConfigGroup cg(KGlobal::config(), "General");
00198 Plasma::Theme::defaultTheme()->setFont(cg.readEntry("desktopFont", font()));
00199 m_activeOpacity = cg.readEntry("activeOpacity", 1.0);
00200 m_idleOpacity = cg.readEntry("idleOpacity", 1.0);
00201
00202 if (cg.readEntry("forceNoComposite", false)) {
00203 composite = false;
00204 }
00205
00206
00207 tag = XInternAtom(QX11Info::display(), "_KDE_SCREENSAVER_OVERRIDE", False);
00208 qApp->installEventFilter(this);
00209
00210
00211 corona();
00212
00213 connect(QApplication::desktop(), SIGNAL(resized(int)), SLOT(adjustSize(int)));
00214 connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
00215
00216 setup(KCmdLineArgs::parsedArgs()->isSet("setup"));
00217 }
00218
00219 PlasmaApp::~PlasmaApp()
00220 {
00221 }
00222
00223 void PlasmaApp::cleanup()
00224 {
00225 if (m_corona) {
00226 m_corona->saveLayout();
00227 }
00228
00229 delete m_view;
00230 delete m_corona;
00231
00232 KGlobal::config()->sync();
00233 }
00234
00235 void PlasmaApp::setActiveOpacity(qreal opacity)
00236 {
00237 if (qFuzzyCompare(opacity, m_activeOpacity)) {
00238 return;
00239 }
00240 m_activeOpacity = opacity;
00241 if (m_view) {
00242
00243 m_view->setWindowOpacity(opacity);
00244 }
00245 KConfigGroup cg(KGlobal::config(), "General");
00246 cg.writeEntry("activeOpacity", opacity);
00247 m_corona->requestConfigSync();
00248 }
00249
00250 void PlasmaApp::setIdleOpacity(qreal opacity)
00251 {
00252 if (qFuzzyCompare(opacity, m_idleOpacity)) {
00253 return;
00254 }
00255 m_idleOpacity = opacity;
00256 KConfigGroup cg(KGlobal::config(), "General");
00257 cg.writeEntry("idleOpacity", opacity);
00258 m_corona->requestConfigSync();
00259 }
00260
00261 qreal PlasmaApp::activeOpacity() const
00262 {
00263 return m_activeOpacity;
00264 }
00265
00266 qreal PlasmaApp::idleOpacity() const
00267 {
00268 return m_idleOpacity;
00269 }
00270
00271
00272 void PlasmaApp::setActive(bool activate)
00273 {
00274 if (!m_view) {
00275 return;
00276 }
00277
00278 if (activate) {
00279 m_view->setWindowOpacity(m_activeOpacity);
00280 m_view->showView();
00281 m_view->containment()->openToolBox();
00282 } else if (m_view->isVisible()) {
00283 if (qFuzzyCompare(m_idleOpacity + qreal(1.0), qreal(1.0))) {
00284
00285 m_view->hideView();
00286 } else {
00287 lock();
00288 m_view->setWindowOpacity(m_idleOpacity);
00289 m_view->containment()->closeToolBox();
00290 }
00291 } else {
00292 if (m_idleOpacity > 0) {
00293 m_view->setWindowOpacity(m_idleOpacity);
00294 m_view->showView();
00295 }
00296 lock();
00297 }
00298 }
00299
00300 void PlasmaApp::adjustSize(int screen)
00301 {
00302 if (! m_view) {
00303 return;
00304 }
00305
00306 QDesktopWidget *desktop = QApplication::desktop();
00307 QRect geom = desktop->screenGeometry(0);
00308 m_view->setGeometry(geom);
00309 }
00310
00311 void PlasmaApp::syncConfig()
00312 {
00313 KGlobal::config()->sync();
00314 }
00315
00316 Plasma::Corona* PlasmaApp::corona()
00317 {
00318 if (!m_corona) {
00319 m_corona = new SaverCorona(this);
00320 connect(m_corona, SIGNAL(containmentAdded(Plasma::Containment*)),
00321 this, SLOT(createView(Plasma::Containment*)));
00322 connect(m_corona, SIGNAL(configSynced()), SLOT(syncConfig()));
00323
00324
00325
00326
00327
00328
00329
00330 m_corona->setItemIndexMethod(QGraphicsScene::NoIndex);
00331 m_corona->initializeLayout();
00332
00333
00334
00335 }
00336
00337 return m_corona;
00338 }
00339
00340 bool PlasmaApp::hasComposite()
00341 {
00342 return composite;
00343 }
00344
00345
00346
00347 void PlasmaApp::createView(Plasma::Containment *containment)
00348 {
00349 kDebug() << "Containment name:" << containment->name()
00350 << "| type" << containment->containmentType()
00351 << "| screen:" << containment->screen()
00352 << "| geometry:" << containment->geometry()
00353 << "| zValue:" << containment->zValue();
00354
00355 if (m_view) {
00356
00357 return;
00358 }
00359
00360 kDebug() << "creating a view for" << containment->screen() << "and we have"
00361 << QApplication::desktop()->numScreens() << "screens";
00362
00363
00364 m_view = new SaverView(containment, 0);
00365
00366
00367
00368
00369
00370 m_view->setGeometry(QApplication::desktop()->screenGeometry(containment->screen()));
00371
00372
00373
00374
00375
00376 connect(containment, SIGNAL(locked()), SLOT(hideDialogs()));
00377 connect(containment, SIGNAL(locked()), m_view, SLOT(disableSetupMode()));
00378 connect(containment, SIGNAL(unlocked()), SLOT(showDialogs()));
00379 connect(containment, SIGNAL(configureRequested(Plasma::Containment*)),
00380 this, SLOT(configureContainment(Plasma::Containment*)));
00381
00382 connect(m_view, SIGNAL(hidden()), SLOT(lock()));
00383 connect(m_view, SIGNAL(hidden()), SIGNAL(hidden()));
00384
00385 kDebug() << "view created";
00386 }
00387
00388 void PlasmaApp::setup(bool setupMode)
00389 {
00390 kDebug() << setupMode;
00391 if (! m_view) {
00392 kDebug() << "too soon!!";
00393 return;
00394 }
00395
00396 if (setupMode) {
00397 m_view->enableSetupMode();
00398 if (m_corona->immutability() == Plasma::UserImmutable) {
00399 m_corona->setImmutability(Plasma::Mutable);
00400 }
00401 setActive(true);
00402 } else {
00403 kDebug() << "checking lockprocess is still around";
00404 QDBusInterface lockprocess("org.kde.screenlocker", "/LockProcess",
00405 "org.kde.screenlocker.LockProcess", QDBusConnection::sessionBus(), this);
00406 if (lockprocess.isValid()) {
00407 kDebug() << "success!";
00408 setActive(false);
00409 } else {
00410 kDebug() << "bailing out";
00411 qApp->quit();
00412 }
00413 }
00414 }
00415
00416 bool PlasmaApp::eventFilter(QObject *obj, QEvent *event)
00417 {
00418 if (event->type() == QEvent::Show) {
00419
00420
00421
00422
00423 QWidget *widget = qobject_cast<QWidget*>(obj);
00424 if (widget && widget->isWindow() && !(qobject_cast<QDesktopWidget*>(widget) ||
00425 widget->testAttribute(Qt::WA_DontShowOnScreen))) {
00426 unsigned char data = 0;
00427 if (qobject_cast<SaverView*>(widget)) {
00428 data = VIEW;
00429 } else if (m_dialogs.contains(widget)) {
00430 data = DIALOG;
00431 } else {
00432 Qt::WindowFlags oldFlags = widget->windowFlags();
00433 Qt::WindowFlags newFlags = oldFlags | Qt::X11BypassWindowManagerHint;
00434 if (oldFlags != newFlags) {
00435
00436
00437
00438 kDebug() << "!!!!!!!setting flags on!!!!!" << widget;
00439 if (qobject_cast<Plasma::Dialog*>(widget)) {
00440
00441
00442 newFlags = Qt::Popup;
00443 } else {
00444
00445
00446 m_dialogs.append(widget);
00447 connect(widget, SIGNAL(destroyed(QObject*)), SLOT(dialogDestroyed(QObject*)));
00448 }
00449 widget->setWindowFlags(newFlags);
00450 widget->show();
00451
00452
00453
00454 widget->activateWindow();
00455 return false;
00456 } else {
00457 widget->activateWindow();
00458 }
00459 }
00460
00461 XChangeProperty(QX11Info::display(), widget->effectiveWinId(), tag, tag, 8, PropModeReplace, &data, 1);
00462 kDebug() << "tagged" << widget << widget->effectiveWinId() << "as" << data;
00463 }
00464 }
00465 return false;
00466 }
00467
00468 void PlasmaApp::dialogDestroyed(QObject *obj)
00469 {
00470 m_dialogs.removeAll(qobject_cast<QWidget*>(obj));
00471 if (m_dialogs.isEmpty()) {
00472 if (m_view) {
00473
00474 m_view->activateWindow();
00475 }
00476
00477
00478
00479
00480 }
00481 }
00482
00483 void PlasmaApp::hideDialogs()
00484 {
00485 foreach (QWidget *w, m_dialogs) {
00486 w->hide();
00487 }
00488 if (m_view) {
00489 m_view->hideAppletBrowser();
00490 }
00491
00492 }
00493
00494 void PlasmaApp::showDialogs()
00495 {
00496 foreach (QWidget *w, m_dialogs) {
00497 w->show();
00498 }
00499
00500 }
00501
00502 void PlasmaApp::configureContainment(Plasma::Containment *containment)
00503 {
00504 if (!m_view) {
00505 return;
00506 }
00507
00508 if (m_configDialog) {
00509 m_configDialog->reloadConfig();
00510 } else {
00511 const QSize resolution = QApplication::desktop()->screenGeometry(containment->screen()).size();
00512
00513 m_configDialog = new BackgroundDialog(resolution, containment, m_view);
00514 m_configDialog->setAttribute(Qt::WA_DeleteOnClose);
00515 connect(m_configDialog, SIGNAL(destroyed(QObject*)),
00516 this, SLOT(configDialogRemoved(QObject*)));
00517 }
00518
00519 m_configDialog->show();
00520 }
00521
00522 void PlasmaApp::configDialogRemoved(QObject* dialog)
00523 {
00524 m_configDialog = 0;
00525 }
00526
00527 void PlasmaApp::lock()
00528 {
00529 if (corona() && corona()->immutability() == Plasma::Mutable) {
00530 hideDialogs();
00531 if (m_view) {
00532 m_view->disableSetupMode();
00533 }
00534 corona()->setImmutability(Plasma::UserImmutable);
00535 }
00536 }
00537
00538 void PlasmaApp::quit()
00539 {
00540 qApp->quit();
00541 }
00542
00543 #include "plasmaapp.moc"