1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <QtX11Support.hxx>
#include <config_vclplug.h>
#include <QtCore/QVersionNumber>
#include <QtInstance.hxx>
#include <QtTools.hxx>
#if CHECK_QT5_USING_X11
#include <QtX11Extras/QX11Info>
#endif
#if QT5_HAVE_XCB_ICCCM
#include <xcb/xcb_icccm.h>
#endif
#include <unx/gensys.h>
xcb_atom_t QtX11Support::m_nWindowGroupAtom = 0;
bool QtX11Support::m_bDidAtomLookups = false;
xcb_atom_t QtX11Support::lookupAtom(xcb_connection_t* pConn, const char* const sAtomName)
{
xcb_atom_t nAtom = 0;
xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(pConn, 1, strlen(sAtomName), sAtomName);
xcb_intern_atom_reply_t* atom_reply = xcb_intern_atom_reply(pConn, atom_cookie, nullptr);
if (atom_reply)
{
nAtom = atom_reply->atom;
free(atom_reply);
}
return nAtom;
}
void QtX11Support::fetchAtoms()
{
#if CHECK_QT5_USING_X11
if (m_bDidAtomLookups)
return;
m_bDidAtomLookups = true;
xcb_connection_t* pXcbConn = QX11Info::connection();
m_nWindowGroupAtom = lookupAtom(pXcbConn, m_sWindowGroupName);
#endif
}
void QtX11Support::setApplicationID(const xcb_window_t nWinId, std::u16string_view rWMClass)
{
#if CHECK_QT5_USING_X11
OString aResClass = OUStringToOString(rWMClass, RTL_TEXTENCODING_ASCII_US);
const char* pResClass
= !aResClass.isEmpty() ? aResClass.getStr() : SalGenericSystem::getFrameClassName();
OString aResName = SalGenericSystem::getFrameResName();
// the WM_CLASS data consists of two concatenated cstrings, including the terminating '\0' chars
const uint32_t data_len = aResName.getLength() + 1 + strlen(pResClass) + 1;
char* data = new char[data_len];
memcpy(data, aResName.getStr(), aResName.getLength() + 1);
memcpy(data + aResName.getLength() + 1, pResClass, strlen(pResClass) + 1);
xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, nWinId, XCB_ATOM_WM_CLASS,
XCB_ATOM_STRING, 8, data_len, data);
delete[] data;
#else
Q_UNUSED(nWinId);
Q_UNUSED(rWMClass);
#endif
}
bool QtX11Support::fixICCCMwindowGroup(const xcb_window_t nWinId)
{
#if CHECK_QT5_USING_X11 && QT5_HAVE_XCB_ICCCM
// older Qt5 just sets WM_CLIENT_LEADER, but not the XCB_ICCCM_WM_HINT_WINDOW_GROUP
// see Qt commit 0de4b326d8 ("xcb: fix issue with dialogs hidden by other windows")
// or QTBUG-46626. So LO has to set this itself to help some WMs.
if (QVersionNumber::fromString(qVersion()) >= QVersionNumber(5, 12))
return false;
xcb_connection_t* pXcbConn = QX11Info::connection();
xcb_icccm_wm_hints_t hints;
xcb_get_property_cookie_t prop_cookie = xcb_icccm_get_wm_hints_unchecked(pXcbConn, nWinId);
if (!xcb_icccm_get_wm_hints_reply(pXcbConn, prop_cookie, &hints, nullptr))
return false;
if (hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP)
return false;
fetchAtoms();
if (!m_nWindowGroupAtom)
return false;
prop_cookie = xcb_get_property(pXcbConn, 0, nWinId, m_nWindowGroupAtom, XCB_ATOM_WINDOW, 0, 1);
xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(pXcbConn, prop_cookie, nullptr);
if (!prop_reply)
return true;
if (xcb_get_property_value_length(prop_reply) != 4)
{
free(prop_reply);
return true;
}
xcb_window_t leader = *static_cast<xcb_window_t*>(xcb_get_property_value(prop_reply));
free(prop_reply);
hints.flags |= XCB_ICCCM_WM_HINT_WINDOW_GROUP;
hints.window_group = leader;
xcb_icccm_set_wm_hints(pXcbConn, nWinId, &hints);
return true;
#else
Q_UNUSED(nWinId);
return false;
#endif
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|