• 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  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "plasmaapp.h"
00021 
00022 #ifdef Q_WS_WIN
00023 #ifdef _WIN32_WINNT
00024 #undef _WIN32_WINNT
00025 #endif
00026 #define _WIN32_WINNT 0x0500
00027 #include <windows.h>
00028 #endif
00029 
00030 #include <unistd.h>
00031 
00032 #ifndef _SC_PHYS_PAGES
00033     #ifdef Q_OS_FREEBSD
00034     #include <sys/types.h>
00035     #include <sys/sysctl.h>
00036     #endif
00037 
00038     #ifdef Q_OS_NETBSD
00039     #include <sys/param.h>
00040     #include <sys/sysctl.h>
00041     #endif
00042 #endif
00043 
00044 #include <QApplication>
00045 #include <QDesktopWidget>
00046 #include <QPixmapCache>
00047 #include <QTimer>
00048 #include <QtDBus/QtDBus>
00049 
00050 #include <KAction>
00051 #include <KCrash>
00052 #include <KDebug>
00053 #include <KCmdLineArgs>
00054 #include <KWindowSystem>
00055 
00056 #include <ksmserver_interface.h>
00057 
00058 #include <Plasma/Containment>
00059 #include <Plasma/Theme>
00060 
00061 #include "appletbrowser.h"
00062 #include "appadaptor.h"
00063 #include "backgrounddialog.h"
00064 #include "desktopcorona.h"
00065 #include "desktopview.h"
00066 #include "panelview.h"
00067 #include "plasma-shell-desktop.h"
00068 
00069 #include <kephal/screens.h>
00070 
00071 #ifdef Q_WS_X11
00072 #include <X11/Xlib.h>
00073 #include <X11/extensions/Xrender.h>
00074 
00075 Display* dpy = 0;
00076 Colormap colormap = 0;
00077 Visual *visual = 0;
00078 #endif
00079 
00080 void checkComposite()
00081 {
00082 #ifdef Q_WS_X11
00083     dpy = XOpenDisplay(0); // open default display
00084     if (!dpy) {
00085         kError() << "Cannot connect to the X server" << endl;
00086         return;
00087     }
00088     if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
00089         return;
00090 
00091     int screen = DefaultScreen(dpy);
00092     int eventBase, errorBase;
00093 
00094     if (XRenderQueryExtension(dpy, &eventBase, &errorBase)) {
00095         int nvi;
00096         XVisualInfo templ;
00097         templ.screen  = screen;
00098         templ.depth   = 32;
00099         templ.c_class = TrueColor;
00100         XVisualInfo *xvi = XGetVisualInfo(dpy,
00101                                           VisualScreenMask | VisualDepthMask | VisualClassMask,
00102                                           &templ, &nvi);
00103         for (int i = 0; i < nvi; ++i) {
00104             XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual);
00105             if (format->type == PictTypeDirect && format->direct.alphaMask) {
00106                 visual = xvi[i].visual;
00107                 colormap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
00108                 break;
00109             }
00110         }
00111         XFree(xvi);
00112     }
00113 
00114     kDebug() << (colormap ? "Plasma has an argb visual" : "Plasma lacks an argb visual") << visual << colormap;
00115     kDebug() << ((KWindowSystem::compositingActive() && colormap) ? "Plasma can use COMPOSITE for effects"
00116                                                                     : "Plasma is COMPOSITE-less") << "on" << dpy;
00117 #endif
00118 }
00119 
00120 PlasmaApp* PlasmaApp::self()
00121 {
00122     if (!kapp) {
00123         checkComposite();
00124 #ifdef Q_WS_X11
00125         return new PlasmaApp(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0);
00126 #else
00127         return new PlasmaApp(0, 0, 0);
00128 #endif
00129     }
00130 
00131     return qobject_cast<PlasmaApp*>(kapp);
00132 }
00133 
00134 PlasmaApp::PlasmaApp(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap)
00135 #ifdef Q_WS_X11
00136     : KUniqueApplication(display, visual, colormap),
00137 #else
00138     : KUniqueApplication(),
00139 #endif
00140       m_corona(0),
00141       m_appletBrowser(0),
00142       m_zoomLevel(Plasma::DesktopZoom),
00143       m_panelHidden(0)
00144 {
00145     KGlobal::locale()->insertCatalog("libplasma");
00146     KGlobal::locale()->insertCatalog("plasma-shells-common");
00147     KCrash::setFlags(KCrash::AutoRestart);
00148 
00149     new PlasmaAppAdaptor(this);
00150     QDBusConnection::sessionBus().registerObject("/App", this);
00151     notifyStartup(false);
00152 
00153     // Enlarge application pixmap cache
00154     // Calculate the size required to hold background pixmaps for all screens.
00155     // Add 10% so that other (smaller) pixmaps can also be cached.
00156     int cacheSize = 0;
00157     for (int i = 0; i < Kephal::ScreenUtils::numScreens(); i++) {
00158         QSize size = Kephal::ScreenUtils::screenSize(i);
00159         cacheSize += 4 * size.width() * size.height() / 1024;
00160     }
00161     cacheSize += cacheSize / 10;
00162 
00163     // Calculate the size of physical system memory; _SC_PHYS_PAGES *
00164     // _SC_PAGESIZE is documented to be able to overflow 32-bit integers,
00165     // so apply a 10-bit shift. FreeBSD 6-STABLE doesn't have _SC_PHYS_PAGES
00166     // (it is documented in FreeBSD 7-STABLE as "Solaris and Linux extension")
00167     // so use sysctl in those cases.
00168 #if defined(_SC_PHYS_PAGES)
00169     int memorySize = sysconf(_SC_PHYS_PAGES);
00170     memorySize *= sysconf(_SC_PAGESIZE) / 1024;
00171 #else
00172 #ifdef Q_OS_FREEBSD
00173     int sysctlbuf[2];
00174     size_t size = sizeof(sysctlbuf);
00175     int memorySize;
00176     // This could actually use hw.physmem instead, but I can't find
00177     // reliable documentation on how to read the value (which may
00178     // not fit in a 32 bit integer).
00179     if (!sysctlbyname("vm.stats.vm.v_page_size", sysctlbuf, &size, NULL, 0)) {
00180         memorySize = sysctlbuf[0] / 1024;
00181         size = sizeof(sysctlbuf);
00182         if (!sysctlbyname("vm.stats.vm.v_page_count", sysctlbuf, &size, NULL, 0)) {
00183             memorySize *= sysctlbuf[0];
00184         }
00185     }
00186 #endif
00187 #ifdef Q_OS_NETBSD
00188     size_t memorySize;
00189     size_t len;
00190     static int mib[] = { CTL_HW, HW_PHYSMEM };
00191 
00192     len = sizeof(memorySize);
00193     sysctl(mib, 2, &memorySize, &len, NULL, 0);
00194     memorySize /= 1024;
00195 #endif
00196 #ifdef Q_WS_WIN
00197     size_t memorySize;
00198 
00199     MEMORYSTATUSEX statex;
00200     statex.dwLength = sizeof (statex);
00201     GlobalMemoryStatusEx (&statex);
00202 
00203     memorySize = (statex.ullTotalPhys/1024) + (statex.ullTotalPageFile/1024);
00204 #endif
00205     // If you have no suitable sysconf() interface and are not FreeBSD,
00206     // then you are out of luck and get a compile error.
00207 #endif
00208 
00209     // Increase the pixmap cache size to 1% of system memory if it isn't already
00210     // larger so as to maximize cache usage. 1% of 1GB ~= 10MB.
00211     if (cacheSize < memorySize / 100) {
00212         cacheSize = memorySize / 100;
00213     }
00214 
00215     kDebug() << "Setting the pixmap cache size to" << cacheSize << "kilobytes";
00216     QPixmapCache::setCacheLimit(cacheSize);
00217 
00218     //TODO: Make the shortcut configurable
00219     KAction *showAction = new KAction( this );
00220     showAction->setText( i18n( "Show Dashboard" ) );
00221     showAction->setObjectName( "Show Dashboard" ); // NO I18N
00222     showAction->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F12 ) );
00223     connect( showAction, SIGNAL( triggered() ), this, SLOT( toggleDashboard() ) );
00224 
00225     connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
00226     QTimer::singleShot(0, this, SLOT(setupDesktop()));
00227 }
00228 
00229 PlasmaApp::~PlasmaApp()
00230 {
00231     delete m_appletBrowser;
00232 }
00233 
00234 void PlasmaApp::setupDesktop()
00235 {
00236 #ifdef Q_WS_X11
00237     Atom atoms[5];
00238     const char *atomNames[] = {"XdndAware", "XdndEnter", "XdndFinished", "XdndPosition", "XdndStatus"};
00239     XInternAtoms(QX11Info::display(), const_cast<char **>(atomNames), 5, False, atoms);
00240     m_XdndAwareAtom = atoms[0];
00241     m_XdndEnterAtom = atoms[1];
00242     m_XdndFinishedAtom = atoms[2];
00243     m_XdndPositionAtom = atoms[3];
00244     m_XdndStatusAtom = atoms[4];
00245     const int xdndversion = 5;
00246     m_XdndVersionAtom = (Atom)xdndversion;
00247 #endif
00248 
00249     // intialize the default theme and set the font
00250     Plasma::Theme *theme = Plasma::Theme::defaultTheme();
00251     theme->setFont(AppSettings::desktopFont());
00252     connect(theme, SIGNAL(themeChanged()), this, SLOT(compositingChanged()));
00253 
00254     // this line initializes the corona.
00255     corona();
00256 
00257     Kephal::Screens *screens = Kephal::Screens::self();
00258     connect(screens, SIGNAL(screenRemoved(int)), SLOT(screenRemoved(int)));
00259 
00260     // and now, let everyone know we're ready!
00261     notifyStartup(true);
00262 }
00263 
00264 void PlasmaApp::cleanup()
00265 {
00266     if (m_corona) {
00267         m_corona->saveLayout();
00268     }
00269 
00270     // save the mapping of Views to Containments at the moment
00271     // of application exit so we can restore that when we start again.
00272     KConfigGroup viewIds(KGlobal::config(), "ViewIds");
00273     viewIds.deleteGroup();
00274 
00275     foreach (PanelView *v, m_panels) {
00276         if (v->containment()) {
00277             viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
00278         }
00279     }
00280 
00281     foreach (DesktopView *v, m_desktops) {
00282         if (v->containment()) {
00283             viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
00284         }
00285     }
00286 
00287     QList<DesktopView*> desktops = m_desktops;
00288     m_desktops.clear();
00289     qDeleteAll(desktops);
00290 
00291     QList<PanelView*> panels = m_panels;
00292     m_panels.clear();
00293     qDeleteAll(panels);
00294 
00295     QHash<Plasma::Containment *, BackgroundDialog *> dialogs = m_configDialogs;
00296     m_configDialogs.clear();
00297     qDeleteAll(dialogs);
00298 
00299     delete m_corona;
00300 
00301     //TODO: This manual sync() should not be necessary. Remove it when
00302     // KConfig was fixed
00303     KGlobal::config()->sync();
00304 }
00305 
00306 void PlasmaApp::syncConfig()
00307 {
00308     KGlobal::config()->sync();
00309 }
00310 
00311 void PlasmaApp::toggleDashboard()
00312 {
00313     int currentScreen = 0;
00314     if (Kephal::ScreenUtils::numScreens() > 1) {
00315         currentScreen = Kephal::ScreenUtils::screenId(QCursor::pos());
00316     }
00317 
00318     int currentDesktop = -1;
00319     if (AppSettings::perVirtualDesktopViews()) {
00320         currentDesktop = KWindowSystem::currentDesktop();
00321     }
00322 
00323     DesktopView *view = viewForScreen(currentScreen, currentDesktop);
00324     if (!view) {
00325         kWarning() << "we don't have a DesktopView for the current screen!" << currentScreen << currentDesktop;
00326         return;
00327     }
00328 
00329     view->toggleDashboard();
00330 }
00331 
00332 void PlasmaApp::panelHidden(bool hidden)
00333 {
00334     if (hidden) {
00335         ++m_panelHidden;
00336         //kDebug() << "panel hidden" << m_panelHidden;
00337     } else {
00338         --m_panelHidden;
00339         if (m_panelHidden < 0) {
00340             kDebug() << "panelHidden(false) called too many times!";
00341             m_panelHidden = 0;
00342         }
00343         //kDebug() << "panel unhidden" << m_panelHidden;
00344     }
00345 }
00346 
00347 Plasma::ZoomLevel PlasmaApp::desktopZoomLevel() const
00348 {
00349     return m_zoomLevel;
00350 }
00351 
00352 QList<PanelView*> PlasmaApp::panelViews() const
00353 {
00354     return m_panels;
00355 }
00356 
00357 void PlasmaApp::compositingChanged()
00358 {
00359 #ifdef Q_WS_X11
00360     foreach (PanelView *panel, m_panels) {
00361         panel->recreateUnhideTrigger();
00362     }
00363 #endif
00364 }
00365 
00366 #ifdef Q_WS_X11
00367 PanelView *PlasmaApp::findPanelForTrigger(WId trigger) const
00368 {
00369     foreach (PanelView *panel, m_panels) {
00370         if (panel->unhideTrigger() == trigger) {
00371             return panel;
00372         }
00373     }
00374 
00375     return 0;
00376 }
00377 
00378 bool PlasmaApp::x11EventFilter(XEvent *event)
00379 {
00380     if (m_panelHidden &&
00381         (event->type == ClientMessage ||
00382          (event->xany.send_event != True && (event->type == EnterNotify ||
00383                                              event->type == MotionNotify)))) {
00384 
00385         /*
00386         if (event->type == ClientMessage) {
00387             kDebug() << "client message with" << event->xclient.message_type << m_XdndEnterAtom << event->xcrossing.window;
00388         }
00389         */
00390 
00391         bool dndEnter = false;
00392         bool dndPosition = false;
00393         if (event->type == ClientMessage) {
00394             dndEnter = event->xclient.message_type == m_XdndEnterAtom;
00395             if (!dndEnter) {
00396                 dndPosition = event->xclient.message_type == m_XdndPositionAtom;
00397                 if (!dndPosition) {
00398                     //kDebug() << "FAIL!";
00399                     return KUniqueApplication::x11EventFilter(event);
00400                 }
00401             } else {
00402                 //kDebug() << "on enter" << event->xclient.data.l[0];
00403             }
00404         }
00405 
00406         PanelView *panel = findPanelForTrigger(event->xcrossing.window);
00407         //kDebug() << "panel?" << panel << ((dndEnter || dndPosition) ? "Drag and drop op" : "Mouse move op");
00408         if (panel) {
00409             if (dndEnter || dndPosition) {
00410                 QPoint p;
00411 
00412                 const unsigned long *l = (const unsigned long *)event->xclient.data.l;
00413                 if (dndPosition) {
00414                     p = QPoint((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
00415                 }
00416 
00417                 XClientMessageEvent response;
00418                 response.type = ClientMessage;
00419                 response.window = l[0];
00420                 response.format = 32;
00421                 response.data.l[0] = panel->winId(); //event->xcrossing.window;
00422 
00423                 if (panel->hintOrUnhide(p, true)) {
00424                     response.message_type = m_XdndFinishedAtom;
00425                     response.data.l[1] = 0; // flags
00426                     response.data.l[2] = XNone;
00427                 } else {
00428                     response.message_type = m_XdndStatusAtom;
00429                     response.data.l[1] = 0; // flags
00430                     response.data.l[2] = 0; // x, y
00431                     response.data.l[3] = 0; // w, h
00432                     response.data.l[4] = 0; // action
00433                 }
00434 
00435                 XSendEvent(QX11Info::display(), l[0], False, NoEventMask, (XEvent*)&response);
00436             } else if (event->type == EnterNotify) {
00437                 panel->hintOrUnhide(QPoint(-1, -1));
00438                 //kDebug() << "entry";
00439             //FIXME: this if it was possible to avoid the polling
00440             /*} else if (event->type == LeaveNotify) {
00441                 panel->unhintHide();
00442             */
00443             } else if (event->type == MotionNotify) {
00444                 XMotionEvent *motion = (XMotionEvent*)event;
00445                 //kDebug() << "motion" << motion->x << motion->y << panel->location();
00446                 panel->hintOrUnhide(QPoint(motion->x_root, motion->y_root));
00447             }
00448 
00449             return true;
00450         }
00451     }
00452 
00453     return KUniqueApplication::x11EventFilter(event);
00454 }
00455 #endif
00456 
00457 void PlasmaApp::screenRemoved(int id)
00458 {
00459     kDebug() << id;
00460     QMutableListIterator<DesktopView *> it(m_desktops);
00461     while (it.hasNext()) {
00462         DesktopView *view = it.next();
00463         if (view->screen() == id) {
00464             // the screen was removed, so we'll destroy the
00465             // corresponding view
00466             kDebug() << "removing the view for screen" << id;
00467             view->setContainment(0);
00468             it.remove();
00469             delete view;
00470         }
00471     }
00472 
00473     /*
00474     TODO: remove panels when screen goes away.
00475           first, however, we need to be able to reserve and restore the panelsettings
00476           even when the view itself goes away
00477     QMutableListIterator<PanelView*> it(m_panels);
00478     while (it.hasNext()) {
00479         PanelView *panel = it.next();
00480         if (panel->screen() == i) {
00481             delete panel;
00482             it.remove();
00483         }
00484     }
00485     */
00486 }
00487 
00488 DesktopView* PlasmaApp::viewForScreen(int screen, int desktop) const
00489 {
00490     foreach (DesktopView *view, m_desktops) {
00491         //kDebug() << "comparing" << view->screen() << screen;
00492         if (view->screen() == screen && (desktop < 0 || view->desktop() == desktop)) {
00493             return view;
00494         }
00495     }
00496 
00497     return 0;
00498 }
00499 
00500 Plasma::Corona* PlasmaApp::corona()
00501 {
00502     if (!m_corona) {
00503         QTime t;
00504         t.start();
00505         DesktopCorona *c = new DesktopCorona(this);
00506         connect(c, SIGNAL(containmentAdded(Plasma::Containment*)),
00507                 this, SLOT(containmentAdded(Plasma::Containment*)));
00508         connect(c, SIGNAL(configSynced()), this, SLOT(syncConfig()));
00509 
00510         foreach (DesktopView *view, m_desktops) {
00511             connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00512                     view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00513         }
00514 
00515         m_corona = c;
00516         c->setItemIndexMethod(QGraphicsScene::NoIndex);
00517         c->initializeLayout();
00518         c->checkScreens();
00519         kDebug() << " ------------------------------------------>" << t.elapsed();
00520     }
00521 
00522     return m_corona;
00523 }
00524 
00525 void PlasmaApp::showAppletBrowser()
00526 {
00527     Plasma::Containment *containment = dynamic_cast<Plasma::Containment *>(sender());
00528 
00529     if (!containment) {
00530         return;
00531     }
00532 
00533     foreach (DesktopView *view, m_desktops) {
00534         if (view->containment() == containment && view->isDashboardVisible()) {
00535             // the dashboard will pick this one up!
00536             return;
00537         }
00538     }
00539 
00540     showAppletBrowser(containment);
00541 }
00542 
00543 void PlasmaApp::showAppletBrowser(Plasma::Containment *containment)
00544 {
00545     if (!containment) {
00546         return;
00547     }
00548 
00549     if (!m_appletBrowser) {
00550         m_appletBrowser = new Plasma::AppletBrowser();
00551         m_appletBrowser->setContainment(containment);
00552         m_appletBrowser->setApplication();
00553         m_appletBrowser->setAttribute(Qt::WA_DeleteOnClose);
00554         m_appletBrowser->setWindowTitle(i18n("Add Widgets"));
00555         m_appletBrowser->setWindowIcon(KIcon("plasmagik"));
00556         connect(m_appletBrowser, SIGNAL(destroyed()), this, SLOT(appletBrowserDestroyed()));
00557     } else {
00558         m_appletBrowser->setContainment(containment);
00559     }
00560 
00561     KWindowSystem::setOnDesktop(m_appletBrowser->winId(), KWindowSystem::currentDesktop());
00562     m_appletBrowser->show();
00563     KWindowSystem::activateWindow(m_appletBrowser->winId());
00564 }
00565 
00566 void PlasmaApp::appletBrowserDestroyed()
00567 {
00568     m_appletBrowser = 0;
00569 }
00570 
00571 bool PlasmaApp::hasComposite()
00572 {
00573 //    return true;
00574 #ifdef Q_WS_X11
00575     return colormap && KWindowSystem::compositingActive();
00576 #else
00577     return false;
00578 #endif
00579 }
00580 
00581 void PlasmaApp::notifyStartup(bool completed)
00582 {
00583     org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
00584 
00585     const QString startupID("workspace desktop");
00586     if (completed) {
00587         ksmserver.resumeStartup(startupID);
00588     } else {
00589         ksmserver.suspendStartup(startupID);
00590     }
00591 }
00592 
00593 void PlasmaApp::createView(Plasma::Containment *containment)
00594 {
00595     kDebug() << "Containment name:" << containment->name()
00596              << "| type" << containment->containmentType()
00597              <<  "| screen:" << containment->screen()
00598              <<  "| desktop:" << containment->desktop()
00599              << "| geometry:" << containment->geometry()
00600              << "| zValue:" << containment->zValue();
00601 
00602     // find the mapping of View to Containment, if any,
00603     // so we can restore things on start.
00604     KConfigGroup viewIds(KGlobal::config(), "ViewIds");
00605     int id = viewIds.readEntry(QString::number(containment->id()), 0);
00606 
00607     WId viewWindow = 0;
00608 
00609     switch (containment->containmentType()) {
00610         case Plasma::Containment::PanelContainment: {
00611             PanelView *panelView = new PanelView(containment, id);
00612             viewWindow = panelView->winId();
00613             connect(panelView, SIGNAL(destroyed(QObject*)), this, SLOT(panelRemoved(QObject*)));
00614             m_panels << panelView;
00615             panelView->show();
00616             break;
00617         }
00618         default:
00619             if (containment->screen() > -1 &&
00620                 containment->screen() < Kephal::ScreenUtils::numScreens()) {
00621                 DesktopView *view = viewForScreen(containment->screen(), containment->desktop());
00622                 if (view) {
00623                     kDebug() << "had a view for" << containment->screen() << containment->desktop();
00624                     // we already have a view for this screen
00625                     return;
00626                 }
00627 
00628                 kDebug() << "creating a new view for" << containment->screen() << containment->desktop()
00629                          << "and we have" << Kephal::ScreenUtils::numScreens() << "screens";
00630 
00631 
00632                 // we have a new screen. neat.
00633                 view = new DesktopView(containment, id, 0);
00634                 viewWindow = view->winId();
00635                 if (m_corona) {
00636                     connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00637                             view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00638                 }
00639 
00640                 m_desktops.append(view);
00641                 view->show();
00642             }
00643             break;
00644     }
00645 
00646 #ifdef Q_WS_X11
00647     //FIXME: if argb visuals enabled Qt will always set WM_CLASS as "qt-subapplication" no matter what
00648     //the application name is we set the proper XClassHint here, hopefully won't be necessary anymore when
00649     //qapplication will manage apps with argvisuals in a better way
00650     if (viewWindow) {
00651         XClassHint classHint;
00652         classHint.res_name = const_cast<char*>("Plasma");
00653         classHint.res_class = const_cast<char*>("Plasma");
00654         XSetClassHint(QX11Info::display(), viewWindow, &classHint);
00655     }
00656 #endif
00657 }
00658 
00659 void PlasmaApp::containmentAdded(Plasma::Containment *containment)
00660 {
00661     createView(containment);
00662     disconnect(containment, 0, this, 0);
00663     connect(containment, SIGNAL(zoomRequested(Plasma::Containment*,Plasma::ZoomDirection)),
00664             this, SLOT(zoom(Plasma::Containment*,Plasma::ZoomDirection)));
00665     connect(containment, SIGNAL(showAddWidgetsInterface(QPointF)), this, SLOT(showAppletBrowser()));
00666     connect(containment, SIGNAL(configureRequested(Plasma::Containment*)),
00667             this, SLOT(configureContainment(Plasma::Containment*)));
00668 
00669     if (containment->containmentType() != Plasma::Containment::PanelContainment) {
00670         connect(containment, SIGNAL(addSiblingContainment(Plasma::Containment *)),
00671                 this, SLOT(addContainment(Plasma::Containment *)));
00672     }
00673 }
00674 
00675 void PlasmaApp::configureContainment(Plasma::Containment *containment)
00676 {
00677     BackgroundDialog *configDialog = 0;
00678 
00679     if (m_configDialogs.contains(containment)) {
00680         configDialog = m_configDialogs.value(containment);
00681         configDialog->reloadConfig();
00682     } else {
00683         const QSize resolution = QApplication::desktop()->screenGeometry(containment->screen()).size();
00684         Plasma::View *view = viewForScreen(containment->screen(), containment->desktop());
00685 
00686         if (!view) {
00687             view = viewForScreen(desktop()->screenNumber(QCursor::pos()), containment->desktop());
00688 
00689             if (!view) {
00690                 if (m_desktops.count() < 1) {
00691                     return;
00692                 }
00693 
00694                 view = m_desktops.at(0);
00695             }
00696 
00697         }
00698 
00699         configDialog = new BackgroundDialog(resolution, containment, view);
00700         configDialog->setAttribute(Qt::WA_DeleteOnClose);
00701         connect(configDialog, SIGNAL(destroyed(QObject*)),
00702                 this, SLOT(configDialogRemoved(QObject*)));
00703     }
00704 
00705     configDialog->show();
00706     KWindowSystem::setOnDesktop(configDialog->winId(), KWindowSystem::currentDesktop());
00707     KWindowSystem::activateWindow(configDialog->winId());
00708 }
00709 
00710 void PlasmaApp::addContainment(Plasma::Containment *fromContainment)
00711 {
00712     QString plugin = fromContainment ? fromContainment->pluginName() : QString();
00713     Plasma::Containment *c = m_corona->addContainment(plugin);
00714 
00715     if (c && fromContainment) {
00716         foreach (DesktopView *view, m_desktops) {
00717             if (view->containment() == c){
00718                 view->setContainment(c);
00719                 return;
00720             }
00721         }
00722 
00723         // if we reach here, the containment isn't going to be taken over by the view,
00724         // so we're going to resize it ourselves!
00725         c->resize(fromContainment->size());
00726     }
00727 }
00728 
00729 void PlasmaApp::zoom(Plasma::Containment *containment, Plasma::ZoomDirection direction)
00730 {
00731     if (direction == Plasma::ZoomIn) {
00732         zoomIn(containment);
00733         foreach (DesktopView *view, m_desktops) {
00734             view->zoomIn(m_zoomLevel);
00735         }
00736 
00737         if (m_zoomLevel == Plasma::DesktopZoom) {
00738             int currentDesktop = -1;
00739             if (AppSettings::perVirtualDesktopViews()) {
00740                 currentDesktop = KWindowSystem::currentDesktop();
00741             }
00742 
00743             DesktopView *view = viewForScreen(desktop()->screenNumber(QCursor::pos()), currentDesktop);
00744 
00745             if (view && view->containment() != containment) {
00746                 // zooming in all the way, so lets swap containments about if need be
00747                 view->setContainment(containment);
00748             }
00749         }
00750     } else if (direction == Plasma::ZoomOut) {
00751         zoomOut(containment);
00752         foreach (DesktopView *view, m_desktops) {
00753             view->zoomOut(m_zoomLevel);
00754         }
00755     }
00756 }
00757 
00758 void PlasmaApp::zoomIn(Plasma::Containment *containment)
00759 {
00760     bool isMutable = m_corona->immutability() == Plasma::Mutable;
00761     bool zoomIn = true;
00762     bool zoomOut = true;
00763     bool addSibling = isMutable;
00764     bool lock = false;
00765     bool remove = false;
00766 
00767     if (m_zoomLevel == Plasma::GroupZoom) {
00768         m_zoomLevel = Plasma::DesktopZoom;
00769         containment->closeToolBox();
00770         addSibling = false;
00771         zoomIn = false;
00772         lock = true;
00773     } else if (m_zoomLevel == Plasma::OverviewZoom) {
00774         m_zoomLevel = Plasma::GroupZoom;
00775         remove = isMutable && true;
00776     }
00777 
00778     //make sure everybody can zoom out again
00779     foreach (Plasma::Containment *c, m_corona->containments()) {
00780         if (c->containmentType() == Plasma::Containment::PanelContainment) {
00781             continue;
00782         }
00783 
00784         c->enableAction("zoom in", zoomIn);
00785         c->enableAction("zoom out", zoomOut);
00786         c->enableAction("add sibling containment", addSibling);
00787         c->enableAction("lock widgets", lock);
00788         c->enableAction("remove", remove && (c->screen() == -1));
00789         c->enableAction("add widgets", isMutable);
00790     }
00791 }
00792 
00793 void PlasmaApp::zoomOut(Plasma::Containment *)
00794 {
00795     bool isMutable = m_corona->immutability() == Plasma::Mutable;
00796     bool zoomIn = true;
00797     bool zoomOut = true;
00798     bool addSibling = isMutable && true;
00799     bool lock = false;
00800     bool addWidgets = isMutable && true;
00801 
00802     if (m_zoomLevel == Plasma::DesktopZoom) {
00803         m_zoomLevel = Plasma::GroupZoom;
00804     } else if (m_zoomLevel == Plasma::GroupZoom) {
00805         m_zoomLevel = Plasma::OverviewZoom;
00806         zoomOut = false;
00807         addWidgets = false;
00808     }
00809 
00810     //make sure everybody can zoom out again
00811     foreach (Plasma::Containment *c, m_corona->containments()) {
00812         if (c->containmentType() == Plasma::Containment::PanelContainment) {
00813             continue;
00814         }
00815 
00816         c->enableAction("zoom in", zoomIn);
00817         c->enableAction("zoom out", zoomOut);
00818         c->enableAction("add sibling containment", addSibling);
00819         c->enableAction("lock widgets", lock);
00820         c->enableAction("remove", isMutable && c->screen() == -1);
00821         c->enableAction("add widgets", addWidgets);
00822     }
00823 }
00824 
00825 void PlasmaApp::panelRemoved(QObject* panel)
00826 {
00827     m_panels.removeAll((PanelView*)panel);
00828 }
00829 
00830 void PlasmaApp::configDialogRemoved(QObject* dialog)
00831 {
00832     QMutableHashIterator<Plasma::Containment *, BackgroundDialog *> it(m_configDialogs);
00833     while (it.hasNext()) {
00834         it.next();
00835         if (it.value() == (BackgroundDialog*)dialog) {
00836            it.remove();
00837         }
00838     }
00839 }
00840 
00841 #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