Misleading API documentation

With the following simple test code, I can observe behavior that is not consistent with what the API documentation led me to believe:

#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void getTimestamp(char buf[32]) {
	time_t rawNow;
	time(&rawNow);

	struct tm localNow;
	localtime_s(&localNow, &rawNow);

	strftime(buf, 32, "%c", &localNow);
}

void window_size_callback(GLFWwindow *window, int callbackwidth, int callbackheight) {
	char timestamp[32];
	getTimestamp(timestamp);

	int width, height;
	glfwGetWindowSize(window, &width, &height);

	if (printf("%s\nWindow size as reported to callback function: %dx%d\nWindow size according to glfwGetWindowSize: %dx%d\n\n", timestamp, callbackwidth, callbackheight, width, height) < 0)
		perror("printf");
}

void framebuffer_size_callback(GLFWwindow *window, int callbackwidth, int callbackheight) {
	char timestamp[32];
	getTimestamp(timestamp);

	int width, height;
	glfwGetFramebufferSize(window, &width, &height);

	if (printf("%s\nFrame buffer size as reported to callback function: %dx%d\nFrame buffer size according to glfwGetFramebufferSize: %dx%d\n\n", timestamp, callbackwidth, callbackheight, width, height) < 0)
		perror("printf");
}

int main() {
	if (!glfwInit()) {
		if (fprintf(stderr, "Failed to initialize GLFW.\n") < 0)
			perror("fprintf");
		exit(EXIT_FAILURE);
	}

	GLFWmonitor *primarymonitor = glfwGetPrimaryMonitor();
	const GLFWvidmode *videomode = glfwGetVideoMode(primarymonitor);

	glfwWindowHint(GLFW_RED_BITS, videomode->redBits);
	glfwWindowHint(GLFW_GREEN_BITS, videomode->greenBits);
	glfwWindowHint(GLFW_BLUE_BITS, videomode->blueBits);
	glfwWindowHint(GLFW_REFRESH_RATE, videomode->refreshRate);
	GLFWwindow *window = glfwCreateWindow(videomode->width, videomode->height, "Test", primarymonitor, NULL);
	if (!window) {
		if (fprintf(stderr, "Failed to open GLFW window.") < 0)
			perror("fprintf");
		exit(EXIT_FAILURE);
	}
	glfwMakeContextCurrent(window);

	glfwSetWindowSizeCallback(window, window_size_callback);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	{
		char timestamp[32];
		getTimestamp(timestamp);

		int wwidth, wheight;
		glfwGetWindowSize(window, &wwidth, &wheight);

		int fbwidth, fbheight;
		glfwGetFramebufferSize(window, &fbwidth, &fbheight);

		if (printf("Started test at %s\nInitial window size: %dx%d\nInitial frame buffer size: %dx%d\n\n", timestamp, wwidth, wheight, fbwidth, fbheight) < 0)
			perror("printf");
	}

	do {
		glfwPollEvents();
	} while (!glfwWindowShouldClose(window));
}

My experiment is to start the program in Windows 7, go to the Control Panel and change the primary monitor from landscape to portrait, and then restore focus to the test program. Here is what I get:

Started test at 04/17/16 10:57:26
Initial window size: 1920x1200
Initial frame buffer size: 1920x1200

04/17/16 10:57:43
Frame buffer size as reported to callback function: 0x0
Frame buffer size according to glfwGetFramebufferSize: 0x0

04/17/16 10:57:43
Window size as reported to callback function: 0x0
Window size according to glfwGetWindowSize: 0x0

04/17/16 10:58:03
Frame buffer size as reported to callback function: 1200x1920
Frame buffer size according to glfwGetFramebufferSize: 1200x1920

04/17/16 10:58:03
Window size as reported to callback function: 1200x1920
Window size according to glfwGetWindowSize: 1200x1920

04/17/16 10:58:03
Frame buffer size as reported to callback function: 1920x1200
Frame buffer size according to glfwGetFramebufferSize: 1200x1920

04/17/16 10:58:03
Window size as reported to callback function: 1920x1200
Window size according to glfwGetWindowSize: 1200x1920

So you see, restoring focus to the test program results in two calls to each of the two callback functions: one to go back from 0x0 to 1920x1200, and another to change to 1200x1920. Unfortunately, the one that reports 1200x1920 comes first, followed by 1920x1200. There must be something wrong; if nothing else, the API documentation is misleading where it gives this example frame buffer callback function:

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

The above function does not work. Here is my attempt at it:

void framebuffer_size_callback(GLFWwindow* window, int eventwidth, int eventheight)
{
	int width, height;
	glfwGetFramebufferSize(window, &width, &height);

	glViewport(0, 0, width, height);
}

A window size callback has to be written with the same consideration in mind, that calls may happen in no particular order.

It looks like this is a bug and not a documentation issue, caused by the fact Microsoft are passing the wrong size to WM_SIZE for fullscreen apps when the orientation of a monitor is switched.

If you’re on Github you can file the bug here: https://github.com/glfw/glfw/issues, or I can file the bug for you if you like. I have a local fix which I’ll do a bit more testing on.

You are welcome to file the bug for me, as you seem to have a more complete idea of what is going on and what to do about it.

I’ve filed the issue here:

This should be fixed now. Thank you for reporting it!

https://github.com/glfw/glfw/commit/e640d840b710c79074cc99766222f86bda94f417

1 Like