diff --git a/include/editor.h b/include/editor.h index bb6a7ba..160e068 100644 --- a/include/editor.h +++ b/include/editor.h @@ -24,7 +24,11 @@ #define EDITOR_H +#include "common.h" + + void winEditorCreate(char *filename); +void winEditorGoto(char *filename, size_t line, size_t column); #endif // EDITOR_H diff --git a/include/scintillaHeaders.h b/include/scintillaHeaders.h index 0832d12..8ced920 100644 --- a/include/scintillaHeaders.h +++ b/include/scintillaHeaders.h @@ -36,4 +36,4 @@ #define MARGIN_SCRIPT_FOLD_INDEX 1 -#endif //SCINTILLAHEADERS_H +#endif // SCINTILLAHEADERS_H diff --git a/src/editor.c b/src/editor.c index a93626f..28b5624 100644 --- a/src/editor.c +++ b/src/editor.c @@ -22,7 +22,6 @@ #include -#include "common.h" #include "editor.h" #include "utils.h" #include "scintillaHeaders.h" @@ -42,6 +41,9 @@ typedef struct EditorDataS { void *pLexer; int id; guint statusBarId; + size_t textLine; + size_t textColumn; + gboolean editorPainted; } EditorDataT; typedef struct LexerDataS { @@ -50,6 +52,8 @@ typedef struct LexerDataS { } LexerDataT; +static EditorDataT **_editorWindows = NULL; + static LexerDataT _lexerInfo[] = { { "h", "cpp" }, { "c", "cpp" }, @@ -63,27 +67,29 @@ static LexerDataT _lexerInfo[] = { static int _nextEditorId = 0; -static void clearEditor(EditorDataT *self); -static int determineLexer(char *filename); -EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData); -static gboolean fileIsSupported(char *filename); -static void loadEditor(EditorDataT *self); -static void loadEditorConfig(char *lexer, EditorDataT *self); -EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData); -EVENT void menuEditorEditCut(GtkWidget *object, gpointer userData); -EVENT void menuEditorEditDelete(GtkWidget *object, gpointer userData); -EVENT void menuEditorEditPaste(GtkWidget *object, gpointer userData); -EVENT void menuEditorFileClose(GtkWidget *object, gpointer userData); -EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData); -EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData); -EVENT void menuEditorFileSave(GtkWidget *object, gpointer userData); -EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData); -EVENT void menuEditorHelpEditor(GtkWidget *object, gpointer userData); -static void setLexer(EditorDataT *self, int lexer); -static void status(EditorDataT *self, char *message); -EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData); -static void winEditorDelete(gpointer userData); -static void writeEditorConfig(char *lexer, EditorDataT *self); +static void clearEditor(EditorDataT *self); +static int determineLexer(char *filename); +EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotification *notifyData, gpointer userData); +static gboolean fileIsSupported(char *filename); +static EditorDataT *isAlreadyOpen(char *filename); +static void loadEditor(EditorDataT *self); +static void loadEditorConfig(char *lexer, EditorDataT *self); +EVENT void menuEditorEditCopy(GtkWidget *object, gpointer userData); +EVENT void menuEditorEditCut(GtkWidget *object, gpointer userData); +EVENT void menuEditorEditDelete(GtkWidget *object, gpointer userData); +EVENT void menuEditorEditPaste(GtkWidget *object, gpointer userData); +EVENT void menuEditorFileClose(GtkWidget *object, gpointer userData); +EVENT void menuEditorFileNew(GtkWidget *object, gpointer userData); +EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData); +EVENT void menuEditorFileSave(GtkWidget *object, gpointer userData); +EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData); +EVENT void menuEditorHelpEditor(GtkWidget *object, gpointer userData); +static void setLexer(EditorDataT *self, int lexer); +static void status(EditorDataT *self, char *message); +EVENT gboolean winEditorClose(GtkWidget *object, gpointer userData); +static void winEditorDelete(gpointer userData); +static gboolean winEditorGotoUpdate(gpointer userData); +static void writeEditorConfig(char *lexer, EditorDataT *self); static void clearEditor(EditorDataT *self) { @@ -157,6 +163,9 @@ EVENT void editorEditorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi } break; + case SCN_PAINTED: + self->editorPainted = TRUE; + break; } } @@ -174,6 +183,20 @@ static gboolean fileIsSupported(char *filename) { } +static EditorDataT *isAlreadyOpen(char *filename) { + int i; + + for (i=0; iwindowData.filename, filename) == 0) { + // Focus the existing window. + gtk_window_present_with_time(GTK_WINDOW(_editorWindows[i]->windowData.window), GDK_CURRENT_TIME); + return _editorWindows[i]; + } + } + return NULL; +} + + static void loadEditor(EditorDataT *self) { FILE *in = NULL; char *line = NULL; @@ -364,6 +387,10 @@ EVENT void menuEditorFileOpen(GtkWidget *object, gpointer userData) { if (utilFileOpen((WindowDataT *)userData, "*.*", "Code")) { if (!fileIsSupported(self->windowData.filename)) return; + if (isAlreadyOpen(self->windowData.filename) != NULL) { + DEL(self->windowData.filename); + return; + } clearEditor(self); setLexer(self, determineLexer(self->windowData.filename)); loadEditor(self); @@ -421,6 +448,7 @@ EVENT void menuEditorFileSaveAs(GtkWidget *object, gpointer userData) { (void)object; + //***TODO*** If they save over an existing file that is open to edit they will have two editors open on the same filename. if (utilFileSaveAs((WindowDataT *)userData, "*.*", "Code")) { menuEditorFileSave(object, (EditorDataT *)userData); } @@ -488,8 +516,12 @@ void winEditorCreate(char *filename) { NULL }; + // Can we edit this? if (filename && !fileIsSupported(filename)) return; + // Is there already an editor window open for this file? + if (isAlreadyOpen(filename) != NULL) return; + // Set up instance data. self = NEW(EditorDataT); self->windowData.closeWindow = winEditorClose; @@ -565,6 +597,9 @@ void winEditorCreate(char *filename) { // Show window. gtk_widget_show_all(self->windowData.window); + // Remember window. + arrput(_editorWindows, self); + if (filename != NULL) { self->windowData.filename = strdup(filename); loadEditor(self); @@ -574,16 +609,59 @@ void winEditorCreate(char *filename) { static void winEditorDelete(gpointer userData) { EditorDataT *self = (EditorDataT *)userData; + int i; // Scintilla keeps sending events after we delete things it expects to still exist. Prevent that. g_signal_handlers_disconnect_by_func(G_OBJECT(self->editor), G_CALLBACK(editorEditorNotify), self); + // Remove from open results window list. + for (i=0; itextLine = line; + self->textColumn = column; + self->editorPainted = FALSE; + g_idle_add(winEditorGotoUpdate, self); + } +} + + +static gboolean winEditorGotoUpdate(gpointer userData) { + EditorDataT *self = (EditorDataT *)userData; + int position; + + // Wait for Scintilla to be ready. + if (self->editorPainted == FALSE) return G_SOURCE_CONTINUE; + + // Move caret. + SSM(SCI_GRABFOCUS, 0, 0); + position = SSM(SCI_POSITIONFROMLINE, (uptr_t)self->textLine, (sptr_t)0) + self->textColumn; + SSM(SCI_GOTOPOS, (uptr_t)position, (sptr_t)0); + + return G_SOURCE_REMOVE; +} + + static void writeEditorConfig(char *lexer, EditorDataT *self) { char *name = NULL; char *tags = NULL; diff --git a/src/results.c b/src/results.c index 1f45041..99f5674 100644 --- a/src/results.c +++ b/src/results.c @@ -27,6 +27,7 @@ #include "common.h" #include "results.h" #include "utils.h" +#include "editor.h" typedef struct ResultsDataS { @@ -45,6 +46,7 @@ typedef struct ResultsDataS { static ResultsDataT **_resultWindows = NULL; +EVENT void messageClicked(GtkButton *widget, gpointer userData); EVENT void resultClicked(GtkButton *widget, gpointer userData); static void resultLoadRaw(gboolean release, int target, int arch, ResultsDataT *self); static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *self); @@ -53,6 +55,34 @@ EVENT gboolean winBuildResultsClose(GtkWidget *object, gpointer userData); static void winBuildResultsDelete(gpointer userData); +EVENT void messageClicked(GtkButton *widget, gpointer userData) { + ResultsDataT *self = (ResultsDataT *)userData; + const char *name = gtk_widget_get_name(GTK_WIDGET(widget)); + char *tok; + char *temp; + char *file; + size_t line; + size_t column; + gboolean isWarning; + + // Extract info from button name. + tok = strdup(name); + temp = strtok(tok, ":"); + isWarning = (temp[0] == 'w'); + temp = strtok(NULL, ":"); + file = utilCreateString("%s%s", self->project->windowData.path, temp); + temp = strtok(NULL, ":"); + line = atol(temp); + temp = strtok(NULL, ":"); + column = atol(temp); + + winEditorGoto(file, line, column); + + DEL(tok); + DEL(file); +} + + EVENT void resultClicked(GtkButton *widget, gpointer userData) { ResultsDataT *self = (ResultsDataT *)userData; const char *name = gtk_widget_get_name(GTK_WIDGET(widget)); @@ -60,9 +90,9 @@ EVENT void resultClicked(GtkButton *widget, gpointer userData) { int a; gboolean r; - // Highlight the button pressed button. - gtk_button_set_relief(widget, GTK_RELIEF_NONE); - gtk_button_set_relief(GTK_BUTTON(self->pressedButton), GTK_RELIEF_NORMAL); + // Highlight the pressed button. + gtk_button_set_relief(widget, GTK_RELIEF_NORMAL); + gtk_button_set_relief(GTK_BUTTON(self->pressedButton), GTK_RELIEF_NONE); self->pressedButton = GTK_WIDGET(widget); // Extract button info from widget name. @@ -127,7 +157,11 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel GtkWidget *button; int i; char *temp; + char *tok; char *text; + char *file; + size_t line; + size_t column; gboolean isWarning; messages = release ? self->lstRelease : self->lstDebug; @@ -135,6 +169,9 @@ static void resultParseRaw(gboolean release, char **lineArray, ResultsDataT *sel for (i=0; igridResults), w, 2, gridLine, 1, 1); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); @@ -248,13 +298,14 @@ static void resultsUpdate(ResultsDataT *self) { 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_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE); gtk_grid_attach(GTK_GRID(self->gridResults), w, 3, gridLine, 1, 1); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(resultClicked), self); if (firstSystem < 0) { firstSystem = i; // Highlight the button pressed button. - gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE); + gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL); self->pressedButton = w; }