Search Unity

Feedback Multi-Display: Deactivate Secondary Displays Workarounds?

Discussion in 'Scripting' started by DizzyWascal, Jun 5, 2018.

  1. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    Last edited: Jun 5, 2018
    AcKeskin and deus0 like this.
  2. L0ri3n

    L0ri3n

    Joined:
    Aug 1, 2015
    Posts:
    6
    I second this. Not being able to deactivate the Secondary Display is a real pain for my project.
    You have my vote!
    I'd like to know if anyone has come up with a workaround as well.
     
    AcKeskin likes this.
  3. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    I finally got a workaround but only for Windows.

    Since the name of the Secondary Display is always "Unity Secondary Display" I just created a .exe using .Net Framework to find and hide it fully.

    The script and the exe can be downloaded here.

    To apply in runtime just have that .exe file somewhere and use the code:
    Code (CSharp):
    1. Process process = new Process();
    2.  
    3. // Stop the process from opening a new window
    4. process.StartInfo.RedirectStandardOutput = true;
    5. process.StartInfo.UseShellExecute = false;
    6. process.StartInfo.CreateNoWindow = true;
    7.  
    8. // Setup executable and parameters
    9. process.StartInfo.FileName = @Application.streamingAssetsPath + "/" +  "Third Party Functions/Minimise Secondary Display/Windows/Windows-Minimise-Secondary.exe";
    10. //process.StartInfo.Arguments = "--test";
    11.  
    12. // Go
    13. process.Start();
    In my case I put it into my Streaming Asset Path.

    Will need to figure out code for linux and mac however.
     
    Last edited: Jun 18, 2018
  4. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    I would love the ability to deactivate displays, it would give the end user much more control.
     
    deus0 likes this.
  5. 1Riptide

    1Riptide

    Joined:
    Jan 10, 2016
    Posts:
    4
    Dealing with an Android (AOSP) project that features Unity in a MultiDisplay environment.
    2021.3.12f1

    If Unity gets ahold of an external display and starts sending camera data to it Android can never regain control of it. We can send other Android Activities to this external display, but it appears Unity just keep drawing over the top of them, even when the camera itself is not enabled (everything just freezes).

    Come on Unity. You have to let go of the Display. It's almost nonsensical to have Activate() without a DeActivate().
     
    DizzyWascal likes this.
  6. prakyathd801

    prakyathd801

    Joined:
    Oct 7, 2020
    Posts:
    5
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Runtime.InteropServices;
    5. using UnityEngine;
    6.  
    7. public class SetWindowState : MonoBehaviour
    8. {
    9.     public enum ShowStates
    10.     {
    11.         Hide = 0,
    12.         Normal = 1,
    13.         Minimized = 2,
    14.         Maximized = 3,
    15.         ShowNoActivateRecentPosition = 4,
    16.         Show = 5,
    17.         MinimizeActivateNext = 6,
    18.         MinimizeNoActivate = 7,
    19.         ShowNoActivate = 8,
    20.         Restore = 9,
    21.         ShowDefault = 10,
    22.         ForceMinimize = 11
    23.     }
    24.     static int hWnd = 0;
    25.  
    26.     private const int SW_HIDE = 0;
    27.     private const int SW_SHOW = 5;
    28.     [DllImport("User32")]
    29.     private static extern int ShowWindowAsync(int hwnd, int nCmdShow);
    30.  
    31.     [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
    32.     static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    33.  
    34.     [DllImport("user32.dll", SetLastError = true)]
    35.     static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    36.  
    37.  
    38.     public static void Hide()
    39.     {
    40.         hWnd = FindWindow(null, "Unity Secondary Display").ToInt32();
    41.         ShowWindowAsync(hWnd, SW_HIDE);
    42.     }
    43.  
    44.     public static void Show()
    45.     {
    46.         if (hWnd != 0)
    47.         {
    48.             ShowWindowAsync(hWnd, SW_SHOW);
    49.             hWnd = 0;
    50.         }
    51.     }
    52.  
    53.     static List<IntPtr> GetAllChildrenWindowHandles(IntPtr hParent, int maxCount)
    54.     {
    55.         List<IntPtr> result = new List<IntPtr>();
    56.         int ct = 0;
    57.         IntPtr prevChild = IntPtr.Zero;
    58.         IntPtr currChild = IntPtr.Zero;
    59.         while (true && ct < maxCount)
    60.         {
    61.             currChild = FindWindowEx(hParent, prevChild, null, null);
    62.             if (currChild == IntPtr.Zero) break;
    63.             result.Add(currChild);
    64.             prevChild = currChild;
    65.             ++ct;
    66.         }
    67.         return result;
    68.     }
    69.  
    70. }
    71.  
     
    DizzyWascal likes this.
  7. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    @prakyathd801 Thanks! That works really well. More neater, don't have to use a second .exe to hide the second screen.
     
  8. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    Are there any pointers/ leads for getting the second display to hide for Mac?
     
  9. prakyathd801

    prakyathd801

    Joined:
    Oct 7, 2020
    Posts:
    5
    Yes
     
  10. rithesh_unity758

    rithesh_unity758

    Joined:
    Aug 24, 2022
    Posts:
    1
    For mac :

    {
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Runtime.InteropServices;

    public class MacSecondaryWindow : ISecondaryWindow
    {
    private const string libName = "MacWindowsService";
    [DllImport(libName)]
    private static extern int GetWindowsCount();
    [DllImport(libName)]
    private static extern void OrderOut(int windowIndex);
    [DllImport(libName)]
    private static extern void OrderBack(int windowIndex);
    [DllImport(libName)]
    private static extern void OrderFront(int windowIndex);
    [DllImport(libName)]
    private static extern void OrderWindow();
    [DllImport(libName)]
    private static extern void OrderWindowByIndex(int windowIndex, int otherWindowIndex);
    [DllImport(libName)]
    private static extern void OrderWindowWithResolution(int windowIndex, int otherWindowIndex, int screenWidth, int screenHeight);

    [DllImport(libName)]
    private static extern void Order(int windowOrder, int windowIndex, int otherWindowIndex);
    public static int WindowsCount()
    {
    return GetWindowsCount();
    }
    public static void WindowOrderOut(int windowIndex)
    {
    OrderOut(windowIndex);
    }
    public static void WindowOrderBack(int windowIndex)
    {
    OrderBack(windowIndex);
    }
    public static void WindowOrderFront(int windowIndex)
    {
    OrderFront(windowIndex);
    }
    public static void WindowOrder(int windowOrder, int windowIndex, int otherWindowIndex)
    {
    Order(windowOrder, windowIndex, otherWindowIndex);
    }
    public static void WindowOrder()
    {
    OrderWindow();
    }
    public static void WindowOrder(int windowIndex, int otherWindowIndex)
    {
    OrderWindowByIndex(windowIndex, otherWindowIndex);
    }
    public void HideWindow()
    {
    // throw new System.NotImplementedException();
    WindowOrderOut(1);
    }

    public void MoveToMonitor(int x, int y, Vector2 screenResolution)
    {
    // throw new System.NotImplementedException();
    WindowOrder(1, 1, 1);
    }

    public void ShowWindow()
    {
    // throw new System.NotImplementedException();
    WindowOrderFront(1);
    WindowOrder(1, 1, 1);
    // OrderWindowWithResolution(1, 1, 128, 128);
    }
    public void DebugShowWindow()
    {
    WindowOrderFront(1);
    }
    }
    }
     
  11. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    This code won't work without that MacWindowsService plugin, any chance you could provide it?

    Helpful pointer though thanks for posting
     
  12. DizzyWascal

    DizzyWascal

    Joined:
    Jul 16, 2015
    Posts:
    21
    Because of @rithesh_unity758 post, the pointer really helped a lot.
    It took me a while to realise it isn't NSWindow [1] but NSWindow[2] that held Unity's Second Screen....

    I made a bundle in XCode called "MacMinimiseSecondary"
    It is attached. Place that .bundle file into Plugins > MacOS.

    Create a script anywhere and write this so you can access the functions:

    Code (CSharp):
    1. #if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using System.Runtime.InteropServices;
    6.  
    7.     public static class SetWindowState
    8.     {
    9.         [DllImport("MacMinimiseSecondary")]
    10.         private static extern void _HideWindow();
    11.         [DllImport("MacMinimiseSecondary")]
    12.         private static extern void _ShowWindow();
    13.  
    14.         public static void Hide()
    15.         {
    16.             _HideWindow();
    17.         }
    18.  
    19.         public static void Show()
    20.         {
    21.             _ShowWindow();
    22.         }
    23.     }
    24. #endif
    Use Hide() or Show() to hide and show the second display after you've used Display.Activate().

    If you're hesitant to use the .bundle attached.
    Download XCode and use New > Bundle.
    Create a Folder called 'Source' in that folder create an Objective-C++ script.
    (no option for Objective-C++ ? just select Objective-C and rename that file with .mm)

    Then type in the code in the screenshot.



    In the XCode Build Settings make sure you have Cocoa and Appkit frameworks:


    Then go to Product and Build.
    Product should also have the Open Build in Finder option. Under Debug folder your .bundle should be there.
    Drag and drop that .bundle file in you Plugin > MacOS folder.

    Whatever file name that .bundle folder is make sure it is reflected on the
    [DllImport("bundle name")] part of your Unity script.

    If it is called MyPlugin.bundle
    then it will be [DllImport("MyPlugin")]
     

    Attached Files: