feat: add laptop/display brightness modulation
This commit is contained in:
1 parent
ef1e69ae83
commit
7979acc2eb
34 files changed
+1308
-78
No files matched your search
@@ -20,7 +20,7 @@ extern "C" {
|
||||
using namespace gui;
|
||||
|
||||
static constexpr int WIN_W = 760;
|
||||
static constexpr int WIN_H = 560;
|
||||
static constexpr int WIN_H = 582; // one grid row per capability
|
||||
static constexpr int TAB_H = 36;
|
||||
static constexpr int FOOTER_H = 44;
|
||||
static constexpr int PAD = 18;
|
||||
@@ -60,11 +60,12 @@ static const char* const kCapDescriptions[CAP_COUNT] = {
|
||||
"Configure network interfaces, DHCP and Wi-Fi",
|
||||
"Set the system clock",
|
||||
"Manage user accounts and session identities",
|
||||
"Change display modes and panel brightness",
|
||||
"Change display modes",
|
||||
"Manage hardware devices (Bluetooth, radio)",
|
||||
"Read the kernel log",
|
||||
"Write to 0:/os and 0:/apps (never part of \"all\")",
|
||||
"Read and send input to other windows (never part of \"all\")",
|
||||
"Set the display backlight",
|
||||
};
|
||||
|
||||
// ==== Grant table model ====
|
||||
|
||||
@@ -56,7 +56,7 @@ LDFLAGS := \
|
||||
|
||||
# ---- C++ source files ----
|
||||
|
||||
CORE_SRCS := main.cpp window.cpp panel.cpp wifi.cpp battery.cpp compose.cpp input.cpp dialogs.cpp launcher.cpp desktop_builtin.cpp desktop_catalog.cpp consent.cpp font_data.cpp stb_truetype_impl.cpp
|
||||
CORE_SRCS := main.cpp window.cpp panel.cpp wifi.cpp battery.cpp brightness.cpp compose.cpp input.cpp dialogs.cpp launcher.cpp desktop_builtin.cpp desktop_catalog.cpp consent.cpp font_data.cpp stb_truetype_impl.cpp
|
||||
APP_SRCS := $(sort $(shell find apps -name '*.cpp' -print))
|
||||
SRCS := $(CORE_SRCS) $(APP_SRCS)
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* brightness.cpp
|
||||
* Panel brightness control: the icon that appears when the active display
|
||||
* has a controllable backlight (laptop panel or DDC/CI monitor), and the
|
||||
* slider popout that drives it.
|
||||
*
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include "desktop_internal.hpp"
|
||||
#include <gui/mtk.hpp>
|
||||
|
||||
using namespace gui;
|
||||
|
||||
// ============================================================================
|
||||
// Geometry
|
||||
// ============================================================================
|
||||
|
||||
static constexpr int BRIGHT_POPUP_W = 220;
|
||||
static constexpr int BRIGHT_SLIDER_INSET = 16;
|
||||
static constexpr int BRIGHT_SLIDER_H = 8;
|
||||
static constexpr int BRIGHT_KNOB_R = 8;
|
||||
static constexpr int BRIGHT_STEP = 5; // [-]/[+] and one wheel notch
|
||||
static constexpr int BRIGHT_MIN = 5; // keep the screen readable
|
||||
static constexpr int BRIGHT_POLL_MS = 2000; // follow the Display app
|
||||
static constexpr int BRIGHT_ABSENT_POLL_MS = 30000;
|
||||
// A DDC/CI monitor needs ~50ms per command, so a drag is sampled rather than
|
||||
// forwarding every mouse move; the release always sends the final level.
|
||||
static constexpr int BRIGHT_DRAG_SEND_MS = 100;
|
||||
|
||||
static const char* DISPLAY_APP_PATH = "0:/apps/display/display.elf";
|
||||
|
||||
static int brightness_popup_x(const DesktopState* ds) {
|
||||
int x = ds->brightness_icon_rect.x + ds->brightness_icon_rect.w - BRIGHT_POPUP_W;
|
||||
return x < 4 ? 4 : x;
|
||||
}
|
||||
|
||||
static int brightness_header_y(const DesktopState* ds) {
|
||||
(void)ds;
|
||||
return PANEL_HEIGHT + 2 + 12;
|
||||
}
|
||||
|
||||
static Rect brightness_slider_rect(const DesktopState* ds) {
|
||||
int y = brightness_header_y(ds) + system_font_height() + 18;
|
||||
return {brightness_popup_x(ds) + BRIGHT_SLIDER_INSET, y,
|
||||
BRIGHT_POPUP_W - 2 * BRIGHT_SLIDER_INSET, BRIGHT_SLIDER_H};
|
||||
}
|
||||
|
||||
// [-] [+] row under the slider.
|
||||
static Rect brightness_minus_rect(const DesktopState* ds) {
|
||||
Rect s = brightness_slider_rect(ds);
|
||||
return {brightness_popup_x(ds) + (BRIGHT_POPUP_W - (36 * 2 + 8)) / 2,
|
||||
s.y + s.h + 16, 36, 24};
|
||||
}
|
||||
|
||||
static Rect brightness_plus_rect(const DesktopState* ds) {
|
||||
Rect m = brightness_minus_rect(ds);
|
||||
return {m.x + m.w + 8, m.y, m.w, m.h};
|
||||
}
|
||||
|
||||
static Rect brightness_settings_rect(const DesktopState* ds) {
|
||||
Rect m = brightness_minus_rect(ds);
|
||||
return {brightness_popup_x(ds) + 8, m.y + m.h + 12,
|
||||
BRIGHT_POPUP_W - 16, system_font_height() + 10};
|
||||
}
|
||||
|
||||
static Rect brightness_popup_rect(const DesktopState* ds) {
|
||||
Rect settings = brightness_settings_rect(ds);
|
||||
int y = PANEL_HEIGHT + 2;
|
||||
return {brightness_popup_x(ds), y, BRIGHT_POPUP_W, settings.y + settings.h + 8 - y};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Hardware access
|
||||
// ============================================================================
|
||||
|
||||
static int clamp_level(int level) {
|
||||
if (level < BRIGHT_MIN) return BRIGHT_MIN;
|
||||
if (level > 100) return 100;
|
||||
return level;
|
||||
}
|
||||
|
||||
// Send `level` now. The kernel reports what the hardware ended up at, which
|
||||
// for a panel with coarse steps is not always exactly what was asked.
|
||||
static void brightness_apply(DesktopState* ds, int level) {
|
||||
ds->brightness_pending = -1;
|
||||
ds->brightness_last_send = montauk::get_milliseconds();
|
||||
int result = montauk::display_brightness(level);
|
||||
if (result >= 0 && !ds->brightness_dragging) ds->brightness_level = result;
|
||||
}
|
||||
|
||||
// While dragging, the slider tracks the pointer immediately and the hardware
|
||||
// catches up at most every BRIGHT_DRAG_SEND_MS.
|
||||
static void brightness_request(DesktopState* ds, int level) {
|
||||
level = clamp_level(level);
|
||||
ds->brightness_level = level;
|
||||
uint64_t now = montauk::get_milliseconds();
|
||||
if (ds->brightness_dragging && now - ds->brightness_last_send < BRIGHT_DRAG_SEND_MS) {
|
||||
ds->brightness_pending = level;
|
||||
return;
|
||||
}
|
||||
brightness_apply(ds, level);
|
||||
}
|
||||
|
||||
static int brightness_from_x(const DesktopState* ds, int mx) {
|
||||
Rect s = brightness_slider_rect(ds);
|
||||
int v = ((mx - s.x) * 100) / s.w;
|
||||
return clamp_level(v);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Startup and polling
|
||||
// ============================================================================
|
||||
|
||||
void desktop_brightness_init(DesktopState* ds) {
|
||||
ds->icon_brightness = svg_load("0:/os/icons/display-brightness-symbolic.svg",
|
||||
16, 16, colors::PANEL_TEXT);
|
||||
ds->brightness_popup_open = false;
|
||||
ds->brightness_icon_rect = {0, 0, 0, 0};
|
||||
ds->brightness_dragging = false;
|
||||
ds->brightness_pending = -1;
|
||||
ds->brightness_last_send = 0;
|
||||
ds->brightness_last_poll = montauk::get_milliseconds();
|
||||
|
||||
int level = montauk::display_brightness(-1);
|
||||
ds->brightness_present = level >= 0;
|
||||
ds->brightness_level = level >= 0 ? level : 100;
|
||||
}
|
||||
|
||||
bool desktop_brightness_poll(DesktopState* ds, uint64_t now) {
|
||||
// Flush a drag sample that was held back by the send throttle.
|
||||
if (ds->brightness_pending >= 0 && now - ds->brightness_last_send >= BRIGHT_DRAG_SEND_MS)
|
||||
brightness_apply(ds, ds->brightness_pending);
|
||||
|
||||
if (ds->brightness_dragging) return false;
|
||||
|
||||
// An absent backlight is re-checked now and then: an external monitor
|
||||
// can be switched to DDC/CI in its menu, and the kernel retries that.
|
||||
uint64_t interval = ds->brightness_present ? BRIGHT_POLL_MS : BRIGHT_ABSENT_POLL_MS;
|
||||
if (now - ds->brightness_last_poll < interval) return false;
|
||||
ds->brightness_last_poll = now;
|
||||
|
||||
int level = montauk::display_brightness(-1);
|
||||
bool present = level >= 0;
|
||||
bool changed = present != ds->brightness_present;
|
||||
ds->brightness_present = present;
|
||||
if (!present) {
|
||||
if (changed) ds->brightness_popup_open = false;
|
||||
return changed;
|
||||
}
|
||||
if (level != ds->brightness_level) {
|
||||
ds->brightness_level = level;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool desktop_brightness_dragging(const DesktopState* ds) {
|
||||
return ds->brightness_dragging;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Popout
|
||||
// ============================================================================
|
||||
|
||||
static void draw_button(DesktopState* ds, const Rect& r, const char* label) {
|
||||
Framebuffer& fb = ds->fb;
|
||||
Color bg = r.contains(ds->mouse.x, ds->mouse.y) ? Color::from_rgb(0xD0, 0xD0, 0xD0)
|
||||
: Color::from_rgb(0xE0, 0xE0, 0xE0);
|
||||
fill_rounded_rect(fb, r.x, r.y, r.w, r.h, 6, bg);
|
||||
int tw = text_width(label);
|
||||
draw_text(fb, r.x + (r.w - tw) / 2, r.y + (r.h - system_font_height()) / 2,
|
||||
label, colors::TEXT_COLOR);
|
||||
}
|
||||
|
||||
void desktop_draw_brightness_popup(DesktopState* ds) {
|
||||
Framebuffer& fb = ds->fb;
|
||||
Rect popup = brightness_popup_rect(ds);
|
||||
Color accent = ds->settings.accent_color;
|
||||
|
||||
draw_shadow(fb, popup.x, popup.y, popup.w, popup.h, 4, colors::SHADOW);
|
||||
fill_rounded_rect(fb, popup.x, popup.y, popup.w, popup.h, 8, colors::MENU_BG);
|
||||
draw_rect(fb, popup.x, popup.y, popup.w, popup.h, colors::BORDER);
|
||||
|
||||
int ty = brightness_header_y(ds);
|
||||
draw_text(fb, popup.x + 14, ty, "Brightness", colors::TEXT_COLOR);
|
||||
char value[8];
|
||||
snprintf(value, sizeof(value), "%d%%", ds->brightness_level);
|
||||
draw_text(fb, popup.x + popup.w - 14 - text_width(value), ty, value, accent);
|
||||
|
||||
Rect s = brightness_slider_rect(ds);
|
||||
fill_rounded_rect(fb, s.x, s.y, s.w, s.h, 4, Color::from_rgb(0xDD, 0xDD, 0xDD));
|
||||
int fill_w = (ds->brightness_level * s.w) / 100;
|
||||
if (fill_w > 0) fill_rounded_rect(fb, s.x, s.y, fill_w, s.h, 4, accent);
|
||||
int knob_cx = s.x + fill_w;
|
||||
int knob_cy = s.y + s.h / 2;
|
||||
fill_circle(fb, knob_cx, knob_cy, BRIGHT_KNOB_R, accent);
|
||||
fill_circle(fb, knob_cx, knob_cy, BRIGHT_KNOB_R - 3, colors::WHITE);
|
||||
|
||||
draw_button(ds, brightness_minus_rect(ds), "-");
|
||||
draw_button(ds, brightness_plus_rect(ds), "+");
|
||||
|
||||
Rect settings = brightness_settings_rect(ds);
|
||||
if (settings.contains(ds->mouse.x, ds->mouse.y))
|
||||
fill_rounded_rect(fb, settings.x, settings.y, settings.w, settings.h, 5,
|
||||
Color::from_rgb(0xF0, 0xF3, 0xF6));
|
||||
draw_text(fb, settings.x + 6, settings.y + (settings.h - system_font_height()) / 2,
|
||||
"Display Settings...", colors::TEXT_COLOR);
|
||||
}
|
||||
|
||||
// Returns true when the event was consumed.
|
||||
bool desktop_brightness_handle_mouse(DesktopState* ds, int mx, int my, bool left_pressed,
|
||||
bool left_held, bool left_released, int scroll) {
|
||||
if (!ds->brightness_present) return false;
|
||||
|
||||
if (ds->brightness_dragging) {
|
||||
if (left_held) {
|
||||
brightness_request(ds, brightness_from_x(ds, mx));
|
||||
return true;
|
||||
}
|
||||
if (left_released) {
|
||||
ds->brightness_dragging = false;
|
||||
brightness_apply(ds, ds->brightness_level);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The wheel works over the panel icon too, without opening anything.
|
||||
bool over_popup = ds->brightness_popup_open && brightness_popup_rect(ds).contains(mx, my);
|
||||
if (scroll != 0 && (over_popup || ds->brightness_icon_rect.contains(mx, my))) {
|
||||
brightness_request(ds, ds->brightness_level + scroll * BRIGHT_STEP);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ds->brightness_popup_open || !left_pressed) return false;
|
||||
|
||||
if (!over_popup) {
|
||||
if (!ds->brightness_icon_rect.contains(mx, my)) ds->brightness_popup_open = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Rect s = brightness_slider_rect(ds);
|
||||
if (my >= s.y - 10 && my <= s.y + s.h + 10
|
||||
&& mx >= s.x - BRIGHT_KNOB_R && mx <= s.x + s.w + BRIGHT_KNOB_R) {
|
||||
ds->brightness_dragging = true;
|
||||
brightness_request(ds, brightness_from_x(ds, mx));
|
||||
return true;
|
||||
}
|
||||
if (brightness_minus_rect(ds).contains(mx, my)) {
|
||||
brightness_request(ds, ds->brightness_level - BRIGHT_STEP);
|
||||
return true;
|
||||
}
|
||||
if (brightness_plus_rect(ds).contains(mx, my)) {
|
||||
brightness_request(ds, ds->brightness_level + BRIGHT_STEP);
|
||||
return true;
|
||||
}
|
||||
if (brightness_settings_rect(ds).contains(mx, my)) {
|
||||
ds->brightness_popup_open = false;
|
||||
desktop_spawn_app(ds, DISPLAY_APP_PATH, nullptr);
|
||||
return true;
|
||||
}
|
||||
return true; // inside the popup, on nothing in particular
|
||||
}
|
||||
@@ -273,6 +273,10 @@ void gui::desktop_compose(DesktopState* ds) {
|
||||
desktop_draw_battery_popup(ds);
|
||||
}
|
||||
|
||||
if (ds->brightness_popup_open) {
|
||||
desktop_draw_brightness_popup(ds);
|
||||
}
|
||||
|
||||
// Draw volume popup if open
|
||||
if (ds->vol_popup_open) {
|
||||
desktop_draw_vol_popup(ds);
|
||||
|
||||
@@ -68,6 +68,7 @@ void desktop_lock_screen(DesktopState* ds) {
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
|
||||
// Cache display name for lock screen rendering
|
||||
montauk::strncpy(ds->lock_display_name, ds->current_user, sizeof(ds->lock_display_name));
|
||||
|
||||
@@ -205,6 +205,15 @@ bool desktop_battery_poll(gui::DesktopState* ds, uint64_t now);
|
||||
void desktop_draw_battery_popup(gui::DesktopState* ds);
|
||||
bool desktop_battery_handle_mouse(gui::DesktopState* ds, int mx, int my);
|
||||
|
||||
// brightness.cpp
|
||||
void desktop_brightness_init(gui::DesktopState* ds);
|
||||
bool desktop_brightness_poll(gui::DesktopState* ds, uint64_t now);
|
||||
bool desktop_brightness_dragging(const gui::DesktopState* ds);
|
||||
void desktop_draw_brightness_popup(gui::DesktopState* ds);
|
||||
bool desktop_brightness_handle_mouse(gui::DesktopState* ds, int mx, int my,
|
||||
bool left_pressed, bool left_held,
|
||||
bool left_released, int scroll);
|
||||
|
||||
// compose.cpp
|
||||
void desktop_draw_lock_screen(gui::DesktopState* ds);
|
||||
void desktop_mark_background_dirty(gui::DesktopState* ds);
|
||||
|
||||
@@ -187,6 +187,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->app_menu_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
@@ -518,11 +519,17 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
return; // click inside popup but not on any control
|
||||
} else if (!ds->vol_icon_rect.contains(mx, my)) {
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->vol_dragging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Brightness popup, a drag on its slider, or the wheel over its icon.
|
||||
if (desktop_brightness_handle_mouse(ds, mx, my, left_pressed, left_held,
|
||||
left_released, ev.scroll))
|
||||
return;
|
||||
|
||||
// Wi-Fi popup. The passphrase dialog is an ordinary window and needs
|
||||
// nothing here.
|
||||
if (ds->wifi_popup_open) {
|
||||
@@ -566,6 +573,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
return;
|
||||
}
|
||||
@@ -583,6 +591,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
return;
|
||||
}
|
||||
@@ -591,6 +600,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
if (ds->vol_icon_rect.w > 0 && ds->vol_icon_rect.contains(mx, my)) {
|
||||
ds->vol_popup_open = !ds->vol_popup_open;
|
||||
ds->vol_dragging = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->app_menu_open = false;
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
@@ -599,11 +609,25 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Brightness icon
|
||||
if (ds->brightness_present && ds->brightness_icon_rect.w > 0
|
||||
&& ds->brightness_icon_rect.contains(mx, my)) {
|
||||
ds->brightness_popup_open = !ds->brightness_popup_open;
|
||||
ds->app_menu_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
return;
|
||||
}
|
||||
|
||||
// Network icon
|
||||
if (ds->net_icon_rect.w > 0 && ds->net_icon_rect.contains(mx, my)) {
|
||||
ds->net_popup_open = !ds->net_popup_open;
|
||||
ds->app_menu_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
@@ -615,6 +639,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->wifi_popup_open = !ds->wifi_popup_open;
|
||||
ds->app_menu_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->net_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
@@ -626,6 +651,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->battery_popup_open = !ds->battery_popup_open;
|
||||
ds->app_menu_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
@@ -783,6 +809,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->app_menu_open = false;
|
||||
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
}
|
||||
|
||||
// Forward continuous mouse events to focused window (hover, drag, release).
|
||||
@@ -861,6 +888,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ds->wifi_popup_open = false;
|
||||
ds->battery_popup_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,6 +408,7 @@ void desktop_open_launcher(DesktopState* ds) {
|
||||
ds->net_popup_open = false;
|
||||
ds->wifi_popup_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->brightness_popup_open = false;
|
||||
ds->vol_dragging = false;
|
||||
desktop_update_launcher_results(ds);
|
||||
}
|
||||
|
||||
@@ -393,6 +393,7 @@ void gui::desktop_init(DesktopState* ds) {
|
||||
desktop_refresh_netifs(ds);
|
||||
desktop_wifi_init(ds);
|
||||
desktop_battery_init(ds);
|
||||
desktop_brightness_init(ds);
|
||||
desktop_consent_init(ds);
|
||||
|
||||
ds->vol_popup_open = false;
|
||||
@@ -445,6 +446,7 @@ static bool desktop_has_visible_dirty_window(const DesktopState* ds) {
|
||||
|
||||
static bool desktop_has_active_interaction(const DesktopState* ds) {
|
||||
if (ds->vol_dragging) return true;
|
||||
if (desktop_brightness_dragging(ds)) return true;
|
||||
|
||||
for (int i = 0; i < ds->window_count; i++) {
|
||||
const Window& win = ds->windows[i];
|
||||
@@ -521,6 +523,7 @@ static bool desktop_refresh_panel_state(DesktopState* ds, uint64_t now) {
|
||||
|
||||
if (desktop_wifi_poll(ds, now)) changed = true;
|
||||
if (desktop_battery_poll(ds, now)) changed = true;
|
||||
if (desktop_brightness_poll(ds, now)) changed = true;
|
||||
|
||||
// Event-driven sync: the kernel mixer bumps a serial on every state
|
||||
// change. Reading it is one cheap syscall; refresh only when the serial
|
||||
|
||||
@@ -173,6 +173,17 @@ void gui::desktop_draw_panel(DesktopState* ds) {
|
||||
int icon_y = (PANEL_HEIGHT - 16) / 2;
|
||||
int next_icon_x = vol_icon_x - 16 - 10;
|
||||
|
||||
// Brightness sits next to the speaker: the two slider controls together.
|
||||
if (ds->brightness_present) {
|
||||
ds->brightness_icon_rect = {next_icon_x, icon_y, 16, 16};
|
||||
next_icon_x -= 16 + 10;
|
||||
if (ds->icon_brightness.pixels)
|
||||
fb.blit_alpha(ds->brightness_icon_rect.x, icon_y, ds->icon_brightness.width,
|
||||
ds->icon_brightness.height, ds->icon_brightness.pixels);
|
||||
} else {
|
||||
ds->brightness_icon_rect = {0, 0, 0, 0};
|
||||
}
|
||||
|
||||
if (ds->eth_present) {
|
||||
ds->net_icon_rect = {next_icon_x, icon_y, 16, 16};
|
||||
next_icon_x -= 16 + 10;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/user.h>
|
||||
#include <montauk/config.h>
|
||||
#include <montauk/capabilities.h>
|
||||
#include <gui/gui.hpp>
|
||||
#include <gui/framebuffer.hpp>
|
||||
#include <gui/draw.hpp>
|
||||
|
||||
@@ -52,6 +52,10 @@ void launch_session(LoginState* ls) {
|
||||
caps.effective = montauk::user::is_admin(ls->username)
|
||||
? montauk::abi::CAP_ADMIN_SESSION
|
||||
: montauk::abi::CAP_STANDARD_SESSION;
|
||||
// Clamp to what this login may delegate: a grant table from before a
|
||||
// capability existed would otherwise make the kernel refuse the spawn
|
||||
// outright, leaving no session at all rather than one without it.
|
||||
caps.effective &= montauk::caps::self_delegable();
|
||||
caps.delegable = caps.effective;
|
||||
|
||||
int pid;
|
||||
|
||||
@@ -30,6 +30,7 @@ static void maybe_run_setup_session() {
|
||||
caps.effective = admin
|
||||
? montauk::abi::CAP_ADMIN_SESSION
|
||||
: montauk::abi::CAP_STANDARD_SESSION;
|
||||
caps.effective &= montauk::caps::self_delegable();
|
||||
// Matches launch_session(): a session delegates from what it holds, and
|
||||
// the grant table decides which program receives which part of it.
|
||||
caps.delegable = caps.effective;
|
||||
|
||||
Reference in new issue
Block a user