#include "ls_gtk.h"

int PerfLevels;
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;


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

	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);
	/*
	#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_Get(iAdapterIndex, &PerfRanges.def_force3d, &PerfRanges.cur_force3d);
	if(ret_val != ADL_OK){
		printf("ADL_Adapter_Speed_Get(\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		return FALSE;
	}
	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");
	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;
	}
	if(num1 == ADL_ADAPTER_SPEEDCAPS_SUPPORTED){
		printf("num1 ADL_ADAPTER_SPEEDCAPS_SUPPORTED\n");
	}else if(num1 == 0){
		printf("num1 0\n");
	}

	if(num2 == ADL_ADAPTER_SPEEDCAPS_SUPPORTED){
		printf("num2 ADL_ADAPTER_SPEEDCAPS_SUPPORTED\n");
	}else if(num2 == 0){
		printf("num2 0\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;


	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 load_file(gchar *filename){
//}



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){
	//if(PerfRanges.cur_force3d == ADL_ADAPTER_SPEEDCAPS_SUPPORTED){
	//	printf("Force3d speedcaps not supported !\n");
	//	return FALSE;
	//}
	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");
	}
	int 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);
		//if(PerfRanges.cur_force3d == ADL_ADAPTER_SPEEDCAPS_SUPPORTED)
		return FALSE;
	}
	return TRUE;
}



void *Refresh_Func(void *empty){
	char value[16];
	int ret_val = 0;
	int num1 = 0;
	gdouble dtmp = 0;
	ADLPMActivity current;
	ADLFanSpeedInfo FanSpeedInfo;
	ADLFanSpeedValue FanSpeedValue;

	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();
		for(num1=0; num1<PerfLevels; num1++){
			if(num1 == ret_val){
				(void)sprintf(value, "-->%d", ret_val);
			}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);
		}
		//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

		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);
		//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();
		//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];
	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, 210);
	gtk_window_set_title(GTK_WINDOW(gtk.main_win), "lsadl v0.0.1");
	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+6, 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("");
	gtk.table_labels[15] = gtk_label_new("Temp");


	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[0],        0, 1, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[1],        1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[2],        2, 3, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), gtk.table_labels[3],        3, 4, 0, 1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 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_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].gpu_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(PerfCur[num1].mem_b),      2, 3, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].vddc_b),     3, 4, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
		gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(PerfCur[num1].apply_b),    4, 5, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 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);

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

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

	gtk_combo_box_text_prepend_text((GtkComboBoxText *)gtk.combo_box, "ForceLow");
	gtk_combo_box_text_prepend_text((GtkComboBoxText *)gtk.combo_box, "ForceHigh");
	gtk_combo_box_text_prepend_text((GtkComboBoxText *)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_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	g_signal_connect(G_OBJECT(gtk.combo_box), "changed", G_CALLBACK(on_toggle_force3d), (gpointer)&gtk.combo_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_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).save_b),           4, 5, 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) );

	num1++;
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[6]),  0, 1, 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).table_labels[7]),  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).table_labels[8]),  2, 3, 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).table_labels[9]),  3, 4, 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).table_labels[10]), 4, 5, 1+num1, 2+num1, GTK_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 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("");
	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_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).ca_labels[1]),  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).ca_labels[2]),  2, 3, 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[3]),  3, 4, 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[4]),  4, 5, 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[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_EXPAND|GTK_FILL, 0, GTK_EXPAND|GTK_FILL, 0);
	gtk_table_attach(GTK_TABLE(gtk.table), GTK_WIDGET(((struct GTK_Widgets) gtk).table_labels[12]),  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).table_labels[13]),  2, 3, 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).table_labels[14]),  3, 4, 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).table_labels[15]),  4, 5, 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[5]),  0, 1, 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]),  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).ca_labels[7]),  2, 3, 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[8]),  3, 4, 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[9]),  4, 5, 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_box_pack_start(GTK_BOX(gtk.main_vbox), gtk.main_menubar, FALSE, FALSE, 3);
	gtk_box_pack_end(GTK_BOX(gtk.main_vbox), gtk.scrolled_win, 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);
	//"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_main();
	//gdk_threads_leave();
	pthread_exit(NULL);
}




gboolean exit_cb(GtkWidget *widget, gpointer data){
	gtk_main_quit();
	No_Exit = 0;
	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;
}