summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2023-05-09 08:46:09 +0100
committerCaolán McNamara <caolanm@redhat.com>2023-05-09 20:42:49 +0200
commitc04d0570b6c8c78e35c2c9b58bf37bb1218021f5 (patch)
treec80ae21c87958b7c61e3fb9ceb0b4a35808e7887 /vcl
parent5c73c3aa6875b1e69b2d58a47ba823faf78b8aa2 (diff)
Resolves: tdf#142176 under GNOME inhibit logout if there are modified docs
and if we are forced to quit anyway, unset modifications on documents and terminate. Change-Id: If4a3aed48a4621950e2d630fdfef34b28ba1b089 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151575 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Library_vcl.mk2
-rw-r--r--vcl/inc/qt5/QtFrame.hxx2
-rw-r--r--vcl/inc/strings.hrc3
-rw-r--r--vcl/inc/unx/gtk/gtkframe.hxx9
-rw-r--r--vcl/inc/unx/salframe.h2
-rw-r--r--vcl/inc/unx/sessioninhibitor.hxx (renamed from vcl/inc/unx/screensaverinhibitor.hxx)3
-rw-r--r--vcl/unx/generic/window/sessioninhibitor.cxx (renamed from vcl/unx/generic/window/screensaverinhibitor.cxx)19
-rw-r--r--vcl/unx/gtk3/gtkframe.cxx174
8 files changed, 195 insertions, 19 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 9eca7534218e..a7c1fbc22b2f 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -579,7 +579,7 @@ endif
ifeq ($(USING_X11),TRUE)
$(eval $(call gb_Library_add_exception_objects,vcl,\
- vcl/unx/generic/window/screensaverinhibitor \
+ vcl/unx/generic/window/sessioninhibitor \
vcl/unx/generic/printer/cpdmgr \
))
diff --git a/vcl/inc/qt5/QtFrame.hxx b/vcl/inc/qt5/QtFrame.hxx
index b927d366765d..09abe5301538 100644
--- a/vcl/inc/qt5/QtFrame.hxx
+++ b/vcl/inc/qt5/QtFrame.hxx
@@ -34,7 +34,7 @@
#include <QtCore/QObject>
#if CHECK_ANY_QT_USING_X11
-#include <unx/screensaverinhibitor.hxx>
+#include <unx/sessioninhibitor.hxx>
// any better way to get rid of the X11 / Qt type clashes?
#undef Bool
#undef CursorShape
diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc
index 83beea008e9e..c2e95f20ceac 100644
--- a/vcl/inc/strings.hrc
+++ b/vcl/inc/strings.hrc
@@ -122,6 +122,9 @@
#define STR_QUIRKY NC_("STR_QUIRKY", "Quirky Tests: %1")
#define STR_FAILED NC_("STR_FAILED", "Failed Tests: %1")
#define STR_SKIPPED NC_("STR_SKIPPED", "Skipped Tests: %1")
+
+#define STR_UNSAVED_DOCUMENTS NC_("STR_UNSAVED_DOCUMENTS", "There are unsaved documents")
+
#endif // INCLUDED_VCL_INC_STRINGS_HRC
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 1a83a7fc39d3..890bcdb8a6ea 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -32,7 +32,7 @@
#include <vcl/idle.hxx>
#include <vcl/sysdata.hxx>
#include <unx/saltype.h>
-#include <unx/screensaverinhibitor.hxx>
+#include <unx/sessioninhibitor.hxx>
#include <tools/link.hxx>
@@ -187,6 +187,9 @@ class GtkSalFrame final : public SalFrame
#endif
gulong m_nPortalSettingChangedSignalId;
GDBusProxy* m_pSettingsPortal;
+ gulong m_nSessionClientSignalId;
+ GDBusProxy* m_pSessionManager;
+ GDBusProxy* m_pSessionClient;
#if !GTK_CHECK_VERSION(4, 0, 0)
GdkWindow* m_pForeignParent;
GdkNativeWindow m_aForeignParentWindow;
@@ -425,6 +428,8 @@ class GtkSalFrame final : public SalFrame
void ListenPortalSettings();
+ void ListenSessionManager();
+
void UpdateGeometryFromEvent(int x_root, int y_root, int nEventX, int nEventY);
public:
@@ -654,6 +659,8 @@ public:
void SetColorScheme(GVariant* variant);
+ void SessionManagerInhibit(bool bStart, ApplicationInhibitFlags eType, std::u16string_view sReason, const char* application_id);
+
void DisallowCycleFocusOut();
bool IsCycleFocusOutDisallowed() const;
void AllowCycleFocusOut();
diff --git a/vcl/inc/unx/salframe.h b/vcl/inc/unx/salframe.h
index d8a177d9a867..c14c3254c489 100644
--- a/vcl/inc/unx/salframe.h
+++ b/vcl/inc/unx/salframe.h
@@ -24,7 +24,7 @@
#include <unx/saltype.h>
#include <unx/saldisp.hxx>
-#include <unx/screensaverinhibitor.hxx>
+#include <unx/sessioninhibitor.hxx>
#include <salframe.hxx>
#include <salwtype.hxx>
#include <salinst.hxx>
diff --git a/vcl/inc/unx/screensaverinhibitor.hxx b/vcl/inc/unx/sessioninhibitor.hxx
index 6cfa3e2fd700..5385cde383cf 100644
--- a/vcl/inc/unx/screensaverinhibitor.hxx
+++ b/vcl/inc/unx/sessioninhibitor.hxx
@@ -31,7 +31,8 @@ class VCL_PLUGIN_PUBLIC SessionManagerInhibitor
{
public:
void inhibit(bool bInhibit, std::u16string_view sReason, ApplicationInhibitFlags eType,
- unsigned int window_system_id, std::optional<Display*> pDisplay);
+ unsigned int window_system_id, std::optional<Display*> pDisplay,
+ const char* application_id = nullptr);
private:
// These are all used as guint, however this header may be included
diff --git a/vcl/unx/generic/window/screensaverinhibitor.cxx b/vcl/unx/generic/window/sessioninhibitor.cxx
index b1cfcb3f4993..300df9ff8031 100644
--- a/vcl/unx/generic/window/screensaverinhibitor.cxx
+++ b/vcl/unx/generic/window/sessioninhibitor.cxx
@@ -12,7 +12,7 @@
#include <functional>
#include <unx/gensys.h>
-#include <unx/screensaverinhibitor.hxx>
+#include <unx/sessioninhibitor.hxx>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@@ -47,9 +47,10 @@
#include <sal/log.hxx>
void SessionManagerInhibitor::inhibit(bool bInhibit, std::u16string_view sReason, ApplicationInhibitFlags eType,
- unsigned int window_system_id, std::optional<Display*> pDisplay)
+ unsigned int window_system_id, std::optional<Display*> pDisplay,
+ const char* application_id)
{
- const char* appname = SalGenericSystem::getFrameClassName();
+ const char* appname = application_id ? application_id : SalGenericSystem::getFrameClassName();
const OString aReason = OUStringToOString( sReason, RTL_TEXTENCODING_UTF8 );
if (eType == APPLICATION_INHIBIT_IDLE)
@@ -85,10 +86,10 @@ static void dbusInhibit( bool bInhibit,
GError *error = nullptr;
GDBusConnection *session_connection = g_bus_get_sync( G_BUS_TYPE_SESSION, nullptr, &error );
if (session_connection == nullptr) {
- SAL_WARN( "vcl.screensaverinhibitor", "failed to connect to dbus session bus" );
+ SAL_WARN( "vcl.sessioninhibitor", "failed to connect to dbus session bus" );
if (error != nullptr) {
- SAL_WARN( "vcl.screensaverinhibitor", "Error: " << error->message );
+ SAL_WARN( "vcl.sessioninhibitor", "Error: " << error->message );
g_error_free( error );
}
@@ -107,7 +108,7 @@ static void dbusInhibit( bool bInhibit,
g_object_unref( G_OBJECT( session_connection ) );
if (proxy == nullptr) {
- SAL_INFO( "vcl.screensaverinhibitor", "could not get dbus proxy: " << service );
+ SAL_INFO( "vcl.sessioninhibitor", "could not get dbus proxy: " << service );
return;
}
@@ -128,7 +129,7 @@ static void dbusInhibit( bool bInhibit,
}
else
{
- SAL_INFO( "vcl.screensaverinhibitor", service << ".Inhibit failed");
+ SAL_INFO( "vcl.sessioninhibitor", service << ".Inhibit failed");
}
}
else
@@ -142,13 +143,13 @@ static void dbusInhibit( bool bInhibit,
}
else
{
- SAL_INFO( "vcl.screensaverinhibitor", service << ".UnInhibit failed" );
+ SAL_INFO( "vcl.sessioninhibitor", service << ".UnInhibit failed" );
}
}
if (error != nullptr)
{
- SAL_INFO( "vcl.screensaverinhibitor", "Error: " << error->message );
+ SAL_INFO( "vcl.sessioninhibitor", "Error: " << error->message );
g_error_free( error );
}
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index b6b4cd52f8cf..ea13a70ad0ca 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -31,6 +31,7 @@
#include <sal/log.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <vcl/toolkit/floatwin.hxx>
+#include <vcl/toolkit/unowrap.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <vcl/window.hxx>
@@ -42,6 +43,7 @@
#include <X11/Xutil.h>
#include <unx/gtk/gtkbackend.hxx>
+#include <strings.hrc>
#include <window.h>
#include <basegfx/vector/b2ivector.hxx>
@@ -62,6 +64,8 @@
#include <com/sun/star/awt/MouseButton.hpp>
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
#if !GTK_CHECK_VERSION(4, 0, 0)
# define GDK_ALT_MASK GDK_MOD1_MASK
@@ -630,7 +634,6 @@ void on_registrar_unavailable( GDBusConnection * /*connection*/,
SAL_INFO("vcl.unity", "on_registrar_unavailable");
- //pSessionBus = NULL;
GtkSalFrame* pSalFrame = static_cast< GtkSalFrame* >( user_data );
SalMenu* pSalMenu = pSalFrame->GetMenu();
@@ -720,6 +723,15 @@ GtkSalFrame::~GtkSalFrame()
if (m_pSettingsPortal)
g_object_unref(m_pSettingsPortal);
+
+ if (m_nSessionClientSignalId)
+ g_signal_handler_disconnect(m_pSessionClient, m_nSessionClientSignalId);
+
+ if (m_pSessionClient)
+ g_object_unref(m_pSessionClient);
+
+ if (m_pSessionManager)
+ g_object_unref(m_pSessionManager);
}
GtkWidget *pEventWidget = getMouseEventWidget();
@@ -940,7 +952,10 @@ void GtkSalFrame::InitCommon()
m_nGrabLevel = 0;
m_bSalObjectSetPosSize = false;
m_nPortalSettingChangedSignalId = 0;
+ m_nSessionClientSignalId = 0;
m_pSettingsPortal = nullptr;
+ m_pSessionManager = nullptr;
+ m_pSessionClient = nullptr;
m_aDamageHandler.handle = this;
m_aDamageHandler.damaged = ::damaged;
@@ -1417,9 +1432,151 @@ void GtkSalFrame::ListenPortalSettings()
UpdateDarkMode();
+ if (!m_pSettingsPortal)
+ return;
+
m_nPortalSettingChangedSignalId = g_signal_connect(m_pSettingsPortal, "g-signal", G_CALLBACK(settings_portal_changed_cb), this);
}
+static void session_client_response(GDBusProxy* client_proxy)
+{
+ g_dbus_proxy_call(client_proxy,
+ "EndSessionResponse",
+ g_variant_new ("(bs)", true, ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ nullptr, nullptr, nullptr);
+}
+
+// unset documents "modify" flag so they won't veto closing
+static void clear_modify_and_terminate()
+{
+ css::uno::Reference<css::uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference<frame::XDesktop> xDesktop(frame::Desktop::create(xContext));
+ uno::Reference<css::container::XEnumeration> xComponents = xDesktop->getComponents()->createEnumeration();
+ while (xComponents->hasMoreElements())
+ {
+ css::uno::Reference<css::util::XModifiable> xModifiable(xComponents->nextElement(), css::uno::UNO_QUERY);
+ if (xModifiable)
+ xModifiable->setModified(false);
+ }
+ xDesktop->terminate();
+}
+
+static void session_client_signal(GDBusProxy* client_proxy, const char*, const char* signal_name,
+ GVariant* /*parameters*/, gpointer frame)
+{
+ GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
+
+ if (g_str_equal (signal_name, "QueryEndSession"))
+ {
+ css::uno::Reference<css::uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference<frame::XDesktop2> xDesktop(frame::Desktop::create(xContext));
+
+ bool bModified = false;
+
+ // find the XModifiable for this GtkSalFrame
+ if (UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper(false))
+ {
+ VclPtr<vcl::Window> xThisWindow = pThis->GetWindow();
+ css::uno::Reference<css::container::XIndexAccess> xList = xDesktop->getFrames();
+ sal_Int32 nFrameCount = xList->getCount();
+ for (sal_Int32 i = 0; i < nFrameCount; ++i)
+ {
+ css::uno::Reference<css::frame::XFrame> xFrame;
+ xList->getByIndex(i) >>= xFrame;
+ if (!xFrame)
+ continue;
+ VclPtr<vcl::Window> xWin = pWrapper->GetWindow(xFrame->getContainerWindow());
+ if (!xWin)
+ continue;
+ if (xWin->GetFrameWindow() != xThisWindow)
+ continue;
+ css::uno::Reference<css::frame::XController> xController = xFrame->getController();
+ if (!xController)
+ break;
+ css::uno::Reference<css::util::XModifiable> xModifiable(xController->getModel(), css::uno::UNO_QUERY);
+ if (!xModifiable)
+ break;
+ bModified = xModifiable->isModified();
+ break;
+ }
+ }
+
+ pThis->SessionManagerInhibit(bModified, APPLICATION_INHIBIT_LOGOUT, VclResId(STR_UNSAVED_DOCUMENTS),
+ gtk_window_get_icon_name(GTK_WINDOW(pThis->getWindow())));
+
+ session_client_response(client_proxy);
+ }
+ else if (g_str_equal (signal_name, "CancelEndSession"))
+ {
+ // restore back to uninhibited (to set again if queried), so frames
+ // that go away before the next logout don't affect that logout
+ pThis->SessionManagerInhibit(false, APPLICATION_INHIBIT_LOGOUT, VclResId(STR_UNSAVED_DOCUMENTS),
+ gtk_window_get_icon_name(GTK_WINDOW(pThis->getWindow())));
+ }
+ else if (g_str_equal (signal_name, "EndSession"))
+ {
+ session_client_response(client_proxy);
+ clear_modify_and_terminate();
+ }
+ else if (g_str_equal (signal_name, "Stop"))
+ {
+ clear_modify_and_terminate();
+ }
+}
+
+void GtkSalFrame::ListenSessionManager()
+{
+ EnsureSessionBus();
+
+ if (!pSessionBus)
+ return;
+
+ m_pSessionManager = g_dbus_proxy_new_sync(pSessionBus,
+ G_DBUS_PROXY_FLAGS_NONE,
+ nullptr,
+ "org.gnome.SessionManager",
+ "/org/gnome/SessionManager",
+ "org.gnome.SessionManager",
+ nullptr,
+ nullptr);
+
+ if (!m_pSessionManager)
+ return;
+
+ GVariant* res = g_dbus_proxy_call_sync(m_pSessionManager,
+ "RegisterClient",
+ g_variant_new ("(ss)", "org.libreoffice", ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ G_MAXINT,
+ nullptr,
+ nullptr);
+
+ if (!res)
+ return;
+
+ gchar* client_path;
+ g_variant_get(res, "(o)", &client_path);
+ g_variant_unref(res);
+
+ m_pSessionClient = g_dbus_proxy_new_sync(pSessionBus,
+ G_DBUS_PROXY_FLAGS_NONE,
+ nullptr,
+ "org.gnome.SessionManager",
+ client_path,
+ "org.gnome.SessionManager.ClientPrivate",
+ nullptr,
+ nullptr);
+
+ g_free(client_path);
+
+ if (!m_pSessionClient)
+ return;
+
+ m_nSessionClientSignalId = g_signal_connect(m_pSessionClient, "g-signal", G_CALLBACK(session_client_signal), this);
+}
+
void GtkSalFrame::UpdateDarkMode()
{
g_autoptr (GVariant) value = nullptr;
@@ -1610,6 +1767,9 @@ void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
// Listen to portal settings for e.g. prefer dark theme
ListenPortalSettings();
+
+ // Listen to session manager for e.g. query-end
+ ListenSessionManager();
}
}
@@ -2470,7 +2630,7 @@ void GtkSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nScreen )
}
}
-void GtkSalFrame::StartPresentation( bool bStart )
+void GtkSalFrame::SessionManagerInhibit(bool bStart, ApplicationInhibitFlags eType, std::u16string_view sReason, const char* application_id)
{
guint nWindow(0);
std::optional<Display*> aDisplay;
@@ -2481,9 +2641,13 @@ void GtkSalFrame::StartPresentation( bool bStart )
aDisplay = gdk_x11_display_get_xdisplay(getGdkDisplay());
}
- m_SessionManagerInhibitor.inhibit(bStart, u"presentation",
- APPLICATION_INHIBIT_IDLE,
- nWindow, aDisplay);
+ m_SessionManagerInhibitor.inhibit(bStart, sReason, eType,
+ nWindow, aDisplay, application_id);
+}
+
+void GtkSalFrame::StartPresentation( bool bStart )
+{
+ SessionManagerInhibit(bStart, APPLICATION_INHIBIT_IDLE, u"presentation", nullptr);
}
void GtkSalFrame::SetAlwaysOnTop( bool bOnTop )