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 10 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 and Macos; **set_overlay_icon** for Windows
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)]
if modifiers.is_empty() {
let mut path = current_dir().unwrap();
path.push("./examples/icon.ico");

window.set_overlay_icon(Some(path.to_str().unwrap().to_string()));
} else if modifiers.control_key() && key_str == "1" {
window.set_overlay_icon(None);
}
}
_ => {}
},
_ => {}
}
});
}
13 changes: 13 additions & 0 deletions src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,19 @@ impl<T> EventLoopWindowTarget<T> {
self.p.set_progress_bar(_progress)
}

/// Sets the badge count
///
/// ## Platform-specific
///
/// - **Windows:** Unsupported. Use the Progress Bar Function Available in Window (Windows can have different taskbar badges for different Window)
/// - **Linux:** Only supported desktop environments with `libunity` (e.g. GNOME).
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
/// - **iOS / Android:** Unsupported.
#[inline]
pub fn set_badge_count(&self, _badge: Option<i64>, _desktop_filename: Option<String>) {
#[cfg(any(target_os = "linux", target_os = "macos"))]
self.p.set_bage_count(_progress, _desktop_filename)
}

/// Sets the theme for the application.
///
/// ## Platform-specific
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/android/ndk_glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ macro_rules! android_binding {
};
($domain:ident, $package:ident, $activity:ident, $setup:path, $main:ident, $tao:path) => {{
// NOTE: be careful when changing how this use statement is written
use $tao::{platform::android::prelude::android_fn, platform::android::prelude::*};
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
use $tao::platform::android::prelude::{android_fn, *};
fn _____tao_store_package_name__() {
PACKAGE.get_or_init(move || generate_package_name!($domain, $package));
}
Expand Down
13 changes: 13 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 @@ -921,6 +931,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(&self, 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];
}
}
11 changes: 11 additions & 0 deletions src/platform_impl/macos/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::{
util::{self, IdRef},
},
set_progress_indicator,
set_badge_label
},
window::{ProgressBarState, Theme},
};
Expand Down Expand Up @@ -125,6 +126,16 @@ impl<T: 'static> EventLoopWindowTarget<T> {
set_progress_indicator(progress);
}

#[inline]
pub fn set_badge_count(&self, count: Option<i64>, _desktop_filename: Option<String>) {
set_badge_label(count.and_then(|count| Some(format!("{}", count))));
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
}

#[inline]
pub fn set_badge_label(&self, label: Option<String>) {
set_badge_label(label);
}
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved

#[inline]
pub fn set_theme(&self, theme: Option<Theme>) {
set_ns_theme(theme)
Expand Down
1 change: 1 addition & 0 deletions src/platform_impl/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod keycode;
mod monitor;
mod observer;
mod progress_bar;
mod badge;
mod util;
mod view;
mod window;
Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::{
OsError,
},
set_progress_indicator,
set_badge_label
},
window::{
CursorIcon, Fullscreen, ProgressBarState, ResizeDirection, Theme, UserAttentionType,
Expand Down Expand Up @@ -1498,6 +1499,14 @@ impl UnownedWindow {
pub fn set_progress_bar(&self, progress: ProgressBarState) {
set_progress_indicator(progress);
}

pub fn set_badge_count(&self, count: Option<i64>, _desktop_filename: Option<String>) {
set_badge_label(count.and_then(|count| Some(format!("{}", count))));
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn set_badge_label(&self, label: Option<String>) {
set_badge_label(label);
}
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
}

impl WindowExtMacOS for UnownedWindow {
Expand Down
38 changes: 38 additions & 0 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::{
os::windows::ffi::OsStrExt,
sync::Arc,
};
use windows_core::HSTRING;

use crossbeam_channel as channel;
use windows::{
Expand Down Expand Up @@ -1023,6 +1024,43 @@ impl Window {
}
}

#[inline]
pub fn set_overlay_icon(&self, icon: Option<String>) {
let Some(icon) = icon else {
unsafe {
let taskbar_list: ITaskbarList =
CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER).unwrap();
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved

taskbar_list
.SetOverlayIcon(self.window.0, None, None)
.unwrap();
}
return;
};

let image = unsafe {
LoadImageW(
None,
PCWSTR(HSTRING::from(icon).as_ptr()),
IMAGE_ICON,
0,
0,
IMAGE_FLAGS(0x00000040 | 0x00000010),
)
}
.unwrap();

let icon = HICON(image.0);

unsafe {
let taskbar_list: ITaskbarList = CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER).unwrap();

taskbar_list
.SetOverlayIcon(self.window.0, icon, None)
.unwrap();
}
}

#[inline]
pub fn set_undecorated_shadow(&self, shadow: bool) {
let window = self.window.clone();
Expand Down
39 changes: 38 additions & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ impl Window {
///
/// ## Platform-specific
///
/// - **Linux / macOS**: Progress bar is app-wide and not specific to this window. Only supported desktop environments with `libunity` (e.g. GNOME).
/// - **Linux / macOS**: Unlike windows, progress bar is app-wide and not specific to this window. Only supported desktop environments with `libunity` (e.g. GNOME).
/// - **iOS / Android:** Unsupported.
#[inline]
pub fn set_progress_bar(&self, _progress: ProgressBarState) {
Expand All @@ -1115,6 +1115,43 @@ impl Window {
self.window.set_progress_bar(_progress)
}

/// Sets the badge count on the taskbar
///
/// ## Implementation Details
/// - _desktop_filename is for linux ONLY!
///
/// ## Platform-specific
///
/// - **Windows**: Windows allows to set an arbitrary .ico file. See set_overlay_icon
/// - **Linux / macOS**: Badge count is app-wide and not specific to this window. Only supported desktop environments with `libunity` (e.g. GNOME).
/// - **iOS / Android:** Unsupported.
#[inline]
pub fn set_badge_count(&self, _count: Option<i64>, _desktop_filename: Option<String>) {
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_os = "macos")]
self.window.set_badge_count(_count);

#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
self.window.set_badge_count(_count, _desktop_filename);
}

/// Sets the Overlay Icon **(Windows only)**
///
/// ## Platform-specific
///
/// - **Linux / macOS**: See set_taskbar_badge
/// - **iOS / Android:** Unsupported.
#[inline]
pub fn set_overlay_icon(&self, _icon_path: Option<String>) {
ahqsoftwares marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(windows)]
self.window.set_overlay_icon(_icon_path)
}

/// Requests user attention to the window, this has no effect if the application
/// is already focused. How requesting for user attention manifests is platform dependent,
/// see `UserAttentionType` for details.
Expand Down
Loading