Getting Continuous Window Resize Event in SDL 2 - c++

I use the following structure to get new width and height of the resized SDL window:
if (sdl_set->GetMainEvent()->type == SDL_WINDOWEVENT)
{
if (sdl_set->GetMainEvent()->window.event == SDL_WINDOWEVENT_RESIZED)
{
ScreenWidth = sdl_set->GetMainEvent()->window.data1;
ScreenHeight = sdl_set->GetMainEvent()->window.data2;
cout << "Window Resized!" << endl;
}
}
But with this structure I'm only able to get new data after the resizing is done that is when I finish dragging and release the mouse button.
How can I get the new data continuously, that is while I'm dragging the window?

static int resizingEventWatcher(void* data, SDL_Event* event) {
if (event->type == SDL_WINDOWEVENT &&
event->window.event == SDL_WINDOWEVENT_RESIZED) {
SDL_Window* win = SDL_GetWindowFromID(event->window.windowID);
if (win == (SDL_Window*)data) {
printf("resizing.....\n");
}
}
return 0;
}
int main() {
SDL_Window* win = ...
...
SDL_AddEventWatch(resizingEventWatcher, win);
...
}
use SDL's EventWatch can resolve it.

If you are on windows, have you tried using the windows api?
I know its not a real fix but if you are not making a cross platform application, you should give it a shot.
Use HWND to find SDL's window and return the window size.

Related

Context menu does not consistently work on arch linux?

I am using arch linux and a basic cpp xlib custom window manager. However, every time I right click to open the context menu it just flickers and disappears. I cannot use it at all. I also cannot use top drop down menus (file, edit, about, ect.) on any application. Is there anything in Xlib which I have to look out for to ensure I may use the context menus normally?
This is the case in every application I have tried. Only clue I have is in brave it occasionally displays the following message:
XGetWindowAttributes failed for window [WINDOW_ID]
The following simplified example also has this issue:
int main()
{
display = XOpenDisplay(nullptr);
root = DefaultRootWindow(display);
XSelectInput(display, root, SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask);
XGrabServer(display);
Window returned_root;
Window returned_parent;
Window* top_level_windows;
unsigned int num_top_level_windows;
XQueryTree(display, root, &returned_root, &returned_parent, &top_level_windows, &num_top_level_windows);
for(unsigned int i = 0; i < num_top_level_windows; ++i)
{
Frame(top_level_windows[i], true);
}
XFree(top_level_windows);
XUngrabServer(display);
for(;;)
{
XEvent event;
XNextEvent(display, &event);
switch (event.type)
{
case MapRequest:
{
Frame(event.xmaprequest.window, false);
XMapWindow(display, event.xmaprequest.window);
break;
}
case ButtonPress:
XRaiseWindow(display, event.xbutton.window);
break;
}
}
return true;
}
void Frame(Window window, bool created_before_manager)
{
//Retrieve attributes of window to frame
XWindowAttributes attr = {0};
XGetWindowAttributes(display, window, &attr);
//If window was created before window manager started, we should frame it only if it is visible and does not set override_redirect
if(created_before_manager && (attr.override_redirect || attr.map_state != IsViewable))
{
return;
}
//Create frame
Window frame = XCreateSimpleWindow(display, root, attr.x, attr.y, attr.width, attr.height, 5, 0xff0000, 0xffffff);
XReparentWindow(display, window, frame, 0, 0);
XMapWindow(display, frame);
XGrabButton(display, Button1Mask, Mod1Mask, window, None, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
}
To be clear it also works with a super simple example such as:
int main()
{
Display* display = XOpenDisplay(nullptr);
for(;;) {}
return true;
}
The reason I believe the window manager is at fault is because this issue only occurs after I run the window manager.
I expected this to work out of the box. I have not found any information on context menus needing special treatment. They do have the override_redirect flag set to true, so I do not frame them. I cannot find information on any other special treatment required.
It is necessary to make sure the client window has input. I had the input set to whatever was clicked (frame, title bar, or client) because it worked fine as far as normal input is concerned. However, the context menus will only work if you make sure the input is set to the client window directly.

Why isn't SDL_CreateWindow showing a window when called from another class?

Rewriting this to try to provide some clarity and update the code with some things that have changed.
I am restructuring a project that used SDL2, and have encountered issues trying to create a blank window. I have attempted to structure the project similarly to the original by separating all functionality dealing with SDL_Window into its own class. If I move the call to SDL_CreateWindow into the same class as the event loop or move the event loop to the same class as the window, the window is created and shown as expected, however as it is now, the window appears to be created successfully (SDL_CreateWindow is not returning NULL) and the program doesn't seem to be hanging, but it does not display a window while the program is running.
The SDL_Window is created in the Graphics class and stored in a member variable:
Graphics::Graphics(const char* title, unsigned int w, unsigned int h, unsigned int flags, int& status) {
screen = SDL_CreateWindow(title,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w, h,
flags);
status = 0;
if (screen == NULL)
status = 1;
}
Graphics is instantiated in the Window class and stored in a member variable.
Window::Window(const char* title, unsigned int w, unsigned int h, unsigned int flags, int& status) {
g = Graphics(title, w,h, flags, status);
}
Window is instantiated in main, and if the window is created successfully, it starts the event loop.
{
int status;
Window window("Mirari", 640,480, SDL_WINDOW_SHOWN, status);
if (status == 0) {
window.eventLoop();
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError());
return 1;
}
}
The event loop itself to be thorough (update and draw are both currently empty functions).
void Window::eventLoop() {
SDL_Event ev;
bool running = true;
while (running) {
const int start_time = SDL_GetTicks();
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_QUIT:
running = false;
break;
default:
break;
}
}
//update();
//draw();
std::cout << "." << std::endl;
const int elapsed = SDL_GetTicks() - start_time;
if (elapsed < 1000 / FPS)
SDL_Delay(1000 / FPS - elapsed);
}
}
SDL is initialized with this static function and these flags.
void Window::init(unsigned int sdl_flags, IMG_InitFlags img_flags) {
SDL_Init(sdl_flags);
IMG_Init(img_flags);
TTF_Init();
}
...
Window::init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER, IMG_INIT_PNG);
I know that a window can be created in a separate class because the first version of this project did that and it worked, I'm just not sure what has changed that is causing the window not to show up.
As said by some programmer dude, you design is not perfect and should be thought again.
Nevertheless, from what we can see on your code : If the Window constructor is called (and the SDL_Init was called before, which I assume so), then the windows should be created.
From there we only can guess what we can't see (as it's not part of what you are displaying) :
is the definition of SDL_WINDOWPOS_UNDEFINED, the same in both context ?
is the screen variable definition the same in both context ?
is the "screen" used in "update", or "draw" method, and, as uninitialized : it fails
... ?
As you probably are new to development, I suggest you adopt this habit very early : your code should check and report everything it does. A good program is easy to debug, as it says what's wrong
For instance, just after :
screen = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w, h, flags);
you may want to write something like :
if(!screen)
{
std::cout << "Failed to create window\n";
return -1;
}
or better :
if(!screen)
{
throw std::exception("Failed to create window\n");
}
And so on.
For instance, in your function update, you may want to have something like :
if(!screen)
{
throw std::exception("Unable to update the display as it is uninitialized\n");
}
I assume your application would not end without any comment... but that's a guess

How do you create a gtk window handle from an X11 window handle

I'm trying to open a gtk file dialog window with a GLFW window.
Now since GLFW is a pretty low level API it only exposes the X11 window and display, because it just creates a window without any GUI stuff.
The problem I'm having is that gtk_file_chooser_dialog_new() expects a parent window to be passed on, but since I only have an X11 handle I'm not quite sure how to create a GTK handle from it.
I followed this tutorial which resulted in the following code:
glfwSetKeyCallback(windowHandle1, [](GLFWwindow *window, int keyCode, int scanCode, int action, int mods) {
if (action == GLFW_PRESS)
{
if (keyCode == GLFW_KEY_O && mods == (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL))
{
GtkWidget *dialog;
GtkFileChooserAction fileAction = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
// Window x11Window = glfwGetX11Window(window);
// Display *x11Display = glfwGetX11Display();
int argc = 0;
gtk_init(&argc, nullptr); // TODO: don't do this every time
dialog = gtk_file_chooser_dialog_new("Open File",
nullptr, // should be _GtkWindow of the GLFWwindow
fileAction,
_("_Cancel"),
GTK_RESPONSE_CANCEL,
_("_Open"),
GTK_RESPONSE_ACCEPT,
nullptr);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
filename = gtk_file_chooser_get_filename(chooser);
std::cout << filename << std::endl;
g_free(filename);
}
gtk_widget_destroy(dialog);
std::cout << "destroyed file dialog" << std::endl;
}
}
});
This opens an open file dialog, but because I didn't specify a parent window the main window can still be focused, and another problem is that the dialog doesn't close for some reason even though I call gtk_widget_destroy(dialog).
I already took a look at this post, but the only answer seems to be getting the xid of the file dialog window, which is not what I want to do.
This google search result doesn't seem to help either, as it creates a completely new gdk (not gtk) window on the default display.
I've got the same problem and found hackish way to fix this. Null parent is not really problem here, but lack of event dispatching, so I've added:
gtk_widget_destroy(dialog);
while (g_main_context_iteration(nullptr, false));

SDL2 Segfaults - Implementing a renderer

Just implemented a SDL_Renderer in my engine
state_t init_rend(window_t *context,flag_t flags) {
rend.renderer = NULL;
rend.renderer = SDL_CreateRenderer(context,-1,flags);
rend.index = -1;
if (rend.renderer != NULL) {
return TRUE;
} else {
return FALSE;
}
}
In my client/test app:
// Init Base2D game
init_env(VIDEO|AUDIO);
// Init Display display
init_disp(640,480,"Display",RESIZABLE|VISIBLE,make_color(255,255,255,255));
// Init Renderer renderer
init_rend(display->window,SOFTWARE);
// Game Loop
state_t status;
while (TRUE) {
update();
status = listen();
if (!status) {
break;
}
/* User Event Handles */
}
And I could handle window resizing successfully with:
void resize_window() {
printf("I was here!\n");
SDL_FreeSurface(display->container);
printf("Now I am here\n");
display->container = SDL_GetWindowSurface(display->window);
SDL_FillRect(
display->container,
NULL,
SDL_MapRGBA(
display->container->format,
get_red(),
get_green(),
get_blue(),
get_alpha()
)
);
}
However, since I have implemented the renderer, whenever I attempt to resize my display it segfaults when trying to SDL_FreeSurface(display->container).
As I have mentioned, the resizing worked fine until I implemented a renderer.
Why is this happening?
Following the link provided by user:keltar,
It seems to me the way to go with SDL2 is to use a renderer for drawing to the window intead of the old SDL1 method of using a surface.
I did just that, removed the surface code and used a renderer only and the code works without problem
Thank You

Handle "new top level window" events in Xlib/Xt

So I'm in a situation where I need to know when a top level window gets created. I'm working at the Xlib/Xt level and on a Window Manager that doesn't support the EWMH specification. My idea is to hook into the root window's SubstructureNotify events. But things are not as simple as just that.
The problem is that not every CreateNotify event corresponds to the creation of a [b]top level[/b] window. So what I think I need to do is test the window I get from the event somehow to confirm that it is a top level window. I've got close, but some spurious windows still make it through my net. For example, in a GTK application if you have a dropdown box and you click it, a new window is created that I can't figure out how to catch and ignore. Such a window is troublesomely indistinguishable from a typical top level application window.
Here's what I have so far:
// I am omiting (tons of) cleanup code and where I set the display and toplevel variables.
Display* display;
Widget toplevel;
bool has_name(Window window)
{
XTextProperty data = XTextProperty ();
return (!XGetWMName (display, window, &data));
}
bool has_client_leader(Window window)
{
unsigned long nitems = 0;
unsigned char* data = 0;
Atom actual_type;
int actual_format;
unsigned long bytes;
// WM_CLIENT_LEADER is an interned Atom for the WM_CLIENT_LEADER property
int status = XGetWindowProperty (display, window, WM_CLIENT_LEADER, 0L, (~0L), False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &data);
if (status != Success || acutal_type == None) return false;
Window* leader = reinterpret_cast<Window*> (data);
return (*leader != 0);
}
bool has_class(Window window)
{
XClassHint data = XClassHint ();
return (!GetClassHint (display, window, &data));
}
void handle_event(Widget widget, XtPointer, XEvent* event, Boolean*)
{
if (event->type != CreateNotify) return;
Window w = event->xcreatewindow.window;
// confirm window has a name
if (!has_name (w)) return;
// confirm window is a client window
Window client = XmuClientWindow (display, w);
if (!client || client != w) return;
// confirm window has a client leader that is not 0x0
if (!has_client_leader (client)) return;
// confirm window has a class
if (!has_class (client)) return;
// The window has passed all our checks!
// Go on to do stuff with the window ...
}
int main(int argc, char* argv[])
{
// ...
// Setting up the event handler for SubstructureNotify on root window
Window root_window = XDefaultRootWindow (display);
Widget dummy = XtCreateWidget ("dummy", coreWidgetClass, toplevel, 0, 0);
XtRegisterDrawable (display, root_window, dummy);
XSelectInput (display, root_window, SubstructureNotifyMask);
XtAddRawEventHandler (dummy, SubstructureNotifyMask, False, handle_event, 0);
// ...
}
A long shot, but does anyone have any ideas I could try? I can't think of much else I can really do here.
I assume you're familiar with the ICCCM and its long-winded discussion.
Have you checked the WM_TRANSIENT_FOR property?