Rusty Windows

Thanks @Julen Ibarretxe Uriguen and @Bill Gookin , between the two of you, I’ve massaged your code together to get exactly what I was looking for.

It’s as fast as I would have expected and has the exact affect that I’m looking for. I was seeing two 1 pixel lines on the bottom and the right hand side (but setting the size to 1 less) seemed to fix that. Also it was flickering on open, so I dug into the WFS (and found these declares in there) and injected in some code to prevent the flicker on open.

[code] #If TargetWin32 then
//////////////////////////////////////////////////////////////////////////////////////////////////
// — Custom shaped window code - by the Xojo community.
// Original code by Julen Ibarretxe Uriguen
// Modified by Bill Gookin
// Lastly modified by Sam Rowlands
//
// This uses code from the Windows Functionality Suite to reduce flicker.
//
// It works by removing the window’s border and title, then telling the OS to mask out
// a certain color. This is faster than using CreateRectRgn, CombineRgn, DeleteObject
//////////////////////////////////////////////////////////////////////////////////////////////////

// --- The following code reduces the border and window title to nothing!
Const WS_BORDER = &H800000
Const WS_CAPTION = &HC00000
Const WS_THICKFRAME = &H40000
Const WS_MINIMIZE = &H20000000
Const WS_MAXIMIZE = &H1000000
Const GWL_EXSTYLE=-20
Const SWP_FRAMECHANGED = &H20
Const WS_EX_LAYERED=&h00080000
Const GWL_STYLE = -16
const WS_SYSMENU = &h00080000

Declare function GetWindowLong lib "User32" Alias "GetWindowLongA" ( hwnd as integer, flags as integer ) as integer
Dim WS_NOBORDER as integer = GetWindowLong(me.Handle, GWL_EXSTYLE) and not WS_CAPTION and not WS_THICKFRAME and not WS_MINIMIZE and not WS_MAXIMIZE and WS_SYSMENU

Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (hwnd As Integer, nIndex As Integer, dwNewLong As Integer) As Integer
call setwindowlong (me.Handle, GWL_STYLE, WS_NOBORDER)
call setwindowlong (me.Handle, GWL_EXSTYLE,WS_EX_LAYERED) // -- Needed to allow the setLayerWindowAttributes to work

Declare Function SetWindowPos Lib "User32" (hwnd as Integer, hWndInstertAfter as Integer, x as Integer, y as Integer, cx as Integer, cy as Integer, flags as Integer) as Integer
call SetWindowPos(me.WinHWND, 0, left, top, width-1, height-1, SWP_FRAMECHANGED) //Apply border reduction

// --- This last declare is the magic one, that masks out via color. The color is in ARGB, instead of RGBA (Xojo)
Declare function SetLayeredWindowAttributes lib "user32" (hWnd as Integer, ColorRef as integer, AlphaCode as byte, dwFlags as integer) as Boolean
call setlayeredwindowattributes(me.Handle, &h0000FF00, 0, 1)

// --- To reduce 'flickering' we'll freeze the display, refresh and then release.
Soft Declare Function SendMessageA Lib "User32" ( hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer ) as Integer
Soft Declare Function SendMessageW Lib "User32" ( hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer ) as Integer

Const WM_SETREDRAW = &hB

if System.IsFunctionAvailable( "SendMessageW", "User32" ) then
  call sendMessageW( me.handle, WM_SETREDRAW, 0, 0 )
  me.refresh( true )
  call sendMessageW( me.handle, WM_SETREDRAW, 1, 0 )
  
else
  call sendMessageA( me.handle, WM_SETREDRAW, 0, 0 )
  me.refresh( true )
  call sendMessageA( me.handle, WM_SETREDRAW, 1, 0 )
  
end if

#endif[/code]

Sam - a couple of notes:

  1. The color is not AARRGGBB, it’s actually AABBGGRR.
  2. I was having a similar “extra line” issue around my image. I was creating a picture in memory, filling it with red, drawing my figure shape on top of that, and I ended up having an extra line on two sides. When you do it that way, the fill is actually blended with the figure shape color near the edge and you end up with an extra line. I fixed that by not using a picture and just painting my shape instead. I do the setup like you did, then in my paint event I do this:
  #if TargetWin32 then
    g.AntiAlias = false
    g.ForeColor = &cFF0000
    g.FillRect 0,0,g.Width,g.Height
    g.ForeColor = &c000000
  #Endif
  
  if windowFigureShape = nil then return
  windowFigureShape.FillColor = windowColor
  g.DrawObject windowFigureShape, 0, 0

Note the “g.AntiAlias = false”, that’s also needed or you’ll get the line (you might be able to do that when you create the picture, now that I think of it). I also have GDI Plus set to “on”, but I don’t know if it makes a difference for this. I can’t turn it off because it breaks other parts of my code.

Thanks for cleaning that up Bill… It’s been a long long time since I’ve seen a color in complete reversal! Which is why I rather terribly presumed it was ARGB and not ABGR!

Thanks for the advice on the single line issue. I don’t know at the moment if the clients project is using GDI or not, I’ll check when I get the time.