debug: Display log in the background
This commit is contained in:
parent
9aa1d3ebc9
commit
62379bc74c
9 changed files with 498 additions and 69 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
|
@ -302,6 +302,8 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"edid-rs",
|
"edid-rs",
|
||||||
"egui",
|
"egui",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-async",
|
"slog-async",
|
||||||
"slog-scope",
|
"slog-scope",
|
||||||
|
|
@ -654,6 +656,12 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
@ -1123,6 +1131,12 @@ version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scan_fmt"
|
name = "scan_fmt"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
|
|
@ -1147,6 +1161,17 @@ version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slog"
|
name = "slog"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ slog-term = "2.8"
|
||||||
slog-async = "2.7"
|
slog-async = "2.7"
|
||||||
slog-scope = "4.4"
|
slog-scope = "4.4"
|
||||||
slog-stdlog = "4.1"
|
slog-stdlog = "4.1"
|
||||||
|
serde = { version = "1", optional = true }
|
||||||
|
serde_json = { version = "1", optional = true }
|
||||||
egui = { version = "0.16", optional = true }
|
egui = { version = "0.16", optional = true }
|
||||||
edid-rs = { version = "0.1" }
|
edid-rs = { version = "0.1" }
|
||||||
thiserror = "1.0.26"
|
thiserror = "1.0.26"
|
||||||
|
|
@ -32,4 +34,4 @@ optional = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
debug = ["egui", "smithay-egui"]
|
debug = ["egui", "smithay-egui", "serde", "serde_json"]
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::state::Common;
|
use crate::state::Common;
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::{debug_ui, fps_ui},
|
debug::{debug_ui, fps_ui, log_ui},
|
||||||
state::Fps,
|
state::Fps,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -44,7 +44,9 @@ pub fn render_output(
|
||||||
|
|
||||||
let mut area = state.spaces.global_space();
|
let mut area = state.spaces.global_space();
|
||||||
area.loc = state.spaces.space_relative_output_geometry((0, 0), output);
|
area.loc = state.spaces.space_relative_output_geometry((0, 0), output);
|
||||||
//let output_geo = state.spaces.output_geometry(output);
|
if let Some(log_ui) = log_ui(state, area, scale, output_geo.size.w as f32 * 0.6) {
|
||||||
|
custom_elements.push(Box::new(log_ui));
|
||||||
|
}
|
||||||
if let Some(debug_overlay) = debug_ui(state, area, scale) {
|
if let Some(debug_overlay) = debug_ui(state, area, scale) {
|
||||||
custom_elements.push(Box::new(debug_overlay));
|
custom_elements.push(Box::new(debug_overlay));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
93
src/debug.rs
93
src/debug.rs
|
|
@ -96,7 +96,7 @@ pub fn debug_ui(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(state.egui.state.run(
|
Some(state.egui.debug_state.run(
|
||||||
|ctx| {
|
|ctx| {
|
||||||
egui::Window::new("Workspaces")
|
egui::Window::new("Workspaces")
|
||||||
.default_pos([0.0, 300.0])
|
.default_pos([0.0, 300.0])
|
||||||
|
|
@ -206,3 +206,94 @@ pub fn debug_ui(
|
||||||
state.egui.modifiers.clone(),
|
state.egui.modifiers.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn log_ui(
|
||||||
|
state: &mut Common,
|
||||||
|
area: Rectangle<i32, Logical>,
|
||||||
|
scale: f64,
|
||||||
|
default_width: f32,
|
||||||
|
) -> Option<EguiFrame> {
|
||||||
|
if !state.egui.active {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(state.egui.log_state.run(
|
||||||
|
|ctx| {
|
||||||
|
egui::SidePanel::right("Log")
|
||||||
|
.default_width(default_width)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
|
for (i, record) in state.log.debug_buffer.lock().unwrap().iter().enumerate() {
|
||||||
|
let mut message = egui::text::LayoutJob::single_section(
|
||||||
|
record.level.as_short_str().to_string(),
|
||||||
|
egui::TextFormat::simple(egui::TextStyle::Monospace, match record.level {
|
||||||
|
slog::Level::Critical => egui::Color32::RED,
|
||||||
|
slog::Level::Error => egui::Color32::LIGHT_RED,
|
||||||
|
slog::Level::Warning => egui::Color32::LIGHT_YELLOW,
|
||||||
|
slog::Level::Info => egui::Color32::LIGHT_BLUE,
|
||||||
|
slog::Level::Debug => egui::Color32::LIGHT_GREEN,
|
||||||
|
slog::Level::Trace => egui::Color32::GRAY,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
message.append(&record.message, 1.0, egui::TextFormat::simple(
|
||||||
|
egui::TextStyle::Body, egui::Color32::WHITE,
|
||||||
|
));
|
||||||
|
egui::containers::CollapsingHeader::new(message)
|
||||||
|
.id_source(i)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for (k, v) in &record.kv {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add(egui::Label::new(egui::RichText::new(k).code())
|
||||||
|
.sense(egui::Sense::click()))
|
||||||
|
.on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||||
|
render_value(ui, v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
area,
|
||||||
|
scale,
|
||||||
|
state.egui.alpha,
|
||||||
|
&state.start_time,
|
||||||
|
state.egui.modifiers.clone(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_value(ui: &mut egui::Ui, value: &serde_json::Value) {
|
||||||
|
use serde_json::Value::*;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Null => { ui.label(egui::RichText::new("null").code()); },
|
||||||
|
Bool(val) => { ui.label(egui::RichText::new(format!("{}", val)).code()); },
|
||||||
|
Number(val) => { ui.label(egui::RichText::new(format!("{}", val)).code()); },
|
||||||
|
String(val) => { ui.label(val); },
|
||||||
|
Array(list) => {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.label("[");
|
||||||
|
for val in list {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add_space(4.0);
|
||||||
|
render_value(ui, val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ui.label("]");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Object(map) => {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
for (k, val) in map {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.add_space(4.0);
|
||||||
|
ui.add(egui::Label::new(egui::RichText::new(k).code()));
|
||||||
|
render_value(ui, val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
104
src/input/mod.rs
104
src/input/mod.rs
|
|
@ -159,7 +159,8 @@ impl Common {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
self.egui.state.handle_device_added(&device);
|
self.egui.debug_state.handle_device_added(&device);
|
||||||
|
self.egui.log_state.handle_device_added(&device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::DeviceRemoved { device } => {
|
InputEvent::DeviceRemoved { device } => {
|
||||||
|
|
@ -183,7 +184,8 @@ impl Common {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
self.egui.state.handle_device_added(&device);
|
self.egui.debug_state.handle_device_added(&device);
|
||||||
|
self.egui.log_state.handle_device_added(&device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::Keyboard { event, .. } => {
|
InputEvent::Keyboard { event, .. } => {
|
||||||
|
|
@ -225,14 +227,23 @@ impl Common {
|
||||||
}
|
}
|
||||||
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
||||||
&& self.egui.active
|
&& self.egui.active
|
||||||
&& self.egui.state.wants_keyboard()
|
|
||||||
{
|
{
|
||||||
self.egui.state.handle_keyboard(
|
if self.egui.debug_state.wants_keyboard() {
|
||||||
&handle,
|
self.egui.debug_state.handle_keyboard(
|
||||||
state == KeyState::Pressed,
|
&handle,
|
||||||
modifiers.clone(),
|
state == KeyState::Pressed,
|
||||||
);
|
modifiers.clone(),
|
||||||
return FilterResult::Intercept(());
|
);
|
||||||
|
return FilterResult::Intercept(());
|
||||||
|
}
|
||||||
|
if self.egui.log_state.wants_keyboard() {
|
||||||
|
self.egui.log_state.handle_keyboard(
|
||||||
|
&handle,
|
||||||
|
state == KeyState::Pressed,
|
||||||
|
modifiers.clone(),
|
||||||
|
);
|
||||||
|
return FilterResult::Intercept(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,7 +302,10 @@ impl Common {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.seats.iter().position(|x| x == seat).unwrap() == 0 {
|
if self.seats.iter().position(|x| x == seat).unwrap() == 0 {
|
||||||
self.egui
|
self.egui
|
||||||
.state
|
.debug_state
|
||||||
|
.handle_pointer_motion(position.to_i32_round());
|
||||||
|
self.egui
|
||||||
|
.log_state
|
||||||
.handle_pointer_motion(position.to_i32_round());
|
.handle_pointer_motion(position.to_i32_round());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -321,7 +335,10 @@ impl Common {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.seats.iter().position(|x| x == seat).unwrap() == 0 {
|
if self.seats.iter().position(|x| x == seat).unwrap() == 0 {
|
||||||
self.egui
|
self.egui
|
||||||
.state
|
.debug_state
|
||||||
|
.handle_pointer_motion(position.to_i32_round());
|
||||||
|
self.egui
|
||||||
|
.log_state
|
||||||
.handle_pointer_motion(position.to_i32_round());
|
.handle_pointer_motion(position.to_i32_round());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -342,16 +359,27 @@ impl Common {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
||||||
&& self.egui.active
|
&& self.egui.active
|
||||||
&& self.egui.state.wants_pointer()
|
|
||||||
{
|
{
|
||||||
if let Some(button) = event.button() {
|
if self.egui.debug_state.wants_pointer() {
|
||||||
self.egui.state.handle_pointer_button(
|
if let Some(button) = event.button() {
|
||||||
button,
|
self.egui.debug_state.handle_pointer_button(
|
||||||
event.state() == ButtonState::Pressed,
|
button,
|
||||||
self.egui.modifiers.clone(),
|
event.state() == ButtonState::Pressed,
|
||||||
);
|
self.egui.modifiers.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if self.egui.log_state.wants_pointer() {
|
||||||
|
if let Some(button) = event.button() {
|
||||||
|
self.egui.log_state.handle_pointer_button(
|
||||||
|
button,
|
||||||
|
event.state() == ButtonState::Pressed,
|
||||||
|
self.egui.modifiers.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
|
@ -436,19 +464,33 @@ impl Common {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
if self.seats.iter().position(|x| x == seat).unwrap() == 0
|
||||||
&& self.egui.active
|
&& self.egui.active
|
||||||
&& self.egui.state.wants_pointer()
|
|
||||||
{
|
{
|
||||||
self.egui.state.handle_pointer_axis(
|
if self.egui.debug_state.wants_pointer() {
|
||||||
event
|
self.egui.debug_state.handle_pointer_axis(
|
||||||
.amount_discrete(Axis::Horizontal)
|
event
|
||||||
.or_else(|| event.amount(Axis::Horizontal).map(|x| x * 3.0))
|
.amount_discrete(Axis::Horizontal)
|
||||||
.unwrap_or(0.0),
|
.or_else(|| event.amount(Axis::Horizontal).map(|x| x * 3.0))
|
||||||
event
|
.unwrap_or(0.0),
|
||||||
.amount_discrete(Axis::Vertical)
|
event
|
||||||
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
|
.amount_discrete(Axis::Vertical)
|
||||||
.unwrap_or(0.0),
|
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
|
||||||
);
|
.unwrap_or(0.0),
|
||||||
break;
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if self.egui.log_state.wants_pointer() {
|
||||||
|
self.egui.log_state.handle_pointer_axis(
|
||||||
|
event
|
||||||
|
.amount_discrete(Axis::Horizontal)
|
||||||
|
.or_else(|| event.amount(Axis::Horizontal).map(|x| x * 3.0))
|
||||||
|
.unwrap_or(0.0),
|
||||||
|
event
|
||||||
|
.amount_discrete(Axis::Vertical)
|
||||||
|
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
|
||||||
|
.unwrap_or(0.0),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let userdata = seat.user_data();
|
let userdata = seat.user_data();
|
||||||
|
|
|
||||||
145
src/logger/mod.rs
Normal file
145
src/logger/mod.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
sync::{Arc, Mutex, atomic::{AtomicBool, Ordering}},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use slog::Drain;
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
mod serializer;
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
const MAX_RECORDS: usize = 1000;
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub type LogBuffer = Arc<Mutex<VecDeque<OwnedRecord>>>;
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct DebugDrain {
|
||||||
|
buffer: LogBuffer,
|
||||||
|
dirty_flag:Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LogState {
|
||||||
|
_guard: slog_scope::GlobalLoggerGuard,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub dirty_flag:Arc<AtomicBool>,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub debug_buffer: LogBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
pub struct OwnedRecord {
|
||||||
|
pub message: String,
|
||||||
|
pub level: slog::Level,
|
||||||
|
pub kv: serde_json::map::Map<String, serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
impl DebugDrain {
|
||||||
|
fn new() -> (DebugDrain, LogBuffer, Arc<AtomicBool>) {
|
||||||
|
let dirty_flag = Arc::new(AtomicBool::new(false));
|
||||||
|
let buffer = Arc::new(Mutex::new(VecDeque::new()));
|
||||||
|
(
|
||||||
|
DebugDrain {
|
||||||
|
buffer: buffer.clone(),
|
||||||
|
dirty_flag: dirty_flag.clone()
|
||||||
|
},
|
||||||
|
buffer,
|
||||||
|
dirty_flag,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
impl Drain for DebugDrain {
|
||||||
|
type Ok = ();
|
||||||
|
type Err = slog::Error;
|
||||||
|
|
||||||
|
fn log(
|
||||||
|
&self,
|
||||||
|
record: &slog::Record<'_>,
|
||||||
|
values: &slog::OwnedKVList
|
||||||
|
) -> Result<Self::Ok, Self::Err> {
|
||||||
|
use slog::KV;
|
||||||
|
use serializer::SerdeSerializer;
|
||||||
|
use serde_json::value::{
|
||||||
|
Serializer as ValueSerializer,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut serializer = SerdeSerializer::start(ValueSerializer, None)?;
|
||||||
|
values.serialize(record, &mut serializer)?;
|
||||||
|
record.kv().serialize(record, &mut serializer)?;
|
||||||
|
let value = match serializer.end().map_err(|_| slog::Error::Other)? {
|
||||||
|
Value::Object(map) => map,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buffer = self.buffer.lock().unwrap();
|
||||||
|
buffer.push_front(OwnedRecord {
|
||||||
|
message: format!("{}", record.msg()),
|
||||||
|
level: record.level(),
|
||||||
|
kv: value,
|
||||||
|
});
|
||||||
|
buffer.truncate(MAX_RECORDS);
|
||||||
|
self.dirty_flag.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_logger() -> Result<LogState> {
|
||||||
|
let decorator = slog_term::TermDecorator::new().stderr().build();
|
||||||
|
// usually we would not want to use a Mutex here, but this is usefull for a prototype,
|
||||||
|
// to make sure we do not miss any in-flight messages, when we crash.
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
|
let logger = slog::Logger::root(
|
||||||
|
std::sync::Mutex::new(
|
||||||
|
slog_term::CompactFormat::new(decorator)
|
||||||
|
.build()
|
||||||
|
.ignore_res(),
|
||||||
|
)
|
||||||
|
.fuse(),
|
||||||
|
slog::o!(),
|
||||||
|
);
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
let (debug_drain, debug_buffer, dirty_flag) = DebugDrain::new();
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
let logger = slog::Logger::root(
|
||||||
|
slog::Duplicate::new(
|
||||||
|
std::sync::Mutex::new(
|
||||||
|
slog_term::CompactFormat::new(decorator)
|
||||||
|
.build()
|
||||||
|
.ignore_res()
|
||||||
|
),
|
||||||
|
debug_drain,
|
||||||
|
)
|
||||||
|
.fuse(),
|
||||||
|
slog::o!(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _guard = slog_scope::set_global_logger(logger);
|
||||||
|
slog_stdlog::init().unwrap();
|
||||||
|
|
||||||
|
slog_scope::info!("Version: {}", std::env!("CARGO_PKG_VERSION"));
|
||||||
|
if cfg!(feature = "debug") {
|
||||||
|
slog_scope::debug!(
|
||||||
|
"Debug build ({})",
|
||||||
|
std::option_env!("GIT_HASH").unwrap_or("Unknown")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LogState {
|
||||||
|
_guard,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
debug_buffer,
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
dirty_flag,
|
||||||
|
})
|
||||||
|
}
|
||||||
135
src/logger/serializer.rs
Normal file
135
src/logger/serializer.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT OR Apache-2.0
|
||||||
|
// Taken from slog_json:
|
||||||
|
// https://github.com/slog-rs/json/blob/c45d09422d7114222ee5b7f6b0123de2605c7864/src/lib.rs#L39-L160
|
||||||
|
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
use serde::serde_if_integer128;
|
||||||
|
use slog::Key;
|
||||||
|
use std::{fmt, io, result};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static TL_BUF: RefCell<String> = RefCell::new(String::with_capacity(128))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `slog::Serializer` adapter for `serde::Serializer`
|
||||||
|
///
|
||||||
|
/// Newtype to wrap serde Serializer, so that `Serialize` can be implemented
|
||||||
|
/// for it
|
||||||
|
pub struct SerdeSerializer<S: serde::Serializer> {
|
||||||
|
/// Current state of map serializing: `serde::Serializer::MapState`
|
||||||
|
ser_map: S::SerializeMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: serde::Serializer> SerdeSerializer<S> {
|
||||||
|
/// Start serializing map of values
|
||||||
|
pub fn start(ser: S, len: Option<usize>) -> result::Result<Self, slog::Error> {
|
||||||
|
let ser_map = ser.serialize_map(len).map_err(|e| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("serde serialization error: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(SerdeSerializer { ser_map })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finish serialization, and return the serializer
|
||||||
|
pub fn end(self) -> result::Result<S::Ok, S::Error> {
|
||||||
|
self.ser_map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_m(
|
||||||
|
($s:expr, $key:expr, $val:expr) => ({
|
||||||
|
let k_s: &str = $key.as_ref();
|
||||||
|
$s.ser_map.serialize_entry(k_s, $val)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("serde serialization error: {}", e)))?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<S> slog::Serializer for SerdeSerializer<S>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
fn emit_bool(&mut self, key: Key, val: bool) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_unit(&mut self, key: Key) -> slog::Result {
|
||||||
|
impl_m!(self, key, &())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_char(&mut self, key: Key, val: char) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_none(&mut self, key: Key) -> slog::Result {
|
||||||
|
let val: Option<()> = None;
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_u8(&mut self, key: Key, val: u8) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_i8(&mut self, key: Key, val: i8) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_u16(&mut self, key: Key, val: u16) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_i16(&mut self, key: Key, val: i16) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_usize(&mut self, key: Key, val: usize) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_isize(&mut self, key: Key, val: isize) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_u32(&mut self, key: Key, val: u32) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_i32(&mut self, key: Key, val: i32) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_f32(&mut self, key: Key, val: f32) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_u64(&mut self, key: Key, val: u64) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_i64(&mut self, key: Key, val: i64) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_f64(&mut self, key: Key, val: f64) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
serde_if_integer128! {
|
||||||
|
fn emit_u128(&mut self, key: Key, val: u128) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_i128(&mut self, key: Key, val: i128) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn emit_str(&mut self, key: Key, val: &str) -> slog::Result {
|
||||||
|
impl_m!(self, key, &val)
|
||||||
|
}
|
||||||
|
fn emit_arguments(
|
||||||
|
&mut self,
|
||||||
|
key: Key,
|
||||||
|
val: &fmt::Arguments,
|
||||||
|
) -> slog::Result {
|
||||||
|
TL_BUF.with(|buf| {
|
||||||
|
let mut buf = buf.borrow_mut();
|
||||||
|
|
||||||
|
buf.write_fmt(*val).unwrap();
|
||||||
|
|
||||||
|
let res = { || impl_m!(self, key, &*buf) }();
|
||||||
|
buf.clear();
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main.rs
33
src/main.rs
|
|
@ -6,13 +6,13 @@ use smithay::reexports::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use slog::Drain;
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod shell;
|
pub mod shell;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
mod logger;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
|
@ -20,7 +20,7 @@ pub mod debug;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// setup logger
|
// setup logger
|
||||||
let _guard = init_logger();
|
let log = logger::init_logger()?;
|
||||||
slog_scope::info!("Cosmic starting up!");
|
slog_scope::info!("Cosmic starting up!");
|
||||||
|
|
||||||
// init event loop
|
// init event loop
|
||||||
|
|
@ -28,7 +28,7 @@ fn main() -> Result<()> {
|
||||||
// init wayland
|
// init wayland
|
||||||
let display = init_wayland_display(&mut event_loop)?;
|
let display = init_wayland_display(&mut event_loop)?;
|
||||||
// init state
|
// init state
|
||||||
let mut state = state::State::new(display, event_loop.handle());
|
let mut state = state::State::new(display, event_loop.handle(), log);
|
||||||
// init backend
|
// init backend
|
||||||
backend::init_backend_auto(&mut event_loop, &mut state)?;
|
backend::init_backend_auto(&mut event_loop, &mut state)?;
|
||||||
|
|
||||||
|
|
@ -60,33 +60,6 @@ fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_logger() -> Result<slog_scope::GlobalLoggerGuard> {
|
|
||||||
let decorator = slog_term::TermDecorator::new().stderr().build();
|
|
||||||
// usually we would not want to use a Mutex here, but this is usefull for a prototype,
|
|
||||||
// to make sure we do not miss any in-flight messages, when we crash.
|
|
||||||
let logger = slog::Logger::root(
|
|
||||||
std::sync::Mutex::new(
|
|
||||||
slog_term::CompactFormat::new(decorator)
|
|
||||||
.build()
|
|
||||||
.ignore_res(),
|
|
||||||
)
|
|
||||||
.fuse(),
|
|
||||||
slog::o!(),
|
|
||||||
);
|
|
||||||
let guard = slog_scope::set_global_logger(logger);
|
|
||||||
slog_stdlog::init().unwrap();
|
|
||||||
|
|
||||||
slog_scope::info!("Version: {}", std::env!("CARGO_PKG_VERSION"));
|
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
slog_scope::debug!(
|
|
||||||
"Debug build ({})",
|
|
||||||
std::option_env!("GIT_HASH").unwrap_or("Unknown")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(guard)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_wayland_display(event_loop: &mut EventLoop<state::State>) -> Result<Display> {
|
fn init_wayland_display(event_loop: &mut EventLoop<state::State>) -> Result<Display> {
|
||||||
let mut display = Display::new();
|
let mut display = Display::new();
|
||||||
let socket_name = display.add_socket_auto()?;
|
let socket_name = display.add_socket_auto()?;
|
||||||
|
|
|
||||||
22
src/state.rs
22
src/state.rs
|
|
@ -3,6 +3,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
||||||
shell::{init_shell, workspaces::Workspaces, ShellStates},
|
shell::{init_shell, workspaces::Workspaces, ShellStates},
|
||||||
|
logger::LogState,
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::{
|
reexports::{
|
||||||
|
|
@ -47,13 +48,15 @@ pub struct Common {
|
||||||
pub start_time: Instant,
|
pub start_time: Instant,
|
||||||
pub should_stop: bool,
|
pub should_stop: bool,
|
||||||
|
|
||||||
|
pub log: LogState,
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
pub egui: Egui,
|
pub egui: Egui,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
pub struct Egui {
|
pub struct Egui {
|
||||||
pub state: smithay_egui::EguiState,
|
pub debug_state: smithay_egui::EguiState,
|
||||||
|
pub log_state: smithay_egui::EguiState,
|
||||||
pub modifiers: smithay::wayland::seat::ModifiersState,
|
pub modifiers: smithay::wayland::seat::ModifiersState,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
pub alpha: f32,
|
pub alpha: f32,
|
||||||
|
|
@ -122,7 +125,7 @@ pub fn get_dnd_icon(seat: &Seat) -> Option<WlSurface> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(mut display: Display, handle: LoopHandle<'static, State>) -> State {
|
pub fn new(mut display: Display, handle: LoopHandle<'static, State>, log: LogState) -> State {
|
||||||
init_shm_global(&mut display, vec![], None);
|
init_shm_global(&mut display, vec![], None);
|
||||||
init_xdg_output_manager(&mut display, None);
|
init_xdg_output_manager(&mut display, None);
|
||||||
let shell_handles = init_shell(&mut display);
|
let shell_handles = init_shell(&mut display);
|
||||||
|
|
@ -151,6 +154,11 @@ impl State {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "debug"))]
|
||||||
|
let dirty_flag = Arc::new(AtomicBool::new(false));
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
let dirty_flag = log.dirty_flag.clone();
|
||||||
|
|
||||||
State {
|
State {
|
||||||
common: Common {
|
common: Common {
|
||||||
display: Rc::new(RefCell::new(display)),
|
display: Rc::new(RefCell::new(display)),
|
||||||
|
|
@ -159,7 +167,7 @@ impl State {
|
||||||
spaces: Workspaces::new(),
|
spaces: Workspaces::new(),
|
||||||
shell: shell_handles,
|
shell: shell_handles,
|
||||||
pending_toplevels: Vec::new(),
|
pending_toplevels: Vec::new(),
|
||||||
dirty_flag: Arc::new(AtomicBool::new(false)),
|
dirty_flag,
|
||||||
|
|
||||||
seats: vec![initial_seat.clone()],
|
seats: vec![initial_seat.clone()],
|
||||||
last_active_seat: initial_seat,
|
last_active_seat: initial_seat,
|
||||||
|
|
@ -167,9 +175,15 @@ impl State {
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
should_stop: false,
|
should_stop: false,
|
||||||
|
|
||||||
|
log,
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
egui: Egui {
|
egui: Egui {
|
||||||
state: smithay_egui::EguiState::new(smithay_egui::EguiMode::Continuous),
|
debug_state: smithay_egui::EguiState::new(smithay_egui::EguiMode::Continuous),
|
||||||
|
log_state: {
|
||||||
|
let mut state = smithay_egui::EguiState::new(smithay_egui::EguiMode::Continuous);
|
||||||
|
state.set_zindex(0);
|
||||||
|
state
|
||||||
|
},
|
||||||
modifiers: Default::default(),
|
modifiers: Default::default(),
|
||||||
active: false,
|
active: false,
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue