mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 17:05:59 +01:00
Added IHyprWindowDecoration and Group Bars
This commit is contained in:
parent
b1b24cb21a
commit
bdf1c16195
11 changed files with 248 additions and 5 deletions
|
@ -13,4 +13,7 @@ CWindow::~CWindow() {
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
g_pCompositor->m_pLastWindow = nullptr;
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& wd : m_dWindowDecorations)
|
||||||
|
delete wd;
|
||||||
}
|
}
|
|
@ -4,6 +4,8 @@
|
||||||
#include "events/Events.hpp"
|
#include "events/Events.hpp"
|
||||||
#include "helpers/SubsurfaceTree.hpp"
|
#include "helpers/SubsurfaceTree.hpp"
|
||||||
#include "helpers/AnimatedVariable.hpp"
|
#include "helpers/AnimatedVariable.hpp"
|
||||||
|
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
struct SWindowSpecialRenderData {
|
struct SWindowSpecialRenderData {
|
||||||
float alpha = 1.f;
|
float alpha = 1.f;
|
||||||
|
@ -88,6 +90,9 @@ public:
|
||||||
// For hidden windows and stuff
|
// For hidden windows and stuff
|
||||||
bool m_bHidden = false;
|
bool m_bHidden = false;
|
||||||
|
|
||||||
|
// Window decorations
|
||||||
|
std::deque<IHyprWindowDecoration*> m_dWindowDecorations;
|
||||||
|
|
||||||
// Special render data, rules, etc
|
// Special render data, rules, etc
|
||||||
SWindowSpecialRenderData m_sSpecialRenderData;
|
SWindowSpecialRenderData m_sSpecialRenderData;
|
||||||
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
SWindowAdditionalConfigData m_sAdditionalConfigData;
|
||||||
|
|
|
@ -275,6 +275,10 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) {
|
||||||
|
|
||||||
if (OPENINGON->pGroupParent) {
|
if (OPENINGON->pGroupParent) {
|
||||||
// means we opened on a group
|
// means we opened on a group
|
||||||
|
|
||||||
|
// add the group deco
|
||||||
|
pWindow->m_dWindowDecorations.emplace_back(new CHyprGroupBarDecoration(pWindow));
|
||||||
|
|
||||||
PNODE->pGroupParent = OPENINGON->pGroupParent;
|
PNODE->pGroupParent = OPENINGON->pGroupParent;
|
||||||
PNODE->pGroupParent->groupMembers.push_back(PNODE);
|
PNODE->pGroupParent->groupMembers.push_back(PNODE);
|
||||||
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
|
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
|
||||||
|
@ -693,6 +697,10 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||||
for (auto& node : PGROUPPARENT->groupMembers) {
|
for (auto& node : PGROUPPARENT->groupMembers) {
|
||||||
node->pGroupParent = nullptr;
|
node->pGroupParent = nullptr;
|
||||||
node->pWindow->m_cRealBorderColor.setValueAndWarp(INACTIVEBORDERCOL); // no anim here because they pop in
|
node->pWindow->m_cRealBorderColor.setValueAndWarp(INACTIVEBORDERCOL); // no anim here because they pop in
|
||||||
|
|
||||||
|
for (auto& wd : node->pWindow->m_dWindowDecorations) {
|
||||||
|
wd->updateWindow(node->pWindow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PGROUPPARENT->groupMembers.clear();
|
PGROUPPARENT->groupMembers.clear();
|
||||||
|
@ -725,6 +733,8 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||||
c->pGroupParent = PPARENT;
|
c->pGroupParent = PPARENT;
|
||||||
c->pWindow->m_cRealBorderColor = GROUPINACTIVEBORDERCOL;
|
c->pWindow->m_cRealBorderColor = GROUPINACTIVEBORDERCOL;
|
||||||
|
|
||||||
|
c->pWindow->m_dWindowDecorations.push_back(new CHyprGroupBarDecoration(c->pWindow));
|
||||||
|
|
||||||
if (c->pWindow == g_pCompositor->m_pLastWindow)
|
if (c->pWindow == g_pCompositor->m_pLastWindow)
|
||||||
c->pWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active"));
|
c->pWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active"));
|
||||||
}
|
}
|
||||||
|
@ -735,6 +745,31 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
|
||||||
|
|
||||||
|
std::deque<CWindow*> result;
|
||||||
|
|
||||||
|
if (!g_pCompositor->windowExists(pWindow))
|
||||||
|
return result; // reject with empty
|
||||||
|
|
||||||
|
// get the node
|
||||||
|
const auto PNODE = getNodeFromWindow(pWindow);
|
||||||
|
|
||||||
|
if (!PNODE)
|
||||||
|
return result; // reject with empty
|
||||||
|
|
||||||
|
const auto PGROUPPARENT = PNODE->pGroupParent;
|
||||||
|
|
||||||
|
if (!PGROUPPARENT)
|
||||||
|
return result; // reject with empty
|
||||||
|
|
||||||
|
for (auto& node : PGROUPPARENT->groupMembers) {
|
||||||
|
result.push_back(node->pWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
||||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||||
return; // reject
|
return; // reject
|
||||||
|
@ -760,6 +795,12 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
||||||
|
|
||||||
PNODE->pGroupParent->recalcSizePosRecursive();
|
PNODE->pGroupParent->recalcSizePosRecursive();
|
||||||
|
|
||||||
|
for (auto& gm : PNODE->pGroupParent->groupMembers) {
|
||||||
|
for (auto& deco : gm->pWindow->m_dWindowDecorations) {
|
||||||
|
deco->updateWindow(gm->pWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// focus
|
// focus
|
||||||
g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow);
|
g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow);
|
||||||
}
|
}
|
||||||
|
@ -850,7 +891,7 @@ void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||||
PNODE->pParent->recalcSizePosRecursive();
|
PNODE->pParent->recalcSizePosRecursive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
|
std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
|
||||||
if (message == "togglegroup")
|
if (message == "togglegroup")
|
||||||
toggleWindowGroup(header.pWindow);
|
toggleWindowGroup(header.pWindow);
|
||||||
else if (message == "changegroupactivef")
|
else if (message == "changegroupactivef")
|
||||||
|
@ -859,6 +900,12 @@ void CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::string
|
||||||
switchGroupWindow(header.pWindow, false);
|
switchGroupWindow(header.pWindow, false);
|
||||||
else if (message == "togglesplit")
|
else if (message == "togglesplit")
|
||||||
toggleSplit(header.pWindow);
|
toggleSplit(header.pWindow);
|
||||||
|
else if (message == "groupinfo") {
|
||||||
|
auto res = getGroupMembers(g_pCompositor->m_pLastWindow);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
|
void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
|
||||||
|
@ -871,3 +918,7 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
|
||||||
|
|
||||||
PNODE->pParent->recalcSizePosRecursive();
|
PNODE->pParent->recalcSizePosRecursive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CHyprDwindleLayout::getLayoutName() {
|
||||||
|
return "dwindle";
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include "IHyprLayout.hpp"
|
#include "IHyprLayout.hpp"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||||
|
|
||||||
class CHyprDwindleLayout;
|
class CHyprDwindleLayout;
|
||||||
|
|
||||||
|
@ -50,10 +51,11 @@ public:
|
||||||
virtual void onMouseMove(const Vector2D&);
|
virtual void onMouseMove(const Vector2D&);
|
||||||
virtual void onWindowCreatedFloating(CWindow*);
|
virtual void onWindowCreatedFloating(CWindow*);
|
||||||
virtual void fullscreenRequestForWindow(CWindow*);
|
virtual void fullscreenRequestForWindow(CWindow*);
|
||||||
virtual void layoutMessage(SLayoutMessageHeader, std::string);
|
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||||
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||||
virtual void switchWindows(CWindow*, CWindow*);
|
virtual void switchWindows(CWindow*, CWindow*);
|
||||||
virtual void alterSplitRatioBy(CWindow*, float);
|
virtual void alterSplitRatioBy(CWindow*, float);
|
||||||
|
virtual std::string getLayoutName();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ public:
|
||||||
void toggleWindowGroup(CWindow*);
|
void toggleWindowGroup(CWindow*);
|
||||||
void switchGroupWindow(CWindow*, bool forward);
|
void switchGroupWindow(CWindow*, bool forward);
|
||||||
void toggleSplit(CWindow*);
|
void toggleSplit(CWindow*);
|
||||||
|
std::deque<CWindow*> getGroupMembers(CWindow*);
|
||||||
|
|
||||||
friend struct SDwindleNodeData;
|
friend struct SDwindleNodeData;
|
||||||
};
|
};
|
|
@ -75,8 +75,9 @@ public:
|
||||||
/*
|
/*
|
||||||
Called when a dispatcher requests a custom message
|
Called when a dispatcher requests a custom message
|
||||||
The layout is free to ignore.
|
The layout is free to ignore.
|
||||||
|
std::any is the reply. Can be empty.
|
||||||
*/
|
*/
|
||||||
virtual void layoutMessage(SLayoutMessageHeader, std::string) = 0;
|
virtual std::any layoutMessage(SLayoutMessageHeader, std::string) = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Required to be handled, but may return just SWindowRenderLayoutHints()
|
Required to be handled, but may return just SWindowRenderLayoutHints()
|
||||||
|
@ -96,4 +97,9 @@ public:
|
||||||
on a window
|
on a window
|
||||||
*/
|
*/
|
||||||
virtual void alterSplitRatioBy(CWindow*, float) = 0;
|
virtual void alterSplitRatioBy(CWindow*, float) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when something wants the current layout's name
|
||||||
|
*/
|
||||||
|
virtual std::string getLayoutName() = 0;
|
||||||
};
|
};
|
|
@ -140,8 +140,12 @@ void CAnimationManager::tick() {
|
||||||
case AVARDAMAGE_ENTIRE: {
|
case AVARDAMAGE_ENTIRE: {
|
||||||
g_pHyprRenderer->damageBox(&WLRBOXPREV);
|
g_pHyprRenderer->damageBox(&WLRBOXPREV);
|
||||||
|
|
||||||
if (PWINDOW)
|
if (PWINDOW) {
|
||||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||||
|
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||||
|
wd->updateWindow(PWINDOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AVARDAMAGE_BORDER: {
|
case AVARDAMAGE_BORDER: {
|
||||||
|
|
|
@ -109,6 +109,10 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
|
||||||
|
|
||||||
g_pHyprOpenGL->m_pCurrentWindow = pWindow;
|
g_pHyprOpenGL->m_pCurrentWindow = pWindow;
|
||||||
|
|
||||||
|
// render window decorations first
|
||||||
|
for (auto& wd : pWindow->m_dWindowDecorations)
|
||||||
|
wd->draw(pMonitor);
|
||||||
|
|
||||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
|
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
|
||||||
|
|
||||||
if (pWindow->m_bIsX11) {
|
if (pWindow->m_bIsX11) {
|
||||||
|
|
99
src/render/decorations/CHyprGroupBarDecoration.cpp
Normal file
99
src/render/decorations/CHyprGroupBarDecoration.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include "CHyprGroupBarDecoration.hpp"
|
||||||
|
#include "../../Compositor.hpp"
|
||||||
|
|
||||||
|
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) {
|
||||||
|
m_pWindow = pWindow;
|
||||||
|
updateWindow(pWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents CHyprGroupBarDecoration::getWindowDecorationExtents() {
|
||||||
|
return m_seExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
eDecorationType CHyprGroupBarDecoration::getDecorationType() {
|
||||||
|
return DECORATION_GROUPBAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
|
||||||
|
damageEntire();
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
|
|
||||||
|
if (pWindow->m_vRealPosition.vec() != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) {
|
||||||
|
// we draw 3px above the window's border with 3px
|
||||||
|
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
|
||||||
|
|
||||||
|
m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3);
|
||||||
|
m_seExtents.bottomRight = Vector2D();
|
||||||
|
|
||||||
|
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||||
|
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's check if the window group is different.
|
||||||
|
|
||||||
|
if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle") {
|
||||||
|
// ????
|
||||||
|
for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) {
|
||||||
|
if ((*it) == this) {
|
||||||
|
pWindow->m_dWindowDecorations.erase(it);
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the group info
|
||||||
|
SLayoutMessageHeader header;
|
||||||
|
header.pWindow = g_pCompositor->m_pLastWindow;
|
||||||
|
|
||||||
|
m_dwGroupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
|
||||||
|
|
||||||
|
damageEntire();
|
||||||
|
|
||||||
|
if (m_dwGroupMembers.size() == 0) {
|
||||||
|
// remove
|
||||||
|
for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) {
|
||||||
|
if ((*it) == this) {
|
||||||
|
pWindow->m_dWindowDecorations.erase(it);
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprGroupBarDecoration::damageEntire() {
|
||||||
|
wlr_box dm = {m_vLastWindowPos.x - m_seExtents.topLeft.x, m_vLastWindowPos.y - m_seExtents.topLeft.y, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, m_seExtents.topLeft.y};
|
||||||
|
g_pHyprRenderer->damageBox(&dm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) {
|
||||||
|
// get how many bars we will draw
|
||||||
|
int barsToDraw = m_dwGroupMembers.size();
|
||||||
|
|
||||||
|
if (barsToDraw < 1 || m_pWindow->m_bHidden || !g_pCompositor->windowValidMapped(m_pWindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int PAD = 2; //2px
|
||||||
|
|
||||||
|
const int BARW = (m_vLastWindowSize.x - PAD * (barsToDraw - 1)) / barsToDraw;
|
||||||
|
|
||||||
|
int xoff = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < barsToDraw; ++i) {
|
||||||
|
wlr_box rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x, m_vLastWindowPos.y - m_seExtents.topLeft.y - pMonitor->vecPosition.y, BARW, 3};
|
||||||
|
|
||||||
|
if (rect.width <= 0 || rect.height <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border"));
|
||||||
|
g_pHyprOpenGL->renderRect(&rect, color);
|
||||||
|
|
||||||
|
xoff += PAD + BARW;
|
||||||
|
}
|
||||||
|
}
|
30
src/render/decorations/CHyprGroupBarDecoration.hpp
Normal file
30
src/render/decorations/CHyprGroupBarDecoration.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IHyprWindowDecoration.hpp"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
class CHyprGroupBarDecoration : public IHyprWindowDecoration {
|
||||||
|
public:
|
||||||
|
CHyprGroupBarDecoration(CWindow*);
|
||||||
|
virtual ~CHyprGroupBarDecoration();
|
||||||
|
|
||||||
|
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
||||||
|
|
||||||
|
virtual void draw(SMonitor*);
|
||||||
|
|
||||||
|
virtual eDecorationType getDecorationType();
|
||||||
|
|
||||||
|
virtual void updateWindow(CWindow*);
|
||||||
|
|
||||||
|
virtual void damageEntire();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SWindowDecorationExtents m_seExtents;
|
||||||
|
|
||||||
|
CWindow* m_pWindow = nullptr;
|
||||||
|
|
||||||
|
Vector2D m_vLastWindowPos;
|
||||||
|
Vector2D m_vLastWindowSize;
|
||||||
|
|
||||||
|
std::deque<CWindow*> m_dwGroupMembers;
|
||||||
|
};
|
7
src/render/decorations/IHyprWindowDecoration.cpp
Normal file
7
src/render/decorations/IHyprWindowDecoration.cpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include "IHyprWindowDecoration.hpp"
|
||||||
|
|
||||||
|
#include "../../Window.hpp"
|
||||||
|
|
||||||
|
IHyprWindowDecoration::~IHyprWindowDecoration() {
|
||||||
|
|
||||||
|
}
|
31
src/render/decorations/IHyprWindowDecoration.hpp
Normal file
31
src/render/decorations/IHyprWindowDecoration.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../defines.hpp"
|
||||||
|
|
||||||
|
enum eDecorationType {
|
||||||
|
DECORATION_NONE = -1,
|
||||||
|
DECORATION_GROUPBAR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SWindowDecorationExtents {
|
||||||
|
Vector2D topLeft;
|
||||||
|
Vector2D bottomRight;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWindow;
|
||||||
|
struct SMonitor;
|
||||||
|
|
||||||
|
class IHyprWindowDecoration {
|
||||||
|
public:
|
||||||
|
virtual ~IHyprWindowDecoration() = 0;
|
||||||
|
|
||||||
|
virtual SWindowDecorationExtents getWindowDecorationExtents() = 0;
|
||||||
|
|
||||||
|
virtual void draw(SMonitor*) = 0;
|
||||||
|
|
||||||
|
virtual eDecorationType getDecorationType() = 0;
|
||||||
|
|
||||||
|
virtual void updateWindow(CWindow*) = 0;
|
||||||
|
|
||||||
|
virtual void damageEntire() = 0;
|
||||||
|
};
|
Loading…
Reference in a new issue