I dunno that this makes it any easier...

I tried splitting up the sources to speed
up some compiling... but it didn't help.
I dunno that it's more readable this way.

I'm checkpointing this just in case.
This commit is contained in:
2026-01-26 03:47:52 -05:00
parent 9fca970fc5
commit c368696cc2
11 changed files with 279 additions and 200 deletions

84
ConfigFile.cc Normal file
View File

@ -0,0 +1,84 @@
#include "ConfigFile.h"
#include <iostream>
#include <algorithm>
namespace Config::Hydrogen ::detail:: ConfigFile_m
{
namespace
{
struct EoF {};
std::string
readLine( std::istream &input )
{
std::string rv;
std::getline( input, rv );
if( not input ) throw EoF{};
// SStrip trailing '#' comments...
const auto endComment= std::find( begin( rv ), end( rv ), '#' );
rv.erase( endComment, end( rv ) );
return rv;
}
std::string
trimWhitespace( std::string s )
{
// Trim from the front
std::reverse( begin( s ), end( s ) );
while( not s.empty() and s.back() == ' ' ) s.pop_back();
// Trim from the back
std::reverse( begin( s ), end( s ) );
while( not s.empty() and s.back() == ' ' ) s.pop_back();
return s;
}
auto
parseLine( const std::string &line )
{
const auto split= std::find( begin( line ), end( line ), '=' );
if( split == end( line ) ) throw std::runtime_error{ "Unable to parse configuration line: `" + line + "`" };
const auto key= trimWhitespace( { begin( line ), split } );
const auto value= trimWhitespace( { split + 1, end( line ) } );
return std::tuple{ key, value };
}
}
ConfigFile::ConfigFile( std::istream &&input, const std::map< std::string, std::string > &schema )
: config( schema )
{
while( input )
try
{
const std::string line= trimWhitespace( readLine( input ) );
if( line.empty() ) continue; // Skip blank lines.
const auto [ key, value ]= parseLine( line );
if( not schema.contains( key ) )
{
std::cerr << "Unrecognized key in config file: `" << key << "`" << std::endl;
continue;
}
config.at( key )= value;
}
catch( const EoF & ) { break; }
std::cerr << "Configuration parsed:" << std::endl;
for( const auto &[ key, value ]: config )
{
std::cerr << key << " = " << value << std::endl;
}
}
std::string
ConfigFile::get( const std::string &name ) const
{
return config.at( name );
}
}

View File

@ -3,8 +3,6 @@
#include <map> #include <map>
#include <string> #include <string>
#include <istream> #include <istream>
#include <ostream>
#include <optional>
namespace Config::inline Hydrogen {} namespace Config::inline Hydrogen {}
@ -20,77 +18,10 @@ namespace Config::Hydrogen ::detail:: ConfigFile_m
private: private:
std::map< std::string, std::string > config; std::map< std::string, std::string > config;
struct EoF {};
std::string
readLine( std::istream &input )
{
std::string rv;
std::getline( input, rv );
if( not input ) throw EoF{};
// SStrip trailing '#' comments...
const auto endComment= std::find( begin( rv ), end( rv ), '#' );
rv.erase( endComment, end( rv ) );
return rv;
}
std::string
trimWhitespace( std::string s )
{
// Trim from the front
std::reverse( begin( s ), end( s ) );
while( not s.empty() and s.back() == ' ' ) s.pop_back();
// Trim from the back
std::reverse( begin( s ), end( s ) );
while( not s.empty() and s.back() == ' ' ) s.pop_back();
return s;
}
auto
parseLine( const std::string &line )
{
const auto split= std::find( begin( line ), end( line ), '=' );
if( split == end( line ) ) throw std::runtime_error{ "Unable to parse configuration line: `" + line + "`" };
const auto key= trimWhitespace( { begin( line ), split } );
const auto value= trimWhitespace( { split + 1, end( line ) } );
return std::tuple{ key, value };
}
public: public:
explicit explicit ConfigFile( std::istream &&input, const std::map< std::string, std::string > &schema );
ConfigFile( std::istream &&input, const std::map< std::string, std::string > &schema )
{
config= schema;
while( input )
try
{
const std::string line= trimWhitespace( readLine( input ) );
if( line.empty() ) continue; // Skip blank lines.
const auto [ key, value ]= parseLine( line );
if( not schema.contains( key ) ) std::string get( const std::string &name ) const;
{
std::cerr << "Unrecognized key in config file: `" << key << "`" << std::endl;
continue;
}
config.at( key )= value;
}
catch( const EoF & ) { break; }
std::cerr << "Configuration parsed:" << std::endl;
for( const auto &[ key, value ]: config )
{
std::cerr << key << " = " << value << std::endl;
}
}
std::string get( const std::string &name ) const { return config.at( name ); }
}; };
} }

View File

@ -1,4 +1,7 @@
OBJECTS := power_console.o power_console_main.o OBJECTS= power_console.o power_console_main.o
OBJECTS+= MouseWheelSlider.o ConfigFile.o power_profile.o
OBJECTS+= backlight.o
X_INSTALL_DIR := /usr/X11R6 X_INSTALL_DIR := /usr/X11R6
LINKOPTS := -L$(X_INSTALL_DIR)/lib -lfltk -lXext -lX11 -lm LINKOPTS := -L$(X_INSTALL_DIR)/lib -lfltk -lXext -lX11 -lm
FLUID := fluid FLUID := fluid
@ -26,5 +29,7 @@ power_console_main.o: power_console_main.cc power_console.h power_console.h
power_console.h: power_console.fluid power_console.h: power_console.fluid
$(FLUID) -c power_console.fluid $(FLUID) -c power_console.fluid
power_console.cxx: power_console.h
power_console.o: power_console.h power_console.cxx power_console.o: power_console.h power_console.cxx
$(CXX) $(CXXFLAGS) -c power_console.cxx $(CXX) $(CXXFLAGS) -c power_console.cxx

44
MouseWheelSlider.cc Normal file
View File

@ -0,0 +1,44 @@
#include "MouseWheelSlider.h"
#include <iostream>
MouseWheelSlider::MouseWheelSlider( const int x, const int y, const int w, const int h,
const char *const l )
: Fl_Value_Slider( x, y, w, h, l )
{
step( 1 );
}
int
MouseWheelSlider::handle( const int event )
{
switch( event )
{
case FL_MOUSEWHEEL:
{
// Negative, because I use this for the Brightness control.
const int dy= -Fl::event_dy();
const int newVal= value() - dy * step();
if( 0 ) std::cerr << "newVal: " << newVal << " max: " << maximum() << " min: " << minimum() << std::endl;
if( newVal >= maximum()
and newVal <= minimum() )
{
value( newVal );
}
do_callback();
return 1;
}
break;
default:
{
return this->Fl_Value_Slider::handle( event );
}
break;
}
}

13
MouseWheelSlider.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <Fl/Fl.H>
#include <Fl/Fl_Window.H>
#include <Fl/Fl_Value_Slider.H>
class MouseWheelSlider : public Fl_Value_Slider
{
public:
explicit MouseWheelSlider( const int x, const int y, const int w, const int h, const char *const l= 0 );
int handle( const int event ) override;
};

65
backlight.cc Normal file
View File

@ -0,0 +1,65 @@
#include "backlight.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include "power_console.h"
int
getBacklightPercent( const std::filesystem::path &backlightPath )
{
std::ifstream i_max{ backlightPath / "max_brightness" };
int max;
i_max >> max;
std::ifstream inf{ backlightPath / "brightness" };
int in;
inf >> in;
return 100 * in / max;
}
std::filesystem::path getBacklightPath();
namespace
{
void
changeBrightness( int pct )
{
std::ifstream i_max{ getBacklightPath() / "max_brightness" };
int max;
i_max >> max;
// Clamp to never hit 0 backlight or pass max.
int adj= std::clamp( max * pct / 100, 1, max );
std::cerr << "Adjustment computed: " << adj << std::endl;
std::ofstream out{ getBacklightPath() / "brightness" };
out << adj;
}
void
increaseBrightness( int pct )
{
changeBrightness( pct );
}
void
decreaseBrightness( int pct )
{
changeBrightness( -pct );
}
}
void
adjustBrightness( MouseWheelSlider *, void * )
{
const int amount= brightness->value();
std::cerr << "Adjusting brightness by " << amount << std::endl;
changeBrightness( amount );
}

8
backlight.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include <filesystem>
#include "MouseWheelSlider.h"
void adjustBrightness( MouseWheelSlider *, void * );
int getBacklightPercent( const std::filesystem::path &backlightPath );

View File

@ -1,56 +1,7 @@
#pragma once #pragma once
#include <Fl/Fl.H> #include "MouseWheelSlider.h"
#include <Fl/Fl_Window.H>
#include <Fl/Fl_Value_Slider.H>
#include <iostream>
void saverChosen(); void saverChosen();
void perfChosen(); void perfChosen();
void balChosen(); void balChosen();
class MouseWheelSlider : public Fl_Value_Slider
{
public:
explicit
MouseWheelSlider( const int x, const int y, const int w, const int h,
const char *const l= 0 )
: Fl_Value_Slider( x, y, w, h, l )
{
step( 1 );
}
int
handle( const int event ) override
{
switch( event )
{
case FL_MOUSEWHEEL:
{
// Negative, because I use this for the Brightness control.
const int dy= -Fl::event_dy();
const int newVal= value() - dy * step();
if( 0 ) std::cerr << "newVal: " << newVal << " max: " << maximum() << " min: " << minimum() << std::endl;
if( newVal >= maximum()
and newVal <= minimum() )
{
value( newVal );
}
do_callback();
return 1;
}
break;
default:
{
return this->Fl_Value_Slider::handle( event );
}
break;
}
}
};

View File

@ -12,6 +12,8 @@
#include <filesystem> #include <filesystem>
#include "ConfigFile.h" #include "ConfigFile.h"
#include "power_profile.h"
#include "backlight.h"
namespace C namespace C
{ {
@ -43,17 +45,16 @@ const std::map< int, Fl_Color > levelColors=
{ 100, FL_BLUE }, { 100, FL_BLUE },
}; };
const std::map< std::string, Fl_Round_Button ** > powerMode=
{
{ "power-saver", &saver },
{ "balanced", &balance },
{ "performance", &perfButton },
};
using Config::exports::ConfigFile; using Config::exports::ConfigFile;
std::unique_ptr< ConfigFile > config; std::unique_ptr< ConfigFile > config;
std::filesystem::path
getBacklightPath()
{
return config->get( "backlight_path" );
}
std::string battLevelString= "UNKNOWN"; std::string battLevelString= "UNKNOWN";
void void
@ -92,31 +93,9 @@ scheduledUpdate( void * )
if( C::debugUpdate ) std::cerr << "AC state read as: " << ac << std::endl; if( C::debugUpdate ) std::cerr << "AC state read as: " << ac << std::endl;
std::ifstream i_max{ C::path / config->get( "backlight_path" ) / "max_brightness" }; const auto backlightPercent= getBacklightPercent( config->get( "backlight_path" ) );
int max; brightness->value( backlightPercent );
i_max >> max;
std::ifstream inf{ C::path / config->get( "backlight_path" ) / "brightness" };
int in;
inf >> in;
brightness->value( 100 * in / max );
}
// Since this requires launching bg processes, we only do it at startup and then every 30s.
void
profileUpdate( void * )
{
FILE *prof= popen( "powerprofilesctl get", "r" );
char buffer[ 1024 ]= "";
fscanf( prof, "%s", buffer );
pclose( prof );
( *powerMode.at( buffer ) )->setonly();
Fl::repeat_timeout( 30, profileUpdate, nullptr );
} }
int int
@ -175,14 +154,6 @@ consClicked( Fl_Light_Button *, void * )
std::cerr << "Tried to set new state to " << newState << std::endl; std::cerr << "Tried to set new state to " << newState << std::endl;
} }
void
setPowerMode( const std::string &mode )
{
( *powerMode.at( mode ) )->setonly();
std::thread bg{ [mode]{ system( ( "powerprofilesctl set " + mode ).c_str() ); } };
bg.detach();
}
void void
saverChosen() saverChosen()
{ {
@ -200,42 +171,3 @@ perfChosen()
{ {
setPowerMode( "performance" ); setPowerMode( "performance" );
} }
namespace
{
void
changeBrightness( int pct )
{
std::ifstream i_max{ C::path / config->get( "backlight_path" ) / "max_brightness" };
int max;
i_max >> max;
// Clamp to never hit 0 backlight or pass max.
int adj= std::clamp( max * pct / 100, 1, max );
std::cerr << "Adjustment computed: " << adj << std::endl;
std::ofstream out{ C::path / config->get( "backlight_path" ) / "brightness" };
out << adj;
}
void
increaseBrightness( int pct )
{
changeBrightness( pct );
}
void
decreaseBrightness( int pct )
{
changeBrightness( -pct );
}
}
void
adjustBrightness( MouseWheelSlider *, void * )
{
const int amount= brightness->value();
std::cerr << "Adjusting brightness by " << amount << std::endl;
changeBrightness( amount );
}

38
power_profile.cc Normal file
View File

@ -0,0 +1,38 @@
#include "power_profile.h"
#include <thread>
#include <map>
#include "power_console.h"
const std::map< std::string, Fl_Round_Button ** > powerMode=
{
{ "power-saver", &saver },
{ "balanced", &balance },
{ "performance", &perfButton },
};
// Since this requires launching bg processes, we only do it at startup and then every 30s.
void
profileUpdate( void * )
{
FILE *prof= popen( "powerprofilesctl get", "r" );
char buffer[ 1024 ]= "";
fscanf( prof, "%s", buffer );
pclose( prof );
( *powerMode.at( buffer ) )->setonly();
Fl::repeat_timeout( 30, profileUpdate, nullptr );
}
void
setPowerMode( const std::string &mode )
{
( *powerMode.at( mode ) )->setonly();
std::thread bg{ [mode]{ system( ( "powerprofilesctl set " + mode ).c_str() ); } };
bg.detach();
}

8
power_profile.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include <string>
// Since this requires launching bg processes, we only do it at startup and then every 30s.
void profileUpdate( void * );
void setPowerMode( const std::string &mode );