Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions misc/systemd/treeland.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ PartOf=graphical.target
StartLimitIntervalSec=30
StartLimitBurst=2

Requires=seatd-dde.service
After=seatd-dde.service
Requires=seatd.service
After=seatd.service
Comment thread
calsys456 marked this conversation as resolved.

[Service]
User=dde
Expand Down
15 changes: 15 additions & 0 deletions src/core/qml/PrimaryOutput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ OutputItem {
target: wallpaper
scale: 1.4
}
},
State {
name: "ScaleWithoutAnimation"
PropertyChanges {
target: wallpaper
scale: 1.4
}
}
]

Expand All @@ -129,6 +136,14 @@ OutputItem {
duration: 1000
easing.type: Easing.OutExpo
}
},
Transition {
from: "*"
to: "ScaleWithoutAnimation"
PropertyAnimation {
property: "scale"
duration: 0
}
}
]
}
Expand Down
28 changes: 23 additions & 5 deletions src/greeter/greeterproxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
#include <QGuiApplication>
#include <QLocalSocket>
#include <QVariantMap>
#include <QDBusInterface>
#include <QDBusPendingCall>
#include <QDBusReply>

#include <woutputrenderwindow.h>

struct SessionInfo
{
Expand Down Expand Up @@ -216,10 +220,23 @@ void GreeterProxy::init()
this,
&GreeterProxy::onSessionRemoved);

auto sessions = d->displayManager->sessions();
for (auto session : sessions) {
onSessionAdded(session);
}
// Use async call to avoid blocking
QDBusInterface dbus("org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus.Properties",
QDBusConnection::systemBus());
QDBusPendingCall call = dbus.asyncCall("Get", DisplayManager::staticInterfaceName(), "Sessions");
auto *watcher = new QDBusPendingCallWatcher(call);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
QDBusReply<QList<QDBusObjectPath>> reply = watcher->reply();
if (reply.isValid()) {
auto sessions = reply.value();
for (auto session : sessions) {
onSessionAdded(session);
}
}
watcher->deleteLater();
});
}

void GreeterProxy::login(const QString &user, const QString &password, const int sessionIndex)
Expand Down Expand Up @@ -344,7 +361,8 @@ void GreeterProxy::connected()
{
qCDebug(treelandGreeter) << "Connected to the daemon.";

SocketWriter(d->socket) << quint32(GreeterMessages::Connect);
SocketWriter(d->socket) << quint32(GreeterMessages::Connect)
<< Helper::instance()->defaultWaylandSocket()->fullServerName();
}

void GreeterProxy::disconnected()
Expand Down
1 change: 1 addition & 0 deletions src/modules/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ add_subdirectory(virtual-output)
add_subdirectory(dde-shell)
add_subdirectory(capture)
add_subdirectory(item-selector)
add_subdirectory(ddm)
14 changes: 14 additions & 0 deletions src/modules/ddm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
find_package(TreelandProtocols REQUIRED)

ws_generate_local(server ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-ddm-v1.xml treeland-ddm-v1-protocol)

impl_treeland(
NAME
module_ddm
SOURCE
${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev1.h
${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev1.cpp
${WAYLAND_PROTOCOLS_OUTPUTDIR}/treeland-ddm-v1-protocol.c
INCLUDE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
117 changes: 117 additions & 0 deletions src/modules/ddm/ddminterfacev1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (C) 2025 April Lu <apr3vau@outlook.com>.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "ddminterfacev1.h"
#include "treeland-ddm-v1-protocol.h"
#include "common/treelandlogging.h"
#include "helper.h"
#include "usermodel.h"

#include <wayland-server-core.h>
#include <wayland-server.h>
#include <wayland-util.h>
#include <QDebug>

struct treeland_ddm {
wl_resource *resource;
};

// request implementation

static void switchToGreeter([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) {
Helper::instance()->showLockScreen(false);
}

static void switchToUser([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource, const char *username) {
if (strcmp(username, "ddm") != 0) {
Helper::instance()->userModel()->setCurrentUserName(QString(username));
}
}

static void activateSession([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) {
Helper::instance()->activateSession();
}

static void deactivateSession([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) {
Helper::instance()->deactivateSession();
}

static const struct treeland_ddm_interface treeland_ddm_impl {
.switch_to_greeter = switchToGreeter,
.switch_to_user = switchToUser,
.activate_session = activateSession,
.deactivate_session = deactivateSession,
};

// wayland object binding

static void handleResourceDestroy(struct wl_resource *resource) {
qCWarning(treelandCore) << "DDM connection lost";
auto ddm = static_cast<struct treeland_ddm *>(wl_resource_get_user_data(resource));
ddm->resource = nullptr;
}

void handleBindingGlobal(struct wl_client *client, void *data, uint32_t version, uint32_t id) {
auto ddm = static_cast<struct treeland_ddm *>(data);
auto *resource = wl_resource_create(client, &treeland_ddm_interface, version, id);
wl_resource_set_implementation(resource, &treeland_ddm_impl, ddm, handleResourceDestroy);
ddm->resource = resource;
qCDebug(treelandCore) << "DDM connection established";

treeland_ddm_send_acquire_vt(resource, 0);
}

// DDMInterfaceV1

DDMInterfaceV1::DDMInterfaceV1() {

}

DDMInterfaceV1::~DDMInterfaceV1() {
}

QByteArrayView DDMInterfaceV1::interfaceName() const {
QByteArray arr(treeland_ddm_interface.name);
return QByteArrayView(arr);
}

bool DDMInterfaceV1::isConnected() const {
auto ddm = static_cast<struct treeland_ddm *>(m_handle);
return ddm && ddm->resource;
}

void DDMInterfaceV1::create(WServer *server) {
auto ddm = new treeland_ddm { .resource = nullptr };
m_handle = ddm;
m_global = wl_global_create(server->handle()->handle(), &treeland_ddm_interface,
treeland_ddm_interface.version, ddm, handleBindingGlobal);
}

void DDMInterfaceV1::destroy([[maybe_unused]] WServer *server) {
wl_global_destroy(m_global);
auto ddm = static_cast<struct treeland_ddm *>(m_handle);
delete ddm;
m_handle = nullptr;
}

wl_global *DDMInterfaceV1::global() const {
return m_global;
}

// Event wrapper

void DDMInterfaceV1::switchToVt(int vtnr) {
auto ddm = static_cast<struct treeland_ddm *>(m_handle);
if (isConnected())
treeland_ddm_send_switch_to_vt(ddm->resource, vtnr);
else
qCWarning(treelandCore) << "DDM is not conected when trying to call switchToVt";
}

void DDMInterfaceV1::acquireVt(int vtnr) {
auto ddm = static_cast<struct treeland_ddm *>(m_handle);
if (isConnected())
treeland_ddm_send_acquire_vt(ddm->resource, vtnr);
else
qCWarning(treelandCore) << "DDM is not connected when trying to call acquireVt";
}
23 changes: 23 additions & 0 deletions src/modules/ddm/ddminterfacev1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2025 April Lu <apr3vau@outlook.com>.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "wserver.h"

/**
* The server-side wrapper for treeland private protocol.
*/
class DDMInterfaceV1 : public Waylib::Server::WServerInterface {
public:
DDMInterfaceV1();
~DDMInterfaceV1() override;
QByteArrayView interfaceName() const override;
bool isConnected() const;
void switchToVt(int vtnr);
void acquireVt(int vtnr);
protected:
void create(Waylib::Server::WServer *server) override;
void destroy(Waylib::Server::WServer *server) override;
wl_global *global() const override;
private:
struct wl_global *m_global { nullptr };
};
11 changes: 10 additions & 1 deletion src/modules/primary-output/impl/output_manager_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "output_manager_impl.h"

#include <wayland-server-core.h>
#include <wayland-util.h>

#include <cassert>

Expand Down Expand Up @@ -65,6 +66,11 @@ treeland_output_manager_v1 *treeland_output_manager_v1::create(qw_display *displ
void treeland_output_manager_v1::set_primary_output(const char *name)
{
this->primary_output_name = name;

// Sometimes the whole resources list will be removed and leaved in an invalid state
// (e.g. after a VT switching), so we need to ensure resources is valid before operations.
wl_list_init(&this->resources);

wl_resource *resource;
wl_list_for_each(resource, &this->resources, link)
{
Expand All @@ -85,7 +91,10 @@ static treeland_output_manager_v1 *output_manager_from_resource(wl_resource *res

static void output_manager_resource_destroy(struct wl_resource *resource)
{
wl_list_remove(wl_resource_get_link(resource));
// Safely remove resource from list
auto link = wl_resource_get_link(resource);
wl_list_init(link);
wl_list_remove(link);
}

static void output_manager_bind(wl_client *client, void *data, uint32_t version, uint32_t id)
Expand Down
8 changes: 6 additions & 2 deletions src/plugins/lockscreen/qml/Greeter.qml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ FocusScope {
}
lockView.showAnimation = showAnimation
lockView.forceActiveFocus()
wallpaperController.type = WallpaperController.Scale
if (showAnimation) {
wallpaperController.type = WallpaperController.Scale
} else {
wallpaperController.type = WallpaperController.ScaleWithoutAnimation
}
switch (root.currentMode) {
case Greeter.CurrentMode.Lock:
lockView.start()
Expand Down Expand Up @@ -69,7 +73,7 @@ FocusScope {
opacity: wallpaperController.type === WallpaperController.Normal ? 0 : 0.6
Behavior on opacity {
PropertyAnimation {
duration: 1000
duration: wallpaperController.type === WallpaperController.ScaleWithoutAnimation ? 0 : 1000
easing.type: Easing.OutExpo
}
}
Expand Down
Loading