Stop being topmost window - windows

My window should be on top of a specific "target" window that I don't have control over.
When the target window is activated, I call SetWindowPos with HWND_TOPMOST to place my window on top of it while the target can still be the active window.
When the target window is no longer the foreground window, I want my window to still be on top of the target window, but no longer topmost, so other windows are not covered by it.
Two ideas I had:
Call SetWindowPos with hWndInsertAfter to be the just activated window. This fails when the just activated window is topmost, because my window then does not lose the topmost status. Another issue with this: If the just activated window is the desktop, then my window is placed below the target window.
Call SetWindowPos with HWND_NOTOPMOST to lose the topmost status. However, this brings my window to the top of all non-topmost windows, so it covers the just activated window. To fix this I have to bring the just activated window on top again with another SetWindowPos with HWND_TOP. This feels like the wrong way to do it and may cause flicker.
Is it possible to have a window just stop being topmost and placing it below the current foreground window?

The only automatic method to make a window permanently on top of another one whether the target window is top-most or not is an owner/owned relationship. You could try using SetParent to create this relationship but note that Raymond Chen does say it's not recommended.
Assuming you're tracking window activations somehow, I think your SetWindowPos idea (the first one) is the way to do it, with the following modification:
When the target window is active, set your window to HWND_TOPMOST
When the target loses activation, insert your window after the target window's immediate predecessor in the z-order (i.e. effectively still on top of the target window, but not top-most)
Something like this psuedo-code:
if (foregroundwindow == targetwindow)
SetWindowPos(my_window, HWND_TOPMOST, ...);
else
{
HWND hwndPred = GetWindow(targetwindow, GW_HWNDPREV);
if (!hwndPred)
{
// no predecessor so my_window will still be on top, just not top-most any more
if (GetWindowLong(targetwindow, GWL_EXSTYLE) & WS_EX_TOPMOST)
hwndPred = HWND_NOTOPMOST;
}
SetWindowPos(my_window, hwndPred, ...);
}

Related

How to capture the action about starting dragging a window and releasing the capture of a window?

When cursor honver over the title zone (HTCAPTION),press left mouse button, then you can drag a window and move it. When you release the left mouse button , you can stop this dragging action. When you move a window , it triggered the message WM_MOVE. When release the mouse button , I don't know which message should be handled for catching this action.
What I'm doing is when you drag a window(let's say window A) into another window's area(window B), make window A a child window of window B, when drag window A out of window B's area , make window A a WS_POPUP window, without WS_CHILD style.
I handled message WM_MOVE and WM_CAPTURECHANGED( I don't think it's the right one).
In WM_CAPTURECHANGED , I found something wired. The API SetWindowPos seemed not work well. To be percise, the 3rd and the 4th parmater , specified the window's position not work.
case WM_CAPTURECHANGED: {
RECT rcc;
GetClientRect(main,&rcc);
// here main is the handler of window B , hwnd is for window A,as referrence above.
if(docker_mode==DOCKER_LEFT) {
// docker_mode is assigned by WM_MOVE message handler. recording which area window A was moved into.
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))!=WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,(~WS_POPUP)&(WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE)));
SetParent(hwnd,main);
}
//The following code not work. It should be moved into the left-top corner of window B,
//but NOT in fact.
SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_NOZORDER);
}
else {
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,((~WS_CHILD)&GetWindowLongPtr(hwnd,GWL_STYLE))|WS_POPUP);
SetParent(hwnd,NULL);
SetWindowPos(hwnd,NULL,300,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
}
}
} break;
SetWindowLongPtr(...,GWL_STYLE,...) was called to set the window style . A top level has no WS_CHILD style, and the handle of parent window should be NULL , I use SetParent(hwnd,NULL) to do this. A child window should have WS_CHILD style, and the parent window should be assigned.
I put a button into the window , and copy those code into the handle of button click event. When click the button it works well , change a popup window into a sub window , put the sub window into right position. SetWindowPos has no problem at all. I don't know why.
SetWindowPos is a very interesting API when working on WM_CAPTURECHANGED handler. What's wrong ?
If I recall correctly, when the user drags a window, that window receives a sequence of messages like this:
WM_ENTERSIZEMOVE
WM_WINDOWPOSCHANGING
WM_MOVING
WM_WINDOWPOSCHANGED
WM_MOVE
WM_EXITSIZEMOVE
(There are other messages, too, but I don't think you need to worry about those. There may be some final messages after WM_EXITSIZEMOVE with the final resting place for the window.)
The steps in the middle will happen repeatedly as the user drags the window. (In the Old Days, only some of those middle steps would happen, and there may still be an option to cut down on the messages during the drag operation.)
You can try using Spy++ (included with Visual Studio) to confirm the above.
So you shouldn't need to deal with the mouse capture messages. Have window A watch for WM_EXITSIZEMOVE. At that point, window A can check its position to see if it overlaps the target window (B). If it does overlap, then it should send a message to window B to initiate the docking operation.

How can I change the owner of a Windows window?

I have a floating window that is owned by my app's main frame window. Now, I have created a new frame window and I want to change the owner of the floating window to the new frame window I created. But, I have not been able to find a way to do so.
Essentially, as a user activates either of my frame windows, I want to make the newly activated frame the owner of the floating window.
I tried SetParent hoping if I didn't change the style of the floating window from WS_POPUP to WS_CHILD, that would be a trick that would work but the floating window just fails to display after doing that. And, it is actually becomes a child window in that it shows up when enumerating the child windows of the frame I passed to SetParent.
Is it possible to change the owner of a window after calling CreateEx where I pass in the initial owner?

How can i draw to or add a custom button to every window of all applications?

I have seen several tools adding a custom button and/or drawing on the title bar of all windows of all applications in Windows. How is that done?
Extra points for an example in Delphi.
EDIT:
I found something for dotNET that does this:
http://www.thecodeking.co.uk/2007/09/adding-caption-buttons-to-non-client.html#.VdmioEDenqQ
How I see this job:
First of all we should be able to paint this button on the our own window caption. This procedure will be used later
This part of the program enumerates the active and visible windows
This part of the program using injection attach our dll to enumerated windows
From injected dll we can draw the button on the window caption
Inside this dll we should process the click on the button
We should have mechanism to send result to our main program
I haven't done this, so the following is what I would investigate if I were to try:
For each application / each top-level window:
Create a floating window and position it over the title bar wherever you want it to sit. Set up the parent / child relationship, but this window is part of your own process. (There are occasionally problems parenting a window from one process to one from another process, but try. I'd avoid injecting into other processes if possible.)
You can investigate the window flags to see if the window has a title bar (ie if you should add a button) via GetWindowLong with GWL_STYLE looking for WS_CAPTION. The same call will also let you see the type of caption / frame, which you can combine with GetSystemMetrics with, eg, SM_CYDLGFRAME to figure out the right size for your button on this specific window's title bar.
This window is now your button: paint, handle clicks etc as appropriate.
Make it a non-focusable window so that clicks to it don't take focus away from the window is is on the title bar of. You don't want clicking it to make the title bar change colour, for example. Do this by setting the WS_EX_NOACTIVATE window flag, something like: SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) orWS_EX_NOACTIVATE).
The main problem is to keep it positioned correctly when the window moves, is resized, etc. To do this, install a hook for the system move events. You can also hook minimize and restore via EVENT_SYSTEM_MINIMIZESTART and EVENT_SYSTEM_MINIMIZEEND. This will allow you to keep track of all windows moving around onscreen, such that you can adjust the button-window position if necessary.
That gives you a window which you can paint as a button (and respond to clicks etc), that visually is "attached" to other windows so it stays in the same place as the user drags the title bar, minimizes or maximises the app, etc, and that is in your own process without cross-process problems.

XLIB Decoration questions

I'm writing a small window manager, that add a basic decoration around a window, but actually i have several question about adding/remove decoration of a window.
First Question
Actually the decoration is added during MapNotify event, but it seems to be not a good idea, because it add decoration also to a menu opened by an application everytime the mapnotify is fired with a new window, but i want only to add decoration to main window. Maybe i have to check if the current window is a child of another window ? Actually my code just create the decoration window with a specific name, so at every MapNotify request i give the decoration window a dummy name (Parent) to distinguish it from all other windows in that way if the MapNotify event is launched on a decoration window, at least it doesn't add another decoration.
But i don't understand if MapNotify is launched not only for parent window but also for childrend probably the risk is that i add more than one decoration window.
The actual code is the following:
void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){
printf("Map Notify\n");
XWindowAttributes win_attr;
char *child_name;
XGetWindowAttributes(display, local_event.xmap.window, &win_attr);
XFetchName(display, local_event.xmap.window, &child_name);
printf("Attributes: W: %d - H: %d - Name: %s\n", win_attr.width, win_attr.height, child_name);
if(child_name!=NULL){
if(strcmp(child_name, "Parent")){
Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num,
win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0,
BlackPixel(display, infos.screen_num));
XMapWindow(display, new_win);
XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT);
XSelectInput(display, local_event.xmap.window, SubstructureNotifyMask);
put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num));
}
}
XFree(child_name);
}
So how to avoid adding of decoration on every window except the main application window (or the popup windows, there is a way to distinguish the type of window? How can i figure it out?)
Second Question
WHen i exit a program the window that is destroyed is just the application window not the parent decoration, how to destroy the current window and also the decoration?
I tried with the following:
void destroy_notify_handler(XEvent local_event, Display *display){
Window window = local_event.xdestroywindow.event;
XDestroyWindow(display, window);
}
But i receive the following error:
Error occurred: BadWindow (invalid Window parameter)
I use event instead of window because it seems that it contains the parent window (i read it from there: http://tronche.com/gui/x/xlib/events/window-state-change/destroy.html)
But even if i use window i have the same problem.
Or maybe i have to destroy the parent window earlier? Maybe during UnMapNotify? But how to understand if the event is launched just because the window is going to be closed or for some other reasons?
Thanks for the help :)
Read EWMH spec and you'll find answers to all questions.
Check "override redirect" window flag
You are trying
to destroy window which is already destroyed. Instead of using
event.xdestroywindow.event window id just delete your decoration
window.
Don't forget to add client window to save set if you are
writing reparenting WM. That way if you kill wm application windows
are not destroyed but reparented back to root window

Problem when maximizing window in C++

My program needs to arbitrarily maximize any window on the current desktop. I achieve this by calling ShowWindow(hWnd, SW_MAXIMIZE), where hWnd is the HWND of the window I want to maximize. When that line of code executes, the window in question (here, Notepad) looks like this:
Everything seems fine, except for the fact that the window has not been positioned correctly, i.e. the window seems to be a few pixels to low, and the title bar does not look "squashed" like it should. Compared to how it should look when the maximize button is clicked, the problem is clearly visible:
Does anyone know why this behaviour occurs, and what I can do to fix it?
Telling the window to maximize itself might bypass some internal adjustments that the program makes when it maximizes via a system menu command. To emulate clicking on the maximize button, send it a SC_MAXIMIZE command:
SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
Antoher way to use SetWindowPos(); For example you got HWND handleWnd;
RECT rcWnd;
GetWindowRect(handleWnd,&rcWnd);
SetWindowPos(handleWnd,WHND_TOP,rcWnd.left,rcWnd.top,(rcWnd.right-rcWnd.left),(rcWnd.bottom-rcWnd.top),SWP_SHOWWINDOW);
So you got your previous position, place window on top of Z and show

Resources