Initial revision
diff --git a/Demo/sgi/gl/mclock.py b/Demo/sgi/gl/mclock.py
new file mode 100755
index 0000000..5a94dcb
--- /dev/null
+++ b/Demo/sgi/gl/mclock.py
@@ -0,0 +1,731 @@
+#! /usr/local/python
+
+#############################################################################
+# NOTA BENE: Before installing, fix TZDIFF to reflect your local time zone! #
+#############################################################################
+
+# "M Clock"
+#
+# An implementation in software of an original design by Rob Juda.
+# Clock implementation: Guido van Rossum.
+# Alarm and Gong features: Sape Mullender.
+#
+# XXX TO DO:
+# add arguments to specify initial window position and size
+# find out local time zone difference automatically
+# add a date indicator
+# allow multiple alarms
+# allow the menu to change more parameters
+
+import sys
+
+from gl import *
+from GL import *
+from DEVICE import *
+import time
+import getopt
+import string
+import os
+from math import pi
+import math
+
+FULLC = 3600		# Full circle in 1/10-ths of a degree
+MIDN = 900		# Angle of the 12 o'clock position
+R, G, B = 0, 1, 2	# Indices of colors in RGB list
+
+HOUR = 3600		# Number of seconds per hour
+MINUTE = 60		# Number of seconds per minute
+
+class struct: pass	# Class to define featureless structures
+Gl = struct()		# Object to hold writable global variables
+
+# Default constants (used in multiple places)
+
+SCREENBG = 127, 156, 191
+NPARTS = 9
+TITLE = 'M Clock'
+TZDIFF = -2*HOUR	# <--- change this to reflect your local time zone
+
+# Default parameters
+
+Gl.foreground = 0	# If set, run in the foreground
+Gl.fullscreen = 0	# If set, run on full screen
+Gl.tzdiff = TZDIFF	# Seconds west of Greenwich (winter time)
+Gl.nparts = NPARTS	# Number of parts each circle is divided in (>= 2)
+Gl.debug = 0		# If set, print debug output
+Gl.doublebuffer = 1	# If set, use double buffering
+Gl.update = 0		# Update interval; seconds hand is suppressed if > 1
+Gl.colorsubset = 0	# If set, display only a subset of the colors
+Gl.cyan = 0		# If set, display cyan overlay (big hand)
+Gl.magenta = 0		# If set, display magenta overlay (little hand)
+Gl.yellow = 0		# If set, display yellow overlay (fixed background)
+Gl.black = 0		# If set, display black overlay (hands)
+Gl.colormap = 0		# If set, use colormap mode instead of RGB mode
+Gl.warnings = 0		# If set, print warnings
+Gl.title = ''		# Window title (default set later)
+Gl.name = 'mclock'	# Window title for resources
+Gl.border = 1		# If set, use a window border (and title)
+Gl.bg = 0, 0, 0		# Background color R, G, B value
+Gl.iconic = 0		# Set in iconic state
+Gl.fg = 255, 0, 0	# Alarm background RGB (either normal or alarm)
+Gl.ox,Gl.oy = 0,0	# Window origin
+Gl.cx,Gl.cy = 0,0	# Window size
+Gl.alarm_set = 0	# Alarm on or off
+Gl.alarm_on = 0		# Alarm is ringing
+Gl.alarm_time = 0	# Alarm time in seconds after midnight
+Gl.alarm_hours = 0	# Alarm hour setting, 24 hour clock
+Gl.alarm_minutes = 0	# Alarm minutes setting
+Gl.alarm_rgb = 0,0,0	# Alarm display RGB colors
+Gl.alarm_cmd = ''	# Command to execute when alarm goes off
+Gl.mouse2down = 0	# Mouse button state
+Gl.mouse3down = 0	# Mouse button state
+Gl.gong_cmd = ''	# Command to execute when chimes go off
+Gl.gong_int = 3600	# Gong interval
+Gl.indices = R, G, B	# Colors (permuted when alarm is on)
+
+def main():
+	#
+	sys.stdout = sys.stderr		# All output is errors/warnings etc.
+	#
+	try:
+		args = getoptions()
+	except string.atoi_error, value:
+		usage(string.atoi_error, value)
+	except getopt.error, msg:
+		usage(getopt.error, msg)
+	#
+	if args:
+		realtime = 0
+		hours = string.atoi(args[0])
+		minutes = seconds = 0
+		if args[1:]: minutes = string.atoi(args[1])
+		if args[2:]: seconds = string.atoi(args[2])
+		localtime = ((hours*60)+minutes)*60+seconds
+	else:
+		realtime = 1
+	#
+	if Gl.title == '':
+		if realtime:
+			Gl.title = TITLE
+		else:
+			title = ''
+			for arg in args: title = title + ' ' + arg
+			Gl.title = title[1:]
+			del title
+	#
+	wid = makewindow()
+	Gl.ox,Gl.oy = getorigin()
+	Gl.cx,Gl.cy = getsize()
+	initmenu()
+	clearall()
+	#
+	if not Gl.update:
+		Gl.update = 60
+	#
+	if Gl.update <= 1:
+		Gl.timernoise = 6
+	else:
+		Gl.timernoise = 60
+	noise(TIMER0, Gl.timernoise)
+	#
+	qdevice(WINSHUT)
+	qdevice(WINQUIT)
+	qdevice(ESCKEY)
+	if realtime:
+		qdevice(TIMER0)
+	qdevice(REDRAW)
+	qdevice(WINFREEZE)
+	qdevice(WINTHAW)
+	qdevice(MENUBUTTON)	# MOUSE1
+	qdevice(MOUSE3)		# Left button
+	qdevice(MOUSE2)		# Middle button
+	unqdevice(INPUTCHANGE)
+	#
+	lasttime = 0
+	Gl.change = 1
+	while 1:
+		if realtime:
+			localtime = time.time() - Gl.tzdiff
+		if Gl.alarm_set:
+			if localtime%(24*HOUR) == Gl.alarm_time:
+				# Ring the alarm!
+				if Gl.debug:
+					print 'Rrrringg!'
+				Gl.alarm_on = 1
+				if Gl.alarm_cmd <> '':
+					d = os.system(Gl.alarm_cmd+' '+`Gl.alarm_time/3600`+' '+`(Gl.alarm_time/60)%60` + ' &')
+				Gl.change = 1
+				clearall()
+		if Gl.alarm_on:
+			if (localtime - Gl.alarm_time) % (24*HOUR) > 300:
+				# More than 5 minutes away from alarm
+				Gl.alarm_on = 0
+				if Gl.debug:
+					print 'Alarm turned off'
+				Gl.change = 1
+				clearall()
+				Gl.indices = R, G, B
+			else:
+				if localtime % 2 == 0:
+				  # Permute color indices
+				  Gl.indices = Gl.indices[2:] + Gl.indices[:2]
+				  Gl.change = 1
+		if Gl.gong_cmd <> '' and localtime%Gl.gong_int == 0:
+			d = os.system(Gl.gong_cmd+' '+`(localtime/3600)%24`+' '+`(localtime/60)%60` + ' &')
+		if localtime/Gl.update <> lasttime/Gl.update:
+			if Gl.debug: print 'new time'
+			Gl.change = 1
+		if Gl.change:
+			if Gl.debug: print 'drawing'
+			doit(localtime)
+			lasttime = localtime
+			Gl.change = 0
+		dev, data = qread()
+		if Gl.debug and dev <> TIMER0:
+			print dev, data
+		if dev == TIMER0:
+			if Gl.debug > 1:
+				print dev, data
+		elif dev == MOUSE3:
+			mousex = getvaluator(MOUSEX)
+			mousey = getvaluator(MOUSEY)
+			if mouseclick(3, data, mousex, mousey):
+				Gl.change = 1
+		elif dev == MOUSE2:
+			mousex = getvaluator(MOUSEX)
+			mousey = getvaluator(MOUSEY)
+			if mouseclick(2, data, mousex, mousey):
+				Gl.change = 1
+		elif dev == MOUSEX:
+			mousex = data
+			if Gl.mouse2down:
+				mouse2track(mousex, mousey)
+			if Gl.mouse3down:
+				mouse3track(mousex, mousey)
+		elif dev == MOUSEY:
+			mousey = data
+			if Gl.mouse2down:
+				mouse2track(mousex, mousey)
+			if Gl.mouse3down:
+				mouse3track(mousex, mousey)
+		elif dev == REDRAW or dev == REDRAWICONIC:
+			if Gl.debug:
+				if dev == REDRAW: print 'REDRAW'
+				else: print 'REDRAWICONIC'
+			reshapeviewport()
+			Gl.ox,Gl.oy = getorigin()
+			Gl.cx,Gl.cy = getsize()
+			Gl.change = 1
+			clearall()
+		elif dev == MENUBUTTON:
+			if Gl.debug: print 'MENUBUTTON'
+			handlemenu()
+		elif dev == WINFREEZE:
+			if Gl.debug: print 'WINFREEZE'
+			Gl.iconic = 1
+			noise(TIMER0, 60*60) # Redraw every 60 seconds only
+		elif dev == WINTHAW:
+			if Gl.debug: print 'WINTHAW'
+			Gl.iconic = 0
+			noise(TIMER0, Gl.timernoise)
+			Gl.change = 1
+		elif dev == ESCKEY or dev == WINSHUT or dev == WINQUIT:
+			if Gl.debug: print 'Exit'
+			sys.exit(0)
+
+def getoptions():
+	optlist, args = getopt.getopt(sys.argv[1:], 'A:a:B:bc:dFfG:g:n:sT:t:u:wCMYK')
+	for optname, optarg in optlist:
+		if optname == '-A':
+			Gl.fg = eval(optarg)	# Should be (r,g,b)
+		elif optname == '-a':
+			Gl.alarm_cmd = optarg
+		elif optname == '-B':
+			Gl.bg = eval(optarg)	# Should be (r,g,b)
+		elif optname == '-b':
+			Gl.border = 0
+		elif optname == '-c':
+			Gl.colormap = string.atoi(optarg)
+		elif optname == '-d':
+			Gl.debug = Gl.debug + 1
+			Gl.warnings = 1
+		elif optname == '-F':
+			Gl.foreground = 1
+		elif optname == '-f':
+			Gl.fullscreen = 1
+		elif optname == '-G':
+			Gl.gong_int = 60*string.atoi(optarg)
+		elif optname == '-g':
+			Gl.gong_cmd = optarg
+		elif optname == '-n':
+			Gl.nparts = string.atoi(optarg)
+		elif optname == '-s':
+			Gl.doublebuffer = 0
+		elif optname == '-T':
+			Gl.title = Gl.name = optarg
+		elif optname == '-t':
+			Gl.tzdiff = string.atoi(optarg)
+		elif optname == '-u':
+			Gl.update = string.atoi(optarg)
+		elif optname == '-w':
+			Gl.warnings = 1
+		elif optname == '-C':
+			Gl.cyan = Gl.colorsubset = 1
+		elif optname == '-M':
+			Gl.magenta = Gl.colorsubset = 1
+		elif optname == '-Y':
+			Gl.yellow = Gl.colorsubset = 1
+		elif optname == '-K':
+			Gl.black = Gl.colorsubset = 1
+		else:
+			print 'Unsupported option', optname
+	return args
+
+def usage(exc, msg):
+	if sys.argv:
+		progname = os.path.basename(sys.argv[0])
+	else:
+		progname = 'mclock'
+	#
+	print progname + ':',
+	if exc == string.atoi_error:
+		print 'non-numeric argument:',
+	print msg
+	#
+	print 'usage:', progname, '[options] [hh [mm [ss]]]'
+	#
+	print '-A r,g,b  : alarm background red,green,blue [255,0,0]'
+	print '-a cmd    : shell command executed when alarm goes off'
+	print '-B r,g,b  : background red,green,blue [0,0,0]'
+	print '            (-B SCREENBG uses the default screen background)'
+	print '-b        : suppress window border and title'
+	print '-c cmapid : select explicit colormap'
+	print '-d        : more debug output (implies -F, -w)'
+	print '-F        : run in foreground'
+	print '-f        : use full screen'
+	print '-G intrvl : interval between chimes in minutes [60]'
+	print '-g cmd    : shell command executed when chimes go off'
+	print '-s        : single buffer mode'
+	print '-w        : print various warnings'
+	print '-n nparts : number of parts [' + `NPARTS` + ']'
+	print '-T title  : alternate window title [\'' + TITLE + '\']'
+	print '-t tzdiff : time zone difference [' + `TZDIFF` + ']'
+	print '-u update : update interval [60]'
+	print '-CMYK     : Cyan, Magenta, Yellow or blacK overlay only'
+	print 'if hh [mm [ss]] is specified, display that time statically'
+	print 'on machines with < 12 bitplanes, -c and -s are forced on'
+	#
+	sys.exit(2)
+
+def doit(localtime):
+	hands = makehands(localtime)
+	list = makelist(hands)
+	render(list, hands)
+
+def makehands(localtime):
+	localtime = localtime % (12*HOUR)
+	seconds_hand = MIDN + FULLC - (localtime*60) % FULLC
+	big_hand = (MIDN + FULLC - (localtime%HOUR)) % FULLC
+	little_hand = (MIDN + FULLC - ((localtime/12) % HOUR)) % FULLC
+	return little_hand, big_hand, seconds_hand
+
+def makelist(little_hand, big_hand, seconds_hand):
+	total = []
+	if Gl.cyan or not Gl.colorsubset:
+		total = total + makesublist(big_hand, Gl.indices[0])
+	if Gl.magenta or not Gl.colorsubset:
+		total = total + makesublist(little_hand, Gl.indices[1])
+	if Gl.yellow or not Gl.colorsubset:
+		total = total + makesublist(MIDN, Gl.indices[2])
+	total.sort()
+	return total
+
+def makesublist(first, icolor):
+	list = []
+	alpha = FULLC/Gl.nparts
+	a = first - alpha/2
+	for i in range(Gl.nparts):
+		angle = (a + i*alpha + FULLC) % FULLC
+		value = 255*(Gl.nparts-1-i)/(Gl.nparts-1)
+		list.append(angle, icolor, value)
+	list.sort()
+	a, icolor, value = list[0]
+	if a <> 0:
+		a, icolor, value = list[len(list)-1]
+		t = 0, icolor, value
+		list.insert(0, t)
+	return list
+
+def rgb_fg():
+	return Gl.fg
+	# Obsolete code:
+	if Gl.alarm_on:
+		return Gl.bg
+	else:
+		return Gl.fg
+
+def rgb_bg():
+	return Gl.bg
+	# Obsolete code:
+	if Gl.alarm_on:
+		return Gl.fg
+	else:
+		return Gl.bg
+
+def clearall():
+	Gl.c3i(rgb_bg())
+	clear()
+	if Gl.doublebuffer:
+		swapbuffers()
+		clear()
+
+def draw_alarm(color):
+	frontbuffer(TRUE)
+	Gl.c3i(color)
+	pushmatrix()
+	rotate(-((Gl.alarm_time/12)%3600), 'z')
+	bgnpolygon()
+	v2f( 0.00,1.00)
+	v2f( 0.04,1.05)
+	v2f(-0.04,1.05)
+	endpolygon()
+	popmatrix()
+	#
+	pushmatrix()
+	rotate(-((Gl.alarm_time)%3600), 'z')
+	bgnpolygon()
+	v2f( 0.00,1.05)
+	v2f( 0.07,1.10)
+	v2f(-0.07,1.10)
+	endpolygon()
+	popmatrix()
+	#
+	cmov2(-1.06, -1.06)
+	charstr(string.rjust(`Gl.alarm_time/3600`,2))
+	charstr(':')
+	charstr(string.zfill((Gl.alarm_time/60)%60,2))
+	frontbuffer(FALSE)
+
+def render(list, (little_hand, big_hand, seconds_hand)):
+	#
+	if Gl.colormap:
+		resetindex()
+	#
+	if not list:
+		Gl.c3i(255, 255, 255) # White
+		circf(0.0, 0.0, 1.0)
+	else:
+		list.append(3600, 0, 255) # Sentinel
+	#
+	rgb = [255, 255, 255]
+	a_prev = 0
+	for a, icolor, value in list:
+		if a <> a_prev:
+			[r, g, b] = rgb
+			if Gl.debug > 1:
+				print rgb, a_prev, a
+			Gl.c3i(r, g, b)
+			arcf(0.0, 0.0, 1.0, a_prev, a)
+		rgb[icolor] = value
+		a_prev = a
+	#
+	if Gl.black or not Gl.colorsubset:
+		#
+		# Draw the hands -- in black
+		#
+		Gl.c3i(0, 0, 0)
+		#
+		if Gl.update == 1 and not Gl.iconic:
+			# Seconds hand is only drawn if we update every second
+			pushmatrix()
+			rotate(seconds_hand, 'z')
+			bgnline()
+			v2f(0.0, 0.0)
+			v2f(1.0, 0.0)
+			endline()
+			popmatrix()
+		#
+		pushmatrix()
+		rotate(big_hand, 'z')
+		rectf(0.0, -0.01, 0.97, 0.01)
+		circf(0.0, 0.0, 0.01)
+		circf(0.97, 0.0, 0.01)
+		popmatrix()
+		#
+		pushmatrix()
+		rotate(little_hand, 'z')
+		rectf(0.04, -0.02, 0.63, 0.02)
+		circf(0.04, 0.0, 0.02)
+		circf(0.63, 0.0, 0.02)
+		popmatrix()
+		#
+		# Draw the alarm time, if set or being set
+		#
+		if Gl.alarm_set:
+			draw_alarm(rgb_fg())
+	#
+	if Gl.doublebuffer: swapbuffers()
+
+def makewindow():
+	#
+	if Gl.debug or Gl.foreground:
+		foreground()
+	#
+	if Gl.fullscreen:
+		scrwidth, scrheight = getgdesc(GD_XPMAX), getgdesc(GD_YPMAX)
+		prefposition(0, scrwidth-1, 0, scrheight-1)
+	else:
+		keepaspect(1, 1)
+		prefsize(100, 100)
+	#
+	if not Gl.border:
+		noborder()
+	wid = winopen(Gl.name)
+	wintitle(Gl.title)
+	#
+	if not Gl.fullscreen:
+		keepaspect(1, 1)
+		minsize(10, 10)
+		maxsize(2000, 2000)
+		iconsize(66, 66)
+		winconstraints()
+	#
+	nplanes = getplanes()
+	nmaps = getgdesc(GD_NMMAPS)
+	if Gl.warnings:
+		print nplanes, 'color planes,', nmaps, 'color maps'
+	#
+	if nplanes < 12 or Gl.colormap:
+		if not Gl.colormap:
+			Gl.colormap = nmaps - 1
+			if Gl.warnings:
+				print 'not enough color planes available',
+				print 'for RGB mode; forcing colormap mode'
+				print 'using color map number', Gl.colormap
+		if not Gl.colorsubset:
+			needed = 3
+		else:
+			needed = Gl.cyan + Gl.magenta + Gl.yellow
+		needed = needed*Gl.nparts
+		if Gl.bg <> (0, 0, 0):
+			needed = needed+1
+		if Gl.fg <> (0, 0, 0):
+			needed = needed+1
+		if Gl.doublebuffer:
+			if needed > available(nplanes/2):
+				Gl.doublebuffer = 0
+				if Gl.warnings:
+					print 'not enough colors available',
+					print 'for double buffer mode;',
+					print 'forcing single buffer mode'
+			else:
+				nplanes = nplanes/2
+		if needed > available(nplanes):
+			# Do this warning always
+			print 'still not enough colors available;',
+			print 'parts will be left white'
+			print '(needed', needed, 'but have only',
+			print available(nplanes), 'colors available)'
+	#
+	if Gl.doublebuffer:
+		doublebuffer()
+		gconfig()
+	#
+	if Gl.colormap:
+		Gl.c3i = pseudo_c3i
+		fixcolormap()
+	else:
+		Gl.c3i = c3i
+		RGBmode()
+		gconfig()
+	#
+	if Gl.fullscreen:
+		# XXX Should find out true screen size using getgdesc()
+		ortho2(-1.1*1.280, 1.1*1.280, -1.1*1.024, 1.1*1.024)
+	else:
+		ortho2(-1.1, 1.1, -1.1, 1.1)
+	#
+	return wid
+
+def available(nplanes):
+	return pow(2, nplanes) - 1	# Reserve one pixel for black
+
+def fixcolormap():
+	multimap()
+	gconfig()
+	nplanes = getplanes()
+	if Gl.warnings:
+		print 'multimap mode has', nplanes, 'color planes'
+	imap = Gl.colormap
+	Gl.startindex = pow(2, nplanes) - 1
+	Gl.stopindex = 1
+	setmap(imap)
+	mapcolor(0, 0, 0, 0) # Fixed entry for black
+	if Gl.bg <> (0, 0, 0):
+		r, g, b = Gl.bg
+		mapcolor(1, r, g, b) # Fixed entry for Gl.bg
+		Gl.stopindex = 2
+	if Gl.fg <> (0, 0, 0):
+		r, g, b = Gl.fg
+		mapcolor(2, r, g, b) # Fixed entry for Gl.fg
+		Gl.stopindex = 3
+	Gl.overflow_seen = 0
+	resetindex()
+
+def resetindex():
+	Gl.index = Gl.startindex
+
+r0g0b0 = (0, 0, 0)
+
+def pseudo_c3i(rgb):
+	if rgb == r0g0b0:
+		index = 0
+	elif rgb == Gl.bg:
+		index = 1
+	elif rgb == Gl.fg:
+		index = 2
+	else:
+		index = definecolor(rgb)
+	color(index)
+
+def definecolor(rgb):
+	index = Gl.index
+	if index < Gl.stopindex:
+		if Gl.debug: print 'definecolor hard case', rgb
+		# First see if we already have this one...
+		for index in range(Gl.stopindex, Gl.startindex+1):
+			if rgb == getmcolor(index):
+				if Gl.debug: print 'return', index
+				return index
+		# Don't clobber reserverd colormap entries
+		if not Gl.overflow_seen:
+			# Shouldn't happen any more, hence no Gl.warnings test
+			print 'mclock: out of colormap entries'
+			Gl.overflow_seen = 1
+		return Gl.stopindex
+	r, g, b = rgb
+	if Gl.debug > 1: print 'mapcolor', (index, r, g, b)
+	mapcolor(index, r, g, b)
+	Gl.index = index - 1
+	return index
+
+# Compute n**i
+def pow(n, i):
+	x = 1
+	for j in range(i): x = x*n
+	return x
+
+def mouseclick(mouse, updown, x, y):
+	if updown == 1:
+		# mouse button came down, start tracking
+		if Gl.debug:
+			print 'mouse', mouse, 'down at', x, y
+		if mouse == 2:
+			Gl.mouse2down = 1
+			mouse2track(x, y)
+		elif mouse == 3:
+			Gl.mouse3down = 1
+			mouse3track(x, y)
+		else:
+			print 'fatal error'
+		qdevice(MOUSEX)
+		qdevice(MOUSEY)
+		return 0
+	else:
+		# mouse button came up, stop tracking
+		if Gl.debug:
+			print 'mouse', mouse, 'up at', x, y
+		unqdevice(MOUSEX)
+		unqdevice(MOUSEY)
+		if mouse == 2:
+			mouse2track(x, y)
+			Gl.mouse2down = 0
+		elif mouse == 3:
+			mouse3track(x, y)
+			Gl.mouse3down = 0
+		else:
+			print 'fatal error'
+		Gl.alarm_set = 1
+		return 1
+
+def mouse3track(x, y):
+	# first compute polar coordinates from x and y
+	cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2
+	x, y = x - cx, y - cy
+	if (x, y) == (0, 0): return	# would cause an exception
+	minutes = int(30.5 + 30.0*math.atan2(float(-x), float(-y))/pi)
+	if minutes == 60: minutes = 0
+	a,b = Gl.alarm_minutes/15, minutes/15
+	if (a,b) == (0,3):
+		# Moved backward through 12 o'clock:
+		Gl.alarm_hours = Gl.alarm_hours - 1
+		if Gl.alarm_hours < 0: Gl.alarm_hours = Gl.alarm_hours + 24
+	if (a,b) == (3,0):
+		# Moved forward through 12 o'clock:
+		Gl.alarm_hours = Gl.alarm_hours + 1
+		if Gl.alarm_hours >= 24: Gl.alarm_hours = Gl.alarm_hours - 24
+	Gl.alarm_minutes = minutes
+	seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE
+	if seconds <> Gl.alarm_time:
+		draw_alarm(rgb_bg())
+		Gl.alarm_time = seconds
+		draw_alarm(rgb_fg())
+
+def mouse2track(x, y):
+	# first compute polar coordinates from x and y
+	cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2
+	x, y = x - cx, y - cy
+	if (x, y) == (0, 0): return	# would cause an exception
+	hours = int(6.5 - float(Gl.alarm_minutes)/60.0 + 6.0*math.atan2(float(-x), float(-y))/pi)
+	if hours == 12: hours = 0
+	if (Gl.alarm_hours,hours) == (0,11):
+		# Moved backward through midnight:
+		Gl.alarm_hours = 23
+	elif (Gl.alarm_hours,hours) == (12,11):
+		# Moved backward through noon:
+		Gl.alarm_hours = 11
+	elif (Gl.alarm_hours,hours) == (11,0):
+		# Moved forward through noon:
+		Gl.alarm_hours = 12
+	elif (Gl.alarm_hours,hours) == (23,0):
+		# Moved forward through midnight:
+		Gl.alarm_hours = 0
+	elif Gl.alarm_hours < 12:
+		Gl.alarm_hours = hours
+	else:
+		Gl.alarm_hours = hours + 12
+	seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE
+	if seconds <> Gl.alarm_time:
+		draw_alarm(rgb_bg())
+		Gl.alarm_time = seconds
+		draw_alarm(rgb_fg())
+
+def initmenu():
+	Gl.pup = pup = newpup()
+	addtopup(pup, 'M Clock%t|Alarm On/Off|Seconds Hand On/Off|Quit', 0)
+
+def handlemenu():
+	item = dopup(Gl.pup)
+	if item == 1:
+		# Toggle alarm
+		if Gl.alarm_set:
+			Gl.alarm_set = 0
+			Gl.alarm_on = 0
+		else:
+			Gl.alarm_set = 1
+		Gl.change = 1
+		clearall()
+	elif item == 2:
+		# Toggle Seconds Hand
+		if Gl.update == 1:
+			Gl.update = 60
+			Gl.timernoise = 60
+		else:
+			Gl.update = 1
+			Gl.timernoise = 6
+		Gl.change = 1
+	elif item == 3:
+		if Gl.debug: print 'Exit'
+		sys.exit(0)
+
+main()