Index: trunk/hiptop/pester/locale/en_US/Pester.rsrc
===================================================================
--- trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 241)
+++ trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 242)
@@ -98,11 +98,11 @@
 
 	typeAheadTextField
-		fillToRight = 0
 		id = ID_MESSAGE_FIELD
-		alignBaseline = ID_MESSAGE_LABEL
-		positionToRight = ID_MESSAGE_LABEL : 3	
 		autoCap
 		initiallySelectAll
 		initialFocus
+		alignBaseline = ID_MESSAGE_LABEL
+		positionToRight = ID_MESSAGE_LABEL : 3	
+		fillToRight = 0
 
 	groupBox
@@ -175,13 +175,26 @@
 	button
 		id = ID_DISCARD_ALARM_BUTTON
+		event = EVENT_DISCARD_ALARM
 		position = buttonTop2
 		title = "Discard"
-		event = EVENT_DISCARD_ALARM
 
 	button
 		id = ID_SET_ALARM_BUTTON
+		event = EVENT_SET_ALARM
 		position = buttonBottom1
 		title = "Set"
 		shortcut = doneButton
-		event = EVENT_SET_ALARM
 endDialog
+
+alert ID_ALARM_ALERT
+	systemDialog
+	title = "Alarm"
+	icon = ID_LARGE_ICON
+	font = "BortBold12"
+	text = "Alarm!"
+	button
+		event = EVENT_DISMISS_ALARM
+		title = "OK"
+		position = buttonBottom1
+		shortcut = doneButton
+endAlert
Index: trunk/hiptop/pester/net/sabi/pester/Alarm.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 241)
+++ trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 242)
@@ -5,5 +5,7 @@
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
+import danger.app.Application;
 import danger.internal.Date;
+import danger.util.StdActiveList;
 import danger.util.StdActiveObject;
 import danger.util.DEBUG;
@@ -20,7 +22,9 @@
     // transient
     private int mState;
+    private danger.app.Alarm mAlarm;
 
     public Alarm() {
 	mState = STATE_INVALID;
+	mAlarm = new danger.app.Alarm(0, Application.getCurrentApp(), this);
     }
 
@@ -92,7 +96,20 @@
     void beginEditing() {
 	mState = STATE_EDITING;
+	mAlarm.deactivate();
     }
 
-    void endEditing() {
+    void dismiss() {
+	if (getRepeating())
+	    schedule();
+	else
+	    ((StdActiveList)getDelegate()).removeItem(this);
+    }
+
+    void cancel() {
+	mState = STATE_INVALID;
+	mAlarm.deactivate();
+    }
+
+    void schedule() {
 	mState = STATE_SCHEDULED;
 	DEBUG.p("schedule alarm: " + mMessage);
@@ -105,4 +122,5 @@
 	    DEBUG.p(" - date: " + mDate); break;
 	}
+	mAlarm.resetWake(mPeriod);
     }
     
@@ -118,4 +136,3 @@
     public static final int STATE_EDITING = 1;
     public static final int STATE_SCHEDULED = 2;
-    public static final int STATE_EXPIRED = 3;
 }
Index: trunk/hiptop/pester/net/sabi/pester/AlarmListView.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/AlarmListView.java	(revision 241)
+++ trunk/hiptop/pester/net/sabi/pester/AlarmListView.java	(revision 242)
@@ -35,4 +35,5 @@
     private Menu sPeriodUnitsMenu;
     private PopupMenu sPeriodUnitsPopup;
+    // XXX don't allow <5 second repeating alarms
     private CheckBox sRepeatCheckBox;
     private DateTimeEditor sTimeEditor, sDateEditor;
@@ -128,8 +129,10 @@
     protected void constrainDate() {
 	// XXX schedule every minute (second?) if in AT mode
+	// XXX could use onPeriodicPulse() perhaps
 	Date now = new Date();
 	sDateEditor.min(now);
 	sDatePicker.min(now);
-	sSetAlarmButton.setEnabled(editingDate().compareTo(now) > 0);
+	sSetAlarmButton.setEnabled(sInButton.getValue() == 1 ||
+				   editingDate().compareTo(now) > 0);
     }
 
@@ -153,13 +156,11 @@
 		sAlarmList.addItem(sEditingAlarm);
 		setFocusedItem(sEditingAlarm);
-		sFocusedAlarm = sEditingAlarm; // XXX do we need this?
+		sFocusedAlarm = sEditingAlarm;
 	    } else {
 		sEditingAlarm.update();
 	    }
 	case EVENT_CANCEL_ALARM:
-	    if (sEditingAlarm == sFocusedAlarm) { // existing alarm
-		// XXX (re)schedule alarm
-		sEditingAlarm.endEditing();
-	    }
+	    if (sEditingAlarm == sFocusedAlarm)
+		sEditingAlarm.schedule();
 	    sEditingAlarm = null;
 	    return true;
@@ -170,4 +171,5 @@
 	case EVENT_IN:
 	    sAtButton.setValue(0);
+	    constrainDate();
 	    return true;
 	case EVENT_AT:
@@ -177,5 +179,4 @@
 	case EVENT_TIME_EDITOR:
 	    Date date = editingDate();
-	    // XXX factor this out (it's used twice)
 	    // XXX do this on exit from the field, not on change
 	    if (date.compareTo(new Date()) <= 0) {
@@ -214,4 +215,5 @@
     }
     public void onItemRemoved(ActiveList list, Object item, int index) {
+	((Alarm)item).cancel();
 	sAlarmListWindow.updateAlarmCount();
 	super.onItemRemoved(list, item, index);
Index: trunk/hiptop/pester/net/sabi/pester/AlarmListWindow.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/AlarmListWindow.java	(revision 241)
+++ trunk/hiptop/pester/net/sabi/pester/AlarmListWindow.java	(revision 242)
@@ -19,5 +19,5 @@
 	StringBuffer sb = new StringBuffer().append(size).append(" alarm");
 	if (size != 1) sb.append('s');
-	sb.append(" set");
+	// sb.append(" set");
 	setSubTitle(sb.toString());
     }
Index: trunk/hiptop/pester/net/sabi/pester/Pester.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Pester.java	(revision 241)
+++ trunk/hiptop/pester/net/sabi/pester/Pester.java	(revision 242)
@@ -2,12 +2,35 @@
 
 import danger.app.Application;
+import danger.app.Event;
+import danger.ui.AlertWindow;
 import danger.ui.ScreenWindow;
+import danger.util.DEBUG;
+import java.util.Stack;
 
 public class Pester extends Application implements Resources, Commands {
+    private static ScreenWindow sAlarmListWindow;
+    private static Stack sAlarmStack;
+
     public Pester() {
-	alarmListWindow = (ScreenWindow)getResources().getScreen(ID_ALARM_LIST_SCREEN);
-	alarmListWindow.show();
+	sAlarmListWindow = (ScreenWindow)getResources().getScreen(ID_ALARM_LIST_SCREEN);
+	sAlarmListWindow.show();
+	sAlarmStack = new Stack();
     }
 
-    static private ScreenWindow alarmListWindow;
+    public boolean receiveEvent(Event e) {
+	switch (e.type) {
+	case Event.EVENT_ALARM:
+	    Alarm alarm = (Alarm)e.argument;
+	    AlertWindow alert = getAlert(ID_ALARM_ALERT, this);
+	    alert.setMessage(alarm.getMessage());
+	    // alert.setMessageFormatDate(alarm.getDate());
+	    alert.show(AlertWindow.SYSTEM_ALERT_TYPE_ALARM);
+	    sAlarmStack.push(alarm);
+	    return true;
+	case EVENT_DISMISS_ALARM:
+	    ((Alarm)sAlarmStack.pop()).dismiss();
+	    return true;
+	}
+	return super.receiveEvent(e);
+    }
 }
