/*

  Original idea by Richard L. Hamilton, slightly modified by Mariusz Zynel.
  
  Compile with the command:
  gcc ldthalt.c -lXm -lXt -lX11 -lsocket -lnsl -L/usr/dt/lib:/usr/openwin/lib -R/usr/dt/lib:/usr/openwin/lib -o ldthalt

*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/extensions/shape.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/MessageB.h>
#include <sys/utsname.h>

struct callbackData {
    Widget top;
    Widget dialog;
    Widget toRaise;
    Widget haltDialog;
    Widget rebootDialog;
};

void HaltAskYN(Widget widget, XtPointer closure, XtPointer call_data)
{
    ((struct callbackData*) closure)->dialog = ((struct callbackData*) closure)->haltDialog;
    ((struct callbackData*) closure)->toRaise = XtParent(((struct callbackData*) closure)->dialog);
    XtManageChild(((struct callbackData *) closure)->dialog);
}

void RebootAskYN(Widget widget, XtPointer closure, XtPointer call_data)
{
    ((struct callbackData*) closure)->dialog = ((struct callbackData*) closure)->rebootDialog;
    ((struct callbackData*) closure)->toRaise = XtParent(((struct callbackData*) closure)->dialog);
    XtManageChild(((struct callbackData *) closure)->dialog);
}

void No(Widget widget, XtPointer closure, XtPointer call_data)
{
    XtUnmanageChild(((struct callbackData *) closure)->dialog);

}

void UnAsk(Widget widget, XtPointer closure, XtPointer call_data)
{
    ((struct callbackData*) closure)->toRaise = ((struct callbackData*) closure)->top;

}

void Halt(Widget widget, XtPointer closure, XtPointer call_data)
{
    execl("/usr/sbin/init","init","5",NULL);
    perror("/usr/sbin/init 5");
    exit(2);

}

void Reboot(Widget widget, XtPointer closure, XtPointer call_data)
{
    execl("/usr/sbin/init","init","6",NULL);
    perror("/usr/sbin/init 6");
    exit(2);

}

void raiseMe(Widget widget, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch)
{
    if (event->type == VisibilityNotify && event->xvisibility.state != VisibilityUnobscured)
       XRaiseWindow(XtDisplay(((struct callbackData *) client_data)->toRaise),
             XtWindow(((struct callbackData *) client_data)->toRaise));
}

int main(int argc, char **argv)
{
    static XtAppContext app_con;
    static Screen *screen;
    static Position x, y;
    static Widget toplevel, shell, haltbutton, rebootbutton, helpbutton;
    static Arg dialog_args[9];
    static struct utsname utsname;
    static struct callbackData cdata;
    static XtCallbackRec hdc[] = {{HaltAskYN, NULL}, {NULL, NULL}},
                         hyc[] = {{Halt, NULL}, {NULL, NULL}},
                         hnc[] = {{No, NULL}, {NULL, NULL}},
                         huc[] = {{UnAsk, NULL}, {NULL, NULL}};
    static XtCallbackRec rdc[] = {{RebootAskYN, NULL}, {NULL, NULL}},
                         ryc[] = {{Reboot, NULL}, {NULL, NULL}},
                         rnc[] = {{No, NULL}, {NULL, NULL}},
                         ruc[] = {{UnAsk, NULL}, {NULL, NULL}};
    static String fallback_resources[] = {
       "LdtHalt*FontList: -dt-interface system-medium-r-normal-l*-*-*-*-*-*-*-*",
       "LdtHalt*XmPushButton.FontList: -dt-interface system-medium-r-normal-l*-*-*-*-*-*-*-*",
       "LdtHalt*XmPushButton.Background: Red",
       "LdtHalt*Background: #416d89",
       "LdtHalt*shell.shadowThickness: 0",
       NULL,
    };
    static char msgbuf[SYS_NMLN + 80];

    toplevel = XtAppInitialize(&app_con, "LdtHalt", NULL, 0,
       &argc, argv, fallback_resources, NULL, 0);

    if (toplevel == NULL) {
       fprintf(stderr,"ldthalt: can't initialize display\n");
       exit(1);
    }

    screen = XtScreen(toplevel);
    x = WidthOfScreen(screen) * 0.075;
    y = HeightOfScreen(screen) - HeightOfScreen(screen) * 0.075;
    XtVaSetValues(toplevel, XmNwidth, 260, XmNheight, 38, XmNx, x, XmNy, y, NULL);

    cdata.top = cdata.toRaise = toplevel;

    shell = XtVaCreateWidget("shell", xmFormWidgetClass,
                     toplevel,
                     NULL);

    hdc[0].closure = hnc[0].closure = huc[0].closure = &cdata;

    haltbutton = XtVaCreateManagedWidget("haltbutton", xmPushButtonWidgetClass,
                     shell,
                     XmNlabelString, XmStringCreateSimple("Shutdown"),
                     XmNwidth, 120,
                     XmNheight, 38,
                     XmNx, 0,
                     XmNy, 0,
                     XmNactivateCallback, hdc,
                     NULL);

    uname(&utsname);
    sprintf(msgbuf, "Do you really want to shut down \"%s\"?", utsname.nodename);

    XtSetArg(dialog_args[0], XmNmessageString, XmStringCreateSimple(msgbuf));
    XtSetArg(dialog_args[1], XmNokLabelString, XmStringCreateSimple("Yes"));
    XtSetArg(dialog_args[2], XmNcancelLabelString, XmStringCreateSimple("No"));
    XtSetArg(dialog_args[3], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL);
    XtSetArg(dialog_args[4], XmNdialogTitle, XmStringCreateSimple("Shutdown Question"));
    XtSetArg(dialog_args[5], XmNokCallback, hyc);
    XtSetArg(dialog_args[6], XmNcancelCallback, hnc);
    XtSetArg(dialog_args[7], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
    XtSetArg(dialog_args[8], XmNunmapCallback, huc);

    cdata.haltDialog = XmCreateQuestionDialog(toplevel, "shutdown_question", dialog_args, 9);

    helpbutton = XmMessageBoxGetChild(cdata.haltDialog, XmDIALOG_HELP_BUTTON);
    XtUnmanageChild(helpbutton);

    rdc[0].closure = rnc[0].closure = ruc[0].closure = &cdata;

    rebootbutton = XtVaCreateManagedWidget("rebootbutton", xmPushButtonWidgetClass,
                     shell,
                     XmNlabelString, XmStringCreateSimple("Reboot"),
                     XmNwidth, 120,
                     XmNheight, 38,
                     XmNx, 140,
                     XmNy, 0,
                     XmNactivateCallback, rdc,
                     NULL);

    sprintf(msgbuf, "Do you really want to reboot \"%s\"?", utsname.nodename);

    XtSetArg(dialog_args[0], XmNmessageString, XmStringCreateSimple(msgbuf));
    XtSetArg(dialog_args[1], XmNokLabelString, XmStringCreateSimple("Yes"));
    XtSetArg(dialog_args[2], XmNcancelLabelString, XmStringCreateSimple("No"));
    XtSetArg(dialog_args[3], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL);
    XtSetArg(dialog_args[4], XmNdialogTitle, XmStringCreateSimple("Reboot Question"));
    XtSetArg(dialog_args[5], XmNokCallback, ryc);
    XtSetArg(dialog_args[6], XmNcancelCallback, rnc);
    XtSetArg(dialog_args[7], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
    XtSetArg(dialog_args[8], XmNunmapCallback, ruc);

    cdata.rebootDialog = XmCreateQuestionDialog(toplevel, "reboot_question", dialog_args, 9);

    helpbutton = XmMessageBoxGetChild(cdata.rebootDialog, XmDIALOG_HELP_BUTTON);
    XtUnmanageChild(helpbutton);

    XtAddEventHandler(toplevel, VisibilityChangeMask, FALSE, raiseMe, &cdata);
    XtAddEventHandler(cdata.haltDialog, VisibilityChangeMask, FALSE, raiseMe, &cdata);
    XtAddEventHandler(cdata.rebootDialog, VisibilityChangeMask, FALSE, raiseMe, &cdata);

    XtManageChild(shell);
    XtRealizeWidget(toplevel);

    XtAppMainLoop(app_con);

    return(0);
}




