File indexing completed on 2024-11-10 04:57:45

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
0006     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "group.h"
0012 #include "effect/effecthandler.h"
0013 #include "workspace.h"
0014 #include "x11window.h"
0015 
0016 #include <KX11Extras>
0017 #include <QDebug>
0018 
0019 namespace KWin
0020 {
0021 
0022 //********************************************
0023 // Group
0024 //********************************************
0025 
0026 Group::Group(xcb_window_t leader_P)
0027     : leader_client(nullptr)
0028     , leader_wid(leader_P)
0029     , leader_info(nullptr)
0030     , user_time(-1U)
0031     , refcount(0)
0032 {
0033     if (leader_P != XCB_WINDOW_NONE) {
0034         leader_client = workspace()->findClient(Predicate::WindowMatch, leader_P);
0035         leader_info = std::make_unique<NETWinInfo>(kwinApp()->x11Connection(), leader_P, kwinApp()->x11RootWindow(),
0036                                                    NET::Properties(), NET::WM2StartupId);
0037     }
0038     effect_group = std::make_unique<EffectWindowGroup>(this);
0039     workspace()->addGroup(this);
0040 }
0041 
0042 Group::~Group() = default;
0043 
0044 QIcon Group::icon() const
0045 {
0046     if (leader_client != nullptr) {
0047         return leader_client->icon();
0048     } else if (leader_wid != XCB_WINDOW_NONE) {
0049         QIcon ic;
0050         NETWinInfo info(kwinApp()->x11Connection(), leader_wid, kwinApp()->x11RootWindow(), NET::WMIcon, NET::WM2IconPixmap);
0051         auto readIcon = [&ic, &info, this](int size, bool scale = true) {
0052             const QPixmap pix = KX11Extras::icon(leader_wid, size, size, scale, KX11Extras::NETWM | KX11Extras::WMHints, &info);
0053             if (!pix.isNull()) {
0054                 ic.addPixmap(pix);
0055             }
0056         };
0057         readIcon(16);
0058         readIcon(32);
0059         readIcon(48, false);
0060         readIcon(64, false);
0061         readIcon(128, false);
0062         return ic;
0063     }
0064     return QIcon();
0065 }
0066 
0067 void Group::addMember(X11Window *member_P)
0068 {
0069     _members.append(member_P);
0070     //    qDebug() << "GROUPADD:" << this << ":" << member_P;
0071     //    qDebug() << kBacktrace();
0072 }
0073 
0074 void Group::removeMember(X11Window *member_P)
0075 {
0076     //    qDebug() << "GROUPREMOVE:" << this << ":" << member_P;
0077     //    qDebug() << kBacktrace();
0078     Q_ASSERT(_members.contains(member_P));
0079     _members.removeAll(member_P);
0080     // there are cases when automatic deleting of groups must be delayed,
0081     // e.g. when removing a member and doing some operation on the possibly
0082     // other members of the group (which would be however deleted already
0083     // if there were no other members)
0084     if (refcount == 0 && _members.isEmpty()) {
0085         workspace()->removeGroup(this);
0086         delete this;
0087     }
0088 }
0089 
0090 void Group::ref()
0091 {
0092     ++refcount;
0093 }
0094 
0095 void Group::deref()
0096 {
0097     if (--refcount == 0 && _members.isEmpty()) {
0098         workspace()->removeGroup(this);
0099         delete this;
0100     }
0101 }
0102 
0103 void Group::gotLeader(X11Window *leader_P)
0104 {
0105     Q_ASSERT(leader_P->window() == leader_wid);
0106     leader_client = leader_P;
0107 }
0108 
0109 void Group::lostLeader()
0110 {
0111     Q_ASSERT(!_members.contains(leader_client));
0112     leader_client = nullptr;
0113     if (_members.isEmpty()) {
0114         workspace()->removeGroup(this);
0115         delete this;
0116     }
0117 }
0118 
0119 } // namespace