diff --git a/atom/browser/api/atom_api_top_level_window.cc b/atom/browser/api/atom_api_top_level_window.cc
index 879a15667a82..10011e747d94 100644
--- a/atom/browser/api/atom_api_top_level_window.cc
+++ b/atom/browser/api/atom_api_top_level_window.cc
@@ -548,11 +548,9 @@ std::vector<int> TopLevelWindow::GetPosition() {
   return result;
 }
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
 void TopLevelWindow::MoveTop() {
   window_->MoveTop();
 }
-#endif
 
 void TopLevelWindow::SetTitle(const std::string& title) {
   window_->SetTitle(title);
@@ -1067,9 +1065,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("setResizable", &TopLevelWindow::SetResizable)
       .SetMethod("isResizable", &TopLevelWindow::IsResizable)
       .SetMethod("setMovable", &TopLevelWindow::SetMovable)
-#if defined(OS_WIN) || defined(OS_MACOSX)
       .SetMethod("moveTop", &TopLevelWindow::MoveTop)
-#endif
       .SetMethod("isMovable", &TopLevelWindow::IsMovable)
       .SetMethod("setMinimizable", &TopLevelWindow::SetMinimizable)
       .SetMethod("isMinimizable", &TopLevelWindow::IsMinimizable)
diff --git a/atom/browser/api/atom_api_top_level_window.h b/atom/browser/api/atom_api_top_level_window.h
index 21e29181713b..9366a9177234 100644
--- a/atom/browser/api/atom_api_top_level_window.h
+++ b/atom/browser/api/atom_api_top_level_window.h
@@ -126,9 +126,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
   void SetResizable(bool resizable);
   bool IsResizable();
   void SetMovable(bool movable);
-#if defined(OS_WIN) || defined(OS_MACOSX)
   void MoveTop();
-#endif
   bool IsMovable();
   void SetMinimizable(bool minimizable);
   bool IsMinimizable();
diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h
index 1fa2cac35c9b..7dee6b2443f9 100644
--- a/atom/browser/native_window.h
+++ b/atom/browser/native_window.h
@@ -113,9 +113,7 @@ class NativeWindow : public base::SupportsUserData,
   virtual double GetSheetOffsetX();
   virtual double GetSheetOffsetY();
   virtual void SetResizable(bool resizable) = 0;
-#if defined(OS_WIN) || defined(OS_MACOSX)
   virtual void MoveTop() = 0;
-#endif
   virtual bool IsResizable() = 0;
   virtual void SetMovable(bool movable) = 0;
   virtual bool IsMovable() = 0;
diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc
index 1a412c5a5c56..5b9d2ebcf19b 100644
--- a/atom/browser/native_window_views.cc
+++ b/atom/browser/native_window_views.cc
@@ -657,15 +657,19 @@ void NativeWindowViews::SetResizable(bool resizable) {
   resizable_ = resizable;
 }
 
-#if defined(OS_WIN)
 void NativeWindowViews::MoveTop() {
+  // TODO(julien.isorce): fix chromium in order to use existing
+  // widget()->StackAtTop().
+#if defined(OS_WIN)
   gfx::Point pos = GetPosition();
   gfx::Size size = GetSize();
   ::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
                  size.width(), size.height(),
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-}
+#elif defined(USE_X11)
+  atom::MoveWindowToForeground(GetAcceleratedWidget());
 #endif
+}
 
 bool NativeWindowViews::IsResizable() {
 #if defined(OS_WIN)
diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h
index 0d7a9850ea5c..53028b4bff12 100644
--- a/atom/browser/native_window_views.h
+++ b/atom/browser/native_window_views.h
@@ -74,9 +74,7 @@ class NativeWindowViews : public NativeWindow,
   void SetContentSizeConstraints(
       const extensions::SizeConstraints& size_constraints) override;
   void SetResizable(bool resizable) override;
-#if defined(OS_WIN)
   void MoveTop() override;
-#endif
   bool IsResizable() override;
   void SetMovable(bool movable) override;
   bool IsMovable() override;
diff --git a/atom/browser/ui/x/x_window_utils.cc b/atom/browser/ui/x/x_window_utils.cc
index 64aa8596a437..410c54e34a6e 100644
--- a/atom/browser/ui/x/x_window_utils.cc
+++ b/atom/browser/ui/x/x_window_utils.cc
@@ -88,4 +88,25 @@ bool ShouldUseGlobalMenuBar() {
   return false;
 }
 
+void MoveWindowToForeground(::Window xwindow) {
+  XDisplay* xdisplay = gfx::GetXDisplay();
+  XEvent xclient;
+  memset(&xclient, 0, sizeof(xclient));
+
+  xclient.type = ClientMessage;
+  xclient.xclient.display = xdisplay;
+  xclient.xclient.window = xwindow;
+  xclient.xclient.message_type = GetAtom("_NET_RESTACK_WINDOW");
+  xclient.xclient.format = 32;
+  xclient.xclient.data.l[0] = 2;
+  xclient.xclient.data.l[1] = 0;
+  xclient.xclient.data.l[2] = Above;
+  xclient.xclient.data.l[3] = 0;
+  xclient.xclient.data.l[4] = 0;
+
+  XSendEvent(xdisplay, DefaultRootWindow(xdisplay), x11::False,
+             SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
+  XFlush(xdisplay);
+}
+
 }  // namespace atom
diff --git a/atom/browser/ui/x/x_window_utils.h b/atom/browser/ui/x/x_window_utils.h
index 5888a2b25663..a2e3315d0fc0 100644
--- a/atom/browser/ui/x/x_window_utils.h
+++ b/atom/browser/ui/x/x_window_utils.h
@@ -23,6 +23,9 @@ void SetWindowType(::Window xwindow, const std::string& type);
 // Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
 bool ShouldUseGlobalMenuBar();
 
+// Bring the given window to the front and give it the focus.
+void MoveWindowToForeground(::Window xwindow);
+
 }  // namespace atom
 
 #endif  // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_
diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md
index 4ed4e611b9d2..294ecba017d0 100644
--- a/docs/api/browser-window.md
+++ b/docs/api/browser-window.md
@@ -1089,7 +1089,7 @@ can not be focused on.
 
 Returns `Boolean` - Whether the window is always on top of other windows.
 
-#### `win.moveTop()` _macOS_ _Windows_
+#### `win.moveTop()`
 
 Moves window to top(z-order) regardless of focus
 
diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js
index 575e6c7dcfa1..4c9ef7ca67f4 100644
--- a/spec/api-browser-window-spec.js
+++ b/spec/api-browser-window-spec.js
@@ -494,6 +494,48 @@ describe('BrowserWindow module', () => {
     })
   })
 
+  describe('BrowserWindow.moveTop()', () => {
+    it('should not steal focus', async () => {
+      const posDelta = 50
+      const wShownInactive = emittedOnce(w, 'show')
+      w.showInactive()
+      await wShownInactive
+      assert(!w.isFocused())
+
+      const otherWindow = new BrowserWindow({ show: false, title: 'otherWindow' })
+      const otherWindowShown = emittedOnce(otherWindow, 'show')
+      otherWindow.loadURL('data:text/html,<html><body background-color: rgba(255,255,255,0)></body></html>')
+      otherWindow.show()
+      await otherWindowShown
+      assert(otherWindow.isFocused())
+
+      w.moveTop()
+      const wPos = w.getPosition()
+      const wMoving = emittedOnce(w, 'move')
+      w.setPosition(wPos[0] + posDelta, wPos[1] + posDelta)
+      await wMoving
+      assert(!w.isFocused())
+      assert(otherWindow.isFocused())
+
+      const wFocused = emittedOnce(w, 'focus')
+      w.focus()
+      await wFocused
+      assert(w.isFocused())
+
+      otherWindow.moveTop()
+      const otherWindowPos = otherWindow.getPosition()
+      const otherWindowMoving = emittedOnce(otherWindow, 'move')
+      otherWindow.setPosition(otherWindowPos[0] + posDelta, otherWindowPos[1] + posDelta)
+      await otherWindowMoving
+      assert(!otherWindow.isFocused())
+      assert(w.isFocused())
+
+      await closeWindow(otherWindow, { assertSingleWindow: false }).then(() => {
+        assert.strictEqual(BrowserWindow.getAllWindows().length, 2) // Test window + w
+      })
+    })
+  })
+
   describe('BrowserWindow.capturePage(rect)', (done) => {
     it('returns a Promise with a Buffer', async () => {
       const image = await w.capturePage({