· 6 years ago · Apr 25, 2019, 12:20 PM
1/*
2ThinkPad fan control
3Copyright 2008, Stanko Tadić <stanko@mfhinc.net>
4
5ThinkPad fan control is free software; you can redistribute it
6and/or modify it under the terms of the GNU General Public License
7version 2 as published by the Free Software Foundation.
8Note that I am not granting permission to redistribute or
9modify ThinkPad fan control under the terms of any later version of the
10General Public License.
11
12ThinkPad fan control is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program (in the file "LICENCE"); if not, write to the
19Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20MA 02111, USA.
21*/
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <gtk/gtk.h>
28
29#define AUTO 10
30#define FORCED 100
31#define FULL_SPEED 8
32
33
34/* location of UI XML file relative to path in which program is running */
35#define BUILDER_XML_FILE "data/gtk_gui.xml"
36
37// global GTK widgets
38GtkSpinButton *sleepField, *criticalField, *safeField;
39GtkComboBox *autoSpeed, *speedValue;
40GtkStatusbar *statusbar;
41GtkLabel *level, *txtLog, *optionsLabel;
42GtkWidget *window;
43GtkButton *run, *exitButton, *hide, *speedButton;
44GtkStatusIcon *tray_icon;
45
46// global variables
47int visible = 1, running = 1, errorTemp=0, manual=0;
48int fansLevel = AUTO;
49int sleepTime = 120, criticalTemp = 55, safeTemp = 50, autoSpeedValue = 7;
50gint timeout;
51
52/****** FUNCTIONS *******/
53// when program is closed, turns fans to auto and write that in terminal
54void on_window_destroy ();
55// main function for controlling fans
56int fans();
57//changes speed to value 'speed'
58void change_speed(int speed);
59// when run button is clicked
60void run_clicked();
61// changes fans speed when user want that
62void manual_change ();
63// hides window when tray icon is clicked
64void hide_window(GtkStatusIcon *status_icon, gpointer user_data);
65// popup menu, right button on tray icon
66void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data);
67// creates tray icon
68static GtkStatusIcon *create_tray_icon();
69
70//------------------------------------ MAIN ---------------------------------------------//
71int main (int argc, char *argv[]){
72
73 GtkBuilder *builder;
74
75 gtk_init (&argc, &argv);
76
77 builder = gtk_builder_new ();
78 gtk_builder_add_from_file (builder, BUILDER_XML_FILE, NULL);
79
80 // making tray icon
81 tray_icon = create_tray_icon();
82
83 // getting all the widgets
84 window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
85 run = GTK_BUTTON (gtk_builder_get_object (builder, "run"));
86 exitButton = GTK_BUTTON (gtk_builder_get_object (builder, "exit"));
87 speedButton = GTK_BUTTON (gtk_builder_get_object (builder, "speedButton"));
88 hide = GTK_BUTTON (gtk_builder_get_object (builder, "hide"));
89 sleepField = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "sleep"));
90 criticalField = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "critical"));
91 safeField = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "safe"));
92 txtLog = GTK_LABEL (gtk_builder_get_object (builder, "log"));
93 optionsLabel = GTK_LABEL (gtk_builder_get_object (builder, "optionsLabel"));
94 statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar"));
95 level = GTK_LABEL (gtk_builder_get_object (builder, "level"));
96 speedValue = GTK_COMBO_BOX (gtk_builder_get_object (builder, "speed"));
97 autoSpeed = GTK_COMBO_BOX (gtk_builder_get_object (builder, "autoSpeed"));
98
99 // combo boxes default values
100 gtk_combo_box_set_active(autoSpeed,7);
101 gtk_combo_box_set_active(speedValue,0);
102
103 // callbacks
104 // when clicked on run button
105 g_signal_connect(G_OBJECT(run), "clicked", G_CALLBACK(run_clicked), NULL);
106 // when clicked on exit button
107 g_signal_connect(G_OBJECT(exitButton), "clicked", G_CALLBACK(on_window_destroy), NULL);
108 // when clicked on to tray button
109 g_signal_connect(G_OBJECT(hide), "clicked", G_CALLBACK(hide_window), NULL);
110 // when clicked on manual change button
111 g_signal_connect(G_OBJECT(speedButton), "clicked", G_CALLBACK(manual_change), NULL);
112 // on window destroy
113 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(on_window_destroy), NULL);
114
115 gtk_builder_connect_signals (builder, NULL);
116 g_object_unref (G_OBJECT (builder));
117
118 gtk_widget_show (window);
119
120 // welcome terminal message, and changing fans control to auto at startup
121 system("echo level auto > /proc/acpi/ibm/fan");
122 printf("** Welcome! **\n");
123 printf("** ThinkPad fan control by Stanko! **\n");
124 printf("** Fan control changed to auto **\n");
125
126
127 // starting fans function with default values (global variables)
128 fans();
129 // setting sleep time (timeout) for fans function, also default value (global)
130 timeout = g_timeout_add_seconds(sleepTime,fans,NULL);
131
132 gtk_main ();
133
134 return 0;
135}
136
137//-------------------------------------- FANS ---------------------------------------------//
138int fans(){
139 // tepmerature of CPU
140 int temp;
141 // file pointer on file in which is CPU temperature, and second for popen for getting time from terminal
142 FILE *tempInput, *sysIn;
143 // status and other messages
144 char message[80];
145 char tempMessage[120];
146 char tmpString[45];
147 char speedString[15];
148
149 // wrong options
150 if(safeTemp >= criticalTemp){
151 gtk_label_set_text(txtLog,"CRITICAL TEMPERATURE MUST BE GREATER THAN SAFE TEMPERATURE!");
152 errorTemp=1;
153 gtk_button_set_label(run,"Run auto control");
154 running = 0;
155 return FALSE;
156 }
157
158 // if manual control was active, change fan control back to auto
159 if(manual){
160 change_speed(0);
161 fansLevel = AUTO;
162 manual=0;
163 }
164
165 // reading the CPU temperature
166 tempInput = fopen("/proc/acpi/ibm/thermal","r");
167 if(tempInput ==NULL){
168 gtk_label_set_text(txtLog,"YOU ARE NOT RUNNING KERNEL WITH THINKPAD PATCH!");
169 return FALSE;
170 }
171 fscanf(tempInput,"temperatures: %d",&temp);
172 fclose(tempInput);
173
174 // getting time
175 sysIn = popen("date '+%H:%M:%S'","r");
176 fgets(tmpString,9,sysIn);
177 pclose(sysIn);
178 // writing CPU temperature, and time when it's checked
179 sprintf(message,"Temperature: %dC, Checked at %s",temp,tmpString);
180 gtk_statusbar_push(statusbar,0,message);
181
182 // if critical temperature is reached. and fans level is auto
183 if(temp>=criticalTemp && fansLevel==AUTO){
184 switch(autoSpeedValue){
185 case 0: strcpy(speedString,"auto"); break;
186 case 8: strcpy(speedString,"full-speed"); break;
187 default: sprintf(speedString,"%d",autoSpeedValue);
188 }
189 // changing fans level to one user choosed
190 change_speed(autoSpeedValue);
191 fansLevel = FORCED;
192 // putting log message
193 sprintf(tempMessage,"\n%s\nTemperature is %d, critical is %d\nTurning fans to %s!",tmpString, temp, criticalTemp, speedString);
194 gtk_label_set_text(txtLog,tempMessage);
195 }
196 // if safe temperature is reached and fans level are forced by user
197 else if(temp<=safeTemp){
198// else if(temp<=safeTemp && fansLevel==FORCED){
199 // changing fans level to auto
200 change_speed(0);
201 fansLevel = AUTO;
202 // putting log message
203 sprintf(tempMessage,"\n%s\nTemperature is %d, safe is %d\nTurning fans to auto!",tmpString,temp,safeTemp);
204 gtk_label_set_text(txtLog,tempMessage);
205 }
206 else if(errorTemp){
207 gtk_label_set_text(txtLog,"");
208 errorTemp=0;
209 }
210 return TRUE;
211}
212
213//------------------------------------ RUN ---------------------------------------------//
214void run_clicked(){
215 char tmpString[100];
216 char speedString[15];
217 // getparameters
218 criticalTemp = gtk_spin_button_get_value_as_int (criticalField);
219 safeTemp = gtk_spin_button_get_value_as_int (safeField);
220 autoSpeedValue = gtk_combo_box_get_active (autoSpeed);
221 sleepTime = gtk_spin_button_get_value_as_int (sleepField);
222 fans();
223 if(running == 1){
224 gtk_timeout_remove(timeout);
225 if(fansLevel==FORCED)
226 change_speed(autoSpeedValue);
227 timeout = g_timeout_add_seconds(sleepTime,fans,NULL);
228 }
229 else{
230 timeout = g_timeout_add_seconds(sleepTime,fans,NULL);
231 running = 1;
232 }
233
234 if(!errorTemp){
235 switch(autoSpeedValue){
236 case 0: strcpy(speedString,"auto"); break;
237 case 8: strcpy(speedString,"full-speed"); break;
238 default: sprintf(speedString,"%d",autoSpeedValue);
239 }
240 gtk_button_set_label(run,"Change options");
241 sprintf(tmpString,"Current options: %d, %d, %d, %s",sleepTime,criticalTemp,safeTemp,speedString);
242 gtk_label_set_text(optionsLabel,tmpString);
243 }
244}
245
246//------------------------------------ EXIT ---------------------------------------------//
247void on_window_destroy (){
248 system("echo level auto > /proc/acpi/ibm/fan");
249 printf("** Fan control changed to auto **\n");
250 printf("** Goodbye! **\n");
251 gtk_main_quit();
252}
253
254//------------------------------------ TRAY ---------------------------------------------//
255void hide_window(GtkStatusIcon *status_icon, gpointer user_data){
256 if(visible){
257 gtk_widget_hide(window);
258 visible=0;
259 }
260 else{
261 gtk_widget_show(window);
262 visible=1;
263 }
264}
265
266void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data){
267 printf("Popup menu\n");
268}
269
270//------------------------------------ STATUS ICON ---------------------------------------------//
271static GtkStatusIcon *create_tray_icon() {
272 GtkStatusIcon *tray_icon;
273
274 tray_icon = gtk_status_icon_new();
275 g_signal_connect(G_OBJECT(tray_icon), "activate", G_CALLBACK(hide_window), NULL);
276 g_signal_connect(G_OBJECT(tray_icon), "popup-menu",G_CALLBACK(tray_icon_on_menu), NULL);
277 gtk_status_icon_set_from_file(tray_icon, "data/icon.png");
278 gtk_status_icon_set_tooltip(tray_icon, "ThinkPad Fan Control .:: level - auto ::.");
279 gtk_status_icon_set_visible(tray_icon, TRUE);
280
281 return tray_icon;
282}
283//------------------------------------ MANUAL CHANGE ---------------------------------------------//
284void manual_change (){
285 int speed = gtk_combo_box_get_active (speedValue);
286
287 if(running){
288 gtk_button_set_label(run,"Run auto control");
289 gtk_timeout_remove(timeout);
290 running = 0;
291 }
292
293 change_speed(speed);
294 manual = 1;
295 gtk_label_set_text(txtLog,"");
296 gtk_statusbar_push(statusbar,0,"Manual control is active!");
297}
298
299//------------------------------------ CHANGE SPEED ---------------------------------------------//
300void change_speed(int speed){
301 char tmpString[60];
302 char speedString[15];
303
304 switch(speed){
305 case 0: strcpy(speedString,"auto"); break;
306 case 8: strcpy(speedString,"full-speed"); break;
307 default: sprintf(speedString,"%d",speed);
308 }
309 sprintf(tmpString,"echo level %s > /proc/acpi/ibm/fan",speedString);
310 system(tmpString);
311 sprintf(tmpString,"Fans level - %s",speedString);
312 gtk_label_set_text(level,tmpString);
313
314 sprintf(tmpString,"ThinkPad Fan Control .:: level - %s ::.",speedString);
315 gtk_status_icon_set_tooltip(tray_icon, tmpString);
316
317 printf("** Speed level changed to %s **\n",speedString);
318}