79
77
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
80
78
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
82
QHash<QString, std::weak_ptr<Decoration::DecorationPalette>> Client::s_palettes;
83
std::shared_ptr<Decoration::DecorationPalette> Client::s_defaultPalette;
85
80
// Creating a client:
86
81
// - only by calling Workspace::createClient()
87
82
// - it creates a new client and calls manage() for it
114
109
, m_transientForId(XCB_WINDOW_NONE)
115
110
, m_originalTransientForId(XCB_WINDOW_NONE)
116
111
, shade_below(NULL)
117
, skip_switcher(false)
118
112
, m_motif(atoms->motif_wm_hints)
119
113
, blocks_compositing(false)
120
114
, m_cursor(Qt::ArrowCursor)
121
, autoRaiseTimer(NULL)
122
115
, shadeHoverTimer(NULL)
123
116
, delayedMoveResizeTimer(NULL)
124
117
, m_colormap(XCB_COLORMAP_NONE)
134
127
, pending_geometry_update(PendingGeometryNone)
135
128
, shade_geometry_change(false)
136
129
, sm_stacking_order(-1)
137
, m_firstInTabBox(false)
138
130
, electricMaximizing(false)
139
131
, activitiesDefined(false)
140
132
, needsSessionInteract(false)
141
133
, needsXWindowMove(false)
142
134
, m_decoInputExtent()
143
135
, m_focusOutTimer(nullptr)
144
, m_colorScheme(QStringLiteral("kdeglobals"))
145
136
, m_clientSideDecorated(false)
147
138
// TODO: Do all as initialization
164
154
shade_mode = ShadeNone;
166
155
deleting = false;
169
156
fullscreen_mode = FullScreenNone;
170
skip_taskbar = false;
171
original_skip_taskbar = false;
175
159
noborder = false;
176
160
app_noborder = false;
177
161
ignore_focus_stealing = false;
178
demands_attention = false;
179
162
check_active_modal = false;
183
164
max_mode = MaximizeRestore;
185
166
//Client to workspace connections require that each
186
167
//client constructed be connected to the workspace wrapper
188
#ifdef KWIN_BUILD_TABBOX
190
m_tabBoxClient = QSharedPointer<TabBox::TabBoxClientImpl>(new TabBox::TabBoxClientImpl(this));
193
169
geom = QRect(0, 0, 100, 100); // So that decorations don't start with size being (0,0)
194
170
client_size = QSize(100, 100);
195
171
ready_for_painting = false; // wait for first damage or sync reply
197
173
connect(this, &Client::geometryShapeChanged, this, &Client::geometryChanged);
198
auto signalMaximizeChanged = static_cast<void (Client::*)(KWin::Client*, MaximizeMode)>(&Client::clientMaximizedStateChanged);
174
auto signalMaximizeChanged = static_cast<void (Client::*)(KWin::AbstractClient*, MaximizeMode)>(&Client::clientMaximizedStateChanged);
199
175
connect(this, signalMaximizeChanged, this, &Client::geometryChanged);
200
176
connect(this, &Client::clientStepUserMovedResized, this, &Client::geometryChanged);
201
177
connect(this, &Client::clientStartUserMovedResized, this, &Client::moveResizedChanged);
202
178
connect(this, &Client::clientFinishUserMovedResized, this, &Client::moveResizedChanged);
203
179
connect(this, &Client::clientStartUserMovedResized, this, &Client::removeCheckScreenConnection);
204
180
connect(this, &Client::clientFinishUserMovedResized, this, &Client::setupCheckScreenConnection);
181
connect(this, &Client::paletteChanged, this, &Client::triggerDecorationRepaint);
206
183
connect(clientMachine(), &ClientMachine::localhostChanged, this, &Client::updateCaption);
207
184
connect(options, &Options::condensedTitleChanged, this, &Client::updateCaption);
410
388
((m_decoration == NULL && noBorder()) || (m_decoration != NULL && !noBorder())))
412
390
QRect oldgeom = geometry();
391
QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom());
413
392
blockGeometryUpdates(true);
415
394
destroyDecoration();
435
414
connect(m_decoration, &KDecoration2::Decoration::bordersChanged, this,
437
416
GeometryUpdatesBlocker blocker(this);
438
move(calculateGravitation(true));
439
move(calculateGravitation(false));
417
// TODO: this is obviously idempotent
418
// calculateGravitation(true) would have to operate on the old border sizes
419
// move(calculateGravitation(true));
420
// move(calculateGravitation(false));
440
421
QRect oldgeom = geometry();
441
422
plainResize(sizeForClientSize(clientSize()), ForceGeometrySet);
442
checkWorkspacePosition(oldgeom);
424
checkWorkspacePosition(oldgeom);
443
425
emit geometryShapeChanged(this, oldgeom);
749
void Client::setMinimized(bool set)
751
set ? minimize() : unminimize();
755
* Minimizes this client plus its transients
757
void Client::minimize(bool avoid_animation)
759
if (!isMinimizable() || isMinimized())
762
if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
763
info->setState(0, NET::Shaded);
768
updateAllowedActions();
769
workspace()->updateMinimizedOfTransients(this);
770
updateWindowRules(Rules::Minimize);
771
FocusChain::self()->update(this, FocusChain::MakeFirstMinimized);
772
// TODO: merge signal with s_minimized
773
emit clientMinimized(this, !avoid_animation);
775
// Update states of all other windows in this group
777
tabGroup()->updateStates(this, TabGroup::Minimized);
778
emit minimizedChanged();
781
void Client::unminimize(bool avoid_animation)
786
if (rules()->checkMinimize(false)) {
790
if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
791
info->setState(NET::Shaded, NET::Shaded);
795
updateAllowedActions();
796
workspace()->updateMinimizedOfTransients(this);
797
updateWindowRules(Rules::Minimize);
798
emit clientUnminimized(this, !avoid_animation);
800
// Update states of all other windows in this group
802
tabGroup()->updateStates(this, TabGroup::Minimized);
803
emit minimizedChanged();
731
void Client::doMinimize()
734
updateAllowedActions();
735
workspace()->updateMinimizedOfTransients(this);
736
// Update states of all other windows in this group
738
tabGroup()->updateStates(this, TabGroup::Minimized);
806
741
QRect Client::iconGeometry() const
826
761
return !isSpecialWindow() && !noBorder() && (rules()->checkShade(ShadeNormal) != rules()->checkShade(ShadeNone));
829
void Client::setShade(bool set) {
830
set ? setShade(ShadeNormal) : setShade(ShadeNone);
833
764
void Client::setShade(ShadeMode mode)
835
766
if (mode == ShadeHover && isMove())
891
822
QSize s(sizeForClientSize(clientSize()));
892
823
shade_geometry_change = false;
825
geom_restore = geometry();
894
826
if ((shade_mode == ShadeHover || shade_mode == ShadeActivated) && rules()->checkAcceptFocus(info->input()))
896
828
if (shade_mode == ShadeHover) {
958
890
if (hidden && isCurrentTab()) {
959
891
info->setState(NET::Hidden, NET::Hidden);
960
setSkipTaskbar(true, false); // Also hide from taskbar
892
setSkipTaskbar(true); // Also hide from taskbar
961
893
if (compositing() && options->hiddenPreviews() == HiddenPreviewsAlways)
967
899
if (isCurrentTab())
968
setSkipTaskbar(original_skip_taskbar, false); // Reset from 'hidden'
900
setSkipTaskbar(originalSkipTaskbar()); // Reset from 'hidden'
970
902
info->setState(NET::Hidden, NET::Hidden);
971
903
if (compositing() && options->hiddenPreviews() == HiddenPreviewsAlways)
1266
void Client::setSkipTaskbar(bool b, bool from_outside)
1268
int was_wants_tab_focus = wantsTabFocus();
1270
b = rules()->checkSkipTaskbar(b);
1271
original_skip_taskbar = b;
1273
if (b == skipTaskbar())
1276
info->setState(b ? NET::SkipTaskbar : NET::States(0), NET::SkipTaskbar);
1277
updateWindowRules(Rules::SkipTaskbar);
1278
if (was_wants_tab_focus != wantsTabFocus())
1279
FocusChain::self()->update(this,
1280
isActive() ? FocusChain::MakeFirst : FocusChain::Update);
1281
emit skipTaskbarChanged();
1284
void Client::setSkipPager(bool b)
1286
b = rules()->checkSkipPager(b);
1287
if (b == skipPager())
1290
info->setState(b ? NET::SkipPager : NET::States(0), NET::SkipPager);
1291
updateWindowRules(Rules::SkipPager);
1292
emit skipPagerChanged();
1295
void Client::setSkipSwitcher(bool set)
1297
set = rules()->checkSkipSwitcher(set);
1298
if (set == skipSwitcher())
1300
skip_switcher = set;
1301
updateWindowRules(Rules::SkipSwitcher);
1302
emit skipSwitcherChanged();
1198
void Client::doSetSkipTaskbar()
1200
info->setState(skipTaskbar() ? NET::SkipTaskbar : NET::States(0), NET::SkipTaskbar);
1203
void Client::doSetSkipPager()
1205
info->setState(skipPager() ? NET::SkipPager : NET::States(0), NET::SkipPager);
1305
1208
void Client::setModal(bool m)
1313
1216
// _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
1316
void Client::setDesktop(int desktop)
1219
void Client::doSetDesktop(int desktop, int was_desk)
1318
const int numberOfDesktops = VirtualDesktopManager::self()->count();
1319
if (desktop != NET::OnAllDesktops) // Do range check
1320
desktop = qMax(1, qMin(numberOfDesktops, desktop));
1321
desktop = qMin(numberOfDesktops, rules()->checkDesktop(desktop));
1322
if (desk == desktop)
1325
int was_desk = desk;
1326
const bool wasOnCurrentDesktop = isOnCurrentDesktop();
1328
1221
info->setDesktop(desktop);
1329
1222
if ((was_desk == NET::OnAllDesktops) != (desktop == NET::OnAllDesktops)) {
1330
1223
// onAllDesktops changed
1344
1237
foreach (Client * c2, mainClients())
1345
1238
c2->setDesktop(desktop);
1348
FocusChain::self()->update(this, FocusChain::MakeFirst);
1349
1240
updateVisibility();
1350
updateWindowRules(Rules::Desktop);
1352
1242
// Update states of all other windows in this group
1353
1243
if (tabGroup())
1354
1244
tabGroup()->updateStates(this, TabGroup::Desktop);
1355
emit desktopChanged();
1356
if (wasOnCurrentDesktop != isOnCurrentDesktop())
1357
emit desktopPresenceChanged(this, was_desk);
1367
1254
void Client::setOnActivity(const QString &activity, bool enable)
1369
1256
#ifdef KWIN_BUILD_ACTIVITIES
1257
if (! Activities::self()) {
1370
1260
QStringList newActivitiesList = activities();
1371
1261
if (newActivitiesList.contains(activity) == enable) //nothing to do
1390
1280
void Client::setOnActivities(QStringList newActivitiesList)
1392
1282
#ifdef KWIN_BUILD_ACTIVITIES
1283
if (!Activities::self()) {
1393
1286
QString joinedActivitiesList = newActivitiesList.join(QStringLiteral(","));
1394
1287
joinedActivitiesList = rules()->checkActivity(joinedActivitiesList, false);
1395
1288
newActivitiesList = joinedActivitiesList.split(QStringLiteral(","), QString::SkipEmptyParts);
1475
1368
return activityList;
1478
void Client::setOnAllDesktops(bool b)
1480
if ((b && isOnAllDesktops()) ||
1481
(!b && !isOnAllDesktops()))
1484
setDesktop(NET::OnAllDesktops);
1486
setDesktop(VirtualDesktopManager::self()->current());
1488
// Update states of all other windows in this group
1490
tabGroup()->updateStates(this, TabGroup::Desktop);
1494
1372
* if @p on is true, sets on all activities.
1495
1373
* if it's false, sets it to only be on the current activity
1855
1733
void Client::getIcons()
1857
1735
// First read icons from the window itself
1859
auto readIcon = [this](int size, bool scale = true) {
1737
auto readIcon = [this, &icon](int size, bool scale = true) {
1860
1738
const QPixmap pix = KWindowSystem::icon(window(), size, size, scale, KWindowSystem::NETWM | KWindowSystem::WMHints, info);
1861
1739
if (!pix.isNull()) {
1862
m_icon.addPixmap(pix);
1740
icon.addPixmap(pix);
1867
1745
readIcon(48, false);
1868
1746
readIcon(64, false);
1869
1747
readIcon(128, false);
1870
if (m_icon.isNull()) {
1748
if (icon.isNull()) {
1871
1749
// Then try window group
1872
m_icon = group()->icon();
1750
icon = group()->icon();
1874
if (m_icon.isNull() && isTransient()) {
1752
if (icon.isNull() && isTransient()) {
1875
1753
// Then mainclients
1876
1754
ClientList mainclients = mainClients();
1877
1755
for (ClientList::ConstIterator it = mainclients.constBegin();
1878
it != mainclients.constEnd() && m_icon.isNull();
1756
it != mainclients.constEnd() && icon.isNull();
1880
1758
if (!(*it)->icon().isNull()) {
1881
m_icon = (*it)->icon();
1759
icon = (*it)->icon();
1886
if (m_icon.isNull()) {
1764
if (icon.isNull()) {
1887
1765
// And if nothing else, load icon from classhint or xapp icon
1888
m_icon.addPixmap(KWindowSystem::icon(window(), 32, 32, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1889
m_icon.addPixmap(KWindowSystem::icon(window(), 16, 16, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1890
m_icon.addPixmap(KWindowSystem::icon(window(), 64, 64, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1891
m_icon.addPixmap(KWindowSystem::icon(window(), 128, 128, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1766
icon.addPixmap(KWindowSystem::icon(window(), 32, 32, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1767
icon.addPixmap(KWindowSystem::icon(window(), 16, 16, true, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1768
icon.addPixmap(KWindowSystem::icon(window(), 64, 64, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1769
icon.addPixmap(KWindowSystem::icon(window(), 128, 128, false, KWindowSystem::ClassHint | KWindowSystem::XApp, info));
1896
1774
void Client::getSyncCounter()
1899
1776
if (!Xcb::Extensions::self()->isSyncAvailable())
1984
1861
syncRequest.lastTimestamp = xTime();
1987
bool Client::wantsTabFocus() const
1989
return (isNormalWindow() || isDialog()) && wantsInput();
1992
1864
bool Client::wantsInput() const
1994
1866
return rules()->checkAcceptFocus(info->input() || info->supportsProtocol(NET::TakeFocusProtocol));
1997
bool Client::isSpecialWindow() const
2000
return isDesktop() || isDock() || isSplash() || isToolbar() || isNotification() || isOnScreenDisplay();
2004
1870
* Sets an appropriate cursor shape for the logical mouse position \a m
2185
2038
//if the activities are not synced, and there are existing clients with
2186
2039
//activities specified, somebody has restarted kwin. we can not validate
2187
2040
//activities in this case. we need to trust the old values.
2188
if (Activities::self()->serviceStatus() != KActivities::Consumer::Unknown) {
2041
if (Activities::self() && Activities::self()->serviceStatus() != KActivities::Consumer::Unknown) {
2189
2042
QStringList allActivities = Activities::self()->all();
2190
2043
if (allActivities.isEmpty()) {
2191
2044
qCDebug(KWIN_CORE) << "no activities!?!?";
2225
2078
return QRect(0, 0, width(), height());
2228
Client::Position Client::titlebarPosition() const
2230
// TODO: still needed, remove?
2234
2081
Xcb::Property Client::fetchFirstInTabBox() const
2236
2083
return Xcb::Property(false, m_client, atoms->kde_first_in_window_list,
2257
2104
void Client::readColorScheme(Xcb::StringProperty &property)
2259
QString path = QString::fromUtf8(property);
2260
path = rules()->checkDecoColor(path);
2262
if (path.isEmpty()) {
2263
path = QStringLiteral("kdeglobals");
2266
if (!m_palette || m_colorScheme != path) {
2267
m_colorScheme = path;
2270
disconnect(m_palette.get(), &Decoration::DecorationPalette::changed, this, &Client::handlePaletteChange);
2273
auto it = s_palettes.find(m_colorScheme);
2275
if (it == s_palettes.end() || it->expired()) {
2276
m_palette = std::make_shared<Decoration::DecorationPalette>(m_colorScheme);
2277
if (m_palette->isValid()) {
2278
s_palettes[m_colorScheme] = m_palette;
2280
if (!s_defaultPalette) {
2281
s_defaultPalette = std::make_shared<Decoration::DecorationPalette>(QStringLiteral("kdeglobals"));
2282
s_palettes[QStringLiteral("kdeglobals")] = s_defaultPalette;
2285
m_palette = s_defaultPalette;
2288
if (m_colorScheme == QStringLiteral("kdeglobals")) {
2289
s_defaultPalette = m_palette;
2292
m_palette = it->lock();
2295
connect(m_palette.get(), &Decoration::DecorationPalette::changed, this, &Client::handlePaletteChange);
2297
emit paletteChanged(palette());
2298
triggerDecorationRepaint();
2106
AbstractClient::updateColorScheme(rules()->checkDecoColor(QString::fromUtf8(property)));
2302
2109
void Client::updateColorScheme()
2433
2234
void Client::addDamage(const QRegion &damage)
2435
2236
if (!ready_for_painting) { // avoid "setReadyForPainting()" function calling overhead
2436
if (syncRequest.counter == XCB_NONE) // cannot detect complete redraw, consider done now
2237
if (syncRequest.counter == XCB_NONE) { // cannot detect complete redraw, consider done now
2437
2238
setReadyForPainting();
2239
setupWindowManagementInterface();
2439
2242
Toplevel::addDamage(damage);
2245
bool Client::belongsToSameApplication(const AbstractClient *other, bool active_hack) const
2247
const Client *c2 = dynamic_cast<const Client*>(other);
2251
return Client::belongToSameApplication(this, c2, active_hack);
2254
bool Client::processDecorationButtonPress(QMouseEvent *event)
2256
return processDecorationButtonPress(qtToX11Button(event->button()), 0,
2257
event->x(), event->y(),
2258
event->globalX(), event->globalY());
2261
void Client::processDecorationButtonRelease(QMouseEvent *event)
2264
if (!event->isAccepted() && m_decoration->titleBar().contains(event->pos()) && event->button() == Qt::LeftButton) {
2265
m_decorationDoubleClickTimer.start();
2269
if (event->buttons() == Qt::NoButton) {
2271
stopDelayedMoveResize();
2272
if (moveResizeMode) {
2273
finishMoveResize(false);
2274
mode = mousePosition();
2280
void Client::processDecorationMove()
2285
// TODO: handle modifiers
2286
Position newmode = mousePosition();
2287
if (newmode != mode) {
2444
2295
#include "client.moc"