If you have a setup similar to this:
|----------------|
| xxxxxxxxxx |
| xxxxxxxxxx | Secondary display
| xxxxxxxxxx |
|----------------|
|--------|
| | Primary display
|--------|
then WingPanel's struts prevent you from moving windows to the overlapped part the top, secondary display (marked with x). If you kill WingPanel, you can move windows freely.
The same behavior happens with other dock/panel windows, like putting Plank at the top of the Primary display; you cannot place windows directly above Plank on the secondary display, only on the left or right edges.
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
Bug previously filed against WingPanel https://github.com/elementary/wingpanel/issues/33
This appears to happen in Mutter itself on elementary OS Loki as well, so we might not be able to fix it directly in Gala.
There are some nice visualizations at https://github.com/elementary/switchboard-plug-display/issues/61
A workaround for this issue would be: configure the upper display as main display. Once elementaryOS status bar isn't in the way, you'll be able to pull windows up and down two stacked displays.
@viniciusrtf I believe we used to enforce that and we thought it was buggy. But I think that's the best workaround if we can't fix it directly; the top-most display must be the primary display. That causes some less-severe issues with Plank (it's hard to reveal it if it's hidden).
Honnestly, some fix or better workaround must be found.
This works at home only, but not in front of an audience when you have confidentiality concerns (talk, lesson, customer presentation).
@cassidyjames
Making the top screen the primary display as a workaround is not a good idea in my opinion.
I refer to work use cases or public demonstrations, when you plug your computer to a projector: you don't want to show your private stuff (because if the external screen becomes primary, all windows will appear there).
I don't know the technical issue regarding Mutter, but I can say it works without issue in Gnome with its top bar.
Gonna punt this since it happens in Loki already so it's not a regression
@phocean in case of confidentiality concerns, you can leave the default setup of having monitors side-by-side. Putting windows to the second monitor would be little bit awkward (dragging to the right instead of up) but there is a chance the projector is behind you anyway so any direction would be awkward.
I did this before discovering I can drag the monitors in switchboard to rearrange them, so it's definitely possible to use it that way.
Has this been fixed? Had this problem since Loki.
This happens when the windows are on top of each other.
This workout, while its not ideal, works. However my primary display keeps switching back. Is this is a known issue?
I'm also facing the same issue, would love to have it working. It's a very common occurrence nowadays to have this setup with the small laptops.
TL;DR To my understanding this issue is not in Gala or Mutter! I think the problem are the struts of the wingpanel (as stated in https://github.com/elementary/wingpanel/issues/33)
I did a first implementation (https://github.com/elementary/wingpanel/pull/235) which should solve this problem for all multi-monitor setups with up to 3 monitor. As far as I understand the specification it is not possible to solve this problem for all multi-monitor layouts in general.
Specification:
freedesktop.org defines the specifaction _NET_WM_STRUT_PARTIAL which clients can use to reserve space at the edge of the screen. The Window Manager then reduces the WORKSPACE_AREA by this indicated area.
var position_top = monitor_y - panel_displacement;
long struts[12];
this.screen.get_monitor_geometry (monitor, out primary_monitor_rect);
// We need to manually include the scale factor here as GTK gives us unscaled sizes for widgets
struts = { 0, 0, position_top * scale_factor, 0, /* strut-left, strut-right, strut-top, strut-bottom */
0, 0, /* strut-left-start-y, strut-left-end-y */
0, 0, /* strut-right-start-y, strut-right-end-y */
monitor_x, ((monitor_x + monitor_width) * scale_factor) - 1, /* strut-top-start-x, strut-top-end-x */
0, 0 }; /* strut-bottom-start-x, strut-bottom-end-x */
As one can see the wingpanel is actually reserving ALL space above the bottom edge of panel. Therefore it is not possible to move a window above the wingpanel.
Visualization:

Solid dark lines: Monitors, Blue area: area that client reserves. Dotted area: screen area
A problem is that, the _NET_WM_STRUCT_PARTICAL specification is limited in that way that it does not allow to reserve space for arbitrary rectangles. Instead it only allows to reserve space at the borders of screen area (which is the sum of all monitor areas). As for multi-monitor layouts the wingpanel can also be within this screen area (and not at the border) this makes it impossible to reserve the correct space for all possible multi-monitor layouts.
One Solution:
Fortunately for up to 3 monitors it is always a possible to reserve the correct space by also using the struct-left and struct-right cardinals as shown in this example:

Solid dark lines: Monitors, Blue area: area that client reserves. Dotted area: screen area
For setups where the primary monitor has a left, right and top neighbor (example with ❌) I think there is no way one can use this specification to reserve the correct area. I think in this case it is the best to reserve no space at all.
Closing to re-focus the issue on https://github.com/elementary/wingpanel/issues/33
Most helpful comment
@cassidyjames
Making the top screen the primary display as a workaround is not a good idea in my opinion.
I refer to work use cases or public demonstrations, when you plug your computer to a projector: you don't want to show your private stuff (because if the external screen becomes primary, all windows will appear there).
I don't know the technical issue regarding Mutter, but I can say it works without issue in Gnome with its top bar.