How to programmatically move Windows taskbar? - c++

I'd like to know any sort of API or workaround (e.g., script or registry) to move (or resize) Windows taskbar to another position including another monitor (if dual monitors). Definitely, we can move task bar by using mouse, but I want to move it by a program, or a sort of automated way.
I tried to find Win32 API, but it seems no one does this job.
EDIT: I was surprised by many people's opinion. Let me explain why I wanted it. In my workplace, I'm using dual monitors (resolutions are different), and the taskbar is placed on the left monitor while the primary monitor is the right monitor. However, I often connect to my workplace computer via remote desktop. After the remote connection, the taskbar position is switched. That's why I wanted to make a simple program that can save/restore taskbar's position. Everyday I have to rearrange my taskbar. That's it. I just want it for me.

I also have this need on Windows 7. Here is my take to do this using autohotkey script:
; This script will try to drag and move the taskbar to where the *current* mouse
; cursor is
; 0x111: WM_COMMAND, 424: lock/unlock taskbar, http://www.codeproject.com/KB/miscctrl/Taskbar_Manipulation.aspx
RegRead, TaskbarLocked, HKEY_CURRENT_USER, SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced, TaskbarSizeMove
If TaskbarLocked = 0
SendMessage 0x111, 424, , , ahk_class Shell_TrayWnd
WinActivate ahk_class Shell_TrayWnd
MouseGetPos targetX, targetY
ControlGetPos x, y, w, h, MSTaskListWClass1, ahk_class Shell_TrayWnd
MouseMove x+1, y+1
MouseClickDrag Left, x+1, y+1, targetX, targetY, 10
; often after dragging the taskbar to left or right side of a monitor, even though
; there are enough room to show two columns of icons, it will only show one column,
; it seems showing or hiding an icon will fix this
Menu, Tray, NoIcon
Menu, Tray, Icon
; lock the taskbar if it was previously locked
If TaskbarLocked = 0
SendMessage 0x111, 424, , , ahk_class Shell_TrayWnd
I have tested this on Windows 7 with classic window theme. To use this, assign a hotkey to call this script, then position mouse cursor to where you want to drag the taskbar to, then press the hotkey.

The taskbar is a window. Use SetWindowPos() to move it. See also SHAppBarMessage() and ABM_WINDOWPOSCHANGED.
Though the taskbar may be special and Windows may not like you moving it around. There are a lot of special cases in the Shell appbar API implementation for the taskbar.
To move to another monitor, use EnumDisplayMonitors() with GetMonitorInfo(). Some monitors may have negative coordinates.

I've had some luck with this task in an AutoHotkey script, just in case you don't care about the language used. It uses simulated keystrokes and mouse movements to move your taskbar. I stopped short of automatically unlocking/locking the taskbar.
The hard part was getting it to work reliably. A lot of the code is dedicated to making sure that the taskbar moved. It still doesn't work 100%... it fails like 10% of the time from what I've seen. However, it should be good enough to get you started!
If I ever come back to this script to make it work perfectly, I'll repost here.
Here is the example script (highlighting is a bit odd here, as the language is AHK):
F3::
reload
return
F5::
MoveTaskbar(2,"bottom")
return
F6::
MoveTaskbar(2,"left")
return
F7::
MoveTaskbar(1,"top")
return
; Move the taskbar
; dspNumber: number. device number (primary display is 1, secondary display is 2...)
; edge: string. Top, Right, Bottom, or Left
MoveTaskbar(dspNumber, edge)
{
Critical
OutputDebug MoveTaskbar - called to move taskbar to display #%dspNumber% ("%edge%" edge)
; absolute coordinate system
CoordMode, Mouse, Screen
; error checking for dspNumber
SysGet, numMonitors, MonitorCount
if (numMonitors<dspNumber)
{
OutputDebug MoveTaskbar - [ERROR] target monitor does not exist (dspNumber = "%dspNumber%")
return
}
; get screen position for target monitor
SysGet, target, Monitor, %dspNumber%
oX := 7
oY := 7
; get coordinates for where to move the taskbar
if (edge = "Top")
{
oX := (targetRight-targetLeft)/2
trgX := oX+targetLeft
trgY := targetTop+15
}
else if (edge = "Right")
{
oY := -(targetBottom-targetTop)/2
trgX := targetRight-15
trgY := -oY + targetTop
}
else if (edge = "Bottom")
{
oX := -(targetRight-targetLeft)/2
trgX := -oX+targetLeft
trgY := targetBottom-15
}
else if (edge = "Left")
{
oY := (targetBottom-targetTop)/2
trgX := targetLeft+15
trgY := oY+targetTop
}
else
{
OutputDebug MoveTaskbar - [ERROR] target edge was improperly specified (edge = "%edge%")
return
}
trgX := round(trgX)
trgY := round(trgY)
oX := round(oX)
oY := round(oY)
OutputDebug MoveTaskbar - target location is (%trgX%,%trgY%)
MouseGetPos, startX, startY
OutputDebug MoveTaskbar - mouse is currently at (%startX%,%startY%)
; request the move mode (via context menu)
SendInput #b
SendInput !+{Space}
SendInput m
; wait for the move mode to be ready
Loop
{
if A_Cursor = SizeAll
break
}
OutputDebug MoveTaskbar - move mode is ready
; start the move mode
SendInput {Right}
; wait for the move mode to become active for mouse control
Loop
{
if A_Cursor = Arrow
break
}
OutputDebug MoveTaskbar - move mode is active for mouse control
; move taskbar (and making sure it actually does move)
offset := 7
count := 0
Loop
{
; move the taskbar to the desired location
OutputDebug MoveTaskbar - attempting to move mouse to (%trgX%,%trgY%)
MouseMove, %trgX%, %trgY%, 0
MouseGetPos, mX, mY, win_id
WinGetClass, win_class, ahk_id %win_id%
count += 1
; if the mouse didn't get where it was supposed to, try again
If ((mX != trgX) or (mY != trgY))
{
OutputDebug MoveTaskbar - mouse didn't get to its destination (currently at (%mX%,%mY%)). Trying the move again...
continue
}
; if the taskbar hasn't followed yet, wiggle the mouse!
if (win_class != "Shell_TrayWnd")
{
OutputDebug MoveTaskbar - window with class "%win_class%" is under the mouse... wiggling the mouse until the taskbar gets over here
;offset := - offset
trgX -= round(oX/2)
trgY -= round(oY/2)
oX := -oX
oY := -oY
if count = 50
{
OutputDebug, MoveTaskbar - wiggling isn't working, so I'm giving up.
return
}
}
else
break
}
OutputDebug MoveTaskbar - taskbar successfully moved
SendInput {Enter}
}

Thank you for asking this question!
Its Windows 10 now and i got the same kind of problem where i made a script to switch between a 2 screens setup and only the tv for movies. After switching back to the 2 screens setup, the taskbar is back on the right monitor, just like you experienced.
I found a solution involving modifying the registry key that defines the taskbar location.
This is the said key:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3
Open the regisrty editor while your taskbar is at the right spot and size (Win+R, type regedit", the enter), then navigate to the key path above. You should find a binary value named "Settings" that looks like this:
30 00 00 00 fe ff ff ff 02 00 00 00 03 00 00 00 4e 00 00 00 32 00 00 00 80 f8 ff ff b2 01 00 00 be f8 ff ff ea 05 00 00 60 00 00 00 01 00 00 00
Your numbers may vary, but it doesn't matter. Simply click on file>export action in the menu once you navigated to the value, then use the file->export option from the top menu, and and save the .reg file in your system forlder (C:\Windows\System32). Make sure the export range is set to "Selected Branch" so only this value is affected. This will create a registry script that will restore the exact position of your taskbar.
However, if you just use the "merge" option on your script, you won't see the change since you will need to restart the explorer.exe process. To achieve this, you can simply make a batch script in noptepad looking like this:
#echo off
%windir%\system32\regedit.exe /s file.reg
taskkill /f /im explorer.exe
start explorer.exe
end
Simply replace in the 2nd line the "file.reg" by the complete file name of the .reg script you previously created, then save the file as a ".bat".
Running this script as an admin will reset the taskbar to where it should be. You will see the ui flashing briefly, since the taskbar and desktop will reset.
You could call this script from a Task, or make a shortcut that is set to run as admin to make it even easier!
I hope this answer reaches you, even if is is a "little" late XD
Your Welcome!

As far as I can tell, Vista and onwards ignore any program trying to move the taskbar. The old method was ABM_SETPOS + MoveWindow, and this no longer works on the taskbar. The only way that I am aware of that still works is simulating a mouse move (click-move-release). I've read about that method, but I've never done it myself.

Here is a solution with PowerShell. My code is based on the solutions presented in the answers here:
2,3 | ForEach-Object {
$local:regPath = "HKCU:\$(
)SOFTWARE\Microsoft\Windows\$(
)CurrentVersion\Explorer\StuckRects$_"
$s = Get-ItemProperty $regPath |
Select-Object -ExpandProperty Settings
$s[12] = 2
Set-ItemProperty -Path $regPath -Name Settings -Value $s
}
# Restart the Explorer process so that registry is read again
Get-Process Explorer | Stop-Process
$local:stop = $false
do {
Start-Sleep -Seconds 5
$stop = Get-Process Explorer -ErrorAction SilentlyContinue
if( $stop ) { continue }
Write-Host -ForegroundColor Yellow "$(
)Explorer hasn't auto-started, attempting to restart..."
Start-Process Explorer
} until ( $stop )
The code will change to 2 (right-side) the 13th position of the Settings registry stream at the following keys:
HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2
HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3
Afterwards, it kills the explorer.exe process, waits around for 5 seconds and if explorer hasn't started again, it will start a new instance.

SHAppBarMessage(ABM_SETPOS,...)

In my experience the task bar on the left and right side clash unworkably with the rest of the experience. Even top has the problem that Preview appear outside the screen at the top.
For me this works in windows 11 to toggle task bar between top and bottom.
$RegistryPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3'
$Name = "Settings"
$NewValue = Get-ItemProperty -Path $RegistryPath
$NewValue.Settings[12] = 4-$NewValue.Settings[12]
Set-ItemProperty -Path $RegistryPath -Name $Name -Value $NewValue.Settings
Stop-Process -Name "Explorer"
Explorer is autmatically started when it is killed so there is no need to start it manually.

Related

C++ program for PC keyboard release event

I'm writing C++ code to control an User interface file. The purpose is to adjust the FPS (frame per second) of the UI after pressing the button.
Press button 1: Adjust UI to run at a low FPS.
Press button 0: Adjust UI back to run at the original FPS.
Currently, my program can work at low FPS if I press the button 1 and hold. If I press and release immediately, UI will not run at low FPS anymore. I want to make FPS being fixed at the value after pressed and released keyboard button without having to hold it.
Please tell me the way to modify my code to get my expected result.
Below is my brief code:
double ti = FPS.Tick(); // original FPS
if(Inp.Key[0] == 1)
{
ti = FPS.Tick();
do
{
ti = FPS.Tick();
}while(Inp.Key[0] != 1);
}
else if(Inp.Key[1] == 1)
{
ti = 0.001;
do
{
ti = 0.001;
}while(Inp.Key[1] != 1);
}
UI.Run(ti); // execute UI at the adjusted FPS.
if you mean release key on foreground app then use local hook. see SetWindowsHookEx on msdn . you need NULL for HINSTANCE means no dll

Session 0 capture screen

Tried https://stackoverflow.com/a/30138664/533237 and able to capture screen.
But I want to capture screen from an application running in session 0 or another user.Introduced a 10 sec sleep before capturing and switched to another user.
Also tried PsExec.exe -h -s E:\sc.exe. Both throws error
C:\Users\unity\Documents\Visual Studio 2015\Projects\ConsoleApplication2\Debug>sc.exe
FAILURE 0x8876086C (-2005530516)
line: 60 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->GetAdapterDisplayMode(adapter, &mode)'
C:\Users\unity\Documents\Visual Studio 2015\Projects\ConsoleApplication2\Debug>PsExec.exe -h -s E:\sc.exe -w E:\
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
FAILURE 0x8876086C (-2005530516)
line: 60 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->GetAdapterDisplayMode(adapter, &mode)'
Commented out GetAdapterDisplayMode and hardcoded height and width but CreateDevice failed
FAILURE 0x8876086A (-2005530518)
line: 76 file: 'c:\users\unity\documents\visual studio 2015\projects\consoleapplication2\consoleapplication2\consoleapplication2.cpp'
expr: 'd3d->CreateDevice(adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &device)'
Edited:
Idea is to have a single app running in background and capture anything getting displayed irrespective of the user logged in or even if no one is logged in (lock/login screen)
There are two levels of problems with this.
On one level, while a lot of GDI will work, session 0 is not linked to a functional display device, certainly not one that is capable of D3D.
On another level, while things like the DWM have been introduced, the Windows API has always presented a display model where invisible screen pixels simply don't exist. The entire windows display model is built around getting windows to co-operative paint to a shared display surface, and any parts of a window that are uncovered are repainted on demand by the desktop composition system.
This means, in a very fundamental way, you cannot screen capture anything from session 0 as, in order to do so, session 0 would have to be attached to the active display device.

AutoHotkey (AHK): GetKeyState not recognizing keypress made by ControlSend

I have a very complex script that depresses a key, and needs to check at cerrtain points whether that key is still depressed or not, so GetKeyState seemed perfect, but I could not get it to work, so I made a simple script doing only that, and it still doesn't recognize the state.
The script is as follows:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
~#Right::
ControlSend,, {d down}, ahk_pid 6920
Loop{
GetKeyState, dState, d
;MsgBox, d Key State: %dState%
SplashTextOn,300,50, AutoNavigatorInfo, d Key State: %dState%
WinMove, AutoNavigatorInfo, , 300, 0 ; Move the splash window to the top left corner.
}
Sadly, the splashText window I use keeps relaying dState as U. Very odd seeing as in the test window I am using, it is interacting properly with the d key depressed.
I agree with blackholyman "GetKeyState will not work for controlsend as GetKeyState Gets the global system state of the key but controlsend only sets the state locally i.e the key state is only set for one control or window."
But if you need "ControlSend for certain window functions, such as sending commandby PID" I think you can do it with Send command too. Use WinActivate to activate window that you need to send key and after use Send to send key. You can use PID with WinActivate command instead of Wintitle parameter, more about it here: http://ahkscript.org/docs/misc/WinTitle.htm
Try this code:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
~#Right::
WinActivate, ahk_pid 6920
Send, {d down}
Loop{
GetKeyState, dState, d
;MsgBox, d Key State: %dState%
SplashTextOn,300,50, AutoNavigatorInfo, d Key State: %dState%
WinMove, AutoNavigatorInfo, , 300, 0 ; Move the splash window to the top left corner.
}
GetKeyState will not work for controlsend as GetKeyState Gets the global system state of the key but controlsend only sets the state locally i.e the key state is only set for one control or window.

TouchPanelSetCalibration not updating calibration

Problem
Our product is providing a wizard to calibrate the touch screen. A special requirement is that I need to verify every new calibration which is made by this wizard. The verification is quite simple tho. After the touch screen has been calibrated a new screen containing 4 touch targets (buttons) is shown, if the user is able to hit each target within a given time frame the calibration is considered successful. If time runs out, the calibration data in the registry shall be restored and the touch driver shall be restored without restarting.
Approach
Backup of HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\TOUCH\CalibrationData
Show Windows CE built-in calibration UI using: TouchCalibrate()
Show custom verification screen as described above.
If verification failed restore registry and call TouchPanelSetCalibration(...) using old calibration data.
When calling TouchPanelSetCalibration(...) I get the following output:
Maximum Allowed Error 54:
Calibration Results:
Screen => Mapped
( 240, 136) => ( 240, 130)
( 96, 54) => ( 93, 57)
( 96, 218) => ( 99, 218)
( 384, 218) => ( 381, 220)
( 384, 54) => ( 387, 55)
Maximum error (square of Euclidean distance in screen units) = 36
The registry is properly restored and considering the output I'm assuming the calibration data is also properly forwarded to the driver.
But somehow the touch calibration is not restored without restarting the system.
Do I need to signal this change somehow by sending a message or firing an event? Do I need to make any additional API calls?
...Any help is appreciated
Thanks.
~Sambuca
I also posted this question on MSDN forums. Here's the answer I got there:
The Touch Driver Entrypoint TouchPanelSetCalibration must be called
by GWES to get the calibration data updated. When called from a user
application, the API would only update data held inside the
application process.
But there is an other approach to implement your touch calibration
wizard.
The Touch Calibration UI (calibrui) shown by TouchCalibrate() can be
customized. Basically, you'd need to replace the default confirmation
screen with your own implementation.
The instructions on how to clone the default CalibrUi can be found:
For Windows CE 5.0 in MSDN: http://msdn.microsoft.com/en-us/library/aa452834.aspx
For CE 6.0 and Compact 7: http://guruce.com/blogpost/cloning-calibrui-in-windows-ce-60

How do you exit X11 program without Error

I have a fairly simple "Hello World" in X11 at end of question. But when it exits I get the run time error messages below:
$ ./xtest
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 9 requests (7 known processed) with 0 events remaining.
So I tried handling the wmDeleteMessage myself, and I was able to stop the window from closing, so i know I am getting the event correctly. Than I added a XDestroyWindow() to the event handling and I get new errors.
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 4 (X_DestroyWindow)
Resource id in failed request: 0x130
Serial number of failed request: 12
Current serial number in output stream: 12
It sounds like i am trying to destroy a already destroyed Window, but if I take out the XDestroyWindow() it stays alive on my screen.
Below is my code with an attempt at a destroy window handler. How do I exit without any errors?
#include<X11/Xlib.h>
#include <iostream>
int main()
{
Display *display;
if(!(display=XOpenDisplay(NULL)))
{
std::cerr << "ERROR: could not open display\n";
return 1;
}
int screen = DefaultScreen(display);
Window rootwind = RootWindow(display, screen);
Colormap cmap = DefaultColormap(display, screen);
Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
int blackColor = BlackPixel(display, screen);
int whiteColor = WhitePixel(display, screen);
Window w = XCreateSimpleWindow(display, rootwind, 0, 0, 200, 100, 0, blackColor, blackColor);
XMapWindow(display, w);
XSetWMProtocols(display, w, &wmDeleteMessage, 1);
bool running = true;
while(running)
{
XEvent e;
XNextEvent(display, &e);
switch (e.type)
{
case ClientMessage:
if(e.xclient.data.l[0] == wmDeleteMessage)
{
std::cout << "Shutting down now!!!" << std::endl;
XDestroyWindow(display,e.xdestroywindow.window);
running=false;
break;
}
break;
}
}
XCloseDisplay(display);
return 0;
}
Update
Changed line to :
std::cout << "Shutting down now!!!" << std::endl;
XDestroyWindow(display,w);
Which I don't like because I plan on having more than window, but for now I am
back to the first error message I had :
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 9 requests (7 known processed) with 0 events remaining.
Update
Tried changing many things around like having the loop run off of XPending().
Decided to run someone else's hello world and I get the same problem with their code. Must be something wrong with my setup.
Update
Apparently alot of people have this problem. Google ftk had this problem and they fixed it in their change log. They call FTK_QUIT() which i am guessing is like Exit(). So i put my return right there inside the loop and that solved the problem. Not sure why but it did. fixed code:
case ClientMessage:
if(e.xclient.data.l[0] == wmDeleteMessage)
{
XDestroyWindow(display,e.xclient.window);
XCloseDisplay(display);
return 0;
}
Will still give correct answer to someone who can explain why and if is possible move the return statement (along with the XCloseDisplay) outside of the loop.
The Event loop should look like this to exit properly:
XEvent e;
do
{
XNextEvent(display, &e);
if(e.type == ClientMessage && e.xclient.data.l[0] == wmDeleteMessage)
{
XDestroyWindow(display,e.xclient.window);
break;
}
//...
}while (XPending(display) > 0)
XCloseDisplay(display);
return 0;
When running in a switch statement the code does not work. Even if it exits the loop without calling another X function. The if statement above placed before your switch statement fixes the issue without returning from the program inside the loop.
The solution to this problem is straightforward:
You must use the right structure member with the XDestroyWindow() function.
Due to the implementation standard of the X11 event structures, they're very similar each other. Every structure begins with the 'type' member, and the first members are practically always the same.
Now assume:
int = 4 bytes
Bool = 4 bytes
unsigned long = 8 bytes
Display* = 8 bytes
Window = 4 bytes
If you call XDestroyWindow() with e.xdestroywindow.window, you are going to be 28 bytes away from the beginning of the event structure, while if you use e.xclient.window, you would be 24 bytes away.
Since you're going to call XDestroyWindow() with a wrong Window argument, it will fail. Instead if you call it using e.xdestroywindow.event (which is 24 bytes away from the beginning of the event structure), the address would be right and the function would work gracefully.
If you take a look yourself at the Xlib.h file, you'll notice that the two structures have the window element positioned differently.
Stated this, remember that Xlib has been developed for years and many programmers every day work with it, so if there is a mysterious error, it's probably not within Xlib. As a last hint I want to tell you: if you want to get farther with Xlib programming, always take the header files as the primary reference, followed by the system manual, then all the rest.
The only error with your code in the end is:
XDestroyWindow(display,e.xdestroywindow.window);
Which must be changed to this:
XDestroyWindow(display,e.xclient.window);
Instead the usage of switch is good, and is the most implemented, with no issues on the X11 code.
NOTE: I've tested your code myself, by changing that line only, and then doing various tests, printing the result. The XDestroyWindow() line is for sure the only error.
Just call XDestroyWindow() right before XCloseDisplay().
Edit:
Sorry, I didn't understand the XSetWMProtocols thing. Now I've read up on it. I think you're accessing the wrong member of the event union.
XDestroyWindow(display,e.xdestroywindow.window);
Should probably be:
XDestroyWindow(display,e.xclient.window);
I had the same problem, and after digging through Xlib documentation and a lot of experimenting I think I know the answer to your question and I can explain it to you.
When you call XCreateWindow or XCreateSimpleWindow and then XMapWindow, you instruct the X Server to create your window and map in onto the screen. After sending these commands from the local buffer to the server (by calling XFlush or any function which requests some data from the server, since it implicitly flushes the command buffer), the X Server displays your window. Then it's a job of the Window Manager to attach all the decorations to your window, e.g. some borders, title bar, window menu and those buttons to minimize/maximize/close the window.
Now your window is being displayed, and after a while you can decide to destroy it with XDestroyWindow and close the connection to the X Server by calling XCloseDisplay, and everything will be fine, no errors.
The problem is that when the user clicks on that X on your window's title bar, it is not the job of the X Server to handle it, but the Window Manager's job (the X Server knows nothing about those decorations and it doesn't care). The usual reaction of the Window Manager when the user closes the top-level window of your program is to destroy the window and close the connection to the X Server, because that's what most users would expect. Your program may still run off-screen, but the top-level window is usually associated with the X Server connection by the Window Manager.
So when the Window Manager destroys your window, you cannot call XDestroyWindow, because the window is already destroyed and its Window handle is invalid. You will get an error about BadWindow. You also cannot call XCloseDisplay, because the connection to the X Server is already closed, and this will cause the XIO: fatal IO error 11 (Resource temporarily unavailable) on X server error many users experience from applications whose authors didn't knew that. It is a common mistake, because in one hand you are encouraged to clean up after yourself, but in the other hand the documentation is misleading about how this should be done properly.
There is a convention, though, about how X Server and Window Manager should cooperate, which also covers responding to user's commands to close the top-level window. There's an extension to the X protocol that handles it. Here's how the Xlib documentation explains it:
Clients, usually those with multiple top-level windows, whose server connection must survive the deletion of some of their top-level windows, should include the atom WM_DELETE_WINDOW in the WM_PROTOCOLS property on each such window. They will receive a ClientMessage event as described above whose data[0] field is WM_DELETE_WINDOW.
[...]
Clients that choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property may be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.
So there are two solutions to this problem: either avoid calling XDestroyWindow and XCloseDisplay when your window is being closed by the Window Manager and not by yourself (you actually don't have to clean up the top-level window since the X Server will destroy it nevertheless when your program ends), or you need to register the WM_DESTROY_WINDOW extension and wait for notification from the Window Manager when it is instructed by the user to close your window (it will send you a ClientMessage event then, with its data[0] set to WM_DELETE_WINDOW). And after receiving it just destroy the window and close the connection to the X Server yourself, and end your program. Or leave the connection to the X Server open to perform some more communication with it if you wish. When you handle WM_DESTROY_WINDOW, the Window Manager will not try to destroy your window nor close the connection to the X Server.
// this code from : https://en.wikibooks.org/wiki/X_Window_Programming/Xlib don't show error...
/*
Simple Xlib application drawing a box in a window.
To Compile: gcc -o test test.c -lX11 */
#include<X11/Xlib.h>
#include<stdio.h>
#include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc
int main() {
Display *d;
int s;
Window w;
XEvent e;
/* open connection with the server */
d=XOpenDisplay(NULL);
if(d==NULL) {
printf("Cannot open display\n");
exit(1);
}
s=DefaultScreen(d);
/* create window */
w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s));
// Process Window Close Event through event handler so XNextEvent does Not fail
Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 );
XSetWMProtocols(d , w, &delWindow, 1);
/* select kind of events we are interested in */
XSelectInput(d, w, ExposureMask | KeyPressMask);
/* map (show) the window */
XMapWindow(d, w);
/* event loop */
while(1) {
XNextEvent(d, &e);
/* draw or redraw the window */
if(e.type==Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
}
/* exit on key press */
if(e.type==KeyPress)
break;
// Handle Windows Close Event
if(e.type==ClientMessage)
break;
}
/* destroy our window */
XDestroyWindow(d, w);
/* close connection to server */
XCloseDisplay(d);
return 0;
}