diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6963f9dc9a..3cf349d18b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -506,26 +506,42 @@ if(Wayland_Client_FOUND AND XKB_FOUND)
endif()
endif()
-kf5_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS})
+add_library(kwin SHARED ${kwin_KDEINIT_SRCS})
-target_link_libraries(kdeinit_kwin ${kwinLibs})
-set_target_properties(kwin PROPERTIES OUTPUT_NAME ${KWIN_INTERNAL_NAME_X11})
-generate_export_header(kdeinit_kwin EXPORT_FILE_NAME kwin_export.h)
+set_target_properties(kwin PROPERTIES
+ VERSION GENERIC_LIB_VERSION
+ SOVERSION GENERIC_LIB_SOVERSION
+ )
+
+target_link_libraries(kwin ${kwinLibs})
+generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h)
if(KWIN_BUILD_OPENGL)
- target_link_libraries(kdeinit_kwin kwinglutils ${epoxy_LIBRARY})
+ target_link_libraries(kwin kwinglutils ${epoxy_LIBRARY})
# -ldl used by OpenGL code
find_library(DL_LIBRARY dl)
if (DL_LIBRARY)
- target_link_libraries(kdeinit_kwin ${DL_LIBRARY})
+ target_link_libraries(kwin ${DL_LIBRARY})
endif()
elseif(KWIN_BUILD_OPENGLES)
- target_link_libraries(kdeinit_kwin ${kwinLibs} kwinglesutils ${epoxy_LIBRARY})
- set_target_properties(kdeinit_kwin PROPERTIES COMPILE_FLAGS "-DKWIN_HAVE_OPENGLES")
+ target_link_libraries(kwin ${kwinLibs} kwinglesutils ${epoxy_LIBRARY})
+ set_target_properties(kwin PROPERTIES COMPILE_FLAGS "-DKWIN_HAVE_OPENGLES")
endif()
-install(TARGETS kdeinit_kwin ${INSTALL_TARGETS_DEFAULT_ARGS} )
-install(TARGETS kwin ${INSTALL_TARGETS_DEFAULT_ARGS} )
+kf5_add_kdeinit_executable(kwin_x11 main_x11.cpp)
+target_link_libraries(kdeinit_kwin_x11 kwin)
+
+install(TARGETS kwin ${INSTALL_TARGETS_DEFAULT_ARGS} )
+install(TARGETS kdeinit_kwin_x11 ${INSTALL_TARGETS_DEFAULT_ARGS} )
+install(TARGETS kwin_x11 ${INSTALL_TARGETS_DEFAULT_ARGS} )
+
+if(Wayland_Client_FOUND AND XKB_FOUND)
+ kf5_add_kdeinit_executable(kwin_wayland main_wayland.cpp)
+ target_link_libraries(kdeinit_kwin_wayland kwin)
+
+ install(TARGETS kdeinit_kwin_wayland ${INSTALL_TARGETS_DEFAULT_ARGS} )
+ install(TARGETS kwin_wayland ${INSTALL_TARGETS_DEFAULT_ARGS} )
+endif()
########### install files ###############
diff --git a/libkwineffects/kwinglobals.h b/libkwineffects/kwinglobals.h
index 041b488c7b..8c9b5cb52f 100644
--- a/libkwineffects/kwinglobals.h
+++ b/libkwineffects/kwinglobals.h
@@ -30,7 +30,6 @@ along with this program. If not, see .
#include
#define KWIN_QT5_PORTING 0
-#define KWIN_EXPORT KDEINIT_KWIN_EXPORT
namespace KWin
{
diff --git a/main.cpp b/main.cpp
index 76fc78eaf8..9aeddd96a8 100644
--- a/main.cpp
+++ b/main.cpp
@@ -26,7 +26,6 @@ along with this program. If not, see .
#include "options.h"
#include "sm.h"
#include "workspace.h"
-#include "xcbutils.h"
// KDE
#include
@@ -48,9 +47,6 @@ along with this program. If not, see .
#include
#include
#include
-#include
-// TODO: remove once QX11Info provides the X screen
-#include
// system
#ifdef HAVE_UNISTD_H
@@ -71,68 +67,6 @@ Atoms* atoms;
int screen_number = -1;
bool is_multihead = false;
-//************************************
-// KWinSelectionOwner
-//************************************
-
-KWinSelectionOwner::KWinSelectionOwner(int screen_P)
- : KSelectionOwner(make_selection_atom(screen_P), screen_P)
-{
-}
-
-xcb_atom_t KWinSelectionOwner::make_selection_atom(int screen_P)
-{
- if (screen_P < 0)
- screen_P = QX11Info::appScreen();
- QByteArray screen(QByteArrayLiteral("WM_S"));
- screen.append(QByteArray::number(screen_P));
- ScopedCPointer atom(xcb_intern_atom_reply(
- connection(),
- xcb_intern_atom_unchecked(connection(), false, screen.length(), screen.constData()),
- nullptr));
- if (atom.isNull()) {
- return XCB_ATOM_NONE;
- }
- return atom->atom;
-}
-
-void KWinSelectionOwner::getAtoms()
-{
- KSelectionOwner::getAtoms();
- if (xa_version == XCB_ATOM_NONE) {
- const QByteArray name(QByteArrayLiteral("VERSION"));
- ScopedCPointer atom(xcb_intern_atom_reply(
- connection(),
- xcb_intern_atom_unchecked(connection(), false, name.length(), name.constData()),
- nullptr));
- if (!atom.isNull()) {
- xa_version = atom->atom;
- }
- }
-}
-
-void KWinSelectionOwner::replyTargets(xcb_atom_t property_P, xcb_window_t requestor_P)
-{
- KSelectionOwner::replyTargets(property_P, requestor_P);
- xcb_atom_t atoms[ 1 ] = { xa_version };
- // PropModeAppend !
- xcb_change_property(connection(), XCB_PROP_MODE_APPEND, requestor_P,
- property_P, XCB_ATOM_ATOM, 32, 1, atoms);
-}
-
-bool KWinSelectionOwner::genericReply(xcb_atom_t target_P, xcb_atom_t property_P, xcb_window_t requestor_P)
-{
- if (target_P == xa_version) {
- int32_t version[] = { 2, 0 };
- xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, requestor_P,
- property_P, XCB_ATOM_INTEGER, 32, 2, version);
- } else
- return KSelectionOwner::genericReply(target_P, property_P, requestor_P);
- return true;
-}
-
-xcb_atom_t KWinSelectionOwner::xa_version = XCB_ATOM_NONE;
-
class AlternativeWMDialog : public QDialog
{
public:
@@ -181,13 +115,31 @@ private:
int Application::crashes = 0;
-Application::Application(int &argc, char **argv)
+bool Application::isX11MultiHead()
+{
+ return is_multihead;
+}
+
+void Application::setX11MultiHead(bool multiHead)
+{
+ is_multihead = multiHead;
+}
+
+void Application::setX11ScreenNumber(int screenNumber)
+{
+ screen_number = screenNumber;
+}
+
+int Application::x11ScreenNumber()
+{
+ return screen_number;
+}
+
+Application::Application(Application::OperationMode mode, int &argc, char **argv)
: QApplication(argc, argv)
- , owner()
, m_eventFilter(new XcbEventFilter())
- , m_replace(false)
, m_configLock(false)
- , m_operationMode(OperationModeX11)
+ , m_operationMode(mode)
{
}
@@ -196,11 +148,6 @@ void Application::setConfigLock(bool lock)
m_configLock = lock;
}
-void Application::setReplace(bool replace)
-{
- m_replace = replace;
-}
-
Application::OperationMode Application::operationMode() const
{
return m_operationMode;
@@ -232,67 +179,13 @@ void Application::start()
config->reparseConfiguration();
}
- if (screen_number == -1)
- screen_number = QX11Info::appScreen();
-
- owner.reset(new KWinSelectionOwner(screen_number));
- connect(owner.data(), &KSelectionOwner::failedToClaimOwnership, []{
- fputs(i18n("kwin: unable to claim manager selection, another wm running? (try using --replace)\n").toLocal8Bit().constData(), stderr);
- ::exit(1);
- });
- connect(owner.data(), SIGNAL(lostOwnership()), SLOT(lostSelection()));
- connect(owner.data(), &KSelectionOwner::claimedOwnership, [this]{
- // we want all QQuickWindows with an alpha buffer
- QQuickWindow::setDefaultAlphaBuffer(true);
-
- installNativeEventFilter(m_eventFilter.data());
- // first load options - done internally by a different thread
- options = new Options;
-
- // Check whether another windowmanager is running
- const uint32_t maskValues[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT};
- ScopedCPointer redirectCheck(xcb_request_check(connection(),
- xcb_change_window_attributes_checked(connection(),
- rootWindow(),
- XCB_CW_EVENT_MASK,
- maskValues)));
- if (!redirectCheck.isNull()) {
- fputs(i18n("kwin: another window manager is running (try using --replace)\n").toLocal8Bit().constData(), stderr);
- ::exit(1);
- }
-
- atoms->retrieveHelpers();
-
- // This tries to detect compositing options and can use GLX. GLX problems
- // (X errors) shouldn't cause kwin to abort, so this is out of the
- // critical startup section where x errors cause kwin to abort.
-
- // create workspace.
- (void) new Workspace(isSessionRestored());
-
- Xcb::sync(); // Trigger possible errors, there's still a chance to abort
-
- // Tell KSplash that KWin has started
- QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
- QStringLiteral("/KSplash"),
- QStringLiteral("org.kde.KSplash"),
- QStringLiteral("setStage"));
- ksplashProgressMessage.setArguments(QList() << QStringLiteral("wm"));
- QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
- });
crashChecking();
- // we need to do an XSync here, otherwise the QPA might crash us later on
- Xcb::sync();
- owner->claim(m_replace, true);
- atoms = new Atoms;
+ performStartup();
}
Application::~Application()
{
- delete Workspace::self();
- if (!owner.isNull() && owner->ownerWindow() != XCB_WINDOW_NONE) // If there was no --replace (no new WM)
- Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
delete options;
delete atoms;
}
@@ -328,15 +221,6 @@ void Application::crashChecking()
QTimer::singleShot(15 * 1000, this, SLOT(resetCrashesCount()));
}
-void Application::lostSelection()
-{
- sendPostedEvents();
- delete Workspace::self();
- // Remove windowmanager privileges
- Xcb::selectInput(rootWindow(), XCB_EVENT_MASK_PROPERTY_CHANGE);
- quit();
-}
-
bool Application::notify(QObject* o, QEvent* e)
{
if (Workspace::self()->workspaceEvent(e))
@@ -344,11 +228,6 @@ bool Application::notify(QObject* o, QEvent* e)
return QApplication::notify(o, e);
}
-static void sighandler(int)
-{
- QApplication::exit();
-}
-
void Application::crashHandler(int signal)
{
crashes++;
@@ -377,26 +256,68 @@ bool Application::wasCrash()
return crashes > 0;
}
-bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long int *result)
-{
- Q_UNUSED(result)
- if (!Workspace::self()) {
- // Workspace not yet created
- return false;
- }
- if (eventType != "xcb_generic_event_t") {
- return false;
- }
- return Workspace::self()->workspaceEvent(static_cast(message));
-}
-
-} // namespace
-
-static const char version[] = KWIN_VERSION_STRING;
static const char description[] = I18N_NOOP("KDE window manager");
-extern "C"
-KWIN_EXPORT int kdemain(int argc, char * argv[])
+void Application::createAboutData()
+{
+ KAboutData aboutData(QStringLiteral(KWIN_NAME), // The program name used internally
+ i18n("KWin"), // A displayable program name string
+ QStringLiteral(KWIN_VERSION_STRING), // The program version string
+ i18n(description), // Short description of what the app does
+ KAboutLicense::GPL, // The license this code is released under
+ i18n("(c) 1999-2013, The KDE Developers")); // Copyright Statement
+
+ aboutData.addAuthor(i18n("Matthias Ettrich"), QString(), QStringLiteral("ettrich@kde.org"));
+ aboutData.addAuthor(i18n("Cristian Tibirna"), QString(), QStringLiteral("tibirna@kde.org"));
+ aboutData.addAuthor(i18n("Daniel M. Duley"), QString(), QStringLiteral("mosfet@kde.org"));
+ aboutData.addAuthor(i18n("Luboš Luňák"), QString(), QStringLiteral("l.lunak@kde.org"));
+ aboutData.addAuthor(i18n("Martin Gräßlin"), i18n("Maintainer"), QStringLiteral("mgraesslin@kde.org"));
+ KAboutData::setApplicationData(aboutData);
+}
+
+static const QString s_lockOption = QStringLiteral("lock");
+static const QString s_crashesOption = QStringLiteral("crashes");
+
+void Application::setupCommandLine(QCommandLineParser *parser)
+{
+ QCommandLineOption lockOption(s_lockOption, i18n("Disable configuration options"));
+ QCommandLineOption crashesOption(s_crashesOption, i18n("Indicate that KWin has recently crashed n times"), QStringLiteral("n"));
+
+ parser->setApplicationDescription(i18n("KDE window manager"));
+ parser->addVersionOption();
+ parser->addHelpOption();
+ parser->addOption(lockOption);
+ parser->addOption(crashesOption);
+ KAboutData::applicationData().setupCommandLine(parser);
+}
+
+void Application::processCommandLine(QCommandLineParser *parser)
+{
+ setConfigLock(parser->isSet(s_lockOption));
+ Application::setCrashCount(parser->value(s_crashesOption).toInt());
+}
+
+void Application::registerDBusService()
+{
+ QString appname;
+ if (x11ScreenNumber() == 0)
+ appname = QStringLiteral("org.kde.kwin");
+ else
+ appname.sprintf("org.kde.kwin-screen-%d", KWin::Application::x11ScreenNumber());
+
+ QDBusConnection::sessionBus().interface()->registerService(
+ appname, QDBusConnectionInterface::DontQueueService);
+}
+
+void Application::setupTranslator()
+{
+ QTranslator qtTranslator;
+ qtTranslator.load("qt_" + QLocale::system().name(),
+ QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+ installTranslator(&qtTranslator);
+}
+
+void Application::setupMalloc()
{
#ifdef M_TRIM_THRESHOLD
// Prevent fragmentation of the heap by malloc (glibc).
@@ -412,146 +333,79 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
#endif // HAVE_UNISTD_H
mallopt(M_TRIM_THRESHOLD, 5*pagesize);
#endif // M_TRIM_THRESHOLD
-
- KLocalizedString::setApplicationDomain("kwin");
- QLoggingCategory::setFilterRules(QStringLiteral("aurorae.debug = true\n") +
- QStringLiteral("kwineffects.debug = true"));
-
- int primaryScreen = 0;
- xcb_connection_t *c = xcb_connect(nullptr, &primaryScreen);
- if (!c || xcb_connection_has_error(c)) {
- fprintf(stderr, "%s: FATAL ERROR while trying to open display %s\n",
- argv[0], qgetenv("DISPLAY").constData());
- exit(1);
- }
-
- const int number_of_screens = xcb_setup_roots_length(xcb_get_setup(c));
-
- // multi head
- auto isMultiHead = []() -> bool {
- QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
- if (!multiHead.isEmpty()) {
- return (multiHead.toLower() == "true");
- }
- return true;
- };
- if (number_of_screens != 1 && isMultiHead()) {
- KWin::is_multihead = true;
- KWin::screen_number = primaryScreen;
- int pos; // Temporarily needed to reconstruct DISPLAY var if multi-head
- QByteArray display_name = qgetenv("DISPLAY");
- xcb_disconnect(c);
- c = nullptr;
-
- if ((pos = display_name.lastIndexOf('.')) != -1)
- display_name.remove(pos, 10); // 10 is enough to be sure we removed ".s"
-
- QString envir;
- for (int i = 0; i < number_of_screens; i++) {
- // If execution doesn't pass by here, then kwin
- // acts exactly as previously
- if (i != KWin::screen_number && fork() == 0) {
- KWin::screen_number = i;
- // Break here because we are the child process, we don't
- // want to fork() anymore
- break;
- }
- }
- // In the next statement, display_name shouldn't contain a screen
- // number. If it had it, it was removed at the "pos" check
- envir.sprintf("DISPLAY=%s.%d", display_name.data(), KWin::screen_number);
-
- if (putenv(strdup(envir.toAscii().constData()))) {
- fprintf(stderr, "%s: WARNING: unable to set DISPLAY environment variable\n", argv[0]);
- perror("putenv()");
- }
- }
-
- if (signal(SIGTERM, KWin::sighandler) == SIG_IGN)
- signal(SIGTERM, SIG_IGN);
- if (signal(SIGINT, KWin::sighandler) == SIG_IGN)
- signal(SIGINT, SIG_IGN);
- if (signal(SIGHUP, KWin::sighandler) == SIG_IGN)
- signal(SIGHUP, SIG_IGN);
-
- // Disable the glib event loop integration, since it seems to be responsible
- // for several bug reports about high CPU usage (bug #239963)
- setenv("QT_NO_GLIB", "1", true);
-
- // enforce xcb plugin, unfortunately command line switch has precedence
- setenv("QT_QPA_PLATFORM", "xcb", true);
-
- KWin::Application a(argc, argv);
-
- QTranslator qtTranslator;
- qtTranslator.load("qt_" + QLocale::system().name(),
- QLibraryInfo::location(QLibraryInfo::TranslationsPath));
- a.installTranslator(&qtTranslator);
-
- KAboutData aboutData(QStringLiteral(KWIN_NAME), // The program name used internally
- i18n("KWin"), // A displayable program name string
- QStringLiteral(KWIN_VERSION_STRING), // The program version string
- i18n(description), // Short description of what the app does
- KAboutLicense::GPL, // The license this code is released under
- i18n("(c) 1999-2013, The KDE Developers")); // Copyright Statement
-
- aboutData.addAuthor(i18n("Matthias Ettrich"), QString(), QStringLiteral("ettrich@kde.org"));
- aboutData.addAuthor(i18n("Cristian Tibirna"), QString(), QStringLiteral("tibirna@kde.org"));
- aboutData.addAuthor(i18n("Daniel M. Duley"), QString(), QStringLiteral("mosfet@kde.org"));
- aboutData.addAuthor(i18n("Luboš Luňák"), QString(), QStringLiteral("l.lunak@kde.org"));
- aboutData.addAuthor(i18n("Martin Gräßlin"), i18n("Maintainer"), QStringLiteral("mgraesslin@kde.org"));
- KAboutData::setApplicationData(aboutData);
-
- QCommandLineOption lockOption(QStringLiteral("lock"), i18n("Disable configuration options"));
- QCommandLineOption replaceOption(QStringLiteral("replace"), i18n("Replace already-running ICCCM2.0-compliant window manager"));
- QCommandLineOption crashesOption(QStringLiteral("crashes"), i18n("Indicate that KWin has recently crashed n times"), QStringLiteral("n"));
-
- QCommandLineParser parser;
- parser.setApplicationDescription(i18n("KDE window manager"));
- parser.addVersionOption();
- parser.addHelpOption();
- parser.addOption(lockOption);
- parser.addOption(replaceOption);
- parser.addOption(crashesOption);
- aboutData.setupCommandLine(&parser);
-
- parser.process(a);
- aboutData.processCommandLine(&parser);
-
- KWin::Application::setCrashCount(parser.value(crashesOption).toInt());
- a.setConfigLock(parser.isSet(lockOption));
- a.setReplace(parser.isSet(replaceOption));
-
- // perform sanity checks
- if (a.platformName().toLower() != QStringLiteral("xcb")) {
- fprintf(stderr, "%s: FATAL ERROR expecting platform xcb but got platform %s\n",
- argv[0], qPrintable(a.platformName()));
- exit(1);
- }
- if (!KWin::display()) {
- fprintf(stderr, "%s: FATAL ERROR KWin requires Xlib support in the xcb plugin. Do not configure Qt with -no-xcb-xlib\n",
- argv[0]);
- exit(1);
- }
-
- a.start();
-
-#warning SessionManager needs porting
-#if KWIN_QT5_PORTING
- KWin::SessionManager weAreIndeed;
-#endif
- KWin::SessionSaveDoneHelper helper;
-
- QString appname;
- if (KWin::screen_number == 0)
- appname = QStringLiteral("org.kde.kwin");
- else
- appname.sprintf("org.kde.kwin-screen-%d", KWin::screen_number);
-
- QDBusConnection::sessionBus().interface()->registerService(
- appname, QDBusConnectionInterface::DontQueueService);
-
- return a.exec();
}
+void Application::setupLocalizedString()
+{
+ KLocalizedString::setApplicationDomain("kwin");
+}
+
+void Application::setupLoggingCategoryFilters()
+{
+ QLoggingCategory::setFilterRules(QStringLiteral("aurorae.debug = true\n") +
+ QStringLiteral("kwineffects.debug = true"));
+}
+
+void Application::notifyKSplash()
+{
+ // Tell KSplash that KWin has started
+ QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"),
+ QStringLiteral("/KSplash"),
+ QStringLiteral("org.kde.KSplash"),
+ QStringLiteral("setStage"));
+ ksplashProgressMessage.setArguments(QList() << QStringLiteral("wm"));
+ QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage);
+}
+
+void Application::createWorkspace()
+{
+ // ensure the helper atoms are retrieved before we create the Workspace
+ atoms->retrieveHelpers();
+
+ // we want all QQuickWindows with an alpha buffer, do here as Workspace might create QQuickWindows
+ QQuickWindow::setDefaultAlphaBuffer(true);
+
+ // This tries to detect compositing options and can use GLX. GLX problems
+ // (X errors) shouldn't cause kwin to abort, so this is out of the
+ // critical startup section where x errors cause kwin to abort.
+
+ // create workspace.
+ (void) new Workspace(isSessionRestored());
+}
+
+void Application::createAtoms()
+{
+ atoms = new Atoms;
+}
+
+void Application::createOptions()
+{
+ options = new Options;
+}
+
+void Application::setupEventFilters()
+{
+ installNativeEventFilter(m_eventFilter.data());
+}
+
+void Application::destroyWorkspace()
+{
+ delete Workspace::self();
+}
+
+bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long int *result)
+{
+ Q_UNUSED(result)
+ if (!Workspace::self()) {
+ // Workspace not yet created
+ return false;
+ }
+ if (eventType != "xcb_generic_event_t") {
+ return false;
+ }
+ return Workspace::self()->workspaceEvent(static_cast(message));
+}
+
+} // namespace
+
#include "main.moc"
diff --git a/main.h b/main.h
index db4f581139..dc71bac288 100644
--- a/main.h
+++ b/main.h
@@ -22,12 +22,16 @@ along with this program. If not, see .
#ifndef MAIN_H
#define MAIN_H
+#include
+
#include
#include
// Qt
#include
#include
+class QCommandLineParser;
+
namespace KWin
{
@@ -37,22 +41,7 @@ public:
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long int *result) override;
};
-class KWinSelectionOwner
- : public KSelectionOwner
-{
- Q_OBJECT
-public:
- explicit KWinSelectionOwner(int screen);
-protected:
- virtual bool genericReply(xcb_atom_t target, xcb_atom_t property, xcb_window_t requestor);
- virtual void replyTargets(xcb_atom_t property, xcb_window_t requestor);
- virtual void getAtoms();
-private:
- xcb_atom_t make_selection_atom(int screen);
- static xcb_atom_t xa_version;
-};
-
-class Application : public QApplication
+class KWIN_EXPORT Application : public QApplication
{
Q_OBJECT
public:
@@ -73,10 +62,8 @@ public:
*/
OperationModeWaylandAndX11
};
- Application(int &argc, char **argv);
- ~Application();
+ virtual ~Application();
- void setReplace(bool replace);
void setConfigLock(bool lock);
void start();
@@ -90,22 +77,62 @@ public:
bool shouldUseWaylandForCompositing() const;
bool requiresCompositing() const;
+ void setupTranslator();
+ void setupCommandLine(QCommandLineParser *parser);
+ void processCommandLine(QCommandLineParser *parser);
+
+ void registerDBusService();
+
static void setCrashCount(int count);
static bool wasCrash();
+ /**
+ * Creates the KAboutData object for the KWin instance and registers it as
+ * KAboutData::setApplicationData.
+ **/
+ static void createAboutData();
+
+ /**
+ * @returns the X11 Screen number. If not applicable it's set to @c -1.
+ **/
+ static int x11ScreenNumber();
+ /**
+ * Sets the X11 screen number of this KWin instance to @p screenNumber.
+ **/
+ static void setX11ScreenNumber(int screenNumber);
+ /**
+ * @returns whether this is a multi head setup on X11.
+ **/
+ static bool isX11MultiHead();
+ /**
+ * Sets whether this is a multi head setup on X11.
+ */
+ static void setX11MultiHead(bool multiHead);
+
+ static void setupMalloc();
+ static void setupLocalizedString();
+ static void setupLoggingCategoryFilters();
+
protected:
+ Application(OperationMode mode, int &argc, char **argv);
+ virtual void performStartup() = 0;
+
+ void notifyKSplash();
+ void createWorkspace();
+ void createAtoms();
+ void createOptions();
+ void setupEventFilters();
+ void destroyWorkspace();
+
bool notify(QObject* o, QEvent* e);
static void crashHandler(int signal);
private Q_SLOTS:
- void lostSelection();
void resetCrashesCount();
private:
void crashChecking();
- QScopedPointer owner;
QScopedPointer m_eventFilter;
- bool m_replace;
bool m_configLock;
OperationMode m_operationMode;
static int crashes;
diff --git a/main_wayland.cpp b/main_wayland.cpp
new file mode 100644
index 0000000000..0baf84aa87
--- /dev/null
+++ b/main_wayland.cpp
@@ -0,0 +1,138 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2014 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, 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 General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "main_wayland.h"
+#include
+// kwin
+#include "xcbutils.h"
+
+// KDE
+#include
+// Qt
+#include
+#include
+
+// system
+#ifdef HAVE_UNISTD_H
+#include
+#endif // HAVE_UNISTD_H
+
+namespace KWin
+{
+
+//************************************
+// ApplicationWayland
+//************************************
+
+ApplicationWayland::ApplicationWayland(int &argc, char **argv)
+ : Application(OperationModeWaylandAndX11, argc, argv)
+{
+}
+
+ApplicationWayland::~ApplicationWayland()
+{
+ destroyWorkspace();
+ // TODO: only if we support X11
+ Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
+}
+
+void ApplicationWayland::performStartup()
+{
+ // we don't support X11 multi-head in Wayland
+ Application::setX11ScreenNumber(0);
+
+ // we need to do an XSync here, otherwise the QPA might crash us later on
+ // TODO: remove
+ Xcb::sync();
+
+ createAtoms();
+
+ setupEventFilters();
+ // first load options - done internally by a different thread
+ createOptions();
+
+ // Check whether another windowmanager is running
+ const uint32_t maskValues[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT};
+ ScopedCPointer redirectCheck(xcb_request_check(connection(),
+ xcb_change_window_attributes_checked(connection(),
+ rootWindow(),
+ XCB_CW_EVENT_MASK,
+ maskValues)));
+ if (!redirectCheck.isNull()) {
+ fputs(i18n("kwin: an X11 window manager is running on the X11 Display.\n").toLocal8Bit().constData(), stderr);
+ ::exit(1);
+ }
+
+ createWorkspace();
+
+ Xcb::sync(); // Trigger possible errors, there's still a chance to abort
+
+ notifyKSplash();
+}
+
+} // namespace
+
+extern "C"
+KWIN_EXPORT int kdemain(int argc, char * argv[])
+{
+ KWin::Application::setupMalloc();
+ KWin::Application::setupLocalizedString();
+ KWin::Application::setupLoggingCategoryFilters();
+
+ // TODO: check whether we have a wayland connection
+
+ // Disable the glib event loop integration, since it seems to be responsible
+ // for several bug reports about high CPU usage (bug #239963)
+ setenv("QT_NO_GLIB", "1", true);
+
+ // enforce xcb plugin, unfortunately command line switch has precedence
+ // TODO: ensure it's not xcb once we support the Wayland QPA
+ setenv("QT_QPA_PLATFORM", "xcb", true);
+
+ KWin::ApplicationWayland a(argc, argv);
+ a.setupTranslator();
+
+ KWin::Application::createAboutData();
+
+ QCommandLineParser parser;
+ a.setupCommandLine(&parser);
+
+ parser.process(a);
+ a.processCommandLine(&parser);
+
+ // perform sanity checks
+ // TODO: remove those two
+ if (a.platformName().toLower() != QStringLiteral("xcb")) {
+ fprintf(stderr, "%s: FATAL ERROR expecting platform xcb but got platform %s\n",
+ argv[0], qPrintable(a.platformName()));
+ exit(1);
+ }
+ if (!KWin::display()) {
+ fprintf(stderr, "%s: FATAL ERROR KWin requires Xlib support in the xcb plugin. Do not configure Qt with -no-xcb-xlib\n",
+ argv[0]);
+ exit(1);
+ }
+
+ a.start();
+
+ // TODO: is this still needed?
+ a.registerDBusService();
+
+ return a.exec();
+}
diff --git a/main_wayland.h b/main_wayland.h
new file mode 100644
index 0000000000..a0fc82d057
--- /dev/null
+++ b/main_wayland.h
@@ -0,0 +1,40 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2014 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, 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 General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_MAIN_WAYLAND_H
+#define KWIN_MAIN_WAYLAND_H
+#include "main.h"
+
+namespace KWin
+{
+
+class ApplicationWayland : public Application
+{
+ Q_OBJECT
+public:
+ ApplicationWayland(int &argc, char **argv);
+ virtual ~ApplicationWayland();
+
+protected:
+ void performStartup() override;
+};
+
+}
+
+#endif
diff --git a/main_x11.cpp b/main_x11.cpp
new file mode 100644
index 0000000000..738486eb65
--- /dev/null
+++ b/main_x11.cpp
@@ -0,0 +1,295 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 1999, 2000 Matthias Ettrich
+Copyright (C) 2003 Lubos Lunak
+Copyright (C) 2014 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, 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 General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "main_x11.h"
+#include
+// kwin
+#include "sm.h"
+#include "xcbutils.h"
+
+// KDE
+#include
+// Qt
+#include
+#include
+
+// system
+#ifdef HAVE_UNISTD_H
+#include
+#endif // HAVE_UNISTD_H
+
+namespace KWin
+{
+
+static void sighandler(int)
+{
+ QApplication::exit();
+}
+
+//************************************
+// KWinSelectionOwner
+//************************************
+
+KWinSelectionOwner::KWinSelectionOwner(int screen_P)
+ : KSelectionOwner(make_selection_atom(screen_P), screen_P)
+{
+}
+
+xcb_atom_t KWinSelectionOwner::make_selection_atom(int screen_P)
+{
+ if (screen_P < 0)
+ screen_P = QX11Info::appScreen();
+ QByteArray screen(QByteArrayLiteral("WM_S"));
+ screen.append(QByteArray::number(screen_P));
+ ScopedCPointer atom(xcb_intern_atom_reply(
+ connection(),
+ xcb_intern_atom_unchecked(connection(), false, screen.length(), screen.constData()),
+ nullptr));
+ if (atom.isNull()) {
+ return XCB_ATOM_NONE;
+ }
+ return atom->atom;
+}
+
+void KWinSelectionOwner::getAtoms()
+{
+ KSelectionOwner::getAtoms();
+ if (xa_version == XCB_ATOM_NONE) {
+ const QByteArray name(QByteArrayLiteral("VERSION"));
+ ScopedCPointer atom(xcb_intern_atom_reply(
+ connection(),
+ xcb_intern_atom_unchecked(connection(), false, name.length(), name.constData()),
+ nullptr));
+ if (!atom.isNull()) {
+ xa_version = atom->atom;
+ }
+ }
+}
+
+void KWinSelectionOwner::replyTargets(xcb_atom_t property_P, xcb_window_t requestor_P)
+{
+ KSelectionOwner::replyTargets(property_P, requestor_P);
+ xcb_atom_t atoms[ 1 ] = { xa_version };
+ // PropModeAppend !
+ xcb_change_property(connection(), XCB_PROP_MODE_APPEND, requestor_P,
+ property_P, XCB_ATOM_ATOM, 32, 1, atoms);
+}
+
+bool KWinSelectionOwner::genericReply(xcb_atom_t target_P, xcb_atom_t property_P, xcb_window_t requestor_P)
+{
+ if (target_P == xa_version) {
+ int32_t version[] = { 2, 0 };
+ xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, requestor_P,
+ property_P, XCB_ATOM_INTEGER, 32, 2, version);
+ } else
+ return KSelectionOwner::genericReply(target_P, property_P, requestor_P);
+ return true;
+}
+
+xcb_atom_t KWinSelectionOwner::xa_version = XCB_ATOM_NONE;
+
+//************************************
+// ApplicationX11
+//************************************
+
+ApplicationX11::ApplicationX11(int &argc, char **argv)
+ : Application(OperationModeX11, argc, argv)
+ , owner()
+ , m_replace(false)
+{
+}
+
+ApplicationX11::~ApplicationX11()
+{
+ destroyWorkspace();
+ if (!owner.isNull() && owner->ownerWindow() != XCB_WINDOW_NONE) // If there was no --replace (no new WM)
+ Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
+}
+
+void ApplicationX11::setReplace(bool replace)
+{
+ m_replace = replace;
+}
+
+void ApplicationX11::lostSelection()
+{
+ sendPostedEvents();
+ destroyWorkspace();
+ // Remove windowmanager privileges
+ Xcb::selectInput(rootWindow(), XCB_EVENT_MASK_PROPERTY_CHANGE);
+ quit();
+}
+
+void ApplicationX11::performStartup()
+{
+ if (Application::x11ScreenNumber() == -1) {
+ Application::setX11ScreenNumber(QX11Info::appScreen());
+ }
+
+ owner.reset(new KWinSelectionOwner(Application::x11ScreenNumber()));
+ connect(owner.data(), &KSelectionOwner::failedToClaimOwnership, []{
+ fputs(i18n("kwin: unable to claim manager selection, another wm running? (try using --replace)\n").toLocal8Bit().constData(), stderr);
+ ::exit(1);
+ });
+ connect(owner.data(), SIGNAL(lostOwnership()), SLOT(lostSelection()));
+ connect(owner.data(), &KSelectionOwner::claimedOwnership, [this]{
+ setupEventFilters();
+ // first load options - done internally by a different thread
+ createOptions();
+
+ // Check whether another windowmanager is running
+ const uint32_t maskValues[] = {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT};
+ ScopedCPointer redirectCheck(xcb_request_check(connection(),
+ xcb_change_window_attributes_checked(connection(),
+ rootWindow(),
+ XCB_CW_EVENT_MASK,
+ maskValues)));
+ if (!redirectCheck.isNull()) {
+ fputs(i18n("kwin: another window manager is running (try using --replace)\n").toLocal8Bit().constData(), stderr);
+ ::exit(1);
+ }
+
+ createWorkspace();
+
+ Xcb::sync(); // Trigger possible errors, there's still a chance to abort
+
+ notifyKSplash();
+ });
+ // we need to do an XSync here, otherwise the QPA might crash us later on
+ Xcb::sync();
+ owner->claim(m_replace, true);
+
+ createAtoms();
+}
+
+} // namespace
+
+extern "C"
+KWIN_EXPORT int kdemain(int argc, char * argv[])
+{
+ KWin::Application::setupMalloc();
+ KWin::Application::setupLocalizedString();
+ KWin::Application::setupLoggingCategoryFilters();
+
+ int primaryScreen = 0;
+ xcb_connection_t *c = xcb_connect(nullptr, &primaryScreen);
+ if (!c || xcb_connection_has_error(c)) {
+ fprintf(stderr, "%s: FATAL ERROR while trying to open display %s\n",
+ argv[0], qgetenv("DISPLAY").constData());
+ exit(1);
+ }
+
+ const int number_of_screens = xcb_setup_roots_length(xcb_get_setup(c));
+
+ // multi head
+ auto isMultiHead = []() -> bool {
+ QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
+ if (!multiHead.isEmpty()) {
+ return (multiHead.toLower() == "true");
+ }
+ return true;
+ };
+ if (number_of_screens != 1 && isMultiHead()) {
+ KWin::Application::setX11MultiHead(true);
+ KWin::Application::setX11ScreenNumber(primaryScreen);
+ int pos; // Temporarily needed to reconstruct DISPLAY var if multi-head
+ QByteArray display_name = qgetenv("DISPLAY");
+ xcb_disconnect(c);
+ c = nullptr;
+
+ if ((pos = display_name.lastIndexOf('.')) != -1)
+ display_name.remove(pos, 10); // 10 is enough to be sure we removed ".s"
+
+ QString envir;
+ for (int i = 0; i < number_of_screens; i++) {
+ // If execution doesn't pass by here, then kwin
+ // acts exactly as previously
+ if (i != KWin::Application::x11ScreenNumber() && fork() == 0) {
+ KWin::Application::setX11ScreenNumber(i);
+ // Break here because we are the child process, we don't
+ // want to fork() anymore
+ break;
+ }
+ }
+ // In the next statement, display_name shouldn't contain a screen
+ // number. If it had it, it was removed at the "pos" check
+ envir.sprintf("DISPLAY=%s.%d", display_name.data(), KWin::Application::x11ScreenNumber());
+
+ if (putenv(strdup(envir.toAscii().constData()))) {
+ fprintf(stderr, "%s: WARNING: unable to set DISPLAY environment variable\n", argv[0]);
+ perror("putenv()");
+ }
+ }
+
+ if (signal(SIGTERM, KWin::sighandler) == SIG_IGN)
+ signal(SIGTERM, SIG_IGN);
+ if (signal(SIGINT, KWin::sighandler) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+ if (signal(SIGHUP, KWin::sighandler) == SIG_IGN)
+ signal(SIGHUP, SIG_IGN);
+
+ // Disable the glib event loop integration, since it seems to be responsible
+ // for several bug reports about high CPU usage (bug #239963)
+ setenv("QT_NO_GLIB", "1", true);
+
+ // enforce xcb plugin, unfortunately command line switch has precedence
+ setenv("QT_QPA_PLATFORM", "xcb", true);
+
+ KWin::ApplicationX11 a(argc, argv);
+ a.setupTranslator();
+
+ KWin::Application::createAboutData();
+
+ QCommandLineOption replaceOption(QStringLiteral("replace"), i18n("Replace already-running ICCCM2.0-compliant window manager"));
+
+ QCommandLineParser parser;
+ a.setupCommandLine(&parser);
+ parser.addOption(replaceOption);
+
+ parser.process(a);
+ a.processCommandLine(&parser);
+ a.setReplace(parser.isSet(replaceOption));
+
+ // perform sanity checks
+ if (a.platformName().toLower() != QStringLiteral("xcb")) {
+ fprintf(stderr, "%s: FATAL ERROR expecting platform xcb but got platform %s\n",
+ argv[0], qPrintable(a.platformName()));
+ exit(1);
+ }
+ if (!KWin::display()) {
+ fprintf(stderr, "%s: FATAL ERROR KWin requires Xlib support in the xcb plugin. Do not configure Qt with -no-xcb-xlib\n",
+ argv[0]);
+ exit(1);
+ }
+
+ a.start();
+
+#warning SessionManager needs porting
+#if KWIN_QT5_PORTING
+ KWin::SessionManager weAreIndeed;
+#endif
+ KWin::SessionSaveDoneHelper helper;
+
+ // TODO: is this still needed?
+ a.registerDBusService();
+
+ return a.exec();
+}
diff --git a/main_x11.h b/main_x11.h
new file mode 100644
index 0000000000..ef3c44464f
--- /dev/null
+++ b/main_x11.h
@@ -0,0 +1,64 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2014 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, 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 General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_MAIN_X11_H
+#define KWIN_MAIN_X11_H
+#include "main.h"
+
+namespace KWin
+{
+
+class KWinSelectionOwner
+ : public KSelectionOwner
+{
+ Q_OBJECT
+public:
+ explicit KWinSelectionOwner(int screen);
+protected:
+ virtual bool genericReply(xcb_atom_t target, xcb_atom_t property, xcb_window_t requestor);
+ virtual void replyTargets(xcb_atom_t property, xcb_window_t requestor);
+ virtual void getAtoms();
+private:
+ xcb_atom_t make_selection_atom(int screen);
+ static xcb_atom_t xa_version;
+};
+
+class ApplicationX11 : public Application
+{
+ Q_OBJECT
+public:
+ ApplicationX11(int &argc, char **argv);
+ virtual ~ApplicationX11();
+
+ void setReplace(bool replace);
+
+protected:
+ void performStartup() override;
+
+private Q_SLOTS:
+ void lostSelection();
+
+private:
+ QScopedPointer owner;
+ bool m_replace;
+};
+
+}
+
+#endif
diff --git a/sm.h b/sm.h
index 7ab8bd5dff..cc63aa3da1 100644
--- a/sm.h
+++ b/sm.h
@@ -82,7 +82,7 @@ enum SMSavePhase {
SMSavePhase2Full // complete saving in phase2, there was no phase 0
};
-class SessionSaveDoneHelper
+class KWIN_EXPORT SessionSaveDoneHelper
: public QObject
{
Q_OBJECT
diff --git a/wayland_backend.cpp b/wayland_backend.cpp
index 03f73a486b..7c2d57b24a 100644
--- a/wayland_backend.cpp
+++ b/wayland_backend.cpp
@@ -21,7 +21,6 @@ along with this program. If not, see .
#include "wayland_backend.h"
// KWin
#include "cursor.h"
-#include "main.h"
#include "input.h"
// Qt
#include
@@ -751,7 +750,6 @@ WaylandBackend::WaylandBackend(QObject *parent)
}
initConnection();
- kwinApp()->setOperationMode(Application::OperationModeWaylandAndX11);
}
WaylandBackend::~WaylandBackend()