XLib: Windows Manager not Sending Client Message after Calling XSetWMProtocols - c++

There are many examples on how to handle the closing of a window using XLib, which can be found on the internet:
http://cboard.cprogramming.com/linux-programming/60466-xwindows-close-window-event.html
https://en.wikibooks.org/wiki/X_Window_Programming/XLib
https://john.nachtimwald.com/2009/11/01/x11-intercept-window-close-event/
There are several more. That said I have tried to implement them in code, as seen below. However when I click on X in the corner of my window I get no event sent to my message loop. Is this because XChcekWindowEvent ignores or does not process Client Messages? If this is not the case what are some other things I should be looking for to get messages from XLib set using SetWMProtocols?
m_impl->m_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
if (!XSetWMProtocols(display, window, &m_impl->m_delete_window, 1)) {
std::cout << "Set Window Protocols Failed" << std::endl;
}
...
while (!terminate) {
while (::XCheckWindowEvent(display, window, events::mask, &x_event)) {
if (x_event.type == ClientMessage) {
std::cout << "Client Message" << std::endl;
if ((Atom)x_event.xclient.data.l[0] == m_impl->m_delete_window) {
terminate = true;
}
}
}
}

The XCheckWindowEvent() will not return ClientMessage. It returns none of the non maskable ones. Work around:
while (XPending(display))
{
XNextEvent(display, &event);
But could create extra work to filter event by window.
BR Pekka

If you want to prevent using XNextEvent (which is not applied in real-time event loops), you may use the following code based on XCheckTypedWindowEvent:
// Globals
Atom wm_protocols;
Atom wm_delete_window;
// Functions
void PreventClose(Display* disp, Window& win)
{
wm_protocols = XInternAtom(disp, "WM_PROTOCOLS", false);
wm_delete_window = XInternAtom(disp, "WM_DELETE_WINDOW", false);
XSetWMProtocols(disp, win, &wm_delete_window, 1);
}
bool IsClosed(Display* disp, Window& win)
{
XEvent e;
if (XCheckTypedWindowEvent(disp, win, ClientMessage, &e))
if (e.xclient.message_type == wm_protocols &&
e.xclient.data.l[0] == wm_delete_window_)
return true;
return false;
}
// Usage
int main()
{
...
PreventClose(disp, win);
do {
if (IsClosed(disp, win))
// break, some actions, etc...
...
} while(true);
return 0;
}
For more info see man 3 XCheckTypedWindowEvent

Related

How to detect mouse scroll events with the emulated mouse (connecting to a pc by VNC)?

Does anyone have any idea why the scroll is not tracked when I remotely connect to the computer via VNC? The scroll action itself is tracked, but the delta is always 0 (event->delta_y). I want to be able to detect in which direction I scroll (Up or Down) while working with my application remotely - using VNC. I was trying to go around this problem by using x11. This system tracks mouse scroll events correctly, but I must create a loop to track the event, not what I want. Also I was trying to get ( event->direction ), but it always returns SMOOTH_SCROLL, but should return the particular direction. The code I have now:
bool OcctGtkViewer::onMouseScroll(GdkEventScroll *theEvent)
{
bool isPressed = false;
int init_x, init_y, fin_x, fin_y;
Display *xdisplay = XOpenDisplay(0);
XEvent xevent;
::Window xroot = gdk_x11_window_get_xid(gtk_widget_get_window((GtkWidget *)myGLArea->gobj()));
int scr = DefaultScreen(xdisplay);
const Graphic3d_Vec2d aNewPos2d = myView->Window()->ConvertPointToBacking(Graphic3d_Vec2d(theEvent->x, theEvent->y));
XGrabPointer(xdisplay, xroot, 1, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
while (1)
{
XNextEvent(xdisplay, &xevent);
if (xevent.type == ButtonPress)
{
switch (xevent.xbutton.button)
{
case Button4:
if (true)
{
const Aspect_ScrollDelta aScroll(Graphic3d_Vec2i(aNewPos2d + Graphic3d_Vec2d(0.5)), 1);
if (UpdateMouseScroll(aScroll))
{
myGLArea->queue_draw();
}
break;
}
case Button5:
if (true)
{
const Aspect_ScrollDelta aScroll(Graphic3d_Vec2i(aNewPos2d + Graphic3d_Vec2d(0.5)), -1);
if (UpdateMouseScroll(aScroll))
{
myGLArea->queue_draw();
}
break;
}
default:
break;
}
}
break;
}
XFlush(xdisplay);
XCloseDisplay(xdisplay);
return true;
}

Getting Continuous Window Resize Event in SDL 2

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.

SDL Event Handling Delay

I am getting a major (1-2 second) delay between key presses.
Here is main.cpp (the lagging input handling):
#include <iostream>
#include "src/Input/InputManager.h"
#include "src/Graphics/Display.h"
#define LOG(x) std::cout << x << std::endl;
using namespace Rambug;
int main(int arc, char** argv)
{
Graphics::Display display(900, 600, "Rambug Engine Tester", true);
display.createDisplay();
SDL_Event event;
Input::InputManager inputManager;
// "Game" Loop
while (!display.isClosed())
{
display.update();
glClearColor(0.0f, 0.02f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN)
{
std::cout << "Keydowner" << std::endl;
}
if (event.type == SDL_KEYUP)
{
std::cout << "Keyupper" << std::endl;
}
}
// inputManager.update();
}
display.destroyDisplay();
system("PAUSE");
return 0;
}
Here is Display.cpp, which runs PERFECTLY without any delay when I run the same code (SDL_KEYDOWN, SDL_KEYUP) I just run SDL_QUIT down there.
#include "Display.h"
namespace Rambug
{
namespace Graphics
{
Display::Display(int width, int height, std::string title, bool log)
{
m_displayWidth = width;
m_displayHeight = height;
m_displayTitle = title;
m_log = log;
m_window = nullptr;
}
Display::Display()
{
}
Display::~Display()
{
}
void Display::createDisplay()
{
// Initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
// Setting attributes to our window
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Create window
m_window = SDL_CreateWindow((m_displayTitle.c_str()), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_displayWidth, m_displayHeight, SDL_WINDOW_OPENGL);
// Error Check Window
if (m_window == nullptr)
{
if (m_log)
std::cerr << "Window could not be created!" << std::endl;
}
else
{
if (m_log)
std::cout << "Window Created Successfully With SDL!" << std::endl;
}
// Create OpenGL Context
m_glContext = SDL_GL_CreateContext(m_window);
// Initialize GLEW
glewExperimental = GL_TRUE;
GLenum status = glewInit();
if (glewExperimental)
{
if (m_log)
std::cout << "Glew Experimental: On" << std::endl;
}
// Error Check GLEW
if (status != GLEW_OK)
{
if (m_log)
{
std::cerr << "GLEW could not be initialized!" << std::endl;
}
}
else
{
if (m_log)
{
std::cout << "GLEW Was Initilized Successfully!" << std::endl;
}
}
// Log OpenGL Version Number
if (m_log)
{
std::cout << "Using OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
}
m_closed = false;
}
void Display::destroyDisplay()
{
SDL_GL_DeleteContext(m_glContext);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
void Display::update()
{
SDL_GL_SwapWindow(m_window);
// Check for Input
while (SDL_PollEvent(&m_sdlEvent))
{
if (m_sdlEvent.type == SDL_QUIT)
{
m_closed = true;
}
}
}
bool Display::isClosed()
{
return m_closed;
}
}
}
I also tried experimenting with an Input manager class, but that was the same deal: delays. The update method is what I would call in main.cpp (I believe that it is commented out)
#include "InputManager.h"
#include <iostream>
#define LOG(x) std::cout << x << std::endl;
namespace Rambug
{
namespace Input
{
InputManager::InputManager()
{
}
InputManager::~InputManager()
{
}
void InputManager::keyPressed(unsigned int keyCode)
{
m_keyMap[keyCode] = true;
}
void InputManager::keyReleased(unsigned int keyCode)
{
m_keyMap[keyCode] = false;
}
bool InputManager::isKeyDown(unsigned int keyCode)
{
auto it = m_keyMap.find(keyCode);
if (it != m_keyMap.end())
{
return it->second;
}
else
{
return false;
}
}
void InputManager::update()
{
while (SDL_PollEvent(&m_event))
{
switch (m_event.type)
{
case SDL_KEYDOWN:
LOG("SDL_KEYDOWN");
keyPressed(m_event.key.keysym.sym);
break;
case SDL_KEYUP:
LOG("SDL_KEYUP");
keyReleased(m_event.key.keysym.sym);
break;
}
}
}
}
}
So InputManager and main.cpp have major delays, while Display.cpp runs perfectly. Is it because I cannot run SDL_PollEvents twice?
Is it because I cannot run SDL_PollEvents twice?
Your problem isn't what I'd expect, but, yes, it's a bad idea to run SDL_PollEvents twice. SDL keeps an event stack which is added to as your program runs. SDL_PollEvents pops events from the stack until it is empty. As a result, running two polling loops, one will remove events which the other will then not see. Blind luck (or execution bottlenecks) will determine which loop is more likely to see any particular event occur. (See http://wiki.libsdl.org/SDL_PollEvent).
If you really want to run two polling loops, you can store unhandled events in your default case, and push the list of events back after each loop with SDL_PushEvent: http://wiki.libsdl.org/SDL_PushEvent
This said, I'm surprised that your events "get through" after a delay: I would expect them to vanish. Are you holding the keys down? Then, your OS key-repeat delay might be what you're seeing, after which the event queue is being flooded between each loop. You might want to check the repeat flag of the key event: http://wiki.libsdl.org/SDL_KeyboardEvent
I would say this points to a design problem. You should ask yourself, why does the Display delegate the Game ending? Would it not be more sensible to inform the Display, along with everything else, of this fact?
SDL keeps an event stack which is added to as your program runs. SDL_PollEvents pops events from the stack until it is empty.
I am fairly sure that it is not a stack, but a queue. The SDL_PushEvent has a somewhat misleading name there; what it really does is shove the event back into the queue from the "wrong" end. (It might be implemented internally as a stack, but it's behaviour is that of a queue.)
Still, Qualia's answer is the right way to go.
However, I don't agree that it is necessarily bad to have multiple event loops - they can be very useful. 2 scenarios:
1) You catch something like a resize event in your main event loop. If the ensuing operations are very time-consuming the event queue will be flooded with more resize events as long as the user keeps resizing the window.
In this case, on can have a separate event loop after the time-consuming repaint, which simply loops until it finds the first non-resize event, then pushes the last 2 events it saw back into the queue, and returns control to the main loop. That way you can discard the accumulated resize events. (It can be done more elegantly using the SDL_PeepEvents function, especially if there is a really huge pile-up of events in the queue.)
2) The action your program takes after catching a specific event will trigger other events, like when using SDL_RaiseWindow, which may trigger a multitude of focus and window related subsequent events, especially if you have more than one SDL window. Here, having a separate event loop can be used to deal with these triggered events, especially if the response to these events should be suppressed.
On the issue of delays, I have also encountered all sorts of strange behaviour with the SDL_KEYDOWN event, usually the event being triggered multiple times, and definitely not related to OS key repetition. This seems to occur only when using SDL_PollEvent; SDL_WaitEventTimeout, even with the timeout delay set to just '1', seems to inhibit this strange behaviour. Interestingly, the SDL_KEYUP event does not exhibit this behaviour.

Getting mouse events from HIDManager in OSX with C++

I'm porting a game from pc to osx and I'm getting stuck with input events. The main game window is a cocoa app that interfaces with a C++ backend. The pc code uses DirectInput and windows messages to generate keyboard and mouse events that the game understands.
When I first started the port I replaced the windows messages with Carbon event handling, but since discovered that Cocoa apps don't fire off carbon events. I did a bit more reading and discovered the HIDManager which seemed to do what I want and was accessible from c++. Using the information in the post here Using IOHIDManager to Get Modifier Key Events I managed to get keyboard input working, but have so far been unable to extend the example code to generate mouse events as well. The code is have is as follows:
void myHIDCallback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
{
IOHIDElementRef elem = IOHIDValueGetElement(value);
if (IOHIDElementGetUsagePage(elem) == 0x07)
{
// Keyboard events
card32 scancode = IOHIDElementGetUsage(elem);
if (scancode >= 4 && scancode <= 231)
{
long pressed = IOHIDValueGetIntegerValue(value);
KEY_EVENT_DETAILS details = { KEY_EVENT_NONE, NUM_KEYS };
for (card32 n=0; n<NUM_KEYS; ++n)
{
if (n_direct_input_mappings[n].direct_input_key == scancode)
{
details.key_type = n_direct_input_mappings[n].key;
break;
}
}
switch (pressed)
{
case 0:
details.event_type = KEY_EVENT_KEY_DOWN;
break;
case 1:
details.event_type = KEY_EVENT_KEY_UP;
break;
}
sApplication->handle_key_event(details);
}
}
else
if (IOHIDElementGetUsagePage(elem) == 0x02)
{
// Mouse events
card32 usage = IOHIDElementGetUsage(elem);
long pressed = IOHIDValueGetIntegerValue(value);
}
else
{
}
}
CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage)
{
CFMutableDictionaryRef ret = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (ret)
{
CFNumberRef pageNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage);
if (pageNumberRef)
{
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef);
CFRelease(pageNumberRef);
CFNumberRef usageNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
if (usageNumberRef)
{
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef);
CFRelease(usageNumberRef);
return ret;
}
}
CFRelease(ret);
}
return NULL;
}
bool acquire_hardware_controllers(CA::Application& app, CAWindow& window_handle)
{
sApplication = &app;
// Setup the keyboard event handler
sHIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
IOHIDManagerOpen(sHIDManager, kIOHIDOptionsTypeNone);
CFMutableDictionaryRef mouse = myCreateDeviceMatchingDictionary(0x01, 2);
CFMutableDictionaryRef keyboard = myCreateDeviceMatchingDictionary(0x01, 6);
CFMutableDictionaryRef keypad = myCreateDeviceMatchingDictionary(0x01, 7);
CFMutableDictionaryRef matchesList[] = {
keyboard,
keypad,
mouse
};
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault, (const void**)matchesList, 3, NULL);
IOHIDManagerSetDeviceMatchingMultiple(sHIDManager, matches);
IOHIDManagerRegisterInputValueCallback(sHIDManager, myHIDCallback, NULL);
IOHIDManagerScheduleWithRunLoop(sHIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
}
If anyone can help me out then that would be great. If I can't get this working then I guess I can move over to Cocoa event handling, but the pc code also has some keyboard and mouse polling that I was hoping to implement as well, and I'm not sure that Cocoa supports polling keyboard state - although I will be happy to be corrected.
TIA.

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?