Skip to content

Commit

Permalink
feat: add WindowBuilder::with_focused (#576)
Browse files Browse the repository at this point in the history
* feat: add `WindowBuilder::with_focused`

ref: tauri-apps/tauri#5120

* fix linux build

* macos orderfront only

* restore accept-focus

* fix linux impl

* remove set_transient_for call

* Update src/window.rs

* Update src/window.rs

* Update src/platform_impl/linux/window.rs

* fmt

* import parent

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
amrbashir and lucasfernog committed Oct 3, 2022
1 parent 0637c60 commit e42ff07
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changes/window-builder-focused.md
@@ -0,0 +1,5 @@
---
"tao": "patch"
---

Add `WindowBuilder::with_focused` to specify whether to initially focus the window or not.
25 changes: 23 additions & 2 deletions src/platform_impl/linux/window.rs
Expand Up @@ -6,7 +6,10 @@ use std::{
cell::RefCell,
collections::VecDeque,
rc::Rc,
sync::atomic::{AtomicBool, AtomicI32, Ordering},
sync::{
atomic::{AtomicBool, AtomicI32, Ordering},
Arc,
},
};

use gdk::{WindowEdge, WindowState};
Expand Down Expand Up @@ -70,7 +73,10 @@ impl Window {
) -> Result<Self, RootOsError> {
let app = &event_loop_window_target.app;
let window_requests_tx = event_loop_window_target.window_requests_tx.clone();
let window = gtk::ApplicationWindow::new(app);
let window = gtk::ApplicationWindow::builder()
.application(app)
.accept_focus(attributes.focused)
.build();
let window_id = WindowId(window.id());
event_loop_window_target
.windows
Expand Down Expand Up @@ -246,6 +252,21 @@ impl Window {
window.set_transient_for(Some(&parent));
}

// restore accept-focus after the window has been drawn
// if the window was initially created without focus
if !attributes.focused {
let signal_id = Arc::new(RefCell::new(None));
let signal_id_ = signal_id.clone();
let id = window.connect_draw(move |window, _| {
if let Some(id) = signal_id_.take() {
window.set_accept_focus(true);
window.disconnect(id);
}
Inhibit(false)
});
signal_id.borrow_mut().replace(id);
}

let w_pos = window.position();
let position: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_pos.0.into(), w_pos.1.into()));
let position_clone = position.clone();
Expand Down
9 changes: 7 additions & 2 deletions src/platform_impl/macos/window.rs
Expand Up @@ -488,6 +488,7 @@ impl UnownedWindow {
let fullscreen = win_attribs.fullscreen.take();
let maximized = win_attribs.maximized;
let visible = win_attribs.visible;
let focused = win_attribs.focused;
let decorations = win_attribs.decorations;
let inner_rect = win_attribs
.inner_size
Expand Down Expand Up @@ -526,8 +527,12 @@ impl UnownedWindow {
// state, since otherwise we'll briefly see the window at normal size
// before it transitions.
if visible {
// Tightly linked with `app_state::window_activation_hack`
unsafe { window.ns_window.makeKeyAndOrderFront_(nil) };
if focused {
// Tightly linked with `app_state::window_activation_hack`
unsafe { window.ns_window.makeKeyAndOrderFront_(nil) };
} else {
unsafe { window.ns_window.orderFront_(nil) };
}
}

if maximized {
Expand Down
2 changes: 2 additions & 0 deletions src/platform_impl/windows/window.rs
Expand Up @@ -880,6 +880,8 @@ unsafe fn init<T: 'static>(
// WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured.
window_flags.set(WindowFlags::RESIZABLE, attributes.resizable);

window_flags.set(WindowFlags::MARKER_DONT_FOCUS, !attributes.focused);

let parent = match pl_attribs.parent {
Parent::ChildOf(parent) => {
window_flags.set(WindowFlags::CHILD, true);
Expand Down
28 changes: 19 additions & 9 deletions src/platform_impl/windows/window_state.rs
Expand Up @@ -79,26 +79,28 @@ bitflags! {
const TRANSPARENT = 1 << 6;
const CHILD = 1 << 7;
const MAXIMIZED = 1 << 8;
const POPUP = 1 << 14;
const ALWAYS_ON_BOTTOM = 1 << 16;
const POPUP = 1 << 9;
const ALWAYS_ON_BOTTOM = 1 << 10;

/// Marker flag for fullscreen. Should always match `WindowState::fullscreen`, but is
/// included here to make masking easier.
const MARKER_EXCLUSIVE_FULLSCREEN = 1 << 9;
const MARKER_BORDERLESS_FULLSCREEN = 1 << 13;
const MARKER_EXCLUSIVE_FULLSCREEN = 1 << 11;
const MARKER_BORDERLESS_FULLSCREEN = 1 << 12;

/// The `WM_SIZE` event contains some parameters that can effect the state of `WindowFlags`.
/// In most cases, it's okay to let those parameters change the state. However, when we're
/// running the `WindowFlags::apply_diff` function, we *don't* want those parameters to
/// effect our stored state, because the purpose of `apply_diff` is to update the actual
/// window's state to match our stored state. This controls whether to accept those changes.
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 10;
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 13;

const MARKER_IN_SIZE_MOVE = 1 << 11;
const MARKER_IN_SIZE_MOVE = 1 << 14;

const MINIMIZED = 1 << 12;
const MARKER_DONT_FOCUS = 1 << 15;

const IGNORE_CURSOR_EVENT = 1 << 15;
const MINIMIZED = 1 << 16;

const IGNORE_CURSOR_EVENT = 1 << 17;

const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits;
}
Expand Down Expand Up @@ -277,7 +279,15 @@ impl WindowFlags {

if new.contains(WindowFlags::VISIBLE) {
unsafe {
ShowWindow(window, SW_SHOW);
ShowWindow(
window,
if self.contains(WindowFlags::MARKER_DONT_FOCUS) {
self.set(WindowFlags::MARKER_DONT_FOCUS, false);
SW_SHOWNOACTIVATE
} else {
SW_SHOW
},
);
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/window.rs
Expand Up @@ -208,6 +208,13 @@ pub struct WindowAttributes {
pub window_menu: Option<platform_impl::Menu>,

pub preferred_theme: Option<Theme>,

/// Whether the window should be initially focused or not.
///
/// ## Platform-specific:
///
/// **Android / iOS:** Unsupported.
pub focused: bool,
}

impl Default for WindowAttributes {
Expand All @@ -230,6 +237,7 @@ impl Default for WindowAttributes {
window_icon: None,
window_menu: None,
preferred_theme: None,
focused: false,
}
}
}
Expand Down Expand Up @@ -411,6 +419,17 @@ impl WindowBuilder {
self
}

/// Whether the window will be initially focused or not.
///
/// ## Platform-specific:
///
/// **Android / iOS:** Unsupported.
#[inline]
pub fn with_focused(mut self, focused: bool) -> WindowBuilder {
self.window.focused = focused;
self
}

/// Builds the window.
///
/// Possible causes of error include denied permission, incompatible system, and lack of memory.
Expand Down

0 comments on commit e42ff07

Please sign in to comment.