├── shaders ├── solid.hlsl ├── text.hlsl ├── chamfer.hlsl ├── default.hlsl └── frame.hlsl ├── share └── chamfer.desktop ├── LICENSE ├── src ├── main.h ├── CompositorFont.h ├── container.h ├── config.h ├── CompositorResource.h ├── backend.h ├── compositor.h ├── CompositorFont.cpp ├── container.cpp └── main.cpp ├── README.md ├── meson.build ├── config └── config.py └── third └── spirv_reflect └── include └── spirv └── unified1 └── spirv.h /shaders/solid.hlsl: -------------------------------------------------------------------------------- 1 | 2 | #if defined(SHADER_STAGE_PS) 3 | 4 | float4 main(float4 posh : SV_Position) : SV_Target{ 5 | return float4(0.2,0.2,0.2,1); 6 | } 7 | 8 | #endif 9 | 10 | -------------------------------------------------------------------------------- /share/chamfer.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=chamfer 3 | Comment=A tiling X11 window manager with Vulkan compositor. 4 | Exec=chamfer --shader-path=~/.local/share/chamfer/shaders --shader-path=~/.config/chamfer/shaders/ --shader-path=/usr/share/chamfer/shaders/ 5 | Type=Application 6 | -------------------------------------------------------------------------------- /shaders/text.hlsl: -------------------------------------------------------------------------------- 1 | 2 | struct PS_INPUT{ 3 | float4 posh : SV_Position; 4 | float2 texc : TEXCOORD; 5 | }; 6 | 7 | #if defined(SHADER_STAGE_VS) 8 | 9 | [[vk::push_constant]] cbuffer cb{ 10 | float2x2 transform; 11 | float2 xy0; 12 | float2 screen; 13 | }; 14 | 15 | void main(float2 pos : POSITION, uint2 texc : TEXCOORD, out PS_INPUT output){ 16 | output.posh = float4(xy0+2.0f*mul(transform,pos)/screen-1.0f,0,1.0f); 17 | output.texc = float2(texc.x,texc.y); 18 | } 19 | 20 | #elif defined(SHADER_STAGE_PS) 21 | 22 | [[vk::binding(0)]] Texture2D fontAtlas; 23 | 24 | float4 main(PS_INPUT input) : SV_Target{ 25 | float c = fontAtlas.Load(float3(input.texc+0.5f,0)); 26 | return float4(0,0,0,c); 27 | } 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /shaders/chamfer.hlsl: -------------------------------------------------------------------------------- 1 | 2 | #define FLAGS_FOCUS 0x1 3 | #define FLAGS_CONTAINER_FOCUS 0x2 4 | #define FLAGS_FLOATING 0x4 5 | #define FLAGS_STACKED 0x8 6 | #define FLAGS_USER_BIT 0x10 7 | 8 | #define FLAGS_FOCUS_NEXT (FLAGS_USER_BIT<<0x0) 9 | 10 | [[vk::push_constant]] cbuffer cb{ 11 | float2 xy0; //normalized top-left corner location 12 | float2 xy1; //normalized bottom-right corner location 13 | float2 screen; //screen pixel dimensions 14 | float2 margin; //normalized gap margin in x and y directions 15 | float2 titlePad; //title padding vector 16 | float2 titleSpan; //title span when tabbing or stacking 17 | uint stackIndex; //index of the client in a tabbed stack 18 | uint flags; //flags such as whether client is focused 19 | float time; //time in seconds since client creation 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /shaders/default.hlsl: -------------------------------------------------------------------------------- 1 | 2 | #if defined(SHADER_STAGE_VS) 3 | 4 | float2 main(uint x : SV_VertexID) : POSITION0{ 5 | return float2(0,0); 6 | } 7 | 8 | #elif defined(SHADER_STAGE_GS) 9 | 10 | #include "chamfer.hlsl" 11 | 12 | struct GS_OUTPUT{ 13 | float4 posh : SV_Position; 14 | }; 15 | 16 | const float2 vertexPositions[4] = { 17 | float2(0.0f,0.0f), 18 | float2(1.0f,0.0f), 19 | float2(0.0f,1.0f), 20 | float2(1.0f,1.0f) 21 | }; 22 | 23 | const float2 vertices[4] = { 24 | xy0, 25 | float2(xy1.x,xy0.y), 26 | float2(xy0.x,xy1.y), 27 | xy1 28 | }; 29 | 30 | [maxvertexcount(4)] 31 | void main(point float2 posh[1], inout TriangleStream stream){ 32 | GS_OUTPUT output; 33 | 34 | //expand the vertex into a quad 35 | [unroll] 36 | for(uint i = 0; i < 4; ++i){ 37 | output.posh = float4(vertices[i],0,1); 38 | stream.Append(output); 39 | } 40 | stream.RestartStrip(); 41 | 42 | } 43 | 44 | #elif defined(SHADER_STAGE_PS) 45 | 46 | #include "chamfer.hlsl" 47 | 48 | [[vk::binding(0)]] Texture2D content; 49 | 50 | float4 main(float4 posh : SV_Position) : SV_Target{ 51 | float2 p = screen*(0.5f*xy0+0.5f); 52 | float2 r = posh.xy-p; 53 | float4 c = content.Load(float3(r,0)); //p already has the 0.5f offset 54 | 55 | return c; 56 | } 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Jasper Parkkila 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef unsigned int uint; 15 | typedef int sint; 16 | 17 | typedef unsigned long long int uint64; 18 | typedef long long int sint64; 19 | 20 | void DebugPrintf(FILE *, const char *, ...); 21 | 22 | #define mstrdup(s) strcpy(new char[strlen(s)+1],s) 23 | #define mstrndup(s,n) strncpy(new char[n+1],s,n) 24 | #define mstrfree(s) delete []s 25 | 26 | #define timespec_diff(b,a) (double)(b.tv_sec-a.tv_sec)+(double)((b.tv_nsec-a.tv_nsec)/1e9) 27 | #define timespec_diff_sec(b,a) (b.tv_sec-a.tv_sec) 28 | 29 | static inline void timespec_diff_ptr(struct timespec &b, struct timespec &a, struct timespec &r){ 30 | if(b.tv_nsec < a.tv_nsec){ 31 | r.tv_sec = b.tv_sec-1-a.tv_sec; 32 | r.tv_nsec = b.tv_nsec-a.tv_nsec+1e9; 33 | }else{ 34 | r.tv_sec = b.tv_sec-a.tv_sec; 35 | r.tv_nsec = b.tv_nsec-a.tv_nsec; 36 | } 37 | } 38 | 39 | template 40 | static inline bool any(T t, T *parray, uint n){ 41 | for(uint i = 0; i < n; ++i) 42 | if(t == parray[i]) 43 | return true; 44 | return false; 45 | } 46 | 47 | class Exception{ 48 | public: 49 | Exception(); 50 | Exception(const char *); 51 | ~Exception(); 52 | const char * what(); 53 | static char buffer[4096]; 54 | private: 55 | const char *pmsg; 56 | }; 57 | 58 | class Blob{ 59 | public: 60 | Blob(const char *); 61 | ~Blob(); 62 | const char * GetBufferPointer() const; 63 | size_t GetBufferLength() const; 64 | private: 65 | char *pbuffer; 66 | size_t buflen; 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/CompositorFont.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPOSITOR_FONT_H 2 | #define COMPOSITOR_FONT_H 3 | 4 | #include 5 | #include 6 | //#include 7 | #include 8 | 9 | namespace Compositor{ 10 | 11 | class Text : public Drawable{ 12 | friend class TextEngine; 13 | public: 14 | Text(const char *[Pipeline::SHADER_MODULE_COUNT], class TextEngine *); 15 | ~Text(); 16 | void Set(const char *, const VkCommandBuffer *); //updates the vertex buffers 17 | void Draw(const glm::uvec2 &, const glm::mat2x2 &, const VkCommandBuffer *); 18 | void UpdateDescSets(); 19 | float GetTextLength() const; 20 | float GetBaseline() const; 21 | protected: 22 | hb_buffer_t *phbBuf; 23 | uint glyphCount; 24 | float textLength; 25 | class TextEngine *ptextEngine; 26 | class Buffer *pvertexBuffer; 27 | class FontAtlas *pfontAtlas; 28 | struct Vertex{ 29 | glm::vec2 pos; 30 | glm::uvec2 texc; 31 | };// alignas(16); 32 | static std::vector> vertexBufferLayout; 33 | }; 34 | 35 | class TextEngine{ 36 | friend class FontAtlas; 37 | friend class Text; 38 | friend class CompositorInterface; 39 | public: 40 | TextEngine(const char *, uint, class CompositorInterface *); 41 | ~TextEngine(); 42 | struct Glyph{ 43 | uint codepoint; 44 | uint w; 45 | uint h; 46 | uint pitch; 47 | glm::vec2 offset; 48 | unsigned char *pbuffer; 49 | }; 50 | FontAtlas * CreateAtlas(hb_glyph_info_t *, uint, const VkCommandBuffer *); 51 | void ReleaseAtlas(FontAtlas *); 52 | Buffer * CreateVertexBuffer(); 53 | void ReleaseVertexBuffer(Buffer *); 54 | void ReleaseCycle(); 55 | Glyph * LoadGlyph(uint); 56 | float GetFontSize() const; 57 | private: 58 | class CompositorInterface *pcomp; 59 | Buffer *pindexBuffer; //shared index buffer between text objects 60 | bool indexBufferMapped; 61 | std::vector glyphMap; 62 | std::vector fontAtlasMap; 63 | struct VertexBufferCacheEntry{ 64 | Buffer *pvertexBuffer; 65 | uint64 releaseTag; 66 | struct timespec releaseTime; 67 | }; 68 | std::vector vertexBufferCache; 69 | FT_Library library; 70 | FT_Face fontFace; 71 | hb_font_t *phbFont; 72 | }; 73 | 74 | class FontAtlas{ 75 | public: 76 | FontAtlas(uint, class TextEngine *); 77 | ~FontAtlas(); 78 | void Update(hb_glyph_info_t *, uint, const VkCommandBuffer *); 79 | TextEngine *ptextEngine; 80 | TextureStaged *ptexture; 81 | struct GlyphEntry{ 82 | uint codepoint; 83 | glm::uvec2 texc; 84 | TextEngine::Glyph *pglyph; 85 | }; 86 | //std::vector> glyphCollection; 87 | std::vector glyphCollection; 88 | glm::uvec2 fontAtlasCursor; //this is useless since Map() for the full region erases everything 89 | uint size; 90 | uint refCount; 91 | uint64 releaseTag; 92 | }; 93 | 94 | } 95 | 96 | #endif 97 | 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chamferwm 2 | A tiling window manager with Vulkan based compositor. Vulkan compositor for external X11 window managers. [Documentation](https://jaelpark.github.io/chamferwm-docs/) 3 | 4 | > **Note** 5 | > Support for DMA-buf import has been added, and *has been made default*. This can be disabled with `--memory-import-mode=1`, which will revert to host pointer import method. 6 | 7 | > **Note** 8 | > Initial support for standalone compositor feature has been merged. The program can now be configured to run the Vulkan compositor on external X11 window managers. See below for instructions. 9 | 10 | [![Preview](http://users.jyu.fi/~jaelpark/gitres/scrot-chamfer-1.jpg)](http://users.jyu.fi/~jaelpark/gitres/scrot-chamfer.png) 11 | 12 | ## Features 13 | Window manager: 14 | 15 | - Dynamic horizontal and vertical tiling with gaps and stacking 16 | - Specify container size restrictions, overlap when necessary 17 | - Resize and translate individual containers in their place while keeping the surrounding layout 18 | - Floating containers and automatic dialog, dock, widget etc. handling 19 | - Multiple named workspaces 20 | - Yank and paste containers to move them within the tree hierarchy along with typical move operations 21 | - Configuration with python, scriptable behaviour with client and container specific callbacks 22 | - Fully keyboard controllable 23 | 24 | Compositor: 25 | 26 | - Vulkan renderer 27 | - Arbitrary window decorations and borders with user supplied shaders 28 | - Per-client materials 29 | - Automatically disable for fullscreen applications 30 | - Optional, alternatively use any other external compositor 31 | - Standalone compositor mode (beta) to be used in combination with any other window manager 32 | 33 | ## Installing 34 | ##### Prerequisites 35 | 36 | - XCB libraries 37 | - Vulkan SDK 38 | - glm 39 | - Python 3.6+ and boost modules 40 | - python-xlib 41 | - [shaderc Shader compiler](https://github.com/google/shaderc) 42 | - FreeType2 43 | - HarfBuzz 44 | - fontconfig 45 | 46 | ##### General setup 47 | 48 | Currently a PKGBUILD is available for testing purposes. Install from [AUR](https://aur.archlinux.org/packages/chamfer-git/), or run meson to build manually. The package from AUR will install a default configuration and the precompiled shaders to /usr/share/chamfer/. Copy the configuration to another location to make modifications. Put the following line to your .xinitrc: 49 | 50 | ```sh 51 | exec chamfer --config=/usr/share/chamfer/config/config.py --shader-path=/usr/share/chamfer/shaders/ 52 | ``` 53 | 54 | When multiple rendering devices are available, make the choice with `--device-index=n`, where `n` is the zero-based index of the device (default = 0). The ordering follows the list reported by `vulkaninfo` utility. Launch Xorg with `startx`. 55 | 56 | - To automatically let fullscreen applications bypass the compositor, use `--unredir-on-fullscreen`. A dedicated workspace with the compositor always disabled is provided, and by default bound to Meta+0. 57 | - NVIDIA users may have to add ``Option "AllowSHMPixmaps" "1"`` to their Xorg configuration, if shared memory import is used (`--memory-import-mode=1`). 58 | - For compositor compatibility mode if encountering any issues, use `--memory-import-mode=1` or `2` and/or `--no-scissoring`. 59 | 60 | To run the WM without the integrated compositor, use 61 | 62 | ```sh 63 | exec chamfer --config=/usr/share/chamfer/config/config.py -n 64 | ``` 65 | 66 | In this case, any other external compositor may be used. 67 | 68 | ##### Compositor mode for other WMs 69 | 70 | The Vulkan compositor can be used together with external X11 window managers. To launch the program in this mode, run 71 | 72 | ```sh 73 | chamfer -C --config=/usr/share/chamfer/config/config.py --shader-path=/usr/share/chamfer/shaders/ 74 | ``` 75 | 76 | ##### Style and decorations 77 | 78 | The default "demo" style draws rounded borders around the windows, as well as shadows. The style can be changed by [editing the shaders section of the config](https://github.com/jaelpark/chamferwm/blob/5ed340fece89eda381f25a8354a8c2dc18dd8787/config/config.py#L53-L71). Changing the style attributes (color, borders etc.) of the stock shaders is at the moment only possible by editing the values in the fragment shader itself, and then rebuilding. For a complete custom look, the shaders can be replaced entirely. Shaders can be specified on per-window basis, enabling some interesting looks for your desktop. 79 | 80 | -------------------------------------------------------------------------------- /src/container.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTAINER_H 2 | #define CONTAINER_H 3 | 4 | namespace WManager{ 5 | 6 | struct Rectangle{ 7 | sint x; 8 | sint y; 9 | sint w; 10 | sint h; 11 | }; 12 | 13 | class Client{ 14 | public: 15 | //Client(class BackendInterface *); 16 | Client(class Container *); 17 | virtual ~Client(); 18 | // 19 | //virtual functions for the backend implementation 20 | virtual void UpdateTranslation(){}// = 0; 21 | virtual void Kill(){}// = 0; 22 | Rectangle rect; //pixel coordinates of the client 23 | Rectangle oldRect; //to animate the transitions 24 | Rectangle titleRect; 25 | glm::vec2 position; //interpolated, animated rectangle 26 | glm::vec2 titlePad1; //title pad in pixels 27 | glm::vec2 titleStackOffset; 28 | glm::vec2 titleFrameExtent; 29 | uint stackIndex; 30 | struct timespec translationTime; 31 | class Container *pcontainer; 32 | }; 33 | 34 | class Container{ 35 | public: 36 | enum FLAG{ 37 | FLAG_FLOATING = 0x1, 38 | FLAG_NO_FOCUS = 0x2, 39 | FLAG_FULLSCREEN = 0x4, 40 | FLAG_STACKED = 0x8 41 | }; 42 | enum LAYOUT{ 43 | LAYOUT_VSPLIT, 44 | LAYOUT_HSPLIT, 45 | }; 46 | enum TITLEBAR{ 47 | TITLEBAR_NONE, 48 | TITLEBAR_LEFT, 49 | TITLEBAR_TOP, 50 | TITLEBAR_RIGHT, 51 | TITLEBAR_BOTTOM 52 | //TITLEBAR_AUTO_TOP_LEFT, 53 | //TITLEBAR_AUTO_BOTTOM_RIGHT, 54 | }; 55 | struct Setup{ 56 | const char *pname = 0; 57 | glm::vec2 canvasOffset = glm::vec2(0.0f); 58 | glm::vec2 canvasExtent = glm::vec2(0.0f); 59 | //Border width can be set anytime before the client creation 60 | glm::vec2 margin = glm::vec2(0.0f); 61 | //For performance reasons, the min/maxSize has to be known before the container is created. 62 | glm::vec2 size = glm::vec2(1.0f); 63 | glm::vec2 minSize = glm::vec2(0.0f); 64 | glm::vec2 maxSize = glm::vec2(1.0f); 65 | uint flags = 0; 66 | TITLEBAR titleBar = TITLEBAR_NONE; 67 | bool titleStackOnly = false; 68 | float titlePad = 0.0f; 69 | }; 70 | Container(); //root container 71 | Container(Container *, const Setup &); 72 | virtual ~Container(); 73 | void AppendRoot(Container *); 74 | void Place(Container *); 75 | Container * Remove(); 76 | Container * Collapse(); 77 | void Focus(); 78 | void SetFullscreen(bool); 79 | void SetStacked(bool); 80 | //void SetFloating(bool); 81 | Container * GetNext(); 82 | Container * GetPrev(); 83 | Container * GetParent() const; 84 | Container * GetFocus() const; 85 | Container * GetRoot(); 86 | void SetName(const char *); 87 | void SetSize(glm::vec2); 88 | void SetTitlebar(TITLEBAR, bool = true); 89 | 90 | void MoveNext(); 91 | void MovePrev(); 92 | 93 | glm::vec2 GetMinSize() const; 94 | void TranslateRecursive(glm::vec2, glm::vec2, glm::vec2, glm::vec2); 95 | void Translate(); 96 | void StackRecursive(); 97 | void Stack(); 98 | void SetLayout(LAYOUT); 99 | 100 | virtual void Focus1(){} 101 | virtual void Place1(WManager::Container *){} 102 | virtual void Stack1(){} 103 | virtual void Fullscreen1(){} 104 | 105 | Container *pParent; 106 | Container *pch; //First children 107 | Container *pnext; //Subsequent container in the parent container 108 | Container *pRootNext; //Parallel workspace. To avoid bugs, pnext (null for root containers) will not be used for this. 109 | std::deque focusQueue; 110 | std::deque stackQueue; 111 | 112 | Client *pclient; 113 | char *pname; //name identifier for searches 114 | 115 | //absolute normalized coordinates 116 | glm::vec2 p; 117 | glm::vec2 posFullCanvas; 118 | glm::vec2 e; 119 | glm::vec2 extFullCanvas; 120 | glm::vec2 canvasOffset; //should be multiplied by e? 121 | glm::vec2 canvasExtent; 122 | 123 | glm::vec2 margin; 124 | glm::vec2 titlePad; //title size either horizontally or vertically - depends on font size 125 | glm::vec2 titleSpan; //title span in normalized coords: region that the title bar spans 126 | glm::mat2x2 titleTransform; 127 | float absTitlePad; 128 | 129 | glm::vec2 size; //size relative to the parent container, V split and H split size. When floating, this is the actual size (rect). 130 | glm::vec2 minSize; //min size, relative to screen 131 | glm::vec2 maxSize; //max size, relative to screen 132 | 133 | uint flags; 134 | LAYOUT layout; 135 | TITLEBAR titleBar; 136 | bool titleStackOnly; //title is rendered only when stacking 137 | 138 | static WManager::Container *ptreeFocus; //client focus, managed by Python 139 | static std::deque> tiledFocusQueue; 140 | static std::deque floatFocusQueue; 141 | static std::deque rootQueue; //Root container queue in the order of creation. Mainly used for EWMH 142 | }; 143 | 144 | //for diamond inheritance: 145 | /*class RootContainer : Container{ 146 | public: 147 | RootContainer(const char *); 148 | virtual ~RootContainer(); 149 | void Link(RootContainer *); 150 | RootContainer *pRootNext; //Parallel workspace. To avoid bugs, pnext (null for root containers) will not be used for this. 151 | char *pname; 152 | //noComp 153 | };*/ 154 | 155 | } 156 | 157 | #endif 158 | 159 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('chamferwm',['c','cpp']) 2 | 3 | src = [ 4 | 'src/main.cpp', 5 | 'src/config.cpp', 6 | 'src/container.cpp', 7 | 'src/backend.cpp', 8 | 'src/compositor.cpp', 9 | 'src/CompositorResource.cpp', 10 | 'src/CompositorFont.cpp', 11 | 'third/spirv_reflect/spirv_reflect.c' 12 | ] 13 | 14 | inc = [ 15 | include_directories('third/spirv_reflect'), 16 | include_directories('third/args') 17 | ] 18 | 19 | xcb = [ 20 | dependency('xcb'), 21 | dependency('xcb-keysyms'), 22 | dependency('xcb-cursor'), 23 | dependency('xcb-xfixes'), 24 | dependency('xcb-damage'), 25 | dependency('xcb-shm'), 26 | dependency('xcb-dri3'), 27 | dependency('xcb-composite'), 28 | dependency('xcb-icccm'), 29 | dependency('xcb-ewmh'), 30 | dependency('xcb-randr'), 31 | dependency('xcb-util') 32 | ] 33 | 34 | vk = [ 35 | dependency('vulkan'), 36 | dependency('glm') 37 | #dependency('gbm') 38 | ] 39 | 40 | python = [ 41 | dependency('python3'), 42 | dependency('python3-embed'), #python 3.8 43 | dependency('boost',modules:['system','filesystem','python3']) 44 | ] 45 | 46 | ft = [ 47 | dependency('freetype2'), 48 | dependency('fontconfig'), 49 | dependency('harfbuzz') 50 | ] 51 | 52 | glslc = find_program('glslc') 53 | spirv_opt = find_program('spirv-opt') #optimization has to be done separately as a post-processing step, since glslc removes the reflection info 54 | 55 | #glslc_invoke_vertex = [glslc,'--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=vertex','-O','-g','-x','hlsl','-DSHADER_STAGE_VS','-o','@OUTPUT@','@INPUT@'] 56 | #glslc_invoke_geometry = [glslc,'--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=geometry','-O','-g','-x','hlsl','-DSHADER_STAGE_GS','-o','@OUTPUT@','@INPUT@'] 57 | #glslc_invoke_fragment = [glslc,'--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=fragment','-O','-g','-x','hlsl','-DSHADER_STAGE_PS','-o','@OUTPUT@','@INPUT@'] 58 | glslc_args_vertex = ['--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=vertex','-x','hlsl','-DSHADER_STAGE_VS','-o','@OUTPUT@','@INPUT@'] 59 | glslc_args_geometry = ['--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=geometry','-x','hlsl','-DSHADER_STAGE_GS','-o','@OUTPUT@','@INPUT@'] 60 | glslc_args_fragment = ['--target-env=vulkan','-fhlsl_functionality1','-fshader-stage=fragment','-x','hlsl','-DSHADER_STAGE_PS','@EXTRA_ARGS@','-o','@OUTPUT@','@INPUT@'] 61 | invoke_spirv_opt = [spirv_opt,'-O','-o','@OUTPUT@','@INPUT@'] 62 | 63 | #custom_target('default_vertex',output:'default_vertex.spv',input:'shaders/default.hlsl',command:glslc_invoke_vertex,install:true,install_dir:'.') 64 | #custom_target('default_geometry',output:'default_geometry.spv',input:'shaders/default.hlsl',command:glslc_invoke_geometry,install:true,install_dir:'.') 65 | #custom_target('default_fragment',output:'default_fragment.spv',input:'shaders/default.hlsl',command:glslc_invoke_fragment,install:true,install_dir:'.') 66 | #custom_target('solid_fragment',output:'solid_fragment.spv',input:'shaders/solid.hlsl',command:glslc_invoke_fragment,install:true,install_dir:'.') 67 | #custom_target('frame_vertex',output:'frame_vertex.spv',input:'shaders/frame.hlsl',command:glslc_invoke_vertex,install:true,install_dir:'.') 68 | #custom_target('frame_geometry',output:'frame_geometry.spv',input:'shaders/frame.hlsl',command:glslc_invoke_geometry,install:true,install_dir:'.') 69 | #obj = custom_target('frame_fragment',output:'frame_fragment.spv',input:'shaders/frame.hlsl',command:glslc_invoke_fragment,install:false)#,install:true,install_dir:'.') 70 | 71 | gen_vertex = generator(glslc,output:'@BASENAME@_vertex_unopt.spv',arguments:glslc_args_vertex) 72 | gen_geometry = generator(glslc,output:'@BASENAME@_geometry_unopt.spv',arguments:glslc_args_geometry) 73 | gen_fragment = generator(glslc,output:'@BASENAME@_fragment_unopt.spv',arguments:glslc_args_fragment) 74 | 75 | obj = gen_vertex.process(['shaders/default.hlsl']) 76 | custom_target('default_vertex',output:'default_vertex.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 77 | 78 | obj = gen_vertex.process(['shaders/frame.hlsl']) 79 | custom_target('frame_vertex',output:'frame_vertex.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 80 | 81 | obj = gen_vertex.process(['shaders/text.hlsl']) 82 | custom_target('text_vertex',output:'text_vertex.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 83 | 84 | obj = gen_geometry.process(['shaders/default.hlsl']) 85 | custom_target('default_geometry',output:'default_geometry.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 86 | 87 | obj = gen_geometry.process(['shaders/frame.hlsl']) 88 | custom_target('frame_geometry',output:'frame_geometry.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 89 | 90 | obj = gen_fragment.process(['shaders/default.hlsl']) 91 | custom_target('default_fragment',output:'default_fragment.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 92 | 93 | foreach name,args : { 94 | 'fragment':['-DSTOCK_FRAME_STYLE=1'], #default "demo" decoration with border and rounded corners 95 | 'fragment_basic':['-DSTOCK_FRAME_STYLE=0'], #rectangular borders, no bling 96 | 'fragment_ext':['-DSTOCK_FRAME_STYLE=1','-DDRAW_BORDER=1','-DENABLE_TITLE=0','-DDRAW_SHADOW=1'], #default rounded corner style for external wms 97 | 'fragment_ext_basic':['-DSTOCK_FRAME_STYLE=0','-DDRAW_BORDER=0','-DENABLE_TITLE=0','-DDRAW_SHADOW=1'] #simple compatible style for external wms, only draw shadows 98 | } 99 | obj = generator(glslc,output:'@BASENAME@_'+name+'_unopt.spv',arguments:glslc_args_fragment).process(['shaders/frame.hlsl'],extra_args:args) 100 | custom_target('frame_'+name,output:'frame_'+name+'.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 101 | endforeach 102 | 103 | #obj = gen_fragment.process(['shaders/frame.hlsl'],extra_args:['-DSTOCK_FRAME_STYLE=1']) 104 | #custom_target('frame_fragment',output:'frame_fragment.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 105 | 106 | obj = gen_fragment.process(['shaders/text.hlsl']) 107 | custom_target('text_fragment',output:'text_fragment.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 108 | 109 | obj = gen_fragment.process(['shaders/solid.hlsl']) 110 | custom_target('solid_fragment',output:'solid_fragment.spv',input:obj,command:invoke_spirv_opt,install:true,install_dir:'.') 111 | 112 | executable('chamfer',sources:src,include_directories:inc,dependencies:[xcb,vk,python,ft],cpp_args:['-std=c++17','-Wno-reorder','-Wno-error=narrowing']) 113 | 114 | -------------------------------------------------------------------------------- /shaders/frame.hlsl: -------------------------------------------------------------------------------- 1 | 2 | #if defined(SHADER_STAGE_VS) 3 | 4 | float2 main(uint x : SV_VertexID) : POSITION0{ 5 | return float2(0,0); 6 | } 7 | 8 | #elif defined(SHADER_STAGE_GS) 9 | 10 | #include "chamfer.hlsl" 11 | 12 | struct GS_OUTPUT{ 13 | float4 posh : SV_Position; 14 | float2 texc : TEXCOORD; 15 | }; 16 | 17 | const float2 vertexPositions[4] = { 18 | float2(0.0f,0.0f), 19 | float2(1.0f,0.0f), 20 | float2(0.0f,1.0f), 21 | float2(1.0f,1.0f) 22 | }; 23 | 24 | static float2 titlePadAspect = 2.0f*titlePad*float2(1.0f,screen.x/screen.y); 25 | static float2 xy0_1 = xy0+min(titlePadAspect,0.0f); 26 | static float2 xy1_1 = xy1+max(titlePadAspect,0.0f); 27 | const float2 vertices[4] = { 28 | xy0_1, 29 | float2(xy1_1.x,xy0_1.y), 30 | float2(xy0_1.x,xy1_1.y), 31 | xy1_1 32 | }; 33 | 34 | [maxvertexcount(4)] 35 | //void main(point GS_INTPUT input[1], inout TriangleStream stream){ 36 | void main(point float2 posh[1], inout TriangleStream stream){ 37 | GS_OUTPUT output; 38 | 39 | float2 aspect = float2(1.0f,screen.x/screen.y); 40 | float2 marginWidth = margin*aspect; //this results in borders half the gap size 41 | 42 | //stretch to make room for the effects (border + shadow) - also includes screen space 2.0f 43 | marginWidth *= 8.0f; 44 | 45 | //expand the vertex into a quad 46 | [unroll] 47 | for(uint i = 0; i < 4; ++i){ 48 | output.posh = float4(vertices[i]+(2.0*vertexPositions[i]-1.0f)*marginWidth,0,1); 49 | output.texc = vertexPositions[i]; 50 | stream.Append(output); 51 | } 52 | stream.RestartStrip(); 53 | } 54 | 55 | #elif defined(SHADER_STAGE_PS) 56 | 57 | #include "chamfer.hlsl" 58 | 59 | #ifndef STOCK_FRAME_STYLE 60 | #define STOCK_FRAME_STYLE 1 //select between two stock styles (1: chamfered edges, other: basic rectangle borders) 61 | #endif 62 | 63 | #ifndef DRAW_SHADOW 64 | #define DRAW_SHADOW 1 //set 1 to draw shadow 65 | #endif 66 | 67 | #ifndef DRAW_BORDER 68 | #define DRAW_BORDER 1 69 | #endif 70 | 71 | #ifndef ENABLE_TITLE 72 | #define ENABLE_TITLE 1 73 | #endif 74 | 75 | #define BORDER_RADIUS 0.02f 76 | #define BORDER_THICKNESS 0.008f 77 | 78 | const float4 borderColor = float4(0.07f,0.07f,0.07f,1.0f); 79 | const float4 focusColor = float4(1.0f,0.6f,0.33f,1.0f); 80 | const float4 titleBackground[2] = {float4(0.4f,0.4f,0.4f,1.0f),float4(0.5,0.5,0.5,1.0f)}; //second value for alternating stack tabs 81 | const float4 taskSelectColor = float4(0.957f,0.910f,0.824f,1.0f); 82 | 83 | [[vk::binding(0)]] Texture2D content; 84 | //[[vk::binding(1)]] SamplerState sm; 85 | 86 | //signed distance field of a rectangle 87 | float RectangleMap(float2 p, float2 b){ 88 | float2 d = abs(p)-b; 89 | return length(max(d,0.0f))+min(max(d.x,d.y),0.0f); 90 | } 91 | 92 | //signed distance field of a chamfered rectangle 93 | float ChamferMap(float2 p, float2 b, float r){ 94 | float2 d = abs(p)-b; 95 | return length(max(d,0.0f))-r+min(max(d.x,d.y),0.0f); 96 | } 97 | 98 | float4 main(float4 posh : SV_Position, float2 texc : TEXCOORD) : SV_Target{ 99 | float2 aspect = float2(1.0f,screen.x/screen.y); 100 | 101 | float2 borderScalingScr = screen*aspect; 102 | 103 | float2 titlePadAspect = 2.0f*titlePad*aspect; 104 | float2 xy0_1 = xy0+min(titlePadAspect,0.0f); 105 | float2 xy1_1 = xy1+max(titlePadAspect,0.0f); 106 | 107 | float2 a = screen*(0.5f*xy0_1+0.5f); //top-left corner in pixels 108 | float2 b = screen*(0.5f*xy1_1+0.5f); //bottom-right corner in pixels 109 | float2 center = 0.5f*(a+b); //center location in pixels 110 | float2 d1 = b-a; //d1: pixel extent of the window 111 | 112 | float2 q = posh.xy-center; //pixel offset from center of the window 113 | 114 | #if STOCK_FRAME_STYLE == 1 115 | // ----- frame 1: rounded corners (demo frame) ------------------- 116 | 117 | float sr1 = ChamferMap(q,0.5f*d1-BORDER_RADIUS*borderScalingScr.x,(BORDER_RADIUS+DRAW_BORDER*BORDER_THICKNESS)*borderScalingScr.x); //with border (thicknes determined here) 118 | if(sr1 > -1.0f){ 119 | //shadow region 120 | #if DRAW_SHADOW 121 | if(stackIndex == 0) //only first in stack casts a shadow 122 | return float4(0.0f,0.0f,0.0f,0.7f*saturate(1.0f-sr1/(0.0078f*borderScalingScr.x))); 123 | else{ 124 | #else 125 | { 126 | #endif 127 | discard; 128 | return 0.0f; 129 | } 130 | } 131 | #if DRAW_BORDER 132 | //radius extends from the rectangle 133 | float br1 = ChamferMap(q,0.5f*d1-BORDER_RADIUS*borderScalingScr.x,BORDER_RADIUS*borderScalingScr.x); 134 | if(br1 > -1.0f){ 135 | //border region 136 | if(flags & FLAGS_FOCUS) 137 | //dashed line around focus 138 | if((any(posh > center-0.5f*d1 && posh < center+0.5f*d1 && fmod(floor(posh/(0.0130f*borderScalingScr.x)),3.0f) < 0.5f) && 139 | any(posh < center-0.5f*d1-0.6f*BORDER_THICKNESS*borderScalingScr || posh > center+0.5f*d1+0.6f*BORDER_THICKNESS*borderScalingScr))) //0.0037f 140 | return focusColor; 141 | 142 | if(flags & FLAGS_FOCUS_NEXT) 143 | if((any(posh > center-0.5f*d1 && posh < center+0.5f*d1 && fmod(floor(posh/(0.0130f*borderScalingScr.x)),3.0f) < 0.5f) && 144 | any(posh < center-0.5f*d1-0.6f*BORDER_THICKNESS*borderScalingScr || posh > center+0.5f*d1+0.6f*BORDER_THICKNESS*borderScalingScr))) 145 | return taskSelectColor; 146 | 147 | return borderColor; 148 | } 149 | #endif //DRAW_BORDER 150 | #else //STOCK_FRAME_STYLE 151 | // ----- frame 0: basic rectangular ------------------------------ 152 | 153 | float sr1 = RectangleMap(q,0.5f*d1+DRAW_BORDER*BORDER_THICKNESS*borderScalingScr.x); 154 | if(sr1 > -1.0f){ 155 | //shadow region 156 | #if DRAW_SHADOW 157 | if(stackIndex == 0) //only first in stack casts a shadow 158 | return float4(0.0f,0.0f,0.0f,0.9f*saturate(1.0f-sr1/(0.0078f*borderScalingScr.x))); 159 | else{ 160 | #else 161 | { 162 | #endif 163 | discard; 164 | return 0.0f; 165 | } 166 | } 167 | #if DRAW_BORDER 168 | float br1 = RectangleMap(q,0.5f*d1); 169 | if(br1 > -1.0f){ 170 | //border region 171 | if(flags & FLAGS_FOCUS) 172 | return focusColor; 173 | if(flags & FLAGS_FOCUS_NEXT) 174 | return taskSelectColor; 175 | 176 | return borderColor; 177 | } 178 | #endif //DRAW_BORDER 179 | #endif //STOCK_FRAME_STYLE 180 | 181 | float2 a_content = screen*(0.5f*xy0+0.5f); //top-left corner in pixels, content area 182 | #if ENABLE_TITLE 183 | float2 b_content = screen*(0.5f*xy1+0.5f); //bottom-right corner in pixels, content area 184 | if(any(posh.xy < a_content) || any(posh.xy > b_content)){ //title region 185 | bool1 tb = abs(titlePad.x) < abs(titlePad.y); //check whether the title bar is horizontal or vertical 186 | bool2 sb = posh < (a+(b-a)*titleSpan.x) || posh > (a+(b-a)*titleSpan.y); 187 | if((tb && sb[0]) || (!tb && sb[1])) 188 | discard; //clear the region to show the titles of the clients stacked under 189 | if(flags & FLAGS_FOCUS) 190 | return focusColor; 191 | return titleBackground[stackIndex%2]; 192 | } 193 | #endif 194 | //content region 195 | if(flags & FLAGS_CONTAINER_FOCUS){ 196 | float4 c = content.Load(float3(posh.xy-a_content,0)); 197 | return c; 198 | } 199 | discard; 200 | return 0.0f; 201 | } 202 | 203 | #endif 204 | 205 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | 6 | namespace WManager{ 7 | class Client; 8 | class Container; 9 | } 10 | 11 | namespace Config{ 12 | 13 | class ContainerInterface{ 14 | public: 15 | ContainerInterface(); 16 | virtual ~ContainerInterface(); 17 | void CopySettingsSetup(WManager::Container::Setup &); 18 | void DeferredPropertyTransfer(); 19 | virtual void OnSetupContainer(); 20 | virtual void OnSetupClient(); 21 | virtual boost::python::object OnParent(); 22 | virtual void OnCreate(); 23 | enum PROPERTY_ID{ 24 | PROPERTY_ID_NAME, 25 | PROPERTY_ID_CLASS 26 | }; 27 | virtual bool OnFullscreen(bool); 28 | virtual void OnStack(bool); 29 | virtual void OnFloat(bool); 30 | virtual bool OnFocus(); 31 | virtual void OnEnter(); 32 | virtual void OnPropertyChange(PROPERTY_ID); 33 | boost::python::object GetNext() const; 34 | boost::python::object GetPrev() const; 35 | boost::python::object GetParent() const; 36 | boost::python::object GetFocus() const; 37 | boost::python::object GetTiledFocus() const; 38 | boost::python::object GetFloatFocus() const; 39 | void Move(boost::python::object); 40 | //public: 41 | //temporary storage for deferred assignment (before container is created) 42 | boost::python::tuple canvasOffset; 43 | boost::python::tuple canvasExtent; 44 | boost::python::tuple margin; 45 | boost::python::tuple size; 46 | boost::python::tuple minSize; 47 | boost::python::tuple maxSize; 48 | enum FLOAT{ 49 | FLOAT_AUTOMATIC, 50 | FLOAT_ALWAYS, 51 | FLOAT_NEVER 52 | } floatingMode; 53 | WManager::Container::TITLEBAR titleBar; 54 | bool titleStackOnly; 55 | //float titlePadding; 56 | //client variables 57 | uint shaderUserFlags; 58 | //-------------------------------- 59 | std::string name; 60 | std::string vertexShader; 61 | std::string geometryShader; 62 | std::string fragmentShader; 63 | std::string wm_name; 64 | std::string wm_class; 65 | 66 | WManager::Container *pcontainer; 67 | boost::python::object self; 68 | 69 | static void UpdateShaders(); 70 | static std::set shaderUpdateQueue; 71 | }; 72 | 73 | class ContainerProxy : public ContainerInterface, public boost::python::wrapper{ 74 | public: 75 | ContainerProxy(); 76 | ~ContainerProxy(); 77 | void OnSetupContainer(); 78 | void OnSetupClient(); 79 | boost::python::object OnParent(); 80 | void OnCreate(); 81 | bool OnFullscreen(bool); 82 | void OnStack(bool); 83 | void OnFloat(bool); 84 | bool OnFocus(); 85 | void OnEnter(); 86 | void OnPropertyChange(PROPERTY_ID); 87 | }; 88 | 89 | class ContainerConfig{ 90 | public: 91 | ContainerConfig(ContainerInterface *, class Backend::X11Backend *); 92 | ContainerConfig(class Backend::X11Backend *); 93 | virtual ~ContainerConfig(); 94 | ContainerInterface *pcontainerInt; 95 | class Backend::X11Backend *pbackend; 96 | }; 97 | 98 | /*template 99 | class BackendContainerConfig : public T, public ContainerConfig{ 100 | public: 101 | BackendContainerConfig(ContainerInterface *, WManager::Container *, const WManager::Container::Setup &, class Backend::X11Backend *); 102 | BackendContainerConfig(class Backend::X11Backend *); 103 | ~BackendContainerConfig(); 104 | };*/ 105 | 106 | class X11ContainerConfig : public Backend::X11Container, public ContainerConfig{ 107 | public: 108 | X11ContainerConfig(ContainerInterface *, WManager::Container *, const WManager::Container::Setup &, class Backend::X11Backend *); 109 | X11ContainerConfig(class Backend::X11Backend *, bool = false); 110 | ~X11ContainerConfig(); 111 | }; 112 | 113 | class DebugContainerConfig : public Backend::DebugContainer, public ContainerConfig{ 114 | public: 115 | DebugContainerConfig(ContainerInterface *, WManager::Container *, const WManager::Container::Setup &, class Backend::X11Backend *); 116 | DebugContainerConfig(class Backend::X11Backend *); 117 | ~DebugContainerConfig(); 118 | }; 119 | 120 | /*class WorkspaceInterface{ 121 | public: 122 | WorkspaceInterface(); 123 | virtual ~WorkspaceInterface(); 124 | }; 125 | 126 | class WorkspaceProxy : public WorkspaceInterface, public boost::python::wrapper{ 127 | public: 128 | WorkspaceProxy(); 129 | ~WorkspaceProxy(); 130 | };*/ 131 | 132 | class BackendInterface{ 133 | public: 134 | BackendInterface(); 135 | virtual ~BackendInterface(); 136 | virtual void OnSetupKeys(bool); 137 | virtual boost::python::object OnCreateContainer(); 138 | //virtual boost::python::object OnCreateWorkspace(); 139 | virtual void OnKeyPress(uint); 140 | virtual void OnKeyRelease(uint); 141 | virtual void OnTimer(); 142 | virtual void OnExit(); 143 | boost::python::object GetFocus(); 144 | boost::python::object GetRoot(boost::python::object = boost::python::object()); 145 | void BindKey(uint, uint, uint); 146 | void MapKey(uint, uint, uint); 147 | void GrabKeyboard(bool); 148 | 149 | bool standaloneComp; 150 | 151 | class BackendConfig *pbackend; 152 | 153 | static void Bind(boost::python::object); 154 | 155 | static BackendInterface defaultInt; 156 | static BackendInterface *pbackendInt; 157 | }; 158 | 159 | class BackendProxy : public BackendInterface, public boost::python::wrapper{ 160 | public: 161 | BackendProxy(); 162 | ~BackendProxy(); 163 | // 164 | void OnSetupKeys(bool); 165 | boost::python::object OnCreateContainer(); 166 | boost::python::object OnCreateWorkspace(); 167 | void OnKeyPress(uint); 168 | void OnKeyRelease(uint); 169 | void OnTimer(); 170 | void OnExit(); 171 | }; 172 | 173 | class BackendConfig{ 174 | public: 175 | BackendConfig(BackendInterface *); 176 | virtual ~BackendConfig(); 177 | BackendInterface *pbackendInt; 178 | }; 179 | 180 | class CompositorInterface{ 181 | public: 182 | CompositorInterface(); 183 | virtual ~CompositorInterface(); 184 | virtual bool OnRedirectExternal(std::string, std::string); 185 | 186 | bool noCompositor; 187 | sint deviceIndex; 188 | bool debugLayers; 189 | bool scissoring; 190 | bool incrementalPresent; 191 | //bool hostMemoryImport; 192 | Compositor::CompositorInterface::IMPORT_MODE memoryImportMode; 193 | bool unredirOnFullscreen; 194 | bool enableAnimation; 195 | float animationDuration; 196 | 197 | std::string fontName; 198 | uint fontSize; 199 | 200 | class CompositorConfig *pcompositor; 201 | 202 | static void Bind(boost::python::object); 203 | 204 | static CompositorInterface defaultInt; 205 | static CompositorInterface *pcompositorInt; 206 | }; 207 | 208 | class CompositorProxy : public CompositorInterface, public boost::python::wrapper{ 209 | public: 210 | CompositorProxy(); 211 | ~CompositorProxy(); 212 | bool OnRedirectExternal(std::string, std::string); 213 | }; 214 | 215 | class CompositorConfig{ 216 | public: 217 | CompositorConfig(CompositorInterface *); 218 | virtual ~CompositorConfig(); 219 | CompositorInterface *pcompositorInt; 220 | }; 221 | 222 | class Loader{ 223 | public: 224 | Loader(const char *); 225 | ~Loader(); 226 | bool Run(const char *, const char *); 227 | 228 | //backend 229 | static bool standaloneComp; 230 | 231 | //compositor 232 | static bool noCompositor; 233 | static sint deviceIndex; 234 | static bool debugLayers; 235 | static bool scissoring; 236 | static bool incrementalPresent; 237 | //static bool hostMemoryImport; 238 | static Compositor::CompositorInterface::IMPORT_MODE memoryImportMode; 239 | static bool unredirOnFullscreen; 240 | }; 241 | 242 | } 243 | 244 | #endif 245 | 246 | -------------------------------------------------------------------------------- /src/CompositorResource.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPOSITOR_RESOURCE_H 2 | #define COMPOSITOR_RESOURCE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Compositor{ 8 | 9 | #define TEXTURE_BASE_FLAG_SKIP 0x1 10 | 11 | class TextureBase{ 12 | public: 13 | TextureBase(uint, uint, VkFormat, const VkComponentMapping *, uint, const class CompositorInterface *); 14 | virtual ~TextureBase(); 15 | // 16 | uint w, h; 17 | uint flags; 18 | uint formatIndex; 19 | uint componentMappingHash; 20 | VkImageLayout imageLayout; 21 | 22 | VkImage image; 23 | VkImageView imageView; 24 | VkDeviceMemory deviceMemory; 25 | 26 | const class CompositorInterface *pcomp; 27 | 28 | static inline uint GetComponentMappingHash(const VkComponentMapping *pcomponentMapping){ 29 | return pcomponentMapping->r|((uint)pcomponentMapping->g<<8)|((uint)pcomponentMapping->b<<16)|((uint)pcomponentMapping->a<<24); 30 | } 31 | static const std::vector> formatSizeMap; 32 | static const VkComponentMapping defaultComponentMapping; 33 | }; 34 | 35 | //texture class for shader reads 36 | class TextureStaged : virtual public TextureBase{ 37 | public: 38 | TextureStaged(uint, uint, VkFormat, const VkComponentMapping *, uint, const class CompositorInterface *); 39 | virtual ~TextureStaged(); 40 | const void * Map() const; 41 | void Unmap(const VkCommandBuffer *, const VkRect2D *, uint); 42 | //virtual void Update(const VkCommandBuffer *, const VkRect2D *, uint) = 0; 43 | 44 | VkBuffer stagingBuffer; 45 | VkDeviceMemory stagingMemory; 46 | 47 | uint stagingMemorySize; 48 | 49 | std::vector bufferImageCopyBuffer; //to avoid repeated dynamic allocations each time texture is updated in multiple regions 50 | }; 51 | 52 | class TexturePixmap : virtual public TextureBase{ 53 | public: 54 | TexturePixmap(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 55 | virtual ~TexturePixmap(); 56 | bool Attach(xcb_pixmap_t); 57 | void Detach(); 58 | void Update(const VkCommandBuffer *, const VkRect2D *, uint); 59 | 60 | const VkComponentMapping *pcomponentMapping; 61 | 62 | sint dmafd; 63 | const class X11Compositor *pcomp11; 64 | 65 | static const VkComponentMapping pixmapComponentMapping; 66 | static const VkComponentMapping pixmapComponentMapping24; 67 | }; 68 | 69 | class TextureHostPointer : virtual public TextureBase{ 70 | public: 71 | TextureHostPointer(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 72 | virtual ~TextureHostPointer(); 73 | bool Attach(unsigned char *); 74 | void Detach(uint64); 75 | void Update(const VkCommandBuffer *, const VkRect2D *, uint); 76 | 77 | const VkComponentMapping *pcomponentMapping; 78 | 79 | VkBuffer transferBuffer; 80 | std::vector> discards; 81 | }; 82 | 83 | class TextureDMABuffer : public TexturePixmap{ 84 | public: 85 | TextureDMABuffer(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 86 | ~TextureDMABuffer(); 87 | }; 88 | 89 | class TextureSharedMemory : public TextureHostPointer{ 90 | public: 91 | TextureSharedMemory(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 92 | ~TextureSharedMemory(); 93 | }; 94 | 95 | class TextureSharedMemoryStaged : public TextureStaged{ 96 | public: 97 | TextureSharedMemoryStaged(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 98 | ~TextureSharedMemoryStaged(); 99 | }; 100 | 101 | class TextureCompatible : public TextureStaged{ 102 | public: 103 | TextureCompatible(uint, uint, const VkComponentMapping *, uint, const class CompositorInterface *); 104 | ~TextureCompatible(); 105 | }; 106 | 107 | class Buffer{ 108 | public: 109 | Buffer(uint, VkBufferUsageFlagBits, const class CompositorInterface *); 110 | ~Buffer(); 111 | const void * Map() const; 112 | void Unmap(const VkCommandBuffer *); 113 | 114 | const class CompositorInterface *pcomp; 115 | VkBuffer buffer; 116 | VkDeviceMemory deviceMemory; 117 | 118 | VkBuffer stagingBuffer; 119 | VkDeviceMemory stagingMemory; 120 | 121 | uint stagingMemorySize; 122 | uint size; 123 | }; 124 | 125 | class ShaderModule{ 126 | public: 127 | ShaderModule(const char *, const Blob *, const class CompositorInterface *); 128 | ~ShaderModule(); 129 | 130 | const class CompositorInterface *pcomp; 131 | const char *pname; 132 | VkShaderModule shaderModule; 133 | VkPushConstantRange *pPushConstantRanges; 134 | //VKPushConstantRange pushConstantRange; //only one range can exist 135 | VkDescriptorSetLayout *pdescSetLayouts; 136 | uint pushConstantBlockCount; 137 | uint setCount; 138 | //uint inputCount; 139 | //uint inputStride; 140 | 141 | struct Binding{ 142 | const char *pname; 143 | VkDescriptorType type; 144 | uint setIndex; 145 | uint binding; 146 | }; 147 | std::vector bindings; 148 | 149 | struct Input{ 150 | uint location; //index of the input 151 | uint binding; 152 | //uint offset; //byte offset 153 | uint semanticMapIndex; //index to semantic map 154 | }; 155 | std::vector inputs; 156 | 157 | struct Variable{ 158 | uint offset; 159 | uint variableMapIndex; 160 | }; 161 | std::vector variables; 162 | 163 | enum INPUT{ 164 | INPUT_POSITION_SFLOAT2, 165 | INPUT_POSITION_UINT2, 166 | INPUT_TEXCOORD_SFLOAT2, 167 | INPUT_TEXCOORD_UINT2, 168 | INPUT_COUNT 169 | }; 170 | static const std::vector> semanticMap; 171 | enum VARIABLE{ 172 | VARIABLE_XY0, 173 | VARIABLE_XY1, 174 | VARIABLE_TRANSFORM, 175 | VARIABLE_SCREEN, 176 | VARIABLE_MARGIN, 177 | VARIABLE_TITLEPAD, 178 | VARIABLE_TITLESPAN, 179 | VARIABLE_STACKINDEX, 180 | VARIABLE_FLAGS, 181 | VARIABLE_TIME, 182 | VARIABLE_COUNT 183 | }; 184 | static const std::vector> variableMap; 185 | }; 186 | 187 | class Pipeline{ 188 | public: 189 | Pipeline(ShaderModule *, ShaderModule *, ShaderModule *, const std::vector> *, const VkPipelineInputAssemblyStateCreateInfo *, const VkPipelineRasterizationStateCreateInfo *, const VkPipelineDepthStencilStateCreateInfo *, const VkPipelineColorBlendStateCreateInfo *, const VkPipelineDynamicStateCreateInfo *, const class CompositorInterface *); 190 | virtual ~Pipeline(); 191 | 192 | enum SHADER_MODULE{ 193 | SHADER_MODULE_VERTEX, 194 | SHADER_MODULE_GEOMETRY, 195 | SHADER_MODULE_FRAGMENT, 196 | SHADER_MODULE_COUNT 197 | }; //note: code in Pipeline() relies on this order 198 | ShaderModule *pshaderModule[SHADER_MODULE_COUNT]; 199 | const class CompositorInterface *pcomp; 200 | VkPushConstantRange pushConstantRange; 201 | VkPipelineLayout pipelineLayout; 202 | VkPipeline pipeline; 203 | }; 204 | 205 | class ClientPipeline : public Pipeline{ //, public Desc 206 | public: 207 | ClientPipeline(ShaderModule *, ShaderModule *, ShaderModule *, const std::vector> *, const class CompositorInterface *); 208 | ~ClientPipeline(); 209 | static const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; 210 | static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState; 211 | static const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo; 212 | static const VkDynamicState dynamicStatesScissoring[1]; 213 | static const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo; 214 | static const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfoScissoring; 215 | static const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo; 216 | }; 217 | 218 | class TextPipeline : public Pipeline{ 219 | public: 220 | TextPipeline(ShaderModule *, ShaderModule *, ShaderModule *, const std::vector> *, const class CompositorInterface *); 221 | ~TextPipeline(); 222 | static const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; 223 | static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState; 224 | static const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo; 225 | static const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo; 226 | }; 227 | 228 | } 229 | 230 | #endif 231 | 232 | -------------------------------------------------------------------------------- /src/backend.h: -------------------------------------------------------------------------------- 1 | #ifndef BACKEND_H 2 | #define BACKEND_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Compositor{ 10 | //declarations for friend classes 11 | class X11ClientFrame; 12 | class X11Background; 13 | class X11Compositor; 14 | class X11DebugCompositor; 15 | class TexturePixmap; 16 | } 17 | 18 | namespace WManager{ 19 | class Client; 20 | class Container; 21 | } 22 | 23 | namespace Backend{ 24 | 25 | class BackendProperty{ 26 | public: 27 | enum PROPERTY_TYPE{ 28 | PROPERTY_TYPE_STRING, 29 | PROPERTY_TYPE_CLIENT, 30 | PROPERTY_TYPE_PIXMAP 31 | }; 32 | BackendProperty(PROPERTY_TYPE); 33 | virtual ~BackendProperty(); 34 | PROPERTY_TYPE type; 35 | }; 36 | 37 | class BackendStringProperty : public BackendProperty{ 38 | public: 39 | BackendStringProperty(const char *); 40 | ~BackendStringProperty(); 41 | const char *pstr; 42 | }; 43 | 44 | class BackendContainerProperty : public BackendProperty{ 45 | public: 46 | BackendContainerProperty(WManager::Container *); 47 | ~BackendContainerProperty(); 48 | WManager::Container *pcontainer; 49 | }; 50 | 51 | class BackendPixmapProperty : public BackendProperty{ 52 | public: 53 | BackendPixmapProperty(xcb_pixmap_t); 54 | ~BackendPixmapProperty(); 55 | xcb_pixmap_t pixmap; 56 | }; 57 | 58 | class BackendEvent{ 59 | public: 60 | BackendEvent(); 61 | virtual ~BackendEvent(); 62 | }; 63 | 64 | class BackendInterface{ 65 | public: 66 | BackendInterface(); 67 | virtual ~BackendInterface(); 68 | virtual void Start() = 0; 69 | virtual void Stop() = 0; 70 | //virtual sint GetEventFileDescriptor() = 0; 71 | //virtual void SetupEnvironment() = 0; 72 | virtual sint HandleEvent(bool) = 0; 73 | virtual void MoveContainer(WManager::Container *, WManager::Container *) = 0; 74 | virtual void FloatContainer(WManager::Container *) = 0; 75 | virtual const std::vector> * GetStackAppendix() const = 0; 76 | virtual void SortStackAppendix() = 0; 77 | protected: 78 | //Functions defined by the implementing backends. 79 | virtual void DefineBindings() = 0; 80 | virtual bool EventNotify(const BackendEvent *) = 0; 81 | virtual void WakeNotify() = 0; 82 | virtual void KeyPress(uint, bool) = 0; 83 | }; 84 | 85 | class X11Event : public BackendEvent{ 86 | public: 87 | X11Event(xcb_generic_event_t *, const class X11Backend *); 88 | ~X11Event(); 89 | xcb_generic_event_t *pevent; 90 | const X11Backend *pbackend; 91 | }; 92 | 93 | class X11Client : public WManager::Client{ 94 | public: 95 | struct CreateInfo{ 96 | xcb_window_t window; 97 | const WManager::Rectangle *prect; 98 | const WManager::Client *pstackClient; //TODO: -> client 99 | const class X11Backend *pbackend; 100 | enum{ 101 | CREATE_CONTAINED, 102 | CREATE_AUTOMATIC 103 | } mode; 104 | enum{ 105 | HINT_DESKTOP = 0x1, 106 | HINT_ABOVE = 0x2, 107 | HINT_NO_INPUT = 0x4, 108 | HINT_FULLSCREEN = 0x8, 109 | HINT_FLOATING = 0x10 110 | }; 111 | uint hints; 112 | const BackendStringProperty *pwmName; 113 | const BackendStringProperty *pwmClass; 114 | }; 115 | X11Client(class X11Container *, const CreateInfo *); 116 | ~X11Client(); 117 | virtual void AdjustSurface1(){}; 118 | virtual void Redirect1(){}; 119 | virtual void StartComposition1(){}; 120 | virtual void Unredirect1(){}; 121 | virtual void StopComposition1(){}; 122 | virtual void SetTitle1(const char *){}; 123 | //virtual void SetFullscreen1(bool){}; 124 | void UpdateTranslation(); //manual mode update 125 | void UpdateTranslation(const WManager::Rectangle *); //automatic mode update 126 | bool ProtocolSupport(xcb_atom_t); 127 | void Kill(); 128 | xcb_window_t window; 129 | enum FLAG{ 130 | FLAG_UNMAPPING = 0x1 131 | }; 132 | uint flags; 133 | const X11Backend *pbackend; 134 | }; 135 | 136 | class X11Container : public WManager::Container{ 137 | public: 138 | X11Container(class X11Backend *, bool); 139 | X11Container(WManager::Container *, const WManager::Container::Setup &, class X11Backend *); 140 | virtual ~X11Container(); 141 | void Focus1(); 142 | void Place1(WManager::Container *); 143 | void Stack1(); 144 | void Fullscreen1(); 145 | void SetClient(X11Client *); 146 | const X11Backend *pbackend; 147 | X11Client *pclient11; 148 | bool noComp; 149 | }; 150 | 151 | class X11Backend : public BackendInterface{ 152 | friend class X11Event; 153 | friend class X11Client; 154 | friend class X11Container; 155 | friend class DebugClient; 156 | friend class Compositor::X11ClientFrame; 157 | friend class Compositor::X11Background; 158 | friend class Compositor::X11Compositor; 159 | friend class Compositor::X11DebugCompositor; 160 | friend class Compositor::TexturePixmap; 161 | public: 162 | X11Backend(bool); 163 | virtual ~X11Backend(); 164 | bool QueryExtension(const char *, sint *, sint *) const; 165 | xcb_atom_t GetAtom(const char *) const; 166 | void StackRecursiveAppendix(const WManager::Client *, const WManager::Container *); 167 | void StackRecursive(const WManager::Container *, const WManager::Container *); 168 | void StackClients(const WManager::Container *); 169 | void ForEachRecursive(X11Container *, WManager::Container *, void (*)(X11Container *, WManager::Client *)); 170 | void ForEach(X11Container *, void (*)(X11Container *, WManager::Client *)); 171 | void BindKey(uint, uint, uint); 172 | void MapKey(uint, uint, uint); 173 | void GrabKeyboard(bool); 174 | //void HandleTimer() const; 175 | enum MODE{ 176 | MODE_UNDEFINED, 177 | MODE_MANUAL, 178 | MODE_AUTOMATIC 179 | }; 180 | virtual X11Client * FindClient(xcb_window_t, MODE) const = 0; 181 | virtual void TimerEvent() = 0; 182 | virtual bool ApproveExternal(const BackendStringProperty *, const BackendStringProperty *) = 0; 183 | //void * GetProperty(xcb_atom_t, xcb_atom_t) const; 184 | //void FreeProperty(...) const; 185 | protected: 186 | xcb_connection_t *pcon; 187 | xcb_screen_t *pscr; 188 | xcb_key_symbols_t *psymbols; 189 | xcb_window_t window; //root or test window 190 | xcb_timestamp_t lastTime; 191 | struct timespec eventTimer; 192 | struct timespec pollTimer; 193 | struct timespec inputTimer; //track time since last keypress 194 | //bool polling; 195 | struct KeyBinding{ 196 | xcb_keycode_t keycode; 197 | uint mask; 198 | uint keyId; 199 | }; 200 | std::vector keycodes; //user defined id associated with the keycode 201 | xcb_ewmh_connection_t ewmh; 202 | xcb_window_t ewmh_window; 203 | 204 | public: 205 | std::deque clientStack; 206 | WManager::Client *pfocusInClient; //from XCB_FOCUS_IN events (uncontained clients) 207 | protected: 208 | std::deque> appendixQueue; //no need to store, rather keep it here to avoid repeated construction 209 | bool standaloneComp; 210 | 211 | enum ATOM{ 212 | //ATOM_CHAMFER_ALARM, 213 | //add to patomStrs 214 | ATOM_WM_PROTOCOLS, 215 | ATOM_WM_DELETE_WINDOW, 216 | ATOM_WM_TAKE_FOCUS, 217 | ATOM_ESETROOT_PMAP_ID, 218 | ATOM_X_ROOTPMAP_ID, 219 | ATOM_COUNT 220 | }; 221 | xcb_atom_t atoms[ATOM_COUNT]; 222 | static const char *patomStrs[ATOM_COUNT]; 223 | 224 | xcb_cursor_context_t *pcursorctx; 225 | enum CURSOR{ 226 | CURSOR_POINTER, 227 | CURSOR_COUNT 228 | }; 229 | xcb_cursor_t cursors[CURSOR_COUNT]; 230 | static const char *pcursorStrs[CURSOR_COUNT]; 231 | }; 232 | 233 | class Default : public X11Backend{ 234 | public: 235 | Default(bool); 236 | virtual ~Default(); 237 | void Start(); 238 | void Stop(); 239 | sint HandleEvent(bool); 240 | X11Client * FindClient(xcb_window_t, MODE) const; 241 | protected: 242 | enum PROPERTY_ID{ 243 | PROPERTY_ID_PIXMAP, 244 | PROPERTY_ID_WM_NAME, 245 | PROPERTY_ID_WM_CLASS, 246 | PROPERTY_ID_TRANSIENT_FOR, 247 | }; 248 | virtual X11Client * SetupClient(const X11Client::CreateInfo *) = 0; 249 | virtual WManager::Container * CreateWorkspace(const char *) = 0; 250 | virtual void SetFullscreen(X11Client *, bool) = 0; 251 | virtual void SetFocus(X11Client *) = 0; 252 | virtual void Enter(X11Client *) = 0; 253 | virtual void PropertyChange(X11Client *, PROPERTY_ID, const BackendProperty *) = 0; 254 | virtual void DestroyClient(X11Client *) = 0; 255 | private: 256 | xcb_keycode_t exitKeycode; 257 | //xcb_keycode_t testKeycode; 258 | typedef std::tuple ConfigCacheElement; 259 | std::vector> clients; 260 | std::vector configCache; 261 | std::vector netClientList; //used only to update the property - not maintained 262 | std::set unmappingQueue; 263 | X11Client *pdragClient; 264 | sint dragRootX, dragRootY; 265 | }; 266 | 267 | class DebugClient : public WManager::Client{ 268 | public: 269 | struct CreateInfo{ 270 | const class X11Backend *pbackend; 271 | }; 272 | DebugClient(class DebugContainer *, const CreateInfo *); 273 | ~DebugClient(); 274 | virtual void AdjustSurface1(){}; 275 | virtual void SetTitle1(const char *){}; 276 | void UpdateTranslation(); 277 | void Kill(); 278 | const X11Backend *pbackend; 279 | }; 280 | 281 | class DebugContainer : public WManager::Container{ 282 | public: 283 | DebugContainer(class X11Backend *); 284 | DebugContainer(WManager::Container *, const WManager::Container::Setup &, class X11Backend *); 285 | virtual ~DebugContainer(); 286 | void Focus1(); 287 | void Stack1(); 288 | //void Fullscreen1(); 289 | void SetClient(DebugClient *); 290 | const X11Backend *pbackend; 291 | DebugClient *pdebugClient; 292 | }; 293 | 294 | class Debug : public X11Backend{ 295 | public: 296 | Debug(); 297 | virtual ~Debug(); 298 | void Start(); 299 | void Stop(); 300 | sint HandleEvent(bool); 301 | X11Client * FindClient(xcb_window_t, MODE) const; 302 | protected: 303 | virtual DebugClient * SetupClient(const DebugClient::CreateInfo *) = 0; 304 | virtual void DestroyClient(DebugClient *) = 0; 305 | private: 306 | xcb_keycode_t exitKeycode; 307 | xcb_keycode_t launchKeycode; 308 | xcb_keycode_t closeKeycode; 309 | std::vector clients; 310 | }; 311 | 312 | } 313 | 314 | #endif 315 | 316 | -------------------------------------------------------------------------------- /src/compositor.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPOSITOR_H 2 | #define COMPOSITOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | //struct gbm_device; 15 | 16 | namespace Backend{ 17 | class X11Backend; 18 | }; 19 | 20 | namespace Compositor{ 21 | 22 | class Drawable{ 23 | friend class CompositorInterface; 24 | public: 25 | Drawable(Pipeline *, CompositorInterface *); 26 | virtual ~Drawable(); 27 | // 28 | bool AssignPipeline(const Pipeline *); 29 | protected: 30 | void BindShaderResources(const std::vector> *, const VkCommandBuffer *); 31 | virtual void UpdateDescSets(){}; 32 | class CompositorInterface *pcomp; 33 | struct PipelineDescriptorSet{ 34 | uint64 fenceTag; 35 | const Pipeline *p; 36 | VkDescriptorSet *pdescSets[Pipeline::SHADER_MODULE_COUNT]; 37 | }; 38 | PipelineDescriptorSet *passignedSet; 39 | std::vector descSets; 40 | }; 41 | 42 | class ColorFrame : public Drawable{ 43 | friend class CompositorInterface; 44 | public: 45 | ColorFrame(const char *[Pipeline::SHADER_MODULE_COUNT], class CompositorInterface *); 46 | virtual ~ColorFrame(); 47 | void Draw(const VkRect2D &, const glm::vec2 &, const glm::vec2 &, const glm::vec2 &, uint, uint, const VkCommandBuffer *); 48 | protected: 49 | struct timespec creationTime; 50 | float time; 51 | public: 52 | uint shaderUserFlags; 53 | protected: 54 | uint shaderFlags; //current frame shader flags 55 | uint oldShaderFlags; //used to keep track of changes 56 | }; 57 | 58 | class ClientFrame : public ColorFrame{ 59 | friend class CompositorInterface; 60 | friend class X11Compositor; 61 | public: 62 | ClientFrame(const char *[Pipeline::SHADER_MODULE_COUNT], class CompositorInterface *); 63 | virtual ~ClientFrame(); 64 | virtual void UpdateContents(const VkCommandBuffer *) = 0; 65 | virtual void Exclude(bool); 66 | enum SURFACE_DEPTH{ 67 | SURFACE_DEPTH_24, 68 | SURFACE_DEPTH_32 69 | }; 70 | void CreateSurface(uint, uint, SURFACE_DEPTH, bool = false); 71 | void AdjustSurface(uint, uint); 72 | void DestroySurface(); 73 | void SetShaders(const char *[Pipeline::SHADER_MODULE_COUNT]); 74 | void SetTitle(const char *); 75 | enum SHADER_FLAG{ //+config 76 | SHADER_FLAG_FOCUS = 0x1, 77 | SHADER_FLAG_CONTAINER_FOCUS = 0x2, 78 | SHADER_FLAG_FLOATING = 0x4, 79 | SHADER_FLAG_STACKED = 0x8, 80 | SHADER_FLAG_USER_BIT = 0x10 81 | }; 82 | protected: 83 | void UpdateDescSets(); 84 | //Texture *ptexture; 85 | TextureBase *ptexture; 86 | class Text *ptitle; 87 | std::string title; 88 | SURFACE_DEPTH surfaceDepth; 89 | public: 90 | bool enabled; //in use and ready to draw 91 | protected: 92 | bool fullRegionUpdate; 93 | bool animationCompleted; 94 | }; 95 | 96 | class CompositorInterface{ 97 | friend class TextureBase; 98 | friend class TextureStaged; 99 | friend class TexturePixmap; 100 | friend class TextureHostPointer; 101 | //friend class Texture; 102 | friend class Buffer; 103 | friend class ShaderModule; 104 | friend class Pipeline; 105 | friend class ClientPipeline; 106 | friend class FontAtlas; 107 | friend class Text; 108 | friend class TextEngine; 109 | friend class Drawable; 110 | friend class ColorFrame; 111 | friend class ClientFrame; 112 | friend class X11ClientFrame; 113 | friend class X11Background; 114 | friend class X11DebugClientFrame; 115 | public: 116 | enum IMPORT_MODE{ 117 | IMPORT_MODE_DMABUF, 118 | IMPORT_MODE_HOST_MEMORY, 119 | IMPORT_MODE_CPU_COPY, 120 | IMPORT_MODE_COUNT 121 | }; 122 | struct Configuration{ 123 | uint deviceIndex; 124 | bool debugLayers; 125 | bool scissoring; 126 | bool incrementalPresent; 127 | //bool hostMemoryImport; 128 | IMPORT_MODE memoryImportMode; 129 | bool unredirOnFullscreen; 130 | bool enableAnimation; 131 | float animationDuration; 132 | const char *pfontName; 133 | uint fontSize; 134 | }; 135 | CompositorInterface(const Configuration *); 136 | virtual ~CompositorInterface(); 137 | virtual void Start() = 0; //initialize and start for the first time 138 | virtual void Stop() = 0; //stop and cleanup 139 | virtual void Resume() = 0; //resume after suspension 140 | virtual void Suspend() = 0; //suspend (unredirection, for example) 141 | protected: 142 | void InitializeRenderEngine(); 143 | void InitializeSwapchain(); 144 | void DestroyRenderEngine(); 145 | void DestroySwapchain(); 146 | void AddShader(const char *, const Blob *); 147 | void AddDamageRegion(const VkRect2D *); 148 | void AddDamageRegion(const WManager::Client *); 149 | public: //probably need a proxy 150 | void FullDamageRegion(); //quickly mark the whole screen for redrawing 151 | protected: 152 | void WaitIdle(); 153 | void CreateRenderQueueAppendix(const WManager::Client *, const WManager::Container *); 154 | void CreateRenderQueue(const WManager::Container *, const WManager::Container *); 155 | bool PollFrameFence(bool); 156 | void GenerateCommandBuffers(const std::deque *, const WManager::Container *, const WManager::Client *); 157 | void Present(); 158 | virtual bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const = 0; 159 | virtual void CreateSurfaceKHR(VkSurfaceKHR *) const = 0; 160 | virtual VkExtent2D GetExtent() const = 0; 161 | virtual glm::vec2 GetDPI() const = 0; 162 | VkInstance instance; 163 | VkSurfaceCapabilitiesKHR surfaceCapabilities; 164 | VkSurfaceKHR surface; 165 | VkDebugReportCallbackEXT debugReportCb; 166 | VkPhysicalDevice physicalDev; 167 | VkPhysicalDeviceProperties physicalDevProps; 168 | VkPhysicalDeviceExternalMemoryHostPropertiesEXT physicalDevExternalMemoryHostProps; 169 | VkDevice logicalDev; 170 | enum QUEUE_INDEX{ 171 | QUEUE_INDEX_GRAPHICS, 172 | QUEUE_INDEX_PRESENT, 173 | //QUEUE_INDEX_TRANSFER, 174 | QUEUE_INDEX_COUNT 175 | }; 176 | VkQueue queue[QUEUE_INDEX_COUNT]; 177 | VkRenderPass renderPass; 178 | VkSwapchainKHR swapChain; 179 | VkExtent2D imageExtent; 180 | VkImage *pswapChainImages; 181 | VkImageView *pswapChainImageViews; 182 | VkFramebuffer *pframebuffers; 183 | enum SEMAPHORE_INDEX{ 184 | SEMAPHORE_INDEX_IMAGE_AVAILABLE, 185 | SEMAPHORE_INDEX_RENDER_FINISHED, 186 | SEMAPHORE_INDEX_COUNT 187 | }; 188 | VkSemaphore (*psemaphore)[SEMAPHORE_INDEX_COUNT]; 189 | VkFence *pfence; 190 | //back buffer to enable the use of previous frame contents 191 | //VkImage renderImage; 192 | //VkDeviceMemory renderImageDeviceMemory; 193 | 194 | VkCommandPool commandPool; 195 | VkCommandBuffer *pcommandBuffers; 196 | VkCommandBuffer *pcopyCommandBuffers; 197 | 198 | //VkDescriptorPool descPool; 199 | std::deque descPoolArray; 200 | std::vector> descPoolReference; 201 | 202 | uint queueFamilyIndex[QUEUE_INDEX_COUNT]; // 203 | uint physicalDevIndex; 204 | uint swapChainImageCount; 205 | uint currentFrame; 206 | uint imageIndex; 207 | 208 | template 209 | Pipeline * LoadPipeline(const char *[Pipeline::SHADER_MODULE_COUNT], const std::vector> *); 210 | 211 | std::vector shaders; 212 | std::vector> pipelines; //hash, pipeline 213 | 214 | std::vector updateQueue; 215 | std::vector titleUpdateQueue; 216 | //Scissoring regions based on client damage. Second (uint) is a bitmask for 217 | //swap chain images, indicating which image has been updated so far. When 218 | //all images have been updated, the region is removed from the list. 219 | std::vector> scissorRegions; 220 | std::vector presentRectLayers; 221 | 222 | void ClearBackground(); 223 | 224 | ColorFrame *pcolorBackground; 225 | ColorFrame *pbackground; 226 | public: 227 | class TextEngine *ptextEngine; 228 | const char *pfontName; 229 | uint fontSize; 230 | protected: 231 | 232 | VkSampler pointSampler; 233 | 234 | struct timespec frameTime; 235 | uint64 frameTag; //frame counter, to prevent releasing resources still in use 236 | 237 | struct RenderObject{ 238 | WManager::Client *pclient; 239 | ClientFrame *pclientFrame; 240 | //uint flags; 241 | }; 242 | std::vector renderQueue; 243 | 244 | //Used textures get stored for potential reuse before they get destroyed and while waiting for the pipeline to get flushed. 245 | //Many of the allocated window textures will initially have some common reoccuring size. 246 | TextureBase * CreateTexture(uint, uint, ClientFrame::SURFACE_DEPTH, bool = false); 247 | void ReleaseTexture(TextureBase *); 248 | 249 | struct TextureCacheEntry{ 250 | TextureBase *ptexture; 251 | uint64 releaseTag; 252 | struct timespec releaseTime; 253 | }; 254 | std::vector textureCache; 255 | 256 | VkDescriptorSet * CreateDescSets(const ShaderModule *); 257 | void ReleaseDescSets(const ShaderModule *, VkDescriptorSet *); 258 | 259 | struct DescSetCacheEntry{ 260 | VkDescriptorSet *pdescSets; 261 | uint setCount; 262 | uint64 releaseTag; 263 | }; 264 | std::vector descSetCache; 265 | 266 | std::set> drmFormatModifiers; //mod, planes 267 | 268 | ClientFrame *pfsApp; //fullscreen state app for the current frame (for unredirection) 269 | ClientFrame *pfsAppPrev; //fullscreen state app during previous frame (for unredirection) 270 | bool frameApproval; 271 | bool suspended; //entire compositor is suspended - all windows are unredirected 272 | bool unredirected; //one of the applications is underirected due to it being fullscreen 273 | bool playingAnimation; 274 | 275 | //config 276 | bool debugLayers; 277 | bool scissoring; 278 | bool incrementalPresent; 279 | bool unredirOnFullscreen; 280 | IMPORT_MODE memoryImportMode; 281 | 282 | public: 283 | bool enableAnimation; 284 | float animationDuration; 285 | protected: 286 | 287 | static VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayerDebugCallback(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *, void *); 288 | static VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayerDebugCallback2(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *); 289 | }; 290 | 291 | class X11ClientFrame : public Backend::X11Client, public ClientFrame{ 292 | public: 293 | X11ClientFrame(Backend::X11Container *, const Backend::X11Client::CreateInfo *, const char *[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *); 294 | ~X11ClientFrame(); 295 | void UpdateContents(const VkCommandBuffer *); 296 | void Exclude(bool); 297 | void AdjustSurface1(); 298 | void Redirect1(); 299 | void StartComposition1(); 300 | void Unredirect1(); 301 | void StopComposition1(); 302 | void SetTitle1(const char *); 303 | xcb_pixmap_t windowPixmap; 304 | xcb_shm_seg_t segment; 305 | xcb_damage_damage_t damage; 306 | std::vector damageRegions; 307 | sint shmid; 308 | unsigned char *pchpixels; 309 | }; 310 | 311 | class X11Background : public ClientFrame{ 312 | public: 313 | X11Background(xcb_pixmap_t, uint, uint, const char *[Pipeline::SHADER_MODULE_COUNT], X11Compositor *); 314 | ~X11Background(); 315 | void UpdateContents(const VkCommandBuffer *); 316 | 317 | X11Compositor *pcomp11; 318 | xcb_pixmap_t pixmap; 319 | xcb_shm_seg_t segment; 320 | uint w, h; 321 | sint shmid; 322 | unsigned char *pchpixels; 323 | }; 324 | 325 | //Default compositor assumes XCB for its surface 326 | class X11Compositor : public CompositorInterface{ 327 | friend class TexturePixmap; 328 | public: 329 | //Derivatives of compositor classes should not point to their default corresponding backend classes (Backend::Default in this case). This is to allow the compositor to be independent of the backend implementation, as long as it's based on X11 here. 330 | X11Compositor(const Configuration *, const Backend::X11Backend *); 331 | ~X11Compositor(); 332 | virtual void Start(); 333 | virtual void Stop(); 334 | virtual void Resume(); 335 | virtual void Suspend(); 336 | bool FilterEvent(const Backend::X11Event *); 337 | bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const; 338 | void CreateSurfaceKHR(VkSurfaceKHR *) const; 339 | void SetBackgroundPixmap(const Backend::BackendPixmapProperty *); 340 | VkExtent2D GetExtent() const; 341 | glm::vec2 GetDPI() const; 342 | const Backend::X11Backend *pbackend; 343 | /*struct gbm_device *pgbmdev; 344 | sint cardfd;*/ 345 | xcb_window_t overlay; 346 | protected: 347 | sint compEventOffset; 348 | sint compErrorOffset; 349 | sint xfixesEventOffset; 350 | sint xfixesErrorOffset; 351 | sint damageEventOffset; 352 | sint damageErrorOffset; 353 | }; 354 | 355 | class X11DebugClientFrame : public Backend::DebugClient, public ClientFrame{ 356 | public: 357 | X11DebugClientFrame(Backend::DebugContainer *, const Backend::DebugClient::CreateInfo *, const char *[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *); 358 | ~X11DebugClientFrame(); 359 | void UpdateContents(const VkCommandBuffer *); 360 | void AdjustSurface1(); 361 | void Redirect1(); 362 | void StartComposition1(); 363 | void Unredirect1(); 364 | void StopComposition1(); 365 | void SetTitle1(const char *); 366 | }; 367 | 368 | class X11DebugCompositor : public X11Compositor{ 369 | public: 370 | X11DebugCompositor(const Configuration *, const Backend::X11Backend *); 371 | ~X11DebugCompositor(); 372 | void Start(); 373 | void Stop(); 374 | void Resume(); 375 | void Suspend(); 376 | }; 377 | 378 | class NullCompositor : public CompositorInterface{ 379 | public: 380 | NullCompositor(); 381 | ~NullCompositor(); 382 | void Start(); 383 | void Stop(); 384 | void Resume(); 385 | void Suspend(); 386 | bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const; 387 | void CreateSurfaceKHR(VkSurfaceKHR *) const; 388 | VkExtent2D GetExtent() const; 389 | glm::vec2 GetDPI() const; 390 | Configuration config{ //dummy config 391 | .deviceIndex = 0, 392 | .debugLayers = false, 393 | .scissoring = true, 394 | .incrementalPresent = true, 395 | //.hostMemoryImport = true, 396 | .memoryImportMode = IMPORT_MODE_DMABUF, 397 | .enableAnimation = false, 398 | .animationDuration = 0.3f, 399 | .pfontName = "Monospace", 400 | .fontSize = 18, 401 | }; 402 | }; 403 | 404 | } 405 | 406 | #endif 407 | 408 | -------------------------------------------------------------------------------- /src/CompositorFont.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "container.h" 3 | #include "backend.h" 4 | #include "CompositorResource.h" 5 | #include "compositor.h" 6 | #include "CompositorFont.h" 7 | #include 8 | #include 9 | 10 | namespace Compositor{ 11 | 12 | FontAtlas::FontAtlas(uint _size, TextEngine *_ptextEngine) : ptextEngine(_ptextEngine), size(_size), fontAtlasCursor(0), refCount(1), releaseTag(_ptextEngine->pcomp->frameTag){ 13 | // 14 | ptexture = new TextureStaged(size,size,VK_FORMAT_R8_UNORM,&TextureBase::defaultComponentMapping,0,ptextEngine->pcomp); 15 | } 16 | 17 | FontAtlas::~FontAtlas(){ 18 | delete ptexture; 19 | } 20 | 21 | void FontAtlas::Update(hb_glyph_info_t *pglyphInfo, uint glyphCount, const VkCommandBuffer *pcommandBuffer){ 22 | for(uint i = 0; i < glyphCount; ++i) 23 | if(std::find_if(glyphCollection.begin(),glyphCollection.end(),[&](auto r)->bool{ 24 | return r.codepoint == pglyphInfo[i].codepoint; 25 | }) == glyphCollection.end()){ 26 | TextEngine::Glyph *pglyph = ptextEngine->LoadGlyph(pglyphInfo[i].codepoint); 27 | if(fontAtlasCursor.x+pglyph->w >= size){ 28 | fontAtlasCursor.x = 0; 29 | fontAtlasCursor.y += (ptextEngine->fontFace->size->metrics.height>>6)+1; 30 | } 31 | 32 | GlyphEntry glyphEntry; 33 | glyphEntry.codepoint = pglyphInfo[i].codepoint; 34 | glyphEntry.texc = fontAtlasCursor; 35 | glyphEntry.pglyph = pglyph; 36 | glyphCollection.push_back(glyphEntry); 37 | 38 | fontAtlasCursor.x += pglyph->w+1; 39 | } 40 | 41 | unsigned char *pdata = (unsigned char *)ptexture->Map(); 42 | 43 | for(auto &glyphEntry : glyphCollection){ 44 | TextEngine::Glyph *pglyph = ptextEngine->LoadGlyph(glyphEntry.codepoint); 45 | for(uint y = 0; y < pglyph->h; ++y){ 46 | uint offsetDst = size*(glyphEntry.texc.y+y)+glyphEntry.texc.x; 47 | uint offsetSrc = pglyph->w*y; 48 | memcpy(pdata+offsetDst,pglyph->pbuffer+offsetSrc,pglyph->w); 49 | } 50 | } 51 | 52 | /*FILE *pf = fopen("/tmp/output.bin","wb"); 53 | fwrite(pdata,1,pfontAtlas->size*pfontAtlas->size,pf); 54 | fclose(pf);*/ 55 | 56 | //loop over glyphCollection, map everything according to their texcoord 57 | 58 | //TODO: partial update 59 | /*std::vector glyphIndexMap; //todo: move to TextEngine, clear() after use 60 | for(uint i = 0; i < glyphCount; ++i) 61 | if(std::find_if(pfontAtlas->glyphCollection.begin(),pfontAtlas->glyphCollection.end(),[&](auto r)->bool{ 62 | return r.first == pglyphInfo[i].codepoint; 63 | }) == pfontAtlas->glyphCollection.end()){ 64 | auto m = std::find_if(ptextEngine->glyphMap.begin(),ptextEngine->glyphMap.end(),[&](auto r1)->bool{ 65 | return pglyphInfo[i].codepoint == r1.codepoint; 66 | }); 67 | glyphIndexMap.push_back(m-ptextEngine->glyphMap.begin()); 68 | } 69 | 70 | for(uint i : glyphIndexMap){ 71 | if(pfontAtlas->fontAtlasCursor.x+ptextEngine->glyphMap[i].w >= pfontAtlas->size){ 72 | pfontAtlas->fontAtlasCursor.x = 0; 73 | pfontAtlas->fontAtlasCursor.y += (ptextEngine->fontFace->size->metrics.height>>6)+1; 74 | } 75 | ptextEngine->glyphMap[i].texc = pfontAtlas->fontAtlasCursor; 76 | pfontAtlas->fontAtlasCursor.x += ptextEngine->glyphMap[i].w+1; 77 | 78 | for(uint y = 0; y < ptextEngine->glyphMap[i].h; ++y){ 79 | uint offsetDst = pfontAtlas->size*(ptextEngine->glyphMap[i].texc.y+y)+ptextEngine->glyphMap[i].texc.x; 80 | uint offsetSrc = ptextEngine->glyphMap[i].w*y; 81 | memcpy(pdata+offsetDst,ptextEngine->glyphMap[i].pbuffer+offsetSrc,ptextEngine->glyphMap[i].w); 82 | } 83 | }*/ 84 | 85 | VkRect2D atlasRect; 86 | atlasRect.offset = {0,0}; 87 | atlasRect.extent = {size,size}; 88 | ptexture->Unmap(pcommandBuffer,&atlasRect,1); 89 | } 90 | 91 | Text::Text(const char *pshaderName[Pipeline::SHADER_MODULE_COUNT], TextEngine *_ptextEngine) : Drawable(_ptextEngine->pcomp->LoadPipeline(pshaderName,&vertexBufferLayout),_ptextEngine->pcomp), glyphCount(0), textLength(0.0f), ptextEngine(_ptextEngine), pfontAtlas(0){ 92 | // 93 | phbBuf = hb_buffer_create(); 94 | hb_buffer_set_direction(phbBuf,HB_DIRECTION_LTR); 95 | hb_buffer_set_script(phbBuf,HB_SCRIPT_LATIN); 96 | hb_buffer_set_language(phbBuf,hb_language_from_string("en",-1)); 97 | 98 | pvertexBuffer = ptextEngine->CreateVertexBuffer(); 99 | } 100 | 101 | Text::~Text(){ 102 | if(pfontAtlas) 103 | ptextEngine->ReleaseAtlas(pfontAtlas); 104 | ptextEngine->ReleaseVertexBuffer(pvertexBuffer); 105 | 106 | hb_buffer_destroy(phbBuf); 107 | } 108 | 109 | //TODO: text max length, terminate oversized text with '...' 110 | void Text::Set(const char *ptext, const VkCommandBuffer *pcommandBuffer){ 111 | hb_buffer_reset(phbBuf); 112 | hb_buffer_add_utf8(phbBuf,ptext,-1,0,-1); 113 | hb_buffer_guess_segment_properties(phbBuf); 114 | hb_shape(ptextEngine->phbFont,phbBuf,0,0); 115 | 116 | hb_glyph_info_t *pglyphInfo = hb_buffer_get_glyph_infos(phbBuf,&glyphCount); 117 | hb_glyph_position_t *pglyphPos = hb_buffer_get_glyph_positions(phbBuf,&glyphCount); 118 | 119 | FontAtlas *pfontAtlas1 = ptextEngine->CreateAtlas(pglyphInfo,glyphCount,pcommandBuffer); 120 | if(pfontAtlas1 != pfontAtlas){ 121 | if(pfontAtlas) 122 | ptextEngine->ReleaseAtlas(pfontAtlas); 123 | pfontAtlas = pfontAtlas1; 124 | 125 | AssignPipeline(passignedSet->p); 126 | UpdateDescSets(); 127 | } 128 | 129 | if(glyphCount == 0) 130 | return; 131 | 132 | //pfontAtlas->Update(pglyphInfo,glyphCount,pcommandBuffer); 133 | 134 | Vertex *pvertices = (Vertex*)pvertexBuffer->Map(); 135 | 136 | //TODO: load all glyphs here before filling the vertex buffers. If change in texture size is required, 137 | //create a new texture. At the same time, see if any of the old glyphs can be purged. 138 | //Descriptor set for only this Text has to be updated. If texture size stays the same, 139 | //append to the current most recently created texture (or any other previously created texture - there might 140 | //even be a texture with everything readily available). 141 | 142 | //Text objects keep a pointer to the texture they use. If the users of some particular texture decreases to zero, 143 | //texture is freed. Use ReleaseTexture to decrease a reference counter, and mark the frame tag when ready to free. 144 | 145 | //test triangle 146 | /*pvertices[0].pos = glm::vec2(0.0f,-0.5f); 147 | pvertices[1].pos = glm::vec2(0.5f,0.5f); 148 | pvertices[2].pos = glm::vec2(-0.5f,0.5f);*/ 149 | 150 | //test quad 151 | /*pvertices[0].pos = glm::vec2(-1.0f,-1.0f); 152 | pvertices[1].pos = glm::vec2(-1.0f,0.0f); 153 | pvertices[2].pos = glm::vec2(0.0f,-1.0f); 154 | pvertices[3].pos = glm::vec2(0.0f,0.0f);*/ 155 | 156 | glm::vec2 position(0.0f); 157 | for(uint i = 0; i < glyphCount; ++i){ 158 | glm::vec2 advance = glm::vec2(pglyphPos[i].x_advance,pglyphPos[i].y_advance)/64.0f; 159 | glm::vec2 offset = glm::vec2(pglyphPos[i].x_offset,pglyphPos[i].y_offset)/64.0f; 160 | 161 | auto m = std::find_if(pfontAtlas->glyphCollection.begin(),pfontAtlas->glyphCollection.end(),[&](auto r)->bool{ 162 | return r.codepoint == pglyphInfo[i].codepoint; 163 | }); 164 | 165 | glm::vec2 xy0 = position+offset+(*m).pglyph->offset; //+0.5f in Draw() 166 | glm::vec2 xy1 = xy0+glm::vec2((*m).pglyph->w,(*m).pglyph->h); 167 | 168 | pvertices[4*i+0].pos = xy0; 169 | pvertices[4*i+1].pos = glm::vec2(xy1.x,xy0.y); 170 | pvertices[4*i+2].pos = glm::vec2(xy0.x,xy1.y); 171 | pvertices[4*i+3].pos = glm::vec2(xy1.x,xy1.y); 172 | /*pvertices[4*i+0].pos = scale*xy0-1.0f; 173 | pvertices[4*i+1].pos = scale*glm::vec2(xy1.x,xy0.y)-1.0f; 174 | pvertices[4*i+2].pos = scale*glm::vec2(xy0.x,xy1.y)-1.0f; 175 | pvertices[4*i+3].pos = scale*glm::vec2(xy1.x,xy1.y)-1.0f;*/ 176 | 177 | pvertices[4*i+0].texc = (*m).texc;//use posh to get sample location 178 | pvertices[4*i+1].texc = (*m).texc+glm::uvec2((*m).pglyph->w,0); 179 | pvertices[4*i+2].texc = (*m).texc+glm::uvec2(0,(*m).pglyph->h); 180 | pvertices[4*i+3].texc = (*m).texc+glm::uvec2((*m).pglyph->w,(*m).pglyph->h); 181 | 182 | position += advance; 183 | } 184 | pvertexBuffer->Unmap(pcommandBuffer); 185 | 186 | textLength = position.x+(float)(ptextEngine->fontFace->size->metrics.max_advance>>6); 187 | 188 | if(ptextEngine->indexBufferMapped) 189 | return; //shared between all the Text objects, mapped only once 190 | ptextEngine->indexBufferMapped = true; 191 | 192 | unsigned short *pindices = (unsigned short*)ptextEngine->pindexBuffer->Map(); 193 | 194 | //test quad 195 | /*pindices[0] = 0; 196 | pindices[1] = 1; 197 | pindices[2] = 2; 198 | pindices[3] = 1; 199 | pindices[4] = 2; 200 | pindices[5] = 3;*/ 201 | 202 | //for(uint i = 0; i < glyphCount; ++i){ 203 | for(uint i = 0; i < 1024; ++i){ 204 | pindices[6*i+0] = 4*i; 205 | pindices[6*i+1] = 4*i+1; 206 | pindices[6*i+2] = 4*i+2; 207 | pindices[6*i+3] = 4*i+1; 208 | pindices[6*i+4] = 4*i+2; 209 | pindices[6*i+5] = 4*i+3; 210 | } 211 | 212 | ptextEngine->pindexBuffer->Unmap(pcommandBuffer); 213 | } 214 | 215 | void Text::Draw(const glm::uvec2 &pos, const glm::mat2x2 &transform, const VkCommandBuffer *pcommandBuffer){ 216 | // 217 | glm::vec2 imageExtent = glm::vec2(ptextEngine->pcomp->imageExtent.width,ptextEngine->pcomp->imageExtent.height); 218 | 219 | glm::vec2 posh = 2.0f*(glm::vec2(pos)+0.5f)/glm::vec2(pcomp->imageExtent.width,pcomp->imageExtent.height); //-1.0f in shader 220 | //glm::mat2x2 transform = glm::mat2x2(0,1,-1,0); 221 | 222 | std::vector> varAddrs = { 223 | {ShaderModule::VARIABLE_XY0,&posh}, 224 | {ShaderModule::VARIABLE_TRANSFORM,&transform}, 225 | {ShaderModule::VARIABLE_SCREEN,&imageExtent} 226 | }; 227 | BindShaderResources(&varAddrs,pcommandBuffer); 228 | 229 | VkDeviceSize offset = 0; 230 | vkCmdBindVertexBuffers(*pcommandBuffer,0,1,&pvertexBuffer->buffer,&offset); 231 | vkCmdBindIndexBuffer(*pcommandBuffer,ptextEngine->pindexBuffer->buffer,0,VK_INDEX_TYPE_UINT16); 232 | vkCmdDrawIndexed(*pcommandBuffer,6*glyphCount,1,0,0,0); 233 | 234 | passignedSet->fenceTag = pcomp->frameTag; 235 | } 236 | 237 | void Text::UpdateDescSets(){ 238 | VkDescriptorImageInfo descImageInfo = {}; 239 | descImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 240 | descImageInfo.imageView = pfontAtlas->ptexture->imageView; 241 | descImageInfo.sampler = pcomp->pointSampler; 242 | 243 | std::vector writeDescSets; 244 | for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i){ 245 | if(!passignedSet->p->pshaderModule[i]) 246 | continue; 247 | auto m1 = std::find_if(passignedSet->p->pshaderModule[i]->bindings.begin(),passignedSet->p->pshaderModule[i]->bindings.end(),[&](auto &r)->bool{ 248 | return r.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && strcmp(r.pname,"fontAtlas") == 0; 249 | }); 250 | if(m1 != passignedSet->p->pshaderModule[i]->bindings.end()){ 251 | VkWriteDescriptorSet &writeDescSet = writeDescSets.emplace_back(); 252 | writeDescSet = (VkWriteDescriptorSet){}; 253 | writeDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 254 | writeDescSet.dstSet = passignedSet->pdescSets[i][(*m1).setIndex]; 255 | writeDescSet.dstBinding = (*m1).binding; 256 | writeDescSet.dstArrayElement = 0; 257 | writeDescSet.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; 258 | writeDescSet.descriptorCount = 1; 259 | writeDescSet.pImageInfo = &descImageInfo; 260 | } 261 | } 262 | 263 | vkUpdateDescriptorSets(pcomp->logicalDev,writeDescSets.size(),writeDescSets.data(),0,0); 264 | } 265 | 266 | float Text::GetTextLength() const{ 267 | return textLength; 268 | } 269 | 270 | std::vector> Text::vertexBufferLayout = { 271 | {ShaderModule::INPUT_POSITION_SFLOAT2,offsetof(Text::Vertex,pos)}, 272 | {ShaderModule::INPUT_TEXCOORD_UINT2,offsetof(Text::Vertex,texc)} 273 | }; 274 | 275 | TextEngine::TextEngine(const char *pfontName, uint fontSize, CompositorInterface *_pcomp) : pcomp(_pcomp){ 276 | if(FT_Init_FreeType(&library) != FT_Err_Ok) 277 | throw Exception("Failed to initialize Freetype2."); 278 | 279 | FcConfig *pfontConfig = FcInitLoadConfigAndFonts(); 280 | 281 | FcPattern *pPattern = FcNameParse((const FcChar8*)pfontName); 282 | FcConfigSubstitute(pfontConfig,pPattern,FcMatchPattern); 283 | FcDefaultSubstitute(pPattern); 284 | 285 | FcResult result; 286 | FcPattern *pPatternResult = FcFontMatch(pfontConfig,pPattern,&result); 287 | if(!pPatternResult || result != FcResultMatch) 288 | throw Exception("Could not find font."); 289 | FcChar8 *pfileName; 290 | if(FcPatternGetString(pPatternResult,FC_FILE,0,&pfileName) != FcResultMatch) 291 | throw Exception("Could not find font."); 292 | printf("Loaded font: %s\n",pfileName); 293 | if(FT_New_Face(library,(const char*)pfileName,0,&fontFace) != FT_Err_Ok) 294 | throw Exception("Failed to load font."); 295 | 296 | FcPatternDestroy(pPatternResult); 297 | FcPatternDestroy(pPattern); 298 | FcConfigDestroy(pfontConfig); 299 | 300 | glm::vec2 dpi = pcomp->GetDPI(); 301 | FT_Set_Char_Size(fontFace,0,fontSize<<6,(uint)dpi.x,(uint)dpi.y); 302 | 303 | phbFont = hb_ft_font_create(fontFace,0); 304 | 305 | glyphMap.reserve(1024); 306 | 307 | pindexBuffer = new Buffer(1024*6*2,VK_BUFFER_USAGE_INDEX_BUFFER_BIT,pcomp); 308 | indexBufferMapped = false; 309 | } 310 | 311 | TextEngine::~TextEngine(){ 312 | delete pindexBuffer; 313 | 314 | for(VertexBufferCacheEntry &vertexBufferCacheEntry : vertexBufferCache) 315 | delete vertexBufferCacheEntry.pvertexBuffer; 316 | for(FontAtlas *pfontAtlas : fontAtlasMap) 317 | delete pfontAtlas; 318 | 319 | for(auto &m : glyphMap) 320 | delete []m.pbuffer; 321 | glyphMap.clear(); 322 | 323 | hb_font_destroy(phbFont); 324 | FT_Done_Face(fontFace); 325 | //FTC_Manager_Done(fontCacheManager); 326 | FT_Done_FreeType(library); 327 | } 328 | 329 | FontAtlas * TextEngine::CreateAtlas(hb_glyph_info_t *pglyphInfo, uint glyphCount, const VkCommandBuffer *pcommandBuffer){ 330 | //1. check if there's an atlas if all glyphs readily available 331 | auto m1 = std::find_if(fontAtlasMap.begin(),fontAtlasMap.end(),[&](auto r)->bool{ 332 | //check if pglyphInfo array is a subset of the glyphCollection of the current font atlas 333 | for(uint i = 0; i < glyphCount; ++i) 334 | if(std::find_if(r->glyphCollection.begin(),r->glyphCollection.end(),[&](auto r1)->bool{ 335 | return pglyphInfo[i].codepoint == r1.codepoint; 336 | }) == r->glyphCollection.end()) 337 | return false; 338 | return true; 339 | }); 340 | if(m1 != fontAtlasMap.end()){ 341 | ++(*m1)->refCount; 342 | return (*m1); 343 | } 344 | 345 | //2. check if one of the atlases can be appended without resizing it 346 | auto m2 = std::find_if(fontAtlasMap.begin(),fontAtlasMap.end(),[&](auto r)->bool{ 347 | uint size = (1+(fontFace->size->metrics.height>>6))*ceilf(sqrtf(r->glyphCollection.size()+glyphCount)); // /64 348 | size = ((size-1)/128+1)*128; //round up to nearest multiple of 128 to improve reuse of the texture 349 | return size <= r->size; 350 | }); 351 | if(m2 != fontAtlasMap.end()){ 352 | ++(*m2)->refCount; 353 | (*m2)->Update(pglyphInfo,glyphCount,pcommandBuffer); 354 | return (*m2); 355 | } 356 | 357 | uint size = (1+(fontFace->size->metrics.height>>6))*ceilf(sqrtf(glyphCount)); // /64 358 | size = ((size-1)/128+1)*128; //round up to nearest multiple of 128 to improve reuse of the texture 359 | 360 | FontAtlas *pfontAtlas = new FontAtlas(size,this); 361 | pfontAtlas->Update(pglyphInfo,glyphCount,pcommandBuffer); 362 | 363 | fontAtlasMap.push_back(pfontAtlas); 364 | 365 | return pfontAtlas; 366 | } 367 | 368 | void TextEngine::ReleaseAtlas(FontAtlas *pfontAtlas){ 369 | --pfontAtlas->refCount; 370 | pfontAtlas->releaseTag = pcomp->frameTag; 371 | } 372 | 373 | Buffer * TextEngine::CreateVertexBuffer(){ 374 | Buffer *pvertexBuffer; 375 | 376 | auto m = vertexBufferCache.begin(); 377 | if(m != vertexBufferCache.end()){ 378 | pvertexBuffer = (*m).pvertexBuffer; 379 | 380 | std::iter_swap(m,vertexBufferCache.end()-1); 381 | vertexBufferCache.pop_back(); 382 | }else pvertexBuffer = new Buffer(1024*4*sizeof(Text::Vertex),VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,pcomp); 383 | 384 | return pvertexBuffer; 385 | } 386 | 387 | void TextEngine::ReleaseVertexBuffer(Buffer *pvertexBuffer){ 388 | VertexBufferCacheEntry vertexBufferCacheEntry; 389 | vertexBufferCacheEntry.pvertexBuffer = pvertexBuffer; 390 | vertexBufferCacheEntry.releaseTag = pcomp->frameTag; 391 | clock_gettime(CLOCK_MONOTONIC,&vertexBufferCacheEntry.releaseTime); 392 | 393 | vertexBufferCache.push_back(vertexBufferCacheEntry); 394 | } 395 | 396 | void TextEngine::ReleaseCycle(){ 397 | // 398 | vertexBufferCache.erase(std::remove_if(vertexBufferCache.begin(),vertexBufferCache.end(),[&](auto &vertexBufferCacheEntry)->bool{ 399 | if(pcomp->frameTag < vertexBufferCacheEntry.releaseTag+pcomp->swapChainImageCount+1 || timespec_diff(pcomp->frameTime,vertexBufferCacheEntry.releaseTime) < 5.0f) 400 | return false; 401 | delete vertexBufferCacheEntry.pvertexBuffer; 402 | return true; 403 | }),vertexBufferCache.end()); 404 | 405 | fontAtlasMap.erase(std::remove_if(fontAtlasMap.begin(),fontAtlasMap.end(),[&](FontAtlas *pfontAtlas)->bool{ 406 | if(pcomp->frameTag < pfontAtlas->releaseTag+pcomp->swapChainImageCount+1 || pfontAtlas->refCount > 0) 407 | return false; 408 | delete pfontAtlas; 409 | return true; 410 | }),fontAtlasMap.end()); 411 | } 412 | 413 | TextEngine::Glyph * TextEngine::LoadGlyph(uint codePoint){ 414 | auto m = std::find_if(glyphMap.begin(),glyphMap.end(),[&](auto r)->bool{ 415 | return r.codepoint == codePoint; 416 | }); 417 | if(m != glyphMap.end()) 418 | return &(*m); 419 | 420 | FT_Load_Glyph(fontFace,codePoint,FT_LOAD_RENDER); 421 | FT_Bitmap *pbitmap = &fontFace->glyph->bitmap; 422 | 423 | Glyph glyph; 424 | glyph.codepoint = codePoint; 425 | glyph.w = pbitmap->width; 426 | glyph.h = pbitmap->rows; 427 | glyph.pitch = pbitmap->pitch; 428 | glyph.offset = glm::vec2(fontFace->glyph->bitmap_left,-fontFace->glyph->bitmap_top); 429 | glyph.pbuffer = new unsigned char[pbitmap->rows*pbitmap->pitch]; 430 | memcpy(glyph.pbuffer,pbitmap->buffer,pbitmap->rows*pbitmap->pitch); 431 | glyphMap.push_back(glyph); 432 | 433 | return &glyphMap.back(); 434 | } 435 | 436 | float TextEngine::GetFontSize() const{ 437 | return (float)(fontFace->size->metrics.height>>6)/(float)pcomp->imageExtent.width; 438 | } 439 | 440 | } 441 | 442 | -------------------------------------------------------------------------------- /src/container.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "container.h" 3 | 4 | #include 5 | 6 | namespace WManager{ 7 | 8 | Client::Client(Container *_pcontainer) : stackIndex(0), pcontainer(_pcontainer){ 9 | // 10 | } 11 | 12 | Client::~Client(){ 13 | // 14 | } 15 | 16 | Container::Container() : pParent(0), pch(0), pnext(0), pRootNext(this), 17 | pclient(0), 18 | pname(0), 19 | //scale(1.0f), p(0.0f), e(1.0f), margin(0.0f), minSize(0.0f), maxSize(1.0f), mode(MODE_TILED), 20 | p(0.0f), posFullCanvas(0.0f), e(1.0f), extFullCanvas(1.0f), canvasOffset(0.0f), canvasExtent(0.0f), 21 | margin(0.015f), titlePad(0.0f), titleSpan(0.0f,1.0f), titleTransform(glm::mat2x2(1.0f)), absTitlePad(0.0f), size(1.0f), minSize(0.015f), maxSize(1.0f), 22 | flags(0), layout(LAYOUT_VSPLIT), titleBar(TITLEBAR_NONE), titleStackOnly(false){ 23 | //This constructor creates a root container, since no parent is given. 24 | rootQueue.push_back(this); 25 | } 26 | 27 | Container::Container(Container *_pParent, const Setup &setup) : 28 | pParent(_pParent), pch(0), pnext(0), pRootNext(this), 29 | pclient(0), 30 | pname(0), 31 | canvasOffset(setup.canvasOffset), canvasExtent(setup.canvasExtent), 32 | margin(setup.margin), titlePad(0.0f), titleSpan(0.0f,1.0f), titleTransform(glm::mat2x2(1.0f)), absTitlePad(setup.titlePad), size(setup.size), minSize(setup.minSize), maxSize(setup.maxSize),// mode(setup.mode), 33 | flags(setup.flags), layout(LAYOUT_VSPLIT), titleBar(setup.titleBar), titleStackOnly(setup.titleStackOnly){ 34 | 35 | if(setup.pname) 36 | SetName(setup.pname); 37 | 38 | if(flags & FLAG_FLOATING) 39 | return; 40 | 41 | SetTitlebar(titleBar,false); 42 | 43 | //TODO: allow reparenting containers without client 44 | if(pParent->pclient){ 45 | //if(pParent->pclient || setup.insert == Setup::INSERT_REPARENT){ 46 | size = pParent->size; 47 | pParent->size = setup.size; 48 | //reparent 49 | Container *pbase = pParent->pParent; 50 | //replace the original parent with this new container 51 | if(std::find(pbase->focusQueue.begin(),pbase->focusQueue.end(),pParent) != pbase->focusQueue.end()){ 52 | std::replace(pbase->focusQueue.begin(),pbase->focusQueue.end(),pParent,this); 53 | focusQueue.push_back(pParent); //carry on the focus queue if it exists 54 | } 55 | for(Container *pcontainer = pbase->pch, *pPrev = 0; pcontainer; pPrev = pcontainer, pcontainer = pcontainer->pnext) 56 | if(pcontainer == pParent){ 57 | if(pPrev) 58 | pPrev->pnext = this; 59 | else pbase->pch = this; 60 | pnext = pcontainer->pnext; 61 | break; 62 | } 63 | 64 | //add the original parent under the new one 65 | pParent->pParent = this; 66 | pParent->pnext = 0; 67 | 68 | pch = pParent; 69 | pParent = pbase; 70 | 71 | }else{ 72 | if(pParent->focusQueue.size() > 0){ 73 | //place next to the focused container 74 | Container *pfocus = pParent->focusQueue.back(); 75 | pnext = pfocus->pnext; 76 | pfocus->pnext = this; 77 | 78 | }else{ 79 | Container **pn = &pParent->pch; 80 | while(*pn) 81 | pn = &(*pn)->pnext; 82 | *pn = this; 83 | } 84 | 85 | uint containerCount = 0; 86 | for(Container *pcontainer = pParent->pch; pcontainer; ++containerCount, pcontainer = pcontainer->pnext); 87 | //size = glm::vec2(1.0f/(float)containerCount); 88 | size = glm::max(glm::vec2(1.0f/(float)containerCount),glm::vec2(0.1f)); 89 | 90 | glm::vec2 sizeComp = glm::vec2(1.0f)-size; 91 | for(Container *pcontainer = pParent->pch; pcontainer; pcontainer = pcontainer->pnext) 92 | if(pcontainer != this) 93 | pcontainer->size = glm::max(pcontainer->size*sizeComp,glm::vec2(0.1f)); 94 | //pcontainer->size *= glm::vec2(1.0f)-size; 95 | 96 | } 97 | 98 | pParent->stackQueue.push_back(this); 99 | pParent->Translate(); 100 | } 101 | 102 | Container::~Container(){ 103 | if(pname) 104 | mstrfree(pname); 105 | rootQueue.erase(std::remove(rootQueue.begin(),rootQueue.end(),this),rootQueue.end()); 106 | } 107 | 108 | void Container::AppendRoot(Container *pcontainer){ 109 | pcontainer->pRootNext = pRootNext; 110 | pRootNext = pcontainer; 111 | } 112 | 113 | void Container::Place(Container *pParent1){ 114 | //TODO: reparent the floating container 115 | if(flags & FLAG_FLOATING) 116 | return; 117 | WManager::Container *pOrigParent = pParent; 118 | pParent = pParent1; 119 | if(pParent->focusQueue.size() > 0){ 120 | //place next to the focused container 121 | Container *pfocus = pParent->focusQueue.back(); 122 | pnext = pfocus->pnext; 123 | pfocus->pnext = this; 124 | 125 | }else{ 126 | Container **pn = &pParent->pch; 127 | while(*pn) 128 | pn = &(*pn)->pnext; 129 | *pn = this; 130 | } 131 | 132 | uint containerCount = 0; 133 | for(Container *pcontainer = pParent->pch; pcontainer; ++containerCount, pcontainer = pcontainer->pnext); 134 | size = glm::max(glm::vec2(1.0f/(float)containerCount),glm::vec2(0.1f)); 135 | 136 | glm::vec2 sizeComp = glm::vec2(1.0f)-size; 137 | for(Container *pcontainer = pParent->pch; pcontainer; pcontainer = pcontainer->pnext) 138 | if(pcontainer != this) 139 | pcontainer->size = glm::max(pcontainer->size*sizeComp,glm::vec2(0.1f)); 140 | //pcontainer->size *= glm::vec2(1.0f)-size; 141 | 142 | GetRoot()->Stack(); 143 | pParent->Translate(); 144 | 145 | Place1(pOrigParent); 146 | } 147 | 148 | Container * Container::Remove(){ 149 | if(flags & FLAG_FLOATING) 150 | return this; 151 | 152 | Container *pRootPrev = pRootNext; 153 | for(; pRootPrev->pRootNext != this; pRootPrev = pRootPrev->pRootNext); 154 | pRootPrev->pRootNext = pRootNext; 155 | 156 | Container *pbase = pParent, *pch1 = this; //remove all the split containers (although there should be only one) 157 | for(; pbase->pParent; pch1 = pbase, pbase = pbase->pParent){ 158 | if(pbase->pch->pnext) 159 | break; //more than one container 160 | } 161 | pbase->focusQueue.erase(std::remove(pbase->focusQueue.begin(),pbase->focusQueue.end(),pch1),pbase->focusQueue.end()); 162 | for(Container *pcontainer = pbase->pch, *pPrev = 0; pcontainer; pPrev = pcontainer, pcontainer = pcontainer->pnext) 163 | if(pcontainer == pch1){ 164 | if(pPrev) 165 | pPrev->pnext = pcontainer->pnext; 166 | else pbase->pch = pcontainer->pnext; 167 | break; 168 | } 169 | 170 | for(Container *pcontainer = pParent->pch; pcontainer; pcontainer = pcontainer->pnext) 171 | pcontainer->size /= 1.0f-size; 172 | 173 | GetRoot()->Stack(); 174 | pbase->Translate(); 175 | 176 | return pch1; 177 | } 178 | 179 | Container * Container::Collapse(){ 180 | if(flags & FLAG_FLOATING) 181 | return 0; 182 | if(!pParent || !pch) 183 | return 0; 184 | 185 | if(pParent->pch->pnext){ 186 | if(pch->pnext) 187 | return 0; //should not collapse 188 | 189 | pch->size = size; 190 | 191 | //only one container to collapse 192 | //printf("** type 1 collapse\n"); 193 | std::replace(pParent->focusQueue.begin(),pParent->focusQueue.end(),this,pch); 194 | 195 | pch->pParent = pParent; 196 | 197 | for(Container *pcontainer = pParent->pch, *pPrev = 0; pcontainer; pPrev = pcontainer, pcontainer = pcontainer->pnext){ 198 | if(pcontainer == this){ 199 | if(pPrev) 200 | pPrev->pnext = pch; 201 | else pParent->pch = pch; 202 | pch->pnext = pcontainer->pnext; 203 | break; 204 | } 205 | } 206 | 207 | pch = 0; 208 | focusQueue.clear(); 209 | 210 | GetRoot()->Stack(); 211 | if(titleStackOnly && flags & FLAG_STACKED) //this is only needed to handle the stacking exclusive titlebars 212 | pParent->Translate(); 213 | 214 | return this; 215 | 216 | }else 217 | if(pch->pnext){ //if there are more than one container 218 | if(pParent->pch->pnext) //and there's a container next to this one 219 | return 0; //should not collapse 220 | 221 | //more than one container to deal with 222 | //printf("** type 2 collapse\n"); 223 | Container *pfocus = focusQueue.size() > 0?focusQueue.back():pch; 224 | std::replace(pParent->focusQueue.begin(),pParent->focusQueue.end(),this,pfocus); 225 | 226 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext) 227 | pcontainer->pParent = pParent; 228 | 229 | pParent->pch = pch; 230 | 231 | pch = 0; //dereference the leftover container 232 | focusQueue.clear(); 233 | 234 | GetRoot()->Stack(); 235 | if(titleStackOnly && flags & FLAG_STACKED) //this is only needed to handle the stacking exclusive titlebars 236 | pParent->Translate(); 237 | 238 | return this; 239 | } 240 | 241 | return 0; 242 | } 243 | 244 | void Container::Focus(){ 245 | if(flags & FLAG_NO_FOCUS) 246 | return; 247 | if(flags & FLAG_FLOATING){ 248 | floatFocusQueue.erase(std::remove(floatFocusQueue.begin(),floatFocusQueue.end(),this),floatFocusQueue.end()); 249 | floatFocusQueue.push_back(this); 250 | 251 | Stack1(); 252 | 253 | }else{ 254 | tiledFocusQueue.erase(std::remove_if(tiledFocusQueue.begin(),tiledFocusQueue.end(),[&](auto &p)->bool{ 255 | return p.first == this; 256 | }),tiledFocusQueue.end()); 257 | struct timespec focusTime; 258 | clock_gettime(CLOCK_MONOTONIC,&focusTime); 259 | if(tiledFocusQueue.size() > 1 && //keep the previous container if it's the only one 260 | timespec_diff(focusTime,tiledFocusQueue.back().second) < 0.5) 261 | tiledFocusQueue.back() = std::pair(this,focusTime); 262 | else tiledFocusQueue.push_back(std::pair(this,focusTime)); 263 | 264 | for(Container *pcontainer = this; pcontainer->pParent; pcontainer = pcontainer->pParent){ 265 | pcontainer->pParent->focusQueue.erase(std::remove(pcontainer->pParent->focusQueue.begin(),pcontainer->pParent->focusQueue.end(),pcontainer),pcontainer->pParent->focusQueue.end()); 266 | pcontainer->pParent->focusQueue.push_back(pcontainer); 267 | } 268 | 269 | GetRoot()->Stack(); 270 | } 271 | 272 | Focus1(); 273 | ptreeFocus = this; 274 | } 275 | 276 | void Container::SetFullscreen(bool toggle){ 277 | if(toggle) 278 | flags |= FLAG_FULLSCREEN; 279 | else flags &= ~FLAG_FULLSCREEN; 280 | 281 | Fullscreen1(); 282 | if(flags & FLAG_FLOATING) 283 | return; 284 | Translate(); 285 | } 286 | 287 | void Container::SetStacked(bool toggle){ 288 | if(toggle) 289 | flags |= FLAG_STACKED; 290 | else flags &= ~FLAG_STACKED; 291 | 292 | Translate(); 293 | } 294 | 295 | Container * Container::GetNext(){ 296 | if(flags & FLAG_FLOATING) 297 | return this; 298 | if(!pParent) 299 | return this; //root container 300 | if(!pnext) 301 | return pParent->pch; 302 | return pnext; 303 | } 304 | 305 | Container * Container::GetPrev(){ 306 | if(flags & FLAG_FLOATING) 307 | return this; 308 | if(!pParent) 309 | return this; //root container 310 | Container *pcontainer = pParent->pch; 311 | if(pcontainer == this) 312 | for(; pcontainer->pnext; pcontainer = pcontainer->pnext); 313 | else for(; pcontainer->pnext != this; pcontainer = pcontainer->pnext); 314 | return pcontainer; 315 | } 316 | 317 | Container * Container::GetParent() const{ 318 | return pParent; 319 | } 320 | 321 | Container * Container::GetFocus() const{ 322 | return focusQueue.size() > 0?focusQueue.back():pch; 323 | } 324 | 325 | Container * Container::GetRoot(){ 326 | Container *proot = this; 327 | for(Container *pcontainer = pParent; pcontainer; proot = pcontainer, pcontainer = pcontainer->pParent); 328 | return proot; 329 | } 330 | 331 | void Container::SetSize(glm::vec2 sizeNew){ 332 | if(glm::any(glm::lessThan(sizeNew,glm::vec2(0.1f)))) 333 | return; //ensure reasonable constraints 334 | if(flags & FLAG_FLOATING){ 335 | sizeNew = glm::max(sizeNew,glm::vec2(0.1f)); 336 | p += 0.5f*(size-sizeNew); 337 | e = sizeNew; 338 | size = sizeNew; 339 | if(pclient) 340 | pclient->UpdateTranslation(); 341 | return; 342 | } 343 | glm::vec2 sizeCompRatio = (glm::vec2(1.0f)-sizeNew)/(glm::vec2(1.0f)-size); 344 | if(size.x >= 1.0f){ 345 | sizeCompRatio.x = 1.0f; 346 | sizeNew.x = 1.0f; 347 | } 348 | if(size.y >= 1.0f){ 349 | sizeCompRatio.y = 1.0f; 350 | sizeNew.y = 1.0f; 351 | } 352 | //precheck - ensure the operation results in positive size for all windows 353 | for(Container *pcontainer = pParent->pch; pcontainer; pcontainer = pcontainer->pnext) 354 | if(pcontainer != this) 355 | if(glm::any(glm::lessThan(pcontainer->size*sizeCompRatio,glm::vec2(0.1f)))) 356 | return; //cancel the resize 357 | for(Container *pcontainer = pParent->pch; pcontainer; pcontainer = pcontainer->pnext) 358 | if(pcontainer != this) 359 | pcontainer->size *= sizeCompRatio; 360 | size = sizeNew; 361 | 362 | pParent->Translate(); 363 | } 364 | 365 | void Container::SetTitlebar(TITLEBAR titleBar, bool translate){ 366 | switch(titleBar){ 367 | case TITLEBAR_LEFT: 368 | titlePad = glm::vec2(-absTitlePad,0.0f); 369 | titleTransform = glm::mat2x2(0,-1,1,0); 370 | break; 371 | case TITLEBAR_RIGHT: 372 | titlePad = glm::vec2(absTitlePad,0.0f); 373 | titleTransform = glm::mat2x2(0,-1,1,0); 374 | break; 375 | case TITLEBAR_TOP: 376 | titlePad = glm::vec2(0.0f,-absTitlePad); 377 | titleTransform = glm::mat2x2(1.0f); 378 | break; 379 | case TITLEBAR_BOTTOM: 380 | titlePad = glm::vec2(0.0f,absTitlePad); 381 | default: 382 | titlePad = glm::vec2(0.0f); 383 | titleTransform = glm::mat2x2(1.0f); 384 | break; 385 | } 386 | 387 | this->titleBar = titleBar; 388 | 389 | if(translate && pParent) 390 | pParent->Translate(); 391 | } 392 | 393 | void Container::SetName(const char *_pname){ 394 | if(pname) 395 | mstrfree(pname); 396 | pname = mstrdup(_pname); 397 | printf("created workspace '%s'\n",pname); 398 | } 399 | 400 | void Container::MoveNext(){ 401 | if(flags & FLAG_FLOATING) 402 | return; 403 | if(!pParent) 404 | return; 405 | Container *pcontainer = GetNext(); 406 | Container *pPrev = GetPrev(); 407 | Container *pPrevNext = pPrev->pnext; 408 | 409 | Container *pnext1 = pcontainer->pnext; 410 | pcontainer->pnext = pnext?this:0; 411 | pnext = pnext1 != this?pnext1:pcontainer; 412 | 413 | if(pParent->pch == this) 414 | pParent->pch = pcontainer; 415 | else 416 | if(pParent->pch == pcontainer) 417 | pParent->pch = this; 418 | 419 | if(pPrevNext != 0 && pPrev != pcontainer) 420 | pPrev->pnext = pcontainer; 421 | 422 | pParent->Stack(); 423 | pParent->Translate(); 424 | } 425 | 426 | void Container::MovePrev(){ 427 | GetPrev()->MoveNext(); 428 | } 429 | 430 | glm::vec2 Container::GetMinSize() const{ 431 | //Return the minimum size requirement for the container 432 | glm::vec2 chSize(0.0f); 433 | for(Container *pcontainer = pch; pcontainer; chSize = glm::max(chSize,pcontainer->GetMinSize()), pcontainer = pcontainer->pnext); 434 | return glm::max(chSize,minSize); 435 | } 436 | 437 | void Container::TranslateRecursive(glm::vec2 posFullCanvas, glm::vec2 extFullCanvas, glm::vec2 p, glm::vec2 e){ 438 | if(flags & FLAG_FULLSCREEN){ 439 | p = glm::vec2(0.0f); 440 | e = glm::vec2(1.0f); 441 | } 442 | uint count = 0; 443 | 444 | glm::vec2 minSizeSum(0.0f); 445 | glm::vec2 maxMinSize(0.0f); 446 | for(Container *pcontainer = pch; pcontainer; ++count, pcontainer = pcontainer->pnext){ 447 | glm::vec2 e1 = pcontainer->GetMinSize(); 448 | minSizeSum += e1; 449 | maxMinSize = glm::max(e1,maxMinSize); 450 | } 451 | 452 | glm::vec2 position(p); 453 | if(flags & FLAG_STACKED){ 454 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext) 455 | pcontainer->TranslateRecursive(position,e,position,e); 456 | }else 457 | switch(layout){ 458 | default: 459 | case LAYOUT_VSPLIT: 460 | if(e.x-minSizeSum.x < 0.0f){ 461 | //overlap required, everything has been minimized to the limit 462 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 463 | glm::vec2 e1 = glm::vec2(maxMinSize.x,e.y); 464 | glm::vec2 p1 = glm::vec2(position.x,p.y);//position; 465 | 466 | /*if(pcontainer->pnext){ 467 | if(p1.x+e1.x+pcontainer->pnext->e1.x > 1.0f) 468 | e1.x = 1.0f; 469 | else position += ...; 470 | */ 471 | 472 | //---- 473 | /*if(pcontainer->pnext){ 474 | if(p1.x+e1.x+pcontainer->pnext->e1.x <= 1.0) 475 | pcontainer->pnext->p1.x = p1.x+e1.x; 476 | else{ 477 | pcontainer->pnext->p1.x = position.x; 478 | //TODO: resize the previous row 479 | } 480 | position.x += maxMinSize.x-((float)count*maxMinSize.x-e.x)/(float)(count-1); 481 | }*/ 482 | 483 | //position.x += e1.x-(minSizeSum.x-e.x)/(float)(count-1); 484 | position.x += e1.x-((float)count*maxMinSize.x-e.x)/(float)(count-1); 485 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 486 | } 487 | 488 | }else{ 489 | //optimize the containers, minimize interior overlap 490 | /*for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 491 | glm::vec2 e1 = glm::vec2(pcontainer->e1.x+(e.x-minSizeSum.x)/(float)count,e.y); 492 | glm::vec2 p1 = position; 493 | 494 | position.x += e1.x; 495 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 496 | }*/ 497 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 498 | float s = pcontainer->size.x*e.x; 499 | //glm::vec2 e1 = glm::vec2(std::max(s,pcontainer->GetMinSize().x),e.y); 500 | glm::vec2 e1 = glm::vec2(s,e.y); 501 | glm::vec2 p1 = position; 502 | 503 | position.x += s; 504 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 505 | } 506 | } 507 | break; 508 | case LAYOUT_HSPLIT: 509 | if(e.y-minSizeSum.y < 0.0f){ 510 | //overlap required, everything has been minimized to the limit 511 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 512 | glm::vec2 e1 = glm::vec2(e.x,maxMinSize.y); 513 | glm::vec2 p1 = glm::vec2(p.x,position.y);//position; 514 | 515 | position.y += e1.y-((float)count*maxMinSize.y-e.y)/(float)(count-1); 516 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 517 | } 518 | 519 | }else{ 520 | /*for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 521 | glm::vec2 e1 = glm::vec2(e.x,pcontainer->e1.y+(e.y-minSizeSum.y)/(float)count); 522 | glm::vec2 p1 = position; 523 | 524 | position.y += e1.y; 525 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 526 | }*/ 527 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext){ 528 | float s = pcontainer->size.y*e.y; 529 | glm::vec2 e1 = glm::vec2(e.x,s); 530 | //glm::vec2 e1 = glm::vec2(e.x,std::max(s,pcontainer->GetMinSize().y)); 531 | glm::vec2 p1 = position; 532 | 533 | position.y += s; 534 | pcontainer->TranslateRecursive(p1,e1,p1+pcontainer->canvasOffset,e1-pcontainer->canvasExtent); 535 | } 536 | } 537 | break; 538 | } 539 | 540 | this->posFullCanvas = posFullCanvas; 541 | this->extFullCanvas = extFullCanvas; 542 | glm::vec2 pcorr = glm::min(p,glm::vec2(0.0f)); 543 | p -= pcorr; //make sure the containers stay within the screen limits 544 | glm::vec2 ecorr = glm::min(1.0f-(p+e),glm::vec2(0.0f)); 545 | this->p = glm::max(p+ecorr,0.0f); 546 | this->e = glm::min(e,1.0f); 547 | if(pclient) 548 | pclient->UpdateTranslation(); 549 | } 550 | 551 | void Container::Translate(){ 552 | glm::vec2 size1 = GetMinSize(); 553 | 554 | //Check the parent hierarchy, up to which point they won't have to be updated (condition overlappedSize <= e). 555 | //Find the first ancestor large enough to contain everything without modifiying its size. 556 | Container *pcontainer; 557 | for(pcontainer = pParent; pcontainer && glm::any(glm::lessThan(pcontainer->e,size1-1e-5f)); pcontainer = pcontainer->pParent); 558 | if(!pcontainer) 559 | pcontainer = this; //reached the root 560 | 561 | //pcontainer->posFullCanvas-canvasOffset,e,posFullCanvas,extFullCanvas 562 | //pcontainer->TranslateRecursive(pcontainer->p,pcontainer->e); 563 | pcontainer->TranslateRecursive(pcontainer->posFullCanvas,pcontainer->extFullCanvas, 564 | pcontainer->posFullCanvas+pcontainer->canvasOffset,pcontainer->extFullCanvas-pcontainer->canvasExtent); 565 | } 566 | 567 | void Container::StackRecursive(){ 568 | stackQueue.clear(); 569 | 570 | Container *pfocus = focusQueue.size() > 0?focusQueue.back():pch; 571 | if(!pfocus) 572 | return; 573 | 574 | for(Container *pcontainer = pch; pcontainer != pfocus; pcontainer = pcontainer->pnext) 575 | stackQueue.push_back(pcontainer); 576 | for(Container *pcontainer = pch->GetPrev(); pcontainer != pfocus; pcontainer = pcontainer->GetPrev()) 577 | stackQueue.push_back(pcontainer); 578 | 579 | stackQueue.push_back(pfocus); 580 | 581 | for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext) 582 | pcontainer->StackRecursive(); 583 | } 584 | 585 | void Container::Stack(){ 586 | /*stackQueue.clear(); 587 | Container *pfocus = focusQueue.size() > 0?focusQueue.back():pch; 588 | if(!pfocus) 589 | return;*/ 590 | //stacking scheme 1: prefer to show left side of the window 591 | //problem: may hide some windows completely 592 | /*for(Container *pcontainer = pch; pcontainer != pfocus; pcontainer = pcontainer->pnext) 593 | stackQueue.push_back(pcontainer); 594 | Container *pstack = 0; 595 | for(Container *pcontainer = pch->GetPrev(); pcontainer != pfocus; pcontainer = pcontainer->GetPrev()){ 596 | if((layout == LAYOUT_VSPLIT && pcontainer->p.x < pfocus->p.x+pfocus->e.x) || 597 | (layout == LAYOUT_HSPLIT && pcontainer->p.y < pfocus->p.y+pfocus->e.y)) 598 | pstack = pcontainer; 599 | if(pstack) 600 | stackQueue.push_back(pcontainer); 601 | } 602 | for(Container *pcontainer = pstack; pcontainer; pcontainer = pcontainer->pnext) 603 | stackQueue.push_back(pcontainer);*/ 604 | 605 | //TODO: stacking scheme 3: stack from left to right, except that all the windows before the 606 | //one that would be completely visible after focus (see 1), will be more tightly spaced to 607 | //avoid waste. This needs modifications in Translate(), otherwise same as 2. 608 | 609 | //1. check if any of the windows would be visible completely after the focus 610 | //2. stack the windows normally until the next after focus 611 | //3. for a length of one stack spacing, tighly place all the windows before the one found in 1. 612 | //-if no such window was found, continue stacking according to scheme 3. 613 | //4. after this, stack the remaining windows according to 2. The first of the remaining should 614 | //be in the same place as it would be in normal left to right stacking. 615 | 616 | //stacking scheme 3: for every window always keep at least small part visible 617 | //problem(?): may waste screen space if there are many windows with left-aligned text (terminals) 618 | //----------- 619 | /*for(Container *pcontainer = pch; pcontainer != pfocus; pcontainer = pcontainer->pnext) 620 | stackQueue.push_back(pcontainer); 621 | for(Container *pcontainer = pch->GetPrev(); pcontainer != pfocus; pcontainer = pcontainer->GetPrev()) 622 | stackQueue.push_back(pcontainer); 623 | 624 | stackQueue.push_back(pfocus);*/ 625 | //----------- 626 | /*for(Container *pcontainer = pch; pcontainer; pcontainer = pcontainer->pnext) 627 | stackQueue.push_back(pcontainer); 628 | 629 | if(focusQueue.size() == 0) 630 | return; 631 | Container *pfocus = focusQueue.back(); 632 | auto m = std::find(stackQueue.begin(),stackQueue.end(),pfocus); 633 | std::iter_swap(m,stackQueue.end()-1);*/ 634 | 635 | /*std::sort(stackQueue.begin(),stackQueue.end(),[&](Container *pa, Container *pb)->bool{ 636 | return pa != pfocus && (pb == pfocus || pb->p[layout] > pfocus->p[layout]+pfocus->e[layout] || pb->p[layout]+pb->e[layout] < pfocus->p[layout]); 637 | });*/ 638 | /*std::sort(stackQueue.begin(),stackQueue.end(),[&](Container *pa, Container *pb)->bool{ 639 | return pa != pfocus && (pb == pfocus || pb->p[layout] > pfocus->p[layout]+pfocus->e[layout] || pb->p[layout]+pb->e[layout] < pfocus->p[layout]); 640 | });*/ 641 | StackRecursive(); 642 | Stack1(); 643 | } 644 | 645 | void Container::SetLayout(LAYOUT layout){ 646 | this->layout = layout; 647 | if(flags & FLAG_FLOATING) 648 | return; 649 | Translate(); 650 | } 651 | 652 | WManager::Container *Container::ptreeFocus = 0; //initially set to root container as soon as it's created 653 | std::deque> Container::tiledFocusQueue; 654 | std::deque Container::floatFocusQueue; 655 | std::deque Container::rootQueue; 656 | 657 | /*RootContainer::RootContainer(const char *_pname) : Container(), pRootNext(0), pname(mstrdup(_pname)){ 658 | 659 | } 660 | 661 | RootContainer::~RootContainer(){ 662 | mstrfree(pname); 663 | }*/ 664 | 665 | } 666 | 667 | -------------------------------------------------------------------------------- /config/config.py: -------------------------------------------------------------------------------- 1 | 2 | import chamfer 3 | import sys 4 | import os 5 | from enum import Enum,auto 6 | 7 | class ShaderFlag(Enum): 8 | FOCUS_NEXT = chamfer.shaderFlag.USER_BIT<<0x0 9 | 10 | #Refer to the documentation 11 | #https://jaelpark.github.io/chamferwm-docs/bindings.html 12 | #for all the keybindings and how to setup them. 13 | #TLDR: define the key binding in OnSetupKeys() and the 14 | #behaviour in OnKeyPress(). 15 | 16 | class Container(chamfer.Container): 17 | #setup the container before it's created (dimensions) 18 | def OnSetupContainer(self): 19 | self.margin = (0.015,0.015); #Relative amount of empty space around containers (i.e. gap). Fragment shader covers this area for over-reaching decorations. 20 | self.minSize = (0.3,0.2); #Minimum size of the container, before they start to overlap 21 | 22 | self.titleBar = chamfer.titleBar.TOP; #options for the title bar location are NONE, LEFT, TOP, RIGHT or BOTTOM 23 | self.titleStackOnly = True; #disable to always show title bars 24 | 25 | #WM_CLASS/TITLE rules to force floating mode / never float 26 | if self.wm_class == "matplotlib": 27 | #Example: always float matplotlib graph windows. 28 | self.floatingMode = chamfer.floatingMode.ALWAYS; #.NEVER 29 | 30 | #setup the client before it's created (shaders) 31 | def OnSetupClient(self): 32 | try: 33 | print("Setting up \"{}\" ({})".format(self.wm_name,self.wm_class),flush=True); 34 | except UnicodeDecodeError: 35 | pass; 36 | 37 | #Setup shaders for the newly created client container. 38 | #The stock build includes the following fragment shaders 39 | #build by default: 40 | 41 | #1. frame_fragment.spv: default "demo" decoration with border and rounded corners 42 | #2. frame_fragment_basic.spv: rectangular borders with focus highlight, no bling 43 | #3. frame_fragment_ext.spv: #default rounded corner style for external wms 44 | #4. frame_fragment_ext_basic.spv: #simple compatible style for external wms, only draw shadows 45 | #5. default_fragment.spv: #absolutely no decoration (goes together with default_vertex.spv and 46 | # (default_geometry.spv) 47 | 48 | #All shader builds include the shadows by default. Shadows can be 49 | #removed by disabling the build feature in meson.build. Other features 50 | #such as the border thickness, rounding, and colors can be edited 51 | #in the shader source itself (for now). 52 | 53 | if not chamfer.backend.standaloneCompositor: 54 | #Shaders for the chamferwm. 55 | if self.wm_class == "Conky": 56 | #Example: zero decoration for conky system monitor. 57 | #Add docks and other desktop widgets similarly, 58 | #if needed. 59 | self.vertexShader = "default_vertex.spv"; 60 | self.geometryShader = "default_geometry.spv"; 61 | self.fragmentShader = "default_fragment.spv"; 62 | else: 63 | self.vertexShader = "frame_vertex.spv"; 64 | self.geometryShader = "frame_geometry.spv"; 65 | self.fragmentShader = "frame_fragment.spv"; 66 | else: 67 | #Shader for other window managers (standalone 68 | #compositor mode). 69 | self.vertexShader = "frame_vertex.spv"; 70 | self.geometryShader = "frame_geometry.spv"; 71 | self.fragmentShader = "frame_fragment_ext.spv"; 72 | 73 | #this is just to restore the defaults when leaving fullscreen (used in OnFullscreen()) 74 | self.defaultShaders = (self.vertexShader,self.geometryShader,self.fragmentShader); 75 | 76 | #select and assign a parent container 77 | def OnParent(self): 78 | focus = chamfer.backend.GetFocus(); 79 | if hasattr(focus,'splitArmed') and focus.splitArmed: 80 | focus.splitArmed = False; 81 | return focus; 82 | 83 | parent = focus.GetParent(); 84 | if parent is None: 85 | return focus; #root container 86 | 87 | return parent; 88 | 89 | #called once client has been created and mapped to display 90 | def OnCreate(self): 91 | try: 92 | print("Created client \"{}\" ({})".format(self.wm_name,self.wm_class),flush=True); 93 | except UnicodeDecodeError: 94 | pass 95 | self.Focus(); 96 | 97 | #Called to request fullscreen mode - either by calling SetFullscreen or by client message. 98 | #Not used in standalone compositor mode. 99 | def OnFullscreen(self, toggle): 100 | #In fullscreen mode, no decorations. 101 | if toggle: 102 | self.vertexShader = "default_vertex.spv"; 103 | self.geometryShader = "default_geometry.spv"; 104 | self.fragmentShader = "default_fragment.spv"; 105 | else: 106 | self.vertexShader,self.geometryShader,self.fragmentShader = self.defaultShaders; 107 | 108 | return True; 109 | 110 | #called to request focus - either by calling container.Focus or by client message 111 | def OnFocus(self): 112 | return True; 113 | 114 | #called when window is stacked or unstacked - only called for the parent container 115 | def OnStack(self, toggle): 116 | pass; 117 | 118 | #called every time a client property has changed (title etc.) 119 | def OnPropertyChange(self, propId): 120 | pass; #self.wm_name, etc. 121 | 122 | #called whenever cursor enters the window 123 | def OnEnter(self): 124 | #self.Focus(); 125 | pass; 126 | 127 | #Place container under another so that its structure remains intact. 128 | #Return the container at the original targets place. 129 | def Place(self, target): 130 | focus = target.GetFocus(); 131 | if focus is not None: 132 | peers = [focus.GetNext()]; 133 | while peers[-1] is not focus: 134 | peers.append(peers[-1].GetNext()); 135 | 136 | self.Move(target); 137 | if focus is not None: 138 | for peer in peers[1:]: 139 | peer.Place(peers[0]); 140 | return target; 141 | else: 142 | return target.GetParent(); 143 | 144 | def GetFocusDescend(self): 145 | #get the focused container in this container tree 146 | container = self; 147 | while container.GetFocus() is not None: 148 | container = container.GetFocus(); 149 | return container; 150 | 151 | def FindParentLayout(self, layout): 152 | try: 153 | container = self; 154 | while container.GetParent().layout != layout: 155 | container = container.GetParent(); 156 | return container; 157 | 158 | except AttributeError: 159 | return self; 160 | 161 | class Backend(chamfer.Backend): 162 | def OnSetupKeys(self, debug): 163 | #Helper function to create key binding IDs 164 | def KeyId(keyId): 165 | nonlocal self; 166 | if hasattr(self,keyId): 167 | return getattr(self,keyId); 168 | try: 169 | self.keyCounter += 1; 170 | setattr(self,keyId,self.keyCounter); 171 | except AttributeError: 172 | self.keyCounter = 0; 173 | setattr(self,keyId,0); 174 | return self.keyCounter; 175 | 176 | if not debug: 177 | self.modMask = chamfer.MOD_MASK_1; 178 | #setup key bindings 179 | #focusing clients 180 | self.BindKey(ord('l'),self.modMask,KeyId('FOCUS_RIGHT')); 181 | self.BindKey(ord('l'),self.modMask|chamfer.MOD_MASK_SHIFT,KeyId('MOVE_RIGHT')); 182 | self.BindKey(ord('h'),self.modMask,KeyId('FOCUS_LEFT')); 183 | self.BindKey(ord('h'),self.modMask|chamfer.MOD_MASK_SHIFT,KeyId('MOVE_LEFT')); 184 | self.BindKey(ord('k'),self.modMask,KeyId('FOCUS_UP')); 185 | self.BindKey(ord('j'),self.modMask,KeyId('FOCUS_DOWN')); 186 | self.BindKey(ord('a'),self.modMask,KeyId('FOCUS_PARENT')); 187 | self.BindKey(ord('s'),self.modMask,KeyId('FOCUS_CHILD')); 188 | self.BindKey(miscellany.XK_Tab,chamfer.MOD_MASK_4,KeyId('FOCUS_MRU')); 189 | self.BindKey(miscellany.XK_Tab,chamfer.MOD_MASK_1,KeyId('FOCUS_FLOAT')); 190 | self.BindKey(miscellany.XK_Tab,chamfer.MOD_MASK_1|chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_FLOAT_PREV')); 191 | 192 | #reserved 193 | self.BindKey(ord('l'),chamfer.MOD_MASK_4,KeyId('FOCUS_PARENT_RIGHT')); 194 | self.BindKey(ord('h'),chamfer.MOD_MASK_4,KeyId('FOCUS_PARENT_LEFT')); 195 | 196 | #yanking and pasting containers 197 | self.BindKey(ord('y'),self.modMask,KeyId('YANK_CONTAINER')); 198 | self.BindKey(ord('y'),self.modMask|chamfer.MOD_MASK_CONTROL,KeyId('YANK_APPEND_CONTAINER')); 199 | self.BindKey(ord('p'),self.modMask,KeyId('PASTE_CONTAINER')); 200 | 201 | #misc grouping and parenting operations 202 | self.BindKey(ord('w'),self.modMask,KeyId('LIFT_CONTAINER')); 203 | 204 | #layout, splits and fullscreen 205 | self.BindKey(ord('e'),self.modMask,KeyId('LAYOUT')); 206 | self.BindKey(latin1.XK_onehalf,self.modMask,KeyId('SPLIT_V')); 207 | self.BindKey(ord('v'),self.modMask,KeyId('SPLIT_V')); 208 | self.BindKey(ord('f'),self.modMask,KeyId('FULLSCREEN')); 209 | self.BindKey(ord('t'),self.modMask,KeyId('STACK')); 210 | self.BindKey(ord('l'),self.modMask|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('STACK_RIGHT')); 211 | self.BindKey(ord('h'),self.modMask|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('STACK_LEFT')); 212 | self.BindKey(latin1.XK_space,self.modMask,KeyId('FLOAT')); 213 | 214 | #workspace dimensions 215 | self.BindKey(ord('r'),chamfer.MOD_MASK_4,KeyId('CONTRACT_ROOT_RESET')); 216 | self.BindKey(ord('u'),chamfer.MOD_MASK_4,KeyId('CONTRACT_ROOT_LEFT')); 217 | self.BindKey(ord('i'),chamfer.MOD_MASK_4,KeyId('CONTRACT_ROOT_RIGHT')); 218 | self.BindKey(ord('u'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT,KeyId('EXPAND_ROOT_LEFT')); 219 | self.BindKey(ord('i'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT,KeyId('EXPAND_ROOT_RIGHT')); 220 | 221 | #client dimensions 222 | self.BindKey(ord('r'),self.modMask,KeyId('CONTRACT_RESET')); 223 | 224 | self.BindKey(latin1.XK_minus,self.modMask,KeyId('CONTRACT_HORIZONTAL')); 225 | self.BindKey(ord('j'),chamfer.MOD_MASK_4,KeyId('CONTRACT_HORIZONTAL')); 226 | self.BindKey(latin1.XK_minus,self.modMask|chamfer.MOD_MASK_CONTROL,KeyId('CONTRACT_HORIZONTAL_LOCAL')); 227 | self.BindKey(ord('j'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_CONTROL,KeyId('CONTRACT_HORIZONTAL_LOCAL')); 228 | 229 | self.BindKey(latin1.XK_minus,self.modMask|chamfer.MOD_MASK_SHIFT,KeyId('CONTRACT_VERTICAL')); 230 | self.BindKey(ord('j'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT,KeyId('CONTRACT_VERTICAL')); 231 | self.BindKey(latin1.XK_minus,self.modMask|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('CONTRACT_VERTICAL_LOCAL')); 232 | self.BindKey(ord('j'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('CONTRACT_VERTICAL_LOCAL')); 233 | 234 | self.BindKey(latin1.XK_plus,self.modMask,KeyId('EXPAND_HORIZONTAL')); 235 | self.BindKey(ord('k'),chamfer.MOD_MASK_4,KeyId('EXPAND_HORIZONTAL')); 236 | self.BindKey(latin1.XK_plus,self.modMask|chamfer.MOD_MASK_CONTROL,KeyId('EXPAND_HORIZONTAL_LOCAL')); 237 | self.BindKey(ord('k'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_CONTROL,KeyId('EXPAND_HORIZONTAL_LOCAL')); 238 | 239 | self.BindKey(latin1.XK_plus,self.modMask|chamfer.MOD_MASK_SHIFT,KeyId('EXPAND_VERTICAL')); 240 | self.BindKey(ord('k'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT,KeyId('EXPAND_VERTICAL')); 241 | self.BindKey(latin1.XK_plus,self.modMask|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('EXPAND_VERTICAL_LOCAL')); 242 | self.BindKey(ord('k'),chamfer.MOD_MASK_4|chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('EXPAND_VERTICAL_LOCAL')); 243 | 244 | #workspaces (regular and composed) 245 | self.BindKey(ord('1'),self.modMask,KeyId('WORKSPACE_1')); 246 | self.BindKey(ord('2'),self.modMask,KeyId('WORKSPACE_2')); 247 | self.BindKey(ord('3'),self.modMask,KeyId('WORKSPACE_3')); 248 | self.BindKey(ord('4'),self.modMask,KeyId('WORKSPACE_4')); 249 | #one special workspace without compositor (maximize performance for fullscreen games, video and such) 250 | self.BindKey(ord('0'),self.modMask,KeyId('WORKSPACE_NOCOMP')); 251 | 252 | #kill + launching applications (setup your default programs in the respective OnKeyPress if-branch) 253 | self.BindKey(ord('q'),self.modMask|chamfer.MOD_MASK_SHIFT,KeyId('KILL')); 254 | self.BindKey(miscellany.XK_Return,self.modMask,KeyId('LAUNCH_TERMINAL')); 255 | self.BindKey(ord('1'),chamfer.MOD_MASK_4,KeyId('LAUNCH_BROWSER')); 256 | self.BindKey(ord('2'),chamfer.MOD_MASK_4,KeyId('LAUNCH_BROWSER_PRIVATE')); 257 | 258 | #volume 259 | self.BindKey(xf86.XK_XF86_AudioMute,0,KeyId('AUDIO_VOLUME_MUTE')); 260 | self.BindKey(xf86.XK_XF86_AudioRaiseVolume,0,KeyId('AUDIO_VOLUME_UP')); 261 | self.BindKey(xf86.XK_XF86_AudioLowerVolume,0,KeyId('AUDIO_VOLUME_DOWN')); 262 | 263 | #screenshots 264 | self.BindKey(ord('s'),chamfer.MOD_MASK_4,KeyId('SCREENSHOT')); 265 | 266 | #monitor brightness 267 | self.BindKey(xf86.XK_XF86_MonBrightnessUp,0,KeyId('MONITOR_BRIGHTNESS_UP')); 268 | self.BindKey(xf86.XK_XF86_MonBrightnessDown,0,KeyId('MONITOR_BRIGHTNESS_DOWN')); 269 | 270 | #control mappings 271 | self.MapKey(XK.XK_Alt_L,chamfer.MOD_MASK_1,KeyId('MODIFIER_1')); 272 | self.MapKey(XK.XK_Super_L,chamfer.MOD_MASK_4,KeyId('MODIFIER_4')); 273 | 274 | #hacks 275 | self.BindKey(ord('q'),chamfer.MOD_MASK_CONTROL,KeyId('NOOP')); #prevent madness while web browsing (disable Ctrl+Q by overriding it) 276 | 277 | else: 278 | #debug only (compositor testing mode) 279 | self.BindKey(ord('h'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_LEFT')); 280 | self.BindKey(ord('k'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_UP')); 281 | self.BindKey(ord('l'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_RIGHT')); 282 | self.BindKey(ord('j'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_DOWN')); 283 | self.BindKey(ord('u'),chamfer.MOD_MASK_SHIFT,KeyId('MOVE_LEFT')); 284 | self.BindKey(ord('i'),chamfer.MOD_MASK_SHIFT,KeyId('MOVE_RIGHT')); 285 | self.BindKey(ord('a'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_PARENT')); 286 | self.BindKey(ord('s'),chamfer.MOD_MASK_SHIFT,KeyId('FOCUS_CHILD')); 287 | self.BindKey(ord('y'),chamfer.MOD_MASK_SHIFT,KeyId('YANK_CONTAINER')); 288 | self.BindKey(ord('y'),chamfer.MOD_MASK_SHIFT|chamfer.MOD_MASK_CONTROL,KeyId('YANK_APPEND_CONTAINER')); 289 | self.BindKey(ord('p'),chamfer.MOD_MASK_SHIFT,KeyId('PASTE_CONTAINER')); 290 | self.BindKey(ord('w'),chamfer.MOD_MASK_SHIFT,KeyId('LIFT_CONTAINER')); 291 | self.BindKey(ord('e'),chamfer.MOD_MASK_SHIFT,KeyId('LAYOUT')); 292 | self.BindKey(ord('t'),chamfer.MOD_MASK_SHIFT,KeyId('STACK')); 293 | self.BindKey(latin1.XK_onehalf,chamfer.MOD_MASK_SHIFT,KeyId('SPLIT_V')); 294 | 295 | def OnCreateContainer(self): 296 | print("OnCreateContainer()",flush=True); 297 | return Container(); 298 | 299 | def OnKeyPress(self, keyId): 300 | focus = self.GetFocus(); 301 | parent = focus.GetParent(); 302 | 303 | if keyId == self.FOCUS_RIGHT: 304 | focus = focus.GetTiledFocus() if focus.IsFloating() else focus.FindParentLayout(chamfer.layout.VSPLIT).GetNext().GetFocusDescend(); 305 | focus.Focus(); 306 | 307 | elif keyId == self.FOCUS_LEFT: 308 | focus = focus.GetTiledFocus() if focus.IsFloating() else focus.FindParentLayout(chamfer.layout.VSPLIT).GetPrev().GetFocusDescend(); 309 | focus.Focus(); 310 | 311 | elif keyId == self.FOCUS_DOWN: 312 | focus = focus.GetTiledFocus() if focus.IsFloating() else focus.FindParentLayout(chamfer.layout.HSPLIT).GetNext().GetFocusDescend(); 313 | focus.Focus(); 314 | 315 | elif keyId == self.FOCUS_UP: 316 | focus = focus.GetTiledFocus() if focus.IsFloating() else focus.FindParentLayout(chamfer.layout.HSPLIT).GetPrev().GetFocusDescend(); 317 | focus.Focus(); 318 | 319 | elif keyId == self.MOVE_RIGHT: 320 | focus.MoveNext(); 321 | 322 | elif keyId == self.MOVE_LEFT: 323 | focus.MovePrev(); 324 | 325 | elif keyId == self.FOCUS_PARENT: 326 | if parent is None: 327 | return; 328 | parent.Focus(); 329 | 330 | elif keyId == self.FOCUS_CHILD: 331 | focus = focus.GetFocus(); 332 | if focus is None: 333 | return; 334 | focus.Focus(); 335 | 336 | elif keyId == self.FOCUS_MRU: 337 | try: 338 | self.shiftFocus.shaderFlags &= ~ShaderFlag.FOCUS_NEXT.value; 339 | except AttributeError: 340 | pass; 341 | 342 | try: 343 | self.shiftFocus = self.shiftFocus.GetTiledFocus(); 344 | except AttributeError: 345 | self.shiftFocus = focus.GetTiledFocus(); 346 | 347 | if self.shiftFocus is None: 348 | return; 349 | self.shiftFocus.shaderFlags |= ShaderFlag.FOCUS_NEXT.value; 350 | 351 | self.GrabKeyboard(True); 352 | 353 | elif keyId == self.FOCUS_FLOAT: 354 | try: 355 | self.shiftFocus.shaderFlags &= ~ShaderFlag.FOCUS_NEXT.value; 356 | except AttributeError: 357 | pass; 358 | 359 | try: 360 | self.shiftFocus = self.shiftFocus.GetFloatFocus(); 361 | except AttributeError: 362 | self.shiftFocus = focus.GetFloatFocus(); 363 | 364 | if self.shiftFocus is None: 365 | return; 366 | self.shiftFocus.shaderFlags |= ShaderFlag.FOCUS_NEXT.value; 367 | 368 | self.GrabKeyboard(True); 369 | 370 | elif keyId == self.FOCUS_FLOAT_PREV: 371 | #TODO, get previous from the focus history 372 | pass; 373 | 374 | elif keyId == self.FOCUS_PARENT_RIGHT: 375 | if parent is None: 376 | return; 377 | parent1 = parent.GetNext(); 378 | focus = parent1.GetFocus(); 379 | if focus is None: 380 | return; 381 | focus.Focus(); 382 | 383 | elif keyId == self.FOCUS_PARENT_LEFT: 384 | if parent is None: 385 | return; 386 | parent1 = parent.GetPrev(); 387 | focus = parent1.GetFocus(); 388 | if focus is None: 389 | return; 390 | focus.Focus(); 391 | 392 | elif keyId == self.YANK_CONTAINER: 393 | print("yanking container...",flush=True); 394 | self.yank = {focus}; 395 | 396 | elif keyId == self.YANK_APPEND_CONTAINER: 397 | print("yanking container (append)...",flush=True); 398 | try: 399 | self.yank.add(focus); 400 | except AttributeError: 401 | self.yank = {focus}; 402 | 403 | elif keyId == self.PASTE_CONTAINER: 404 | print("pasting container...",flush=True); 405 | try: 406 | if focus in self.yank: 407 | print("cannot paste on selection (one of the yanked containers).",flush=True); 408 | self.yank.remove(focus); 409 | peers = list(self.yank); 410 | 411 | focus1 = focus.GetFocus(); 412 | peers[0].Move(focus); 413 | 414 | if focus1 is None: 415 | focus = focus.GetParent(); 416 | for peer in peers[1:]: 417 | peer.Move(focus); 418 | 419 | except (AttributeError,IndexError): 420 | print("no containers to paste.",flush=True); 421 | except ValueError: 422 | print("expired container.",flush=True); 423 | 424 | elif keyId == self.LIFT_CONTAINER: 425 | sibling = focus.GetNext(); 426 | peer = sibling.GetNext(); 427 | if peer is not focus: 428 | sibling = peer.Place(sibling); 429 | 430 | peer = sibling.GetNext(); 431 | while peer is not focus: 432 | peer1 = peer.GetNext(); 433 | peer.Move(sibling); 434 | peer = peer1; 435 | 436 | elif keyId == self.LAYOUT: 437 | if parent is None: 438 | return; 439 | layout = { 440 | chamfer.layout.VSPLIT:chamfer.layout.HSPLIT, 441 | chamfer.layout.HSPLIT:chamfer.layout.VSPLIT 442 | }[parent.layout]; 443 | parent.ShiftLayout(layout); 444 | 445 | elif keyId == self.SPLIT_V: 446 | try: 447 | #Indicate that next time a container is created, 448 | #the current focus will be split. 449 | focus.splitArmed = not focus.splitArmed; 450 | except AttributeError: 451 | focus.splitArmed = True; 452 | 453 | elif keyId == self.FULLSCREEN: 454 | print("setting fullscreen",flush=True); 455 | focus.SetFullscreen(not focus.fullscreen); 456 | 457 | elif keyId == self.STACK: 458 | if parent is None: 459 | return; 460 | parent.SetStacked(not parent.stacked); 461 | 462 | elif keyId == self.STACK_RIGHT: 463 | container = focus.FindParentLayout(chamfer.layout.VSPLIT).GetNext(); 464 | if container is focus: 465 | return; 466 | focus.Move(container); 467 | 468 | parent1 = focus.GetParent(); 469 | parent1.SetStacked(True); 470 | parent1.ShiftLayout(chamfer.layout.HSPLIT); 471 | 472 | elif keyId == self.STACK_LEFT: 473 | container = focus.FindParentLayout(chamfer.layout.VSPLIT).GetPrev(); 474 | if container is focus: 475 | return; 476 | focus.Move(container); 477 | 478 | parent1 = focus.GetParent(); 479 | parent1.SetStacked(True); 480 | parent1.ShiftLayout(chamfer.layout.HSPLIT); 481 | 482 | elif keyId == self.FLOAT: 483 | focus.SetFloating(True); 484 | 485 | elif keyId == self.CONTRACT_ROOT_RESET: 486 | root = self.GetRoot(); 487 | root.canvasOffset = (0.0,0.0); 488 | root.canvasExtent = (0.0,0.0); 489 | root.ShiftLayout(root.layout); 490 | 491 | elif keyId == self.CONTRACT_ROOT_LEFT: 492 | root = self.GetRoot(); 493 | root.canvasOffset = (root.canvasOffset[0]+0.1,root.canvasOffset[1]); 494 | root.canvasExtent = (root.canvasExtent[0]+0.1,root.canvasExtent[1]);#root.canvasOffset; 495 | root.ShiftLayout(root.layout); 496 | 497 | elif keyId == self.CONTRACT_ROOT_RIGHT: 498 | root = self.GetRoot(); 499 | root.canvasExtent = (root.canvasExtent[0]+0.1,root.canvasExtent[1]); 500 | root.ShiftLayout(root.layout); 501 | 502 | elif keyId == self.EXPAND_ROOT_LEFT: 503 | root = self.GetRoot(); 504 | root.canvasOffset = (root.canvasOffset[0]-0.1,root.canvasOffset[1]); 505 | root.canvasExtent = (root.canvasExtent[0]-0.1,root.canvasExtent[1]); 506 | root.ShiftLayout(root.layout); 507 | 508 | elif keyId == self.EXPAND_ROOT_RIGHT: 509 | root = self.GetRoot(); 510 | root.canvasExtent = (root.canvasExtent[0]-0.1,root.canvasExtent[1]); 511 | root.ShiftLayout(root.layout); 512 | 513 | elif keyId == self.CONTRACT_RESET: 514 | container = parent if (parent is not None) and parent.stacked else focus; 515 | container.canvasOffset = (0.0,0.0); 516 | container.canvasExtent = (0.0,0.0); 517 | container.ShiftLayout(container.layout); 518 | 519 | elif keyId == self.CONTRACT_HORIZONTAL: 520 | container = parent if (parent is not None) and parent.stacked else focus; 521 | container.size = (container.size[0]-0.1,container.size[1]); 522 | 523 | elif keyId == self.CONTRACT_HORIZONTAL_LOCAL: 524 | container = parent if (parent is not None) and parent.stacked else focus; 525 | container.canvasOffset = (container.canvasOffset[0]+0.05,container.canvasOffset[1]); 526 | container.canvasExtent = (container.canvasExtent[0]+0.10,container.canvasExtent[1]); 527 | container.ShiftLayout(container.layout); 528 | 529 | elif keyId == self.CONTRACT_VERTICAL: 530 | container = parent if (parent is not None) and parent.stacked else focus; 531 | container.size = (container.size[0],container.size[1]-0.1); 532 | 533 | elif keyId == self.CONTRACT_VERTICAL_LOCAL: 534 | container = parent if (parent is not None) and parent.stacked else focus; 535 | container.canvasOffset = (container.canvasOffset[0],container.canvasOffset[1]+0.05); 536 | container.canvasExtent = (container.canvasExtent[0],container.canvasExtent[1]+0.10); 537 | container.ShiftLayout(container.layout); 538 | 539 | elif keyId in [self.WORKSPACE_1,self.WORKSPACE_2,self.WORKSPACE_3,self.WORKSPACE_4]: 540 | #add more workspaces by defining more WORKSPACE_* 541 | wsName = str(keyId-self.WORKSPACE_1+1); 542 | root = self.GetRoot(wsName); 543 | root.GetFocusDescend = Container.GetFocusDescend.__get__(root); #RootContainer does not have GetFocusDescend, so we will add it now 544 | root.GetFocusDescend().Focus(); 545 | 546 | elif keyId == self.WORKSPACE_NOCOMP: 547 | root = self.GetRoot("nocomp"); 548 | root.GetFocusDescend = Container.GetFocusDescend.__get__(root); 549 | root.GetFocusDescend().Focus(); 550 | 551 | elif keyId == self.EXPAND_HORIZONTAL: 552 | container = parent if (parent is not None) and parent.stacked else focus; 553 | container.size = (container.size[0]+0.1,container.size[1]); 554 | 555 | elif keyId == self.EXPAND_HORIZONTAL_LOCAL: 556 | container = parent if (parent is not None) and parent.stacked else focus; 557 | container.canvasOffset = (container.canvasOffset[0]-0.05,container.canvasOffset[1]); 558 | container.canvasExtent = (container.canvasExtent[0]-0.10,container.canvasExtent[1]); 559 | container.ShiftLayout(container.layout); 560 | 561 | elif keyId == self.EXPAND_VERTICAL: 562 | container = parent if (parent is not None) and parent.stacked else focus; 563 | container.size = (container.size[0],container.size[1]+0.1); 564 | 565 | elif keyId == self.EXPAND_VERTICAL_LOCAL: 566 | container = parent if (parent is not None) and parent.stacked else focus; 567 | container.canvasOffset = (container.canvasOffset[0],container.canvasOffset[1]-0.05); 568 | container.canvasExtent = (container.canvasExtent[0],container.canvasExtent[1]-0.10); 569 | container.ShiftLayout(container.layout); 570 | 571 | elif keyId == self.KILL: 572 | focus.Kill(); 573 | 574 | elif keyId == self.LAUNCH_TERMINAL: 575 | for t in [os.getenv("TERMINAL"),"alacritty","kitty","urxvt","rxvt","st","xterm"]: 576 | try: 577 | psutil.Popen([t],stdout=None,stderr=None); 578 | break; 579 | except (TypeError,FileNotFoundError): 580 | pass; 581 | 582 | elif keyId == self.LAUNCH_BROWSER: 583 | psutil.Popen(["firefox"],stdout=None,stderr=None); 584 | 585 | elif keyId == self.LAUNCH_BROWSER_PRIVATE: 586 | psutil.Popen(["firefox","--private-window"],stdout=None,stderr=None); 587 | 588 | elif keyId == self.AUDIO_VOLUME_MUTE: 589 | if "pulsectl" in sys.modules: 590 | with pulsectl.Pulse('chamferwm') as pulse: 591 | defSinkName = pulse.server_info().default_sink_name; 592 | for sink in pulse.sink_list(): 593 | if sink.name == defSinkName: 594 | pulse.mute(sink,not sink.mute); 595 | break; 596 | 597 | elif keyId == self.AUDIO_VOLUME_UP: 598 | if "pulsectl" in sys.modules: 599 | with pulsectl.Pulse('chamferwm') as pulse: 600 | defSinkName = pulse.server_info().default_sink_name; 601 | for sink in pulse.sink_list(): 602 | if sink.name == defSinkName: 603 | pulse.volume_change_all_chans(sink,0.05); 604 | break; 605 | 606 | elif keyId == self.AUDIO_VOLUME_DOWN: 607 | if "pulsectl" in sys.modules: 608 | with pulsectl.Pulse('chamferwm') as pulse: 609 | defSinkName = pulse.server_info().default_sink_name; 610 | for sink in pulse.sink_list(): 611 | if sink.name == defSinkName: 612 | pulse.volume_change_all_chans(sink,-0.05); 613 | break; 614 | 615 | elif keyId == self.SCREENSHOT: 616 | psutil.Popen(["sh","-c","import png:- | xclip -selection clipboard -t image/png"]); 617 | 618 | elif keyId == self.MONITOR_BRIGHTNESS_UP: 619 | psutil.Popen(["xbacklight","-inc","20"]); 620 | 621 | elif keyId == self.MONITOR_BRIGHTNESS_DOWN: 622 | psutil.Popen(["xbacklight","-dec","20"]); 623 | 624 | def OnKeyRelease(self, keyId): 625 | if keyId == self.MODIFIER_1 or keyId == self.MODIFIER_4: 626 | self.GrabKeyboard(False); 627 | try: 628 | self.shiftFocus.shaderFlags &= ~ShaderFlag.FOCUS_NEXT.value; 629 | self.shiftFocus.Focus(); #ignoreTimer=True 630 | except AttributeError: 631 | pass; 632 | 633 | self.shiftFocus = None; 634 | 635 | class Compositor(chamfer.Compositor): 636 | def OnRedirectExternal(self, title, className): 637 | #Used only in standalone compositor mode. Return False to filter out incompatible WM/UI components. 638 | return True; 639 | 640 | backend = Backend(); 641 | chamfer.BindBackend(backend); 642 | 643 | if not backend.standaloneCompositor: 644 | #Import some modules for WM use 645 | try: 646 | import psutil 647 | except ModuleNotFoundError: 648 | print("No psutil module."); 649 | 650 | try: 651 | from Xlib.keysymdef import latin1,miscellany,xf86 652 | from Xlib import XK 653 | except ModuleNotFoundError: 654 | print("No Xlib module."); 655 | 656 | try: 657 | import pulsectl 658 | except ModuleNotFoundError: 659 | print("No pulsectl module."); 660 | 661 | compositor = Compositor(); 662 | #compositor.deviceIndex = 0; 663 | compositor.fontName = "Monospace"; 664 | compositor.fontSize = 24; 665 | compositor.enableAnimation = True; 666 | chamfer.BindCompositor(compositor); 667 | 668 | if not backend.standaloneCompositor: 669 | #Acquire list of running processes to not launch something that is already running. 670 | pids = psutil.pids(); 671 | pnames = [psutil.Process(pid).name() for pid in pids]; 672 | pcmdls = [a for p in [psutil.Process(pid).cmdline() for pid in pids] for a in p]; 673 | 674 | #---set wallpaper with feh 675 | #psutil.Popen(["feh","--no-fehbg","--image-bg","black","--bg-center","background.png"]); 676 | 677 | #---startup programs examples: 678 | #launch notification system 679 | #if not "dunst" in pnames: 680 | # print("starting dunst..."); 681 | # psutil.Popen(["dunst"],stdout=None,stderr=None); 682 | 683 | #launch clipboard manager 684 | #if not any(["clipster" in p for p in pcmdls]): 685 | # print("starting clipster..."); #clipboard manager 686 | # psutil.Popen(["clipster","-d"],stdout=None,stderr=None); 687 | 688 | #launch gestures daemon for touch devices 689 | #if not any(["libinput-gestures" in p for p in pcmdls]): 690 | # print("starting libinput-gestures..."); #touchpad gestures 691 | # psutil.Popen(["libinput-gestures-setup","start"],stdout=None,stderr=None); 692 | 693 | -------------------------------------------------------------------------------- /third/spirv_reflect/include/spirv/unified1/spirv.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 2014-2018 The Khronos Group Inc. 3 | ** 4 | ** Permission is hereby granted, free of charge, to any person obtaining a copy 5 | ** of this software and/or associated documentation files (the "Materials"), 6 | ** to deal in the Materials without restriction, including without limitation 7 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | ** and/or sell copies of the Materials, and to permit persons to whom the 9 | ** Materials are furnished to do so, subject to the following conditions: 10 | ** 11 | ** The above copyright notice and this permission notice shall be included in 12 | ** all copies or substantial portions of the Materials. 13 | ** 14 | ** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS 15 | ** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND 16 | ** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 17 | ** 18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | ** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | ** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS 24 | ** IN THE MATERIALS. 25 | */ 26 | 27 | /* 28 | ** This header is automatically generated by the same tool that creates 29 | ** the Binary Section of the SPIR-V specification. 30 | */ 31 | 32 | /* 33 | ** Enumeration tokens for SPIR-V, in various styles: 34 | ** C, C++, C++11, JSON, Lua, Python 35 | ** 36 | ** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL 37 | ** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL 38 | ** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL 39 | ** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL 40 | ** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] 41 | ** 42 | ** Some tokens act like mask values, which can be OR'd together, 43 | ** while others are mutually exclusive. The mask-like ones have 44 | ** "Mask" in their name, and a parallel enum that has the shift 45 | ** amount (1 << x) for each corresponding enumerant. 46 | */ 47 | 48 | #ifndef spirv_H 49 | #define spirv_H 50 | 51 | typedef unsigned int SpvId; 52 | 53 | #define SPV_VERSION 0x10300 54 | #define SPV_REVISION 1 55 | 56 | static const unsigned int SpvMagicNumber = 0x07230203; 57 | static const unsigned int SpvVersion = 0x00010300; 58 | static const unsigned int SpvRevision = 1; 59 | static const unsigned int SpvOpCodeMask = 0xffff; 60 | static const unsigned int SpvWordCountShift = 16; 61 | 62 | typedef enum SpvSourceLanguage_ { 63 | SpvSourceLanguageUnknown = 0, 64 | SpvSourceLanguageESSL = 1, 65 | SpvSourceLanguageGLSL = 2, 66 | SpvSourceLanguageOpenCL_C = 3, 67 | SpvSourceLanguageOpenCL_CPP = 4, 68 | SpvSourceLanguageHLSL = 5, 69 | SpvSourceLanguageMax = 0x7fffffff, 70 | } SpvSourceLanguage; 71 | 72 | typedef enum SpvExecutionModel_ { 73 | SpvExecutionModelVertex = 0, 74 | SpvExecutionModelTessellationControl = 1, 75 | SpvExecutionModelTessellationEvaluation = 2, 76 | SpvExecutionModelGeometry = 3, 77 | SpvExecutionModelFragment = 4, 78 | SpvExecutionModelGLCompute = 5, 79 | SpvExecutionModelKernel = 6, 80 | SpvExecutionModelMax = 0x7fffffff, 81 | } SpvExecutionModel; 82 | 83 | typedef enum SpvAddressingModel_ { 84 | SpvAddressingModelLogical = 0, 85 | SpvAddressingModelPhysical32 = 1, 86 | SpvAddressingModelPhysical64 = 2, 87 | SpvAddressingModelMax = 0x7fffffff, 88 | } SpvAddressingModel; 89 | 90 | typedef enum SpvMemoryModel_ { 91 | SpvMemoryModelSimple = 0, 92 | SpvMemoryModelGLSL450 = 1, 93 | SpvMemoryModelOpenCL = 2, 94 | SpvMemoryModelMax = 0x7fffffff, 95 | } SpvMemoryModel; 96 | 97 | typedef enum SpvExecutionMode_ { 98 | SpvExecutionModeInvocations = 0, 99 | SpvExecutionModeSpacingEqual = 1, 100 | SpvExecutionModeSpacingFractionalEven = 2, 101 | SpvExecutionModeSpacingFractionalOdd = 3, 102 | SpvExecutionModeVertexOrderCw = 4, 103 | SpvExecutionModeVertexOrderCcw = 5, 104 | SpvExecutionModePixelCenterInteger = 6, 105 | SpvExecutionModeOriginUpperLeft = 7, 106 | SpvExecutionModeOriginLowerLeft = 8, 107 | SpvExecutionModeEarlyFragmentTests = 9, 108 | SpvExecutionModePointMode = 10, 109 | SpvExecutionModeXfb = 11, 110 | SpvExecutionModeDepthReplacing = 12, 111 | SpvExecutionModeDepthGreater = 14, 112 | SpvExecutionModeDepthLess = 15, 113 | SpvExecutionModeDepthUnchanged = 16, 114 | SpvExecutionModeLocalSize = 17, 115 | SpvExecutionModeLocalSizeHint = 18, 116 | SpvExecutionModeInputPoints = 19, 117 | SpvExecutionModeInputLines = 20, 118 | SpvExecutionModeInputLinesAdjacency = 21, 119 | SpvExecutionModeTriangles = 22, 120 | SpvExecutionModeInputTrianglesAdjacency = 23, 121 | SpvExecutionModeQuads = 24, 122 | SpvExecutionModeIsolines = 25, 123 | SpvExecutionModeOutputVertices = 26, 124 | SpvExecutionModeOutputPoints = 27, 125 | SpvExecutionModeOutputLineStrip = 28, 126 | SpvExecutionModeOutputTriangleStrip = 29, 127 | SpvExecutionModeVecTypeHint = 30, 128 | SpvExecutionModeContractionOff = 31, 129 | SpvExecutionModeInitializer = 33, 130 | SpvExecutionModeFinalizer = 34, 131 | SpvExecutionModeSubgroupSize = 35, 132 | SpvExecutionModeSubgroupsPerWorkgroup = 36, 133 | SpvExecutionModeSubgroupsPerWorkgroupId = 37, 134 | SpvExecutionModeLocalSizeId = 38, 135 | SpvExecutionModeLocalSizeHintId = 39, 136 | SpvExecutionModePostDepthCoverage = 4446, 137 | SpvExecutionModeStencilRefReplacingEXT = 5027, 138 | SpvExecutionModeMax = 0x7fffffff, 139 | } SpvExecutionMode; 140 | 141 | typedef enum SpvStorageClass_ { 142 | SpvStorageClassUniformConstant = 0, 143 | SpvStorageClassInput = 1, 144 | SpvStorageClassUniform = 2, 145 | SpvStorageClassOutput = 3, 146 | SpvStorageClassWorkgroup = 4, 147 | SpvStorageClassCrossWorkgroup = 5, 148 | SpvStorageClassPrivate = 6, 149 | SpvStorageClassFunction = 7, 150 | SpvStorageClassGeneric = 8, 151 | SpvStorageClassPushConstant = 9, 152 | SpvStorageClassAtomicCounter = 10, 153 | SpvStorageClassImage = 11, 154 | SpvStorageClassStorageBuffer = 12, 155 | SpvStorageClassMax = 0x7fffffff, 156 | } SpvStorageClass; 157 | 158 | typedef enum SpvDim_ { 159 | SpvDim1D = 0, 160 | SpvDim2D = 1, 161 | SpvDim3D = 2, 162 | SpvDimCube = 3, 163 | SpvDimRect = 4, 164 | SpvDimBuffer = 5, 165 | SpvDimSubpassData = 6, 166 | SpvDimMax = 0x7fffffff, 167 | } SpvDim; 168 | 169 | typedef enum SpvSamplerAddressingMode_ { 170 | SpvSamplerAddressingModeNone = 0, 171 | SpvSamplerAddressingModeClampToEdge = 1, 172 | SpvSamplerAddressingModeClamp = 2, 173 | SpvSamplerAddressingModeRepeat = 3, 174 | SpvSamplerAddressingModeRepeatMirrored = 4, 175 | SpvSamplerAddressingModeMax = 0x7fffffff, 176 | } SpvSamplerAddressingMode; 177 | 178 | typedef enum SpvSamplerFilterMode_ { 179 | SpvSamplerFilterModeNearest = 0, 180 | SpvSamplerFilterModeLinear = 1, 181 | SpvSamplerFilterModeMax = 0x7fffffff, 182 | } SpvSamplerFilterMode; 183 | 184 | typedef enum SpvImageFormat_ { 185 | SpvImageFormatUnknown = 0, 186 | SpvImageFormatRgba32f = 1, 187 | SpvImageFormatRgba16f = 2, 188 | SpvImageFormatR32f = 3, 189 | SpvImageFormatRgba8 = 4, 190 | SpvImageFormatRgba8Snorm = 5, 191 | SpvImageFormatRg32f = 6, 192 | SpvImageFormatRg16f = 7, 193 | SpvImageFormatR11fG11fB10f = 8, 194 | SpvImageFormatR16f = 9, 195 | SpvImageFormatRgba16 = 10, 196 | SpvImageFormatRgb10A2 = 11, 197 | SpvImageFormatRg16 = 12, 198 | SpvImageFormatRg8 = 13, 199 | SpvImageFormatR16 = 14, 200 | SpvImageFormatR8 = 15, 201 | SpvImageFormatRgba16Snorm = 16, 202 | SpvImageFormatRg16Snorm = 17, 203 | SpvImageFormatRg8Snorm = 18, 204 | SpvImageFormatR16Snorm = 19, 205 | SpvImageFormatR8Snorm = 20, 206 | SpvImageFormatRgba32i = 21, 207 | SpvImageFormatRgba16i = 22, 208 | SpvImageFormatRgba8i = 23, 209 | SpvImageFormatR32i = 24, 210 | SpvImageFormatRg32i = 25, 211 | SpvImageFormatRg16i = 26, 212 | SpvImageFormatRg8i = 27, 213 | SpvImageFormatR16i = 28, 214 | SpvImageFormatR8i = 29, 215 | SpvImageFormatRgba32ui = 30, 216 | SpvImageFormatRgba16ui = 31, 217 | SpvImageFormatRgba8ui = 32, 218 | SpvImageFormatR32ui = 33, 219 | SpvImageFormatRgb10a2ui = 34, 220 | SpvImageFormatRg32ui = 35, 221 | SpvImageFormatRg16ui = 36, 222 | SpvImageFormatRg8ui = 37, 223 | SpvImageFormatR16ui = 38, 224 | SpvImageFormatR8ui = 39, 225 | SpvImageFormatMax = 0x7fffffff, 226 | } SpvImageFormat; 227 | 228 | typedef enum SpvImageChannelOrder_ { 229 | SpvImageChannelOrderR = 0, 230 | SpvImageChannelOrderA = 1, 231 | SpvImageChannelOrderRG = 2, 232 | SpvImageChannelOrderRA = 3, 233 | SpvImageChannelOrderRGB = 4, 234 | SpvImageChannelOrderRGBA = 5, 235 | SpvImageChannelOrderBGRA = 6, 236 | SpvImageChannelOrderARGB = 7, 237 | SpvImageChannelOrderIntensity = 8, 238 | SpvImageChannelOrderLuminance = 9, 239 | SpvImageChannelOrderRx = 10, 240 | SpvImageChannelOrderRGx = 11, 241 | SpvImageChannelOrderRGBx = 12, 242 | SpvImageChannelOrderDepth = 13, 243 | SpvImageChannelOrderDepthStencil = 14, 244 | SpvImageChannelOrdersRGB = 15, 245 | SpvImageChannelOrdersRGBx = 16, 246 | SpvImageChannelOrdersRGBA = 17, 247 | SpvImageChannelOrdersBGRA = 18, 248 | SpvImageChannelOrderABGR = 19, 249 | SpvImageChannelOrderMax = 0x7fffffff, 250 | } SpvImageChannelOrder; 251 | 252 | typedef enum SpvImageChannelDataType_ { 253 | SpvImageChannelDataTypeSnormInt8 = 0, 254 | SpvImageChannelDataTypeSnormInt16 = 1, 255 | SpvImageChannelDataTypeUnormInt8 = 2, 256 | SpvImageChannelDataTypeUnormInt16 = 3, 257 | SpvImageChannelDataTypeUnormShort565 = 4, 258 | SpvImageChannelDataTypeUnormShort555 = 5, 259 | SpvImageChannelDataTypeUnormInt101010 = 6, 260 | SpvImageChannelDataTypeSignedInt8 = 7, 261 | SpvImageChannelDataTypeSignedInt16 = 8, 262 | SpvImageChannelDataTypeSignedInt32 = 9, 263 | SpvImageChannelDataTypeUnsignedInt8 = 10, 264 | SpvImageChannelDataTypeUnsignedInt16 = 11, 265 | SpvImageChannelDataTypeUnsignedInt32 = 12, 266 | SpvImageChannelDataTypeHalfFloat = 13, 267 | SpvImageChannelDataTypeFloat = 14, 268 | SpvImageChannelDataTypeUnormInt24 = 15, 269 | SpvImageChannelDataTypeUnormInt101010_2 = 16, 270 | SpvImageChannelDataTypeMax = 0x7fffffff, 271 | } SpvImageChannelDataType; 272 | 273 | typedef enum SpvImageOperandsShift_ { 274 | SpvImageOperandsBiasShift = 0, 275 | SpvImageOperandsLodShift = 1, 276 | SpvImageOperandsGradShift = 2, 277 | SpvImageOperandsConstOffsetShift = 3, 278 | SpvImageOperandsOffsetShift = 4, 279 | SpvImageOperandsConstOffsetsShift = 5, 280 | SpvImageOperandsSampleShift = 6, 281 | SpvImageOperandsMinLodShift = 7, 282 | SpvImageOperandsMax = 0x7fffffff, 283 | } SpvImageOperandsShift; 284 | 285 | typedef enum SpvImageOperandsMask_ { 286 | SpvImageOperandsMaskNone = 0, 287 | SpvImageOperandsBiasMask = 0x00000001, 288 | SpvImageOperandsLodMask = 0x00000002, 289 | SpvImageOperandsGradMask = 0x00000004, 290 | SpvImageOperandsConstOffsetMask = 0x00000008, 291 | SpvImageOperandsOffsetMask = 0x00000010, 292 | SpvImageOperandsConstOffsetsMask = 0x00000020, 293 | SpvImageOperandsSampleMask = 0x00000040, 294 | SpvImageOperandsMinLodMask = 0x00000080, 295 | } SpvImageOperandsMask; 296 | 297 | typedef enum SpvFPFastMathModeShift_ { 298 | SpvFPFastMathModeNotNaNShift = 0, 299 | SpvFPFastMathModeNotInfShift = 1, 300 | SpvFPFastMathModeNSZShift = 2, 301 | SpvFPFastMathModeAllowRecipShift = 3, 302 | SpvFPFastMathModeFastShift = 4, 303 | SpvFPFastMathModeMax = 0x7fffffff, 304 | } SpvFPFastMathModeShift; 305 | 306 | typedef enum SpvFPFastMathModeMask_ { 307 | SpvFPFastMathModeMaskNone = 0, 308 | SpvFPFastMathModeNotNaNMask = 0x00000001, 309 | SpvFPFastMathModeNotInfMask = 0x00000002, 310 | SpvFPFastMathModeNSZMask = 0x00000004, 311 | SpvFPFastMathModeAllowRecipMask = 0x00000008, 312 | SpvFPFastMathModeFastMask = 0x00000010, 313 | } SpvFPFastMathModeMask; 314 | 315 | typedef enum SpvFPRoundingMode_ { 316 | SpvFPRoundingModeRTE = 0, 317 | SpvFPRoundingModeRTZ = 1, 318 | SpvFPRoundingModeRTP = 2, 319 | SpvFPRoundingModeRTN = 3, 320 | SpvFPRoundingModeMax = 0x7fffffff, 321 | } SpvFPRoundingMode; 322 | 323 | typedef enum SpvLinkageType_ { 324 | SpvLinkageTypeExport = 0, 325 | SpvLinkageTypeImport = 1, 326 | SpvLinkageTypeMax = 0x7fffffff, 327 | } SpvLinkageType; 328 | 329 | typedef enum SpvAccessQualifier_ { 330 | SpvAccessQualifierReadOnly = 0, 331 | SpvAccessQualifierWriteOnly = 1, 332 | SpvAccessQualifierReadWrite = 2, 333 | SpvAccessQualifierMax = 0x7fffffff, 334 | } SpvAccessQualifier; 335 | 336 | typedef enum SpvFunctionParameterAttribute_ { 337 | SpvFunctionParameterAttributeZext = 0, 338 | SpvFunctionParameterAttributeSext = 1, 339 | SpvFunctionParameterAttributeByVal = 2, 340 | SpvFunctionParameterAttributeSret = 3, 341 | SpvFunctionParameterAttributeNoAlias = 4, 342 | SpvFunctionParameterAttributeNoCapture = 5, 343 | SpvFunctionParameterAttributeNoWrite = 6, 344 | SpvFunctionParameterAttributeNoReadWrite = 7, 345 | SpvFunctionParameterAttributeMax = 0x7fffffff, 346 | } SpvFunctionParameterAttribute; 347 | 348 | typedef enum SpvDecoration_ { 349 | SpvDecorationRelaxedPrecision = 0, 350 | SpvDecorationSpecId = 1, 351 | SpvDecorationBlock = 2, 352 | SpvDecorationBufferBlock = 3, 353 | SpvDecorationRowMajor = 4, 354 | SpvDecorationColMajor = 5, 355 | SpvDecorationArrayStride = 6, 356 | SpvDecorationMatrixStride = 7, 357 | SpvDecorationGLSLShared = 8, 358 | SpvDecorationGLSLPacked = 9, 359 | SpvDecorationCPacked = 10, 360 | SpvDecorationBuiltIn = 11, 361 | SpvDecorationNoPerspective = 13, 362 | SpvDecorationFlat = 14, 363 | SpvDecorationPatch = 15, 364 | SpvDecorationCentroid = 16, 365 | SpvDecorationSample = 17, 366 | SpvDecorationInvariant = 18, 367 | SpvDecorationRestrict = 19, 368 | SpvDecorationAliased = 20, 369 | SpvDecorationVolatile = 21, 370 | SpvDecorationConstant = 22, 371 | SpvDecorationCoherent = 23, 372 | SpvDecorationNonWritable = 24, 373 | SpvDecorationNonReadable = 25, 374 | SpvDecorationUniform = 26, 375 | SpvDecorationSaturatedConversion = 28, 376 | SpvDecorationStream = 29, 377 | SpvDecorationLocation = 30, 378 | SpvDecorationComponent = 31, 379 | SpvDecorationIndex = 32, 380 | SpvDecorationBinding = 33, 381 | SpvDecorationDescriptorSet = 34, 382 | SpvDecorationOffset = 35, 383 | SpvDecorationXfbBuffer = 36, 384 | SpvDecorationXfbStride = 37, 385 | SpvDecorationFuncParamAttr = 38, 386 | SpvDecorationFPRoundingMode = 39, 387 | SpvDecorationFPFastMathMode = 40, 388 | SpvDecorationLinkageAttributes = 41, 389 | SpvDecorationNoContraction = 42, 390 | SpvDecorationInputAttachmentIndex = 43, 391 | SpvDecorationAlignment = 44, 392 | SpvDecorationMaxByteOffset = 45, 393 | SpvDecorationAlignmentId = 46, 394 | SpvDecorationMaxByteOffsetId = 47, 395 | SpvDecorationExplicitInterpAMD = 4999, 396 | SpvDecorationOverrideCoverageNV = 5248, 397 | SpvDecorationPassthroughNV = 5250, 398 | SpvDecorationViewportRelativeNV = 5252, 399 | SpvDecorationSecondaryViewportRelativeNV = 5256, 400 | SpvDecorationHlslCounterBufferGOOGLE = 5634, 401 | SpvDecorationHlslSemanticGOOGLE = 5635, 402 | SpvDecorationMax = 0x7fffffff, 403 | } SpvDecoration; 404 | 405 | typedef enum SpvBuiltIn_ { 406 | SpvBuiltInPosition = 0, 407 | SpvBuiltInPointSize = 1, 408 | SpvBuiltInClipDistance = 3, 409 | SpvBuiltInCullDistance = 4, 410 | SpvBuiltInVertexId = 5, 411 | SpvBuiltInInstanceId = 6, 412 | SpvBuiltInPrimitiveId = 7, 413 | SpvBuiltInInvocationId = 8, 414 | SpvBuiltInLayer = 9, 415 | SpvBuiltInViewportIndex = 10, 416 | SpvBuiltInTessLevelOuter = 11, 417 | SpvBuiltInTessLevelInner = 12, 418 | SpvBuiltInTessCoord = 13, 419 | SpvBuiltInPatchVertices = 14, 420 | SpvBuiltInFragCoord = 15, 421 | SpvBuiltInPointCoord = 16, 422 | SpvBuiltInFrontFacing = 17, 423 | SpvBuiltInSampleId = 18, 424 | SpvBuiltInSamplePosition = 19, 425 | SpvBuiltInSampleMask = 20, 426 | SpvBuiltInFragDepth = 22, 427 | SpvBuiltInHelperInvocation = 23, 428 | SpvBuiltInNumWorkgroups = 24, 429 | SpvBuiltInWorkgroupSize = 25, 430 | SpvBuiltInWorkgroupId = 26, 431 | SpvBuiltInLocalInvocationId = 27, 432 | SpvBuiltInGlobalInvocationId = 28, 433 | SpvBuiltInLocalInvocationIndex = 29, 434 | SpvBuiltInWorkDim = 30, 435 | SpvBuiltInGlobalSize = 31, 436 | SpvBuiltInEnqueuedWorkgroupSize = 32, 437 | SpvBuiltInGlobalOffset = 33, 438 | SpvBuiltInGlobalLinearId = 34, 439 | SpvBuiltInSubgroupSize = 36, 440 | SpvBuiltInSubgroupMaxSize = 37, 441 | SpvBuiltInNumSubgroups = 38, 442 | SpvBuiltInNumEnqueuedSubgroups = 39, 443 | SpvBuiltInSubgroupId = 40, 444 | SpvBuiltInSubgroupLocalInvocationId = 41, 445 | SpvBuiltInVertexIndex = 42, 446 | SpvBuiltInInstanceIndex = 43, 447 | SpvBuiltInSubgroupEqMask = 4416, 448 | SpvBuiltInSubgroupEqMaskKHR = 4416, 449 | SpvBuiltInSubgroupGeMask = 4417, 450 | SpvBuiltInSubgroupGeMaskKHR = 4417, 451 | SpvBuiltInSubgroupGtMask = 4418, 452 | SpvBuiltInSubgroupGtMaskKHR = 4418, 453 | SpvBuiltInSubgroupLeMask = 4419, 454 | SpvBuiltInSubgroupLeMaskKHR = 4419, 455 | SpvBuiltInSubgroupLtMask = 4420, 456 | SpvBuiltInSubgroupLtMaskKHR = 4420, 457 | SpvBuiltInBaseVertex = 4424, 458 | SpvBuiltInBaseInstance = 4425, 459 | SpvBuiltInDrawIndex = 4426, 460 | SpvBuiltInDeviceIndex = 4438, 461 | SpvBuiltInViewIndex = 4440, 462 | SpvBuiltInBaryCoordNoPerspAMD = 4992, 463 | SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993, 464 | SpvBuiltInBaryCoordNoPerspSampleAMD = 4994, 465 | SpvBuiltInBaryCoordSmoothAMD = 4995, 466 | SpvBuiltInBaryCoordSmoothCentroidAMD = 4996, 467 | SpvBuiltInBaryCoordSmoothSampleAMD = 4997, 468 | SpvBuiltInBaryCoordPullModelAMD = 4998, 469 | SpvBuiltInFragStencilRefEXT = 5014, 470 | SpvBuiltInViewportMaskNV = 5253, 471 | SpvBuiltInSecondaryPositionNV = 5257, 472 | SpvBuiltInSecondaryViewportMaskNV = 5258, 473 | SpvBuiltInPositionPerViewNV = 5261, 474 | SpvBuiltInViewportMaskPerViewNV = 5262, 475 | SpvBuiltInFullyCoveredEXT = 5264, 476 | SpvBuiltInMax = 0x7fffffff, 477 | } SpvBuiltIn; 478 | 479 | typedef enum SpvSelectionControlShift_ { 480 | SpvSelectionControlFlattenShift = 0, 481 | SpvSelectionControlDontFlattenShift = 1, 482 | SpvSelectionControlMax = 0x7fffffff, 483 | } SpvSelectionControlShift; 484 | 485 | typedef enum SpvSelectionControlMask_ { 486 | SpvSelectionControlMaskNone = 0, 487 | SpvSelectionControlFlattenMask = 0x00000001, 488 | SpvSelectionControlDontFlattenMask = 0x00000002, 489 | } SpvSelectionControlMask; 490 | 491 | typedef enum SpvLoopControlShift_ { 492 | SpvLoopControlUnrollShift = 0, 493 | SpvLoopControlDontUnrollShift = 1, 494 | SpvLoopControlDependencyInfiniteShift = 2, 495 | SpvLoopControlDependencyLengthShift = 3, 496 | SpvLoopControlMax = 0x7fffffff, 497 | } SpvLoopControlShift; 498 | 499 | typedef enum SpvLoopControlMask_ { 500 | SpvLoopControlMaskNone = 0, 501 | SpvLoopControlUnrollMask = 0x00000001, 502 | SpvLoopControlDontUnrollMask = 0x00000002, 503 | SpvLoopControlDependencyInfiniteMask = 0x00000004, 504 | SpvLoopControlDependencyLengthMask = 0x00000008, 505 | } SpvLoopControlMask; 506 | 507 | typedef enum SpvFunctionControlShift_ { 508 | SpvFunctionControlInlineShift = 0, 509 | SpvFunctionControlDontInlineShift = 1, 510 | SpvFunctionControlPureShift = 2, 511 | SpvFunctionControlConstShift = 3, 512 | SpvFunctionControlMax = 0x7fffffff, 513 | } SpvFunctionControlShift; 514 | 515 | typedef enum SpvFunctionControlMask_ { 516 | SpvFunctionControlMaskNone = 0, 517 | SpvFunctionControlInlineMask = 0x00000001, 518 | SpvFunctionControlDontInlineMask = 0x00000002, 519 | SpvFunctionControlPureMask = 0x00000004, 520 | SpvFunctionControlConstMask = 0x00000008, 521 | } SpvFunctionControlMask; 522 | 523 | typedef enum SpvMemorySemanticsShift_ { 524 | SpvMemorySemanticsAcquireShift = 1, 525 | SpvMemorySemanticsReleaseShift = 2, 526 | SpvMemorySemanticsAcquireReleaseShift = 3, 527 | SpvMemorySemanticsSequentiallyConsistentShift = 4, 528 | SpvMemorySemanticsUniformMemoryShift = 6, 529 | SpvMemorySemanticsSubgroupMemoryShift = 7, 530 | SpvMemorySemanticsWorkgroupMemoryShift = 8, 531 | SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, 532 | SpvMemorySemanticsAtomicCounterMemoryShift = 10, 533 | SpvMemorySemanticsImageMemoryShift = 11, 534 | SpvMemorySemanticsMax = 0x7fffffff, 535 | } SpvMemorySemanticsShift; 536 | 537 | typedef enum SpvMemorySemanticsMask_ { 538 | SpvMemorySemanticsMaskNone = 0, 539 | SpvMemorySemanticsAcquireMask = 0x00000002, 540 | SpvMemorySemanticsReleaseMask = 0x00000004, 541 | SpvMemorySemanticsAcquireReleaseMask = 0x00000008, 542 | SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010, 543 | SpvMemorySemanticsUniformMemoryMask = 0x00000040, 544 | SpvMemorySemanticsSubgroupMemoryMask = 0x00000080, 545 | SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100, 546 | SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, 547 | SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, 548 | SpvMemorySemanticsImageMemoryMask = 0x00000800, 549 | } SpvMemorySemanticsMask; 550 | 551 | typedef enum SpvMemoryAccessShift_ { 552 | SpvMemoryAccessVolatileShift = 0, 553 | SpvMemoryAccessAlignedShift = 1, 554 | SpvMemoryAccessNontemporalShift = 2, 555 | SpvMemoryAccessMax = 0x7fffffff, 556 | } SpvMemoryAccessShift; 557 | 558 | typedef enum SpvMemoryAccessMask_ { 559 | SpvMemoryAccessMaskNone = 0, 560 | SpvMemoryAccessVolatileMask = 0x00000001, 561 | SpvMemoryAccessAlignedMask = 0x00000002, 562 | SpvMemoryAccessNontemporalMask = 0x00000004, 563 | } SpvMemoryAccessMask; 564 | 565 | typedef enum SpvScope_ { 566 | SpvScopeCrossDevice = 0, 567 | SpvScopeDevice = 1, 568 | SpvScopeWorkgroup = 2, 569 | SpvScopeSubgroup = 3, 570 | SpvScopeInvocation = 4, 571 | SpvScopeMax = 0x7fffffff, 572 | } SpvScope; 573 | 574 | typedef enum SpvGroupOperation_ { 575 | SpvGroupOperationReduce = 0, 576 | SpvGroupOperationInclusiveScan = 1, 577 | SpvGroupOperationExclusiveScan = 2, 578 | SpvGroupOperationClusteredReduce = 3, 579 | SpvGroupOperationPartitionedReduceNV = 6, 580 | SpvGroupOperationPartitionedInclusiveScanNV = 7, 581 | SpvGroupOperationPartitionedExclusiveScanNV = 8, 582 | SpvGroupOperationMax = 0x7fffffff, 583 | } SpvGroupOperation; 584 | 585 | typedef enum SpvKernelEnqueueFlags_ { 586 | SpvKernelEnqueueFlagsNoWait = 0, 587 | SpvKernelEnqueueFlagsWaitKernel = 1, 588 | SpvKernelEnqueueFlagsWaitWorkGroup = 2, 589 | SpvKernelEnqueueFlagsMax = 0x7fffffff, 590 | } SpvKernelEnqueueFlags; 591 | 592 | typedef enum SpvKernelProfilingInfoShift_ { 593 | SpvKernelProfilingInfoCmdExecTimeShift = 0, 594 | SpvKernelProfilingInfoMax = 0x7fffffff, 595 | } SpvKernelProfilingInfoShift; 596 | 597 | typedef enum SpvKernelProfilingInfoMask_ { 598 | SpvKernelProfilingInfoMaskNone = 0, 599 | SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, 600 | } SpvKernelProfilingInfoMask; 601 | 602 | typedef enum SpvCapability_ { 603 | SpvCapabilityMatrix = 0, 604 | SpvCapabilityShader = 1, 605 | SpvCapabilityGeometry = 2, 606 | SpvCapabilityTessellation = 3, 607 | SpvCapabilityAddresses = 4, 608 | SpvCapabilityLinkage = 5, 609 | SpvCapabilityKernel = 6, 610 | SpvCapabilityVector16 = 7, 611 | SpvCapabilityFloat16Buffer = 8, 612 | SpvCapabilityFloat16 = 9, 613 | SpvCapabilityFloat64 = 10, 614 | SpvCapabilityInt64 = 11, 615 | SpvCapabilityInt64Atomics = 12, 616 | SpvCapabilityImageBasic = 13, 617 | SpvCapabilityImageReadWrite = 14, 618 | SpvCapabilityImageMipmap = 15, 619 | SpvCapabilityPipes = 17, 620 | SpvCapabilityGroups = 18, 621 | SpvCapabilityDeviceEnqueue = 19, 622 | SpvCapabilityLiteralSampler = 20, 623 | SpvCapabilityAtomicStorage = 21, 624 | SpvCapabilityInt16 = 22, 625 | SpvCapabilityTessellationPointSize = 23, 626 | SpvCapabilityGeometryPointSize = 24, 627 | SpvCapabilityImageGatherExtended = 25, 628 | SpvCapabilityStorageImageMultisample = 27, 629 | SpvCapabilityUniformBufferArrayDynamicIndexing = 28, 630 | SpvCapabilitySampledImageArrayDynamicIndexing = 29, 631 | SpvCapabilityStorageBufferArrayDynamicIndexing = 30, 632 | SpvCapabilityStorageImageArrayDynamicIndexing = 31, 633 | SpvCapabilityClipDistance = 32, 634 | SpvCapabilityCullDistance = 33, 635 | SpvCapabilityImageCubeArray = 34, 636 | SpvCapabilitySampleRateShading = 35, 637 | SpvCapabilityImageRect = 36, 638 | SpvCapabilitySampledRect = 37, 639 | SpvCapabilityGenericPointer = 38, 640 | SpvCapabilityInt8 = 39, 641 | SpvCapabilityInputAttachment = 40, 642 | SpvCapabilitySparseResidency = 41, 643 | SpvCapabilityMinLod = 42, 644 | SpvCapabilitySampled1D = 43, 645 | SpvCapabilityImage1D = 44, 646 | SpvCapabilitySampledCubeArray = 45, 647 | SpvCapabilitySampledBuffer = 46, 648 | SpvCapabilityImageBuffer = 47, 649 | SpvCapabilityImageMSArray = 48, 650 | SpvCapabilityStorageImageExtendedFormats = 49, 651 | SpvCapabilityImageQuery = 50, 652 | SpvCapabilityDerivativeControl = 51, 653 | SpvCapabilityInterpolationFunction = 52, 654 | SpvCapabilityTransformFeedback = 53, 655 | SpvCapabilityGeometryStreams = 54, 656 | SpvCapabilityStorageImageReadWithoutFormat = 55, 657 | SpvCapabilityStorageImageWriteWithoutFormat = 56, 658 | SpvCapabilityMultiViewport = 57, 659 | SpvCapabilitySubgroupDispatch = 58, 660 | SpvCapabilityNamedBarrier = 59, 661 | SpvCapabilityPipeStorage = 60, 662 | SpvCapabilityGroupNonUniform = 61, 663 | SpvCapabilityGroupNonUniformVote = 62, 664 | SpvCapabilityGroupNonUniformArithmetic = 63, 665 | SpvCapabilityGroupNonUniformBallot = 64, 666 | SpvCapabilityGroupNonUniformShuffle = 65, 667 | SpvCapabilityGroupNonUniformShuffleRelative = 66, 668 | SpvCapabilityGroupNonUniformClustered = 67, 669 | SpvCapabilityGroupNonUniformQuad = 68, 670 | SpvCapabilitySubgroupBallotKHR = 4423, 671 | SpvCapabilityDrawParameters = 4427, 672 | SpvCapabilitySubgroupVoteKHR = 4431, 673 | SpvCapabilityStorageBuffer16BitAccess = 4433, 674 | SpvCapabilityStorageUniformBufferBlock16 = 4433, 675 | SpvCapabilityStorageUniform16 = 4434, 676 | SpvCapabilityUniformAndStorageBuffer16BitAccess = 4434, 677 | SpvCapabilityStoragePushConstant16 = 4435, 678 | SpvCapabilityStorageInputOutput16 = 4436, 679 | SpvCapabilityDeviceGroup = 4437, 680 | SpvCapabilityMultiView = 4439, 681 | SpvCapabilityVariablePointersStorageBuffer = 4441, 682 | SpvCapabilityVariablePointers = 4442, 683 | SpvCapabilityAtomicStorageOps = 4445, 684 | SpvCapabilitySampleMaskPostDepthCoverage = 4447, 685 | SpvCapabilityFloat16ImageAMD = 5008, 686 | SpvCapabilityImageGatherBiasLodAMD = 5009, 687 | SpvCapabilityFragmentMaskAMD = 5010, 688 | SpvCapabilityStencilExportEXT = 5013, 689 | SpvCapabilityImageReadWriteLodAMD = 5015, 690 | SpvCapabilitySampleMaskOverrideCoverageNV = 5249, 691 | SpvCapabilityGeometryShaderPassthroughNV = 5251, 692 | SpvCapabilityShaderViewportIndexLayerEXT = 5254, 693 | SpvCapabilityShaderViewportIndexLayerNV = 5254, 694 | SpvCapabilityShaderViewportMaskNV = 5255, 695 | SpvCapabilityShaderStereoViewNV = 5259, 696 | SpvCapabilityPerViewAttributesNV = 5260, 697 | SpvCapabilityFragmentFullyCoveredEXT = 5265, 698 | SpvCapabilityGroupNonUniformPartitionedNV = 5297, 699 | SpvCapabilitySubgroupShuffleINTEL = 5568, 700 | SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, 701 | SpvCapabilitySubgroupImageBlockIOINTEL = 5570, 702 | SpvCapabilityMax = 0x7fffffff, 703 | } SpvCapability; 704 | 705 | typedef enum SpvOp_ { 706 | SpvOpNop = 0, 707 | SpvOpUndef = 1, 708 | SpvOpSourceContinued = 2, 709 | SpvOpSource = 3, 710 | SpvOpSourceExtension = 4, 711 | SpvOpName = 5, 712 | SpvOpMemberName = 6, 713 | SpvOpString = 7, 714 | SpvOpLine = 8, 715 | SpvOpExtension = 10, 716 | SpvOpExtInstImport = 11, 717 | SpvOpExtInst = 12, 718 | SpvOpMemoryModel = 14, 719 | SpvOpEntryPoint = 15, 720 | SpvOpExecutionMode = 16, 721 | SpvOpCapability = 17, 722 | SpvOpTypeVoid = 19, 723 | SpvOpTypeBool = 20, 724 | SpvOpTypeInt = 21, 725 | SpvOpTypeFloat = 22, 726 | SpvOpTypeVector = 23, 727 | SpvOpTypeMatrix = 24, 728 | SpvOpTypeImage = 25, 729 | SpvOpTypeSampler = 26, 730 | SpvOpTypeSampledImage = 27, 731 | SpvOpTypeArray = 28, 732 | SpvOpTypeRuntimeArray = 29, 733 | SpvOpTypeStruct = 30, 734 | SpvOpTypeOpaque = 31, 735 | SpvOpTypePointer = 32, 736 | SpvOpTypeFunction = 33, 737 | SpvOpTypeEvent = 34, 738 | SpvOpTypeDeviceEvent = 35, 739 | SpvOpTypeReserveId = 36, 740 | SpvOpTypeQueue = 37, 741 | SpvOpTypePipe = 38, 742 | SpvOpTypeForwardPointer = 39, 743 | SpvOpConstantTrue = 41, 744 | SpvOpConstantFalse = 42, 745 | SpvOpConstant = 43, 746 | SpvOpConstantComposite = 44, 747 | SpvOpConstantSampler = 45, 748 | SpvOpConstantNull = 46, 749 | SpvOpSpecConstantTrue = 48, 750 | SpvOpSpecConstantFalse = 49, 751 | SpvOpSpecConstant = 50, 752 | SpvOpSpecConstantComposite = 51, 753 | SpvOpSpecConstantOp = 52, 754 | SpvOpFunction = 54, 755 | SpvOpFunctionParameter = 55, 756 | SpvOpFunctionEnd = 56, 757 | SpvOpFunctionCall = 57, 758 | SpvOpVariable = 59, 759 | SpvOpImageTexelPointer = 60, 760 | SpvOpLoad = 61, 761 | SpvOpStore = 62, 762 | SpvOpCopyMemory = 63, 763 | SpvOpCopyMemorySized = 64, 764 | SpvOpAccessChain = 65, 765 | SpvOpInBoundsAccessChain = 66, 766 | SpvOpPtrAccessChain = 67, 767 | SpvOpArrayLength = 68, 768 | SpvOpGenericPtrMemSemantics = 69, 769 | SpvOpInBoundsPtrAccessChain = 70, 770 | SpvOpDecorate = 71, 771 | SpvOpMemberDecorate = 72, 772 | SpvOpDecorationGroup = 73, 773 | SpvOpGroupDecorate = 74, 774 | SpvOpGroupMemberDecorate = 75, 775 | SpvOpVectorExtractDynamic = 77, 776 | SpvOpVectorInsertDynamic = 78, 777 | SpvOpVectorShuffle = 79, 778 | SpvOpCompositeConstruct = 80, 779 | SpvOpCompositeExtract = 81, 780 | SpvOpCompositeInsert = 82, 781 | SpvOpCopyObject = 83, 782 | SpvOpTranspose = 84, 783 | SpvOpSampledImage = 86, 784 | SpvOpImageSampleImplicitLod = 87, 785 | SpvOpImageSampleExplicitLod = 88, 786 | SpvOpImageSampleDrefImplicitLod = 89, 787 | SpvOpImageSampleDrefExplicitLod = 90, 788 | SpvOpImageSampleProjImplicitLod = 91, 789 | SpvOpImageSampleProjExplicitLod = 92, 790 | SpvOpImageSampleProjDrefImplicitLod = 93, 791 | SpvOpImageSampleProjDrefExplicitLod = 94, 792 | SpvOpImageFetch = 95, 793 | SpvOpImageGather = 96, 794 | SpvOpImageDrefGather = 97, 795 | SpvOpImageRead = 98, 796 | SpvOpImageWrite = 99, 797 | SpvOpImage = 100, 798 | SpvOpImageQueryFormat = 101, 799 | SpvOpImageQueryOrder = 102, 800 | SpvOpImageQuerySizeLod = 103, 801 | SpvOpImageQuerySize = 104, 802 | SpvOpImageQueryLod = 105, 803 | SpvOpImageQueryLevels = 106, 804 | SpvOpImageQuerySamples = 107, 805 | SpvOpConvertFToU = 109, 806 | SpvOpConvertFToS = 110, 807 | SpvOpConvertSToF = 111, 808 | SpvOpConvertUToF = 112, 809 | SpvOpUConvert = 113, 810 | SpvOpSConvert = 114, 811 | SpvOpFConvert = 115, 812 | SpvOpQuantizeToF16 = 116, 813 | SpvOpConvertPtrToU = 117, 814 | SpvOpSatConvertSToU = 118, 815 | SpvOpSatConvertUToS = 119, 816 | SpvOpConvertUToPtr = 120, 817 | SpvOpPtrCastToGeneric = 121, 818 | SpvOpGenericCastToPtr = 122, 819 | SpvOpGenericCastToPtrExplicit = 123, 820 | SpvOpBitcast = 124, 821 | SpvOpSNegate = 126, 822 | SpvOpFNegate = 127, 823 | SpvOpIAdd = 128, 824 | SpvOpFAdd = 129, 825 | SpvOpISub = 130, 826 | SpvOpFSub = 131, 827 | SpvOpIMul = 132, 828 | SpvOpFMul = 133, 829 | SpvOpUDiv = 134, 830 | SpvOpSDiv = 135, 831 | SpvOpFDiv = 136, 832 | SpvOpUMod = 137, 833 | SpvOpSRem = 138, 834 | SpvOpSMod = 139, 835 | SpvOpFRem = 140, 836 | SpvOpFMod = 141, 837 | SpvOpVectorTimesScalar = 142, 838 | SpvOpMatrixTimesScalar = 143, 839 | SpvOpVectorTimesMatrix = 144, 840 | SpvOpMatrixTimesVector = 145, 841 | SpvOpMatrixTimesMatrix = 146, 842 | SpvOpOuterProduct = 147, 843 | SpvOpDot = 148, 844 | SpvOpIAddCarry = 149, 845 | SpvOpISubBorrow = 150, 846 | SpvOpUMulExtended = 151, 847 | SpvOpSMulExtended = 152, 848 | SpvOpAny = 154, 849 | SpvOpAll = 155, 850 | SpvOpIsNan = 156, 851 | SpvOpIsInf = 157, 852 | SpvOpIsFinite = 158, 853 | SpvOpIsNormal = 159, 854 | SpvOpSignBitSet = 160, 855 | SpvOpLessOrGreater = 161, 856 | SpvOpOrdered = 162, 857 | SpvOpUnordered = 163, 858 | SpvOpLogicalEqual = 164, 859 | SpvOpLogicalNotEqual = 165, 860 | SpvOpLogicalOr = 166, 861 | SpvOpLogicalAnd = 167, 862 | SpvOpLogicalNot = 168, 863 | SpvOpSelect = 169, 864 | SpvOpIEqual = 170, 865 | SpvOpINotEqual = 171, 866 | SpvOpUGreaterThan = 172, 867 | SpvOpSGreaterThan = 173, 868 | SpvOpUGreaterThanEqual = 174, 869 | SpvOpSGreaterThanEqual = 175, 870 | SpvOpULessThan = 176, 871 | SpvOpSLessThan = 177, 872 | SpvOpULessThanEqual = 178, 873 | SpvOpSLessThanEqual = 179, 874 | SpvOpFOrdEqual = 180, 875 | SpvOpFUnordEqual = 181, 876 | SpvOpFOrdNotEqual = 182, 877 | SpvOpFUnordNotEqual = 183, 878 | SpvOpFOrdLessThan = 184, 879 | SpvOpFUnordLessThan = 185, 880 | SpvOpFOrdGreaterThan = 186, 881 | SpvOpFUnordGreaterThan = 187, 882 | SpvOpFOrdLessThanEqual = 188, 883 | SpvOpFUnordLessThanEqual = 189, 884 | SpvOpFOrdGreaterThanEqual = 190, 885 | SpvOpFUnordGreaterThanEqual = 191, 886 | SpvOpShiftRightLogical = 194, 887 | SpvOpShiftRightArithmetic = 195, 888 | SpvOpShiftLeftLogical = 196, 889 | SpvOpBitwiseOr = 197, 890 | SpvOpBitwiseXor = 198, 891 | SpvOpBitwiseAnd = 199, 892 | SpvOpNot = 200, 893 | SpvOpBitFieldInsert = 201, 894 | SpvOpBitFieldSExtract = 202, 895 | SpvOpBitFieldUExtract = 203, 896 | SpvOpBitReverse = 204, 897 | SpvOpBitCount = 205, 898 | SpvOpDPdx = 207, 899 | SpvOpDPdy = 208, 900 | SpvOpFwidth = 209, 901 | SpvOpDPdxFine = 210, 902 | SpvOpDPdyFine = 211, 903 | SpvOpFwidthFine = 212, 904 | SpvOpDPdxCoarse = 213, 905 | SpvOpDPdyCoarse = 214, 906 | SpvOpFwidthCoarse = 215, 907 | SpvOpEmitVertex = 218, 908 | SpvOpEndPrimitive = 219, 909 | SpvOpEmitStreamVertex = 220, 910 | SpvOpEndStreamPrimitive = 221, 911 | SpvOpControlBarrier = 224, 912 | SpvOpMemoryBarrier = 225, 913 | SpvOpAtomicLoad = 227, 914 | SpvOpAtomicStore = 228, 915 | SpvOpAtomicExchange = 229, 916 | SpvOpAtomicCompareExchange = 230, 917 | SpvOpAtomicCompareExchangeWeak = 231, 918 | SpvOpAtomicIIncrement = 232, 919 | SpvOpAtomicIDecrement = 233, 920 | SpvOpAtomicIAdd = 234, 921 | SpvOpAtomicISub = 235, 922 | SpvOpAtomicSMin = 236, 923 | SpvOpAtomicUMin = 237, 924 | SpvOpAtomicSMax = 238, 925 | SpvOpAtomicUMax = 239, 926 | SpvOpAtomicAnd = 240, 927 | SpvOpAtomicOr = 241, 928 | SpvOpAtomicXor = 242, 929 | SpvOpPhi = 245, 930 | SpvOpLoopMerge = 246, 931 | SpvOpSelectionMerge = 247, 932 | SpvOpLabel = 248, 933 | SpvOpBranch = 249, 934 | SpvOpBranchConditional = 250, 935 | SpvOpSwitch = 251, 936 | SpvOpKill = 252, 937 | SpvOpReturn = 253, 938 | SpvOpReturnValue = 254, 939 | SpvOpUnreachable = 255, 940 | SpvOpLifetimeStart = 256, 941 | SpvOpLifetimeStop = 257, 942 | SpvOpGroupAsyncCopy = 259, 943 | SpvOpGroupWaitEvents = 260, 944 | SpvOpGroupAll = 261, 945 | SpvOpGroupAny = 262, 946 | SpvOpGroupBroadcast = 263, 947 | SpvOpGroupIAdd = 264, 948 | SpvOpGroupFAdd = 265, 949 | SpvOpGroupFMin = 266, 950 | SpvOpGroupUMin = 267, 951 | SpvOpGroupSMin = 268, 952 | SpvOpGroupFMax = 269, 953 | SpvOpGroupUMax = 270, 954 | SpvOpGroupSMax = 271, 955 | SpvOpReadPipe = 274, 956 | SpvOpWritePipe = 275, 957 | SpvOpReservedReadPipe = 276, 958 | SpvOpReservedWritePipe = 277, 959 | SpvOpReserveReadPipePackets = 278, 960 | SpvOpReserveWritePipePackets = 279, 961 | SpvOpCommitReadPipe = 280, 962 | SpvOpCommitWritePipe = 281, 963 | SpvOpIsValidReserveId = 282, 964 | SpvOpGetNumPipePackets = 283, 965 | SpvOpGetMaxPipePackets = 284, 966 | SpvOpGroupReserveReadPipePackets = 285, 967 | SpvOpGroupReserveWritePipePackets = 286, 968 | SpvOpGroupCommitReadPipe = 287, 969 | SpvOpGroupCommitWritePipe = 288, 970 | SpvOpEnqueueMarker = 291, 971 | SpvOpEnqueueKernel = 292, 972 | SpvOpGetKernelNDrangeSubGroupCount = 293, 973 | SpvOpGetKernelNDrangeMaxSubGroupSize = 294, 974 | SpvOpGetKernelWorkGroupSize = 295, 975 | SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296, 976 | SpvOpRetainEvent = 297, 977 | SpvOpReleaseEvent = 298, 978 | SpvOpCreateUserEvent = 299, 979 | SpvOpIsValidEvent = 300, 980 | SpvOpSetUserEventStatus = 301, 981 | SpvOpCaptureEventProfilingInfo = 302, 982 | SpvOpGetDefaultQueue = 303, 983 | SpvOpBuildNDRange = 304, 984 | SpvOpImageSparseSampleImplicitLod = 305, 985 | SpvOpImageSparseSampleExplicitLod = 306, 986 | SpvOpImageSparseSampleDrefImplicitLod = 307, 987 | SpvOpImageSparseSampleDrefExplicitLod = 308, 988 | SpvOpImageSparseSampleProjImplicitLod = 309, 989 | SpvOpImageSparseSampleProjExplicitLod = 310, 990 | SpvOpImageSparseSampleProjDrefImplicitLod = 311, 991 | SpvOpImageSparseSampleProjDrefExplicitLod = 312, 992 | SpvOpImageSparseFetch = 313, 993 | SpvOpImageSparseGather = 314, 994 | SpvOpImageSparseDrefGather = 315, 995 | SpvOpImageSparseTexelsResident = 316, 996 | SpvOpNoLine = 317, 997 | SpvOpAtomicFlagTestAndSet = 318, 998 | SpvOpAtomicFlagClear = 319, 999 | SpvOpImageSparseRead = 320, 1000 | SpvOpSizeOf = 321, 1001 | SpvOpTypePipeStorage = 322, 1002 | SpvOpConstantPipeStorage = 323, 1003 | SpvOpCreatePipeFromPipeStorage = 324, 1004 | SpvOpGetKernelLocalSizeForSubgroupCount = 325, 1005 | SpvOpGetKernelMaxNumSubgroups = 326, 1006 | SpvOpTypeNamedBarrier = 327, 1007 | SpvOpNamedBarrierInitialize = 328, 1008 | SpvOpMemoryNamedBarrier = 329, 1009 | SpvOpModuleProcessed = 330, 1010 | SpvOpExecutionModeId = 331, 1011 | SpvOpDecorateId = 332, 1012 | SpvOpGroupNonUniformElect = 333, 1013 | SpvOpGroupNonUniformAll = 334, 1014 | SpvOpGroupNonUniformAny = 335, 1015 | SpvOpGroupNonUniformAllEqual = 336, 1016 | SpvOpGroupNonUniformBroadcast = 337, 1017 | SpvOpGroupNonUniformBroadcastFirst = 338, 1018 | SpvOpGroupNonUniformBallot = 339, 1019 | SpvOpGroupNonUniformInverseBallot = 340, 1020 | SpvOpGroupNonUniformBallotBitExtract = 341, 1021 | SpvOpGroupNonUniformBallotBitCount = 342, 1022 | SpvOpGroupNonUniformBallotFindLSB = 343, 1023 | SpvOpGroupNonUniformBallotFindMSB = 344, 1024 | SpvOpGroupNonUniformShuffle = 345, 1025 | SpvOpGroupNonUniformShuffleXor = 346, 1026 | SpvOpGroupNonUniformShuffleUp = 347, 1027 | SpvOpGroupNonUniformShuffleDown = 348, 1028 | SpvOpGroupNonUniformIAdd = 349, 1029 | SpvOpGroupNonUniformFAdd = 350, 1030 | SpvOpGroupNonUniformIMul = 351, 1031 | SpvOpGroupNonUniformFMul = 352, 1032 | SpvOpGroupNonUniformSMin = 353, 1033 | SpvOpGroupNonUniformUMin = 354, 1034 | SpvOpGroupNonUniformFMin = 355, 1035 | SpvOpGroupNonUniformSMax = 356, 1036 | SpvOpGroupNonUniformUMax = 357, 1037 | SpvOpGroupNonUniformFMax = 358, 1038 | SpvOpGroupNonUniformBitwiseAnd = 359, 1039 | SpvOpGroupNonUniformBitwiseOr = 360, 1040 | SpvOpGroupNonUniformBitwiseXor = 361, 1041 | SpvOpGroupNonUniformLogicalAnd = 362, 1042 | SpvOpGroupNonUniformLogicalOr = 363, 1043 | SpvOpGroupNonUniformLogicalXor = 364, 1044 | SpvOpGroupNonUniformQuadBroadcast = 365, 1045 | SpvOpGroupNonUniformQuadSwap = 366, 1046 | SpvOpSubgroupBallotKHR = 4421, 1047 | SpvOpSubgroupFirstInvocationKHR = 4422, 1048 | SpvOpSubgroupAllKHR = 4428, 1049 | SpvOpSubgroupAnyKHR = 4429, 1050 | SpvOpSubgroupAllEqualKHR = 4430, 1051 | SpvOpSubgroupReadInvocationKHR = 4432, 1052 | SpvOpGroupIAddNonUniformAMD = 5000, 1053 | SpvOpGroupFAddNonUniformAMD = 5001, 1054 | SpvOpGroupFMinNonUniformAMD = 5002, 1055 | SpvOpGroupUMinNonUniformAMD = 5003, 1056 | SpvOpGroupSMinNonUniformAMD = 5004, 1057 | SpvOpGroupFMaxNonUniformAMD = 5005, 1058 | SpvOpGroupUMaxNonUniformAMD = 5006, 1059 | SpvOpGroupSMaxNonUniformAMD = 5007, 1060 | SpvOpFragmentMaskFetchAMD = 5011, 1061 | SpvOpFragmentFetchAMD = 5012, 1062 | SpvOpGroupNonUniformPartitionNV = 5296, 1063 | SpvOpSubgroupShuffleINTEL = 5571, 1064 | SpvOpSubgroupShuffleDownINTEL = 5572, 1065 | SpvOpSubgroupShuffleUpINTEL = 5573, 1066 | SpvOpSubgroupShuffleXorINTEL = 5574, 1067 | SpvOpSubgroupBlockReadINTEL = 5575, 1068 | SpvOpSubgroupBlockWriteINTEL = 5576, 1069 | SpvOpSubgroupImageBlockReadINTEL = 5577, 1070 | SpvOpSubgroupImageBlockWriteINTEL = 5578, 1071 | SpvOpDecorateStringGOOGLE = 5632, 1072 | SpvOpMemberDecorateStringGOOGLE = 5633, 1073 | SpvOpMax = 0x7fffffff, 1074 | } SpvOp; 1075 | 1076 | #endif // #ifndef spirv_H 1077 | 1078 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "container.h" 3 | #include "backend.h" 4 | #include "CompositorResource.h" 5 | #include "compositor.h" 6 | #include "CompositorFont.h" //font size 7 | #include "config.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | Exception::Exception(){ 21 | this->pmsg = buffer; 22 | } 23 | 24 | Exception::Exception(const char *pmsg){ 25 | this->pmsg = pmsg; 26 | } 27 | 28 | Exception::~Exception(){ 29 | // 30 | } 31 | 32 | const char * Exception::what(){ 33 | return pmsg; 34 | } 35 | 36 | char Exception::buffer[4096]; 37 | 38 | Blob::Blob(const char *pfileName){ 39 | FILE *pf; 40 | do{ 41 | //try with filename directly 42 | pf = fopen(pfileName,"rb"); 43 | if(pf) 44 | break; 45 | 46 | //search in the binary directory 47 | char path[256]; 48 | ssize_t len = readlink("/proc/self/exe",path,sizeof(path)); 49 | if(len == -1) 50 | throw Exception("readlink() failed for /proc/self/exe."); 51 | path[len] = 0; 52 | pf = fopen((boost::filesystem::path(path).parent_path()/pfileName).string().c_str(),"rb"); 53 | if(pf) 54 | break; 55 | 56 | //try /usr/share 57 | pf = fopen((std::string("/usr/share/chamfer/")+pfileName).c_str(),"rb"); 58 | if(pf) 59 | break; 60 | 61 | snprintf(Exception::buffer,sizeof(Exception::buffer),"Unable to open file: %s",pfileName); 62 | throw Exception(); 63 | }while(0); 64 | 65 | fseek(pf,0,SEEK_END); 66 | buflen = ftell(pf); 67 | fseek(pf,0,SEEK_SET); 68 | 69 | pbuffer = new char[buflen]; 70 | fread(pbuffer,1,buflen,pf); 71 | fclose(pf); 72 | } 73 | 74 | Blob::~Blob(){ 75 | delete []pbuffer; 76 | } 77 | 78 | const char * Blob::GetBufferPointer() const{ 79 | return pbuffer; 80 | } 81 | 82 | size_t Blob::GetBufferLength() const{ 83 | return buflen; 84 | } 85 | 86 | void DebugPrintf(FILE *pf, const char *pfmt, ...){ 87 | time_t rt; 88 | time(&rt); 89 | const struct tm *pti = localtime(&rt); 90 | 91 | //pf = fopen("/tmp/log1","a+"); 92 | char tbuf[256]; 93 | strftime(tbuf,sizeof(tbuf),"[chamferwm %F %T]",pti); 94 | fprintf(pf,"%s ",tbuf); 95 | 96 | va_list args; 97 | va_start(args,pfmt); 98 | if(pf == stderr) 99 | fprintf(pf,"Error: "); 100 | vfprintf(pf,pfmt,args); 101 | //fclose(pf); 102 | va_end(args); 103 | } 104 | 105 | static bool sigTerm = false; 106 | void SignalHandler(int sig){ 107 | if(sig == 15) 108 | sigTerm = true; 109 | } 110 | 111 | typedef std::pair StackAppendixElement; 112 | class RunCompositor : public Config::CompositorConfig{ 113 | public: 114 | //RunCompositor(std::vector *_pstackAppendix, Config::CompositorInterface *_pcompositorInt) : pstackAppendix(_pstackAppendix), Config::CompositorConfig(_pcompositorInt){} 115 | RunCompositor(std::vector *_pstackAppendix, Config::CompositorInterface *_pcompositorInt) : Config::CompositorConfig(_pcompositorInt){} 116 | virtual ~RunCompositor(){} 117 | virtual void Present() = 0; 118 | virtual bool IsAnimating() const = 0; 119 | virtual void WaitIdle() = 0; 120 | //protected: 121 | // std::vector *pstackAppendix; 122 | }; 123 | 124 | class RunBackend : public Config::BackendConfig{ 125 | public: 126 | RunBackend(Config::BackendInterface *_pbackendInt) : pcomp(0), Config::BackendConfig(_pbackendInt){ 127 | // 128 | } 129 | 130 | virtual ~RunBackend(){} 131 | 132 | void SetCompositor(class RunCompositor *pcomp){ 133 | this->pcomp = pcomp; 134 | pcompInt = dynamic_cast(pcomp); 135 | } 136 | 137 | struct ContainerCreateInfo{ 138 | std::string wm_name; 139 | std::string wm_class; 140 | std::string shaderName[Compositor::Pipeline::SHADER_MODULE_COUNT]; 141 | bool floating; 142 | }; 143 | 144 | template 145 | Config::ContainerInterface & SetupContainer(const ContainerCreateInfo *pcreateInfo){ 146 | boost::python::object containerObject = Config::BackendInterface::pbackendInt->OnCreateContainer(); 147 | boost::python::extract containerExtract(containerObject); 148 | if(!containerExtract.check()) 149 | throw Exception("OnCreateContainer(): Invalid container object returned."); //TODO: create default 150 | 151 | Config::ContainerInterface &containerInt = containerExtract(); 152 | containerInt.self = containerObject; 153 | 154 | if(pcreateInfo){ 155 | containerInt.wm_name = pcreateInfo->wm_name; 156 | containerInt.wm_class = pcreateInfo->wm_class; 157 | containerInt.vertexShader = pcreateInfo->shaderName[Compositor::Pipeline::SHADER_MODULE_VERTEX]; 158 | containerInt.geometryShader = pcreateInfo->shaderName[Compositor::Pipeline::SHADER_MODULE_GEOMETRY]; 159 | containerInt.fragmentShader = pcreateInfo->shaderName[Compositor::Pipeline::SHADER_MODULE_FRAGMENT]; 160 | } 161 | 162 | return containerInt; 163 | } 164 | 165 | template 166 | Config::ContainerInterface & SetupContainer(WManager::Container *pParent, const ContainerCreateInfo *pcreateInfo){ 167 | Config::ContainerInterface &containerInt = SetupContainer(pcreateInfo); 168 | containerInt.OnSetupContainer(); 169 | 170 | WManager::Container::Setup setup; 171 | if(containerInt.floatingMode == Config::ContainerInterface::FLOAT_ALWAYS || 172 | (containerInt.floatingMode != Config::ContainerInterface::FLOAT_NEVER && pcreateInfo && pcreateInfo->floating)) 173 | setup.flags = WManager::Container::FLAG_FLOATING; 174 | if(pcompInt->ptextEngine) 175 | setup.titlePad = pcompInt->ptextEngine->GetFontSize(); 176 | containerInt.CopySettingsSetup(setup); 177 | 178 | if(!(setup.flags & WManager::Container::FLAG_FLOATING)){ 179 | if(!pParent){ 180 | boost::python::object parentObject = containerInt.OnParent(); 181 | boost::python::extract parentExtract(parentObject); 182 | if(!parentExtract.check()) 183 | throw Exception("OnParent(): Invalid parent container object returned."); 184 | 185 | Config::ContainerInterface &parentInt = parentExtract(); 186 | if(parentInt.pcontainer == containerInt.pcontainer) 187 | throw Exception("OnParent(): Cannot parent to itself."); 188 | 189 | if(parentInt.pcontainer->pclient){ 190 | Config::ContainerInterface &parentInt1 = SetupContainer(parentInt.pcontainer,0); 191 | pParent = parentInt1.pcontainer; 192 | 193 | }else pParent = parentInt.pcontainer; 194 | } 195 | 196 | T *pcontainer = new T(&containerInt,pParent,setup,static_cast(this)); 197 | containerInt.pcontainer = pcontainer; 198 | 199 | }else{ 200 | WManager::Container *proot = WManager::Container::ptreeFocus->GetRoot(); 201 | T *pcontainer = new T(&containerInt,proot,setup,static_cast(this)); 202 | containerInt.pcontainer = pcontainer; 203 | } 204 | 205 | return containerInt; 206 | } 207 | 208 | template 209 | void MoveContainer(WManager::Container *pcontainer, WManager::Container *pdst){ 210 | // 211 | WManager::Container *proot = pcontainer->GetRoot(); 212 | PrintTree(proot,0); 213 | printf("-----------\n"); 214 | 215 | if(pcontainer == pdst || pdst->flags & WManager::Container::FLAG_FLOATING) 216 | return; 217 | 218 | WManager::Container *premoved = pcontainer->Remove(); 219 | WManager::Container *pOrigParent = premoved->pParent; 220 | 221 | if(pdst->pclient){ 222 | Config::ContainerInterface &parentInt1 = SetupContainer(pdst,0); 223 | pdst = parentInt1.pcontainer; 224 | } 225 | pcontainer->Place(pdst); 226 | 227 | printf("----------- removed %p\n",premoved); 228 | PrintTree(proot,0); 229 | printf("-----------\n"); 230 | 231 | WManager::Container *pNewParent = premoved->pParent; 232 | 233 | WManager::Container *pcollapsed = 0; 234 | //if(pNewParent != proot) 235 | if(pNewParent->pParent) //new parent might also be a root 236 | pcollapsed = pNewParent->Collapse(); 237 | if(!pcollapsed && pNewParent->pch) 238 | pcollapsed = pNewParent->pch->Collapse(); 239 | 240 | if(WManager::Container::ptreeFocus == pcollapsed){ 241 | WManager::Container *pNewFocus = proot; 242 | for(WManager::Container *pcontainer = pNewFocus; pcontainer; pNewFocus = pcontainer, pcontainer = pcontainer->GetFocus()); 243 | Config::X11ContainerConfig *pNewFocus1 = static_cast(pNewFocus); 244 | if(pNewFocus1->pcontainerInt->OnFocus()) 245 | pNewFocus1->Focus(); 246 | } 247 | 248 | if(pcollapsed){ 249 | if(pcollapsed->pch) 250 | ReleaseContainersRecursive(pcollapsed->pch); 251 | delete pcollapsed; 252 | } 253 | 254 | pcollapsed = 0; 255 | //if(pOrigParent != proot) 256 | if(pOrigParent->pParent) 257 | pcollapsed = pOrigParent->Collapse(); 258 | if(!pcollapsed && pOrigParent->pch) 259 | pcollapsed = pOrigParent->pch->Collapse(); 260 | if(pcollapsed){ 261 | if(pcollapsed->pch) 262 | ReleaseContainersRecursive(pcollapsed->pch); 263 | delete pcollapsed; 264 | } 265 | 266 | if(premoved != pcontainer) 267 | pcontainer->pParent->pch = 0; 268 | 269 | Config::X11ContainerConfig *pcontainer1 = static_cast(pcontainer); 270 | if(pcontainer1->pcontainerInt->OnFocus()) 271 | pcontainer1->Focus(); 272 | 273 | PrintTree(proot,0); 274 | printf("-----------\n"); 275 | 276 | //if(premoved->pch) 277 | //ReleaseContainersRecursive(premoved->pch); //should this be here??? once container trees can be moved 278 | //PrintTree(proot,0); 279 | } 280 | 281 | void ReleaseContainersRecursive(const WManager::Container *pcontainer){ 282 | for(const WManager::Container *pcont = pcontainer; pcont;){ 283 | if(pcont->pclient) 284 | delete pcont->pclient; 285 | else 286 | if(pcont->pch) 287 | ReleaseContainersRecursive(pcont->pch); 288 | 289 | const Config::ContainerConfig *pcontainer1 = dynamic_cast(pcont); 290 | if(pcontainer1 && pcontainer1->pcontainerInt->pcontainer == pcont) 291 | pcontainer1->pcontainerInt->pcontainer = 0; 292 | 293 | const WManager::Container *pdiscard = pcont; 294 | pcont = pcont->pnext; 295 | delete pdiscard; 296 | } 297 | } 298 | 299 | void ReleaseContainers(){ 300 | for(auto &p : stackAppendix){ 301 | if(p.second->pcontainer->GetParent() != 0){ //check that it's not a root container 302 | const Config::ContainerConfig *pcontainer1 = dynamic_cast(p.second->pcontainer); 303 | if(pcontainer1 && pcontainer1->pcontainerInt->pcontainer == p.second->pcontainer) 304 | pcontainer1->pcontainerInt->pcontainer = 0; 305 | 306 | if(p.second->pcontainer) 307 | delete p.second->pcontainer; 308 | } 309 | delete p.second; 310 | } 311 | stackAppendix.clear(); 312 | // 313 | if(!WManager::Container::rootQueue.empty()){ 314 | WManager::Container *proot1 = WManager::Container::rootQueue.front(); 315 | WManager::Container *pRootNext = proot1->pRootNext; 316 | do{ 317 | if(pRootNext->pch) 318 | ReleaseContainersRecursive(pRootNext->pch); 319 | 320 | pRootNext = pRootNext->pRootNext; 321 | }while(pRootNext != proot1); 322 | } 323 | } 324 | 325 | void PrintTree(WManager::Container *pcontainer, uint level) const{ 326 | for(uint i = 0; i < level; ++i) 327 | printf(" "); 328 | printf("%p: ",pcontainer); 329 | if(pcontainer->pclient) 330 | printf("(client), "); 331 | if(pcontainer->pParent) 332 | printf("(parent: %p), ",pcontainer->pParent); 333 | if(WManager::Container::ptreeFocus == pcontainer) 334 | printf("(focus), "); 335 | if(pcontainer->flags & WManager::Container::FLAG_STACKED) 336 | printf("(+stacked), "); 337 | if(pcontainer->flags & WManager::Container::FLAG_FULLSCREEN) 338 | printf("(+fullscr.), "); 339 | Config::ContainerConfig *pcontainerConfig = dynamic_cast(pcontainer); 340 | printf("[ContainerConfig: %p, (->container: %p)], ",pcontainerConfig,pcontainerConfig->pcontainerInt->pcontainer); 341 | //printf("focusQueue: %lu (%p), stackQueue: %lu (%p)\n",pcontainer->focusQueue.size(),pcontainer->focusQueue.size() > 0?pcontainer->focusQueue.back():0,pcontainer->stackQueue.size(),pcontainer->stackQueue.size() > 0?pcontainer->stackQueue.back():0); 342 | printf("focusQueue: %lu (%p), stackQueue: %lu (%p) {",pcontainer->focusQueue.size(),pcontainer->focusQueue.size() > 0?pcontainer->focusQueue.back():0,pcontainer->stackQueue.size(),pcontainer->stackQueue.size() > 0?pcontainer->stackQueue.back():0); 343 | for(WManager::Container *pcont : pcontainer->stackQueue) 344 | printf("%p,",pcont); 345 | printf("}\n"); 346 | for(WManager::Container *pcontainer1 = pcontainer->pch; pcontainer1; pcontainer1 = pcontainer1->pnext) 347 | PrintTree(pcontainer1,level+1); 348 | if(level == 0) 349 | for(auto &p : stackAppendix) 350 | printf("FLOAT %p, flags: %x\n",p.second->pcontainer,p.second->pcontainer->flags); 351 | } 352 | 353 | //protected: 354 | std::vector stackAppendix; 355 | class RunCompositor *pcomp; 356 | Compositor::CompositorInterface *pcompInt; //dynamic casted from pcomp on initialization 357 | }; 358 | 359 | class DefaultBackend : public Backend::Default, public RunBackend{ 360 | public: 361 | DefaultBackend(Config::BackendInterface *_pbackendInt) : Default(_pbackendInt->standaloneComp), RunBackend(_pbackendInt){ 362 | Start(); 363 | DebugPrintf(stdout,"Backend initialized.\n"); 364 | } 365 | 366 | ~DefaultBackend(){ 367 | Stop(); 368 | if(!WManager::Container::rootQueue.empty()){ 369 | WManager::Container *proot1 = WManager::Container::rootQueue.front(); 370 | WManager::Container *pRootNext = proot1->pRootNext; 371 | do{ 372 | WManager::Container *pRootNext2 = pRootNext->pRootNext; 373 | delete pRootNext; 374 | 375 | pRootNext = pRootNext2; 376 | }while(pRootNext != proot1); 377 | } 378 | } 379 | 380 | void DefineBindings(){ 381 | Config::BackendInterface::pbackendInt->OnSetupKeys(false); 382 | } 383 | 384 | Backend::X11Client * SetupClient(const Backend::X11Client::CreateInfo *pcreateInfo){ 385 | //Containers should be created always under the parent of the current focus. 386 | //config script should manage this (point to container which should be the 387 | //parent of the new one), while also setting some of the parameters like border 388 | //width and such. 389 | //Compositor::X11Compositor *pcomp11 = dynamic_cast(pcomp); 390 | 391 | ContainerCreateInfo containerCreateInfo; 392 | containerCreateInfo.wm_name = pcreateInfo->pwmName->pstr; 393 | containerCreateInfo.wm_class = pcreateInfo->pwmClass->pstr; 394 | containerCreateInfo.shaderName[Compositor::Pipeline::SHADER_MODULE_VERTEX] = "frame_vertex.spv"; 395 | containerCreateInfo.shaderName[Compositor::Pipeline::SHADER_MODULE_GEOMETRY] = "frame_geometry.spv"; 396 | containerCreateInfo.shaderName[Compositor::Pipeline::SHADER_MODULE_FRAGMENT] = "frame_fragment.spv"; 397 | containerCreateInfo.floating = (pcreateInfo->hints & Backend::X11Client::CreateInfo::HINT_FLOATING) != 0; 398 | 399 | if(pcreateInfo->mode == Backend::X11Client::CreateInfo::CREATE_AUTOMATIC){ 400 | //create a temporary container through which (py) OnSetupClient() can be called. The container is discarded as soon as the call has been made. 401 | Config::ContainerInterface &containerInt = SetupContainer(&containerCreateInfo); 402 | 403 | containerInt.OnSetupClient(); 404 | 405 | const char *pshaderName[Compositor::Pipeline::SHADER_MODULE_COUNT] = { 406 | containerInt.vertexShader.c_str(),containerInt.geometryShader.c_str(),containerInt.fragmentShader.c_str() 407 | }; 408 | //WManager::Container *proot = WManager::Container::ptreeFocus->GetRoot(); //TODO: stack's root? 409 | Backend::X11Container *proot = static_cast(WManager::Container::ptreeFocus->GetRoot()); 410 | Backend::X11Client *pclient11 = SetupClient(proot,pcreateInfo,pshaderName); 411 | 412 | if(pclient11) //in some cases the window is found to be unmanageable 413 | stackAppendix.push_back(StackAppendixElement(pcreateInfo->pstackClient,pclient11)); 414 | return pclient11; 415 | 416 | }else{ 417 | Config::ContainerInterface &containerInt = SetupContainer(0,&containerCreateInfo); //null parent = obtain parent from config script 418 | 419 | if(pcreateInfo->hints & Backend::X11Client::CreateInfo::HINT_NO_INPUT) 420 | containerInt.pcontainer->flags |= WManager::Container::FLAG_NO_FOCUS; 421 | 422 | containerInt.OnSetupClient(); 423 | 424 | const char *pshaderName[Compositor::Pipeline::SHADER_MODULE_COUNT] = { 425 | containerInt.vertexShader.c_str(),containerInt.geometryShader.c_str(),containerInt.fragmentShader.c_str() 426 | }; 427 | Backend::X11Container *pcontainer11 = static_cast(containerInt.pcontainer); 428 | Backend::X11Client *pclient11 = SetupClient(pcontainer11,pcreateInfo,pshaderName); 429 | pcontainer11->SetClient(pclient11); 430 | if(pclient11 && containerInt.pcontainer->flags & WManager::Container::FLAG_FLOATING) 431 | stackAppendix.push_back(StackAppendixElement(pcreateInfo->pstackClient,pclient11)); 432 | 433 | containerInt.DeferredPropertyTransfer(); 434 | containerInt.OnCreate(); 435 | 436 | return pclient11; 437 | } 438 | } 439 | 440 | Backend::X11Client * SetupClient(Backend::X11Container *pcontainer, const Backend::X11Client::CreateInfo *pcreateInfo, const char *pshaderName[Compositor::Pipeline::SHADER_MODULE_COUNT]){ 441 | Backend::X11Client *pclient11; 442 | Compositor::X11Compositor *pcomp11 = dynamic_cast(pcomp); 443 | if(!pcomp11) 444 | pclient11 = new Backend::X11Client(pcontainer,pcreateInfo); 445 | else{ 446 | if(pcreateInfo->window == pcomp11->overlay) 447 | return 0; 448 | pclient11 = new Compositor::X11ClientFrame(pcontainer,pcreateInfo,pshaderName,pcomp11); 449 | } 450 | 451 | return pclient11; 452 | } 453 | 454 | void MoveContainer(WManager::Container *pcontainer, WManager::Container *pdst){ 455 | // 456 | RunBackend::MoveContainer(pcontainer,pdst); 457 | } 458 | 459 | void FloatContainer(WManager::Container *pcontainer){ 460 | if(!pcontainer->pclient){ 461 | DebugPrintf(stderr,"Only client containers can be floated.\n"); 462 | return; //who knows we'll fix this limitation someday 463 | } 464 | auto n1 = std::find_if(WManager::Container::tiledFocusQueue.begin(),WManager::Container::tiledFocusQueue.end(),[&](auto &p)->bool{ 465 | return p.first == pcontainer; 466 | }); 467 | if(n1 != WManager::Container::tiledFocusQueue.end()) 468 | WManager::Container::tiledFocusQueue.erase(n1); 469 | auto n2 = std::find(WManager::Container::floatFocusQueue.begin(),WManager::Container::floatFocusQueue.end(),pcontainer); 470 | if(n2 != WManager::Container::floatFocusQueue.end()) 471 | WManager::Container::floatFocusQueue.erase(n2); 472 | 473 | WManager::Container *proot = pcontainer->GetRoot(); 474 | PrintTree(proot,0); 475 | printf("-----------\n"); 476 | 477 | WManager::Client *pbase = pcontainer->pclient; 478 | auto m = std::find_if(stackAppendix.begin(),stackAppendix.end(),[&](auto &p)->bool{ 479 | return pbase == p.second; 480 | }); 481 | if(m != stackAppendix.end()){ 482 | stackAppendix.erase(m); 483 | //TODO: call OnParent 484 | pcontainer->flags &= ~WManager::Container::FLAG_FLOATING; 485 | pcontainer->Place(proot); 486 | 487 | printf("----------- placed %p\n",pcontainer); 488 | PrintTree(proot,0); 489 | 490 | return; 491 | } 492 | WManager::Container *premoved = pcontainer->Remove(); 493 | WManager::Container *pOrigParent = premoved->pParent; 494 | 495 | printf("----------- removed %p\n",premoved); 496 | PrintTree(proot,0); 497 | 498 | WManager::Container *pcollapsed = 0; 499 | if(pOrigParent != proot) 500 | pcollapsed = pOrigParent->Collapse(); 501 | //check if pch is alive, in this case this wasn't the last container 502 | if(!pcollapsed && pOrigParent->pch) 503 | pcollapsed = pOrigParent->pch->Collapse(); 504 | 505 | if(WManager::Container::ptreeFocus == pcontainer || WManager::Container::ptreeFocus == pcollapsed){ 506 | WManager::Container *pNewFocus = proot; 507 | for(WManager::Container *pcontainer = pNewFocus; pcontainer; pNewFocus = pcontainer, pcontainer = pcontainer->GetFocus()); 508 | Config::X11ContainerConfig *pNewFocus1 = static_cast(pNewFocus); 509 | if(pNewFocus1->pcontainerInt->OnFocus()) 510 | pNewFocus1->Focus(); 511 | } 512 | 513 | printf("----------- collapsed %p\n",pcollapsed); 514 | PrintTree(proot,0); 515 | 516 | /*if(premoved->pch) //in this case nothing gets removed 517 | ReleaseContainersRecursive(premoved->pch); 518 | delete premoved;*/ 519 | if(pcollapsed){ 520 | if(pcollapsed->pch) //this should not exist 521 | ReleaseContainersRecursive(pcollapsed->pch); 522 | delete pcollapsed; 523 | } 524 | 525 | static WManager::Client dummyClient(0); //base client being unavailable means that the client is stacked on top of everything else 526 | 527 | pcontainer->flags |= WManager::Container::FLAG_FLOATING; 528 | pcontainer->p = pcontainer->p+0.5f*(pcontainer->e-glm::vec2(0.3f,0.4f)); 529 | pcontainer->SetSize(glm::vec2(0.3f,0.4f)); //TODO: this should be determined better or memorized 530 | if(pcontainer->pclient) 531 | stackAppendix.push_back(StackAppendixElement(&dummyClient,pcontainer->pclient)); 532 | 533 | pcontainer->pParent = proot; 534 | pcontainer->Focus(); 535 | } 536 | 537 | WManager::Container * CreateWorkspace(const char *pname){ 538 | WManager::Container *plastRoot = WManager::Container::rootQueue.back(); 539 | Config::X11ContainerConfig *pnewRoot = new Config::X11ContainerConfig(this); 540 | pnewRoot->SetName(pname); 541 | plastRoot->AppendRoot(pnewRoot); 542 | return pnewRoot; 543 | } 544 | 545 | //Called for spontaneous (client requested) fullscreen triggered by an event 546 | void SetFullscreen(Backend::X11Client *pclient, bool toggle){ 547 | if(!pclient || pclient->pcontainer == pclient->pcontainer->GetRoot()) 548 | return; 549 | Config::X11ContainerConfig *pcontainer1 = static_cast(pclient->pcontainer); 550 | if(pcontainer1->pcontainerInt->OnFullscreen(toggle)) 551 | pcontainer1->SetFullscreen(toggle); 552 | } 553 | 554 | //Called for spontaneous (client requested) focus triggered by an event 555 | void SetFocus(Backend::X11Client *pclient){ 556 | if(!pclient || pclient->pcontainer == pclient->pcontainer->GetRoot()) 557 | return; 558 | Config::X11ContainerConfig *pcontainer1 = static_cast(pclient->pcontainer); 559 | if(pcontainer1->pcontainerInt->OnFocus()) 560 | pcontainer1->Focus(); 561 | } 562 | 563 | void Enter(Backend::X11Client *pclient){ 564 | if(!pclient || pclient->pcontainer == pclient->pcontainer->GetRoot()) 565 | return; 566 | Config::X11ContainerConfig *pcontainer1 = static_cast(pclient->pcontainer); 567 | pcontainer1->pcontainerInt->OnEnter(); 568 | } 569 | 570 | void PropertyChange(Backend::X11Client *pclient, PROPERTY_ID id, const Backend::BackendProperty *pProperty){ 571 | if(!pclient){ 572 | //root window 573 | const Backend::BackendPixmapProperty *pPixmapProperty = static_cast(pProperty); 574 | Compositor::X11Compositor *pcomp11 = dynamic_cast(pcomp); 575 | if(pcomp11) 576 | pcomp11->SetBackgroundPixmap(pPixmapProperty); 577 | return; 578 | } 579 | if(pclient->pcontainer == pclient->pcontainer->GetRoot()) 580 | return; 581 | Config::X11ContainerConfig *pcontainer1 = static_cast(pclient->pcontainer); 582 | if(id == PROPERTY_ID_WM_NAME){ 583 | pcontainer1->pcontainerInt->wm_name = static_cast(pProperty)->pstr; 584 | pcontainer1->pcontainerInt->OnPropertyChange(Config::ContainerInterface::PROPERTY_ID_NAME); 585 | }else 586 | if(id == PROPERTY_ID_WM_CLASS){ 587 | pcontainer1->pcontainerInt->wm_name = static_cast(pProperty)->pstr; 588 | pcontainer1->pcontainerInt->OnPropertyChange(Config::ContainerInterface::PROPERTY_ID_CLASS); 589 | }else 590 | if(id == PROPERTY_ID_TRANSIENT_FOR){ 591 | // 592 | //TODO!! 593 | /*WManager::Container *pstackContainer = static_cast(pProperty)->pcontainer; 594 | auto m = std::find_if(stackAppendix.begin(),stackAppendix.end(),[&](auto &p)->bool{ 595 | return pclient == p.second; 596 | }); 597 | if(m != stackAppendix.end()) 598 | (*m).first = pstackContainer;*/ 599 | //else: TODO: should we remove it from the tiling tree and make it floating according to its rect? 600 | } 601 | } 602 | 603 | void DestroyClient(Backend::X11Client *pclient){ 604 | auto n1 = std::find_if(WManager::Container::tiledFocusQueue.begin(),WManager::Container::tiledFocusQueue.end(),[&](auto &p)->bool{ 605 | return p.first == pclient->pcontainer; 606 | }); 607 | if(n1 != WManager::Container::tiledFocusQueue.end()) 608 | WManager::Container::tiledFocusQueue.erase(n1); 609 | auto n2 = std::find(WManager::Container::floatFocusQueue.begin(),WManager::Container::floatFocusQueue.end(),pclient->pcontainer); 610 | if(n2 != WManager::Container::floatFocusQueue.end()) 611 | WManager::Container::floatFocusQueue.erase(n2); 612 | 613 | WManager::Container *proot = pclient->pcontainer->GetRoot(); 614 | PrintTree(proot,0); 615 | 616 | WManager::Client *pbase = pclient; 617 | auto m = std::find_if(stackAppendix.begin(),stackAppendix.end(),[&](auto &p)->bool{ 618 | return pbase == p.second; 619 | }); 620 | if(m != stackAppendix.end()) 621 | stackAppendix.erase(m); 622 | if(pclient->pcontainer == proot){ 623 | delete pclient; 624 | return; 625 | } 626 | WManager::Container *premoved = pclient->pcontainer->Remove(); 627 | WManager::Container *pOrigParent = premoved->pParent; 628 | 629 | printf("----------- removed %p\n",premoved); 630 | PrintTree(proot,0); 631 | 632 | WManager::Container *pcollapsed = 0; 633 | if(pOrigParent != proot) 634 | pcollapsed = pOrigParent->Collapse(); 635 | //check if pch is alive, in this case this wasn't the last container 636 | if(!pcollapsed && pOrigParent->pch) 637 | pcollapsed = pOrigParent->pch->Collapse(); 638 | 639 | if(WManager::Container::ptreeFocus == pclient->pcontainer || WManager::Container::ptreeFocus == pcollapsed){ 640 | WManager::Container *pNewFocus = proot; 641 | //for(WManager::Container *pcontainer = pNewFocus; pcontainer; pNewFocus = pcontainer, pcontainer = pcontainer->focusQueue.size() > 0?pcontainer->focusQueue.back():pcontainer->pch); 642 | for(WManager::Container *pcontainer = pNewFocus; pcontainer; pNewFocus = pcontainer, pcontainer = pcontainer->GetFocus()); 643 | Config::X11ContainerConfig *pNewFocus1 = static_cast(pNewFocus); 644 | if(pNewFocus1->pcontainerInt->OnFocus()) 645 | pNewFocus1->Focus(); 646 | } 647 | if(premoved->pch) 648 | ReleaseContainersRecursive(premoved->pch); 649 | if(premoved->pclient) 650 | delete premoved->pclient; 651 | delete premoved; 652 | if(pcollapsed){ 653 | if(pcollapsed->pch) 654 | ReleaseContainersRecursive(pcollapsed->pch); 655 | delete pcollapsed; 656 | } 657 | 658 | printf("----------- collapsed %p\n",pcollapsed); 659 | PrintTree(proot,0); 660 | printf("stackAppendix: %lu\n",stackAppendix.size()); 661 | } 662 | 663 | bool EventNotify(const Backend::BackendEvent *pevent){ 664 | Compositor::X11Compositor *pcomp11 = dynamic_cast(pcomp); 665 | if(!pcomp11) 666 | return false; 667 | const Backend::X11Event *pevent11 = static_cast(pevent); 668 | return pcomp11->FilterEvent(pevent11); 669 | } 670 | 671 | void WakeNotify(){ 672 | pcompInt->FullDamageRegion(); 673 | } 674 | 675 | void KeyPress(uint keyId, bool down){ 676 | if(down) 677 | Config::BackendInterface::pbackendInt->OnKeyPress(keyId); 678 | else Config::BackendInterface::pbackendInt->OnKeyRelease(keyId); 679 | } 680 | 681 | const std::vector * GetStackAppendix() const{ 682 | return &stackAppendix; 683 | } 684 | 685 | void SortStackAppendix(){ 686 | std::sort(stackAppendix.begin(),stackAppendix.end(),[&](StackAppendixElement &a, StackAppendixElement &b)->bool{ 687 | for(auto *p : WManager::Container::floatFocusQueue){ 688 | if(p == a.second->pcontainer) 689 | return true; 690 | if(p == b.second->pcontainer) 691 | return false; 692 | } 693 | return false; 694 | }); 695 | } 696 | 697 | void TimerEvent(){ 698 | // 699 | Config::BackendInterface::pbackendInt->OnTimer(); 700 | } 701 | 702 | bool ApproveExternal(const Backend::BackendStringProperty *pwmName, const Backend::BackendStringProperty *pwmClass){ 703 | return Config::CompositorInterface::pcompositorInt->OnRedirectExternal(pwmName->pstr,pwmClass->pstr); 704 | } 705 | }; 706 | 707 | //TODO: some of these functions can be templated and shared with the DefaultBackend 708 | class DebugBackend : public Backend::Debug, public RunBackend{ 709 | public: 710 | DebugBackend(Config::BackendInterface *_pbackendInt) : Debug(), RunBackend(_pbackendInt){ 711 | Start(); 712 | DebugPrintf(stdout,"Backend initialized.\n"); 713 | } 714 | 715 | ~DebugBackend(){ 716 | Stop(); 717 | if(!WManager::Container::rootQueue.empty()){ 718 | WManager::Container *proot1 = WManager::Container::rootQueue.front(); 719 | WManager::Container *pRootNext = proot1->pRootNext; 720 | do{ 721 | WManager::Container *pRootNext2 = pRootNext->pRootNext; 722 | delete pRootNext; 723 | 724 | pRootNext = pRootNext2; 725 | }while(pRootNext != proot1); 726 | } 727 | } 728 | 729 | Backend::DebugClient * SetupClient(const Backend::DebugClient::CreateInfo *pcreateInfo){ 730 | Config::ContainerInterface &containerInt = SetupContainer(0,0); 731 | 732 | static const char *pshaderName[Compositor::Pipeline::SHADER_MODULE_COUNT] = { 733 | "frame_vertex.spv","frame_geometry.spv","frame_fragment.spv" 734 | }; 735 | 736 | Backend::DebugClient *pclient; 737 | Compositor::X11DebugCompositor *pcomp11 = dynamic_cast(pcomp); 738 | Backend::DebugContainer *pdebugContainer = static_cast(containerInt.pcontainer); 739 | if(!pcomp11) 740 | pclient = new Backend::DebugClient(pdebugContainer,pcreateInfo); 741 | else pclient = new Compositor::X11DebugClientFrame(pdebugContainer,pcreateInfo,pshaderName,pcomp11); 742 | pdebugContainer->SetClient(pclient); 743 | //containerInt.pcontainer->pclient = pclient; 744 | // 745 | 746 | containerInt.OnCreate(); 747 | 748 | return pclient; 749 | } 750 | 751 | void MoveContainer(WManager::Container *pcontainer, WManager::Container *pdst){ 752 | // 753 | RunBackend::MoveContainer(pcontainer,pdst); 754 | } 755 | 756 | void FloatContainer(WManager::Container *pcontainer){ 757 | // 758 | } 759 | 760 | void DestroyClient(Backend::DebugClient *pclient){ 761 | WManager::Client *pbase = pclient; 762 | auto m = std::find_if(stackAppendix.begin(),stackAppendix.end(),[&](auto &p)->bool{ 763 | return pbase == p.second; 764 | }); 765 | if(m != stackAppendix.end()) 766 | stackAppendix.erase(m); 767 | WManager::Container *proot = pclient->pcontainer->GetRoot(); 768 | if(pclient->pcontainer == proot){ 769 | delete pclient; 770 | return; 771 | } 772 | WManager::Container *premoved = pclient->pcontainer->Remove(); 773 | 774 | WManager::Container *pcollapsed = 0; 775 | if(premoved->pParent != proot) 776 | pcollapsed = premoved->pParent->Collapse(); 777 | if(!pcollapsed && premoved->pParent->pch) //check if pch is alive, in this case this wasn't the last container 778 | pcollapsed = premoved->pParent->pch->Collapse(); 779 | 780 | if(WManager::Container::ptreeFocus == pclient->pcontainer || WManager::Container::ptreeFocus == pcollapsed){ 781 | WManager::Container *pNewFocus = proot; 782 | for(WManager::Container *pcontainer = pNewFocus; pcontainer; pNewFocus = pcontainer, pcontainer = pcontainer->GetFocus()); 783 | Config::DebugContainerConfig *pNewFocus1 = dynamic_cast(pNewFocus); 784 | if(pNewFocus1->pcontainerInt->OnFocus()) 785 | pNewFocus1->Focus(); 786 | } 787 | if(premoved->pch) 788 | ReleaseContainersRecursive(premoved->pch); 789 | if(premoved->pclient) 790 | delete premoved->pclient; 791 | delete premoved; 792 | if(pcollapsed){ 793 | if(pcollapsed->pch) 794 | ReleaseContainersRecursive(pcollapsed->pch); 795 | delete pcollapsed; 796 | } 797 | } 798 | 799 | void DefineBindings(){ 800 | Config::BackendInterface::pbackendInt->OnSetupKeys(true); 801 | } 802 | 803 | bool EventNotify(const Backend::BackendEvent *pevent){ 804 | //nothing to process 805 | return false; 806 | } 807 | 808 | void WakeNotify(){ 809 | pcompInt->FullDamageRegion(); 810 | } 811 | 812 | void KeyPress(uint keyId, bool down){ 813 | if(down) 814 | Config::BackendInterface::pbackendInt->OnKeyPress(keyId); 815 | else Config::BackendInterface::pbackendInt->OnKeyRelease(keyId); 816 | } 817 | 818 | const std::vector * GetStackAppendix() const{ 819 | return &stackAppendix; 820 | } 821 | 822 | void SortStackAppendix(){ 823 | // 824 | } 825 | 826 | void TimerEvent(){ 827 | // 828 | } 829 | 830 | bool ApproveExternal(const Backend::BackendStringProperty *pwmName, const Backend::BackendStringProperty *pwmClass){ 831 | return true; 832 | } 833 | }; 834 | 835 | class DefaultCompositor : public Compositor::X11Compositor, public RunCompositor{ 836 | public: 837 | DefaultCompositor(std::vector *_pstackAppendix, Backend::X11Backend *pbackend, args::ValueFlagList &shaderPaths, Config::CompositorInterface *_pcompositorInt) : X11Compositor(pconfig = new Configuration{_pcompositorInt->deviceIndex,_pcompositorInt->debugLayers,_pcompositorInt->scissoring,_pcompositorInt->incrementalPresent,_pcompositorInt->memoryImportMode,_pcompositorInt->unredirOnFullscreen,_pcompositorInt->enableAnimation,_pcompositorInt->animationDuration,_pcompositorInt->fontName.c_str(),_pcompositorInt->fontSize},pbackend), RunCompositor(_pstackAppendix,_pcompositorInt){ 838 | Start(); 839 | 840 | wordexp_t expResult; 841 | for(auto &m : args::get(shaderPaths)){ 842 | wordexp(m.c_str(),&expResult,WRDE_NOCMD); 843 | try{ 844 | boost::filesystem::directory_iterator end; 845 | for(boost::filesystem::directory_iterator di(expResult.we_wordv[0]); di != end; ++di){ 846 | if(boost::filesystem::is_regular_file(di->status()) && 847 | //boost::filesystem::extension(di->path()) == ".spv"){ 848 | di->path().extension() == ".spv"){ 849 | Blob blob(di->path().string().c_str()); 850 | AddShader(di->path().filename().string().c_str(),&blob); 851 | } 852 | } 853 | }catch(boost::filesystem::filesystem_error &e){ 854 | DebugPrintf(stderr,"%s\n",e.what()); 855 | } 856 | wordfree(&expResult); 857 | } 858 | 859 | ClearBackground(); 860 | 861 | DebugPrintf(stdout,"Compositor enabled.\n"); 862 | } 863 | 864 | ~DefaultCompositor(){ 865 | delete pconfig; 866 | Stop(); 867 | } 868 | 869 | void Present(){ 870 | Config::ContainerInterface::UpdateShaders(); 871 | Backend::X11Container *proot = static_cast(WManager::Container::ptreeFocus->GetRoot()); 872 | 873 | if(!PollFrameFence(proot->noComp)) 874 | return; 875 | 876 | GenerateCommandBuffers(&pbackend->clientStack,WManager::Container::ptreeFocus,pbackend->pfocusInClient); 877 | Compositor::X11Compositor::Present(); 878 | } 879 | 880 | bool IsAnimating() const{ 881 | return playingAnimation; 882 | } 883 | 884 | void WaitIdle(){ 885 | Compositor::X11Compositor::WaitIdle(); 886 | } 887 | 888 | Configuration *pconfig; 889 | }; 890 | 891 | class DebugCompositor : public Compositor::X11DebugCompositor, public RunCompositor{ 892 | public: 893 | DebugCompositor(std::vector *_pstackAppendix, Backend::X11Backend *pbackend, args::ValueFlagList &shaderPaths, Config::CompositorInterface *_pcompositorInt) : X11DebugCompositor(pconfig = new Configuration{_pcompositorInt->deviceIndex,_pcompositorInt->debugLayers,_pcompositorInt->scissoring,_pcompositorInt->incrementalPresent,_pcompositorInt->memoryImportMode,_pcompositorInt->unredirOnFullscreen,_pcompositorInt->enableAnimation,_pcompositorInt->animationDuration,_pcompositorInt->fontName.c_str(),_pcompositorInt->fontSize},pbackend), RunCompositor(_pstackAppendix,_pcompositorInt){ 894 | Compositor::X11DebugCompositor::Start(); 895 | 896 | wordexp_t expResult; 897 | for(auto &m : args::get(shaderPaths)){ 898 | wordexp(m.c_str(),&expResult,WRDE_NOCMD); 899 | try{ 900 | boost::filesystem::directory_iterator end; 901 | for(boost::filesystem::directory_iterator di(expResult.we_wordv[0]); di != end; ++di){ 902 | if(boost::filesystem::is_regular_file(di->status()) && 903 | di->path().extension() == ".spv"){ 904 | Blob blob(di->path().string().c_str()); 905 | AddShader(di->path().filename().string().c_str(),&blob); 906 | } 907 | } 908 | }catch(boost::filesystem::filesystem_error &e){ 909 | DebugPrintf(stderr,"%s\n",e.what()); 910 | } 911 | wordfree(&expResult); 912 | } 913 | 914 | ClearBackground(); 915 | 916 | DebugPrintf(stdout,"Compositor enabled.\n"); 917 | } 918 | 919 | ~DebugCompositor(){ 920 | Compositor::X11DebugCompositor::Stop(); 921 | delete pconfig; 922 | } 923 | 924 | void Present(){ 925 | Config::ContainerInterface::UpdateShaders(); 926 | if(!PollFrameFence(false)) 927 | return; 928 | 929 | GenerateCommandBuffers(&pbackend->clientStack,WManager::Container::ptreeFocus,pbackend->pfocusInClient); 930 | Compositor::X11DebugCompositor::Present(); 931 | } 932 | 933 | bool IsAnimating() const{ 934 | return playingAnimation; 935 | } 936 | 937 | void WaitIdle(){ 938 | Compositor::X11DebugCompositor::WaitIdle(); 939 | } 940 | 941 | Configuration *pconfig; 942 | }; 943 | 944 | class NullCompositor : public Compositor::NullCompositor, public RunCompositor{ 945 | public: 946 | NullCompositor(Config::CompositorInterface *_pcompositorInt) : Compositor::NullCompositor(), RunCompositor(0,_pcompositorInt){ 947 | Start(); 948 | } 949 | 950 | ~NullCompositor(){ 951 | Stop(); 952 | } 953 | 954 | void Present(){ 955 | // 956 | } 957 | 958 | bool IsAnimating() const{ 959 | return false; 960 | } 961 | 962 | void WaitIdle(){ 963 | // 964 | } 965 | }; 966 | 967 | int main(sint argc, const char **pargv){ 968 | args::ArgumentParser parser("chamferwm - A compositing window manager",""); 969 | args::HelpFlag help(parser,"help","Display this help menu",{'h',"help"}); 970 | 971 | args::ValueFlag configPath(parser,"path","Configuration Python script",{"config",'c'}); 972 | 973 | args::Group group_backend(parser,"Backend",args::Group::Validators::DontCare); 974 | args::Flag debugBackend(group_backend,"debugBackend","Create a test environment for the compositor engine without redirection. The application will not act as a window manager.",{'d',"debug-backend"}); 975 | args::Flag staComp(group_backend,"standaloneCompositor","Standalone compositor for external window managers.",{'C',"standalone-compositor"}); 976 | 977 | args::Group group_comp(parser,"Compositor",args::Group::Validators::DontCare); 978 | args::Flag noComp(group_comp,"noComp","Disable compositor.",{"no-compositor",'n'}); 979 | args::ValueFlag deviceIndexOpt(group_comp,"id","GPU to use by its index. By default the first device in the list of enumerated GPUs will be used.",{"device-index"}); 980 | args::Flag debugLayersOpt(group_comp,"debugLayers","Enable Vulkan debug layers.",{"debug-layers",'l'},false); 981 | args::Flag noScissoringOpt(group_comp,"noScissoring","Disable scissoring optimization.",{"no-scissoring"},false); 982 | args::Flag noIncPresentOpt(group_comp,"noIncPresent","Disable incremental present support.",{"no-incremental-present"},false); 983 | args::ValueFlag memoryImportMode(group_comp,"memoryImportMode","Memory import mode:\n0: DMA-buf import (fastest, default)\n1: Host memory import (compatibility)\n2: CPU copy (slow, compatibility)",{"memory-import-mode",'m'}); 984 | args::Flag unredirOnFullscreenOpt(group_comp,"unredirOnFullscreen","Unredirect a fullscreen window bypassing the compositor to improve performance.",{"unredir-on-fullscreen"},false); 985 | args::ValueFlagList shaderPaths(group_comp,"path","Shader lookup path. SPIR-V shader objects are identified by an '.spv' extension. Multiple paths may be specified through multiple --shader-path, and the first specified paths will take priority over the later ones.",{"shader-path"},{"/usr/share/chamfer/shaders"}); 986 | 987 | try{ 988 | parser.ParseCLI(argc,pargv); 989 | 990 | }catch(args::Help &e){ 991 | std::cout<= Compositor::CompositorInterface::IMPORT_MODE_COUNT){ 1007 | DebugPrintf(stderr,"Invalid memory import mode specified (%u). Mode specifier must be less than %u. See --help for available options.\n",memoryImportMode.Get(),Compositor::CompositorInterface::IMPORT_MODE_COUNT); 1008 | return 1; 1009 | } 1010 | Config::Loader::memoryImportMode = (Compositor::CompositorInterface::IMPORT_MODE)memoryImportMode.Get(); 1011 | }else Config::Loader::memoryImportMode = Compositor::CompositorInterface::IMPORT_MODE_DMABUF; 1012 | Config::Loader::unredirOnFullscreen = unredirOnFullscreenOpt.Get(); 1013 | 1014 | Config::Loader *pconfigLoader = new Config::Loader(pargv[0]); 1015 | if(!pconfigLoader->Run(configPath?configPath.Get().c_str():0,"config.py")) 1016 | return 1; 1017 | 1018 | if(staComp.Get()){ 1019 | if(noComp.Get()){ 1020 | DebugPrintf(stderr,"Incompatible options: --no-compositor (-n) and --standalone-compositor (-C).\n"); 1021 | return 1; 1022 | } 1023 | Config::BackendInterface::pbackendInt->standaloneComp = true; 1024 | } 1025 | 1026 | if(noComp) 1027 | Config::CompositorInterface::pcompositorInt->noCompositor = noComp.Get(); 1028 | if(deviceIndexOpt) 1029 | Config::CompositorInterface::pcompositorInt->deviceIndex = deviceIndexOpt.Get(); 1030 | if(debugLayersOpt.Get()) 1031 | Config::CompositorInterface::pcompositorInt->debugLayers = true; 1032 | if(noScissoringOpt.Get()) 1033 | Config::CompositorInterface::pcompositorInt->scissoring = false; 1034 | if(noIncPresentOpt.Get()) 1035 | Config::CompositorInterface::pcompositorInt->incrementalPresent = false; 1036 | if(memoryImportMode) 1037 | Config::CompositorInterface::pcompositorInt->memoryImportMode = (Compositor::CompositorInterface::IMPORT_MODE)memoryImportMode.Get(); 1038 | if(unredirOnFullscreenOpt.Get()) 1039 | Config::CompositorInterface::pcompositorInt->unredirOnFullscreen = true; 1040 | 1041 | Backend::X11Backend *pbackend11; 1042 | try{ 1043 | if(debugBackend.Get()){ 1044 | pbackend11 = new DebugBackend(Config::BackendInterface::pbackendInt); 1045 | WManager::Container::ptreeFocus = new Config::DebugContainerConfig(pbackend11); //self registered 1046 | }else{ 1047 | pbackend11 = new DefaultBackend(Config::BackendInterface::pbackendInt); 1048 | WManager::Container::ptreeFocus = new Config::X11ContainerConfig(pbackend11); //self registered 1049 | } 1050 | 1051 | }catch(Exception e){ 1052 | DebugPrintf(stderr,"%s\n",e.what()); 1053 | return 1; 1054 | } 1055 | 1056 | WManager::Container::ptreeFocus->SetName("1"); 1057 | 1058 | RunBackend *pbackend = dynamic_cast(pbackend11); 1059 | 1060 | RunCompositor *pcomp; 1061 | try{ 1062 | if(Config::CompositorInterface::pcompositorInt->noCompositor) 1063 | pcomp = new NullCompositor(Config::CompositorInterface::pcompositorInt); 1064 | else 1065 | if(debugBackend.Get()) 1066 | pcomp = new DebugCompositor(&pbackend->stackAppendix,pbackend11,shaderPaths,Config::CompositorInterface::pcompositorInt); 1067 | else pcomp = new DefaultCompositor(&pbackend->stackAppendix,pbackend11,shaderPaths,Config::CompositorInterface::pcompositorInt); 1068 | 1069 | }catch(Exception e){ 1070 | DebugPrintf(stderr,"%s\n",e.what()); 1071 | delete pbackend; 1072 | return 1; 1073 | } 1074 | 1075 | pbackend->SetCompositor(pcomp); 1076 | 1077 | signal(SIGTERM,SignalHandler); 1078 | 1079 | for(;;){ 1080 | //TODO: can we wait for vsync before handling the event? Might help with the stuttering 1081 | sint result = pbackend11->HandleEvent(pcomp->IsAnimating()); 1082 | if(result == -1 || sigTerm) 1083 | break; 1084 | else 1085 | if(result == 0 && !pcomp->IsAnimating()) 1086 | continue; 1087 | 1088 | try{ 1089 | pcomp->Present(); 1090 | 1091 | }catch(Exception e){ 1092 | DebugPrintf(stderr,"%s\n",e.what()); 1093 | break; 1094 | } 1095 | } 1096 | 1097 | DebugPrintf(stdout,"Exit\n"); 1098 | 1099 | Config::BackendInterface::pbackendInt->OnExit(); 1100 | 1101 | pcomp->WaitIdle(); 1102 | pbackend->ReleaseContainers(); 1103 | 1104 | delete pcomp; 1105 | delete pbackend; 1106 | delete pconfigLoader; 1107 | 1108 | return 0; 1109 | } 1110 | 1111 | --------------------------------------------------------------------------------