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; uint y;
25     KeyMods mods;
26 }
27 
28 alias MouseHandler = void delegate(MouseEvent ev);
29 alias KeyHandler = void delegate(KeyEvent ev);
30 alias ResizeHandler = void delegate(uint width, uint height);
31 alias CloseHandler = bool delegate();
32 
33 interface Display : IAtomicRefCounted
34 {
35     @property Instance instance();
36     @property Window[] windows();
37     Window createWindow(string title="Gfx-d Window");
38     void pollAndDispatch();
39 }
40 
41 interface Window
42 {
43     import gfx.graal.presentation : Surface;
44 
45     void show(uint width, uint height);
46     void close();
47 
48     @property string title();
49     void setTitle(string title);
50 
51     @property Surface surface();
52     @property bool closeFlag() const;
53     @property void closeFlag(in bool flag);
54 
55     @property void onResize(ResizeHandler handler);
56     @property void onMouseMove(MouseHandler handler);
57     @property void onMouseOn(MouseHandler handler);
58     @property void onMouseOff(MouseHandler handler);
59     @property void onKeyOn(KeyHandler handler);
60     @property void onKeyOff(KeyHandler handler);
61     @property void onClose(CloseHandler handler);
62 }
63 
64 /// Identifier of the display to use on linux
65 enum LinuxDisplay {
66     /// Instantiate a wayland display
67     /// (no Client Side Decorations at this point)
68     wayland,
69     /// Instantiate an XCB display (X windowing system)
70     xcb,
71 }
72 
73 debug {
74     private enum defaultDebugCb = Yes.debugCallback;
75     private enum defaultValidation = Yes.validation;
76 }
77 else {
78     private enum defaultDebugCb = No.debugCallback;
79     private enum defaultValidation = No.validation;
80 }
81 
82 /// Options that influence how the display is created, and how it will create
83 /// a Gfx-D instance.
84 struct DisplayCreateInfo
85 {
86     /// Order into which backend creation is tried.
87     /// The first successfully created backend is used.
88     Backend[] backendCreateOrder = [ Backend.vulkan, Backend.gl3 ];
89     /// Order into which display creation is tried on linux.
90     /// The first successfully created display is used.
91     LinuxDisplay[] linuxDisplayCreateOrder = [ LinuxDisplay.wayland, LinuxDisplay.xcb ];
92     /// Whether DebugCallback should be available. Only meaningful with Vulkan backend.
93     Flag!"debugCallback" debugCallbackEnabled = defaultDebugCb;
94     /// Whether validation should be enabled. Only meaningful with Vulkan backend.
95     Flag!"validation" validationEnabled = defaultValidation;
96 }
97 
98 /// Create a display for the running platform.
99 /// The display will load a backend instance during startup.
100 /// It will try the backends in the provided loadOrder.
101 /// On linux, more than one display implementation are provided. You may
102 /// use linuxDisplayOrder to choose. The first succesfully created display is returned.
103 Display createDisplay(DisplayCreateInfo createInfo)
104 {
105     version(linux) {
106         import gfx.window.wayland : WaylandDisplay;
107         import gfx.window.xcb : XcbDisplay;
108 
109         foreach (ld; createInfo.linuxDisplayCreateOrder) {
110             try {
111                 final switch (ld)
112                 {
113                 case LinuxDisplay.wayland:
114                     return new WaylandDisplay(createInfo);
115                 case LinuxDisplay.xcb:
116                     return new XcbDisplay(createInfo);
117                 }
118             }
119             catch (Exception ex) {
120                 gfxWindowLog.warningf(
121                     "Failed to create %s linux display:\n%s", ld, ex.msg
122                 );
123             }
124         }
125         throw new Exception("Could not create a functional display");
126     }
127     else version(Windows) {
128         import gfx.window.win32 : Win32Display;
129         return new Win32Display(createInfo);
130     }
131     else {
132         pragma(msg, "Unsupported platform");
133         assert(false, "Unsupported platform");
134     }
135 }