How to make a program run in a specific monitor?

Everything else that doesn't fall into one of the other PB categories.
Kaiser
Enthusiast
Enthusiast
Posts: 118
Joined: Tue Jan 11, 2005 8:36 am

How to make a program run in a specific monitor?

Post by Kaiser »

Hi ^^

Yup, I got a dual monitor set up now :) but I'm worried the other monitor doesn't do much than staying with the same screen most of the time (I use MSN, and WinAmp, and browse some stuff there, but when I'm playing or doing something else...) so, I saw a screensaver code in the forum doing some search, and found code from blueznl about getting the handles of the monitors, that's good - but then, how do I make it so I can open a screen (or a window, whatever) so it appears on that display, and not in the monitor the app's running? (of course, I know there may be stuff that can override it, like nView and such, but since it's a program for personal use, I'll just have to hardcode it and it'll be ready :P

So, in short... I have the Monitor's Handle... how to put it to use? :)
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

you don't need the monitor's handle

lemme see if i can dig it up... this should give you some info

all you need to remember is that windows sees multiple monitors as simply a large desktop (unless multiple desktops have been defined, but that's a different ballgame)

so all you need to know is the origin of the monitor you want to put your window on

unfortunately, that's the one thing fred left out of his desktop library, but i think code below will give you a clue what to do

it uses some other parts of the x_lib.pb file, so you may have to download the whole thing for a working 3.94 sample, see the survival guide (link below) where it is included

http://www.xs4all.nl/~bluez/datatalk/survival_guide.arj

Code: Select all


Procedure.l x_monitor_monitorenumproc(windowid, message, wParam, lParam)                 ; deprecated
  ;
  ; store on each call the monitor handle in the x_monitor() list
  ; called by windows in callback as set up in x_monitor_detect() by the api EnumDisplayMonitors_()
  ; also known as MonitorEnumProc
  ;
  AddElement(x_monitor())
  x_monitor()\hnd = windowid
  ;
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure.l x_monitor_detect()                                                           ; find info on (multi) monitor setup and desktop sizes and coords
  Protected info.MONITORINFOEX, device.DISPLAY_DEVICE, n.l, x.l
  Global x_retval.l, x_monitor_n.l
  Global x_monitor_sameformat.l, x_monitor_primary.l
  Global x_desktop_x, x_desktop_y, x_desktop_width.l, x_desktop_height.l
  ;
  ; *** detect number of screens and retrieve their properties
  ;
  ; retval: n                         - number of screens
  ; out:    x_monitor_n.l             - number of screens
  ;         x_monitor_primary.l       - number of primary display
  ;         x_monitor_sameformat.l    - whaddayah think?
  ;         x_desktop_width.l         - desktop width
  ;         x_desktop_height.l        - desktop height
  ;         x_desktop_x.l             - top left corner of most top left screen
  ;         x_desktop_y.l             - top left corner of most top left screen
  ;         x_monitor.x_monitorinfo() - linked list starting at 0 containing monitor info
  ;
  ; note:
  ;
  ; - forget nt3 nt4 w95... all pretty much hopeless when it comes to multimonitor support
  ; - set x_multimonitorsupport = #false to disable multimonitor support
  ; - looks like fred is adding natural support for multi monitor configs in purebasic... oh well... at least i had the excercise
  ;
  If OSVersion() = #PB_OS_Windows_95 Or OSVersion() = #PB_OS_Windows_NT3_51 Or OSVersion() = #PB_OS_Windows_NT_4
    ;
    ; just report to the system there is only one monitor...
    ;
    x_monitor_n = 1
    x_monitor_primary = 1
    x_monitor_sameformat = #True
    x_desktop_width = GetSystemMetrics_(#SM_CXSCREEN)
    x_desktop_height = GetSystemMetrics_(#SM_CYSCREEN)
    x_desktop_x = 0
    x_desktop_y = 0
    ;
    ClearList(x_monitor())
    AddElement(x_monitor())
    x_monitor()\n = x_monitor_n
    x_monitor()\name = ""
    x_monitor()\flags = 0
    x_monitor()\f = 0
    x_monitor()\d = 0
    x_monitor()\w = x_desktop_width
    x_monitor()\h = x_desktop_height
    x_monitor()\x = x_desktop_x
    x_monitor()\y = x_desktop_y
    ;
  Else
    ;
    ;
    ; *** using GetSystemMetrics_()
    ;
    ; provides quite a bit info on display adapters, screens etc. but does not provide info
    ; per monitor / device on multi monitor setups
    ;
    ; x_monitor_n = GetSystemMetrics_(#SM_CMONITORS)
    ;
    x_monitor_sameformat.l = GetSystemMetrics_(#SM_SAMEDISPLAYFORMAT)
    ;
    x_desktop_x = GetSystemMetrics_(#SM_XVIRTUALSCREEN)
    x_desktop_y = GetSystemMetrics_(#SM_YVIRTUALSCREEN)
    x_desktop_width = GetSystemMetrics_(#SM_CXVIRTUALSCREEN)
    x_desktop_height = GetSystemMetrics_(#SM_CYVIRTUALSCREEN)
    ;
    ; Debug "same display format on all screens (0 = no)"
    ; Debug x_monitor_sameformat
    ; Debug "counted using getsystemmetrics"
    ; Debug x_monitor_n
    ;
    ; *** using EnumDisplayMonitors()
    ;
    ; returns monitors overlapping a given rectangle, including pseudo / mirror monitors!
    ; after the call, for each monitor a handle will be stored in x_monitor()\hnd
    ; this can be used to obtain more information using GetMonitorInfo_()
    ; flags returned are different from EnumDisplayDevices()
    ;
    ; the results were not always conclusive when using these functions, so i choose to use
    ; EnumDisplayDevices instead (see below)
    ;
    ; ClearList(x_monitor())
    ; EnumDisplayMonitors_(0,0,@x_monitor_monitorenumproc(),0)      ; call the function
    ; info.MONITORINFOEX                                            ; create a struct for GetMonitorInfo_()
    ; info\cb = SizeOf(info)                                        ; length of struct (important for MONITORINFO vs. MONITORINFOEX)
    ; x_monitor_n = 0                                               ; nr. of monitors
    ; ResetList(x_monitor())                                        ; reset and...
    ; While NextElement(x_monitor())                                ; go through the list
    ;   x_monitor_n = x_monitor_n+1
    ;   x_monitor()\n = x_monitor_n                                 ; sequential number
    ;   GetMonitorInfo_(x_monitor()\hnd,@info)                      ; get info on the monitor
    ;   x_monitor()\x = info\m_x1
    ;   x_monitor()\y = info\m_y1
    ;   x_monitor()\w = info\m_x2 - info\m_x1
    ;   x_monitor()\h = info\m_y2 - info\m_y1
    ;   x_monitor()\name = PeekS(@info\name,32)                     ; i want my fixed length strings!
    ; Wend
    ; ;
    ; Debug "counted using enumdisplaymonitors"
    ; Debug x_monitor_n
    ;
    ; *** using EnumDisplayDevices_()
    ;
    ; walks through all available devices, retrieve names and flags
    ; by using the returned flags all 'non-real' monitors can be filtered out
    ;
    device.DISPLAY_DEVICE                                           ; to store results from EnumDisplayDevices_()
    device\cb = SizeOf(DISPLAY_DEVICE)
    settings.DEVMODE                                                ; to store results from EnumDisplaySettings_()
    settings\dmSize = SizeOf(settings)                              ; DEVMODE is defined in purebasic itself
    settings\dmDriverExtra = 0
    ;
    ClearList(x_monitor())
    ;
    n.l = 0
    x_monitor_n = 0
    x_desktop_x = 0
    x_desktop_y = 0
    While EnumDisplayDevices_(0,n,@device,0) > 0                    ; check all devices
      n = n+1
      ;
      ; the StateFlags field in the filled struct contains information on the device / monitor
      ; some values to check with (not all cards / drivers support all functions):
      ;
      ; #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP - in use and part of the desktop
      ; #DISPLAY_DEVICE_PRIMARY_DEVICE      - primary device
      ; #DISPLAY_DEVICE_VGA_COMPATIBLE      - none reported
      ; #DISPLAY_DEVICE_MULTI_DRIVER
      ; #DISPLAY_DEVICE_ACTIVE
      ; #DISPLAY_DEVICE_ATTACHED
      ;
      If device\StateFlags & #DISPLAY_DEVICE_ATTACHED_TO_DESKTOP      ; check if it's part of the desktop
        ;
        ; if a device is part of the desktop, additional information can be retrieved using
        ; EnumDisplaySettings_() with the device name
        ;
        If EnumDisplaySettings_(@device\DeviceName,#ENUM_CURRENT_SETTINGS,@settings) > 0
          ;
          ; first store some info found via EnumDisplayDevices_()
          ;
          AddElement(x_monitor())
          x_monitor()\n = x_monitor_n
          x_monitor()\name = PeekS(@device\DeviceName,32)             ; i want my fixed length strings!
          x_monitor()\flags = device\StateFlags
          ;
          If x_monitor()\flags & #DISPLAY_DEVICE_PRIMARY_DEVICE
            x_monitor_primary = x_monitor_n
          EndIf
          ;
          ; and more stuff found via EnumDisplaySettings_()
          ;
          x_monitor()\f = settings\dmDisplayFrequency
          x_monitor()\d = settings\dmBitsPerPel
          x_monitor()\w = settings\dmPelsWidth
          x_monitor()\h = settings\dmPelsHeight
          x_monitor()\x = PeekL(@settings\dmOrientation)              ; the default definition in purebasic didn't include the onion, well, this works as well
          x_monitor()\y = PeekL(@settings\dmPaperLength)
          ;
          ; x_desktop_x = x_min( x_desktop_x , x_monitor()\x )
          ; x_desktop_y = x_min( x_desktop_y , x_monitor()\y )
          ; x_desktop_width = x_max( x_monitor()\x + x_monitor()\w - x_desktop_x , x_desktop_width )
          ; x_desktop_height = x_max( x_monitor()\y + x_monitor()\h - x_desktop_height , x_desktop_height )
          ;
          ; still, the handle is missing, so find it one using a point that is somewhere on the monitor
          ; theoretically, overlapping devices would be possible and thus screw retrieving any handle...
          ; haven't seent that though... yet :-( note that enummonitorsettings allows a different way to
          ; find screen handles
          ;
          ; work around for calling the monitorfrompoint function, purebasic tries to get the address of
          ; the function at program start, thus it will error out on nt4, however by opening the dll
          ; by hand and looking for the function by name we can circumvent this
          ;
          ;   x_monitor()\hnd = MonitorFromPoint_(x_monitor()\x,x_monitor()\y,#MONITOR_DEFAULTTONULL)
          ;
          x = OpenLibrary(#PB_Any,"USER32.DLL")
          x_monitor()\hnd = CallFunction(x,"MonitorFromPoint",x_monitor()\x,x_monitor()\y,#MONITOR_DEFAULTTONULL)
          CloseLibrary(x)
          ;
          x_monitor_n = x_monitor_n+1
        EndIf
      EndIf
    Wend
    ;
    ; Debug "counted using enumdisplaydevices"
    ; Debug x_monitor_n
    ;
  EndIf
  ;
  x_retval = x_monitor_n
  ProcedureReturn x_retval
EndProcedure
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

You can check if another desktop is used for the other monitor by enumerating the desktops. There should be some code for this on the forums.
Post Reply