How to maximize a window using GLUT - glut

Do you know how can I create a maximized Window in GLUT ? (maximized, not full-screen)
I have searched in Google for the solution but I couldn't find it, so I started trying to do it with the Windows API, even tough I later will need to solve it for Linux as well :(
This is what I tried:
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, "GLUT", -1, wString, 4096);
HWND vWnd = FindWindow(wString, NULL);
long currentStyle = GetWindowLong(vWnd, GWL_STYLE);
SetWindowLong(vWnd, GWL_STYLE, currentStyle | WS_MAXIMIZE);
But it is not changing the Window's state. I also tried this:
ShowWindow(vWnd, WS_MAXIMIZE);
Because the documentation (here) states that this function: "Sets the specified window's show state". But I guess it is only for Windows that are not yet visible, and mine was created and shown using GLUT (glutCreateWindow).
Currently there is an answer stating that this cannot be done, but I'd like a confirmation on that from a credible source.
Thanks,

I spent a few hours testing and experimenting different solutions, but at the end what worked was:
/* Maximize window using Windows API after glutCreateWindow() has been called */
HWND win_handle = FindWindow(0, L"Stackoverflow");
if (!win_handle)
{
printf("!!! Failed FindWindow\n");
return -1;
}
SetWindowLong(win_handle, GWL_STYLE, (GetWindowLong(win_handle, GWL_STYLE) | WS_MAXIMIZE));
ShowWindowAsync(win_handle, SW_SHOWMAXIMIZED);
/* Activate GLUT main loop */
glutMainLoop();
It's pretty simple, and I just want to empathize that you can only call glutMainLoop() at the end.
Now, since you are looking for a cross-platform solution I must say that this approach is a terrible idea. Let me share a few other approaches:
Consider using Qt (a cross-platform C++ framework to build applications with GUI). Here's an example;
Consider writing individual platform code to retrieve the current monitor resolution. When glutInitWindowSize() is called, you can pass the right values instead of trying to hack the window to maximize it;
Here's the source code to a minimal, complete and verifiable example (for Windows):
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <GL/glut.h>
int WIDTH = 480;
int HEIGHT = 480;
void initializeGL()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat aspect = (GLfloat) WIDTH / HEIGHT;
gluPerspective(45, aspect, 1.0f, 500.0f);
glViewport(0, 0, WIDTH, HEIGHT);
glMatrixMode(GL_MODELVIEW);
glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void displayGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-3.0f);
glBegin(GL_TRIANGLES);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutCreateWindow("Stackoverflow");
glutDisplayFunc(displayGL);
initializeGL();
/* Maximize window using Windows API */
HWND win_handle = FindWindow(0, L"Stackoverflow");
if (!win_handle)
{
printf("!!! Failed FindWindow\n");
return -1;
}
SetWindowLong(win_handle, GWL_STYLE, (GetWindowLong(win_handle, GWL_STYLE) | WS_MAXIMIZE));
ShowWindowAsync(win_handle, SW_SHOWMAXIMIZED);
/* Activate GLUT main loop */
glutMainLoop();
return 0;
}

As far as I know, there is no platform independent way to maximize windows from glut. One possible work around would be to forget maximizing the window and instead set its size to that of the display. That is, use glutGet(GLUT_SCREEN_WIDTH) and glutGet(GLUT_SCREEN_HEIGHT) to get the size of the display and then use those values in glutInitWindowSize.

Related

Generating relative mouse events on macOS using Core Graphics

I'm using the Core Graphics framework to generate mouse events. I want to be able to move the mouse around normally and also move the mouse inside of an FPS game. The issue I'm having is that these two situations seem to require different events.
I can use the following to move the mouse outside of a game.
// Event source was created with this:
// CGEventSourceCreate(kCGEventSourceStateCombinedSessionState)
CGPoint mouse_location(CGEventSourceRef source) {
CGEventRef event = CGEventCreate(source);
CGPoint loc = CGEventGetLocation(event);
CFRelease(event);
}
void mouse_move_relative(CGEventSourceRef source, int x, int y) {
CGPoint pos = mouse_location(source);
pos.x += x;
pos.y += y;
CGEventRef event = CGEventCreateMouseEvent(source, kCGEventMouseMoved, loc, kCGMouseButtonLeft);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, x);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, y);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
This works outside of a game but inside a game, the mouse seems to hit the edge of the screen and stop. So I tried using deltas without setting the position.
void mouse_move_relative(CGEventSourceRef source, int x, int y) {
CGEventRef event = CGEventCreate(source);
CGEventSetType(event, kCGEventMouseMoved);
CGEventSetIntegerValueField(event, kCGMouseEventButtonNumber, kCGMouseButtonLeft);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, x);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, y);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
This works inside of a game and the mouse doesn't hit the edge of the screen but the mouse doesn't move when outside of the game. If I'm inside a game and open a menu screen, I can't move the mouse anymore. I need two separate code paths or two separate modes for these two situations. I'm trying to avoid having to switch between modes and wondering if this is at all possible.
Can I generate a mouse event that works in both situations?
Maybe there's some way that I tell when the system has gone into relative mouse mode and change the emitted events accordingly? I'm not sure if Core Graphics can do that (or if that even makes sense). Also, I don't fully understand what kCGHIDEventTap and kCGEventSourceStateCombinedSessionState mean. The docs are talking about taps and tables and I don't really get it. Maybe all I need to do is change one of those...?
Note that the above snippets might not be quite right because I'm using a wrapper library in Rust but that's besides the point.
Turned out to be quite simple. All I needed to do was limit the mouse coordinates within the display.
CGDirectDisplayID display = CGMainDisplayID();
size_t width = CGDisplayPixelsWide(display);
size_t height = CGDisplayPixelsHigh(display);
pos.x = min(max(pos.x, 0), width - 1);
pos.y = min(max(pos.y, 0), height - 1);

SDL left mouse button event without press on startup

On the start-up of my SDL program a left mouse button event is registered without me pressing the physical left mouse button. The next physical left button press is not registered. All other keys and buttons work normal. When clicking the .exe the mouse is not located within the location of the window.
Here are the specifications of that event (taken from the SDL_Event struct):
type=1025 (SDL_MOUSEBUTTONDOWN)
timestamp=24
windowID=1
which=0
button=1 (SDL_BUTTON_LEFT)
state=1
clicks=1
x=0
y=0
I am on windows 8.1 compiling with MinGW (gcc version 4.8.1).
I have SDL version 2.0.3
This is my source code:
#include <stdio.h>
#include <SDL.h>
int main(int argc, char* argv[])
{
SDL_Window* window = NULL;
SDL_Surface* screen = NULL;
SDL_Event ev;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0);
screen = SDL_GetWindowSurface(window);
while (1) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT)
return 0;
else {
if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (ev.button.button == SDL_BUTTON_LEFT) {
printf("MOUSE DOWN\n");
printf("type=%d\n", ev.button.type);
printf("timestamp=%d\n", ev.button.timestamp);
printf("windowID=%d\n", ev.button.windowID);
printf("which=%d\n", ev.button.which);
printf("button=%d\n", ev.button.button);
printf("state=%d\n", ev.button.state);
printf("clicks=%d\n", ev.button.clicks);
printf("x=%d\n", ev.button.x);
printf("y=%d\n\n", ev.button.y);
}
}
}
}
SDL_UpdateWindowSurface(window);
SDL_Delay(5);
}
SDL_FreeSurface(screen);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I have tried to solve it by calling SDL_PumpEvents() and SDL_FlushEvents() and while this removed the first (erroneous) event, the second press was still not registered.
Something strange I noticed was that it worked as expected when I opened the program .exe by right clicking and then pressing 'open'.
It'd be very grateful if somebody could shed light on this issue.

CGEventPostToPSN() not working for mouse clicking

I need to send mouse click events to an arbitrary process (not necessarily the front one) without bringing that process's window to the front.
This code works for sending a mouse click and letting the window server send it to whatever process it decides has focus:
#include <ApplicationServices/ApplicationServices.h>
int
main()
{
CGEventRef down, up;
down = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseDown,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
up = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseUp,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
CGEventPost(kCGHIDEventTap, down);
CGEventPost(kCGHIDEventTap, up);
CFRelease(down);
CFRelease(up);
return 0;
}
I can send mouse click events via CGEventPost() just fine, but that requires the target process to have focus (which I am trying to avoid).
I can send keyboard events via CGEventPostToPSN() just fine, and as far as I can tell, mouse move events work too, what I'm having trouble with is mouse down/up events.
This code (pretty much the above, the only difference being that I specify myself which process to send the events to) does not work and I don't even know how to find out where it breaks down.
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h> /* for ProcessSerialNumber stuff */
#include <stdio.h>
int
main()
{
ProcessSerialNumber psn;
CGEventRef down, up;
if (GetFrontProcess(&psn) != noErr) {
printf("Unable to get front process\n");
return 1;
}
down = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseDown,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
up = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseUp,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
CGEventPostToPSN(&psn, down);
CGEventPostToPSN(&psn, up);
CFRelease(down);
CFRelease(up);
return 0;
}
I've been stuck on this for a few days now, and I can't seem to figure it out. According to the documentation this is (as far as I can tell) exactly how it is supposed to be done.
I have tested this code on Snow Leopard and Lion, with the same results.
Could somebody who has had success with clicking via CGEventPostToPSN() please shed some insight on the proper way to accomplish this?

Changing size of glui window

Can anyone tell me if there is any function for changing size of glui window? Also do anyone have any idea about how to add scroll bars to glut window?
Thanx in advance.
did you try glutReshapeWindow?
void glutReshapeWindow(int width, int height);
glutReshapeWindow requests a change in the size of the current window. The width and height parameters are size extents in pixels. The width and height must be positive values.
You didn't specify the version you are using, but v2.2 comes with some examples. If you check example5.cpp and example3.cpp, you'll notice that a GLUI window is created on top of a GLUT window (see the code below):
int main_window = glutCreateWindow( "GLUI Example" ); // Creating GLUT window
// Setting up callbacks
glutDisplayFunc( myGlutDisplay );
GLUI_Master.set_glutReshapeFunc( myGlutReshape ); // Humm, this could be it!
GLUI_Master.set_glutKeyboardFunc( myGlutKeyboard );
GLUI_Master.set_glutSpecialFunc( NULL );
GLUI_Master.set_glutMouseFunc( myGlutMouse );
// Blah Blah to create objects and make it fancy
GLUI* glui = GLUI_Master.create_glui( "GLUI", 0, 400, 500 ); // Create GLUI window
glui->set_main_gfx_window( main_window ); // Associate it with GLUT
So it seems you have 2 options: the first, execute the callback myGlutReshape() directly to see if it resizes the window (specified below):
void myGlutReshape( int x, int y )
{
int tx, ty, tw, th;
GLUI_Master.get_viewport_area( &tx, &ty, &tw, &th );
glViewport( tx, ty, tw, th );
xy_aspect = (float)tw / (float)th;
glutPostRedisplay();
}
or (the second), which is calling glutReshapeWindow() to change the window dimensions (probably followed by glutPostRedisplay()) .
glutReshapeWindow( 800, 600);
glutPostRedisplay(); // This call may or may not be necessary
Notice that glutReshapeWindow() is also executed by the callback, so this cold be the answer after all.

Preserve line width while scaling all points in the context with CGAffineTransform

I have a CGPath in some coordinate system that I'd like to draw. Doing so involves scaling the old coordinate system onto the Context's one. For that purpose, I use CGContextConcatCTM() which does transform all the points as it should. But, as it is a scaling operation, the horizontal/vertical line widths get changed to. E.g. a scale of 10 in x-direction, but of 1 in y-direction would lead to vertical lines being 10 times as thick as horizontal ones. Is there a way to keep the ease of use of translation matrices (e.g. CGAffineTransform) but not scaling line widths at the same time, e.g. a function like CGPathApplyAffineTransformToPoints?
Cheers
MrMage
Do the transform when you add the path, but then remove the transform before you stroke the path. Instead of this:
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 10, 10); // scale path 10x
CGContextAddPath(ctx, somePath);
CGContextSetStrokeColorWithColor(ctx, someColor);
CGContextSetLineWidth(ctx, someWidth); // uh-oh, line width is 10x, too
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx); // back to normal
Do this:
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 10, 10); // scale path 10x
CGContextAddPath(ctx, somePath);
CGContextRestoreGState(ctx); // back to normal
CGContextSetStrokeColorWithColor(ctx, someColor);
CGContextSetLineWidth(ctx, someWidth);
CGContextStrokePath(ctx);
You can use CGPathApply to iterate through the elements in a path. It's a little bit more complex than just a one-liner but if you package it up in a simple helper function, it might be useful for you. Here is one version that creates a new path and transforms it:
typedef struct {
CGMutablePathRef path;
CGAffineTransform transform;
} PathTransformInfo;
static void
PathTransformer(void *info, const CGPathElement *element)
{
PathTransformInfo *transformerInfo = info;
switch (element->type) {
case kCGPathElementMoveToPoint:
CGPathMoveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddLineToPoint:
CGPathAddLineToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddQuadCurveToPoint:
CGPathAddQuadCurveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y);
break;
case kCGPathElementAddCurveToPoint:
CGPathAddCurveToPoint(transformerInfo->path, &transformerInfo->transform,
element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y,
element->points[2].x, element->points[2].y);
break;
case kCGPathElementCloseSubpath:
CGPathCloseSubpath(transformerInfo->path);
break;
}
}
To use it you would do (this is the part I would put inside a helper function):
PathTransformInfo info;
info.path = CGPathCreateMutable();
info.transform = CGAffineTransformMakeScale(2, 1);
CGPathApply(originalPath, &info, PathTransformer);
The transformed path is in info.path at this point.