# Drag Popup Outside of Project

**URL:** <https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303>\
**Category:** Ignition\
**Tags:** ignition81, vision\
**Created:** [October 10, 2023, 7:55pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303 "2023-10-10T19:55:09Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [October 10, 2023, 7:55pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/1 "2023-10-10T19:55:09Z")

</div>

I have 2 monitors and I have a popup that I would like to be able to drag to a different screen and keep the main project on the other display. However, the popup dragging is constrained to the display that the project is displayed on.

Is there a way to allow the popup to be moved to the second monitor?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 10, 2023, 8:01pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/2 "2023-10-10T20:01:41Z")

</div>

Not moved, but you can open another desktop instance on the second monitor, and have the popup open there.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [October 10, 2023, 8:05pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/3 "2023-10-10T20:05:09Z")

</div>

Trying to do that now, but it's still stuck on my ~~main monitor.~~ inside the project. I can't even drag it on top of my docked window.

```auto
system.nav.desktop(1).openWindow('ALARMS - ACTIVE')

```

ALARMS - ACTIVE is a popup window

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [October 10, 2023, 8:25pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/4 "2023-10-10T20:25:07Z")

</div>

Ok, so not using a popup anymore, but I have a full-screen view of the window I want on another page, but I have no menu bar on the top to close it. I assume that the menu bar follows project properties, and that's why it's hidden?

```auto
system.gui.openDesktop(screen = 1, handle='Alarm Window')
system.nav.desktop('Alarm Window').openWindow('ALARMS - ACTIVE')

```

trying to use `system.gui.closeDesktop('Alarm Window)` on window close results in a java recursion limit error.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [October 10, 2023, 8:51pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/5 "2023-10-10T20:51:25Z")

</div>

> [@amarks](#):
>
> java recursion limit error.

That's ugly. Definitely want to report that--recursion limit that isn't jython is always a bug.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 8:06pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/6 "2024-03-01T20:06:57Z")

</div>

So, circling back to this again. I have one main client that will have multiple screens, but not all clients will have the same number of displays. The easy solution would be to allow popups to be dragged out of the vision client application and then they can be moved to whatever monitors are available.

If that's not an option, I might have to figure out how to script it to find how many monitors are available and provide a way to specify which monitor to open it on.

Thoughts?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 1, 2024, 8:35pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/7 "2024-03-01T20:35:38Z")

</div>

[system.gui.getScreens()](https://www.docs.inductiveautomation.com/docs/8.1/appendix/scripting-functions/system-gui/system-gui-getScreens), perhaps?

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 8:37pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/8 "2024-03-01T20:37:19Z")

</div>

Ya, working on it

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [March 1, 2024, 8:45pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/9 "2024-03-01T20:45:03Z")

</div>

system.gui.getScreens() doesn't return the relative positions of the screens.

Use this one instead.

> [@Inconsistent Screen Indexes](https://forum.inductiveautomation.com/t/inconsistent-screen-indexes/28578/4):
>
> As Phil has stated elsewhere, sun, moon, stars, etc. However, I believe it sources from java.awt.GraphicsEnvironment. I don’t know how it puts things in order, possibly in hardware names. getScreens() should probably also return the x and y properties from the bounds to give the location in the desktop space. In single monitor apps, they’d always be 0,0, but for my three-monitor setup, I get this: def getScreens(): import java.awt.GraphicsEnvironment as GE g\_env = G…

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 8:52pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/10 "2024-03-01T20:52:04Z")

</div>

Thanks. Adjusting the script from [this](https://forum.inductiveautomation.com/t/system-gui-opendesktop-fails-occasionally/73647/4) unfinished post, I have

```auto
openDesktops = len(system.gui.getDesktopHandles())
monitorData = Navigation.getScreens()
if openDesktops == 0 and len(monitorData) > 1:
	for desktopIndex, desktopWidth, desktopHeight, desktopX, desktopY in monitorData[1:]:
		handleName = "Desktop %d" %desktopIndex
		system.gui.openDesktop(screen=desktopIndex, handle=handleName, width=desktopWidth, height=desktopHeight, x=desktopX, y=desktopY).setAlwaysOnTop(False)
		#system.nav.desktop(handleName).swapTo('whatever/window/path')

```

Desktop 1 still opens on monitor 0 and desktop 2 is now not on any of the monitors.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [March 1, 2024, 9:00pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/11 "2024-03-01T21:00:39Z")

</div>

Try it with just the screen indexes first. Then try to get fancy after that. 😉

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 9:01pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/12 "2024-03-01T21:01:37Z")

</div>

So Ignition thinks my screen 3 is screen 1? Do the screen numbers not match the numbering in my Windows display settings?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 1, 2024, 9:06pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/13 "2024-03-01T21:06:58Z")

</div>

> [@amarks](#):
>
> not match

Correct, they do not (necessarily) match.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 9:08pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/14 "2024-03-01T21:08:28Z")

</div>

Well, not sure that it really matters in this case. The main window will be locked to fullscreen and I think I'll just use a button to open a maximized window that can be moved wherever the user wants.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 9:38pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/15 "2024-03-01T21:38:38Z")

</div>

This is what I came up with:

```auto
#base desktop handle
dHandle = 'Desktop '

#get handles
handles = system.gui.getDesktopHandles()

#no desktops open yet
if len(handles) == 0:
	nextIndex = 0
#other desktops open
else:
	#get list of the desktop indicies from the handle
	openDesktopIndicies = [int(handle.replace(dHandle,'')) for handle in handles]
	#get max index and increment for next index
	nextIndex = max(openDesktopIndicies)+1

#get the current window
window = system.nav.getCurrentWindow()

#open new desktop with current window
system.gui.openDesktop(handle=dHandle+str(nextIndex),windows = [window]).setAlwaysOnTop(False)

```

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 9:51pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/16 "2024-03-01T21:51:53Z")

</div>

What I'm running into now is that with the project open in fullscreen mode, opening a new desktop is in fullscreen mode. How can I make it windowed mode for the new desktops?

Thinking I could do something with [this](https://forum.inductiveautomation.com/t/max-window-size-in-different-monitors/32030/3) script after opening the new desktop?

```auto
from javax.swing import JFrame

window = system.gui.getParentWindow(event)
while not isinstance(window, JFrame):
	window = window.getParent()
if window.isUndecorated():
	# Switch to windowed mode.
	window.dispose()
	window.setUndecorated(False)
	window.setExtendedState(JFrame.NORMAL)
	# Restore previous window size and location, if available.
	try:
		normalW = event.source.getClientProperty('normalW')
		normalH = event.source.getClientProperty('normalH')
		normalX = event.source.getClientProperty('normalX')
		normalY = event.source.getClientProperty('normalY')
		window.setSize(normalW, normalH)
		window.setLocation(normalX, normalY)
	except:
		pass
	window.setVisible(True)
else:
	# Store window size and location for restore.
	event.source.putClientProperty('normalW', window.size.width)
	event.source.putClientProperty('normalH', window.size.height)
	event.source.putClientProperty('normalX', window.x)
	event.source.putClientProperty('normalY', window.y)
	# Switch to full screen mode.
	window.dispose()
	window.setUndecorated(True)
	window.setExtendedState(JFrame.MAXIMIZED_BOTH)
	window.setVisible(True)

```

Just not sure how to use this with the new desktop and window

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [March 1, 2024, 10:17pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/17 "2024-03-01T22:17:40Z")

</div>

Since I already have the JFrame from `system.gui.openDesktop()`, I should be able to pass that directly to the function that I've placed in the project script library.

```auto
#base desktop handle
dHandle = 'Desktop '

#get handles
handles = system.gui.getDesktopHandles()

#no desktops open yet
if len(handles) == 0:
	nextIndex = 0
#other desktops open
else:
	#get list of the desktop indicies from the handle
	openDesktopIndicies = [int(handle.replace(dHandle,'')) for handle in handles]
	#get max index and increment for next index
	nextIndex = max(openDesktopIndicies)+1

#get the current window
window = system.nav.getCurrentWindow()

#open new desktop with current window
desktop = system.gui.openDesktop(handle=dHandle+str(nextIndex),windows = [window]).setAlwaysOnTop(False)

Navigation.desktopSwapToWindowedMode(desktop)

```

```auto
#pass desktop JFrame directly
def desktopSwapToWindowedMode(desktop):

	from javax.swing import JFrame
	
	window = desktop
#skip this because we already have the JFrame
#	window = system.gui.getParentWindow(event)
#	while not isinstance(window, JFrame):
# window = window.getParent()
	if window.isUndecorated():
		# Switch to windowed mode.
		window.dispose()
		window.setUndecorated(False)
		window.setExtendedState(JFrame.NORMAL)
		# Restore previous window size and location, if available.
		try:
			normalW = event.source.getClientProperty('normalW')
			normalH = event.source.getClientProperty('normalH')
			normalX = event.source.getClientProperty('normalX')
			normalY = event.source.getClientProperty('normalY')
			window.setSize(normalW, normalH)
			window.setLocation(normalX, normalY)
		except:
			pass
		window.setVisible(True)
	else:
		# Store window size and location for restore.
		event.source.putClientProperty('normalW', window.size.width)
		event.source.putClientProperty('normalH', window.size.height)
		event.source.putClientProperty('normalX', window.x)
		event.source.putClientProperty('normalY', window.y)
		# Switch to full screen mode.
		window.dispose()
		window.setUndecorated(True)
		window.setExtendedState(JFrame.MAXIMIZED_BOTH)
		window.setVisible(True)

```

but I get an error at the first if statement

```auto
File "<module:Navigation>", line 146, in desktopSwapToWindowedMode
AttributeError: 'NoneType' object has no attribute 'isUndecorated'

```

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [March 1, 2024, 10:45pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/18 "2024-03-01T22:45:35Z")

</div>

> [@amarks](#):
>
> `system.gui.openDesktop(handle=dHandle+str(nextIndex),windows = [window]).setAlwaysOnTop(False)`

That needs to be broken into two lines:

```auto
desktop = system.gui.openDesktop(handle=dHandle+str(nextIndex),windows = [window])
desktop.setAlwaysOnTop(False)

```

You are assigning the result of `setAlwaysOnTop` to `desktop` instead of the window object from `system.gui.openDesktop`

I do the same thing all the time with the dictionary `.update` method

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [April 22, 2024, 9:01pm UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/19 "2024-04-22T21:01:22Z")

</div>

I'm getting an error now when I try to swap the window back to fullscreen mode. It says `event` doesn't exist.

Button script:

```python
desktop = Nav.getParentDesktop(system.gui.getParentWindow(event))

if Nav.desktopIsWindowedMode(desktop):
	Nav.desktopSwapDisplayMode(desktop)
else:
	Nav.desktopSwapDisplayMode(Nav.openNewDesktop())

```

Nav scripts:

```python
def getParentDesktop(window):
	'''
		Get the parent desktop JFrame for supplied window.
		
		Args:
			window	(obj) :	window on the desktop
			
		Returns:
			desktop	(JFrame)	:	window's parent desktop JFrame
	'''
	while not isinstance(window, JFrame):
		window = window.getParent()
		
	desktop = window
	
	return desktop
	
		
		
def desktopIsWindowedMode(window):
	'''
		Determine if a desktop is in windowed mode or not.
		
		Args:
			window	(ovj) :	Window to determine if the parent desktop is in fullscreen or windowed mode
			
		Returns:
			isWindowMode	(BOOL)	:	True if desktop is in window mode
	'''
	
	#undecorated = fullscreen
	return not Nav.getParentDesktop(window).isUndecorated()
	
		
def openNewDesktop():
	'''
		Open a new desktop window
		
		Args:
			n/a
			
		Returns:
			desktop (JFrame)	:	newly opened desktop
	'''
	
	#base desktop handle
	dHandle = 'Desktop '
	
	#get handles
	handles = system.gui.getDesktopHandles()
	
	#no desktops open yet
	if len(handles) == 0:
	    nextIndex = 0
	#other desktops open
	else:
	    #get list of the desktop indicies from the handle
	    openDesktopIndicies = [int(handle.replace(dHandle,'')) for handle in handles]
	    #get max index and increment for next index
	    nextIndex = max(openDesktopIndicies)+1
	
	#get the current window
	window = system.nav.getCurrentWindow()
	
	#open new desktop with current window
	desktop = system.gui.openDesktop(handle=dHandle+str(nextIndex),windows = [window, 'Nav'])
	desktop.setAlwaysOnTop(False)
	
	return desktop
	
def desktopSwapDisplayMode(desktop):
    '''
        Swap the selected "desktop" to windowed/fullscreen mode from fullscreen/windowed mode.
        
        Args:
            desktop (JFrame) : JFrame of desktop to be swapped to windowed mode.
        
        Returns:
            n/a
    '''

    
    window = desktop
    if window.isUndecorated():
        # Switch to windowed mode.
        window.dispose()
        window.setUndecorated(False)
        window.setExtendedState(JFrame.NORMAL)
        # Restore previous window size and location, if available.
        try:
            normalW = event.source.getClientProperty('normalW')
            normalH = event.source.getClientProperty('normalH')
            normalX = event.source.getClientProperty('normalX')
            normalY = event.source.getClientProperty('normalY')
            window.setSize(normalW, normalH)
            window.setLocation(normalX, normalY)
        except:
            pass
        window.setVisible(True)
    else:
        # Store window size and location for restore.
        event.source.putClientProperty('normalW', window.size.width)
        event.source.putClientProperty('normalH', window.size.height)
        event.source.putClientProperty('normalX', window.x)
        event.source.putClientProperty('normalY', window.y)
        # Switch to full screen mode.
        window.dispose()
        window.setUndecorated(True)
        window.setExtendedState(JFrame.MAXIMIZED_BOTH)
        window.setVisible(True)

```

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [April 23, 2024, 7:59am UTC](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303/20 "2024-04-23T07:59:46Z")

</div>

> [@amarks](#):
>
> `event` doesn't exist.

> [@amarks](#):
>
> `def desktopSwapDisplayMode(desktop):`

Change the argument in the `desktopSwapDisplayMode` library script, and get the desktop directly from there:

```python
def desktopSwapDisplayMode(event):
        desktop = getParentDesktop(system.gui.getParentWindow(event))

```

Then, all of the `event.` stuff in that script will work without throwing an error. As it is currently written, event isn't defined in that function.

[Next page](https://forum.inductiveautomation.com/t/drag-popup-outside-of-project/80303.md?page=2)
