! testpattern.f90 ! Public domain 2007-2010 James Van Buskirk ! Compiled with: ! gfortran -Wall -mwindows -fno-range-check testpattern.f90 -otestpattern -lgdi32 module win32_types use ISO_C_BINDING implicit none private public WNDCLASSEX_T type, bind(C) :: WNDCLASSEX_T integer(C_INT) cbSize integer(C_INT) style type(C_FUNPTR) lpfnWndProc integer(C_INT) cbClsExtra integer(C_INT) cbWndExtra integer(C_INTPTR_T) hInstance integer(C_INTPTR_T) hIcon integer(C_INTPTR_T) hCursor integer(C_INTPTR_T) hbrBackground type(C_PTR) lpszMenuName type(C_PTR) lpszClassName integer(C_INTPTR_T) hIconSm end type WNDCLASSEX_T public POINT_T type, bind(C) :: POINT_T integer(C_LONG) x integer(C_LONG) y end type POINT_T public MSG_T type, bind(C) :: MSG_T integer(C_INTPTR_T) hwnd integer(C_INT) message integer(C_INTPTR_T) wParam integer(C_INTPTR_T) lParam integer(C_LONG) time type(POINT_T) pt end type MSG_T public RECT_T type, bind(C) :: RECT_T integer(C_LONG) left integer(C_LONG) top integer(C_LONG) right integer(C_LONG) bottom end type RECT_T public PAINTSTRUCT_T type, bind(C) :: PAINTSTRUCT_T integer(C_INTPTR_T) hdc integer(C_INT) fErase type(RECT_T) rcPaint integer(C_INT) fRestore integer(C_INT) fIncUpdate integer(C_INT8_T) rgbReserved(32) end type PAINTSTRUCT_T public MONITORINFO_T type,bind(C) :: MONITORINFO_T integer(C_LONG) cbSize type(RECT_T) rcMonitor type(RECT_T) rcWork integer(C_LONG) dwFlags end type MONITORINFO_T end module win32_types module win32 use ISO_C_BINDING implicit none private public GetModuleHandle interface function GetModuleHandle(lpModuleName) & bind(C,name='GetModuleHandleA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: GetModuleHandle integer(C_INTPTR_T) GetModuleHandle character(kind=C_CHAR) lpModuleName(*) end function GetModuleHandle end interface public GetCommandLine interface function GetCommandLine() & bind(C,name='GetCommandLineA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: GetCommandLine type(C_PTR) GetCommandLine end function GetCommandLine end interface public DefWindowProc interface function DefWindowProc(hwnd, Msg, wParam, lParam) & bind(C,name='DefWindowProcA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: DefWindowProc integer(C_LONG) DefWindowProc integer(C_INTPTR_T), value :: hwnd integer(C_INT), value :: Msg integer(C_INTPTR_T), value :: wParam integer(C_INTPTR_T), value :: lParam end function DefWindowProc end interface public LoadIcon interface function LoadIcon(hInstance, lpIconName) & bind(C,name='LoadIconA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: LoadIcon integer(C_INTPTR_T) LoadIcon integer(C_INTPTR_T), value :: hInstance character(kind=C_CHAR) lpIconName(*) end function LoadIcon end interface public LoadCursor interface function LoadCursor(hInstance, lpCursorName) & bind(C,name='LoadCursorA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: LoadCursor integer(C_INTPTR_T) LoadCursor integer(C_INTPTR_T), value :: hInstance character(kind=C_CHAR) lpCursorName(*) end function LoadCursor end interface public GetStockObject interface function GetStockObject(fnObject) & bind(C,name='GetStockObject') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: GetStockObject integer(C_INTPTR_T) GetStockObject integer(C_INT), value :: fnObject end function GetStockObject end interface integer(C_INT), parameter, public :: WHITE_BRUSH = 0 ! Stock object integer(C_INT), parameter, public :: BLACK_BRUSH = 4 ! Stock object public RegisterClassEx interface function RegisterClassEx(lpwcx) & bind(C,name='RegisterClassExA') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: RegisterClassEx integer(C_SHORT) RegisterClassEx type(WNDCLASSEX_T) lpwcx end function RegisterClassEx end interface public CreateWindowEx interface function CreateWindowEx(dwExStyle, lpClassName, & lpWindowName, dwStyle, x, y, nWidth, nHeight, & hwndParent, hMenu, hInstance, lpParam) & bind(C,name='CreateWindowExA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: CreateWindowEx integer(C_INTPTR_T) CreateWindowEx integer(C_LONG), value :: dwExStyle character(kind=C_CHAR) lpClassName(*) character(kind=C_CHAR) lpWindowName(*) integer(C_LONG), value :: dwStyle integer(C_INT), value :: x integer(C_INT), value :: y integer(C_INT), value :: nWidth integer(C_INT), value :: nHeight integer(C_INTPTR_T), value :: hWndParent integer(C_INTPTR_T), value :: hMenu integer(C_INTPTR_T), value :: hInstance type(C_PTR), value :: lpParam end function CreateWindowEx end interface public ShowWindow interface function ShowWindow(hWnd,nCmdShow) bind(C,name='ShowWindow') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: ShowWindow integer(C_INT) ShowWindow integer(C_INTPTR_T), value :: hWnd integer(C_INT), value :: nCmdShow end function ShowWindow end interface public UpdateWindow interface function UpdateWindow(hWnd) bind(C,name='UpdateWindow') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: UpdateWindow integer(C_INT) UpdateWindow integer(C_INTPTR_T), value :: hWnd end function UpdateWindow end interface public GetMessage interface function GetMessage(lpMsg,hWnd,wMsgFilterMin,wMsgFilterMax) & bind(C,name='GetMessageA') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: GetMessage integer(C_INT) GetMessage type(MSG_T) lpMsg integer(C_INTPTR_T), value :: hWnd integer(C_INT), value :: wMsgFilterMin integer(C_INT), value :: wMsgFilterMax end function GetMessage end interface public TranslateMessage interface function TranslateMessage(lpMsg) bind(C,name='TranslateMessage') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: TranslateMessage integer(C_INT) TranslateMessage type(MSG_T) lpMsg end function TranslateMessage end interface public DispatchMessage interface function DispatchMessage(lpMsg) bind(C,name='DispatchMessageA') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: DispatchMessage integer(C_LONG) DispatchMessage type(MSG_T) lpMsg end function DispatchMessage end interface public ExitProcess interface subroutine ExitProcess(uExitCode) bind(C,name='ExitProcess') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: ExitProcess integer(C_INT), value :: uExitCode end subroutine ExitProcess end interface public BeginPaint interface function BeginPaint(hwnd,lpPaint) bind(C,name='BeginPaint') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: BeginPaint integer(C_INTPTR_T) BeginPaint integer(C_INTPTR_T), value :: hwnd type(PAINTSTRUCT_T) lpPaint end function BeginPaint end interface public GetClientRect interface function GetClientRect(hwnd,lpRect) bind(C,name='GetClientRect') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: GetClientRect integer(C_INT) GetClientRect integer(C_INTPTR_T), value :: hwnd type(RECT_T) lpRect end function GetClientRect end interface public DrawText interface function DrawText(hdc, lpString, nCount, lpRect, & uFormat) bind(C,name='DrawTextA') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: DrawText integer(C_INT) DrawText integer(C_INTPTR_T), value :: hdc character(kind=C_CHAR) lpString(*) integer(C_INT), value :: nCount type(RECT_T) lpRect integer(C_INT), value :: uFormat end function DrawText end interface public EndPaint interface function EndPaint(hwnd,lpPaint) bind(C,name='EndPaint') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: EndPaint integer(C_INT) EndPaint integer(C_INTPTR_T), value :: hwnd type(PAINTSTRUCT_T) lpPaint end function EndPaint end interface public PostQuitMessage interface subroutine PostQuitMessage(nExitCode) bind(C,name='PostQuitMessage') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: PostQuitMessage integer(C_INT), value :: nExitCode end subroutine PostQuitMessage end interface public GetLastError interface function GetLastError() bind(C,name='GetLastError') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: GetLastError integer(C_LONG) GetLastError end function GetLastError end interface public MessageBox interface function MessageBox(hWnd,lpText,lpCaption,uType) & bind(C,name='MessageBoxA') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: MessageBox integer(C_INT) MessageBox integer(C_INTPTR_T), value :: hWnd character(kind=C_CHAR) lpText(*) character(kind=C_CHAR) lpCaption(*) integer(C_INT), value :: uType end function MessageBox end interface public MoveToEx interface function MoveToEx(hdc,X,Y,lpPoint) bind(C,name='MoveToEx') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: MoveToEx integer(C_INT) MoveToEx integer(C_INTPTR_T),value :: hdc integer(C_INT), value :: X integer(C_INT), value :: Y type(POINT_T) lpPoint end function MoveToEx end interface public LineTo interface function LineTo(hdc,nXEnd,nYEnd) bind(C,name='LineTo') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: LineTo integer(C_INT) LineTo integer(C_INTPTR_T),value :: hdc integer(C_INT), value :: nXEnd integer(C_INT), value :: nYEnd end function LineTo end interface public FillRect interface function FillRect(hdc,lprc,hbr) bind(C,name='FillRect') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: FillRect integer(C_INT) FillRect integer(C_INTPTR_T),value :: hdc type(RECT_T) lprc integer(C_INTPTR_T), value :: hbr end function FillRect end interface public DestroyWindow interface function DestroyWindow(hWnd) bind(C,name='DestroyWindow') use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: DestroyWindow integer(C_INT) DestroyWindow integer(C_INTPTR_T),value :: hWnd end function DestroyWindow end interface public InvalidateRect interface function InvalidateRect(hWnd,lpRect,bErase) & bind(C,name='InvalidateRect') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: InvalidateRect integer(C_INT) InvalidateRect integer(C_INTPTR_T),value :: hWnd type(RECT_T) lpRect integer(C_INT), value :: bErase end function InvalidateRect end interface public MonitorFromPoint interface function MonitorFromPoint(pt,dwFlags) & bind(C,name='MonitorFromPoint') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: MonitorFromPoint integer(C_INTPTR_T) MonitorFromPoint type(POINT_T), value :: pt integer(C_LONG), value :: dwFlags end function MonitorFromPoint end interface public GetMonitorInfo interface function GetMonitorInfo(hMonitor,lpmi) & bind(C,name='GetMonitorInfoA') use ISO_C_BINDING use win32_types implicit none !GCC$ ATTRIBUTES STDCALL :: GetMonitorInfo integer(C_INT) GetMonitorInfo integer(C_INTPTR_T), value :: hMonitor type(MONITORINFO_T) lpmi end function GetMonitorInfo end interface end module win32 module procs use win32 use win32_types use ISO_C_BINDING implicit none private public WndProc integer mode contains function WndProc(hwnd, iMsg, wParam, lParam) bind(C) !GCC$ ATTRIBUTES STDCALL :: WndProc integer(C_LONG) WndProc integer(C_INTPTR_T), value :: hwnd integer(C_INT), value :: iMsg integer(C_INTPTR_T), value :: wParam integer(C_INTPTR_T), value :: lParam integer(C_INTPTR_T) hdc type(PAINTSTRUCT_T) ps integer(C_INT) result4 type(RECT_T) rect select case(iMsg) case(1) ! WM_CREATE WndProc = 0 return case(15) ! WM_PAINT hdc = BeginPaint(hwnd, ps) call PaintContent(hwnd, hdc) result4 = EndPaint(hwnd, ps) WndProc = 0 return case(2) ! WM_DESTROY call PostQuitMessage(0) WndProc = 0 return case(792) ! WM_PRINTCLIENT ! Didn't work ps%hdc = wParam result4 = GetClientRect(hwnd, ps%rcPaint) call PaintContent(hwnd, ps%hdc) WndProc = 0 return case(256) ! WM_KEYDOWN select case(wParam) case(72) ! H mode = 0 result4 = GetClientRect(hwnd, rect) result4 = InvalidateRect(hwnd,rect,1) result4 = UpdateWindow(hwnd) WndProc = 0 return case(86) ! V mode = 1 result4 = GetClientRect(hwnd, rect) result4 = InvalidateRect(hwnd,rect,1) result4 = UpdateWindow(hwnd) WndProc = 0 return case(88) ! X result4 = DestroyWindow(hwnd) end select end select WndProc = DefWindowProc(hwnd, iMsg, wParam, lParam) end function WndProc subroutine PaintContent(hwnd, hdc) integer(C_INTPTR_T), value :: hwnd integer(C_INTPTR_T), value :: hdc type(RECT_T) rect character(kind=C_CHAR) message*(80) integer(C_INT) result4 integer(C_INT) i integer(C_INT) top integer(C_INT) bottom type(POINT_T) pt integer(C_INTPTR_T) br type(RECT_T) current_rect integer(C_INT) delta integer(C_INT) left integer(C_INT) right integer(C_INT) uFormat result4 = GetClientRect(hwnd, rect) delta = int(0.05*(rect%top-rect%bottom)) br = GetStockObject(BLACK_BRUSH) if(mode == 0) then bottom = int(rect%bottom+0.25*(rect%top-rect%bottom)) top = bottom+delta do i = rect%left+1,rect%right,2 result4 = MoveToEx(hdc,i,top,pt) result4 = LineTo(hdc,i,bottom) end do bottom = top top = bottom+delta do i = rect%left+10,rect%right,20 current_rect = RECT_T(i,top,i+10,bottom) result4 = FillRect(hdc,current_rect,br) end do bottom = top top = bottom+delta do i = rect%left+100,rect%right,200 current_rect = RECT_T(i,top,i+100,bottom) result4 = FillRect(hdc,current_rect,br) end do else if(mode == 1) then right = int(rect%right+0.2*(rect%left-rect%right)) left = right+delta do i = rect%bottom-2,rect%top,-2 result4 = MoveToEx(hdc,left,i,pt) result4 = LineTo(hdc,right,i) end do right = left left = right+delta do i = rect%bottom-10,rect%top,-20 current_rect = RECT_T(left,i-10,right,i) result4 = FillRect(hdc,current_rect,br) end do right = left left = right+delta do i = rect%bottom-100,rect%top,-200 current_rect = RECT_T(left,i-100,right,i) result4 = FillRect(hdc,current_rect,br) end do end if current_rect = rect uFormat = 40 ! iany([DT_BOTTOM,DT_LEFT,DT_SINGLELINE]) current_rect%bottom = int(rect%bottom+0.85*(rect%top-rect%bottom)) current_rect%left = int(rect%left+0.1*(rect%right-rect%left)) message = 'Press H for horizontal pattern'//achar(0) result4 = DrawText(hdc, message, -1, current_rect, uFormat) current_rect%bottom = int(rect%bottom+0.8*(rect%top-rect%bottom)) message = 'Press V for vertical pattern'//achar(0) result4 = DrawText(hdc, message, -1, current_rect, uFormat) current_rect%bottom = int(rect%bottom+0.75*(rect%top-rect%bottom)) message = 'Press X to exit'//achar(0) result4 = DrawText(hdc, message, -1, current_rect, uFormat) end subroutine PaintContent end module procs function WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) & bind(C, name='WinMain') use win32 use win32_types use procs use ISO_C_BINDING implicit none !GCC$ ATTRIBUTES STDCALL :: WinMain integer(C_INT) WinMain integer(C_INTPTR_T), value :: hInstance integer(C_INTPTR_T), value :: hPrevInstance type(C_PTR), value :: lpCmdLine integer(C_INT), value :: nCmdShow character(kind=C_CHAR), pointer :: pcNull(:) type(WNDCLASSEX_T) WndClass character(kind=C_CHAR), pointer :: cDefault(:) character(kind=C_CHAR), target :: szAppName*(80) integer(C_SHORT) result2 integer(C_INTPTR_T) hwnd character(kind=C_CHAR), target :: szWindowCaption*(80) integer(C_INT) result4 type(MSG_T) msg type(POINT_T) pt integer(C_INTPTR_T) hmon type(MONITORINFO_T) mi ! use unused dummies result4 = int(hprevinstance+ncmdshow,kind(result4)) nullify(pcNull) call C_F_POINTER(lpCmdLine,cDefault,[0]) szAppName = 'testpattern'//achar(0) WndClass%cbSize = int(C_SIZEOF(Wndclass),C_INT) WndClass%style = 3 ! ior(CS_HREDRAW, CS_VREDRAW) WndClass%lpfnWndProc = C_FUNLOC(WndProc) WndClass%cbClsExtra = 0 WndClass%cbWndExtra = 0 WndClass%hInstance = hInstance call C_F_POINTER(transfer(32512_C_INTPTR_T,C_NULL_PTR), & cDefault,[0]) WndClass%hIcon = LoadIcon(0_C_INTPTR_T, cDefault) call C_F_POINTER(transfer(32512_C_INTPTR_T,C_NULL_PTR), & cDefault,[0]) WndClass%hCursor = LoadCursor(0_C_INTPTR_T, cDefault) WndClass%hbrBackground = GetStockObject(WHITE_BRUSH) WndClass%lpszMenuName = C_NULL_PTR WndClass%lpszClassName = C_LOC(szAppName(1:1)) call C_F_POINTER(transfer(32512_C_INTPTR_T,C_NULL_PTR), & cDefault,[0]) WndClass%hIconSm = LoadIcon(0_C_INTPTR_T, cDefault) result2 = RegisterClassEx(WndClass) pt = POINT_T(0,0) hmon = MonitorFromPoint(pt,1) ! MONITOR_DEFAULTTOPRIMARY result4 = GetMonitorInfo(hmon,mi) szWindowCaption = 'The Test Pattern'//achar(0) hwnd = CreateWindowEx(0_C_LONG, szAppName, szWindowCaption, & int(Z'91000000'), mi%rcMonitor%left, mi%rcMonitor%top, & mi%rcMonitor%right-mi%rcMonitor%left, & mi%rcMonitor%bottom-mi%rcMonitor%top, & 0_C_INTPTR_T, 0_C_INTPTR_T, hInstance, C_NULL_PTR) result4 = ShowWindow(hwnd, 5) ! SW_SHOW result4 = UpdateWindow(hwnd) do while(GetMessage(msg, 0_C_INTPTR_T, 0, 0) /= 0) result4 = TranslateMessage(msg) result4 = DispatchMessage(msg) end do call ExitProcess(int(msg%wParam, C_INT)) WinMain = 0 end function WinMain