From 55283e90df5bcfa1089e189b0fcb3bf6d3ea838c Mon Sep 17 00:00:00 2001 From: klein panic Date: Sun, 29 Sep 2024 02:33:20 -0400 Subject: [PATCH] initial commit --- Makefile | 22 +++ README.md | 0 battery_daemon.sh | 67 ++++++++ battery_monitor | Bin 0 -> 28160 bytes battery_monitor.service | 16 ++ include/battery_monitor.h | 16 ++ include/log_message.h | 7 + include/process_monitor.h | 8 + install.sh | 73 +++++++++ obj/battery_monitor.o | Bin 0 -> 2904 bytes obj/notification.o | Bin 0 -> 12360 bytes obj/process_monitor.o | Bin 0 -> 7592 bytes src/battery_monitor.c | 70 ++++++++ src/notification.c | 325 ++++++++++++++++++++++++++++++++++++++ src/notification.c.bak | 307 +++++++++++++++++++++++++++++++++++ src/process_monitor.c | 209 ++++++++++++++++++++++++ src/process_monitor.c.bak | 177 +++++++++++++++++++++ 17 files changed, 1297 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100755 battery_daemon.sh create mode 100755 battery_monitor create mode 100755 battery_monitor.service create mode 100644 include/battery_monitor.h create mode 100644 include/log_message.h create mode 100644 include/process_monitor.h create mode 100755 install.sh create mode 100644 obj/battery_monitor.o create mode 100644 obj/notification.o create mode 100644 obj/process_monitor.o create mode 100644 src/battery_monitor.c create mode 100644 src/notification.c create mode 100644 src/notification.c.bak create mode 100644 src/process_monitor.c create mode 100644 src/process_monitor.c.bak diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..63be530 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CFLAGS = `pkg-config --cflags gtk+-3.0` -I$(INC_DIR) +LDFLAGS = `pkg-config --libs gtk+-3.0` +SRC_DIR = src +INC_DIR = include +OBJ_DIR = obj +OBJS = $(OBJ_DIR)/battery_monitor.o $(OBJ_DIR)/notification.o $(OBJ_DIR)/process_monitor.o +TARGET = battery_monitor + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c + @mkdir -p $(OBJ_DIR) + $(CC) $(CFLAGS) -I$(INC_DIR) -o $@ -c $< + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) + +clean: + rm -rf $(OBJ_DIR) $(TARGET) + +.PHONY: all clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/battery_daemon.sh b/battery_daemon.sh new file mode 100755 index 0000000..8dd1307 --- /dev/null +++ b/battery_daemon.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# Path to the battery monitor binary +BINARY_PATH="/usr/local/bin/battery_monitor" + +# Log file +LOG_FILE="/tmp/battery_monitor.log" + +# Create Log Directory if it doesn't exist +LOG_DIR=$(dirname "$LOG_FILE") + +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi + +if [ ! -d "$LOG_FILE" ]; then + echo "Creating Find the log file" + touch "$LOG_FILE" +fi + +if [ ! -w "$LOG_FILE" ]; then + echo "Cannot Write to the Log: $LOG_FILE. Attempting to change perms..." + sudo chown $USER "$LOG_FILE" || { + echo "Failed to change perms. Exiting" + exit 1 + } +fi + +# Log starting message and environment variables +echo "Starting battery monitor script" >> "$LOG_FILE" +echo "DISPLAY=$DISPLAY" >> "$LOG_FILE" +echo "XAUTHORITY=$XAUTHORITY" >> "$LOG_FILE" + +# Check if binary exists and is executable +if [ ! -x "$BINARY_PATH" ]; then + echo "Binary not found or not executable: $BINARY_PATH" >> "$LOG_FILE" + exit 1 +fi + +check_x_server() { + if xset q > /dev/null 2>&1; then + echo "X Server is running." + return 0 + else + echo "X Server is not running yet." + return 1 + fi +} + +until check_x_server; do + sleep 1 +done + +while true; do + if pgrep -x "dwm" > /dev/null; then + echo "dwm running" + # Start the battery monitor and redirect output to log file + exec "$BINARY_PATH" >> "$LOG_FILE" 2>&1 + + while pgrep -x "dwm" > /dev/null; do + sleep 1 + done + else + echo "waiting for DWM to start" + sleep 1 + fi +done diff --git a/battery_monitor b/battery_monitor new file mode 100755 index 0000000000000000000000000000000000000000..30eaa3723a5a24491dde4aa8afe106c4dc0d4a96 GIT binary patch literal 28160 zcmb<-^>JfjWMqH=W(GS35O0DqM8p9?F*u|_84L^z4h$9yybKNu@(gkeYzzzxEMPH+ zJX}45%W#7U!hq2n5H15VRG$Qh!N9b{|XO8AB;xU2MU`7z7Y8Zv8eO}u%QeL2cYhS z=>r89NZ$siz70@)Fj@elfPsMlM#I7rWE==vK*JNAM)NKMy1odgK6Kgz;%o*O4YC6y z6#TR#1;j?T2gb)`UjS5JfCtDF1_pHc2}GCyMuY4C2?ahaNdbimh)oQJMms|g)IMDC zkN^!&7!67%AoKNeGLy_q^m9^lb29TvD|9O?%yi96^osNKj6l-hG!L=^l&0MMLK&DE z7!H8k3eyi_gQ6A`tRVSkA_cqIUkOy5m?wWPXXU+zrrB5dKx#l{fb@XWfD8tyhdK$w z1?Lkh1_p4R1o^+iVIfF42T05otb&2T$@S`+3#sRFcR!v~bF(l4mSv!_sMHlk1_mKi zAuz88hj=IxcJ&}fU^C|c4)rQH%>RT#JwF3>dyR3Zx5gnJjl9Tj4u2iPq5cC7 z_ZQ+&{~CvQ1rG6vIK%^Rh@Zsao|!n*$KVhLRWI1`7YmN?$-!ZcJPz>>IL!HrL)-#~ zcry<1c{swsAF1jE7d%kH4Tm`rINZMwhj=y)^Q&-(Z^hxxb2!YOf|P5)bz~alGLIQU+0|syws4yq?}ZS`1thP{Ji+$lEk8t_;`p?tP0cPi%W`< za|;X@(o3@Ab5o0p6Vp@UQ!*2C^3&t@@<(YXY`Q`EHsU`6xl?AC#u@n%$I3vG2 zJ~1Z;Su7>BxTGk*5-bEY38WORHMzJrzMv?-EHfpwC_X1YF(p2&C_fkK$CB*$@=UPN zD0*@eGxOpLOEXKrrlObtb7gT!Wlkz6#7a^tz#$B`1gr;S0+^AR2Q>xiw#1Z__@vU3 zlKecdG?MKoCPF2_AyEtpiOiB5NKinO!F>dGcUpRCNihQ`daXJ zQwtahQj3c6ix|?1Qd2=HQc4RzR7rj|Lt1`8Y92#zWpPPrE<;LYQC?y$SV>N59z%S5 zGAI<|lj3volNpLq6H`FCic5+Z(o;(cGE=}pIhlFc42dQAnGCs!IUscf$vOGOpfr(_ znUoAo6X4KDgF2}sKPSIDwTK};KC?JK+0rsTtvER`FAZc}MPhtfW?o`WW>qRf0oY~f zsU@j-WejN$Lm}xDp|cpG6XfaK0*3OU%#u`woXn*3l5AaLP|M2z%!8z3T_ZgMgjh~y z5{f`FNXm>MJ{6qy}jh)>N+VQ}~HbaIY2(lds$%;79!6FAdI&lKG9Vq{=q zK*k^*h|kQx1cr=YSr(`&R}6GINDVadS20PBaq z+W!SA5OY^R`x!8C1E~0kM2I|09L9fuChp+|QTGB(JOC>G0Zlv}BptiO(gb5~3Ac^yVMIgilBymHC z5SYAyBo0bNU_k~3h6hOEW-vhzod6;j7}&un4#EbJ97y8G{Q?0bacIiG$n(6SqJThs6y@&H+iB6C?n|9!TO`P%#h{fF#Zh z5`f|eBynih8Z485B+d&Kfe;x;;-EeQM3jM{07)Fw$AXDhAc+gY1Q{3@8j!@1+g%+< z;=)MkCm@M~`gt&^8A#%yFhNkhLlPH55?_HNE{-I=0ZAM>Gy#^~fg~;o7J(24ki?}R zLSXU)lDITj1VUUu5=ZVZ-arzUg(wA+50J#=z#R=HFVSpsA z0TBX|7D(cnU=ax6fFus;vq3}|7(9@~wPAt`3=9EC;yOs;5lG^?Na6`d;(AEp8A#&# zNa6)Z;s!|K6-eTckqn4r1CqEgLoRMIgikByn?y5SW~SByIr~fe;Ij#4RC0 zqvU7^jE2By2#kinXb6mkz-S1JhQMeDjD`T6L%^f?4TncJ>sfmS29MSQB~1S>cr+j3 zI1G2if74U;3=IEO&)73C@XI?e{8t6>GeGh$AN>FS|G(-Xdj^IK&|uZe3t;{(5Fa#D z@$vwezX`+#4N<(@0Oqd(@j*iqFBgFMi$HwPki^RgVE!x+A2by4vH{GW1mc6bg)a-h z{4Nk5H1zN?0nBd#@j*ilF9X2*Di9wu)bP>)%r64*K|>5L4Z!>?5Fa$O@KOQHPXh5l zLkcei!2Bo>A2h`Ck^#&Q0`WmZ3ok$X1Nqkr#0L#2ynF!WJAwG1p@f$gz>0dqo^ACaepsxJO3t;{(5FgZq ze|Z4R-vr`=y6!JGfcdLHd{CGD!I{?Y-=F9PvFUGJ9$V15>e59)HiQ~>jnKzvYF z`=tPw9|hury4Wun!2BQ(AJnye`QZ=9|6U+Is7w9w0hsRu;)90%US0t6tw4NG*ZSoF zFy9Eo2X(1mZUFPOKzvYF`sD&J-^zx8A#DOELxHg2ThGpmaUPwIJer?;2ncaCJYaaz zqu2Hv0|UcHo|x_p8B{)sBIIp;SB6quI6!G)n5x`Lu+`quaL3mVx1g=KufyU!?s1|Nj{4 zU0VhQ#@NIB@+kUWmjD0%Kh&f1sYml00gqnR25ANckIv&SrZX`x>;O6T#Z@i_hSmcm zMjpMa)lkVQCI*J%ti8}R564;Cp{)Hnj0_AfO#l4<|5BI{rk{_IfuYm&M|16u|D|#s zy{u_aLrj?%81~yRFfhDe0cm)|z`$_a^$$p(x%P*59p`b^KOo~?%QV;iV66vnK^fsS zZ*%Pr{(5$VQr3FAZdOiPkRwY?JbGEppypp?1V=>(n0w5lmo*j4I{reN1LXS4HlP80 z28P#8U;}NsSr6KP%>a2c3957=#Eeof7i2~~n05Tcb9Rs!-B2??Ce(2qXRQXgo`Hb@ z;<)P_P+51}^$RHYUu$=} ze({*$(d}~dfk&@sI#~TRPz=@m{{P>j)Aff(bL|g?Qod%_FO1!;Uz&d~mYsdgH~}K6 ziWDB}e*ORN(aWk1HsSb-Z43+yJ3tn_PVwjsz2njC`op7_R}CzC&ZF};M05*E=TP4tYJs^XjKKft6@6pTZ1y*zX#iXBLw_95?FhC7ze4`)$vVZT3 z_aLd(4`51ksuTmmKClHaAGCvlsTU^S2et|ves)N{Qv(o$aU^u!;ZfQ`T76<1gN{3-#B#Ep7H2qg-C(|l{E*f&h^7_*EcEP zRQ>`KvmV{9ANGM6FsHux@&A9P>yzf%C;v+|JbIz}j=%Ww1LQ^4SgJD&(Rr@(_zPB$TbqCUFNyK!b-e{jD#5=%2EXZcebRaS#W!$-yy0K( zdd4I9f=A{h`PSEg9tU43bY498lXYh23C#);8|9^1_92P%3dRsyD%sx=8g2K6u z8&uSNX|Db9zf{trmo*xy$LlZDmY35Q!KEC?f|m}A3=G|_e?XbLfzDb3zq4f3NfN}!tek8Jv&c$ zfP;}ql7V602~Zrs(pmvH2EeL7E?)sEf>(nSpqq2x7m_)5LD7L?jt0aWkSdTl31Ejq z-48V#6px2M8bQT5JUP9Gcn9Q6kVb`Xpn~Rqsg_4C>jDW#x)T2L|9^Mr7icJVf^)4p zFRa+|Yj*v^*zNkq+Vu;6&lXUcLsR;Phk;=~sPcc21TMw?mx_7xvc^LV-}W0CC$Cw- z;R}uLUe-9Mf~nwwgEbk-t^fM}e=MvJQ}F1lec{nr`rt(d$Qz(CtGo08D9`K!MXks2 zL!gosz+uC5;L~R%D(;o4_5t}bq6TJLj$7ujX-DZACF$vWl)W+zYzBKvflU)^2@RPpw7h$=CA+% zPk;taXYCJ<&e9JaouQyIHiE2rR-pZXsNqSzcs-~lZAzOeiA|Nm5Bl`7eh_0|0H=msAjy58fC4LnxIqD=w$t^; z3wCgXAvd`tNCA$7mw|K!OXz$A{Asrx9bl_aA-M# z!w1at=oNhoQrK%+1~%yU3n{4C*pz|_W{+Oe5UA4kAEC+m1*r6eWVPcjeu6@<IMPNPRD>FqCWd9ajF- zd-R5006VakR{$&v%KPA8c%k_jR4hW;Uq3}bb{~K7^aH4JV0{JUzJ-)9KR_jn7Rb|} zqUW_1*uc)?FT}ytx?b?;6}<-50e1YxkDw&LKji@bwgZqP9_-QlMgmr>y|x6ES^V1= z__rPCJpSVH$N&F34|{aGK7b1y`1t?7<>3-`urptqc{IDeVDxBqeZUCS*m9tR8>*q@ zK$2TIvM%-2aE5)?0w-hrYl08$e$UH~=QK_=(^00q|%4@=h<#p*BSf|{^k zJAUA{;}kevn-4G^1BHR>3rO%mJ8v!`kQA~QWD-1Sf?6VmP?-Z?pt<7ZR8VCP&XC7n zID?$md_W!K)OLv84<6069~esVJi0@FfJ$y?0l5;SvfK3oNF^_b4bJ)>JQy!{?9R|NnPx-2$qwK?&dmH>hmtbba8_T>F3l+|H^N1}QxL z;?ZYlo_g5_Y8iKfGPGzrSQ4D-y}>Say#Y#wARk17_|3I9Af_aM6&`;v2X2Z7sI}I5 z=J)^qAd6qV1qE4e>jiMbK-34U9Bl67H~;^8v>xDZIgO&i6`|rG$R<#;x|dZSEP4!F z7rZzL6K}44!NA|r4bl%vti7UKU}a$Amp~Q0j)JA9$iM&pcTWX5%p>`dM=#G+ko!Ek zr-FjYqgO@{;yABdRaFJfkF%F01vP#*B2fj2bAzZR9m)!Lc4yV zM|bEAQ0wbAsG0*u#_<>GAPubt_**~y1J^A#Kz3~c1wb#vLEWujS3ue|3ZNz&#A0|} z_W+f-(DqYj=$+%Pe?YE(Z3<}%!?HOj@)$38fb#>aaTD?zRBDw#8xMl;2H>5V!{BlV zk#ufwfc&^u<2xwnsC@tbA6lk(^s;UP7vZj;)*7f@%m8!2;r!+ms8({l;Q>z)r@)fO zUv$FC)tCLCgw@-+;m7~~@MgcyUr_hz%1h8lhez+;72qcE)&fw=u(x*&m^ak`%mb$# z&(5EoogX}UP3J&N2Rr>m{A*B2&%)mdYF>ATUh(Md1zF$pmJVKN*p77{q0QU?u1VJ5UNZdjk z687f*|7O=WjIW)#VU7p8pttqG_y7MLVO@&v0_a@|S#Tl%s{*BoP;ilnnSh>wT-SP_ zgumPMjdd$1ZuonS{R71iq_~#^rT-Zo-7QDK{_i~gV#_O#i(W8xyS}h?y;5`E160U& z9)I!Y6{s8c2C39;e4_x0pU%B6{(&O?35c8u8XATsvX`KYf|kx&L25w-ST}g!OZ_z{ zGJkZt{;+NZ=`0oT=w&qmk2M^B(fI!V|ChbsJ}Rj52O7i%hoS{WU8mvbSqzBYJfp>}SfYM)YD@X-M5ARD*iuhkD=+VpihaZ%lkH27e{~t2; zzyx*C`*)zQfpmmgLH_0Mk@^4s{{+N%1i0baS^5MT1h19R{O|e#;dw8Rm9TErlbWj_ zV;C5~^AadC5ugk^ibq3WGz3ONU^E0qLtr!ns1X97eJmhzoFKg?1!$*90lfPwHH85t zo>{DroRL_Ro|%`fqmY+hl9`s7oLG{XpI599)S^GZun;pQh7WtLnMQshJn-~TgBiE zRips3B|NbxFEcNlfdOs~$emDCFr$)EbMng-OjSY7gR8@BiBEnxhWRl2GK(RugBWRO zs>+~WTv@E2oRe5wtX}}y2NhpjT2PQvsqf?%VxXU#Sdf^USyIWsfKQzvLR}Gq8#u5O zO7ayz8>SRsCMcw3=A<&HrXb0K!xq}8KonOBmU6OZ606@i5FQj3d` z{fCf8SD%|$5s#z?WD%Nwa}z5R5Go+r0(%DC3?$Ej_mzPH7()%n z9LMC6%(BE1P||~iZE<25h?|?AlFEQ&PI_vILPlnKhJtfIr~)Y9Q;UmJiy2fcixpHY zEsH^hF)%O$XJ-}^fVAhA=fPB2DX11JXasn=fEbz#-kCW$AQezEK!QlJ*_k;x3c8jG zs>Milg9V}LAr>M0Uz}Qk9E2tL3Z@3C46b=4sYM`Lz*`6vz@CBZ6HG42Q7A4gE&y$e zL*yf9{zuC6pgnsa15k1#L$Ig2r(cLda$;$EMv0C>W_n&e*c#`Oq8wdkhS1{FB8B9f z%;fCU6a{~828ci+B#={6;2A9#62`uuFb3->DauSwPc2GKQ3wX@c~k()1ZU)zV>m&z zn8Dv0p0AM&!dYB^jf8}of`WpAmO?d%0%K6(O)ttX%}dcu&dCwT zmuF;_q(Ve%LBa}!y~a=7Gyt zqTb!ZQ0VEtDX(@#v zBEKk|AtkA_ST`jxH8($x!7sI>JijR0H!&|UJ++7-r979xCES;xI3*>QAw4CR0kV%Y zg~7w$*OdW1e}M!QQuE3(i}LewQ}ap`$`Xq*!JCww^GkD5KoyZfN@_`JQEp~lszOOd zssd!F59|qrg2a*x2FxNAJYWb`!2nLKsi3{S$>7`@pO#+~56&SBwhW*(LJS4P3c9KJ z3Z=!VMLGqUDLTpdxw$&3$pxhfy1K>rMJ2YnU`~xfdQobDf^M0sf_hw0etrpP!4fEB z5Mf+Ynx_ELotT#bDt&MjA10vkBL!T9D5$1^ihPhUh;js0QDQ4hQZy0jKt%*7uYd!k zw5SLade9O>5535N6*noG3?Oab;s&{@0SiJkGXxang91wdB$%3_P+Xb};-;165WMJsK z_y7L}Mh1rK_x}ICz{tRmfB*k~(D?-R5C8uMopYoA`2T+cCI*J!$N&F>&Rw|r`2YU` zCI$wJC;$IXU}9hhee(bR1||lEf+zp~UtnTjSoP%p{|`(I3~o>V{}*6pV32?Q|Gxn< z1B2#^|NjG+85owo`2W9znSsIl<^TUPm>C$Jz5M@w2Qvf1j#vNx-(Y5701d7FVP;_X z{O13E85RbHx9|S{cVJ;)`2YU@{{+y=MFs{2&;mYC#4uI`F)&sLFiP{Vb4*}l7XXQa z7S~za`u`ua2o9tMghApU8dW_5185-}Nd1g!|Nkd|R!Q;+xbaDN@pG4RG%(mpS!)@q zfQ?MVdJg;|MNjpsg8UCZA{L*paqmL`5F-8&j0`4 zKr~FA=_3z22Ll60{~QJehHH2J|Mx_ZcY(|A0WChe^Z)-06#2<;`8x~@4CQwramN5N zpZPQ+NCC)v&{(TFG)@unui^4Cj0_ClAN>Ch3JbV=JV-aheKw2?48I@z|KEgSe=S%6 z$ov>a28P&&|NkeW$j8CuYZw_A7Cij_AGF93Zhiz<8sdLO28Ov0|NjT2S-5-{LVgb@ ztv>w!A9UspT)q?`e}|EQVbjC^|3TphmuH#|RseF}A4UcSy+{B5-$afd<|_#QGchnc zfBgSH7m7S9SRS;{(uRqF;o_73|Lc(b=i1E7R06gFG!w*-z{J3y{q+BT@IpdZ9Dvlc zLDYcU(Za;QF#YNO|Lc*>VOj-N0FqzA#K55T?En8uDDr2)@*sB{VPaso@$CQq+sN+p zXl7kR>%af`ApQcV{h)>2ApQ!_3T*}k@Og0{KB$}p(V%r!Ai4so9<)#!#0M>K2GO8} z(I6Uzp~@IuK=;u@gMr}(TDc5bFb>iKS~v}&J3uSA86f-XLHrL;kHg$O0~)YUXEMO- z|NS50A6O9lgYp+Z_5X+Rq1qWfK=}$#`JYfeJlsK+4*-UpABS$W87O0e+FejO3`(a# z=`twY2BoJ#>19xQ8v($ApuHz>^pS^*F8Ka^I3(q>TF4N8YW=`<)^2Bp#C4V@1=mjhiKb}k3( z91hsI8?bXWVCQPU&e4FKn*lo~19mP3%v^V8XDbB_m(--p#5@Huy@fuG?3TDXApfy6(ciGvp2 zgT!IwC(Le8TZfTBiopST4hYD7Ah}R*87j&EE8jq3APj0lfy{xG#~?8f?f|P7fuE}a z5(DAo;PWjp{R>)Tgw0=|8CZ~e5}@t@ttSSVa~X#@xWeZt*ge7w7kogvQ86}qKZBJB z!Ovj?b3x@aBWS6*7z28_!4DRffS128^{R{v41x?&3?5MTLyKbua~$V-1>+FU#32r9 z!+|!{!0dz3U5wbz-2$zm7h>RNaE2bf0&Z_GFfgpZVg4?#I6uQZ(9RPE1_n_20ND}5 z3OXuOlHmaK`~r{|2%iP}R}gdrA7^XqRIY1eWfq? z_AiWwpp`)C5nMRS9*1}!Se&0BAG9Ngfq?INUloV>S-)bvVQigT?t7enHa@xDNvA&q2ixK*hm*7X}7~$6#@|b#TT{ z9O67U!Yzyyl73+41VgJi1~nY&EpdqZfW`S49)os7F)%QI`wbu(EDm=boKcEHd@&m+ z-g!Wo6|NS<=mo3iXP5@s;l;qf0Pce^Ffhz#fuuw9bM{t))q`}R;=MS;FW?Y=h(r7p z4)MP@#08<@Tn|nE(Co^f1QthiBZz0p3Mz*s8DQsg1%Lz@7#IRrA>|}`ITi~R$2^BH z35WTmIK(?}h|j?xz7~i0K^)>&afrWwx*t6rzu-{M3`!@^FhQo2afqAX5O)WQ^E0SJ z2l~KcBcSnqusE{G5OyjK@hY%5KZ7mw5FK!zmw|y{5?CCf7nxjuLwqF;@dIoaSpsa_ z9k6_|TqT=|((h7#;{M>?^)RNQ`Jp=42KxZmu#wQjPC053#=9Lsx zGNctH=BCD{l;-AEGQ`It@!~+1Ctq$r*rg@8Ilrcw_Ir_TByZX6+4hD^P_X~}8^?(X`xCAl8yF~gq`g%Gu#Jl_WJ30Eq`@6XXyN1Mv zI6C>b#zXB&O^JsMVuR1c#B~HF=ulD2V>XLRii%5$9AHN{g3f3}JsK5y=p*PPP0;jQ zd~!i4Vt^lV4kfDY)RK6ZuTzst@{1}N;ywN2i%U{6^Wsa3Q&Yf>L^|0Mbc!Yecoq@G z9LQO$umFZkrrDmp$LHv0EKxiJ}0xdgrTG;GdCVQ zF;!fUn4Aha*)tw}jsxr+NSG(*=V6|A8XuohoFAW&n3s~1%8*o=nS+Qfm}RNO5bF{_ zQ{C~&#l>JVk%9=tcm{BaWr&YQJ3 zNoE=7pw`@i#3G3QU?C2f0*9Q9ieeIEY6?XNl(e7+(-y;zW6jTlom~r`fXmN|&rYq3 z2hYLbI9L~ST4_Ngis|s9P$37J!sX1N2cNma{1$<~N?Cjf2@DaD5SrtS^0nNaH z4rfKti*lqZT*jCIw0I&OIb$=#$A|bjL-Q^8kXX2CkQ*Qev7!ip(iVyU$erMWUm<6> zV#q;rDk$55Ge|0E!Z{v1mlhA6ZH62ui=r2gG@y^To~qX>acPKF+&%m6+D7)2I#4ls%!XdW&eOGyWE4k*G9Cm(}q18`1- z+5k)LphJ-3@f-+UoLW*^06SG0Trhyv+<-C;VhIJo{x1^@T z=j4}zays;2YX-gI%G{E~BnCZDWP#}n7z?zzrKo^GFE76&RWCiSRIi{YzaX`!q!LL8 zTz=|ira*-poji3xO#`sG1GPIrV{fo=d|dayz)T0J zg|R_2Xt)nF)(_JUyMF{mgT@6x>R=c)-Vfu0&frDXkAD9NtiJ_Q4;$Bl@j>H6$ogU9 zm@pdMesule3=9n4{{PR1xgR!f0;8ebV)(oXy8A)HQlL2#n10y23XHx0oqz$k5fpYX z{jm9sOa{SSQVE-nhPe|) zgT_ffb1E=CY+eOM!}_o2?gyC(!k~>2pfH8$ht2E2XxO|C%zkwLPX~{$GB7xS3e9(9eC|*G3gTxe|`d~D8 zO#ny&ia`etftWBFG|r5yzX6mXK<61lX_$LKdO#S)htV6*+z%VifzfPe6L2tlL1uw4 z=tvJ_`(fj5Fd8(z4^juiptypuK{RM>0Z2bA{un?PUw|Z_v>(i&ATih^9Fz^BjzHZH z(~s*uA&^=SMzmm6hn;_Z0CZ6Y0|Nu-pe2w#7>4PG(SM=g57Q5umwf@%e*k1SOfypa!Su6% z=Mx}h5J(wpeCj|Th{wQC0HNR{G<(4LJdBXJX_)=6`5c2Fh!W6=Ef5xjMAt6}wI4cc z3sJ /dev/null; then + echo "$1 is not installed. Installing..." + sudo apt-get install -y "$1" + else + echo "$1 is already installed." + fi +} + +# Step 1: Finding the current working directory and script location +SCRIPT_DIR=$(pwd) +BASH_SCRIPT="$SCRIPT_DIR/battery_daemon.sh" +SRC_SCRIPT="$SCRIPT_DIR/battery_monitor" + +# Check if battery_daemon.sh exists +if [[ -f "$BASH_SCRIPT" ]]; then + echo "Found battery_daemon.sh. Moving to /usr/local/bin." + sudo cp "$BASH_SCRIPT" /usr/local/bin/battery_daemon.sh + sudo cp "$SRC_SCRIPT" /usr/local/bin/battery_monitor + sudo chmod +x /usr/local/bin/battery_monitor + sudo chmod +x /usr/local/bin/battery_daemon.sh +else + echo "battery_daemon.sh not found in the current directory!" + exit 1 +fi + +# Step 2: Check for dependencies and install if not present +dependencies=("gcc" "make" "brightnessctl") + +for dep in "${dependencies[@]}"; do + check_dependency "$dep" +done + +# Step 3: Copy battery_monitor.service to user systemd folder +SYSTEMD_SERVICE="$SCRIPT_DIR/battery_monitor.service" +USER_SYSTEMD_DIR="$HOME/.config/systemd/user" + +if [[ -f "$SYSTEMD_SERVICE" ]]; then + echo "Found battery_monitor.service." + + # Create the user systemd directory if it doesn't exist + if [[ ! -d "$USER_SYSTEMD_DIR" ]]; then + echo "Creating user systemd directory: $USER_SYSTEMD_DIR" + mkdir -p "$USER_SYSTEMD_DIR" + fi + + echo "Copying battery_monitor.service to $USER_SYSTEMD_DIR" + cp "$SYSTEMD_SERVICE" "$USER_SYSTEMD_DIR/" +else + echo "battery_monitor.service not found in the current directory!" + exit 1 +fi + +# Step 4: Reload the systemd daemon, enable and restart the service (user-level) +echo "Reloading systemd user daemon..." +systemctl --user daemon-reload + +echo "Enabling battery_monitor.service..." +systemctl --user enable battery_monitor.service + +echo "Restarting battery_monitor.service..." +systemctl --user restart battery_monitor.service + +# Check if the service was successfully started +if systemctl --user is-active --quiet battery_monitor.service; then + echo "Service started successfully!" +else + echo "Failed to start the service." + exit 1 +fi diff --git a/obj/battery_monitor.o b/obj/battery_monitor.o new file mode 100644 index 0000000000000000000000000000000000000000..b5992b1c73d7c7d3021c3381aadb2ec52756c848 GIT binary patch literal 2904 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 literal 0 HcmV?d00001 diff --git a/src/battery_monitor.c b/src/battery_monitor.c new file mode 100644 index 0000000..1e5fdc4 --- /dev/null +++ b/src/battery_monitor.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include "battery_monitor.h" + +// Define the battery thresholds +#define THRESHOLD_LOW 15 +#define THRESHOLD_CRITICAL 5 +#define THRESHOLD_HIGH 75 + +// Track if notifications have been sent +int notified_low = 0; +int notified_critical = 0; + +int main() { + log_message("Battery monitor started"); + + while (1) { + if (is_charging()) { + // Reset notifications if the battery is charging + log_message("Battery is charging, notifications reset"); + notified_low = 0; + notified_critical = 0; + sleep(300); // Sleep for 5 minutes while charging + continue; + } + + int battery_level = get_battery_level(); + if (battery_level == -1) { + log_message("Battery level read failed, retrying in 1 minute"); + sleep(60); + continue; + } + + // Dynamic sleep interval based on battery level + int sleep_duration = 60; // Default 1 minute + + if (battery_level > THRESHOLD_HIGH) { + sleep_duration = 300; // Sleep for 5 minutes + } else if (battery_level <= THRESHOLD_CRITICAL) { + sleep_duration = 30; // Sleep for 30 seconds when critically low + } else if (battery_level <= THRESHOLD_LOW) { + sleep_duration = 60; // Sleep for 1 minute when low + } + + // Check if the battery level is below the critical threshold + if (battery_level <= THRESHOLD_CRITICAL && !notified_critical) { + log_message("Battery critically low, showing notification"); + show_notification("Battery is critically low, below 5%", "Critical Battery Warning"); + notified_critical = 1; + } else if (battery_level <= THRESHOLD_LOW && !notified_low) { + log_message("Battery low, showing notification"); + show_notification("Battery is low, below 15%", "Low Battery Warning"); + notified_low = 1; + } + + // Reset notifications if battery level goes back up + if (battery_level > THRESHOLD_LOW) { + notified_low = 0; + } + if (battery_level > THRESHOLD_CRITICAL) { + notified_critical = 0; + } + + // Wait for the dynamically determined duration before checking again + sleep(sleep_duration); + } + + return 0; +} diff --git a/src/notification.c b/src/notification.c new file mode 100644 index 0000000..09af4b6 --- /dev/null +++ b/src/notification.c @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "battery_monitor.h" +#include "process_monitor.h" +#include "log_message.h" + +#define CSS_STYLE "\ + * { \ + background-color: #333333; \ + color: white; \ + } \ + button { \ + background-color: #555555; \ + color: white; \ + } \ +" + +// Function to get the battery level +int get_battery_level() { + const char *battery_paths[] = { + "/sys/class/power_supply/BAT0/capacity", + "/sys/class/power_supply/BAT1/capacity" + }; + FILE *file; + int battery_level = -1; + + for (int i = 0; i < sizeof(battery_paths) / sizeof(battery_paths[0]); i++) { + file = fopen(battery_paths[i], "r"); + if (file != NULL) { + break; + } + } + + if (file == NULL) { + perror("Failed to open capacity file"); + log_message("Failed to open capacity file"); + return -1; + } + + if (fscanf(file, "%d", &battery_level) != 1) { + perror("Failed to read battery level"); + log_message("Failed to read battery level"); + fclose(file); + return -1; + } + + fclose(file); + return battery_level; +} + +// Function to get the base directory of the executable +char *get_base_directory() { + static char base_dir[PATH_MAX]; + ssize_t count = readlink("/proc/self/exe", base_dir, PATH_MAX); + if (count != -1) { + dirname(base_dir); + } + return base_dir; +} + +// Function to log messages to a file +void log_message(const char *message) { + char log_file[PATH_MAX]; + snprintf(log_file, PATH_MAX, "/tmp/battery_monitor.log"); + + FILE *log_file_ptr = fopen(log_file, "a"); + if (log_file_ptr) { + fprintf(log_file_ptr, "%s\n", message); + fclose(log_file_ptr); + } else { + perror("Failed to open log file"); + } +} + +// Function to set the screen brightness +int set_brightness(int brightness) { + const char *brightness_path = "/sys/class/backlight/intel_backlight/brightness"; + const char *max_brightness_path = "/sys/class/backlight/intel_backlight/max_brightness"; + int max_brightness = 100; + int new_brightness = 0; + char buffer[10]; + + // Open max brightness file + int fd = open(max_brightness_path, O_RDONLY); + if (fd == -1) { + perror("Failed to open max brightness file"); + log_message("Failed to open max brightness file"); + return -1; + } + + // Read max brightness value + if (read(fd, buffer, sizeof(buffer)) != -1) { + max_brightness = atoi(buffer); + } else { + perror("Failed to read max brightness"); + log_message("Failed to read max brightness"); + close(fd); + return -1; + } + close(fd); + + // Calculate the new brightness + new_brightness = max_brightness * brightness / 100; + + // Write the new brightness value to the brightness file + fd = open(brightness_path, O_WRONLY); + if (fd == -1) { + perror("Failed to open brightness file"); + log_message("Failed to open brightness file"); + return -1; + } + + snprintf(buffer, sizeof(buffer), "%d", new_brightness); + if (write(fd, buffer, strlen(buffer)) == -1) { + perror("Failed to write to brightness file"); + log_message("Failed to write to brightness file"); + close(fd); + return -1; + } + + close(fd); + return 0; +} + +// Function to activate battery saving mode +int activate_battery_saving_mode() { + log_message("Activating battery saving mode"); + + // Get the current PID of the running program + pid_t current_pid = getpid(); + + // Call the get_high_cpu_processes from process_monitor.c to get the list of high CPU-consuming processes + char *process_list[100]; + int process_count = get_high_cpu_processes(process_list, 100); + + if (process_count == -1) { + log_message("Failed to get high CPU processes"); + return -1; + } + + // Loop through each high CPU process and kill it, excluding this program's own PID + for (int i = 0; i < process_count; i++) { + char command[300]; + char pid[10]; + char process_name[100]; + sscanf(process_list[i], "%9s %99s", pid, process_name); + + pid_t process_pid = atoi(pid); + + if (process_pid == current_pid) { + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Skipping own process: %s (PID: %s)", process_name, pid); + log_message(log_msg); + continue; + } + + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Killing process: %s (PID: %s)", process_name, pid); + log_message(log_msg); + + snprintf(command, sizeof(command), "kill -9 %s", pid); + if (system(command) == -1) { + log_message("Failed to kill process"); + free_process_list(process_list, process_count); + return -1; + } + } + + free_process_list(process_list, process_count); + + // Set the brightness to 50% for battery saving + if (set_brightness(50) == -1) { + log_message("Failed to set brightness to 50%"); + return -1; + } + + return 0; +} + +// Function to enter sleep mode +int enter_sleep_mode() { + log_message("Entering sleep mode"); + return system("systemctl suspend"); +} + +// Function to apply custom CSS styles to the GTK widgets +void apply_css(GtkWidget *widget, const char *css) { + GtkCssProvider *provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(provider, css, -1, NULL); + GtkStyleContext *context = gtk_widget_get_style_context(widget); + gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + g_object_unref(provider); +} + +// Function to check the battery status and close the dialog if charging +gboolean check_battery_status(gpointer user_data) { + GtkWidget *dialog = GTK_WIDGET(user_data); + if (is_charging()) { + log_message("Battery started charging, closing notification"); + gtk_widget_destroy(dialog); + gtk_main_quit(); + return FALSE; + } + return TRUE; +} + +// Signal handler for SIGINT +void handle_sigint(int sig) { + log_message("SIGINT caught, ignoring Ctrl-C"); +} + +// Function to set up signal handling +void setup_signal_handling() { + signal(SIGINT, handle_sigint); +} + +// Function to ignore Enter key and other keyboard inputs +gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { + if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_Escape) { + return TRUE; // Prevent default behavior for Enter and Escape keys + } + return FALSE; // Allow other keys if needed +} + +// Function to handle dialog response +void on_dialog_response(GtkDialog *dialog, gint response_id, gpointer user_data) { + switch (response_id) { + case GTK_RESPONSE_OK: + log_message("User clicked OK"); + break; + case GTK_RESPONSE_APPLY: + log_message("User activated Battery Saving Mode"); + activate_battery_saving_mode(); + break; + case GTK_RESPONSE_CLOSE: + log_message("User triggered Sleep Mode"); + enter_sleep_mode(); + break; + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); + gtk_main_quit(); +} + +// Function to show the notification dialog +void show_notification(const char *message, const char *title) { + log_message("Showing notification"); + + GtkWidget *dialog; + gtk_init(0, NULL); + + dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_NONE, + "%s", message); + gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_OK); + gtk_dialog_add_button(GTK_DIALOG(dialog), "Battery Saving Mode", GTK_RESPONSE_APPLY); + + if (g_strcmp0(title, "Critical Battery Warning") == 0) { + gtk_dialog_add_button(GTK_DIALOG(dialog), "Sleep", GTK_RESPONSE_CLOSE); + } + + gtk_window_set_title(GTK_WINDOW(dialog), title); + + // Apply CSS styles + apply_css(dialog, CSS_STYLE); + + // Set up the callback to check battery status and close if charging + g_timeout_add(1000, check_battery_status, dialog); + + // Connect the dialog response to handle button clicks and ensure proper cleanup + g_signal_connect(dialog, "response", G_CALLBACK(on_dialog_response), NULL); + + // Connect key-press-event signal to disable Enter key behavior + g_signal_connect(dialog, "key-press-event", G_CALLBACK(on_key_press), NULL); + + // Set up signal handling to trap SIGINT + setup_signal_handling(); + + // Show the dialog and enter the GTK main loop + gtk_widget_show_all(dialog); + gtk_main(); +} + +// Function to check if the battery is charging +int is_charging() { + const char *status_paths[] = { + "/sys/class/power_supply/BAT0/status", + "/sys/class/power_supply/BAT1/status" + }; + FILE *file; + char status[16]; + + for (int i = 0; i < sizeof(status_paths) / sizeof(status_paths[0]); i++) { + file = fopen(status_paths[i], "r"); + if (file != NULL) { + break; + } + } + + if (file == NULL) { + perror("Failed to open status file"); + log_message("Failed to open status file"); + return -1; + } + + if (fscanf(file, "%15s", status) != 1) { + perror("Failed to read battery status"); + log_message("Failed to read battery status"); + fclose(file); + return -1; + } + + fclose(file); + return (strcmp(status, "Charging") == 0); +} + diff --git a/src/notification.c.bak b/src/notification.c.bak new file mode 100644 index 0000000..58b0938 --- /dev/null +++ b/src/notification.c.bak @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include +#include +#include +#include "battery_monitor.h" +#include "process_monitor.h" +#include "log_message.h" + +#define CSS_STYLE "\ + * { \ + background-color: #333333; \ + color: white; \ + } \ + button { \ + background-color: #555555; \ + color: white; \ + } \ +" + +// Function to get the battery level +int get_battery_level() { + const char *battery_paths[] = { + "/sys/class/power_supply/BAT0/capacity", + "/sys/class/power_supply/BAT1/capacity" + }; + FILE *file; + int battery_level = -1; + + for (int i = 0; i < sizeof(battery_paths) / sizeof(battery_paths[0]); i++) { + file = fopen(battery_paths[i], "r"); + if (file != NULL) { + break; + } + } + + if (file == NULL) { + perror("Failed to open capacity file"); + log_message("Failed to open capacity file"); + return -1; + } + + if (fscanf(file, "%d", &battery_level) != 1) { + perror("Failed to read battery level"); + log_message("Failed to read battery level"); + fclose(file); + return -1; + } + + fclose(file); + return battery_level; +} + +// Function to get the base directory of the executable +char *get_base_directory() { + static char base_dir[PATH_MAX]; + ssize_t count = readlink("/proc/self/exe", base_dir, PATH_MAX); + if (count != -1) { + dirname(base_dir); + } + return base_dir; +} + +// Function to log messages to a file +void log_message(const char *message) { + char log_file[PATH_MAX]; + snprintf(log_file, PATH_MAX, "/tmp/battery_monitor.log"); + + FILE *log_file_ptr = fopen(log_file, "a"); + if (log_file_ptr) { + fprintf(log_file_ptr, "%s\n", message); + fclose(log_file_ptr); + } else { + perror("Failed to open log file"); + } +} + +// Function to set the screen brightness +int set_brightness(int brightness) { + const char *brightness_path = "/sys/class/backlight/intel_backlight/brightness"; + const char *max_brightness_path = "/sys/class/backlight/intel_backlight/max_brightness"; + int max_brightness = 100; + int new_brightness = 0; + char buffer[10]; + + // Open max brightness file + int fd = open(max_brightness_path, O_RDONLY); + if (fd == -1) { + perror("Failed to open max brightness file"); + log_message("Failed to open max brightness file"); + return -1; // Return failure if the file can't be opened + } + + // Read max brightness value + if (read(fd, buffer, sizeof(buffer)) != -1) { + max_brightness = atoi(buffer); + } else { + perror("Failed to read max brightness"); + log_message("Failed to read max brightness"); + close(fd); + return -1; // Return failure if the file can't be read + } + close(fd); + + // Calculate the new brightness + new_brightness = max_brightness * brightness / 100; + + // Write the new brightness value to the brightness file + fd = open(brightness_path, O_WRONLY); + if (fd == -1) { + perror("Failed to open brightness file"); + log_message("Failed to open brightness file"); + return -1; // Return failure if the file can't be opened + } + + snprintf(buffer, sizeof(buffer), "%d", new_brightness); + if (write(fd, buffer, strlen(buffer)) == -1) { + perror("Failed to write to brightness file"); + log_message("Failed to write to brightness file"); + close(fd); + return -1; // Return failure if the write fails + } + + close(fd); + return 0; // Success +} + +// Function to activate battery saving mode +int activate_battery_saving_mode() { + log_message("Activating battery saving mode"); + + // Get the current PID of the running program + pid_t current_pid = getpid(); + + // Call the get_high_cpu_processes from process_monitor.c to get the list of high CPU-consuming processes + char *process_list[100]; // Assuming a maximum of 100 processes to handle + int process_count = get_high_cpu_processes(process_list, 100); + + if (process_count == -1) { + log_message("Failed to get high CPU processes"); + return -1; // Return failure if processes couldn't be killed + } + + // Loop through each high CPU process and kill it, excluding this program's own PID + for (int i = 0; i < process_count; i++) { + char command[300]; + + // Extract the PID and process name from process_list[i] + char pid[10]; + char process_name[100]; + sscanf(process_list[i], "%9s %99s", pid, process_name); // Assuming the format "PID ProcessName" in process_list + + // Convert the PID string to a number for comparison + pid_t process_pid = atoi(pid); + + // Check if the process PID matches the current program's PID, if so, skip it + if (process_pid == current_pid) { + char log_msg[200]; // Declare log_msg correctly + snprintf(log_msg, sizeof(log_msg), "Skipping own process: %s (PID: %s)", process_name, pid); + log_message(log_msg); + continue; // Skip killing the current program's own process + } + + // Log the process name and PID before killing the process + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Killing process: %s (PID: %s)", process_name, pid); + log_message(log_msg); + + // Kill the process by PID + snprintf(command, sizeof(command), "kill -9 %s", pid); + if (system(command) == -1) { + log_message("Failed to kill process"); + free_process_list(process_list, process_count); + return -1; // Return failure if the command fails + } + } + + // Free the dynamically allocated process list + free_process_list(process_list, process_count); + + // Set the brightness to 50% for battery saving + if (set_brightness(50) == -1) { + log_message("Failed to set brightness to 50%"); + return -1; // Return failure if brightness couldn't be set + } + + return 0; // Success +} + +// Function to enter sleep mode +int enter_sleep_mode() { + log_message("Entering sleep mode"); + return system("systemctl suspend"); // Return system command result +} + +// Function to apply custom CSS styles to the GTK widgets +void apply_css(GtkWidget *widget, const char *css) { + GtkCssProvider *provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(provider, css, -1, NULL); + GtkStyleContext *context = gtk_widget_get_style_context(widget); + gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + g_object_unref(provider); +} + +// Function to check the battery status and close the dialog if charging +gboolean check_battery_status(gpointer user_data) { + GtkWidget *dialog = GTK_WIDGET(user_data); + if (is_charging()) { + log_message("Battery started charging, closing notification"); + gtk_widget_destroy(dialog); + gtk_main_quit(); // Exit the GTK main loop + return FALSE; // Stop checking + } + return TRUE; // Continue checking +} + +// Function to handle dialog response +void on_dialog_response(GtkDialog *dialog, gint response_id, gpointer user_data) { + switch (response_id) { + case GTK_RESPONSE_OK: + log_message("User clicked OK"); + break; + case GTK_RESPONSE_APPLY: + log_message("User activated Battery Saving Mode"); + activate_battery_saving_mode(); + break; + case GTK_RESPONSE_CLOSE: + log_message("User triggered Sleep Mode"); + enter_sleep_mode(); + break; + default: + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); + gtk_main_quit(); // Exit the GTK main loop +} + +// Function to show the notification dialog +void show_notification(const char *message, const char *title) { + log_message("Showing notification"); + + GtkWidget *dialog; + gtk_init(0, NULL); + + dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_NONE, + "%s", message); + gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_OK); + gtk_dialog_add_button(GTK_DIALOG(dialog), "Battery Saving Mode", GTK_RESPONSE_APPLY); + + if (g_strcmp0(title, "Critical Battery Warning") == 0) { + gtk_dialog_add_button(GTK_DIALOG(dialog), "Sleep", GTK_RESPONSE_CLOSE); + } + + gtk_window_set_title(GTK_WINDOW(dialog), title); + + // Apply CSS styles + apply_css(dialog, CSS_STYLE); + + // Set up the callback to check battery status and close if charging + g_timeout_add(1000, check_battery_status, dialog); + + // Connect the dialog response to handle button clicks and ensure proper cleanup + g_signal_connect(dialog, "response", G_CALLBACK(on_dialog_response), NULL); + + // Show the dialog and enter the GTK main loop + gtk_widget_show_all(dialog); + gtk_main(); // Start the GTK main loop +} + +// Function to check if the battery is charging +int is_charging() { + const char *status_paths[] = { + "/sys/class/power_supply/BAT0/status", + "/sys/class/power_supply/BAT1/status" + }; + FILE *file; + char status[16]; + + for (int i = 0; i < sizeof(status_paths) / sizeof(status_paths[0]); i++) { + file = fopen(status_paths[i], "r"); + if (file != NULL) { + break; + } + } + + if (file == NULL) { + perror("Failed to open status file"); + log_message("Failed to open status file"); + return -1; + } + + if (fscanf(file, "%15s", status) != 1) { + perror("Failed to read battery status"); + log_message("Failed to read battery status"); + fclose(file); + return -1; + } + + fclose(file); + return (strcmp(status, "Charging") == 0); +} + diff --git a/src/process_monitor.c b/src/process_monitor.c new file mode 100644 index 0000000..3c168ae --- /dev/null +++ b/src/process_monitor.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include "log_message.h" + +#define BUFFER_SIZE 1024 +#define CONFIG_FILE "/.config/battery_monitor/config.config" +#define MAX_CRITICAL_PROCESSES 100 +#define MAX_IGNORE_PROCESSES 100 + +// List of default critical processes (expanded with more essential processes) +const char *default_critical_processes[] = {"systemd", "Xorg", "dbus-daemon", "NetworkManager", "dwm", "DWM", "sddm", "gdm", "fprintd", NULL}; + +// Function to perform case-insensitive string comparison +int case_insensitive_compare(const char *a, const char *b) { + while (*a && *b) { + if (tolower((unsigned char)*a) != tolower((unsigned char)*b)) { + return 0; + } + a++; + b++; + } + return *a == *b; +} + +// Function to dynamically build the list of critical processes +void build_critical_processes_list(char *critical_list[], int *count) { + int index = 0; + + // Add default critical processes + for (int i = 0; default_critical_processes[i] != NULL; i++) { + critical_list[index++] = strdup(default_critical_processes[i]); + } + + *count = index; +} + +// Helper function to remove leading/trailing whitespace +char *trim_whitespace(char *str) { + char *end; + + // Trim leading space + while (isspace((unsigned char)*str)) str++; + + if (*str == 0) return str; // All spaces? + + // Trim trailing space + end = str + strlen(str) - 1; + while (end > str && isspace((unsigned char)*end)) end--; + + // Write new null terminator character + end[1] = '\0'; + + return str; +} + +// Function to dynamically get the user's home directory and build the config file path +char *get_config_file_path() { + const char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + log_message("Failed to get HOME environment variable"); + return NULL; + } + + char *config_file_path = malloc(strlen(home_dir) + strlen(CONFIG_FILE) + 1); + if (config_file_path != NULL) { + strcpy(config_file_path, home_dir); + strcat(config_file_path, CONFIG_FILE); + } + + return config_file_path; +} + +// Function to parse the ignore list from the config file +int get_ignore_processes(char *ignore_list[], int max_ignores) { + char *config_file_path = get_config_file_path(); + if (config_file_path == NULL) { + log_message("Could not determine the config file path"); + return -1; + } + + FILE *config_file = fopen(config_file_path, "r"); + free(config_file_path); + + if (config_file == NULL) { + log_message("Failed to open config file"); + return -1; + } + + char buffer[BUFFER_SIZE]; + int ignore_count = 0; + + while (fgets(buffer, sizeof(buffer), config_file) != NULL) { + if (strstr(buffer, "ignore_processes_for_sleep") != NULL) { + char *token = strtok(buffer, "="); + token = strtok(NULL, "="); // Get the processes list after '=' + + if (token != NULL) { + token = strtok(token, ","); + while (token != NULL && ignore_count < max_ignores) { + ignore_list[ignore_count] = strdup(trim_whitespace(token)); + ignore_count++; + token = strtok(NULL, ","); + } + } + } + } + + fclose(config_file); + + // Add default critical processes like dwm and Xorg if not already included + build_critical_processes_list(ignore_list, &ignore_count); + + return ignore_count; +} + +// Function to check if a process is critical (case-insensitive check) +int is_process_critical(const char *process_name, char *ignore_list[], int ignore_count) { + for (int i = 0; i < ignore_count; i++) { + if (case_insensitive_compare(process_name, ignore_list[i])) { + return 1; // Process is critical + } + } + return 0; +} + +// Get the list of high CPU processes excluding ignored and root processes +int get_high_cpu_processes(char *process_list[], int max_processes) { + FILE *fp; + char buffer[BUFFER_SIZE]; + int process_count = 0; + + // Command to get top CPU-consuming processes excluding root processes + const char *command = "ps -eo user,pid,comm,%cpu --sort=-%cpu | grep -vE '^root'"; + + fp = popen(command, "r"); + if (fp == NULL) { + log_message("Failed to run command to get high CPU processes"); + return -1; + } + + // Load ignore processes from config file + char *ignore_list[100]; + int ignore_count = get_ignore_processes(ignore_list, 100); + + // Parse each line from the process list + while (fgets(buffer, sizeof(buffer), fp) != NULL && process_count < max_processes) { + char user[50], command_name[100]; + int pid; + float cpu_usage; + + if (sscanf(buffer, "%49s %d %99s %f", user, &pid, command_name, &cpu_usage) == 4) { + if (!is_process_critical(command_name, ignore_list, ignore_count)) { + // Allocate memory for the process info and store the PID + process_list[process_count] = malloc(BUFFER_SIZE); + snprintf(process_list[process_count], BUFFER_SIZE, "%d", pid); // Only storing the PID + process_count++; + } else { + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Skipping critical process: %s (PID: %d)", command_name, pid); + log_message(log_msg); // Log critical processes skipped + } + } + } + + // Free ignore list + for (int i = 0; i < ignore_count; i++) { + free(ignore_list[i]); + } + + pclose(fp); + return process_count; +} + +// Function to handle killing high CPU processes +void kill_high_cpu_processes(char *process_list[], int process_count, pid_t current_pid) { + for (int i = 0; i < process_count; i++) { + pid_t process_pid = atoi(process_list[i]); + + if (process_pid == current_pid) { + log_message("Skipping killing the current process."); + continue; + } + + // Log the process PID before killing + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Killing process (PID: %d)", process_pid); + log_message(log_msg); + + // Kill the process by PID + char command[50]; + snprintf(command, sizeof(command), "kill -9 %d", process_pid); + if (system(command) == -1) { + log_message("Failed to kill process"); + } else { + log_message("Process killed successfully"); + } + } +} + +// Free the process list +void free_process_list(char *process_list[], int count) { + for (int i = 0; i < count; i++) { + free(process_list[i]); + } +} diff --git a/src/process_monitor.c.bak b/src/process_monitor.c.bak new file mode 100644 index 0000000..404e7fb --- /dev/null +++ b/src/process_monitor.c.bak @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include "log_message.h" + +#define BUFFER_SIZE 1024 +#define CONFIG_FILE "/.config/battery_monitor/config.config" +#define MAX_CRITICAL_PROCESSES 100 +#define MAX_IGNORE_PROCESSES 100 + +// List of default critical processes +const char *default_critical_processes[] = {"systemd", "Xorg", "dbus-daemon", "NetworkManager", NULL}; + +// Helper function to remove leading/trailing whitespace +char *trim_whitespace(char *str) { + char *end; + + // Trim leading space + while (isspace((unsigned char)*str)) str++; + + if (*str == 0) return str; // All spaces? + + // Trim trailing space + end = str + strlen(str) - 1; + while (end > str && isspace((unsigned char)*end)) end--; + + // Write new null terminator character + end[1] = '\0'; + + return str; +} + +// Function to dynamically get the user's home directory and build the config file path +char *get_config_file_path() { + const char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + log_message("Failed to get HOME environment variable"); + return NULL; + } + + char *config_file_path = malloc(strlen(home_dir) + strlen(CONFIG_FILE) + 1); + if (config_file_path != NULL) { + strcpy(config_file_path, home_dir); + strcat(config_file_path, CONFIG_FILE); + } + + return config_file_path; +} + +// Function to parse the ignore list from the config file +int get_ignore_processes(char *ignore_list[], int max_ignores) { + char *config_file_path = get_config_file_path(); + if (config_file_path == NULL) { + log_message("Could not determine the config file path"); + return -1; + } + + FILE *config_file = fopen(config_file_path, "r"); + free(config_file_path); + + if (config_file == NULL) { + log_message("Failed to open config file"); + return -1; + } + + char buffer[BUFFER_SIZE]; + int ignore_count = 0; + + while (fgets(buffer, sizeof(buffer), config_file) != NULL) { + if (strstr(buffer, "ignore_processes_for_sleep") != NULL) { + char *token = strtok(buffer, "="); + token = strtok(NULL, "="); // Get the processes list after '=' + + if (token != NULL) { + token = strtok(token, ","); + while (token != NULL && ignore_count < max_ignores) { + ignore_list[ignore_count] = strdup(trim_whitespace(token)); + ignore_count++; + token = strtok(NULL, ","); + } + } + } + } + + fclose(config_file); + return ignore_count; +} + +// Function to check if a process is critical +int is_process_critical(const char *process_name, char *ignore_list[], int ignore_count) { + for (int i = 0; i < ignore_count; i++) { + if (strcmp(process_name, ignore_list[i]) == 0) { + return 1; // Process is critical + } + } + return 0; +} + +// Get the list of high CPU processes excluding ignored and root processes +int get_high_cpu_processes(char *process_list[], int max_processes) { + FILE *fp; + char buffer[BUFFER_SIZE]; + int process_count = 0; + + // Command to get top CPU-consuming processes excluding root processes + const char *command = "ps -eo user,pid,comm,%cpu --sort=-%cpu | grep -vE '^root'"; + + fp = popen(command, "r"); + if (fp == NULL) { + log_message("Failed to run command to get high CPU processes"); + return -1; + } + + // Load ignore processes from config file + char *ignore_list[100]; + int ignore_count = get_ignore_processes(ignore_list, 100); + + // Parse each line from the process list + while (fgets(buffer, sizeof(buffer), fp) != NULL && process_count < max_processes) { + char user[50], command_name[100]; + int pid; + float cpu_usage; + + if (sscanf(buffer, "%49s %d %99s %f", user, &pid, command_name, &cpu_usage) == 4) { + if (!is_process_critical(command_name, ignore_list, ignore_count)) { + // Allocate memory for the process info and store the PID + process_list[process_count] = malloc(BUFFER_SIZE); + snprintf(process_list[process_count], BUFFER_SIZE, "%d", pid); // Only storing the PID + process_count++; + } + } + } + + // Free ignore list + for (int i = 0; i < ignore_count; i++) { + free(ignore_list[i]); + } + + pclose(fp); + return process_count; +} + +// Function to handle killing high CPU processes +void kill_high_cpu_processes(char *process_list[], int process_count, pid_t current_pid) { + for (int i = 0; i < process_count; i++) { + pid_t process_pid = atoi(process_list[i]); + + if (process_pid == current_pid) { + log_message("Skipping killing the current process."); + continue; + } + + // Log the process PID before killing + char log_msg[200]; + snprintf(log_msg, sizeof(log_msg), "Killing process (PID: %d)", process_pid); + log_message(log_msg); + + // Kill the process by PID + char command[50]; + snprintf(command, sizeof(command), "kill -9 %d", process_pid); + if (system(command) == -1) { + log_message("Failed to kill process"); + } else { + log_message("Process killed successfully"); + } + } +} + +// Free the process list +void free_process_list(char *process_list[], int count) { + for (int i = 0; i < count; i++) { + free(process_list[i]); + } +}