/*
    lsadl is a frontend/wrapper to the adl_sdk using gtk
    Copyright (C) 2011  Sterling Pickens

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ls_gtk.h"
#define GRAPH_W 680
#define GRAPH_H 480
//#define FAN_PERCENTAGE 1
int PerfLevels;
int Not_Started = 1;
int Disable_Fan = 0;
int Disable_Temp = 0;
int Disable_Usage = 0;
int Disable_PowerControl = 0;
int Disable_Force3d = 0;
int unlocked = 0;
struct GTK_Widgets gtk;
struct PERF_Cur *PerfCur;
struct PERF_Ranges PerfRanges;
ADLODParameters PerfParams;
//ADLPowerControlInfo PowerControlInfo;
//ADLI2C plI2C;
ADLODPerformanceLevels *PLevels;
GdkColor color;
struct Graph_Data{
	int perf[60];
	int usage[60];
	int fan[60];
	double temp[60];
}graphdata;
int graph_idx = 0;
int total_charts = 4;
struct Chart_Vectors{
	double black_top; //start of black
	double black_bottom; //end of black
	double data_top;
	double data_bottom;
}cv[4];

void on_toggle_unlock(GtkWidget *widget, GdkEventExpose *event, gpointer data);

void Adjust_spinner(GtkAdjustment *adjustment, GtkWidget *spiner, gdouble value){
	gtk_adjustment_set_value(adjustment, value);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(spiner), value);
	gtk_widget_show_all(spiner);
}

char Perf_Alloc(void){
	int num1 = 0;
	int num2 = 0;
	int ret_val = 0;
	ADLBiosInfo BiosInfo;
	ADLFanSpeedInfo FanSpeedInfo;
    ADLFanSpeedValue FanSpeedValue;
	ADLPowerControlInfo lpPowerControlInfo;
	PerfParams.iSize = sizeof(ADLODParameters);
	//plI2C.iSize = sizeof(ADLI2C);
	FanSpeedInfo.iSize = sizeof(ADLFanSpeedInfo);
	FanSpeedValue.iSize = sizeof(ADLFanSpeedValue);

	(void)memset(&graphdata, '\0', sizeof(struct Graph_Data));

	ret_val = LSADL_Adapter_VideoBiosInfo_Get(iAdapterIndex, &BiosInfo);
	if(ret_val != ADL_OK){
		printf("Cannot get VideoBiosInfo !\n");
		Print_Code(ret_val);
	}else{
		printf("Bios:\n");
		printf("\tPartNumber  %s\n", BiosInfo.strPartNumber);
		printf("\tVersion     %s\n", BiosInfo.strVersion);
		printf("\tDate        %s\n", BiosInfo.strDate);
	}
	ret_val = LSADL_OD5_FanSpeedInfo_Get(iAdapterIndex, 0, &FanSpeedInfo);
	if(ret_val != ADL_OK){
		printf("Cannot get FanSpeedInfo !\n");
		Print_Code(ret_val);
		Disable_Fan = 1;
	}
	ret_val = LSADL_OD5_FanSpeed_Get(iAdapterIndex, 0, &FanSpeedValue);
	if(ret_val != ADL_OK){
		printf("Cannot get FanSpeedValue !\n");
		Print_Code(ret_val);
		Disable_Fan = 1;
	}
	if(Disable_Fan)
		total_charts--;
	if(Disable_Temp)
		total_charts--;
	ret_val = LSADL_Adapter_ASICFamilyType_Get(iAdapterIndex, &num1, &num2);
	if(ret_val != ADL_OK){
		printf("Cannot get ASICFamilyType !\n");
		Print_Code(ret_val);
	}else{
		printf("Asic:\n");
		if((num1 & (int)ADL_ASIC_DISCRETE) != 0)
			printf("\tADL_ASIC_DISCRETE\n");
		if((num1 & (int)ADL_ASIC_INTEGRATED) != 0)
			printf("\tADL_ASIC_INTEGRATED\n");
		if((num1 & (int)ADL_ASIC_FIREGL) != 0)
			printf("\tADL_ASIC_FIREGL\n");
		if((num1 & (int)ADL_ASIC_FIREMV) != 0)
			printf("\tADL_ASIC_FIREMV\n");
		if((num1 & (int)ADL_ASIC_XGP) != 0)
			printf("\tADL_ASIC_XGP\n");
		if((num1 & (int)ADL_ASIC_FUSION) != 0)
			printf("\tADL_ASIC_FUSION\n");
		if((num1 & (int)ADL_ASIC_FIRESTREAM) != 0)
			printf("\tADL_ASIC_FIRESTREAM\n");
		if(num1 == (int)ADL_ASIC_UNDEFINED) //zero crude
			printf("\tADL_ASIC_UNDEFINED\n");
		//FIXME: bit vector valids nonsense
		//num2 check would be secondary
	}
	ret_val = LSADL_OD5_ODParameters_Get(iAdapterIndex, &PerfParams);
	if(ret_val != ADL_OK){
		printf("LSADL_OD5_ODParameters_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		return FALSE;
	}
	//if(!PerfParams.iActivityReportingSupported){
	//	printf("ActivityReportingSupported: False\n");
	//	Disable_Usage = 1;
		//printf("ERROR: lsadl cannot function without ActivityReporting support\n");
		//printf("Exiting!\n");
		//return FALSE;
	//}
	Disable_Usage = !PerfParams.iActivityReportingSupported;
	printf("ActivityReportingSupported: %d\n", PerfParams.iActivityReportingSupported);
	if(Disable_Usage)
		total_charts--;

	ret_val = LSADL_OD5_PowerControl_Caps(iAdapterIndex, &Disable_PowerControl);
	if(ret_val != ADL_OK){
		printf("ADL_OD5_PowerControl_Caps(\n");
		Print_Code(ret_val);
	}
	Disable_PowerControl ^= 1;

	if(!Disable_PowerControl){
		ret_val = LSADL_OD5_PowerControlInfo_Get(iAdapterIndex, &lpPowerControlInfo);
		if(ret_val != ADL_OK){
			printf("ADL_OD5_PowerControlInfo_Get(\n");
			Print_Code(ret_val);
		}
		printf("PowerControlInfo:\n");
		printf("min\t%d\n", lpPowerControlInfo.iMinValue);
		printf("max\t%d\n", lpPowerControlInfo.iMaxValue);
		printf("step\t%d\n", lpPowerControlInfo.iStepValue);

		ret_val = LSADL_OD5_PowerControl_Get(iAdapterIndex, &num1, &num2);
		if(ret_val != ADL_OK){
			printf("ADL_OD5_PowerControl_Get(\n");
			Print_Code(ret_val);
		}
		printf("cur\t%d\n", num1);
		printf("default\t%d\n", num2);
		PerfRanges.pc_min  = lpPowerControlInfo.iMinValue;
		PerfRanges.pc_max  = lpPowerControlInfo.iMaxValue;
		PerfRanges.pc_step = lpPowerControlInfo.iStepValue;
		PerfRanges.pc_cur  = num1;

	}

	ret_val = LSADL_Adapter_Speed_Caps(iAdapterIndex, &num1, &num2);
	if(ret_val != ADL_OK){
		printf("ADL_Adapter_Speed_Caps(\n");
		Print_Code(ret_val);
		Disable_Force3d = 1;
		//printf("Exiting!\n");
		//return FALSE;
	}
	ret_val = LSADL_Adapter_Speed_Get(iAdapterIndex, &PerfRanges.cur_force3d, &PerfRanges.def_force3d);
	if(ret_val != ADL_OK){
		printf("ADL_Adapter_Speed_Get(\n");
		Print_Code(ret_val);
		//printf("Exiting!\n");
		//return FALSE;
		Disable_Force3d = 1;
	}
	/*
	if(num2 == ADL_ADAPTER_SPEEDCAPS_SUPPORTED){
		printf("ADL_ADAPTER_SPEEDCAPS_SUPPORTED\n");
		if( PerfRanges.cur_force3d == ADL_CONTEXT_SPEED_UNFORCED)
			printf("ADL_CONTEXT_SPEED_UNFORCED is current force3d\n");
		if( PerfRanges.cur_force3d == ADL_CONTEXT_SPEED_FORCEHIGH)
			printf("ADL_CONTEXT_SPEED_FORCEHIGH is current force3d\n");
		if( PerfRanges.cur_force3d == ADL_CONTEXT_SPEED_FORCELOW)
			printf("ADL_CONTEXT_SPEED_FORCELOW is current force3d\n");
	}else{
		printf("no speedcaps support\n");
	}
	*/
	PerfLevels            = PerfParams.iNumberOfPerformanceLevels;
	PerfRanges.gpu_min    = PerfParams.sEngineClock.iMin;
	PerfRanges.gpu_max    = PerfParams.sEngineClock.iMax;
	PerfRanges.gpu_step   = 1;
	//PerfRanges.gpu_step   = PerfParams.sEngineClock.iStep;

	PerfRanges.mem_min    = PerfParams.sMemoryClock.iMin;
	PerfRanges.mem_max    = PerfParams.sMemoryClock.iMax;
	PerfRanges.mem_step   = 1;
	//PerfRanges.mem_step   = PerfParams.sMemoryClock.iStep;

	PerfRanges.vddc_min   = PerfParams.sVddc.iMin;
	//PerfRanges.vddc_min   = 700;
	PerfRanges.vddc_max   = PerfParams.sVddc.iMax;
	PerfRanges.vddc_step  = PerfParams.sVddc.iStep;

	PerfRanges.gpu_min    /= 100;
	PerfRanges.gpu_max    /= 100;
	//PerfRanges.gpu_step   /= 100;
	PerfRanges.mem_min    /= 100;
	PerfRanges.mem_max    /= 100;
	//PerfRanges.mem_step   /= 100;
	PerfRanges.vddc_min   /= 1000;
	PerfRanges.vddc_max   /= 1000;
	PerfRanges.vddc_step  /= 1000;

	if(!Disable_Fan){
#ifdef FAN_PERCENTAGE
		PerfRanges.fan_min = FanSpeedInfo.iMinPercent;
		PerfRanges.fan_max = FanSpeedInfo.iMaxPercent;
#else
		PerfRanges.fan_min = FanSpeedInfo.iMinRPM;
		PerfRanges.fan_max = FanSpeedInfo.iMaxRPM;
#endif
		PerfRanges.fan_step = 1;
		PerfRanges.fan_cur = FanSpeedValue.iFanSpeed;
	}

	num1 = sizeof(ADLODPerformanceLevels)+sizeof(ADLODPerformanceLevel)*(PerfLevels-1);
	PLevels = (ADLODPerformanceLevels *)malloc(num1);
	if(PLevels == NULL){
		printf("Error: malloc returned NULL !\n");
		return FALSE;
	}
	PLevels->iSize = num1;
	ret_val = LSADL_OD5_ODPerformanceLevels_Get(iAdapterIndex, 0, PLevels);
	if(ret_val != ADL_OK){
		printf("ADL_OD5_ODPerformanceLevels_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		return FALSE;
	}

	PerfCur = (struct PERF_Cur *)malloc(sizeof(struct PERF_Cur)*PerfLevels);
	if(PerfCur == NULL){
		printf("Error: malloc returned NULL !\n");
		free(PLevels);
		return FALSE;
	}

	for(num1=0; num1<PerfLevels; num1++){
		PerfCur[num1].id   = num1;
		PerfCur[num1].gpu  = PLevels->aLevels[num1].iEngineClock;
		PerfCur[num1].mem  = PLevels->aLevels[num1].iMemoryClock;
		PerfCur[num1].vddc = PLevels->aLevels[num1].iVddc;
		PerfCur[num1].gpu /= 100;
		PerfCur[num1].mem /= 100;
		PerfCur[num1].vddc /= 1000;
		//if any of these is out of range unlock should be done to display
	}

	return TRUE;
}

char Perf_Dealloc(void){
    free(PerfCur);
	free(PLevels);

	return TRUE;
}

static void on_destroy(GtkWidget *widget, gpointer mw){
	gtk_widget_destroy(mw);
}

gboolean on_file_load(GtkWidget *widget, GdkEventButton *event, gpointer data){
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new("Open File", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
		GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
	if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT){
		gchar *filename;
		char buff[8];
		int perf_id = 0;
		int line_num = 0;
		int remainder = 0;
		int gpu = 0;
		int mem = 0;
		int vddc = 0;
		(void)memset((void*)buff, '\0', 8);
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		printf("filename: %s\n", filename);
		FILE* fp;
		if( ( fp = fopen(filename, "r" ) ) == NULL ) {
			printf("Error opening file: %s\n", filename);
			g_free(filename);
			gtk_widget_destroy(dialog);
			return FALSE;
		}
		while( fgets(buff, 8, fp) != NULL){
			line_num++;
		}
		if(line_num != PerfLevels*3){
			printf("Error file contains wrong # of lines\n");
			g_free(filename);
			gtk_widget_destroy(dialog);
			fclose(fp);
			return FALSE;
		}
		line_num = 0;
		rewind(fp);
		(void)memset((void*)buff, '\0', 8);

		while( fgets(buff, 8, fp) != NULL){
			buff[strlen(buff)-1] = '\0';
			printf("%s\n", buff);

			if(line_num == 0){
				line_num++;
				gpu = atoi(buff);
				PLevels->aLevels[perf_id].iEngineClock = atoi(buff);
				PerfCur[perf_id].gpu  = PLevels->aLevels[perf_id].iEngineClock;
				PerfCur[perf_id].gpu /= 100;
				Adjust_spinner(PerfCur[perf_id].gpu_adj, PerfCur[perf_id].gpu_b, PerfCur[perf_id].gpu);
				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			if(line_num == 1){
				line_num++;
				mem = atoi(buff);
				PLevels->aLevels[perf_id].iMemoryClock = mem;
				PerfCur[perf_id].mem = PLevels->aLevels[perf_id].iMemoryClock;
				PerfCur[perf_id].mem /= 100;
				Adjust_spinner(PerfCur[perf_id].mem_adj, PerfCur[perf_id].mem_b, PerfCur[perf_id].mem);

				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			if(line_num == 2){
				line_num++;
				vddc = atoi(buff);
				PLevels->aLevels[perf_id].iVddc = vddc;
				PerfCur[perf_id].vddc = PLevels->aLevels[perf_id].iVddc;
				PerfCur[perf_id].vddc /= 1000;
				Adjust_spinner(PerfCur[perf_id].vddc_adj, PerfCur[perf_id].vddc_b, PerfCur[perf_id].vddc);
				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			//FIXME: unlock causes non-correct load if above range
			remainder = line_num % 3;
			if(remainder == 0){
				line_num++;
				perf_id++;
				gpu = atoi(buff);
				PLevels->aLevels[perf_id].iEngineClock = gpu;
				PerfCur[perf_id].gpu  = PLevels->aLevels[perf_id].iEngineClock;
				PerfCur[perf_id].gpu /= 100;
				//adjust spin button
				Adjust_spinner(PerfCur[perf_id].gpu_adj, PerfCur[perf_id].gpu_b, PerfCur[perf_id].gpu);
				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			if(remainder == 1){
				line_num++;
				mem = atoi(buff);
				PLevels->aLevels[perf_id].iMemoryClock = mem;
				PerfCur[perf_id].mem = PLevels->aLevels[perf_id].iMemoryClock;
				PerfCur[perf_id].mem /= 100;

				Adjust_spinner(PerfCur[perf_id].mem_adj, PerfCur[perf_id].mem_b, PerfCur[perf_id].mem);
				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			if(remainder == 2){
				line_num++;
				vddc = atoi(buff);
				PLevels->aLevels[perf_id].iVddc = vddc;
				PerfCur[perf_id].vddc = PLevels->aLevels[perf_id].iVddc;
				PerfCur[perf_id].vddc /= 1000;

				Adjust_spinner(PerfCur[perf_id].vddc_adj, PerfCur[perf_id].vddc_b, PerfCur[perf_id].vddc);
				(void)memset((void*)buff, '\0', 8);
				continue;
			}
			printf("Error: Failed to parse file!\n");
		}
		g_free(filename);
		fclose(fp);
	}
	gtk_widget_destroy (dialog);
	gtk_widget_show_all(GTK_WIDGET( widget ));
	return TRUE;
}

gboolean on_file_save(GtkWidget *widget, GdkEventButton *event, gpointer data){
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new("Save File", NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
		GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT){
		gchar *filename;
		FILE* fp;
		int perf_id = 0;
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
		printf("filename: %s\n", filename);

		//Need an ABI check and line  or md5sum check (gcrypt)
		if( (fp = fopen(filename, "w")) ){
			for(perf_id=0; perf_id<PerfLevels; perf_id++){
				fprintf(fp, "%d\n", PLevels->aLevels[perf_id].iEngineClock);
				fprintf(fp, "%d\n", PLevels->aLevels[perf_id].iMemoryClock);
				fprintf(fp, "%d\n", PLevels->aLevels[perf_id].iVddc);
			}
		}else{
			printf("Error opening file!\n");
		}
		g_free(filename);
		fclose(fp);
	}
	gtk_widget_destroy(dialog);
	gtk_widget_show_all(GTK_WIDGET(widget));
	return TRUE;
}

gboolean on_toggle_force3d(GtkWidget *widget, gpointer mw){
	if(Disable_Force3d)
		return FALSE;
	int ret_val = 0;
	printf("Here to force3d\n");
	if(gtk_combo_box_get_active((GtkComboBox *)(gtk.combo_box)) == ADL_CONTEXT_SPEED_UNFORCED){
		PerfRanges.cur_force3d = ADL_CONTEXT_SPEED_UNFORCED;
		printf("\tunforced\n");
	}
	if(gtk_combo_box_get_active((GtkComboBox *)(gtk.combo_box)) == ADL_CONTEXT_SPEED_FORCELOW){
		PerfRanges.cur_force3d = ADL_CONTEXT_SPEED_FORCELOW;
		printf("\tlow\n");
	}
	if(gtk_combo_box_get_active((GtkComboBox *)(gtk.combo_box)) == ADL_CONTEXT_SPEED_FORCEHIGH){
		PerfRanges.cur_force3d = ADL_CONTEXT_SPEED_FORCEHIGH;
		printf("\thigh\n");
	}
	ret_val = LSADL_Adapter_Speed_Set(iAdapterIndex, PerfRanges.cur_force3d);
	if(ret_val != ADL_OK){
		printf("Error: ADL_Adapter_Speed_Set\n");
		Print_Code(ret_val);
		return FALSE;
	}
	return TRUE;
}

void *Refresh_Func(void *empty){
	char value[16];
	int ret_val = 0;
	int num1 = 0;
	int seconds = 0;
	int cur_perf = 0;
	gdouble dtmp = 0;
	ADLPMActivity current;
	ADLFanSpeedInfo FanSpeedInfo;
	ADLFanSpeedValue FanSpeedValue;
	gpointer data = NULL;
	GdkEventExpose *event = NULL;

	current.iSize = sizeof(ADLPMActivity);
	FanSpeedInfo.iSize = sizeof(ADLFanSpeedInfo);
	FanSpeedValue.iSize = sizeof(ADLFanSpeedValue);

	while(Not_Started)
		sleep(1);

	while(No_Exit == 1){
		sleep(2);
		ret_val = LSADL_OD5_CurrentActivity_Get(iAdapterIndex, &current);
		if(ret_val != ADL_OK){
			printf("Cannot get the number of od5 power state!\n");
			Print_Code(ret_val);
			printf("Exiting!\n");
			No_Exit = 0;
			break;
		}

		ret_val = current.iCurrentPerformanceLevel;
		gdk_threads_enter();

		if(ret_val == PerfLevels)
			ret_val--;
		cur_perf = ret_val;
		for(num1=0; num1<PerfLevels; num1++){
			if(num1 == cur_perf){
				(void)sprintf(value, "-->%d", num1);
			}else{
				(void)sprintf(value, "%d", num1);
			}
			gtk_label_set_text((GtkLabel *)PerfCur[num1].table_labels, (const gchar *)value);
			gtk_widget_show(PerfCur[num1].table_labels);
		}
		(void)sprintf(value, "%d", ret_val);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[0], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[0]);

		dtmp = (double)current.iEngineClock/100;
		(void)sprintf(value, "%.02lfMHz", dtmp);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[1], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[1]);
		dtmp = (double)current.iMemoryClock/100;
		(void)sprintf(value, "%.02lfMHz", dtmp);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[2], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[2]);
		dtmp = (double)current.iVddc/1000;
		(void)sprintf(value, "%.02lfV", dtmp);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[3], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[3]);
		if(!Disable_Usage){
			(void)sprintf(value, "%d%%", current.iActivityPercent);
			gtk_label_set_text((GtkLabel *)gtk.ca_labels[4], (const gchar *)value);
			gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[4]);
		}
		dtmp = (double)current.iCurrentBusSpeed/1000;
		(void)sprintf(value, "%.02lfGT/s", dtmp);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[5], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[5]);
		(void)sprintf(value, "%dX", current.iMaximumBusLanes);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[6], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[6]);
		(void)sprintf(value, "%dX", current.iCurrentBusLanes);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[7], (const gchar *)value);
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[7]);

		if(!Disable_Fan){
			ret_val = LSADL_OD5_FanSpeedInfo_Get(iAdapterIndex, 0, &FanSpeedInfo);
			if(ret_val != ADL_OK){
				printf("Cannot get FanSpeedInfo !\n");
				Print_Code(ret_val);
				printf("Exiting!\n");
				No_Exit = 0;
				break;
			}
		}
		//#define ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ   1
		//#define ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE   2
		//#define ADL_DL_FANCTRL_SUPPORTS_RPM_READ   4
		//#define ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE   8

/*
		if(FanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ)
			printf("ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ\n");
		if(FanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE)
			printf("ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE\n");
		if(FanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_RPM_READ)
			printf("ADL_DL_FANCTRL_SUPPORTS_RPM_READ\n");
		if(FanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE)
			printf("ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE\n");
		printf("FanSpeedInfo\n");
		//iFlags
		printf("\t%d\n", FanSpeedInfo.iFlags);
		//iMinPercent
		printf("\t%d\n", FanSpeedInfo.iMinPercent);
		//iMaxPercent
		printf("\t%d\n", FanSpeedInfo.iMaxPercent);
		//iMinRPM
		printf("\t%d\n", FanSpeedInfo.iMinRPM);
		//iMaxRPM
		printf("\t%d\n", FanSpeedInfo.iMaxRPM);

*/
		if(!Disable_Fan){
			ret_val = LSADL_OD5_FanSpeed_Get(iAdapterIndex, 0, &FanSpeedValue);
			if(ret_val != ADL_OK){
				printf("Cannot get FanSpeedValue !\n");
				Print_Code(ret_val);
				printf("Exiting!\n");
				No_Exit = 0;
				break;
			}
#ifdef FAN_PERCENTAGE
			(void)sprintf(value, "%d%%", FanSpeedValue.iFanSpeed);
#else
			(void)sprintf(value, "%dRPM", FanSpeedValue.iFanSpeed);
#endif
			gtk_label_set_text((GtkLabel *)gtk.ca_labels[8], (const gchar *)value);
		}
		if(!Disable_Temp){
			ret_val = LSADL_OD5_Temperature_Get(iAdapterIndex, 0, &iTemperature);
			if(ret_val != ADL_OK){
				printf("Cannot get the number of od5 temperature!\n");
				Print_Code(ret_val);
				printf("Exiting!\n");
				No_Exit = 0;
				break;
			}
			dtmp = (double)iTemperature.iTemperature/1000;
			(void)sprintf(value, "%.02lfC", dtmp);
			gtk_label_set_text((GtkLabel *)gtk.ca_labels[9], (const gchar *)value);
			gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[9]);
		}
		seconds += 2;
		if(seconds % 60 == 0){
			graphdata.perf[graph_idx] = cur_perf;
			if(!Disable_Usage)
				graphdata.usage[graph_idx] = current.iActivityPercent;
			if(!Disable_Fan)
				graphdata.fan[graph_idx] = FanSpeedValue.iFanSpeed;
			if(!Disable_Temp)
				graphdata.temp[graph_idx] = dtmp;
			if(graph_idx == 59)
				graph_idx = 0;
			else
				graph_idx++;
			seconds = 0;
			(void)g_signal_emit_by_name(G_OBJECT(gtk.graph),  "expose-event", G_CALLBACK(on_expose_cairo), &data);
		}
		gdk_threads_leave();
	}
	pthread_exit(NULL);
}

void *GTK_Func(void *empty){
	int ret_val = 0;
	int num1 = 0;
	char tmp[10];
	gdouble temp_num = 0;
	gtk.main_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	//gtk_window_set_decorated(GTK_WINDOW(gtk.main_win), FALSE);
	gtk_container_set_border_width(GTK_CONTAINER(gtk.main_win), 2);
	gtk_window_set_default_size(GTK_WINDOW(gtk.main_win), 680, 400);
	gtk_window_set_title(GTK_WINDOW(gtk.main_win), PACKAGE_STRING);
	gtk.main_vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(gtk.main_win), gtk.main_vbox);

	gtk.main_menubar = gtk_menu_bar_new();
	gtk.main_filemenu = gtk_menu_new();
	gtk.main_file = gtk_menu_item_new_with_label("File");
	gtk.main_results = gtk_menu_item_new_with_label("API Results");
	gtk.main_quit = gtk_menu_item_new_with_label("Quit");

	gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtk.main_file), gtk.main_filemenu);
	gtk_menu_shell_append(GTK_MENU_SHELL(gtk.main_filemenu), gtk.main_results);
	gtk_menu_shell_append(GTK_MENU_SHELL(gtk.main_filemenu), gtk.main_quit);
	gtk_menu_shell_append(GTK_MENU_SHELL(gtk.main_menubar), gtk.main_file);

	gtk.table = gtk_table_new(PerfLevels+8, 5, TRUE); //h, w

	gtk.table_labels[0] = gtk_label_new("PerfLevel");
	gtk.table_labels[1] = gtk_label_new("GPU");
	gtk.table_labels[2] = gtk_label_new("MEM");
	gtk.table_labels[3] = gtk_label_new("Vddc");
	if(!Disable_PowerControl)
		gtk.table_labels[4] = gtk_label_new("PowerControl");
	gtk.table_labels[5] = gtk_label_new("Current:");
	gtk.table_labels[6] = gtk_label_new("PerfLevel");
	gtk.table_labels[7] = gtk_label_new("GPU");
	gtk.table_labels[8] = gtk_label_new("MEM");
	gtk.table_labels[9] = gtk_label_new("Vddc");
	if(!Disable_Usage)
		gtk.table_labels[10] = gtk_label_new("GPU usage");
	gtk.table_labels[11] = gtk_label_new("pcie speed");
	gtk.table_labels[12] = gtk_label_new("max lanes");
	gtk.table_labels[13] = gtk_label_new("cur lanes");
	gtk.table_labels[14] = gtk_label_new("Fan");
	gtk.table_labels[15] = gtk_label_new("Temp");
	gtk.table_labels[16] = gtk_label_new("");
	gtk.table_labels[17] = gtk_label_new("Fan:");

	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[0],        0, 1, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[1],        1, 2, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[2],        2, 3, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[3],        3, 4, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	for(num1=0; num1<PerfLevels; num1++){
		(void)sprintf(tmp, "%d", num1);
		PerfCur[num1].table_labels = gtk_label_new((const gchar *)tmp);

		temp_num = PerfCur[num1].gpu;
		if(temp_num > PerfRanges.gpu_max)
			PerfRanges.gpu_max = PerfCur[num1].gpu;
		if(temp_num < PerfRanges.gpu_min)
			PerfRanges.gpu_min = PerfCur[num1].gpu;
		PerfCur[num1].gpu_adj  = (GtkAdjustment *)gtk_adjustment_new(temp_num,   PerfRanges.gpu_min,  PerfRanges.gpu_max,  PerfRanges.gpu_step,  PerfRanges.gpu_step, 0.0);

		temp_num = PerfCur[num1].mem;
		if(temp_num > PerfRanges.mem_max)
			PerfRanges.mem_max = PerfCur[num1].mem;
		if(temp_num < PerfRanges.mem_min)
			PerfRanges.mem_min = PerfCur[num1].mem;
		PerfCur[num1].mem_adj  = (GtkAdjustment *)gtk_adjustment_new(temp_num,   PerfRanges.mem_min,  PerfRanges.mem_max,  PerfRanges.mem_step,  PerfRanges.mem_step, 0.0);

		temp_num = PerfCur[num1].vddc;
		if(temp_num > PerfRanges.vddc_max)
			PerfRanges.vddc_max = PerfCur[num1].vddc;
		if(temp_num < PerfRanges.vddc_min)
			PerfRanges.vddc_min = PerfCur[num1].vddc;
		PerfCur[num1].vddc_adj = (GtkAdjustment *)gtk_adjustment_new(temp_num,  PerfRanges.vddc_min, PerfRanges.vddc_max, PerfRanges.vddc_step, PerfRanges.vddc_step, 0.0);

		PerfCur[num1].gpu_b    = gtk_spin_button_new(PerfCur[num1].gpu_adj,  1, 3);
		PerfCur[num1].mem_b    = gtk_spin_button_new(PerfCur[num1].mem_adj,  1, 3);
		PerfCur[num1].vddc_b   = gtk_spin_button_new(PerfCur[num1].vddc_adj, 1, 3);
		PerfCur[num1].apply_b  = gtk_button_new_with_label("Apply");
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].table_labels),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].gpu_b),         1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].mem_b),         2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].vddc_b),        3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].apply_b),       4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		g_signal_connect(G_OBJECT(PerfCur[num1].apply_b), "clicked", G_CALLBACK(apply_cb), (gpointer)&(PerfCur[num1]));
	}
	if(!Disable_PowerControl){
		if(PerfRanges.pc_cur > PerfRanges.pc_max)
			PerfRanges.pc_max = PerfRanges.pc_cur;
		if(PerfRanges.pc_cur < PerfRanges.pc_min)
			PerfRanges.pc_min = PerfRanges.pc_cur;
		PerfCur[0].powercontrol_adj  = (GtkAdjustment *)gtk_adjustment_new(PerfRanges.pc_cur,   PerfRanges.pc_min,  PerfRanges.pc_max,  PerfRanges.pc_step,  PerfRanges.pc_step, 0.0);
		PerfCur[0].powercontrol_b    = gtk_spin_button_new(PerfCur[0].powercontrol_adj,  1, 3);
		PerfCur[0].powercontrol_set_b  = gtk_button_new_with_label("Apply");
		PerfCur[0].powercontrol_reset_b  = gtk_button_new_with_label("Reset");
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[4]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].powercontrol_b),       2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].powercontrol_set_b),   3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].powercontrol_reset_b), 4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		g_signal_connect(G_OBJECT(PerfCur[0].powercontrol_set_b), "clicked", G_CALLBACK(set_powercontrol_cb), (gpointer)&(PerfCur[0]));
		g_signal_connect(G_OBJECT(PerfCur[0].powercontrol_reset_b), "clicked", G_CALLBACK(reset_powercontrol_cb), (gpointer)&(PerfCur[0]));
	}
	num1++;
	if(!Disable_Fan){
		if(PerfRanges.fan_cur > PerfRanges.fan_max)
			PerfRanges.fan_max = PerfRanges.fan_cur;
		if(PerfRanges.fan_cur < PerfRanges.fan_min)
			PerfRanges.fan_min = PerfRanges.fan_cur;
		PerfCur[0].fan_adj  = (GtkAdjustment *)gtk_adjustment_new(PerfRanges.fan_cur,   PerfRanges.fan_min,  PerfRanges.fan_max,  PerfRanges.fan_step,  PerfRanges.fan_step, 0.0);
		PerfCur[0].fan_b    = gtk_spin_button_new(PerfCur[0].fan_adj,  1, 3);
		PerfCur[0].fan_set_b  = gtk_button_new_with_label("Apply");
		PerfCur[0].fan_reset_b  = gtk_button_new_with_label("Reset");
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[17]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].fan_b),       2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].fan_set_b),   3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[0].fan_reset_b), 4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		g_signal_connect(G_OBJECT(PerfCur[0].fan_set_b), "clicked", G_CALLBACK(set_fanspeed_cb), (gpointer)&(PerfCur[0]));
		g_signal_connect(G_OBJECT(PerfCur[0].fan_reset_b), "clicked", G_CALLBACK(reset_fanspeed_cb), (gpointer)&(PerfCur[0]));
	}
	num1++;
	//Current:
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[5]),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);

	if(!Disable_Force3d){
		gtk.combo_box = gtk_combo_box_text_new();
		gtk_combo_box_prepend_text((GtkComboBox *)gtk.combo_box, "ForceLow");
		gtk_combo_box_prepend_text((GtkComboBox *)gtk.combo_box, "ForceHigh");
		gtk_combo_box_prepend_text((GtkComboBox *)gtk.combo_box, "Unforced");
		gtk_combo_box_set_active((GtkComboBox *)gtk.combo_box, (gint)PerfRanges.cur_force3d);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).combo_box),        1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
		g_signal_connect(G_OBJECT(gtk.combo_box), "changed", G_CALLBACK(on_toggle_force3d), (gpointer)&gtk.combo_box);
	}

	gtk.unlock_box = gtk_check_button_new_with_label("unlock limts");
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).unlock_box),        2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	g_signal_connect(G_OBJECT(gtk.unlock_box), "toggled", G_CALLBACK(on_toggle_unlock), (gpointer)&gtk.unlock_box);


	gtk.load_b  = gtk_button_new_with_label("Load");
	gtk.save_b  = gtk_button_new_with_label("Save");
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).load_b),           3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).save_b),           4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	g_signal_connect(G_OBJECT(gtk.load_b), "clicked", G_CALLBACK(on_file_load), (gpointer)&(gtk.main_win) );
	g_signal_connect(G_OBJECT(gtk.save_b), "clicked", G_CALLBACK(on_file_save), (gpointer)&(gtk.main_win) );

	num1++;
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[6]),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[7]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[8]),  2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[9]),  3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	if(!Disable_Usage)
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[10]), 4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);

	gtk.ca_labels[0] = gtk_label_new("0");
	gtk.ca_labels[1] = gtk_label_new("0");
	gtk.ca_labels[2] = gtk_label_new("0");
	gtk.ca_labels[3] = gtk_label_new("0");
	gtk.ca_labels[4] = gtk_label_new("0");
	gtk.ca_labels[5] = gtk_label_new("0");
	gtk.ca_labels[6] = gtk_label_new("0");
	gtk.ca_labels[7] = gtk_label_new("0");
	gtk.ca_labels[8] = gtk_label_new("0"); //fan speed
	gtk.ca_labels[9] = gtk_label_new("0"); //temp
	gtk.ca_labels[10] = gtk_label_new("0");

	num1++;
	//ca_labels
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[0]),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[1]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[2]),  2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[3]),  3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	if(!Disable_Usage)
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[4]),  4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);

	num1++;

	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[11]),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[12]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[13]),  2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[14]),  3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[15]),  4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);

	num1++;

	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[5]),  0, 1, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[6]),  1, 2, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[7]),  2, 3, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[8]),  3, 4, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[9]),  4, 5, 1+num1, 2+num1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);

	gtk.scrolled_win = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk.scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(gtk.scrolled_win), gtk.table);

    gtk.notebook_label1 = gtk_label_new("settings");
    gtk.notebook_label2 = gtk_label_new("graphs");

	gtk.graph = gtk_drawing_area_new();
	gtk_widget_set_size_request(gtk.graph, GRAPH_W, GRAPH_H);

	gtk.graph_scroll = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk.graph_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(gtk.graph_scroll), gtk.graph);

	gtk.notebook = gtk_notebook_new();
    ret_val = gtk_notebook_append_page(GTK_NOTEBOOK(gtk.notebook), GTK_WIDGET(gtk.scrolled_win), GTK_WIDGET(gtk.notebook_label1));
    if(ret_val == -1){
        //error
        printf("Error creating notebook!\n");
        pthread_exit(NULL);
    }
    ret_val = gtk_notebook_append_page(GTK_NOTEBOOK(gtk.notebook), GTK_WIDGET(gtk.graph_scroll), GTK_WIDGET(gtk.notebook_label2));
    if(ret_val == -1){
        //error
        printf("Error creating notebook!\n");
        pthread_exit(NULL);
    }

	gtk_box_pack_start(GTK_BOX(gtk.main_vbox), gtk.main_menubar, FALSE, FALSE, 3);
	gtk_box_pack_end(GTK_BOX(gtk.main_vbox), gtk.notebook, TRUE, TRUE, 3);

	g_signal_connect(gtk.main_win, "destroy", G_CALLBACK(exit_cb), NULL);
	g_signal_connect(G_OBJECT(gtk.main_quit), "activate", G_CALLBACK(exit_cb), NULL);
	g_signal_connect(G_OBJECT(gtk.main_results), "activate", G_CALLBACK(API_Funcs_Found_Popup_cb), NULL);
	//Note that the ::expose-event signal has been replaced by a ::draw signal in GTK+ 3. The GTK+ 3 migration guide for hints on how to port from ::expose-event to ::draw.
#ifndef USE_GTK3
	g_signal_connect(G_OBJECT(gtk.graph),  "expose-event", G_CALLBACK(on_expose_cairo), NULL);
#else
	g_signal_connect(G_OBJECT(gtk.graph), "draw", G_CALLBACK(on_expose_cairo), NULL);
#endif
	gtk_widget_show_all(gtk.main_win);
	gtk_widget_realize(gtk.graph);
	Not_Started = 0;
	gtk_main();
	pthread_exit(NULL);
}

gboolean exit_cb(GtkWidget *widget, gpointer data){
	gtk_main_quit();
	No_Exit = 0;
	return TRUE;
}

gboolean set_powercontrol_cb(GtkWidget *widget, gpointer data){
	int ret_val = 0;
	int num1 = 0;
	//ADLPowerControlInfo	PCValue;
	if(Disable_PowerControl)
		return FALSE;
	gdouble pc = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->powercontrol_b) );
	printf("requested: %.03lf\n", pc);
	//PCValue.iSize = sizeof(PCValue);
	//ADL_Overdrive5_PowerControl_Get

	//ret_val = LSADL_OD5_PowerControl_Get(iAdapterIndex, 0, &PCValue);
	//if(ret_val != ADL_OK){
	//	printf("Cannot get PCValue !\n");
	//	Print_Code(ret_val);
	//	printf("\n");
	//	return FALSE;
	//}
	//PCValue.iFanSpeed = (int)floor(fan_rpm);
	//PCValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_PERCENT;
    //PCValue.iFlags = ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED;
    ret_val = LSADL_OD5_PowerControl_Set(iAdapterIndex, (int)floor(pc));
    if(ret_val != ADL_OK){
        printf("Cannot set PowerControl value !\n");
        Print_Code(ret_val);
        printf("\n");
        return FALSE;
    }

    printf("Success!\n");
    return TRUE;
}

gboolean reset_powercontrol_cb(GtkWidget *widget, gpointer data){
	int ret_val = 0;
	//ADLPowerControlInfo   PCValue;
	int lpDefaultValue = 0;
	int lpCurrentValue = 0;
	if(Disable_PowerControl)
		return FALSE;
	ret_val = LSADL_OD5_PowerControl_Get(iAdapterIndex, &lpCurrentValue, &lpDefaultValue);
	if(ret_val != ADL_OK){
		printf("Cannot get PowerControl values !\n");
		Print_Code(ret_val);
		printf("\n");
		return FALSE;
	}
	ret_val = LSADL_OD5_PowerControl_Set(iAdapterIndex, lpDefaultValue);
	if(ret_val != ADL_OK){
		printf("Cannot set PowerControl value !\n");
		Print_Code(ret_val);
		printf("\n");
		return FALSE;
	}
	Adjust_spinner(((struct PERF_Cur *)data)->powercontrol_adj, ((struct PERF_Cur *)data)->powercontrol_b, (gdouble)lpDefaultValue);
    gtk_widget_show_all( ((struct GTK_Widgets)gtk).main_win );
    printf("Success: powercontrol reset to default\n");
    return TRUE;
}

gboolean set_fanspeed_cb(GtkWidget *widget, gpointer data){
	int ret_val = 0;
	int num1 = 0;
    //ADLPMActivity current;
    //ADLFanSpeedInfo FanSpeedInfo;
	ADLFanSpeedValue FanSpeedValue;
	if(Disable_Fan)
		return FALSE;
	gdouble fan_rpm = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->fan_b) );
	printf("requested: %.03lf\n", fan_rpm);
	FanSpeedValue.iSize = sizeof(ADLFanSpeedValue);
	/*
        ret_val = LSADL_OD5_FanSpeedInfo_Get(iAdapterIndex, 0, &FanSpeedInfo);
        if(ret_val != ADL_OK){
            printf("Cannot get FanSpeedInfo !\n");
            Print_Code(ret_val);
            printf("Exiting!\n");
            No_Exit = 0;
            break;
        }
	*/
	ret_val = LSADL_OD5_FanSpeed_Get(iAdapterIndex, 0, &FanSpeedValue);
	if(ret_val != ADL_OK){
		printf("Cannot get FanSpeedValue !\n");
		Print_Code(ret_val);
		printf("\n");
		return FALSE;
	}
	FanSpeedValue.iFanSpeed = (int)floor(fan_rpm);
#ifdef FAN_PERCENTAGE
	FanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_PERCENT;
#else
	FanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
#endif
	FanSpeedValue.iFlags = ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED;
	ret_val = LSADL_OD5_FanSpeed_Set(iAdapterIndex, 0, &FanSpeedValue);
	if(ret_val != ADL_OK){
		printf("Cannot set FanSpeedValue !\n");
		Print_Code(ret_val);
		printf("\n");
		return FALSE;
	}
	printf("Success!\n");
	return TRUE;
}

gboolean reset_fanspeed_cb(GtkWidget *widget, gpointer data){
	int ret_val = 0;
	ADLFanSpeedValue FanSpeedValue;
	if(Disable_Fan)
		return FALSE;
	FanSpeedValue.iSize = sizeof(ADLFanSpeedValue);
	ret_val = LSADL_OD5_FanSpeedToDefault_Set(iAdapterIndex, 0);
	if(ret_val != ADL_OK){
		printf("Failed to Set fanspeed to default !\n");
		return FALSE;
	}

	ret_val = LSADL_OD5_FanSpeed_Get(iAdapterIndex, 0, &FanSpeedValue);
	if(ret_val != ADL_OK){
		printf("Cannot get FanSpeedValue !\n");
		Print_Code(ret_val);
		return FALSE;
	}

	Adjust_spinner(((struct PERF_Cur *)data)->fan_adj, ((struct PERF_Cur *)data)->fan_b, (gdouble)FanSpeedValue.iFanSpeed);
	gtk_widget_show_all( ((struct GTK_Widgets)gtk).main_win );
	printf("Success: fanspeeds reset to default\n");
	return TRUE;
}

gboolean apply_cb(GtkWidget *widget, gpointer data){
	gdouble gpu  = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->gpu_b) );
	gdouble mem  = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->mem_b) );
	gdouble vddc = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->vddc_b) );
	printf("requested: %.03lf %.03lf %.03lf\n", (double)gpu, (double)mem, (double)vddc);
	int ret_val = 0;
	int perf_id = (int)(((struct PERF_Cur *)data)->id);
	int gpu_bak  = PLevels->aLevels[perf_id].iEngineClock;
	int mem_bak  = PLevels->aLevels[perf_id].iMemoryClock;
	int vddc_bak = PLevels->aLevels[perf_id].iVddc;

	PLevels->aLevels[perf_id].iEngineClock = floor(gpu*100);
	PLevels->aLevels[perf_id].iMemoryClock = floor(mem*100);
	PLevels->aLevels[perf_id].iVddc        = floor(vddc*1000);

	printf("Attempting: %d %d %d\n", PLevels->aLevels[perf_id].iEngineClock, PLevels->aLevels[perf_id].iMemoryClock, PLevels->aLevels[perf_id].iVddc);

    ret_val = LSADL_OD5_ODPerformanceLevels_Set(iAdapterIndex, PLevels);
    if(ret_val != ADL_OK){
        printf("LSADL_OD5_ODPerformanceLevels_Set(\n");
        Print_Code(ret_val);
        printf("Failed!\n");
		//should just set defaults instead !! FIXME:
		PLevels->aLevels[perf_id].iEngineClock = gpu_bak;
		PLevels->aLevels[perf_id].iMemoryClock = mem_bak;
		PLevels->aLevels[perf_id].iVddc        = vddc_bak;
        return FALSE;
    }
	PerfCur[perf_id].gpu  = PLevels->aLevels[perf_id].iEngineClock;
	PerfCur[perf_id].mem  = PLevels->aLevels[perf_id].iMemoryClock;
	PerfCur[perf_id].vddc = PLevels->aLevels[perf_id].iVddc;
	PerfCur[perf_id].gpu /= 100;
	PerfCur[perf_id].mem /= 100;
	PerfCur[perf_id].vddc /= 1000;
	printf("Success!\n");
	gtk_widget_show_all( ((struct GTK_Widgets)gtk).main_win );
	return TRUE;
}

gboolean API_Funcs_Found_Popup_cb(GtkWidget *widget, gpointer data){
	int num1 = 0;
	int num2 = 0;
    GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_container_set_border_width(GTK_CONTAINER(win), 2);
    gtk_window_set_default_size(GTK_WINDOW(win), 600, 400);
    gtk_window_set_title(GTK_WINDOW(win), "API Status");
    GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(win), vbox);
    GtkWidget *top_table = gtk_table_new(LSADL_FUNCS, 3, TRUE);
	GtkWidget *top_table_labels[3];
    top_table_labels[0] = gtk_label_new("Function:");
    top_table_labels[1] = gtk_label_new("Status:");
    top_table_labels[2] = gtk_label_new("Note:");
	GtkWidget *all_labels[LSADL_FUNCS*3];

    gtk_table_attach(GTK_TABLE(top_table), top_table_labels[0],  0, 1, 0, 1, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 5, 5);
    gtk_table_attach(GTK_TABLE(top_table), top_table_labels[1],  1, 2, 0, 1, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 5, 5);
    gtk_table_attach(GTK_TABLE(top_table), top_table_labels[2],  2, 3, 0, 1, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 5, 5);

	num2 = 0;
	for(num1=0; num1<LSADL_FUNCS*3; num1+=3){
		all_labels[num1] = gtk_label_new((const gchar *)ADL_Func_Names[num2]);
		if(ADL_Func_Enabled[num2] == 1)
			all_labels[num1+1] = gtk_label_new((const gchar *)"Enabled");
		else
			all_labels[num1+1] = gtk_label_new((const gchar *)"Disabled");
		if(ADL_Func_Notes[num2] == FUNC_FOUND_IN_API)
			all_labels[num1+2] = gtk_label_new((const gchar *)"Found in API");
		else if(ADL_Func_Notes[num2] == FUNC_MISSING_FROM_API)
			all_labels[num1+2] = gtk_label_new((const gchar *)"Missing From API");
		else
			all_labels[num1+2] = gtk_label_new((const gchar *)"Disabled by LSADL");
		gtk_table_attach(GTK_TABLE(top_table), all_labels[num1],  0, 1, num1+1, num1+2, GTK_SHRINK, GTK_SHRINK, 5, 5);
		gtk_table_attach(GTK_TABLE(top_table), all_labels[num1+1],  1, 2, num1+1, num1+2, GTK_SHRINK, GTK_SHRINK, 5, 5);
		gtk_table_attach(GTK_TABLE(top_table), all_labels[num1+2],  2, 3, num1+1, num1+2, GTK_SHRINK, GTK_SHRINK, 5, 5);
		num2++;
	}
	GtkWidget *close_button = gtk_button_new_with_label("Close");
    GtkWidget *scrolled_win = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_win), top_table);
    gtk_box_pack_start(GTK_BOX(vbox), scrolled_win, TRUE, TRUE, 3);
    gtk_box_pack_end(GTK_BOX(vbox), close_button, FALSE, FALSE, 3);
	g_signal_connect(win, "destroy", G_CALLBACK(on_destroy), (gpointer)(win));
	g_signal_connect(G_OBJECT(close_button), "clicked", G_CALLBACK(on_destroy), (gpointer)(win));
	gtk_widget_show_all(win);

	return TRUE;
}

#ifndef USE_GTK3
void on_expose_cairo(GtkWidget *widget, GdkEventExpose *event, gpointer data){
#else
void on_expose_cairo(GtkWidget *widget, CairoContext *cr, gpointer data){
//Signal handlers connected to this signal can modify the cairo context passed as cr in any way they
//like and don't need to restore it. The signal emission takes care of calling cairo_save() before and cairo_restore() after invoking the handler.
#endif
	cairo_format_t format;
	cairo_surface_t *target;
	cairo_t *context;
	cairo_status_t status;
	double red, green, blue, alpha;
	double x1, y1, x2, y2;
	double last_x[4] = {0, 0, 0, 0};
	double last_y[4] = {0, 0, 0, 0};
	double tmp1 = 0;
	double tmp2 = 0;
	double highest_temp = 0;
	double highest_fan = 0;
	double highest_usage = 0;
	double width = (double)widget->allocation.width;
	double height = (double)widget->allocation.height;
	double white_height = height * 0.03;
	//double black_height = (height - white_height*5) / total_charts;
	double data_w = width * 0.95;
	//double data_h = black_height * 0.86;
	double black_height = 0;
	double data_h = 0;
	double data_s = data_w/60;
	int stride;
	int num1 = 0;
	int num2 = 0;
	int local_idx = graph_idx;
	unsigned char *img_data;
	char buffer[16];

	black_height = height;
	tmp1 = white_height;
	tmp1 *= total_charts + 1;
	black_height -= tmp1;
	black_height /= total_charts;
	data_h = black_height * 0.86;

	for(num1=0; num1<total_charts; num1++){
		cv[num1].black_top = (num1+1)*white_height + black_height*num1;
		cv[num1].black_bottom = cv[num1].black_top + black_height;
		cv[num1].data_top = cv[num1].black_top + black_height * 0.07;
		cv[num1].data_bottom = cv[num1].black_top + black_height - black_height * 0.07;
	}

	format = CAIRO_FORMAT_ARGB32;
	stride = cairo_format_stride_for_width(format, width);
	img_data = malloc(stride * height);
	target = cairo_image_surface_create_for_data(img_data, format, width, height, stride);
	context = gdk_cairo_create(GDK_DRAWABLE((gtk.graph)->window));

	status = cairo_status(context);
	if(status != 0){
		printf("Error: %s\n", cairo_status_to_string(status) );
		free(img_data);
		return;
	}

	red = 0;
	green = 0;
	blue = 0;
	alpha = 1.0;
	cairo_set_source_rgba(context, red, green, blue, alpha);
	cairo_rectangle(context, 0, 0, width, height);
	cairo_fill(context);
	red = 1.0;
	green = 1.0;
	blue = 1.0;
	alpha = 1.0;
	x1 = 0;
	y1 = 0;
	for(num1=0; num1<total_charts+1; num1++){
		cairo_set_source_rgba(context, red, green, blue, alpha);
		cairo_rectangle(context, x1, y1, width, white_height);
		cairo_fill(context);
		y1 += white_height + black_height;
	}

	x1 = 0;
	y1 = 0;
	x2 = width;
	y2 = height;

	red = 0;
	green = 1;
	blue = 0;
	alpha = 1.0;
	cairo_set_dash(context, 0, 0, 0);
	cairo_set_source_rgba(context, red, green, blue, alpha);
	cairo_set_line_width(context, 1);
	cairo_select_font_face(context, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(context, 10.0);
	for(num1=0; num1<60; num1++){
		if(!Disable_Fan){
			if(graphdata.fan[num1] > highest_fan)
				highest_fan = graphdata.fan[num1];
		}
		if(!Disable_Temp){
			if(graphdata.temp[num1] > highest_temp)
				highest_temp = graphdata.temp[num1];
		}
		if(!Disable_Usage){
			if(graphdata.usage[num1] > highest_usage)
				highest_usage = graphdata.usage[num1];
		}
	}

	/*
	//cairo labels
	num1 = 0;
	cairo_move_to(context, width/2, cv[num1].data_top);
	cairo_show_text(context, "Perf Level");
	num1++;

	cairo_move_to(context, width/2, cv[num1].data_top);
	cairo_show_text(context, "GPU Usage");
	num1++;
	if(!Disable_Fan){
		cairo_move_to(context, width/2, cv[num1].data_top);
		cairo_show_text(context, "Fan Speed");
		num1++;
	}
	cairo_move_to(context, width/2, cv[num1].data_top);
	cairo_show_text(context, "GPU Temp");
	*/

	//labels and High/low legend
	num1 = 0;
	cairo_move_to(context, width/2, cv[num1].data_top);
	cairo_show_text(context, "Perf Level");
	cairo_move_to(context, data_w, cv[num1].data_top);
	(void)memset(buffer, '\0', 16);
	(void)sprintf(buffer, "%d", (int)PerfLevels-1);
	cairo_show_text(context, buffer);
	cairo_move_to(context, data_w, cv[num1].data_bottom);
	cairo_show_text(context, "0");
	num1++;

	if(!Disable_Usage){
		cairo_move_to(context, width/2, cv[num1].data_top);
		cairo_show_text(context, "GPU Usage");
		cairo_move_to(context, data_w, cv[num1].data_top);
		cairo_show_text(context, "100");
		cairo_move_to(context, data_w, cv[num1].data_bottom);
		cairo_show_text(context, "0");
		num1++;
	}

	if(!Disable_Fan){
		cairo_move_to(context, width/2, cv[num1].data_top);
		cairo_show_text(context, "Fan Speed");
		cairo_move_to(context, data_w, cv[num1].data_top);
		(void)memset(buffer, '\0', 16);
		(void)sprintf(buffer, "%u", (unsigned int)highest_fan);
		cairo_show_text(context, buffer);
		cairo_move_to(context, data_w, cv[num1].data_bottom);
		cairo_show_text(context, "0");
		num1++;
	}

	if(!Disable_Temp){
		cairo_move_to(context, width/2, cv[num1].data_top);
		cairo_show_text(context, "GPU Temp");
		cairo_move_to(context, data_w, cv[num1].data_top);
		(void)memset(buffer, '\0', 16);
		(void)sprintf(buffer, "%.01lf", highest_temp);
		cairo_show_text(context, buffer);
		cairo_move_to(context, data_w, cv[num1].data_bottom);
		cairo_show_text(context, "0");
	}

	for(num1=0; num1<60; num1++){
		num2 = 0;

		tmp1 = cv[num2].data_bottom;
		tmp2 = (double)graphdata.perf[local_idx]/(PerfLevels-1);
		tmp2 *= data_h;
		tmp1 -= tmp2;
		if(last_x[num2] + last_y[num2] != 0){
			cairo_move_to(context, last_x[num2], last_y[num2]);
			cairo_line_to(context, (double)num1*data_s, tmp1);
			cairo_stroke(context);
		}
		last_x[num2] = num1*data_s;
		last_y[num2] = tmp1;
		num2++;

		if(!Disable_Usage){
			tmp1 = cv[num2].data_bottom;
			tmp2 = (double)graphdata.usage[local_idx]/100;
			tmp2 *= data_h;
			tmp1 -= tmp2;
			if(last_x[num2] + last_y[num2] != 0){
				cairo_move_to(context, last_x[num2], last_y[num2]);
				cairo_line_to(context, (double)num1*data_s, tmp1);
				cairo_stroke(context);
			}
			last_x[num2] = num1*data_s;
			last_y[num2] = tmp1;
			num2++;
		}

		if(!Disable_Fan){
			tmp1 = cv[num2].data_bottom;
			tmp2 = (double)graphdata.fan[local_idx]/highest_fan;
			tmp2 *= data_h;
			tmp1 -= tmp2;
			if(last_x[num2] + last_y[num2] != 0){
				cairo_move_to(context, last_x[num2], last_y[num2]);
				cairo_line_to(context, (double)num1*data_s, tmp1);
				cairo_stroke(context);
			}
			last_x[num2] = num1*data_s;
			last_y[num2] = tmp1;
			num2++;
		}

		if(!Disable_Temp){
			tmp1 = cv[num2].data_bottom;
			tmp2 = (double)graphdata.temp[local_idx]/highest_temp;
			tmp2 *= data_h;
			tmp1 -= tmp2;
			if(last_x[num2] + last_y[num2] != 0){
				cairo_move_to(context, last_x[num2], last_y[num2]);
				cairo_line_to(context, (double)num1*data_s, tmp1);
				cairo_stroke(context);
			}
			last_x[num2] = num1*data_s;
			last_y[num2] = tmp1;
		}

		if(local_idx == 59)
			local_idx = 0;
		else
			local_idx++;
	}

	cairo_destroy(context);
	cairo_surface_destroy(target);
	free(img_data);
}

void on_toggle_unlock(GtkWidget *widget, GdkEventExpose *event, gpointer data){
	int num1 = 0;
	unlocked ^= 1;
	while(num1 < PerfLevels){
		if(unlocked){
			PerfCur[num1].gpu_adj->lower = PerfRanges.gpu_step;
			PerfCur[num1].gpu_adj->upper = 10000;
			PerfCur[num1].mem_adj->lower = PerfRanges.mem_step;
			PerfCur[num1].mem_adj->upper = 10000;
			PerfCur[num1].vddc_adj->lower = PerfRanges.vddc_step;
			PerfCur[num1].vddc_adj->upper = 2.0;
		}else{
			PerfCur[num1].gpu_adj->lower = PerfRanges.gpu_min;
			PerfCur[num1].gpu_adj->upper = PerfRanges.gpu_max;
			PerfCur[num1].mem_adj->lower = PerfRanges.mem_min;
			PerfCur[num1].mem_adj->upper = PerfRanges.mem_max;
			PerfCur[num1].vddc_adj->lower = PerfRanges.vddc_min;
			PerfCur[num1].vddc_adj->upper = PerfRanges.vddc_max;
		}
		num1++;
	}
	if(!Disable_PowerControl){
		if(unlocked){
			PerfCur[0].powercontrol_adj->lower = -10000;
			PerfCur[0].powercontrol_adj->upper = 10000;
		}else{
			PerfCur[0].powercontrol_adj->lower = PerfRanges.pc_min;
			PerfCur[0].powercontrol_adj->upper = PerfRanges.pc_max;
		}
	}
	if(!Disable_Fan){
		//fan
		if(unlocked){
			PerfCur[0].fan_adj->lower = PerfRanges.fan_step;
			PerfCur[0].fan_adj->upper = 10000;
		}else{
			PerfCur[0].fan_adj->lower = PerfRanges.fan_min;
			PerfCur[0].fan_adj->upper = PerfRanges.fan_max;
		}
	}
	gtk_widget_show_all(((struct GTK_Widgets)gtk).main_win);
}