Pantheon on laptop + external monitor, windows created under panel

I’m having fun with the different panel configs, and have more or less settled on Pantheon + Dock. The problem is that if I leave the panel at the top of the screen (where I want it) when I have an external monitor plugged into my laptop (which I usually do) every window that is created on the laptop screen has its top edge at the very top of the screen, under the panel.

I know how to use the Alt key to click the window and drag it down, but that gets tiresome. How do I tell Mate to take the panel into account when creating windows? It does that just fine when the external monitor is not connected.

I have the external monitor set to extend the display. What seems to be the issue is that the external is above the laptop screen. If I tell it that the laptop is to either side, the new windows are created with their top edge at the bottom edge of the panel.

I’ve looked through every setting I can find, but haven’t found one that fixes this issue. Thoughts or suggestions welcome. :slight_smile:

Are you using Marco or Compiz?

What are your screen resolutions?
Next command will print the resolutions.

xrandr -q | grep '*'

Thanks, for your response. I’m using Marco (Adaptive Compositor). Happy to try other options if that would help. Here is the output:

1366x768 59.91*+
1280x1024 60.02*+ 75.02

The first is the laptop. Here is the output of the xprop command when I click on the panel:

xprop _NET_WM_STRUT_PARTIAL
_NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 0, 0, 0, 0, 0, 0, 1365, 0, 0

and

xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 0, 1366, 1792, 0, 0, 1366, 1792, 0, 0, 1366, 1792, 0, 0, 1366, 1792

OK, you have one big virtual screen 1366x1792 pixels.

The monitors are aligned like this:

+-------------------+
|                   |
|    1280x1024      |
|                   |
|                   |
|                   |
+-------------------+-----+
|      panel              |
+-------------------------+
|                         |
|         1366x768        |

+-------------------------+

You want to preserve space on the left side of the screen.
You need to set the left group in _NET_WM_STRUT_PARTIAL

_NET_WM_STRUT_PARTIAL, left, right, top, bottom, left_start_y, left_end_y,
right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
bottom_end_x,CARDINAL[12]/32

left = the width of your panel, 1365
left_start_y = height of upper monitor. 1024
left_end_y = left_start_y + height of area you want to reserve ( 1024+heigth of the panel )

This is an example with the panel height of 30 pixels, therefore left_end_y= 1024+30= 1054.

Connect the second monitor run next in the terminal and when + appears click on the panel.

xprop -f _NET_WM_STRUT_PARTIAL 32c -set _NET_WM_STRUT_PARTIAL 1365,0,0,0,1024,1054,0,0,0,0,0,0

Instead of clicking to change the panel strut you could write a script that detects the change of workarea, finds the window id of the top panel and uses that window id to set the panel strut. Simple, right? :slight_smile:

Ok, thanks! I did a little more searching, and also found this article which was very helpful: https://alice-at-ubuntu.blogspot.com/2015/01/how-to-reserve-space-for-panel-between.html

I put together a quick and dirty script which “cheats” by taking advantage of the fact that the top panel is named, conveniently enough, “Top Panel” :grin:

#!/bin/sh

PATH=/usr/bin
export PATH

xprop -root _NET_WORKAREA | while read prop equals value; do
	case "$value" in
	# Strut has not been set
	'0, 0, 1366, 1792,'*)
		xprop -name "Top Panel" -f _NET_WM_STRUT_PARTIAL 32c -set _NET_WM_STRUT_PARTIAL 1366,0,0,0,1024,1052,0,0,0,0,0,0
		echo 'Strut set'
		#xprop -name "Top Panel" _NET_WM_STRUT_PARTIAL
		;;
	# Strut has been set
	'0, 0, 1366, 1024,'*)
		echo 'Strut already set'
		#xprop -name "Top Panel" _NET_WM_STRUT_PARTIAL
		;;
	# Should not be reached
	*)	echo 'Something weird is happening'
		echo "Workarea: $value"
		exit 1 ;;
	esac
done

exit $?

I found it interesting that after setting the strut that that the value of net-workarea changed, but it was useful here.

I’m curious, when you say “detects the change of workarea,” is there an event that occurs when the external monitor is initialized that I can use to trigger the script? Where could I find more information about that, if so? I could run a cron job to check repeatedly, or even run a job that starts at boot and loops for a while to see if I’ve plugged in the monitor yet, but that seems … inelegant.

Also, what is the best technique to use to “properly” detect the window id of the panel? In the script referenced above the author uses wmctrl, which is apparently not installed by default. Is that the best way to get information about all the windows? I found this command on line, seems Ok?

xwininfo -tree -idxwininfo -root | awk ‘/^xwininfo/{print $4}’`

I do appreciate your help though, as the information in the other thread was a bit too dense for me to parse.

I am curious, why isn’t the panel setting a new strut for itself when the external monitor is plugged in? When running just the laptop’s monitor the top panel does set an appropriate strut. I can maximize windows, open new windows, etc. and the panel strut is always respected. Same if the monitors are side by side (and I would imagine it would be the same if the primary display were on top, although I have not tested it). It seems to only be this configuration that is troublesome. I imagine that’s because the strut it already set works in those other configurations, so it’s actually not changing anything, it’s just a happy accident. Whereas in this configuration that strut doesn’t work.

And one more question. I’m running Pantheon and the dock (Plank). If I open the panel’s properties dialog, the panel appears as an icon in Plank, and won’t go away. It also allows minimizing the panel window if I click on the Plank icon for it. Is this a bug? If so, can you point me to a reference to report it?

As soon as the monitor is plugged in, _NET_WORKAREA root window property changes.
Xprop can spy on that property.

xprop -root -spy _NET_WORKAREA

If the workarea changes when the strut is set. the previous xprop command will print every time the panel strut is set, the change the strut again and create an indefinite loop.
So you have to skip setting the strut once it's set. Maybe check if the strut is already set to preserve space.

Window id is in the window stack.
There are several ways to get the window id. With wmctrl is the easiest.

wmctrl -lx | grep "mate-panel.Mate-panel" | grep "Top Panel" | cut -d' ' -f1

-x Include WM_CLASS in the window list or interpret as the WM_CLASS name.

First grep checks for window class mate-panel, the second one check the window name.
If there is a file named "Top Panel" and that file is opened with some other app, the window name can also be "Top Panel". That's why there is a check for the window class first.


The same with xprop:

[code]WIN_STACK="$(xprop -root _NET_CLIENT_LIST_STACKING | cut -d '#' -f 2 | tr ',' '\n' )"
for WIN_ID in $WIN_STACK; do
xprop -notype -id $WIN_ID -f WM_CLASS 8u ' $0\n' WM_CLASS
| awk '/mate-panel/{print $2}'
| xprop -notype -id $WIN_ID -f _NET_WM_NAME 8u " $0" _NET_WM_NAME
| grep -q 'Top Panel'
&& printf -v TOP_PANEL $WIN_ID
done

echo $TOP_PANEL
[/code]

Probably because the monitors are not the same width/height.

Panel is a window, but it's sticky window. Windows with that property are not shown in the window list in the panel and are not suppose to appear in plank.

That's why wmctrl prints "-1" when you do
wmctrl -l

bugs reports here Bugs : Plank

Thanks again, this is great stuff! I can’t wait to play around with it. That -spy command for xprop is an elegant solution. :sunglasses:

One more item for the archive, I discovered this morning when I resumed from sleep that the strut was reset to the default. Probably as a result of the suspend event “disconnecting” the external monitor, but I’m not sure. I’ll be able to solve that now with the xprop -spy option when I redo this script, but I thought it was worth mentioning.

Here is my script, as discussed. Thoughts and suggestions welcome. :grinning:

One additional note, I found while testing that the panel resets its own strut every time an icon enters or leaves the notification area. Fun!

#!/bin/bash

    PATH=/usr/bin:/bin
    export PATH

    spy () {
    	xprop -root -spy _NET_WORKAREA | read -a new_net_work

    	if [ "${net_work[*]}" != "${new_net_work[*]}" ]; then
    		exec "$0"
    	fi
    }

    # Determine display(s) and resolution(s)
    while read a b c d ; do
    	case "$b" in
    	connected)
    		case "$c" in
    		primary)
    			pri_x=${d%%x*}
    			#pri_y=${d%%+*} ; pri_y=${pri_y#*x}
    			;;
    		[0-9]*)
    			sec_x=${c%%x*}
    			sec_y=${c%%+*} ; sec_y=${sec_y#*x}
    			;;
    		esac
    	esac
    done < <(xrandr -q)

    # Store this here to use in spy
    read -a net_work < <(xprop -root _NET_WORKAREA)

    # If there is only one monitor, we're done for now
    if [ -z "$sec_x" ]; then
    	spy
    fi

    largest_x=$pri_x
    [ $sec_x -gt $largest_x ] && largest_x=$sec_x

    # If the monitors are arranged horizontally, we're done for now
    if [ "${net_work[4]}" != "${largest_x}," ]; then
    	spy
    fi

    # Find the panel and its resolution so we know how tall it is
    read p_id p_res < <(xwininfo -root -children |
        awk '/[Tt]op\ [Pp]anel.*[Mm]ate-[Pp]anel/ {print $1,$6}')
    p_y=${p_res%%+*} ; p_y=${p_y#*x}

    read -a strut < <(xprop -id $p_id _NET_WM_STRUT_PARTIAL)

    case "${strut[2]} ${strut[3]} ${strut[4]} ${strut[5]}" in
    '0, 0, 0, 0,'|found*)
    	# There is no vertical strut set, so set one
    	#echo "Debug> Setting strut"
    	xprop -id $p_id -f _NET_WM_STRUT_PARTIAL 32c -set _NET_WM_STRUT_PARTIAL ${pri_x},0,0,0,${sec_y},$(( $sec_y + $p_y )),0,0,0,0,0,0
    	# This value changes when the strut is set,
    	# so use it to detect if it gets unset
    	read -a net_work < <(xprop -root _NET_WORKAREA)
    	;;
    esac

    spy

    exit 0

Um, you could spy on that panel's strut just to see when the strut is set. :grinning:
The sript is nicely done.

I hope that Victor and the other dev from gnome have a proper solution.

When the panel resets the strut it also resets net workarea, so by -spy’ing on that property I can detect both the panel reset, and when I plug in the second monitor.

Thank you for the kind words on the script. :slight_smile: I made a couple of tweaks based on some more testing with just one monitor.

Sorry, I meant for debugging, you could spy on that panel's strut in another terminal. :grin:

The script does what it is intended in case the top panel borders the second monitor and when the new monitor screen is aligned on top.
But what if you put the first monitor on top? Will then the bottom panel's strut be incorrect?
There is also the case when the left and right panels are bordering the screen.

I was thinking, inspired by the way xfce handles the xfce4-panels, if there is a way to set the correct strut in all the situations when the panel isn't on the big virtual screen edge.

if you can check all the panels and detect if there is a floating panel, I guess you could (in theory) set the correct struts for all the panels in all the situations ( if the left panel isn't connected to the left virtual screen edge, top panel isn't on the top edge, the same for right and bottom panel). Just not sure what would happen if there are two or more panels with the same position. E. g. two or more top panels, two or more left panels...