[Windows] Blurry Forms Simulator

Share your advanced PureBasic knowledge/code with the community.
punak
Enthusiast
Enthusiast
Posts: 115
Joined: Tue Sep 07, 2021 12:08 pm

[Windows] Blurry Forms Simulator

Post by punak »

Hi all
after a long search and help from ai to simulate blurred windows, the initial version is finally ready.
In fact, my main goal was to add this beautiful feature to operating systems like Windows 8 and 8.1.
this version uses Magnification API to take live images from behind the software window. I used wilbert powerful and fast module to make it blur effect.
I ask everyone who reads this topic to test it on different versions of Windows and if you have any ideas for improving it, please write.

Code: Select all

; ============================================================
;  Live Blurred Window (PureBasic)
;  -----------------------------------------
;  Compatible with: Windows 8, 10, 11
;  Language: PureBasic 6.21 (x64)
;  Description:
;    Displays a live, blurred version of the desktop background
;    inside a borderless window using Magnification.dll.
;    Fully supports placing gadgets (e.g., buttons) on top.
; ============================================================

EnableExplicit

XIncludeFile "blur.pbi"
UseModule DirectionalBlur

Prototype.i MAGINITIALIZE()
Prototype.i MAGUNINITIALIZE()
Prototype.i MAGSETWINDOWSOURCE(hwnd.i, *rect.RECT)
PrototypeC.i MAGSETIMAGESCALINGCALLBACK(hwnd.i, *callback)

Global CanvasID, hwndMain, hwndMag, magLib
Global MagInitialize.MAGINITIALIZE
Global MagUninitialize.MAGUNINITIALIZE
Global MagSetWindowSource.MAGSETWINDOWSOURCE
Global MagSetImageScalingCallback.MAGSETIMAGESCALINGCALLBACK
Global rect.RECT
Global alphaLevel = 255
Global isMoving.i = #False

; Helper for older PB versions
Procedure Min(a, b)
  If a < b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

; ============================================================
; Magnification API callback - copies and blurs the live frame
; ============================================================
ProcedureC.i ImageCallback(hwnd.i, srcData.i, srcHeader.i, destData.i, destHeader.i, unclippedRect.i, clippedRect.i, dirtyRect.i)
  If srcHeader = 0 Or destData = 0 Or srcData = 0
    ProcedureReturn #False
  EndIf

  Protected width  = PeekL(srcHeader + 0)
  Protected height = PeekL(srcHeader + 4)
  Protected srcStride  = PeekL(srcHeader + 24)
  Protected destStride = PeekL(destHeader + 24)

  If srcStride = 0 : srcStride = width * 4 : EndIf
  If destStride = 0 : destStride = width * 4 : EndIf
  If width <= 0 Or height <= 0
    ProcedureReturn #False
  EndIf

  ; Apply blur using your custom module
  BlurPixelBuf32(destData, width, height, 10, #Blur_Full, destStride)

  ProcedureReturn #True
EndProcedure

; ============================================================
; Update captured source rectangle (sync with window position)
; ============================================================
Procedure UpdateSource()
  Protected client.RECT, pt.POINT
  client\right  = GadgetWidth(CanvasID)
  client\bottom = GadgetHeight(CanvasID)
  pt\x = 0 : pt\y = 0
  ClientToScreen_(WindowID(hwndMain), @pt)
  rect\left = pt\x : rect\top = pt\y
  rect\right = rect\left + client\right
  rect\bottom = rect\top + client\bottom
  MagSetWindowSource(hwndMag, rect)
EndProcedure

; ============================================================
; Timer callback to refresh the magnifier output (60 FPS)
; ============================================================
Procedure TimerProc(hWnd, uMsg, idEvent, dwTime)
  If Not isMoving
    InvalidateRect_(hwndMag, #Null, #True)
    UpdateWindow_(hwndMag)
  EndIf
EndProcedure

; ============================================================
; Allow dragging the borderless window
; ============================================================
Procedure WindowDrag()
  If EventType() = #PB_EventType_LeftButtonDown
    isMoving = #True
    KillTimer_(WindowID(hwndMain), 1)
    ReleaseCapture_()
    SendMessage_(WindowID(hwndMain), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
    isMoving = #False
    UpdateSource()
    SetTimer_(WindowID(hwndMain), 1, 1, @TimerProc())
  EndIf
EndProcedure

; ============================================================
; Main program
; ============================================================
magLib = OpenLibrary(#PB_Any, "Magnification.dll")
If magLib
  MagInitialize = GetFunction(magLib, "MagInitialize")
  MagUninitialize = GetFunction(magLib, "MagUninitialize")
  MagSetWindowSource = GetFunction(magLib, "MagSetWindowSource")
  MagSetImageScalingCallback = GetFunction(magLib, "MagSetImageScalingCallback")

  If MagInitialize()
    ; Create borderless main window
    hwndMain = OpenWindow(#PB_Any, 300, 200, 800, 600, "Live Blur Background", #PB_Window_BorderLess|#PB_Window_ScreenCentered)
    CanvasID = CanvasGadget(#PB_Any, 0, 0, WindowWidth(hwndMain), WindowHeight(hwndMain))

    ; Semi-transparent main window
    SetWindowLong_(WindowID(hwndMain), #GWL_EXSTYLE, GetWindowLong_(WindowID(hwndMain), #GWL_EXSTYLE) | #WS_EX_LAYERED)
    SetLayeredWindowAttributes_(WindowID(hwndMain), 0, alphaLevel, #LWA_ALPHA)

    ; Allow dragging
    BindGadgetEvent(CanvasID, @WindowDrag(), #PB_EventType_LeftButtonDown)

    ; Create magnifier child window (the live background)
    hwndMag = CreateWindowEx_(#WS_EX_TOOLWINDOW | #WS_EX_NOACTIVATE, "Magnifier", "", #WS_CHILD | #WS_VISIBLE, 0, 0, WindowWidth(hwndMain), WindowHeight(hwndMain), WindowID(hwndMain), 0, GetModuleHandle_(0), 0)
    SetWindowLong_(hwndMag, #GWL_EXSTYLE, #WS_EX_TRANSPARENT | #WS_EX_TOOLWINDOW)

    ; Put magnifier behind all gadgets
    SetWindowPos_(hwndMag, #HWND_BOTTOM, 0, 0, 0, 0, #SWP_NOMOVE | #SWP_NOSIZE | #SWP_NOACTIVATE)

    ; Create your gadgets on top of the blurred live view
    ButtonGadget(#PB_Any, 20, 20, 180, 30, "Click Me!")
    ButtonGadget(#PB_Any, 20, 60, 180, 30, "Another Button")

    ; Set callback and start updates
    MagSetImageScalingCallback(hwndMag, @ImageCallback())
    UpdateSource()
    SetTimer_(WindowID(hwndMain), 1, 1, @TimerProc())

    ; Event loop
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_SizeWindow
          ResizeGadget(CanvasID, 0, 0, WindowWidth(hwndMain), WindowHeight(hwndMain))
          UpdateSource()
        Case #PB_Event_MoveWindow
          isMoving = #True : KillTimer_(WindowID(hwndMain), 1)
          UpdateSource()
          isMoving = #False
          SetTimer_(WindowID(hwndMain), 1, 1, @TimerProc())
        Case #PB_Event_CloseWindow
          KillTimer_(WindowID(hwndMain), 1)
          MagUninitialize()
          End
      EndSelect
    ForEver
  Else
    MessageRequester("Error", "MagInitialize failed.")
  EndIf
  CloseLibrary(magLib)
Else
  MessageRequester("Error", "Magnification.dll not found.")
EndIf