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 /// Options that influence how the display is created, and how it will create 90 /// a Gfx-D instance. 91 struct DisplayCreateInfo 92 { 93 /// Order into which backend creation is tried. 94 /// The first successfully created backend is used. 95 Backend[] backendCreateOrder = [Backend.vulkan, Backend.gl3]; 96 97 version(linux) 98 { 99 /// Order into which display creation is tried on linux. 100 /// The first successfully created display is used. 101 /// If empty, Wayland will be tried if available, and XCB will be used as fallback. 102 LinuxDisplay[] linuxDisplayCreateOrder; 103 } 104 105 /// Whether DebugCallback should be available. Only meaningful with Vulkan backend. 106 Flag!"debugCallback" debugCallbackEnabled = defaultDebugCb; 107 /// Whether validation should be enabled. Only meaningful with Vulkan backend. 108 Flag!"validation" validationEnabled = defaultValidation; 109 } 110 111 /// Create a display for the running platform. 112 /// The display will load a backend instance during startup. 113 /// It will try the backends in the provided loadOrder. 114 /// On linux, more than one display implementation are provided. You may 115 /// use linuxDisplayOrder to choose. The first succesfully created display is returned. 116 Display createDisplay(DisplayCreateInfo createInfo) 117 { 118 version (linux) 119 { 120 import gfx.window.wayland : WaylandDisplay; 121 import gfx.window.xcb : XcbDisplay; 122 import std.process : environment; 123 124 auto order = createInfo.linuxDisplayCreateOrder; 125 if (order.length == 0) 126 { 127 order = [ 128 environment["XDG_SESSION_TYPE"] == "wayland" ? LinuxDisplay.wayland : LinuxDisplay.xcb 129 ]; 130 } 131 132 foreach (ld; order) 133 { 134 try 135 { 136 final switch (ld) 137 { 138 case LinuxDisplay.wayland: 139 return new WaylandDisplay(createInfo); 140 case LinuxDisplay.xcb: 141 return new XcbDisplay(createInfo); 142 } 143 } 144 catch (Exception ex) 145 { 146 gfxWindowLog.warningf("Failed to create %s linux display:\n%s", ld, ex.msg); 147 } 148 } 149 throw new Exception("Could not create a functional display"); 150 } 151 else version (Windows) 152 { 153 import gfx.window.win32 : Win32Display; 154 155 return new Win32Display(createInfo); 156 } 157 else 158 { 159 pragma(msg, "Unsupported platform"); 160 assert(false, "Unsupported platform"); 161 } 162 }