/* * main.cc * * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes * * 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 2 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 blwm; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_XSMP #include #endif #include #include "misc.h" #include "blwm.h" #include "fbutton.h" #include "tbutton.h" #include "taskbar.h" #include "menu.h" #include "util.h" #include "event.h" #include "parse.h" #include "main.h" #include "blwmrc.h" #include "icon.h" #include "switcher.h" #include "paging.h" #include "pager.h" #include "mini.h" #include "timer.h" #include "key.h" #include "debug.h" #include "ver.h" #include "focus_mgr.h" #include "desktop.h" #include "dialog.h" #include "indicator.h" #include "mwm.h" #include "gnome.h" #include "info_display.h" #include "pixmap_image.h" #include "tooltip.h" #include "accessory.h" #include "startmenu.h" #include "radio_button.h" #include "session.h" #include "remote_cmd.h" #include "function.h" #include "bitmaps/logo16.xpm" #include "bitmaps/logo32.xpm" #include "bitmaps/cursor_arrow.xbm" #include "bitmaps/csmask_arrow.xbm" #include "bitmaps/cursor_size_h.xbm" #include "bitmaps/csmask_size_h.xbm" #include "bitmaps/cursor_size_v.xbm" #include "bitmaps/csmask_size_v.xbm" #include "bitmaps/cursor_size_l.xbm" #include "bitmaps/csmask_size_l.xbm" #include "bitmaps/cursor_size_r.xbm" #include "bitmaps/csmask_size_r.xbm" #include "bitmaps/cursor_busy.xbm" #include "bitmaps/csmask_busy.xbm" #include "bitmaps/cursor_move.xbm" #include "bitmaps/csmask_move.xbm" #include "bitmaps/cursor_wait.xbm" #include "bitmaps/csmask_wait.xbm" #include "bitmaps/cursor_no.xbm" #include "bitmaps/csmask_no.xbm" static char* rcFileName = NULL; /* Rc file name */ char* displayName = NULL; /* Display name */ Display* display; /* Display structure */ int screen; /* Default screen */ unsigned int depth; /* Default depth */ Colormap colormap; /* Default colormap */ Window root; /* Root window */ Blwm* rootBlwm; /* Virtual blwm for root window */ Rect rcScreen; /* Screen size (not include taskbar) */ GC gc, gcXor, gcDash; BlImage *imgLogo, *imgLargeLogo; Cursor cursor[9]; XFontSet fsDefault; XFontSet fsTitle, fsTaskbar, fsBoldTaskbar, fsIcon; XFontSet fsCtrlMenu, fsCascadeMenu, fsStartMenu, fsDialog; XColor black, white; XColor gray, darkGray, grey, darkGrey, blue, lightBlue, royalBlue; XColor yellow, lightYellow; XColor gray95, darkGray95, lightGray95, grey95, blue95, lightBlue95; XColor green95, yellow95; Bool synch = False; Bool shapeSupport; char** blArgv; Bool start = False; Bool restart = False; // ignora a sessao [Iniciar] Bool noParse = False; // not parse ~/.blwmrc and system.blwmrc Event event; FocusMgr focusMgr; Desktop desktop; Pixmap pixWallPaper; int failCount = 0; #ifdef USE_XSMP char* previousId = NULL; // The client Id from the previous session Session* session = NULL; #endif Bool enableTaskbar = True, enablePager = True; /* * Internal atoms. */ Atom _XA_WM_CHANGE_STATE; Atom _XA_WM_STATE; Atom _XA_WM_COLORMAP_WINDOWS; Atom _XA_WM_PROTOCOLS; Atom _XA_WM_TAKE_FOCUS; Atom _XA_WM_DELETE_WINDOW; Atom _XA_WM_DESKTOP; Atom _XA_WM_ICON_SIZE; #ifdef USE_XSMP Atom _XA_WM_WINDOW_ROLE; Atom _XA_WM_CLIENT_LEADER; Atom _XA_SM_CLIENT_ID; #endif //USE_XSMP Taskbar* taskBar = NULL; StartMenu* startMenu = NULL; TaskSwitcher* taskSwitcher = NULL; Paging* paging; Pager* pager = NULL; Menu* ctrlMenu; ExitDialog* exitDlg = NULL; ConfirmDialog* confirmDlg = NULL; Timer* timer; InfoDisplay* infoDisp; #ifdef ALLOW_RMTCMD RemoteCommand* remoteCmd = NULL; #endif /* * Local function prototype declaration. */ void AnalizeOptions(int argc, char** argv); void Usage(); void DisplayVersion(); void DisplayConfig(); void InitBlwm(); void SetSignal(); void SetGC(); void SetColor(); void CreateLogoMarkPixmap(); void CreateCursor(); void CreateInternAtom(); int CatchRedirectError(Display* display, XErrorEvent *ev); int CatchFatalError(Display *display); int BlwmErrorHandler(Display* display, XErrorEvent* ev); void TrapSignal(int sig); void TrapChild(int sig); void TrapAlarm(int sig); void TrapHup(int sig); int main(int argc, char** argv) { blArgv = argv; AnalizeOptions(argc, argv); /* * Open the display. */ if ((display = XOpenDisplay(displayName)) == NULL) { BlwmError("Nao foi possivel abrir o display %s", XDisplayName(displayName)); exit(1); } if (displayName) SetDisplayEnv(displayName); /* * Synchronize X events. */ if (synch) { XSynchronize(display, True); BlwmError("Modo Sincrono"); } /* * Set system defaults. */ screen = DefaultScreen(display); root = RootWindow(display, screen); depth = DefaultDepth(display, screen); colormap = DefaultColormap(display, screen); rcScreen = Rect(0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen)); /* * Select inputs for window manager. */ XSetErrorHandler(CatchRedirectError); XSetIOErrorHandler((XIOErrorHandler)CatchFatalError); XSelectInput(display, root, LeaveWindowMask | EnterWindowMask | PropertyChangeMask | SubstructureRedirectMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | SubstructureNotifyMask); XSync(display, 0); XSetErrorHandler(NULL); int shapeErrorBase; shapeSupport = XShapeQueryExtension(display, &event.shapeEventBase, &shapeErrorBase); SetSignal(); /* * Cleanup leftovers from previous session (after restart) */ if (restart) while (waitpid(-1, NULL, WNOHANG) > 0) ; /* * Set resources for blwm. */ CreateInternAtom(); ShortCutKey::SetModifier(); Indicator::Initialize(); BlFunction::initialize(); SetColor(); SetGC(); // used in ExecCommand for indicators timer = new Timer(); scKey = new SCKeyTable(); menuKey = new SCKeyTable(); desktop.CreateTopWindow(); ParseBlwmrc(rcFileName); if (XSupportsLocale() == False) BlwmError("O servidor grafico atual (\"X-Server\") \nnao suporta configuracoes regionais (\"locale\") "); InitBlwm(); start = True; event.MainLoop(); } /* * AnalizeOptions -- * Analize command line options. */ void AnalizeOptions(int argc, char** argv) { for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (strcmp(&argv[i][1], "-display") == 0 || strcmp(&argv[i][1], "d") == 0 ) displayName = argv[++i]; else if (strcmp(&argv[i][1], "-rcfile") == 0 || strcmp(&argv[i][1], "f") == 0) rcFileName = argv[++i]; else if (strcmp(&argv[i][1], "-noparse") == 0 || strcmp(&argv[i][1], "n") == 0) noParse = True; else if (strcmp(&argv[i][1], "-restart") == 0 || strcmp(&argv[i][1], "r") == 0) restart = True; #ifdef USE_XSMP else if (strcmp(&argv[i][1], "-clientid") == 0 || strcmp(&argv[i][1], "id") == 0 ) previousId = argv[++i]; #endif else if (strcmp(&argv[i][1], "-synch") == 0 || strcmp(&argv[i][1], "s") == 0 ) synch = True; else if (strcmp(&argv[i][1], "-version") == 0 || strcmp(&argv[i][1], "v") == 0) DisplayVersion(); else if (strcmp(&argv[i][1], "-config") == 0 || strcmp(&argv[i][1], "cfg") == 0) DisplayConfig(); else if (strcmp(&argv[i][1], "-failcount") == 0 || strcmp(&argv[i][1], "c") == 0) failCount = atoi(argv[++i]); else if (strcmp(&argv[i][1], "-help") == 0 || strcmp(&argv[i][1], "h") == 0) Usage(); else { printf("opcao invalida: %s\n", argv[i]); Usage(); } } else Usage(); } } void Usage() { printf("Use:\n"); printf("xinit [/usr/local/bin/]blwm [opcoes]\n"); printf(" Opcoes:\n"); printf(" --clientid client_id Especifica um ID para gerenciar a sessao\n"); printf(" --config Mostra opcoes de compilacao\n"); printf(" --display display_name Especifica um display\n"); printf(" --help Mostra esta ajuda\n"); printf(" --noparse Nao le nenhum arquivo de parametrizacao\n"); printf(" --rcfile rcfile_name Especifica um arquivo de parametrizacao\n"); printf(" --restart Inicia sem executar a sessao [Iniciar]\n"); printf(" --synch Executa o blanes2000 em modo sincrono\n"); printf(" --version Mostra informacoes de versao\n"); exit(0); } void DisplayVersion() { printf("Blanes 2000 versao %s (%s)\n", Version, Codename); printf("Copyright (C) 1999, 2001, 2001, 2002 Luiz Blanes.\n"); printf("E-mail: blanes@blanes.com.br\n"); printf("A ultima versao do Blanes 2000 pode ser encontrada em:\n"); printf("URL: http://www.blanes.com.br\n"); printf("\n"); printf("Este programa e uma versao simplificada do QVWM \n"); printf("que foi originalmente criado por Kenichi Kourai. \n"); printf("URL: http://www.qvwm.org\n"); exit(0); } void DisplayConfig() { printf("Config:\n"); printf(" binary directory: %s\n", BLWMDIR); printf(" images directory: %s\n", IMGDIR); printf(" options:"); #ifdef DEBUG printf(" [DEBUG]"); #endif #ifdef USE_XSMP printf(" [XSMP]"); #endif #ifdef ALLOW_RMTCMD printf(" [RMTCMD]"); #endif printf("\n"); exit(0); } /* * Initialize blwm. */ void InitBlwm() { XSetErrorHandler(BlwmErrorHandler); Blwm::Initialize(); TaskbarButton::Initialize(); Taskbar::Initialize(); Menu::Initialize(); Button::Initialize(); Dialog::Initialize(); TaskSwitcher::Initialize(); Miniature::Initialize(); Icon::Initialize(); Tooltip::Initialize(); FrameButton::Initialize(); StartMenu::Initialize(); RadioButton::Initialize(); CreateLogoMarkPixmap(); CreateCursor(); if (GradTitlebar) CreateGradPattern(); rootBlwm = new Blwm(root); ctrlMenu = new Menu(CtrlMenuItem, fsCtrlMenu, NULL, NULL); Icon::ctrlMenu = new IconMenu(IconMenuItem, fsCtrlMenu, NULL, NULL); desktop.SetWallPaper(); paging = new Paging(TopLeftPage, PagingSize); if (UsePager) { pager = new Pager(PagerGeometry); pager->MapPager(); } infoDisp = new InfoDisplay(); #ifdef ALLOW_RMTCMD if (AllowRemoteCmd) remoteCmd = new RemoteCommand(); #endif Mwm::Init(); Gnome::Init(); Gnome::SetGnomeCompliant(desktop.GetTopWindow()); taskBar->MoveTaskbar(TaskbarPosition); #ifdef USE_XSMP session = new Session(previousId); session->LoadSessionFile(); #endif desktop.CaptureAllWindows(); desktop.CreateIcons(); desktop.RedrawAllIcons(); desktop.CreateAccessories(); if (UseTaskbar) taskBar->MapTaskbar(); /* * Key bind for menu. */ for (int i = 0; i < MenuKeyNum; i++) menuKey->AddSCKey(scMenuKey[i].sym, scMenuKey[i].mod, scMenuKey[i].func); } /* * SetSignal -- * Set signal handlers. */ void SetSignal() { signal(SIGINT, TrapSignal); signal(SIGQUIT, TrapSignal); signal(SIGTERM, TrapSignal); signal(SIGSEGV, TrapSignal); signal(SIGBUS, TrapSignal); signal(SIGFPE, TrapSignal); //#ifndef USE_XSMP signal(SIGCHLD, TrapChild); //#endif signal(SIGHUP, TrapHup); } /* * SetColor -- * Allocate mininum colors for blwm. */ void SetColor() { if (CreateColor(0x0000, 0x0000, 0x0000, &black) == 0) { BlwmError("cannot allocate color: black"); exit(1); } if (CreateColor(0xffff, 0xffff, 0xffff, &white) == 0) { BlwmError("cannot allocate color: white"); exit(1); } CreateColor(0xd4d4, 0xd0d0, 0xc8c8, &gray, &white, "gray"); CreateColor(0x8080, 0x8080, 0x8080, &darkGray, &black, "dark gray"); CreateColor(0xc0c0, 0xc0c0, 0xc0c0, &grey, &gray, "grey"); CreateColor(0x4040, 0x4040, 0x4040, &darkGrey, &black, "dark grey"); CreateColor(0x0a0a, 0x2424, 0x6a6a, &blue, &black, "blue"); CreateColor(0xa6a6, 0xcaca, 0xf0f0, &lightBlue, &blue, "light blue"); CreateColor(0x3a3a, 0x6e6e, 0xa5a5, &royalBlue, &blue, "royal blue"); CreateColor(0xf5f5, 0xdbdb, 0x9595, &yellow, &white, "yellow"); CreateColor(0xffff, 0xffff, 0xe1e1, &lightYellow, &white, "lightYellow"); // backward compatibility gray95.pixel = 0; darkGray95.pixel = 0; lightGray95.pixel = 0; grey95.pixel = 0; blue95.pixel = 0; lightBlue95.pixel = 0; green95.pixel = 0; yellow95.pixel = 0; IconForeColor = black; IconBackColor = white; IconStringColor = white; IconStringActiveColor = white; MiniatureColor = black; MiniatureActiveColor = white; TitlebarColor = darkGray; TitlebarActiveColor = blue; TitlebarColor2 = grey; TitlebarActiveColor2 = lightBlue; TitleStringColor = gray; TitleStringActiveColor = white; MenuColor = gray; MenuActiveColor = blue; MenuStringColor = black; MenuStringActiveColor = white; DialogColor = gray; DialogStringColor = black; SwitcherColor = gray; SwitcherActiveColor = blue; SwitcherStringColor = black; FrameColor = gray; FrameActiveColor = gray; PagerColor = gray; PagerActiveColor = darkGray; ButtonColor = gray; ButtonActiveColor = gray; ButtonStringColor = black; ButtonStringActiveColor = black; TaskbarColor = gray; ClockStringColor = black; DesktopColor = royalBlue; DesktopActiveColor = blue; StartMenuLogoColor = black; CursorColor = white; TooltipColor = lightYellow; TooltipStringColor = black; } /* * SetGC -- * Set GC for normal, xor and dash. */ void SetGC() { XGCValues gcv; unsigned long gcm; char dash[] = {1, 1}; gc = XCreateGC(display, root, 0, 0); gcv.function = GXxor; gcv.line_width = 4; gcv.foreground = darkGray.pixel; gcv.subwindow_mode = IncludeInferiors; gcm = GCFunction | GCLineWidth | GCForeground | GCSubwindowMode; gcXor = XCreateGC(display, root, gcm, &gcv); gcDash = XCreateGC(display, root, 0, 0); XSetDashes(display, gcDash, 0, dash, 2); XSetLineAttributes(display, gcDash, 1, LineOnOffDash, CapButt, JoinMiter); } /* * CreateCursor -- * Create cursors. */ void CreateCursor() { Pixmap pixCursor, maskCursor; char* curbits[9] = { cursor_arrow_bits, cursor_size_h_bits, cursor_size_v_bits, cursor_size_l_bits, cursor_size_r_bits, cursor_busy_bits, cursor_move_bits, cursor_wait_bits, cursor_no_bits }; char* maskbits[9] = { csmask_arrow_bits, csmask_size_h_bits, csmask_size_v_bits, csmask_size_l_bits, csmask_size_r_bits, csmask_busy_bits, csmask_move_bits, csmask_wait_bits, csmask_no_bits }; Dim size[9] = { Dim(cursor_arrow_width, cursor_arrow_height), Dim(cursor_size_h_width, cursor_size_h_height), Dim(cursor_size_v_width, cursor_size_v_height), Dim(cursor_size_l_width, cursor_size_l_height), Dim(cursor_size_r_width, cursor_size_r_height), Dim(cursor_busy_width, cursor_busy_height), Dim(cursor_move_width, cursor_move_height), Dim(cursor_wait_width, cursor_wait_height), Dim(cursor_no_width, cursor_no_height) }; Point spot[9] = { Point(10, 6), Point(15, 15), Point(14, 15), Point(14, 15), Point(14, 14), Point(15, 15), Point(16, 16), Point(4, 5), Point(17, 17) }; for (int i = 0; i < 9; i++) { pixCursor = XCreateBitmapFromData(display, root, curbits[i], size[i].width, size[i].height); maskCursor = XCreateBitmapFromData(display, root, maskbits[i], size[i].width, size[i].height); cursor[i] = XCreatePixmapCursor(display, pixCursor, maskCursor, &black, &CursorColor, spot[i].x, spot[i].y); XFreePixmap(display, pixCursor); XFreePixmap(display, maskCursor); } XDefineCursor(display, root, cursor[SYS]); } /* * CreateInternAtom -- * Create internal atoms of window manager. */ void CreateInternAtom() { _XA_WM_CHANGE_STATE = XInternAtom(display, "WM_CHANGE_STATE", False); _XA_WM_STATE = XInternAtom(display, "WM_STATE", False); _XA_WM_COLORMAP_WINDOWS = XInternAtom(display, "WM_COLORMAP_WINDOWS", False); _XA_WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False); _XA_WM_TAKE_FOCUS = XInternAtom(display, "WM_TAKE_FOCUS", False); _XA_WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False); _XA_WM_DESKTOP = XInternAtom(display, "WM_DESKTOP", False); _XA_WM_ICON_SIZE = XInternAtom(display, "WM_ICON_SIZE", False); #ifdef USE_XSMP _XA_WM_WINDOW_ROLE = XInternAtom(display, "WM_WINDOW_ROLE", False); _XA_WM_CLIENT_LEADER = XInternAtom(display, "WM_CLIENT_LEADER", False); _XA_SM_CLIENT_ID = XInternAtom(display, "SM_CLIENT_ID", False); #endif } /* * CreateLogoMarkPixmap -- * Create pixmaps for logo mark. */ void CreateLogoMarkPixmap() { if (DefaultIcon == NULL) imgLogo = new PixmapImage(logo16); else { imgLogo = CreateImageFromFile(DefaultIcon, timer); if (imgLogo == NULL) imgLogo = new PixmapImage(logo16); } if (DefaultLargeIcon == NULL) imgLargeLogo = new PixmapImage(logo32); else { imgLargeLogo = CreateImageFromFile(DefaultLargeIcon, TaskSwitcher::swTimer); if (imgLargeLogo == NULL) imgLargeLogo = new PixmapImage(logo32); } } /* * CatchRedirectError -- * Jump here when another window manager is running. */ int CatchRedirectError(Display* display, XErrorEvent *ev) { BlwmError("Outro gerenciador de Janelas esta ativo"); exit(1); } /* * CatchFatalError -- * Jump here when an fatal I/O error happens in X server. */ int CatchFatalError(Display *display) { XCloseDisplay(display); exit(1); } /* * BlwmErrorHandler -- * Jump here when an error happens in X server. */ int BlwmErrorHandler(Display *display, XErrorEvent* ev) { #ifndef DEBUG if (ev->error_code == BadWindow || ev->error_code == BadDrawable || ev->request_code == X_GetGeometry || ev->request_code == X_GrabButton || ev->request_code == X_SetInputFocus || ev->request_code == X_ChangeWindowAttributes || ev->request_code == X_InstallColormap) return 0; #endif char msg[128], number[32], request[128]; XGetErrorText(display, ev->error_code, msg, 128); sprintf(number, "%d", ev->request_code); XGetErrorDatabaseText(display, "XRequest", number, "", request, 128); if (*request == '\0') sprintf(request, "Unknown_Code_%d", ev->request_code); BlwmError("%s (0x%lx): %s", request, ev->resourceid, msg); return 0; } #define DEBUGGER "gdb" /* * TrapSignal -- * General signal handler. */ void TrapSignal(int sig) { if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV) { signal(SIGSEGV, SIG_DFL); BlwmError("Falha de Segmentacao"); } else { signal(SIGBUS, SIG_DFL); BlwmError("Erro de Bus"); } if (UseDebugger) { Debug debug; BlwmError("Iniciando %s...", DEBUGGER); debug.TraceStack(DEBUGGER, blArgv[0]); } // terminate accessory processes // This is done in FinishBlwm, but it is not called from here... List::Iterator i(&desktop.GetAccList()); for (Accessory* acc = i.GetHead(); acc; acc = i.Remove()) delete acc; if (RestartOnFailure) { timer->ResetAllTimeouts(); XSetInputFocus(display, root, RevertToNone, CurrentTime); if (start) paging->PagingProc(Point(0, 0)); // Exit blwm if failure coutinues if (failCount < MAX_FAILURE_COUNT) { BlwmError("Reiniciando Automaticamente..."); RestartBlwm(False, failCount + 1, False); } else { BlwmError("Numero de falhas ultrapassou o maximo. Inicie o Blanes2000 novamente."); XCloseDisplay(display); exit(1); } } else { XSetInputFocus(display, root, RevertToNone, CurrentTime); if (start) paging->PagingProc(Point(0, 0)); XCloseDisplay(display); exit(1); } } FinishBlwm(); } /* * TrapChild -- * Signal handler for child termination. */ void TrapChild(int sig) { pid_t pid; while (1) { pid = waitpid(-1, NULL, WNOHANG); if (pid <= 0) break; if (Indicator::NotifyDeadPid(pid)) continue; } signal(SIGCHLD, TrapChild); } void TrapHup(int sig) { RestartBlwm(); } #ifdef HAVE_VPRINTF /* * BlwmError -- * Display an error in blwm. */ void BlwmError(const char* fmt, ...) { va_list args; char buf[256]; va_start(args, fmt); sprintf(buf, "blwm: %s\n", fmt); vfprintf(stderr, buf, args); va_end(args); } #endif // HAVE_VPRINTF void FinishBlwm() { #ifdef USE_XSMP if (session->GetStatus()) { if (!session->RequestQuit()) desktop.FinishBlwm(False); } else #endif // USE_XSMP desktop.FinishBlwm(False); } void RestartBlwm(Bool minimumRestart, int count, Bool cleanup) { char *p, *argv[20], buf[8]; int i, j; if (cleanup) desktop.FinishBlwm(True); // Fvwm family sets "fvwm" to argument 0 of blwm. // I think that it is a bug of fvwm... for (p = blArgv[0]; *p; p++) ; while (--p >= blArgv[0] && *p != '/') ; // Allows blwm* (e.g. "blwm", "blwm-1.0r4") // If you want another name (e.g. "Blwm"), use "EXEC ..." instead. if (strncmp(++p, "blwm", 4) != 0) { BlwmError("blwm's 1st argument is not 'blwm*' but '%s'", p); BlwmError("restart 'blwm'"); blArgv[0] = "blwm"; } for (i = 0, j = 0; blArgv[i] != NULL && j < 16; i++) { // read through a restart option if (strcmp(blArgv[i], "-r") == 0) continue; // read through a failure count option if (strcmp(blArgv[i], "-c") == 0) { i++; continue; } argv[j++] = blArgv[i]; } if (minimumRestart) argv[j++] = "-n"; else { argv[j++] = "-r"; // add an option if from FailureOnRestart if (count > 0) { argv[j++] = "-c"; sprintf(buf, "%d", count); argv[j++] = buf; } } argv[j] = NULL; execvp(argv[0], argv); }