1 /// Optional window package, mainly to run gfx-d examples 2 module gfx.window; 3 4 import gfx.core.rc : IAtomicRefCounted; 5 import gfx.core.log : LogTag; 6 import gfx.graal : Backend, Instance; 7 public import gfx.window.keys; 8 9 import std.typecons : Flag, No, Yes; 10 11 enum gfxWindowLogMask = 0x0800_0000; 12 package immutable gfxWindowLog = LogTag("GFX-WINDOW", gfxWindowLogMask); 13 14 struct KeyEvent 15 { 16 KeySym sym; 17 KeyCode code; 18 KeyMods mods; 19 string text; 20 } 21 22 struct MouseEvent 23 { 24 uint x; 25 uint y; 26 KeyMods mods; 27 } 28 29 alias MouseHandler = void delegate(MouseEvent ev); 30 alias KeyHandler = void delegate(KeyEvent ev); 31 alias ResizeHandler = void delegate(uint width, uint height); 32 alias CloseHandler = bool delegate(); 33 34 interface Display : IAtomicRefCounted 35 { 36 @property Instance instance(); 37 @property Window[] windows(); 38 Window createWindow(string title = "Gfx-d Window"); 39 void pollAndDispatch(); 40 } 41 42 interface Window 43 { 44 import gfx.graal.presentation : Surface; 45 46 void show(uint width, uint height); 47 void close(); 48 49 @property string title(); 50 void setTitle(string title); 51 52 @property Surface surface(); 53 @property bool closeFlag() const; 54 @property void closeFlag(in bool flag); 55 56 @property void onResize(ResizeHandler handler); 57 @property void onMouseMove(MouseHandler handler); 58 @property void onMouseOn(MouseHandler handler); 59 @property void onMouseOff(MouseHandler handler); 60 @property void onKeyOn(KeyHandler handler); 61 @property void onKeyOff(KeyHandler handler); 62 @property void onClose(CloseHandler handler); 63 } 64 65 version (linux) 66 { 67 /// Identifier of the display to use on linux 68 enum LinuxDisplay 69 { 70 /// Instantiate a wayland display 71 /// (no Client Side Decorations at this point) 72 wayland, 73 /// Instantiate an XCB display (X windowing system) 74 xcb, 75 } 76 } 77 78 debug 79 { 80 private enum defaultDebugCb = Yes.debugCallback; 81 private enum defaultValidation = Yes.validation; 82 } 83 else 84 { 85 private enum defaultDebugCb = No.debugCallback; 86 private enum defaultValidation = No.validation; 87 } 88 89 90 /// Options that influence how the display is created, and how it will create 91 /// a Gfx-D instance. 92 struct DisplayCreateInfo 93 { 94 /// Order into which backend creation is tried. 95 /// The first successfully created backend is used. 96 /// If empty, Vulkan is tried first, and OpenGL3 is tried as fallback if enabled and available 97 Backend[] backendCreateOrder; 98 99 version (linux) 100 { 101 /// Order into which display creation is tried on linux. 102 /// The first successfully created display is used. 103 /// If empty, Wayland will be tried if available and VkWayland enabled, and XCB will be used as fallback. 104 LinuxDisplay[] linuxDisplayCreateOrder; 105 } 106 107 /// Whether DebugCallback should be available. Only meaningful with Vulkan backend. 108 Flag!"debugCallback" debugCallbackEnabled = defaultDebugCb; 109 /// Whether validation should be enabled. Only meaningful with Vulkan backend. 110 Flag!"validation" validationEnabled = defaultValidation; 111 } 112 113 /// Create a display for the running platform. 114 /// The display will load a backend instance during startup. 115 /// It will try the backends in the provided loadOrder. 116 /// On linux, more than one display implementation are provided. You may 117 /// use linuxDisplayOrder to choose. The first succesfully created display is returned. 118 Display createDisplay(DisplayCreateInfo createInfo) 119 { 120 if (createInfo.backendCreateOrder.length == 0) 121 { 122 version(GfxGl3) 123 createInfo.backendCreateOrder = [Backend.vulkan, Backend.gl3]; 124 else 125 createInfo.backendCreateOrder = [Backend.vulkan]; 126 } 127 128 version (linux) 129 { 130 import gfx.window.xcb : XcbDisplay; 131 import std.process : environment; 132 133 auto order = createInfo.linuxDisplayCreateOrder; 134 if (order.length == 0) 135 { 136 version (VkWayland) { 137 order = environment["XDG_SESSION_TYPE"] == "wayland" ? [ 138 LinuxDisplay.wayland, LinuxDisplay.xcb 139 ] : [LinuxDisplay.xcb]; 140 } 141 else { 142 order = [LinuxDisplay.xcb]; 143 } 144 } 145 146 foreach (ld; order) 147 { 148 try 149 { 150 final switch (ld) 151 { 152 case LinuxDisplay.wayland: 153 version (VkWayland) { 154 import gfx.window.wayland : WaylandDisplay; 155 156 return new WaylandDisplay(createInfo); 157 } 158 else { 159 assert(false, "Wayland support is disabled"); 160 } 161 case LinuxDisplay.xcb: 162 return new XcbDisplay(createInfo); 163 } 164 } 165 catch (Exception ex) 166 { 167 gfxWindowLog.warningf("Failed to create %s linux display:\n%s", ld, ex.msg); 168 } 169 } 170 throw new Exception("Could not create a functional display"); 171 } 172 else version (Windows) 173 { 174 import gfx.window.win32 : Win32Display; 175 176 return new Win32Display(createInfo); 177 } 178 else 179 { 180 pragma(msg, "Unsupported platform"); 181 assert(false, "Unsupported platform"); 182 } 183 }