Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add set_badge_count for Linux, iOS; set_badge_label for Macos; set_overlay_icon for Windows #1002

Merged
merged 34 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
95b44b9
overlay_icon
ahqsoftwares Oct 30, 2024
04d7d0c
Initial Commit
ahqsoftwares Oct 31, 2024
89f1959
fix
ahqsoftwares Oct 31, 2024
5a7ea43
Implement set_badge_count for linux
ahqsoftwares Oct 31, 2024
2ae0181
fix set_badge_count
ahqsoftwares Oct 31, 2024
d48c540
fix set_badge_count
ahqsoftwares Oct 31, 2024
b2d7324
.md file
ahqsoftwares Oct 31, 2024
282d310
chore: rename overlay_icon.rs to overlay.rs
ahqsoftwares Oct 31, 2024
0f50130
fix: refactor in overlay.rs
ahqsoftwares Oct 31, 2024
2f61655
Merge branch 'dev' into dev
ahqsoftwares Nov 4, 2024
f647ab6
fix: Fix typos with the code that somehow crept into the pr
ahqsoftwares Nov 4, 2024
b990279
refactor
ahqsoftwares Nov 4, 2024
1836855
Update src/platform_impl/windows/window.rs
ahqsoftwares Nov 4, 2024
e881d17
refactor: fix example + impl requested changes
ahqsoftwares Nov 4, 2024
f54fcee
Merge branch 'dev' of https://github.com/ahqsoftwares/tao into dev
ahqsoftwares Nov 4, 2024
348acf6
add: implement ios
ahqsoftwares Nov 4, 2024
0bf3c38
fix: macos
ahqsoftwares Nov 5, 2024
ce4eb27
refactor: remove unnecessary set_badge_count
ahqsoftwares Nov 5, 2024
68d1d6d
add: WindowExtIos set_badge_count
ahqsoftwares Nov 5, 2024
3b86266
Update badge_count.md
ahqsoftwares Nov 5, 2024
12bd9b8
chore: fmt
ahqsoftwares Nov 5, 2024
7e697e1
Update .changes/badge_count.md
ahqsoftwares Nov 5, 2024
e799df9
fix example: overlay
ahqsoftwares Nov 5, 2024
d69c57e
Merge branch 'dev' of https://github.com/ahqsoftwares/tao into dev
ahqsoftwares Nov 5, 2024
995d0f8
fmt
ahqsoftwares Nov 5, 2024
aa5e852
fmt
ahqsoftwares Nov 5, 2024
6110dde
fix: set_overlay_icon for Windows
ahqsoftwares Nov 5, 2024
b0eb6c1
fix: typos + impl for UnownedWindow
ahqsoftwares Nov 5, 2024
e46b9e8
fix: macos issue
ahqsoftwares Nov 5, 2024
33e0c32
feat: introduce EventLoopWindowTargetExtIos
ahqsoftwares Nov 5, 2024
0c6c8b5
fix: Probably fixed overlay example
ahqsoftwares Nov 5, 2024
49d870d
add a missing import
ahqsoftwares Nov 5, 2024
f4424b9
add another missing ios import
ahqsoftwares Nov 5, 2024
f84c710
chore: fmt
ahqsoftwares Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/badge_count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Add **set_badge_count** for Linux, iOS; **set_badge_label** for Macos; **set_overlay_icon** for Windows
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
Binary file added examples/icon.ico
Binary file not shown.
79 changes: 79 additions & 0 deletions examples/overlay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2014-2021 The winit contributors
// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0

use std::env::current_dir;
use tao::{
event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::{Key, ModifiersState}, window::WindowBuilder
};

#[allow(clippy::single_match)]
fn main() {
env_logger::init();
let event_loop = EventLoop::new();

let window = WindowBuilder::new().build(&event_loop).unwrap();

let mut modifiers = ModifiersState::default();

eprintln!("Key mappings:");
#[cfg(windows)]
eprintln!(" [any key]: Show the Overlay Icon");
#[cfg(not(windows))]
eprintln!(" [1-5]: Show a Badge count");
eprintln!(" Ctrl+1: Clear");

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::WindowEvent { event, .. } => match event {
WindowEvent::ModifiersChanged(new_state) => {
modifiers = new_state;
}
WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key: Key::Character(key_str),
state: ElementState::Released,
..
},
..
} => {
#[cfg(not(windows))]
if modifiers.is_empty() {
window.set_badge_count(Some(match key_str {
"1" => 1,
"2" => 2,
"3" => 3,
"4" => 4,
"5" => 5,
_ => 20
}), None);
} else if modifiers.control_key() && key_str == "1" {
window.set_badge_count(None, None);
}

#[cfg(windows)]
{
use tao::{window::Icon, platform::windows::WindowExtWindows, platform::windows::IconExtWindows};
if modifiers.is_empty() {
let mut path = current_dir().unwrap();
path.push("./examples/icon.ico");

window.set_overlay_icon(Some(Icon::from_path(path, None).unwrap()));
} else if modifiers.control_key() && key_str == "1" {
window.set_overlay_icon(None);
}
}
}
_ => {}
},
_ => {}
}
});
}
15 changes: 15 additions & 0 deletions src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ pub trait WindowExtMacOS {
///
/// <https://developer.apple.com/documentation/appkit/nswindow/1419167-titlebarappearstransparent>
fn set_titlebar_transparent(&self, transparent: bool);

/// Sets the badge label on the taskbar
fn set_badge_label(&self, label: Option<String>);
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
}

impl WindowExtMacOS for Window {
Expand Down Expand Up @@ -161,6 +164,11 @@ impl WindowExtMacOS for Window {
fn set_titlebar_transparent(&self, transparent: bool) {
self.window.set_titlebar_transparent(transparent);
}

#[inline]
fn set_badge_label(&self, label: Option<String>) {
self.window.set_badge_label(label);
}
}

/// Corresponds to `NSApplicationActivationPolicy`.
Expand Down Expand Up @@ -388,6 +396,9 @@ pub trait EventLoopWindowTargetExtMacOS {
/// To set the activation policy before the app starts running, see
/// [`EventLoopExtMacOS::set_activation_policy`](crate::platform::macos::EventLoopExtMacOS::set_activation_policy).
fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy);

/// Sets the badge label on macos dock
fn set_badge_label(&self, label: Option<String>);
}

impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
Expand Down Expand Up @@ -415,4 +426,8 @@ impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
let ns_activation_policy: NSApplicationActivationPolicy = activation_policy.into();
unsafe { msg_send![app, setActivationPolicy: ns_activation_policy] }
}

fn set_badge_label(&self, label: Option<String>) {
set_badge_label(label);
}
}
14 changes: 14 additions & 0 deletions src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ pub trait WindowExtUnix {

/// Whether to show the window icon in the taskbar or not.
fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError>;

fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>);
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
}

impl WindowExtUnix for Window {
Expand All @@ -100,6 +102,10 @@ impl WindowExtUnix for Window {
let window = UnixWindow::new_from_gtk_window(&event_loop_window_target.p, window)?;
Ok(Window { window: window })
}

fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) {
self.window.set_badge_count(count, desktop_filename);
}
}

pub trait WindowBuilderExtUnix {
Expand Down Expand Up @@ -208,6 +214,9 @@ pub trait EventLoopWindowTargetExtUnix {

/// Returns the gtk application for this event loop.
fn gtk_app(&self) -> &gtk::Application;

/// Sets the badge count on the taskbar
fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>);
}

impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
Expand Down Expand Up @@ -249,6 +258,11 @@ impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
fn gtk_app(&self) -> &gtk::Application {
&self.p.app
}

#[inline]
fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) {
self.p.set_badge_count(count, desktop_filename);
}
}

unsafe extern "C" fn x_error_callback(
Expand Down
8 changes: 8 additions & 0 deletions src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ pub trait WindowExtWindows {
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);

/// This sets the overlay icon
fn set_overlay_icon(&self, icon: Option<Icon>);

/// Returns the current window theme.
fn theme(&self) -> Theme;

Expand Down Expand Up @@ -238,6 +241,11 @@ impl WindowExtWindows for Window {
fn set_rtl(&self, rtl: bool) {
self.window.set_rtl(rtl)
}

#[inline]
fn set_overlay_icon(&self, icon: Option<Icon>) {
self.window.set_overlay_icon(icon);
}
}

/// Additional methods on `WindowBuilder` that are specific to Windows.
Expand Down
10 changes: 10 additions & 0 deletions src/platform_impl/ios/badge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};

pub fn set_badge_count(count: i32) {
unsafe {
let ui_application = Class::get("UIApplication").expect("Failed to get UIApplication class");
let app: *mut Object = msg_send![ui_application, sharedApplication];
let _: () = msg_send![app, setApplicationIconBadgeNumber:count];
}
}
6 changes: 6 additions & 0 deletions src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
};

use crate::platform_impl::platform::{
set_badge_count,
app_state,
ffi::{
id, kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes,
Expand Down Expand Up @@ -94,6 +95,11 @@ impl<T: 'static> EventLoopWindowTarget<T> {
debug!("`EventLoopWindowTarget::cursor_position` is ignored on iOS");
Ok((0, 0).into())
}

/// Sets badge count on iOS launcher. 0 hides the count
pub fn set_badge_count(&self, count: i32) {
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
set_badge_count(count);
}
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down
3 changes: 2 additions & 1 deletion src/platform_impl/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ mod keycode;
mod monitor;
mod view;
mod window;
mod badge;

use std::fmt;

Expand All @@ -90,7 +91,7 @@ pub use self::{
monitor::{MonitorHandle, VideoMode},
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
};

pub(crate) use badge::set_badge_count;
pub(crate) use crate::icon::NoIcon as PlatformIcon;

// todo: implement iOS keyboard event
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
monitor::MonitorHandle as RootMonitorHandle,
platform::ios::{MonitorHandleExtIOS, ScreenEdge, ValidOrientations},
platform_impl::platform::{
set_badge_count,
app_state,
event_loop::{self, EventProxy, EventWrapper},
ffi::{
Expand Down Expand Up @@ -440,6 +441,11 @@ impl Inner {
pub fn theme(&self) -> Theme {
Theme::Light
}

/// Sets badge count on iOS launcher. 0 hides the count
pub fn set_badge_count(&self, count: i32) {
set_badge_count(count);
}
}

pub struct Window {
Expand Down
14 changes: 14 additions & 0 deletions src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ impl<T> EventLoopWindowTarget<T> {
}
}

#[inline]
pub fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) {
if let Err(e) = self
.window_requests_tx
.send((WindowId::dummy(), WindowRequest::BadgeCount(count, desktop_filename)))
{
log::warn!("Fail to send update progress bar request: {e}");
}
}

#[inline]
pub fn set_theme(&self, theme: Option<Theme>) {
if let Err(e) = self
Expand Down Expand Up @@ -432,6 +442,7 @@ impl<T: 'static> EventLoop<T> {
};
}
WindowRequest::ProgressBarState(_) => unreachable!(),
WindowRequest::BadgeCount(_, _) => unreachable!(),
WindowRequest::SetTheme(_) => unreachable!(),
WindowRequest::WireUpEvents {
transparent,
Expand Down Expand Up @@ -921,6 +932,9 @@ impl<T: 'static> EventLoop<T> {
WindowRequest::ProgressBarState(state) => {
taskbar.update(state);
}
WindowRequest::BadgeCount(count, desktop_filename) => {
taskbar.update_count(count, desktop_filename);
}
WindowRequest::SetTheme(theme) => {
if let Some(settings) = Settings::default() {
match theme {
Expand Down
38 changes: 38 additions & 0 deletions src/platform_impl/linux/taskbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ struct UnityLib {
unity_launcher_entry_set_progress: unsafe extern "C" fn(entry: *const isize, value: f64) -> i32,
unity_launcher_entry_set_progress_visible:
unsafe extern "C" fn(entry: *const isize, value: i32) -> i32,
unity_launcher_entry_set_count: unsafe extern "C" fn(entry: *const isize, value: i64) -> i32,
unity_launcher_entry_set_count_visible:
unsafe extern "C" fn(entry: *const isize, value: bool) -> bool,
}

pub struct TaskbarIndicator {
Expand Down Expand Up @@ -120,4 +123,39 @@ impl TaskbarIndicator {
}
}
}

pub fn update_count(&mut self, count: Option<i64>, desktop_filename: Option<String>) {
if let Some(uri) = desktop_filename {
self.desktop_filename = Some(uri);
}

self.ensure_lib_load();

if !self.is_unity_running() {
return;
}

if let Some(uri) = &self.desktop_filename {
self.desktop_filename_c_str = Some(CString::new(uri.as_str()).unwrap_or_default());
}

if self.unity_entry.is_none() {
self.ensure_entry_load();
}

if let Some(unity_lib) = &self.unity_lib {
if let Some(unity_entry) = &self.unity_entry {
// Sets count
if let Some(count) = count {
unsafe { (unity_lib.unity_launcher_entry_set_count)(*unity_entry, count) };
unsafe { (unity_lib.unity_launcher_entry_set_count_visible)(*unity_entry, true) };
}
// removes the count
else {
unsafe { (unity_lib.unity_launcher_entry_set_count)(*unity_entry, 0) };
unsafe { (unity_lib.unity_launcher_entry_set_count_visible)(*unity_entry, false) };
}
}
}
}
}
10 changes: 10 additions & 0 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,15 @@ impl Window {
}
}

pub fn set_badge_count(&self, count: Option<i64>, desktop_filename: Option<String>) {
if let Err(e) = self
.window_requests_tx
.send((WindowId::dummy(), WindowRequest::BadgeCount(count, desktop_filename)))
{
log::warn!("Fail to send update badge count request: {}", e);
}
}

pub fn theme(&self) -> Theme {
if let Some(theme) = *self.preferred_theme.borrow() {
return theme;
Expand Down Expand Up @@ -1068,6 +1077,7 @@ pub enum WindowRequest {
},
SetVisibleOnAllWorkspaces(bool),
ProgressBarState(ProgressBarState),
BadgeCount(Option<i64>, Option<String>),
SetTheme(Option<Theme>),
BackgroundColor(CssProvider, Option<RGBA>),
}
Expand Down
12 changes: 12 additions & 0 deletions src/platform_impl/macos/badge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use cocoa::{appkit::NSApp, base::nil, foundation::NSString};

pub fn set_badge_label(label: Option<String>) {
unsafe {
let label = match label {
None => nil,
Some(label) => NSString::alloc(nil).init_str(&label)
};
let dock_tile: cocoa::base::id = msg_send![NSApp(), dockTile];
let _: cocoa::base::id = msg_send![dock_tile, setBadgeLabel: label];
}
}
Loading
Loading