• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

plasmaapp.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2006 Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2008 Chani Armitage <chanika@gmail.com>
00004  *
00005  *
00006  *   This program is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU General Public License as
00008  *   published by the Free Software Foundation; either version 2,
00009  *   or (at your option) any later version.
00010  *
00011  *   This program is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details
00015  *
00016  *   You should have received a copy of the GNU Library General Public
00017  *   License along with this program; if not, write to the
00018  *   Free Software Foundation, Inc.,
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  */
00021 
00022 // plasma.loadEngine("hardware")
00023 // LineGraph graph
00024 // plasma.connect(graph, "hardware", "cpu");
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 //#include <KCrash>
00048 #include <KDebug>
00049 #include <KCmdLineArgs>
00050 #include <KWindowSystem>
00051 
00052 //#include <ksmserver_interface.h>
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; //FIXME should this be a member var or what?
00068 const unsigned char DIALOG = 1; //FIXME this is really bad code
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); // open default display
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     //load translations for libplasma
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     //FIXME this is probably totally invalid
00140     // Enlarge application pixmap cache
00141     // Calculate the size required to hold background pixmaps for all screens.
00142     // Add 10% so that other (smaller) pixmaps can also be cached.
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     // Calculate the size of physical system memory; _SC_PHYS_PAGES *
00152     // _SC_PAGESIZE is documented to be able to overflow 32-bit integers,
00153     // so apply a 10-bit shift. FreeBSD 6-STABLE doesn't have _SC_PHYS_PAGES
00154     // (it is documented in FreeBSD 7-STABLE as "Solaris and Linux extension")
00155     // so use sysctl in those cases.
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     // This could actually use hw.physmem instead, but I can't find
00165     // reliable documentation on how to read the value (which may 
00166     // not fit in a 32 bit integer).
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     // If you have no suitable sysconf() interface and are not FreeBSD,
00185     // then you are out of luck and get a compile error.
00186 #endif
00187 
00188     // Increase the pixmap cache size to 1% of system memory if it isn't already
00189     // larger so as to maximize cache usage. 1% of 1GB ~= 10MB.
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     //we have to keep an eye on created windows
00207     tag = XInternAtom(QX11Info::display(), "_KDE_SCREENSAVER_OVERRIDE", False);
00208     qApp->installEventFilter(this);
00209 
00210     // this line initializes the corona.
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         //assume it's active, since things are happening
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             //opacity is 0
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     //FIXME someone needs to tell us what size to use if we've got >1 screen
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         //kDebug() << "connected to containmentAdded";
00324         /*
00325         foreach (DesktopView *view, m_desktops) {
00326             connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00327                             view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00328         }*/
00329 
00330         m_corona->setItemIndexMethod(QGraphicsScene::NoIndex);
00331         m_corona->initializeLayout();
00332 
00333         //kDebug() << "layout should exist";
00334         //c->checkScreens();
00335     }
00336 
00337     return m_corona;
00338 }
00339 
00340 bool PlasmaApp::hasComposite()
00341 {
00342     return composite;
00343 }
00344 
00345 //I think we need this for when the corona loads the default setup
00346 //but maybe something simpler would suffice
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         // we already have a view for this screen
00357         return;
00358     }
00359 
00360     kDebug() << "creating a view for" << containment->screen() << "and we have"
00361         << QApplication::desktop()->numScreens() << "screens";
00362 
00363     // we have a new screen. neat.
00364     m_view = new SaverView(containment, 0);
00365                 /*if (m_corona) {
00366                     connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00367                             view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00368                 }*/
00369     //FIXME is this the right geometry for multi-screen?
00370     m_view->setGeometry(QApplication::desktop()->screenGeometry(containment->screen()));
00371 
00372     //FIXME why do I get BadWindow?
00373     //unsigned char data = VIEW;
00374     //XChangeProperty(QX11Info::display(), m_view->effectiveWinId(), tag, tag, 8, PropModeReplace, &data, 1);
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(); //this failed once. why?
00412         }
00413     }
00414 }
00415 
00416 bool PlasmaApp::eventFilter(QObject *obj, QEvent *event)
00417 {
00418     if (event->type() == QEvent::Show) {
00419         //apparently this means we created a new window
00420         //so, add a tag to prove it's our window
00421         //FIXME using the show event means we tag on every show, not just the first.
00422         //harmless but kinda wasteful.
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                     //now we're *really* fucking with things
00436                     //we force-disable window management and frames to cut off access to wm-y stuff
00437                     //and to make it easy to check the tag (frames are a pain)
00438                     kDebug() << "!!!!!!!setting flags on!!!!!" << widget;
00439                     if (qobject_cast<Plasma::Dialog*>(widget)) {
00440                         //this is a terrible horrible hack that breaks extenders but it mostly works
00441                         //weird thing is, it sometimes makes the calendar popup too small.
00442                         newFlags = Qt::Popup;
00443                     } else {
00444                         //plasmadialogs can't handle direct input
00445                         //but configdialogs need it
00446                         m_dialogs.append(widget);
00447                         connect(widget, SIGNAL(destroyed(QObject*)), SLOT(dialogDestroyed(QObject*)));
00448                     }
00449                     widget->setWindowFlags(newFlags);
00450                     widget->show(); //setting the flags hid it :(
00451                     //qApp->setActiveWindow(widget); //gives kbd but not mouse events
00452                     //kDebug() << "parent" << widget->parentWidget();
00453                     //FIXME why can I only activate these dialogs from this exact line?
00454                     widget->activateWindow(); //gives keyboard focus
00455                     return false; //we'll be back when we get the new show event
00456                 } else {
00457                     widget->activateWindow(); //gives keyboard focus
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             //this makes qactions work again
00474             m_view->activateWindow();
00475         }
00476     /*} else { failed attempt to fix kbd input after a subdialog closes
00477         QWidget *top = m_dialogs.last();
00478         top->activateWindow();
00479         kDebug() << top;*/
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     //FIXME where does the focus go?
00492 }
00493 
00494 void PlasmaApp::showDialogs()
00495 {
00496     foreach (QWidget *w, m_dialogs) {
00497         w->show();
00498     }
00499     //FIXME where does the focus go?
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"

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal