ColmanJ
ColmanJ

Reputation: 456

transparency layered window white

I'm trying to make a layered window with c++ win32 but I'm having a problem with the drawing or "collision" of it

For reference the picture that I'm trying to display.

default

This is the basic creation of the window

//window
DWORD exFlags = 0;
if(m_bTransparent)
    exFlags |= WS_EX_LAYERED;
Create(WS_POPUP, exFlags);

std::wstring sPic(L"power-disconnected.png");
m_pAlertPic = m_pPowerMon->GetGPPicMan()->LoadPicture(sPic.c_str());

// make the window layered when using transparency
if(m_bTransparent && m_pAlertPic != nullptr)
{
    HDC hdcScreen = GetDC(GetHandle());
    HDC hdc = CreateCompatibleDC(hdcScreen);
    HBITMAP hbmpold = (HBITMAP)SelectObject(hdc, m_pAlertPic->GetBuffer());

    POINT dcOffset = {0, 0};
    SIZE size = {ww, wh};

    BLENDFUNCTION bf = {AC_SRC_OVER, 0, (int) (2.55 * 100), AC_SRC_ALPHA}; // blend function combines opacity and pixel based transparency
    UpdateLayeredWindow(GetHandle(), hdcScreen, NULL, &size, hdc, &dcOffset, RGB(255, 255, 255), &bf, ULW_ALPHA);
    SelectObject(hdc, hbmpold);
    DeleteDC(hdc);
    ReleaseDC(GetHandle(), hdcScreen);
}

and the message loop

int WindowAlert::WndProc(Gnaq::WindowBase* pWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
   case WM_CLOSE:
       Hide();
       return 1;
   case WM_PAINT:
       // only draw when the widow is not transparent
       // layered window redraw them self
       if(!m_bTransparent)
           m_pCanvas->Draw(m_pGraphics);
       break;
   case WM_LBUTTONUP:
       pWnd->Hide();
       m_bDismised = true;
       break;
   }
   return DefWindowProcW(pWnd->GetHandle(), msg, wParam, lParam);

}

So this is the result I get UpdateLayeredWindow result As you can see with this method I'm getting white borders where is should actually be fully transparent, but the semi transparent parts do work correctly.

here's what I've tried that gave me a "useful" change. First I just tried to add the ULW_COLORKEY flag to hide the white color

UpdateLayeredWindow(GetHandle(), hdcScreen, NULL, &size, hdc, &dcOffset, RGB(255, 255, 255), &bf, ULW_ALPHA | ULW_COLORKEY);

And the result. ULW_COLORKEY

So this hides the white border but also all the white in the picture. Next thing I've tried was using SetLayeredWindowAttributes in combination of UpdateLayeredWindow, without the ULW_COLORKEY flag

SetLayeredWindowAttributes(GetHandle(), 0xFFFFFF00, 255, LWA_COLORKEY);

Also in the window proc enable the paint, like this

case WM_PAINT:
    m_pCanvas->Draw(m_pGraphics);
    break;

This way I'm visually getting what I want like this SetLayeredWindowAttributes

But the problem with his approach is that it the complete window is click able while with just using the UpdateLayeredWindow only the parts that should be fully transparent are click able like it should be. I also have the feeling with this last approach that it is more a "hack" than a decent approach.

So i hope that someone can tell me what I'm doing wrong.

Upvotes: 1

Views: 2650

Answers (1)

ColmanJ
ColmanJ

Reputation: 456

The first way was the correct. The fault was in the bitmap, which didn't had premultiplied alpha

Upvotes: 1

Related Questions