How to get the physical display resolution in SDL2? - sdl

I have tried
SDL_DisplayMode DM;
SDL_GetDesktopDisplayMode(0, &DM);
auto Width = DM.w;
auto Height = DM.h;
but on a high-DPI display it returns the virtual screen resolution. SDL_GetCurrentDisplayMode does the same.
So, how can I get the physical screen size also on high-DPI displays?

The only way seems to be to create a fullscreen SDL_Window (passing SDL_WINDOW_ALLOW_HIGHDPI in the flags) and query its "drawable size" with SDL_GL_GetDrawableSize.

Related

Calculate font "size" in DIPs of a system font

I have few BS_OWNERDRAWN buttons and using Direct2D and Direct Write to draw them.
I also need to draw button text within button rectangle, for this I use IDWriteTextFormat which requires to specify "font size" in DIPs (device independent pixels).
I want font size in those buttons to be of same size as other non owner drawn common controls or same as system font that is present in window caption bar.
Following code is "chopped out" version to present my workaround which of course doesn't give expected results because I get LOGFONT structure of a font in caption bar which gives me the width of a font (single character) but not font size that the IDWriteTextFormat expects to specify font size in DIPs.
class CustomControl
{
protected:
/** Caption text format used to draw text */
CComPtr<IDWriteTextFormat> mpTextFormat;
/** Caption font size (button text size) */
float mFontSize;
};
// Calculate caption bar (default) font size of a top level window
void CustomControl::CalculateFontSize()
{
NONCLIENTMETRICSW metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
LOGFONTW font = metrics.lfCaptionFont;
mFontSize = static_cast<float>(font.lfHeight);
}
// Create text format that is of same font size as default system font
HRESULT CustomControl::CreateTextFormat()
{
HRESULT hr = S_OK;
if (!mpTextFormat)
{
CalculateFontSize();
hr = mpWriteFactory->CreateTextFormat(
L"Arial",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
mFontSize, // <-- Specifies font size in DIP's..
L"en-us",
&mpTextFormat);
}
return hr;
}
Here is test program that shows the differences in font size between default system font in window caption and custom button text below.
I need help in figuring out how to correctly calculate font size for IDWriteTextFormat parameter to be of same size as text in other common controls that are not BS_OWNERDRAW or in this example default font in window caption.
EDIT:
I figured out issue is in my CalculateFontSize() I wrote mFontSize = static_cast<float>(font.lfHeight); but this is negative number so appending - sign gives the expected result:
mFontSize = static_cast<float>(-font.lfHeight);
Why negative? I'm not sure yet but this answer helped:
How to set font size using CreateFontA?
Now my question remains in that how should I update CalculateFontSize() so that it gets font size of common controls that are not BS_OWNERDRAW instead of a window caption bar font size?
I figured out to calculate font size of other common controls to be used for IDWriteTextFormat the formula is simple:
float CustomControl::CalculateFontSize()
{
const long units = GetDialogBaseUnits();
const DWORD height = HIWORD(units);
return static_cast<float>(height);
}
Only problem with this is if you use custom font for common controls, or if your dialog uses different font then you need to update your CalculateFontSize() to take these changes into account.
However for your TextFormat to be truly consistent with native common controls you also need to apply font weight (boldness), for example after you create TextLayout (by using your TextFormat):
std::size_t caption_len = 0;
StringCchLengthW(mCaption, STRSAFE_MAX_CCH, &caption_len);
DWRITE_TEXT_RANGE range = { 0u, caption_len };
mpTextLayout->SetFontSize(mFontSize, range);
mpTextLayout->SetFontWeight(DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_BOLD, range);

How to get the handle of the active window in win32 using c++?

[![enter image description here][1]][1]I am trying to capture the active window in Win32 using C++. With the BitBlt function I am able to capture, but once another window opens, the same window which I have already captured should only be captured. I don't want the other window which I have opened, it should be black. Can someone help with a solution?
https://www.codeproject.com/Articles/20367/Screen-Capture-Simple-Win32-Dialog-Based
void CaptureActiveWindow(void)
{
RECT ActWndRect;
WCHAR buf [100],buf1[20];
int xSrc=0,ySrc=-19;
int DepcWidth=10, DepcHeight=5;
OutputDebugString(L"Start capture act window ");
HDC ActWndDC = GetDC(hWndActWnd); //DC for the window you have clicked on
MemDC = CreateCompatibleDC(ActWndDC); //Memory DC Compatible with Above DC
GetWindowRect(hWndActWnd,&ActWndRect); //Will Store the Windows Are in Rectangle
wsprintf(buf,L"x1 = %d , y1 = %d, x2 = %d y2 =%d",ActWndRect.left,ActWndRect.top,ActWndRect.right,ActWndRect.bottom);
OutputDebugString(buf);
int Width = ActWndRect.right-ActWndRect.left; //Width of the Window
int Height =ActWndRect.bottom-ActWndRect.top; //Hight of the Window
if(GetWindowText(hWndActWnd,buf1,20) >0)
{
OutputDebugString(buf1);
}
if(CaptureControl)
{
ySrc= DepcWidth = DepcHeight = 0;
}
HBITMAP hBitmap = CreateCompatibleBitmap(DlgDC,Width-DepcWidth,Height-DepcHeight);//Will Create Bitmap Comatible With Our Window
SelectObject(MemDC,hBitmap);
BitBlt(MemDC,0,0,Width,Height,ActWndDC,xSrc,ySrc,SRCCOPY);//Will Copy the Window into MemDC
//BitBlt(DeskDC,110,110,Width,Height,MemDC,Begpt.x,Begpt.y,SRCCOPY);
SaveBitmap(MemDC, hBitmap,"Sample.bmp"); // will Save DC into .bmp File
ShowImage(); //Will Show u the .bmp File in MSPAINT.
}
Hook the mouse event Before sending active message to the window. Use WindowFromPoint to get the specified window(Hwnd). Then use GetWindowRect to get the window rect area. In this area, call WindowFromPoint for all the point in the rect, compare it with Hwnd(if it is a child window or not), and get the overlap RECT. After getting the bitmap of the capture window and then overwrites the black on the covered rect.
PS: I encounter BITMAPINFO error: Run-Time Check Failure #2 - Stack around the variable was corrupted.
Here provide a solution.
You can't capture the image of Chrome using BitBlt(), unless disable the Hardware Acceleration option of Chrome. But PrintWindow() works with PW_RENDERFULLCONTENT flag. When use it, the image in center will have a black border. While using PrintWindow (hWndActWnd,ActWndDC,0x00000003) align the image to the left.Then modify cx and cy of CreateCompatibleBitmap(), you can remove the border easily.

wxWidgets screenshot leaves most of image blank when applying to wxstaticbitmap

When I tried capturing the wxwidgets screenshot, it doesn't showed any error. If I save it, it saves perfectly. But when I try to add it to a static bitmap, it just shows some icons and everything leaves transparent.
wxClientDC dcScreen(GetParent());
//Get the size of the screen/DC
wxCoord screenWidth, screenHeight;
dcScreen.GetSize(&screenWidth, &screenHeight);
//Create a Bitmap that will later on hold the screenshot image
//Note that the Bitmap must have a size big enough to hold the screenshot
//-1 means using the current default colour depth
screenshot.Create(screenWidth, screenHeight,-1);
//Create a memory DC that will be used for actually taking the screenshot
wxMemoryDC memDC;
//Tell the memory DC to use our Bitmap
//all drawing action on the memory DC will go to the Bitmap now
memDC.SelectObject(screenshot);
//Blit (in this case copy) the actual screen on the memory DC
//and thus the Bitmap
memDC.Blit( 0, //Copy to this X coordinate
0, //Copy to this Y coordinate
screenWidth, //Copy this width
screenHeight, //Copy this height
&dcScreen, //From where do we copy?
0, //What's the X offset in the original DC?
0 //What's the Y offset in the original DC?
);
//Select the Bitmap out of the memory DC by selecting a new
//uninitialized Bitmap
memDC.SelectObject(wxNullBitmap);
staticbitmap1->SetBitmap(screenshot);
In the wxStaticBitmap docs you can read:
Native implementations on some platforms are only meant for display of
the small icons in the dialog boxes.
If you want to display larger images portably, you may use generic
implementation wxGenericStaticBitmap declared in
.
It seems your screenshot is not small, and so the OS is messing you. Thus follow the advice and use wxGenericStaticBitmap

How to display a image on a user defined rectangle with SDL_surface?

Im working on a project with my friend and we have run into an issue with surfaces and windows in SDL.
Currently we are able to create a window and display a rectangle on that window and move it around. The next thing we want to do is take a image and display it on a rectangle and then move it around the screen.
We started with taking the SDL_window* and turning it into SDL_surface* though this would take the image and display it on the background of the window.
Is there a way to turn a rectangle we create into a surface and display the image on that rectangle?
I have also tried using textures and it distorts the image when I tried to move it and the whole image doesn’t move with the rectangle.
// this happens in the constructor
temp_image_sur = IMG_Load( image_location.c_str() );
if( temp_image_sur == NULL )
{
std::cout << "Image could not be loaded" <<std::endl;
exit(1);
}
// This is in the actual draw function.
display_surface = SDL_GetWindowSurface( display_window );
if(display_surface == NULL )
{
printf(" null im exiting here %s\n", SDL_GetError());
exit(1);
}
image_surface = SDL_ConvertSurface( temp_image_sur, display_surface->format, 0 );
image_size = { this->location.x, this->location.y, this->size.width, this->size.height };
SDL_BlitSurface( image_surface, &image_size, display_surface, &image_size );
This is what we did for our first attempt, and the image was displaying on the base window. I believe I understand why it is displaying on the base window, it is because we are using that window as the surface, though I'm confused how do I make a user defined rectangle the surface?
We did try using SDL_CreateRGBSurface, though nothing is being displayed on the screen when we do this either.
display_surface = SDL_CreateRGBSurface(0, this->size.width, this->size.height, 1, this->color.red, this->color.green, this->color.blue, this->color.alpha);
Thanks guys!
Please let me know if there is anymore information you need, this is my first time posting and I tried to put all the info that I could think of.
Create a texture from your image surface by using SDL_CreateTextureFromSurface:
SDL_Texture* image_surface = SDL_CreateTextureFromSurface(renderer, temp_image_sur);
(remember to free it with SDL_DestroyTexture)
then use SDL_RenderCopy to draw it:
SDL_RenderCopy(renderer, image_texture, nullptr, &image_rect);
where image_rect is a SDL_Rect and the destination rectangle you want to draw your image to, for example:
SDL_rect image_rect = {10, 10, 200, 200};
To move your image simply change image_rect.x and/or image_rect.y

Change SDL background

Is there any way to change the color of an empty SDL window to be white instead of black? I don't want to change any default settings. I'm just trying to change it for this particular program that I'm writing. I don't want to use an image file, but if I have to, I will.
I don't know if this matters, but I'm using SDL_SetVideoMode()
My code is very basic:
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
return 1;
SDL_Surface * screen = NULL;
screen = SDL_SetVideoMode(width, height, bpp, SDL_SWSURFACE);
SDL_FillRect(screen, NULL, 0xFFFFFF);
SDL_Delay(3000);
You need to call SDL_Flip for your changes to show up.
Acquire the surface from your Window using surf = SDL_SetVideoMode(...) and then do
SDL_FillRect(surf, NULL, 0xFFFFFF); // 0xFFFFFF = white in RGB, NULL = full window
SDL_Flip(surf);
You could use SDL_FillRect to fill the screen/a surface with your desired color.
You need to call SDL_UpdateRect after SDL_FillRect.