/* * JoeyDev * Copyright (C) 2018-2023 Scott Duensing * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "common.h" #include "results.h" #include "utils.h" typedef struct ResultsDataS { WindowDataT windowData; ProjectDataT *project; GtkWidget *gridResults; GtkWidget *notebookResults; GtkWidget *lstDebug; GtkWidget *lstRelease; GtkWidget *lstRaw; int lastSelected; } ResultsDataT; static ResultsDataT **_resultWindows = NULL; EVENT void resultClicked(GtkButton *widget, gpointer userData); static void resultShow(gboolean release, int target, int arch, ResultsDataT *self); static void resultsUpdate(ResultsDataT *self); EVENT gboolean winBuildResultsClose(GtkWidget *object, gpointer userData); static void winBuildResultsDelete(gpointer userData); EVENT void resultClicked(GtkButton *widget, gpointer userData) { const char *name = gtk_widget_get_name(GTK_WIDGET(widget)); int t; int a; gboolean r; // Extract button info from widget name. r = (name[0] == 'r'); t = atoi(&name[1]); a = atoi(strstr(name, "a") + 1); resultShow(r, t, a, userData); } static void resultShow(gboolean release, int target, int arch, ResultsDataT *self) { FILE *in; char *temp; char *line = NULL; size_t len = 0; TargetT *t; // Do we need to load new results? if (target != self->lastSelected) { self->lastSelected = target; // Clear existing contents. utilClearContainer(GTK_CONTAINER(self->lstDebug)); utilClearContainer(GTK_CONTAINER(self->lstRelease)); utilClearContainer(GTK_CONTAINER(self->lstRaw)); // Load raw results. t = self->project->targets[target]; temp = utilCreateString("%sresults%cbuild.%s.%s.%s", self->project->windowData.path, UTIL_PATH_CHAR, t->name, t->archs[arch]->name, release ? "release" : "debug"); in = fopen(temp, "rt"); if (in) { while (!feof(in)) { utilEnsureBufferSize((unsigned char **)&line, (int *)&len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. while (getline(&line, &len, in) != -1) { if (strlen(line) > 0) line[strlen(line) - 1] = 0; utilAddTextToListBox(GTK_LIST_BOX(self->lstRaw), line); //***TODO*** Parse these for the other tabs. And, oops, we need two RAW tabs! } } fclose(in); DEL(line); } DEL(temp); } // Display appropriate tab. gtk_notebook_set_current_page(GTK_NOTEBOOK(self->notebookResults), release ? 1 : 0); } static void resultsUpdate(ResultsDataT *self) { int i; int j; int x; int gridLine = 0; TargetT *t; GtkWidget *w; char *temp; int firstSystem = -1; gboolean debugFound; gboolean releaseFound; DIR *directory; struct dirent *entry; utilClearContainer(GTK_CONTAINER(self->gridResults)); // Iterate over target data and load results. for (i=0; iproject->targets); i++) { t = self->project->targets[i]; for (j=0; jarchs); j++) { if (t->archs[j]->selected) { if (firstSystem < 0) { firstSystem = i; } // Add to grid. Name. w = gtk_label_new(t->longName); gtk_label_set_line_wrap(GTK_LABEL(w), FALSE); gtk_label_set_xalign(GTK_LABEL(w), 1.0); gtk_grid_attach(GTK_GRID(self->gridResults), w, 0, gridLine, 1, 1); // Add to grid. Arch. w = gtk_label_new(t->archs[j]->name); gtk_label_set_line_wrap(GTK_LABEL(w), FALSE); gtk_label_set_xalign(GTK_LABEL(w), 1.0); gtk_grid_attach(GTK_GRID(self->gridResults), w, 1, gridLine, 1, 1); // See if we got binaries for debug and release. debugFound = FALSE; releaseFound = FALSE; // This for loop is an ugly way to check both debug and release without making a function for the enclosed code. for (x=0; x<2; x++) { temp = utilCreateString("%sresults%c%s-%s%c%s", self->project->windowData.path, UTIL_PATH_CHAR, t->name, t->archs[j]->name, UTIL_PATH_CHAR, x == 0 ? "debug" : "release"); directory = opendir(temp); DEL(temp); if (directory) { // Anything in here that's not a directory is a binary. while ((entry = readdir(directory))) { if (entry->d_type == DT_REG) { if (x == 0) { debugFound = TRUE; } else { releaseFound = TRUE; } break; } } closedir(directory); } } // Add debug button. w = gtk_button_new_from_icon_name(debugFound ? "mail-mark-notjunk" : "mail-mark-junk", GTK_ICON_SIZE_BUTTON); temp = utilCreateString("d%da%d", i, j); // We store data about this button in its name. gtk_widget_set_name(w, temp); DEL(temp); gtk_grid_attach(GTK_GRID(self->gridResults), w, 2, gridLine, 1, 1); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); // Add release button. w = gtk_button_new_from_icon_name(releaseFound ? "mail-mark-notjunk" : "mail-mark-junk", GTK_ICON_SIZE_BUTTON); temp = utilCreateString("r%da%d", i, j); // We store data about this button in its name. gtk_widget_set_name(w, temp); DEL(temp); gtk_grid_attach(GTK_GRID(self->gridResults), w, 3, gridLine, 1, 1); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); // Next result! gridLine++; } } } // Did we load anything? if (gridLine > 0) { resultShow(FALSE, firstSystem, 0, self); } } EVENT gboolean winBuildResultsClose(GtkWidget *object, gpointer userData) { // userData is not reliable due to util indirectly calling us. WindowDataT *self = (WindowDataT *)utilGetWindowData(object); (void)userData; winBuildResultsDelete(self); return FALSE; } void winBuildResultsCreate(ProjectDataT *project) { int i; ResultsDataT *self; char *widgetNames[] = { "winBuildResults", "gridBuildResults", "lstBuildMessagesDebug", "lstBuildMessagesRelease", "lstBuildMessagesRaw", "notebookResults", NULL };static GtkWidget **widgets[] = { NULL, NULL, NULL, NULL, NULL, NULL }; // Is there already a results window open for this project? for (i=0; iproject == project) { // Focus the existing window. gtk_window_present_with_time(GTK_WINDOW(_resultWindows[i]->windowData.window), GDK_CURRENT_TIME); resultsUpdate(_resultWindows[i]); return; } } // Create new window and associate it with the project. self = NEW(ResultsDataT); self->windowData.closeWindow = winBuildResultsClose; self->project = project; self->lastSelected = -1; project->buildResults = self; // Load widgets from XML. widgets[0] = &self->windowData.window; widgets[1] = &self->gridResults; widgets[2] = &self->lstDebug; widgets[3] = &self->lstRelease; widgets[4] = &self->lstRaw; widgets[5] = &self->notebookResults; utilGetWidgetsFromMemory("/com/kangaroopunch/joeydev/BuildResults.glade", widgetNames, widgets, self); // Register window. utilWindowRegister(self); // Draw contents. resultsUpdate(self); // Show window. gtk_widget_show_all(self->windowData.window); // Remember window. arrput(_resultWindows, self); } static void winBuildResultsDelete(gpointer userData) { ResultsDataT *self = (ResultsDataT *)userData; int i; // Remove from open results window list. for (i=0; i