1 /// Simple example of a GLFW application that creates a black window and reads some input and output
2 ///
3 /// Does not load OpenGL / Vulkan.
4 module app;
5 
6 import glfw3.api;
7 import core.stdc.stdio;
8 
9 int main() {
10 	GLFWwindow* window;
11 	glfwSetErrorCallback(&errorCallback);
12 
13 	if (!glfwInit()) {
14 		return -1;
15 	}
16 	scope(exit) glfwTerminate();
17 
18 	printClipboardState();
19 	printJoystickState();
20 	printMonitorState();
21 
22 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
23 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
24 
25 	WindowData data;
26 	window = glfwCreateWindow(800, 600, "Black window - press F11 to toggle fullscreen, press ESC to exit", null, null);
27 	scope(exit) glfwDestroyWindow(window);
28 	if (!window) {
29 		glfwTerminate();
30 		return -1;
31 	}
32 	glfwSetWindowUserPointer(window, &data);
33 
34 	glfwSetKeyCallback(window, &keyCallback);
35 	glfwMakeContextCurrent(window);
36 	glfwSwapInterval(1); // Set vsync on so glfwSwapBuffers will wait for monitor updates.
37 	// note: 1 is not a boolean! Set e.g. to 2 to run at half the monitor refresh rate.
38 
39 	double oldTime = glfwGetTime();
40 	while (!glfwWindowShouldClose(window)) {
41 		const newTime = glfwGetTime();
42 		const elapsedTime = newTime - oldTime;
43 		oldTime = newTime;
44 
45 		glfwSwapBuffers(window);
46 		glfwPollEvents();
47 	}
48 	return 0;
49 }
50 
51 /// Data stored in the window's user pointer
52 ///
53 /// Note: assuming you only have one window, you could make these global variables.
54 struct WindowData {
55 	// These are stored in the window's user data so that when exiting fullscreen,
56 	// the window can be set to the position where it was before entering fullscreen
57 	// instead of resetting to e.g. (0, 0)
58 	int xpos;
59 	int ypos;
60 	int width;
61 	int height;
62 
63 	@nogc nothrow void update(GLFWwindow* window) {
64 		glfwGetWindowPos(window, &this.xpos, &this.ypos);
65 		glfwGetWindowSize(window, &this.width, &this.height);
66 	}
67 }
68 
69 extern(C) @nogc nothrow void errorCallback(int error, const(char)* description) {
70 	fprintf(stderr, "Error: %s\n", description);
71 }
72 
73 extern(C) @nogc nothrow void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
74 	if (action == GLFW_PRESS) {
75 		switch (key) {
76 			case GLFW_KEY_ESCAPE:
77 				glfwSetWindowShouldClose(window, GLFW_TRUE);
78 				break;
79 			case GLFW_KEY_F11:
80 				toggleFullScreen(window);
81 				break;
82 			default: break;
83 		}
84 	}
85 }
86 
87 @nogc nothrow void toggleFullScreen(GLFWwindow* window) {
88 	WindowData* wd = cast(WindowData*) glfwGetWindowUserPointer(window);
89 	assert(wd);
90 	if (glfwGetWindowMonitor(window)) {
91 		glfwSetWindowMonitor(window, null, wd.xpos, wd.ypos, wd.width, wd.height, 0);
92 	} else {
93 		GLFWmonitor* monitor = glfwGetPrimaryMonitor();
94 		if (monitor) {
95 			const GLFWvidmode* mode = glfwGetVideoMode(monitor);
96 			wd.update(window);
97 			glfwSetWindowMonitor(window, monitor, 0, 0, mode.width, mode.height, mode.refreshRate);
98 		}
99 	}
100 }
101 
102 void printClipboardState() {
103 	printf("Clipboard contents: `%s.80`\n", glfwGetClipboardString(null));
104 }
105 
106 void printMonitorState() {
107 	int monitorsLength;
108 	GLFWmonitor** monitorsPtr = glfwGetMonitors(&monitorsLength);
109 	GLFWmonitor*[] monitors = monitorsPtr[0..monitorsLength];
110 
111 	foreach(GLFWmonitor* mt; monitors) {
112 		int widthMM, heightMM;
113 		int xpos, ypos, width, height;
114 		glfwGetMonitorPos(mt, &xpos, &ypos);
115 		glfwGetMonitorPhysicalSize(mt, &widthMM, &heightMM);
116 		const(GLFWvidmode)* mode = glfwGetVideoMode(mt);
117 		printf("Monitor `%s` has size %dx%d mm\n", glfwGetMonitorName(mt), widthMM, heightMM);
118 		printf("  current video mode: %dx%d %dHz r%dg%db%d\n", mode.width, mode.height, mode.refreshRate, mode.redBits, mode.greenBits, mode.blueBits);
119 		printf("  position: %d, %d\n", xpos, ypos);
120 		glfwGetMonitorWorkarea(mt, &xpos, &ypos, &width, &height);
121 		printf("  work area: %d, %d to %d, %d\n", xpos, ypos, width, height);
122 	}
123 }
124 
125 void printJoystickState() {
126 	for (int js = GLFW_JOYSTICK_1; js <= GLFW_JOYSTICK_LAST; js++) {
127 		if (glfwJoystickPresent(js)) {
128 			printf("Joystick %d has name `%s` and GUID `%s`\n", js, glfwGetJoystickName(js), glfwGetJoystickGUID(js));
129 			int buttonsLength, axesLength, hatsLength;
130 			const(ubyte)* buttonsPtr = glfwGetJoystickButtons(js, &buttonsLength);
131 			const(float)* axesPtr = glfwGetJoystickAxes(js, &axesLength);
132 			const(ubyte)* hatsPtr = glfwGetJoystickHats(js, &hatsLength);
133 			const(ubyte)[] buttons = buttonsPtr[0..buttonsLength];
134 			const(float)[] axes = axesPtr[0..axesLength];
135 			const(ubyte)[] hats = hatsPtr[0..hatsLength];
136 
137 			if (glfwJoystickIsGamepad(js)) {
138 				printf("  It is a gamepad with name `%s`\n", glfwGetGamepadName(js));
139 				GLFWgamepadstate state;
140 				if (glfwGetGamepadState(js, &state)) {
141 					//
142 					printf("Left stick: %f,%f\n", state.axes[GLFW_GAMEPAD_AXIS_LEFT_X], state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]);
143 					printf("A: %d, B: %d\n", state.buttons[GLFW_GAMEPAD_BUTTON_A], state.buttons[GLFW_GAMEPAD_BUTTON_B]);
144 				}
145 			}
146 		} else {
147 			//printf("Joystick %d not present\n", js);
148 		}
149 	}
150 }