#include "ui/views/widget/widget_hwnd_utils.h"
#include <dwmapi.h>
#include "base/command_line.h"
#include "components/viz/common/features.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/base/mojom/window_show_state.mojom.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/win/hwnd_message_handler.h"
namespace views {
namespace {
struct WindowStyles {
DWORD style;
DWORD ex_style;
DWORD class_style;
};
WindowStyles CalculateWindowStylesFromInitParams(
const Widget::InitParams& params,
WidgetDelegate* widget_delegate,
internal::NativeWidgetDelegate* native_widget_delegate,
bool is_translucent) {
WindowStyles styles = {.style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
.ex_style = 0,
.class_style = CS_DBLCLKS};
if (features::ShouldRemoveRedirectionBitmap()) {
styles.ex_style |= WS_EX_NOREDIRECTIONBITMAP;
}
if (params.child) {
styles.style |= WS_CHILD;
}
if (params.show_state == ui::mojom::WindowShowState::kMaximized) {
styles.style |= WS_MAXIMIZE;
}
if (params.show_state == ui::mojom::WindowShowState::kMinimized) {
styles.style |= WS_MINIMIZE;
}
if (!params.accept_events) {
styles.ex_style |= WS_EX_TRANSPARENT;
}
DCHECK_NE(Widget::InitParams::Activatable::kDefault, params.activatable);
if (params.activatable == Widget::InitParams::Activatable::kNo) {
styles.ex_style |= WS_EX_NOACTIVATE;
}
if (params.EffectiveZOrderLevel() != ui::ZOrderLevel::kNormal) {
styles.ex_style |= WS_EX_TOPMOST;
}
if (params.shadow_type == Widget::InitParams::ShadowType::kDrop) {
styles.class_style |= CS_DROPSHADOW;
}
switch (params.type) {
case Widget::InitParams::TYPE_WINDOW: {
styles.style |= WS_OVERLAPPEDWINDOW;
if (!widget_delegate->CanMaximize()) {
styles.style &= static_cast<DWORD>(~WS_MAXIMIZEBOX);
}
if (!widget_delegate->CanMinimize()) {
styles.style &= static_cast<DWORD>(~WS_MINIMIZEBOX);
}
if (!widget_delegate->CanResize()) {
styles.style &= static_cast<DWORD>(~(WS_THICKFRAME | WS_MAXIMIZEBOX));
}
if (params.remove_standard_frame) {
styles.style &= static_cast<DWORD>(~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
WS_CAPTION | WS_SYSMENU));
}
if (native_widget_delegate->IsDialogBox()) {
styles.style |= DS_MODALFRAME;
styles.style |= native_widget_delegate->IsModal() ? WS_POPUP : 0;
}
styles.ex_style |=
native_widget_delegate->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0;
if (is_translucent) {
styles.style &= static_cast<DWORD>(~(WS_THICKFRAME | WS_CAPTION));
}
break;
}
case Widget::InitParams::TYPE_CONTROL:
styles.style |= WS_VISIBLE;
break;
case Widget::InitParams::TYPE_BUBBLE:
styles.style |= WS_POPUP;
styles.style |= WS_CLIPCHILDREN;
styles.ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_POPUP:
styles.style |= WS_POPUP;
styles.ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_MENU:
styles.style |= WS_POPUP;
if (params.remove_standard_frame) {
styles.style |= WS_THICKFRAME;
}
styles.ex_style |= WS_EX_TOOLWINDOW;
break;
case Widget::InitParams::TYPE_DRAG:
case Widget::InitParams::TYPE_TOOLTIP:
case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
styles.style |= WS_POPUP;
if (params.dont_show_in_taskbar) {
styles.ex_style |= WS_EX_TOOLWINDOW;
}
if (params.force_system_menu_for_frameless &&
params.type == Widget::InitParams::TYPE_WINDOW_FRAMELESS) {
styles.style |= WS_SYSMENU;
}
break;
default:
NOTREACHED();
}
return styles;
}
}
bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) {
return !(window_pos->flags & SWP_NOSIZE) ||
window_pos->flags & SWP_FRAMECHANGED;
}
bool DidMinimizedChange(UINT old_size_param, UINT new_size_param) {
return (
(old_size_param == SIZE_MINIMIZED && new_size_param != SIZE_MINIMIZED) ||
(old_size_param != SIZE_MINIMIZED && new_size_param == SIZE_MINIMIZED));
}
void ConfigureWindowStyles(
HWNDMessageHandler* handler,
const Widget::InitParams& params,
WidgetDelegate* widget_delegate,
internal::NativeWidgetDelegate* native_widget_delegate) {
bool is_translucent =
(params.opacity == Widget::InitParams::WindowOpacity::kTranslucent);
WindowStyles styles = CalculateWindowStylesFromInitParams(
params, widget_delegate, native_widget_delegate, is_translucent);
handler->set_is_translucent(is_translucent);
handler->set_use_rounded_corner(
!params.rounded_corners.value_or(gfx::RoundedCornersF()).IsEmpty());
handler->set_initial_class_style(styles.class_style);
handler->set_window_style(handler->window_style() | styles.style);
handler->set_window_ex_style(handler->window_ex_style() | styles.ex_style);
}
}