# include <kernel/OS.h> # include <app/Message.h> # include <app/Messenger.h> # include <app/Application.h> # include <storage/FilePanel.h> # include <storage/Path.h> # include <interface/TextView.h> # include <interface/Window.h> # include <interface/MenuBar.h> # include <interface/Menu.h> # include <interface/MenuItem.h> # include <interface/Button.h> # include <interface/Alert.h> # include <signal.h> static int32 dgd_argc; /* argument count */ static char **dgd_argv; /* arguments */ static bool arg_started; /* started with arguments? */ static bool dgd_started; /* driver started? */ static bool dgd_running; /* driver running? */ static BPath config_file; static BPath restore_file; extern "C" { # include "dgd.h" # include "version.h" # undef bool # undef exit thread_id driver; /* driver thread */ /* * NAME: term() * DESCRIPTION: catch SIGTERM */ static void term(int arg) { interrupt(); } void dgd_exit(int code) { dgd_running = FALSE; if (code != 0 && !arg_started) { exit_thread(code); } else { exit(code); } } void dgd_abort() { dgd_running = FALSE; exit_thread(2); } } /* * NAME: run_dgd() * DESCRIPTION: actually run the driver */ static int32 run_dgd(void *data) { char *argv[4]; P_srandom((long) P_time()); signal(SIGPIPE, SIG_IGN); signal(SIGTERM, term); if (!arg_started) { argv[0] = "DGD"; argv[1] = (char *) config_file.Path(); argv[2] = (char *) restore_file.Path(); argv[3] = NULL; dgd_argv = argv; dgd_argc = (argv[2] == NULL) ? 2 : 3; } dgd_running = true; dgd_exit(dgd_main(dgd_argc, dgd_argv)); } enum { DGD_CONFIG = 'dgdc', DGD_RESTORE = 'dgdr', DGD_START = 'dgds', DGD_MESSAGE = 'dgdm', DGD_CONFIG_DONE = 'dgdC', DGD_RESTORE_DONE = 'dgdR', DGD_LEFT = 47, DGD_TOP = 47, DGD_MENU = 19, DGD_WIDTH = 560, DGD_HEIGHT = 375, ABOUT_LEFT = 80, ABOUT_TOP = 80, ABOUT_WIDTH = 480, ABOUT_HEIGHT = 340, ABOUT_INDENT = 80, ABOUT_GRAY = 220 }; class LogView : public BTextView { public: LogView(); virtual void Select(int32 start, int32 finish); virtual void MakeFocus(bool flag = true); bool selected; }; /* * NAME: LogView->LogView() * DESCRIPTION: LogView constructor */ LogView::LogView() : BTextView(BRect(2, DGD_MENU + 2, DGD_WIDTH + 2, DGD_MENU + DGD_HEIGHT + 2), NULL, BRect(0, 0, DGD_WIDTH, DGD_HEIGHT), be_fixed_font, NULL, 0, 0) { MakeEditable(false); SetWordWrap(false); SetTabWidth(7); selected = false; } /* * NAME: LogView->Select() * DESCRIPTION: remember if anything was selected */ void LogView::Select(int32 start, int32 finish) { selected = (start != finish); BTextView::Select(start, finish); } /* * NAME: LogView->MakeFocus() * DESCRIPTION: skip the BTextView MakeFocus stage */ void LogView::MakeFocus(bool flag) { BView::MakeFocus(flag); } class MainFrame : public BWindow { public: MainFrame(); virtual void MessageReceived(BMessage *message); virtual bool QuitRequested(void); virtual void MenusBeginning(void); private: BMenuItem *config; BMenuItem *restore; BMenuItem *start; BMenuItem *copy; BMenuItem *select; BMenuBar *menubar; LogView *log; short lines, length; short len[25]; BFilePanel *config_panel; BFilePanel *restore_panel; entry_ref directory; }; MainFrame::MainFrame() : BWindow(BRect(DGD_LEFT, DGD_TOP, DGD_LEFT + DGD_WIDTH + 4, DGD_TOP + DGD_MENU + DGD_HEIGHT + 4), "DGD", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) { BMenu *filemenu; BMenu *editmenu; BMenuItem *item; /* log window */ log = new LogView(); AddChild(log); log->MakeFocus(); /* file menu */ filemenu = new BMenu("File"); config = new BMenuItem("Config File" B_UTF8_ELLIPSIS, new BMessage(DGD_CONFIG), 'O'); filemenu->AddItem(config); restore = new BMenuItem("Restore File" B_UTF8_ELLIPSIS, new BMessage(DGD_RESTORE), 'R'); filemenu->AddItem(restore); filemenu->AddItem(new BSeparatorItem()); start = new BMenuItem("Start DGD", new BMessage(DGD_START), 'S'); filemenu->AddItem(start); filemenu->SetTargetForItems(this); filemenu->AddItem(new BSeparatorItem()); item = new BMenuItem("About DGD" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)); item->SetTarget(be_app); filemenu->AddItem(item); filemenu->AddItem(new BSeparatorItem()); item = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'); item->SetTarget(this); filemenu->AddItem(item); /* edit menu */ editmenu = new BMenu("Edit"); item = new BMenuItem("Undo", NULL, 'Z'); item->SetEnabled(false); editmenu->AddItem(item); editmenu->AddItem(new BSeparatorItem()); item = new BMenuItem("Cut", NULL, 'X'); item->SetEnabled(false); editmenu->AddItem(item); copy = new BMenuItem("Copy", new BMessage(B_COPY), 'C'); editmenu->AddItem(copy); item = new BMenuItem("Paste", NULL, 'V'); item->SetEnabled(false); editmenu->AddItem(item); item = new BMenuItem("Clear", NULL); item->SetEnabled(false); editmenu->AddItem(item); editmenu->AddItem(new BSeparatorItem()); select = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A'); editmenu->AddItem(select); editmenu->SetTargetForItems(log); /* menu bar */ menubar = new BMenuBar(BRect(0, 0, 0, 0), NULL); menubar->AddItem(filemenu); menubar->AddItem(editmenu); AddChild(menubar); lines = 0; length = 0; config_panel = NULL; restore_panel = NULL; } void MainFrame::MessageReceived(BMessage *message) { entry_ref ref; switch (message->what) { case DGD_CONFIG: if (config_panel == NULL) { config_panel = new BFilePanel(B_OPEN_PANEL, &BMessenger(this), &directory, 0, false, &BMessage(DGD_CONFIG_DONE)); config_panel->Window()->SetTitle("DGD: Config File"); } config_panel->Show(); break; case DGD_RESTORE: if (restore_panel == NULL) { restore_panel = new BFilePanel(B_OPEN_PANEL, &BMessenger(this), &directory, 0, false, &BMessage(DGD_RESTORE_DONE)); restore_panel->Window()->SetTitle("DGD: Restore File"); } restore_panel->Show(); break; case DGD_START: dgd_started = true; driver = spawn_thread(run_dgd, "driver", B_NORMAL_PRIORITY, NULL); resume_thread(driver); break; case B_CANCEL: if (message->FindInt32("old_what") == DGD_CONFIG_DONE) { config_panel->GetPanelDirectory(&directory); delete config_panel; config_panel = NULL; } else { restore_panel->GetPanelDirectory(&directory); delete restore_panel; restore_panel = NULL; } break; case DGD_CONFIG_DONE: message->FindRef("refs", 0, &ref); BEntry(&ref).GetPath(&config_file); break; case DGD_RESTORE_DONE: message->FindRef("refs", 0, &ref); BEntry(&ref).GetPath(&restore_file); break; case DGD_MESSAGE: char *mesg, *p; int32 start, finish; bool eoln; short n; message->FindString("mesg", &mesg); if (log->selected) { log->GetSelection(&start, &finish); } else { start = finish = 0; } if (lines == 0) { /* first line */ select->SetEnabled(true); lines = 1; len[0] = 0; } eoln = false; for (;;) { if (eoln || len[lines - 1] == 80) { if (!eoln) { log->Insert(length, "\n", 1); len[lines - 1]++; length++; } if (lines == 25) { /* delete first line */ log->Delete(0, len[0]); length -= len[0]; start -= len[0]; finish -= len[0]; memcpy(len, len + 1, 24 * sizeof(short)); } else { /* add new line */ lines++; } len[lines - 1] = 0; } if (mesg[0] == '\0') { if (start < 0) { start = 0; } if (finish < 0) { finish = 0; } if (log->selected) { log->Select(start, finish); } break; } p = strchr(mesg, LF); if (p != NULL && len[lines - 1] + (n=++p - mesg) <= 81) { eoln = true; } else { eoln = false; n = strlen(mesg); if (n + len[lines - 1] > 80) { /* wrap line */ n = 80 - len[lines - 1]; } } log->Insert(length, mesg, n); mesg += n; len[lines - 1] += n; length += n; } break; default: BWindow::MessageReceived(message); break; } } bool MainFrame::QuitRequested(void) { if (!dgd_running || (new BAlert("", "Are you sure you want to terminate the running process?", "Yes", "No", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go() == 0) { be_app->PostMessage(&BMessage(B_QUIT_REQUESTED), NULL); } return false; } void MainFrame::MenusBeginning(void) { config->SetEnabled(!dgd_running); restore->SetEnabled(!dgd_running); restore->SetMarked(restore_file.Path() != NULL); start->SetEnabled(!dgd_running && config_file.Path() != NULL && config_panel == NULL && restore_panel == NULL); copy->SetEnabled(log->selected); select->SetEnabled(lines != 0); } static MainFrame *mainframe; class DGD : public BApplication { public: DGD(); virtual void ArgvReceived(int32 argc, char **argv); virtual void RefsReceived(BMessage *message); virtual void AboutRequested(void); virtual bool QuitRequested(void); /* private: icon */ }; DGD::DGD() : BApplication("application/x-DGD") { mainframe = new MainFrame(); mainframe->Show(); } void DGD::ArgvReceived(int32 argc, char **argv) { arg_started = true; dgd_started = true; driver = spawn_thread(run_dgd, "driver", B_NORMAL_PRIORITY, NULL); resume_thread(driver); } void DGD::RefsReceived(BMessage *message) { } void DGD::AboutRequested(void) { BWindow *about; BTextView *view; BFont font; uint32 dummy; char buf[100]; BButton *button; about = new BWindow(BRect(ABOUT_LEFT, ABOUT_TOP, ABOUT_WIDTH + ABOUT_LEFT, ABOUT_HEIGHT + ABOUT_TOP), NULL, B_MODAL_WINDOW, B_NOT_MOVABLE | B_NOT_RESIZABLE); view = new BTextView(BRect(0, 0, ABOUT_WIDTH, ABOUT_INDENT), NULL, BRect(ABOUT_INDENT, 20, ABOUT_WIDTH - 10, ABOUT_INDENT - 10), 0, 0); view->SetViewColor(220, 220, 220); view->MakeEditable(false); view->MakeSelectable(false); view->GetFontAndColor(&font, &dummy); font.SetSize(font.Size() * 1.1); view->SetFontAndColor(&font); about->AddChild(view); sprintf(buf, "\ DGD %s\n© 1993 - 1998 BeeHive Internet Technologies, Inc. \ All Rights Reserved.", VERSION); view->SetText(buf); view = new BTextView(BRect(0, ABOUT_INDENT, ABOUT_WIDTH, ABOUT_HEIGHT), NULL, BRect(10, 0, ABOUT_WIDTH - 10, ABOUT_HEIGHT - ABOUT_INDENT - 10), 0, 0); view->SetViewColor(ABOUT_GRAY, ABOUT_GRAY, ABOUT_GRAY); view->MakeEditable(false); view->MakeSelectable(false); about->AddChild(view); view->SetText("\ Permission is granted to copy the source and executables made therefrom, but \ any commercial distribution or use whatsoever is not allowed. Commercial \ distribution or use refers to any distribution or use from which any form of \ income is received regardless of profit therefrom, or from which any revenue \ or promotional value is received, as well as any distribution to or use in a \ corporate environment. Use of the source or executables made therefrom to \ promote or support a commercial venture is included in this restriction. \ Exclusive worldwide rights to this program for use as a server are held by \ ichat, Inc. If you wish to purchase a commercial license, please send email \ to sales@ichat.com. For more information please look at the ichat web site \ which can be found at http://www.ichat.com.\n\nAny modifications of this \ program lacking an explicit copyright notice are subject to the copyright \ notice stated herein. Any explicit copyright notices added to this program \ shall not contradict the terms stated herein, but may further restrict \ distribution or use. Any modifications should be made in such a way that it \ is clear that this copyright notice applies to the source, executables made \ therefrom and any derivatives thereof and in such a way that it is possible \ to regain the unmodified source."); button = new BButton(BRect(ABOUT_WIDTH / 2 - 30, ABOUT_HEIGHT - ABOUT_INDENT - 40, ABOUT_WIDTH / 2 + 30, ABOUT_HEIGHT - ABOUT_INDENT - 20), NULL, "OK", new BMessage(B_QUIT_REQUESTED)); view->AddChild(button); button->MakeDefault(true); button->SetTarget(about); about->Show(); } bool DGD::QuitRequested() { if (dgd_running) { interrupt(); return false; } return true; } /* * NAME: main() * DESCRIPTION: main program */ int main(int argc, char *argv[]) { DGD *app; dgd_argc = argc; dgd_argv = argv; app = new DGD(); app->Run(); delete app; return 0; } /* * NAME: P->message() * DESCRIPTION: show message */ extern "C" void P_message(char *mesg) { BMessage message(DGD_MESSAGE); message.AddString("mesg", mesg); mainframe->PostMessage(&message, NULL); }