Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
69279c9
new light widget
AKArien Dec 21, 2025
affc565
added light to panel.cpp
AKArien Jan 24, 2026
25b50ff
icon selection
AKArien Dec 21, 2025
a4dd098
squash me
AKArien Dec 31, 2025
d2b002a
fixed iteration, calling fs interractions
AKArien Jan 1, 2026
e93f55e
initial filesystem interactions
AKArien Jan 1, 2026
1952218
ddcutil build
AKArien Jan 24, 2026
d28668d
fs slider working
AKArien Jan 4, 2026
5325f2b
fix permissions checking
AKArien Jan 4, 2026
45ba77a
add invert scroll toggle
AKArien Jan 4, 2026
7175300
config metadata
AKArien Jan 4, 2026
f7d563b
added icon
AKArien Jan 4, 2026
4c924ba
light icon size config
AKArien Jan 4, 2026
7bfa6be
type fix
AKArien Jan 4, 2026
3fe0b5c
rename filesystem to sysfs
AKArien Jan 5, 2026
2ac73fc
singleton master design, basic inotify code
AKArien Jan 6, 2026
140a352
remove thing from when it was appended to the wireplumber branch
AKArien Jan 21, 2026
c4bd2bf
this had no buisness being here
AKArien Jan 21, 2026
b878e16
let’s try that again oops
AKArien Jan 22, 2026
c3e4d15
works better this way around
AKArien Jan 22, 2026
e7998fa
tweaks and fixes but not there yet
AKArien Jan 22, 2026
ea1d613
actually grab the reference
AKArien Jan 23, 2026
605b49a
hi soreau the code is the worst mess rn but it works ty !
AKArien Jan 23, 2026
db492a6
basic layout, various cleanups
AKArien Jan 23, 2026
8c6ce26
added inotify for creation and deletion
AKArien Jan 23, 2026
26e6f15
just get monitor from the panel, magic !!
AKArien Jan 23, 2026
713a60e
get value from scale instead of always reading value
AKArien Jan 23, 2026
abf24f5
added config options
AKArien Jan 23, 2026
fc422d0
implemented some of the config options, switched to shared pointers, …
AKArien Jan 23, 2026
3e7a985
heavy round of commenting on sysfs
AKArien Jan 24, 2026
02a6a47
hanlding of in_attrib to recheck permissions
AKArien Jan 24, 2026
f09d94e
oopsie
AKArien Jan 24, 2026
322773d
use substring
AKArien Jan 24, 2026
523ba89
don’t break on card > 9
AKArien Jan 24, 2026
da52f45
fix and align build after rebasing on master
AKArien Jan 24, 2026
11de226
dependancy is hard to spell
AKArien Jan 24, 2026
61d24ca
some ddcutil squeleton
AKArien Jan 31, 2026
fd61dfe
fixed library name
AKArien Jan 31, 2026
dab208d
more abstraction
AKArien Jan 31, 2026
dbaca7d
more ddcutil core
AKArien Jan 31, 2026
b43e598
add error output
AKArien Jan 31, 2026
1efcbb9
update for new icon size after rebase
AKArien Jan 31, 2026
9a933b7
can only have one handle, noted
AKArien Jan 31, 2026
b1ac8cf
Dear diary : today, i made soreau crack up with a dumb commit message
AKArien Jan 31, 2026
1552f9b
fixed some icon updating
AKArien Jan 31, 2026
b7a4cfd
added popup on change
AKArien Jan 31, 2026
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 meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ epoxy = dependency('epoxy')
gtklayershell = dependency('gtk4-layer-shell-0', fallback: ['gtk4-layer-shell'])
libpulse = dependency('libpulse', required: get_option('pulse'))
wireplumber = dependency('wireplumber-0.5', required: get_option('wireplumber'))
ddcutil = dependency('ddcutil', required: get_option('ddcutil'))
dbusmenu_gtk = dependency('dbusmenu-glib-0.4')
libgvc = subproject('gvc', default_options: ['static=true'], required: get_option('pulse'))
xkbregistry = dependency('xkbregistry')
Expand All @@ -40,6 +41,10 @@ if wireplumber.found()
add_project_arguments('-DHAVE_WIREPLUMBER=1', language: 'cpp')
endif

if ddcutil.found()
add_project_arguments('-DHAVE_DDCUTIL=1', language: 'cpp')
endif

needs_libinotify = ['freebsd', 'dragonfly'].contains(host_machine.system())
libinotify = dependency('libinotify', required: needs_libinotify)

Expand Down
6 changes: 6 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ option(
value: 'auto',
description: 'Build wireplumber and mixer widget',
)
option(
'ddcutil',
type: 'feature',
value: 'auto',
description: 'Build external monitor support for backlight widget'
)
option(
'wayland-logout',
type: 'boolean',
Expand Down
33 changes: 33 additions & 0 deletions metadata/panel.xml
Original file line number Diff line number Diff line change
Expand Up @@ -467,5 +467,38 @@ Set to -1 to only run it by clicking the button.
<min>1</min>
</option>
</group>
<group>
<_short>Light</_short>
<option name="light_popup_on_change" type="bool">
<_short>Popup on change</_short>
<default>true</default>
</option>
<option name="light_popup_timeout" type="double">
<_short>Popup timeout</_short>
<default>2.5</default>
<min>0</min>
</option>
<option name="light_slider_length" type="int">
<_short>Slider length</_short>
<default>300</default>
<min>1</min>
</option>
<option name="light_scroll_sensitivity" type="double">
<_short>Scroll sensitivity</_short>
<default>1</default>
</option>
<option name="light_invert_scroll" type="bool">
<_short>Invert scroll</_short>
<_long>
Inverts which scroll direction raises and lowers display brightness
</_long>
<default>false</default>
</option>
<option name="light_icon_size" type="int">
<_short>Light icon size</_short>
<default>0</default>
<min>0</min>
</option>
</group>
</plugin>
</wf-shell>
9 changes: 9 additions & 0 deletions src/panel/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ widget_sources = [
'widgets/tray/item.cpp',
'widgets/tray/host.cpp',
'widgets/tray/dbusmenu.cpp',
'widgets/light/light.cpp',
'widgets/light/sysfs.cpp',
]

deps = [
Expand Down Expand Up @@ -56,6 +58,13 @@ else
message('Wireplumber not found, mixer widget will not be available.')
endif

if ddcutil.found()
widget_sources += 'widgets/light/ddcutil.cpp'
deps += ddcutil
else
message('Libddcutil not found, light widget will not support external monitors.')
endif

executable(
'wf-panel',
['panel.cpp'] + widget_sources,
Expand Down
13 changes: 12 additions & 1 deletion src/panel/panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#ifdef HAVE_WIREPLUMBER
#include "widgets/wp-mixer/wp-mixer.hpp"
#endif
#include "widgets/light/light.hpp"
#include "widgets/window-list/window-list.hpp"
#include "widgets/notifications/notification-center.hpp"
#include "widgets/tray/tray.hpp"
Expand Down Expand Up @@ -178,6 +179,15 @@ class WayfirePanel::impl
#endif
}

if (name == "light")
{
return Widget(new WayfireLight(output));
#ifndef HAVE_DDCUTIL
std::cout << "Built without DDC/CI support, light widget "
" doesn’t support external monitors." << std::endl;
#endif
}

if (name == "window-list")
{
return Widget(new WayfireWindowList(output));
Expand Down Expand Up @@ -381,7 +391,8 @@ void WayfirePanelApp::on_activate()
{"panel/volume_icon_size", ".volume"},
{"panel/wp_icon_size", ".wireplumber"},
{"panel/notifications_icon_size", ".notification-center "},
{"panel/tray_icon_size", ".tray-button"}
{"panel/tray_icon_size", ".tray-button"},
{"panel/light_icon_size", ".light"}
};
for (auto pair : icon_sizes_args)
{
Expand Down
103 changes: 103 additions & 0 deletions src/panel/widgets/light/ddcutil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include <iostream>
extern "C"{
#include <ddcutil_c_api.h>
#include <ddcutil_status_codes.h>
}

#include "light.hpp"

#define VCP_BRIGHTNESS_CODE 0x10

void show_err(std::string location, DDCA_Status status){
// if (!status)
std::cerr << location << " :" << ddca_rc_name(status) << " : " << ddca_rc_desc(status) << "\n";
}


class WfLightDdcaControl : public WfLightControl
{
private:
DDCA_Display_Ref ref;
int max;

int get_max(){
return max;
}

public:
WfLightDdcaControl(WayfireLight *parent, DDCA_Display_Ref _ref) : WfLightControl(parent){
ref = _ref;

DDCA_Display_Handle handle;
DDCA_Status status = ddca_open_display2(ref, false, &handle);
show_err("open display", status);

DDCA_Non_Table_Vcp_Value value;
status = ddca_get_non_table_vcp_value(handle, VCP_BRIGHTNESS_CODE, &value);
max = value.mh << 8 | value.ml;

ddca_close_display(handle);
}

std::string get_name(){
std::string name;
name = "display";
return name;
}

void set_brightness(double brightness){
DDCA_Display_Handle handle;
DDCA_Status status = ddca_open_display2(ref, false, &handle);
show_err("open display", status);

uint16_t value = (uint16_t)(get_max() * brightness);
uint8_t sh = value >> 8;
uint8_t sl = value & 0xFF;
status = ddca_set_non_table_vcp_value(handle, VCP_BRIGHTNESS_CODE, sh, sl);
show_err("set brigthness", status);
ddca_close_display(handle);
}

double get_brightness(){
DDCA_Display_Handle handle;
DDCA_Status status = ddca_open_display2(ref, false, &handle);
show_err("open display", status);

DDCA_Non_Table_Vcp_Value value;
status = ddca_get_non_table_vcp_value(handle, VCP_BRIGHTNESS_CODE, &value);
show_err("get brightness", status);
ddca_close_display(handle);
return value.sh << 8 | value.sl;
}
};

DdcaSurveillor::DdcaSurveillor(){
ddca_enable_verify(true);
DDCA_Display_Info_List *display_list = NULL;
ddca_get_display_info_list2(false, &display_list);

for (int i = 0 ; i < display_list->ct ; i++){
displays_info.push_back(&display_list->info[i]);
}
}

void DdcaSurveillor::catch_up_widget(WayfireLight *widget){
for (auto info : displays_info){
auto control = std::make_shared<WfLightDdcaControl>(widget, info->dref);
// it.second.second.push_back(std::shared_ptr<WfLightSysfsControl>(control));
widget->add_control((std::shared_ptr<WfLightControl>)control);
}

}

void DdcaSurveillor::strip_widget(WayfireLight *widget){

}

DdcaSurveillor& DdcaSurveillor::get(){
if (!instance)
{
instance = std::unique_ptr<DdcaSurveillor>(new DdcaSurveillor());
}
return *instance;
}
Loading
Loading