00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "plasmaapp.h"
00025
00026 #include <unistd.h>
00027
00028 #ifndef _SC_PHYS_PAGES
00029 #ifdef Q_OS_FREEBSD
00030 #include <sys/types.h>
00031 #include <sys/sysctl.h>
00032 #endif
00033
00034 #ifdef Q_OS_NETBSD
00035 #include <sys/param.h>
00036 #include <sys/sysctl.h>
00037 #endif
00038 #endif
00039
00040 #include <QApplication>
00041 #include <QDesktopWidget>
00042 #include <QPixmapCache>
00043 #include <QTimer>
00044 #include <QtDBus/QtDBus>
00045
00046 #include <KCrash>
00047 #include <KDebug>
00048 #include <KCmdLineArgs>
00049 #include <KWindowSystem>
00050 #include <KAction>
00051
00052 #include <ksmserver_interface.h>
00053
00054 #include "plasma/appletbrowser.h"
00055 #include <plasma/containment.h>
00056 #include <plasma/theme.h>
00057
00058 #include "appadaptor.h"
00059 #include "desktopcorona.h"
00060 #include "desktopview.h"
00061 #include "panelview.h"
00062
00063 #include <X11/Xlib.h>
00064 #include <X11/extensions/Xrender.h>
00065
00066 Display* dpy = 0;
00067 Colormap colormap = 0;
00068 Visual *visual = 0;
00069
00070 void checkComposite()
00071 {
00072 dpy = XOpenDisplay(0);
00073 if (!dpy) {
00074 kError() << "Cannot connect to the X server" << endl;
00075 return;
00076 }
00077
00078 int screen = DefaultScreen(dpy);
00079 int eventBase, errorBase;
00080
00081 if (XRenderQueryExtension(dpy, &eventBase, &errorBase)) {
00082 int nvi;
00083 XVisualInfo templ;
00084 templ.screen = screen;
00085 templ.depth = 32;
00086 templ.c_class = TrueColor;
00087 XVisualInfo *xvi = XGetVisualInfo(dpy,
00088 VisualScreenMask | VisualDepthMask | VisualClassMask,
00089 &templ, &nvi);
00090 for (int i = 0; i < nvi; ++i) {
00091 XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual);
00092 if (format->type == PictTypeDirect && format->direct.alphaMask) {
00093 visual = xvi[i].visual;
00094 colormap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
00095 break;
00096 }
00097 }
00098 }
00099
00100 kDebug() << (colormap ? "Plasma has an argb visual" : "Plasma lacks an argb visual") << visual << colormap;
00101 kDebug() << ((KWindowSystem::compositingActive() && colormap) ? "Plasma can use COMPOSITE for effects"
00102 : "Plasma is COMPOSITE-less") << "on" << dpy;
00103 }
00104
00105 PlasmaApp* PlasmaApp::self()
00106 {
00107 if (!kapp) {
00108 checkComposite();
00109 return new PlasmaApp(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0);
00110 }
00111
00112 return qobject_cast<PlasmaApp*>(kapp);
00113 }
00114
00115 PlasmaApp::PlasmaApp(Display* display, Qt::HANDLE visual, Qt::HANDLE colormap)
00116 : KUniqueApplication(display, visual, colormap),
00117 m_corona(0),
00118 m_appletBrowser(0)
00119 {
00120 KGlobal::locale()->insertCatalog("libplasma");
00121
00122 new PlasmaAppAdaptor(this);
00123 QDBusConnection::sessionBus().registerObject("/App", this);
00124 notifyStartup(false);
00125
00126
00127
00128 if (!KCrash::crashHandler())
00129 {
00130
00131
00132
00133 QTimer::singleShot(10000, this, SLOT(setCrashHandler()));
00134 }
00135 else
00136 {
00137
00138
00139
00140 setCrashHandler();
00141 }
00142
00143
00144
00145
00146 int cacheSize = 0;
00147 QDesktopWidget *desktop = QApplication::desktop();
00148 for (int i = 0; i < desktop->numScreens(); i++) {
00149 QRect geometry = desktop->screenGeometry(i);
00150 cacheSize += 4 * geometry.width() * geometry.height() / 1024;
00151 }
00152 cacheSize += cacheSize / 10;
00153
00154
00155
00156
00157
00158
00159 #if defined(_SC_PHYS_PAGES)
00160 int memorySize = sysconf(_SC_PHYS_PAGES);
00161 memorySize *= sysconf(_SC_PAGESIZE) / 1024;
00162 #else
00163 #ifdef Q_OS_FREEBSD
00164 int sysctlbuf[2];
00165 size_t size = sizeof(sysctlbuf);
00166 int memorySize;
00167
00168
00169
00170 if (!sysctlbyname("vm.stats.vm.v_page_size", sysctlbuf, &size, NULL, 0)) {
00171 memorySize = sysctlbuf[0] / 1024;
00172 size = sizeof(sysctlbuf);
00173 if (!sysctlbyname("vm.stats.vm.v_page_count", sysctlbuf, &size, NULL, 0)) {
00174 memorySize *= sysctlbuf[0];
00175 }
00176 }
00177 #endif
00178 #ifdef Q_OS_NETBSD
00179 size_t memorySize;
00180 size_t len;
00181 static int mib[] = { CTL_HW, HW_PHYSMEM };
00182
00183 len = sizeof(memorySize);
00184 sysctl(mib, 2, &memorySize, &len, NULL, 0);
00185 memorySize /= 1024;
00186 #endif
00187
00188
00189 #endif
00190
00191
00192
00193 if (cacheSize < memorySize / 100) {
00194 cacheSize = memorySize / 100;
00195 }
00196
00197 kDebug() << "Setting the pixmap cache size to" << cacheSize << "kilobytes";
00198 QPixmapCache::setCacheLimit(cacheSize);
00199
00200 KConfigGroup cg(KGlobal::config(), "General");
00201 Plasma::Theme::defaultTheme()->setFont(cg.readEntry("desktopFont", font()));
00202
00203 setIsDesktop(KCmdLineArgs::parsedArgs()->isSet("desktop"));
00204
00205
00206 KAction *showAction = new KAction( this );
00207 showAction->setText( i18n( "Show Dashboard" ) );
00208 showAction->setObjectName( "Show Dashboard" );
00209 showAction->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F12 ) );
00210 connect( showAction, SIGNAL( triggered() ), this, SLOT( toggleDashboard() ) );
00211
00212
00213 corona();
00214
00215 notifyStartup(true);
00216
00217 connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
00218 }
00219
00220 PlasmaApp::~PlasmaApp()
00221 {
00222 delete m_appletBrowser;
00223 }
00224
00225 void PlasmaApp::cleanup()
00226 {
00227 if (m_corona) {
00228 m_corona->saveLayout();
00229 }
00230
00231
00232
00233 KConfigGroup viewIds(KGlobal::config(), "ViewIds");
00234 viewIds.deleteGroup();
00235
00236 foreach (PanelView *v, m_panels) {
00237 if (v->containment()) {
00238 viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
00239 }
00240 }
00241
00242 int numScreens = QApplication::desktop()->numScreens();
00243 for (int i = 0; i < numScreens; ++i) {
00244 DesktopView *v = viewForScreen(i);
00245 if (v && v->containment()) {
00246 viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
00247 }
00248 }
00249
00250 QList<DesktopView*> desktops = m_desktops;
00251 m_desktops.clear();
00252 qDeleteAll(desktops);
00253
00254 QList<PanelView*> panels = m_panels;
00255 m_panels.clear();
00256 qDeleteAll(panels);
00257 delete m_corona;
00258
00259
00260
00261 KGlobal::config()->sync();
00262 }
00263
00264 void PlasmaApp::syncConfig()
00265 {
00266 KGlobal::config()->sync();
00267 }
00268
00269 void PlasmaApp::toggleDashboard()
00270 {
00271 int currentScreen = 0;
00272 if (QApplication::desktop()->numScreens() > 1) {
00273 currentScreen = QApplication::desktop()->screenNumber(QCursor::pos());
00274 }
00275
00276 DesktopView *view = viewForScreen(currentScreen);
00277 if (!view) {
00278 kWarning() << "we don't have a DesktopView for the current screen!";
00279 return;
00280 }
00281
00282 view->toggleDashboard();
00283 }
00284
00285 void PlasmaApp::setIsDesktop(bool isDesktop)
00286 {
00287 m_isDesktop = isDesktop;
00288 foreach (DesktopView *view, m_desktops) {
00289 view->setIsDesktop(isDesktop);
00290 }
00291
00292 if (isDesktop) {
00293 connect(QApplication::desktop(), SIGNAL(resized(int)), SLOT(adjustSize(int)));
00294 } else {
00295 disconnect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(adjustSize(int)));
00296 }
00297 }
00298
00299 bool PlasmaApp::isDesktop() const
00300 {
00301 return m_isDesktop;
00302 }
00303
00304 void PlasmaApp::adjustSize(int screen)
00305 {
00306 kDebug() << "adjust size for screen" << screen;
00307 QDesktopWidget *desktop = QApplication::desktop();
00308 bool screenExists = screen < desktop->numScreens();
00309
00310 QRect screenGeom;
00311 if (screenExists) {
00312 screenGeom = desktop->screenGeometry(screen);
00313 }
00314
00315 DesktopView *view = viewForScreen(screen);
00316
00317 if (view) {
00318 if (screenExists) {
00319 kDebug() << "here we go ... adjusting size";
00320 view->adjustSize();
00321 } else {
00322
00323
00324 kDebug() << "removing the view for screen" << screen;
00325 view->setContainment(0);
00326 m_desktops.removeAll(view);
00327 delete view;
00328 }
00329 } else if (screenExists) {
00330
00331
00332 }
00333
00334 foreach (PanelView *panel, m_panels) {
00335 if (panel->screen() == screen) {
00336 if (screenExists) {
00337 panel->pinchContainment(screenGeom);
00338 } else {
00339
00340
00341
00342
00343 }
00344 }
00345 }
00346 }
00347
00348 DesktopView* PlasmaApp::viewForScreen(int screen) const
00349 {
00350 foreach (DesktopView *view, m_desktops) {
00351
00352 if (view->screen() == screen) {
00353 return view;
00354 }
00355 }
00356
00357 return 0;
00358 }
00359
00360 void PlasmaApp::setCrashHandler()
00361 {
00362 KCrash::setEmergencySaveFunction(PlasmaApp::crashHandler);
00363 }
00364
00365 void PlasmaApp::crashHandler(int signal)
00366 {
00367 Q_UNUSED(signal);
00368
00369 fprintf(stderr, "Plasma crashed, attempting to automatically recover\n");
00370
00371 sleep(1);
00372 system("plasma --nocrashhandler &");
00373 }
00374
00375 Plasma::Corona* PlasmaApp::corona()
00376 {
00377 if (!m_corona) {
00378 DesktopCorona *c = new DesktopCorona(this);
00379 connect(c, SIGNAL(containmentAdded(Plasma::Containment*)),
00380 this, SLOT(createView(Plasma::Containment*)));
00381 connect(c, SIGNAL(configSynced()), this, SLOT(syncConfig()));
00382
00383 foreach (DesktopView *view, m_desktops) {
00384 connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00385 view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00386 }
00387
00388 c->setItemIndexMethod(QGraphicsScene::NoIndex);
00389 c->initializeLayout();
00390 c->checkScreens();
00391 m_corona = c;
00392 }
00393
00394 return m_corona;
00395 }
00396
00397 void PlasmaApp::showAppletBrowser(Plasma::Containment *containment)
00398 {
00399 if (!containment) {
00400 return;
00401 }
00402
00403 if (!m_appletBrowser) {
00404 m_appletBrowser = new Plasma::AppletBrowser();
00405 m_appletBrowser->setContainment(containment);
00406 m_appletBrowser->setApplication();
00407 m_appletBrowser->setAttribute(Qt::WA_DeleteOnClose);
00408 m_appletBrowser->setWindowTitle(i18n("Add Widgets"));
00409 m_appletBrowser->setWindowIcon(KIcon("plasmagik"));
00410 connect(m_appletBrowser, SIGNAL(destroyed()), this, SLOT(appletBrowserDestroyed()));
00411 } else {
00412 m_appletBrowser->setContainment(containment);
00413 }
00414
00415 KWindowSystem::setOnDesktop(m_appletBrowser->winId(), KWindowSystem::currentDesktop());
00416 m_appletBrowser->show();
00417 KWindowSystem::activateWindow(m_appletBrowser->winId());
00418 }
00419
00420 void PlasmaApp::appletBrowserDestroyed()
00421 {
00422 m_appletBrowser = 0;
00423 }
00424
00425 bool PlasmaApp::hasComposite()
00426 {
00427 return colormap && KWindowSystem::compositingActive();
00428 }
00429
00430 void PlasmaApp::notifyStartup(bool completed)
00431 {
00432 org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
00433
00434 const QString startupID("workspace desktop");
00435 if (completed) {
00436 ksmserver.resumeStartup(startupID);
00437 } else {
00438 ksmserver.suspendStartup(startupID);
00439 }
00440 }
00441
00442 void PlasmaApp::createView(Plasma::Containment *containment)
00443 {
00444 kDebug() << "Containment name:" << containment->name()
00445 << "| type" << containment->containmentType()
00446 << "| screen:" << containment->screen()
00447 << "| geometry:" << containment->geometry()
00448 << "| zValue:" << containment->zValue();
00449
00450
00451
00452 KConfigGroup viewIds(KGlobal::config(), "ViewIds");
00453 int id = viewIds.readEntry(QString::number(containment->id()), 0);
00454
00455 WId viewWindow = 0;
00456
00457 switch (containment->containmentType()) {
00458 case Plasma::Containment::PanelContainment: {
00459 PanelView *panelView = new PanelView(containment, id);
00460 viewWindow = panelView->winId();
00461 connect(panelView, SIGNAL(destroyed(QObject*)), this, SLOT(panelRemoved(QObject*)));
00462 m_panels << panelView;
00463 panelView->show();
00464 break;
00465 }
00466 default:
00467 if (containment->screen() > -1 &&
00468 containment->screen() < QApplication::desktop()->numScreens()) {
00469 if (viewForScreen(containment->screen())) {
00470
00471 return;
00472 }
00473
00474 kDebug() << "creating a view for" << containment->screen() << "and we have"
00475 << QApplication::desktop()->numScreens() << "screens";
00476
00477
00478 DesktopView *view = new DesktopView(containment, id, 0);
00479 viewWindow = view->winId();
00480 if (m_corona) {
00481 connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
00482 view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
00483 }
00484 view->setGeometry(QApplication::desktop()->screenGeometry(containment->screen()));
00485 m_desktops.append(view);
00486 view->setIsDesktop(m_isDesktop);
00487 view->show();
00488 }
00489 break;
00490 }
00491
00492
00493
00494
00495 if (viewWindow) {
00496 XClassHint classHint;
00497 classHint.res_name = const_cast<char*>("Plasma");
00498 classHint.res_class = const_cast<char*>("Plasma");
00499 XSetClassHint(QX11Info::display(), viewWindow, &classHint);
00500 }
00501 }
00502
00503 void PlasmaApp::panelRemoved(QObject* panel)
00504 {
00505 m_panels.removeAll((PanelView*)panel);
00506 }
00507
00508 #include "plasmaapp.moc"