1 /****************************************************************************
2 *    Copyright © 2014-2020 Xorg
3 *
4 *    This program is free software: you can redistribute it and/or modify
5 *    it under the terms of the GNU General Public License as published by
6 *    the Free Software Foundation, either version 3 of the License, or
7 *    (at your option) any later version.
8 *
9 *    This program is distributed in the hope that it will be useful,
10 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *    GNU General Public License for more details.
13 *
14 *    You should have received a copy of the GNU General Public License
15 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 *
17 ****************************************************************************/
18 
19 /*
20 * PROJECT CPU-X
21 * FILE gui_gtk.c
22 */
23 #include <sys/wait.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <libintl.h>
29 #include "cpu-x.h"
30 #include "ipc.h"
31 #include "gui_gtk.h"
32 #include "gui_gtk_id.h"
33 
34 
35 /************************* Public function *************************/
36 
37 /* Load and apply settings from GSettings */
load_settings()38 void load_settings()
39 {
40 	settings            = g_settings_new(PRGNAME_LOW);
41 	theme               = g_settings_get_enum(settings, "gui-theme");
42 	opts->refr_time     = g_settings_get_uint(settings, "refresh-time");
43 	opts->selected_page = g_settings_get_enum(settings, "default-tab");
44 	opts->selected_core = g_settings_get_uint(settings, "default-cpu-core");
45 	opts->bw_test       = g_settings_get_uint(settings, "default-cache-test");
46 	opts->with_daemon   = g_settings_get_boolean(settings, "always-start-daemon");
47 	g_settings_delay(settings);
48 }
49 
50 /* Start CPU-X in GTK mode */
start_gui_gtk(int * argc,char ** argv[],Labels * data)51 void start_gui_gtk(int *argc, char **argv[], Labels *data)
52 {
53 	int i;
54 	GtkLabels  glab;
55 	GThrd      refr     = { &glab, data };
56 	GtkBuilder *builder = gtk_builder_new();
57 	const gchar *ui_files[] = { "cpu-x-gtk-3.12.ui", NULL };
58 
59 	MSG_VERBOSE("%s", _("Starting GTK GUI…"));
60 	gtk_init(argc, argv);
61 	g_set_prgname(PRGNAME_LOW);
62 
63 	/* Build UI from Glade file */
64 	for(i = 0; (ui_files[i] != NULL) && (!gtk_builder_add_from_file(builder, data_path(ui_files[i]), NULL)); i++);
65 	if(ui_files[i] == NULL)
66 	{
67 		MSG_ERROR("%s", _("failed to import UI in GtkBuilder"));
68 		exit(EXIT_FAILURE);
69 	}
70 
71 	/* Set widgets */
72 	get_widgets(builder, &glab);
73 	g_object_unref(G_OBJECT(builder));
74 	set_colors (&glab);
75 	set_logos  (&glab, data);
76 	set_labels (&glab, data);
77 	set_signals(&glab, data, &refr);
78 	labels_free(data);
79 
80 	/* Bind settings to get_widgets */
81 	g_settings_bind(settings, "refresh-time",        glab.refreshtime,      "value",     G_SETTINGS_BIND_DEFAULT);
82 	g_settings_bind(settings, "gui-theme",           glab.theme,            "active-id", G_SETTINGS_BIND_DEFAULT);
83 	g_settings_bind(settings, "default-tab",         glab.defaulttab,       "active-id", G_SETTINGS_BIND_DEFAULT);
84 	g_settings_bind(settings, "default-cpu-core",    glab.defaultcore,      "active",    G_SETTINGS_BIND_DEFAULT);
85 	g_settings_bind(settings, "default-cache-test",  glab.defaultcachetest, "active",    G_SETTINGS_BIND_DEFAULT);
86 	g_settings_bind(settings, "always-start-daemon", glab.startdaemon,      "active",    G_SETTINGS_BIND_DEFAULT);
87 
88 	g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, opts->refr_time, (gpointer)grefresh, &refr, modify_refresh_time);
89 	gtk_main();
90 
91 	if(data->reload)
92 		execvp((*argv)[0], *argv);
93 }
94 
95 
96 /************************* Private functions *************************/
97 
98 /* Refresh dynamic values */
grefresh(GThrd * refr)99 static gboolean grefresh(GThrd *refr)
100 {
101 	int i;
102 	Labels    *(data) = refr->data;
103 	GtkLabels *(glab) = refr->glab;
104 
105 	opts->selected_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(glab->notebook));
106 	do_refresh(data);
107 
108 	switch(opts->selected_page)
109 	{
110 		case NO_CPU:
111 			gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][VOLTAGE]),      data->tab_cpu[VALUE][VOLTAGE]);
112 			gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][TEMPERATURE]),  data->tab_cpu[VALUE][TEMPERATURE]);
113 			gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][MULTIPLIER]),   data->tab_cpu[VALUE][MULTIPLIER]);
114 			gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][CORESPEED]),    data->tab_cpu[VALUE][CORESPEED]);
115 			gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][USAGE]),        data->tab_cpu[VALUE][USAGE]);
116 			break;
117 		case NO_CACHES:
118 			for(i = L1SPEED; i < data->cache_count * CACHEFIELDS; i += CACHEFIELDS)
119 				gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[VALUE][i]), data->tab_caches[VALUE][i]);
120 			break;
121 		case NO_SYSTEM:
122 			gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][UPTIME]),    data->tab_system[VALUE][UPTIME]);
123 			for(i = USED; i < LASTSYSTEM; i++)
124 				gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][i]), data->tab_system[VALUE][i]);
125 			break;
126 		case NO_GRAPHICS:
127 			for(i = 0; i < data->gpu_count; i++)
128 			{
129 				gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1TEMPERATURE + i * GPUFIELDS]), data->tab_graphics[VALUE][GPU1TEMPERATURE + i * GPUFIELDS]);
130 				gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1USAGE       + i * GPUFIELDS]), data->tab_graphics[VALUE][GPU1USAGE       + i * GPUFIELDS]);
131 				gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1CORECLOCK   + i * GPUFIELDS]), data->tab_graphics[VALUE][GPU1CORECLOCK   + i * GPUFIELDS]);
132 				gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1MEMCLOCK    + i * GPUFIELDS]), data->tab_graphics[VALUE][GPU1MEMCLOCK    + i * GPUFIELDS]);
133 			}
134 			break;
135 		case NO_BENCH:
136 			for(i = PRIMESLOWSCORE; i <= PRIMEFASTSCORE; i += BENCHFIELDS)
137 				gtk_progress_bar_set_text(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][i]), data->tab_bench[VALUE][i]);
138 			change_benchsensitive(glab, data);
139 			break;
140 		default:
141 			break;
142 	}
143 
144 	/* Destroy current timeout when refresh time is updated
145 	Note: modify_refresh_time() will create a new timeout */
146 	return (opts->refr_time == g_settings_get_uint(settings, "refresh-time"));
147 }
148 
149 /* Create new timeout when old one is destroyed */
modify_refresh_time(gpointer data)150 static void modify_refresh_time(gpointer data)
151 {
152 	opts->refr_time = g_settings_get_uint(settings, "refresh-time");
153 	g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, opts->refr_time, (gpointer)grefresh, data, modify_refresh_time);
154 }
155 
156 /* Show settings window */
open_settings_window(GtkWidget * __button,GtkLabels * glab)157 static void open_settings_window(GtkWidget *__button, GtkLabels *glab)
158 {
159 	UNUSED(__button);
160 	gtk_widget_show(GTK_WIDGET(glab->settingswindow));
161 }
162 
163 /* Hide settings window and revert changes */
hide_settings_window(GtkWidget * widget,GdkEvent * event,GtkLabels * glab)164 static gboolean hide_settings_window(GtkWidget *widget, GdkEvent *event, GtkLabels *glab)
165 {
166 	UNUSED(event);
167 	UNUSED(glab);
168 	g_settings_revert(settings);
169 	gtk_widget_hide(widget);
170 	return TRUE;
171 }
172 
173 /* Hide settings window and revert changes */
close_settings_window(GtkWidget * __button,GtkLabels * glab)174 static void close_settings_window(GtkWidget *__button, GtkLabels *glab)
175 {
176 	UNUSED(__button);
177 	g_settings_revert(settings);
178 	gtk_widget_hide(GTK_WIDGET(glab->settingswindow));
179 }
180 
181 /* Hide settings window and apply changes */
save_settings(GtkWidget * __button,GtkLabels * glab)182 static void save_settings(GtkWidget *__button, GtkLabels *glab)
183 {
184 	UNUSED(__button);
185 	theme = g_settings_get_enum(settings, "gui-theme");
186 	set_colors(glab);
187 	g_settings_apply(settings);
188 	gtk_widget_hide(GTK_WIDGET(glab->settingswindow));
189 }
190 
191 /* Start daemon and reload CPU-X */
reload_with_daemon(GtkWidget * button,GThrd * refr)192 static void reload_with_daemon(GtkWidget *button, GThrd *refr)
193 {
194 	Labels    *(data) = refr->data;
195 	GtkLabels *(glab) = refr->glab;
196 
197 	gtk_widget_set_sensitive(button, false);
198 	const char *msg = start_daemon(true);
199 
200 	if(msg == NULL)
201 	{
202 		data->reload = true;
203 		gtk_main_quit();
204 	}
205 	else
206 	{
207 		GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(glab->mainwindow),
208 			GTK_DIALOG_DESTROY_WITH_PARENT,
209 			GTK_MESSAGE_WARNING,
210 			GTK_BUTTONS_CLOSE,
211 			"%s", _(msg));
212 		if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_CLOSE)
213 			gtk_widget_destroy(GTK_WIDGET(dialog));
214 		gtk_widget_set_sensitive(button, true);
215 	}
216 }
217 
218 /* Event in CPU tab when Core number is changed */
change_activecore(GtkComboBox * box,Labels * data)219 static void change_activecore(GtkComboBox *box, Labels *data)
220 {
221 	const gint core = gtk_combo_box_get_active(GTK_COMBO_BOX(box));
222 
223 	if(0 <= core && core < data->cpu_count)
224 		opts->selected_core = core;
225 }
226 
227 /* Event in Caches tab when Test number is changed */
change_activetest(GtkComboBox * box,Labels * data)228 static void change_activetest(GtkComboBox *box, Labels *data)
229 {
230 	const gint test = gtk_combo_box_get_active(GTK_COMBO_BOX(box));
231 
232 	if(0 <= test && test < data->w_data->test_count)
233 		opts->bw_test = test;
234 }
235 
236 /* Events in Bench tab when a benchmark start/stop */
start_benchmark_bg(GtkSwitch * gswitch,GdkEvent * __event,GThrd * refr)237 static void start_benchmark_bg(GtkSwitch *gswitch, GdkEvent *__event, GThrd *refr)
238 {
239 	UNUSED(__event);
240 	Labels *data = refr->data;
241 
242 	if(!data->b_data->run)
243 	{
244 		change_benchsensitive(refr->glab, data);
245 		data->b_data->fast_mode = !strcmp(gtk_widget_get_name(GTK_WIDGET(gswitch)), objectbench[PRIMEFASTRUN]);
246 		start_benchmarks(data);
247 	}
248 	else
249 		data->b_data->run = false;
250 }
251 
252 /* Events in Bench tab when Duration/Threads SpinButtons are changed */
change_benchparam(GtkSpinButton * spinbutton,Labels * data)253 static void change_benchparam(GtkSpinButton *spinbutton, Labels *data)
254 {
255 	const gint val = gtk_spin_button_get_value_as_int(spinbutton);
256 
257 	if(!g_strcmp0(gtk_widget_get_name     (GTK_WIDGET(spinbutton)), objectbench[PARAMDURATION]))
258 		data->b_data->duration = val;
259 	else if(!g_strcmp0(gtk_widget_get_name(GTK_WIDGET(spinbutton)), objectbench[PARAMTHREADS]))
260 		data->b_data->threads = val;
261 
262 	gtk_spin_button_update(spinbutton);
263 }
264 
265 /* Set/Unset widgets sensitive when a benchmark start/stop */
change_benchsensitive(GtkLabels * glab,Labels * data)266 static void change_benchsensitive(GtkLabels *glab, Labels *data)
267 {
268 	static gboolean skip = false;
269 	const enum EnTabBench indP = data->b_data->fast_mode ? PRIMEFASTSCORE : PRIMESLOWSCORE;
270 	const enum EnTabBench indS = data->b_data->fast_mode ? PRIMESLOWRUN   : PRIMEFASTRUN;
271 	const enum EnTabBench indA = data->b_data->fast_mode ? PRIMEFASTRUN   : PRIMESLOWRUN;
272 
273 	if(data->b_data->run)
274 	{
275 		skip = false;
276 #if GTK_CHECK_VERSION(3, 15, 0)
277 		gtk_switch_set_state(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]), true);
278 #endif /* GTK_CHECK_VERSION(3, 15, 0) */
279 		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][indP]),
280 			(double) data->b_data->elapsed / (data->b_data->duration * 60));
281 		gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][indS],         false);
282 		gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][PARAMTHREADS], false);
283 	}
284 	else if(!data->b_data->run && !skip)
285 	{
286 		skip = true;
287 #if GTK_CHECK_VERSION(3, 15, 0)
288 		gtk_switch_set_state(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]),  false);
289 #endif /* GTK_CHECK_VERSION(3, 15, 0) */
290 		gtk_switch_set_active(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]), false);
291 		gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][indS],          true);
292 		gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][PARAMTHREADS],  true);
293 	}
294 }
295 
296 /* Get label ID ('type' must be "lab" or "val") */
get_id(const gchar * objectstr,gchar * type)297 static gchar *get_id(const gchar *objectstr, gchar *type)
298 {
299 	static gchar *buff = NULL;
300 	gchar **split;
301 
302 	g_free(buff);
303 	split = g_strsplit(objectstr, "_", 2);
304 	buff  = g_strconcat(split[0], "_", type, split[1], NULL);
305 	g_strfreev(split);
306 
307 	return buff;
308 }
309 
310 /* Search file location in standard paths */
data_path(const gchar * file)311 static gchar *data_path(const gchar *file)
312 {
313 	int i;
314 	gboolean file_exists = false;
315 	static gchar *path = NULL;
316 	const gchar *prgname = g_get_prgname();
317 	const gchar *const *paths = g_get_system_data_dirs();
318 
319 	for(i = 0; (!file_exists) && (paths[i] != NULL); i++)
320 	{
321 		g_free(path);
322 		path = g_build_filename(paths[i], prgname, file, NULL);
323 		file_exists = g_file_test(path, G_FILE_TEST_EXISTS);
324 	}
325 
326 	return path;
327 }
328 
329 /* Retrieve widgets from GtkBuilder */
get_widgets(GtkBuilder * builder,GtkLabels * glab)330 static void get_widgets(GtkBuilder *builder, GtkLabels *glab)
331 {
332 	int i;
333 
334 	glab->mainwindow     = GTK_WIDGET(gtk_builder_get_object(builder, "mainwindow"));
335 	glab->settingsbutton = GTK_WIDGET(gtk_builder_get_object(builder, "settingsbutton"));
336 	glab->daemonbutton   = GTK_WIDGET(gtk_builder_get_object(builder, "daemonbutton"));
337 	glab->labprgver	     = GTK_WIDGET(gtk_builder_get_object(builder, "labprgver"));
338 	glab->footer         = GTK_WIDGET(gtk_builder_get_object(builder, "footer_box"));
339 	glab->notebook       = GTK_WIDGET(gtk_builder_get_object(builder, "header_notebook"));
340 	glab->logocpu        = GTK_WIDGET(gtk_builder_get_object(builder, "proc_logocpu"));
341 	glab->activecore     = GTK_WIDGET(gtk_builder_get_object(builder, "trg_activecore"));
342 	glab->activetest     = GTK_WIDGET(gtk_builder_get_object(builder, "test_activetest"));
343 	glab->logoprg        = GTK_WIDGET(gtk_builder_get_object(builder, "about_logoprg"));
344 	glab->butcol         = GTK_WIDGET(gtk_builder_get_object(builder, "colorbutton"));
345 
346 	glab->settingswindow   = GTK_WIDGET(gtk_builder_get_object(builder, "settingswindow"));
347 	glab->validatebutton   = GTK_WIDGET(gtk_builder_get_object(builder, "validatebutton"));
348 	glab->cancelbutton     = GTK_WIDGET(gtk_builder_get_object(builder, "cancelbutton"));
349 	glab->refreshtime      = GTK_WIDGET(gtk_builder_get_object(builder, "refreshtime_val"));
350 	glab->theme            = GTK_WIDGET(gtk_builder_get_object(builder, "theme_val"));
351 	glab->defaulttab       = GTK_WIDGET(gtk_builder_get_object(builder, "defaulttab_val"));
352 	glab->defaultcore      = GTK_WIDGET(gtk_builder_get_object(builder, "defaultcore_val"));
353 	glab->defaultcachetest = GTK_WIDGET(gtk_builder_get_object(builder, "defaultcachetest_val"));
354 	glab->startdaemon      = GTK_WIDGET(gtk_builder_get_object(builder, "startdaemon"));
355 
356 	gtk_widget_set_name(glab->footer, "footer_box");
357 	gtk_notebook_set_current_page(GTK_NOTEBOOK(glab->notebook), opts->selected_page);
358 
359 	/* Various labels to translate */
360 	for(i = TABCPU; i < LASTOBJ; i++)
361 		glab->gtktrad[i] = GTK_WIDGET(gtk_builder_get_object(builder, trad[i]));
362 
363 	/* Tab CPU */
364 	for(i = VENDOR; i < LASTCPU; i++)
365 	{
366 		glab->gtktab_cpu[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcpu[i], "lab")));
367 		glab->gtktab_cpu[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcpu[i], "val")));
368 		gtk_widget_set_name(glab->gtktab_cpu[VALUE][i], "value");
369 	}
370 
371 	/* Tab Caches */
372 	for(i = L1SIZE; i < LASTCACHES; i++)
373 	{
374 		glab->gtktab_caches[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcache[i], "lab")));
375 		glab->gtktab_caches[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcache[i], "val")));
376 		gtk_widget_set_name(glab->gtktab_caches[VALUE][i], "value");
377 	}
378 	glab->gridcaches = GTK_WIDGET(gtk_builder_get_object(builder, "caches_grid"));
379 
380 	/* Tab Motherboard */
381 	for(i = MANUFACTURER; i < LASTMOTHERBOARD; i++)
382 	{
383 		glab->gtktab_motherboard[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectmb[i], "lab")));
384 		glab->gtktab_motherboard[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectmb[i], "val")));
385 		gtk_widget_set_name(glab->gtktab_motherboard[VALUE][i], "value");
386 	}
387 
388 	/* Tab RAM */
389 	for(i = BANK0; i < LASTMEMORY; i++)
390 	{
391 		glab->gtktab_memory[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectram[i], "lab")));
392 		glab->gtktab_memory[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectram[i], "val")));
393 		gtk_widget_set_name(glab->gtktab_memory[VALUE][i], "value");
394 	}
395 	glab->gridbanks   = GTK_WIDGET(gtk_builder_get_object(builder, "memory_grid"));
396 	glab->scrollbanks = GTK_WIDGET(gtk_builder_get_object(builder, "memory_scrolledwindow"));
397 
398 	/* Tab System */
399 	for(i = KERNEL; i < LASTSYSTEM; i++)
400 	{
401 		glab->gtktab_system[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectsys[i], "lab")));
402 		glab->gtktab_system[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectsys[i], "val")));
403 		gtk_widget_set_name(glab->gtktab_system[VALUE][i], "value");
404 	}
405 	for(i = BARUSED; i < LASTBAR; i++)
406 	{
407 		glab->bar[i] = GTK_WIDGET(gtk_builder_get_object(builder, objectsys_bar[i]));
408 		gtk_widget_set_name(GTK_WIDGET(glab->bar[i]), format("%i", i));
409 	}
410 
411 	/* Tab Graphics */
412 	for(i = GPU1VENDOR; i < LASTGRAPHICS; i++)
413 	{
414 		glab->gtktab_graphics[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectgpu[i], "lab")));
415 		glab->gtktab_graphics[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectgpu[i], "val")));
416 		gtk_widget_set_name(glab->gtktab_graphics[VALUE][i], "value");
417 	}
418 	glab->gridcards = GTK_WIDGET(gtk_builder_get_object(builder, "graphics_box"));
419 
420 	/* Tab Bench */
421 	for(i = PRIMESLOWSCORE; i < LASTBENCH; i++)
422 	{
423 		glab->gtktab_bench[NAME][i]  = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectbench[i], "lab")));
424 		glab->gtktab_bench[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectbench[i], "val")));
425 		gtk_widget_set_name(glab->gtktab_bench[VALUE][i], objectbench[i]);
426 	}
427 
428 	/* Tab About */
429 	for(i = DESCRIPTION; i < LASTABOUT; i++)
430 		glab->gtktab_about[i] = GTK_WIDGET(gtk_builder_get_object(builder, objectabout[i]));
431 }
432 
is_dark_theme(GtkLabels * glab)433 static gboolean is_dark_theme(GtkLabels *glab)
434 {
435 	gdouble contrast;
436 	GdkRGBA *fg, *bg;
437 	GtkStyleContext *context;
438 
439 	if (theme != AUTO)
440 		return (theme == DARK);
441 
442 	context = gtk_widget_get_style_context(GTK_WIDGET(glab->mainwindow));
443 	gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL,
444 		GTK_STYLE_PROPERTY_COLOR, &fg,
445 		GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &bg,
446 		NULL);
447 	contrast = bg->red - fg->red + bg->green - fg->green + bg->blue - fg->blue;
448 	gdk_rgba_free(fg);
449 	gdk_rgba_free(bg);
450 
451 	return (contrast < -1);
452 }
453 
454 /* Set custom GTK theme */
set_colors(GtkLabels * glab)455 static void set_colors(GtkLabels *glab)
456 {
457 	gchar *filename = NULL;
458 	GtkCssProvider *provider = gtk_css_provider_new();
459 
460 	if(gtk_check_version(3, 19, 2) == NULL) // GTK 3.20 or newer
461 		filename = is_dark_theme(glab) ? g_strdup("cpu-x-gtk-3.20-dark.css") : g_strdup("cpu-x-gtk-3.20.css");
462 	else // GTK 3.12 to 3.18
463 		filename = is_dark_theme(glab) ? g_strdup("cpu-x-gtk-3.12-dark.css") : g_strdup("cpu-x-gtk-3.12.css");
464 
465 	gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
466 	gtk_css_provider_load_from_path(provider, data_path(filename), NULL);
467 
468 	g_free(filename);
469 	g_object_unref(provider);
470 }
471 
472 /* Set CPU vendor logo and program logo */
set_logos(GtkLabels * glab,Labels * data)473 static void set_logos(GtkLabels *glab, Labels *data)
474 {
475 	int width, height, prg_size = 72;
476 	GdkPixbuf *cpu_pixbuf = NULL, *unknown_pixbuf = NULL, *prg_pixbuf = NULL;
477 	GError *error = NULL;
478 
479 	width  = gtk_widget_get_allocated_width(glab->gtktab_cpu[VALUE][SPECIFICATION]) -
480 	         gtk_widget_get_allocated_width(glab->gtktab_cpu[VALUE][VENDOR]) - 6;
481 	height = (gtk_widget_get_allocated_height(glab->gtktab_cpu[VALUE][VENDOR]) + 4) * 4;
482 
483 	cpu_pixbuf     = gdk_pixbuf_new_from_file_at_scale(data_path(format("%s.png", data->tab_cpu[VALUE][VENDOR])), width, height, TRUE, &error);
484 	unknown_pixbuf = gdk_pixbuf_new_from_file_at_scale(data_path("Unknown.png"), width, height, TRUE, NULL);
485 	prg_pixbuf     = gdk_pixbuf_new_from_file_at_scale(data_path("CPU-X.png"), prg_size, prg_size, TRUE, NULL);
486 
487 	gtk_window_set_icon(GTK_WINDOW(glab->mainwindow),   prg_pixbuf);
488 	gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logocpu), cpu_pixbuf);
489 	gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logoprg), prg_pixbuf);
490 	g_object_unref(cpu_pixbuf);
491 	g_object_unref(prg_pixbuf);
492 
493 	if(error != NULL)
494 		gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logocpu), unknown_pixbuf);
495 	g_object_unref(unknown_pixbuf);
496 }
497 
498 /* Filling all labels */
set_labels(GtkLabels * glab,Labels * data)499 static void set_labels(GtkLabels *glab, Labels *data)
500 {
501 	int i;
502 	const int pkcheck = system(format("pkcheck --action-id org.freedesktop.policykit.exec --process %u > /dev/null 2>&1", getpid()));
503 	const gint width1 = gtk_widget_get_allocated_width(glab->gtktab_system[VALUE][COMPILER]);
504 	const gint width2 = width1 - gtk_widget_get_allocated_width(glab->gtktab_system[VALUE][USED]) - 6;
505 	GtkRequisition requisition;
506 
507 	/* Footer label */
508 	gtk_label_set_text(GTK_LABEL(glab->labprgver), data->tab_about[VERSIONSTR]);
509 	gtk_widget_set_sensitive(glab->daemonbutton, false);
510 	if(DAEMON_UP)
511 		gtk_widget_set_tooltip_text(glab->daemonbutton, _("Connected to daemon"));
512 	else if(WEXITSTATUS(pkcheck) > 2)
513 		gtk_widget_set_tooltip_text(glab->daemonbutton, _("No polkit authentication agent found"));
514 	else
515 	{
516 		gtk_widget_set_sensitive(glab->daemonbutton, true);
517 		gtk_widget_set_tooltip_text(glab->daemonbutton, _("Ask password to start daemon in background"));
518 	}
519 
520 	/* Various labels to translate */
521 	for(i = TABCPU; i < LASTOBJ; i++)
522 		gtk_label_set_text(GTK_LABEL(glab->gtktrad[i]), data->objects[i]);
523 	gtk_button_set_label(GTK_BUTTON(glab->daemonbutton), _("Start daemon"));
524 
525 	/* Tab CPU */
526 	for(i = VENDOR; i < LASTCPU; i++)
527 	{
528 		gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[NAME][i]),  data->tab_cpu[NAME][i]);
529 		gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][i]), data->tab_cpu[VALUE][i]);
530 	}
531 	for(i = 0; i < data->cpu_count; i++)
532 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->activecore), format(_("Core #%i"), i));
533 	gtk_combo_box_set_active(GTK_COMBO_BOX(glab->activecore), opts->selected_core);
534 
535 	/* Tab Caches */
536 	for(i = L1SIZE; i < LASTCACHES; i++)
537 	{
538 		gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[NAME][i]),  data->tab_caches[NAME][i]);
539 		gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[VALUE][i]), data->tab_caches[VALUE][i]);
540 	}
541 	for(i = LASTCACHES / CACHEFIELDS; i > data->cache_count; i--)
542 		gtk_grid_remove_row(GTK_GRID(glab->gridcaches), i - 1);
543 	for(i = 0; i < data->w_data->test_count; i++)
544 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->activetest), data->w_data->test_name[i]);
545 	gtk_combo_box_set_active(GTK_COMBO_BOX(glab->activetest), opts->bw_test);
546 	if(!data->cache_count)
547 		gtk_widget_hide(GTK_WIDGET(glab->gridcaches));
548 
549 	/* Tab Motherboard */
550 	for(i = MANUFACTURER; i < LASTMOTHERBOARD; i++)
551 	{
552 		gtk_label_set_text(GTK_LABEL(glab->gtktab_motherboard[NAME][i]),  data->tab_motherboard[NAME][i]);
553 		gtk_label_set_text(GTK_LABEL(glab->gtktab_motherboard[VALUE][i]), data->tab_motherboard[VALUE][i]);
554 	}
555 
556 	/* Tab RAM */
557 	for(i = BANK0; i < data->dimm_count; i++)
558 	{
559 		g_strdelimit(data->tab_memory[VALUE][i], ",", '\n');
560 		gtk_label_set_text(GTK_LABEL(glab->gtktab_memory[NAME][i]),  data->tab_memory[NAME][i]);
561 		gtk_label_set_text(GTK_LABEL(glab->gtktab_memory[VALUE][i]), data->tab_memory[VALUE][i]);
562 	}
563 	for(i = BANK7; i >= data->dimm_count; i--)
564 		gtk_grid_remove_row(GTK_GRID(glab->gridbanks), i);
565 	if(!data->dimm_count)
566 		gtk_widget_hide(GTK_WIDGET(glab->scrollbanks));
567 
568 	/* Tab System */
569 	for(i = KERNEL; i < LASTSYSTEM; i++)
570 	{
571 		gtk_label_set_text(GTK_LABEL(glab->gtktab_system[NAME][i]),  data->tab_system[NAME][i]);
572 		gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][i]), data->tab_system[VALUE][i]);
573 	}
574 	for(i = BARUSED; i < LASTBAR; i++)
575 	{
576 		gtk_widget_get_preferred_size(glab->gtktab_system[VALUE][USED], NULL, &requisition);
577 		gtk_widget_set_size_request(glab->bar[i], width2, requisition.height);
578 	}
579 
580 	/* Tab Graphics */
581 	for(i = GPU1VENDOR; i < LASTGRAPHICS; i++)
582 	{
583 		gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[NAME][i]),  data->tab_graphics[NAME][i]);
584 		gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][i]), data->tab_graphics[VALUE][i]);
585 	}
586 	for(i = LASTGRAPHICS / GPUFIELDS; i >= data->gpu_count; i--)
587 		gtk_grid_remove_row(GTK_GRID(glab->gridcards), i);
588 	if(!data->gpu_count)
589 		gtk_widget_hide(GTK_WIDGET(glab->gridcards));
590 
591 	/* Tab Bench */
592 	for(i = PRIMESLOWSCORE; i < LASTBENCH; i++)
593 		gtk_label_set_text(GTK_LABEL(glab->gtktab_bench[NAME][i]), data->tab_bench[NAME][i]);
594 	for(i = PRIMESLOWSCORE; i <= PRIMEFASTSCORE; i += BENCHFIELDS)
595 	{
596 		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][i]), data->tab_bench[VALUE][i]);
597 		gtk_widget_set_size_request(glab->gtktab_bench[VALUE][i], width1, -1);
598 	}
599 	gtk_spin_button_set_increments(GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMDURATION]), 1, 60);
600 	gtk_spin_button_set_increments(GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMTHREADS]),  1, 1);
601 	gtk_spin_button_set_range     (GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMDURATION]), 1, 60 * 24);
602 	gtk_spin_button_set_range     (GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMTHREADS]),  1, data->cpu_count);
603 
604 	/* Tab About */
605 	for(i = DESCRIPTION; i < LASTABOUT; i++)
606 		gtk_label_set_text(GTK_LABEL(glab->gtktab_about[i]), data->tab_about[i]);
607 
608 	/* Settings window */
609 	gtk_spin_button_set_range     (GTK_SPIN_BUTTON(glab->refreshtime),  1, G_MAXUSHORT);
610 	gtk_spin_button_set_increments(GTK_SPIN_BUTTON(glab->refreshtime),  1, 60);
611 	for (i = NO_CPU; i <= NO_ABOUT; i++)
612 		gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(glab->defaulttab), i, nicktab[i], format(_("%s"), data->objects[i]));
613 	gtk_combo_box_set_active(GTK_COMBO_BOX(glab->defaulttab), opts->selected_page);
614 	for(i = 0; i < data->cpu_count; i++)
615 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->defaultcore), format(_("Core #%i"), i));
616 	gtk_combo_box_set_active(GTK_COMBO_BOX(glab->defaultcore), opts->selected_core);
617 	for(i = 0; i < data->w_data->test_count; i++)
618 		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->defaultcachetest), data->w_data->test_name[i]);
619 	gtk_combo_box_set_active(GTK_COMBO_BOX(glab->defaultcachetest), opts->bw_test);
620 	gtk_widget_set_sensitive(GTK_WIDGET(glab->defaultcachetest), data->cache_count > 0);
621 }
622 
623 /* Call defined functions on signals */
set_signals(GtkLabels * glab,Labels * data,GThrd * refr)624 static void set_signals(GtkLabels *glab, Labels *data, GThrd *refr)
625 {
626 	int i;
627 
628 	g_signal_connect(glab->mainwindow,     "destroy",      G_CALLBACK(gtk_main_quit),        NULL);
629 	g_signal_connect(glab->settingswindow, "delete-event", G_CALLBACK(hide_settings_window), NULL);
630 	g_signal_connect(glab->settingsbutton, "clicked",      G_CALLBACK(open_settings_window), glab);
631 	g_signal_connect(glab->daemonbutton,   "clicked",      G_CALLBACK(reload_with_daemon),   refr);
632 	g_signal_connect(glab->activecore,     "changed",      G_CALLBACK(change_activecore),    data);
633 	g_signal_connect(glab->activetest,     "changed",      G_CALLBACK(change_activetest),    data);
634 
635 	/* Tab Bench */
636 	g_signal_connect(glab->gtktab_bench[VALUE][PRIMESLOWRUN],  "button-press-event", G_CALLBACK(start_benchmark_bg), refr);
637 	g_signal_connect(glab->gtktab_bench[VALUE][PRIMEFASTRUN],  "button-press-event", G_CALLBACK(start_benchmark_bg), refr);
638 	g_signal_connect(glab->gtktab_bench[VALUE][PARAMDURATION], "value-changed",      G_CALLBACK(change_benchparam),  data);
639 	g_signal_connect(glab->gtktab_bench[VALUE][PARAMTHREADS],  "value-changed",      G_CALLBACK(change_benchparam),  data);
640 
641 	/* Tab System */
642 	for(i = BARUSED; i < LASTBAR; i++)
643 		g_signal_connect(G_OBJECT(glab->bar[i]),  "draw", G_CALLBACK(fill_frame), refr);
644 
645 	/* Settings window */
646 	g_signal_connect(glab->validatebutton, "clicked", G_CALLBACK(save_settings), glab);
647 	g_signal_connect(glab->cancelbutton,   "clicked", G_CALLBACK(close_settings_window), glab);
648 }
649 
650 /* Draw bars in Memory tab */
fill_frame(GtkWidget * widget,cairo_t * cr,GThrd * refr)651 void fill_frame(GtkWidget *widget, cairo_t *cr, GThrd *refr)
652 {
653 	int i = USED, page;
654 	guint width, height;
655 	double before = 0, percent = 0;
656 	const gchar *widget_name;
657 	cairo_pattern_t *pat;
658 	PangoLayout *reflayout, *newlayout;
659 
660 	Labels *(data)    = refr->data;
661 	GtkLabels *(glab) = refr->glab;
662 
663 	widget_name = gtk_widget_get_name(widget);
664 	width       = gtk_widget_get_allocated_width(widget);
665 	height      = gtk_widget_get_allocated_height(widget);
666 	page        = atoi(widget_name);
667 	reflayout   = gtk_label_get_layout(GTK_LABEL(glab->gtktab_system[VALUE][page + USED]));
668 	newlayout   = pango_layout_copy(reflayout);
669 
670 	if((page == BARSWAP && data->m_data->swap_total == 0) || (page != BARSWAP && data->m_data->mem_total == 0))
671 		return;
672 
673 	for(i = BARUSED; (i <= page) && (page != BARSWAP); i++) /* Get value to start */
674 	{
675 		before += percent;
676 		percent = (double) data->m_data->mem_usage[i] / data->m_data->mem_total * 100;
677 	}
678 
679 	if(page == BARSWAP)
680 		percent = (double) data->m_data->mem_usage[BARSWAP] / data->m_data->swap_total * 100;
681 
682 	pat = cairo_pattern_create_linear(before / 100 * width, 0, percent / 100 * width, height);
683 
684 	switch(page) /* Set differents level bar color */
685 	{
686 		case BARUSED:
687 			cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 1.00, 0.15, 1);
688 			cairo_pattern_add_color_stop_rgba(pat, 1, 1.00, 0.75, 0.15, 1);
689 			break;
690 		case BARBUFFERS:
691 			cairo_pattern_add_color_stop_rgba(pat, 0, 0.00, 0.30, 0.75, 1);
692 			cairo_pattern_add_color_stop_rgba(pat, 1, 0.25, 0.55, 1.00, 1);
693 			break;
694 		case BARCACHED:
695 			cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 0.25, 0.90, 1);
696 			cairo_pattern_add_color_stop_rgba(pat, 1, 0.75, 0.00, 0.65, 1);
697 			break;
698 		case BARFREE:
699 			cairo_pattern_add_color_stop_rgba(pat, 0, 0.20, 1.00, 0.25, 1);
700 			cairo_pattern_add_color_stop_rgba(pat, 1, 0.00, 0.75, 0.05, 1);
701 			break;
702 		case BARSWAP:
703 			cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 0.35, 0.15, 1);
704 			cairo_pattern_add_color_stop_rgba(pat, 1, 0.75, 0.15, 0.00, 1);
705 			break;
706 	}
707 
708 	cairo_rectangle(cr, before / 100 * width, 0, percent / 100 * width, height); /* Print a colored rectangle */
709 	cairo_set_source(cr, pat);
710 	cairo_fill(cr);
711 	cairo_pattern_destroy(pat);
712 
713 	/* Print percentage */
714 	if(is_dark_theme(glab))
715 		cairo_set_source_rgb(cr, 0.8080, 0.8080, 0.0);
716 	else
717 		cairo_set_source_rgb(cr, 0.0, 0.0, 0.8080);
718 
719 	cairo_move_to(cr, -40, 0);
720 	pango_layout_set_text(newlayout, format("%.2f%%", percent), -1);
721 	pango_cairo_show_layout(cr, newlayout);
722 	cairo_fill(cr);
723 	g_object_unref(newlayout);
724 }
725