/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <X11/X.h>
#include <X11/Xlib.h>
#include <string.h>

#include <memory>

#include "api/scoped_refptr.h"
#include "modules/desktop_capture/desktop_capture_types.h"
#include "modules/desktop_capture/desktop_geometry.h"
#include "modules/desktop_capture/linux/x11/shared_x_display.h"
#include "modules/desktop_capture/rgba_color.h"
#include "modules/desktop_capture/screen_drawer.h"
#include "modules/desktop_capture/screen_drawer_lock_posix.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/sleep.h"

namespace webrtc {

namespace {

// A ScreenDrawer implementation for X11.
class ScreenDrawerLinux : public ScreenDrawer {
 public:
  ScreenDrawerLinux();
  ~ScreenDrawerLinux() override;

  // ScreenDrawer interface.
  DesktopRect DrawableRegion() override;
  void DrawRectangle(DesktopRect rect, RgbaColor color) override;
  void Clear() override;
  void WaitForPendingDraws() override;
  bool MayDrawIncompleteShapes() override;
  WindowId window_id() const override;

 private:
  // Bring the window to the front, this can help to avoid the impact from other
  // windows or shadow effect.
  void BringToFront();

  rtc::scoped_refptr<SharedXDisplay> display_;
  int screen_num_;
  DesktopRect rect_;
  Window window_;
  GC context_;
  Colormap colormap_;
};

ScreenDrawerLinux::ScreenDrawerLinux() {
  display_ = SharedXDisplay::CreateDefault();
  RTC_CHECK(display_.get());
  screen_num_ = DefaultScreen(display_->display());
  XWindowAttributes root_attributes;
  if (!XGetWindowAttributes(display_->display(),
                            RootWindow(display_->display(), screen_num_),
                            &root_attributes)) {
    RTC_DCHECK_NOTREACHED() << "Failed to get root window size.";
  }
  window_ = XCreateSimpleWindow(
      display_->display(), RootWindow(display_->display(), screen_num_), 0, 0,
      root_attributes.width, root_attributes.height, 0,
      BlackPixel(display_->display(), screen_num_),
      BlackPixel(display_->display(), screen_num_));
  XSelectInput(display_->display(), window_, StructureNotifyMask);
  XMapWindow(display_->display(), window_);
  while (true) {
    XEvent event;
    XNextEvent(display_->display(), &event);
    if (event.type == MapNotify) {
      break;
    }
  }
  XFlush(display_->display());
  Window child;
  int x, y;
  if (!XTranslateCoordinates(display_->display(), window_,
                             RootWindow(display_->display(), screen_num_), 0, 0,
                             &x, &y, &child)) {
    RTC_DCHECK_NOTREACHED() << "Failed to get window position.";
  }
  // Some window manager does not allow a window to cover two or more monitors.
  // So if the window is on the first monitor of a two-monitor system, the
  // second half won't be able to show up without changing configurations of WM,
  // and its DrawableRegion() is not accurate.
  rect_ = DesktopRect::MakeLTRB(x, y, root_attributes.width,
                                root_attributes.height);
  context_ = DefaultGC(display_->display(), screen_num_);
  colormap_ = DefaultColormap(display_->display(), screen_num_);
  BringToFront();
  // Wait for window animations.
  SleepMs(200);
}

ScreenDrawerLinux::~ScreenDrawerLinux() {
  XUnmapWindow(display_->display(), window_);
  XDestroyWindow(display_->display(), window_);
}

DesktopRect ScreenDrawerLinux::DrawableRegion() {
  return rect_;
}

void ScreenDrawerLinux::DrawRectangle(DesktopRect rect, RgbaColor color) {
  rect.Translate(-rect_.left(), -rect_.top());
  XColor xcolor;
  // X11 does not support Alpha.
  // X11 uses 16 bits for each primary color, so we need to slightly normalize
  // a 8 bits channel to 16 bits channel, by setting the low 8 bits as its high
  // 8 bits to avoid a mismatch of color returned by capturer.
  xcolor.red = (color.red << 8) + color.red;
  xcolor.green = (color.green << 8) + color.green;
  xcolor.blue = (color.blue << 8) + color.blue;
  xcolor.flags = DoRed | DoGreen | DoBlue;
  XAllocColor(display_->display(), colormap_, &xcolor);
  XSetForeground(display_->display(), context_, xcolor.pixel);
  XFillRectangle(display_->display(), window_, context_, rect.left(),
                 rect.top(), rect.width(), rect.height());
  XFlush(display_->display());
}

void ScreenDrawerLinux::Clear() {
  DrawRectangle(rect_, RgbaColor(0, 0, 0));
}

// TODO(zijiehe): Find the right signal from X11 to indicate the finish of all
// pending paintings.
void ScreenDrawerLinux::WaitForPendingDraws() {
  SleepMs(50);
}

bool ScreenDrawerLinux::MayDrawIncompleteShapes() {
  return true;
}

WindowId ScreenDrawerLinux::window_id() const {
  return window_;
}

void ScreenDrawerLinux::BringToFront() {
  Atom state_above = XInternAtom(display_->display(), "_NET_WM_STATE_ABOVE", 1);
  Atom window_state = XInternAtom(display_->display(), "_NET_WM_STATE", 1);
  if (state_above == None || window_state == None) {
    // Fallback to use XRaiseWindow, it's not reliable if two windows are both
    // raise itself to the top.
    XRaiseWindow(display_->display(), window_);
    return;
  }

  XEvent event;
  memset(&event, 0, sizeof(event));
  event.type = ClientMessage;
  event.xclient.window = window_;
  event.xclient.message_type = window_state;
  event.xclient.format = 32;
  event.xclient.data.l[0] = 1;  // _NET_WM_STATE_ADD
  event.xclient.data.l[1] = state_above;
  XSendEvent(display_->display(), RootWindow(display_->display(), screen_num_),
             False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
}

}  // namespace

// static
std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
  return std::make_unique<ScreenDrawerLockPosix>();
}

// static
std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
  if (SharedXDisplay::CreateDefault().get()) {
    return std::make_unique<ScreenDrawerLinux>();
  }
  return nullptr;
}

}  // namespace webrtc
