openFrameworks icon indicating copy to clipboard operation
openFrameworks copied to clipboard

ofAppGLFWWindow issues & improvements

Open dimitre opened this issue 2 years ago • 13 comments

  • [ ] ofSetFullscreen queries all the monitor list more than once (two or three times) for different reasons, we can do a monitor callback and store the data there. I already have the code working for using glfwSetMonitorCallback
  • [ ] There is an erroneous assumption that in macOS you have to set position after setting dimensions in a window, but the issue is that one function calls the other, so I'm proposing setting the window position and dimensions from a rectangle (and getting window rectangle too) https://github.com/openframeworks/openFrameworks/issues/6950
  • [ ] https://github.com/openframeworks/openFrameworks/issues/6952 - updating GLFW to 3.4.0 fixes some stuff
  • [ ] when choosing which monitor the fullscreen will appear I think it makes more sense to get the window rectangle center to check, in the case the window is positioned between two displays
  • [ ] when resizing window to fullscreen the framebuffer appears distorted for one frame. it is easier to see with low framerates like 6 fps. I think this is related as how the viewport is updated only in new frames.
  • [ ] it seems there is no need to call clear on currentRenderer when getBackgroundAuto() == false now. even if it was needed it could be called on resize_cb and not in the third frame after window resized, as it is now.
  • [ ] framebuffer_size_cb calls resize_cb but it is redundant from what I've seen.
  • [ ] If you start a software in fullscreen and toggle fullscreen it never recover dimensions More about this: in setup if your window is set to fullscreen the window settings are set to the fullscreen size like this:
		auto size = getScreenSize();
		settings.setSize(size.x, size.y);

and windowmode is forcefully set to OF_WINDOW in order to trigger the setFullscreen function, if target and settings are the same, the function returns

		settings.windowMode = OF_WINDOW;

and this act overwrites the settings.setSize original values. this can be easily solved by different ways, my suggestion is a second optional parameter in setFullScreen

	void		setFullscreen(bool fullscreen, bool force = false);

which allows OF_FULLSCREEN to be set, even when settings already have the same value

Question: is there a situation where the framebuffer dimensions are different than the window dimensions? I thought it was for different retina resolutions but they are always the same here.

dimitre avatar May 02 '22 23:05 dimitre

Cool! Some of the monitor size / position stuff was really funky due to the way Cocoa used to handle this stuff. It could be that some of these hacks have now been fixed in GLFW itself.

I would just triple check any fixes and run loads of multi monitor tests to test any changes.

I like the idea of the callback ( if it works ), assuming that would get called too if the resolution of a monitor changes?

The center / fullscreen thing is the only one I am unsure about, I would maybe check what other applications do a maybe mirror that?

ofTheo avatar May 03 '22 01:05 ofTheo

the callback is working perfectly, even when you drag the position of monitors a little in system preferences (so I make sure the all monitors rectangle keeps in line) I suggest the center of rectangle when let's say, 90% of the window is on the second monitor (right) and the top left is on the first, it gets fullscreen on second. it's a suggestion only

dimitre avatar May 03 '22 01:05 dimitre

Hey @ofTheo, I've just submitted this PR, still WIP (some cout and comments to debug) https://github.com/openframeworks/openFrameworks/pull/6954 but it already fixes some issues in ofAppGLFWWindow But they are unrelated to Cocoa, more related to the way of treats position / dimensions.

dimitre avatar May 03 '22 01:05 dimitre

Thigs to test: App starting with settings.windowMode = OF_FULLSCREEN; and then toggling fullscreen. with and without settings.setPosition({300, 100}); with and without settings.multiMonitorFullScreen = true;

I've been testing with this skeleton here, fullscreen can be toggled in key 'f'

#pragma once
#include "ofMain.h"

class ofApp : public ofBaseApp{
public:
	void setup() {}

	void update() {}

	void draw() {
		for (int a=0; a<20; a++) {
			ofSetColor(ofColor::fromHsb(a*10, 255, 255));
			ofDrawCircle(200,200,200);
			ofTranslate(400, 0);
		}
		ofSetColor(0,0,250);
		ofDrawRectangle(10, 10, 190, 10);
	}

	void keyPressed(int key) {
		if (key == '1') {
			ofSetFullscreen(true);
		}
		if (key == '2') {
			ofSetFullscreen(false);
		}
		if (key == 'f') {
			ofToggleFullscreen();
			cout << "---- ofToggleFullscreen" << endl;
		}
	}
};

dimitre avatar May 03 '22 02:05 dimitre

About the window center it is useful in this case, window is red, its origin is in first monitor but the body of the window is mostly on second monitor. for simpler cases, smaller windows the center and origin of the window will be in the same monitor Screen Shot 2022-05-03 at 11 26 22

dimitre avatar May 03 '22 14:05 dimitre

Thanks for the example @dimitre. Out of curiosity I tried the macOS native fullscreen window and it does a weird hybrid. For the most part it goes fullscreen on the window the top left corner is on, but if the window top left is past 95% ( approx ) the width of the screen it goes fullscreen on the second monitor. So not particularly helpful. 🙂

The reason I was cautious about this feature is I know a lot of our projects have very specific fullscreen behavior and I am wondering if the proposed approach would break anything there. pinging @NickHardeman to take a look.

ofTheo avatar May 03 '22 16:05 ofTheo

Yeah for me it is the same, it is already working great with origin. I did the same test out of curiosity, and marking with a rectangle the middle of the window. macOS native fullscreen (green button) behaves considering the monitor the center of the window is too.

dimitre avatar May 03 '22 16:05 dimitre

there is another issue I've noticed, hard to reproduce. you position your window in arbitrary place, like bleeding outside the window, and when toggling fullscreen it changes shape first and maybe the OS decides to move your window once before you set position, triggering twice the event resize_cb, and this leads to the window gaining the proportions of fullscreen even after fullscreen is triggered.

two solutions: setting position before shape, or storing the frame number resize_cb is called and avoid triggering twice the same frame (untested)

dimitre avatar May 03 '22 17:05 dimitre

Yes a lot of our projects use the top left origin for window placement and which monitor to go fullscreen. It could be changed to use the center point, but would cause different behavior in our previous projects since we often have 4+ displays.

NickHardeman avatar May 03 '22 17:05 NickHardeman

listVideoModes function doesn't work because it needs a monitor as a parameter. I'm proposing this, so it interates each display and list available resolutions and refreshrates

void ofAppGLFWWindow::listVideoModes(){
	glfwInit();
	int numModes;
	int count;
	const auto monitors = glfwGetMonitors(&count);
	for(int a = 0; a<count; a++){
		ofLogNotice() << glfwGetMonitorName(monitors[a]);
		const GLFWvidmode * vidModes = glfwGetVideoModes(monitors[a], &numModes );
		for(int i=0; i<numModes; i++){
			ofLogNotice() << vidModes[i].width << " x " << vidModes[i].height
			<< " : "
			<< vidModes[i].redBits+vidModes[i].greenBits+vidModes[i].blueBits << "bit"
			<< " : " << vidModes[i].refreshRate << "hz";
		}
	}
}

dimitre avatar May 04 '22 00:05 dimitre

There is a mix between framesize and window size in OF code. I know both used to be the same before retina but temporary fixes created a confusion there. the window should be treated without pixelScreenCoordScale for window purposes, it works well both with High Resolution Capable = YES and NO I'm testing with multiple monitors, mixing retina and regular resolutions.

the problem is other parts of OF uses a function called getWindowSize which in turn have to consider pixelScreenCoordScale to calculate matrixes and so.

I think we should reconsider and maybe creating a function called getFramebufferSize, to use in other parts of OF so both subjects are correctly separated from now on (window and framebuffer / renderSurface).

dimitre avatar May 04 '22 16:05 dimitre

There is a function in GLFW to get the pixelScreenCoordScale, like this:

	float xscale, yscale;
	glfwGetWindowContentScale(windowP_, &xscale, &yscale);
	pixelScreenCoordScale = xscale;

potentially closes this one

  • https://github.com/openframeworks/openFrameworks/issues/6902

dimitre avatar May 10 '22 19:05 dimitre

I think defines in ofMain.h ofConstants.h can be improved. tidy up and documented.

dimitre avatar Jun 28 '22 20:06 dimitre