/*
    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
int PerfLevels;
int Not_Started = 1;
int unlocked = 0;
long long total_gmem = 0;
//int cb_graph[4] = {0, 1, 2, 3};
struct GTK_Widgets gtk;
struct PERF_Cur *PerfCur;
struct PERF_Ranges PerfRanges;
ADLODParameters PerfParams;
ADLODPerformanceLevels *PLevels;
//ADLPMActivity
GdkColor color;
//GdkColor color_red;
//GdkColor color_green;
//GdkColor color_blue;
//    unsigned int params[4];

//    (void)GL_Mem_Free(params);



struct Graph_Data{
	int perf[60];
	int usage[60];
	int fan[60];
	double mem[60];
	double temp[60];
	//int idx;
}graphdata;
int graph_idx = 0;
const int total_charts = 5;
struct Chart_Vectors{
	double black_top; //start of black
	double black_bottom; //end of black
	double data_top;
	double data_bottom;

	//double right; // end of data points
	//double h; // pixels for data points
	//double w; // pixels for data points
	//double h_tenth; //used for borders
	//double w_tenth; // used for borders
	//double w_step; // step for each data point
}cv[5];


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

//typedef struct {
//  guint32 pixel;
//  guint16 red;
//  guint16 green;
//  guint16 blue;
//} GdkColor;

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


char Perf_Alloc(void){
	int num1 = 0;
	int num2 = 0;
	int ret_val = 0;
	ADLBiosInfo BiosInfo;
	ADLFanSpeedInfo FanSpeedInfo;
    ADLFanSpeedValue FanSpeedValue;

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

	ret_val = LSADL_Adapter_VideoBiosInfo_Get(iAdapterIndex, &BiosInfo);
	if(ret_val != ADL_OK){
		printf("Error: ADL_Adapter_VideoBiosInfo_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		return FALSE;
	}
	printf("%s\n", BiosInfo.strPartNumber);
	printf("%s\n", BiosInfo.strVersion);
	printf("%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);
		printf("Exiting!\n");
		//No_Exit = 0;
		//break;
		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);
		printf("Exiting!\n");
		return FALSE;
	}


	/*
	#define 	ADL_ASIC_UNDEFINED   0
	#define 	ADL_ASIC_DISCRETE   (1 << 0)
	#define 	ADL_ASIC_INTEGRATED   (1 << 1)
	#define 	ADL_ASIC_FIREGL   (1 << 2)
	#define 	ADL_ASIC_FIREMV   (1 << 3)
	#define 	ADL_ASIC_XGP   (1 << 4)
	#define 	ADL_ASIC_FUSION   (1 << 5)
	*/
	ret_val = LSADL_Adapter_ASICFamilyType_Get(iAdapterIndex, &num1, &num2);
	if(ret_val != ADL_OK){
		printf("Error: ADL_Adapter_ASICFamilyType_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		return FALSE;
	}
	printf("Asic: %d %d\n", num1, num2);


	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;
	}
	/*
    ret_val = LSADL_Adapter_Speed_Set(iAdapterIndex, ADL_CONTEXT_SPEED_FORCEHIGH);
    if(ret_val != ADL_OK){
        printf("Error: ADL_Adapter_Speed_Set\n");
        Print_Code(ret_val);
        //if(PerfRanges.cur_force3d == ADL_ADAPTER_SPEEDCAPS_SUPPORTED)
        return FALSE;
    }
	*/

	ret_val = LSADL_Adapter_Speed_Caps(iAdapterIndex, &num1, &num2);
	if(ret_val != ADL_OK){
		printf("ADL_Adapter_Speed_Caps(\n");
		Print_Code(ret_val);
		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;
	}
	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");
	/*
	if(num1 == ADL_ADAPTER_SPEEDCAPS_SUPPORTED){
		printf("num1 ADL_ADAPTER_SPEEDCAPS_SUPPORTED\n");
	}else if(num1 == 0){
		printf("num1 0\n");
	}
	*/
		/*
		if(num1 == ADL_CONTEXT_SPEED_UNFORCED){
			printf("\tcurrent: ADL_CONTEXT_SPEED_UNFORCED\n");
		}else if(num1 == ADL_CONTEXT_SPEED_FORCEHIGH){
			printf("\tcurrent: ADL_CONTEXT_SPEED_FORCEHIGH\n");
		}else if(num1 == ADL_CONTEXT_SPEED_FORCELOW){
			printf("\tcurrent: ADL_CONTEXT_SPEED_FORCELOW\n");
		}else{
			 printf("\tcurrent: unrecognized return value !\n");
		}
		*/
	}else{
		printf("no speedcaps support\n");
	}

	/*
	color_red.red     = 255;
	color_red.green   = 5;
	color_red.blue    = 5;
	color_green.red   = 5;
	color_green.green = 255;
	color_green.blue  = 5;
	color_blue.red    = 5;
	color_blue.green  = 5;
	color_blue.blue   = 255;
	gdk_color_parse("red", &color_red);
	gdk_color_parse("green", &color_green);
	gdk_color_parse("blue", &color_blue);
	*/
	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;

	//PerfRanges.fan_min = 0;
	//PerfRanges.fan_max = 100;
	PerfRanges.fan_min = FanSpeedInfo.iMinRPM;
	PerfRanges.fan_max = FanSpeedInfo.iMaxRPM;
	PerfRanges.fan_step = 1;
	PerfRanges.fan_cur = FanSpeedValue.iFanSpeed;

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

	//allocate memory
	PerfCur           = (struct PERF_Cur *)malloc(sizeof(struct PERF_Cur)*PerfLevels);
	if(PerfCur == NULL){
		free(PLevels);
		return FALSE;
	}

	for(num1=0; num1<PerfLevels; num1++){
		//printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iEngineClock);
		//printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iMemoryClock);
		//printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iVddc);
		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;
		//printf("%lf %lf %lf\n", PerfCur[num1].gpu, PerfCur[num1].mem, PerfCur[num1].vddc);
	}
	//ADL_Adapter_Speed_Get(iAdapterIndex, 




	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){
	//gdk_threads_enter();
	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);
		//load_portfolio(filename);
		FILE* fp;
		if( ( fp = fopen(filename, "r" ) ) == NULL ) {
			printf("Error opening file: %s\n", filename);
			g_free(filename);
			gtk_widget_destroy(dialog);
			//gdk_threads_leave();
			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);
			//gdk_threads_leave();
			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);
				//gtk_adjustment_set_value(PerfCur[num1].gpu_adj, PerfCur[num1].gpu);
				//gtk_spin_button_set_value(GTK_SPIN_BUTTON(PerfCur[num1].gpu_b), PerfCur[num1].gpu);
				//gtk_widget_show_all(GTK_WIDGET(PerfCur[num1].gpu_b));
				(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;
			}

			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;
			}
			//atoi(buff);
			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 #55!\n");
		}
		g_free(filename);
		fclose(fp);
	}
	gtk_widget_destroy (dialog);
	gtk_widget_show_all(GTK_WIDGET( widget ));
	//gdk_threads_leave();

	return TRUE;
}

gboolean on_file_save(GtkWidget *widget, GdkEventButton *event, gpointer data){
	//gdk_threads_enter();
	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;
		//gchar linestring[16];
		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)


		//linestring = (gchar *)mallo
		if( (fp = fopen(filename, "w")) ){
			//(void)memset((void*)linestring, '\0', 16);
			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));
	//gdk_threads_leave();
	return TRUE;
}

gboolean on_toggle_force3d(GtkWidget *widget, gpointer mw){
	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 params[4] = {0, 0, 0, 0};
	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;


	while(Not_Started)
		sleep(1);

	while(No_Exit == 1){
		sleep(2);
//		for(num1=0; num1<PerfLevels; num1++){
//			printf("%d: %lf %lf %lf\n", num1, (double)(PerfCur[num1].gpu), (double)(PerfCur[num1].mem), (double)(PerfCur[num1].vddc));
//			gtk_adjustment_set_value(((struct PERF_Cur )PerfCur[num1]).gpu_adj, PerfCur[num1].gpu);
//			gtk_adjustment_set_value(((struct PERF_Cur )PerfCur[num1]).mem_adj, PerfCur[num1].mem);
//			gtk_adjustment_set_value(((struct PERF_Cur )PerfCur[num1]).vddc_adj, PerfCur[num1].vddc);

			//gtk_spin_button_set_value(GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).gpu_b), PerfCur[num1].gpu);
		//	gtk_spin_button_set_value(GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).mem_b), PerfCur[num1].mem);
		//	gtk_spin_button_set_value(GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).vddc_b), PerfCur[num1].vddc);
//(uint32_t)gtk_spin_button_get_value_as_int( (GtkSpinButton *)(((struct GTK_Widgets *)data)->gpu_button) );

//gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).gpu_b), ((struct PERF_Cur )PerfCur[num1]).gpu_adj);
//gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).mem_b), ((struct PERF_Cur )PerfCur[num1]).mem_adj);
//gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(((struct PERF_Cur )PerfCur[num1]).vddc_b), ((struct PERF_Cur )PerfCur[num1]).vddc_adj);

//gtk_spin_button_set_value( GtkSpinButton *spin_button,
//                                gfloat         value );


//			gtk_widget_show( GTK_WIDGET(((struct PERF_Cur )PerfCur[num1]).gpu_b) );
//			gtk_widget_show( GTK_WIDGET(((struct PERF_Cur )PerfCur[num1]).mem_b) );
//			gtk_widget_show( GTK_WIDGET(((struct PERF_Cur )PerfCur[num1]).vddc_b) );
//		}
		//printf("here !\n");
		//query temps

		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;
		//PerfCur[ret_val].table_labels
		gdk_threads_enter();
		//printf("%d\n", PerfLevels);

		// CARD BIOS/DRIVER BUG ?
		//0 and 2 reported, instead of 0 and 1
		//2 other cards report right
		if(ret_val == PerfLevels)
			ret_val--;
		cur_perf = ret_val;
		for(num1=0; num1<PerfLevels; num1++){
			if(num1 == cur_perf){
				//(void)sprintf(value, "%d", ret_val);
				//gtk_label_set_text((GtkLabel *)gtk.ca_labels[0], (const gchar *)value);
				(void)sprintf(value, "-->%d", num1);
			}else{
				(void)sprintf(value, "%d", num1);
			}
			//gtk.ca_labels[0]
			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]);

		//gdk_threads_enter();
		//printf("CurrentActivity:\n");
		//iCurrentPerformanceLevel
		//printf("\t%d\n", current.iCurrentPerformanceLevel);
		//dtmp = (double)current.iCurrentPerformanceLevel;
		//(void)sprintf(value, "%d", current.iCurrentPerformanceLevel);
		//gtk_label_set_text((GtkLabel *)gtk.ca_labels[0], (const gchar *)value);
		//gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[0]);
		//iEngineClock
		//printf("\t%.03lf\n", (double)current.iEngineClock/100);
		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]);
		//iMemoryClock
		//printf("\t%.03lf\n", (double)current.iMemoryClock/100);
		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]);
		//iVddc
		//printf("\t%.03lf\n", (double)current.iVddc/1000);
		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]);
		//iActivityPercent
		//printf("\t%.03lf\n", (double)current.iActivityPercent);
		(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]);
		//iCurrentBusSpeed
		//printf("\t%.03lf\n", (double)current.iCurrentBusSpeed);
		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]);
		//iMaximumBusLanes
		(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]);
		//iCurrentBusLanes
		//printf("\t%d\n", current.iCurrentBusLanes);
		(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]);
		//iMaximumBusLanes
		//printf("\t%d\n", current.iMaximumBusLanes);
		//iReserved
		//printf("\t%d\n", current.iReserved);



		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);

*/
		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;
		}


//		printf("FanSpeedValues\n");
		//ADL_DL_FANCTRL_SPEED_TYPE_PERCENT or ADL_DL_FANCTRL_SPEED_TYPE_RPM
		//iSpeedType
/*
#ifdef ADL_DL_FANCTRL_SPEED_TYPE_PERCENT
		if(FanSpeedValue.iSpeedType == ADL_DL_FANCTRL_SPEED_TYPE_PERCENT)
			printf("\tADL_DL_FANCTRL_SPEED_TYPE_PERCENT\n");
#endif
#ifdef ADLDL_FANCTRL_SPEED_TYPE_RPM
		if(FanSpeedValue.iSpeedType == ADLDL_FANCTRL_SPEED_TYPE_RPM)
			printf("\tADLDL_FANCTRL_SPEED_TYPE_RPM\n");
#endif
		//iFanSpeed
//		printf("%d\n", FanSpeedValue.iFanSpeed);
*/
//		if(FanSpeedValue.iSpeedType == ADLDL_FANCTRL_SPEED_TYPE_RPM)
			(void)sprintf(value, "%d rpm", FanSpeedValue.iFanSpeed);
//		else
//			(void)sprintf(value, "%d %%", FanSpeedValue.iFanSpeed);
		gtk_label_set_text((GtkLabel *)gtk.ca_labels[8], (const gchar *)value);
		//ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED
		//iFlags
// #define ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED   1
/*
#ifdef ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED
		if(FanSpeedValue.iFlags == ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED)
			printf("\tADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED\n");
#endif
*/


		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);
		//update labels

/*
		if(dtmp > 40){
			gdk_color_parse("red", &color);
			gtk_widget_modify_fg(((struct GTK_Widgets) gtk).table_labels[5], GTK_STATE_NORMAL, &color);
		}else{
			gdk_color_parse("green", &color);
			gtk_widget_modify_fg(((struct GTK_Widgets) gtk).table_labels[5], GTK_STATE_NORMAL, &color);
		}
*/
		//refresh the labels
		gtk_widget_show(((struct GTK_Widgets) gtk).ca_labels[9]);
		gdk_threads_leave();
		//(void)GL_Mem_Free(params);
		//printf("%u\n", params[0]);
		//gtk_widget_show_all(gtk.main_win);
		seconds += 2;
		if(seconds % 60 == 0){
			//GL_Mem_Free();
			//printf("%u\n", params[0]);
			glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, (GLint *)params);
			graphdata.mem[graph_idx] = (double)total_gmem - params[0];
			printf("%lf\n", graphdata.mem[graph_idx]);

			graphdata.perf[graph_idx] = cur_perf;
			graphdata.usage[graph_idx] = current.iActivityPercent;
			graphdata.fan[graph_idx] = FanSpeedValue.iFanSpeed;
			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);

			//gtk_signal_emit_by_name(G_OBJECT(gtk.graph),  "expose-event", G_CALLBACK(on_expose_cairo), NULL);
			//g_signal_connect(G_OBJECT(gtk.graph),  "expose-event", G_CALLBACK(on_expose_cairo), NULL);
			//(void)on_expose_cairo(gtk.graph, event, data);
		}
		//gdk_threads_leave();
		//gtk_widget_show_all(((struct GTK_Widgets)gtk).main_win);
	}
	pthread_exit(NULL);
}

void *GTK_Func(void *empty){
	//uint32_t num1 = 0;
	//struct GTK_Widgets gtk;
	int ret_val = 0;
	int num1 = 0;
	/*
	ADLODParameters lpOdParams;
	ADLODPerformanceLevels *lpOdPerfLevels;
	gdouble mem_min = 0;
	gdouble mem_max = 0;
	gdouble mem_step = 0;
	gdouble mem_cur = 0;
	gdouble gpu_min = 0;
	gdouble gpu_max = 0;
	gdouble gpu_step = 0;
	gdouble gpu_cur = 0;
	gdouble vddc_min = 0;
	gdouble vddc_max = 0;
	gdouble vddc_step = 0;
	gdouble vddc_cur = 0;
	*/
	char tmp[10];
	//char title[14];
	//(void)strcpy(title, PACKAGE_NAME);

	gdouble temp_num = 0;
	//struct PERF_Cur *PerfCur;
	//ADLODParameterRange gpu_range;
	//ADLODParameterRange mem_range;
	//ADLODParameterRange vddc_range;
	//gdk_threads_enter();
	gtk.main_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_container_set_border_width(GTK_CONTAINER(gtk.main_win), 2);
	gtk_window_set_default_size(GTK_WINDOW(gtk.main_win), 680, 360);
	gtk_window_set_title(GTK_WINDOW(gtk.main_win), PACKAGE_STRING);
/*
	gtk.notebook_label1 = gtk_label_new("settings");
	gtk.notebook_label2 = gtk_label_new("graphs");

	gtk.notebook = gtk_notebook_new();
	ret_val = gtk_notebook_append_page(GTK_NOTEBOOK(gtk.notebook), GTK_WIDGET(gtk.notebook_page1), 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.notebook_page2), GTK_WIDGET(gtk.notebook_label2));
	if(ret_val == -1){
		//error
		printf("Error creating notebook!\n");
		pthread_exit(NULL);
	}
	gtk_container_add (GTK_CONTAINER(gtk.main_vbox), gtk.notebook);

*/
	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_box_pack_start(GTK_BOX(gtk.main_vbox), gtk.main_menubar, FALSE, FALSE, 3);

	//get number of perflevels
	//LSADL_OD5_ODPerformanceLevels_Get(iAdapterIndex, 1, ADLODPerformanceLevels *lpOdPerformanceLevels)
	/*
	ret_val = LSADL_OD5_ODParameters_Get(iAdapterIndex, &lpOdParams);
	if(ret_val != ADL_OK){
		printf("LSADL_OD5_ODParameters_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		No_Exit = 0;
		// FIXME
	}
	PerfLevels = lpOdParams.iNumberOfPerformanceLevels;
	gpu_min    = lpOdParams.sEngineClock.iMin;
	gpu_max    = lpOdParams.sEngineClock.iMax;
	gpu_step   = lpOdParams.sEngineClock.iStep;
	mem_min    = lpOdParams.sMemoryClock.iMin;
	mem_max    = lpOdParams.sMemoryClock.iMax;
	mem_step   = lpOdParams.sMemoryClock.iStep;
	vddc_min   = lpOdParams.sVddc.iMin;
	vddc_max   = lpOdParams.sVddc.iMax;
	vddc_step  = lpOdParams.sVddc.iStep;


	//(void)memset((void *)&lpOdPerformanceLevels, '\0', sizeof(struct ADLODPerformanceLevels));
	//lpOdPerformanceLevels.aLevels = NULL;
	num1 = sizeof(ADLODPerformanceLevels)+sizeof(ADLODPerformanceLevel)*(PerfLevels-1);
	lpOdPerfLevels = (ADLODPerformanceLevels *)malloc(num1);
	lpOdPerfLevels->iSize = num1;
	//lpOdPerformanceLevels.aLevels = (struct ADLODPerformanceLevel *)malloc(sizeof(struct ADLODPerformanceLevel)*PerfLevels);
	//'struct ADLODPerformanceLevel[1]' from type 'void *'

	ret_val = LSADL_OD5_ODPerformanceLevels_Get(iAdapterIndex, 1, lpOdPerfLevels);
	if(ret_val != ADL_OK){
		printf("LSADL_OD5_ODPerformanceLevels_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		No_Exit = 0;
	}

	//allocate memory
	PerfCur           = (struct PERF_Cur *)malloc(sizeof(struct PERF_Cur)*PerfLevels);
	gtk.apply_button  = (GtkWidget **)malloc(sizeof(GtkWidget *)*PerfLevels);

	gtk.gpu_adj       = (GtkAdjustment **)malloc(sizeof(GtkAdjustment *)*PerfLevels);
	gtk.mem_adj       = (GtkAdjustment **)malloc(sizeof(GtkAdjustment *)*PerfLevels);
	gtk.vddc_adj      = (GtkAdjustment **)malloc(sizeof(GtkAdjustment *)*PerfLevels);
	gtk.fan_adj       = (GtkAdjustment **)malloc(sizeof(GtkAdjustment *)*PerfLevels);

	gtk.mem_button    = (GtkWidget **)malloc(sizeof(GtkWidget *)*PerfLevels);
	gtk.gpu_button    = (GtkWidget **)malloc(sizeof(GtkWidget *)*PerfLevels);
	gtk.vddc_button   = (GtkWidget **)malloc(sizeof(GtkWidget *)*PerfLevels);
	gtk.fan_button    = (GtkWidget **)malloc(sizeof(GtkWidget *)*PerfLevels);

	gtk.table_labels  = (GtkWidget **)malloc(sizeof(GtkWidget *)*(PerfLevels+6));

//iSize = sizeof( ADLODPerformanceLevels ) + sizeof( ADLODPerformanceLevel ) * (ADLODParameters.iNumberOfPerformanceLevels - 1);
	//ret_val = LSADL_OD5_ODPerformanceLevels_Get(iAdapterIndex, 1, &lpOdPerformanceLevels);

	for(num1=0; num1<PerfLevels; num1++){
		printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iEngineClock);
		printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iMemoryClock);
		printf("%d: %d\n", num1, lpOdPerfLevels->aLevels[num1].iVddc);

		PerfCur[num1].gpu  = (lpOdPerfLevels->aLevels[num1]).iEngineClock;
		PerfCur[num1].mem  = (lpOdPerfLevels->aLevels[num1]).iMemoryClock;
		PerfCur[num1].vddc = (lpOdPerfLevels->aLevels[num1]).iVddc;
		PerfCur[num1].gpu /= 100;
		PerfCur[num1].mem /= 100;
		PerfCur[num1].vddc /= 1000;


		printf("%lf %lf %lf\n", PerfCur[num1].gpu, PerfCur[num1].mem, PerfCur[num1].vddc);
		

	}
	*/


//ADLODParameterRange 	sEngineClock
//ADLODParameterRange 	sMemoryClock
//ADLODParameterRange 	sVddc



	gtk.table = gtk_table_new(PerfLevels+7, 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");
	gtk.table_labels[4] = gtk_label_new("empty");

	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");
	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);
	//gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[4],        4, 5, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	for(num1=0; num1<PerfLevels; num1++){
		(void)sprintf(tmp, "%d", num1);
		//gtk.table_labels[6+num1] = gtk_label_new((const gchar *)tmp);
		PerfCur[num1].table_labels = gtk_label_new((const gchar *)tmp);
		temp_num = 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;
		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;
		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);
		//gtk_spin_button_set_digits(
		//gtk_spin_button_set_digits(
		//gtk_spin_button_set_digits(
		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]));
	}

	//gtk.fixed1 = gtk_fixed_new();
	//gtk_fixed_put(GTK_FIXED(gtk.fixed1), gtk.table_labels[5], 0, 0);
	//gtk_widget_set_size_request(gtk.table_labels[5], 30, 30);
	//gtk_container_add (GTK_CONTAINER(window1), fixed1);

	//gdk_color_parse("green", &color);
	//gtk_widget_modify_fg(((struct GTK_Widgets) gtk).table_labels[5], GTK_STATE_NORMAL, &color);
	//gtk_widget_modify_bg(GTK_WIDGET(gtk.table_labels[5]), GTK_STATE_NORMAL, &color);

	//temp_num = 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);

	gtk.combo_box = gtk_combo_box_text_new();
	//PerfRanges.cur_force3d

	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_text_prepend_text((GtkComboBoxText *)pco[num1].type, "Lock");
	//ADL_ADAPTER_SPEEDCAPS_SUPPORTED
	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);
	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");
	//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);
	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);
	//gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[5]),  5, 6, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	//gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[6]),  6, 7, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	//gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[7]),  7, 8, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 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);

/*
	num1++;
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[16]),  0, 1, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);

	num1++;
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[10]),  0, 1, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
*/

	//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),        1, 2, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	//gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).save_b),        2, 3, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 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) );

	//gtk_box_pack_end(GTK_BOX(gtk.main_vbox), gtk.table, TRUE, TRUE, 3);

	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_container_add (GTK_CONTAINER(gtk.notebook_page1), GTK_WIDGET(gtk.scrolled_win));

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


//	gtk.graph_perf = gtk_drawing_area_new();
//	gtk.graph_usage = gtk_drawing_area_new();
//	gtk.graph_fan  = gtk_drawing_area_new();
//	gtk.graph_temp = gtk_drawing_area_new();
//	gtk_widget_set_size_request(gtk.graph_perf, 680, 110);
//	gtk_widget_set_size_request(gtk.graph_usage, 680, 110);
//	gtk_widget_set_size_request(gtk.graph_fan,  680, 110);
//	gtk_widget_set_size_request(gtk.graph_temp, 680, 110);

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

//	gtk.graph_labels[0] = gtk_label_new("PerfLevel");
//	gtk.graph_labels[1] = gtk_label_new("GPU Usage");
//	gtk.graph_labels[2] = gtk_label_new("Fan RPM");
//	gtk.graph_labels[3] = gtk_label_new("Temp");
//gtk.graph_labels[0] = gtk_spinner_new();
//gtk_spinner_start (GTK_SPINNER(gtk.graph_labels[0]));
//gtk_label_set_justify(GTK_LABEL(gtk.graph_labels[0]), GTK_JUSTIFY_RIGHT);

//	gtk.graph_table = gtk_table_new(4, 1, TRUE);
//	gtk_table_attach(GTK_TABLE(gtk.graph_table), gtk.graph_perf,          0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
//	gtk_table_attach(GTK_TABLE(gtk.graph_table), gtk.graph_usage,         0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
//	gtk_table_attach(GTK_TABLE(gtk.graph_table), gtk.graph_fan,           0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
//	gtk_table_attach(GTK_TABLE(gtk.graph_table), gtk.graph_temp,          0, 1, 3, 4, GTK_FILL, GTK_FILL, 0, 0);


	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_container_add (GTK_CONTAINER(gtk.main_vbox), gtk.notebook);



	//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_box_pack_start(GTK_BOX(gtk.main_vbox), gtk.main_menubar, FALSE, FALSE, 3);
	//gtk_container_add (GTK_CONTAINER(gtk.notebook_page1), GTK_WIDGET(gtk.scrolled_win));
	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 USING_GTK_3
	g_signal_connect(G_OBJECT(gtk.graph),  "expose-event", G_CALLBACK(on_expose_cairo), NULL);
	//g_signal_connect(G_OBJECT(gtk.graph_perf),  "expose-event", G_CALLBACK(on_expose_cairo), &cb_graph[0]);
	//g_signal_connect(G_OBJECT(gtk.graph_usage), "expose-event", G_CALLBACK(on_expose_cairo), &cb_graph[1]);
	//g_signal_connect(G_OBJECT(gtk.graph_fan),   "expose-event", G_CALLBACK(on_expose_cairo), &cb_graph[2]);
	//g_signal_connect(G_OBJECT(gtk.graph_temp),  "expose-event", G_CALLBACK(on_expose_cairo), &cb_graph[3]);
#else
	g_signal_connect(G_OBJECT(gtk.graph), "draw", G_CALLBACK(on_expose_cairo), NULL);
#endif
	//g_signal_connect(G_OBJECT(gtk.graph_perf), "expose-event", G_CALLBACK(on_expose_cairo), NULL);
	//g_signal_connect(G_OBJECT(gtk.graph_fan), "expose-event", G_CALLBACK(on_expose_cairo), NULL);
	//g_signal_connect(G_OBJECT(gtk.graph_temp), "expose-event", G_CALLBACK(on_expose_cairo), NULL);
	//"button-release-event"
	//g_signal_connect(G_OBJECT(gtk.apply_button), "clicked", G_CALLBACK(apply_cb), (gpointer)&gtk);
	gtk_widget_show_all(gtk.main_win);
	gtk_widget_realize(gtk.graph);
	Not_Started = 0;
	gtk_main();
	//gdk_threads_leave();
	pthread_exit(NULL);
}




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


gboolean set_fanspeed_cb(GtkWidget *widget, gpointer data){
	
	int ret_val = 0;
	int num1 = 0;
    //ADLPMActivity current;
    //ADLFanSpeedInfo FanSpeedInfo;
	ADLFanSpeedValue FanSpeedValue;
	gdouble fan_rpm = gtk_spin_button_get_value( (GtkSpinButton *)(((struct PERF_Cur *)data)->fan_b) );
	printf("requested: %.03lf rpm\n", fan_rpm);

	/*
        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;
	}
	//(void)sprintf(value, "%d rpm", FanSpeedValue.iFanSpeed);
	FanSpeedValue.iSize = sizeof(ADLFanSpeedValue);
	FanSpeedValue.iFanSpeed = (int)floor(fan_rpm);
	FanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
	//FanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_PERCENT;
	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;
	//int num1 = 0;
	ADLFanSpeedValue FanSpeedValue;
	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);
        printf("Exiting!\n");
        return FALSE;
    }
    //(void)sprintf(value, "%d rpm", FanSpeedValue.iFanSpeed);
    //FanSpeedValue.iFanSpeed = fan_rpm;

	Adjust_spinner(((struct PERF_Cur *)data)->fan_adj, ((struct PERF_Cur *)data)->fan_b, (gdouble)FanSpeedValue.iFanSpeed);


    //gdk_threads_enter();
    //gtk_adjustment_set_value(adjustment, value);
    //gtk_spin_button_set_value(GTK_SPIN_BUTTON(spiner), value);
    //gtk_widget_show_all(spiner);
    //gdk_threads_leave();
	//}


	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){
	//gdk_threads_enter();
	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;
		//gdk_threads_leave();
        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");

	//uint32_t s_size = strlen("nvidia-settings -a GPU2DClockFreqs=1000,1000")+1;
	//char *setting = malloc(sizeof(char)*s_size);
	//(void)memset(setting, '\0', s_size);
	//(void)sprintf(setting, "GPUOverclockingState=1");
	//printf("%s\n", setting);

	//system("

	//(void)sprintf(setting, "nvidia-settings -a GPU2DClockFreqs=%u,%u", gpu, mem);
	//printf("%s\n", setting);
	//system("nvidia-settings -a GPUOverclockingState=1");
	//system(setting);
	gtk_widget_show_all( ((struct GTK_Widgets)gtk).main_win );
	//printf("set:: GPU: %u MEM: %u\n", gpu, mem);
//	gtk_widget_show_all(((struct GTK_Widgets *)data)->main_win);
	//nvidia-settings -a GPUOverclockingState=1
	//nvidia-settings -a GPU2DClockFreqs=200,800
	//free(setting);
	//gdk_threads_leave();
	return TRUE;
}

gboolean API_Funcs_Found_Popup_cb(GtkWidget *widget, gpointer data){
	int num1 = 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);
    //player  type  min_dice_will_roll  min_score_will_keep
    GtkWidget *top_table = gtk_table_new(LSADL_FUNCS, 3, TRUE);
    //ng.top_table = gtk_table_new(4, gs.Num_Players+2, 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:");
    //top_table_labels[3] = gtk_label_new("Min score will keep");
	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);
    //gtk_table_attach(GTK_TABLE(top_table), top_table_labels[3],  3, 4, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);

	for(num1=0; num1<LSADL_FUNCS; num1+=3){
		all_labels[num1] = gtk_label_new((const gchar *)ADL_Func_Names[num1]);
		if(ADL_Func_Enabled[num1] == 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[num1] == FUNC_FOUND_IN_API)
			all_labels[num1+2] = gtk_label_new((const gchar *)"Found in API");
		else if(ADL_Func_Notes[num1] == 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);
	}
	//bottom_table = gtk_table_new(4, 5, TRUE);
	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 USING_GTK_3
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[5] = {0, 0, 0, 0, 0};
	double last_y[5] = {0, 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;
	//const int pixels_h = (GRAPH_H-40)/4;
	//const int total_charts = 4;

	//double tenth_height = height/50;
	//double tenth_width = width/10;

	double white_height = height * 0.03;
	double black_height = (height - (white_height*(total_charts+1))) / total_charts;
	double data_w = width * 0.95;
	double data_h = black_height * 0.86;
	double data_s = data_w/60;

	int stride;
	int num1 = 0;
	int local_idx = graph_idx;
	unsigned char *img_data;
	char buffer[16];

	//int params[4];
	//(void)GL_Mem_Free(params);
	//printf("total free: %u\n", params[0]);

	//(void)GL_Mem_Free(params);
            //printf("%u\n", params[0]);
/*
	struct Chart_Vectors{
		double top; //start of black
		double bottom; //end of black
		double right; // end of data points
		double h; // pixels for data points
		double w; // pixels for data points
		double h_tenth; //used for borders
		double w_tenth; // used for borders
		double w_step; // step for each data point
	}cv[total_charts];
	*/

	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;
		//return FALSE;
	}

	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(graphdata.fan[num1] > highest_fan)
			highest_fan = graphdata.fan[num1];
		if(graphdata.temp[num1] > highest_temp)
			highest_temp = graphdata.temp[num1];
		if(graphdata.usage[num1] > highest_usage)
			highest_usage = graphdata.usage[num1];
	}
	//cairo labels
	cairo_move_to(context, width/2, cv[0].data_top);
	cairo_show_text(context, "Perf Level");
	cairo_move_to(context, width/2, cv[1].data_top);
	cairo_show_text(context, "GPU Usage");
	cairo_move_to(context, width/2, cv[2].data_top);
	cairo_show_text(context, "Fan Speed");
	cairo_move_to(context, width/2, cv[3].data_top);
	cairo_show_text(context, "GPU Temp");
	cairo_move_to(context, width/2, cv[4].data_top);
	cairo_show_text(context, "MEM Usage");

	//High/low legend
	cairo_move_to(context, data_w, cv[0].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[0].data_bottom);
	cairo_show_text(context, "0");

	cairo_move_to(context, data_w, cv[1].data_top);
	cairo_show_text(context, "100");
	cairo_move_to(context, data_w, cv[1].data_bottom);
	cairo_show_text(context, "0");

	cairo_move_to(context, data_w, cv[2].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[2].data_bottom);
	cairo_show_text(context, "0");

	cairo_move_to(context, data_w, cv[3].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[3].data_bottom);
	cairo_show_text(context, "0");

	cairo_move_to(context, data_w, cv[4].data_top);
	(void)memset(buffer, '\0', 16);
	(void)sprintf(buffer, "%.01lf", (double)total_gmem/1024/1024);
	cairo_show_text(context, buffer);
	cairo_move_to(context, data_w, cv[4].data_bottom);
	cairo_show_text(context, "0");

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

        tmp1 = cv[1].data_bottom;
		tmp2 = (double)graphdata.usage[local_idx]/100;
		tmp2 *= data_h;
		tmp1 -= tmp2;
        //tmp1 -= (double)graphdata.usage[local_idx]/100*data_h;
        cairo_move_to(context, last_x[1], last_y[1]);
        cairo_line_to(context, (double)num1*data_s, tmp1);
        cairo_stroke(context);
        last_x[1] = num1*data_s;
        last_y[1] = tmp1;

        tmp1 = cv[2].data_bottom;
		tmp2 = (double)graphdata.fan[local_idx]/highest_fan;
		tmp2 *= data_h;
		tmp1 -= tmp2;
        //tmp1 -= (double)graphdata.fan[local_idx]/highest_fan*data_h;
        cairo_move_to(context, last_x[2], last_y[2]);
        cairo_line_to(context, (double)num1*data_s, tmp1);
        cairo_stroke(context);
        last_x[2] = num1*data_s;
        last_y[2] = tmp1;

        tmp1 = cv[3].data_bottom;
		tmp2 = (double)graphdata.temp[local_idx]/highest_temp;
		tmp2 *= data_h;
		tmp1 -= tmp2;
        //tmp1 -= (double)graphdata.temp[local_idx]/highest_temp*data_h;
        cairo_move_to(context, last_x[3], last_y[3]);
        cairo_line_to(context, (double)num1*data_s, tmp1);
        cairo_stroke(context);
        last_x[3] = num1*data_s;
        last_y[3] = tmp1;


        tmp1 = cv[4].data_bottom;
        tmp2 = (double)graphdata.mem[local_idx]/total_gmem;
        tmp2 *= data_h;
        tmp1 -= tmp2;
        //tmp1 -= (double)graphdata.usage[local_idx]/100*data_h;
        cairo_move_to(context, last_x[4], last_y[4]);
        cairo_line_to(context, (double)num1*data_s, tmp1);
        cairo_stroke(context);
        last_x[4] = num1*data_s;
        last_y[4] = tmp1;

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

	cairo_destroy(context);
	cairo_surface_destroy(target);

	free(img_data);
	//return TRUE;
}

gboolean 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;

			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].gpu_adj),  PerfRanges.gpu_step, 10000);
			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].mem_adj),  PerfRanges.mem_step, 10000);
			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].vddc_adj), PerfRanges.vddc_step, 10);
		}else{
			PerfCur[num1].gpu_adj->lower = PerfRanges.gpu_min;
			PerfCur[num1].gpu_adj->upper = PerfRanges.gpu_max;

			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].gpu_adj),  PerfRanges.gpu_min,  PerfRanges.gpu_max);
			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].mem_adj),  PerfRanges.mem_min,  PerfRanges.mem_max);
			//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[num1].mem_adj),  PerfRanges.vddc_min, PerfRanges.vddc_max);
		}
		num1++;
	}
	//fan
	if(unlocked){
		PerfCur[0].fan_adj->lower = PerfRanges.fan_step;
		PerfCur[0].fan_adj->upper = 10000;
		//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[0].fan_adj),  PerfRanges.fan_step, 10000);
	}else{
		PerfCur[0].fan_adj->lower = PerfRanges.fan_min;
		PerfCur[0].fan_adj->upper = PerfRanges.fan_max;
	}
		//gtk_adjustment_clamp_page(GTK_ADJUSTMENT(PerfCur[0].fan_adj),  PerfRanges.fan_min, PerfRanges.fan_max);
	//gtk_widget_show(((struct GTK_Widgets) gtk).);
	gtk_widget_show_all(((struct GTK_Widgets)gtk).main_win);
	return TRUE;
}