/*
 * $Source: /afs/athena.mit.edu/user/j/i/jik/sipbsrc/src/xscreensaver/RCS/menuIcon.c,v $
 * $Author: jik $
 *
 * This file is part of xscreensaver.  It contains the code for the
 * xscreensaver icon and for the pop-up menu.
 *
 * Author: Jonathan Kamens, MIT Project Athena and
 *                          MIT Student Information Processing Board
 *
 * Copyright (c) 1989 by Jonathan Kamens.  This code may be
 * distributed freely as long as this notice is kept intact in its
 * entirety and every effort is made to send all corrections and
 * improvements to the code back to the author.  Also, don't try to
 * make any money off of it or pretend that you wrote it.
 */

#ifndef lint
     static char rcsid_menuIcon_c[] = "$Header: /afs/athena.mit.edu/user/j/i/jik/sipbsrc/src/xscreensaver/RCS/menuIcon.c,v 1.22 1992/08/23 05:27:52 jik Exp $";
#endif

#include "xsaver.h"
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Shell.h>
#include "globals.h"
#include "getstring.h"
#include "check_mark"

extern void ActivateRoot(), XtMoveWidget(), change_timeout(),
     change_lock(), change_unlock(), change_message();

void ClickSave(), ActivateMenu(), ActivateMenuCallback(), build_menu(),
     build_icon(), check_lock();

static Widget menu_shell, icon_widget;
static Widget *SmeWidgets;

static Pixmap checkmark = 0;
static Pixmap blankmark = 0;


/************************************/
/* Callback procedures for the menu */
/************************************/


/*ARGSUSED*/
void autolockCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     defs.auto_lock = !defs.auto_lock;

     if (defs.auto_lock)
	  XtVaSetValues(XtNameToWidget(menu_shell, "autoLock"),
			XtNleftBitmap, checkmark,
			NULL);
     else
	  XtVaSetValues(XtNameToWidget(menu_shell, "autoLock"),
			XtNleftBitmap, blankmark,
			NULL);
}


/*ARGSUSED*/
void blankCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     lock_flag = False;
     ActivateRoot();
     return;
}


/*ARGSUSED*/
void lockCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     lock_flag = True;
     ActivateRoot();
     return;
}


/*ARGSUSED*/
void changeTimeoutCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     xscr_getstring(top_widget, "newTimeout", "Enter new timeout:",
		    -1, change_timeout, GS_CURSORPOS);
     return;
}


/*ARGSUSED*/
void changeLockCommandCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     xscr_getstring(top_widget, "newLock", "Enter new lock command:",
		    -1, change_lock, GS_CURSORPOS);
     return;
}


/*ARGSUSED*/
void changeUnlockCommandCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     xscr_getstring(top_widget, "newUnlock", "Enter new unlock command:",
		    -1, change_unlock, GS_CURSORPOS);
     return;
}


/*ARGSUSED*/
void changeLockMessageCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     xscr_getstring(top_widget, "newMessage", "Enter new lock message:",
		    -1, change_message, GS_CURSORPOS);
     return;
}


/*ARGSUSED*/
void exitCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     if (debug_file) {
	  fprintf(debug_file,
		  "About to destroy top widget 0x%x (window id 0x%x) in menu_select.\n",
		  top_widget, XtWindow(top_widget));
     }
     XtDestroyWidget(top_widget);
     XtCloseDisplay(dpy);
     clean_up_and_die(0);
}


/*ARGSUSED*/
void clearPasswordCallback(w, closure, call_data)
Widget w;
XtPointer closure, call_data;
{
     XtFree(defs.key);
     XtFree(defs.ekey);
     defs.key = defs.ekey = 0;
     XBell(XtDisplayOfObject(w), 0);
}



/* The array of strings we will use for the popup menu: */



struct menu_elem {
     String name, label;
     XtCallbackProc callback;
};



static struct menu_elem menu_stringlist[] = {
     {"autoLock", "Auto-Lock", autolockCallback},
     {"blank", "Blank Screen", blankCallback},
     {"lock", "Lock Screen", lockCallback},
     {"changeTimeout", "Change Timeout", changeTimeoutCallback},
     {"changeLockCommand", "Change Lock Command", changeLockCommandCallback},
     {"changeUnlockCommand", "Change Unlock Command", changeUnlockCommandCallback},
     {"changeLockMessage", "Change Lock Message", changeLockMessageCallback},
     {"clearPassword", "Clear Lock Password", clearPasswordCallback},
     {"exit", "Exit", exitCallback}
};
#define NUMLINES 9


void build_icon()
{
     XtTranslations trans;
     static String transStrings[] = {
	  "<EnterWindow>:	highlight()\n\
	   <LeaveWindow>:	reset()\n\
           <Btn1Down>:		set() reset() PopupMenu()\n\
	   <BtnDown>:		set()\n\
           <BtnUp>:		notify() reset()\n\
           <Map>:		check_lock()",
	  "<EnterWindow>:	highlight()\n\
	   <LeaveWindow>:	reset()\n\
           <Btn2Down>:		set() reset() PopupMenu()\n\
	   <BtnDown>:		set()\n\
           <BtnUp>:		notify() reset()\n\
           <Map>:		check_lock()",
	  "<EnterWindow>:	highlight()\n\
	   <LeaveWindow>:	reset()\n\
           <Btn3Down>:		set() reset() PopupMenu()\n\
	   <BtnDown>:		set()\n\
           <BtnUp>:		notify() reset()\n\
           <Map>:		check_lock()"
     };

     icon_widget = XtVaCreateManagedWidget("icon", menuButtonWidgetClass,
					   top_widget,
					   XtNmenuName, "menu",
					   NULL);
     XtAddCallback(icon_widget, XtNcallback, ClickSave, NULL);
     XtUninstallTranslations(icon_widget);
     trans = XtParseTranslationTable(transStrings[defs.menu_button - 1]);
     XtOverrideTranslations(icon_widget, trans);
}




void build_menu()
{
     int i = 0;
     Pixmap fornow = XtUnspecifiedPixmap;

     static String leaveClose =
	  "<Leave>:		unhighlight() MenuPopdown(menu)\n";

     /* Allocate space for them */
     SmeWidgets = (Widget *) XtMalloc(sizeof(Widget) * NUMLINES);

     checkmark = XCreateBitmapFromData (XtDisplay(top_widget),
					RootWindowOfScreen(XtScreen(top_widget)),
					check_bits, check_width, check_height);
     blankmark = XCreateBitmapFromData (XtDisplay(top_widget),
					RootWindowOfScreen(XtScreen(top_widget)),
					blank_bits, check_width, check_height);

     if (defs.auto_lock) 
	  fornow = checkmark;
     else
	  fornow = blankmark;
     
     menu_shell = XtVaCreatePopupShell("menu",
				       simpleMenuWidgetClass,
				       top_widget, NULL);
     
     for (i = 0; i < NUMLINES; i++) {
	  String name, label;
	  
	  name = menu_stringlist[i].name;
	  label = menu_stringlist[i].label;
	  
	  SmeWidgets[i] = XtVaCreateWidget(name,
					   smeBSBObjectClass,
					   menu_shell,
					   XtNlabel, label,
					   NULL);
	  XtAddCallback(SmeWidgets[i], XtNcallback,
			menu_stringlist[i].callback, NULL);
     }

     XtVaSetValues(XtNameToWidget(menu_shell, "autoLock"),
		   XtNleftBitmap, fornow,
		   NULL);
     
     XtManageChildren(SmeWidgets, NUMLINES);

     if (defs.leave_close) {
	  XtTranslations leaveClose_translations =
	       XtParseTranslationTable(leaveClose);
	  XtOverrideTranslations(menu_shell, leaveClose_translations);
     }

     XtAddCallback(menu_shell, XtNpopupCallback, ActivateMenuCallback, NULL);
     XtRealizeWidget(menu_shell);
}











/* Now, the action procedures and callbacks: */

/* ARGSUSED */
void ActivateMenuCallback(widget, closure, call_data)
Widget widget;
XtPointer closure;
XtPointer call_data;
{
     ActivateMenu(0, 0, 0, 0);
}

/* ARGSUSED */
void ActivateMenu(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
     Window garbage1, garbage2;		/* garbage return values */
     int root_x, root_y;		/* the cursor position with */
					/* respect to the origin of */
					/* the root window.  This is */
					/* what we want to use. */
     int x2, y2;			/* more garbage */
     unsigned int mask;			/* still more garbage */
     Dimension width, height, border;	/* dimensions of the menu */
     Arg arglist[3];
     int i = 0;

     /* The purpose of all this rigamarole when all we want to do is */
     /* popup a menu is to place the menu at the current cursor */
     /* position while making sure that it does not go off the screen. */

     if (XQueryPointer(dpy, real_root_window, &garbage1, &garbage2,
		       &root_x, &root_y, &x2, &y2, &mask)) {
	  XtSetArg(arglist[i], XtNwidth, &width); 			i++;
	  XtSetArg(arglist[i], XtNheight, &height); 			i++;
	  XtSetArg(arglist[i], XtNborderWidth, &border); 		i++;
	  XtGetValues(menu_shell, arglist, i); 				i = 0;
	  
	  /* First, calculate the x coordinate so that the menu pops */
	  /* up with the mouse on the vertical center-line if */
	  /* possible, or come as close as possible. */
	  if (root_x >= width / 2 + border) 
	       root_x -= width / 2 + border;
	  else				
	       root_x = 0;

	  /* Make sure we're not falling off the screen. */
	  if (root_x + width + 2 * border > display_width)
	       root_x = display_width - width - 2 * border;
	  if (root_y + height + 2 * border > display_height)
	       root_y = display_height - height - 2 * border;

	  /* Move the widget to the new location. */
	  XtMoveWidget(menu_shell, root_x, root_y);
     }
     else
	  fprintf(stderr, "%s: Error in XQueryWindow.\n", whoami);
}




/* ARGSUSED */
void check_lock(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
     if (defs.start_locked) {
	  sleep(1);  /* give the window manager time to get the icon up */
	  lock_flag = True;
	  ActivateRoot();
     }
}




	  
/* ARGSUSED */
void ClickSave(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
     lock_flag = defs.auto_lock;
     ActivateRoot();
}
