multiple windows, single tray icon - c

My goal is to have a single icon for all the windows of my application.
After some reading, my understanding is that creating a tray icon is achieved through Shell_NotifyIcon(). This function gets a NOTIFYICONDATA structure which contains a hWnd field. This HWND is used by the system to notify the corresponding window of tray icon events. These events are handled by a WindowProc callback that is set on the window with SetWindowLongPtr().
Hence my questions:
How can a single icon notify all the windows of my app of say a left mouse click ?
Can I Shell_NotifyIcon() multiple times with different NOTIFYICONDATA structures, each one with a different hWnd, but with the same icon ?
What if the original window that got registered for creating the tray icon is destroyed ?
Would creating a hidden proxy window be an appropriate solution ?
Some background: my application calls the WinAPI with C (using js-ctypes), and should ideally work on all Windows versions from XP on.

You practically answered your own question in the question itself. The best thing to do is create a hidden window that survives as long as you need the tray icon to exist.
You would call Shell_NotifyIcon() only once with the hWnd referring to this hidden window, and have this window post the messages to the individual windows that need to receive them.
This also gives you the flexibility of being able to decide to skip sending messages to a particular window, or being able to send a different message to each window, depending on the requirements of your particular application.

Related

GTK+3 disable the close icon present in a window (c program)

I'm developing a GUI in Linux (Ubuntu 16.04 - WM: Gnome) using GTK+3 and the graphic library cairo.
After clicked on a push button (Plot), using the instruction of cairo I draw a red square on a new top window where I put a GtkDrawingArea.
In this window I also put a push button (Cancel) that clicked, hide the window. In this way, if I re-push "Plot", the red square reappear.
The issue is the "x" icon present in the top bar of the window.
If (no me) a user push this x, the window disapper and if he re-push the "Plot" an error is reported.
The question is: it is possible avoid this possible cause of error?
(remove this "x" from the top bar of the window or in some way disable its functionality).
I tryed to find alone a solution and the possibility found are:
1 - Remove from the window the property of "decorated".
The top bar disapper (so also the x) but is not possible move the window on the screen
2 - Using the function gtk_window_set_deletable(window, FALSE) (used before to show the window), but the x is always there and pushing it the window is destroyed.
If you think that can be useful, I can report the code.
I'm waiting your suggestion.
Edit:
Now we know what you want to achieve: display a separate window but avoid destroying it so you can display it again. You already have in the "Cancel" button of your secondary window the logic to hide it.
The cleanest solution is to just do the same: when the user tries to close the secondary window, hide it instead. This way the user is not frustrated of seeing something that apparently doesn't work as expected. Hidden or closed, it's different for you but it's the same for the user.
So you just need to connect to the delete-event of that secondary window, and hide it. There's even no need to create a specific callback for that, GTK+ provides it for you: you just need to connect the delete-event to gtk_widget_hide_on_delete. To display the window again, just call gtk_widget_show_all on it.
Original answer:
I realize the plot
"realize" is a term that has a defined meaning in GTK+. Don't use it out of context, and try to use an alternate term if you're not talking about widget realization.
What I would like is to remove this "x" from the top bar of the window
or in some way disable its functionality.
Do you understand this is ultra annoying for a user and defeats a unified user experience? Would you like to use applications that do random different things?
Anyway, one way of disabling the closing button is to connect to the delete-event and return TRUE there to stop the propagation of the event. The button will still be there but do nothing, so you will have to kill the app to exit it.
To make the button disappear, gtk_window_set_deletable will ask the Window Manager to do that, but we'd need some code to know what's wrong with your attempt.

Create transparent window with xlib that does not accept any input events or grab focus

I'm currently writing a window manager, and I was wondering if it were possible to create a window that is overlaid on top of all the other windows, but does not take input focus at all. In other words, I'd ideally like to be able to draw on this window without taking any input.
One approach would be to have the window manager call XQueryTree and then pass input (mouse clicks, keyboard input, etc) to the corresponding window. However, I wonder if there's a way to just prevent this overlay window from ever getting input events at all.
Also, I'd prefer not to draw directly on the root window, as that would break the compositing manager.
Composite extension provides exactly what you want:
https://www.x.org/releases/X11R7.7/doc/compositeproto/compositeproto.txt
3.2 Composite Overlay Window
Version 0.3 of the protocol adds the Composite Overlay Window, which
provides compositing managers with a surface on which to draw without
interference. This window is always above normal windows and is always
below the screen saver window. It is an InputOutput window whose width
and height are the screen dimensions. Its visual is the root visual
and its border width is zero. Attempts to redirect it using the
composite extension are ignored. This window does not appear in the
reply of the QueryTree request. It is also an override redirect window.
These last two features make it invisible to window managers and other X11
clients. The only way to access the XID of this window is via the
CompositeGetOverlayWindow request. Initially, the Composite Overlay
Window is unmapped.
CompositeGetOverlayWindow returns the XID of the Composite Overlay
Window. If the window has not yet been mapped, it is mapped by this
request. When all clients who have called this request have terminated
their X11 connections the window is unmapped.
Composite managers may render directly to the Composite Overlay
Window, or they may reparent other windows to be children of this
window and render to these. Multiple clients may render to the
Composite Overlay Window, create child windows of it, reshape it, and
redefine its input region, but the specific arbitration rules followed
by these clients is not defined by this specification; these policies
should be defined by the clients themselves.
see C api here: https://linux.die.net/man/3/xcompositegetoverlaywindow

Win32 API: process WM_* in tab control's wndproc instead of parent's

Currently I have a tab control attached to a main window on my program.
However, when I switch tabs, the WM_NOTIFY messages are sent to the parent of the tab control, not to the tab control itself.
Is there a way to make the tab control's WndProc receive and process those messages instead of the parent?
I'm using the raw win32 C API. No MFC or any kind of libraries
You have two options.
1. Subclassing
You can subclass the tab control so you can handle messages there in the first place, then in your parent window have some code like
#define msgNOTIFY (WM_APP + 0x40)
// ...
case WM_NOTIFY:
return SendMessageW(nm->hwndFrom, msgNOTIFY, wParam, lParam);
which will bounce the WM_NOTIFY back. Same for WM_COMMAND. I used a separate message ID for this redirected WM_NOTIFY/WM_COMMAND to be safe; you might not have to (I don't know for sure). If your controls move between windows, you'll also have to do this from all windows.
2. Use a Middleman
Instead of placing the tab control directly on your window, place it inside another control (preferably one of your own creation, which does nothing but be sized to fit the child) that you place on your window instead, and handle messages there. This has the advantage of avoiding the reparenting issue linked above, but costs a window handle, so I normally don't suggest doing so. It does work, though. And if you do this for your tab pages, switching pages is as easy as hiding one control and showing another! (In fact, this is what property sheets do with their child dialogs.)

How to let the parent window of a child window (a.k.a. owned window) stay active with winapi?

I am writing a small C application using winapi. There I've got a window with a child window (toolbox). I am able to keep it inside this window and so on, but my question is: How to keep the main window active, if the child window gets focused?
The main window gets grayed out in this moment.
The windows get created by:
hMainWindow = DialogBoxParam(.......);
hChildWindow = CreateDialogParam(..., hMainWindow, ...);
ShowWindow (hChildWindow, SW_SHOW);
Here a little image of the behaviour of the two windows:
I've found out that simply creating it as WS_CHILD and explicitly NOT as WS_POPUP solves that. It also turns the absolute window coordinates to relative ones so that I dont have to care about the window position anymore by moving the parent window.
// Solved
Create the child window as a modeless dialog box instead of a modal one. So instead of using DialogBox, use CreateDialog
Sorry, that's just the way Windows works: one active window at a time.
You can see this in Visual Studio if you bring up Find and Replace as a tool window, you'll see that it gets activated and the main VS window goes inactive.
Trying to have them both active at the same time could confuse users and accessibility tools like screen readers.

Changing window procedure for console window

I want to make console window with a functional tray icon. I figured out that most probably it is necessary to replace initial console's window procedure so I will be able to control all messages including notify area events. But SetWindowLong() function returns 0, and GetLastError() tells that access is denied.
hwndFound = GetConsoleWindow();
SetWindowLong(hwndFound, GWL_WNDPROC, (long)WndProc);
What could it be, or maybe there is some other way to control tray icon manipulations?
If all you want to do is create a notification icon for a console application, there's nothing that says your Shell_NotifyIcon call has to point to the console window. Create an invisible dummy window with your own window class and procedure instead. Note that you'll probably have to do this from a secondary thread in order to run its message loop. (The console window is special, as it's hosted outside your process by conhost.exe/csrss.exe.)
No, you just need a window. Best thing is to startup a thread so you can pump a message loop and receive the icon notifications. Create a little hidden window that you can use for the Shell_NotifyIcon() call.
Which version of Windows are you using? I know that prior to Vista, console windows are treated specially, and can't be manipulated in many of the standard ways. This article by Raymond Chen might shed some further light.

Resources