Placement of graphics window with Screen

General FreeBASIC programming questions.
Post Reply
wallyg
Posts: 276
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Placement of graphics window with Screen

Post by wallyg »

When I use the following command

Code: Select all

Screen 21
A graphics window appears on one of my monitors. Is there a way to specify which monitor it appears on and where on that monitor it appears?

A second question is how do I specify placing two graphics windows on my monitors? Ideally one on each monitor? Since I use a very large TV as monitor 2, can I place several graphics windows on it?

Can different threads each have their own graphics window?

An operating system-independent solution would be best, but if not for now one that works on Windows 10.

Wally
paul doe
Moderator
Posts: 1745
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Placement of graphics window with Screen

Post by paul doe »

Not with fbgfx windows I'm afraid. You need to use something like SDL2 or raylib for that. Currently, you can only have 1 graphics context per process with fbgfx (you can have it working along other contexts if you use the Fb.GFX_NULL driver, though)
UEZ
Posts: 996
Joined: May 05, 2017 19:59
Location: Germany

Re: Placement of graphics window with Screen

Post by UEZ »

You can use the Windows API to enumerate all connected monitors and move the window to the appropriate monitor.

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors
wallyg
Posts: 276
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: Placement of graphics window with Screen

Post by wallyg »

Thank you for the reference to Windows, EnumDisplayMonitors. I am not a Windows programmer and it looks like I would have to learn too much about Windows programming to use this properly.

I do appreciate your wonderful suggestion. If at some point in time, I do have to go this route, I will post my code so that others could use it too.

Wally
UEZ
Posts: 996
Joined: May 05, 2017 19:59
Location: Germany

Re: Placement of graphics window with Screen

Post by UEZ »

It is a little bit complex to list all monitors via WinAPI. When I find some time, I can write an example.
Peter W
Posts: 17
Joined: Jan 19, 2008 2:29
Location: Tasmania, Australia

Re: Placement of graphics window with Screen

Post by Peter W »

Here is an example from 2009 as posted by member 1000101
source: viewtopic.php?t=14193
Unfortunately I am old enough to remember this and have it in my collection of code.

I have only modified slightly it so that it runs.
This should give you all the help you need.

Code: Select all

'https://www.freebasic.net/forum/viewtopic.php?t=14193
'by 1000101 » Jul 18, 2009 1:06

'use fbc -s console
#Include "fbgfx.bi"
#Include "windows.bi"


Const As Integer                SCREEN_X                = 640
Const As Integer                SCREEN_Y                = 480
Const As Integer                SCREEN_hX               = SCREEN_X Shr 1
Const As Integer                SCREEN_hY               = SCREEN_Y Shr 1
Const As Single                 SCREEN_RATIO            = SCREEN_X / SCREEN_Y



Dim Shared As Integer           monCount
Dim Shared As MONITORINFOEX     Monitor()




Sub LogAdd( Text As String = "")
        
        Open Cons For Output As #1
                Print #1, Text
        Close #1
        
End Sub


Function MonitorEnumProc ( Byval hMonitor As HMONITOR, Byval hdcMonitor As HDC, Byval lprcMonitor As LPRECT, Byval dwData As LPARAM ) As BOOL
        
        Redim Preserve As MONITORINFOEX      Monitor( 0 To monCount )
        
        Monitor( monCount ).cbSize = Len( Monitor( monCount ) )
        GetMonitorInfo hMonitor, cPtr( Any Ptr, @Monitor( monCount ) )
        
        With Monitor( monCount )
                
                LogAdd "Monitor: " & ( 1 + monCount )
                LogAdd "   Device Name: " & .szDevice
                LogAdd "   Handle     : " & hMonitor
                LogAdd "   Resolution : " & ( .rcMonitor.Right - .rcMonitor.Left ) & "x" & ( .rcMonitor.Bottom - .rcMonitor.Top )
                LogAdd "   Region     : (" & .rcMonitor.Left & "," & .rcMonitor.Top & ")-(" & .rcMonitor.Right & "," & .rcMonitor.Bottom & ")"
                LogAdd "   Desktop    : (" & .rcWork.Left & "," & .rcWork.Top & ")-(" & .rcWork.Right & "," & .rcWork.Bottom & ")"
                LogAdd "   Flags      : 0x" & Hex( .dwFlags, 8 )
                If (.dwFlags And MONITORINFOF_PRIMARY) Then LogAdd "      Primary"
                LogAdd
                
        End With
        
        monCount = monCount + 1
        
        MonitorEnumProc = 1
        
End Function




Dim As Integer                  TotalWidth
Dim As Integer                  TotalHeight
Dim As Integer                  LowWid          =    1 Shl 30
Dim As Integer                  MidWid
Dim As Integer                  HighWid         = -( 1 Shl 30 )
Dim As Integer                  FullWid
Dim As Integer                  LowHei          =    1 Shl 30
Dim As Integer                  MidHei
Dim As Integer                  HighHei         = -( 1 Shl 30 )
Dim As Integer                  FullHei
Dim As RECT                     M
Dim As Single                   sX
Dim As Single                   sY
Dim As Integer                  curMonitor      = 0




ScreenRes SCREEN_X, SCREEN_Y



/'
        Get the list of monitors
'/
EnumDisplayMonitors 0, 0, @MonitorEnumProc, 0



'' Now we have the monitor info, draw them relative on the screen

/'
        Calculate the total desktop volume
'/
For X As Integer = 0 To ( monCount - 1 )
        
        With Monitor( X )
                
                If( .rcMonitor.Left   < LowWid  )Then LowWid  = .rcMonitor.Left
                If( .rcMonitor.Top    < LowHei  )Then LowHei  = .rcMonitor.Top
                If( .rcMonitor.Right  > HighWid )Then HighWid = .rcMonitor.Right
                If( .rcMonitor.Bottom > HighHei )Then HighHei = .rcMonitor.Bottom
                
        End With
        
Next


/'
        Calculate the scaling for drawing the monitors
'/
FullWid = ( HighWid - LowWid )
FullHei = ( HighHei - LowHei )
MidWid  = LowWid + FullWid Shr 1
MidHei  = LowHei + FullHei Shr 1
If( FullWid > ( FullHei * SCREEN_RATIO ) )Then
        sX = ( SCREEN_X - 8 ) / FullWid
        sY = sX * SCREEN_RATIO
Else
        sY = ( SCREEN_X - 8 ) / FullHei
        sX = sY / SCREEN_RATIO
End If


For X As Integer = 0 To ( monCount - 1 )
        
        /'
                Draw whole region
        '/
        With M
                .Left   = SCREEN_hX + ( ( Monitor( X ).rcMonitor.Left   - MidWid ) * sX )
                .Right  = SCREEN_hX + ( ( Monitor( X ).rcMonitor.Right  - MidWid ) * sX )
                .Top    = SCREEN_hY + ( ( Monitor( X ).rcMonitor.Top    - MidHei ) * ( sY / SCREEN_RATIO ) )
                .Bottom = SCREEN_hY + ( ( Monitor( X ).rcMonitor.Bottom - MidHei ) * ( sY / SCREEN_RATIO ) )
        End With
        Line ( M.Left, M.Top )-( M.Right, M.Bottom ), , B
        
        /'
                Draw desktop
        '/
        With M
                .Left   = SCREEN_hX + ( ( Monitor( X ).rcWork.Left   - MidWid ) * sX )
                .Right  = SCREEN_hX + ( ( Monitor( X ).rcWork.Right  - MidWid ) * sX )
                .Top    = SCREEN_hY + ( ( Monitor( X ).rcWork.Top    - MidHei ) * ( sY / SCREEN_RATIO ) )
                .Bottom = SCREEN_hY + ( ( Monitor( X ).rcWork.Bottom - MidHei ) * ( sY / SCREEN_RATIO ) )
        End With
        Line ( M.Left, M.Top )-( M.Right, M.Bottom ), , B
        
        /'
                Tell us which monitor is which in the display
        '/
        Draw String ( M.Left + ( M.Right - M.Left ) Shr 1 - 4, M.Top + ( M.Bottom - M.Top ) Shr 1 - 4 ), "" & ( 1 + X )
        
Next


Do
        /'
                Move the window to the monitor
        '/
        LowWid = ( Monitor( curMonitor ).rcWork.Left + ( ( Monitor( curMonitor ).rcWork.Right  - Monitor( curMonitor ).rcWork.Left ) - SCREEN_X ) Shr 1 )
        LowHei = ( Monitor( curMonitor ).rcWork.Top  + ( ( Monitor( curMonitor ).rcWork.Bottom - Monitor( curMonitor ).rcWork.Top  ) - SCREEN_Y ) Shr 1 )
        
        ScreenControl FB.SET_WINDOW_POS, LowWid, LowHei
        
        /'
                Tell us which monitor we are on
        '/
        Locate 1, 1 : Print "Moved to monitor: " & ( 1 + curMonitor )
        
        /'
                Wait three seconds then continue to the next one
        '/
        Sleep 3000
        
        /'
                Change monitors
        '/
        curMonitor      += 1
        curMonitor      Mod= MonCount
        
Loop    Until Inkey > ""
wallyg
Posts: 276
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: Placement of graphics window with Screen

Post by wallyg »

Thank you. I shall study it and adapt it to my needs.

I do appreciate all the help the forum provides.

Wally
Peter W
Posts: 17
Joined: Jan 19, 2008 2:29
Location: Tasmania, Australia

Re: Placement of graphics window with Screen

Post by Peter W »

I had an idea regarding multiple graphics (or console) windows from the same program.
This is a work around which you might be able to work with if it suits your program.
In theory there is no limit to the number of windows using this method.
I have incorporated multiple monitors and multiple windows in this example.
Have fun with it.

Code: Select all

'RUN MULTIPLE INSTANCES ON MULTIPLE MONITORS

#include once "fbgfx.bi"
#include once "windows.bi"
#include once "win\shellapi.bi"

'CODE FOR MULTIPLE MONITORS ==============================================
DIM SHARED AS INTEGER MONCOUNT
DIM SHARED AS MONITORINFOEX MONITOR()

FUNCTION MONITORENUMPROC (BYVAL HMONITOR AS HMONITOR, BYVAL HDCMONITOR AS HDC, BYVAL LPRCMONITOR AS LPRECT, BYVAL DWDATA AS LPARAM) AS BOOL 'FIND MONITORS
    REDIM PRESERVE AS MONITORINFOEX MONITOR(0 TO MONCOUNT)
    MONITOR(MONCOUNT).CBSIZE = LEN(MONITOR(MONCOUNT))
    GETMONITORINFO HMONITOR, CPTR( ANY PTR, @MONITOR(MONCOUNT))
    MONCOUNT = MONCOUNT + 1
    MONITORENUMPROC = 1
END FUNCTION
ENUMDISPLAYMONITORS (0, 0, @MONITORENUMPROC, 0)

DIM SHARED AS INTEGER MAIN_MONITOR  'DETERMINE THE MAIN MONITOR - THE PRIMARY MONITOR BY DEFINITION HAS ITS UPPER LEFT CORNER AT (0,0)
FOR M AS INTEGER = 0 TO MONCOUNT-1
    IF (MONITOR(M).DWFLAGS AND MONITORINFOF_PRIMARY) THEN MAIN_MONITOR = M
NEXT M

SUB MOVE_GRAPHICS_WINDOW(BYVAL MON AS INTEGER = 0, BYVAL XPOS AS INTEGER = 0, BYVAL YPOS AS INTEGER = 0)    'MOVE A FB GRAPHICS WINDOW
    IF MON < 0 OR MON > MONCOUNT - 1 THEN MON = 0 : PRINT "SPECIFIED MONITOR NOT FOUND"
    XPOS = XPOS + MONITOR(MON).RCMONITOR.LEFT
    YPOS = YPOS + MONITOR(MON).RCMONITOR.TOP
    SCREENCONTROL FB.SET_WINDOW_POS, XPOS, YPOS
END SUB

SUB MOVE_CONSOLE_WINDOW(BYVAL MON AS INTEGER = 0, BYVAL XPOS AS INTEGER = 0, BYVAL YPOS AS INTEGER = 0)     'MOVE A CONSOLE WINDOW
    DIM AS HWND HWND = GETCONSOLEWINDOW()
    DIM AS RECT RCT
    IF MON < 0 OR MON > MONCOUNT - 1 THEN MON = 0 : PRINT "SPECIFIED MONITOR NOT FOUND"
    XPOS = XPOS + MONITOR(MON).RCMONITOR.LEFT
    YPOS = YPOS + MONITOR(MON).RCMONITOR.TOP
    GETWINDOWRECT(HWND, @RCT)
    MOVEWINDOW( HWND, XPOS, YPOS, RCT.RIGHT - RCT.LEFT, RCT.BOTTOM - RCT.TOP, TRUE )
END SUB

DIM AS INTEGER X_OFFSCREEN, Y_OFFSCREEN 'CALCULATE AREA OFFSCREEN TO PLACE CONSOLE WINDOW. NOT REQUIRED ONCE COMPILED WITH "-s gui"
FOR X AS INTEGER = 0 TO (MONCOUNT - 1)
    IF MONITOR(X).RCMONITOR.RIGHT  > X_OFFSCREEN THEN X_OFFSCREEN = MONITOR(X).RCMONITOR.RIGHT
    IF MONITOR(X).RCMONITOR.BOTTOM > Y_OFFSCREEN THEN Y_OFFSCREEN = MONITOR(X).RCMONITOR.BOTTOM
NEXT

'CODE FOR MULTIPLE WINDOWS ==============================================
DIM SHARED AS STRING PROGRAM_INSTANCE
PROGRAM_INSTANCE = COMMAND(1)

SUB RUN_AGAIN(BYREF RUNNING AS INTEGER, BYREF TASK0 AS INTEGER = 0, BYREF TASK1 AS STRING = "") 'START NEW INSTANCE OF THIS PROGRAM
    DIM AS STRING THIS_PROGRAM_NAME = COMMAND(0)
    ' SHELLEXECUTE(HANDLE,"OPERATION","COMMAND OR FILE","ARGUMENTS","DIRECTORY",SHOW_WINDOW)
    SHELLEXECUTE(NULL,"OPEN", THIS_PROGRAM_NAME, STR(RUNNING) & " " & STR(TASK0) & " " & CHR(34) & TASK1 & CHR(34), NULL, SW_SHOWNORMAL)
END SUB

'RUNNING THE PROGRAM ==============================================

'FIRST INSTANCE ==============================================
SUB PROGRAM_0_TASK  'INITIAL RUN OF PROGRAM
    PRINT "COUNTING NUMBERS TO 50 - NEW WINDOW WILL OPEN AT 10 AND 20"
    FOR I AS INTEGER = 1 TO 50
        IF I= 10 THEN RUN_AGAIN(1)                                          'TRIGGER TO RUN NEW INSTANCE
        IF I= 20 THEN RUN_AGAIN(2, 3, "COUNTING NUMBERS TO 50 WITH STEP ")  'TRIGGER TO RUN NEW INSTANCE WITH OPTIONAL PARAMETERS
        PRINT I, : SLEEP 500
    NEXT I
END SUB

IF PROGRAM_INSTANCE = "" THEN
    MOVE_CONSOLE_WINDOW (MAIN_MONITOR, X_OFFSCREEN, Y_OFFSCREEN)    'MOVE OFFSCREEN. NOT REQUIRED ONCE COMPILED
    SCREENRES 640, 240 : WIDTH 640/8, 240/16
    MOVE_GRAPHICS_WINDOW (0, 0, 0)
    PROGRAM_0_TASK  'TASK REQUIRED FOR THIS INSTANCE
    SLEEP 5000 : END
END IF

'SECOND INSTANCE ==============================================
SUB PROGRAM_1_TASK  'SECOND RUN OF PROGRAM
    PRINT "COUNTING EVEN NUMBERS TO 50"
    FOR I AS INTEGER = 2 TO 50 STEP 2
        PRINT I, : SLEEP 500
    NEXT I
END SUB

IF PROGRAM_INSTANCE = "1" THEN
    MOVE_CONSOLE_WINDOW (MAIN_MONITOR, X_OFFSCREEN, Y_OFFSCREEN)    'MOVE OFFSCREEN. NOT REQUIRED ONCE COMPILED
    SCREENRES 480, 160 : WIDTH 480/8, 160/16
    MOVE_GRAPHICS_WINDOW (1, 50, 50)
    PROGRAM_1_TASK
    SLEEP 5000 : END
END IF

'THIRD INSTANCE ==============================================
SUB PROGRAM_2_TASK(BYREF STEPPING AS INTEGER = 1, BYREF TEXT AS STRING = "STEPPING")    'THIRD RUN OF PROGRAM
    PRINT TEXT & STEPPING
    FOR I AS INTEGER = 0 TO 50 STEP STEPPING
        PRINT I, : SLEEP 500
    NEXT I
END SUB

IF PROGRAM_INSTANCE = "2" THEN
    MOVE_CONSOLE_WINDOW (MAIN_MONITOR, X_OFFSCREEN, Y_OFFSCREEN)    'MOVE OFFSCREEN. NOT REQUIRED ONCE COMPILED
    SCREENRES 480, 160 : WIDTH 480/8, 160/16
    MOVE_GRAPHICS_WINDOW (1, 250, 250)
    PROGRAM_2_TASK(VAL(COMMAND(2)), COMMAND(3))
    SLEEP 5000 : END
END IF

'==============================================
Post Reply