Wayland cOMPositor written in C++ using Louvre.

[feat] 0.2.0 added minimize to top bar for apps

Sunglas 295ce004 f3fa7dde

+321 -10
+2 -1
src/WCompositor.cpp
··· 51 51 { 52 52 return new WOutput; 53 53 } 54 - fn WCompositor::createSurfaceRequest(Handle<LSurface::Params> params) noexcept -> Handle<LSurface> 54 + fn WCompositor::createSurfaceRequest(Handle<LSurface::Params> params) noexcept 55 + -> Handle<LSurface> 55 56 { 56 57 return new WSurface(params); 57 58 }
+2 -1
src/WCompositor.hpp
··· 23 23 24 24 // virtual constructors 25 25 fn createOutputRequest() noexcept -> Handle<LOutput> override; 26 - fn createSurfaceRequest(Handle<LSurface::Params> params) noexcept -> Handle<LSurface> override; 26 + fn createSurfaceRequest(Handle<LSurface::Params> params) noexcept 27 + -> Handle<LSurface> override; 27 28 28 29 // scene and layers 29 30 LScene scene;
+10
src/WOutput.cpp
··· 9 9 * ======================================================================== */ 10 10 #include "WOutput.hpp" 11 11 #include "WCompositor.hpp" 12 + #include "WSurface.hpp" 12 13 #include "WTopBar.hpp" 13 14 #include "global.hpp" 14 15 #include "prelude.hpp" ··· 91 92 92 93 void WOutput::uninitializeGL() noexcept 93 94 { 95 + /* 96 + * set minimized output to nullptr to prevent the compositor from 97 + * crashing when a surface is unminimized and 98 + * WSurface::minimizeChanged() is triggered 99 + */ 100 + for (let surface : G::surfaces()) 101 + if (surface->minimizedOutput == this) 102 + surface->minimizedOutput = nullptr; 103 + 94 104 G::scene()->handleUninitializeGL(this); 95 105 96 106 if (wallpaperView->texture())
+164 -7
src/WSurface.cpp
··· 8 8 * 9 9 * ======================================================================== */ 10 10 #include "WSurface.hpp" 11 - #include "prelude.hpp" 12 - #include "global.hpp" 13 11 #include "WCompositor.hpp" 12 + #include "WOutput.hpp" 13 + #include "WTopBarItem.hpp" 14 + #include "global.hpp" 15 + #include "prelude.hpp" 14 16 #include <LCursor.h> 17 + #include <LSceneView.h> 15 18 19 + WSurface::WSurface(Handle<Params> params) noexcept 20 + : LSurface(params), view(this, &G::compositor()->surfacesLayer) 21 + { 22 + view.enableParentOffset(false); 23 + } 16 24 17 - WSurface::WSurface(Handle<Params> params) noexcept : LSurface(params), 18 - view(this, &G::compositor()->surfacesLayer) 25 + WSurface::~WSurface() noexcept 19 26 { 20 - view.enableParentOffset(false); 27 + // destroy thumbnails 28 + while (not topBarItems.empty()) 29 + delete topBarItems.back(); 30 + 31 + // destroy thumbnail texture 32 + if (thumbnail != nullptr) 33 + delete thumbnail; 21 34 } 22 35 23 36 void WSurface::roleChanged() noexcept ··· 26 39 if (cursorRole()) { 27 40 view.setVisible(false); 28 41 29 - } else if (dndIcon()) { // move drag & drop icons to the cursor layer so they always appear above other views 42 + } else if (dndIcon()) { // move drag & drop icons to the cursor layer so 43 + // they always appear above other views 30 44 // ensure it is positioned behind 'softwareCursor' 31 45 view.setParent(&G::compositor()->cursorLayer); 32 46 view.insertAfter(nullptr, false); ··· 46 60 // view after prev's view 47 61 if (prev != nullptr) { 48 62 view.insertAfter(&prev->view, false); 49 - } else { // if there is no prev surface, insert it at the beginning of the current parent's children list 63 + } else { // if there is no prev surface, insert it at the beginning of 64 + // the current parent's children list 50 65 view.insertAfter(nullptr, false); 51 66 } 52 67 } 68 + 69 + void WSurface::minimizedChanged() noexcept 70 + { 71 + // remove pointer and keyboard focus 72 + if (minimized()) { 73 + if (hasPointerFocus()) 74 + seat()->pointer()->setFocus(nullptr); 75 + 76 + if (hasKeyboardFocus()) 77 + seat()->keyboard()->setFocus(nullptr); 78 + } 79 + 80 + /* 81 + * When a surface is minimized, all its children are also minimized. 82 + * We only want to display toplevels in the top bar so we ignore the 83 + * rest. 84 + */ 85 + 86 + if (not toplevel()) { 87 + view.setVisible(not minimized()); 88 + return; 89 + } 90 + 91 + if (minimized()) { 92 + // find the output where the surface is currently most visible 93 + minimizedOutput = primaryOutput(); 94 + 95 + if (minimizedOutput != nullptr) { 96 + /* 97 + * Save the current surface position relative to the 98 + * output position as a percentage so we can restore it 99 + * later even if the outputs arrangement changes or the 100 + * given output is no longer available. 101 + */ 102 + let localPos = rolePos() - minimizedOutput->pos(); 103 + prevMinimizedPos = 104 + localPos / LSizeF(minimizedOutput->size()); 105 + } else { 106 + /* 107 + * In case the surface is not visible on any output, we 108 + * select the first available output and position the 109 + * surface 1/4 of the output as a fallback. 110 + */ 111 + minimizedOutput = G::outputs().front(); 112 + prevMinimizedPos = LPointF(0.25f, 0.25f); 113 + } 114 + 115 + var tmpScene = LSceneView(sizeB(), bufferScale()); 116 + capture(&tmpScene); 117 + 118 + // scale it to the thumbnail size 119 + thumbnail = tmpScene.texture()->copyB( 120 + LSize((THUMBNAIL_HEIGHT * sizeB().w()) / sizeB().h(), 121 + THUMBNAIL_HEIGHT) * 122 + 2); 123 + 124 + // create a top bar item for each top bar 125 + for (let output : G::outputs()) 126 + new WTopBarItem(output->topBar.get(), this); 127 + } else { 128 + // if minimized output is nullptr, it's because it was 129 + // uninitialized while the surface was minimized 130 + if (minimizedOutput == nullptr) { 131 + minimizedOutput = G::outputs().front(); 132 + prevMinimizedPos = LPointF(0.25f, 0.25f); 133 + } 134 + 135 + // destroy thumbnails 136 + while (not topBarItems.empty()) 137 + delete topBarItems.front(); 138 + 139 + // restory back the previous unminimized position 140 + setPos(minimizedOutput->pos() + 141 + (prevMinimizedPos * minimizedOutput->size())); 142 + minimizedOutput = nullptr; 143 + view.setVisible(true); 144 + 145 + // stack the surface above the rest 146 + raise(); 147 + } 148 + } 149 + 150 + fn WSurface::primaryOutput() const noexcept -> Handle<WOutput> 151 + { 152 + var bestOutput = Handle<WOutput>(nullptr); 153 + var bestArea = 0; 154 + var surfaceRect = LRect(); 155 + 156 + // ignore the decoration of toplevel and pop-up roles 157 + if (toplevel()) 158 + surfaceRect = 159 + LRect(rolePos() + toplevel()->windowGeometry().pos(), 160 + toplevel()->windowGeometry().size()); 161 + else if (popup()) 162 + surfaceRect = LRect(rolePos() + popup()->windowGeometry().pos(), 163 + popup()->windowGeometry().size()); 164 + else 165 + surfaceRect = LRect(rolePos(), size()); 166 + 167 + /* 168 + * Calculate the area of the surface intersected with each output and 169 + * return the one with the largest area 170 + */ 171 + for (let output : G::outputs()) { 172 + // we use LRegion to intersect both rects 173 + var tmpRegion = LRegion(); 174 + tmpRegion.addRect(surfaceRect); 175 + tmpRegion.clip(output->rect()); 176 + 177 + let extents = tmpRegion.extents(); 178 + let area = 179 + (extents.x2 - extents.x1) * (extents.y2 - extents.y1); 180 + 181 + if (area > bestArea) { 182 + bestArea = area; 183 + bestOutput = output; 184 + } 185 + } 186 + 187 + return bestOutput; 188 + } 189 + 190 + void WSurface::capture(Handle<LSceneView> sceneView) 191 + { 192 + /* 193 + * Instead of moving each view to the sceneView, we move the scene to 194 + * the views' position. This is why disabling parent offset is required. 195 + */ 196 + sceneView->setPos(rolePos()); 197 + 198 + /* 199 + * Add the view and any child subsurface view to the scene. Notice that 200 + * we exclude child surfaces with the popup or toplevel roles. 201 + */ 202 + G::moveSurfaceWithChildren(this, sceneView, subSurfacesOnly::on); 203 + sceneView->render(); 204 + 205 + // restore views to the surface layer 206 + while (not sceneView->children().empty()) 207 + sceneView->children().front()->setParent( 208 + &G::compositor()->surfacesLayer); 209 + }
+22
src/WSurface.hpp
··· 14 14 15 15 using namespace Louvre; 16 16 17 + class WTopBarItem; 18 + class WOutput; 19 + 17 20 class WSurface : public LSurface { 18 21 public: 19 22 WSurface(Handle<LSurface::Params> params) noexcept; 23 + ~WSurface() noexcept; 20 24 21 25 void roleChanged() noexcept override; 22 26 void orderChanged() noexcept override; 27 + void minimizedChanged() noexcept override; 28 + 29 + // return the output where the surface is currently the most visible 30 + fn primaryOutput() const noexcept -> Handle<WOutput>; 31 + 32 + // take a snapshot of the surface, including its subsurfaces 33 + void capture(Handle<LSceneView> sceneView); 23 34 24 35 LSurfaceView view; 36 + 37 + // a single thumbnail texture shared by all top bar items 38 + Handle<LTexture> thumbnail = nullptr; 39 + 40 + // list of thumbnail views, one for each output's topbar 41 + std::list<Handle<WTopBarItem>> topBarItems; 42 + 43 + // the output where the surface was most visible before being minimized 44 + Handle<WOutput> minimizedOutput = nullptr; 45 + 46 + LPointF prevMinimizedPos; 25 47 };
+20
src/WTopBar.cpp
··· 10 10 #include "WTopBar.hpp" 11 11 #include "WCompositor.hpp" 12 12 #include "WOutput.hpp" 13 + #include "WTopBarItem.hpp" 13 14 #include "global.hpp" 14 15 15 16 WTopBar::WTopBar(Handle<WOutput> output) noexcept 16 17 : output(output), view(0.f, 0.f, 0.f, 0.8f, &G::compositor()->overlayLayer) 17 18 { 19 + // copy thumbnails from an already initialized output 20 + for (let o : G::outputs()) { 21 + if (o == output) 22 + continue; 23 + 24 + for (let item : Ref<std::list<Handle<WTopBarItem>>>( 25 + o->topBar->view.children())) 26 + new WTopBarItem(this, item->surface); 27 + 28 + break; 29 + } 18 30 update(); 19 31 } 20 32 ··· 28 40 { 29 41 view.setSize(output->size().w(), TOPBAR_HEIGHT); 30 42 view.setPos(output->pos()); 43 + 44 + // update thumbnails 45 + for (var x = TOPBAR_PADDING; 46 + let item : Ref<std::list<Handle<WTopBarItem>>>(view.children())) { 47 + item->setPos(x, TOPBAR_PADDING); 48 + x += item->size().w() + THUMBNAIL_MARGIN; 49 + } 50 + 31 51 output->repaint(); 32 52 }
+33
src/WTopBarItem.cpp
··· 1 + /* ======================================================================== 2 + * 3 + * Filename: WTopBarItem.hpp 4 + * Description: W Compositor WTopBarItem class declaration 5 + * GitHub Repo: https://github.com/diego-est/womp 6 + * Author: Diego A. Estrada Rivera 7 + * License: GPL-3.0 8 + * 9 + * ======================================================================== */ 10 + #include "WTopBarItem.hpp" 11 + #include "WSurface.hpp" 12 + #include "WTopBar.hpp" 13 + #include "prelude.hpp" 14 + 15 + WTopBarItem::WTopBarItem(Handle<WTopBar> topBar, 16 + Handle<WSurface> surface) noexcept 17 + : LTextureView(surface->thumbnail, &topBar->view), topBar(topBar), 18 + surface(surface) 19 + { 20 + surface->topBarItems.push_back(this); 21 + surfaceLink = std::prev(surface->topBarItems.end()); 22 + 23 + setBufferScale(2); 24 + enableParentOpacity(false); 25 + topBar->update(); 26 + } 27 + 28 + WTopBarItem::~WTopBarItem() 29 + { 30 + surface->topBarItems.erase(surfaceLink); 31 + setParent(nullptr); 32 + topBar->update(); 33 + }
+29
src/WTopBarItem.hpp
··· 1 + /* ======================================================================== 2 + * 3 + * Filename: WTopBarItem.hpp 4 + * Description: W Compositor WTopBarItem class declaration 5 + * GitHub Repo: https://github.com/diego-est/womp 6 + * Author: Diego A. Estrada Rivera 7 + * License: GPL-3.0 8 + * 9 + * ======================================================================== */ 10 + #pragma once 11 + 12 + #include "prelude.hpp" 13 + #include <LTextureView.h> 14 + 15 + using namespace Louvre; 16 + 17 + class WTopBar; 18 + class WSurface; 19 + 20 + class WTopBarItem : public LTextureView { 21 + public: 22 + WTopBarItem(Handle<WTopBar> topBar, Handle<WSurface> surface) noexcept; 23 + ~WTopBarItem(); 24 + 25 + std::list<Handle<WTopBarItem>>::iterator surfaceLink; 26 + 27 + Handle<WTopBar> topBar = nullptr; 28 + Handle<WSurface> surface = nullptr; 29 + };
+19
src/global.cpp
··· 9 9 * ======================================================================== */ 10 10 #include "global.hpp" 11 11 #include "WCompositor.hpp" 12 + #include "WSurface.hpp" 12 13 #include "prelude.hpp" 13 14 14 15 fn G::scene() noexcept -> Handle<LScene> 15 16 { 16 17 return &compositor()->scene; 17 18 } 19 + 20 + void G::moveSurfaceWithChildren(Handle<WSurface> surface, Handle<LView> parent, 21 + subSurfacesOnly sso) noexcept 22 + { 23 + surface->view.setParent(parent); 24 + var next = surface; 25 + 26 + if (sso == subSurfacesOnly::on) { 27 + while ((next = Handle<WSurface>(next->nextSurface()))) 28 + if (next->isSubchildOf(surface) and 29 + next->subsurface() != nullptr) 30 + next->view.setParent(parent); 31 + } else { 32 + while ((next = Handle<WSurface>(next->nextSurface()))) 33 + if (next->isSubchildOf(surface)) 34 + next->view.setParent(parent); 35 + } 36 + }
+19
src/global.hpp
··· 12 12 #include <LCompositor.h> 13 13 14 14 #define TOPBAR_HEIGHT 32 15 + #define TOPBAR_PADDING 4 16 + #define THUMBNAIL_MARGIN 4 17 + #define THUMBNAIL_HEIGHT (TOPBAR_HEIGHT - 2 * TOPBAR_PADDING) 18 + 19 + // avoid bool in moveSurfaceWithChildren 20 + enum class subSurfacesOnly { off, on }; 15 21 16 22 using namespace Louvre; 17 23 18 24 class WCompositor; 19 25 class WOutput; 26 + class WSurface; 20 27 21 28 class G { 22 29 public: ··· 32 39 } 33 40 34 41 fn static scene() noexcept -> Handle<LScene>; 42 + 43 + // cast the LCompositor::surfaces() from LSurface to WSurface 44 + fn static inline surfaces() noexcept -> Ref<std::list<Handle<WSurface>>> 45 + { 46 + return Ref<std::list<Handle<WSurface>>>( 47 + LCompositor::compositor()->surfaces()); 48 + } 49 + 50 + // move surface views with children 51 + static void moveSurfaceWithChildren( 52 + Handle<WSurface> surface, Handle<LView> parent, 53 + subSurfacesOnly opt = subSurfacesOnly::off) noexcept; 35 54 };
+1 -1
src/main.cpp
··· 5 5 * GitHub Repo: https://github.com/diego-est/womp 6 6 * Author: Diego A. Estrada Rivera 7 7 * License: GPL-3.0 8 - * Version: 0.1.0 8 + * Version: 0.2.0 9 9 * 10 10 * ======================================================================== */ 11 11 #include "WCompositor.hpp"