Skip to content

Commit

Permalink
[macOS extend-to-title] Add scene/project name to the editor title, f…
Browse files Browse the repository at this point in the history
…ix incorrect window button position/order when system primary language is RTL.
  • Loading branch information
bruvzg committed Sep 22, 2022
1 parent 8e14f9b commit f4b9873
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 62 deletions.
2 changes: 2 additions & 0 deletions doc/classes/DisplayServer.xml
Expand Up @@ -1548,6 +1548,8 @@
</constant>
<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
</constant>
<constant name="WINDOW_EVENT_TITLEBAR_CHANGE" value="7" enum="WindowEvent">
</constant>
<constant name="VSYNC_DISABLED" value="0" enum="VSyncMode">
No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible).
</constant>
Expand Down
5 changes: 5 additions & 0 deletions doc/classes/Window.xml
Expand Up @@ -455,6 +455,11 @@
Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
<signal name="titlebar_changed">
<description>
Emitted when window title bar decorations are changed, e.g., macOS window enter/exit full screen mode, or extend-to-title flag is changed.
</description>
</signal>
<signal name="visibility_changed">
<description>
Emitted when [Window] is made visible or disappears.
Expand Down
70 changes: 50 additions & 20 deletions editor/editor_node.cpp
Expand Up @@ -429,7 +429,7 @@ void EditorNode::_version_control_menu_option(int p_idx) {

void EditorNode::_update_title() {
const String appname = ProjectSettings::get_singleton()->get("application/config/name");
String title = (appname.is_empty() ? TTR("Unnamed Project") : appname) + String(" - ") + VERSION_NAME;
String title = (appname.is_empty() ? TTR("Unnamed Project") : appname);
const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String();
if (!edited.is_empty()) {
// Display the edited scene name before the program name so that it can be seen in the OS task bar.
Expand All @@ -439,8 +439,10 @@ void EditorNode::_update_title() {
// Display the "modified" mark before anything else so that it can always be seen in the OS task bar.
title = vformat("(*) %s", title);
}

DisplayServer::get_singleton()->window_set_title(title);
DisplayServer::get_singleton()->window_set_title(title + String(" - ") + VERSION_NAME);
if (project_title) {
project_title->set_text(title);
}
}

void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
Expand Down Expand Up @@ -659,6 +661,12 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);

Window *window = static_cast<Window *>(get_tree()->get_root());
if (window) {
// Handle macOS fullscreen and extend-to-title changes.
window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
}

OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
get_tree()->get_root()->set_as_audio_listener_3d(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
Expand Down Expand Up @@ -713,6 +721,8 @@ void EditorNode::_notification(int p_what) {
ProjectSettings::get_singleton()->save();
}

_titlebar_resized();

/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;

Expand Down Expand Up @@ -1170,6 +1180,18 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}

void EditorNode::_titlebar_resized() {
const Size2 &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID);
if (left_menu_spacer) {
int w = (gui_base->is_layout_rtl()) ? margin.y : margin.x;
left_menu_spacer->set_custom_minimum_size(Size2(w, 0));
}
if (right_menu_spacer) {
int w = (gui_base->is_layout_rtl()) ? margin.x : margin.y;
right_menu_spacer->set_custom_minimum_size(Size2(w, 0));
}
}

void EditorNode::_version_button_pressed() {
DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
}
Expand Down Expand Up @@ -3390,7 +3412,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
tb->add_theme_font_size_override("font_size", singleton->gui_base->get_theme_font_size(SNAME("main_button_font_size"), SNAME("EditorFonts")));

singleton->main_editor_buttons.push_back(tb);
singleton->main_editor_button_vb->add_child(tb);
singleton->main_editor_button_hb->add_child(tb);
singleton->editor_table.push_back(p_editor);

singleton->distraction_free->move_to_front();
Expand Down Expand Up @@ -6590,14 +6612,14 @@ EditorNode::EditorNode() {

if (can_expand) {
// Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
Control *menu_spacer = memnew(Control);
menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
menu_hb->add_child(menu_spacer);
left_menu_spacer = memnew(Control);
left_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
menu_hb->add_child(left_menu_spacer);
}

main_menu = memnew(MenuBar);
menu_hb->add_child(main_menu);

main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
main_menu->set_flat(true);
main_menu->set_start_index(0); // Main menu, add to the start of global menu.
Expand Down Expand Up @@ -6766,22 +6788,30 @@ EditorNode::EditorNode() {
project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);

// Spacer to center 2D / 3D / Script buttons.
Control *left_spacer = memnew(Control);
HBoxContainer *left_spacer = memnew(HBoxContainer);
left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
left_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(left_spacer);

menu_hb->add_spacer();
if (can_expand && global_menu) {
project_title = memnew(Label);
project_title->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
project_title->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
project_title->set_focus_mode(Control::FOCUS_NONE);
project_title->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
project_title->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
project_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
left_spacer->add_child(project_title);
}

main_editor_button_vb = memnew(HBoxContainer);
menu_hb->add_child(main_editor_button_vb);
main_editor_button_hb = memnew(HBoxContainer);
menu_hb->add_child(main_editor_button_hb);

// Options are added and handled by DebuggerEditorPlugin.
debug_menu = memnew(PopupMenu);
debug_menu->set_name(TTR("Debug"));
main_menu->add_child(debug_menu);

menu_hb->add_spacer();

settings_menu = memnew(PopupMenu);
settings_menu->set_name(TTR("Editor"));
main_menu->add_child(settings_menu);
Expand Down Expand Up @@ -6855,6 +6885,7 @@ EditorNode::EditorNode() {
// Spacer to center 2D / 3D / Script buttons.
Control *right_spacer = memnew(Control);
right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
right_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(right_spacer);

launch_pad = memnew(PanelContainer);
Expand Down Expand Up @@ -6965,10 +6996,9 @@ EditorNode::EditorNode() {

if (can_expand) {
// Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
Control *menu_spacer = memnew(Control);
menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
menu_hb->add_child(menu_spacer);
right_menu_spacer = memnew(Control);
right_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
menu_hb->add_child(right_menu_spacer);
}

String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
Expand Down Expand Up @@ -7523,9 +7553,9 @@ EditorNode::EditorNode() {
screenshot_timer->set_owner(get_owner());

// Adjust spacers to center 2D / 3D / Script buttons.
int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
int max_w = MAX(launch_pad->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));

// Extend menu bar to window title.
if (can_expand) {
Expand Down
6 changes: 5 additions & 1 deletion editor/editor_node.h
Expand Up @@ -322,6 +322,9 @@ class EditorNode : public Node {
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;

Label *project_title = nullptr;
Control *left_menu_spacer = nullptr;
Control *right_menu_spacer = nullptr;
EditorTitleBar *menu_hb = nullptr;
VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr;
Expand Down Expand Up @@ -397,7 +400,7 @@ class EditorNode : public Node {
String current_path;
MenuButton *update_spinner = nullptr;

HBoxContainer *main_editor_button_vb = nullptr;
HBoxContainer *main_editor_button_hb = nullptr;
Vector<Button *> main_editor_buttons;
Vector<EditorPlugin *> editor_table;

Expand Down Expand Up @@ -560,6 +563,7 @@ class EditorNode : public Node {
void _close_messages();
void _show_messages();
void _vp_resized();
void _titlebar_resized();
void _version_button_pressed();

int _save_external_resources();
Expand Down
3 changes: 3 additions & 0 deletions platform/macos/display_server_macos.h
Expand Up @@ -170,6 +170,7 @@ class DisplayServerMacOS : public DisplayServer {
Point2i origin;
bool displays_arrangement_dirty = true;
bool is_resizing = false;
bool is_fs_resizing = false;

CursorShape cursor_shape = CURSOR_ARROW;
NSCursor *cursors[CURSOR_MAX];
Expand Down Expand Up @@ -226,6 +227,8 @@ class DisplayServerMacOS : public DisplayServer {
void popup_close(WindowID p_window);
void set_is_resizing(bool p_is_resizing);
bool get_is_resizing() const;
void set_is_fs_resizing(bool p_is_resizing);
bool get_is_fs_resizing() const;

void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
Expand Down
39 changes: 24 additions & 15 deletions platform/macos/display_server_macos.mm
Expand Up @@ -662,6 +662,14 @@
return is_resizing;
}

void DisplayServerMacOS::set_is_fs_resizing(bool p_is_resizing) {
is_fs_resizing = p_is_resizing;
}

bool DisplayServerMacOS::get_is_fs_resizing() const {
return is_fs_resizing;
}

void DisplayServerMacOS::window_update(WindowID p_window) {
#if defined(GLES3_ENABLED)
if (gl_manager) {
Expand Down Expand Up @@ -2664,21 +2672,17 @@
ERR_FAIL_COND_V(!windows.has(p_window), Vector2i());
const WindowData &wd = windows[p_window];

float max_x = 0.f;
NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton];
if (cb) {
max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width);
}
NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton];
if (mb) {
max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width);
}
NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton];
if (zb) {
max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width);
if (!wd.window_button_view) {
return Vector2i();
}

return Vector2i(max_x * screen_get_max_scale(), 0);
float max_x = wd.wb_offset.x + [wd.window_button_view frame].size.width;

if ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft) {
return Vector2i(0, max_x * screen_get_max_scale());
} else {
return Vector2i(max_x * screen_get_max_scale(), 0);
}
}

void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled) {
Expand All @@ -2687,15 +2691,19 @@
p_wd.window_button_view = nil;
}
if (p_enabled) {
float window_buttons_spacing = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]) - NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
float cb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
float mb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]);
bool is_rtl = ([p_wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft);

float window_buttons_spacing = (is_rtl) ? (cb_frame - mb_frame) : (mb_frame - cb_frame);

[p_wd.window_object setTitleVisibility:NSWindowTitleHidden];
[[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES];

p_wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect];
[p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y)];
[p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y) rtl:is_rtl];
[p_wd.window_view addSubview:p_wd.window_button_view];
} else {
[p_wd.window_object setTitleVisibility:NSWindowTitleVisible];
Expand Down Expand Up @@ -2741,6 +2749,7 @@
}
}
[wd.window_object setFrame:rect display:YES];
send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
} break;
case WINDOW_FLAG_BORDERLESS: {
// OrderOut prevents a lose focus bug with the window.
Expand Down
3 changes: 2 additions & 1 deletion platform/macos/godot_button_view.h
Expand Up @@ -41,9 +41,10 @@
NSPoint offset;
CGFloat spacing;
bool mouse_in_group;
bool rtl;
}

- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset;
- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl;
- (void)displayButtons;

@end
Expand Down
23 changes: 17 additions & 6 deletions platform/macos/godot_button_view.mm
Expand Up @@ -39,29 +39,35 @@ - (id)initWithFrame:(NSRect)frame {
offset = NSMakePoint(8, 8);
spacing = 20;
mouse_in_group = false;
rtl = false;

return self;
}

- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset {
- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl {
spacing = button_spacing;
rtl = is_rtl;

NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled];
[close_button setFrameOrigin:NSMakePoint(0, 0)];
[close_button setFrameOrigin:NSMakePoint(rtl ? spacing * 2 : 0, 0)];
[self addSubview:close_button];

NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled];
[miniaturize_button setFrameOrigin:NSMakePoint(spacing, 0)];
[self addSubview:miniaturize_button];

NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled];
[zoom_button setFrameOrigin:NSMakePoint(spacing * 2, 0)];
[zoom_button setFrameOrigin:NSMakePoint(rtl ? 0 : spacing * 2, 0)];
[self addSubview:zoom_button];

offset.y = button_offset.y - zoom_button.frame.size.height / 2;
offset.x = button_offset.x - zoom_button.frame.size.width / 2;

[self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
if (rtl) {
[self setFrameSize:NSMakeSize(close_button.frame.origin.x + close_button.frame.size.width, close_button.frame.size.height)];
} else {
[self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
}
[self displayButtons];
}

Expand All @@ -70,8 +76,13 @@ - (void)viewDidMoveToWindow {
return;
}

[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
if (rtl) {
[self setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(self.window.frame.size.width - self.frame.size.width - offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
} else {
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
}
}

- (BOOL)_mouseInGroup:(NSButton *)button {
Expand Down

0 comments on commit f4b9873

Please sign in to comment.