Shadows on windows with a bit depth of 32 - x11

In my reparenting window manager, I reparent windows to frames with the same bit depth:
let geom = self.conn.get_geometry(ev.window)?.reply()?;
let attr = self.conn.get_window_attributes(ev.window)?.reply()?;
let frame_win = self.conn.generate_id()?;
let win_aux = xproto::CreateWindowAux::new()
.event_mask(
xproto::EventMask::EXPOSURE
| xproto::EventMask::SUBSTRUCTURE_REDIRECT
| xproto::EventMask::SUBSTRUCTURE_NOTIFY
| xproto::EventMask::BUTTON_PRESS
| xproto::EventMask::BUTTON_RELEASE
| xproto::EventMask::POINTER_MOTION
| xproto::EventMask::ENTER_WINDOW
| xproto::EventMask::PROPERTY_CHANGE,
)
.background_pixel(self.config.background_pixel)
.border_pixel(self.config.border_pixel)
.colormap(attr.colormap);
self.conn.create_window(
geom.depth,
frame_win,
screen.root,
geom.x,
geom.y,
geom.width,
geom.height + self.config.title_height as u16,
self.config.border_width as u16,
xproto::WindowClass::INPUT_OUTPUT,
attr.visual,
&win_aux,
)?;
However, when the bit depth of the inside window and therefore the frame is 32, compositors do not draw shadows around the frame. If it has another depth like 24 they do. why would this happen?

It looks like xcompmgr just doesn't composite windows with a depth of 32. Picom and Compton work fine. Maybe there's some setting to change that; at any rate, there's nothing the wm can do about it.

Related

Drawing on windows with 32-bit color depth

For some reason, I'm not able to draw at all on a X11 window with a depth of 32 in my reparenting WM. I've tried using Xft for drawing text, drawing rectangles, the inbuilt functionality for drawing text... nothing shows up on depth 32 windows. This is how I draw the window, using the X11rb library:
let win_aux = xproto::CreateWindowAux::new()
.event_mask(
xproto::EventMask::EXPOSURE
| xproto::EventMask::SUBSTRUCTURE_REDIRECT
| xproto::EventMask::SUBSTRUCTURE_NOTIFY
| xproto::EventMask::BUTTON_PRESS
| xproto::EventMask::BUTTON_RELEASE
| xproto::EventMask::POINTER_MOTION
| xproto::EventMask::ENTER_WINDOW
| xproto::EventMask::PROPERTY_CHANGE,
)
.background_pixel(self.config.background_pixel)
.border_pixel(self.config.active_border_pixel)
.colormap(attr.colormap);
self.conn.create_window(
geom.depth,
frame_win,
screen.root,
geom.x,
geom.y,
geom.width,
geom.height + self.config.title_height as u16,
self.config.border_width as u16,
xproto::WindowClass::INPUT_OUTPUT,
attr.visual,
&win_aux,
)?;
self.conn.grab_server()?.check()?;
self.conn
.change_save_set(xproto::SetMode::INSERT, ev.window)?
.check()?;
self.conn
.reparent_window(ev.window, frame_win, 0, self.config.title_height as i16)?
.check()?;
self.conn.map_window(ev.window)?.check()?;
self.conn.map_window(frame_win)?.check()?;
How do I resolve this issue?
I haven't fully figured out what is going on, but I ran your code under xtrace and found this:
000:<:005c: 20: RENDER-Request(139,4): CreatePicture pid=0x00200001 drawable=0x00200002 format=0x00000029 values={}
000:<:005d: 16: Request(53): CreatePixmap depth=0x20 pid=0x00200003 drawable=0x0000051f width=1 height=1
000:<:005e: 24: RENDER-Request(139,4): CreatePicture pid=0x00200004 drawable=0x00200003 format=0x00000025 values={repeat=true(0x01)}
000:<:005f: 8: Request(54): FreePixmap drawable=0x00200003
000:>:005c:Error 8=Match: major=139, minor=4, bad=0x00000029, seq=005c
So, something you are doing causes an Error. I guess this then also explains the missing drawing.
So, my first suggestion is to not silently ignore errors:
diff --git a/src/wm.rs b/src/wm.rs
index 68e43f5..bc95d20 100644
--- a/src/wm.rs
+++ b/src/wm.rs
## -240,7 +240,10 ## where
let ev = match self.conn.wait_for_event() {
Ok(ev) => ev,
- Err(_) => continue,
+ Err(e) => {
+ eprintln!("Error: {:?}", e);
+ continue;
+ }
};
let _ = self.dispatch_event(&ev);
}
## -293,6 +296,7 ## where
protocol::Event::DestroyNotify(ev) => self.handle_destroy_notify(ev)?,
protocol::Event::ClientMessage(ev) => self.handle_client_message(ev)?,
protocol::Event::ConfigureNotify(ev) => self.handle_configure_notify(ev)?,
+ protocol::Event::Error(ev) => eprintln!("X11 error: {:?}", ev),
_ => {}
}
Ok(())
(Only the second change is necessary here, but I came across the first one first and only later figured out that I was wrong.)
I am not quite sure what the second problem is, but I would guess that it is the following code:
xft::XftDrawCreate(
self.xlib_conn,
frame_win.into(),
xlib::XDefaultVisual(self.xlib_conn, 0),
xlib::XDefaultColormap(self.xlib_conn, 0),
)
Here, you are telling xft that your frame window uses the screen's default visual and colormap. However, for depth=32 windows, this cannot be true (and I checked - your frame window is also depth=32 in this case).
So... you somehow have to give the right visual to Xft and colormap to Xft. Apparently, you use a GetWindowAttributes request to create your frame window with the same values as the contained client window.
So, now you'll somehow have to translate this visual XID to a Xlib Visual* pointer, which sounds like some hairy code....

Given an HBITMAP, is there any way to find out, whether it contains an alpha channel?

In an attempt to improve this answer, I am looking for a way to determine, whether a bitmap referenced through an HBITMAP contains an alpha channel.
I understand, that I can call GetObject, and retrieve a BITMAP structure:
BITMAP bm = { 0 };
::GetObject(hbitmap, sizeof(bm), &bm);
But that only gets me the number of bits required to store the color of a pixel. It doesn't tell me, which bits are actually used, or how they relate to the individual channels. For example, a 16bpp bitmap could encode a 5-6-5 BGR image, or a 1-5-5-5 ABGR image. Likewise, a 32bpp bitmap could store ABGR or xBGR data.
I could take it a step further, and probe for a DIBSECTION instead (if available):
bool is_dib = false;
BITMAP bm = { 0 };
DIBSECTION ds = { 0 };
if ( sizeof(ds) == ::GetObject(hbitmap, sizeof(ds), &ds ) {
is_dib = true;
} else {
::GetObject(hbitmap, sizeof(bm), &bm );
}
While this can disambiguate the 16bpp case (using the dsBitfields member), it still fails to determine existence of an alpha channel in the case of a 32bpp image.
Is there any way to find out, whether a bitmap referenced through an HBITMAP contains an alpha channel (and which bit(s) are used for it), or is this information simply not available?
You cannot know definitively, but you can make a good educated guess if you're willing to iterate through the pixels..
(Ignoring the 16-bit color with 1-bit alpha channels, for now anyway.)
For there to be an alpha channel, it's necessary (but not sufficient) for the bitmap to be a DIB section and to have 32 bits per pixel. As noted in the question, you can check for those requirements.
We also know that Windows deals only with pre-multiplied alpha. That means, for every pixel A >= max(R, G, B). So, if you're willing to scan all the pixels, you can rule out a bunch of 24-bit images. If that condition holds for all pixels and if any of the A's are non-zero, you almost certainly have an alpha channel (or a corrupted image).
Basically, the only uncertainty left is the all-transparent image versus the all-black image, both of which consist of pixels with all channels set to zero. Perhaps it's sufficient to take an educated guess in that case. I would guess yes, since having a 32-bit DIB section is a pretty strong signal. If you had a 32-bit device-dependent bitmap, then it doesn't have alpha, and if you had a device-independent bitmap without alpha, you'd probably use 24 bits per pixel to save space.
Some of the more detailed bitmap info headers can tell you if bits are reserved for the alpha channel. For example, see BITMAPV5HEADER, which has a mask indicating which bits are the alpha channel (though the documentation says some contradictory things). Likewise for the BITMAPV4HEADER. Unfortunately, I don't think there's a way to get this version of the header from an HBITMAP. (And I'm certain there are alpha-enabled bitmap files out there that don't set these fields correctly.)
It's well-known that GDI doesn't handle alpha channels (with the exception of AlphaBlend, which doesn't take an HBITMAP but accesses one selected into a memory DC). There are user APIs, like UpdateLayeredWindow that work with images with alpha channels, but, like AlphaBlend, take the bitmap data from the information selected into a memory DC. LoadImage, if passed the correct flags, will preserve the alpha channel when loading a DIB to be accessed by HBITMAP.
ImageList_Add, which does take an HBITMAP, will preserve and alpha channel if the image list is created with the proper flags. In all these cases, however, the caller must know that the bitmap data contains proper alpha data and set the right flags for the API. This suggests that the information is not readily available from the bitmap handle.
If you have access to the bitmap resource or file that the image was loaded from, it is possible to see if the original header uses BI_BITFIELDS and has an alpha channel specified, but you can't get to that header from the HBITMAP in all cases. (And there's remains the concern that the header isn't filled out correctly.)
You can get it indirectly by using GetObject function. Tucked away in the documentation is a note:
If hgdiobj is a handle to a bitmap created by calling CreateDIBSection, and the specified buffer is large enough, the GetObject function returns a DIBSECTION structure. In addition, the bmBits member of the BITMAP structure contained within the DIBSECTION will contain a pointer to the bitmap's bit values.
If hgdiobj is a handle to a bitmap created by any other means, GetObject returns only the width, height, and color format information of the bitmap. You can obtain the bitmap's bit values by calling the GetDIBits or GetBitmapBits function.
(emphasis mine)
In other words: if you try to decode it is a DIBSECTION, but it's only a BITMAP, then
dibSection.BitmapInfoHeader
will not be updated. (e.g. left as zeros)
It's helpful to remember how a BITMAP and a DIBSECTION differ:
| BITMAP | DIBSECTION |
|------------------------|--------------------------|
| bmType: Longint | bmType: Longint |
| bmWidth: Longint | bmWidth: Longint |
| bmHeight: Longint | bmHeight: Longint |
| bmWidthBytes: Longint | bmWidthBytes: Longint |
| bmPlanes: Word | bmPlanes: Word |
| bmBitsPixel: Word | bmBitsPixel: Word |
| bmBits: Pointer | bmBits: Pointer |
| | |
| |BITMAPINFOHEADER | <-- will remain unchanged for BITMAPs
| | biSize: DWORD |
| | biWidth: Longint |
| | biHeight: Longint |
| | biPlanes: Word |
| | biBitCount: Word |
| | biCompression: DWORD |
| | biSizeImage: DWORD |
| | biXPelsPerMeter: Longint |
| | biYPelsPerMeter: Longint |
| | biClrUsed: DWORD |
| | biClrImportant: DWORD |
| | |
| | dsBitfields: DWORD[3] |
| | dshSection: HANDLE |
| | dsOffset: DWORD |
If you try to get a BITMAP as a DIBSECTION, the GetObject function will not fill in any fields of the BITMAPINFOHEADER.
So check if all those values are empty, and if so: you know it's not a DIBSECTION (and must be a BITMAP).
Sample
function IsDibSection(bmp: HBITMAP): Boolean
{
Result := True; //assume that it is a DIBSECTION.
var ds: DIBSECTION = Default(DIBSECTION); //initialize everything to zeros
var res: Integer;
//Try to decode hbitmap as a DIBSECTION
res := GetObject(bmp, sizeof(ds), ref ds);
if (res = 0)
ThrowLastWin32Error();
//If the bitmap actually was a BITMAP (and not a DIBSECTION),
//then BitmapInfoHeader values will remain zeros
if ((ds.Bmih.biSize = 0)
and (ds.Bmih.biWidth = 0)
and (ds.Bmih.biHeight= 0)
and (ds.Bmih.biPlanes= 0)
and (ds.Bmih.biBitCount= 0)
and (ds.Bmih.biCompression= 0)
and (ds.Bmih.biSizeImage= 0)
and (ds.Bmih.biXPelsPerMeter= 0)
and (ds.Bmih.biYPelsPerMeter= 0)
and (ds.Bmih.biClrUsed= 0)
and (ds.Bmih.biClrImportant= 0))
Result := False; //it's not a dibsection
}

Fix for DirectX 7 latency on Windows 7?

We have a piece of software that is programmed against DirextX 7 SDK (i.e the code uses LPDIRECTDRAWSURFACE7 and the likes) and runs in fullscreen. The main task is putting something on the screen in response to external triggers in a reliable manner. This behaves very well on Windows XP: bsically the software waits for some trigger and when triggered, creates a new frame, puts it in the backbuffer, then tells DX to flip the buffers. The result is the approximate delay between the trigger and when the frame is effectively shown on the screen is, depending on video card and drivers, 3 frames or 50mSec for a 60Hz screen. This is tested on a variety of systems, all running NVidia cards. On some systems with higher end cards we even get 2 frames.
When running the same software on Windows 7 (with no other software installed at all) however, we cannot get lower than 5 frames. Meaning somewhere in the pipeline the OS or driver or both eat 2 extra frames, which is near to unacceptable for the application. We tried disabling aero/desktop composition/different driver versions/different video cards but no avail.
where does this come from? is this documented somewhere?
is there an easy way to fix? I know DirectX 7 is old, but upgrading to compile agains a more recent version might be tons of work so another type of fix would be nice. Maybe some flag that can be set in code?
edit here's some code which seems relevant:
Creation of front/back surfaces:
ddraw7->SetCooperativeLevel( GetSafeHwnd(),
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_MULTITHREADED )
DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof( desc );
desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE |
DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
desc.dwBackBufferCount = 1;
ddraw7->CreateSurface( &desc, &primsurf, 0 )
DDSCAPS2 surfcaps;
ZeroMemory( &surfcaps,sizeof( surfcaps ) );
surfcaps.dwCaps = DDSCAPS_BACKBUFFER;
primsurf->GetAttachedSurface( &surfcaps, &backsurf );
Creation of surfaces used to render frames before they get drawn:
DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS ;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
desc.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8;
LPDIRECTDRAWSURFACE7 surf;
HRESULT r=ddraw7->CreateSurface( &desc, &surf, 0 )
Rendering loop, in OnIdle:
//clear surface
DDBLTFX bltfx;
ZeroMemory( &bltfx, sizeof(bltfx) );
bltfx.dwSize = sizeof( bltfx );
bltfx.dwFillColor = RGBtoPixel( r, g, b );
backsurf->Blt( rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx )
//blit some prerendered surface onto it, x/y/rect etc are calculated properly)
backsurf->BltFast( x, y, sourceSurf, s&sourceRect, DDBLTFAST_WAIT );
primsurf->Flip( 0, DDFLIP_WAIT )
primsurf->Blt(&drect,backsurf,&srect,DDBLT_WAIT,0);
I think that the Windows XP thing is a red herring. The last version of Windows that ran DirectX 7 directly was Windows 2000. Windows XP is just emulating DX7 in DX9, same as Windows 7 is doing.
I'll venture a guess that your application uses palettized textures, and that when DX emulates that functionality (as it was dropped after DX7) it's generating a texture using the indexed colors. You might try profiling the app with GPUView to see if there's a delay in pushing the texture to the GPU. E.g., perhaps the Win7 driver compressing it first?

How to add image in CTreeCtrl list in MFC

I am trying to add Image before the text in CTreeList control but it is not coming up, But what i observed is the the node name is started after some space , like it is leaving the space for bitmap , but image is not showing up.. here is the code snap:-
CImageList m_ImageList;
CBitmap m_Bitmap1;
m_ImageList.Create(16,16,ILC_COLOR32,1,1);
m_Bitmap1.LoadBitmap(IDB_BITMAP1);
m_ImageList.Add(&m_Bitmap1, RGB(0,0,0));
TreeSoft->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP |
TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT |
TVS_SINGLEEXPAND | TVS_SHOWSELALWAYS |
TVS_TRACKSELECT,
CRect(10, 10, 200, 240), this, 0x1221);
TreeSoft->SetImageList(&m_ImageList, TVSIL_NORMAL);
hTree = TreeSoft->InsertItem( L"Software Production",0,0, TVI_ROOT);
hCompany = TreeSoft->InsertItem(L"Microsoft",0,0, hTree);
Pls tell me what i am missing here...
Now you just need to set the image for the newly created branch:
TreeSoft->SetItemImage(hTree , 0, 0); // I think it starts from 0 (if it does not show try 1)
Just for testing purposes.
Create an icon with 16-bit color palette.
Instead of ILC_COLOR32 use ILC_COLOR.
And instead of RGB(0,0,0) use (COLORREF)0xFFFFFF
I have exact the same code except the smaller color palette and it works.
If this works you can try with the bigger palette.

Storage location of yellow-blue shield icon

Where, in Windows, is this icon stored? I need to use it in a TaskDialog emulation for XP and am having a hard time tracking it down.
It's not in shell32.dll, explorer.exe, ieframe.dll or wmploc.dll (as these contain a lot of icons commonly used in Windows).
Edit:
For clarification, I am emulating a certain type of dialog in XP. The icon is (most likely) not present there. So I want to extract it from the library that holds it in Windows 7. I am extending an existing implementation of this emulation and want to provide a full feature set.
I wanted to point it out explicitly.
You are supposed to put a shield on UI elements that will trigger an elevation: MSDN: Step 4: Redesign Your UI for UAC Compatibility.
Of course, you don't have to go spelunking around DLLs to extract images (although it certainly does make it easier at design time when you can design your design with a design time interface).
Microsoft provides a couple of supported (and therefore guaranteed) ways that you can get ahold of the shield icon at runtime:
Add a shield icon to the user interface?:
Extract a small icon
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &sii);
hiconShield = sii.hIcon;
Extract a large icon
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_LARGEICON, &sii);
hiconShield = sii.hIcon;
Extract an icon of custom size
SHSTOCKICONINFO sii;
sii.cbSize = sizeof(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, &sii);
hiconShield = ExtractIconEx(sii. ...);
Add a Shield Icon to a Button
Button_SetElevationRequiredState(hwndButton, TRUE);
The article forgot to mention LoadIcon:
hIconShield = LoadIcon(0, IDI_SHIELD);
Although LoadIcon has been "superseded" by LoadImage:
hIconShield = LoadImage(0, IDI_SHIELD, IMAGE_ICON, desiredWith, desiredHeight, LR_SHARED); //passing LR_SHARED causes size to be ignored. And you must pass LR_SHARED
Loading the size you want - by avoiding shared images
In order to avoid loading a "shared" version of the icon, you have to load the icon directly out of the file.
We all know that the shield exists in user32.dll as resource id 106:
| Icon | Standard Icon ID | Real Resource ID |
|------------------|-------------------|------------------|
| IDI_APPLICATION | 32512 | 100 |
| IDI_QUESTION | 32514 | 102 |
| IDI_WINLOGO | 32517 | 105 |
| IDI_WARNING | 32515 | 101 |
| IDI_ERROR | 32513 | 103 |
| IDI_INFORMATION | 32516 | 104 |
| IDI_SHIELD | 32518 | 106 |
That was undocumented spellunking.
SHGetStockIconInfo can give us the actual, current, guaranteed to change in the future, path and index:
TSHStockIconInfo sii;
ZeroMemory(#sii, SizeOf(sii));
sii.cbSize := SizeOf(sii);
SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, {var}sii);
resulting in:
sii.szPath: C:\WINDOWS\System32\imageres.dll
sii.iIcon: -78
You can load this image for the size you desire using LoadImage:
HMODULE hmod := LoadLibrary(sii.szPath);
Integer nIconIndex := Abs(sii.iIcon); //-78 --> 78
ico = LoadImage(hmod, MAKEINTRESOURCE(nIconIndex), IMAGE_ICON, 256, 256, 0);
Another slightly easier way is to use SHDefExtractIcon:
HICON GetStockIcon(DWORD StockIconID, Integer IconSize)
{
HRESULT hr;
TSHStockIconInfo sii;
ZeroMemory(#sii, SizeOf(sii));
sii.cbSize := SizeOf(sii);
hr = SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICONLOCATION, {var}sii);
OleCheck(hr);
HICON ico;
hr = SHDefExtractIcon(sii.szPath, sii.iIcon, 0, ref ico, null, IconSize);
OleCheck(hr);
return ico;
}
It does the loading for you, and it handles the negative icon index (and the secret meaning that has):
HICON shieldIcon = GetStockIcon(SIID_SHIELD, 256);
Personally, i then use WIC to wrap that into a IWICBitmap:
IWICBitmap GetStockWicBitmap(DWORD StockIconID, Integer IconSize)
{
HICON ico = GetStockIcon(StockIconID, IconSize);
IWICBitmap bitmap;
IWICImagingFactory factory = new WICImagingFactory();
HRESULT hr = factory.CreateBitmapFromHICON(ico, out bitmap);
OleCheck(hr);
return bitmap;
}
and so:
IWICBitmap bmp = GetStockWicBitmap(SIID_SHIELD, 256);
Now that you have the bitmap, at runtime, do with it what you want.
Small and Large
The problem with ExtractIconEx is that you're again stuck with the two shell sizes:
"small" (i.e. GetSystemMetrics(SM_CXSMICON))
"large" (i.e. GetSystemMetrics(SM_CXICON))
Loading icons is something that is quite a dark art in Windows:
LoadIcon
LoadImage
LoadImage(..., LR_SHARED)
ExtractIcon
ExtractIconEx
IExtractImage
SHDefExtractIcon
SHGetFileInfo(..., SHGFI_ICON, ...);
SHGetFileInfo(..., SHGFI_SYSICONINDEX, ...);
SHGetFileInfo(..., SHGFI_ICONLOCATION, ...);
IThumbnailProvider
Icons available through SHGetStockIconInfo
Microsoft gives a handy page that gives an example, and description, of all the stock icons.
SHSTOCKICONID (archive)
And the 256px shield icon (as of Windows 10):
The shield icon is located in the file C:\Windows\System32\imageres.dll (at least, in my copy of English 32-bit Windows 7). There are several versions of the shield icon there, including the blue and yellow version you have above (icon 78).
Icons extracted from Windows 7 x64 SP1 English:
16x16 shield icon:
24x24 shield icon:
32x32 shield icon:
You are asking the wrong question. It doesn't matter where this icon is stored on any version of windows. If Microsoft don't tell you then you should not use it - it might not be there in windows 8 (or whatever comes after 7).
If you want the icon so bad, there is a decent graphical representation of it above in this question. You could do alt-prt scrn then use your favourite graphics app to turn it into an icon and add it to your app. This may not be legal though (remember, IANAL)

Resources