kde-workspace/plasma/shells/plasma-desktop/plasmaapp.cpp
Ivailo Monev 5949b572bc khotkeys: drop it
the only use case is to launch ksnapshot which can be done by
plasma-desktop, some of the actions code is borked (notably window
matching, global and menu actions were working) and I have no
intention to fix it. even if fixed when a window (and thus possibly
application) key is grabbed there is a chance the window (application)
may want to grab the grabbed key and fail (i.e. grab conflict) so it
shall be left to the application to set what keys shall be global
(grabbed) hence the bits to start ksnapshot are moved to plasma-desktop

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2023-08-29 23:04:14 +03:00

979 lines
31 KiB
C++

/*
* Copyright 2006 Aaron Seigo <aseigo@kde.org>
* Copyright 2010 Chani Armitage <chani@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "plasmaapp.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QtDBus/QtDBus>
#include <QElapsedTimer>
#include <QTimer>
#include <QVBoxLayout>
#include <QTextStream>
#include <KAction>
#include <KCrash>
#include <KDebug>
#include <KCmdLineArgs>
#include <KGlobalAccel>
#include <KGlobalSettings>
#include <KNotification>
#include <KRun>
#include <KWindowSystem>
#include <KService>
#include <KIconLoader>
#include <KStandardDirs>
#include <KActionCollection>
#include <KToolInvocation>
#include <ksmserver_interface.h>
#include <Plasma/AbstractToolBox>
#include <Plasma/Containment>
#include <Plasma/Dialog>
#include <Plasma/Wallpaper>
#include <Plasma/WindowEffects>
#include <Plasma/Package>
#include <plasmagenericshell/backgrounddialog.h>
#include "appadaptor.h"
#include "controllerwindow.h"
#include "checkbox.h"
#include "desktopcorona.h"
#include "desktopview.h"
#include "interactiveconsole.h"
#include "panelshadows.h"
#include "panelview.h"
#include "toolbutton.h"
#include "klistconfirmationdialog.h"
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#endif
static void addInformationForApplet(QTextStream &stream, Plasma::Applet *applet)
{
if (applet->isContainment()) {
stream << "Containment - ";
} else {
stream << "Applet - ";
}
stream << applet->name() << ":\n";
stream << "Plugin Name: " << applet->pluginName() << '\n';
stream << "Category: " << applet->category() << '\n';
if (applet->package()) {
stream << "API: " << applet->package()->metadata().implementationApi() << '\n';
stream << "Type: " << applet->package()->metadata().type() << '\n';
stream << "Version: " << applet->package()->metadata().version() << '\n';
stream << "Author: " << applet->package()->metadata().author() << '\n';
}
// runtime info
stream << "Failed To Launch: " << applet->hasFailedToLaunch() << '\n';
const QRect rect = applet->screenRect();
stream << "ScreenRect: " << rect.x() << ',' << rect.y() << ' ' << rect.width() << 'x' << rect.height() << '\n';
stream << "FormFactor: " << applet->formFactor() << '\n';
stream << "Config Group Name: " << applet->config().name() << '\n';
stream << '\n'; // insert a blank line
}
PlasmaApp* PlasmaApp::self()
{
if (!kapp) {
return new PlasmaApp();
}
return qobject_cast<PlasmaApp*>(kapp);
}
PlasmaApp::PlasmaApp()
: KUniqueApplication(),
m_corona(0),
m_panelHidden(0),
m_mapper(new QSignalMapper(this)),
m_startupSuspendWaitCount(0),
m_unlockCorona(false)
{
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "plasma app ctor start" << "(line:" << __LINE__ << ")";
suspendStartup(true);
KGlobal::locale()->insertCatalog("libplasma");
KGlobal::locale()->insertCatalog("plasmagenericshell");
KCrash::setFlags(KCrash::AutoRestart | KCrash::Log);
m_panelViewCreationTimer.setSingleShot(true);
m_panelViewCreationTimer.setInterval(0);
m_desktopViewCreationTimer.setSingleShot(true);
m_desktopViewCreationTimer.setInterval(0);
new PlasmaAppAdaptor(this);
QDBusConnection::sessionBus().registerObject("/App", this);
KGlobal::setAllowQuit(true);
KGlobal::ref();
KActionCollection* actionCollection = new KActionCollection(this);
KAction* action = actionCollection->addAction("Capture the desktop");
action->setText(i18n("Capture the desktop"));
action->setGlobalShortcut(KShortcut(Qt::Key_Print));
connect(action, SIGNAL(triggered(bool)), SLOT(captureDesktop()));
action = actionCollection->addAction("Capture the current window");
action->setText(i18n("Capture the current window"));
action->setGlobalShortcut(KShortcut(Qt::CTRL+Qt::Key_Print));
connect(action, SIGNAL(triggered(bool)), SLOT(captureCurrentWindow()));
QTimer::singleShot(0, this, SLOT(setupDesktop()));
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "plasma app ctor end" << "(line:" << __LINE__ << ")";
}
PlasmaApp::~PlasmaApp()
{
if (m_corona) {
m_corona->saveLayout(KStandardDirs::locateLocal("config", "plasma-desktoprc"));
// save the mapping of Views to Containments at the moment
// of application exit so we can restore that when we start again.
KConfigGroup viewIds(KGlobal::config(), "ViewIds");
viewIds.deleteGroup();
foreach (PanelView *v, m_panels) {
if (v->containment()) {
viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
}
}
foreach (DesktopView *v, m_desktops) {
if (v->containment()) {
viewIds.writeEntry(QString::number(v->containment()->id()), v->id());
}
}
QList<DesktopView*> desktops = m_desktops;
m_desktops.clear();
qDeleteAll(desktops);
QList<PanelView*> panels = m_panels;
m_panels.clear();
qDeleteAll(panels);
delete m_console.data();
delete m_corona;
m_corona = 0;
delete m_panelShadows;
m_panelShadows = 0;
//TODO: This manual sync() should not be necessary. Remove it when
// KConfig was fixed
KGlobal::config()->sync();
}
KGlobal::deref();
}
void PlasmaApp::setupDesktop()
{
#ifdef Q_WS_X11
Atom atoms[5];
const char * const atomNames[] = {"XdndAware", "XdndEnter", "XdndFinished", "XdndPosition", "XdndStatus"};
XInternAtoms(QX11Info::display(), const_cast<char **>(atomNames), 5, False, atoms);
m_XdndAwareAtom = atoms[0];
m_XdndEnterAtom = atoms[1];
m_XdndFinishedAtom = atoms[2];
m_XdndPositionAtom = atoms[3];
m_XdndStatusAtom = atoms[4];
const int xdndversion = 5;
m_XdndVersionAtom = (Atom)xdndversion;
#endif
m_panelShadows = new PanelShadows();
// this line initializes the corona.
corona();
DesktopTracker *tracker = DesktopTracker::self();
connect(tracker, SIGNAL(screenRemoved(DesktopTracker::Screen)), SLOT(screenRemoved(DesktopTracker::Screen)));
connect(tracker, SIGNAL(screenAdded(DesktopTracker::Screen)), SLOT(screenAdded(DesktopTracker::Screen)));
// free the memory possibly occupied by the background image of the
// root window - login managers will typically set one
QPalette palette;
palette.setColor(desktop()->backgroundRole(), Qt::black);
desktop()->setPalette(palette);
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Plasma App SetupDesktop()" << "(line:" << __LINE__ << ")";
// now connect up the creation timers and start them to get the views created
connect(&m_panelViewCreationTimer, SIGNAL(timeout()), this, SLOT(createWaitingPanels()));
connect(&m_desktopViewCreationTimer, SIGNAL(timeout()), this, SLOT(createWaitingDesktops()));
m_panelViewCreationTimer.start();
m_desktopViewCreationTimer.start();
}
void PlasmaApp::syncConfig()
{
KGlobal::config()->sync();
}
void PlasmaApp::showInteractiveConsole()
{
if (KGlobal::config()->isImmutable()) {
return;
}
InteractiveConsole *console = m_console.data();
if (!console) {
m_console = console = new InteractiveConsole(m_corona);
}
KWindowSystem::setOnDesktop(console->winId(), KWindowSystem::currentDesktop());
console->show();
console->raise();
KWindowSystem::forceActiveWindow(console->winId());
}
void PlasmaApp::loadScriptInInteractiveConsole(const QString &script)
{
showInteractiveConsole();
if (m_console) {
m_console.data()->loadScript(script);
}
}
void PlasmaApp::panelHidden(bool hidden)
{
if (hidden) {
++m_panelHidden;
//kDebug() << "panel hidden" << m_panelHidden;
} else {
--m_panelHidden;
if (m_panelHidden < 0) {
kDebug() << "panelHidden(false) called too many times!";
m_panelHidden = 0;
}
//kDebug() << "panel unhidden" << m_panelHidden;
}
}
QList<PanelView*> PlasmaApp::panelViews() const
{
return m_panels;
}
PanelShadows *PlasmaApp::panelShadows() const
{
return m_panelShadows;
}
ControllerWindow *PlasmaApp::showWidgetExplorer(int screen, Plasma::Containment *containment)
{
return showController(screen, containment, true);
}
ControllerWindow *PlasmaApp::showController(int screen, Plasma::Containment *containment, bool widgetExplorerMode)
{
if (!containment) {
kDebug() << "no containment";
return 0;
}
QWeakPointer<ControllerWindow> controllerPtr = m_widgetExplorers.value(screen);
ControllerWindow *controller = controllerPtr.data();
if (!controller) {
//kDebug() << "controller not found for screen" << screen;
controllerPtr = controller = new ControllerWindow(0);
m_widgetExplorers.insert(screen, controllerPtr);
}
controller->setContainment(containment);
if (!containment || containment->screen() != screen) {
controller->setScreen(screen);
}
controller->setLocation(containment->location());
if (widgetExplorerMode) {
controller->showWidgetExplorer();
}
controller->show();
Plasma::WindowEffects::slideWindow(controller, controller->location());
QTimer::singleShot(0, controller, SLOT(activate()));
return controller;
}
void PlasmaApp::hideController(int screen)
{
QWeakPointer<ControllerWindow> controller = m_widgetExplorers.value(screen);
if (controller) {
controller.data()->hide();
}
}
#ifdef Q_WS_X11
PanelView *PlasmaApp::findPanelForTrigger(WId trigger) const
{
foreach (PanelView *panel, m_panels) {
if (panel->unhideTrigger() == trigger) {
return panel;
}
}
return 0;
}
bool PlasmaApp::x11EventFilter(XEvent *event)
{
if (m_panelHidden > 0 &&
(event->type == ClientMessage ||
(event->xany.send_event != True && (event->type == EnterNotify ||
event->type == MotionNotify)))) {
/*
if (event->type == ClientMessage) {
kDebug() << "client message with" << event->xclient.message_type << m_XdndEnterAtom << event->xcrossing.window;
}
*/
bool dndEnter = false;
bool dndPosition = false;
if (event->type == ClientMessage) {
dndEnter = event->xclient.message_type == m_XdndEnterAtom;
if (!dndEnter) {
dndPosition = event->xclient.message_type == m_XdndPositionAtom;
if (!dndPosition) {
//kDebug() << "FAIL!";
return KUniqueApplication::x11EventFilter(event);
}
} else {
//kDebug() << "on enter" << event->xclient.data.l[0];
}
}
PanelView *panel = findPanelForTrigger(event->xcrossing.window);
//kDebug() << "panel?" << panel << ((dndEnter || dndPosition) ? "Drag and drop op" : "Mouse move op");
if (panel) {
if (dndEnter || dndPosition) {
QPoint p;
const unsigned long *l = (const unsigned long *)event->xclient.data.l;
if (dndPosition) {
p = QPoint((l[2] & 0xffff0000) >> 16, l[2] & 0x0000ffff);
} else {
p = QCursor::pos();
}
XClientMessageEvent response;
response.type = ClientMessage;
response.window = l[0];
response.format = 32;
response.data.l[0] = panel->winId(); //event->xcrossing.window;
if (panel->hintOrUnhide(p, true)) {
response.message_type = m_XdndFinishedAtom;
response.data.l[1] = 0; // flags
response.data.l[2] = XNone;
} else {
response.message_type = m_XdndStatusAtom;
response.data.l[1] = 0; // flags
response.data.l[2] = 0; // x, y
response.data.l[3] = 0; // w, h
response.data.l[4] = 0; // action
}
XSendEvent(QX11Info::display(), l[0], False, NoEventMask, (XEvent*)&response);
} else if (event->type == EnterNotify) {
panel->hintOrUnhide(QPoint(-1, -1));
//kDebug() << "entry";
//FIXME: this if it was possible to avoid the polling
/*} else if (event->type == LeaveNotify) {
panel->unhintHide();
*/
} else if (event->type == MotionNotify) {
XMotionEvent *motion = (XMotionEvent*)event;
//kDebug() << "motion" << motion->x << motion->y << panel->location();
panel->hintOrUnhide(QPoint(motion->x_root, motion->y_root));
}
}
}
return KUniqueApplication::x11EventFilter(event);
}
#endif
void PlasmaApp::screenRemoved(const DesktopTracker::Screen &screen)
{
kDebug() << "@@@@" << screen.id;
QMutableListIterator<DesktopView *> it(m_desktops);
while (it.hasNext()) {
DesktopView *view = it.next();
if (view->screen() == screen.id) {
// the screen was removed, so we'll destroy the
// corresponding view
kDebug() << "@@@@removing the view for screen" << screen.id;
view->setContainment(0);
it.remove();
delete view;
}
}
#if 1
/**
UPDATE: this was linked to kephal events, which are not optimal, but it seems it may well
have been the panel->migrateTo call due to a bug in libplasma fixed in e2108ed. so let's try
and re-enable this.
NOTE: CURRENTLY UNSAFE DUE TO HOW KEPHAL (or rather, it seems, Qt?) PROCESSES EVENTS
DURING XRANDR EVENTS. REVISIT IN 4.8!
*/
const DesktopTracker::Screen primary = DesktopTracker::self()->primaryScreen();
QList<DesktopTracker::Screen> screens = DesktopTracker::self()->screens();
screens.removeAll(primary);
// Now we process panels: if there is room on another screen for the panel,
// we migrate the panel there, otherwise the view is deleted. The primary
// screen is preferred in all cases.
QMutableListIterator<PanelView*> pIt(m_panels);
while (pIt.hasNext()) {
PanelView *panel = pIt.next();
if (panel->screen() == screen.id) {
DesktopTracker::Screen moveTo;
if (canRelocatePanel(panel, primary)) {
moveTo = primary;
} else {
foreach (const DesktopTracker::Screen &screen, screens) {
if (canRelocatePanel(panel, screen)) {
moveTo = screen;
break;
}
}
}
if (moveTo.id >= 0) {
panel->migrateTo(moveTo.id);
} else {
pIt.remove();
delete panel;
continue;
}
}
panel->updateStruts();
}
#else
QMutableListIterator<PanelView*> pIt(m_panels);
while (pIt.hasNext()) {
PanelView *panel = pIt.next();
if (panel->screen() == screen.id) {
pIt.remove();
delete panel;
}
}
#endif
}
void PlasmaApp::screenAdded(const DesktopTracker::Screen &screen)
{
foreach (Plasma::Containment *containment, corona()->containments()) {
if (isPanelContainment(containment) && containment->screen() == screen.id) {
m_panelsWaiting << containment;
m_panelViewCreationTimer.start();
}
}
foreach (PanelView *view, m_panels) {
if (view->migratedFrom(screen.id)) {
view->migrateTo(screen.id);
}
}
}
bool PlasmaApp::canRelocatePanel(PanelView * view, const DesktopTracker::Screen &screen)
{
if (!view->containment()) {
return false;
}
QRect newGeom = view->geometry();
switch (view->location()) {
case Plasma::TopEdge:
newGeom.setY(screen.geom.y());
newGeom.setX(view->offset());
break;
case Plasma::BottomEdge:
newGeom.setY(screen.geom.bottom() - newGeom.height());
newGeom.setX(view->offset());
break;
case Plasma::LeftEdge:
newGeom.setX(screen.geom.left());
newGeom.setY(view->offset());
break;
case Plasma::RightEdge:
newGeom.setX(screen.geom.right() - newGeom.width());
newGeom.setY(view->offset());
break;
default:
break;
}
kDebug() << "testing:" << screen.id << view << view->geometry() << view->location() << newGeom;
foreach (PanelView *pv, m_panels) {
kDebug() << pv << pv->screen() << pv->screen() << pv->location() << pv->geometry();
if (pv != view &&
pv->screen() == screen.id &&
pv->location() == view->location() &&
pv->geometry().intersects(newGeom)) {
return false;
}
}
return true;
}
DesktopView* PlasmaApp::viewForScreen(int screen, int desktop) const
{
foreach (DesktopView *view, m_desktops) {
if (view->containment()) {
kDebug() << "comparing" << view->containment()->screen() << screen;
}
if (view->containment() && view->containment()->screen() == screen && (desktop < 0 || view->containment()->desktop() == desktop)) {
return view;
}
}
return 0;
}
DesktopCorona* PlasmaApp::corona(bool createIfMissing)
{
if (!m_corona && createIfMissing) {
QElapsedTimer t;
t.start();
DesktopCorona *c = new DesktopCorona(this);
connect(c, SIGNAL(containmentAdded(Plasma::Containment*)),
this, SLOT(containmentAdded(Plasma::Containment*)));
connect(c, SIGNAL(configSynced()), this, SLOT(syncConfig()));
connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
this, SLOT(containmentScreenOwnerChanged(int,int,Plasma::Containment*)));
foreach (DesktopView *view, m_desktops) {
connect(c, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
}
//actions!
c->updateShortcuts();
m_corona = c;
c->setItemIndexMethod(QGraphicsScene::NoIndex);
c->initializeLayout();
foreach (Plasma::Containment *containment, c->containments()) {
if (containment->screen() != -1 && containment->wallpaper()) {
++m_startupSuspendWaitCount;
connect(containment->wallpaper(), SIGNAL(update(QRectF)), this, SLOT(wallpaperCheckedIn()));
}
}
QTimer::singleShot(5000, this, SLOT(wallpaperCheckInTimeout()));
kDebug() << " ------------------------------------------>" << t.elapsed() << m_startupSuspendWaitCount;
}
return m_corona;
}
void PlasmaApp::wallpaperCheckInTimeout()
{
if (m_startupSuspendWaitCount > 0) {
m_startupSuspendWaitCount = 0;
suspendStartup(false);
}
}
void PlasmaApp::wallpaperCheckedIn()
{
if (m_startupSuspendWaitCount < 1) {
return;
}
--m_startupSuspendWaitCount;
if (m_startupSuspendWaitCount < 1) {
m_startupSuspendWaitCount = 0;
suspendStartup(false);
}
}
void PlasmaApp::suspendStartup(bool suspend)
{
org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
const QString startupID("workspace desktop");
if (suspend) {
ksmserver.suspendStartup(startupID);
} else {
ksmserver.resumeStartup(startupID);
}
}
bool PlasmaApp::isPanelContainment(Plasma::Containment *containment)
{
if (!containment) {
return false;
}
Plasma::Containment::Type t = containment->containmentType();
return t == Plasma::Containment::PanelContainment ||
t == Plasma::Containment::CustomPanelContainment;
}
void PlasmaApp::createView(Plasma::Containment *containment)
{
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Plasma App createView() start" << "(line:" << __LINE__ << ")";
kDebug() << "Containment name:" << containment->name()
<< "| type" << containment->containmentType()
<< "| screen:" << containment->screen()
<< "| desktop:" << containment->desktop()
<< "| geometry:" << containment->geometry()
<< "| zValue:" << containment->zValue();
// find the mapping of View to Containment, if any,
// so we can restore things on start.
if (isPanelContainment(containment)) {
m_panelsWaiting << containment;
m_panelViewCreationTimer.start();
} else if (containment->screen() > -1 && containment->screen() < m_corona->numScreens()) {
m_desktopsWaiting.append(containment);
m_desktopViewCreationTimer.start();
}
}
void PlasmaApp::setWmClass(WId id)
{
#ifdef Q_WS_X11
XClassHint classHint;
classHint.res_name = const_cast<char*>("Plasma");
classHint.res_class = const_cast<char*>("Plasma");
XSetClassHint(QX11Info::display(), id, &classHint);
#endif
}
void PlasmaApp::createWaitingPanels()
{
if (m_panelsWaiting.isEmpty()) {
return;
}
const QList<QWeakPointer<Plasma::Containment> > containments = m_panelsWaiting;
m_panelsWaiting.clear();
foreach (QWeakPointer<Plasma::Containment> containmentPtr, containments) {
Plasma::Containment *containment = containmentPtr.data();
if (!containment) {
continue;
}
foreach (PanelView *view, m_panels) {
if (view->containment() == containment) {
continue;
}
}
if (containment->screen() < 0) {
continue;
}
// try to relocate the panel if it is on a now-non-existent screen
if (containment->screen() >= m_corona->numScreens()) {
m_panelRelocationCandidates << containment;
continue;
}
createPanelView(containment);
}
if (!m_panelRelocationCandidates.isEmpty()) {
QTimer::singleShot(0, this, SLOT(relocatePanels()));
}
}
void PlasmaApp::relocatePanels()
{
// we go through relocatables last so that all other panels can be set up first,
// preventing panel creation ordering to trip up the canRelocatePanel algorithm
const DesktopTracker::Screen primary = DesktopTracker::self()->primaryScreen();
QList<DesktopTracker::Screen> screens = DesktopTracker::self()->screens();
screens.removeAll(primary);
foreach (QWeakPointer<Plasma::Containment> c, m_panelRelocationCandidates) {
Plasma::Containment *containment = c.data();
if (!containment) {
continue;
}
DesktopTracker::Screen moveTo;
PanelView *panelView = createPanelView(containment);
if (canRelocatePanel(panelView, primary)) {
moveTo = primary;
} else {
foreach (const DesktopTracker::Screen &screen, screens) {
if (canRelocatePanel(panelView, screen)) {
moveTo = screen;
break;
}
}
}
if (moveTo.id >= 0) {
panelView->migrateTo(moveTo.id);
} else {
m_panels.removeAll(panelView);
delete panelView;
}
}
m_panelRelocationCandidates.clear();
}
PanelView *PlasmaApp::createPanelView(Plasma::Containment *containment)
{
KConfigGroup viewIds(KGlobal::config(), "ViewIds");
const int id = viewIds.readEntry(QString::number(containment->id()), 0);
PanelView *panelView = new PanelView(containment, id);
connect(panelView, SIGNAL(destroyed(QObject*)), this, SLOT(panelRemoved(QObject*)));
m_panels << panelView;
panelView->show();
setWmClass(panelView->winId());
return panelView;
}
void PlasmaApp::createWaitingDesktops()
{
const QList<QWeakPointer<Plasma::Containment> > containments = m_desktopsWaiting;
m_desktopsWaiting.clear();
foreach (QWeakPointer<Plasma::Containment> weakContainment, containments) {
if (weakContainment) {
Plasma::Containment *containment = weakContainment.data();
KConfigGroup viewIds(KGlobal::config(), "ViewIds");
const int id = viewIds.readEntry(QString::number(containment->id()), 0);
const int screen = containment->screen();
if (screen >= m_corona->numScreens() || screen < 0) {
kDebug() << "not creating a view on screen" << screen << "as it does not exist";
continue;
}
DesktopView *view = viewForScreen(screen, -1);
if (view) {
kDebug() << "already had a view for" << containment->screen() << containment->desktop();
// we already have a view for this screen
continue;
}
kDebug() << "creating a new view for" << containment->screen() << containment->desktop()
<< "and we have" << m_corona->numScreens() << "screens";
// we have a new screen. neat.
view = new DesktopView(containment, id, 0);
if (m_corona) {
connect(m_corona, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)),
view, SLOT(screenOwnerChanged(int,int,Plasma::Containment*)));
}
m_desktops.append(view);
view->show();
setWmClass(view->winId());
}
}
}
void PlasmaApp::containmentAdded(Plasma::Containment *containment)
{
if (isPanelContainment(containment)) {
foreach (PanelView * panel, m_panels) {
if (panel->containment() == containment) {
kDebug() << "not creating second PanelView with existing Containment!!";
return;
}
}
}
createView(containment);
}
void PlasmaApp::prepareContainment(Plasma::Containment *containment)
{
if (!containment) {
return;
}
disconnect(containment, 0, this, 0);
connect(containment, SIGNAL(configureRequested(Plasma::Containment*)),
this, SLOT(configureContainment(Plasma::Containment*)));
if (isPanelContainment(containment)) {
return;
}
if ((containment->containmentType() == Plasma::Containment::DesktopContainment ||
containment->containmentType() == Plasma::Containment::CustomContainment)) {
QAction *a = containment->action("remove");
delete a; //activities handle removal now
if (containment->containmentType() == Plasma::Containment::DesktopContainment) {
foreach (QAction *action, m_corona->actions()) {
containment->addToolBoxAction(action);
}
}
}
}
void PlasmaApp::containmentScreenOwnerChanged(int wasScreen, int isScreen, Plasma::Containment *containment)
{
Q_UNUSED(wasScreen)
kDebug() << "@@@was" << wasScreen << "is" << isScreen << (QObject*)containment << m_desktops.count();
if (isScreen < 0) {
kDebug() << "@@@screen<0";
return;
}
if (isPanelContainment(containment)) {
kDebug() << "@@@isPanel";
return;
}
foreach (DesktopView *view, m_desktops) {
if (view->screen() == isScreen) {
kDebug() << "@@@@found view" << view;
return;
}
}
kDebug() << "@@@@appending";
m_desktopsWaiting.append(containment);
m_desktopViewCreationTimer.start();
}
void PlasmaApp::configureContainment(Plasma::Containment *containment)
{
const QString id = QString::number(containment->id()) + "settings" + containment->name();
BackgroundDialog *configDialog = qobject_cast<BackgroundDialog*>(KConfigDialog::exists(id));
if (configDialog) {
configDialog->reloadConfig();
} else {
const QSize resolution = QApplication::desktop()->screenGeometry(containment->screen()).size();
Plasma::View *view = viewForScreen(containment->screen(), containment->desktop());
if (!view) {
view = viewForScreen(desktop()->screenNumber(QCursor::pos()), containment->desktop());
if (!view) {
if (m_desktops.count() < 1) {
return;
}
view = m_desktops.at(0);
}
}
KConfigSkeleton *nullManager = new KConfigSkeleton();
configDialog = new BackgroundDialog(resolution, containment, view, 0, id, nullManager);
configDialog->setAttribute(Qt::WA_DeleteOnClose);
connect(configDialog, SIGNAL(destroyed(QObject*)), nullManager, SLOT(deleteLater()));
}
configDialog->show();
KWindowSystem::setOnDesktop(configDialog->winId(), KWindowSystem::currentDesktop());
KWindowSystem::activateWindow(configDialog->winId());
}
void PlasmaApp::panelRemoved(QObject *panel)
{
m_panels.removeAll((PanelView *)panel);
}
QString PlasmaApp::supportInformation() const
{
QString streambuffer;
QTextStream stream(&streambuffer);
stream << "Plasma-desktop Support Information:\n"
<< "The following information should be used when requesting support.\n"
<< "It provides information about the currently running instance and which applets are used.\n"
<< "Please include the information provided underneath this introductory text along with "
<< "whatever you think may be relevant to the issue.\n\n";
stream << "Version\n";
stream << "=======\n";
stream << "KDE SC version (runtime):\n";
stream << KDE::versionString() << '\n';
stream << "KDE SC version (compile):\n";
stream << KDE_VERSION_STRING << '\n';
stream << "Katie Version:\n";
stream << qVersion() << '\n';
stream << '\n' << "=========" << '\n';
foreach (Plasma::Containment *containment, m_corona->containments()) {
// a containment is also an applet so print standard applet information out
addInformationForApplet(stream, containment);
foreach (Plasma::Applet *applet, containment->applets()) {
addInformationForApplet(stream, applet);
}
}
return streambuffer;
}
void PlasmaApp::executeCommands(const QList < QVariant > & commands)
{
foreach (const QVariant & command, commands) {
KRun::runCommand(command.toString(), 0);
}
}
void PlasmaApp::captureDesktop()
{
KToolInvocation::kdeinitExec("ksnapshot", QStringList() << "--fullscreen");
}
void PlasmaApp::captureCurrentWindow()
{
KToolInvocation::kdeinitExec("ksnapshot", QStringList() << "--current");
}
#include "moc_plasmaapp.cpp"