@@ -2,141 +2,216 @@ const Desklet = imports.ui.desklet;
22const St = imports . gi . St ;
33const GLib = imports . gi . GLib ;
44const Util = imports . misc . util ;
5- const Cinnamon = imports . gi . Cinnamon ;
65const Lang = imports . lang ;
76const Mainloop = imports . mainloop ;
8- const Main = imports . ui . main ;
97const Clutter = imports . gi . Clutter ;
10- const GdkPixbuf = imports . gi . GdkPixbuf ;
11- const Cogl = imports . gi . Cogl ;
12- const Gio = imports . gi . Gio ;
13-
14- const DESKLET_ROOT = imports . ui . deskletManager . deskletMeta [ "temperature@india" ] . path ;
8+ const Cairo = imports . gi . cairo ;
9+ const Settings = imports . ui . settings ;
1510
11+ const UUID = "temperature@india" ;
1612
1713function MyDesklet ( metadata , desklet_id ) {
18- this . _init ( metadata , desklet_id ) ;
19- }
20-
21- function main ( metadata , desklet_id ) {
22- return new MyDesklet ( metadata , desklet_id ) ;
23- }
24-
25- function getImageAtScale ( imageFileName , width , height , width2 = 0 , height2 = 0 ) {
26- if ( width2 == 0 || height2 == 0 ) {
27- width2 = width ;
28- height2 = height ;
29- }
30-
31- let pixBuf = GdkPixbuf . Pixbuf . new_from_file_at_size ( imageFileName , width , height ) ;
32- let image = new Clutter . Image ( ) ;
33- image . set_data (
34- pixBuf . get_pixels ( ) ,
35- pixBuf . get_has_alpha ( ) ? Cogl . PixelFormat . RGBA_8888 : Cogl . PixelFormat . RGBA_888 ,
36- width , height ,
37- pixBuf . get_rowstride ( )
38- ) ;
39-
40- let actor = new Clutter . Actor ( { width : width2 , height : height2 } ) ;
41- actor . set_content ( image ) ;
42-
43- return actor ;
14+ this . _init ( metadata , desklet_id ) ;
4415}
4516
46-
47- const Thermal = function ( ) {
48- this . _init . apply ( this , arguments ) ;
49- } ;
50-
51- Thermal . prototype = {
52- _init : function ( sensorFile ) {
53- this . file = sensorFile ;
54- this . degrees = 0 ;
55- this . info = "N/A" ;
56-
57- } ,
58-
59- refresh : function ( ) {
60- if ( GLib . file_test ( this . file , 1 << 4 ) ) {
61- let t_str = Cinnamon . get_file_contents_utf8_sync ( this . file ) . split ( "\n" ) [ 0 ] ;
62- this . degrees = parseInt ( t_str ) / 1000 ;
63- this . info = this . degrees + "°C" ;
17+ MyDesklet . prototype = {
18+ __proto__ : Desklet . Desklet . prototype ,
19+
20+ _init : function ( metadata , desklet_id ) {
21+ Desklet . Desklet . prototype . _init . call ( this , metadata ) ;
22+
23+ this . settings = new Settings . DeskletSettings ( this , this . metadata [ "uuid" ] , desklet_id ) ;
24+ this . settings . bindProperty ( Settings . BindingDirection . IN , "text-color" , "text_color" , this . on_setting_changed , null ) ;
25+ this . settings . bindProperty ( Settings . BindingDirection . IN , "text-size" , "text_size" , this . on_setting_changed , null ) ;
26+ this . settings . bindProperty ( Settings . BindingDirection . IN , "scale-size" , "scale_size" , this . on_setting_changed , null ) ;
27+ this . settings . bindProperty ( Settings . BindingDirection . IN , "update-interval" , "update_interval" , this . on_setting_changed , null ) ;
28+
29+ this . sensorsData = [ ] ;
30+ this . sensorsPath = '/usr/bin/sensors' ;
31+
32+ let desklet_path = GLib . get_user_data_dir ( ) + "/cinnamon/desklets/" + this . metadata [ "uuid" ] ;
33+ this . img_path = desklet_path + "/img/thermometer.svg" ;
34+ this . mercury_img_path = desklet_path + "/img/mercury.svg" ;
35+
36+ this . mainContainer = new St . Widget ( {
37+ style : `background-image: url('${ this . img_path } ');
38+ background-size: 50px 500px;
39+ background-repeat: no-repeat;
40+ background-position: 0px 0px;
41+ background-color: transparent;` ,
42+ layout_manager : new Clutter . BinLayout ( )
43+ } ) ;
44+
45+ // Create the Mercury Widget
46+ this . mercuryWidget = new St . Widget ( {
47+ style : `background-image: url('${ this . mercury_img_path } ');
48+ background-size: 3px 500px;
49+ background-position: 0px 0px;
50+ background-repeat: no-repeat;`
51+ } ) ;
52+
53+ this . setContent ( this . mainContainer ) ;
54+
55+ Util . spawn_async ( [ 'which' , 'sensors' ] , ( ret ) => {
56+ if ( ret && ret . toString ( ) . trim ( ) !== "" ) {
57+ this . sensorsPath = ret . toString ( ) . split ( '\n' , 1 ) [ 0 ] . trim ( ) ;
58+ this . updateTemperature ( ) ;
59+ }
60+ } ) ;
61+ } ,
62+
63+ on_setting_changed : function ( ) {
64+ this . updateTemperature ( ) ;
65+ } ,
66+
67+ updateTemperature : function ( ) {
68+ if ( this . sensorsPath ) {
69+ Util . spawn_async ( [ this . sensorsPath ] , ( output ) => {
70+ if ( output ) {
71+ this . _parseAllSensors ( output . toString ( ) ) ;
72+ }
73+ } ) ;
74+ }
75+
76+ if ( this . timeoutId ) Mainloop . source_remove ( this . timeoutId ) ;
77+ this . timeoutId = Mainloop . timeout_add_seconds (
78+ this . update_interval || 2 ,
79+ ( ) => this . updateTemperature ( )
80+ ) ;
81+ } ,
82+
83+ _parseAllSensors : function ( text ) {
84+ let regex = / ( [ ^ : \n ] + ) : \s + \+ ? ( \d + \. \d + ) ° C / g;
85+ let match ;
86+ let newData = [ ] ;
87+ while ( ( match = regex . exec ( text ) ) !== null ) {
88+ let label = match [ 1 ] . trim ( ) ;
89+ let icon = "🌡️" ;
90+ if ( label . toLowerCase ( ) . includes ( "core" ) ) icon = "⚡" ;
91+ else if ( label . toLowerCase ( ) . includes ( "gpu" ) ) icon = "🔥" ;
92+
93+ newData . push ( {
94+ label : label ,
95+ icon : icon ,
96+ temp : Math . round ( parseFloat ( match [ 2 ] ) )
97+ } ) ;
98+ }
99+ this . sensorsData = newData ;
100+ this . refreshUI ( ) ;
101+ } ,
102+
103+ refreshUI : function ( ) {
104+ this . mainContainer . destroy_all_children ( ) ;
105+
106+ let scale = this . scale_size || 1.0 ;
107+ let maxHeight = 400 * scale ;
108+ let width = 250 * scale ;
109+ let fontSize = this . text_size || 14 ;
110+ let fontColor = this . text_color || 'white' ;
111+ let upperOffset = 30 ;
112+ let startY = 30 ;
113+ let scaleX = 50 * scale ;
114+
115+ this . mainContainer . set_size ( width , maxHeight + 100 ) ;
116+
117+ // Draw Scale Markings (0 to 100)
118+ for ( let i = 0 ; i <= 100 ; i += 10 ) {
119+ let yPos = upperOffset + ( maxHeight * ( 100 - i ) / 100 ) ;
120+ let markLabel = new St . Label ( {
121+ text : i . toString ( ) ,
122+ style : `font-size: ${ 10 * scale } px; color: rgba(0,0,0,1); font-weight: bold;`
123+ } ) ;
124+ this . mainContainer . add_actor ( markLabel ) ;
125+ markLabel . set_position ( 30 , yPos ) ;
126+ }
127+
128+ // Draw Sensor Pointers
129+ for ( let sensor of this . sensorsData ) {
130+ let row = new St . BoxLayout ( { vertical : false , style : "align-items: center;" } ) ;
131+ let percentage = Math . min ( Math . max ( sensor . temp , 0 ) , 100 ) / 100 ;
132+ let yPos = startY + maxHeight * ( 1 - percentage ) ;
133+
134+ let arrowCanvas = new Clutter . Canvas ( ) ;
135+ arrowCanvas . set_size ( 30 * scale , 15 * scale ) ;
136+ arrowCanvas . connect ( 'draw' , ( canvas , cr , w , h ) => {
137+ this . _drawVibrantPointer ( cr , w , h , sensor . temp , scale ) ;
138+ } ) ;
139+ let arrowActor = new Clutter . Actor ( { width : 30 * scale , height : 15 * scale } ) ;
140+ arrowActor . set_content ( arrowCanvas ) ;
141+ arrowCanvas . invalidate ( ) ;
142+
143+ let contentLabel = new St . Label ( {
144+ text : `${ sensor . icon } ${ sensor . temp } ° ${ sensor . label } ` ,
145+ style : `font-size: ${ fontSize } px; color: ${ fontColor } ; font-weight: bold;`
146+ } ) ;
147+ contentLabel . set_size ( 300 , 20 ) ;
148+ //arrowActor.set_size(30,15);
149+ row . add_actor ( arrowActor ) ;
150+ row . add_actor ( contentLabel ) ;
151+
152+ row . set_position ( scaleX , yPos ) ;
153+ this . mainContainer . add_actor ( row ) ;
64154 }
65- else
66- global . logError ( "error reading: " + this . file ) ;
155+ // Calculate Tctl Mercury Logic
156+ let tctlSensor = this . sensorsData . find ( s => s . label === "Tctl" ) || { temp : 0 } ;
157+ let mercuryPercentage = Math . min ( Math . max ( tctlSensor . temp , 0 ) , 100 ) / 100 ;
158+
159+ let mercuryWidth = 3 * scale ;
160+ //let mercuryX = 32 * scale; // Tweak this to move left/right into the tube
161+ let mercuryFillHeight = mercuryPercentage * maxHeight ;
162+ let mercuryY = upperOffset + maxHeight - mercuryFillHeight ;
163+
164+ let thermo_height = 500 * scale ;
165+ let thermo_width = 50 * scale ;
166+ this . mainContainer . set_size ( thermo_width , thermo_height ) ;
167+ this . mainContainer . set_style ( `
168+ background-image: url('${ this . img_path } ');
169+ background-size: ${ thermo_width } px ${ thermo_height } px;
170+ background-repeat: no-repeat;
171+ background-position: bottom;
172+ ` ) ;
173+
174+ // Setup Mercury Widget
175+ this . mercuryWidget . set_size ( mercuryWidth , mercuryFillHeight ) ;
176+ this . mercuryWidget . set_position ( 23 * scale , mercuryY ) ;
177+ this . mercuryWidget . set_style ( `
178+ background-image: url('${ this . mercury_img_path } ');
179+ background-size: ${ mercuryWidth } px ${ mercuryFillHeight } px;
180+ background-position: bottom;
181+ background-repeat: no-repeat;
182+ ` ) ;
183+
184+ // Insert at index 0 to ensure it is the BOTTOM layer
185+ this . mainContainer . insert_child_at_index ( this . mercuryWidget , 0 ) ;
186+
187+
188+ } ,
189+
190+ _drawVibrantPointer : function ( cr , width , height , temp , scale ) {
191+ cr . save ( ) ;
192+ cr . setOperator ( Cairo . Operator . CLEAR ) ;
193+ cr . paint ( ) ;
194+ cr . restore ( ) ;
195+
196+ let h = height ;
197+ if ( temp < 45 ) cr . setSourceRGBA ( 0 , 0.8 , 1 , 1 ) ;
198+ else if ( temp < 75 ) cr . setSourceRGBA ( 1 , 0.8 , 0 , 1 ) ;
199+ else cr . setSourceRGBA ( 1 , 0.1 , 0 , 1 ) ;
200+
201+ cr . setLineWidth ( 2 * scale ) ;
202+ cr . moveTo ( 10 * scale , h / 2 - 7 * scale ) ;
203+ cr . lineTo ( 0 , h / 2 ) ;
204+ cr . lineTo ( 10 * scale , h / 2 + 7 * scale ) ;
205+ cr . stroke ( ) ;
206+
207+ cr . setSourceRGBA ( 1 , 1 , 1 , 0.4 ) ;
208+ cr . setLineWidth ( 1 * scale ) ;
209+ cr . moveTo ( 0 , h / 2 ) ;
210+ cr . lineTo ( width , h / 2 ) ;
211+ cr . stroke ( ) ;
67212 }
68- }
69-
70-
71- MyDesklet . prototype = {
72- __proto__ : Desklet . Desklet . prototype ,
73-
74- _init : function ( metadata , desklet_id ) {
75- Desklet . Desklet . prototype . _init . call ( this , metadata ) ;
76- this . thermal = new Thermal ( "/sys/devices/virtual/thermal/thermal_zone0/temp" ) ;
77- this . setupUI ( ) ;
78- } ,
79-
80- setupUI : function ( ) {
81-
82- // load images and set initial sizes
83- this . refreshDesklet ( true ) ;
84-
85- // set root element
86- this . setContent ( this . battery ) ;
87- this . setHeader ( "Thermometer" ) ;
88- // start update cycle
89- this . update ( ) ;
90- } ,
91-
92- update : function ( ) {
93- this . thermal . refresh ( ) ;
94- this . refreshDesklet ( ) ;
95- // update again in two seconds
96- this . timeout = Mainloop . timeout_add_seconds ( 1 , Lang . bind ( this , this . update ) ) ;
97- } ,
98-
99- refreshDesklet : function ( forceRefresh = false ) {
100-
101- // calc new sizes based on scale factor
102- let batteryWidth = 50 ;
103- let batteryHeight = 500 ;
104- let segmentHeight = 360 ;
105- let segmentWidth = 3 ;
106- let segmentHeightCalc = segmentHeight * ( 20 + parseInt ( this . thermal . info ) ) / 120 ;
107-
108- // set images
109- let bar_img = "mercury.svg" ;
110- this . bg_img = "thermometer.svg" ;
111-
112- // create battery background
113- this . battery = getImageAtScale ( DESKLET_ROOT + "/img/" + this . bg_img , batteryWidth , batteryHeight ) ;
114-
115- // create segment = variable width bar (indicates capacity)
116- this . segment = getImageAtScale ( DESKLET_ROOT + "/img/" + bar_img , segmentWidth , segmentHeight , segmentWidth , segmentHeightCalc ) ;
117- this . segment . set_position ( 23 , 40 + segmentHeight - segmentHeightCalc ) ;
118-
119- // container for subelements (icon, label)
120- this . container = new St . Group ( ) ;
121-
122-
123- // label for percent string
124- this . labelText = new St . Label ( { style_class :"text" } ) ;
125- this . labelText . set_text ( parseInt ( this . thermal . info ) + "°C" ) ;
126- this . labelText . style = "font-size:10px;"
127- this . labelText . set_position ( 10 , 510 ) ;
128-
129- // add actor
130- this . battery . remove_all_children ( ) ;
131- this . battery . add_actor ( this . segment ) ;
132- this . battery . add_actor ( this . labelText ) ;
133- this . setContent ( this . battery ) ;
134-
135-
136- } ,
137-
213+ } ;
138214
139- on_desklet_removed : function ( ) {
140- Mainloop . source_remove ( this . timeout ) ;
141- }
215+ function main ( metadata , desklet_id ) {
216+ return new MyDesklet ( metadata , desklet_id ) ;
142217}
0 commit comments