check for reparented window close events - d

I am trying to make a xlib traybar for X11 where it embeds the tray icons using XEMBED as described in the tray specs. However when I close the application with the tray icon it just removes it from the container window but the black container window rectangle and the entry in my code still exists.
In the XEMBED documentation it says
It is the responsibility of the embedder to keep track of all forwarded
accelerators and to remove them when the client window dies.
However my application does not get any events or indication when a embedded window dies.
I basically only receive a dock request event and nothing else afterwards. When a dock request event comes in I create a child window for my panel which contains the tray window and reparent it like this:
enum trayIconSize = 24; // dimensions of icon
icon.trayWindow = XCreateWindow(x.display, panel.window, 0, 0, ...);
icon.ownerHandle = event.data.l[2]; // window id of icon which wants to dock
XReparentWindow(x.display, icon.ownerHandle, icon.trayWindow, 0, 0);
XMoveResizeWindow(x.display, icon.ownerHandle, 0, 0, trayIconSize, trayIconSize);
Adding it to the panel works without any problems but I don't know how to check when to remove it again.
How do I make my application receive close events for those tray icons or how do I check if the reparented window still exists?

I have actually done this before myself: https://github.com/adamdruppe/taskbar it has hacks for my specific setup in the width thing, but most of it should be reasonably usable and the code might help guide you.
But what you want to do is ask for events on the icon window. It has been a while, so I'm kinda using my own code as a guide here, but when I got the dock request, I called XSelectInput(dd, id, EventMask.StructureNotifyMask);
StructureNotifyMask subscribes to events including MapNotify, DestroyNotify, you prolly see where this is going :)
Once you have selected the input on the icon window, you regular event loop can check for the DestroyNotify and UnmapNotify events (my code checks both, tbh, I'm not sure which one actually triggers when the icon is removed) and compare the .window member of the event to your icon's window ID. If it matches, go ahead and remove it from your list because it is gone now.
My taskbar does seem to have a bug if the application crashes as opposed to being closed normally, so I might still be missing something, but checking the event works in most cases.

Related

CMenu not receiving Windows touch messages

In my application when I receive an ON_WM_RBUTTONDOWN() message in a certain window I create a CMenu, populated with some items, and then displayed with TrackPopupMenu(xxx). It has no other interaction with Windows messages to be created. It defaults to accepting left clicks to select items and I can see these messages coming in when I use the mouse.
I'm trying to allow use of this context menu on a touch screen - the parent window can receive WM_GESTURENOTIFY messages (for other functionality) and in all other aspects of my app, such as other windows and dialogs, it handles touch gestures fine - Spy++ shows gesture messages and a WM_LBUTTONDOWN which gives me normal behaviour across the app. I CAN touch select menu items when this menu is opened with a physical mouse right click, with the touch input coming through as a WM_LBUTTONDOWN.
I've tried creating and displaying this menu by calling that same creation code again from a touch message, or just sending the window an ON_WM_RBUTTONDOWN() message manually after a touch, with the same flags. This is created fine and works as normal with a mouse, and as far as the app is concerned nothing is different. However, the CMenu is not receiving any touch messages at all - I get the touch-style cursor showing where I'm tapping, but nothing is being piped through to the menu.
I've tried changing from gestures to registering touch while this interaction happens and ensuring the original gesture handle is closed in case it was blocking for whatever reason.
My assumption is that Windows is doing something additional behind the scenes beyond what my app is aware of to allow these messages to be sent through, so I'm a bit stuck for a solution.
I was able to get around this issue by enabling the tablet press-and-hold gesture (it's normally disabled) which serves the purpose of being treated as a right click and having a properly interactable context menu, rather than sending the right click message myself. Works on desktop with a touch screen and a Windows tablet.
https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/cpp/language-compilers/mfc-enable-tablet-press-and-hold-gesture
Adding
ULONG CMyView::GetGestureStatus(CPoint /*ptTouch*/) { return 0; } was what enabled this to work.

Is there an event mask I can set in Xlib to receive an event whenever a window title is changes

I'm writing a window manager in C++ (mostly c stuff but i need unordered_map) with Xlib and my current approach to updating window titles is to get window titles whenever it receives any unrelated event. The problem with this is that if I open XTerm, for example, the titlebar says "xterm" until I do something that sends an event (like clicking the titlebar) and then the window title changes to "username#hostname:WD". It's supposed to update to that format after showing "xterm" for only a split second. It's also supposed to change every time you use the cd command.
Is there an event mask I can use to do this? I looked in a list of Xlib event masks and couldn't find an event mask that does this.
The client should set _NET_WM_NAME application window property. If you want to get events when application updates this property you can set PropertyChangeMask on the application window. Mask value is 0x400000.

Can't focus from main window after closing dialog from other thread

I create a new CWindThread in CWinApp::InitInstance(). In that thread, I create a dialog (for displaying a progress bar in that dialog).
After finishing InitInstance(), I close the dialog by calling DestroyWindow() from the dialog, but the application is loosing focus from main window.
I used AfxGetMainWnd()->SetActiveWindow(); to set focus for main window but it is not working.
How can I return the focus to the main window after closing the dialog?
There is no real good way to do that. The focus is set per thread. So there is no "focus" over all windows.
The only chance you have is to set the new foreground window, that belongs to the other thread with SetForegorundWindow. From within the same application this should work without restrictions.
If it doesn't work you need to "synch" both message queues. This is done by AttachThreadInput. If both messages queue are already attached, than there is no problem with settings the focus directly. But the behaviour of the application will change... Please read the docs, of the functions I linked too.
When a modal popup window is displayed, the reason a user cannot interact with the owner window is that it is disabled. When the modal window is destroyed, care must be taken to re-enable the owner window BEFORE destroying the popup as windows cannot activate a disabled window. This is the usual cause of popup windows re-activating the wrong window.

Programmatically clicking toolbar button in parent of modal window

I have an application that hooks into another application via an API. My application launches a modal window which prevents keypresses to reach the parent as one would expect.
However due to limitations in the API I need to click one of the parents toolbar buttons from time to time (yes it's a kludge).
I wonder if this is possible while still having the modal window of my application active? Is it perhaps possible to send the required command directly into the parent command queue?
Clicking the button programmatically with no modal window should not be a problem, one could go by this link for example: http://forums.codeguru.com/showthread.php?307633-How-to-run-a-very-long-SQL-statement. But I would prefer not having to close my window each time I have to click the button.
Although the fifth answer is what I find interesting as I'm thinking this could make it possible to send the command without having to close my modal window first. Also it feels an ever so small bit less ugly.
First of all, when a modal dialog is shown, it runs its own message pump. So any attempt to fake input messages will land in the modal dialog message pump. Which is no good to you. So, you'd have to send a message rather than fake input.
However, when a modal dialog is shown, its owning windows are disabled. Which means that these windows will not respond to any messages you send. So I guess that means that you could:
Enable the owning top-level window that you hosts the toolbar in question.
Send the message to the toolbar button.
Disable the owning window again.
Not the prettiest way to go about things, but you did ask!

Creating Drawer-like window

How do you create a window that is attached to the side of parent window opens like a drawer?
In such a way that you don't lose focus of parent window.
What you basically need to do is create yourself a custom control representing your drawer. I'm not sure if that's something you're familiar with or not, but if not there are plenty of tutorials about, such as this one.
I imagine what you'd do is designate part of your control to be the "handle", which if clicked upon "opens" the drawer. You would achieve this by handling the WM_LBUTTONDOWN/WM_LBUTTONUP messages in your control's window procedure, and changing its size from its closed size to its open size when clicks are detected. I haven't used it before, but you might be able to simply achieve animation using AnimateWindow.
You'd probably also want to have your control send it's parent window a notification whenever it is opened or closed, so that your parent window can re-size or move other controls if necessary. You can achieve this by sending a WM_NOTIFY message to the parent window with your own notification code, or using your own custom message. Your parent window would then have to respond to such messages in its window procedure.
As far as I'm aware there's no specific examples to be found addressing your exact requirements, so I probably can't supply much more info at the moment. If there's anything else in particular you need to know to get this running, don't hesitate to ask.