I want to get the (accurate) on-screen X and Y coordinates of a window (the client area). My problem is that I have to define a horizontal shift which has to be added onto the X coordinate to get the correct result:
#include <windows.h>
inline int get_title_bar_thickness(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
const int height = window_rectangle.bottom - window_rectangle.top -
(client_rectangle.bottom - client_rectangle.top);
const int width = window_rectangle.right - window_rectangle.left -
(client_rectangle.right - client_rectangle.left);
return height - width / 2;
}
#define HORIZONTAL_SHIFT 8
/**
* Gets the window position of the window handle
* excluding the title bar and populates the x and y coordinates
*/
inline void get_window_position(const HWND window_handle, int* x, int* y)
{
RECT rectangle;
const auto window_rectangle = GetWindowRect(window_handle, &rectangle);
const auto title_bar_thickness = get_title_bar_thickness(window_handle);
if (window_rectangle)
{
*x = rectangle.left + HORIZONTAL_SHIFT;
*y = rectangle.top + title_bar_thickness;
}
}
The issue can be observed by moving the window programmatically:
const auto window_handle = FindWindow(nullptr, "Command Prompt");
SetWindowPos(window_handle, nullptr, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
I would expect this SetWindowPos() call to perfectly place the window into the upper left corner of my screen but there is some space left between the window and the screen border (exactly 8 pixels). Is there a way to assure that this horizontal offset is automatically considered? This might be related to laptops so how to make this behave as expected?
As commented by Castorix, the horizontal shift can be retrieved.
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
inline int get_horizontal_shift(const HWND window_handle)
{
RECT window_rectangle, frame_rectangle;
GetWindowRect(window_handle, &window_rectangle);
DwmGetWindowAttribute(window_handle,
DWMWA_EXTENDED_FRAME_BOUNDS, &frame_rectangle, sizeof(RECT));
return frame_rectangle.left - window_rectangle.left;
}
The code is based on this post. The return value is 7 on my machine.
Related
I was trying to get the height of the title bar of a specific window on Windows. You can replicate it with Notepad. I'm using C++ and none of the codes I found online yielded the correct result. Using e.g. Screenpresso I measured 31 pixels for my window bar height.
The functions I tried are the following:
TitleBarHeight.h:
#pragma once
#include <windows.h>
inline int get_title_bar_thickness_1(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
return window_rectangle.bottom - window_rectangle.top -
(client_rectangle.bottom - client_rectangle.top);
}
inline int get_title_bar_thickness_2(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
return (window_rectangle.right - window_rectangle.left - client_rectangle.right) / 2;
}
Results:
auto window_handle = FindWindow("Notepad", nullptr);
auto a = get_title_bar_thickness_1(window_handle); // 59
auto b = get_title_bar_thickness_2(window_handle); // 8
auto c = GetSystemMetrics(SM_CXSIZEFRAME); // 4
auto d = GetSystemMetrics(SM_CYCAPTION); // 23
Getting the system metrics with GetSystemMetrics() does not work because windows can have different title bar heights obviously and there is no argument for the window handle.
How can I really get the result of 31?
Assuming that you don't have menu bar, you can map points from client coordinate system to screen one
RECT wrect;
GetWindowRect( hwnd, &wrect );
RECT crect;
GetClientRect( hwnd, &crect );
POINT lefttop = { crect.left, crect.top }; // Practicaly both are 0
ClientToScreen( hwnd, &lefttop );
POINT rightbottom = { crect.right, crect.bottom };
ClientToScreen( hwnd, &rightbottom );
int left_border = lefttop.x - wrect.left; // Windows 10: includes transparent part
int right_border = wrect.right - rightbottom.x; // As above
int bottom_border = wrect.bottom - rightbottom.y; // As above
int top_border_with_title_bar = lefttop.y - wrect.top; // There is no transparent part
Got 8, 8, 8 and 31 pixels (96DPI aka 100% scaling setting)
You should also take into account DPI awareness mode. Especially GetSystemMetrics is tricky because it remembers state for System DPI when your application was launched.
Send a message WM_GETTITLEBARINFOEX to the window, and you will get the bounding rectangle of the title bar.
TITLEBARINFOEX * ptinfo = (TITLEBARINFOEX *)malloc(sizeof(TITLEBARINFOEX));
ptinfo->cbSize = sizeof(TITLEBARINFOEX);
SendMessage(hWnd, WM_GETTITLEBARINFOEX,0, (LPARAM)ptinfo);
int height = ptinfo->rcTitleBar.bottom- ptinfo->rcTitleBar.top;
int width = ptinfo->rcTitleBar.right - ptinfo->rcTitleBar.left;
free(ptinfo);
First, make sure your application is high DPI aware so that the system doesn't lie to you.
Options:
Trust GetSystemMetrics. Nearly any top-level window that actually has a different caption size is doing custom non-client area management which is going to make it (nearly) impossible. The obvious exception is a tool window (WS_EX_TOOLWINDOW) which probably has a SM_CYSMCAPTION height if the WS_CAPTION style is also set.
Get the target window rect and the target window's style. Use AdjustWindowRectEx to determine the size differences with the WS_CAPTION style toggled. I'm not sure if this will work because there may be some interaction between on whether you can have a caption without some kind of border.
Get the target window rect and send WM_HITTEST messages for coordinates that move down the window. Count how many of those get HT_CAPTION in return. Bonus points if you do this with a binary search rather than a linear search. This is probably the hardest and the most reliable way to do it, assuming the window has a rectangular caption area.
If I've understood correctly, it looks like you want to take the border size of the window (which we should be able to gather from the width as there is no title bar) and subtract it from the the verticle size minus the client window...
inline int get_title_bar_thickness(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
int height, width;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
height = (window_rectangle.bottom - window_rectangle.top) -
(client_rectangle.bottom - client_rectangle.top);
width = (window_rectangle.right - window_rectangle.left) -
(client_rectangle.right - client_rectangle.left);
return height - (width/2);
}
I am currently using the MoveWindow() function in the header Windows.h, and using this function, I can move and resize the output console window any way I want.
MoveWindow(GetConsoleWindow(), x, y, width, height, TRUE);
// x and y is the position of the topleft corner of window
However, I cannot figure out how to center the screen without hard-coding the position of the window. Is there a way to set the position of the window to change depending on the width and height that I set? Thanks!
P.S. I am pretty new to C++
Get the WindowRect ( not to confuse with the ClientWindow)of your screen and find middle position, but ClientRect will remain unchanged since we are not resizing.Try this snippet:
Edited: For proper centering and to allow user to specify the position
void MoveWindow(int posx, int posy)
{
RECT rectClient, rectWindow;
HWND hWnd = GetConsoleWindow();
GetClientRect(hWnd, &rectClient);
GetWindowRect(hWnd, &rectWindow);
MoveWindow(hWnd, posx, posy, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top, TRUE);
}
void MoveCenter()
{
RECT rectClient, rectWindow;
HWND hWnd = GetConsoleWindow();
GetClientRect(hWnd, &rectClient);
GetWindowRect(hWnd, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2,
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2,
MoveWindow(hWnd, posx, posy, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top, TRUE);
}
int main(int argc, char *argv[])
{
MoveWindow(10, 10);
return 0;
}
I have refereed below article to draw a custom frame area with DWM.
Custom Window Frame Using DWM
After removing the standard frame, non client area is not exist in the frame.
void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
int nTHight = 30; /*The title bar height*/
RECT * rc;
RECT aRect;
RECT bRect;
RECT bcRect;
if(bCalcValidRects == TRUE)
{
CopyRect(&aRect,&lpncsp->rgrc[1]);
CopyRect(&bRect,&lpncsp->rgrc[0]);
bcRect.left = bRect.left;
bcRect.top = bRect.top - nTHight;
bcRect.right = bRect.right;
bcRect.bottom = bRect.bottom;
CopyRect(&lpncsp->rgrc[0],&bcRect);
CopyRect(&lpncsp->rgrc[1],&bRect);
CopyRect(&lpncsp->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lpncsp;
rc->left = rc->left;
rc->top = rc->top - nTHight;
rc->right = rc->right;
rc->bottom = rc->bottom;
}
CFrameWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
Because the entire window is client region, I have to adjust the UI control placement for the frame, but I don't know how to handle this problem.
For example, below red rectangle (all UI component) should be shifted into the original coordinate of the client area before removing the non client part.
CWnd::GetWindowRect gives you the rectangle of the window on screen. The dimensions of the caption, border, and scroll bars, if present, are included.
CWnd::GetClientRect gives you the client rectangel of the window. The left and top members will be 0. The right and bottom members will contain the width and height of the window.
CWnd::ScreenToClientand CWnd::ClientToScreen calculate a point or rectangle from the client area to screen coordinates and back to screen.
AdjustWindowRect calculates the required window rectangle, based on the client rectangle of the window.
Here is afunction which calcualtes the margins of a window:
void CalculateWndMargin( const CWnd &wnd, int &leftM, int &rightM , int &topM, int &bottomM )
{
CRect wndRect;
wnd.GetWindowRect( wndRect );
CRect screenRect;
wnd.GetClientRect( screenRect );
wnd.ClientToScreen( screenRect );
leftM = screenRect.left - wndRect.left;
rightM = wndRect.right - screenRect.right;
topM = screenRect.top - wndRect.top;
bottomM = wndRect.bottom - screenRect.bottom;
}
int width = 800;
int height = 600;
int interval = 1000 / 60;
int score_player1 = 0;
int score_player2 = 0;
int racket_width = 10;
int racket_height = 80;
int racket_speed = 8;
int racket_left_x = 10;
int racket_left_y = 50;
int racket_right_x = width - racket_width - 10;
int racket_right_y = 50;
Full code (without the class for the ball): http://pastebin.com/TA9NkV5c
The margin from the right racket to right side of the window is smaller than the left side. The variables for those are right calculated, but still, it is not equally.
http://i.imgur.com/2PA0pGz.png Link to the image
You've set the window to a width of 800 pixels, but everything else is positioned relative to the client region, which is narrower than the window width by the thickness of the border.
Use AdjustWindowRect to compute the size you have to make the window in order get the client area to be the desired size.
// Initialize a RECT with the size you want the client area to be.
RECT rc = { 0, 0, width, height };
// Now adjust the rectangle to the size the window would need to be.
AdjustWindowRect(&rc, my_style_flags, FALSE);
// Now create the window using the sizes in rc. Make sure you use
// consistent style flags or the adjustment may not be correct.
const int window_width = rc.right - rc.left;
const int window_height = rc.bottom - rc.top;
my_hwnd = CreateWindow(..., my_style_flags, x, y, window_width, window_height, ...);
I want to resize a window with Xlib so I made a function (she is inside a class) :
int setSizeAndMove(int top, int left, int width, int height)
{
XMoveResizeWindow(m_display, m_window_terminal, top, left, width, height);
return 1;
}
This function works fine. I have another function who return the size of the current window :
Rect getWindowSize() const
{
XWindowAttributes size_win;
XGetWindowAttributes(m_display, m_window_terminal, &size_win);
Rect size_return;
size_return.X = size_win.width;
size_return.Y = size_win.height;
return size_return;
}
(Rect is just a structur that contain int X & int Y)
My problem is when I do something like this :
setSizeAndMove(0, 0, getWindowSize().X + 10, getWindowSize().Y + 10);
The window correctly add 10 pixel to width but not to height, why ?
//Additional question with 0,0 the window isn't in the top left but something like 5,5.
Thanks for help.