I've got class (called BorderWindow) which is in fact wrap around GtkWidget. This class represents border around specific application's window (lets say Terminal window, for instance). Inside of BorderWindow constructor I create timer so every second BorderWindow::ClockTick function is called.
Inside of this function border size (which is actually GtkWidget) is compared with bound application's window (Terminal in our case) and if it differs gtk_window_resize is called. However, if I call then gtk_window_get_size it returns old values.
gboolean BorderWindow::ClockTick(gpointer data)
{
auto that = reinterpret_cast<BorderWindow*>(data);
int x = 0, y = 0;
GtkWindow* pWindow = GTK_WINDOW(that->m_borderWindowHandle);
gtk_window_get_size(pWindow, &x, &y);
DUMPER_INFO("curr size: %dx%d; new size: %dx%d", x, y, that->m_windowRect.width, that->m_windowRect.height); // added for debug
if(x != that->m_windowRect.width || y != that->m_windowRect.height)
{
gtk_window_resize(pWindow, that->m_windowRect.width, that->m_windowRect.height);
that->CreateBorder();
GtkWindow* pWindow = GTK_WINDOW(that->m_borderWindowHandle); // added for debug
gtk_window_get_size(pWindow, &x, &y); // added for debug
DUMPER_INFO("after resize: %dx%d", x, y); // added for debug
}
gtk_window_get_position(pWindow, &x, &y);
if(x != that->m_windowRect.x || y != that->m_windowRect.y)
{
gtk_window_move(pWindow, that->m_windowRect.x, that->m_windowRect.y);
}
gdk_window_invalidate_rect(gtk_widget_get_window(that->m_borderWindowHandle), nullptr, FALSE);
that->m_highlightFrame = !that->m_highlightFrame;
return TRUE;
}
Here is debug output
20-05-19 11:24:40.294 [139856177248000] INFO 1537 %% - static gboolean LinuxBorderWindow::ClockTick(gpointer): curr size: 734x540; new size: 1024x706
20-05-19 11:24:40.295 [139856177248000] INFO 1537 %% - static gboolean LinuxBorderWindow::ClockTick(gpointer): after resize: 734x540
So as you can see, the window wasn't resized.
This code snippet works fine for xfce and Unity DEs, but doesn't work for GNOME (and GNOME classic).
Could anyone explain what I'm doing wrong and how to resize window for GNOME DE?
Thanks.
Related
I have implemented a Xdnd drop support implementation in VTK some time ago. It was working great except with Thunar file manager. All other file managers were working fine at the time. We dismissed this limitation a Thunar bug at the time.
The feature I implemented was very simple:
Set the window of the application to be XdndAware
Receive the position message and respond that we are ready to receive
Receive the drop mesage and request a selection
Receive the selection notify and recover the URI
Convert the URI into something we can work with
Nothing fancy, I did not even touch the list type.
Fast forward a few years and now dolphin users cannot drop files correctly into our application. The URI is always the first file dropped since dolphin was started. Restarting our application has no effect. No bug at all with pcmanfm.
This is not a dolphin bug and files can be dropped on blender or firefox from dolphin without issues.
So there must be a bug in our implementation, but I've been staring at the code for some time and everything I tried had no effect, except for breaking Xdnd support completely.
Here are the interesting part of the implementation:
//------------------------------------------------------------------------------
vtkXRenderWindowInteractor::vtkXRenderWindowInteractor()
{
this->Internal = new vtkXRenderWindowInteractorInternals;
this->DisplayId = nullptr;
this->WindowId = 0;
this->KillAtom = 0;
this->XdndSource = 0;
this->XdndPositionAtom = 0;
this->XdndDropAtom = 0;
this->XdndActionCopyAtom = 0;
this->XdndStatusAtom = 0;
this->XdndFinishedAtom = 0;
}
[...]
//------------------------------------------------------------------------------
void vtkXRenderWindowInteractor::Enable()
{
// avoid cycles of calling Initialize() and Enable()
if (this->Enabled)
{
return;
}
// Add the event handler to the system.
// If we change the types of events processed by this handler, then
// we need to change the Disable() routine to match. In order for Disable()
// to work properly, both the callback function AND the client data
// passed to XtAddEventHandler and XtRemoveEventHandler must MATCH
// PERFECTLY
XSelectInput(this->DisplayId, this->WindowId,
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask |
StructureNotifyMask | EnterWindowMask | LeaveWindowMask | PointerMotionHintMask |
PointerMotionMask);
// Setup for capturing the window deletion
this->KillAtom = XInternAtom(this->DisplayId, "WM_DELETE_WINDOW", False);
XSetWMProtocols(this->DisplayId, this->WindowId, &this->KillAtom, 1);
// Enable drag and drop
Atom xdndAwareAtom = XInternAtom(this->DisplayId, "XdndAware", False);
char xdndVersion = 5;
XChangeProperty(this->DisplayId, this->WindowId, xdndAwareAtom, XA_ATOM, 32, PropModeReplace,
(unsigned char*)&xdndVersion, 1);
this->XdndPositionAtom = XInternAtom(this->DisplayId, "XdndPosition", False);
this->XdndDropAtom = XInternAtom(this->DisplayId, "XdndDrop", False);
this->XdndActionCopyAtom = XInternAtom(this->DisplayId, "XdndActionCopy", False);
this->XdndStatusAtom = XInternAtom(this->DisplayId, "XdndStatus", False);
this->XdndFinishedAtom = XInternAtom(this->DisplayId, "XdndFinished", False);
this->Enabled = 1;
this->Modified();
}
[...]
//------------------------------------------------------------------------------
void vtkXRenderWindowInteractor::DispatchEvent(XEvent* event)
{
int xp, yp;
switch (event->type)
{
[...]
// Selection request for drag and drop has been delivered
case SelectionNotify:
{
// Sanity checks
if (!event->xselection.property || !this->XdndSource)
{
return;
}
// Recover the dropped file
char* data = nullptr;
Atom actualType;
int actualFormat;
unsigned long itemCount, bytesAfter;
XGetWindowProperty(this->DisplayId, event->xselection.requestor, event->xselection.property,
0, LONG_MAX, False, event->xselection.target, &actualType, &actualFormat, &itemCount,
&bytesAfter, (unsigned char**)&data);
// Conversion checks
if ((event->xselection.target != AnyPropertyType && actualType != event->xselection.target) ||
itemCount == 0)
{
return;
}
// Recover filepaths from uris and invoke DropFilesEvent
std::stringstream uris(data);
std::string uri, protocol, hostname, filePath;
std::string unused0, unused1, unused2, unused3;
vtkNew<vtkStringArray> filePaths;
while (std::getline(uris, uri, '\n'))
{
if (vtksys::SystemTools::ParseURL(
uri, protocol, unused0, unused1, hostname, unused3, filePath, true))
{
if (protocol == "file" && (hostname.empty() || hostname == "localhost"))
{
// The uris can be crlf delimited, remove ending \r if any
if (filePath.back() == '\r')
{
filePath.pop_back();
}
// The extracted filepath miss the first slash
filePath.insert(0, "/");
filePaths->InsertNextValue(filePath);
}
}
}
this->InvokeEvent(vtkCommand::DropFilesEvent, filePaths);
XFree(data);
// Inform the source the the drag and drop operation was sucessfull
XEvent reply;
memset(&reply, 0, sizeof(reply));
reply.type = ClientMessage;
reply.xclient.window = event->xclient.data.l[0];
reply.xclient.message_type = this->XdndFinishedAtom;
reply.xclient.format = 32;
reply.xclient.data.l[0] = this->WindowId;
reply.xclient.data.l[1] = itemCount;
reply.xclient.data.l[2] = this->XdndActionCopyAtom;
XSendEvent(this->DisplayId, this->XdndSource, False, NoEventMask, &reply);
XFlush(this->DisplayId);
this->XdndSource = 0;
}
break;
case ClientMessage:
{
if (event->xclient.message_type == this->XdndPositionAtom)
{
// Drag and drop event inside the window
// Recover the position
int xWindow, yWindow;
int xRoot = event->xclient.data.l[2] >> 16;
int yRoot = event->xclient.data.l[2] & 0xffff;
Window root = DefaultRootWindow(this->DisplayId);
Window child;
XTranslateCoordinates(
this->DisplayId, root, this->WindowId, xRoot, yRoot, &xWindow, &yWindow, &child);
// Convert it to VTK compatible location
double location[2];
location[0] = static_cast<double>(xWindow);
location[1] = static_cast<double>(this->Size[1] - yWindow - 1);
this->InvokeEvent(vtkCommand::UpdateDropLocationEvent, location);
// Reply that we are ready to copy the dragged data
XEvent reply;
memset(&reply, 0, sizeof(reply));
reply.type = ClientMessage;
reply.xclient.window = event->xclient.data.l[0];
reply.xclient.message_type = this->XdndStatusAtom;
reply.xclient.format = 32;
reply.xclient.data.l[0] = this->WindowId;
reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
reply.xclient.data.l[3] = 0;
reply.xclient.data.l[4] = this->XdndActionCopyAtom;
XSendEvent(this->DisplayId, event->xclient.data.l[0], False, NoEventMask, &reply);
XFlush(this->DisplayId);
}
else if (event->xclient.message_type == this->XdndDropAtom)
{
// Item dropped in the window
// Store the source of the drag and drop
this->XdndSource = event->xclient.data.l[0];
// Ask for a conversion of the selection. This will trigger a SelectioNotify event later.
Atom xdndSelectionAtom = XInternAtom(this->DisplayId, "XdndSelection", False);
XConvertSelection(this->DisplayId, xdndSelectionAtom,
XInternAtom(this->DisplayId, "UTF8_STRING", False), xdndSelectionAtom, this->WindowId,
CurrentTime);
}
else if (static_cast<Atom>(event->xclient.data.l[0]) == this->KillAtom)
{
this->ExitCallback();
}
}
break;
}
}
[...]
And header:
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderingUIModule.h" // For export macro
#include <X11/Xlib.h> // Needed for X types in the public interface
class vtkCallbackCommand;
class vtkXRenderWindowInteractorInternals;
class VTKRENDERINGUI_EXPORT vtkXRenderWindowInteractor : public vtkRenderWindowInteractor
{
public:
static vtkXRenderWindowInteractor* New();
vtkTypeMacro(vtkXRenderWindowInteractor, vtkRenderWindowInteractor);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Initializes the event handlers without an XtAppContext. This is
* good for when you don't have a user interface, but you still
* want to have mouse interaction.
*/
void Initialize() override;
/**
* Break the event loop on 'q','e' keypress. Want more ???
*/
void TerminateApp() override;
/**
* Run the event loop and return. This is provided so that you can
* implement your own event loop but yet use the vtk event handling as
* well.
*/
void ProcessEvents() override;
///#{
/**
* Enable/Disable interactions. By default interactors are enabled when
* initialized. Initialize() must be called prior to enabling/disabling
* interaction. These methods are used when a window/widget is being
* shared by multiple renderers and interactors. This allows a "modal"
* display where one interactor is active when its data is to be displayed
* and all other interactors associated with the widget are disabled
* when their data is not displayed.
*/
void Enable() override;
void Disable() override;
///#}
/**
* Update the Size data member and set the associated RenderWindow's
* size.
*/
void UpdateSize(int, int) override;
/**
* Re-defines virtual function to get mouse position by querying X-server.
*/
void GetMousePosition(int* x, int* y) override;
void DispatchEvent(XEvent*);
protected:
vtkXRenderWindowInteractor();
~vtkXRenderWindowInteractor() override;
/**
* Update the Size data member and set the associated RenderWindow's
* size but do not resize the XWindow.
*/
void UpdateSizeNoXResize(int, int);
// Using static here to avoid destroying context when many apps are open:
static int NumAppInitialized;
Display* DisplayId;
Window WindowId;
Atom KillAtom;
int PositionBeforeStereo[2];
vtkXRenderWindowInteractorInternals* Internal;
// Drag and drop related
Window XdndSource;
Atom XdndPositionAtom;
Atom XdndDropAtom;
Atom XdndActionCopyAtom;
Atom XdndStatusAtom;
Atom XdndFinishedAtom;
///#{
/**
* X-specific internal timer methods. See the superclass for detailed
* documentation.
*/
int InternalCreateTimer(int timerId, int timerType, unsigned long duration) override;
int InternalDestroyTimer(int platformTimerId) override;
///#}
void FireTimers();
/**
* This will start up the X event loop and never return. If you
* call this method it will loop processing X events until the
* application is exited.
*/
void StartEventLoop() override;
private:
vtkXRenderWindowInteractor(const vtkXRenderWindowInteractor&) = delete;
void operator=(const vtkXRenderWindowInteractor&) = delete;
};
#endif
The complete file can be seen here:
https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/UI/vtkXRenderWindowInteractor.cxx
You can follow my train of thoughts and debugs here:
https://gitlab.kitware.com/f3d/f3d/-/issues/228
To test this code, a simple way is to use F3D has it is using the dropped file, but a simple VTK application should work as well:
https://gitlab.kitware.com/f3d/f3d
Current Dolphin issue
From some testing, the issue is with the preparation and sending of the XdndFinished ClientMessage back to the drag and drop source when handling the SelectionNotify event.
Instead of:
reply.xclient.window = event->xclient.data.l[0];
the line should be:
reply.xclient.window = this->XdndSource;
This aligns the XClientMessageEvent window member with the target window argument to XSendEvent. This is probably a simple copy-paste error, as xclient isn't valid for the SelectionNotify event type. Most likely the actual value of window was not previously being checked, but that has been changed recently, hence the error.
The spec covers this quite well, and also raises a couple of other things to consider:
For data.l[1]: "Bit 0 is set if the current target accepted the drop and successfully performed the accepted drop action. (new in version 5)", so using itemCount as a value will technically be incorrect whenever the count is even
If the handling of XdndPosition doesn't need to actually track where the current position is (i.e. if you are just using the entire window as a drop target), you may be able to get away with sending the XdndStatus in response to the XdndEnter message
Previous Thunar issue
Looking into this further, I did some troubleshooting regarding the previous issue with Thunar, and it boils down to the code handling XdndDrop assuming that the format of the incoming data can be converted to UTF8_STRING. This diff for GLFW handles almost the exact same issue.
If, when handling the XdndEnter message, you inspect the values of xclient.data.l[2] through xclient.data.l[4] you can see that Dolphin reports supporting the following formats:
text/uri-list
text/x-moz-url
text/plain
whereas Thunar only supports the following:
text/uri-list
The simplest solution is to:
Keep track of a supported format when handling XdndEnter
Provide this format to XConvertSelection when handling XdndDrop (instead of UTF8_STRING)
Handle the format appropriately when handling the SelectionNotify event
To be more complete, if bit 0 of xclient.data.l[1] is set on the XdndEnter message, you should get the XdndTypeList property of the drag and drop source window and based the format selection on that, instead of the formats contained in the message itself.
So I am making a game for a school project. You might be familiar with this one. Its Arkanoid, or the game in which a ball is used to destroy bricks and is deflected on by a platform.
Currently I am stuck at a point. I have got an idea of how to move my platform using _getch(), but when I put in a ball it is also moving on a key press. I cant figure out on how to run it simultaneously with or without any key presses. Or if there is way to skip a key press every time until it is registered.
Here is my code so far. The movement of the ball is not complete it is just a prototype right now. Any help would be appreciated.
I am using a graphics library provided by my school but you can use the C++ graphics library.
#include <iostream>
#include "myconsole.h"
#include "mygraphics.h"
#include <conio.h>
#include <string>
using namespace std;
void rect() {
COLORREF White = RGB(255, 255, 255);
COLORREF Blue = RGB(135, 206, 235);
// x1 y x2 y
myRect(400, 475, 550, 480, Blue, Blue);
_getch();
}
void circle() {
COLORREF Red = RGB(255, 0, 0);
myEllipse(0, 50, 300, 350, Red, Red);
_getch();
}
void moverect() {
COLORREF White = RGB(255, 255, 255);
COLORREF Blue = RGB(135, 206, 235);
char _x;
const char _r = 'd';
const char _l = 'a';
int x1 = 400;
int x2 = 550;
int by1 = 455;
int by2 = 475;
int m = 48;
while (1) {
_x = _getch();
system("cls");
if (_x == _r) {
if (x2 < 970) {
x1 += 10;
x2 += 10;
for (int i = 0; i < 10; i++) {
myRect(x1++, 475, x2++, 480, Blue, Blue);
}
}
else
myRect(x1, 475, x2, 480, Blue, Blue);
}
else if (_x == _l) {
if (x1 > 0) {
x1 -= 10;
x2 -= 10;
for (int i = 0; i < 10; i++) {
myRect(x1--, 475, x2--, 480, Blue, Blue);
}
}
else
myRect(x1, 475, x2, 480, Blue, Blue);
}
myEllipse(463, by1 -= 10, 487, by2 -= 10, White, White);
}
}
int main() {
{
moverect();
return 0;
}
}
Since you seem to be using Windows and Microsoft Visual C++ you could use _kbhit(), which will tell you if a key is pressed. Note that this is not standard C++.
This might look like:
if (_kbhit()) {
_x = _getch();
}
else {
_x = -1;
}
Alternatively, others mentioned threads, although John also noted that _getch() is also not standard C++, but I thought introducing some of the concepts of threads might be helpful.There are multiple ways to do it with threads but I will show what I consider to be the easiest way.
First we will create a class, this is to hide a variable that contains the latest character. We want it hidden so that when it is read from the main thread, the latest character is consumed (set to -1) so that when we next call the function, if another character is yet to be input the function will return -1.
Note that if two threads read and write from a variable at the same time, undefined behaviour occurs, for this reason we are going to use an atomic variable as it is defined when two threads try to access it at the same time. Alternatively mutexes exist, they are slower but allow for more complex types to be locked and unlocked so that only one thread may access them at a time.
class LatestChar {
public:
/// initialize latest character to -1
LatestChar() :
latest_char{ -1 }
{}
/// returns latest character or -1 if there is no latest character
int getLatestChar() {
// get latest character
int temp_latest_char{ latest_char };
// consume latest character (so if this is called again, -1 is returned)
latest_char = -1;
// return latest character
return temp_latest_char;
}
private:
/// equal to latest character or -1 when there is no character to get
///
/// this is atomic because it might be read from the main thread at the same
/// time it is written from the getch thread.
std::atomic_int latest_char;
};
Next we need to create the thread that calls _getch(). This is a member variable and will be declared in the constuctor, where it will start running and getting the latest character and repeating.
class LatestChar {
public:
/// initialize latest character to -1,
/// and starts thread that gets the latest character
LatestChar() :
...,
getch_thread([this] {
while (true) {
latest_char = _getch();
}
})
{}
...
private:
...
/// this thread loops until told to stop, and updates the latest character
std::thread getch_thread;
};
Almost done, we now need to rejoin the thread at the end of the program, we will use another atomic variable, this time a boolean, to represent a flag to say "Hey, we are done getting characters, finish what you are doing and join back up with the main thread.
Note that the getch thread will only check this after it reads a character, so when you close your program you might need to input one more character, the alternative is to call something like std::terminate() which will stop the entire program forcefully, which is probably not desired when it can be avoided.
We will initialize the flag to false in the constructor (make sure it is initialized before the getch thread is, otherwise the getch thread might check the value before it has been set to false. The order is they are initialized is the same order they are declared in the class definition.), check it in the thread, and set it to true in the destructor and then also call the join function which will wait until the thread is finished and connect join it back into main.
class LatestChar {
public:
/// initialize latest character to -1, end thread flag to false,
/// and starts thread that gets the latest character
LatestChar() :
...,
end_thread{ false },
getch_thread([this] {
while (!end_thread) {
latest_char = _getch();
}
})
{}
/// sets end thread flag to true and joins getch thread with main thread
~LatestChar() {
end_thread = true;
getch_thread.join();
}
...
private:
...
/// this flag tells the getch thread to stop, like at the end of a program,
/// _getch() will need to receive a character before this is checked
///
/// this is atomic because it might be read from the getch thread at the
/// same time it is written from the main thread.
///
/// make sure this is initialized before the getch thread begins
std::atomic_bool end_thread;
...
};
Finally, let's instantiate the class and call the function.
// somewhere not in a loop
LatestChar latest_char;
...
// somewhere is a loop
_x = latest_char.getLatestChar();
I am trying to make an autoclicker to mess around with getkeystate and key pressing functions in VS and c++, for some odd reason it will never stop clicking once it is initially clicked. I looked over my code and couldn't find anything wrong with it, i know the issue is gonna be something stupidly small. Heres my code:
#include <iostream>
#include <Windows.h>
using namespace std;
bool click = false;
int x = 0, y = 0, cps;
void gui()
{
cout << "Enter desired clicks per second: ";
cin >> cps;
}
void clicked()
{
while (1)
{
if (GetAsyncKeyState(VK_LBUTTON)) // Left mbutton
{
click = true;
}
else
{
click = false;
}
if (click == true)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
Sleep(1000 / cps);
}
if (click == false)
{
continue;
}
}
}
int main()
{
gui();
clicked();
}```
You maybe missed to read the documentation about return value of GetAsyncKeyState.
The return value of GetAsyncKeyState is zero for the following cases:
The current desktop is not the active desktop
The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.
And,if the most significant bit is set , the key is down.
So, for checking up, you need to check, if the most significant bit is reset.
[Sorry, I am writing the answer on mobile. So, could not provide source code.]
I have a wxwidget application that uses dragandrop and when I close the application, it crashes on this line:
virtual ~wxDropTargetBase()
{ delete m_dataObject; }
I setup the drapand drop in this way:
MainWindow::MainWindow() : MainWindowTemplate(NULL), m_fileDropTarget(textSourceFolder)
{
// connect events
this->Connect(wxEVT_IDLE, wxIdleEventHandler(MainWindow::OnIdle));
// set window minimum size - work around bug that ignores outer border and sets min size slightly too small
wxSize minSize = sizerOuter->GetMinSize();
minSize.SetWidth(minSize.GetWidth() + 16);
minSize.SetHeight(minSize.GetHeight() + 16);
SetMinSize(minSize);
Layout();
// set file drop target
SetDropTarget(&m_fileDropTarget);
}
and the source code for my
class MyFileDropTarget : public wxFileDropTarget
{
public:
MyFileDropTarget(wxTextCtrl *textCtrl)
{
m_fileTextCtrl = textCtrl;
}
virtual bool wxFileDropTarget::OnDropFiles (wxCoord x, wxCoord y, const wxArrayString &filenames)
{
if (filenames.size() > 0)
{
m_fileTextCtrl->SetValue(filenames.Item(0));
return true;
}
return false;
}
private:
wxTextCtrl *m_fileTextCtrl;
};
what is the problem and how I can fix it?
It looks like your m_fileDropTarget is an object, in which case it is deleted twice, as when you call SetDropTarget() it takes ownership of the pointer passed to it.
I don't understand why when I press 'f' it enters into fullscreen but does not exit out of full screen. In the beginning of this method I have set bool fullscreen = false;
Here is the code for my toggle:
case 'f': //toggle screenmode
if(!fullscreen){
glutFullScreen();
fullscreen = true;
} else if(fullscreen){
glutReshapeWindow(1200, 900);
glutPositionWindow(0,0);
fullscreen = false;
}
break;
at the top of this method I have set bool fullscreen = false;
Every time you press a key, GLUT will call your keyboard handler. And at the top of your keyboard handler, you create a bool variable named fullscreen and set its value to false. This happens regardless of whether you're in full-screen mode or not. Every time you press a key, this will happen.
If you want to retain a boolean variable that actually tracks whether you're currently fullscreen, then you need to use a global. And you need to not set it at the start of the function. You set it once when you create the window, and you only set it again when you change the fullscreen status of the window.
To restore the original window size
... switch the calling order of ReshapeWindow and PositionWindow to
glutPositionWindow(0,0);
glutReshapeWindow(1200, 900);
Otherwise it will go back to windowed mode, but not adapt to the window size you specified!
The problem is not in the code you posted above as according to glutFullScreen specification the window should exit fullscreen mode once glutReshapeWindow or glutPositionWindow is being called.
at the top of this method I have set bool fullscreen = false;
I bet you set this inside the same function (not as a global variable) rendering the variable always being false when you press f
Instead of defining the bool at the beginning of the method, you have to define a global variable. Otherwise each time that method is called, it will set the fullscreen bool to 0, and think that it's not in fullscreen mode. Also, you may want to take not of euphrat's answer, he makes a valid point about the method organization.
Try this:
case 'f': //toggle screenmode
fullScreen = !fullScreen;
if (fullScreen) {
glutFullScreen();
} else {
glutReshapeWindow(1200, 900);
glutPositionWindow(0,0);
}
break;
While it might not answer the question directly, I found it an excellent place to post a go-to full-screen and exit source code.
Switch and restore full screen with <GL/glut.h>
myGame.c
...
glutSpecialFunc(handleSpecial);
void handleSpecial(int key, int x, int y) {
oglHandleFullScreen(key, x, y);
}
...
If you are looking forward to responding to a keyboard event instead (glutKeyboardFunc), make sure to change the signature of the below oglHandleFullScreen to (unsigned char key, int x, int y).
fullscreen.h
void oglHandleFullScreen(int key, int x, int y);
void oglWindowed(int positionX, int positionY, int width, int height);
void oglFullScreen();
fullscreen.c
#include <GL/glut.h>
#include "fullscreen.h"
int isFullScreen = 0;
int previousPosition[2] = { 0, 0 };
int previousSize[2] = { 100, 100 };
void oglHandleFullScreen(int key, int x, int y) {
if (key != GLUT_KEY_F11) { // Respond to F11 key (glutSpecialFunc).
return;
}
if (isFullScreen) {
oglWindowed(previousPosition[0], previousPosition[1],
previousSize[0], previousSize[1]);
} else {
previousPosition[0] = glutGet(GLUT_WINDOW_X);
previousPosition[1] = glutGet(GLUT_WINDOW_Y);
previousSize[0] = glutGet(GLUT_WINDOW_WIDTH);
previousSize[1] = glutGet(GLUT_WINDOW_HEIGHT);
oglFullScreen();
}
isFullScreen = !isFullScreen;
}
void oglWindowed(int positionX, int positionY, int width, int height) {
glutReshapeWindow(width, height);
glutPositionWindow(positionX, positionY);
}
void oglFullScreen() {
glutFullScreen();
}
In this case, you may want to add a static keyword before the bool to make this variable initialized only once.
A safer approach would be to make fullscreen global, since static local variables may be implemented differently across compilers and c++ standards.
Edit to add code snippet:
static bool fullscreen = false;
This should fix the problem of initializing the variable every call to the function, and by c++11 standard should be thread-safe
(Many compilers may say otherwise. Visual Studio only supported this feature of c++11 in VS2015 according to another question's accepted answer: Is static init thread-safe with VC2010?)
Better option may be using a global variable (Wrapping into a class is not good for this purpose).
Edit: Also, despite being simple in syntax, this c++11 feature is costly when called frequently.(See Cost of thread-safe local static variable initialization in C++11?)
(A key down is not that frequent as drawing vertices at high FPS, though... Do NOT use this when performance-critical...)